LCOV - code coverage report
Current view: top level - root/contrail/vrouter/dp-core - vr_flow.c (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 1146 1632 70.2 %
Date: 2026-11-09 02:10:49 Functions: 90 101 89.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * vr_flow.c -- flow handling
       3             :  *
       4             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       5             :  * Copyright Contributors to the OpenSDN project
       6             :  */
       7             : #include <vr_os.h>
       8             : #include <vr_types.h>
       9             : #include <vrouter.h>
      10             : #include <vr_packet.h>
      11             : #include <vr_htable.h>
      12             : #include <vr_flow.h>
      13             : #include <vr_mirror.h>
      14             : #include "vr_interface.h"
      15             : #include "vr_sandesh.h"
      16             : #include "vr_message.h"
      17             : #include "vr_btable.h"
      18             : #include "vr_fragment.h"
      19             : #include "vr_datapath.h"
      20             : #include "vr_hash.h"
      21             : #include "vr_ip_mtrie.h"
      22             : #include "vr_bridge.h"
      23             : #include "vr_vrf_table.h"
      24             : #include "vr_nexthop.h"
      25             : 
      26             : #include "vr_offloads_dp.h"
      27             : 
      28             : #define VR_NUM_FLOW_TABLES          1
      29             : 
      30             : #define VR_NUM_OFLOW_TABLES         1
      31             : 
      32             : #define VR_DEF_MAX_FLOW_TABLE_HOLD_COUNT 8192
      33             : 
      34             : unsigned int vr_flow_entries = VR_DEF_FLOW_ENTRIES;
      35             : unsigned int vr_oflow_entries = 0;
      36             : /*
      37             :  * Knob to unconditionally close flow on TCP RST;
      38             :  * If this knob is set, the flow would be closed
      39             :  * on receiving a TCP RST without doing any seqnum
      40             :  * validation (for backward compatibility with older
      41             :  * implementation);
      42             :  * If this knob is off, TCP RST seqnum validation
      43             :  * as per RFC 5961 sec 3.2 will be done. If the
      44             :  * validation fails, the RST will be ignored.
      45             :  * By default the knob is off;
      46             :  */
      47             : unsigned int vr_uncond_close_flow_on_tcp_rst = 0;
      48             : 
      49             : /*
      50             :  * host can provide its own memory . Point in case is the DPDK. In DPDK,
      51             :  * we allocate the table from hugepages and just ask the flow module to
      52             :  * use those tables
      53             :  */
      54             : void *vr_flow_table = NULL;
      55             : void *vr_oflow_table = NULL;
      56             : /*
      57             :  * The flow table memory can also be a file that could be mapped. The path
      58             :  * is set by somebody and passed to agent for it to map
      59             :  */
      60             : unsigned char *vr_flow_path;
      61             : unsigned int vr_flow_hold_limit = VR_DEF_MAX_FLOW_TABLE_HOLD_COUNT;
      62             : 
      63             : #if defined(__linux__) && defined(__KERNEL__)
      64             : extern short vr_flow_major;
      65             : #endif
      66             : 
      67             : void vr_flow_defer_cb(struct vrouter *router, void *arg);
      68             : 
      69             : uint32_t vr_hashrnd = 0;
      70             : int hashrnd_inited = 0;
      71             : 
      72         109 : static struct vr_flow_entry *vr_flow_bucket_first_entry(struct vrouter *router, struct vr_flow *key) {
      73         109 :     return (struct vr_flow_entry*)
      74         109 :         vr_htable_get_bucket(router->vr_flow_table, key, key->flow_key_len);
      75             : }
      76             : 
      77             : /*
      78             :  * The vr_flow_bucket_lock and vr_flow_bucket_unlock callbacks may not be
      79             :  * implemented for all instances of host_os. Those callback are needed only for
      80             :  * implementations that require strict race condition controll for
      81             :  * hardware offloading (like DPDK).
      82             :  * Those helper functions call the locks only when they are available.
      83             :  */
      84         109 : static void vr_flow_bucket_may_lock(struct vr_flow_entry *fe) {
      85         109 :     if (vr_flow_bucket_lock && vr_flow_bucket_unlock)
      86         109 :         vr_flow_bucket_lock(fe);
      87         109 : }
      88             : 
      89         109 : static void vr_flow_bucket_may_unlock(struct vr_flow_entry *fe) {
      90         109 :     if (vr_flow_bucket_lock && vr_flow_bucket_unlock)
      91         109 :         vr_flow_bucket_unlock(fe);
      92         109 : }
      93             : 
      94             : static void vr_flush_entry(struct vrouter *, struct vr_flow_entry *,
      95             :         struct vr_flow_md *, struct vr_forwarding_md *);
      96             : static void __vr_flow_flush_hold_queue(struct vrouter *, struct vr_flow_entry *,
      97             :         struct vr_forwarding_md *, struct vr_flow_queue *);
      98             : static void vr_flow_set_forwarding_md(struct vrouter *, struct vr_flow_entry *,
      99             :         unsigned int, struct vr_forwarding_md *);
     100             : static int
     101             : __vr_flow_schedule_transition(struct vrouter *, struct vr_flow_entry *,
     102             :         unsigned int, unsigned short);
     103             : static bool vr_flow_is_fat_flow(struct vrouter *, struct vr_packet *,
     104             :         struct vr_flow_entry *);
     105             : 
     106             : struct vr_flow_entry *vr_find_flow(struct vrouter *, struct vr_flow *,
     107             :         uint8_t, unsigned int *);
     108             : unsigned int vr_trap_flow(struct vrouter *, struct vr_flow_entry *,
     109             :         struct vr_packet *, unsigned int, struct vr_flow_stats *,
     110             :         struct vr_packet_node *);
     111             : extern struct vr_nexthop *vr_inet_ip_lookup(unsigned short, uint32_t);
     112             : extern struct vr_nexthop *vr_inet6_ip_lookup(unsigned short, uint8_t *);
     113             : 
     114             : bool
     115           1 : vr_valid_link_local_port(struct vrouter *router, int family,
     116             :                          int proto, int port)
     117             : {
     118             :     unsigned char data;
     119             :     unsigned int tmp;
     120             : 
     121           1 :     if (!router->vr_link_local_ports)
     122           0 :         return false;
     123             : 
     124           1 :     if ((family != AF_INET) ||
     125           1 :         ((proto != VR_IP_PROTO_TCP) && (proto != VR_IP_PROTO_UDP) &&
     126             :          (proto != VR_IP_PROTO_ICMP)))
     127           0 :         return false;
     128             : 
     129           1 :     if ((port < VR_DYNAMIC_PORT_START) || (port > VR_DYNAMIC_PORT_END))
     130           0 :         return false;
     131             : 
     132           1 :     tmp = port - VR_DYNAMIC_PORT_START;
     133           1 :     if (proto == VR_IP_PROTO_UDP)
     134           1 :         tmp += (router->vr_link_local_ports_size * 8 / VR_LL_RP_MAX);
     135           1 :     if (proto == VR_IP_PROTO_ICMP)
     136           0 :         tmp += (router->vr_link_local_ports_size * 8 * VR_LL_RP_ICMP_INDEX /
     137             :                                                        VR_LL_RP_MAX);
     138             : 
     139           1 :     data = router->vr_link_local_ports[(tmp / 8)];
     140           1 :     if (data & (1 << (tmp % 8)))
     141           1 :         return true;
     142             : 
     143           0 :     return false;
     144             : }
     145             : 
     146             : static void
     147           3 : vr_clear_link_local_port(struct vrouter *router, int family,
     148             :                        int proto, int port)
     149             : {
     150             :     unsigned char *data;
     151             :     unsigned int tmp;
     152             : 
     153           3 :     if (!router->vr_link_local_ports)
     154           0 :         return;
     155             : 
     156           3 :     if ((family != AF_INET) ||
     157           3 :         ((proto != VR_IP_PROTO_TCP) && (proto != VR_IP_PROTO_UDP) &&
     158             :          (proto != VR_IP_PROTO_ICMP)))
     159           0 :         return;
     160             : 
     161           3 :     if ((port < VR_DYNAMIC_PORT_START) || (port > VR_DYNAMIC_PORT_END))
     162           0 :         return;
     163             : 
     164           3 :     tmp = port - VR_DYNAMIC_PORT_START;
     165           3 :     if (proto == VR_IP_PROTO_UDP)
     166           2 :         tmp += (router->vr_link_local_ports_size * 8 / VR_LL_RP_MAX);
     167           3 :     if (proto == VR_IP_PROTO_ICMP)
     168           1 :         tmp += ((router->vr_link_local_ports_size * 8 * VR_LL_RP_ICMP_INDEX)/
     169             :                                                         VR_LL_RP_MAX);
     170             : 
     171           3 :     data = &router->vr_link_local_ports[(tmp / 8)];
     172           3 :     *data &= (~(1 << (tmp % 8)));
     173             : 
     174           3 :     return;
     175             : }
     176             : 
     177             : static void
     178           2 : vr_set_link_local_port(struct vrouter *router, int family,
     179             :                        int proto, int port)
     180             : {
     181             :     unsigned char *data;
     182             :     unsigned int tmp;
     183             : 
     184           2 :     if (!router->vr_link_local_ports)
     185           0 :         return;
     186             : 
     187           2 :     if ((family != AF_INET) ||
     188           2 :         ((proto != VR_IP_PROTO_TCP) && (proto != VR_IP_PROTO_UDP) &&
     189             :          (proto != VR_IP_PROTO_ICMP)))
     190           0 :         return;
     191             : 
     192           2 :     if ((port < VR_DYNAMIC_PORT_START) || (port > VR_DYNAMIC_PORT_END))
     193           0 :         return;
     194             : 
     195           2 :     tmp = port - VR_DYNAMIC_PORT_START;
     196           2 :     if (proto == VR_IP_PROTO_UDP)
     197           1 :         tmp += (router->vr_link_local_ports_size * 8 / VR_LL_RP_MAX);
     198           2 :     if (proto == VR_IP_PROTO_ICMP)
     199           1 :         tmp += ((router->vr_link_local_ports_size * 8 * VR_LL_RP_ICMP_INDEX)/
     200             :                                                         VR_LL_RP_MAX);
     201             : 
     202           2 :     data = &router->vr_link_local_ports[tmp / 8];
     203           2 :     *data |= (1 << (tmp % 8));
     204             : 
     205           2 :     return;
     206             : }
     207             : 
     208             : static void
     209         215 : vr_flow_reset_mirror(struct vrouter *router, struct vr_flow_entry *fe,
     210             :                                                             unsigned int index)
     211             : {
     212         215 :     if (fe->fe_flags & VR_FLOW_FLAG_MIRROR) {
     213           2 :         fe->fe_mirror_id = VR_MAX_MIRROR_INDICES;
     214           2 :         fe->fe_sec_mirror_id = VR_MAX_MIRROR_INDICES;
     215           2 :         if (fe->fe_mme) {
     216           0 :             vr_mirror_meta_entry_del(router, fe->fe_mme);
     217           0 :             fe->fe_mme = NULL;
     218           0 :             vr_offload_flow_meta_data_set(index, 0, 0, 0);
     219             :         }
     220             :     }
     221         215 :     fe->fe_flags &= ~VR_FLOW_FLAG_MIRROR;
     222         215 :     fe->fe_mirror_id = VR_MAX_MIRROR_INDICES;
     223         215 :     fe->fe_sec_mirror_id = VR_MAX_MIRROR_INDICES;
     224             : 
     225         215 :     return;
     226             : }
     227             : 
     228             : static void
     229         109 : vr_init_flow_entry(struct vr_flow_entry *fe)
     230             : {
     231         109 :     fe->fe_rflow = -1;
     232         109 :     fe->fe_mirror_id = VR_MAX_MIRROR_INDICES;
     233         109 :     fe->fe_sec_mirror_id = VR_MAX_MIRROR_INDICES;
     234         109 :     fe->fe_ecmp_nh_index = -1;
     235             : 
     236         109 :     return;
     237             : }
     238             : 
     239             : 
     240             : static void
     241         117 : __vr_flow_reset_entry(struct vrouter *router, struct vr_flow_entry *fe)
     242             : {
     243         117 :     if (fe->fe_hold_list) {
     244           0 :         vr_printf("vrouter: Potential memory leak @ %s:%d\n",
     245             :                 __FILE__, __LINE__);
     246             :     }
     247         117 :     fe->fe_hold_list = NULL;
     248         117 :     fe->fe_key.flow_key_len = 0;
     249             : 
     250         117 :     (void)vr_offload_flow_del(fe);
     251             : 
     252         117 :     vr_flow_reset_mirror(router, fe, fe->fe_hentry.hentry_index);
     253         117 :     fe->fe_ecmp_nh_index = -1;
     254         117 :     fe->fe_src_nh_index = NH_DISCARD_ID;
     255         117 :     fe->fe_rflow = -1;
     256         117 :     fe->fe_action = VR_FLOW_ACTION_DROP;
     257         117 :     fe->fe_udp_src_port = 0;
     258         117 :     fe->fe_tcp_flags = 0;
     259         117 :     fe->fe_flags &=
     260             :         (VR_FLOW_FLAG_ACTIVE | VR_FLOW_FLAG_EVICTED |
     261             :          VR_FLOW_FLAG_NEW_FLOW | VR_FLOW_FLAG_DELETE_MARKED);
     262         117 :     fe->fe_flags1 &=
     263             :         ~(VR_FLOW_FLAG1_HBS_LEFT | VR_FLOW_FLAG1_HBS_RIGHT);
     264         117 :     fe->fe_ttl = 0;
     265         117 :     fe->fe_underlay_ecmp_index = -1;
     266         117 :     fe->fe_src_info = 0;
     267             : 
     268         117 :     return;
     269             : }
     270             : 
     271             : static void
     272         109 : vr_flow_reset_entry(struct vrouter *router, struct vr_flow_entry *fe)
     273             : {
     274         109 :     __vr_flow_reset_entry(router, fe);
     275         109 :     memset(&fe->fe_stats, 0, sizeof(fe->fe_stats));
     276         109 :     fe->fe_type = VP_TYPE_NULL;
     277         109 :     fe->fe_flags = 0;
     278             : 
     279         109 :     vr_htable_release_hentry(router->vr_flow_table, &fe->fe_hentry);
     280         109 :     return;
     281             : }
     282             : 
     283             : static void
     284           8 : vr_flow_reset_active_entry(struct vrouter *router, struct vr_flow_entry *fe)
     285             : {
     286           8 :     __vr_flow_reset_entry(router, fe);
     287           8 :     vr_htable_release_hentry(router->vr_flow_table, &fe->fe_hentry);
     288           8 :     return;
     289             : }
     290             : 
     291             : 
     292             : static vr_hentry_key
     293          62 : vr_flow_get_key(vr_htable_t flow_table, vr_hentry_t *entry,
     294             :         unsigned int *key_len)
     295             : {
     296          62 :     struct vr_flow_entry *fe = CONTAINER_OF(fe_hentry,
     297             :                              struct vr_flow_entry, entry);
     298             : 
     299          62 :     if ((fe->fe_flags & VR_FLOW_FLAG_DELETE_MARKED) ||
     300          62 :                     !(fe->fe_flags & VR_FLOW_FLAG_ACTIVE))
     301           0 :         return NULL;
     302             : 
     303          62 :     if (key_len)
     304          62 :         *key_len = fe->fe_key.flow_key_len;
     305             : 
     306          62 :     return &fe->fe_key;
     307             : }
     308             : 
     309             : uint32_t
     310           1 : vr_flow_get_rflow_src_info(struct vrouter *router,
     311             :         struct vr_flow_entry *fe)
     312             : {
     313             :     struct vr_flow_entry *rfe;
     314             : 
     315           1 :     if ((!fe) || !(fe->fe_flags & VR_RFLOW_VALID))
     316           0 :         return (unsigned int)-1;
     317             : 
     318           1 :     rfe = vr_flow_get_entry(router, fe->fe_rflow);
     319           1 :     if (!rfe)
     320           0 :         return (unsigned int)-1;
     321             : 
     322           1 :     return rfe->fe_src_info;
     323             : }
     324             : 
     325             : static inline bool
     326         109 : vr_flow_set_active(struct vr_flow_entry *fe)
     327             : {
     328         109 :     return vr_sync_bool_compare_and_swap_16u(&fe->fe_flags,
     329             :             fe->fe_flags & ~VR_FLOW_FLAG_ACTIVE,
     330             :             VR_FLOW_FLAG_ACTIVE | VR_FLOW_FLAG_NEW_FLOW);
     331             : }
     332             : 
     333             : /*
     334             :  * This api is called to get flow table size
     335             :  * NOTE: This api is also called from agent (via sandesh)
     336             :  *       very early during init even before flow table is
     337             :  *       initialized to calculate huge page table size.
     338             :  *       Hence this api should not use vr_htable structures
     339             :  */
     340             : unsigned int
     341          13 : vr_flow_table_size(struct vrouter *router)
     342             : {
     343             :     // set the overlflow flow table entries
     344          13 :     vr_compute_size_oflow_table();
     345          13 :     return (VR_FLOW_TABLE_SIZE + VR_OFLOW_TABLE_SIZE);
     346             : }
     347             : 
     348             : unsigned int
     349          13 : vr_flow_table_used_oflow_entries(struct vrouter *router)
     350             : {
     351          13 :     return vr_htable_used_oflow_entries(router->vr_flow_table);
     352             : }
     353             : 
     354             : unsigned int
     355          13 : vr_flow_table_used_total_entries(struct vrouter *router)
     356             : {
     357          13 :     return vr_htable_used_total_entries(router->vr_flow_table);
     358             : }
     359             : /*
     360             :  * this is used by the mmap code. mmap sees the whole flow table
     361             :  * (including the overflow table) as one large table. so, given
     362             :  * an offset into that large memory, we should return the correct
     363             :  * virtual address
     364             :  */
     365             : void *
     366           0 : vr_flow_get_va(struct vrouter *router, uint64_t offset)
     367             : {
     368           0 :     return vr_htable_get_address(router->vr_flow_table, offset);
     369             : }
     370             : 
     371             : struct vr_flow_entry *
     372        1236 : vr_flow_get_entry(struct vrouter *router, int index)
     373             : {
     374        1236 :     if (index < 0)
     375         104 :         return NULL;
     376             : 
     377        1132 :     return (struct vr_flow_entry *)
     378        1132 :             vr_htable_get_hentry_by_index(router->vr_flow_table, index);
     379             : }
     380             : 
     381             : static inline void
     382         120 : vr_flow_stop_modify(struct vrouter *router, struct vr_flow_entry *fe)
     383             : {
     384         120 :     if (!fe)
     385           0 :         return;
     386             : 
     387         120 :     (void)vr_sync_and_and_fetch_16u(&fe->fe_flags, ~VR_FLOW_FLAG_MODIFIED);
     388         120 :     return;
     389             : }
     390             : 
     391             : static inline bool
     392         222 : vr_flow_start_modify(struct vrouter *router, struct vr_flow_entry *fe)
     393             : {
     394             :     unsigned short flags;
     395             : 
     396         222 :     flags = fe->fe_flags;
     397         222 :     if (!(flags & (VR_FLOW_FLAG_MODIFIED | VR_FLOW_FLAG_EVICTED |
     398             :                     VR_FLOW_FLAG_NEW_FLOW))) {
     399         218 :         if (vr_sync_bool_compare_and_swap_16u(&fe->fe_flags, flags,
     400             :                     flags | VR_FLOW_FLAG_MODIFIED)) {
     401         218 :             return true;
     402             :         }
     403             :     }
     404             : 
     405           4 :     return false;
     406             : }
     407             : 
     408             : 
     409             : /* Non-static due to RCU callback pointer comparison in vRouter/DPDK */
     410             : static void
     411           2 : vr_flow_flush_hold_queue(struct vrouter *router, struct vr_flow_entry *fe,
     412             :         struct vr_flow_queue *vfq)
     413             : {
     414             :     struct vr_forwarding_md fmd;
     415             : 
     416           2 :     if (vfq) {
     417           2 :         vr_init_forwarding_md(&fmd);
     418           2 :         vr_flow_set_forwarding_md(router, fe, vfq->vfq_index, &fmd);
     419           2 :         __vr_flow_flush_hold_queue(router, fe, &fmd, vfq);
     420             :     }
     421             : 
     422           2 :     return;
     423             : }
     424             : 
     425             : static void
     426           8 : vr_flow_evict_flow(struct vrouter *router, struct vr_flow_entry *fe)
     427             : {
     428             :     unsigned short flags;
     429             : 
     430           8 :     if (!fe)
     431           0 :         return;
     432             : 
     433           8 :     if ((fe->fe_flags & VR_FLOW_FLAG_ACTIVE) &&
     434           8 :             (fe->fe_flags & VR_FLOW_FLAG_EVICT_CANDIDATE)) {
     435           8 :         flags = fe->fe_flags | VR_FLOW_FLAG_ACTIVE |
     436             :             VR_FLOW_FLAG_EVICT_CANDIDATE;
     437           8 :         if (vr_sync_bool_compare_and_swap_16u(&fe->fe_flags, flags,
     438             :                 (flags ^ VR_FLOW_FLAG_EVICT_CANDIDATE) |
     439             :                 VR_FLOW_FLAG_EVICTED)) {
     440           8 :             vr_flow_stop_modify(router, fe);
     441           8 :             vr_flow_reset_active_entry(router, fe);
     442             :         }
     443             :     }
     444             : 
     445           8 :     return;
     446             : }
     447             : 
     448             : void
     449           6 : vr_flow_defer_cb(struct vrouter *router, void *arg)
     450             : {
     451             :     struct vr_defer_data *defer;
     452             :     struct vr_flow_entry *fe, *rfe;
     453             :     struct vr_flow_queue *vfq;
     454             :     struct vr_flow_defer_data *vfdd;
     455             : 
     456           6 :     defer = (struct vr_defer_data *)arg;
     457           6 :     if (!defer)
     458           0 :         return;
     459             : 
     460           6 :     vfdd = (struct vr_flow_defer_data *)defer->vdd_data;
     461           6 :     if (!vfdd)
     462           0 :         return;
     463           6 :     fe = vfdd->vfdd_fe;
     464             : 
     465           6 :     vfq = (struct vr_flow_queue *)vfdd->vfdd_flow_queue;
     466           6 :     if (vfq) {
     467           2 :         vr_flow_flush_hold_queue(router, fe, vfq);
     468           2 :         vr_free(vfq, VR_FLOW_QUEUE_OBJECT);
     469           2 :         vfdd->vfdd_flow_queue = NULL;
     470             :     }
     471             : 
     472           6 :     if (vfdd->vfdd_delete) {
     473           0 :         vr_flow_reset_entry(router, fe);
     474           6 :     } else if (vfdd->vfdd_evict_flow) {
     475           4 :         rfe = vr_flow_get_entry(router, fe->fe_rflow);
     476           4 :         vr_flow_evict_flow(router, fe);
     477           4 :         if (rfe)
     478           4 :             vr_flow_evict_flow(router, rfe);
     479             :     }
     480             : 
     481           6 :     vr_free(vfdd, VR_FLOW_DEFER_DATA_OBJECT);
     482             : 
     483           6 :     return;
     484             : }
     485             : 
     486             : static void
     487           0 : vr_flow_reset_evict(struct vrouter *router, struct vr_flow_entry *fe)
     488             : {
     489             :     unsigned short flags;
     490             : 
     491           0 :     if (!fe)
     492           0 :         return;
     493             : 
     494           0 :     flags = fe->fe_flags;
     495           0 :     if (flags & VR_FLOW_FLAG_EVICT_CANDIDATE) {
     496           0 :         (void)vr_sync_bool_compare_and_swap_16u(&fe->fe_flags, flags,
     497             :                 (flags ^ VR_FLOW_FLAG_EVICT_CANDIDATE));
     498             :     }
     499             : 
     500           0 :     vr_flow_stop_modify(router, fe);
     501             : 
     502           0 :     return;
     503             : }
     504             : 
     505             : static void
     506         318 : vr_flow_defer(struct vr_flow_md *flmd, struct vr_flow_entry *fe)
     507             : {
     508             :     struct vr_flow_entry *rfe;
     509         318 :     struct vr_defer_data *vdd = flmd->flmd_defer_data;
     510             :     struct vr_flow_defer_data *vfdd;
     511             : 
     512         318 :     if (!vdd || !vdd->vdd_data) {
     513         312 :         if (flmd->flmd_flags & VR_FLOW_FLAG_EVICT_CANDIDATE) {
     514           0 :             if (fe->fe_rflow) {
     515           0 :                 rfe = vr_flow_get_entry(flmd->flmd_router, fe->fe_rflow);
     516           0 :                 vr_flow_reset_evict(flmd->flmd_router, rfe);
     517             :             }
     518           0 :             vr_flow_reset_evict(flmd->flmd_router, fe);
     519             :         }
     520             : 
     521         312 :         if (!(flmd->flmd_flags & VR_FLOW_FLAG_ACTIVE)) {
     522          98 :             vr_flow_reset_entry(flmd->flmd_router, fe);
     523             :         }
     524             : 
     525         312 :         return;
     526             :     }
     527             : 
     528           6 :     vfdd = (struct vr_flow_defer_data *)vdd->vdd_data;
     529           6 :     vfdd->vfdd_fe = fe;
     530             : 
     531           6 :     vr_defer(flmd->flmd_router, vr_flow_defer_cb, (void *)vdd);
     532           6 :     flmd->flmd_defer_data = NULL;
     533             : 
     534           6 :     return;
     535             : }
     536             : 
     537             : static struct vr_flow_entry *
     538         109 : vr_flow_table_get_free_entry(struct vrouter *router, struct vr_flow *key,
     539             :         unsigned int *free_index)
     540             : {
     541             :     unsigned short flags;
     542             :     struct vr_flow_entry *fe;
     543             : 
     544             :     fe = (struct vr_flow_entry *)
     545         109 :          vr_htable_find_free_hentry(router->vr_flow_table, key,
     546         109 :                  key->flow_key_len);
     547         109 :     if (fe) {
     548         109 :         flags = fe->fe_flags;
     549         109 :         if (!(flags & VR_FLOW_FLAG_ACTIVE)) {
     550         109 :             if (vr_flow_set_active(fe)) {
     551         109 :                 vr_init_flow_entry(fe);
     552             :             }
     553           0 :         } else if (flags & VR_FLOW_FLAG_EVICTED) {
     554           0 :             fe->fe_flags = ((flags & ~VR_FLOW_FLAG_EVICTED) |
     555             :                      VR_FLOW_FLAG_NEW_FLOW);
     556             :         }
     557             : 
     558         109 :         fe->fe_underlay_ecmp_index = -1;
     559             : 
     560         109 :         fe->fe_gen_id = (fe->fe_gen_id + 1) %
     561             :             (1 << (8 * sizeof(fe->fe_gen_id)));
     562         109 :         *free_index = fe->fe_hentry.hentry_index;
     563             :     }
     564             : 
     565         109 :     return fe;
     566             : }
     567             : 
     568             : 
     569             : static struct vr_flow_entry *
     570         109 : vr_flow_get_free_entry(struct vrouter *router, struct vr_flow *key, uint8_t type,
     571             :         bool need_hold, unsigned int *fe_index)
     572             : {
     573         109 :     struct vr_flow_entry *fe = NULL;
     574             : 
     575         109 :     fe = vr_flow_table_get_free_entry(router, key, fe_index);
     576         109 :     if (fe) {
     577         109 :         if (need_hold) {
     578           5 :             fe->fe_hold_list = vr_zalloc(sizeof(struct vr_flow_queue),
     579             :                     VR_FLOW_QUEUE_OBJECT);
     580           5 :             if (!fe->fe_hold_list) {
     581           0 :                 vr_flow_reset_entry(router, fe);
     582           0 :                 fe = NULL;
     583           0 :                 vr_printf("%s:%d flow reset\n", __func__, __LINE__);
     584           0 :                 return fe;
     585             :             } else {
     586           5 :                 fe->fe_hold_list->vfq_index = *fe_index;
     587             :             }
     588             :         }
     589             : 
     590         109 :         fe->fe_type = type;
     591         109 :         memcpy(&fe->fe_key, key, key->flow_key_len);
     592         109 :         fe->fe_key.flow_key_len = key->flow_key_len;
     593             :     }
     594             : 
     595         109 :     return fe;
     596             : }
     597             : 
     598             : 
     599             : struct vr_flow_entry *
     600         176 : vr_find_flow(struct vrouter *router, struct vr_flow *key,
     601             :         uint8_t type, unsigned int *fe_index)
     602             : {
     603             :     struct vr_flow_entry *fe;
     604             : 
     605         176 :     fe = (struct vr_flow_entry *)vr_htable_find_hentry(router->vr_flow_table,
     606         176 :                                                     key, key->flow_key_len);
     607         176 :     if (fe) {
     608          62 :         if (fe_index)
     609          62 :             *fe_index = fe->fe_hentry.hentry_index;
     610             :     }
     611             : 
     612         176 :     return fe;
     613             : }
     614             : 
     615             : 
     616             : void
     617          28 : vr_flow_fill_pnode(struct vr_packet_node *pnode, struct vr_packet *pkt,
     618             :         struct vr_forwarding_md *fmd)
     619             : {
     620          28 :     struct vr_ip *ip = (struct vr_ip *)pkt_inner_network_header(pkt);
     621             : 
     622             :     /*
     623             :      * we cannot cache nexthop here. to cache, we need to hold reference
     624             :      * to the nexthop. to hold a reference, we will have to hold a lock,
     625             :      * which we cannot. the only known case of misbehavior if we do not
     626             :      * cache is ECMP. when the packet comes from the fabric, the nexthop
     627             :      * actually points to a local composite, whereas a route lookup actually
     628             :      * returns a different nexthop, in which case the ecmp index will return
     629             :      * a bad nexthop. to avoid that, we will cache the label, and reuse it
     630             :      */
     631          28 :     pkt->vp_nh = NULL;
     632             : 
     633          28 :     pnode->pl_flags = 0;
     634          28 :     pnode->pl_vif_idx = pkt->vp_if->vif_idx;
     635             : 
     636          28 :     if (fmd) {
     637          28 :         pnode->pl_outer_src_ip = fmd->fmd_outer_src_ip;
     638          28 :         pnode->pl_label = fmd->fmd_label;
     639          28 :         if (vr_fmd_label_is_vxlan_id(fmd))
     640           0 :             pnode->pl_flags |= PN_FLAG_LABEL_IS_VXLAN_ID;
     641          28 :         if (fmd->fmd_to_me)
     642           0 :             pnode->pl_flags |= PN_FLAG_TO_ME;
     643             :     }
     644             : 
     645          28 :     if (ip) {
     646          28 :         if (vr_ip_is_ip4(ip)) {
     647             :             /*
     648             :              * Source IP & Dest IP can change while the packet is in the queue
     649             :              * (NAT). For e.g.: when the cloned head of a fragment is enqueued
     650             :              * to the assembler and subsequently dequeued by the assembler, the
     651             :              * original packet might have undergone a NAT, resulting in wrong
     652             :              * hash and thus a wrong search for other fragments of the packet.
     653             :              * Hence, store them here for others interested in the original IPs
     654             :              */
     655          28 :             pnode->pl_inner_src_ip = ip->ip_saddr;
     656          28 :             pnode->pl_inner_dst_ip = ip->ip_daddr;
     657          28 :             if (vr_ip_fragment_head(ip))
     658           5 :                 pnode->pl_flags |= PN_FLAG_FRAGMENT_HEAD;
     659           0 :         } else if (vr_ip_is_ip6(ip)) {
     660           0 :             if (vr_ip6_fragment_head((struct vr_ip6 *)ip))
     661           0 :                 pnode->pl_flags |= PN_FLAG_FRAGMENT_HEAD;
     662             :         }
     663             :     }
     664             : 
     665          28 :     pnode->pl_dscp = fmd->fmd_dscp;
     666          28 :     pnode->pl_dotonep = fmd->fmd_dotonep;
     667          28 :     pnode->pl_vrf = fmd->fmd_dvrf;
     668          28 :     pnode->pl_vlan = fmd->fmd_vlan;
     669          28 :     pnode->pl_mirror_vlan = fmd->fmd_mirror_data;
     670             : 
     671          28 :     vr_sync_synchronize();
     672          28 :     pnode->pl_packet = pkt;
     673             : 
     674          28 :     return;
     675             : }
     676             : 
     677             : static int
     678           7 : vr_enqueue_flow(struct vrouter *router, struct vr_flow_entry *fe,
     679             :         struct vr_packet *pkt, unsigned int index,
     680             :         struct vr_flow_stats *stats, struct vr_forwarding_md *fmd)
     681             : {
     682           7 :     int ret = 0;
     683             :     unsigned int i;
     684           7 :     unsigned short drop_reason = 0;
     685           7 :     struct vr_flow_queue *vfq = fe->fe_hold_list;
     686             :     struct vr_packet_node *pnode;
     687             : 
     688           7 :     if (!vfq) {
     689           0 :         drop_reason = VP_DROP_FLOW_UNUSABLE;
     690           0 :         PKT_LOG(drop_reason, pkt, 0, VR_FLOW_C, __LINE__);
     691           0 :         goto drop;
     692             :     }
     693             : 
     694           7 :     i = vr_sync_fetch_and_add_32u(&vfq->vfq_entries, 1);
     695           7 :     if (i >= VR_MAX_FLOW_QUEUE_ENTRIES) {
     696           0 :         drop_reason = VP_DROP_FLOW_QUEUE_LIMIT_EXCEEDED;
     697           0 :         PKT_LOG(drop_reason, pkt, 0, VR_FLOW_C, __LINE__);
     698           0 :         goto drop;
     699             :     }
     700             : 
     701           7 :     pnode = &vfq->vfq_pnodes[i];
     702           7 :     vr_flow_fill_pnode(pnode, pkt, fmd);
     703           7 :     if (!i)
     704           5 :         ret = vr_trap_flow(router, fe, pkt, index, stats, pnode);
     705             : 
     706           7 :     return ret;
     707           0 : drop:
     708           0 :     vr_pfree(pkt, drop_reason);
     709           0 :     return 0;
     710             : }
     711             : 
     712             : static flow_result_t
     713           6 : vr_flow_nat(struct vr_flow_entry *fe,
     714             :         struct vr_packet *pkt, struct vr_forwarding_md *fmd)
     715             : {
     716           6 :     if (pkt->vp_type == VP_TYPE_IP)
     717           4 :         return vr_inet_flow_nat(fe, pkt, fmd);
     718             : 
     719           2 :     if (pkt->vp_type == VP_TYPE_IP6)
     720           2 :         return vr_inet6_flow_nat(fe, pkt, fmd);
     721             : 
     722           0 :     PKT_LOG(VP_DROP_FLOW_ACTION_INVALID, pkt, 0, VR_FLOW_C, __LINE__);
     723           0 :     vr_pfree(pkt, VP_DROP_FLOW_ACTION_INVALID);
     724           0 :     return FLOW_CONSUMED;
     725             : }
     726             : 
     727             : static void
     728         395 : vr_flow_set_forwarding_md(struct vrouter *router, struct vr_flow_entry *fe,
     729             :         unsigned int index, struct vr_forwarding_md *md)
     730             : {
     731             :     struct vr_flow_entry *rfe;
     732             : 
     733         395 :     md->fmd_flow_index = index;
     734         395 :     md->fmd_ecmp_nh_index = fe->fe_ecmp_nh_index;
     735         395 :     md->fmd_underlay_ecmp_index = fe->fe_underlay_ecmp_index;
     736         395 :     md->fmd_udp_src_port = fe->fe_udp_src_port;
     737         395 :     if (fe->fe_flags & VR_RFLOW_VALID) {
     738         320 :         rfe = vr_flow_get_entry(router, fe->fe_rflow);
     739         320 :         if (rfe)
     740         275 :             md->fmd_ecmp_src_nh_index = rfe->fe_ecmp_nh_index;
     741             :     }
     742             : 
     743         395 :     return;
     744             : }
     745             : 
     746             : static bool
     747           8 : __vr_flow_mark_evict(struct vrouter *router, struct vr_flow_entry *fe)
     748             : {
     749             :     unsigned short flags;
     750             : 
     751           8 :     flags = fe->fe_flags;
     752           8 :     if (flags & VR_FLOW_FLAG_ACTIVE) {
     753           8 :         flags = vr_sync_fetch_and_or_16u(&fe->fe_flags,
     754             :                 VR_FLOW_FLAG_EVICT_CANDIDATE);
     755           8 :         if (!(flags & VR_FLOW_FLAG_EVICT_CANDIDATE)) {
     756           8 :             return true;
     757             :         }
     758             :     }
     759             : 
     760           0 :     return false;
     761             : }
     762             : 
     763             : static void
     764           8 : vr_flow_mark_evict(struct vrouter *router, struct vr_flow_entry *fe,
     765             :         unsigned int index)
     766             : {
     767           8 :     bool evict_forward_flow = true;
     768             : 
     769           8 :     struct vr_flow_entry *rfe = NULL;
     770             : 
     771             :     /* start modifying the entry */
     772           8 :     if (!vr_flow_start_modify(router, fe)) {
     773           4 :         return;
     774             :     }
     775             : 
     776           4 :     if (fe->fe_rflow >= 0) {
     777           4 :         rfe = vr_flow_get_entry(router, fe->fe_rflow);
     778           4 :         if (rfe) {
     779           4 :             evict_forward_flow = false;
     780           4 :             if (rfe->fe_tcp_flags & VR_FLOW_TCP_DEAD) {
     781           4 :                 if (!vr_flow_start_modify(router, rfe)) {
     782             :                     /* no modification. hence...*/
     783           0 :                     rfe = NULL;
     784             :                 } else {
     785             :                     /* we do not want hold flows to be evicted, just yet */
     786           4 :                     if (((rfe->fe_rflow == index) || (rfe->fe_rflow < 0)) &&
     787           4 :                             (rfe->fe_action != VR_FLOW_ACTION_HOLD)) {
     788           4 :                         evict_forward_flow = __vr_flow_mark_evict(router, rfe);
     789             :                     }
     790             :                 }
     791             :             } else {
     792             :                 /* no modification. hence...*/
     793           0 :                 rfe = NULL;
     794             :             }
     795             :         }
     796             :     }
     797             : 
     798             :     /*
     799             :      * presence of rfe means that we might need to reset the evict bit
     800             :      * or at the minimum reset the modified bit under failure conditions
     801             :      *
     802             :      * CEM-18166: In case rfe has already been deleted, under special
     803             :      * circumstances, fe might still have fe_rflow pointing to it.
     804             :      * In this case (and other cases where rfe is not active anymore),
     805             :      * evict_forward_flow will remain true, which makes sense because we still
     806             :      * want to evict this flow, because of TCP FIN or RST.
     807             :      */
     808           4 :     if (evict_forward_flow) {
     809           4 :         if (__vr_flow_mark_evict(router, fe)) {
     810           4 :             if (!__vr_flow_schedule_transition(router, fe,
     811           4 :                         index, fe->fe_flags)) {
     812           4 :                 return;
     813             :             } else {
     814           0 :                 goto reset_evict;
     815             :             }
     816             :         }
     817             :     }
     818             : 
     819             :     /* stop modifying the forward and the reverse */
     820           0 :     if (rfe)
     821           0 :         vr_flow_stop_modify(router, rfe);
     822           0 :     vr_flow_stop_modify(router, fe);
     823             : 
     824           0 :     return;
     825             : 
     826           0 : reset_evict:
     827           0 :     if (rfe)
     828           0 :         vr_flow_reset_evict(router, rfe);
     829           0 :     vr_flow_reset_evict(router, fe);
     830             : 
     831           0 :     return;
     832             : }
     833             : 
     834             : int16_t
     835          21 : vr_flow_get_qos(struct vrouter *router, struct vr_packet *pkt,
     836             :         struct vr_forwarding_md *fmd)
     837             : {
     838             :     struct vr_flow_entry *fe;
     839             : 
     840          21 :     if (fmd->fmd_flow_index >= 0) {
     841          21 :         fe = vr_flow_get_entry(router, fmd->fmd_flow_index);
     842          21 :         if (fe)
     843          21 :             return fe->fe_qos_id;
     844             :     }
     845             : 
     846           0 :     return -1;
     847             : }
     848             : 
     849             : static int
     850           0 : vr_rflow_update_ecmp_index(struct vrouter *router, struct vr_flow_entry *fe,
     851             :                     unsigned int new_ecmp_index, struct vr_forwarding_md *fmd)
     852             : {
     853             :     struct vr_flow_entry *rfe;
     854             : 
     855           0 :     if (new_ecmp_index == -1)
     856           0 :         return -1;
     857             : 
     858           0 :     rfe = vr_flow_get_entry(router, fe->fe_rflow);
     859           0 :     if ((!rfe) || (rfe->fe_flags & VR_FLOW_FLAG_DELETE_MARKED))
     860           0 :         return -1;
     861             : 
     862           0 :     rfe->fe_ecmp_nh_index = new_ecmp_index;
     863             : 
     864             :     /* Update hardware reverse flow. */
     865           0 :     (void)vr_offload_flow_set(rfe, fe->fe_rflow, NULL);
     866             : 
     867           0 :     fmd->fmd_ecmp_src_nh_index = new_ecmp_index;
     868             : 
     869           0 :     return 0;
     870             : }
     871             : 
     872             : 
     873             : int
     874           1 : vr_flow_update_ecmp_index(struct vrouter *router, struct vr_flow_entry *fe,
     875             :                        unsigned int new_ecmp_index, struct vr_forwarding_md *fmd)
     876             : {
     877             : 
     878           1 :     if (new_ecmp_index == -1)
     879           0 :         return -1;
     880             : 
     881           1 :     if ((!fe) || (fe->fe_flags & VR_FLOW_FLAG_DELETE_MARKED))
     882           0 :         return -1;
     883             : 
     884             :     /* If RPF verification is manipulating this flow, let it succeed */
     885           1 :     (void)vr_sync_bool_compare_and_swap_8s(&fe->fe_ecmp_nh_index,
     886             :                                 fmd->fmd_ecmp_nh_index, new_ecmp_index);
     887             : 
     888           1 :     fmd->fmd_ecmp_nh_index = fe->fe_ecmp_nh_index;
     889             : 
     890           1 :     return 0;
     891             : }
     892             : 
     893             : static flow_result_t
     894          61 : vr_flow_action_default(struct vrouter *router, struct vr_flow_entry *fe,
     895             :         unsigned int index, struct vr_packet *pkt,
     896             :         struct vr_forwarding_md *fmd)
     897             : {
     898          61 :     unsigned int ip_inc_diff_cksum = 0;
     899             :     struct vr_ip *ip;
     900          61 :     flow_result_t result = FLOW_CONSUMED;
     901             : 
     902             :     struct vr_forwarding_md mirror_fmd;
     903             : 
     904          61 :     fmd->fmd_dvrf = fe->fe_vrf;
     905             :     /*
     906             :      * for now, we will not use dvrf if VRFT is set, because the RPF
     907             :      * check needs to happen in the source vrf
     908             :      */
     909             : 
     910          61 :     if (fe->fe_flags & VR_FLOW_FLAG_VRFT) {
     911           5 :         if (fmd->fmd_dvrf != fe->fe_dvrf) {
     912           1 :             fmd->fmd_dvrf = fe->fe_dvrf;
     913           1 :             fmd->fmd_to_me = 1;
     914             :         }
     915             :     }
     916             : 
     917          61 :     if (fe->fe_flags & VR_FLOW_FLAG_MIRROR) {
     918           2 :         if (fe->fe_mirror_id < VR_MAX_MIRROR_INDICES) {
     919           2 :             mirror_fmd = *fmd;
     920           2 :             mirror_fmd.fmd_ecmp_nh_index = -1;
     921           2 :             mirror_fmd.fmd_underlay_ecmp_index = -1;
     922           2 :             vr_mirror(router, fe->fe_mirror_id, pkt, &mirror_fmd,
     923             :                     MIRROR_TYPE_ACL);
     924           2 :             fmd->fmd_mirror_data = mirror_fmd.fmd_mirror_data;
     925             :         }
     926             : 
     927           2 :         if (fe->fe_sec_mirror_id < VR_MAX_MIRROR_INDICES) {
     928           0 :             mirror_fmd = *fmd;
     929           0 :             mirror_fmd.fmd_ecmp_nh_index = -1;
     930           0 :             mirror_fmd.fmd_underlay_ecmp_index = -1;
     931           0 :             vr_mirror(router, fe->fe_sec_mirror_id, pkt, &mirror_fmd,
     932             :                     MIRROR_TYPE_ACL);
     933           0 :             fmd->fmd_mirror_data = mirror_fmd.fmd_mirror_data;
     934             :         }
     935             :     }
     936             : 
     937          61 :     switch (fe->fe_action) {
     938           0 :     case VR_FLOW_ACTION_DROP:
     939           0 :         PKT_LOG(VP_DROP_FLOW_ACTION_DROP, pkt, 0, VR_FLOW_C, __LINE__);
     940           0 :         vr_pfree(pkt, VP_DROP_FLOW_ACTION_DROP);
     941           0 :         result = FLOW_CONSUMED;
     942           0 :         break;
     943             : 
     944          55 :     case VR_FLOW_ACTION_FORWARD:
     945          55 :         result = FLOW_FORWARD;
     946          55 :         break;
     947             : 
     948           6 :     case VR_FLOW_ACTION_NAT:
     949           6 :         result = vr_flow_nat(fe, pkt, fmd);
     950           6 :         break;
     951             : 
     952           0 :     default:
     953           0 :         PKT_LOG(VP_DROP_FLOW_ACTION_INVALID, pkt, 0, VR_FLOW_C, __LINE__);
     954           0 :         vr_pfree(pkt, VP_DROP_FLOW_ACTION_INVALID);
     955           0 :         result = FLOW_CONSUMED;
     956           0 :         break;
     957             :     }
     958             : 
     959          61 :     if (result == FLOW_FORWARD) {
     960          61 :         if (pkt->vp_type == VP_TYPE_IP) {
     961          57 :             ip = (struct vr_ip *)pkt_network_header(pkt);
     962          57 :             if (ip) {
     963          57 :                 if (fe->fe_ttl && (fe->fe_ttl != ip->ip_ttl)) {
     964           0 :                     vr_incremental_diff(ip->ip_ttl, fe->fe_ttl, &ip_inc_diff_cksum);
     965           0 :                     ip->ip_ttl = fe->fe_ttl;
     966             : 
     967           0 :                     if (ip_inc_diff_cksum)
     968           0 :                         vr_ip_incremental_csum(ip, ip_inc_diff_cksum);
     969             :                 }
     970             :             }
     971             :         }
     972             :     }
     973             : 
     974          61 :     if (fe->fe_tcp_flags & VR_FLOW_TCP_DEAD)
     975           4 :         vr_flow_mark_evict(router, fe, index);
     976             : 
     977          61 :     return result;
     978             : }
     979             : 
     980             : static flow_result_t
     981          62 : vr_flow_action_hbs(struct vrouter *router, struct vr_flow_entry *fe,
     982             :         unsigned int index, struct vr_packet *pkt,
     983             :         struct vr_forwarding_md *fmd)
     984             : {
     985          62 :     struct vr_vrf_table_entry *vrf_entry = NULL;
     986             :     uint16_t dvrf;
     987             : 
     988          62 :     dvrf = (fmd->fmd_dvrf == -1)? fe->fe_vrf: fmd->fmd_dvrf;
     989             : 
     990             :     /* If not HBS flow, return */
     991          62 :     if (!(fe->fe_flags1 & VR_FLOW_FLAG1_HBS_MASK))
     992          53 :             return FLOW_FORWARD;
     993             : 
     994           9 :     vrf_entry = vrouter_get_vrf_table(router, dvrf);
     995             : 
     996             :     /* Packet entering vrouter and going to hbs-l or hbs-r
     997             :      * for hbs-flows
     998             :      */
     999           9 :     if (fe->fe_flags1 & VR_FLOW_FLAG1_HBS_LEFT) {
    1000             :         struct vr_interface *hbs_l;
    1001             : 
    1002             :         /* Flow is marked as HBS, but there is no HBS instance,
    1003             :          * so drop the packet
    1004             :          */
    1005           4 :         if (!vrf_entry) {
    1006           0 :             PKT_LOG(VP_DROP_INVALID_HBS_PKT, pkt, 0, VR_FLOW_C, __LINE__);
    1007           0 :             goto drop_pkt;
    1008             :         }
    1009             : 
    1010           4 :         hbs_l = vrf_entry->hbs_l_vif;
    1011           4 :         if (hbs_l) {
    1012             :             struct vr_eth_hbs_md *eth_hbs;
    1013             : 
    1014           4 :             if (vif_is_virtual(pkt->vp_if)) {
    1015             :                 /* Packet entering vrouter from vmi and going to hbs-l,
    1016             :                  * encode flow_id in src mac
    1017             :                  */
    1018           4 :                 eth_hbs = (struct vr_eth_hbs_md*)pkt_data(pkt);
    1019           4 :                 eth_hbs->flow_id_smac = htonl(index);
    1020           4 :                 eth_hbs->magic_smac = htons(VR_HBS_SMAC_MAGIC | VR_HBS_FROM_VMI);
    1021           0 :             } else if (vif_is_fabric(pkt->vp_if)) {
    1022             :                 /* Packet entering vrouter from fabric and going to hbs-l
    1023             :                  * (service chaining case) encode flow_id in dst mac
    1024             :                  */
    1025             : 
    1026             :                 /* Add ethernet header if there is none */
    1027           0 :                 if (pkt_data(pkt) == pkt_network_header(pkt)) {
    1028           0 :                     struct vr_eth *eth = (struct vr_eth*)pkt_data(pkt);
    1029           0 :                     eth = (struct vr_eth *)pkt_push(pkt, VR_ETHER_HLEN);
    1030           0 :                     memcpy(eth->eth_dmac, hbs_l->vif_mac, VR_ETHER_ALEN);
    1031           0 :                     memcpy(eth->eth_smac, hbs_l->vif_mac, VR_ETHER_ALEN);
    1032           0 :                     if (pkt->vp_type == VP_TYPE_IP) {
    1033           0 :                         eth->eth_proto = htons(VR_ETH_PROTO_IP);
    1034           0 :                     } else if (pkt->vp_type == VP_TYPE_IP6) {
    1035           0 :                         eth->eth_proto = htons(VR_ETH_PROTO_IP6);
    1036             :                     }
    1037             :                 }
    1038             : 
    1039           0 :                 eth_hbs = (struct vr_eth_hbs_md*)pkt_data(pkt);
    1040           0 :                 eth_hbs->flow_id_dmac = htonl(index);
    1041           0 :                 eth_hbs->magic_dmac = htons(VR_HBS_DMAC_MAGIC | VR_HBS_FROM_FABRIC);
    1042             :             }
    1043           4 :             pkt->vp_if = hbs_l;
    1044             :             /*
    1045             :              * If for some reason, we have GRO flag set and we have not invoked
    1046             :              * the GRO, we need to unset
    1047             :              */
    1048           4 :             vr_pkt_unset_gro(pkt);
    1049           4 :             pkt->vp_nh = NULL;
    1050           4 :             hbs_l->vif_tx(hbs_l, pkt, fmd);
    1051           4 :             return FLOW_HELD;
    1052             :         }
    1053           0 :         return FLOW_FORWARD;
    1054           5 :     } else if (fe->fe_flags1 & VR_FLOW_FLAG1_HBS_RIGHT) {
    1055             :         struct vr_interface *hbs_r;
    1056             : 
    1057             :         /* Flow is marked as HBS, but there is no HBS instance,
    1058             :          * so drop the packet
    1059             :          */
    1060           5 :         if (!vrf_entry) {
    1061           0 :             PKT_LOG(VP_DROP_INVALID_HBS_PKT, pkt, 0, VR_FLOW_C, __LINE__);
    1062           0 :             goto drop_pkt;
    1063             :         }
    1064             : 
    1065           5 :         hbs_r = vrf_entry->hbs_r_vif;
    1066           5 :         if (hbs_r) {
    1067             :             /* Packet entering vrouter from fabric and going to hbs-r,
    1068             :              * encode flow_id in dst mac
    1069             :              *
    1070             :              * Note: packet can also enter vrouter and goto hbs-r
    1071             :              * from vmi (instead of fabric) in case of intra-compute
    1072             :              */
    1073             :             struct vr_eth *eth;
    1074             :             struct vr_eth_hbs_md *eth_hbs;
    1075           5 :             bool pkt_is_l3 = false;
    1076             : 
    1077             :             /* Add ethernet header if there is none */
    1078           5 :             if (pkt_data(pkt) == pkt_network_header(pkt)) {
    1079           1 :                 eth = (struct vr_eth *)pkt_push(pkt, VR_ETHER_HLEN);
    1080           1 :                 memcpy(eth->eth_dmac, hbs_r->vif_mac, VR_ETHER_ALEN);
    1081           1 :                 memcpy(eth->eth_smac, hbs_r->vif_mac, VR_ETHER_ALEN);
    1082           1 :                 if (pkt->vp_type == VP_TYPE_IP) {
    1083           1 :                     eth->eth_proto = htons(VR_ETH_PROTO_IP);
    1084           0 :                 } else if (pkt->vp_type == VP_TYPE_IP6) {
    1085           0 :                     eth->eth_proto = htons(VR_ETH_PROTO_IP6);
    1086             :                 }
    1087           1 :                 pkt_is_l3 = true;
    1088             :             }
    1089             : 
    1090           5 :             eth_hbs = (struct vr_eth_hbs_md*)pkt_data(pkt);
    1091             : 
    1092           5 :             eth = (struct vr_eth*)pkt_data(pkt);
    1093           5 :             if (!pkt_is_l3 && !memcmp(eth->eth_dmac, hbs_r->vif_mac, VR_ETHER_ALEN))
    1094           1 :                 pkt_is_l3 = true;
    1095             : 
    1096           5 :             eth_hbs->flow_id_dmac = htonl(index);
    1097             : 
    1098             :             /* Encode packet source in the header */
    1099           5 :             if (vif_is_virtual(pkt->vp_if))
    1100           2 :                 eth_hbs->magic_dmac = htons(VR_HBS_DMAC_MAGIC | VR_HBS_FROM_VMI);
    1101           3 :             else if (vif_is_fabric(pkt->vp_if))
    1102           3 :                 eth_hbs->magic_dmac = htons(VR_HBS_DMAC_MAGIC | VR_HBS_FROM_FABRIC);
    1103             :             /* If it's L3 packet, encode it */
    1104           5 :             if (pkt_is_l3)
    1105           2 :                 eth_hbs->magic_dmac |= htons(VR_HBS_L3_PKT);
    1106             : 
    1107           5 :             pkt->vp_if = hbs_r;
    1108             :             /*
    1109             :              * If for some reason, we have GRO flag set and we have not invoked
    1110             :              * the GRO, we need to unset
    1111             :              */
    1112           5 :             vr_pkt_unset_gro(pkt);
    1113           5 :             pkt->vp_nh = NULL;
    1114           5 :             hbs_r->vif_tx(hbs_r, pkt, fmd);
    1115           5 :             return FLOW_HELD;
    1116             :         }
    1117           0 :         return FLOW_FORWARD;
    1118             :     }
    1119           0 :     return FLOW_FORWARD;
    1120             : 
    1121           0 : drop_pkt:
    1122           0 :     vr_pfree(pkt, VP_DROP_INVALID_HBS_PKT);
    1123           0 :     return FLOW_HELD;
    1124             : }
    1125             : 
    1126             : static flow_result_t
    1127          62 : vr_flow_action(struct vrouter *router, struct vr_flow_entry *fe,
    1128             :         unsigned int index, struct vr_packet *pkt,
    1129             :         struct vr_forwarding_md *fmd)
    1130             : {
    1131          62 :     flow_result_t ret = FLOW_CONSUMED;
    1132             :     struct vr_nexthop *src_nh;
    1133          62 :     int valid_src, modified_index = -1;
    1134             : 
    1135          62 :     src_nh = __vrouter_get_nexthop(router, fe->fe_src_nh_index);
    1136          62 :     if (!src_nh) {
    1137           0 :         PKT_LOG(VP_DROP_INVALID_NH, pkt, 0, VR_FLOW_C, __LINE__);
    1138           0 :         vr_pfree(pkt, VP_DROP_INVALID_NH);
    1139           0 :         goto res;
    1140             :     }
    1141             : 
    1142          62 :     if (src_nh->nh_validate_src) {
    1143          60 :         valid_src = src_nh->nh_validate_src(pkt, src_nh, fmd, &modified_index);
    1144          60 :         if (valid_src == NH_SOURCE_INVALID) {
    1145           0 :             PKT_LOG(VP_DROP_INVALID_SOURCE, pkt, 0, VR_FLOW_C, __LINE__);
    1146           0 :             vr_pfree(pkt, VP_DROP_INVALID_SOURCE);
    1147           0 :             goto res;
    1148             :         }
    1149             : 
    1150          60 :         if (valid_src == NH_SOURCE_MISMATCH) {
    1151           0 :             valid_src = vr_rflow_update_ecmp_index(router, fe,
    1152             :                                             modified_index, fmd);
    1153           0 :             if (valid_src == -1) {
    1154           0 :                 PKT_LOG(VP_DROP_INVALID_SOURCE, pkt, 0, VR_FLOW_C, __LINE__);
    1155           0 :                 vr_pfree(pkt, VP_DROP_INVALID_SOURCE);
    1156           0 :                 goto res;
    1157             :             }
    1158             :         }
    1159             :     }
    1160             : 
    1161             : 
    1162         124 :     if ((fe->fe_action == VR_FLOW_ACTION_DROP) ||
    1163          62 :             ((ret = vr_flow_action_hbs(router, fe, index, pkt, fmd)) != FLOW_HELD))
    1164          53 :         ret = vr_flow_action_default(router, fe, index, pkt, fmd);
    1165             : 
    1166           9 : res:
    1167          62 :     if (fe->fe_tcp_flags & VR_FLOW_TCP_DEAD)
    1168           4 :         vr_flow_mark_evict(router, fe, index);
    1169             : 
    1170          62 :     return ret;
    1171             : }
    1172             : 
    1173             : unsigned int
    1174           5 : vr_trap_flow(struct vrouter *router, struct vr_flow_entry *fe,
    1175             :         struct vr_packet *pkt, unsigned int index,
    1176             :         struct vr_flow_stats *stats, struct vr_packet_node *pnode)
    1177             : {
    1178             :     unsigned int trap_reason;
    1179             : 
    1180             :     struct vr_packet *npkt;
    1181             :     struct vr_flow_trap_arg ta;
    1182             : 
    1183           5 :     npkt = vr_pclone(pkt);
    1184           5 :     if (!npkt) {
    1185             :         /* Lets manipulate the stats */
    1186           0 :         pkt_drop_stats(pkt->vp_if, VP_DROP_TRAP_ORIGINAL, pkt->vp_cpu);
    1187           0 :         if (pnode)
    1188           0 :             pnode->pl_packet = NULL;
    1189           0 :         npkt = pkt;
    1190             :     }
    1191             : 
    1192           5 :     vr_preset(npkt);
    1193             : 
    1194           5 :     switch (fe->fe_flags & VR_FLOW_FLAG_TRAP_MASK) {
    1195             :     default:
    1196             :         /*
    1197             :          * agent needs a method to identify new flows from existing flows.
    1198             :          * existing flows can be reused (evicted) or the action of such flows
    1199             :          * can become hold. If existing flows are reused and packet is trapped,
    1200             :          * agent will not re-evaluate the flow. Hence, agent has to be told
    1201             :          * that this is a new flow, which we indicate by the trap reason.
    1202             :          */
    1203           5 :         if (fe->fe_flags & VR_FLOW_FLAG_NEW_FLOW) {
    1204           5 :             trap_reason = AGENT_TRAP_FLOW_MISS;
    1205           5 :             fe->fe_flags ^= VR_FLOW_FLAG_NEW_FLOW;
    1206             :         } else {
    1207           0 :             trap_reason = AGENT_TRAP_FLOW_ACTION_HOLD;
    1208             :         }
    1209             : 
    1210           5 :         ta.vfta_index = index;
    1211           5 :         if ((fe->fe_type == VP_TYPE_IP) || (fe->fe_type == VP_TYPE_IP6))
    1212           5 :             ta.vfta_nh_index = fe->fe_key.flow_nh_id;
    1213           5 :         if (stats) {
    1214           5 :             ta.vfta_stats = *stats;
    1215             :         } else {
    1216           0 :             ta.vfta_stats = fe->fe_stats;
    1217             :         }
    1218             : 
    1219           5 :         ta.vfta_gen_id = fe->fe_gen_id;
    1220             : 
    1221           5 :         break;
    1222             :     }
    1223             : 
    1224           5 :     return vr_trap(npkt, fe->fe_vrf, trap_reason, &ta);
    1225             : }
    1226             : 
    1227             : static flow_result_t
    1228          67 : vr_do_flow_action(struct vrouter *router, struct vr_flow_entry *fe,
    1229             :         unsigned int index, struct vr_packet *pkt,
    1230             :         struct vr_forwarding_md *fmd)
    1231             : {
    1232             :     uint32_t new_stats;
    1233          67 :     struct vr_flow_stats stats, *stats_p = NULL;
    1234             : 
    1235          67 :     if (fe->fe_flags & VR_FLOW_FLAG_NEW_FLOW) {
    1236           5 :         memcpy(&stats, &fe->fe_stats, sizeof(fe->fe_stats));
    1237           5 :         memset(&fe->fe_stats, 0, sizeof(fe->fe_stats));
    1238           5 :         stats_p = &stats;
    1239             :     }
    1240             : 
    1241          67 :     new_stats = vr_sync_add_and_fetch_32u(&fe->fe_stats.flow_bytes, pkt_len(pkt));
    1242          67 :     if (new_stats < pkt_len(pkt))
    1243           0 :         fe->fe_stats.flow_bytes_oflow++;
    1244             : 
    1245          67 :     new_stats = vr_sync_add_and_fetch_32u(&fe->fe_stats.flow_packets, 1);
    1246          67 :     if (!new_stats)
    1247           0 :         fe->fe_stats.flow_packets_oflow++;
    1248             : 
    1249          67 :     if (fe->fe_action == VR_FLOW_ACTION_HOLD) {
    1250           7 :         vr_enqueue_flow(router, fe, pkt, index, stats_p, fmd);
    1251           7 :         return FLOW_HELD;
    1252             :     }
    1253             : 
    1254          60 :     return vr_flow_action(router, fe, index, pkt, fmd);
    1255             : }
    1256             : 
    1257             : static unsigned int
    1258          18 : vr_flow_table_hold_count(struct vrouter *router)
    1259             : {
    1260             :     unsigned int i, num_cpus;
    1261          18 :     uint64_t hcount = 0, act_count;
    1262          18 :     struct vr_flow_table_info *infop = router->vr_flow_table_info;
    1263             : 
    1264          18 :     num_cpus = vr_num_cpus;
    1265         234 :     for (i = 0; i < num_cpus; i++)
    1266         216 :         hcount += infop->vfti_hold_count[i];
    1267             : 
    1268          18 :     act_count = infop->vfti_action_count;
    1269          18 :     if (hcount >= act_count)
    1270          18 :         return hcount - act_count;
    1271             : 
    1272           0 :     return 0;
    1273             : }
    1274             : 
    1275             : static void
    1276           0 : vr_flow_burst_timeout(void *arg)
    1277             : {
    1278             :     int tokens;
    1279           0 :     struct vrouter *router = (struct vrouter *)arg;
    1280           0 :     struct vr_flow_table_info *infop = router->vr_flow_table_info;
    1281             : 
    1282           0 :     tokens = infop->vfti_burst_tokens - infop->vfti_burst_used;
    1283           0 :     if (tokens > 0) {
    1284             : 
    1285           0 :         tokens  = infop->vfti_burst_tokens_configured - tokens;
    1286           0 :         if (tokens <= 0) {
    1287           0 :             infop->vfti_timer->vt_stop_timer = 1;
    1288           0 :             return;
    1289             :         }
    1290             : 
    1291           0 :         if (tokens > infop->vfti_burst_step_configured)
    1292           0 :             tokens = infop->vfti_burst_step_configured;
    1293             :     } else {
    1294           0 :         tokens = infop->vfti_burst_step_configured;
    1295             :     }
    1296             : 
    1297           0 :     infop->vfti_burst_tokens += tokens;
    1298             : 
    1299           0 :     return;
    1300             : }
    1301             : 
    1302             : static void
    1303           0 : vr_flow_start_burst_processing(struct vrouter *router)
    1304             : {
    1305             :     struct vr_timer *vtimer;
    1306           0 :     struct vr_flow_table_info *infop = router->vr_flow_table_info;
    1307             : 
    1308           0 :     if (!infop->vfti_burst_tokens_configured ||
    1309           0 :             !infop->vfti_burst_interval_configured ||
    1310           0 :             !infop->vfti_burst_step_configured) {
    1311           0 :         return;
    1312             :     }
    1313             : 
    1314           0 :     if (!infop->vfti_timer) {
    1315           0 :         vtimer = vr_zalloc(sizeof(*vtimer), VR_TIMER_OBJECT);
    1316           0 :         if (!vtimer) {
    1317           0 :             vr_module_error(-ENOMEM, __FUNCTION__, __LINE__, sizeof(*vtimer));
    1318           0 :             return;
    1319             :         }
    1320             : 
    1321           0 :         vtimer->vt_timer = vr_flow_burst_timeout;
    1322           0 :         vtimer->vt_vr_arg = router;
    1323           0 :         vtimer->vt_msecs = infop->vfti_burst_interval_configured;
    1324             : 
    1325           0 :         if (vr_create_timer(vtimer)) {
    1326           0 :             vr_free(vtimer, VR_TIMER_OBJECT);
    1327           0 :             return;
    1328             :         }
    1329             : 
    1330           0 :         infop->vfti_timer = vtimer;
    1331             :     } else {
    1332           0 :         if (!infop->vfti_timer->vt_stop_timer)
    1333           0 :             return;
    1334             : 
    1335           0 :         if (vr_sync_bool_compare_and_swap_32u(
    1336             :                  &infop->vfti_timer->vt_stop_timer, 1, 0)) {
    1337           0 :             infop->vfti_timer->vt_msecs = infop->vfti_burst_interval_configured;
    1338           0 :             vr_restart_timer(infop->vfti_timer);
    1339             :         }
    1340             :     }
    1341             : 
    1342           0 :     return;
    1343             : }
    1344             : 
    1345             : static void
    1346           5 : vr_flow_entry_set_hold(struct vrouter *router, struct vr_flow_entry
    1347             :         *flow_e, bool burst)
    1348             : {
    1349             :     unsigned int cpu;
    1350             :     uint64_t act_count;
    1351           5 :     struct vr_flow_table_info *infop = router->vr_flow_table_info;
    1352             : 
    1353           5 :     cpu = vr_get_cpu();
    1354           5 :     if (cpu >= vr_num_cpus) {
    1355           0 :         vr_printf("vrouter: Set HOLD failed (cpu %u num_cpus %u)\n",
    1356             :                 cpu, vr_num_cpus);
    1357           0 :         return;
    1358             :     }
    1359             : 
    1360           5 :     flow_e->fe_action = VR_FLOW_ACTION_HOLD;
    1361             : 
    1362           5 :     if (infop->vfti_hold_count[cpu] + 1 < infop->vfti_hold_count[cpu]) {
    1363           0 :         (void)vr_sync_add_and_fetch_32u(&infop->vfti_oflows, 1);
    1364           0 :         act_count = infop->vfti_action_count;
    1365           0 :         if (act_count > infop->vfti_hold_count[cpu]) {
    1366           0 :            (void)vr_sync_sub_and_fetch_64u(&infop->vfti_action_count,
    1367             :                     infop->vfti_hold_count[cpu]);
    1368           0 :             infop->vfti_hold_count[cpu] = 0;
    1369             :         } else {
    1370           0 :             infop->vfti_hold_count[cpu] -= act_count;
    1371           0 :             (void)vr_sync_sub_and_fetch_64u(&infop->vfti_action_count,
    1372             :                     act_count);
    1373             :         }
    1374             :     }
    1375             : 
    1376           5 :     infop->vfti_hold_count[cpu]++;
    1377             : 
    1378           5 :     if (burst == true) {
    1379           0 :         (void)vr_sync_add_and_fetch_64u(&infop->vfti_burst_used, 1);
    1380           0 :         vr_flow_start_burst_processing(router);
    1381             :     }
    1382             : 
    1383           5 :     return;
    1384             : }
    1385             : 
    1386             : static void
    1387           4 : vr_flow_init_close(struct vrouter *router, struct vr_flow_entry *flow_e,
    1388             :         struct vr_packet *pkt, struct vr_forwarding_md *fmd)
    1389             : {
    1390             :     struct vr_flow_entry *rfe;
    1391             : 
    1392           4 :     (void)vr_sync_fetch_and_or_16u(&flow_e->fe_tcp_flags, VR_FLOW_TCP_DEAD);
    1393           4 :     rfe = vr_flow_get_entry(router, flow_e->fe_rflow);
    1394           4 :     if (rfe) {
    1395           4 :         (void)vr_sync_fetch_and_or_16u(&rfe->fe_tcp_flags, VR_FLOW_TCP_DEAD);
    1396             :     }
    1397             : 
    1398           4 :     return;
    1399             : }
    1400             : 
    1401             : static void
    1402          49 : vr_flow_tcp_rflow_set(struct vrouter *router, struct vr_flow_entry *fe,
    1403             :         struct vr_flow_entry *rfe)
    1404             : {
    1405          49 :     uint16_t flags = 0;
    1406             : 
    1407          49 :     if (!fe || !rfe)
    1408           0 :         return;
    1409             : 
    1410          49 :     if (rfe->fe_tcp_flags & VR_FLOW_TCP_SYN) {
    1411           1 :         flags |= VR_FLOW_TCP_SYN_R;
    1412             :     }
    1413             : 
    1414          49 :     if (rfe->fe_tcp_flags & VR_FLOW_TCP_RST) {
    1415           0 :         flags |= VR_FLOW_TCP_RST;
    1416             :     }
    1417             : 
    1418          49 :     if (rfe->fe_tcp_flags & VR_FLOW_TCP_DEAD) {
    1419           0 :         flags |= VR_FLOW_TCP_DEAD;
    1420             :     }
    1421             : 
    1422          49 :     if (rfe->fe_tcp_flags & VR_FLOW_TCP_FIN) {
    1423           0 :         flags |= VR_FLOW_TCP_FIN_R;
    1424             :     }
    1425             : 
    1426          49 :     if (rfe->fe_tcp_flags & VR_FLOW_TCP_ESTABLISHED) {
    1427           0 :         flags |= (VR_FLOW_TCP_ESTABLISHED | VR_FLOW_TCP_ESTABLISHED_R);
    1428             :     }
    1429             : 
    1430          49 :     (void)vr_sync_fetch_and_or_16u(&fe->fe_tcp_flags, flags);
    1431          49 :     return;
    1432             : }
    1433             : 
    1434             : static void
    1435          67 : vr_flow_tcp_digest(struct vrouter *router, struct vr_flow_entry *flow_e,
    1436             :         struct vr_packet *pkt, struct vr_forwarding_md *fmd)
    1437             : {
    1438          67 :     uint8_t proto = 0, hlen = 0;
    1439             :     uint16_t tcp_offset_flags;
    1440          67 :     unsigned int length = 0;
    1441             :     uint16_t flow_tcp_flags;
    1442             : 
    1443             :     struct vr_ip *iph;
    1444             :     struct vr_ip6 *ip6h;
    1445             :     struct vr_tcp *tcph;
    1446             :     struct vr_ip6_frag *v6_frag;
    1447          67 :     struct vr_flow_entry *rflow_e = NULL;
    1448             :     unsigned int rflow_ack;
    1449             : 
    1450          67 :     if (pkt->vp_type == VP_TYPE_IP) {
    1451          63 :         iph = (struct vr_ip *)pkt_network_header(pkt);
    1452          63 :         if (!vr_ip_transport_header_valid(iph))
    1453          12 :             return;
    1454          51 :         proto = iph->ip_proto;
    1455             : 
    1456          51 :         length = ntohs(iph->ip_len) - (iph->ip_hl * 4);
    1457          51 :         hlen = iph->ip_hl * 4;
    1458           4 :     } else if (pkt->vp_type == VP_TYPE_IP6) {
    1459           4 :         ip6h = (struct vr_ip6 *)pkt_network_header(pkt);
    1460           4 :         if (!vr_ip6_transport_header_valid(ip6h))
    1461           0 :             return;
    1462           4 :         proto = ip6h->ip6_nxt;
    1463           4 :         length = ntohs(ip6h->ip6_plen);
    1464           4 :         hlen = sizeof(struct vr_ip6);
    1465           4 :         if (proto == VR_IP6_PROTO_FRAG) {
    1466           0 :             v6_frag = (struct vr_ip6_frag *)(ip6h + 1);
    1467           0 :             proto = v6_frag->ip6_frag_nxt;
    1468           0 :             length -= sizeof(struct vr_ip6_frag);
    1469           0 :             hlen += sizeof(struct vr_ip6_frag);
    1470             :         }
    1471             :     }
    1472             : 
    1473          55 :     if (proto != VR_IP_PROTO_TCP)
    1474          35 :         return;
    1475             : 
    1476          20 :     tcph = (struct vr_tcp *)(pkt_network_header(pkt) + hlen);
    1477             : 
    1478          20 :     if (tcph) {
    1479          20 :         if (vr_flow_is_fat_flow(router, pkt, flow_e))
    1480           0 :             return;
    1481             : 
    1482             :         /*
    1483             :          * there are some optimizations here that makes the code slightly
    1484             :          * not so frugal. For e.g.: the *_R flags are used to make sure that
    1485             :          * for a packet that contains ACK, we will not need to fetch the
    1486             :          * reverse flow if we are not interested, thus saving some execution
    1487             :          * time.
    1488             :          */
    1489          20 :         tcp_offset_flags = ntohs(tcph->tcp_offset_r_flags);
    1490             : 
    1491             :         /*
    1492             :          * If this is an ack, set the last acked seqnum
    1493             :          */
    1494          20 :         if (tcp_offset_flags & VR_TCP_FLAG_ACK) {
    1495           9 :             flow_e->fe_tcp_ack = ntohl(tcph->tcp_ack);
    1496             :         }
    1497             : 
    1498             :         /*
    1499             :          * if we get a reset, TCP session will be closed if the
    1500             :          * vr_uncond_close_flow_on_tcp_rst flag is enabled or the TCP RST
    1501             :          * seqnum matches with the seqnum acked by the receiver
    1502             :          * - as per RFC 5961 sec 3.2
    1503             :          */
    1504          20 :         if (tcp_offset_flags & VR_TCP_FLAG_RST) {
    1505           6 :             if (!vr_uncond_close_flow_on_tcp_rst) {
    1506             :                 /* get the reverse flow ack seq num if valid */
    1507           4 :                 if (flow_e->fe_flags & VR_RFLOW_VALID) {
    1508           4 :                     rflow_e = vr_flow_get_entry(router, flow_e->fe_rflow);
    1509             :                 }
    1510           4 :                 if (rflow_e) {
    1511           4 :                     rflow_ack = rflow_e->fe_tcp_ack;
    1512             :                 /* Implementing rfc-5961 (section 3.2),
    1513             :                  * In the SYN-SENT state (a RST received in response to an initial SYN),
    1514             :                  * the RST is acceptable if the ACK field acknowledges the SYN.  In all
    1515             :                  * other cases the receiver MUST silently discard the segment. */
    1516           4 :                     if ((tcp_offset_flags & VR_TCP_FLAG_ACK)
    1517           2 :                          && (rflow_e->fe_tcp_flags & VR_FLOW_TCP_SYN)) {
    1518           2 :                          if (ntohl(tcph->tcp_ack) != (rflow_e->fe_tcp_seq + 1)) {
    1519             :                             /* Ignore the RST */
    1520           1 :                             return;
    1521             :                          }
    1522             :                     }
    1523           2 :                     else if (ntohl(tcph->tcp_seq) != rflow_ack) {
    1524             :                         /* Ignore the RST */
    1525           1 :                         return;
    1526             :                     }
    1527             :                 }
    1528             :                 /* If Reverse flow not valid, go ahead and close this flow */
    1529             :             }
    1530             : 
    1531           4 :             (void)vr_sync_fetch_and_or_16u(&flow_e->fe_tcp_flags,
    1532             :                     VR_FLOW_TCP_RST);
    1533           4 :             if (flow_e->fe_flags & VR_RFLOW_VALID) {
    1534           4 :                 rflow_e = vr_flow_get_entry(router, flow_e->fe_rflow);
    1535           4 :                 if (rflow_e) {
    1536           4 :                     (void)vr_sync_fetch_and_or_16u(&rflow_e->fe_tcp_flags,
    1537             :                             VR_FLOW_TCP_RST);
    1538             :                 }
    1539             :             }
    1540           4 :             vr_flow_init_close(router, flow_e, pkt, fmd);
    1541           4 :             return;
    1542          14 :         } else if (tcp_offset_flags & VR_TCP_FLAG_SYN) {
    1543             :             /* if only a SYN... */
    1544          11 :             flow_e->fe_tcp_seq = ntohl(tcph->tcp_seq);
    1545          11 :             (void)vr_sync_fetch_and_or_16u(&flow_e->fe_tcp_flags, VR_FLOW_TCP_SYN);
    1546          11 :             if (flow_e->fe_flags & VR_RFLOW_VALID) {
    1547           9 :                 rflow_e = vr_flow_get_entry(router, flow_e->fe_rflow);
    1548           9 :                 if (rflow_e) {
    1549           9 :                     (void)vr_sync_fetch_and_or_16u(&rflow_e->fe_tcp_flags,
    1550             :                             VR_FLOW_TCP_SYN_R);
    1551           9 :                     if ((flow_e->fe_tcp_flags & VR_FLOW_TCP_SYN_R) &&
    1552           3 :                             (tcp_offset_flags & VR_TCP_FLAG_ACK)) {
    1553           3 :                         if (ntohl(tcph->tcp_ack) == (rflow_e->fe_tcp_seq + 1)) {
    1554           3 :                             (void)vr_sync_fetch_and_or_16u(&rflow_e->fe_tcp_flags,
    1555             :                                     VR_FLOW_TCP_ESTABLISHED);
    1556           3 :                             flow_tcp_flags = vr_sync_fetch_and_or_16u(
    1557             :                                 &flow_e->fe_tcp_flags, VR_FLOW_TCP_ESTABLISHED_R);
    1558           3 :                             if (!(flow_tcp_flags & VR_FLOW_TCP_ESTABLISHED_R) &&
    1559           3 :                                 !(flow_tcp_flags & VR_FLOW_TCP_ESTABLISHED)) {
    1560             :                                 // If it wasn't established or reverse established,
    1561             :                                 // it is being established now. Offload both.
    1562           3 :                                 vr_offload_flow_set(flow_e,
    1563             :                                     flow_e->fe_hentry.hentry_index, rflow_e);
    1564           3 :                                 vr_offload_flow_set(rflow_e,
    1565             :                                     rflow_e->fe_hentry.hentry_index, flow_e);
    1566             :                             }
    1567             :                         }
    1568             :                     }
    1569             :                 }
    1570             :             }
    1571           3 :         } else if (tcp_offset_flags & VR_TCP_FLAG_FIN) {
    1572             :             /*
    1573             :              * when a FIN is received, update the sequence of the FIN and set
    1574             :              * the flow FIN flag. It is possible that the FIN packet came with
    1575             :              * some data, in which case the sequence number of the FIN is one
    1576             :              * more than the last data byte in the sequence
    1577             :              */
    1578           0 :             length -= (((tcp_offset_flags) >> 12) * 4);
    1579           0 :             flow_e->fe_tcp_seq = ntohl(tcph->tcp_seq) + length;
    1580           0 :             (void)vr_sync_fetch_and_or_16u(&flow_e->fe_tcp_flags, VR_FLOW_TCP_FIN);
    1581             :             /*
    1582             :              * when an ack for a FIN is sent, we need to take some actions
    1583             :              * on the reverse flow (since FIN came in the reverse flow). to
    1584             :              * avoid looking up the reverse flow for all acks, we mark the
    1585             :              * reverse flow's reverse flow with a flag (FIN_R). we will
    1586             :              * lookup the reverse flow only if this flag is set and the
    1587             :              * tcp header has an ack bit set
    1588             :              */
    1589           0 :             if (flow_e->fe_flags & VR_RFLOW_VALID) {
    1590           0 :                 rflow_e = vr_flow_get_entry(router, flow_e->fe_rflow);
    1591             :                 /* Delete offloaded flow on TCP FIN */
    1592           0 :                 (void)vr_offload_flow_del(flow_e);
    1593           0 :                 if (rflow_e) {
    1594           0 :                     (void)vr_sync_fetch_and_or_16u(&rflow_e->fe_tcp_flags,
    1595             :                             VR_FLOW_TCP_FIN_R);
    1596             :                     /* Delete offloaded reverse flow on TCP FIN */
    1597           0 :                     (void)vr_offload_flow_del(rflow_e);
    1598             :                 }
    1599             :             }
    1600             :         }
    1601             : 
    1602             :         /*
    1603             :          * if FIN_R is set in the flow and if the ACK bit is set in the
    1604             :          * tcp header, then we need to mark the reverse flow as dead.
    1605             :          *
    1606             :          * OR
    1607             :          *
    1608             :          * if the SYN_R is set and ESTABLISHED_R is not set and if this
    1609             :          * is an ack packet, if this ack completes the connection, we
    1610             :          * need to set ESTABLISHED
    1611             :          */
    1612          14 :         if (((flow_e->fe_tcp_flags & VR_FLOW_TCP_FIN_R) ||
    1613          14 :                 (!(flow_e->fe_tcp_flags & VR_FLOW_TCP_ESTABLISHED_R) &&
    1614          11 :                  (flow_e->fe_tcp_flags & VR_FLOW_TCP_SYN_R))) &&
    1615           3 :                 (tcp_offset_flags & VR_TCP_FLAG_ACK)) {
    1616           3 :             if (flow_e->fe_flags & VR_RFLOW_VALID) {
    1617           3 :                 if (!rflow_e) {
    1618           3 :                     rflow_e = vr_flow_get_entry(router, flow_e->fe_rflow);
    1619             :                 }
    1620             : 
    1621           3 :                 if (rflow_e) {
    1622           3 :                     if ((ntohl(tcph->tcp_ack) == (rflow_e->fe_tcp_seq + 1)) &&
    1623           3 :                             (flow_e->fe_tcp_flags & VR_FLOW_TCP_FIN_R)) {
    1624           0 :                         (void)vr_sync_fetch_and_or_16u(&rflow_e->fe_tcp_flags,
    1625             :                                 VR_FLOW_TCP_HALF_CLOSE);
    1626             :                         /*
    1627             :                          * both the forward and the reverse flows are
    1628             :                          * now dead
    1629             :                          */
    1630           0 :                         if (flow_e->fe_tcp_flags & VR_FLOW_TCP_HALF_CLOSE) {
    1631           0 :                             vr_flow_init_close(router, flow_e, pkt, fmd);
    1632             :                         }
    1633           3 :                     } else if (ntohl(tcph->tcp_ack) != rflow_e->fe_tcp_seq) {
    1634           3 :                         if (!(flow_e->fe_tcp_flags &
    1635             :                                     VR_FLOW_TCP_ESTABLISHED_R)) {
    1636           3 :                             (void)vr_sync_fetch_and_or_16u(&rflow_e->fe_tcp_flags,
    1637             :                                     VR_FLOW_TCP_ESTABLISHED);
    1638           3 :                             flow_tcp_flags = vr_sync_fetch_and_or_16u(
    1639             :                                 &flow_e->fe_tcp_flags, VR_FLOW_TCP_ESTABLISHED_R);
    1640           3 :                             if (!(flow_tcp_flags & VR_FLOW_TCP_ESTABLISHED_R) &&
    1641           3 :                                 !(flow_tcp_flags & VR_FLOW_TCP_ESTABLISHED)) {
    1642             :                                 // If it wasn't established or reverse established,
    1643             :                                 // it is being established now. Offload both.
    1644           0 :                                 vr_offload_flow_set(flow_e,
    1645             :                                     flow_e->fe_hentry.hentry_index, rflow_e);
    1646           0 :                                 vr_offload_flow_set(rflow_e,
    1647             :                                     rflow_e->fe_hentry.hentry_index, flow_e);
    1648             :                             }
    1649             :                         }
    1650             :                     }
    1651             :                 }
    1652             :             }
    1653             :         }
    1654             :     }
    1655             : 
    1656          14 :     return;
    1657             : }
    1658             : 
    1659             : static inline bool
    1660           5 : vr_flow_vif_allow_new_flow(struct vrouter *router, struct vr_packet *pkt,
    1661             :                            unsigned short *drop_reason)
    1662             : {
    1663           5 :     struct vr_interface *vif_l = NULL;
    1664           5 :     struct vr_nexthop *nh = NULL;
    1665             : 
    1666           5 :     if (vif_is_virtual(pkt->vp_if)) {
    1667           3 :         vif_l = pkt->vp_if;
    1668           2 :     } else if (vif_is_fabric(pkt->vp_if)) {
    1669           1 :         nh = pkt->vp_nh;
    1670           1 :         if ((nh != NULL) && (nh->nh_flags & NH_FLAG_VALID)) {
    1671           1 :             vif_l = nh->nh_dev;
    1672             :         }
    1673             :     }
    1674             : 
    1675           5 :     if (vif_l && vif_drop_new_flows(vif_l)) {
    1676           0 :         PKT_LOG(VP_DROP_NEW_FLOWS, pkt, 0, VR_FLOW_C, __LINE__);
    1677           0 :         *drop_reason = VP_DROP_NEW_FLOWS;
    1678           0 :         return false;
    1679             :     }
    1680             : 
    1681           5 :     return true;
    1682             : }
    1683             : 
    1684             : void
    1685           0 : vr_flow_get_burst_params(struct vrouter *router, int *burst_tokens,
    1686             :         int *burst_interval, int *burst_step)
    1687             : {
    1688             :     struct vr_flow_table_info *infop;
    1689             : 
    1690           0 :     if (!router || !router->vr_flow_table_info)
    1691           0 :         return;
    1692             : 
    1693           0 :     infop = router->vr_flow_table_info;
    1694             : 
    1695           0 :     if (burst_tokens)
    1696           0 :         *burst_tokens = infop->vfti_burst_tokens_configured;
    1697           0 :     if (burst_interval)
    1698           0 :         *burst_interval = infop->vfti_burst_interval_configured;
    1699           0 :     if (burst_step)
    1700           0 :         *burst_step = infop->vfti_burst_step_configured;
    1701             : 
    1702           0 :     return;
    1703             : }
    1704             : 
    1705             : void
    1706           0 : vr_flow_set_burst_params(struct vrouter *router, int burst_tokens,
    1707             :                                 int burst_interval, int burst_step)
    1708             : {
    1709             :     struct vr_flow_table_info *infop;
    1710             : 
    1711           0 :     if (!router || !router->vr_flow_table_info)
    1712           0 :         return;
    1713             : 
    1714           0 :     infop = router->vr_flow_table_info;
    1715             : 
    1716           0 :     if (burst_tokens != -1)
    1717           0 :         infop->vfti_burst_tokens_configured = burst_tokens;
    1718             : 
    1719           0 :     if (burst_interval != -1)
    1720           0 :         infop->vfti_burst_interval_configured = burst_interval;
    1721             : 
    1722           0 :     if (burst_step != -1)
    1723           0 :         infop->vfti_burst_step_configured = burst_step;
    1724             : 
    1725             : 
    1726           0 :     vr_flow_start_burst_processing(router);
    1727           0 :     return;
    1728             : }
    1729             : 
    1730             : static inline unsigned int
    1731           0 : vr_flow_burst_count(struct vrouter *router)
    1732             : {
    1733           0 :     struct vr_flow_table_info *infop = router->vr_flow_table_info;
    1734             : 
    1735           0 :     return infop->vfti_burst_tokens;
    1736             : }
    1737             : 
    1738             : static inline bool
    1739           5 : vr_flow_allow_new_flow(struct vrouter *router, struct vr_packet *pkt,
    1740             :                        unsigned short *drop_reason, bool *burst)
    1741             : {
    1742             :     unsigned int hold_count;
    1743           5 :     struct vr_flow_table_info *infop = router->vr_flow_table_info;
    1744             : 
    1745           5 :     *drop_reason = VP_DROP_FLOW_UNUSABLE;
    1746           5 :     if (burst)
    1747           5 :         *burst = false;
    1748             : 
    1749           5 :     if (pkt->vp_type == VP_TYPE_IP) {
    1750           5 :         if (!vr_inet_flow_allow_new_flow(router, pkt)) {
    1751           0 :             PKT_LOG(VP_DROP_FLOW_UNUSABLE, pkt, 0, VR_FLOW_C, __LINE__);
    1752           0 :             *drop_reason = VP_DROP_FLOW_UNUSABLE;
    1753           0 :             return false;
    1754             :         }
    1755             :     }
    1756             : 
    1757           5 :     if (vr_flow_hold_limit) {
    1758           5 :         hold_count = vr_flow_table_hold_count(router);
    1759           5 :         if (hold_count > vr_flow_hold_limit) {
    1760           0 :             if (infop->vfti_burst_used >= vr_flow_burst_count(router)) {
    1761           0 :                 PKT_LOG(VP_DROP_FLOW_UNUSABLE, pkt, 0, VR_FLOW_C, __LINE__);
    1762           0 :                 *drop_reason = VP_DROP_FLOW_UNUSABLE;
    1763           0 :                 return false;
    1764             :             }
    1765           0 :             if (burst) {
    1766           0 :                 *burst = true;
    1767             :             }
    1768             :         }
    1769             :     }
    1770             : 
    1771           5 :     return vr_flow_vif_allow_new_flow(router, pkt, drop_reason);
    1772             : }
    1773             : 
    1774             : static inline struct vr_flow_entry *
    1775           5 : vr_flow_new_hold_flow(struct vrouter *router, struct vr_flow *key,
    1776             :                  struct vr_packet *pkt, unsigned int *fe_index,
    1777             :                  struct vr_forwarding_md *fmd) {
    1778             :     struct vr_flow_entry *bucket_fe, *flow_e;
    1779           5 :     unsigned short drop_reason = 0;
    1780           5 :     bool burst = false;
    1781             :     /* Slow path: lock, to make find+create atomic thus avoid races
    1782             :      * with another vr_flow_lookup or vr_add_flow). We also need need
    1783             :      * to retry the find, as previous one was done without locking */
    1784           5 :     bucket_fe = vr_flow_bucket_first_entry(router, key);
    1785           5 :     vr_flow_bucket_may_lock(bucket_fe);
    1786           5 :     flow_e = vr_find_flow(router, key, pkt->vp_type, fe_index);
    1787           5 :     if (!flow_e) {
    1788           5 :         if (!vr_flow_allow_new_flow(router, pkt, &drop_reason, &burst)) {
    1789           0 :             vr_flow_bucket_may_unlock(bucket_fe);
    1790           0 :             PKT_LOG(drop_reason, pkt, key , VR_FLOW_C, __LINE__);
    1791           0 :             vr_pfree(pkt, drop_reason);
    1792           0 :             return flow_e;
    1793             :         }
    1794             : 
    1795           5 :         flow_e = vr_flow_get_free_entry(router, key, pkt->vp_type,
    1796             :                 true, fe_index);
    1797           5 :         if (!flow_e) {
    1798           0 :             vr_flow_bucket_may_unlock(bucket_fe);
    1799           0 :             PKT_LOG(VP_DROP_FLOW_TABLE_FULL, pkt, key, VR_FLOW_C, __LINE__);
    1800           0 :             vr_pfree(pkt, VP_DROP_FLOW_TABLE_FULL);
    1801           0 :             return flow_e;
    1802             :         }
    1803             : 
    1804           5 :         flow_e->fe_vrf = fmd->fmd_dvrf;
    1805             :         /* mark as hold */
    1806           5 :         vr_flow_entry_set_hold(router, flow_e, burst);
    1807             :     }
    1808           5 :     vr_flow_bucket_may_unlock(bucket_fe);
    1809           5 :     return flow_e;
    1810             : }
    1811             : 
    1812             : flow_result_t
    1813          67 : vr_flow_lookup(struct vrouter *router, struct vr_flow *key,
    1814             :                struct vr_packet *pkt, struct vr_forwarding_md *fmd)
    1815             : {
    1816             :     unsigned int fe_index;
    1817             :     struct vr_flow_entry *flow_e;
    1818          67 :     pkt->vp_flags |= VP_FLAG_FLOW_SET;
    1819             : 
    1820          67 :     if (!fmd->fmd_fe) {
    1821             :         /* Happy path: without locking */
    1822          67 :         flow_e = vr_find_flow(router, key, pkt->vp_type,  &fe_index);
    1823          67 :         if (!flow_e) {
    1824           5 :             if (pkt->vp_nh &&
    1825           2 :                 (pkt->vp_nh->nh_flags &
    1826             :                  (NH_FLAG_RELAXED_POLICY | NH_FLAG_FLOW_LOOKUP)))
    1827           0 :                 return FLOW_FORWARD;
    1828             : 
    1829           5 :             flow_e = vr_flow_new_hold_flow(router, key, pkt, &fe_index, fmd);
    1830           5 :             if (!flow_e)
    1831           0 :                 return FLOW_CONSUMED;
    1832             :         }
    1833             :     } else {
    1834           0 :         flow_e = fmd->fmd_fe;
    1835           0 :         fe_index = fmd->fmd_flow_index;
    1836             :     }
    1837             : 
    1838          67 :     if (flow_e->fe_flags & VR_FLOW_FLAG_EVICT_CANDIDATE)
    1839           0 :         return FLOW_EVICT_DROP;
    1840             : 
    1841             :     /*
    1842             :      * Store the source of the packet which gets used incase of Ecmp
    1843             :      * Source
    1844             :      */
    1845          67 :     if (vif_is_fabric(pkt->vp_if))
    1846           8 :         flow_e->fe_src_info = fmd->fmd_outer_src_ip;
    1847          59 :     else if (vif_is_virtual(pkt->vp_if))
    1848          58 :         flow_e->fe_src_info = pkt->vp_if->vif_idx;
    1849             : 
    1850          67 :     vr_flow_set_forwarding_md(router, flow_e, fe_index, fmd);
    1851          67 :     vr_flow_tcp_digest(router, flow_e, pkt, fmd);
    1852             : 
    1853          67 :     return vr_do_flow_action(router, flow_e, fe_index, pkt, fmd);
    1854             : }
    1855             : 
    1856             : static bool
    1857         188 : __vr_flow_forward(flow_result_t result, struct vr_packet *pkt,
    1858             :         struct vr_forwarding_md *fmd)
    1859             : {
    1860         188 :     bool forward = false;
    1861             : 
    1862         188 :     switch (result) {
    1863         164 :     case FLOW_FORWARD:
    1864         164 :         forward = true;
    1865         164 :         break;
    1866             : 
    1867           0 :     case FLOW_TRAP:
    1868           0 :         vr_trap(pkt, fmd->fmd_dvrf, AGENT_TRAP_L3_PROTOCOLS, NULL);
    1869           0 :         break;
    1870             : 
    1871           0 :     case FLOW_EVICT_DROP:
    1872           0 :         PKT_LOG(VP_DROP_FLOW_EVICT, pkt, 0, VR_FLOW_C, __LINE__);
    1873           0 :         vr_pfree(pkt, VP_DROP_FLOW_EVICT);
    1874           0 :         break;
    1875             : 
    1876          24 :     case FLOW_HELD:
    1877             :     case FLOW_CONSUMED:
    1878          24 :         break;
    1879             : 
    1880           0 :     case FLOW_DROP:
    1881             :     default:
    1882           0 :         PKT_LOG(VP_DROP_FLOW_UNUSABLE, pkt, 0, VR_FLOW_C, __LINE__);
    1883           0 :         vr_pfree(pkt, VP_DROP_FLOW_UNUSABLE);
    1884           0 :         break;
    1885             :     }
    1886             : 
    1887         188 :     return forward;
    1888             : }
    1889             : 
    1890             : static bool
    1891          20 : vr_flow_is_fat_flow(struct vrouter *router, struct vr_packet *pkt,
    1892             :         struct vr_flow_entry *fe)
    1893             : {
    1894          20 :     if (pkt->vp_type == VP_TYPE_IP) {
    1895          20 :         return vr_inet_flow_is_fat_flow(router, pkt, fe);
    1896           0 :     } else if (pkt->vp_type == VP_TYPE_IP6) {
    1897           0 :         return vr_inet6_flow_is_fat_flow(router, pkt, fe);
    1898             :     }
    1899             : 
    1900           0 :     return false;
    1901             : }
    1902             : 
    1903             : uint16_t
    1904          59 : vr_flow_fat_flow_lookup(struct vrouter *router, struct vr_packet *pkt,
    1905             :         uint16_t l4_proto, uint16_t sport, uint16_t dport,
    1906             :         unsigned int *saddr, unsigned int *daddr,
    1907             :         unsigned char *ip6_src, unsigned char *ip6_dst)
    1908             : {
    1909          59 :     uint8_t fat_flow_mask, tmp_mask = 0;
    1910             :     struct vr_nexthop *nh;
    1911          59 :     struct vr_interface *vif_l = NULL;
    1912             : 
    1913          59 :     if (vif_is_virtual(pkt->vp_if)) {
    1914          49 :         vif_l = pkt->vp_if;
    1915          10 :     } else if (vif_is_fabric(pkt->vp_if)) {
    1916           8 :         if ((nh = pkt->vp_nh) && (nh->nh_flags & NH_FLAG_VALID)) {
    1917             :             /* In case of ECMP, check the vif within the ECMP member NH */
    1918           8 :             if (vr_is_local_ecmp_nh(nh)) {
    1919           0 :                 vif_l = vr_get_ecmp_first_member_dev(nh);
    1920             :             } else {
    1921           8 :                 vif_l = nh->nh_dev;
    1922             :             }
    1923             :         }
    1924             :     }
    1925             : 
    1926          59 :     if (!vif_l)
    1927           2 :         return VR_FAT_FLOW_NO_MASK;
    1928             : 
    1929          57 :     fat_flow_mask = vif_fat_flow_lookup((pkt->vp_if == vif_l), vif_l, l4_proto, sport, dport,
    1930             :                                         saddr, daddr, ip6_src, ip6_dst);
    1931          57 :     if (pkt->vp_if != vif_l) {
    1932             : 
    1933           8 :         if (fat_flow_mask & VR_FAT_FLOW_SRC_IP_MASK)
    1934           0 :             tmp_mask |= VR_FAT_FLOW_DST_IP_MASK;
    1935             : 
    1936           8 :         if (fat_flow_mask & VR_FAT_FLOW_DST_IP_MASK)
    1937           0 :             tmp_mask |= VR_FAT_FLOW_SRC_IP_MASK;
    1938             : 
    1939           8 :         fat_flow_mask &= ~(VR_FAT_FLOW_DST_IP_MASK |
    1940             :                 VR_FAT_FLOW_SRC_IP_MASK);
    1941             : 
    1942             : 
    1943           8 :         fat_flow_mask |= tmp_mask;
    1944             : 
    1945             :     }
    1946             : 
    1947          57 :     return fat_flow_mask;
    1948             : }
    1949             : 
    1950             : static flow_result_t
    1951         170 : vr_do_flow_lookup(struct vrouter *router, struct vr_packet *pkt,
    1952             :                 struct vr_forwarding_md *fmd)
    1953             : {
    1954         170 :     flow_result_t result = FLOW_FORWARD;
    1955             : 
    1956             :     /* Flow processing is only for untagged unicast IP packets */
    1957         170 :     if (pkt->vp_type == VP_TYPE_IP)
    1958         156 :         result = vr_inet_flow_lookup(router, pkt, fmd);
    1959          14 :     else if (pkt->vp_type == VP_TYPE_IP6)
    1960          10 :         result = vr_inet6_flow_lookup(router, pkt, fmd);
    1961             : 
    1962         170 :     return result;
    1963             : }
    1964             : 
    1965             : static void
    1966           8 : vr_reinit_forwarding_md(struct vrouter *router, struct vr_packet *pkt,
    1967             :                         struct vr_flow_entry *fe, uint32_t flow_index,
    1968             :                         struct vr_nexthop *nh, struct vr_forwarding_md *fmd)
    1969             : {
    1970             :     int i;
    1971           8 :     struct vr_nexthop *src_nh = __vrouter_get_nexthop(router, fe->fe_src_nh_index);
    1972             : 
    1973           8 :     for (i = 0; i < VR_MAX_PHY_INF; i++) {
    1974           8 :         if (nh->nh_dev_arr[i] != NULL) {
    1975           8 :             fmd->fmd_dvrf = nh->nh_dev_arr[i]->vif_vrf;
    1976           8 :             break;
    1977             :         }
    1978             :     }
    1979             : 
    1980           8 :     fmd->fmd_vlan = 0;
    1981           8 :     fmd->fmd_dotonep = -1;
    1982           8 :     fmd->fmd_outer_src_ip = src_nh->nh_udp_tun_dip;
    1983           8 :     vr_flow_set_forwarding_md(router, fe, flow_index, fmd);
    1984           8 : }
    1985             : 
    1986             : bool
    1987         186 : vr_flow_forward(struct vrouter *router, struct vr_packet *pkt,
    1988             :                 struct vr_forwarding_md *fmd)
    1989             : {
    1990         186 :     flow_result_t result = FLOW_FORWARD;
    1991             : 
    1992         186 :     if (vif_is_hbs_right(pkt->vp_if)) {
    1993             :         /* Pkt entering vrouter from hbs-r
    1994             :          *   - If SMAC has magic, Restore actual SMAC from flow_index and continue
    1995             :          *   - If DMAC has magic, Restore actual DMAC from flow_index and continue
    1996             :          */
    1997           4 :         struct vr_eth_hbs_md *eth_hbs = (struct vr_eth_hbs_md*)pkt_data(pkt);
    1998           4 :         struct vr_eth *eth = (struct vr_eth*)pkt_data(pkt);
    1999             :         uint16_t magic;
    2000             :         unsigned int flow_index;
    2001             :         uint32_t nh_id;
    2002           4 :         struct vr_flow_entry *fe = NULL;
    2003             :         unsigned char* mac;
    2004           4 :         if ((ntohs(eth_hbs->magic_smac) & VR_HBS_MAGIC_MASK) ==
    2005             :                                                     VR_HBS_SMAC_MAGIC) {
    2006           4 :             magic = VR_HBS_SMAC_MAGIC;
    2007           4 :             flow_index = ntohl(eth_hbs->flow_id_smac);
    2008           4 :             mac = eth->eth_smac;
    2009           0 :         } else if ((ntohs(eth_hbs->magic_dmac) & VR_HBS_MAGIC_MASK) ==
    2010             :                                                     VR_HBS_DMAC_MAGIC) {
    2011           0 :             magic = VR_HBS_DMAC_MAGIC;
    2012           0 :             flow_index = ntohl(eth_hbs->flow_id_dmac);
    2013           0 :             mac = eth->eth_dmac;
    2014             :         } else {
    2015           0 :             PKT_LOG(VP_DROP_INVALID_HBS_PKT, pkt, 0, VR_FLOW_C, __LINE__);
    2016           0 :             goto drop_pkt;
    2017             :         }
    2018             : 
    2019           4 :         if (vr_htable_get_hentry_by_index(router->vr_flow_table, flow_index)) {
    2020             :             struct vr_nexthop *nh;
    2021           4 :             fe = CONTAINER_OF(
    2022             :                            fe_hentry,
    2023             :                            struct vr_flow_entry,
    2024             :                            vr_htable_get_hentry_by_index(
    2025             :                                 router->vr_flow_table, flow_index)
    2026             :                              );
    2027           4 :             nh_id = fe->fe_key.flow_nh_id;
    2028           4 :             nh = vrouter_get_nexthop(0, nh_id);
    2029           4 :             vr_reinit_forwarding_md(router, pkt, fe, flow_index, nh, fmd);
    2030             : 
    2031           4 :             if(fe->fe_underlay_ecmp_index >= 0) {
    2032           0 :                 if(nh->nh_type == NH_TUNNEL) {
    2033           0 :                     pkt->vp_if = __vrouter_get_interface(router,
    2034           0 :                             fe->fe_underlay_ecmp_index);
    2035             :                 } else
    2036           0 :                     pkt->vp_if = nh->nh_dev;
    2037             :             } else
    2038           4 :                 pkt->vp_if = nh->nh_dev;
    2039             : 
    2040           4 :             memcpy(mac, nh->nh_data, VR_ETHER_ALEN);
    2041           4 :             result = vr_flow_action_default(router, fe, flow_index, pkt, fmd);
    2042           4 :             return __vr_flow_forward(result, pkt, fmd);
    2043             :         }
    2044         182 :     } else if (vif_is_hbs_left(pkt->vp_if)) {
    2045             :         /* Pkt entering vrouter from hbs-l
    2046             :          *   - DMAC of the packet contains flow_index
    2047             :          *   - Restore actual DMAC from flow_index and continue
    2048             :          *     flow action
    2049             :          * If VR_HBS_FROM_VMI is set in the DMAC -
    2050             :          *   - The packet originated from VMI (instead of fabric)
    2051             :          *   - Happens if both src and dst tenant VMs are in
    2052             :          *     the same compute (intra-compute case)
    2053             :          *   - Restore actual DMAC from "reverse flow_index"
    2054             :          */
    2055           4 :         struct vr_eth *eth = (struct vr_eth*)pkt_data(pkt);
    2056           4 :         struct vr_eth_hbs_md *eth_hbs = (struct vr_eth_hbs_md*)pkt_data(pkt);
    2057           4 :         uint16_t magic = ntohs(eth_hbs->magic_dmac);
    2058           4 :         unsigned int flow_index = ntohl(eth_hbs->flow_id_dmac);
    2059             :         uint32_t nh_id;
    2060           4 :         struct vr_flow_entry *fe = NULL;
    2061           4 :         if ((magic & VR_HBS_MAGIC_MASK) != VR_HBS_DMAC_MAGIC) {
    2062           0 :             PKT_LOG(VP_DROP_INVALID_HBS_PKT, pkt, 0, VR_FLOW_C, __LINE__);
    2063           0 :             goto drop_pkt;
    2064             :         }
    2065             : 
    2066           4 :         if (vr_htable_get_hentry_by_index(router->vr_flow_table, flow_index)) {
    2067             :             struct vr_nexthop *nh;
    2068           4 :             fe = CONTAINER_OF(
    2069             :                            fe_hentry,
    2070             :                            struct vr_flow_entry,
    2071             :                            vr_htable_get_hentry_by_index(
    2072             :                                 router->vr_flow_table, flow_index)
    2073             :                              );
    2074             :             /* If packet is coming from VMI instead of fabric,
    2075             :              * restore DMAC using reverse flow
    2076             :              */
    2077           4 :             if (magic & VR_HBS_FROM_VMI) {
    2078           2 :                 flow_index = fe->fe_rflow;
    2079           2 :                 fe = vr_flow_get_entry(router, fe->fe_rflow);
    2080           2 :                 if (!fe) {
    2081           0 :                     PKT_LOG(VP_DROP_INVALID_HBS_PKT, pkt, 0, VR_FLOW_C, __LINE__);
    2082           0 :                     goto drop_pkt;
    2083             :                 }
    2084             :             }
    2085             : 
    2086           4 :             nh_id = fe->fe_key.flow_nh_id;
    2087           4 :             nh = vrouter_get_nexthop(0, nh_id);
    2088           4 :             vr_reinit_forwarding_md(router, pkt, fe, flow_index, nh, fmd);
    2089             : 
    2090           4 :             if(fe->fe_underlay_ecmp_index >= 0) {
    2091           0 :                 if(nh->nh_type == NH_TUNNEL) {
    2092           0 :                     pkt->vp_if = __vrouter_get_interface(router,
    2093           0 :                             fe->fe_underlay_ecmp_index);
    2094             :                 } else
    2095           0 :                     pkt->vp_if = nh->nh_dev;
    2096             :             } else
    2097           4 :                 pkt->vp_if = nh->nh_dev;
    2098             : 
    2099           4 :             if (magic & VR_HBS_L3_PKT)
    2100           0 :                memcpy(eth->eth_dmac, pkt->vp_if->vif_mac, VR_ETHER_ALEN);
    2101             :             else
    2102           4 :                 memcpy(eth->eth_dmac, nh->nh_data, VR_ETHER_ALEN);
    2103           4 :             result = vr_flow_action_default(router, fe, flow_index, pkt, fmd);
    2104           4 :             return __vr_flow_forward(result, pkt, fmd);
    2105             :         }
    2106         178 :     } else if ((!(pkt->vp_flags & VP_FLAG_MULTICAST))
    2107         178 :         && ((fmd->fmd_vlan == VLAN_ID_INVALID) || vif_is_service(pkt->vp_if)))
    2108         170 :         result = vr_do_flow_lookup(router, pkt, fmd);
    2109             : 
    2110         178 :     return __vr_flow_forward(result, pkt, fmd);
    2111             : 
    2112           0 : drop_pkt:
    2113           0 :     vr_pfree(pkt, VP_DROP_INVALID_HBS_PKT);
    2114           0 :     return false;
    2115             : }
    2116             : 
    2117             : int
    2118          29 : vr_flow_flush_pnode(struct vrouter *router, struct vr_packet_node *pnode,
    2119             :         struct vr_flow_entry *fe, struct vr_forwarding_md *fmd)
    2120             : {
    2121             :     bool forward;
    2122             : 
    2123             :     struct vr_interface *vif;
    2124             :     struct vr_packet *pkt;
    2125             :     struct vr_ip *ip;
    2126             :     struct vr_ip6 *ip6;
    2127             :     flow_result_t result;
    2128             : 
    2129          29 :     fmd->fmd_outer_src_ip = pnode->pl_outer_src_ip;
    2130          29 :     if (pnode->pl_flags & PN_FLAG_LABEL_IS_VXLAN_ID) {
    2131           0 :         vr_fmd_set_label(fmd, pnode->pl_label,
    2132             :                 VR_LABEL_TYPE_VXLAN_ID);
    2133             :     } else {
    2134          29 :         vr_fmd_set_label(fmd, pnode->pl_label,
    2135             :                 VR_LABEL_TYPE_MPLS);
    2136             :     }
    2137             : 
    2138          29 :     if (pnode->pl_flags & PN_FLAG_TO_ME)
    2139           0 :         fmd->fmd_to_me = 1;
    2140             : 
    2141          29 :     pkt = pnode->pl_packet;
    2142          29 :     if (!pkt)
    2143          14 :         return -EINVAL;
    2144             : 
    2145          15 :     fmd->fmd_dscp = pnode->pl_dscp;
    2146          15 :     fmd->fmd_dotonep = pnode->pl_dotonep;
    2147          15 :     fmd->fmd_vlan = pnode->pl_vlan;
    2148          15 :     fmd->fmd_mirror_data = pnode->pl_mirror_vlan;
    2149             : 
    2150          15 :     pnode->pl_packet = NULL;
    2151             :     /*
    2152             :      * this is only a security check and not a catch all check. one note
    2153             :      * of caution. please do not access pkt->vp_if till the if block is
    2154             :      * succesfully bypassed
    2155             :      */
    2156          15 :     vif = __vrouter_get_interface(router, pnode->pl_vif_idx);
    2157          15 :     if (!vif || (pkt->vp_if != vif)) {
    2158           5 :         pkt->vp_if = NULL;
    2159           5 :         PKT_LOG(VP_DROP_INVALID_IF, pkt, 0, VR_FLOW_C, __LINE__);
    2160           5 :         vr_pfree(pkt, VP_DROP_INVALID_IF);
    2161           5 :         return -ENODEV;
    2162             :     }
    2163             : 
    2164          10 :     if (!pkt->vp_nh) {
    2165          10 :         if (vif_is_fabric(pkt->vp_if) && fmd &&
    2166           1 :                 (fmd->fmd_label >= 0)) {
    2167           1 :             if (!vr_fmd_label_is_vxlan_id(fmd)) {
    2168           1 :                 pkt->vp_nh = __vrouter_get_label(router, fmd->fmd_label);
    2169             :             }  else {
    2170           0 :                 pkt->vp_nh = __vrouter_bridge_lookup(fmd->fmd_dvrf,
    2171             :                                                         pkt_data(pkt));
    2172             :             }
    2173             :         }
    2174          10 :         if(vif_is_vhost(vif) && !(vif->vif_flags & VIF_FLAG_POLICY_ENABLED)) {
    2175           1 :             if (pkt->vp_type == VP_TYPE_IP) {
    2176           1 :                 ip = (struct vr_ip *) pkt_network_header(pkt);
    2177           1 :                 pkt->vp_nh = vr_inet_ip_lookup(pnode->pl_vrf, ip->ip_daddr);
    2178           0 :             } else if (pkt->vp_type == VP_TYPE_IP6) {
    2179           0 :                 ip6 = (struct vr_ip6 *) pkt_network_header(pkt);
    2180           0 :                 pkt->vp_nh = vr_inet6_ip_lookup(pnode->pl_vrf, ip6->ip6_dst);
    2181             :             }
    2182             :         }
    2183             :     }
    2184             : 
    2185          10 :     if (fe) {
    2186           2 :         result = vr_flow_action(router, fe, fmd->fmd_flow_index, pkt, fmd);
    2187           2 :         forward = __vr_flow_forward(result, pkt, fmd);
    2188             :     } else {
    2189           8 :         forward = vr_flow_forward(router, pkt, fmd);
    2190             :     }
    2191             : 
    2192          10 :     if (forward)
    2193           9 :         vr_reinject_packet(pkt, fmd);
    2194             : 
    2195          10 :     return 0;
    2196             : }
    2197             : 
    2198             : static void
    2199           7 : __vr_flow_flush_hold_queue(struct vrouter *router, struct vr_flow_entry *fe,
    2200             :         struct vr_forwarding_md *fmd, struct vr_flow_queue *vfq)
    2201             : {
    2202             :     unsigned int i;
    2203             :     struct vr_packet_node *pnode;
    2204             : 
    2205          28 :     for (i = 0; i < VR_MAX_FLOW_QUEUE_ENTRIES; i++) {
    2206          21 :         pnode = &vfq->vfq_pnodes[i];
    2207          21 :         vr_flow_flush_pnode(router, pnode, fe, fmd);
    2208             :     }
    2209             : 
    2210           7 :     return;
    2211             : }
    2212             : 
    2213             : static void
    2214         329 : vr_flush_entry(struct vrouter *router, struct vr_flow_entry *fe,
    2215             :         struct vr_flow_md *flmd, struct vr_forwarding_md *fmd)
    2216             : {
    2217             :     bool swapped;
    2218             : 
    2219             :     struct vr_flow_queue *vfq;
    2220         329 :     struct vr_defer_data *vdd = flmd->flmd_defer_data;
    2221             :     struct vr_flow_defer_data *vfdd;
    2222             : 
    2223         329 :     vfq = fe->fe_hold_list;
    2224         329 :     if (vfq) {
    2225           5 :         if (fe->fe_action == VR_FLOW_ACTION_HOLD)
    2226           0 :             return;
    2227             : 
    2228           5 :         swapped = vr_sync_bool_compare_and_swap_p(&fe->fe_hold_list, vfq, NULL);
    2229           5 :         if (swapped) {
    2230           5 :             __vr_flow_flush_hold_queue(router, fe, fmd, vfq);
    2231           5 :             if (!vdd || !vdd->vdd_data)
    2232           3 :                 goto free_flush_queue;
    2233             : 
    2234           2 :             vfdd = (struct vr_flow_defer_data *)vdd->vdd_data;
    2235           2 :             vfdd->vfdd_flow_queue = vfq;
    2236             :         }
    2237             :     }
    2238             : 
    2239         326 :     return;
    2240             : 
    2241           3 : free_flush_queue:
    2242           3 :     if (vfq)
    2243           3 :         vr_free(vfq, VR_FLOW_QUEUE_OBJECT);
    2244           3 :     return;
    2245             : }
    2246             : 
    2247             : static void
    2248         318 : __vr_flow_work(struct vrouter *router, struct vr_flow_entry *fe,
    2249             :         struct vr_flow_md *flmd)
    2250             : {
    2251             :     struct vr_forwarding_md fmd;
    2252             : 
    2253         318 :     vr_init_forwarding_md(&fmd);
    2254         318 :     vr_flow_set_forwarding_md(router, fe, flmd->flmd_index, &fmd);
    2255         318 :     vr_flush_entry(router, fe, flmd, &fmd);
    2256             : 
    2257         318 :     vr_flow_defer(flmd, fe);
    2258         318 :     return;
    2259             : }
    2260             : 
    2261             : 
    2262             : static void
    2263         318 : vr_flow_work(void *arg)
    2264             : {
    2265             :     struct vrouter *router;
    2266             :     struct vr_flow_entry *fe;
    2267         318 :     struct vr_flow_md *flmd =
    2268             :                 (struct vr_flow_md *)arg;
    2269             : 
    2270         318 :     router = flmd->flmd_router;
    2271         318 :     if (!router)
    2272           0 :         goto exit_flush;
    2273             : 
    2274         318 :     fe = vr_flow_get_entry(router, flmd->flmd_index);
    2275         318 :     if (!fe)
    2276           0 :         goto exit_flush;
    2277             : 
    2278         318 :     __vr_flow_work(router, fe, flmd);
    2279             : 
    2280         318 : exit_flush:
    2281         318 :     if (flmd->flmd_defer_data) {
    2282           0 :         if (flmd->flmd_defer_data->vdd_data) {
    2283           0 :             vr_free(flmd->flmd_defer_data->vdd_data,
    2284             :                     VR_FLOW_DEFER_DATA_OBJECT);
    2285             :         }
    2286           0 :         vr_put_defer_data(flmd->flmd_defer_data);
    2287           0 :         flmd->flmd_defer_data = NULL;
    2288             :     }
    2289             : 
    2290         318 :     vr_free(flmd, VR_FLOW_METADATA_OBJECT);
    2291             : 
    2292         318 :     return;
    2293             : }
    2294             : 
    2295             : static void
    2296         216 : vr_flow_set_mirror(struct vrouter *router, vr_flow_req *req,
    2297             :         struct vr_flow_entry *fe)
    2298             : {
    2299         216 :     struct vr_mirror_entry *mirror = NULL, *sec_mirror = NULL;
    2300             : 
    2301         216 :     if (!(req->fr_flags & VR_FLOW_FLAG_MIRROR) &&
    2302         214 :             (fe->fe_flags & VR_FLOW_FLAG_MIRROR)) {
    2303           0 :         vr_flow_reset_mirror(router, fe, req->fr_index);
    2304           0 :         return;
    2305             :     }
    2306             : 
    2307         216 :     if (!(req->fr_flags & VR_FLOW_FLAG_MIRROR))
    2308         214 :         return;
    2309             : 
    2310           2 :     if (fe->fe_mirror_id != req->fr_mir_id) {
    2311           2 :         if (fe->fe_mirror_id < router->vr_max_mirror_indices) {
    2312           0 :             fe->fe_mirror_id = router->vr_max_mirror_indices;
    2313             :         }
    2314             : 
    2315           2 :         if ((unsigned int)req->fr_mir_id < router->vr_max_mirror_indices) {
    2316           2 :             mirror = vrouter_get_mirror(req->fr_rid, req->fr_mir_id);
    2317           2 :             if (mirror)
    2318           2 :                 fe->fe_mirror_id = req->fr_mir_id;
    2319             : 
    2320             :             /* when we reached this point, we had already done all the
    2321             :              * sanity checks we could do. failing here will add only
    2322             :              * complexity to code here. so !mirror case, we will not
    2323             :              * handle
    2324             :              */
    2325             :         }
    2326             :     }
    2327             : 
    2328           2 :     if (fe->fe_sec_mirror_id != req->fr_sec_mir_id) {
    2329           2 :         if (fe->fe_sec_mirror_id < router->vr_max_mirror_indices) {
    2330           0 :             fe->fe_sec_mirror_id = router->vr_max_mirror_indices;
    2331             :         }
    2332             : 
    2333           2 :         if ((unsigned int)req->fr_sec_mir_id < router->vr_max_mirror_indices) {
    2334           2 :             sec_mirror = vrouter_get_mirror(req->fr_rid, req->fr_sec_mir_id);
    2335           2 :             if (sec_mirror)
    2336           0 :                 fe->fe_sec_mirror_id = req->fr_sec_mir_id;
    2337             :         }
    2338             :     }
    2339             : 
    2340           2 :     if (req->fr_pcap_meta_data_size && req->fr_pcap_meta_data) {
    2341           0 :         if (fe->fe_mme) {
    2342           0 :             vr_mirror_meta_entry_del(router, fe->fe_mme);
    2343           0 :             fe->fe_mme = NULL;
    2344             :         }
    2345             : 
    2346           0 :         fe->fe_mme = vr_mirror_meta_entry_set(router, req->fr_index,
    2347           0 :                 req->fr_mir_sip, req->fr_mir_sport,
    2348           0 :                 req->fr_pcap_meta_data, req->fr_pcap_meta_data_size,
    2349           0 :                 req->fr_mir_vrf);
    2350             : 
    2351           0 :         if (fe->fe_mme) {
    2352           0 :             vr_offload_flow_meta_data_set(req->fr_index,
    2353             :                                           req->fr_pcap_meta_data_size,
    2354           0 :                                           req->fr_pcap_meta_data,
    2355           0 :                                           req->fr_mir_vrf);
    2356             :         }
    2357             :     }
    2358             : 
    2359           2 :     return;
    2360             : }
    2361             : 
    2362             : void
    2363         184 : vr_fill_flow_common(struct vr_flow *flowp, unsigned int nh_id,
    2364             :         uint8_t proto, uint16_t sport, uint16_t dport, uint8_t family,
    2365             :         uint8_t valid_fkey_params)
    2366             : {
    2367         184 :     flowp->flow_nh_id = nh_id;
    2368         184 :     flowp->flow_family = family;
    2369         184 :     if (family == AF_INET)
    2370         174 :         flowp->flow_key_len = VR_FLOW_IPV4_HASH_SIZE;
    2371             :     else
    2372          10 :         flowp->flow_key_len = VR_FLOW_IPV6_HASH_SIZE;
    2373         184 :     flowp->flow_unused = 0;
    2374             : 
    2375         184 :     if (valid_fkey_params & VR_FLOW_KEY_PROTO)
    2376         184 :         flowp->flow_proto = proto;
    2377             : 
    2378         184 :     if (valid_fkey_params & VR_FLOW_KEY_SRC_PORT)
    2379         184 :         flowp->flow_sport = sport;
    2380             : 
    2381         184 :     if (valid_fkey_params & VR_FLOW_KEY_DST_PORT)
    2382         184 :         flowp->flow_dport = dport;
    2383             : 
    2384         184 :     return;
    2385             : }
    2386             : 
    2387             : static struct vr_flow_entry *
    2388         104 : vr_add_flow(unsigned int rid, struct vr_flow *key, uint8_t type,
    2389             :         bool need_hold_queue, unsigned int *fe_index,
    2390             :         uint8_t *fe_gen_id)
    2391             : {
    2392             :     struct vr_flow_entry *flow_e;
    2393         104 :     struct vrouter *router = vrouter_get(rid);
    2394             : 
    2395         104 :     struct vr_flow_entry *bucket_fe = vr_flow_bucket_first_entry(router, key);
    2396         104 :     vr_flow_bucket_may_lock(bucket_fe);
    2397         104 :     flow_e = vr_find_flow(router, key, type, fe_index);
    2398         104 :     if (flow_e) {
    2399           0 :         vr_flow_bucket_may_unlock(bucket_fe);
    2400           0 :         *fe_gen_id = flow_e->fe_gen_id;
    2401             :         /* a race between agent and dp. allow agent to handle this error */
    2402           0 :         return NULL;
    2403             :     } else {
    2404         104 :         flow_e = vr_flow_get_free_entry(router, key, type,
    2405             :                 need_hold_queue, fe_index);
    2406         104 :         vr_flow_bucket_may_unlock(bucket_fe);
    2407             :     }
    2408             : 
    2409         104 :     return flow_e;
    2410             : }
    2411             : 
    2412             : static struct vr_flow_entry *
    2413         104 : vr_add_flow_req(vr_flow_req *req, unsigned int *fe_index, uint8_t *fe_gen_id)
    2414             : {
    2415             :     uint8_t type;
    2416         104 :     bool need_hold_queue = false;
    2417             : 
    2418             :     struct vr_flow key;
    2419             :     struct vr_flow_entry *fe;
    2420             : 
    2421         104 :     switch (req->fr_family) {
    2422           6 :     case  AF_INET6:
    2423           6 :         type = VP_TYPE_IP6;
    2424           6 :         vr_inet6_fill_flow_from_req(&key, req);
    2425           6 :         break;
    2426             : 
    2427          98 :     case  AF_INET:
    2428          98 :         type = VP_TYPE_IP;
    2429          98 :         vr_inet_fill_flow(&key, req->fr_flow_nh_id,
    2430          98 :             (uint32_t)req->fr_flow_sip_l, (uint32_t)req->fr_flow_dip_l,
    2431          98 :             req->fr_flow_proto, req->fr_flow_sport, req->fr_flow_dport,
    2432             :             VR_FLOW_KEY_ALL);
    2433          98 :         break;
    2434             : 
    2435           0 :     default:
    2436           0 :         return NULL;
    2437             :     }
    2438             : 
    2439         104 :     if (req->fr_action == VR_FLOW_ACTION_HOLD)
    2440           0 :         need_hold_queue = true;
    2441             : 
    2442         104 :     fe = vr_add_flow(req->fr_rid, &key, type, need_hold_queue, fe_index,
    2443             :                      fe_gen_id);
    2444         104 :     if (fe)
    2445         104 :         req->fr_index = *fe_index;
    2446             : 
    2447         104 :     return fe;
    2448             : }
    2449             : 
    2450             : /*
    2451             :  * can be called with 'fe' as null (specifically when flow is added from
    2452             :  * agent), in which case we should be checking only the request
    2453             :  */
    2454             : static int
    2455         322 : vr_flow_set_req_is_invalid(struct vrouter *router, vr_flow_req *req,
    2456             :         struct vr_flow_entry *fe)
    2457             : {
    2458         322 :     int error = 0, key_type;
    2459             :     struct vr_flow_entry *rfe;
    2460             :     struct vr_flow key;
    2461             :     uint64_t *ip;
    2462             : 
    2463         322 :     if (fe) {
    2464             : 
    2465             :         /* If Delete marked, dont allow any other change */
    2466         210 :         if (fe->fe_flags & VR_FLOW_FLAG_DELETE_MARKED)
    2467           0 :             return -EINVAL;
    2468             : 
    2469         210 :         if ((fe->fe_type == VP_TYPE_IP) || (fe->fe_type == VP_TYPE_IP6)) {
    2470         210 :             if ((uint8_t)req->fr_gen_id != fe->fe_gen_id) {
    2471           0 :                 error = -EBADF;
    2472           0 :                 goto invalid_req;
    2473             :             }
    2474             : 
    2475             :             /*
    2476             :              * when gen id is same flow keys should not mis-match
    2477             :              * send EFAULT if such incident happens
    2478             :              */
    2479         210 :             if((unsigned short)req->fr_flow_sport != fe->fe_key.flow_sport ||
    2480         210 :                     (unsigned short)req->fr_flow_dport != fe->fe_key.flow_dport||
    2481         210 :                     (uint32_t) req->fr_flow_nh_id != (uint32_t) fe->fe_key.flow_nh_id ||
    2482         210 :                     (unsigned char)req->fr_flow_proto != fe->fe_key.flow_proto) {
    2483           0 :                 error = -EFAULT;
    2484           0 :                 goto invalid_req;
    2485             :             }
    2486             : 
    2487         210 :             if (fe->fe_type == VP_TYPE_IP) {
    2488         200 :                 if ((fe->fe_key.flow4_sip != (uint32_t)req->fr_flow_sip_l) ||
    2489         200 :                         (fe->fe_key.flow4_dip != (uint32_t)req->fr_flow_dip_l)) {
    2490           0 :                     error = -EFAULT;
    2491           0 :                     goto invalid_req;
    2492             :                 }
    2493             :             } else {
    2494          10 :                 ip = (uint64_t *)fe->fe_key.flow6_sip;
    2495          10 :                 if ((*ip != req->fr_flow_sip_u) ||
    2496          10 :                         (*(ip+1) != req->fr_flow_sip_l) ||
    2497          10 :                         (*(ip+2) != req->fr_flow_dip_u) ||
    2498          10 :                         (*(ip+3) != req->fr_flow_dip_l)) {
    2499           0 :                     error = -EFAULT;
    2500           0 :                     goto invalid_req;
    2501             :                 }
    2502             :             }
    2503             :         }
    2504             :     } else {
    2505             :         /*
    2506             :          * flow set request received with an index which is
    2507             :          * not active anymore, return ENOENT error
    2508             :          */
    2509         112 :         if ((req->fr_flags & VR_FLOW_FLAG_ACTIVE) && !(req->fr_index < 0)) {
    2510           0 :             error = -ENOENT;
    2511           0 :             goto invalid_req;
    2512             :         }
    2513             :     }
    2514             : 
    2515         322 :     if (req->fr_flags & VR_FLOW_FLAG_VRFT) {
    2516          12 :         if ((unsigned short)req->fr_flow_dvrf >= router->vr_max_vrfs) {
    2517           0 :             error = -EINVAL;
    2518           0 :             goto invalid_req;
    2519             :         }
    2520             :     }
    2521             : 
    2522         322 :     if (req->fr_flags & VR_FLOW_FLAG_MIRROR) {
    2523           2 :         if (((unsigned int)req->fr_mir_id >= router->vr_max_mirror_indices) &&
    2524           0 :                 (unsigned int)req->fr_sec_mir_id >= router->vr_max_mirror_indices) {
    2525           0 :             error = -EINVAL;
    2526           0 :             goto invalid_req;
    2527             :         }
    2528             :     }
    2529             : 
    2530         322 :     if (req->fr_flags & VR_RFLOW_VALID) {
    2531         160 :         if (req->fr_rindex != -1) {
    2532         160 :             rfe = vr_flow_get_entry(router, req->fr_rindex);
    2533             :         } else {
    2534           0 :             if (req->fr_family == AF_INET) {
    2535           0 :                 vr_inet_fill_flow(&key, req->fr_rflow_nh_id,
    2536           0 :                   (uint32_t)req->fr_rflow_sip_l, (uint32_t)req->fr_rflow_dip_l,
    2537           0 :                   req->fr_flow_proto, req->fr_rflow_sport,
    2538           0 :                   req->fr_rflow_dport, VR_FLOW_KEY_ALL);
    2539             : 
    2540           0 :                 key_type = VP_TYPE_IP;
    2541             :             } else {
    2542           0 :                 vr_inet6_fill_rflow_from_req(&key, req);
    2543           0 :                 key_type = VP_TYPE_IP6;
    2544             :             }
    2545             : 
    2546           0 :             rfe = vr_find_flow(router, &key, key_type,  &req->fr_rindex);
    2547             :         }
    2548             : 
    2549         160 :         if (!rfe) {
    2550           0 :             error = -EINVAL;
    2551           0 :             goto invalid_req;
    2552             :         }
    2553             :     }
    2554             : 
    2555         322 :     return 0;
    2556             : 
    2557           0 : invalid_req:
    2558           0 :     return error;
    2559             : }
    2560             : 
    2561             : static int
    2562         318 : __vr_flow_schedule_transition(struct vrouter *router, struct vr_flow_entry *fe,
    2563             :         unsigned int index, unsigned short flags)
    2564             : {
    2565             :     struct vr_flow_md *flmd;
    2566         318 :     struct vr_defer_data *defer = NULL;
    2567         318 :     struct vr_flow_entry *rfe = NULL;
    2568             : 
    2569         318 :     flmd = (struct vr_flow_md *)vr_malloc(sizeof(*flmd),
    2570             :             VR_FLOW_METADATA_OBJECT);
    2571         318 :     if (!flmd)
    2572           0 :         return -ENOMEM;
    2573             : 
    2574         318 :     flmd->flmd_router = router;
    2575         318 :     flmd->flmd_index = index;
    2576         318 :     flmd->flmd_flags = flags;
    2577         318 :     if (fe->fe_hold_list || (flags & VR_FLOW_FLAG_EVICT_CANDIDATE)) {
    2578           6 :         defer = vr_get_defer_data(sizeof(*defer));
    2579           6 :         if (defer) {
    2580           6 :             defer->vdd_data = (void *)vr_zalloc(sizeof(struct vr_flow_defer_data),
    2581             :                     VR_FLOW_DEFER_DATA_OBJECT);
    2582           6 :             if (!(flmd->flmd_flags & VR_FLOW_FLAG_ACTIVE)) {
    2583           0 :                 ((struct vr_flow_defer_data *)defer->vdd_data)->vfdd_delete =
    2584             :                     true;
    2585             :             }
    2586             :             /*
    2587             :              * Set vfdd_evict_flow to true only if there is only one flow
    2588             :              * or both flows have EVICT_CANDIDATE flag set;
    2589             :              * This is to avoid a race condition which can lead to non
    2590             :              * eviction of one of the flows. See CEM-4275 for more details.
    2591             :              *
    2592             :              * CEM-18166: Handle a corner case for BGPaaS where two different
    2593             :              * flows are trapped to agent (due to NAT translation to the same
    2594             :              * port), combined with TCP RST/FIN pkts received on the reverse
    2595             :              * flow. The sequence of events permits deletion of the FF, while
    2596             :              * RF still pointing to it. When the Controller tries to reset the
    2597             :              * connection, thus causing eviction the flow, vrouter will fail
    2598             :              * because rfe for the RF is NULL.
    2599             :              */
    2600           6 :             if ((fe->fe_flags & VR_FLOW_FLAG_EVICT_CANDIDATE)) {
    2601           8 :                 if ((fe->fe_rflow < 0) ||
    2602           4 :                     ((rfe = vr_flow_get_entry(router, fe->fe_rflow)) &&
    2603           4 :                      (rfe->fe_flags & VR_FLOW_FLAG_EVICT_CANDIDATE)) || !rfe) {
    2604           4 :                     ((struct vr_flow_defer_data *)defer->vdd_data)->vfdd_evict_flow =
    2605             :                              true;
    2606             :                 }
    2607             :             }
    2608             :         }
    2609             :     }
    2610         318 :     flmd->flmd_defer_data = defer;
    2611             : 
    2612         318 :     return vr_schedule_work(vr_get_cpu(), vr_flow_work, (void *)flmd);
    2613             : }
    2614             : 
    2615             : static int
    2616         314 : vr_flow_schedule_transition(struct vrouter *router, vr_flow_req *req,
    2617             :         struct vr_flow_entry *fe)
    2618             : {
    2619         314 :     return __vr_flow_schedule_transition(router, fe, req->fr_index, req->fr_flags);
    2620             : }
    2621             : 
    2622             : static int
    2623          98 : vr_flow_delete(struct vrouter *router, vr_flow_req *req,
    2624             :         struct vr_flow_entry *fe)
    2625             : {
    2626          98 :     int port = 0;
    2627             :     /* Delete Mark it */
    2628          98 :     fe->fe_flags |= VR_FLOW_FLAG_DELETE_MARKED;
    2629             : 
    2630             : 
    2631          98 :     if (fe->fe_flags & VR_FLOW_FLAG_LINK_LOCAL) {
    2632           3 :         if (fe->fe_key.flow_proto == VR_IP_PROTO_ICMP) {
    2633             :             /*
    2634             :              * ICMP id passed as source port would be
    2635             :              * used for relaxed policy flow lookup
    2636             :              */
    2637           1 :             port = ntohs(fe->fe_key.flow_sport);
    2638             :         } else {
    2639           2 :             port = ntohs(fe->fe_key.flow_dport);
    2640             :         }
    2641           3 :         vr_clear_link_local_port(router, AF_INET, fe->fe_key.flow_proto, port);
    2642             :     }
    2643             : 
    2644          98 :     fe->fe_action = VR_FLOW_ACTION_DROP;
    2645          98 :     vr_flow_reset_mirror(router, fe, req->fr_index);
    2646          98 :     return vr_flow_schedule_transition(router, req, fe);
    2647             : }
    2648             : 
    2649             : static void
    2650         216 : vr_flow_udp_src_port (struct vrouter *router, struct vr_flow_entry *fe)
    2651             : {
    2652             :     uint32_t hash_key[10], hashval, port_range, hash_len;
    2653             :     uint16_t port;
    2654             : 
    2655         216 :     if (fe->fe_udp_src_port)
    2656         110 :         return;
    2657             : 
    2658         106 :     if (hashrnd_inited == 0) {
    2659          33 :         get_random_bytes(&vr_hashrnd, sizeof(vr_hashrnd));
    2660          33 :         hashrnd_inited = 1;
    2661             :     }
    2662             : 
    2663         106 :     hash_key[0] = fe->fe_vrf;
    2664         106 :     hash_key[1] = (fe->fe_key.flow_sport << 16) | fe->fe_key.flow_dport;
    2665         106 :     memcpy(&hash_key[2], fe->fe_key.flow_ip, 2 * VR_IP_ADDR_SIZE(fe->fe_type));
    2666         106 :     hash_len = VR_FLOW_HASH_SIZE(fe->fe_type);
    2667             : 
    2668         106 :     hashval = vr_hash(hash_key, hash_len, vr_hashrnd);
    2669         106 :     port_range = VR_MUDP_PORT_RANGE_END - VR_MUDP_PORT_RANGE_START;
    2670         106 :     port = (uint16_t ) (((uint64_t ) hashval * port_range) >> 32);
    2671             : 
    2672         106 :     if (port > port_range) {
    2673             :         /*
    2674             :          * Shouldn't happen...
    2675             :          */
    2676           0 :         port = 0;
    2677             :     }
    2678         106 :     fe->fe_udp_src_port = port + VR_MUDP_PORT_RANGE_START;
    2679             : }
    2680             : 
    2681             : static void
    2682         216 : vr_flow_update_link_local_port(struct vrouter *router, vr_flow_req *req,
    2683             :         struct vr_flow_entry *fe)
    2684             : {
    2685         216 :     bool set_port = false;
    2686         216 :     int port = 0;
    2687             : 
    2688         216 :     if (!req || !fe)
    2689           0 :         return;
    2690             : 
    2691         216 :     if (fe->fe_type != VP_TYPE_IP)
    2692          10 :         return;
    2693             : 
    2694         206 :     if (fe->fe_key.flow_proto == VR_IP_PROTO_ICMP) {
    2695             :         /*
    2696             :          * ICMP id passed as source port would be
    2697             :          * used for relaxed policy flow lookup
    2698             :          */
    2699         173 :         port = ntohs(fe->fe_key.flow_sport);
    2700             :     } else {
    2701          33 :         port = ntohs(fe->fe_key.flow_dport);
    2702             :     }
    2703             : 
    2704         206 :     if (req->fr_flags & VR_FLOW_FLAG_LINK_LOCAL) {
    2705           4 :         if (!(fe->fe_flags & VR_FLOW_FLAG_LINK_LOCAL))
    2706           2 :             set_port = true;
    2707         202 :     } else if (fe->fe_flags & VR_FLOW_FLAG_LINK_LOCAL) {
    2708           0 :         vr_clear_link_local_port(router, AF_INET, fe->fe_key.flow_proto,
    2709             :                                                   port);
    2710             :     }
    2711             : 
    2712         206 :     if (req->fr_flags & VR_FLOW_BGP_SERVICE) {
    2713           0 :         if (!(fe->fe_flags & VR_FLOW_BGP_SERVICE))
    2714           0 :             set_port = true;
    2715             :     }
    2716             : 
    2717         206 :     if (set_port) {
    2718           2 :         vr_set_link_local_port(router, AF_INET, fe->fe_key.flow_proto, port);
    2719             :     }
    2720             : 
    2721         206 :     return;
    2722             : }
    2723             : 
    2724             : static int
    2725           0 : vr_flow_force_evict (struct vrouter *router, vr_flow_req *req)
    2726             : {
    2727           0 :     struct vr_flow_entry *fe = NULL;
    2728             : 
    2729           0 :     fe = vr_flow_get_entry(router, req->fr_index);
    2730           0 :     if (fe) {
    2731             :         /* Do force eviction only for TCP flows with dead flag set */
    2732           0 :         if (fe->fe_key.flow_proto != VR_IP_PROTO_TCP) {
    2733           0 :             return -EINVAL;
    2734             :         }
    2735           0 :         if (!(fe->fe_tcp_flags & VR_FLOW_TCP_DEAD)) {
    2736           0 :             return -EINVAL;
    2737             :         }
    2738           0 :         if (!(fe->fe_flags & VR_FLOW_FLAG_ACTIVE)) {
    2739           0 :             return -EINVAL;
    2740             :         }
    2741             :         /*
    2742             :          * We have a TCP flow which is dead,
    2743             :          * Evict Candidate may or may not be set
    2744             :          */
    2745           0 :         vr_flow_start_modify(router, fe);
    2746             :         /*
    2747             :          * Reset flow's reverse flow index as we don't want to
    2748             :          * touch reverse flow
    2749             :          */
    2750           0 :         fe->fe_flags &= ~VR_RFLOW_VALID;
    2751           0 :         fe->fe_rflow = -1;
    2752           0 :         if (!(fe->fe_flags & VR_FLOW_FLAG_EVICT_CANDIDATE)) {
    2753           0 :             __vr_flow_mark_evict(router, fe);
    2754             :         }
    2755           0 :         __vr_flow_schedule_transition(router, fe, req->fr_index, fe->fe_flags);
    2756             :     } else {
    2757           0 :         return -EINVAL;
    2758             :     }
    2759           0 :     return 0;
    2760             : }
    2761             : 
    2762             : 
    2763             : /* command from agent */
    2764             : static int
    2765         322 : vr_flow_set(struct vrouter *router, vr_flow_req *req,
    2766             :             vr_flow_response *flow_resp)
    2767           0 : {
    2768             :     int ret;
    2769             :     int8_t cur_fe_underlay_ecmp_index;
    2770         322 :     unsigned int fe_index = (unsigned int)-1;
    2771         322 :     uint8_t fe_gen_id = 0;
    2772         322 :     bool new_flow = false, modified = false;
    2773             : 
    2774         322 :     struct vr_flow_entry *fe = NULL, *rfe = NULL;
    2775         322 :     struct vr_flow_table_info *infop = router->vr_flow_table_info;
    2776             : 
    2777         322 :     router = vrouter_get(req->fr_rid);
    2778         322 :     if (!router)
    2779           0 :         return -EINVAL;
    2780             : 
    2781         322 :     flow_resp->fresp_index = req->fr_index;
    2782             : 
    2783         322 :     if (req->fr_extflags & VR_FLOW_EXT_FLAG_FORCE_EVICT) {
    2784           0 :         return vr_flow_force_evict(router, req);
    2785             :     }
    2786             : 
    2787         322 :     fe = vr_flow_get_entry(router, req->fr_index);
    2788         322 :     if (fe) {
    2789         210 :         if (!(modified = vr_flow_start_modify(router, fe)))
    2790           0 :             return -EBUSY;
    2791         210 :         fe_index = (unsigned int)(req->fr_index);
    2792             :     }
    2793             : 
    2794         322 :     if ((ret = vr_flow_set_req_is_invalid(router, req, fe)))
    2795           0 :         goto exit_set;
    2796             : 
    2797         322 :     if (fe) {
    2798         210 :         if ((fe->fe_action == VR_FLOW_ACTION_HOLD) &&
    2799           2 :             ((req->fr_action != fe->fe_action) ||
    2800           0 :              !(req->fr_flags & VR_FLOW_FLAG_ACTIVE))) {
    2801           2 :             vr_sync_fetch_and_add_64u(&infop->vfti_action_count, 1);
    2802             :         } else {
    2803         208 :             infop->vfti_changed++;
    2804             :         }
    2805             : 
    2806             :     }
    2807             :     /*
    2808             :      * for delete, absence of the requested flow entry is caustic. so
    2809             :      * handle that case first
    2810             :      */
    2811         322 :     if (!(req->fr_flags & VR_FLOW_FLAG_ACTIVE)) {
    2812         106 :         if (!fe)
    2813           8 :             return -ENOENT;
    2814             : 
    2815          98 :         infop->vfti_deleted++;
    2816          98 :         flow_resp->fresp_flags |= VR_FLOW_RESP_FLAG_DELETED;
    2817          98 :         return vr_flow_delete(router, req, fe);
    2818             :     }
    2819             : 
    2820             : 
    2821             :     /*
    2822             :      * for non-delete cases, absence of flow entry means addition of a
    2823             :      * new flow entry with the key specified in the request
    2824             :      */
    2825         216 :     if (!fe) {
    2826         104 :         fe = vr_add_flow_req(req, &fe_index, &fe_gen_id);
    2827         104 :         if (!fe) {
    2828           0 :             if (fe_index != (unsigned int)-1) {
    2829             :                 /*
    2830             :                  * add flow req failed to allocate an entry due to race
    2831             :                  * between agent and datapath, where flow entry at fe_index
    2832             :                  * was already created due to packet trap, return EEXIST
    2833             :                  * error and allow agent to wait and handle flow add due to
    2834             :                  * packet trap
    2835             :                  */
    2836           0 :                 flow_resp->fresp_index = fe_index;
    2837           0 :                 flow_resp->fresp_gen_id = fe_gen_id;
    2838           0 :                 return -EEXIST;
    2839             :             }
    2840           0 :             return -ENOSPC;
    2841             :         }
    2842             : 
    2843         104 :         new_flow = true;
    2844         104 :         infop->vfti_added++;
    2845             :     } else {
    2846         112 :         if ((req->fr_action == VR_FLOW_ACTION_HOLD) &&
    2847           0 :                 (fe->fe_action != req->fr_action)) {
    2848           0 :             if (!fe->fe_hold_list) {
    2849           0 :                 fe->fe_hold_list = vr_zalloc(sizeof(struct vr_flow_queue),
    2850             :                         VR_FLOW_QUEUE_OBJECT);
    2851           0 :                 if (!fe->fe_hold_list) {
    2852           0 :                     ret = -ENOMEM;
    2853           0 :                     goto exit_set;
    2854             :                 }
    2855             :             }
    2856             :         }
    2857             :     }
    2858             : 
    2859         216 :     flow_resp->fresp_gen_id = fe->fe_gen_id;
    2860         216 :     flow_resp->fresp_index = fe->fe_hentry.hentry_index;
    2861             : 
    2862         216 :     vr_flow_set_mirror(router, req, fe);
    2863             : 
    2864         216 :     if (req->fr_flags & VR_RFLOW_VALID) {
    2865         160 :         fe->fe_rflow = req->fr_rindex;
    2866             :     } else {
    2867          56 :         if (fe->fe_rflow >= 0)
    2868           0 :             fe->fe_rflow = -1;
    2869             :     }
    2870             : 
    2871         216 :     fe->fe_vrf = req->fr_flow_vrf;
    2872         216 :     if (req->fr_flags & VR_FLOW_FLAG_VRFT)
    2873          12 :         fe->fe_dvrf = req->fr_flow_dvrf;
    2874             : 
    2875         216 :     vr_flow_update_link_local_port(router, req, fe);
    2876             : 
    2877         216 :     if (fe->fe_ecmp_nh_index == -1)
    2878         216 :         (void)vr_sync_bool_compare_and_swap_8s(&fe->fe_ecmp_nh_index, -1,
    2879             :                 req->fr_ecmp_nh_index);
    2880             : 
    2881         216 :     fe->fe_src_nh_index = req->fr_src_nh_index;
    2882         216 :     fe->fe_qos_id = req->fr_qos_id;
    2883             : 
    2884         216 :     if ((req->fr_action == VR_FLOW_ACTION_HOLD) &&
    2885           0 :             (fe->fe_action != VR_FLOW_ACTION_HOLD)) {
    2886           0 :         vr_flow_entry_set_hold(router, fe, false);
    2887             :     } else {
    2888         216 :         fe->fe_action = req->fr_action;
    2889             :     }
    2890             : 
    2891         216 :     fe->fe_ttl = req->fr_ttl;
    2892             : 
    2893         216 :     cur_fe_underlay_ecmp_index = req->fr_underlay_ecmp_index;
    2894             :     /* repeats until the comapre and swap operation is successful */
    2895         216 :     while(!vr_sync_bool_compare_and_swap_8s(&fe->fe_underlay_ecmp_index,
    2896             :             fe->fe_underlay_ecmp_index, cur_fe_underlay_ecmp_index)) {
    2897           0 :         continue;
    2898             :     }
    2899             : 
    2900         216 :     if (fe->fe_action == VR_FLOW_ACTION_DROP)
    2901           0 :         fe->fe_drop_reason = (uint8_t)req->fr_drop_reason;
    2902             : 
    2903         216 :     fe->fe_flags = VR_FLOW_FLAG_DP_BITS(fe) |
    2904         216 :         VR_FLOW_FLAG_MASK(req->fr_flags);
    2905         216 :     fe->fe_flags1 = req->fr_flags1;
    2906         216 :     if (new_flow) {
    2907             : 
    2908         104 :         flow_resp->fresp_bytes = fe->fe_stats.flow_bytes;
    2909         104 :         flow_resp->fresp_packets = fe->fe_stats.flow_packets;
    2910         104 :         flow_resp->fresp_stats_oflow = (fe->fe_stats.flow_bytes_oflow |
    2911         104 :                                     (fe->fe_stats.flow_packets_oflow << 16));
    2912             : 
    2913         104 :         if (fe->fe_flags & VR_FLOW_FLAG_NEW_FLOW) {
    2914         104 :             if (fe->fe_stats.flow_packets || fe->fe_stats.flow_packets_oflow)
    2915           0 :                 memset(&fe->fe_stats, 0, sizeof(fe->fe_stats));
    2916             :         }
    2917             : 
    2918         104 :         if (fe->fe_flags & VR_RFLOW_VALID) {
    2919          49 :             rfe = vr_flow_get_entry(router, fe->fe_rflow);
    2920          49 :             if (rfe) {
    2921          49 :                 vr_flow_tcp_rflow_set(router, fe, rfe);
    2922             :             }
    2923             :         }
    2924             : 
    2925             :     }
    2926             : 
    2927         216 :     vr_flow_udp_src_port(router, fe);
    2928             : 
    2929             :     /* Mock Src UDP port used for vrouter simulation - vtest */
    2930         216 :     if(req->fr_extflags & VR_FLOW_EXT_FLAG_MOCK_SRC_UDP)
    2931           2 :         fe->fe_udp_src_port = VR_FLOW_MOCK_SRC_UDP_PORT;
    2932             : 
    2933         216 :     if (fe->fe_flags & VR_FLOW_FLAG_NEW_FLOW)
    2934         104 :         fe->fe_flags &= ~VR_FLOW_FLAG_NEW_FLOW;
    2935             : 
    2936             : 
    2937             : 
    2938         216 :     ret = vr_flow_schedule_transition(router, req, fe);
    2939             : 
    2940             :     /*
    2941             :      * offload, no need to differentiate between add and modify. Pass the
    2942             :      * reverse flow as well if present.
    2943             :      */
    2944         216 :     if (!ret) {
    2945         216 :         vr_offload_flow_set(fe, fe_index, rfe);
    2946             :     }
    2947             : 
    2948           0 : exit_set:
    2949         216 :     if (modified && fe) {
    2950         112 :         vr_flow_stop_modify(router, fe);
    2951             :     }
    2952             : 
    2953         216 :     return ret;
    2954             : }
    2955             : 
    2956             : static void
    2957          13 : vr_flow_table_data_destroy(vr_flow_table_data *ftable)
    2958             : {
    2959          13 :     if (!ftable)
    2960           0 :         return;
    2961             : 
    2962          13 :     if (ftable->ftable_file_path) {
    2963          13 :         vr_free(ftable->ftable_file_path, VR_FLOW_REQ_PATH_OBJECT);
    2964          13 :         ftable->ftable_file_path = NULL;
    2965             :     }
    2966             : 
    2967          13 :     if (ftable->ftable_hold_stat && ftable->ftable_hold_stat_size) {
    2968          13 :         vr_free(ftable->ftable_hold_stat, VR_FLOW_HOLD_STAT_OBJECT);
    2969          13 :         ftable->ftable_hold_stat = NULL;
    2970          13 :         ftable->ftable_hold_stat_size = 0;
    2971             :     }
    2972             : 
    2973          13 :     vr_free(ftable, VR_FLOW_TABLE_DATA_OBJECT);
    2974             : 
    2975          13 :     return;
    2976             : }
    2977             : 
    2978             : static vr_flow_table_data *
    2979          13 : vr_flow_table_data_get(vr_flow_table_data *ref)
    2980             : {
    2981             :     unsigned int hold_stat_size;
    2982          13 :     unsigned int num_cpus = vr_num_cpus;
    2983          13 :     vr_flow_table_data *ftable = vr_zalloc(sizeof(*ref),
    2984             :             VR_FLOW_TABLE_DATA_OBJECT);
    2985             : 
    2986          13 :     if (!ftable)
    2987           0 :         return NULL;
    2988             : 
    2989          13 :     if (vr_flow_path) {
    2990          13 :         ftable->ftable_file_path = vr_zalloc(VR_UNIX_PATH_MAX,
    2991             :                 VR_FLOW_REQ_PATH_OBJECT);
    2992          13 :         if (!ftable->ftable_file_path) {
    2993           0 :             vr_free(ftable, VR_FLOW_TABLE_DATA_OBJECT);
    2994           0 :             return NULL;
    2995             :         }
    2996             :     }
    2997             : 
    2998          13 :     if (num_cpus > VR_FLOW_MAX_CPUS)
    2999           0 :         num_cpus = VR_FLOW_MAX_CPUS;
    3000             : 
    3001          13 :     hold_stat_size = num_cpus * sizeof(uint32_t);
    3002          13 :     ftable->ftable_hold_stat = vr_zalloc(hold_stat_size, VR_FLOW_HOLD_STAT_OBJECT);
    3003          13 :     if (!ftable->ftable_hold_stat) {
    3004           0 :         if (ftable->ftable_file_path) {
    3005           0 :             vr_free(ftable->ftable_file_path, VR_FLOW_REQ_PATH_OBJECT);
    3006           0 :             ftable->ftable_file_path = NULL;
    3007             :         }
    3008             : 
    3009           0 :         vr_free(ftable, VR_FLOW_TABLE_DATA_OBJECT);
    3010           0 :         return NULL;
    3011             :     }
    3012          13 :     ftable->ftable_hold_stat_size = num_cpus;
    3013             : 
    3014          13 :     return ftable;
    3015             : }
    3016             : 
    3017             : void
    3018     8186880 : update_flow_entry(vr_htable_t table __attribute__unused__, vr_hentry_t *ent ,
    3019             :         unsigned int index, void *data __attribute__unused__)
    3020             : {
    3021     8186880 :     struct vr_flow_entry *fe = (struct vr_flow_entry *)ent;
    3022             : 
    3023     8186880 :     if (fe == NULL)
    3024     8186865 :         return;
    3025             : 
    3026          15 :     vr_offload_flow_stats_update(fe);
    3027             : }
    3028             : 
    3029             : /*
    3030             :  * sandesh handler for vr_flow_table_data
    3031             :  */
    3032             : void
    3033          13 : vr_flow_table_data_process(void *s_req)
    3034             : {
    3035          13 :     int i, ret = 0;
    3036          13 :     uint64_t hold_count = 0;
    3037             :     struct vrouter *router;
    3038             :     struct vr_flow_table_info *infop;
    3039          13 :     vr_flow_table_data *resp = NULL, *ftable = (vr_flow_table_data *)s_req;
    3040             : 
    3041          13 :     if (!ftable) {
    3042           0 :         ret = -ENOMEM;
    3043           0 :         goto send_response;
    3044             :     }
    3045          13 :     router = vrouter_get(ftable->ftable_rid);
    3046          13 :     if (! router) {
    3047           0 :         ret = -ENOMEM;
    3048           0 :         goto send_response;
    3049             :     }
    3050             : 
    3051          13 :     if(EINVAL == vr_htable_trav(router->vr_flow_table, 0, update_flow_entry, NULL))
    3052             :     {
    3053           0 :         ret = -ENOMEM;
    3054           0 :         goto send_response;
    3055             :     }
    3056          13 :     resp = vr_flow_table_data_get(ftable);
    3057          13 :     if (!resp) {
    3058           0 :         ret = -ENOMEM;
    3059           0 :         goto send_response;
    3060             :     }
    3061             : 
    3062          13 :     infop = router->vr_flow_table_info;
    3063          13 :     resp->ftable_op = ftable->ftable_op;
    3064          13 :     resp->ftable_size = vr_flow_table_size(router);
    3065             : #if defined(__linux__) && defined(__KERNEL__)
    3066             :     resp->ftable_dev = vr_flow_major;
    3067             : #endif
    3068          13 :     if (vr_flow_path) {
    3069          13 :         strncpy(resp->ftable_file_path, vr_flow_path, VR_UNIX_PATH_MAX - 1);
    3070             :     }
    3071             : 
    3072          13 :     if (!infop)
    3073           0 :         goto send_response;
    3074             : 
    3075          13 :     resp->ftable_used_entries = vr_flow_table_used_total_entries(router);
    3076          13 :     resp->ftable_deleted = infop->vfti_deleted;
    3077          13 :     resp->ftable_changed = infop->vfti_changed;
    3078          13 :     resp->ftable_processed = infop->vfti_action_count;
    3079          13 :     resp->ftable_hold_oflows = infop->vfti_oflows;
    3080          13 :     resp->ftable_added = infop->vfti_added;
    3081          13 :     resp->ftable_cpus = vr_num_cpus;
    3082             :     /* we only have space for 64 stats block max when encoding */
    3083         169 :     for (i = 0; ((i < vr_num_cpus) && (i < VR_FLOW_MAX_CPUS)); i++) {
    3084         156 :         resp->ftable_hold_stat[i] = infop->vfti_hold_count[i];
    3085         156 :         hold_count += resp->ftable_hold_stat[i];
    3086             :     }
    3087             : 
    3088          13 :     resp->ftable_created = hold_count;
    3089          13 :     resp->ftable_oflow_entries = vr_flow_table_used_oflow_entries(router);
    3090          13 :     resp->ftable_burst_free_tokens = infop->vfti_burst_tokens - infop->vfti_burst_used;
    3091          13 :     resp->ftable_hold_entries = vr_flow_table_hold_count(router);
    3092             : 
    3093          13 : send_response:
    3094          13 :     vr_message_response(VR_FLOW_TABLE_DATA_OBJECT_ID, resp, ret, false);
    3095          13 :     if (resp)
    3096          13 :         vr_flow_table_data_destroy(resp);
    3097             : 
    3098          13 :     return;
    3099             : }
    3100             : 
    3101             : /*
    3102             :  * sandesh handler for vr_flow_req
    3103             :  */
    3104             : void
    3105         322 : vr_flow_req_process(void *s_req)
    3106             : {
    3107         322 :     int ret = 0;
    3108             :     struct vrouter *router;
    3109         322 :     vr_flow_req *req = (vr_flow_req *)s_req;
    3110             :     vr_flow_response flow_resp;
    3111             : 
    3112         322 :     router = vrouter_get(req->fr_rid);
    3113         322 :     switch (req->fr_op) {
    3114         322 :     case FLOW_OP_FLOW_SET:
    3115             : 
    3116         322 :         flow_resp.fresp_rid = 0;
    3117         322 :         flow_resp.fresp_op = req->fr_op;
    3118             : 
    3119         322 :         ret = vr_flow_set(router, req, &flow_resp);
    3120         322 :         break;
    3121             : 
    3122           0 :     default:
    3123           0 :         ret = -EINVAL;
    3124             :     }
    3125             : 
    3126         322 :     vr_message_response(VR_FLOW_RESPONSE_OBJECT_ID, &flow_resp, ret, false);
    3127             : 
    3128         322 :     return;
    3129             : }
    3130             : 
    3131             : void
    3132           0 : vr_flow_response_process(void *s_req)
    3133             : {
    3134           0 :     return;
    3135             : }
    3136             : 
    3137             : static void
    3138          53 : vr_flow_table_info_destroy(struct vrouter *router)
    3139             : {
    3140          53 :     if (!router->vr_flow_table_info)
    3141           0 :         return;
    3142             : 
    3143          53 :     vr_free(router->vr_flow_table_info, VR_FLOW_TABLE_INFO_OBJECT);
    3144          53 :     router->vr_flow_table_info = NULL;
    3145          53 :     router->vr_flow_table_info_size = 0;
    3146             : 
    3147          53 :     return;
    3148             : }
    3149             : 
    3150             : static void
    3151          53 : vr_flow_table_info_reset(struct vrouter *router)
    3152             : {
    3153          53 :     if (!router->vr_flow_table_info)
    3154           0 :         return;
    3155             : 
    3156          53 :     if (router->vr_flow_table_info->vfti_timer) {
    3157           0 :         vr_delete_timer(router->vr_flow_table_info->vfti_timer);
    3158           0 :         vr_free(router->vr_flow_table_info->vfti_timer, VR_TIMER_OBJECT);
    3159           0 :         router->vr_flow_table_info->vfti_timer = NULL;
    3160             :     }
    3161             : 
    3162          53 :     memset(router->vr_flow_table_info, 0, router->vr_flow_table_info_size);
    3163             : 
    3164          53 :     return;
    3165             : }
    3166             : 
    3167             : static int
    3168          53 : vr_flow_table_info_init(struct vrouter *router)
    3169             : {
    3170             :     unsigned int size;
    3171             :     struct vr_flow_table_info *infop;
    3172             : 
    3173          53 :     if (router->vr_flow_table_info)
    3174           0 :         return 0;
    3175             : 
    3176          53 :     size = sizeof(struct vr_flow_table_info) + sizeof(uint32_t) * vr_num_cpus;
    3177          53 :     infop = (struct vr_flow_table_info *)vr_zalloc(size,
    3178             :             VR_FLOW_TABLE_INFO_OBJECT);
    3179          53 :     if (!infop)
    3180           0 :         return vr_module_error(-ENOMEM, __FUNCTION__, __LINE__, size);
    3181             : 
    3182          53 :     router->vr_flow_table_info = infop;
    3183          53 :     router->vr_flow_table_info_size = size;
    3184             : 
    3185          53 :     return 0;
    3186             : }
    3187             : 
    3188             : static void
    3189          53 : vr_flow_table_destroy(struct vrouter *router)
    3190             : {
    3191          53 :     if (router->vr_flow_table) {
    3192          53 :         vr_htable_delete(router->vr_flow_table);
    3193          53 :         router->vr_flow_table = NULL;
    3194             :     }
    3195             : 
    3196          53 :     vr_flow_table_info_destroy(router);
    3197             : 
    3198          53 :     return;
    3199             : }
    3200             : 
    3201             : static void
    3202    33377280 : vr_flow_invalidate_entry(vr_htable_t htable, vr_hentry_t *ent,
    3203             :                                 unsigned int index, void *data)
    3204             : {
    3205             :     struct vr_flow_entry *fe;
    3206             :     struct vr_forwarding_md fmd;
    3207             :     struct vr_flow_md flmd;
    3208    33377280 :     struct vrouter *router = (struct vrouter *)data;
    3209             : 
    3210    33377280 :     if (!ent || !data)
    3211    33377269 :         return;
    3212             : 
    3213    33377280 :     fe = CONTAINER_OF(fe_hentry, struct vr_flow_entry, ent);
    3214    33377280 :     if (!(fe->fe_flags & VR_FLOW_FLAG_ACTIVE))
    3215    33377269 :         return;
    3216             : 
    3217          11 :     flmd.flmd_defer_data = NULL;
    3218          11 :     flmd.flmd_index = index;
    3219          11 :     flmd.flmd_flags = fe->fe_flags;
    3220             : 
    3221          11 :     vr_init_forwarding_md(&fmd);
    3222             : 
    3223          11 :     fe->fe_action = VR_FLOW_ACTION_DROP;
    3224          11 :     vr_flush_entry(router, fe, &flmd, &fmd);
    3225          11 :     vr_flow_reset_entry(router, fe);
    3226             : }
    3227             : 
    3228             : static void
    3229          53 : vr_flow_table_reset(struct vrouter *router)
    3230             : {
    3231          53 :     vr_htable_reset(router->vr_flow_table,
    3232             :             vr_flow_invalidate_entry, router);
    3233          53 :     vr_flow_table_info_reset(router);
    3234             : 
    3235          53 :     return;
    3236             : }
    3237             : 
    3238             : void
    3239          66 : vr_compute_size_oflow_table(void)
    3240             : {
    3241             :     /*
    3242             :     * Overflow entries is 20% of the main flow table
    3243             :     * adjusted to next 1k
    3244             :     */
    3245          66 :     if (!vr_oflow_entries) {
    3246           0 :         vr_oflow_entries = ((vr_flow_entries / 5) + 1023) & ~1023;
    3247             :     }
    3248          66 : }
    3249             : 
    3250             : static int
    3251          53 : vr_flow_table_init(struct vrouter *router)
    3252             : {
    3253          53 :     if (!router->vr_flow_table) {
    3254             : 
    3255          53 :         vr_compute_size_oflow_table();
    3256             : 
    3257          53 :         if (!vr_flow_table && vr_huge_page_mem_get) {
    3258             : 
    3259           0 :             vr_flow_table = vr_huge_page_mem_get(VR_FLOW_TABLE_SIZE +
    3260             :                     VR_OFLOW_TABLE_SIZE, &vr_flow_path);
    3261           0 :             if (vr_flow_table)
    3262           0 :                 vr_oflow_table = (char*)vr_flow_table + VR_FLOW_TABLE_SIZE;
    3263             :         }
    3264             : 
    3265          53 :         router->vr_flow_table = vr_htable_attach(router, vr_flow_entries,
    3266             :                 vr_flow_table, vr_oflow_entries, vr_oflow_table,
    3267             :                 sizeof(struct vr_flow_entry), 0, 0, vr_flow_get_key);
    3268             : 
    3269          53 :         if (!router->vr_flow_table) {
    3270           0 :             return vr_module_error(-ENOMEM, __FUNCTION__,
    3271           0 :                     __LINE__, vr_flow_entries + vr_oflow_entries);
    3272             :         }
    3273             :     }
    3274             : 
    3275          53 :     return vr_flow_table_info_init(router);
    3276             : }
    3277             : 
    3278             : static void
    3279          53 : vr_link_local_ports_reset(struct vrouter *router)
    3280             : {
    3281          53 :     if (router->vr_link_local_ports) {
    3282          53 :         memset(router->vr_link_local_ports,
    3283          53 :                0, router->vr_link_local_ports_size);
    3284             :     }
    3285             : 
    3286          53 :     return;
    3287             : }
    3288             : 
    3289             : static void
    3290          53 : vr_link_local_ports_exit(struct vrouter *router)
    3291             : {
    3292          53 :     if (router->vr_link_local_ports) {
    3293          53 :         vr_free(router->vr_link_local_ports, VR_FLOW_LINK_LOCAL_OBJECT);
    3294          53 :         router->vr_link_local_ports = NULL;
    3295          53 :         router->vr_link_local_ports_size = 0;
    3296             :     }
    3297             : 
    3298          53 :     return;
    3299             : }
    3300             : 
    3301             : static int
    3302          53 : vr_link_local_ports_init(struct vrouter *router)
    3303             : {
    3304             :     unsigned int port_range, bytes;
    3305             : 
    3306          53 :     if (router->vr_link_local_ports)
    3307           0 :         return 0;
    3308             : 
    3309             :     /*  ICMP, Udp and TCP inclusive of low and high limits*/
    3310          53 :     port_range = VR_LL_RP_MAX *
    3311             :                      ((VR_DYNAMIC_PORT_END - VR_DYNAMIC_PORT_START) + 1);
    3312             :     /* Make it 16 bit boundary */
    3313          53 :     bytes = (port_range + 15) & ~15;
    3314             :     /* Bits to Bytes */
    3315          53 :     bytes /= 8;
    3316             : 
    3317          53 :     router->vr_link_local_ports = vr_zalloc(bytes, VR_FLOW_LINK_LOCAL_OBJECT);
    3318          53 :     if (!router->vr_link_local_ports)
    3319           0 :         return -1;
    3320          53 :     router->vr_link_local_ports_size = bytes;
    3321             : 
    3322          53 :     return 0;
    3323             : }
    3324             : 
    3325             : /* flow module exit and init */
    3326             : void
    3327          53 : vr_flow_exit(struct vrouter *router, bool soft_reset)
    3328             : {
    3329          53 :     vr_flow_table_reset(router);
    3330          53 :     vr_link_local_ports_reset(router);
    3331          53 :     if (!soft_reset) {
    3332          53 :         vr_flow_table_destroy(router);
    3333          53 :         vr_fragment_table_exit(router);
    3334          53 :         vr_link_local_ports_exit(router);
    3335             :     }
    3336             : 
    3337          53 :     return;
    3338             : }
    3339             : 
    3340             : int
    3341          53 : vr_flow_mem(struct vrouter *router)
    3342             : {
    3343             :     int ret;
    3344             : 
    3345          53 :     if ((ret = vr_fragment_table_init(router)) < 0)
    3346           0 :         return ret;
    3347             : 
    3348          53 :     if ((ret = vr_flow_table_init(router)))
    3349           0 :         return ret;
    3350             : 
    3351          53 :     if ((ret = vr_link_local_ports_init(router)))
    3352           0 :         return ret;
    3353             : 
    3354          53 :     return 0;
    3355             : }
    3356             : 
    3357             : int
    3358          53 : vr_flow_init(struct vrouter *router)
    3359             : {
    3360          53 :     return 0;
    3361             : }
    3362             : 
    3363             : /*
    3364             :  * Called by offload module to update flow stats with packets which have been
    3365             :  * offloaded. over_flow_bytes and over_flow_packets account for overflows which
    3366             :  * happen in firmware between updates using this function.
    3367             :  */
    3368             : int
    3369           0 : vr_flow_incr_stats(int fe_index, uint32_t flow_bytes, uint16_t over_flow_bytes,
    3370             :                    uint32_t flow_packets, uint8_t over_flow_packets)
    3371             : {
    3372           0 :     struct vrouter *router = vrouter_get(0);
    3373             :     struct vr_flow_entry *fe;
    3374             :     uint32_t new_stats;
    3375             : 
    3376           0 :     if (router == NULL)
    3377           0 :         return -EINVAL;
    3378             : 
    3379           0 :     fe = vr_flow_get_entry(router, fe_index);
    3380           0 :     if (fe == NULL)
    3381           0 :         return -ENOENT;
    3382             : 
    3383           0 :     if (!(fe->fe_flags & VR_FLOW_FLAG_ACTIVE))
    3384           0 :         return -ENOENT;
    3385             : 
    3386           0 :     new_stats = vr_sync_add_and_fetch_32u(&fe->fe_stats.flow_bytes, flow_bytes);
    3387           0 :     if (new_stats < flow_bytes)
    3388           0 :         ++fe->fe_stats.flow_bytes_oflow;
    3389           0 :     fe->fe_stats.flow_bytes_oflow += over_flow_bytes;
    3390             : 
    3391           0 :     new_stats = vr_sync_add_and_fetch_32u(&fe->fe_stats.flow_packets,
    3392             :                                           flow_packets);
    3393           0 :     if (new_stats < flow_packets)
    3394           0 :         ++fe->fe_stats.flow_packets_oflow;
    3395           0 :     fe->fe_stats.flow_packets_oflow += over_flow_packets;
    3396             : 
    3397           0 :     return 0;
    3398             : }

Generated by: LCOV version 1.14