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