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

Generated by: LCOV version 1.14