Line data Source code
1 : /*
2 : * flow.c -- flow handling utility
3 : *
4 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
5 : */
6 : #include <stdio.h>
7 : #include <stdlib.h>
8 : #include <unistd.h>
9 : #include <string.h>
10 : #include <errno.h>
11 : #include <stdlib.h>
12 : #include <fcntl.h>
13 : #include <getopt.h>
14 : #include <stdbool.h>
15 : #include <assert.h>
16 : #include <time.h>
17 : #include <inttypes.h>
18 :
19 : #include <sys/types.h>
20 : #include <sys/time.h>
21 : #include <sys/stat.h>
22 : #include <sys/socket.h>
23 : #include <netinet/in.h>
24 : #include <arpa/inet.h>
25 : #include <sys/mman.h>
26 : #if defined(__linux__)
27 : #include <asm/types.h>
28 :
29 : #include <linux/netlink.h>
30 : #include <linux/rtnetlink.h>
31 : #include <linux/if_ether.h>
32 : #endif
33 :
34 : #include <net/if.h>
35 : #if defined(__linux__)
36 : #include <netinet/ether.h>
37 : #endif
38 :
39 : #include "vr_types.h"
40 : #include "vr_qos.h"
41 : #include "vr_flow.h"
42 : #include "vr_mirror.h"
43 : #include "vr_genetlink.h"
44 : #include "nl_util.h"
45 : #include "vr_os.h"
46 : #include "ini_parser.h"
47 : #include "vr_packet.h"
48 : #include "vr_message.h"
49 : #include "vr_mem.h"
50 :
51 : #define TABLE_FLAG_VALID 0x1
52 :
53 : #define MAX_FLOW_NL_MSG_BUNCH 15
54 : #define MAX_FLOWS 4000000
55 :
56 : static int mem_fd;
57 :
58 : static int dvrf_set, mir_set, show_evicted_set, sock_dir_set;
59 : static int help_set, match_set, get_set, force_evict_set;
60 : static unsigned short dvrf;
61 : static int list, flow_cmd, mirror = -1;
62 : static unsigned long flow_index;
63 : static int rate, stats, perf, flush, bunch = 1;
64 : static bool more = false;
65 :
66 : #define FLOW_GET_FIELD_LENGTH 30
67 : #define FLOW_COMPONENT_NH_COUNT 16
68 :
69 : char src_vif_name[IFNAMSIZ];
70 : char src_l3_vif_name[IFNAMSIZ], dst_l3_vif_name[IFNAMSIZ];
71 : char src_l2_vif_name[IFNAMSIZ], dst_l2_vif_name[IFNAMSIZ];
72 : vr_interface_req *src_vif, *src_l3_vif, *dst_l3_vif, *resp_vif;
73 : vr_interface_req *src_l2_vif, *dst_l2_vif;
74 :
75 : vr_nexthop_req *src_nh, *resp_nh;
76 : vr_nexthop_req *src_l3_nh, *dst_l3_nh;
77 : vr_nexthop_req *src_l2_nh, *dst_l2_nh;
78 : vr_nexthop_req *component_nh[FLOW_COMPONENT_NH_COUNT];
79 : vr_nexthop_req *mirror_nh, *mirror1_nh;
80 :
81 : vr_route_req *resp_rt;
82 : vr_route_req *src_l3_rt, *dst_l3_rt;
83 : vr_route_req *src_l2_rt, *dst_l2_rt;
84 :
85 : uint8_t req_prefix[VR_IP6_ADDRESS_LEN];
86 : uint8_t req_mac[VR_ETHER_ALEN];
87 :
88 : vr_mirror_req *resp_mirror;
89 :
90 : vr_drop_stats_req *resp_ds, *global_ds;
91 :
92 : unsigned char addr_string[INET6_ADDRSTRLEN];
93 : int ecmp_index = -1;
94 :
95 : /* match variables */
96 : static unsigned int match_family, match_family_size;
97 : static int32_t match_port1 = -1, match_port2 = -1;
98 : static int32_t match_proto = -1, match_vrf = -1;
99 : static char *match_ip1, *match_ip2;
100 :
101 : /* to accommodate '*' */
102 : bool match_ip1_set, match_ip2_set;
103 :
104 : struct flow_table {
105 : struct vr_flow_entry *ft_entries;
106 : u_int64_t ft_entries_p;
107 : u_int64_t ft_span;
108 : u_int64_t ft_processed;
109 : u_int64_t ft_created;
110 : u_int64_t ft_added;
111 : u_int64_t ft_deleted;
112 : u_int64_t ft_changed;
113 : u_int64_t ft_total_entries;
114 : unsigned int ft_burst_free_tokens;
115 : unsigned int ft_hold_entries;
116 : unsigned int ft_num_entries;
117 : unsigned int ft_flags;
118 : unsigned int ft_cpus;
119 : unsigned int ft_hold_oflows;
120 : unsigned int ft_hold_stat_count;
121 : unsigned int ft_oflow_entries;
122 : u_int32_t ft_hold_stat[128];
123 : char flow_table_path[256];
124 : } main_table;
125 :
126 : struct flow_md {
127 : unsigned int fmd_index;
128 : unsigned int fmd_gen_id;
129 : };
130 :
131 :
132 : struct nl_client *cl;
133 : vr_flow_req flow_req;
134 : vr_flow_table_data ftable;
135 : static struct flow_md flow_md_mem[MAX_FLOWS];
136 : static int array_index;
137 :
138 : static void flow_dump_nexthop(vr_nexthop_req *, vr_interface_req *,
139 : char *, bool);
140 : static vr_nexthop_req *flow_get_nexthop(int);
141 : static int flow_table_map(vr_flow_table_data *);
142 : static int flow_table_get(void);
143 :
144 : static void
145 50 : response_process(void *sresp)
146 : {
147 50 : vr_response *resp = (vr_response *)sresp;
148 :
149 50 : if (resp->resp_code < 0) {
150 0 : printf("%s: %s\n", __func__, strerror(-resp->resp_code));
151 0 : exit(-2);
152 : }
153 :
154 50 : return;
155 : }
156 :
157 : static void
158 0 : flow_response_process(void *sresp)
159 : {
160 0 : if (array_index == -1)
161 0 : return;
162 :
163 0 : vr_flow_response *resp = (vr_flow_response *)sresp;
164 0 : flow_md_mem[array_index].fmd_index = resp->fresp_index;
165 0 : flow_md_mem[array_index].fmd_gen_id = resp->fresp_gen_id;
166 0 : return;
167 : }
168 :
169 :
170 : static void
171 13 : flow_table_data_process(void *sreq)
172 : {
173 13 : vr_flow_table_data *ftable = (vr_flow_table_data *)sreq;
174 :
175 13 : flow_table_map(ftable);
176 :
177 13 : return;
178 : }
179 :
180 : static void
181 7 : interface_req_process(void *arg)
182 : {
183 7 : vr_interface_req *req = (vr_interface_req *)arg;
184 :
185 7 : resp_vif = vr_interface_req_get_copy(req);
186 :
187 7 : return;
188 : }
189 :
190 : static void
191 15 : nexthop_req_process(void *arg)
192 : {
193 15 : vr_nexthop_req *req = (vr_nexthop_req *)arg;
194 :
195 15 : resp_nh = vr_nexthop_req_get_copy(req);
196 :
197 15 : return;
198 : }
199 :
200 : static void
201 10 : route_req_process(void *arg)
202 : {
203 10 : vr_route_req *req = (vr_route_req *)arg;
204 :
205 10 : resp_rt = vr_route_req_get_copy(req);
206 :
207 10 : return;
208 : }
209 :
210 : static void
211 5 : drop_stats_req_process(void *arg)
212 : {
213 5 : vr_drop_stats_req *req = (vr_drop_stats_req *)arg;
214 :
215 5 : resp_ds = vr_drop_stats_req_get_copy(req);
216 :
217 5 : return;
218 : }
219 :
220 : static void
221 13 : flow_fill_nl_callbacks()
222 : {
223 13 : nl_cb.vr_response_process = response_process;
224 13 : nl_cb.vr_flow_response_process = flow_response_process;
225 13 : nl_cb.vr_flow_table_data_process = flow_table_data_process;
226 13 : nl_cb.vr_interface_req_process = interface_req_process;
227 13 : nl_cb.vr_nexthop_req_process = nexthop_req_process;
228 13 : nl_cb.vr_route_req_process = route_req_process;
229 13 : nl_cb.vr_drop_stats_req_process = drop_stats_req_process;
230 13 : }
231 :
232 : struct vr_flow_entry *
233 12 : flow_get(unsigned long flow_index)
234 : {
235 12 : if (flow_index >= main_table.ft_num_entries)
236 0 : return NULL;
237 :
238 12 : return &main_table.ft_entries[flow_index];
239 : }
240 :
241 : static vr_drop_stats_req *
242 5 : flow_get_dropstats(void)
243 : {
244 : int ret;
245 :
246 5 : ret = vr_send_drop_stats_get(cl, 0, 0);
247 5 : if (ret < 0)
248 0 : return NULL;
249 :
250 5 : ret = vr_recvmsg(cl, false);
251 5 : if (ret <= 0)
252 0 : return NULL;
253 :
254 5 : return resp_ds;
255 : }
256 :
257 : static vr_nexthop_req *
258 15 : flow_get_nexthop(int id)
259 : {
260 : int ret;
261 :
262 15 : resp_nh = NULL;
263 :
264 15 : ret = vr_send_nexthop_get(cl, 0, id);
265 15 : if (ret < 0)
266 0 : return NULL;
267 :
268 15 : ret = vr_recvmsg(cl, false);
269 15 : if (ret <= 0)
270 0 : return NULL;
271 :
272 15 : return resp_nh;
273 : }
274 :
275 : static vr_nexthop_req *
276 0 : flow_get_mirror_nh(int id)
277 : {
278 : int ret;
279 :
280 0 : ret = vr_send_mirror_get(cl, 0, id);
281 0 : if (ret < 0)
282 0 : return NULL;
283 :
284 0 : ret = vr_recvmsg(cl, false);
285 0 : if (ret <= 0)
286 0 : return NULL;
287 :
288 0 : return flow_get_nexthop(resp_mirror->mirr_nhid);
289 : }
290 :
291 : static vr_interface_req *
292 7 : flow_get_vif(int vif_index)
293 : {
294 : int ret;
295 :
296 7 : ret = vr_send_interface_get(cl, 0, vif_index, -1, 0, 0);
297 7 : if (ret < 0)
298 0 : return NULL;
299 :
300 7 : ret = vr_recvmsg(cl, false);
301 7 : if (ret <= 0)
302 0 : return NULL;
303 :
304 7 : return resp_vif;
305 : }
306 :
307 : static vr_route_req *
308 10 : flow_get_route(unsigned int family, unsigned int vrf, uint8_t *prefix)
309 : {
310 : int ret;
311 : unsigned int prefix_size;
312 :
313 10 : switch (family) {
314 10 : case AF_INET:
315 10 : prefix_size = VR_IP_ADDRESS_LEN;
316 10 : break;
317 :
318 0 : case AF_INET6:
319 0 : prefix_size = VR_IP6_ADDRESS_LEN;
320 0 : break;
321 :
322 0 : case AF_BRIDGE:
323 0 : prefix_size = VR_ETHER_ALEN;
324 0 : memcpy(req_mac, prefix, prefix_size);
325 0 : break;
326 :
327 0 : default:
328 0 : return NULL;
329 : }
330 :
331 10 : memcpy(req_prefix, prefix, prefix_size);
332 10 : if (family == AF_BRIDGE) {
333 0 : ret = vr_send_route_get(cl, 0, vrf, family, NULL, 0, req_mac);
334 : } else {
335 10 : ret = vr_send_route_get(cl, 0, vrf, family, req_prefix,
336 : prefix_size * 8, req_mac);
337 : }
338 :
339 10 : if (ret < 0)
340 0 : return NULL;
341 :
342 10 : ret = vr_recvmsg(cl, false);
343 10 : if (ret <= 0)
344 0 : return NULL;
345 :
346 10 : return resp_rt;
347 : }
348 :
349 : const char *
350 0 : flow_get_drop_reason(uint8_t drop_code)
351 : {
352 0 : switch (drop_code) {
353 0 : case VR_FLOW_DR_UNKNOWN:
354 0 : return "Unknown";
355 0 : case VR_FLOW_DR_UNAVIALABLE_INTF:
356 0 : return "IntfErr";
357 0 : case VR_FLOW_DR_IPv4_FWD_DIS:
358 0 : return "Ipv4Dis";
359 0 : case VR_FLOW_DR_UNAVAILABLE_VRF:
360 0 : return "VrfErr";
361 0 : case VR_FLOW_DR_NO_SRC_ROUTE:
362 0 : return "NoSrcRt";
363 0 : case VR_FLOW_DR_NO_DST_ROUTE:
364 0 : return "NoDstRt";
365 0 : case VR_FLOW_DR_AUDIT_ENTRY:
366 0 : return "Audit";
367 0 : case VR_FLOW_DR_VRF_CHANGE:
368 0 : return "VrfChange";
369 0 : case VR_FLOW_DR_NO_REVERSE_FLOW:
370 0 : return "NoRevFlow";
371 0 : case VR_FLOW_DR_REVERSE_FLOW_CHANGE:
372 0 : return "RevFlowChng";
373 0 : case VR_FLOW_DR_NAT_CHANGE:
374 0 : return "NatChng";
375 0 : case VR_FLOW_DR_FLOW_LIMIT:
376 0 : return "FlowLim";
377 0 : case VR_FLOW_DR_LINKLOCAL_SRC_NAT:
378 0 : return "LinkSrcNatErr";
379 0 : case VR_FLOW_DR_FAILED_VROUTER_INSTALL:
380 0 : return "VrouterInstallFail";
381 0 : case VR_FLOW_DR_INVALID_L2_FLOW:
382 0 : return "InvalidL2Flow";
383 0 : case VR_FLOW_DR_FLOW_ON_TSN:
384 0 : return "TSNFlow";
385 0 : case VR_FLOW_DR_PORT_MAP_DROP:
386 0 : return "NoFipPortMap";
387 0 : case VR_FLOW_DR_NO_SRC_ROUTE_L2RPF:
388 0 : return "NoSrcRtRpfNh";
389 0 : case VR_FLOW_DR_FAT_FLOW_NAT_CONFLICT:
390 0 : return "FatFlowNatConflict";
391 0 : case VR_FLOW_DR_POLICY:
392 0 : return "Policy";
393 0 : case VR_FLOW_DR_OUT_POLICY:
394 0 : return "OutPolicy";
395 0 : case VR_FLOW_DR_SG:
396 0 : return "SG";
397 0 : case VR_FLOW_DR_OUT_SG:
398 0 : return "OutSG";
399 0 : case VR_FLOW_DR_REVERSE_SG:
400 0 : return "RevSG";
401 0 : case VR_FLOW_DR_REVERSE_OUT_SG:
402 0 : return "RevOutSG";
403 0 : case VR_FLOW_DR_FW_POLICY:
404 0 : return "FwPolicy";
405 0 : case VR_FLOW_DR_OUT_FW_POLICY:
406 0 : return "OutFwPolicy";
407 0 : case VR_FLOW_DR_REVERSE_FW_POLICY:
408 0 : return "RevFwPolicy";
409 0 : case VR_FLOW_DR_REVERSE_OUT_FW_POLICY:
410 0 : return "RevOutFwPolicy";
411 0 : case VR_FLOW_DR_SAME_FLOW_RFLOW_KEY:
412 0 : return "SameFlowRflowKey";
413 0 : case VR_FLOW_DR_NO_MIRROR_ENTRY:
414 0 : return "NoMirrorentry";
415 0 : case VR_FLOW_DR_FWAAS_POLICY:
416 0 : return "FWAASPolicy";
417 0 : case VR_FLOW_DR_OUT_FWAAS_POLICY:
418 0 : return "OutFWAASPolicy";
419 0 : case VR_FLOW_DR_REVERSE_FWAAS_POLICY:
420 0 : return "RevFWAASPolicy";
421 0 : case VR_FLOW_DR_REVERSE_OUT_FWAAS_POLICY:
422 0 : return "RevOutFWAASPolicy";
423 0 : default:
424 0 : break;
425 : }
426 0 : return NULL;
427 : }
428 :
429 : static void
430 4 : flow_dump_legend(void)
431 : {
432 4 : printf("Action:F=Forward, D=Drop ");
433 4 : printf("N=NAT(S=SNAT, D=DNAT, Ps=SPAT, Pd=DPAT, ");
434 4 : printf("L=Link Local Port)\n");
435 :
436 4 : printf(" Other:K(nh)=Key_Nexthop, S(nh)=RPF_Nexthop\n");
437 4 : printf(" Flags:E=Evicted, Ec=Evict Candidate, N=New Flow, M=Modified Dm=Delete Marked\n");
438 4 : printf("TCP(r=reverse):S=SYN, F=FIN, R=RST, C=HalfClose, E=Established, D=Dead\n");
439 4 : printf("\n");
440 :
441 4 : return;
442 : }
443 :
444 : static bool
445 0 : flow_match_dest(struct vr_flow_entry *fe, uint8_t *addr, int32_t port)
446 : {
447 0 : if (!addr && (port < 0))
448 0 : return false;
449 :
450 0 : if (!memcmp(&fe->fe_key.flow_ip[VR_IP_ADDR_SIZE(fe->fe_type)],
451 : addr, match_family_size)) {
452 0 : if (port < 0)
453 0 : return true;
454 0 : if (ntohs(fe->fe_key.flow_dport) == port)
455 0 : return true;
456 : }
457 :
458 0 : return false;
459 : }
460 :
461 : static bool
462 0 : flow_match_source(struct vr_flow_entry *fe, uint8_t *addr, int32_t port)
463 : {
464 0 : if (!addr && (port < 0))
465 0 : return false;
466 :
467 0 : if (!addr || !memcmp(fe->fe_key.flow_ip, addr, match_family_size)) {
468 0 : if (port < 0)
469 0 : return true;
470 0 : if (ntohs(fe->fe_key.flow_sport) == port)
471 0 : return true;
472 : }
473 :
474 0 : return false;
475 : }
476 :
477 : static void
478 66 : flow_print_spaces(void)
479 : {
480 : unsigned int i;
481 :
482 2046 : for (i = 0; i < FLOW_GET_FIELD_LENGTH; i++)
483 1980 : printf("%c", ' ');
484 66 : return;
485 : }
486 :
487 : static void
488 83 : flow_print_field_name(const char *field)
489 : {
490 83 : unsigned int printed = 0, i;
491 :
492 83 : printed = printf("%s:", field);
493 83 : if (printed < FLOW_GET_FIELD_LENGTH) {
494 1273 : for (i = printed; i < FLOW_GET_FIELD_LENGTH; i++)
495 1190 : printf(" ");
496 : }
497 :
498 83 : return;
499 : }
500 :
501 : static void
502 7 : flow_print_nh_header(vr_nexthop_req *nh)
503 : {
504 7 : printf("NextHop(Index, VRF, Type): %u, %u, ",
505 : nh->nhr_id, nh->nhr_vrf);
506 7 : printf("%s", vr_nexthop_type_string(nh));
507 7 : printf("\n");
508 7 : return;
509 : }
510 :
511 : static void
512 7 : flow_print_vif(vr_interface_req *vif, char *vif_name, bool ingress)
513 : {
514 7 : if (vif) {
515 7 : flow_print_spaces();
516 7 : if (ingress)
517 5 : printf("Ingress ");
518 : else
519 2 : printf("Egress ");
520 7 : printf("Interface(Index, VRF, OS): vif0/%u, %d, %s\n",
521 : vif->vifr_idx, vif->vifr_vrf, vif_name);
522 :
523 7 : flow_print_spaces();
524 7 : printf("Interface Statistics(Out, In, Errors): %" PRIu64 ", %" PRIu64 ", %" PRIu64 "\n",
525 : vif->vifr_opackets, vif->vifr_ipackets,
526 7 : vif->vifr_ierrors + vif->vifr_oerrors);
527 : }
528 :
529 7 : return;
530 : }
531 :
532 : static void
533 0 : flow_dump_tunnel(vr_nexthop_req *nh, vr_interface_req *vif,
534 : char *vif_name, bool ingress)
535 : {
536 0 : if (nh) {
537 0 : flow_print_nh_header(nh);
538 0 : flow_print_spaces();
539 0 : printf("Tunnel Source: ");
540 0 : if (nh->nhr_family == AF_INET) {
541 0 : printf("%s\n",
542 0 : inet_ntop(nh->nhr_family, &nh->nhr_tun_dip,
543 : addr_string, sizeof(addr_string)));
544 0 : } else if (nh->nhr_family == AF_INET6) {
545 0 : printf("%s\n",
546 0 : inet_ntop(nh->nhr_family, nh->nhr_tun_dip6,
547 : addr_string, sizeof(addr_string)));
548 : }
549 : }
550 :
551 0 : flow_print_vif(vif, vif_name, ingress);
552 0 : return;
553 : }
554 :
555 : static void
556 0 : flow_dump_composite(vr_nexthop_req *nh, vr_interface_req *vif,
557 : char *vif_name, bool ingress)
558 : {
559 : unsigned int i;
560 :
561 0 : if (nh) {
562 0 : flow_print_nh_header(nh);
563 0 : flow_print_spaces();
564 0 : if (nh->nhr_flags & NH_FLAG_COMPOSITE_ECMP) {
565 0 : printf("ECMP\n");
566 0 : flow_print_spaces();
567 0 : for (i = 0; i < nh->nhr_nh_list_size; i++) {
568 0 : if (i >= FLOW_COMPONENT_NH_COUNT)
569 0 : break;
570 :
571 0 : printf("%d", nh->nhr_nh_list[i]);
572 0 : if (ecmp_index == i)
573 0 : printf("*");
574 0 : printf(", ");
575 : }
576 0 : printf("\n");
577 0 : flow_print_spaces();
578 0 : if (ecmp_index >= 0) {
579 0 : nh = flow_get_nexthop(nh->nhr_nh_list[ecmp_index]);
580 0 : flow_dump_nexthop(nh, vif, vif_name, ingress);
581 : }
582 : }
583 : }
584 :
585 0 : return;
586 : }
587 :
588 : static void
589 7 : flow_dump_encap(vr_nexthop_req *nh, vr_interface_req *vif,
590 : char *vif_name, bool ingress)
591 : {
592 7 : flow_print_nh_header(nh);
593 7 : flow_print_vif(vif, vif_name, ingress);
594 :
595 7 : return;
596 : }
597 :
598 : static void
599 15 : flow_dump_nexthop(vr_nexthop_req *src, vr_interface_req *vif,
600 : char *vif_name, bool ingress)
601 : {
602 15 : if (src) {
603 15 : switch (src->nhr_type) {
604 7 : case NH_ENCAP:
605 : case NH_RCV:
606 7 : flow_dump_encap(src, vif, vif_name, ingress);
607 7 : break;
608 :
609 0 : case NH_COMPOSITE:
610 0 : flow_dump_composite(src, vif, vif_name, ingress);
611 0 : break;
612 :
613 0 : case NH_TUNNEL:
614 0 : flow_dump_tunnel(src, vif, vif_name, ingress);
615 0 : break;
616 :
617 8 : default:
618 8 : break;
619 : }
620 : }
621 :
622 15 : return;
623 : }
624 :
625 : static void
626 5 : flow_dump_source(vr_nexthop_req *src)
627 : {
628 5 : flow_print_field_name("Expected Source");
629 5 : flow_dump_nexthop(src, src_vif, src_vif_name, true);
630 :
631 5 : return;
632 : }
633 :
634 : static void
635 0 : flow_dump_mirror(vr_nexthop_req *req)
636 : {
637 0 : if (req->nhr_type == NH_TUNNEL) {
638 0 : printf("NextHop %u\n", req->nhr_id);
639 0 : flow_print_spaces();
640 0 : printf("To Destination ");
641 0 : if (req->nhr_family == AF_INET) {
642 0 : printf("%s ", inet_ntop(req->nhr_family, &req->nhr_tun_dip,
643 : addr_string, sizeof(addr_string)));
644 0 : } else if (req->nhr_family == AF_INET6) {
645 0 : printf("%s ", inet_ntop(req->nhr_family, req->nhr_tun_dip6,
646 : addr_string, sizeof(addr_string)));
647 : }
648 :
649 0 : if (req->nhr_vrf < 0)
650 0 : printf("in the same VRF (%d)\n", req->nhr_vrf);
651 : else
652 0 : printf("in VRF %d\n", req->nhr_vrf);
653 0 : flow_print_spaces();
654 0 : if (req->nhr_flags & NH_FLAG_TUNNEL_SIP_COPY) {
655 0 : printf("Tunnel Source IP from packet\n");
656 : } else {
657 0 : printf("Tunnel Source IP ");
658 0 : if (req->nhr_family == AF_INET) {
659 0 : printf("%s ", inet_ntop(req->nhr_family, &req->nhr_tun_sip,
660 : addr_string, sizeof(addr_string)));
661 0 : } else if (req->nhr_family == AF_INET6) {
662 0 : printf("%s ", inet_ntop(req->nhr_family, req->nhr_tun_sip6,
663 : addr_string, sizeof(addr_string)));
664 : }
665 : }
666 : } else {
667 0 : printf("NextHop %u of type %u", req->nhr_id, req->nhr_type);
668 : }
669 :
670 0 : return;
671 : }
672 :
673 :
674 : static uint64_t
675 5 : flow_sum_drops_stats(vr_drop_stats_req *req)
676 : {
677 5 : uint64_t sum = 0;
678 :
679 5 : sum += req->vds_flow_queue_limit_exceeded;
680 5 : sum += req->vds_flow_no_memory;
681 5 : sum += req->vds_flow_invalid_protocol;
682 5 : sum += req->vds_flow_nat_no_rflow;
683 5 : sum += req->vds_flow_action_drop;
684 5 : sum += req->vds_flow_action_invalid;
685 5 : sum += req->vds_flow_unusable;
686 5 : sum += req->vds_flow_table_full;
687 5 : sum += req->vds_drop_new_flow;
688 :
689 5 : return sum;
690 : }
691 :
692 : static void
693 5 : flow_dump_entry(struct vr_flow_entry *fe)
694 : {
695 : unsigned int j;
696 : char in_src[INET6_ADDRSTRLEN], in_dest[INET6_ADDRSTRLEN];
697 : char in_rsrc[INET6_ADDRSTRLEN], in_rdest[INET6_ADDRSTRLEN];
698 : char in_rt[INET6_ADDRSTRLEN];
699 :
700 : struct vr_flow_entry *rfe;
701 :
702 5 : system(CLEAN_SCREEN_CMD);
703 5 : flow_print_field_name("Flow Index");
704 5 : printf("%lu\n", flow_index);
705 :
706 5 : flow_print_field_name("Flow Generation ID");
707 5 : printf("%u\n", fe->fe_gen_id);
708 :
709 5 : flow_print_field_name("Reverse Flow Index");
710 5 : if ((fe->fe_flags & VR_RFLOW_VALID) && (fe->fe_rflow >= 0)) {
711 3 : printf("%u", fe->fe_rflow);
712 3 : rfe = flow_get(fe->fe_rflow);
713 3 : if (rfe) {
714 3 : if ((rfe->fe_type == VP_TYPE_IP) || (rfe->fe_type == VP_TYPE_IP6)) {
715 3 : inet_ntop(VR_FLOW_FAMILY(rfe->fe_type), rfe->fe_key.flow_ip,
716 : in_rsrc, sizeof(in_rsrc));
717 3 : inet_ntop(VR_FLOW_FAMILY(rfe->fe_type),
718 3 : &rfe->fe_key.flow_ip[VR_IP_ADDR_SIZE(rfe->fe_type)],
719 : in_rdest, sizeof(in_rdest));
720 : }
721 : }
722 :
723 : } else {
724 2 : printf("-1");
725 : }
726 5 : printf("\n");
727 :
728 5 : if ((fe->fe_type == VP_TYPE_IP) || (fe->fe_type == VP_TYPE_IP6)) {
729 5 : inet_ntop(VR_FLOW_FAMILY(fe->fe_type), fe->fe_key.flow_ip,
730 : in_src, sizeof(in_src));
731 5 : inet_ntop(VR_FLOW_FAMILY(fe->fe_type),
732 5 : &fe->fe_key.flow_ip[VR_IP_ADDR_SIZE(fe->fe_type)],
733 : in_dest, sizeof(in_dest));
734 : }
735 :
736 :
737 5 : flow_print_field_name("VRF");
738 5 : printf("%d\n", fe->fe_vrf);
739 :
740 5 : flow_print_field_name("Destination VRF");
741 5 : if (fe->fe_flags & VR_FLOW_FLAG_VRFT) {
742 0 : printf("%d", fe->fe_dvrf);
743 : } else {
744 5 : printf("%d", fe->fe_vrf);
745 : }
746 5 : printf("\n");
747 :
748 5 : flow_print_field_name("Flow Source");
749 5 : printf("[%s]:%-5u\n", in_src, ntohs(fe->fe_key.flow_sport));
750 :
751 5 : flow_print_field_name("Flow Destination");
752 5 : printf("[%s]:%-5u\n", in_dest, ntohs(fe->fe_key.flow_dport));
753 :
754 5 : flow_print_field_name("Flow Protocol");
755 5 : printf("%s\n", vr_proto_string(fe->fe_key.flow_proto));
756 :
757 5 : if(fe->fe_underlay_ecmp_index >= 0) {
758 1 : flow_print_field_name("Flow Underlay ECMP Index");
759 1 : printf("%d\n", fe->fe_underlay_ecmp_index);
760 : }
761 :
762 5 : flow_print_field_name("Flow Action");
763 5 : switch (fe->fe_action) {
764 0 : case VR_FLOW_ACTION_HOLD:
765 0 : printf("HOLD");
766 0 : break;
767 :
768 5 : case VR_FLOW_ACTION_FORWARD:
769 5 : printf("FORWARD");
770 5 : break;
771 :
772 0 : case VR_FLOW_ACTION_DROP:
773 0 : printf("DROP:");
774 0 : flow_print_spaces();
775 0 : printf("%s", flow_get_drop_reason(fe->fe_drop_reason));
776 0 : break;
777 :
778 0 : case VR_FLOW_ACTION_NAT:
779 0 : printf("NAT: ");
780 0 : for (j = 0; j < (sizeof(fe->fe_flags) * 8); j++) {
781 0 : switch ((1 << j) & fe->fe_flags) {
782 0 : case VR_FLOW_FLAG_SNAT:
783 0 : printf("SourceNAT, ");
784 0 : break;
785 0 : case VR_FLOW_FLAG_DNAT:
786 0 : printf("DestinationNAT, ");
787 0 : break;
788 0 : case VR_FLOW_FLAG_SPAT:
789 0 : printf("SourcePortNAT, ");
790 0 : break;
791 0 : case VR_FLOW_FLAG_DPAT:
792 0 : printf("DestinationPortNAT, ");
793 0 : break;
794 0 : case VR_FLOW_FLAG_LINK_LOCAL:
795 0 : printf("LinkLocalNAT, ");
796 0 : break;
797 : }
798 : }
799 0 : break;
800 :
801 0 : default:
802 0 : printf("Unknown");
803 0 : break;
804 : }
805 5 : printf("\n");
806 :
807 5 : if (fe->fe_action == VR_FLOW_ACTION_NAT) {
808 0 : flow_print_spaces();
809 0 : printf("NAT(Source, Destination): ");
810 0 : if (rfe) {
811 0 : if (fe->fe_flags & VR_FLOW_FLAG_SNAT)
812 0 : printf("[%s]:", in_rdest);
813 : else
814 0 : printf("[%s]:", in_src);
815 :
816 0 : if (fe->fe_flags & VR_FLOW_FLAG_SPAT)
817 0 : printf("%d", ntohs(rfe->fe_key.flow_dport));
818 : else
819 0 : printf("%d", ntohs(fe->fe_key.flow_sport));
820 0 : printf(", ");
821 :
822 0 : if (fe->fe_flags & VR_FLOW_FLAG_DNAT)
823 0 : printf("[%s]:", in_rsrc);
824 : else
825 0 : printf("[%s]:", in_dest);
826 :
827 0 : if (fe->fe_flags & VR_FLOW_FLAG_DPAT)
828 0 : printf("%d", ntohs(rfe->fe_key.flow_sport));
829 : else
830 0 : printf("%d", ntohs(fe->fe_key.flow_dport));
831 : }
832 0 : printf("\n");
833 : }
834 :
835 5 : if (src_nh) {
836 5 : flow_dump_source(src_nh);
837 : }
838 :
839 :
840 5 : if (src_l3_rt) {
841 5 : flow_print_field_name("Source Information");
842 5 : printf("VRF: %u\n", src_l3_rt->rtr_vrf_id);
843 5 : address_mask(src_l3_rt->rtr_prefix, src_l3_rt->rtr_prefix_len,
844 5 : src_l3_rt->rtr_family);
845 5 : flow_print_spaces();
846 5 : printf("Layer 3 Route Information\n");
847 5 : flow_print_spaces();
848 5 : printf("Matching Route: %s/%-2d\n",
849 5 : inet_ntop(src_l3_rt->rtr_family, src_l3_rt->rtr_prefix, in_rt,
850 5 : sizeof(in_rt)), src_l3_rt->rtr_prefix_len);
851 5 : if (src_l3_nh) {
852 5 : flow_print_spaces();
853 5 : flow_dump_nexthop(src_l3_nh, src_l3_vif, src_l3_vif_name, true);
854 : }
855 :
856 5 : if (src_l3_rt->rtr_mac) {
857 3 : printf("\n");
858 3 : flow_print_spaces();
859 3 : printf("Layer 2 Route Information\n");
860 3 : flow_print_spaces();
861 3 : printf("SourceMAC: ");
862 3 : printf("%s\n", ether_ntoa((struct ether_addr *)(src_l3_rt->rtr_mac)));
863 3 : if (src_l2_rt) {
864 0 : flow_print_spaces();
865 0 : flow_dump_nexthop(src_l2_nh, src_l2_vif, src_l2_vif_name, true);
866 : }
867 : }
868 :
869 : }
870 :
871 5 : if (dst_l3_rt) {
872 5 : flow_print_field_name("Destination Information");
873 5 : printf("VRF: %u\n", dst_l3_rt->rtr_vrf_id);
874 5 : address_mask(dst_l3_rt->rtr_prefix, dst_l3_rt->rtr_prefix_len,
875 5 : dst_l3_rt->rtr_family);
876 5 : flow_print_spaces();
877 5 : printf("Layer 3 Route Information\n");
878 5 : flow_print_spaces();
879 5 : printf("Matching Route: %s/%-2d\n",
880 5 : inet_ntop(dst_l3_rt->rtr_family, dst_l3_rt->rtr_prefix, in_rt,
881 5 : sizeof(in_rt)), dst_l3_rt->rtr_prefix_len);
882 5 : if (dst_l3_nh) {
883 5 : flow_print_spaces();
884 5 : flow_dump_nexthop(dst_l3_nh, dst_l3_vif, dst_l3_vif_name, false);
885 : }
886 :
887 5 : if (dst_l3_rt->rtr_mac) {
888 3 : printf("\n");
889 3 : flow_print_spaces();
890 3 : printf("Layer 2 Route Information\n");
891 3 : flow_print_spaces();
892 3 : printf("DestinationMAC: ");
893 3 : printf("%s\n", ether_ntoa((struct ether_addr *)(dst_l3_rt->rtr_mac)));
894 3 : if (dst_l2_rt) {
895 0 : flow_print_spaces();
896 0 : flow_dump_nexthop(dst_l2_nh, dst_l2_vif, dst_l2_vif_name, false);
897 : }
898 : }
899 :
900 : }
901 :
902 5 : printf("\n");
903 5 : flow_print_field_name("Flow Flags");
904 5 : if (fe->fe_flags & VR_FLOW_FLAG_EVICTED)
905 0 : printf("EVICTED ");
906 5 : if (fe->fe_flags & VR_FLOW_FLAG_EVICT_CANDIDATE)
907 0 : printf("EVICT CANDIDATE ");
908 5 : if (fe->fe_flags & VR_FLOW_FLAG_NEW_FLOW)
909 0 : printf("NEW ");
910 5 : if (fe->fe_flags & VR_FLOW_FLAG_MODIFIED)
911 0 : printf("MODIFIED ");
912 5 : if (fe->fe_flags & VR_FLOW_FLAG_MIRROR)
913 0 : printf("MIRROR ");
914 5 : printf("\n");
915 :
916 5 : if (fe->fe_key.flow_proto == VR_IP_PROTO_TCP) {
917 2 : flow_print_field_name("TCP FLAGS");
918 2 : if (fe->fe_tcp_flags & VR_FLOW_TCP_SYN)
919 2 : printf("SYN, ");
920 2 : if (fe->fe_tcp_flags & VR_FLOW_TCP_SYN_R)
921 1 : printf("SYN(REVERSE), ");
922 2 : if (fe->fe_tcp_flags & VR_FLOW_TCP_ESTABLISHED)
923 1 : printf("ESTABLISHED, ");
924 2 : if (fe->fe_tcp_flags & VR_FLOW_TCP_ESTABLISHED_R)
925 1 : printf("ESTABLISHED(REVERSE), ");
926 :
927 2 : if (fe->fe_tcp_flags & VR_FLOW_TCP_FIN)
928 0 : printf("FIN, ");
929 2 : if (fe->fe_tcp_flags & VR_FLOW_TCP_FIN_R)
930 0 : printf("FIN(REVERSE), ");
931 2 : if (fe->fe_tcp_flags & VR_FLOW_TCP_RST)
932 0 : printf("RESET, ");
933 2 : if (fe->fe_tcp_flags & VR_FLOW_TCP_HALF_CLOSE)
934 0 : printf("HALFCLOSED, ");
935 2 : if (fe->fe_tcp_flags & VR_FLOW_TCP_DEAD)
936 0 : printf("DEAD, ");
937 2 : printf("\n");
938 : }
939 :
940 5 : flow_print_field_name("UDP Source Port");
941 5 : printf("%u\n", fe->fe_udp_src_port);
942 :
943 5 : if (fe->fe_flags & VR_FLOW_FLAG_MIRROR) {
944 0 : printf("\n");
945 0 : flow_print_field_name("Mirror Index");
946 0 : if (fe->fe_mirror_id < VR_MAX_MIRROR_INDICES)
947 0 : printf("%d", fe->fe_mirror_id);
948 0 : if (fe->fe_sec_mirror_id < VR_MAX_MIRROR_INDICES)
949 0 : printf(", %d, ", fe->fe_sec_mirror_id);
950 :
951 :
952 0 : if (mirror_nh) {
953 0 : flow_print_field_name("Primary Mirror");
954 0 : flow_dump_mirror(mirror_nh);
955 : }
956 :
957 0 : if (mirror1_nh) {
958 0 : flow_print_field_name("Secondary Mirror");
959 0 : flow_dump_mirror(mirror1_nh);
960 : }
961 : }
962 :
963 5 : printf("\n");
964 5 : flow_print_field_name("Flow Statistics");
965 5 : printf("%u/%u\n", fe->fe_stats.flow_packets, fe->fe_stats.flow_bytes);
966 5 : flow_print_field_name("System Wide Packet Drops");
967 5 : printf("%" PRIu64 "\n", vr_sum_drop_stats(global_ds));
968 5 : flow_print_spaces();
969 5 : printf("Reverse Path Failures: %" PRIu64 "\n", global_ds->vds_invalid_source);
970 5 : flow_print_spaces();
971 5 : printf("Flow Block Drops: %" PRId64 "\n", flow_sum_drops_stats(global_ds));
972 :
973 5 : return;
974 : }
975 :
976 : static void
977 5 : flow_get_routes(struct vr_flow_entry *fe)
978 : {
979 : unsigned int vrf;
980 5 : unsigned int family = VR_FLOW_FAMILY(fe->fe_type);
981 : struct vr_flow_entry *rfe;
982 :
983 5 : if (fe->fe_action == VR_FLOW_ACTION_NAT) {
984 0 : if (!(fe->fe_flags & VR_RFLOW_VALID))
985 0 : return;
986 0 : rfe = flow_get(fe->fe_rflow);
987 0 : if (!rfe)
988 0 : return;
989 :
990 : }
991 :
992 5 : vrf = fe->fe_vrf;
993 5 : src_l3_rt = flow_get_route(family, vrf, fe->fe_key.flow_ip);
994 5 : if (src_l3_rt) {
995 5 : src_l3_nh = flow_get_nexthop(src_l3_rt->rtr_nh_id);
996 5 : if (src_l3_nh) {
997 5 : if (vr_nexthop_req_has_vif(src_l3_nh)) {
998 0 : src_l3_vif = flow_get_vif(src_l3_nh->nhr_encap_oif_id[0]);
999 0 : if_indextoname(src_l3_vif->vifr_os_idx, src_l3_vif_name);
1000 : }
1001 : }
1002 :
1003 5 : if (vr_valid_mac_address(src_l3_rt->rtr_mac)) {
1004 0 : src_l2_rt = flow_get_route(AF_BRIDGE, vrf, src_l3_rt->rtr_mac);
1005 0 : if (src_l2_rt) {
1006 0 : src_l2_nh = flow_get_nexthop(src_l2_rt->rtr_nh_id);
1007 0 : if (vr_nexthop_req_has_vif(src_l2_nh)) {
1008 0 : src_l2_vif = flow_get_vif(src_l2_nh->nhr_encap_oif_id[0]);
1009 0 : if_indextoname(src_l2_vif->vifr_os_idx, src_l2_vif_name);
1010 : }
1011 : }
1012 : }
1013 : }
1014 :
1015 5 : if (fe->fe_flags & VR_FLOW_FLAG_VRFT)
1016 0 : vrf = fe->fe_dvrf;
1017 :
1018 5 : if (fe->fe_flags & VR_FLOW_FLAG_DNAT) {
1019 0 : dst_l3_rt = flow_get_route(family, vrf, rfe->fe_key.flow_ip);
1020 : } else {
1021 5 : dst_l3_rt = flow_get_route(family, vrf,
1022 5 : &fe->fe_key.flow_ip[VR_IP_ADDR_SIZE(fe->fe_type)]);
1023 : }
1024 :
1025 5 : if (dst_l3_rt) {
1026 5 : dst_l3_nh = flow_get_nexthop(dst_l3_rt->rtr_nh_id);
1027 5 : if (dst_l3_nh) {
1028 5 : if (vr_nexthop_req_has_vif(dst_l3_nh)) {
1029 2 : dst_l3_vif = flow_get_vif(dst_l3_nh->nhr_encap_oif_id[0]);
1030 2 : if_indextoname(dst_l3_vif->vifr_os_idx, dst_l3_vif_name);
1031 : }
1032 : }
1033 :
1034 5 : if (vr_valid_mac_address(dst_l3_rt->rtr_mac)) {
1035 0 : dst_l2_rt = flow_get_route(AF_BRIDGE, vrf, dst_l3_rt->rtr_mac);
1036 0 : if (dst_l2_rt) {
1037 0 : dst_l2_nh = flow_get_nexthop(dst_l2_rt->rtr_nh_id);
1038 0 : if (vr_nexthop_req_has_vif(dst_l2_nh)) {
1039 0 : dst_l2_vif = flow_get_vif(dst_l2_nh->nhr_encap_oif_id[0]);
1040 0 : if_indextoname(dst_l2_vif->vifr_os_idx, dst_l2_vif_name);
1041 : }
1042 : }
1043 : }
1044 : }
1045 :
1046 5 : return;
1047 : }
1048 :
1049 : static void
1050 5 : flow_get_source(struct vr_flow_entry *fe)
1051 : {
1052 : int i;
1053 : struct vr_flow_entry *rfe;
1054 :
1055 : if (fe->fe_src_nh_index >= 0) {
1056 5 : src_nh = flow_get_nexthop(fe->fe_src_nh_index);
1057 5 : if (src_nh) {
1058 5 : switch (src_nh->nhr_type) {
1059 0 : case NH_TUNNEL:
1060 0 : if (fe->fe_underlay_ecmp_index >= 0)
1061 0 : src_vif = flow_get_vif(fe->fe_underlay_ecmp_index);
1062 : else
1063 0 : src_vif = flow_get_vif(src_nh->nhr_encap_oif_id[0]);
1064 0 : if (src_vif->vifr_os_idx > 0)
1065 0 : if_indextoname(src_vif->vifr_os_idx, src_vif_name);
1066 0 : break;
1067 5 : case NH_ENCAP:
1068 : case NH_RCV:
1069 5 : src_vif = flow_get_vif(src_nh->nhr_encap_oif_id[0]);
1070 5 : if (src_vif->vifr_os_idx > 0)
1071 0 : if_indextoname(src_vif->vifr_os_idx, src_vif_name);
1072 5 : break;
1073 :
1074 0 : case NH_COMPOSITE:
1075 0 : if ((src_nh->nhr_flags & NH_FLAG_COMPOSITE_ECMP)) {
1076 0 : if (fe->fe_flags & VR_RFLOW_VALID) {
1077 0 : rfe = flow_get(fe->fe_rflow);
1078 0 : if (rfe && (rfe->fe_flags & VR_FLOW_FLAG_ACTIVE))
1079 0 : ecmp_index = rfe->fe_ecmp_nh_index;
1080 : }
1081 :
1082 0 : if (src_nh->nhr_nh_list) {
1083 0 : for (i = 0; i < src_nh->nhr_nh_list_size; i++) {
1084 0 : if (i >= FLOW_COMPONENT_NH_COUNT)
1085 0 : break;
1086 :
1087 0 : component_nh[i] =
1088 0 : flow_get_nexthop(src_nh->nhr_nh_list[i]);
1089 : }
1090 : }
1091 : }
1092 :
1093 0 : break;
1094 :
1095 0 : default:
1096 0 : break;
1097 : }
1098 : }
1099 : }
1100 :
1101 5 : return;
1102 : }
1103 :
1104 : /*
1105 : * cleanup - release all the memory that we allocated for
1106 : * the get operation
1107 : */
1108 : static void
1109 5 : flow_get_cleanup(void)
1110 : {
1111 : unsigned int i;
1112 :
1113 5 : vr_interface_req_destroy(src_vif);
1114 5 : vr_interface_req_destroy(src_l3_vif);
1115 5 : vr_interface_req_destroy(src_l2_vif);
1116 5 : vr_interface_req_destroy(dst_l3_vif);
1117 5 : vr_interface_req_destroy(dst_l2_vif);
1118 5 : src_vif = src_l3_vif = src_l2_vif = dst_l3_vif = dst_l2_vif = NULL;
1119 :
1120 85 : for (i = 0; i < FLOW_COMPONENT_NH_COUNT; i++) {
1121 80 : vr_nexthop_req_destroy(component_nh[i]);
1122 80 : component_nh[i] = NULL;
1123 : }
1124 5 : vr_nexthop_req_destroy(src_nh);
1125 5 : vr_nexthop_req_destroy(src_l3_nh);
1126 5 : vr_nexthop_req_destroy(src_l2_nh);
1127 5 : vr_nexthop_req_destroy(dst_l3_nh);
1128 5 : vr_nexthop_req_destroy(dst_l2_nh);
1129 5 : vr_nexthop_req_destroy(mirror_nh);
1130 5 : vr_nexthop_req_destroy(mirror1_nh);
1131 5 : src_nh = src_l3_nh = src_l2_nh = dst_l3_nh = dst_l2_nh = NULL;
1132 :
1133 5 : vr_route_req_destroy(src_l3_rt);
1134 5 : vr_route_req_destroy(src_l2_rt);
1135 5 : vr_route_req_destroy(dst_l3_rt);
1136 5 : vr_route_req_destroy(dst_l2_rt);
1137 5 : src_l3_rt = src_l2_rt = dst_l3_rt = dst_l2_rt = NULL;
1138 :
1139 5 : vr_drop_stats_req_destroy(global_ds);
1140 5 : global_ds = NULL;
1141 :
1142 5 : return;
1143 : }
1144 :
1145 : static void
1146 5 : flow_get_entry(struct vr_flow_entry *fe)
1147 : {
1148 : /*
1149 : * first step is to get all the information we need, such as
1150 : * nexthops, routes and interfaces
1151 : */
1152 :
1153 : /* get the source nexthop information */
1154 5 : flow_get_source(fe);
1155 : /* if the flow has mirror configuration, get the mirror nexthops */
1156 5 : if (fe->fe_flags & VR_FLOW_FLAG_MIRROR) {
1157 0 : mirror_nh = flow_get_mirror_nh(fe->fe_mirror_id);
1158 0 : mirror1_nh = flow_get_mirror_nh(fe->fe_sec_mirror_id);
1159 : }
1160 :
1161 : /* routes for flow source and destination */
1162 5 : flow_get_routes(fe);
1163 : /* get the system wide dropstats */
1164 5 : global_ds = flow_get_dropstats();
1165 : /* we are now ready to dump the flow entry */
1166 5 : flow_dump_entry(fe);
1167 : /* ...and finally cleanup the memory we allocated */
1168 5 : flow_get_cleanup();
1169 :
1170 5 : return;
1171 : }
1172 :
1173 : static inline int
1174 20 : print_new_line_if_required(int printed, int max_print)
1175 : {
1176 20 : if (printed >= max_print) {
1177 5 : printf("\n");
1178 5 : return 0;
1179 : }
1180 :
1181 15 : return printed;
1182 : }
1183 :
1184 : static void
1185 4 : flow_dump_table(struct flow_table *ft)
1186 : {
1187 4 : unsigned int i, j, k, fi, next_index, need_flag_print = 0, printed = 0;
1188 : struct vr_flow_entry *fe, *ofe;
1189 : char action, flag_string[sizeof(fe->fe_flags) * 8 + 32];
1190 4 : unsigned int need_drop_reason = 0;
1191 4 : const char *drop_reason = NULL;
1192 : char in_src[INET6_ADDRSTRLEN], in_dest[INET6_ADDRSTRLEN];
1193 : char addr[INET6_ADDRSTRLEN];
1194 : bool smatch, dmatch;
1195 :
1196 4 : printf("Flow table(size %" PRIu64 ", entries %u)\n\n", ft->ft_span,
1197 : ft->ft_num_entries);
1198 4 : printf("Entries: Created %" PRIu64 " Added %" PRIu64 " Deleted %" PRIu64 " Changed %" PRIu64 "Processed %" PRIu64 " Used Overflow entries %u\n",
1199 : ft->ft_created, ft->ft_added, ft->ft_deleted, ft->ft_changed,
1200 : ft->ft_processed, ft->ft_oflow_entries);
1201 :
1202 4 : printf("(Created Flows/CPU: ");
1203 52 : for (i = 0; i < ft->ft_hold_stat_count; i++) {
1204 48 : printf("%u", ft->ft_hold_stat[i]);
1205 48 : if (i != (ft->ft_hold_stat_count - 1))
1206 44 : printf(" ");
1207 : }
1208 4 : printf(")(oflows %u)\n\n", ft->ft_hold_oflows);
1209 :
1210 4 : flow_dump_legend();
1211 :
1212 4 : if (match_family || (match_proto > 0) || (match_vrf > 0)) {
1213 0 : printf("Listing flows matching (");
1214 0 : if (match_ip1_set) {
1215 0 : if (match_ip1) {
1216 0 : inet_ntop(match_family, match_ip1, addr, INET6_ADDRSTRLEN);
1217 0 : printed += printf("[%s]", addr);
1218 : } else {
1219 0 : printed += printf("[*]");
1220 : }
1221 :
1222 0 : if (match_port1 >= 0)
1223 0 : printed += printf(":%u", match_port1);
1224 : else
1225 0 : printed += printf(":*");
1226 : }
1227 :
1228 0 : if (match_ip2_set) {
1229 0 : if (printed)
1230 0 : printf(", ");
1231 :
1232 0 : if (match_ip2) {
1233 0 : inet_ntop(match_family, match_ip2, addr, INET6_ADDRSTRLEN);
1234 0 : printed += printf("[%s]", addr);
1235 : } else {
1236 0 : printed += printf("[*]");
1237 : }
1238 :
1239 0 : if (match_port2 >= 0)
1240 0 : printed += printf(":%u", match_port2);
1241 : else
1242 0 : printed += printf(":*");
1243 : }
1244 :
1245 0 : if (match_proto >= 0) {
1246 0 : if (printed)
1247 0 : printf(", ");
1248 0 : printed += printf("Protocol %s", vr_proto_string(match_proto));
1249 : }
1250 :
1251 0 : if (match_vrf >= 0) {
1252 0 : if (printed)
1253 0 : printf(", ");
1254 0 : printf("VRF %d", match_vrf);
1255 : }
1256 :
1257 0 : printf(")");
1258 0 : printed = 0;
1259 0 : printf("\n\n");
1260 : }
1261 :
1262 4 : printf(" Index ");
1263 : /* inter field gap */
1264 4 : printf("%4c", ' ');
1265 : /* 40 byte address field - middled header */
1266 4 : printf("Source:Port/Destination:Port ");
1267 : /* inter field gap */
1268 4 : printf("%4c", ' ');
1269 4 : printf("Proto(V)\n");
1270 4 : printf("-----------------------------------------------------------------");
1271 4 : printf("------------------\n");
1272 2519044 : for (i = 0; i < ft->ft_num_entries; i++) {
1273 2519040 : memset(flag_string, 0, sizeof(flag_string));
1274 2519040 : need_flag_print = 0;
1275 2519040 : need_drop_reason = 0;
1276 2519040 : fe = (struct vr_flow_entry *)((char *)ft->ft_entries + (i * sizeof(*fe)));
1277 2519040 : if (fe->fe_flags & VR_FLOW_FLAG_ACTIVE) {
1278 :
1279 5 : if ((fe->fe_flags & VR_FLOW_FLAG_EVICTED) &&
1280 0 : !show_evicted_set) {
1281 0 : continue;
1282 : }
1283 :
1284 :
1285 5 : if (match_vrf >= 0) {
1286 0 : if (fe->fe_vrf != match_vrf)
1287 0 : continue;
1288 : }
1289 :
1290 5 : if (match_proto >= 0) {
1291 0 : if (fe->fe_key.flow_proto != match_proto)
1292 0 : continue;
1293 : }
1294 :
1295 5 : if (match_family) {
1296 0 : if (match_family != VR_FLOW_FAMILY(fe->fe_type)) {
1297 0 : continue;
1298 : }
1299 :
1300 0 : smatch = dmatch = false;
1301 0 : if (match_ip1_set) {
1302 0 : smatch = flow_match_source(fe, match_ip1, match_port1);
1303 0 : if (!smatch) {
1304 0 : dmatch = flow_match_dest(fe, match_ip1, match_port1);
1305 : }
1306 : }
1307 :
1308 0 : if (match_ip2_set) {
1309 0 : if (smatch) {
1310 0 : dmatch = flow_match_dest(fe, match_ip2, match_port2);
1311 0 : if (!dmatch)
1312 0 : continue;
1313 0 : } else if (dmatch) {
1314 0 : smatch = flow_match_source(fe, match_ip2, match_port2);
1315 0 : if (!smatch)
1316 0 : continue;
1317 : } else {
1318 0 : smatch = flow_match_source(fe, match_ip2, match_port2);
1319 0 : if (!smatch) {
1320 0 : dmatch = flow_match_dest(fe, match_ip2, match_port2);
1321 : }
1322 :
1323 : }
1324 : }
1325 :
1326 0 : if (!smatch && !dmatch)
1327 0 : continue;
1328 :
1329 0 : if (match_ip1_set && match_ip2_set) {
1330 0 : if (!smatch || !dmatch) {
1331 0 : continue;
1332 : }
1333 : }
1334 : }
1335 :
1336 :
1337 5 : if ((fe->fe_type == VP_TYPE_IP) || (fe->fe_type == VP_TYPE_IP6)) {
1338 5 : inet_ntop(VR_FLOW_FAMILY(fe->fe_type), fe->fe_key.flow_ip,
1339 : in_src, sizeof(in_src));
1340 5 : inet_ntop(VR_FLOW_FAMILY(fe->fe_type),
1341 5 : &fe->fe_key.flow_ip[VR_IP_ADDR_SIZE(fe->fe_type)],
1342 : in_dest, sizeof(in_dest));
1343 : }
1344 :
1345 5 : printf("%9d", i);
1346 5 : if (fe->fe_rflow >= 0)
1347 2 : printf("<=>%-9d", fe->fe_rflow);
1348 : else
1349 3 : printf("%12c", ' ');
1350 :
1351 5 : printf("%4c", ' ');
1352 5 : if (fe->fe_type == VP_TYPE_IP) {
1353 5 : printed = printf("%s:%-5d", in_src, ntohs(fe->fe_key.flow_sport));
1354 161 : for (k = printed; k < 46; k++)
1355 156 : printf(" ");
1356 5 : printf("%4c", ' ');
1357 5 : printf("%3d (%d", fe->fe_key.flow_proto, fe->fe_vrf);
1358 5 : if (fe->fe_flags & VR_FLOW_FLAG_VRFT)
1359 0 : printf("->%d", fe->fe_dvrf);
1360 5 : printf(")\n");
1361 5 : printf("%25c", ' ');
1362 5 : printf("%s:%-5d", in_dest, ntohs(fe->fe_key.flow_dport));
1363 0 : } else if (fe->fe_type == VP_TYPE_IP6) {
1364 0 : printed = printf("%s:%-5d ", in_src, ntohs(fe->fe_key.flow_sport));
1365 0 : for (k = printed; k < 46; k++)
1366 0 : printf(" ");
1367 0 : printf("%4c", ' ');
1368 0 : printf("%3d (%d", fe->fe_key.flow_proto, fe->fe_vrf);
1369 0 : if (fe->fe_flags & VR_FLOW_FLAG_VRFT)
1370 0 : printf("->%d", fe->fe_dvrf);
1371 0 : printf(")\n");
1372 0 : printf("%25c", ' ');
1373 0 : printf("%s:%-5d ", in_dest, ntohs(fe->fe_key.flow_dport));
1374 : }
1375 :
1376 5 : printf("\n");
1377 :
1378 5 : switch (fe->fe_action) {
1379 3 : case VR_FLOW_ACTION_HOLD:
1380 3 : action = 'H';
1381 3 : break;
1382 :
1383 2 : case VR_FLOW_ACTION_FORWARD:
1384 2 : action = 'F';
1385 2 : break;
1386 :
1387 0 : case VR_FLOW_ACTION_DROP:
1388 0 : action = 'D';
1389 0 : need_drop_reason = 1;
1390 0 : drop_reason = flow_get_drop_reason(fe->fe_drop_reason);
1391 0 : break;
1392 :
1393 0 : case VR_FLOW_ACTION_NAT:
1394 0 : action = 'N';
1395 0 : need_flag_print = 1;
1396 0 : fi = 0;
1397 0 : for (j = 0; (j < (sizeof(fe->fe_flags) * 8)) &&
1398 0 : fi < sizeof(flag_string); j++)
1399 0 : switch ((1 << j) & fe->fe_flags) {
1400 0 : case VR_FLOW_FLAG_SNAT:
1401 0 : flag_string[fi++] = 'S';
1402 0 : break;
1403 0 : case VR_FLOW_FLAG_DNAT:
1404 0 : flag_string[fi++] = 'D';
1405 0 : break;
1406 0 : case VR_FLOW_FLAG_SPAT:
1407 0 : flag_string[fi++] = 'P';
1408 0 : flag_string[fi++] = 's';
1409 0 : break;
1410 0 : case VR_FLOW_FLAG_DPAT:
1411 0 : flag_string[fi++] = 'P';
1412 0 : flag_string[fi++] = 'd';
1413 0 : break;
1414 0 : case VR_FLOW_FLAG_LINK_LOCAL:
1415 0 : flag_string[fi++] = 'L';
1416 : }
1417 :
1418 0 : break;
1419 :
1420 0 : default:
1421 0 : action = 'U';
1422 : }
1423 :
1424 5 : printed = printf("(");
1425 5 : printed += printf("Gen: %u, ", fe->fe_gen_id);
1426 5 : if ((fe->fe_type == VP_TYPE_IP) || (fe->fe_type == VP_TYPE_IP6))
1427 5 : printed += printf("K(nh):%u, ", fe->fe_key.flow_nh_id);
1428 :
1429 5 : printed += printf("Action:%c", action);
1430 5 : if (need_flag_print)
1431 0 : printed += printf("(%s)", flag_string);
1432 5 : if (need_drop_reason) {
1433 0 : if (drop_reason != NULL)
1434 0 : printed += printf("(%s)", drop_reason);
1435 : else
1436 0 : printed += printf("(%u)", fe->fe_drop_reason);
1437 : }
1438 :
1439 5 : printed += printf(", ");
1440 5 : printed += printf("Flags:");
1441 5 : if (fe->fe_flags & VR_FLOW_FLAG_EVICTED)
1442 0 : printed += printf("E");
1443 5 : if (fe->fe_flags & VR_FLOW_FLAG_EVICT_CANDIDATE)
1444 0 : printed += printf("Ec");
1445 5 : if (fe->fe_flags & VR_FLOW_FLAG_NEW_FLOW)
1446 0 : printed += printf("N");
1447 5 : if (fe->fe_flags & VR_FLOW_FLAG_MODIFIED)
1448 0 : printed += printf("M");
1449 5 : if (fe->fe_flags & VR_FLOW_FLAG_DELETE_MARKED)
1450 0 : printed += printf("Dm");
1451 :
1452 5 : printed += printf(", ");
1453 5 : if (fe->fe_key.flow4_proto == VR_IP_PROTO_TCP) {
1454 2 : printed += printf("TCP:");
1455 :
1456 2 : if (fe->fe_tcp_flags & VR_FLOW_TCP_SYN)
1457 2 : printed += printf("S");
1458 2 : if (fe->fe_tcp_flags & VR_FLOW_TCP_SYN_R)
1459 0 : printed += printf("Sr");
1460 2 : if (fe->fe_tcp_flags & VR_FLOW_TCP_ESTABLISHED)
1461 0 : printed += printf("E");
1462 2 : if (fe->fe_tcp_flags & VR_FLOW_TCP_ESTABLISHED_R)
1463 0 : printed += printf("Er");
1464 :
1465 2 : if (fe->fe_tcp_flags & VR_FLOW_TCP_FIN)
1466 0 : printed += printf("F");
1467 2 : if (fe->fe_tcp_flags & VR_FLOW_TCP_FIN_R)
1468 0 : printed += printf("Fr");
1469 2 : if (fe->fe_tcp_flags & VR_FLOW_TCP_RST)
1470 0 : printed += printf("R");
1471 2 : if (fe->fe_tcp_flags & VR_FLOW_TCP_HALF_CLOSE)
1472 0 : printed += printf("C");
1473 2 : if (fe->fe_tcp_flags & VR_FLOW_TCP_DEAD)
1474 0 : printed += printf("D");
1475 :
1476 2 : printed += printf(", ");
1477 : }
1478 :
1479 5 : if (fe->fe_ecmp_nh_index >= 0)
1480 0 : printed += printf("E:%d, ", fe->fe_ecmp_nh_index);
1481 :
1482 5 : printed += printf("QOS:%d, ", fe->fe_qos_id);
1483 5 : printed += printf("S(nh):%u, ", fe->fe_src_nh_index);
1484 5 : printed = print_new_line_if_required(printed, 70);
1485 5 : printed += printf(" Stats:%u/%u, ", fe->fe_stats.flow_packets,
1486 : fe->fe_stats.flow_bytes);
1487 5 : printed = print_new_line_if_required(printed, 70);
1488 :
1489 5 : if (fe->fe_flags & VR_FLOW_FLAG_MIRROR) {
1490 0 : printed += printf(" Mirror Index :");
1491 0 : if (fe->fe_mirror_id < VR_MAX_MIRROR_INDICES)
1492 0 : printed += printf(" %d", fe->fe_mirror_id);
1493 0 : if (fe->fe_sec_mirror_id < VR_MAX_MIRROR_INDICES)
1494 0 : printed += printf(", %d, ", fe->fe_sec_mirror_id);
1495 0 : printed = print_new_line_if_required(printed, 70);
1496 : }
1497 5 : printed += printf(" SPort %d,", fe->fe_udp_src_port);
1498 5 : printed = print_new_line_if_required(printed, 70);
1499 5 : printf(" TTL %d,", fe->fe_ttl);
1500 5 : printed = print_new_line_if_required(printed, 70);
1501 5 : if(fe->fe_underlay_ecmp_index >= 0) {
1502 0 : printf(" UnderlayEcmpIdx:%d,", fe->fe_underlay_ecmp_index);
1503 0 : printed = print_new_line_if_required(printed, 70);
1504 : }
1505 5 : if (fe->fe_flags1 & VR_FLOW_FLAG1_HBS_LEFT)
1506 0 : printed += printf(" HbsLeft,");
1507 5 : else if (fe->fe_flags1 & VR_FLOW_FLAG1_HBS_RIGHT)
1508 0 : printed += printf(" HbsRight,");
1509 5 : inet_ntop(AF_INET, &fe->fe_src_info, in_dest, sizeof(in_dest));
1510 5 : printf(" Sinfo %s", in_dest);
1511 5 : printf(")");
1512 : }
1513 :
1514 2519040 : j = -1;
1515 2519040 : next_index = fe->fe_hentry.hentry_next_index;
1516 2519040 : while (next_index != VR_INVALID_HENTRY_INDEX) {
1517 0 : ofe = (struct vr_flow_entry *)((char *)ft->ft_entries +
1518 0 : (next_index * sizeof(*fe)));
1519 0 : if (j == -1) {
1520 0 : if (!(fe->fe_flags & VR_FLOW_FLAG_ACTIVE))
1521 0 : printf("%6d", i);
1522 :
1523 0 : printf("\n Oflow entries:\n\t");
1524 0 : j = 0;
1525 : }
1526 0 : j += printf(" %d", ofe->fe_hentry.hentry_index);
1527 0 : if (j > 65) {
1528 0 : printf("\n ");
1529 0 : j = 0;
1530 : }
1531 :
1532 0 : next_index = ofe->fe_hentry.hentry_next_index;
1533 : /* CEM-24972: memory mapped area for flow is pointing to incorrect memory location so next_index coming as 0 */
1534 0 : if(!next_index) {
1535 0 : printf("\nERROR:flow file corrupted,reload vRouter module to recover\n");
1536 0 : return;
1537 : }
1538 : }
1539 :
1540 2519040 : if ((fe->fe_flags & VR_FLOW_FLAG_ACTIVE) || (j != -1))
1541 5 : printf("\n\n");
1542 : }
1543 :
1544 4 : return;
1545 : }
1546 :
1547 : static void
1548 4 : flow_list(void)
1549 : {
1550 4 : flow_dump_table(&main_table);
1551 4 : return;
1552 : }
1553 :
1554 : static void
1555 0 : flow_stats(void)
1556 : {
1557 0 : struct flow_table *ft = &main_table;
1558 0 : unsigned int i, iteration = 0;
1559 : struct vr_flow_entry *fe;
1560 : struct timeval now;
1561 : struct timeval last_time;
1562 0 : int active_entries = 0;
1563 0 : int hold_entries = 0;
1564 0 : int prev_active_entries = 0;
1565 0 : int prev_hold_entries = 0;
1566 0 : int total_entries = 0;
1567 0 : int prev_total_entries = 0;
1568 : int diff_ms;
1569 : int rate;
1570 0 : uint64_t avg_setup_rate = 0;
1571 0 : uint64_t avg_teardown_rate = 0;
1572 0 : uint64_t setup_time = 0;
1573 0 : uint64_t teardown_time = 0;
1574 : int total_rate;
1575 0 : int flow_action_drop = 0;
1576 0 : int flow_action_fwd = 0;
1577 0 : int flow_action_nat = 0;
1578 :
1579 0 : gettimeofday(&last_time, NULL);
1580 0 : while (1) {
1581 0 : active_entries = 0;
1582 0 : total_entries = 0;
1583 0 : hold_entries = 0;
1584 0 : flow_action_drop = 0;
1585 0 : flow_action_fwd = 0;
1586 0 : flow_action_nat = 0;
1587 0 : usleep(500000);
1588 0 : for (i = 0; i < ft->ft_num_entries; i++) {
1589 0 : fe = (struct vr_flow_entry *)((char *)ft->ft_entries +
1590 0 : (i * sizeof(*fe)));
1591 0 : if (fe->fe_flags & VR_FLOW_FLAG_ACTIVE) {
1592 0 : if (fe->fe_flags & VR_FLOW_FLAG_EVICTED) {
1593 0 : continue;
1594 : }
1595 0 : total_entries++;
1596 0 : if (fe->fe_action != VR_FLOW_ACTION_HOLD) {
1597 0 : active_entries++;
1598 : }
1599 0 : if (fe->fe_action == VR_FLOW_ACTION_DROP) {
1600 0 : flow_action_drop++;
1601 0 : } else if (fe->fe_action == VR_FLOW_ACTION_FORWARD) {
1602 0 : flow_action_fwd++;
1603 0 : } else if (fe->fe_action == VR_FLOW_ACTION_NAT) {
1604 0 : flow_action_nat++;
1605 : }
1606 : }
1607 : }
1608 0 : hold_entries = ft->ft_hold_entries;
1609 0 : gettimeofday(&now, NULL);
1610 : /* calc time difference and rate */
1611 0 : diff_ms = (now.tv_sec - last_time.tv_sec) * 1000;
1612 0 : diff_ms += (now.tv_usec - last_time.tv_usec) / 1000;
1613 0 : assert(diff_ms > 0 );
1614 0 : rate = (active_entries - prev_active_entries) * 1000;
1615 0 : rate /= diff_ms;
1616 0 : total_rate = (total_entries - prev_total_entries) * 1000;
1617 0 : total_rate /= diff_ms;
1618 0 : if (iteration == 0) {
1619 0 : rate = 0;
1620 0 : total_rate = 0;
1621 0 : iteration = 1;
1622 : }
1623 :
1624 0 : if (rate != 0 || total_rate != 0) {
1625 0 : if (rate < -1000) {
1626 0 : avg_teardown_rate = avg_teardown_rate * teardown_time -
1627 0 : (active_entries - prev_active_entries) * 1000;
1628 0 : teardown_time += diff_ms;
1629 0 : avg_teardown_rate /= teardown_time;
1630 : }
1631 :
1632 0 : if (rate > 1000) {
1633 0 : avg_setup_rate = avg_setup_rate * setup_time +
1634 0 : (active_entries - prev_active_entries) * 1000;
1635 0 : setup_time += diff_ms;
1636 0 : avg_setup_rate /= setup_time;
1637 : }
1638 : }
1639 :
1640 : /* On Ubuntu system() is declared with warn_unused_result
1641 : * attribute, so we suppress the warning
1642 : */
1643 0 : if (system(CLEAN_SCREEN_CMD) == -1) {
1644 0 : printf("Error: system() failed\n");
1645 : }
1646 :
1647 0 : time_t secs = now.tv_sec;
1648 : struct tm *tm;
1649 : char fmt[64], buf[64];
1650 0 : if((tm = localtime(&secs)) != NULL)
1651 : {
1652 0 : strftime(fmt, sizeof fmt, "%Y-%m-%d %H:%M:%S %z", tm);
1653 0 : snprintf(buf, sizeof buf, fmt, now.tv_usec);
1654 0 : printf("%s\n", buf);
1655 : }
1656 :
1657 0 : printf("Flow Statistics\n");
1658 0 : printf("---------------\n");
1659 0 : printf(" Total Entries --- Total = %7d, new = %7d \n",
1660 : total_entries, (total_entries - prev_total_entries));
1661 0 : printf(" Active Entries --- Total = %7d, new = %7d \n",
1662 : active_entries, (active_entries - prev_active_entries));
1663 0 : printf(" Hold Entries --- Total = %7d, new = %7d \n",
1664 : hold_entries, (hold_entries - prev_hold_entries));
1665 0 : printf(" Fwd flow Entries - Total = %7d\n", flow_action_fwd);
1666 0 : printf(" drop flow Entries - Total = %7d\n", flow_action_drop);
1667 0 : printf(" NAT flow Entries - Total = %7d\n\n", flow_action_nat);
1668 0 : printf(" Rate of change of Active Entries\n");
1669 0 : printf(" --------------------------------\n");
1670 0 : printf(" current rate = %8d\n", rate);
1671 0 : printf(" Avg setup rate = %8zu\n", avg_setup_rate);
1672 0 : printf(" Avg teardown rate = %8zu\n", avg_teardown_rate);
1673 0 : printf(" Rate of change of Flow Entries\n");
1674 0 : printf(" ------------------------------\n");
1675 0 : printf(" current rate = %8d\n", total_rate);
1676 :
1677 0 : last_time = now;
1678 0 : prev_active_entries = active_entries;
1679 0 : prev_total_entries = total_entries;
1680 0 : prev_hold_entries = hold_entries;
1681 : }
1682 : }
1683 :
1684 : static void
1685 0 : flow_rate(void)
1686 : {
1687 0 : struct flow_table *ft = &main_table;
1688 : struct vr_flow_entry *fe;
1689 : struct timeval now;
1690 : struct timeval last_time;
1691 : int diff_ms;
1692 0 : int hold_count_old = 0;
1693 0 : int processed_count_old = 0;
1694 0 : int added_count_old = 0;
1695 0 : int deleted_count_old = 0;
1696 :
1697 0 : gettimeofday(&last_time, NULL);
1698 0 : while (1) {
1699 0 : int hold_rate = 0;
1700 0 : int hold_count = 0;
1701 :
1702 0 : int processed_rate = 0;
1703 0 : int processed_count = 0;
1704 :
1705 0 : int added_rate = 0;
1706 0 : int added_count = 0;
1707 :
1708 0 : int deleted_rate = 0;
1709 0 : int deleted_count = 0;
1710 :
1711 0 : int flow_op_rate = 0;
1712 : struct tm *tm;
1713 :
1714 0 : usleep(500000);
1715 0 : flow_table_get();
1716 0 : gettimeofday(&now, NULL);
1717 :
1718 : /* calc time difference and rate */
1719 0 : diff_ms = (now.tv_sec - last_time.tv_sec) * 1000;
1720 0 : diff_ms += (now.tv_usec - last_time.tv_usec) / 1000;
1721 0 : assert(diff_ms > 0 );
1722 :
1723 0 : hold_count = ft->ft_hold_entries;
1724 0 : hold_rate = hold_count * 1000 / diff_ms;
1725 :
1726 0 : processed_count = ft->ft_processed - processed_count_old;
1727 0 : processed_rate = processed_count * 1000 / diff_ms;
1728 :
1729 0 : added_count = ft->ft_added - added_count_old;
1730 0 : added_rate = added_count * 1000 / diff_ms;
1731 :
1732 0 : deleted_count = ft->ft_deleted - deleted_count_old;
1733 0 : deleted_rate = deleted_count * 1000 / diff_ms;
1734 :
1735 0 : flow_op_rate = processed_rate + added_rate + deleted_rate;
1736 :
1737 : char fmt[64];
1738 0 : time_t secs = now.tv_sec;
1739 0 : tm = localtime(&secs);
1740 0 : strftime(fmt, sizeof fmt, "%Y-%m-%d %H:%M:%S", tm);
1741 :
1742 0 : if (hold_rate || processed_rate || added_rate || deleted_rate) {
1743 0 : printf ("%s.%03d: Entries = %8d "
1744 : "Rate = %6d (Fwd = %8d Rev = %8d Del = %8d) "
1745 : "Hold = %8d Free Burst Tokens = %8d Total Hold Entries %8d\n",
1746 0 : fmt, (int)now.tv_usec/1000,
1747 0 : (int)ft->ft_total_entries, flow_op_rate, processed_count,
1748 : added_count, deleted_count, hold_count,
1749 : ft->ft_burst_free_tokens,
1750 : ft->ft_hold_entries);
1751 0 : fflush(stdout);
1752 : }
1753 :
1754 0 : last_time = now;
1755 0 : hold_count_old = hold_count;
1756 0 : processed_count_old = ft->ft_processed;
1757 0 : added_count_old = ft->ft_added;
1758 0 : deleted_count_old = ft->ft_deleted;
1759 : }
1760 : }
1761 :
1762 : static int
1763 0 : get_flow_table_map_counts(vr_flow_table_data *table, struct flow_table *ft)
1764 : {
1765 0 : ft->ft_processed = table->ftable_processed;
1766 0 : ft->ft_created = table->ftable_created;
1767 0 : ft->ft_hold_oflows = table->ftable_hold_oflows;
1768 0 : ft->ft_added = table->ftable_added;
1769 0 : ft->ft_oflow_entries = table->ftable_oflow_entries;
1770 0 : ft->ft_deleted = table->ftable_deleted;
1771 0 : ft->ft_changed = table->ftable_changed;
1772 0 : ft->ft_total_entries = table->ftable_used_entries;
1773 0 : ft->ft_burst_free_tokens = table->ftable_burst_free_tokens;
1774 0 : ft->ft_hold_entries = table->ftable_hold_entries;
1775 :
1776 :
1777 0 : return 0;
1778 : }
1779 :
1780 : static int
1781 13 : flow_table_map(vr_flow_table_data *table)
1782 : {
1783 : const char *mmap_error_msg;
1784 : int ret;
1785 : unsigned int i;
1786 13 : struct flow_table *ft = &main_table;
1787 : const char *flow_path;
1788 :
1789 : if (table->ftable_dev < 0)
1790 : exit(ENODEV);
1791 :
1792 13 : if (ft->ft_entries != 0) {
1793 0 : get_flow_table_map_counts(table, ft);
1794 0 : return ft->ft_num_entries;
1795 : }
1796 :
1797 13 : mmap_error_msg = vr_table_map(table->ftable_dev, VR_MEM_FLOW_TABLE_OBJECT,
1798 13 : table->ftable_file_path, table->ftable_size, (void **)&ft->ft_entries);
1799 :
1800 13 : if (mmap_error_msg) {
1801 0 : printf("%s\n", mmap_error_msg);
1802 0 : exit(1);
1803 : }
1804 :
1805 13 : ft->ft_span = table->ftable_size;
1806 13 : ft->ft_num_entries = ft->ft_span / sizeof(struct vr_flow_entry);
1807 13 : ft->ft_processed = table->ftable_processed;
1808 13 : ft->ft_created = table->ftable_created;
1809 13 : ft->ft_hold_oflows = table->ftable_hold_oflows;
1810 13 : ft->ft_added = table->ftable_added;
1811 13 : ft->ft_cpus = table->ftable_cpus;
1812 13 : ft->ft_oflow_entries = table->ftable_oflow_entries;
1813 13 : ft->ft_deleted = table->ftable_deleted;
1814 13 : ft->ft_changed = table->ftable_changed;
1815 13 : ft->ft_burst_free_tokens = table->ftable_burst_free_tokens;
1816 13 : ft->ft_hold_entries = table->ftable_hold_entries;
1817 :
1818 :
1819 13 : if (table->ftable_hold_stat && table->ftable_hold_stat_size) {
1820 13 : ft->ft_hold_stat_count = table->ftable_hold_stat_size;
1821 169 : for (i = 0; i < table->ftable_hold_stat_size; i++) {
1822 156 : if (i ==
1823 : (sizeof(ft->ft_hold_stat) / sizeof(ft->ft_hold_stat[0]))) {
1824 0 : ft->ft_hold_stat_count = i;
1825 0 : break;
1826 : }
1827 :
1828 156 : ft->ft_hold_stat[i] = table->ftable_hold_stat[i];
1829 : }
1830 : } else {
1831 0 : ft->ft_hold_stat_count = 0;
1832 0 : memset(ft->ft_hold_stat, 0, sizeof(ft->ft_hold_stat));
1833 : }
1834 :
1835 13 : return ft->ft_num_entries;
1836 : }
1837 :
1838 : static int
1839 13 : flow_make_flow_req(void *req, char *flow_str)
1840 : {
1841 : int ret;
1842 :
1843 13 : ret = vr_sendmsg(cl, req, flow_str);
1844 13 : if (ret <= 0)
1845 0 : return ret;
1846 :
1847 13 : ret = vr_recvmsg(cl, false);
1848 13 : if (ret <= 0)
1849 0 : return ret;
1850 :
1851 13 : cl->cl_buf_offset = 0;
1852 13 : return ret;
1853 : }
1854 :
1855 : static int
1856 13 : flow_table_get(void)
1857 : {
1858 : /* get the kernel's view of the flow table */
1859 13 : memset(&ftable, 0, sizeof(ftable));
1860 13 : ftable.ftable_op = FLOW_OP_FLOW_TABLE_GET;
1861 :
1862 13 : return flow_make_flow_req(&ftable, "vr_flow_table_data");
1863 : }
1864 :
1865 : static int
1866 13 : flow_table_setup(void)
1867 : {
1868 13 : int ret = 0;
1869 :
1870 13 : if (sock_dir_set) {
1871 13 : set_platform_vtest();
1872 : }
1873 13 : cl = vr_get_nl_client(VR_NETLINK_PROTO_DEFAULT);
1874 13 : if (cl == NULL)
1875 0 : return -ENOMEM;
1876 :
1877 13 : cl->cl_buf_offset = 0;
1878 13 : return ret;
1879 : }
1880 :
1881 : static int
1882 9 : fill_flow_req(vr_flow_req *req, unsigned long flow_index, char action,
1883 : bool flush)
1884 : {
1885 : struct vr_flow_entry *fe;
1886 :
1887 9 : memset(req, 0, sizeof(*req));
1888 9 : fe = flow_get(flow_index);
1889 9 : if (!fe) {
1890 0 : printf("Invalid flow index value %lu\n", flow_index);
1891 0 : return -1;
1892 : }
1893 :
1894 9 : if (action == 'g') {
1895 9 : if (!(fe->fe_flags & VR_FLOW_FLAG_ACTIVE)) {
1896 0 : printf("Flow index %lu is not active\n", flow_index);
1897 0 : return -1;
1898 : }
1899 :
1900 9 : if (!show_evicted_set && (fe->fe_flags & VR_FLOW_FLAG_EVICTED)) {
1901 4 : printf("Flow at index %lu is EVICTED. Use --show-evicted\n",
1902 : flow_index);
1903 4 : return -1;
1904 : }
1905 :
1906 5 : flow_get_entry(fe);
1907 5 : return -1;
1908 : }
1909 :
1910 0 : if ((fe->fe_type != VP_TYPE_IP) && (fe->fe_type != VP_TYPE_IP6))
1911 0 : return -1;
1912 :
1913 0 : req->fr_op = FLOW_OP_FLOW_SET;
1914 0 : req->fr_index = flow_index;
1915 0 : req->fr_family = VR_FLOW_FAMILY(fe->fe_type);
1916 0 : req->fr_flags = VR_FLOW_FLAG_ACTIVE;
1917 0 : if (fe->fe_type == VP_TYPE_IP) {
1918 0 : req->fr_flow_sip_l = fe->fe_key.flow4_sip;
1919 0 : req->fr_flow_dip_l = fe->fe_key.flow4_dip;
1920 : } else {
1921 0 : memcpy(&req->fr_flow_sip_u, fe->fe_key.flow6_sip, sizeof(uint64_t));
1922 0 : memcpy(&req->fr_flow_sip_l, (fe->fe_key.flow6_sip + sizeof(uint64_t)),
1923 : sizeof(uint64_t));
1924 0 : memcpy(&req->fr_flow_dip_u, fe->fe_key.flow6_dip, sizeof(uint64_t));
1925 0 : memcpy(&req->fr_flow_dip_l, (fe->fe_key.flow6_dip + sizeof(uint64_t)),
1926 : sizeof(uint64_t));
1927 : }
1928 :
1929 0 : req->fr_flow_proto = fe->fe_key.flow_proto;
1930 0 : req->fr_flow_sport = fe->fe_key.flow_sport;
1931 0 : req->fr_flow_dport = fe->fe_key.flow_dport;
1932 0 : req->fr_flow_nh_id = fe->fe_key.flow_nh_id;
1933 0 : req->fr_gen_id = fe->fe_gen_id;
1934 :
1935 0 : switch (action) {
1936 0 : case 'd':
1937 0 : req->fr_action = VR_FLOW_ACTION_DROP;
1938 0 : break;
1939 :
1940 0 : case 'f':
1941 0 : req->fr_action = VR_FLOW_ACTION_FORWARD;
1942 0 : break;
1943 :
1944 0 : case 'i':
1945 0 : if (fe->fe_flags & VR_FLOW_FLAG_EVICTED) {
1946 0 : if (!flush)
1947 0 : printf("Flow %lu is evicted!\n", flow_index);
1948 0 : return -1;
1949 : }
1950 0 : req->fr_flags = VR_FLOW_FLAG_ACTIVE ^ VR_FLOW_FLAG_ACTIVE;
1951 0 : req->fr_action = VR_FLOW_ACTION_DROP;
1952 0 : break;
1953 :
1954 0 : case 'e':
1955 0 : req->fr_extflags = VR_FLOW_EXT_FLAG_FORCE_EVICT;
1956 0 : break;
1957 :
1958 0 : default:
1959 0 : return -1;
1960 : }
1961 :
1962 0 : if (mirror >= 0) {
1963 0 : req->fr_mir_id = mirror;
1964 0 : req->fr_flags |= VR_FLOW_FLAG_MIRROR;
1965 : } else
1966 0 : req->fr_flags &= ~VR_FLOW_FLAG_MIRROR;
1967 :
1968 0 : return 0;
1969 : }
1970 :
1971 : static void
1972 9 : flow_do_op(unsigned long flow_index, char action)
1973 : {
1974 9 : if (fill_flow_req(&flow_req, flow_index, action, false))
1975 9 : return;
1976 0 : flow_make_flow_req(&flow_req, "vr_flow_req");
1977 0 : return;
1978 : }
1979 :
1980 : static void
1981 0 : flow_process_response()
1982 : {
1983 : int ret;
1984 : struct nl_response *resp;
1985 :
1986 0 : cl->cl_buf_offset = 0;
1987 0 : if ((ret = nl_recvmsg(cl)) > 0) {
1988 0 : resp = nl_parse_reply(cl);
1989 0 : if (resp->nl_op == SANDESH_REQUEST) {
1990 0 : sandesh_decode(resp->nl_data, resp->nl_len, vr_find_sandesh_info, &ret);
1991 : }
1992 : }
1993 0 : }
1994 :
1995 : static int
1996 0 : flow_make_flow_req_perf(vr_flow_req *req)
1997 : {
1998 : int ret, attr_len, error;
1999 : struct nl_response *resp;
2000 : static int count = 0;
2001 : static struct iovec iov[MAX_FLOW_NL_MSG_BUNCH];
2002 : uint8_t *base;
2003 :
2004 0 : base = nl_get_buf_ptr(cl);
2005 :
2006 0 : if (!count) {
2007 0 : ret = nl_build_nlh(cl, cl->cl_genl_family_id, NLM_F_REQUEST);
2008 0 : if (ret)
2009 0 : return ret;
2010 :
2011 0 : ret = nl_build_genlh(cl, SANDESH_REQUEST, 0);
2012 0 : if (ret)
2013 0 : return ret;
2014 :
2015 0 : attr_len = nl_get_attr_hdr_size();
2016 : } else {
2017 0 : attr_len = 0;
2018 : }
2019 :
2020 0 : error = 0;
2021 0 : ret = sandesh_encode(req, "vr_flow_req", vr_find_sandesh_info,
2022 0 : (nl_get_buf_ptr(cl) + attr_len),
2023 0 : (nl_get_buf_len(cl) - attr_len), &error);
2024 :
2025 0 : if ((ret <= 0) || error)
2026 0 : return ret;
2027 :
2028 0 : if (!count) {
2029 0 : nl_build_attr(cl, ret, NL_ATTR_VR_MESSAGE_PROTOCOL);
2030 : } else {
2031 0 : nl_update_attr_len(cl, ret);
2032 : }
2033 :
2034 0 : nl_update_nlh(cl);
2035 :
2036 0 : iov[count].iov_base = base;
2037 0 : iov[count].iov_len = nl_get_buf_ptr(cl) - base;
2038 0 : count++;
2039 0 : if (bunch != count && more)
2040 0 : return 0;
2041 :
2042 : struct msghdr msg;
2043 0 : memset(&msg, 0, sizeof(msg));
2044 : #if defined (__linux__)
2045 0 : msg.msg_name = cl->cl_sa;
2046 0 : msg.msg_namelen = cl->cl_sa_len;
2047 : #endif
2048 :
2049 0 : msg.msg_iov = iov;
2050 0 : msg.msg_iovlen = count;
2051 :
2052 0 : ret = sendmsg(cl->cl_sock, &msg, 0);
2053 0 : if (ret <= 0)
2054 0 : return ret;
2055 :
2056 0 : cl->cl_buf_offset = 0;
2057 0 : if (errno == EAGAIN || errno == EWOULDBLOCK)
2058 0 : ret = 0;
2059 :
2060 0 : while (count != 0) {
2061 0 : count--;
2062 0 : flow_process_response();
2063 : }
2064 :
2065 0 : cl->cl_buf_offset = 0;
2066 :
2067 0 : return ret;
2068 : }
2069 :
2070 : void
2071 0 : run_perf(void)
2072 : {
2073 : struct vr_flow_entry *fe;
2074 0 : uint32_t sip = inet_addr("1.1.1.1");
2075 0 : uint32_t dip = inet_addr("2.2.2.2");
2076 : int ret;
2077 0 : uint8_t proto = 0xFF;
2078 0 : uint16_t sport = 1000;
2079 0 : uint16_t nhid = 1;
2080 :
2081 0 : memset(&flow_req, 0, sizeof(flow_req));
2082 0 : flow_req.fr_family = AF_INET;
2083 0 : flow_req.fr_op = FLOW_OP_FLOW_SET;
2084 0 : flow_req.fr_flags = VR_FLOW_FLAG_ACTIVE;
2085 0 : flow_req.fr_flow_sip_l = sip;
2086 0 : flow_req.fr_flow_dip_l = dip;
2087 0 : flow_req.fr_flow_proto = proto;
2088 0 : flow_req.fr_flow_nh_id = nhid;
2089 0 : flow_req.fr_gen_id = 0;
2090 :
2091 : struct timeval last_time;
2092 0 : gettimeofday(&last_time, NULL);
2093 :
2094 0 : int i = 0;
2095 0 : for (i = 0; i < perf; i++) {
2096 0 : more = false;
2097 0 : array_index = i;
2098 0 : flow_req.fr_action = VR_FLOW_ACTION_HOLD;
2099 0 : flow_req.fr_flow_sport = htons(sport + (i / 65535));
2100 0 : flow_req.fr_flow_dport = htons(i % 65535);
2101 0 : flow_req.fr_index = -1;
2102 0 : flow_make_flow_req_perf(&flow_req);
2103 : }
2104 0 : cl->cl_buf_offset = 0;
2105 :
2106 : struct timeval now;
2107 0 : gettimeofday(&now, NULL);
2108 : int diff_ms;
2109 0 : diff_ms = (now.tv_sec - last_time.tv_sec) * 1000;
2110 0 : diff_ms += (now.tv_usec - last_time.tv_usec) / 1000;
2111 0 : printf("Created %d HOLD entries in %d msec\n", perf, diff_ms);
2112 :
2113 0 : gettimeofday(&last_time, NULL);
2114 0 : for (i = 0; i < perf; i++) {
2115 0 : array_index = -1;
2116 0 : flow_req.fr_flow_sip_l = dip;
2117 0 : flow_req.fr_flow_dip_l = sip;
2118 0 : flow_req.fr_flow_sport = htons(i % 65535);
2119 0 : flow_req.fr_flow_dport = htons(sport + (i / 65535));
2120 0 : flow_req.fr_index = -1;
2121 0 : flow_req.fr_action = VR_FLOW_ACTION_FORWARD;
2122 0 : flow_req.fr_gen_id = 0;
2123 0 : more = true;
2124 0 : flow_make_flow_req_perf(&flow_req);
2125 :
2126 0 : flow_req.fr_flow_sip_l = sip;
2127 0 : flow_req.fr_flow_dip_l = dip;
2128 0 : flow_req.fr_flow_sport = htons(sport + (i / 65535));
2129 0 : flow_req.fr_flow_dport = htons(i % 65535);
2130 0 : flow_req.fr_action = VR_FLOW_ACTION_FORWARD;
2131 0 : flow_req.fr_index = flow_md_mem[i].fmd_index;
2132 0 : flow_req.fr_gen_id = flow_md_mem[i].fmd_gen_id;
2133 0 : if (i == (perf - 1)) {
2134 0 : more = false;
2135 : }
2136 0 : flow_make_flow_req_perf(&flow_req);
2137 : }
2138 :
2139 0 : gettimeofday(&now, NULL);
2140 0 : diff_ms = (now.tv_sec - last_time.tv_sec) * 1000;
2141 0 : diff_ms += (now.tv_usec - last_time.tv_usec) / 1000;
2142 0 : printf("Created %d HOLD and %d FWD entries in %d msec\n",
2143 : perf, perf, diff_ms);
2144 :
2145 0 : }
2146 :
2147 : void
2148 0 : run_flush(void)
2149 : {
2150 : int i;
2151 : int diff_ms;
2152 0 : int count = 0;
2153 : struct vr_flow_entry *fe;
2154 0 : struct flow_table *ft = &main_table;
2155 : struct timeval now;
2156 : struct timeval last_time;
2157 0 : vr_flow_req *table = malloc(sizeof(vr_flow_req) * ft->ft_num_entries);
2158 :
2159 0 : printf("Scanning flow table\n");
2160 0 : gettimeofday(&last_time, NULL);
2161 0 : for (i = 0; i < ft->ft_num_entries; i++) {
2162 0 : if (fill_flow_req(&table[count], i, 'i', true))
2163 0 : continue;
2164 0 : count++;
2165 : }
2166 0 : gettimeofday(&now, NULL);
2167 0 : diff_ms = (now.tv_sec - last_time.tv_sec) * 1000;
2168 0 : diff_ms += (now.tv_usec - last_time.tv_usec) / 1000;
2169 0 : printf("Found %d entries in %d msec\n", count, diff_ms);
2170 :
2171 0 : printf("Deleting %d entries in flow-table\n", count);
2172 0 : gettimeofday(&last_time, NULL);
2173 0 : for (i = 0; i < count; i++) {
2174 0 : flow_make_flow_req(&table[i], "vr_flow_req");
2175 0 : flow_process_response();
2176 : }
2177 :
2178 0 : gettimeofday(&now, NULL);
2179 0 : diff_ms = (now.tv_sec - last_time.tv_sec) * 1000;
2180 0 : diff_ms += (now.tv_usec - last_time.tv_usec) / 1000;
2181 0 : printf("Deleted %d entries in %d msec\n", count, diff_ms);
2182 0 : free(table);
2183 0 : }
2184 :
2185 : static void
2186 0 : Usage(void)
2187 : {
2188 0 : printf("Usage:flow [-f flow_index]\n");
2189 0 : printf(" [-d flow_index]\n");
2190 0 : printf(" [-i flow_index]\n");
2191 0 : printf(" [-e flow_index]\n");
2192 0 : printf(" [--sock-dir <netlink socket dir>\n");
2193 0 : printf(" [--mirror=mirror table index]\n");
2194 0 : printf(" [--match \"match_string\"\n");
2195 0 : printf(" [-l]\n");
2196 0 : printf(" [--show-evicted]\n");
2197 0 : printf(" [-r]\n");
2198 0 : printf(" [-s]\n");
2199 0 : printf(" [-p flow_count]\n");
2200 0 : printf(" [-b bunch_count]\n");
2201 0 : printf(" [-F]\n");
2202 0 : printf("\n");
2203 :
2204 0 : printf("-f <flow_index> Set forward action for flow at flow_index <flow_index>\n");
2205 0 : printf("-d <flow_index> Set drop action for flow at flow_index <flow_index>\n");
2206 0 : printf("-i <flow_index> Invalidate flow at flow_index <flow_index>\n");
2207 0 : printf("-e <flow_index> force evict flow at flow_index <flow_index>\n");
2208 0 : printf("-p <flow_count> Profile time to add/delete flow entries\n");
2209 0 : printf("-b <bunch_count> Bunch flow messages in one netlink message\n");
2210 0 : printf("-F Flush all the flows\n");
2211 0 : printf("--get Get and print flow entry in a particular index\n");
2212 0 : printf(" e.g.: --get <flow_index>\n");
2213 0 : printf("--mirror Mirror index to mirror to\n");
2214 0 : printf("--match Match criteria separated by a '&'; IP:PORT separated by a ','\n");
2215 0 : printf(" e.g.: --match 1.1.1.1:20\n");
2216 0 : printf(" --match \"1.1.1.1:20,2.2.2.2:22\"\n");
2217 0 : printf(" --match \"[fe80::225:90ff:fec3:afa]:22\"\n");
2218 0 : printf(" --match \"10.204.217.10:56910 & vrf 0 & proto tcp\"\n");
2219 0 : printf(" --match \"10.204.217.10:56910,169.254.0.3:22 & vrf 0 & proto tcp\"\n");
2220 0 : printf(" proto {tcp, udp, icmp, icmp6, sctp}\n");
2221 0 : printf("-l List flows\n");
2222 0 : printf("--show-evicted Show evicted flows too\n");
2223 0 : printf("-r Start dumping flow setup rate\n");
2224 0 : printf("-s Start dumping flow stats\n");
2225 0 : printf("--help Print this help\n");
2226 :
2227 0 : exit(-EINVAL);
2228 : }
2229 :
2230 : enum opt_flow_index {
2231 : DVRF_OPT_INDEX,
2232 : GET_OPT_INDEX,
2233 : MIRROR_OPT_INDEX,
2234 : SHOW_EVICTED_OPT_INDEX,
2235 : MATCH_OPT_INDEX,
2236 : HELP_OPT_INDEX,
2237 : FORCE_EVICT_OPT_INDEX,
2238 : SOCK_DIR_OPT_INDEX,
2239 : MAX_OPT_INDEX
2240 : };
2241 :
2242 : static struct option long_options[] = {
2243 : [DVRF_OPT_INDEX] = {"dvrf", required_argument, &dvrf_set, 1},
2244 : [GET_OPT_INDEX] = {"get", required_argument, &get_set, 1},
2245 : [MIRROR_OPT_INDEX] = {"mirror", required_argument, &mir_set, 1},
2246 : [SHOW_EVICTED_OPT_INDEX] = {"show-evicted", no_argument, &show_evicted_set, 1},
2247 : [MATCH_OPT_INDEX] = {"match", required_argument, &match_set, 1},
2248 : [HELP_OPT_INDEX] = {"help", no_argument, &help_set, 1},
2249 : [FORCE_EVICT_OPT_INDEX] = {"force-evict", required_argument, &force_evict_set, 1},
2250 : [SOCK_DIR_OPT_INDEX] = {"sock-dir", required_argument, &sock_dir_set, 1},
2251 : [MAX_OPT_INDEX] = { NULL, 0, 0, 0}
2252 : };
2253 :
2254 : static void
2255 13 : validate_options(void)
2256 : {
2257 13 : if (!flow_index && !list && !rate && !stats && !match_set
2258 0 : && !perf && !flush)
2259 0 : Usage();
2260 :
2261 13 : if (show_evicted_set && !list)
2262 0 : Usage();
2263 :
2264 13 : return;
2265 : }
2266 :
2267 : static int
2268 0 : flow_set_family(unsigned int family, char *addr, const char *port)
2269 : {
2270 : uint8_t ip[VR_IP6_ADDRESS_LEN];
2271 0 : uint8_t *mem = NULL, mem_size;
2272 :
2273 0 : if (match_ip1_set && match_ip2_set && (addr || port)) {
2274 0 : printf("match: Why do you specify \"[%s]:%s\" when both ends of "
2275 : "the flow are already specified\n", addr, port ? port : NULL);
2276 0 : return -EINVAL;
2277 : }
2278 :
2279 0 : switch (family) {
2280 0 : case AF_INET:
2281 0 : mem_size = VR_IP_ADDRESS_LEN;
2282 0 : if (!vr_valid_ipv4_address(addr))
2283 0 : return -EINVAL;
2284 0 : break;
2285 :
2286 0 : case AF_INET6:
2287 0 : mem_size = VR_IP6_ADDRESS_LEN;
2288 0 : if (!vr_valid_ipv6_address(addr))
2289 0 : return -EINVAL;
2290 0 : break;
2291 :
2292 0 : default:
2293 0 : printf("match: Internal logic failure. Family is not one of inet/inet6\n");
2294 0 : return -EINVAL;
2295 : }
2296 :
2297 0 : if (match_family && (match_family != family)) {
2298 0 : printf("match: You are trying to match v4 and v6 flow together\n");
2299 0 : printf("match: It does not make sense to me at this point of time\n");
2300 :
2301 0 : return -EINVAL;
2302 : }
2303 :
2304 0 : if (!match_family) {
2305 0 : match_family = family;
2306 0 : match_family_size = mem_size;
2307 : }
2308 :
2309 0 : if (strlen(addr) != strlen("*")) {
2310 0 : inet_pton(family, addr, ip);
2311 0 : mem = malloc(mem_size);
2312 0 : if (!mem) {
2313 0 : printf("match: Memory Allocation failure. Try again\n");
2314 0 : return -ENOMEM;
2315 : }
2316 0 : memcpy(mem, ip, mem_size);
2317 : }
2318 :
2319 0 : if (!match_ip1_set) {
2320 0 : match_ip1 = mem;
2321 0 : if (port) {
2322 0 : if (strncmp(port, "*", 1))
2323 0 : match_port1 = strtoul(port, NULL, 0);
2324 : }
2325 0 : match_ip1_set = true;
2326 0 : } else if (!match_ip2_set) {
2327 0 : match_ip2 = mem;
2328 0 : if (port) {
2329 0 : if (strncmp(port, "*", 1))
2330 0 : match_port2 = strtoul(port, NULL, 0);
2331 : }
2332 0 : match_ip2_set = true;
2333 : }
2334 :
2335 0 : return 0;
2336 : }
2337 :
2338 : /*
2339 : * Separate out the individual (ip, port) combination
2340 : *
2341 : * For ipv4, the flow will be specified as
2342 : * a.a.a.a:p OR a.a.a.a
2343 : *
2344 : * For ipv6, the corresponding format will be
2345 : * [a:a::a:a]:p OR a:a::a:a
2346 : */
2347 : static int
2348 0 : flow_set_tuple(char *ip_port)
2349 : {
2350 0 : unsigned int len = strlen(ip_port);
2351 : unsigned int address_len;
2352 :
2353 : char *f_colon_sep, *b_colon_sep, *bracket_sep;
2354 :
2355 : /* for ipv6 addresses starting with '[' */
2356 0 : bracket_sep = strchr(ip_port, '[');
2357 0 : if (bracket_sep) {
2358 : /* ...look for closing bracket */
2359 0 : bracket_sep = strrchr(ip_port, ']');
2360 0 : if (!bracket_sep) {
2361 0 : printf("match: No closing ']'\n");
2362 0 : return -EINVAL;
2363 : }
2364 :
2365 :
2366 0 : address_len = bracket_sep - ip_port + 1;
2367 : /* post ']', we should have a ':' and a port number */
2368 0 : if (((len - address_len) < 2) ||
2369 0 : (ip_port[address_len] != ':')) {
2370 0 : printf("match: match string should be in "
2371 : "[aa:aa::aa:aa]:p format\n");
2372 0 : return -EINVAL;
2373 : }
2374 :
2375 : /* replace the ']' with NULL */
2376 0 : ip_port[address_len - 1] = '\0';
2377 : /* the address string is already terminated with NULL */
2378 0 : if (flow_set_family(AF_INET6, ip_port + 1, ip_port + address_len + 1))
2379 0 : return -EINVAL;
2380 :
2381 : } else {
2382 0 : f_colon_sep = strchr(ip_port, ':');
2383 : /*
2384 : * if it is an ipv6 address, we expect to see at least two different
2385 : * ':'
2386 : */
2387 0 : if (f_colon_sep) {
2388 0 : b_colon_sep = strrchr(ip_port, ':');
2389 0 : if (b_colon_sep != f_colon_sep) {
2390 : /* ...hence ipv6 */
2391 0 : flow_set_family(AF_INET6, ip_port, NULL);
2392 : } else {
2393 : /*
2394 : * if they are the same, then it has to be v4 and the
2395 : * ':' is a port separator
2396 : */
2397 0 : ip_port[f_colon_sep - ip_port] = '\0';
2398 0 : if (flow_set_family(AF_INET, ip_port,
2399 0 : ip_port + (f_colon_sep - ip_port) + 1))
2400 0 : return -EINVAL;
2401 : }
2402 : } else {
2403 : /* ...and if there are no ':', then the address is an ipv4 one */
2404 0 : if (flow_set_family(AF_INET, ip_port, NULL))
2405 0 : return -EINVAL;
2406 : }
2407 : }
2408 :
2409 0 : return 0;
2410 : }
2411 :
2412 : static int
2413 0 : flow_set_ip(char *match_string)
2414 : {
2415 0 : int ret = 0;
2416 0 : unsigned int length = strlen(match_string), token_length;
2417 :
2418 0 : char *token, *string = match_string;
2419 :
2420 : do {
2421 0 : token = vr_extract_token(match_string, ',');
2422 0 : if (token) {
2423 0 : token_length = strlen(token) + 1;
2424 : /* ...and use it to set the match tuple */
2425 0 : if (ret = flow_set_tuple(token))
2426 0 : return ret;
2427 : } else {
2428 0 : token = vr_extract_token(match_string, '&');
2429 0 : if (token) {
2430 0 : token_length = strlen(token) + 1;
2431 0 : if (ret = flow_set_tuple(token))
2432 0 : return ret;
2433 : }
2434 : }
2435 :
2436 0 : if (token)
2437 0 : match_string = token + token_length;
2438 :
2439 0 : } while (!ret && token && ((match_string - string) < length));
2440 :
2441 0 : return 0;
2442 : }
2443 :
2444 : static int
2445 0 : flow_set_vrf(char *string)
2446 : {
2447 0 : if (!strlen(string))
2448 0 : return -EINVAL;
2449 :
2450 0 : errno = 0;
2451 0 : match_vrf = strtoul(string, NULL, 0);
2452 0 : if (errno)
2453 0 : return -errno;
2454 :
2455 0 : return 0;
2456 : }
2457 :
2458 : static int
2459 0 : flow_set_proto(char *string)
2460 : {
2461 0 : if (!strlen(string))
2462 0 : return -EINVAL;
2463 :
2464 0 : if (!strncmp(string, "tcp", strlen("tcp"))) {
2465 0 : match_proto = VR_IP_PROTO_TCP;
2466 0 : } else if (!strncmp(string, "udp", strlen("udp"))) {
2467 0 : match_proto = VR_IP_PROTO_UDP;
2468 0 : } else if (!strncmp(string, "icmp6", strlen("icmp6"))) {
2469 0 : match_proto = VR_IP_PROTO_ICMP6;
2470 0 : } else if (!strncmp(string, "icmp", strlen("icmp"))) {
2471 0 : match_proto = VR_IP_PROTO_ICMP;
2472 0 : } else if (!strncmp(string, "sctp", strlen("sctp"))) {
2473 0 : match_proto = VR_IP_PROTO_SCTP;
2474 : } else {
2475 0 : printf("Unsupported protocol \"%s\"\n", string);
2476 0 : return -EINVAL;
2477 : }
2478 :
2479 0 : return 0;
2480 : }
2481 :
2482 : static int
2483 0 : flow_set_match(char *match_string)
2484 : {
2485 0 : int ret = 0;
2486 0 : unsigned int length = strlen(match_string), token_length;
2487 0 : char *token, *string = match_string;
2488 :
2489 : do {
2490 0 : token = vr_extract_token(match_string, '&');
2491 0 : if (token) {
2492 0 : token_length = strlen(token) + 1;
2493 0 : if (!strncmp(token, "proto", strlen("proto"))) {
2494 0 : ret = flow_set_proto(token + strlen("proto") + 1);
2495 0 : } else if (!strncmp(token, "vrf", strlen("vrf"))) {
2496 0 : ret = flow_set_vrf(token + strlen("vrf") + 1);
2497 0 : ret = flow_set_vrf(token + strlen("vrf") + 1);
2498 : } else {
2499 0 : ret = flow_set_ip(token);
2500 : }
2501 0 : match_string = token + token_length;
2502 : }
2503 0 : } while (!ret && token && ((match_string - string) < length));
2504 :
2505 0 : return ret;
2506 : }
2507 :
2508 : static void
2509 22 : parse_long_opts(int opt_flow_index, char *opt_arg)
2510 : {
2511 22 : errno = 0;
2512 22 : switch (opt_flow_index) {
2513 0 : case DVRF_OPT_INDEX:
2514 0 : dvrf = strtoul(opt_arg, NULL, 0);
2515 0 : if (errno)
2516 0 : Usage();
2517 0 : break;
2518 :
2519 9 : case GET_OPT_INDEX:
2520 9 : flow_index = strtoul(opt_arg, NULL, 0);
2521 9 : if (errno)
2522 0 : Usage();
2523 :
2524 9 : flow_cmd = 'g';
2525 9 : break;
2526 :
2527 0 : case MIRROR_OPT_INDEX:
2528 0 : mirror = strtoul(opt_arg, NULL, 0);
2529 0 : if (errno)
2530 0 : Usage();
2531 0 : break;
2532 :
2533 0 : case MATCH_OPT_INDEX:
2534 0 : if (flow_set_match(opt_arg))
2535 0 : exit(-EINVAL);
2536 0 : list = 1;
2537 0 : break;
2538 :
2539 0 : case SHOW_EVICTED_OPT_INDEX:
2540 0 : break;
2541 :
2542 0 : case FORCE_EVICT_OPT_INDEX:
2543 0 : flow_index = strtoul(opt_arg, NULL, 0);
2544 0 : if (errno)
2545 0 : Usage();
2546 :
2547 0 : flow_cmd = 'e';
2548 0 : break;
2549 :
2550 13 : case SOCK_DIR_OPT_INDEX:
2551 13 : vr_socket_dir = opt_arg;
2552 13 : break;
2553 :
2554 0 : case HELP_OPT_INDEX:
2555 : default:
2556 0 : Usage();
2557 : }
2558 :
2559 22 : return;
2560 : }
2561 :
2562 : int
2563 13 : main(int argc, char *argv[])
2564 : {
2565 : char opt;
2566 : int ret;
2567 : int option_index;
2568 :
2569 13 : flow_fill_nl_callbacks();
2570 :
2571 39 : while ((opt = getopt_long(argc, argv, "d:f:g:i:e:p:u:b:lrsF",
2572 39 : long_options, &option_index)) >= 0) {
2573 26 : switch (opt) {
2574 0 : case 'f':
2575 : case 'g':
2576 : case 'd':
2577 : case 'i':
2578 : case 'e':
2579 0 : flow_cmd = opt;
2580 0 : flow_index = strtoul(optarg, NULL, 0);
2581 0 : break;
2582 :
2583 4 : case 'l':
2584 4 : list = 1;
2585 4 : break;
2586 :
2587 0 : case 'r':
2588 0 : rate = 1;
2589 0 : break;
2590 :
2591 0 : case 's':
2592 0 : stats = 1;
2593 0 : break;
2594 :
2595 0 : case 'F':
2596 0 : flush = 1;
2597 0 : break;
2598 :
2599 0 : case 'p':
2600 0 : perf = strtoul(optarg, NULL, 0);
2601 0 : if (perf > MAX_FLOWS) {
2602 0 : printf("Invalid perf count %d. Max value %d\n", perf,
2603 : MAX_FLOWS);
2604 0 : exit(-1);
2605 : }
2606 0 : break;
2607 :
2608 0 : case 'b' :
2609 0 : bunch = strtoul(optarg, NULL, 0);
2610 0 : if (bunch < 1) {
2611 0 : bunch = 1;
2612 : }
2613 0 : if (bunch > MAX_FLOW_NL_MSG_BUNCH) {
2614 0 : printf("Max NETLINK messages in a bunch cannot exceed %u.\n",
2615 : MAX_FLOW_NL_MSG_BUNCH);
2616 0 : bunch = MAX_FLOW_NL_MSG_BUNCH;
2617 : }
2618 0 : break;
2619 0 : case 'u':
2620 0 : sock_dir_set = 1;
2621 0 : parse_long_opts(SOCK_DIR_OPT_INDEX, optarg);
2622 0 : break;
2623 :
2624 22 : case 0:
2625 22 : parse_long_opts(option_index, optarg);
2626 22 : break;
2627 :
2628 0 : default:
2629 0 : Usage();
2630 : }
2631 : }
2632 :
2633 13 : validate_options();
2634 :
2635 13 : ret = flow_table_setup();
2636 13 : if (ret < 0)
2637 0 : return ret;
2638 :
2639 13 : ret = flow_table_get();
2640 13 : if (ret < 0)
2641 0 : return ret;
2642 :
2643 13 : if (list) {
2644 4 : flow_list();
2645 9 : } else if (rate) {
2646 0 : flow_rate();
2647 9 : } else if (stats) {
2648 0 : flow_stats();
2649 9 : } else if (perf) {
2650 0 : run_perf();
2651 9 : } else if (flush) {
2652 0 : run_flush();
2653 : } else {
2654 9 : if (flow_index >= main_table.ft_num_entries) {
2655 0 : printf("Flow index %lu is greater than available indices (%u)\n",
2656 0 : flow_index, main_table.ft_num_entries - 1);
2657 0 : return -1;
2658 : }
2659 :
2660 9 : flow_do_op(flow_index, flow_cmd);
2661 : }
2662 :
2663 13 : return 0;
2664 : }
|