LCOV - code coverage report
Current view: top level - root/contrail/vrouter/utils - flow.c (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 538 1576 34.1 %
Date: 2026-11-09 02:10:49 Functions: 38 60 63.3 %
Legend: Lines: hit not hit

          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             : }

Generated by: LCOV version 1.14