LCOV - code coverage report
Current view: top level - vnsw/agent/pkt - flow_entry.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 1397 2480 56.3 %
Date: 2026-11-09 02:10:49 Functions: 123 179 68.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2015 Juniper Networks, Inc. All rights reserved.
       3             :  * Copyright Contributors to the OpenSDN project
       4             :  */
       5             : 
       6             : #include <atomic>
       7             : #include <vector>
       8             : #include <bitset>
       9             : #include <arpa/inet.h>
      10             : #include <netinet/in.h>
      11             : #include <base/os.h>
      12             : #include <string>
      13             : 
      14             : #include <boost/date_time/posix_time/posix_time.hpp>
      15             : #include <boost/assign/list_of.hpp>
      16             : #include <boost/unordered_map.hpp>
      17             : #include <sandesh/sandesh_trace.h>
      18             : #include <base/address_util.h>
      19             : #include <pkt/flow_table.h>
      20             : #include <vrouter/flow_stats/flow_stats_collector.h>
      21             : #include <vrouter/ksync/ksync_init.h>
      22             : #include <vrouter/ksync/ksync_flow_index_manager.h>
      23             : 
      24             : #include <route/route.h>
      25             : #include <cmn/agent_cmn.h>
      26             : #include <oper/interface_common.h>
      27             : #include <oper/nexthop.h>
      28             : #include <oper/tunnel_nh.h>
      29             : 
      30             : #include <init/agent_param.h>
      31             : #include <cmn/agent_cmn.h>
      32             : #include <cmn/agent_stats.h>
      33             : #include <oper/route_common.h>
      34             : #include <oper/vrf.h>
      35             : #include <oper/vm.h>
      36             : #include <oper/sg.h>
      37             : #include <oper/qos_config.h>
      38             : #include <oper/global_vrouter.h>
      39             : 
      40             : #include <filter/packet_header.h>
      41             : #include <filter/acl.h>
      42             : 
      43             : #include <pkt/proto.h>
      44             : #include <pkt/proto_handler.h>
      45             : #include <pkt/pkt_handler.h>
      46             : #include <pkt/flow_proto.h>
      47             : #include <pkt/pkt_types.h>
      48             : #include <pkt/pkt_sandesh_flow.h>
      49             : #include <pkt/flow_mgmt/flow_entry_info.h>
      50             : #include <pkt/flow_mgmt.h>
      51             : #include <pkt/flow_event.h>
      52             : #include <pkt/flow_entry.h>
      53             : #include <uve/flow_uve_stats_request.h>
      54             : 
      55             : using namespace boost::asio::ip;
      56             : using boost::uuids::nil_uuid;
      57             : const std::map<FlowEntry::FlowPolicyState, const char*>
      58             :     FlowEntry::FlowPolicyStateStr = boost::assign::map_list_of
      59             :         (NOT_EVALUATED,            "00000000-0000-0000-0000-000000000000")
      60             :         (IMPLICIT_ALLOW,           "00000000-0000-0000-0000-000000000001")
      61             :         (IMPLICIT_DENY,            "00000000-0000-0000-0000-000000000002")
      62             :         (DEFAULT_GW_ICMP_OR_DNS,   "00000000-0000-0000-0000-000000000003")
      63             :         (LINKLOCAL_FLOW,           "00000000-0000-0000-0000-000000000004")
      64             :         (MULTICAST_FLOW,           "00000000-0000-0000-0000-000000000005")
      65             :         (NON_IP_FLOW,              "00000000-0000-0000-0000-000000000006")
      66             :         (BGPROUTERSERVICE_FLOW,    "00000000-0000-0000-0000-000000000007");
      67             : 
      68             : const std::map<uint16_t, const char*>
      69             :     FlowEntry::FlowDropReasonStr = boost::assign::map_list_of
      70             :         ((uint16_t)DROP_UNKNOWN,                 "UNKNOWN")
      71             :         ((uint16_t)SHORT_UNAVIALABLE_INTERFACE,
      72             :          "Short flow Interface unavialable")
      73             :         ((uint16_t)SHORT_IPV4_FWD_DIS,       "Short flow Ipv4 forwarding disabled")
      74             :         ((uint16_t)SHORT_UNAVIALABLE_VRF,
      75             :          "Short flow VRF unavailable")
      76             :         ((uint16_t)SHORT_NO_SRC_ROUTE,       "Short flow No Source route")
      77             :         ((uint16_t)SHORT_NO_DST_ROUTE,       "Short flow No Destination route")
      78             :         ((uint16_t)SHORT_AUDIT_ENTRY,        "Short flow Audit Entry")
      79             :         ((uint16_t)SHORT_VRF_CHANGE,         "Short flow VRF CHANGE")
      80             :         ((uint16_t)SHORT_NO_REVERSE_FLOW,    "Short flow No Reverse flow")
      81             :         ((uint16_t)SHORT_REVERSE_FLOW_CHANGE,
      82             :          "Short flow Reverse flow change")
      83             :         ((uint16_t)SHORT_NAT_CHANGE,         "Short flow NAT Changed")
      84             :         ((uint16_t)SHORT_FLOW_LIMIT,         "Short flow Flow Limit Reached")
      85             :         ((uint16_t)SHORT_LINKLOCAL_SRC_NAT,
      86             :          "Short flow Linklocal source NAT failed")
      87             :         ((uint16_t)SHORT_FAILED_VROUTER_INSTALL,
      88             :          "Short flow vrouter install failed")
      89             :         ((uint16_t)SHORT_INVALID_L2_FLOW,    "Short flow invalid L2 flow")
      90             :         ((uint16_t)SHORT_FLOW_ON_TSN,        "Short flow TSN flow")
      91             :         ((uint16_t)SHORT_NO_MIRROR_ENTRY,     "Short flow No mirror entry ")
      92             :         ((uint16_t)SHORT_SAME_FLOW_RFLOW_KEY,"Short flow same flow and rflow")
      93             :         ((uint16_t)DROP_POLICY,              "Flow drop Policy")
      94             :         ((uint16_t)DROP_OUT_POLICY,          "Flow drop Out Policy")
      95             :         ((uint16_t)DROP_SG,                  "Flow drop SG")
      96             :         ((uint16_t)DROP_OUT_SG,              "Flow drop OUT SG")
      97             :         ((uint16_t)DROP_REVERSE_SG,          "Flow drop REVERSE SG")
      98             :         ((uint16_t)DROP_REVERSE_OUT_SG,      "Flow drop REVERSE OUT SG")
      99             :         ((uint16_t)DROP_FIREWALL_POLICY,     "Flow drop Firewall Policy")
     100             :         ((uint16_t)DROP_OUT_FIREWALL_POLICY, "Flow drop OUT Firewall Policy")
     101             :         ((uint16_t)DROP_REVERSE_FIREWALL_POLICY,     "Flow drop REVERSE Firewall Policy")
     102             :         ((uint16_t)DROP_REVERSE_OUT_FIREWALL_POLICY, "Flow drop REVERSE OUT Firewall Policy")
     103             :         ((uint16_t)SHORT_NO_SRC_ROUTE_L2RPF, "Short flow No Source route for RPF NH")
     104             :         ((uint16_t)SHORT_FAT_FLOW_NAT_CONFLICT, "Short flow Conflicting config for NAT and FAT flow")
     105             :         ((uint16_t)DROP_FWAAS_POLICY,     "Flow drop FWAAS Policy")
     106             :         ((uint16_t)DROP_FWAAS_OUT_POLICY, "Flow drop OUT FWAAS Policy")
     107             :         ((uint16_t)DROP_FWAAS_REVERSE_POLICY,     "Flow drop REVERSE FWAAS Policy")
     108             :         ((uint16_t)DROP_FWAAS_REVERSE_OUT_POLICY, "Flow drop REVERSE OUT FWAAS Policy")
     109             :         ((uint16_t)SHORT_L3MH_PHY_INTF_DOWN, "Short flow l3mh compute physical interface flap");
     110             : 
     111             : std::atomic<int> FlowEntry::alloc_count_;
     112             : SecurityGroupList FlowEntry::default_sg_list_;
     113             : 
     114             : /////////////////////////////////////////////////////////////////////////////
     115             : // VmFlowRef
     116             : /////////////////////////////////////////////////////////////////////////////
     117             : const int VmFlowRef::kInvalidFd;
     118       20000 : VmFlowRef::VmFlowRef() :
     119       20000 :     vm_(NULL), fd_(kInvalidFd), port_(0), flow_(NULL) {
     120       20000 : }
     121             : 
     122           0 : VmFlowRef::VmFlowRef(const VmFlowRef &rhs) {
     123             : 
     124           0 :     fd_ = VmFlowRef::kInvalidFd;
     125           0 :     port_ = 0;
     126           0 :     flow_ = NULL;
     127             : 
     128             :     // UPDATE on linklocal flows is not supported. So, fd_ should be invalid
     129           0 :     assert(fd_ == VmFlowRef::kInvalidFd);
     130           0 :     assert(rhs.fd_ == VmFlowRef::kInvalidFd);
     131           0 :     SetVm(rhs.vm_.get());
     132           0 : }
     133             : 
     134       20000 : VmFlowRef:: ~VmFlowRef() {
     135       20000 :     Reset(true);
     136       20000 : }
     137             : 
     138         448 : void VmFlowRef::Init(FlowEntry *flow) {
     139         448 :     flow_ = flow;
     140         448 : }
     141             : 
     142         160 : void VmFlowRef::operator=(const VmFlowRef &rhs) {
     143         160 :     assert(rhs.fd_ == VmFlowRef::kInvalidFd);
     144         160 :     assert(rhs.port_ == 0);
     145             :     // For linklocal flows, we should have called Move already. It would
     146             :     // reset vm_. Validate it
     147         160 :     if (fd_ != VmFlowRef::kInvalidFd)
     148           0 :         assert(rhs.vm_.get() == NULL);
     149         160 : }
     150             : 
     151             : // Move is called from Copy() routine when flow is evicted by vrouter and a
     152             : // new flow-add is received by agent. Use the fd_ and port_ from new flow
     153             : // since reverse flow will be setup based on these
     154          16 : void VmFlowRef::Move(VmFlowRef *rhs) {
     155             :     // Release the old values
     156          16 :     Reset(false);
     157             : 
     158          16 :     fd_ = rhs->fd_;
     159          16 :     port_ = rhs->port_;
     160          16 :     SetVm(rhs->vm_.get());
     161             : 
     162             :     // Ownership for fd_ is transferred. Reset RHS fields
     163             :     // Reset VM first before resetting fd_
     164          16 :     rhs->SetVm(NULL);
     165          16 :     rhs->fd_ = VmFlowRef::kInvalidFd;
     166          16 :     rhs->port_ = 0;
     167          16 : }
     168             : 
     169       81056 : void VmFlowRef::Reset(bool reset_flow) {
     170       81056 :     FreeRef();
     171       81056 :     FreeFd();
     172       81056 :     vm_.reset(NULL);
     173       81056 :     if (reset_flow)
     174       80896 :         flow_ = NULL;
     175       81056 : }
     176             : 
     177       81346 : void VmFlowRef::FreeRef() {
     178       81346 :     if (vm_.get() == NULL)
     179       81066 :         return;
     180             : 
     181         280 :     vm_->update_flow_count(-1);
     182         280 :     if (fd_ != kInvalidFd) {
     183           0 :         vm_->update_linklocal_flow_count(-1);
     184             :     }
     185             : }
     186             : 
     187       81056 : void VmFlowRef::FreeFd() {
     188       81056 :     if (fd_ == kInvalidFd) {
     189       81056 :         assert(port_ == 0);
     190       81056 :         return;
     191             :     }
     192             : 
     193           0 :     FlowProto *proto = flow_->flow_table()->agent()->pkt()->get_flow_proto();
     194           0 :     proto->update_linklocal_flow_count(-1);
     195           0 :     flow_->flow_table()->DelLinkLocalFlowInfo(fd_);
     196           0 :     close(fd_);
     197             : 
     198           0 :     fd_ = kInvalidFd;
     199           0 :     port_ = 0;
     200             : }
     201             : 
     202         480 : void VmFlowRef::SetVm(const VmEntry *vm) {
     203         480 :     if (vm == vm_.get())
     204         190 :         return;
     205         290 :     FreeRef();
     206             : 
     207         290 :     vm_.reset(vm);
     208         290 :     if (vm == NULL)
     209          10 :         return;
     210             : 
     211             :     // update per-vm flow accounting
     212         280 :     vm->update_flow_count(1);
     213         280 :     if (fd_ != kInvalidFd) {
     214           0 :         vm_->update_linklocal_flow_count(1);
     215             :     }
     216             : 
     217         280 :     return;
     218             : }
     219             : 
     220           0 : bool VmFlowRef::AllocateFd(Agent *agent, uint8_t l3_proto) {
     221           0 :     if (fd_ != kInvalidFd)
     222           0 :         return true;
     223             : 
     224           0 :     port_ = 0;
     225             :     // Short flows are always dropped. Dont allocate FD for short flow
     226           0 :     if (flow_->IsShortFlow())
     227           0 :         return false;
     228             : 
     229           0 :     if (l3_proto == IPPROTO_TCP) {
     230           0 :         fd_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
     231           0 :     } else if (l3_proto == IPPROTO_UDP) {
     232           0 :         fd_ = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
     233             :     }
     234             : 
     235           0 :     if (fd_ == kInvalidFd) {
     236           0 :         return false;
     237             :     }
     238             : 
     239             :     // Update agent accounting info
     240           0 :     agent->pkt()->get_flow_proto()->update_linklocal_flow_count(1);
     241           0 :     flow_->flow_table()->AddLinkLocalFlowInfo(fd_, flow_->flow_handle(),
     242           0 :                                               flow_->key(), UTCTimestampUsec());
     243             : 
     244             :     // allow the socket to be reused upon close
     245           0 :     if (l3_proto == IPPROTO_TCP) {
     246           0 :         int optval = 1;
     247           0 :         setsockopt(fd_, SOL_SOCKET, SO_REUSEADDR,
     248             :                 (const char*)&optval, sizeof(optval));
     249             :     }
     250             : 
     251             :     struct sockaddr_in address;
     252           0 :     memset(&address, 0, sizeof(address));
     253           0 :     address.sin_family = AF_INET;
     254           0 :     if (::bind(fd_, (struct sockaddr*) &address, sizeof(address)) < 0) {
     255           0 :         FreeFd();
     256           0 :         return false;
     257             :     }
     258             : 
     259             :     struct sockaddr_in bound_to;
     260           0 :     socklen_t len = sizeof(bound_to);
     261           0 :     if (getsockname(fd_, (struct sockaddr*) &bound_to, &len) < 0) {
     262           0 :         FreeFd();
     263           0 :         return false;
     264             :     }
     265             : 
     266           0 :     port_ = ntohs(bound_to.sin_port);
     267           0 :     return true;
     268             : }
     269             : 
     270             : /////////////////////////////////////////////////////////////////////////////
     271             : // FlowData constructor/destructor
     272             : /////////////////////////////////////////////////////////////////////////////
     273       10000 : FlowData::FlowData() {
     274       10000 :     Reset();
     275       10000 : }
     276             : 
     277       10000 : FlowData::~FlowData() {
     278       10000 : }
     279             : 
     280       30448 : void FlowData::Reset() {
     281       30448 :     smac = MacAddress();
     282       30448 :     dmac = MacAddress();
     283       30448 :     source_vn_list.clear();
     284       30448 :     source_vn_match = "";
     285       30448 :     dest_vn_match = "";
     286       30448 :     dest_vn_list.clear();
     287       30448 :     origin_vn_dst_list.clear();
     288       30448 :     origin_vn_src_list.clear();
     289       30448 :     origin_vn_src = "";
     290       30448 :     origin_vn_dst = "";
     291       30448 :     source_sg_id_l.clear();
     292       30448 :     dest_sg_id_l.clear();
     293       30448 :     flow_source_vrf = VrfEntry::kInvalidIndex;
     294       30448 :     flow_dest_vrf = VrfEntry::kInvalidIndex;
     295       30448 :     match_p.Reset();
     296       30448 :     vn_entry.reset(NULL);
     297       30448 :     intf_entry.reset(NULL);
     298       30448 :     in_vm_entry.Reset(true);
     299       30448 :     out_vm_entry.Reset(true);
     300       30448 :     src_ip_nh.reset(NULL);
     301       30448 :     vrf = VrfEntry::kInvalidIndex;
     302       30448 :     mirror_vrf = VrfEntry::kInvalidIndex;
     303       30448 :     dest_vrf = 0;
     304       30448 :     component_nh_idx = (uint32_t)CompositeNH::kInvalidComponentNHIdx;
     305       30448 :     source_plen = 0;
     306       30448 :     dest_plen = 0;
     307       30448 :     drop_reason = 0;
     308       30448 :     vrf_assign_evaluated = false;
     309       30448 :     if_index_info = 0;
     310       30448 :     tunnel_info.Reset();
     311       30448 :     flow_source_plen_map.clear();
     312       30448 :     flow_dest_plen_map.clear();
     313       30448 :     enable_rpf = true;
     314       30448 :     rpf_nh.reset(NULL);
     315       30448 :     rpf_plen = Address::kMaxV4PrefixLen;
     316       30448 :     rpf_vrf = VrfEntry::kInvalidIndex;
     317       30448 :     disable_validation = false;
     318       30448 :     vm_cfg_name = "";
     319       30448 :     bgp_as_a_service_sport = 0;
     320       30448 :     bgp_as_a_service_dport = 0;
     321       30448 :     acl_assigned_vrf_index_ = VrfEntry::kInvalidIndex;
     322       30448 :     qos_config_idx = AgentQosConfigTable::kInvalidIndex;
     323       30448 :     ttl = 0;
     324       30448 :     src_policy_vrf = VrfEntry::kInvalidIndex;
     325       30448 :     src_policy_plen = 0;
     326       30448 :     dst_policy_vrf = VrfEntry::kInvalidIndex;
     327       30448 :     dst_policy_plen = 0;
     328       30448 :     allocated_port_ = 0;
     329       30448 :     underlay_gw_index_ = -1;
     330       30448 : }
     331             : 
     332         502 : static std::vector<std::string> MakeList(const VnListType &ilist) {
     333         502 :     std::vector<std::string> olist;
     334         502 :     for (VnListType::const_iterator it = ilist.begin();
     335        1004 :          it != ilist.end(); ++it) {
     336         502 :         olist.push_back(*it);
     337             :     }
     338         502 :     return olist;
     339           0 : }
     340             : 
     341         251 : std::vector<std::string> FlowData::SourceVnList() const {
     342         251 :     return MakeList(source_vn_list);
     343             : }
     344             : 
     345         251 : std::vector<std::string> FlowData::DestinationVnList() const {
     346         251 :     return MakeList(dest_vn_list);
     347             : }
     348             : 
     349           0 : std::vector<std::string> FlowData::OriginVnSrcList() const {
     350           0 :     return MakeList(origin_vn_src_list);
     351             : }
     352             : 
     353           0 : std::vector<std::string> FlowData::OriginVnDstList() const {
     354           0 :     return MakeList(origin_vn_dst_list);
     355             : }
     356             : 
     357             : /////////////////////////////////////////////////////////////////////////////
     358             : // MatchPolicy constructor/destructor
     359             : /////////////////////////////////////////////////////////////////////////////
     360       10000 : MatchPolicy::MatchPolicy() {
     361       10000 :     Reset();
     362       10000 : }
     363             : 
     364       10000 : MatchPolicy::~MatchPolicy() {
     365       10000 : }
     366             : 
     367       40448 : void MatchPolicy::Reset() {
     368       40448 :     m_acl_l.clear();
     369       40448 :     policy_action = 0;
     370       40448 :     m_out_acl_l.clear();
     371       40448 :     out_policy_action = 0;
     372       40448 :     sg_policy.Reset();
     373       40448 :     m_mirror_acl_l.clear();
     374       40448 :     mirror_action = 0;
     375       40448 :     m_out_mirror_acl_l.clear();
     376       40448 :     out_mirror_action = 0;
     377       40448 :     m_vrf_assign_acl_l.clear();
     378       40448 :     vrf_assign_acl_action = 0;
     379       40448 :     aps_policy.Reset();
     380       40448 :     fwaas_policy.Reset();
     381       40448 :     action_info.Clear();
     382       40448 : }
     383             : 
     384      121344 : void SessionPolicy::Reset() {
     385      121344 :     m_out_acl_l.clear();
     386      121344 :     out_rule_present = false;
     387      121344 :     out_action = 0;
     388             : 
     389      121344 :     m_acl_l.clear();
     390      121344 :     rule_present = false;
     391      121344 :     action = 0;
     392             : 
     393      121344 :     m_reverse_acl_l.clear();
     394      121344 :     reverse_rule_present = false;
     395      121344 :     reverse_action = 0;
     396             : 
     397      121344 :     m_reverse_out_acl_l.clear();
     398      121344 :     reverse_out_rule_present = false;
     399      121344 :     reverse_out_action = 0;
     400             : 
     401      121344 :     action_summary = 0;
     402      121344 :     rule_uuid_ = FlowEntry::FlowPolicyStateStr.at(FlowEntry::NOT_EVALUATED);
     403      121344 :     acl_name_ = "";
     404      121344 : }
     405             : 
     406         678 : void SessionPolicy::ResetRuleMatchInfo() {
     407         678 :     rule_uuid_ = FlowEntry::FlowPolicyStateStr.at(FlowEntry::NOT_EVALUATED);
     408         678 :     acl_name_ = "";
     409         678 : }
     410             : 
     411         594 : void SessionPolicy::ResetAction() {
     412         594 :     out_action = 0;
     413         594 :     action = 0;
     414         594 :     reverse_action = 0;
     415         594 :     reverse_out_action = 0;
     416         594 :     action_summary = 0;
     417         594 : }
     418             : 
     419         678 : void SessionPolicy::ResetPolicy() {
     420         678 :     rule_present = false;
     421         678 :     m_acl_l.clear();
     422             : 
     423         678 :     out_rule_present = false;
     424         678 :     m_out_acl_l.clear();
     425             : 
     426         678 :     reverse_rule_present = false;
     427         678 :     m_reverse_acl_l.clear();
     428             : 
     429         678 :     reverse_out_rule_present = false;
     430         678 :     m_reverse_out_acl_l.clear();
     431         678 :     ResetRuleMatchInfo();
     432         678 : }
     433             : 
     434             : /////////////////////////////////////////////////////////////////////////////
     435             : // FlowEventLog constructor/destructor
     436             : /////////////////////////////////////////////////////////////////////////////
     437           0 : FlowEventLog::FlowEventLog() : time_(0), event_(EVENT_MAXIMUM),
     438           0 :     flow_handle_(FlowEntry::kInvalidFlowHandle), flow_gen_id_(0),
     439           0 :     ksync_entry_(NULL), hash_id_(FlowEntry::kInvalidFlowHandle), gen_id_(0),
     440           0 :     vrouter_flow_handle_(FlowEntry::kInvalidFlowHandle), vrouter_gen_id_(0) {
     441           0 : }
     442             : 
     443           0 : FlowEventLog::~FlowEventLog() {
     444           0 : }
     445             : 
     446             : /////////////////////////////////////////////////////////////////////////////
     447             : // FlowEntry constructor/destructor
     448             : /////////////////////////////////////////////////////////////////////////////
     449       10000 : FlowEntry::FlowEntry(FlowTable *flow_table) :
     450       20000 :     flow_table_(flow_table), flags_(0),
     451       10000 :     tunnel_type_(TunnelType::INVALID),
     452       10000 :     fip_vmi_(AgentKey::ADD_DEL_CHANGE, nil_uuid(), ""),
     453       20000 :     flow_mgmt_request_(NULL), flow_mgmt_info_() {
     454             :     // ksync entry is set to NULL only on constructor and on flow delete
     455             :     // it should not have any other explicit set to NULL
     456       10000 :     ksync_entry_ = NULL;
     457       10000 :     Reset();
     458       10000 :     alloc_count_++;
     459       10000 : }
     460             : 
     461       30000 : FlowEntry::~FlowEntry() {
     462       10000 :     assert(refcount_ == 0);
     463       10000 :     Reset();
     464       10000 :     alloc_count_--;
     465       20000 : }
     466             : 
     467       20448 : void FlowEntry::Reset() {
     468       20448 :     assert(ksync_entry_ == NULL);
     469       20448 :     uuid_ = flow_table_->rand_gen();
     470       20448 :     egress_uuid_ = flow_table_->rand_gen();
     471       20448 :     if (is_flags_set(FlowEntry::IngressDir)) {
     472             :         const VmInterface *vm_intf =
     473         135 :             dynamic_cast<const VmInterface *>(intf_entry());
     474         135 :         if (vm_intf) {
     475         135 :             vm_intf->update_flow_count(-2);
     476             :         }
     477             :     }
     478       20448 :     data_.Reset();
     479       20448 :     l3_flow_ = true;
     480       20448 :     gen_id_ = 0;
     481       20448 :     flow_handle_ = kInvalidFlowHandle;
     482       20448 :     reverse_flow_entry_ = NULL;
     483       20448 :     deleted_ = false;
     484       20448 :     flags_ = 0;
     485       20448 :     hbs_intf_ = FlowEntry::HBS_INTERFACE_INVALID;
     486       20448 :     short_flow_reason_ = SHORT_UNKNOWN;
     487       20448 :     peer_vrouter_ = "";
     488       20448 :     tunnel_type_ = TunnelType::INVALID;
     489       20448 :     on_tree_ = false;
     490       20448 :     fip_ = 0;
     491       20448 :     fip_vmi_ = VmInterfaceKey(AgentKey::ADD_DEL_CHANGE, nil_uuid(), "");
     492       20448 :     refcount_ = 0;
     493       20448 :     nw_ace_uuid_ = FlowPolicyStateStr.at(NOT_EVALUATED);
     494       20448 :     fsc_ = NULL;
     495       20448 :     trace_ = false;
     496       20448 :     event_logs_.reset();
     497       20448 :     event_log_index_ = 0;
     498       20448 :     last_event_ = FlowEvent::INVALID;
     499       20448 :     flow_retry_attempts_ = 0;
     500       20448 :     is_flow_on_unresolved_list = false;
     501       20448 :     pending_actions_.Reset();
     502       20448 :     assert(flow_mgmt_request_ == NULL);
     503       20448 :     assert(flow_mgmt_info_.get() == NULL);
     504       20448 :     transaction_id_ = 0;
     505       20448 : }
     506             : 
     507         224 : void FlowEntry::Reset(const FlowKey &k) {
     508         224 :     Reset();
     509         224 :     key_ = k;
     510         224 : }
     511             : 
     512           2 : void FlowEntry::Init() {
     513           2 :     alloc_count_ = 0;
     514           2 : }
     515             : 
     516         224 : FlowEntry *FlowEntry::Allocate(const FlowKey &key, FlowTable *flow_table) {
     517             :     // flow_table will be NULL for some UT cases
     518             :     FlowEntry *flow;
     519         224 :     if (flow_table == NULL) {
     520           0 :         flow = new FlowEntry(flow_table);
     521           0 :         flow->Reset(key);
     522             :     } else {
     523         224 :         flow = flow_table->free_list()->Allocate(key);
     524             :     }
     525             : 
     526         224 :     flow->data_.in_vm_entry.Init(flow);
     527         224 :     flow->data_.out_vm_entry.Init(flow);
     528         224 :     return flow;
     529             : }
     530             : 
     531             : // selectively copy fields from RHS
     532             : // When flow is being updated, rhs will be new flow allocated in PktFlowInfo
     533          80 : void FlowEntry::Copy(FlowEntry *rhs, bool update) {
     534          80 :     if (update) {
     535          72 :         rhs->data_.in_vm_entry.Reset(false);
     536          72 :         rhs->data_.out_vm_entry.Reset(false);
     537             :     } else {
     538             :         // The operator= below will call VmFlowRef operator=. In case of flow
     539             :         // eviction, we want to move ownership from rhs to lhs. However rhs is
     540             :         // const ref in operator so, invode Move API to transfer ownership
     541           8 :         data_.in_vm_entry.Move(&rhs->data_.in_vm_entry);
     542           8 :         data_.out_vm_entry.Move(&rhs->data_.out_vm_entry);
     543             :     }
     544          80 :     data_ = rhs->data_;
     545          80 :     flags_ = rhs->flags_;
     546          80 :     hbs_intf_ = rhs->hbs_intf_;
     547          80 :     short_flow_reason_ = rhs->short_flow_reason_;
     548          80 :     nw_ace_uuid_ = rhs->nw_ace_uuid_;
     549          80 :     peer_vrouter_ = rhs->peer_vrouter_;
     550          80 :     tunnel_type_ = rhs->tunnel_type_;
     551          80 :     fip_ = rhs->fip_;
     552          80 :     fip_vmi_ = rhs->fip_vmi_;
     553          80 :     last_event_ = rhs->last_event_;
     554          80 :     flow_retry_attempts_ = rhs->flow_retry_attempts_;
     555          80 :     trace_ = rhs->trace_;
     556          80 :     if (update == false) {
     557           8 :         gen_id_ = rhs->gen_id_;
     558           8 :         flow_handle_ = rhs->flow_handle_;
     559             :         /* Flow Entry is being re-used. Generate a new UUID for it. */
     560           8 :         uuid_ = flow_table_->rand_gen();
     561           8 :         egress_uuid_ = flow_table_->rand_gen();
     562             :     }
     563          80 : }
     564             : 
     565             : /////////////////////////////////////////////////////////////////////////////
     566             : // Routines to initialize FlowEntry from PktControlInfo
     567             : /////////////////////////////////////////////////////////////////////////////
     568        7513 : void intrusive_ptr_add_ref(FlowEntry *fe) {
     569        7513 :     fe->refcount_++;
     570        7517 : }
     571             : 
     572        7505 : void intrusive_ptr_release(FlowEntry *fe) {
     573        7505 :     FlowTable *flow_table = fe->flow_table();
     574        7502 :     int prev = fe->refcount_.fetch_sub(1);
     575        7502 :     if (prev == 1) {
     576         367 :         if (fe->on_tree()) {
     577         287 :             if (flow_table->ConcurrencyCheck(flow_table->flow_task_id())
     578         288 :                 == false) {
     579         144 :                 FlowEntryPtr ref(fe);
     580         144 :                 FlowProto *proto=flow_table->agent()->pkt()->get_flow_proto();
     581         144 :                 proto->ForceEnqueueFreeFlowReference(ref);
     582         144 :                 return;
     583         144 :             }
     584             :             FlowTable::FlowEntryMap::iterator it =
     585         144 :                 flow_table->flow_entry_map_.find(fe->key());
     586         144 :             assert(it != flow_table->flow_entry_map_.end());
     587         144 :             flow_table->flow_entry_map_.erase(it);
     588         144 :             flow_table->agent()->stats()->decr_flow_count();
     589             :         }
     590         224 :         flow_table->free_list()->Free(fe);
     591             :     }
     592             : }
     593             : 
     594             : // Helper Functions
     595           0 : static std::size_t HashCombine(std::size_t hash, uint64_t val) {
     596           0 :     boost::hash_combine(hash, val);
     597           0 :     return hash;
     598             : }
     599             : 
     600           0 : static std::size_t HashIp(std::size_t hash, const IpAddress &ip) {
     601           0 :     if (ip.is_v6()) {
     602             :         uint64_t val[2];
     603           0 :         Ip6AddressToU64Array(ip.to_v6(), val, 2);
     604           0 :         hash = HashCombine(hash, val[0]);
     605           0 :         hash = HashCombine(hash, val[1]);
     606           0 :     } else if (ip.is_v4()) {
     607           0 :         hash = HashCombine(hash, ip.to_v4().to_ulong());
     608             :     } else {
     609           0 :         assert(0);
     610             :     }
     611           0 :     return hash;
     612             : }
     613         224 : bool FlowEntry::InitFlowCmn(const PktFlowInfo *info, const PktControlInfo *ctrl,
     614             :                             const PktControlInfo *rev_ctrl,
     615             :                             FlowEntry *rflow) {
     616         224 :     reverse_flow_entry_ = rflow;
     617         224 :     reset_flags(FlowEntry::ReverseFlow);
     618         224 :     peer_vrouter_ = info->peer_vrouter;
     619         224 :     tunnel_type_ = info->tunnel_type;
     620             : 
     621         224 :     if (info->linklocal_flow) {
     622           0 :         set_flags(FlowEntry::LinkLocalFlow);
     623             :     } else {
     624         224 :         reset_flags(FlowEntry::LinkLocalFlow);
     625             :     }
     626         224 :     if (info->nat_done) {
     627          86 :         set_flags(FlowEntry::NatFlow);
     628             :     } else {
     629         138 :         reset_flags(FlowEntry::NatFlow);
     630             :     }
     631         224 :     if (info->short_flow) {
     632          30 :         set_flags(FlowEntry::ShortFlow);
     633          30 :         short_flow_reason_ = info->short_flow_reason;
     634             :     } else {
     635         194 :         reset_flags(FlowEntry::ShortFlow);
     636         194 :         short_flow_reason_ = SHORT_UNKNOWN;
     637             :     }
     638         224 :     if (info->local_flow) {
     639          50 :         set_flags(FlowEntry::LocalFlow);
     640             :     } else {
     641         174 :         reset_flags(FlowEntry::LocalFlow);
     642             :     }
     643             : 
     644         224 :     if (info->tcp_ack) {
     645           0 :         set_flags(FlowEntry::TcpAckFlow);
     646             :     } else {
     647         224 :         reset_flags(FlowEntry::TcpAckFlow);
     648             :     }
     649         224 :     if (info->bgp_router_service_flow) {
     650           0 :         set_flags(FlowEntry::BgpRouterService);
     651           0 :         data_.bgp_as_a_service_sport = info->nat_sport;
     652           0 :         data_.bgp_as_a_service_dport = info->nat_dport;
     653             :     } else {
     654         224 :         reset_flags(FlowEntry::BgpRouterService);
     655         224 :         data_.bgp_as_a_service_sport = 0;
     656         224 :         data_.bgp_as_a_service_dport = 0;
     657             :     }
     658             : 
     659         224 :     if (info->alias_ip_flow) {
     660           0 :         set_flags(FlowEntry::AliasIpFlow);
     661             :     } else {
     662         224 :         reset_flags(FlowEntry::AliasIpFlow);
     663             :     }
     664             : 
     665         224 :     if (info->underlay_flow) {
     666           0 :         set_flags(FlowEntry::FabricFlow);
     667             :     } else {
     668         224 :         reset_flags(FlowEntry::FabricFlow);
     669             :     }
     670             : 
     671         224 :     if (IsFabricControlFlow()) {
     672           0 :         set_flags(FlowEntry::FabricControlFlow);
     673             :     } else {
     674         224 :         reset_flags(FlowEntry::FabricControlFlow);
     675             :     }
     676             : 
     677         224 :     data_.intf_entry = ctrl->intf_ ? ctrl->intf_ : rev_ctrl->intf_;
     678         224 :     data_.vn_entry = ctrl->vn_ ? ctrl->vn_ : rev_ctrl->vn_;
     679         224 :     data_.in_vm_entry.SetVm(ctrl->vm_);
     680         224 :     data_.out_vm_entry.SetVm(rev_ctrl->vm_);
     681         224 :     l3_flow_ = info->l3_flow;
     682         224 :     data_.acl_assigned_vrf_index_ = VrfEntry::kInvalidIndex;
     683             : 
     684         224 :     return true;
     685             : }
     686             : 
     687         112 : void FlowEntry::InitFwdFlow(const PktFlowInfo *info, const PktInfo *pkt,
     688             :                             const PktControlInfo *ctrl,
     689             :                             const PktControlInfo *rev_ctrl,
     690             :                             FlowEntry *rflow, Agent *agent) {
     691         112 :     gen_id_ = pkt->GetAgentHdr().cmd_param_5;
     692         112 :     flow_handle_ = pkt->GetAgentHdr().cmd_param;
     693         112 :     if (InitFlowCmn(info, ctrl, rev_ctrl, rflow) == false) {
     694           0 :         return;
     695             :     }
     696         112 :     if (info->linklocal_bind_local_port) {
     697           0 :         set_flags(FlowEntry::LinkLocalBindLocalSrcPort);
     698             :     } else {
     699         112 :         reset_flags(FlowEntry::LinkLocalBindLocalSrcPort);
     700             :     }
     701         112 :     uint32_t intf_in = pkt->GetAgentHdr().ifindex;
     702         112 :     data_.vm_cfg_name = InterfaceIdToVmCfgName(agent, intf_in);
     703             : 
     704         112 :     if (info->port_allocated) {
     705           0 :         data_.allocated_port_ = info->nat_sport;
     706             :     }
     707             : 
     708         112 :     if (info->ingress) {
     709          45 :         set_flags(FlowEntry::IngressDir);
     710             :     } else {
     711          67 :         reset_flags(FlowEntry::IngressDir);
     712             :     }
     713         112 :     data_.disable_validation = info->disable_validation;
     714         112 :     if (ctrl->rt_ != NULL) {
     715         102 :         RpfInit(ctrl->rt_, pkt->ip_saddr);
     716             :     }
     717         112 :     data_.ttl = info->ttl;
     718         112 :     if (info->bgp_router_service_flow) {
     719           0 :         if (info->ttl == 1) {
     720           0 :             data_.ttl = BGP_SERVICE_TTL_FWD_FLOW;
     721             :         }
     722             :     }
     723             : 
     724         112 :     data_.flow_source_vrf = info->flow_source_vrf;
     725         112 :     data_.flow_dest_vrf = info->flow_dest_vrf;
     726         112 :     data_.flow_source_plen_map = info->flow_source_plen_map;
     727         112 :     data_.flow_dest_plen_map = info->flow_dest_plen_map;
     728         112 :     data_.dest_vrf = info->dest_vrf;
     729         112 :     data_.vrf = pkt->vrf;
     730         112 :     data_.if_index_info = pkt->agent_hdr.ifindex;
     731         112 :     data_.tunnel_info = pkt->tunnel;
     732             : 
     733         112 :     if (info->ecmp) {
     734          53 :         set_flags(FlowEntry::EcmpFlow);
     735             :     } else {
     736          59 :         reset_flags(FlowEntry::EcmpFlow);
     737             :     }
     738             : 
     739         112 :     data_.component_nh_idx = info->out_component_nh_idx;
     740         112 :     reset_flags(FlowEntry::Trap);
     741         112 :     if (ctrl->rt_ && ctrl->rt_->is_multicast()) {
     742           0 :         set_flags(FlowEntry::Multicast);
     743             :     }
     744         112 :     if (rev_ctrl->rt_ && rev_ctrl->rt_->is_multicast()) {
     745           0 :         set_flags(FlowEntry::Multicast);
     746             :     }
     747             : 
     748         112 :     data_.src_policy_vrf = info->src_policy_vrf;
     749         112 :     data_.dst_policy_vrf = info->dst_policy_vrf;
     750             : 
     751         112 :     reset_flags(FlowEntry::UnknownUnicastFlood);
     752         112 :     if (info->flood_unknown_unicast) {
     753           0 :         set_flags(FlowEntry::UnknownUnicastFlood);
     754           0 :         if (info->ingress) {
     755           0 :             GetSourceRouteInfo(ctrl->rt_);
     756             :         } else {
     757           0 :             GetSourceRouteInfo(rev_ctrl->rt_);
     758             :         }
     759           0 :         data_.dest_vn_list = data_.source_vn_list;
     760             :     } else {
     761         112 :         GetSourceRouteInfo(ctrl->rt_);
     762         112 :         GetDestRouteInfo(rev_ctrl->rt_);
     763             :     }
     764             : 
     765         112 :     data_.smac = pkt->smac;
     766         112 :     data_.dmac = pkt->dmac;
     767             : 
     768         112 :     if (is_flags_set(FlowEntry::IngressDir)) {
     769             :         const VmInterface *vm_intf =
     770          45 :             dynamic_cast<const VmInterface *>(intf_entry());
     771          45 :         if (vm_intf) {
     772          44 :             vm_intf->update_flow_count(2);
     773             :         }
     774             :     }
     775             : 
     776         112 :     data_.underlay_gw_index_ =  GetUnderlayGwIndex(intf_in,
     777         112 :                                 info->pkt->ip_saddr, info->pkt->ip_daddr,
     778         112 :                                 info->pkt->ip_proto, info->pkt->sport, info->pkt->dport);
     779             : }
     780             : 
     781         112 : void FlowEntry::InitRevFlow(const PktFlowInfo *info, const PktInfo *pkt,
     782             :                             const PktControlInfo *ctrl,
     783             :                             const PktControlInfo *rev_ctrl,
     784             :                             FlowEntry *rflow, Agent *agent) {
     785             :     uint32_t intf_in;
     786         112 :     if (InitFlowCmn(info, ctrl, rev_ctrl, rflow) == false) {
     787           0 :         return;
     788             :     }
     789         112 :     set_flags(FlowEntry::ReverseFlow);
     790         112 :     if (ctrl->intf_) {
     791          91 :         intf_in = ctrl->intf_->id();
     792             :     } else {
     793          21 :         intf_in = Interface::kInvalidIndex;
     794             :     }
     795         112 :     data_.vm_cfg_name = InterfaceIdToVmCfgName(agent, intf_in);
     796             : 
     797             :     // Compute reverse flow fields
     798         112 :     reset_flags(FlowEntry::IngressDir);
     799         112 :     if (ctrl->intf_) {
     800          91 :         if (info->ComputeDirection(ctrl->intf_)) {
     801          91 :             set_flags(FlowEntry::IngressDir);
     802             :         } else {
     803           0 :             reset_flags(FlowEntry::IngressDir);
     804             :         }
     805             :     }
     806         112 :     data_.disable_validation = info->disable_validation;
     807         112 :     if (ctrl->rt_ != NULL) {
     808         106 :         RpfInit(ctrl->rt_, pkt->ip_daddr);
     809             :     }
     810             : 
     811         112 :     if (info->bgp_router_service_flow) {
     812           0 :         if ((info->ttl == 1)|| (info->ttl == BGP_SERVICE_TTL_FWD_FLOW)) {
     813           0 :             data_.ttl = BGP_SERVICE_TTL_REV_FLOW;
     814             :         }
     815             :     }
     816             : 
     817         112 :     data_.flow_source_vrf = info->flow_dest_vrf;
     818         112 :     data_.flow_dest_vrf = info->flow_source_vrf;
     819         112 :     data_.flow_source_plen_map = info->flow_dest_plen_map;
     820         112 :     data_.flow_dest_plen_map = info->flow_source_plen_map;
     821         112 :     data_.vrf = info->dest_vrf;
     822             : 
     823         112 :     if (!info->nat_done) {
     824          69 :         data_.dest_vrf = info->flow_source_vrf;
     825             :     } else {
     826          43 :         data_.dest_vrf = info->nat_dest_vrf;
     827             :     }
     828         112 :     if (info->ecmp) {
     829          53 :         set_flags(FlowEntry::EcmpFlow);
     830             :     } else {
     831          59 :         reset_flags(FlowEntry::EcmpFlow);
     832             :     }
     833         112 :     data_.component_nh_idx = CompositeNH::kInvalidComponentNHIdx;
     834             : 
     835         112 :     data_.src_policy_vrf = info->dst_policy_vrf;
     836         112 :     data_.dst_policy_vrf = info->src_policy_vrf;
     837             : 
     838         112 :     reset_flags(FlowEntry::UnknownUnicastFlood);
     839         112 :     if (info->flood_unknown_unicast) {
     840           0 :         set_flags(FlowEntry::UnknownUnicastFlood);
     841           0 :         if (info->ingress) {
     842           0 :             GetSourceRouteInfo(rev_ctrl->rt_);
     843             :         } else {
     844           0 :             GetSourceRouteInfo(ctrl->rt_);
     845             :         }
     846             :         //Set source VN and dest VN to be same
     847             :         //since flooding happens only for layer2 routes
     848             :         //SG id would be left empty, user who wants
     849             :         //unknown unicast to happen should modify the
     850             :         //SG to allow such traffic
     851           0 :         data_.dest_vn_list = data_.source_vn_list;
     852             :     } else {
     853         112 :         GetSourceRouteInfo(ctrl->rt_);
     854         112 :         GetDestRouteInfo(rev_ctrl->rt_);
     855             :     }
     856             : 
     857         112 :     data_.smac = pkt->dmac;
     858         112 :     data_.dmac = pkt->smac;
     859             : 
     860         112 :     if (is_flags_set(FlowEntry::IngressDir)) {
     861             :         const VmInterface *vm_intf =
     862          91 :             dynamic_cast<const VmInterface *>(intf_entry());
     863          91 :         if (vm_intf) {
     864          91 :             vm_intf->update_flow_count(2);
     865             :         }
     866             :     }
     867             : 
     868         112 :     data_.underlay_gw_index_ =  GetUnderlayGwIndex(intf_in,
     869         112 :                                 info->pkt->ip_saddr, info->pkt->ip_daddr,
     870         112 :                                 info->pkt->ip_proto, info->pkt->sport, info->pkt->dport);
     871             : }
     872             : 
     873           0 : void FlowEntry::InitAuditFlow(uint32_t flow_idx, uint8_t gen_id) {
     874           0 :     gen_id_ = gen_id;
     875           0 :     flow_handle_ = flow_idx;
     876           0 :     set_flags(FlowEntry::ShortFlow);
     877           0 :     short_flow_reason_ = SHORT_AUDIT_ENTRY;
     878           0 :     data_.source_vn_list = FlowHandler::UnknownVnList();
     879           0 :     data_.dest_vn_list = FlowHandler::UnknownVnList();
     880           0 :     data_.origin_vn_src_list = FlowHandler::UnknownVnList();
     881           0 :     data_.origin_vn_dst_list = FlowHandler::UnknownVnList();
     882           0 :     data_.source_sg_id_l = default_sg_list();
     883           0 :     data_.dest_sg_id_l = default_sg_list();
     884           0 : }
     885             : 
     886             : 
     887             : // Fabric control flows are following,
     888             : // - XMPP connection to control node
     889             : // - SSH connection to vhost
     890             : // - Ping to vhost
     891             : // - Introspect to vhost
     892             : // - Port-IPC connection to vhost
     893             : // - Contrail-Status UVE
     894             : // TODO : Review this
     895         224 : bool FlowEntry::IsFabricControlFlow() const {
     896         224 :     Agent *agent = flow_table()->agent();
     897         224 :     if (agent->get_vhost_disable_policy()) {
     898         224 :         return false;
     899             :     }
     900             : 
     901           0 :     if (key_.dst_addr.is_v4() == false) {
     902           0 :         return false;
     903             :     }
     904             : 
     905           0 :     if (IsNatFlow()) {
     906           0 :         return false;
     907             :     }
     908             : 
     909           0 :     if (key_.protocol == IPPROTO_TCP) {
     910           0 :         if (key_.src_addr == agent->router_id()) {
     911           0 :             for (int i = 0; i < MAX_XMPP_SERVERS; i++) {
     912           0 :                 if (key_.dst_addr.to_string() !=
     913           0 :                         agent->controller_ifmap_xmpp_server(i))
     914           0 :                     continue;
     915           0 :                 if (key_.dst_port == agent->controller_ifmap_xmpp_port(i)) {
     916           0 :                     return true;
     917             :                 }
     918             :             }
     919             : 
     920           0 :             for (int i = 0; i < MAX_XMPP_SERVERS; i++) {
     921           0 :                 if (key_.dst_addr.to_string() !=
     922           0 :                         agent->dns_server(i))
     923           0 :                     continue;
     924           0 :                 if (key_.dst_port == ContrailPorts::DnsXmpp()) {
     925           0 :                     return true;
     926             :                 }
     927             : 
     928           0 :                 if (key_.dst_port == agent->dns_server_port(i)) {
     929           0 :                     return true;
     930             :                 }
     931             :             }
     932             : 
     933           0 :             std::ostringstream collector;
     934           0 :             collector << key_.dst_addr.to_string() << ":" <<
     935           0 :                          ContrailPorts::CollectorPort();
     936             :             std::vector<string>::const_iterator it =
     937           0 :                 agent->GetCollectorlist().begin();
     938           0 :             for(; it != agent->GetCollectorlist().end(); it++) {
     939           0 :                 if (collector.str() == *it) {
     940           0 :                     return true;
     941             :                 }
     942             :             }
     943             : 
     944           0 :             Ip4Address metadata_fabric_ip;
     945           0 :             uint16_t metadata_fabric_port = 0;
     946           0 :             IpAddress local_ip;
     947           0 :             uint16_t local_port = 0;
     948           0 :             std::string nova_hostname;
     949             :             agent->oper_db()->global_vrouter()->
     950           0 :                 FindLinkLocalService(GlobalVrouter::kMetadataService,
     951             :                                      &local_ip, &local_port,
     952             :                                      &nova_hostname,
     953             :                                      &metadata_fabric_ip,
     954             :                                      &metadata_fabric_port);
     955           0 :             if (key_.dst_addr.to_v4() == metadata_fabric_ip &&
     956           0 :                 key_.dst_port == metadata_fabric_port) {
     957           0 :                 return true;
     958             :             }
     959           0 :         }
     960             : 
     961             : 
     962           0 :         if (key_.dst_addr == agent->router_id()) {
     963           0 :             return (key_.dst_port == 22);
     964             :         }
     965             : 
     966           0 :         if (key_.src_addr == agent->router_id()) {
     967           0 :             return (key_.src_port == 22);
     968             :         }
     969           0 :         return false;
     970             :     }
     971             : 
     972           0 :     if (key_.protocol == IPPROTO_ICMP) {
     973           0 :         return (key_.src_addr == agent->router_id() ||
     974           0 :                 key_.dst_addr == agent->router_id());
     975             :     }
     976             : 
     977           0 :     return false;
     978             : }
     979             : 
     980             : /////////////////////////////////////////////////////////////////////////////
     981             : // Utility routines
     982             : /////////////////////////////////////////////////////////////////////////////
     983             : // Find L2 Route for the MAC address.
     984          85 : AgentRoute *FlowEntry::GetL2Route(const VrfEntry *vrf,
     985             :                                   const MacAddress &mac) {
     986             :     BridgeAgentRouteTable *table = static_cast<BridgeAgentRouteTable *>
     987          85 :         (vrf->GetBridgeRouteTable());
     988          85 :     return table->FindRouteNoLock(mac);
     989             : }
     990             : 
     991         414 : AgentRoute *FlowEntry::GetUcRoute(const VrfEntry *entry,
     992             :                                   const IpAddress &addr) {
     993         414 :     AgentRoute *rt = NULL;
     994         414 :     if (addr.is_v4()) {
     995         414 :         InetUnicastRouteEntry key(NULL, addr, 32, false);
     996         414 :         rt = entry->GetUcRoute(key);
     997         414 :     } else {
     998           0 :         InetUnicastRouteEntry key(NULL, addr, 128, false);
     999           0 :         rt = entry->GetUcRoute(key);
    1000           0 :     }
    1001         414 :     if (rt != NULL && rt->IsRPFInvalid()) {
    1002          11 :         return NULL;
    1003             :     }
    1004         403 :     return rt;
    1005             : }
    1006             : 
    1007          27 : AgentRoute *FlowEntry::GetEvpnRoute(const VrfEntry *vrf,
    1008             :                                     const MacAddress &mac,
    1009             :                                     const IpAddress &ip,
    1010             :                                     uint32_t ethernet_tag) {
    1011             :     EvpnAgentRouteTable *table = static_cast<EvpnAgentRouteTable *>(
    1012          27 :             vrf->GetEvpnRouteTable());
    1013          27 :     return table->FindRouteNoLock(mac, ip,
    1014             :                       EvpnAgentRouteTable::ComputeHostIpPlen(ip),
    1015          27 :                       ethernet_tag);
    1016             : }
    1017             : 
    1018           0 : uint32_t FlowEntry::reverse_flow_fip() const {
    1019           0 :     FlowEntry *rflow = reverse_flow_entry_.get();
    1020           0 :     if (rflow) {
    1021           0 :         return rflow->fip();
    1022             :     }
    1023           0 :     return 0;
    1024             : }
    1025             : 
    1026           0 : VmInterfaceKey FlowEntry::reverse_flow_vmi() const {
    1027           0 :     FlowEntry *rflow = reverse_flow_entry_.get();
    1028           0 :     if (rflow) {
    1029           0 :         return rflow->fip_vmi();
    1030             :     }
    1031           0 :     return VmInterfaceKey(AgentKey::ADD_DEL_CHANGE, nil_uuid(), "");
    1032             : }
    1033             : 
    1034          86 : void FlowEntry::UpdateFipStatsInfo(uint32_t fip, uint32_t id, Agent *agent) {
    1035          86 :     fip_ = fip;
    1036          86 :     fip_vmi_ = InterfaceIdToKey(agent, id);
    1037          86 : }
    1038             : 
    1039          77 : void FlowEntry::set_flow_handle(uint32_t flow_handle, uint8_t gen_id) {
    1040          77 :     if (flow_handle_ != flow_handle) {
    1041          77 :         assert(flow_handle_ == kInvalidFlowHandle);
    1042          77 :         flow_handle_ = flow_handle;
    1043             :     }
    1044          77 :     gen_id_ = gen_id;
    1045          77 : }
    1046             : 
    1047         251 : const std::string& FlowEntry::acl_assigned_vrf() const {
    1048         251 :     return data_.match_p.action_info.vrf_translate_action_.vrf_name();
    1049             : }
    1050             : 
    1051           0 : void FlowEntry::set_acl_assigned_vrf_index() {
    1052           0 :     VrfKey vrf_key(data_.match_p.action_info.vrf_translate_action_.vrf_name());
    1053           0 :     const VrfEntry *vrf = static_cast<const VrfEntry *>(
    1054           0 :             flow_table()->agent()->vrf_table()->FindActiveEntry(&vrf_key));
    1055           0 :     if (vrf) {
    1056           0 :         data_.acl_assigned_vrf_index_ = vrf->vrf_id();
    1057           0 :         bool set_dest_vrf = true;
    1058           0 :         if (is_flags_set(FlowEntry::NatFlow) &&
    1059           0 :             reverse_flow_entry() &&
    1060           0 :             key().dst_addr != reverse_flow_entry()->key().src_addr) {
    1061             :             //Packet is getting DNATed, VRF assign ACL action
    1062             :             //is applied on floating-ip VN and the destination VRF should
    1063             :             //be retained as interface VRF
    1064           0 :             set_dest_vrf = false;
    1065             :         }
    1066             : 
    1067           0 :         if (set_dest_vrf) {
    1068           0 :             data_.dest_vrf = vrf->vrf_id();
    1069             :         }
    1070           0 :         return;
    1071             :     }
    1072           0 :     data_.acl_assigned_vrf_index_ = VrfEntry::kInvalidIndex;
    1073           0 : }
    1074             : 
    1075           0 : uint32_t FlowEntry::acl_assigned_vrf_index() const {
    1076           0 :     return data_.acl_assigned_vrf_index_;
    1077             : }
    1078             : 
    1079         224 : void FlowEntry::RevFlowDepInfo(RevFlowDepParams *params) {
    1080         224 :     params->sip_ = key().src_addr;
    1081         224 :     FlowEntry *rev_flow = reverse_flow_entry();
    1082         224 :     if (rev_flow) {
    1083         189 :         params->rev_uuid_ = rev_flow->uuid();
    1084         189 :         params->vm_cfg_name_ = rev_flow->data().vm_cfg_name;
    1085         189 :         params->sg_uuid_ = rev_flow->sg_rule_uuid();
    1086         189 :         params->rev_egress_uuid_ = rev_flow->egress_uuid();
    1087         189 :         params->nw_ace_uuid_ = rev_flow->nw_ace_uuid();
    1088         189 :         params->drop_reason_ = rev_flow->data().drop_reason;
    1089         189 :         params->action_info_ = rev_flow->data().match_p.action_info;
    1090         189 :         if (rev_flow->intf_entry()) {
    1091             :             const VmInterface *vmi =
    1092         186 :                 dynamic_cast<const VmInterface *>(rev_flow->intf_entry());
    1093         186 :             if (vmi) {
    1094         185 :                 params->vmi_uuid_ = UuidToString(vmi->vmi_cfg_uuid());
    1095             :             } else {
    1096           2 :                 params->vmi_uuid_ = UuidToString(rev_flow->intf_entry()->
    1097           1 :                                                  GetUuid());
    1098             :             }
    1099             :         }
    1100             : 
    1101         189 :         if (key().family != Address::INET) {
    1102           0 :             return;
    1103             :         }
    1104         242 :         if (is_flags_set(FlowEntry::NatFlow) &&
    1105         242 :             is_flags_set(FlowEntry::IngressDir)) {
    1106          14 :             const FlowKey *nat_key = &rev_flow->key();
    1107          14 :             if (key().src_addr != nat_key->dst_addr) {
    1108          11 :                 params->sip_ = nat_key->dst_addr;
    1109             :             }
    1110             :         }
    1111             :     }
    1112             : }
    1113             : 
    1114        2382 : bool FlowEntry::ShouldDrop(uint32_t action) {
    1115        2382 :     if (action & TrafficAction::DROP_FLAGS)
    1116         124 :         return true;
    1117             : 
    1118        2258 :     if (action & TrafficAction::IMPLICIT_DENY_FLAGS)
    1119           0 :         return true;
    1120             : 
    1121        2258 :     return false;
    1122             : }
    1123             : 
    1124             : /////////////////////////////////////////////////////////////////////////////
    1125             : // Flow RPF
    1126             : //
    1127             : // VRouter enforces RPF check based on RPF-NH programmed in the flow. The RPF
    1128             : // NH can be of two types,
    1129             : // - Unicast NH :
    1130             : //   In this case, VRouter matches with incoming interface/tunnel-src with
    1131             : //   RPF NH the flow
    1132             : //
    1133             : // - ECMP NH :
    1134             : //   In this case, VRouter picks an ECMP component-nh and matches with incoming
    1135             : //   interface/tunnel-src. The index for component-nh is got from reverse flow.
    1136             : //
    1137             : // RPF-NH cases
    1138             : // ------------
    1139             : // 1. Baremetals
    1140             : //    Agent is not aware of IP address assigned for baremetals. So, RPF check
    1141             : //    for baremetals is based on the L2-Route
    1142             : //
    1143             : // 2. Layer-2 Flows
    1144             : //    If agent know the Inet route for source-ip in packet, RPF is based on
    1145             : //    the Inet route for source-ip. There are some exceptions for this rule,
    1146             : //    - If Inet route for source-ip is ECMP, then RPF is based on layer-2 route
    1147             : //    - If Inet route for source-ip is not-host route, then RPF is based on
    1148             : //      layer-2 routes
    1149             : //
    1150             : //    If packet is from BMS (egress flow), its possible that agent does not
    1151             : //    know IP address for BMS. In such case, RPF is based on L2-Route
    1152             : //
    1153             : // 3. Layer-3 Flows from VMI
    1154             : //    RPF check will be based on the InterfaceNH for VMI
    1155             : //
    1156             : // 4. Layer-3 Flows from Fabric with unicast-NH
    1157             : //    The unicast-nh is used as RPF-NH
    1158             : //
    1159             : // 5. Layer-3 Flows from Fabric with composite-NH
    1160             : //    VRouter picks NH from flow and the ecmp-index from reverse flow.
    1161             : //
    1162             : //    The ecmp-index in reverse is computed based on route for dest-ip in
    1163             : //    VRF got post VRF translation if any
    1164             : //
    1165             : //    Note, the RPF must be picked post VRF translation since order of members
    1166             : //    in Composite-NH may vary across VRF
    1167             : //
    1168             : // Route Tracking
    1169             : // --------------
    1170             : //   Flow Management should track the route for ip1 in vrf4 to update RPF-NH
    1171             : //
    1172             : // RPF Computation
    1173             : // ---------------
    1174             : // RPF computation happens in two stages
    1175             : // 1. FlowEntry creation (RpfInit):
    1176             : //    Called during FlowEntry init. Computes src_ip_nh for flow.
    1177             : //
    1178             : //    For layer-2 flows, RPF-NH Is same as src_ip_nh
    1179             : //    For Non-ECMP layer-3 flows, RPF-NH is same as src_ip_nh
    1180             : //    For ECMP layer-3 flows, RPF-NH must be computed only after VRF
    1181             : //    translation is computed for reverse flow.
    1182             : //
    1183             : // 2. Post ACL processing (RpfUpdate):
    1184             : //    Post ACL processing, all VRF translation rules are identified.
    1185             : //    The RPF-NH is computed in this method.
    1186             : /////////////////////////////////////////////////////////////////////////////
    1187             : // Utility method to set rpf_vrf and rpf_plen fields
    1188         267 : static void SetRpfFieldsInternal(FlowEntry *flow, const AgentRoute *rt) {
    1189             :     // If there is no route, we should track default route
    1190         267 :     if (rt == NULL) {
    1191           0 :         flow->data().rpf_vrf = flow->data().vrf;
    1192           0 :         flow->data().rpf_plen = 0;
    1193           0 :         return;
    1194             :     }
    1195             : 
    1196             :     const InetUnicastRouteEntry *inet_rt =
    1197         267 :         dynamic_cast<const InetUnicastRouteEntry *>(rt);
    1198         267 :     if (inet_rt) {
    1199         198 :         flow->data().rpf_vrf = inet_rt->vrf()->vrf_id();
    1200         198 :         flow->data().rpf_plen = inet_rt->prefix_length();
    1201         198 :         return;
    1202             :     }
    1203             : 
    1204          69 :     if (!flow->l3_flow()) {
    1205          69 :         flow->data().rpf_vrf = rt->vrf()->vrf_id();
    1206             :         /* 
    1207             :          * For L2 flows also  plen is found using GetUCRoute 
    1208             :          * plen is stored in L2 route entry
    1209             :          * this changed to address CEM-27722  
    1210             :          */
    1211             :         const BridgeRouteEntry *bridge_rt =
    1212          69 :             dynamic_cast<const BridgeRouteEntry *>(rt);
    1213          69 :         if (bridge_rt != NULL) {
    1214          69 :             BridgeRouteEntry *temp = const_cast<BridgeRouteEntry *>(bridge_rt);
    1215          69 :             flow->data().rpf_plen  = temp->prefix_length();
    1216             :         }
    1217          69 :         return;
    1218             :     }
    1219             :     // Route is not INET. Dont track any route
    1220           0 :     flow->data().rpf_vrf = VrfEntry::kInvalidIndex;
    1221           0 :     flow->data().rpf_plen = 0;
    1222           0 :     return;
    1223             : }
    1224             : 
    1225             : // Utility method to set src_ip_nh fields
    1226         264 : void FlowEntry::RpfSetSrcIpNhFields(const AgentRoute *rt,
    1227             :                                     const NextHop *src_ip_nh) {
    1228         264 :     data_.src_ip_nh.reset(src_ip_nh);
    1229         264 :     SetRpfFieldsInternal(this, rt);
    1230         264 :     return;
    1231             : }
    1232             : 
    1233          50 : void FlowEntry::RpfSetRpfNhFields(const NextHop *rpf_nh) {
    1234          50 :     data_.rpf_nh.reset(rpf_nh);
    1235          50 : }
    1236             : 
    1237             : // Utility method to set rpf_nh fields
    1238           3 : void FlowEntry::RpfSetRpfNhFields(const AgentRoute *rt, const NextHop *rpf_nh) {
    1239           3 :     data_.rpf_nh.reset(rpf_nh);
    1240           3 :     SetRpfFieldsInternal(this, rt);
    1241           3 :     return;
    1242             : }
    1243             : 
    1244             : // This method is called when flow is initialized. The RPF-NH cannot be
    1245             : // computed at this stage since we dont know if reverse flow has VRF
    1246             : // translation or not.
    1247             : // This method only sets src_ip_nh field
    1248             : //
    1249             : // In case of layer-3 flow "rt" is inet route for source-ip in source-vrf
    1250             : // In case of layer-2 flow "rt" is l2 route for smac in source-vrf
    1251         208 : void FlowEntry::RpfInit(const AgentRoute *rt, const IpAddress &sip) {
    1252             :     // Set src_ip_nh based on rt first
    1253         208 :     RpfSetSrcIpNhFields(rt, rt->GetActiveNextHop());
    1254             : 
    1255             :     // RPF enabled?
    1256         208 :     bool rpf_enable = true;
    1257         208 :     if (data_.vn_entry && data_.vn_entry->enable_rpf() == false)
    1258           0 :         rpf_enable = false;
    1259         208 :     if (data_.disable_validation)
    1260           0 :         rpf_enable = false;
    1261             : 
    1262             :     // The src_ip_nh can change below only for l2 flows
    1263             :     // For l3-flow, rt will already be a INET route
    1264         208 :     if (l3_flow())
    1265         139 :         return;
    1266             : 
    1267             :     // For layer-2 flows, we use l2-route for RPF in following cases
    1268             :     // 1. Interface is of type BAREMETAL (ToR/TSN only)
    1269             :     //
    1270             :     // 2. ECMP is not supported for l2-flows. If src-ip lookup resulted in
    1271             :     //    ECMP-NH fallback to the original l2-route
    1272             :     //
    1273             :     // 3. In case of OVS, ToR will export layer-2 route and MX will export a
    1274             :     //    layer-3 subnet route covering all the ToRs. In this case, when ToR
    1275             :     //    send layer-2 packet the layer-3 route will point to MX and RPF fails.
    1276             :     //    Assuming MX only gives subnet-route, use inet-route only if its
    1277             :     //    host-route
    1278             :     // 4. Its an egress flow and there is no route for IP address
    1279             :     const VmInterface *vmi =
    1280          69 :         dynamic_cast<const VmInterface *>(intf_entry());
    1281          69 :     if (vmi && vmi->vmi_type() == VmInterface::BAREMETAL) {
    1282           3 :         return;
    1283             :     }
    1284             : 
    1285          66 :     VrfEntry *vrf = rt->vrf();
    1286             :     const InetUnicastRouteEntry *src_ip_rt =
    1287             :         static_cast<InetUnicastRouteEntry *>
    1288          66 :         (FlowEntry::GetUcRoute(vrf, sip));
    1289             : 
    1290          66 :     if (src_ip_rt == NULL) {
    1291             :         // For egress flow, with no l3-route then do rpf based on l2-route
    1292             :         // For ingress flow, with no l3-route, make it short flow
    1293           8 :         if (rpf_enable && IsIngressFlow()) {
    1294           2 :             set_flags(FlowEntry::ShortFlow);
    1295           2 :             short_flow_reason_ = SHORT_NO_SRC_ROUTE_L2RPF;
    1296             :         }
    1297           8 :         return;
    1298             :     }
    1299             : 
    1300          58 :     if (src_ip_rt->IsHostRoute() == false)
    1301           0 :         return;
    1302             : 
    1303          58 :     const NextHop *src_ip_nh = src_ip_rt->GetActiveNextHop();
    1304          58 :     if ((src_ip_nh != NULL) && src_ip_nh->GetType() == NextHop::COMPOSITE)
    1305           2 :         return;
    1306             : 
    1307          56 :     RpfSetSrcIpNhFields(src_ip_rt, src_ip_nh);
    1308          56 :     return;
    1309             : }
    1310             : 
    1311             : // Should src_ip_nh be treated as RPF-NH
    1312         230 : bool FlowEntry::RpfFromSrcIpNh() const {
    1313             :     // For l2-flows, src_ip_nh is same as RPF-NH
    1314         230 :     if (l3_flow() == false)
    1315          84 :         return true;
    1316             : 
    1317             :     // Dont bother about RPF for short-flows
    1318         146 :     if (is_flags_set(FlowEntry::ShortFlow))
    1319          12 :         return true;
    1320             : 
    1321             :     // rpf-nh can change only in case of composite
    1322         134 :     if (data_.src_ip_nh->GetType() != NextHop::COMPOSITE)
    1323          81 :         return true;
    1324             : 
    1325          53 :     const FlowEntry *rflow = reverse_flow_entry();
    1326          53 :     if (rflow == NULL) {
    1327           0 :         FlowInfo flow_info;
    1328           0 :         FillFlowInfo(flow_info);
    1329           0 :         FLOW_TRACE(Trace, "Invalid reverse flow for setting ECMP index",
    1330             :                    flow_info);
    1331           0 :         return true;
    1332           0 :     }
    1333             : 
    1334          53 :     return false;
    1335             : }
    1336             : 
    1337          43 : void FlowEntry::RpfComputeIngress() {
    1338          43 :     const NextHop *nh = NULL;
    1339             :     // If we are here, its guaranteed that src_ip_nh is composite
    1340             :     const CompositeNH *cnh =
    1341          43 :         dynamic_cast<const CompositeNH *>(data_.src_ip_nh.get());
    1342          43 :     assert(cnh != NULL);
    1343             : 
    1344             :     // Use flow_key_nh if VMI is part of composite. Else its guaranteed
    1345             :     // that RPF will fail for flow. So, use discard-nh for RPF
    1346             :     const VmInterface *vmi =
    1347          43 :         dynamic_cast<const VmInterface *>(intf_entry());
    1348          43 :     if (cnh->HasVmInterface(vmi)) {
    1349          42 :         nh = vmi->flow_key_nh();
    1350             :     } else {
    1351           1 :         nh = data_.src_ip_nh.get();
    1352             :     }
    1353             : 
    1354             :     // Change only the RPF-NH. The vrf and plen dont change here
    1355          43 :     RpfSetRpfNhFields(nh);
    1356          43 :     return;
    1357             : }
    1358             : 
    1359          10 : void FlowEntry::RpfComputeEgress() {
    1360          10 :     const FlowEntry *rflow = reverse_flow_entry();
    1361             : 
    1362             :     // RPF-NH can change only if VRF in forward flow and translated VRF in
    1363             :     // reverse flow are different
    1364          10 :     if (rflow->data().flow_dest_vrf == data_.vrf) {
    1365           7 :         RpfSetRpfNhFields(data_.src_ip_nh.get());
    1366           7 :         return;
    1367             :     }
    1368             : 
    1369             :     // Find destination VRF from reverse flow
    1370           3 :     const VrfEntry *vrf = rflow->GetDestinationVrf();
    1371           3 :     if (vrf == NULL) {
    1372           0 :         FlowInfo flow_info;
    1373           0 :         FillFlowInfo(flow_info);
    1374           0 :         FLOW_TRACE(Trace, "Error setting RPF NH. Destination VRF not found "
    1375             :                    "in reverse flow", flow_info);
    1376           0 :         return;
    1377           0 :     }
    1378             : 
    1379             :     InetUnicastRouteEntry *rt = static_cast<InetUnicastRouteEntry *>
    1380           3 :         (FlowEntry::GetUcRoute(vrf, key().src_addr));
    1381           3 :     if (!rt) {
    1382           0 :         FlowInfo flow_info;
    1383           0 :         FillFlowInfo(flow_info);
    1384           0 :         FLOW_TRACE(Trace, "Error setting RPF NH. Route not found in "
    1385             :                   "destination vrf", flow_info);
    1386           0 :         return;
    1387           0 :     }
    1388             : 
    1389           3 :     RpfSetRpfNhFields(rt, rt->GetActiveNextHop());
    1390           3 :     return;
    1391             : }
    1392             : 
    1393             : // Computes RPF-NH for flow based on ip_src_nh
    1394             : // Must be called after policy lookup is done
    1395         230 : void FlowEntry::RpfUpdate() {
    1396             :     // Is RPF check enabled?
    1397         230 :     data_.enable_rpf = true;
    1398         230 :     if (data_.vn_entry) {
    1399         226 :         data_.enable_rpf = data_.vn_entry->enable_rpf();
    1400             :     }
    1401             : 
    1402         230 :     if (data_.disable_validation) {
    1403           0 :         data_.enable_rpf = false;
    1404             :     }
    1405             : 
    1406         230 :     if (data_.enable_rpf == false) {
    1407           0 :         data_.rpf_nh = NULL;
    1408           0 :         return;
    1409             :     }
    1410             : 
    1411         230 :     if (RpfFromSrcIpNh()) {
    1412         177 :         data_.rpf_nh = data_.src_ip_nh;
    1413         177 :         return;
    1414             :     }
    1415             : 
    1416          53 :     if (is_flags_set(FlowEntry::IngressDir)) {
    1417          43 :         RpfComputeIngress();
    1418             :     } else {
    1419          10 :         RpfComputeEgress();
    1420             :     }
    1421             : }
    1422             : 
    1423         226 : bool FlowEntry::IsClientFlow() {
    1424             :     /*
    1425             :      * If the flow is Local + Ingress + Forward
    1426             :      * then it will be considered as client session
    1427             :      */
    1428         276 :     if ((is_flags_set(FlowEntry::LocalFlow)) &&
    1429         276 :         (is_flags_set(FlowEntry::IngressDir)) &&
    1430         276 :         (!(is_flags_set(FlowEntry::ReverseFlow)))) {
    1431          25 :         return true;
    1432             :     }
    1433             :     /*
    1434             :      * If the flow is (Ingress + Forward) OR
    1435             :      *                (Egress + Reverse)
    1436             :      * then it will be consideres as client session
    1437             :      */
    1438         201 :     if (is_flags_set(FlowEntry::IngressDir)) {
    1439          63 :         if (!(is_flags_set(FlowEntry::ReverseFlow))) {
    1440          38 :             return true;
    1441             :         }
    1442             :     } else {
    1443         138 :         if (is_flags_set(FlowEntry::ReverseFlow)) {
    1444           0 :             return true;
    1445             :         }
    1446             :     }
    1447         163 :     return false;
    1448             : }
    1449             : 
    1450         163 : bool FlowEntry::IsServerFlow() {
    1451             :     /*
    1452             :      * If the flow is Local + Ingress + Reverse
    1453             :      * then it will be considered as server session
    1454             :      */
    1455         188 :     if ((is_flags_set(FlowEntry::LocalFlow)) &&
    1456         188 :         (is_flags_set(FlowEntry::IngressDir)) &&
    1457         188 :         (is_flags_set(FlowEntry::ReverseFlow))) {
    1458          25 :         return true;
    1459             :     }
    1460             :     /*
    1461             :      * If the flow is (Egress + Forward) OR
    1462             :      *                (Ingress + Reverse)
    1463             :      * then it will be consideres as server session
    1464             :      */
    1465         138 :     if (!(is_flags_set(FlowEntry::IngressDir))) {
    1466         138 :         if (!(is_flags_set(FlowEntry::ReverseFlow))) {
    1467         138 :             return true;
    1468             :         }
    1469             :     } else {
    1470           0 :         if (is_flags_set(FlowEntry::ReverseFlow)) {
    1471           0 :             return true;
    1472             :         }
    1473             :     }
    1474           0 :     return false;
    1475             : }
    1476             : /////////////////////////////////////////////////////////////////////////////
    1477             : // Flow entry fileds updation routines
    1478             : /////////////////////////////////////////////////////////////////////////////
    1479         516 : std::string FlowEntry::DropReasonStr(uint16_t reason) {
    1480             :     std::map<uint16_t, const char*>::const_iterator it =
    1481         516 :         FlowDropReasonStr.find(reason);
    1482         516 :     if (it != FlowDropReasonStr.end()) {
    1483         516 :         return string(it->second);
    1484             :     }
    1485           0 :     return "UNKNOWN";
    1486             : }
    1487             : 
    1488             : // Get src-vn/sg-id/plen from route
    1489             : // src-vn and sg-id are used for policy lookup
    1490             : // plen is used to track the routes to use by flow_mgmt module
    1491         230 : void FlowEntry::GetSourceRouteInfo(const AgentRoute *rt) {
    1492         230 :     Agent *agent = flow_table()->agent();
    1493             :     const InetUnicastRouteEntry *inet_rt =
    1494         230 :         dynamic_cast<const InetUnicastRouteEntry *>(rt);
    1495             : 
    1496         230 :     if (inet_rt && is_flags_set(FlowEntry::FabricFlow)) {
    1497             :         const VrfEntry *policy_vrf =
    1498             :             static_cast<const VrfEntry *>(agent->
    1499           0 :                         vrf_table()->FindVrfFromId(data_.src_policy_vrf));
    1500             : 
    1501             :         //Policy lookup needs to happen in Policy VRF
    1502           0 :         AgentRoute *new_rt = GetUcRoute(policy_vrf,
    1503           0 :                                         inet_rt->prefix_address());
    1504           0 :         data_.src_policy_plen = 0;
    1505           0 :         if (new_rt) {
    1506           0 :             rt = new_rt;
    1507           0 :             inet_rt = dynamic_cast<const InetUnicastRouteEntry *>(new_rt);
    1508           0 :             data_.src_policy_plen = inet_rt->prefix_length();
    1509           0 :             data_.src_policy_vrf = inet_rt->vrf()->vrf_id();
    1510             :         }
    1511             :     }
    1512             : 
    1513         230 :     const AgentPath *path = NULL;
    1514         230 :     if (rt) {
    1515         214 :         path = rt->GetActivePath();
    1516             :     }
    1517         230 :     if (path == NULL) {
    1518          16 :         data_.source_vn_list = FlowHandler::UnknownVnList();
    1519          16 :         data_.source_vn_match = FlowHandler::UnknownVn();
    1520          16 :         data_.source_sg_id_l = default_sg_list();
    1521          16 :         data_.source_plen = 0;
    1522          16 :         data_.origin_vn_src_list = FlowHandler::UnknownVnList();
    1523          16 :         data_.origin_vn_src = FlowHandler::UnknownVn();
    1524             :     } else {
    1525         214 :         data_.source_vn_list = path->dest_vn_list();
    1526         214 :         if (path->dest_vn_list().size())
    1527         214 :             data_.source_vn_match = *path->dest_vn_list().begin();
    1528         214 :         data_.origin_vn_src = path->origin_vn();
    1529         214 :         if (!path->origin_vn().empty()) {
    1530           0 :             data_.origin_vn_src_list.insert(path->origin_vn());
    1531             :         }
    1532         214 :         data_.source_sg_id_l = path->sg_list();
    1533         214 :         data_.source_plen = rt->prefix_length();
    1534         214 :         data_.source_tag_id_l = path->tag_list();
    1535             :     }
    1536             :     /* Handle case when default route NextHop points to vrf */
    1537         230 :     if (rt) {
    1538         214 :         const NextHop *anh = rt->GetActiveNextHop();
    1539         214 :         if (anh && anh->GetType() == NextHop::VRF) {
    1540           0 :             const VrfNH *nh =
    1541             :                 static_cast<const VrfNH *>(anh);
    1542           0 :             AgentRoute *new_rt = GetUcRoute(nh->GetVrf(), key_.src_addr);
    1543           0 :             if (new_rt) {
    1544           0 :                 path = new_rt->GetActivePath();
    1545           0 :                 if (path) {
    1546           0 :                     data_.origin_vn_src = path->origin_vn();
    1547           0 :                     if (!path->origin_vn().empty()) {
    1548           0 :                         data_.origin_vn_src_list.insert(path->origin_vn());
    1549             :                     }
    1550             :                 }
    1551             :             }
    1552             :         }
    1553             :     }
    1554             : 
    1555         230 : }
    1556             : 
    1557             : // Get dst-vn/sg-id/plen from route
    1558             : // dst-vn and sg-id are used for policy lookup
    1559             : // plen is used to track the routes to use by flow_mgmt module
    1560         230 : void FlowEntry::GetDestRouteInfo(const AgentRoute *rt) {
    1561         230 :     Agent *agent = flow_table()->agent();
    1562         230 :     const AgentPath *path = NULL;
    1563         230 :     if (rt) {
    1564         214 :         path = rt->GetActivePath();
    1565             :     }
    1566             : 
    1567             :     const InetUnicastRouteEntry *inet_rt =
    1568         230 :             dynamic_cast<const InetUnicastRouteEntry *>(rt);
    1569         230 :     if (inet_rt && is_flags_set(FlowEntry::FabricFlow)) {
    1570           0 :         data_.dst_policy_plen = 0;
    1571             :         const VrfEntry *policy_vrf =
    1572             :             static_cast<const VrfEntry *>(agent->
    1573           0 :                     vrf_table()->FindVrfFromId(data_.dst_policy_vrf));
    1574             : 
    1575             :         AgentRoute *new_rt =
    1576           0 :             GetUcRoute(policy_vrf, inet_rt->prefix_address());
    1577           0 :         if (new_rt) {
    1578           0 :             rt = new_rt;
    1579           0 :             inet_rt = dynamic_cast<const InetUnicastRouteEntry *>(rt);
    1580           0 :             data_.dst_policy_plen = inet_rt->prefix_length();
    1581           0 :             data_.dst_policy_vrf = inet_rt->vrf()->vrf_id();
    1582             :         }
    1583             :     }
    1584             : 
    1585         230 :     if (rt) {
    1586         214 :         path = rt->GetActivePath();
    1587             :     }
    1588             : 
    1589         230 :     if (path == NULL) {
    1590          16 :         data_.dest_vn_list = FlowHandler::UnknownVnList();
    1591          16 :         data_.dest_vn_match = FlowHandler::UnknownVn();
    1592          16 :         data_.dest_sg_id_l = default_sg_list();
    1593          16 :         data_.dest_plen = 0;
    1594          16 :         data_.origin_vn_dst_list = FlowHandler::UnknownVnList();
    1595          16 :         data_.origin_vn_dst = FlowHandler::UnknownVn();
    1596             :     } else {
    1597         214 :         data_.dest_vn_list = path->dest_vn_list();
    1598         214 :         if (path->dest_vn_list().size())
    1599         214 :             data_.dest_vn_match = *path->dest_vn_list().begin();
    1600         214 :         data_.origin_vn_dst = path->origin_vn();
    1601         214 :         if (!path->origin_vn().empty()) {
    1602           0 :             data_.origin_vn_dst_list.insert(path->origin_vn());
    1603             :         }
    1604         214 :         data_.dest_sg_id_l = path->sg_list();
    1605         214 :         data_.dest_plen = rt->prefix_length();
    1606         214 :         data_.dest_tag_id_l = path->tag_list();
    1607             :     }
    1608             : 
    1609             :     /* Handle case when default route NextHop points to vrf */
    1610         230 :     if (rt) {
    1611         214 :         const NextHop *anh = rt->GetActiveNextHop();
    1612         214 :         if (anh && anh->GetType() == NextHop::VRF) {
    1613           0 :             const VrfNH *nh =
    1614             :                 static_cast<const VrfNH *>(anh);
    1615           0 :             AgentRoute *new_rt = GetUcRoute(nh->GetVrf(), key_.dst_addr);
    1616           0 :             if (new_rt) {
    1617           0 :                 path = new_rt->GetActivePath();
    1618           0 :                 if (path) {
    1619           0 :                     data_.origin_vn_dst = path->origin_vn();
    1620           0 :                     if (!path->origin_vn().empty()) {
    1621           0 :                         data_.origin_vn_dst_list.insert(path->origin_vn());
    1622             :                     }
    1623             :                 }
    1624             :             }
    1625             :         }
    1626             :     }
    1627         230 : }
    1628             : 
    1629          86 : VmInterfaceKey FlowEntry::InterfaceIdToKey(Agent *agent, uint32_t id) {
    1630          86 :     if (id != Interface::kInvalidIndex) {
    1631          86 :         Interface *itf = agent->interface_table()->FindInterface(id);
    1632          86 :         if (itf && (itf->type() == Interface::VM_INTERFACE)) {
    1633             :             return VmInterfaceKey(AgentKey::ADD_DEL_CHANGE, itf->GetUuid(),
    1634          86 :                                   itf->name());
    1635             :         }
    1636             :     }
    1637           0 :     return VmInterfaceKey(AgentKey::ADD_DEL_CHANGE, nil_uuid(), "");
    1638             : }
    1639             : 
    1640           0 : uint32_t FlowEntry::InterfaceKeyToId(Agent *agent, const VmInterfaceKey &key) {
    1641           0 :     const Interface *intf = dynamic_cast<const Interface*>
    1642           0 :         (agent->interface_table()->FindActiveEntry(&key));
    1643           0 :     if (intf) {
    1644           0 :         return intf->id();
    1645             :     }
    1646           0 :     return Interface::kInvalidIndex;
    1647             : }
    1648             : 
    1649         224 : const std::string FlowEntry::InterfaceIdToVmCfgName(Agent *agent, uint32_t id) {
    1650         224 :     if (id != Interface::kInvalidIndex) {
    1651         203 :         const VmInterface *itf = dynamic_cast <const VmInterface *>
    1652         203 :             (agent->interface_table()->FindInterface(id));
    1653         203 :         if (itf) {
    1654         135 :             const VmEntry *vm = itf->vm();
    1655         135 :             if (vm) {
    1656         135 :                 return vm->GetCfgName();
    1657             :             }
    1658             :         }
    1659             :     }
    1660          89 :     return "";
    1661             : }
    1662             : /////////////////////////////////////////////////////////////////////////////
    1663             : // Routines to compute ACL to be applied (including network-policy, SG and
    1664             : // VRF-Assign Rules
    1665             : /////////////////////////////////////////////////////////////////////////////
    1666         226 : void FlowEntry::ResetPolicy() {
    1667             :     /* Reset acl list*/
    1668         226 :     data_.match_p.m_acl_l.clear();
    1669         226 :     data_.match_p.m_out_acl_l.clear();
    1670         226 :     data_.match_p.m_mirror_acl_l.clear();
    1671         226 :     data_.match_p.m_out_mirror_acl_l.clear();
    1672             :     /* Reset sg acl list*/
    1673         226 :     data_.match_p.sg_policy.ResetPolicy();
    1674         226 :     data_.match_p.aps_policy.ResetPolicy();
    1675         226 :     data_.match_p.fwaas_policy.ResetPolicy();
    1676         226 :     data_.match_p.m_vrf_assign_acl_l.clear();
    1677         226 : }
    1678             : 
    1679             : // Rebuild all the policy rules to be applied
    1680         230 : void FlowEntry::GetPolicyInfo(const VnEntry *vn, const FlowEntry *rflow) {
    1681         230 :     if (vn == NULL) {
    1682           4 :         return;
    1683             :     }
    1684             : 
    1685             :     // Reset old values first
    1686         226 :     ResetPolicy();
    1687             : 
    1688             :     // Short flows means there is some information missing for the flow. Skip
    1689             :     // getting policy information for short flow. When the information is
    1690             :     // complete, GetPolicyInfo is called again
    1691         226 :     if (is_flags_set(FlowEntry::ShortFlow)) {
    1692          30 :         return;
    1693             :     }
    1694             : 
    1695             :     // ACL supported on VMPORT interfaces only
    1696         196 :     if (data_.intf_entry == NULL)
    1697           0 :         return;
    1698             : 
    1699         196 :     bool vgw_pass = true;
    1700         196 :     if (data_.intf_entry->type() == Interface::INET) {
    1701           0 :         vgw_pass = false;
    1702           0 :         InetInterface* inet_intf = (InetInterface*)(data_.intf_entry).get();
    1703           0 :         if ((inet_intf != NULL) && (inet_intf->sub_type() == InetInterface::SIMPLE_GATEWAY))
    1704           0 :                vgw_pass = true;
    1705             :     }
    1706         196 :     if ((data_.intf_entry->type() != Interface::VM_INTERFACE) && !vgw_pass)
    1707           0 :         return;
    1708             : 
    1709             :     // Get Network policy/mirror cfg policy/mirror policies
    1710         196 :     GetPolicy(vn, rflow);
    1711             : 
    1712             :     // Get Sg list
    1713         196 :     GetSgList(data_.intf_entry.get());
    1714             : 
    1715             :     //Get VRF translate ACL
    1716         196 :     GetVrfAssignAcl();
    1717             : 
    1718             :     //Get Application policy set ACL
    1719         196 :     GetApplicationPolicySet(data_.intf_entry.get(), rflow);
    1720             : 
    1721             : }
    1722             : 
    1723         230 : void FlowEntry::GetPolicyInfo() {
    1724         230 :     GetPolicyInfo(data_.vn_entry.get(), reverse_flow_entry());
    1725         230 : }
    1726             : 
    1727           0 : void FlowEntry::GetPolicyInfo(const VnEntry *vn) {
    1728           0 :     GetPolicyInfo(vn, reverse_flow_entry());
    1729           0 : }
    1730             : 
    1731           0 : void FlowEntry::GetPolicyInfo(const FlowEntry *rflow) {
    1732           0 :     GetPolicyInfo(data_.vn_entry.get(), rflow);
    1733           0 : }
    1734             : 
    1735         196 : void FlowEntry::GetPolicy(const VnEntry *vn, const FlowEntry *rflow) {
    1736         196 :     if (vn == NULL)
    1737         172 :         return;
    1738             : 
    1739         196 :     MatchAclParams acl;
    1740             : 
    1741             :     // Get Mirror configuration first
    1742         196 :     if (vn->GetMirrorAcl()) {
    1743           0 :         acl.acl = vn->GetMirrorAcl();
    1744           0 :         data_.match_p.m_mirror_acl_l.push_back(acl);
    1745             :     }
    1746             : 
    1747         196 :     if (vn->GetMirrorCfgAcl()) {
    1748           0 :         acl.acl = vn->GetMirrorCfgAcl();
    1749           0 :         data_.match_p.m_mirror_acl_l.push_back(acl);
    1750             :     }
    1751             : 
    1752             :     // Dont apply network-policy for linklocal, bgp router service
    1753             :     // and subnet broadcast flow
    1754         392 :     if (is_flags_set(FlowEntry::LinkLocalFlow) ||
    1755         392 :         is_flags_set(FlowEntry::Multicast) ||
    1756         392 :         is_flags_set(FlowEntry::BgpRouterService) ||
    1757         588 :         is_flags_set(FlowEntry::FabricControlFlow) ||
    1758         392 :         is_flags_set(FlowEntry::ReverseFlow)) {
    1759          98 :         return;
    1760             :     }
    1761             : 
    1762          98 :     if (vn->GetAcl()) {
    1763           1 :         acl.acl = vn->GetAcl();
    1764           1 :         data_.match_p.m_acl_l.push_back(acl);
    1765             :     }
    1766             : 
    1767          98 :     const VnEntry *rvn = NULL;
    1768             :     // For local flows, we have to apply NW Policy from out-vn also
    1769          98 :     if (!is_flags_set(FlowEntry::LocalFlow) || rflow == NULL) {
    1770             :         // Not local flow
    1771          74 :         return;
    1772             :     }
    1773             : 
    1774          24 :     rvn = rflow->vn_entry();
    1775          24 :     if (rvn == NULL) {
    1776           0 :         return;
    1777             :     }
    1778             : 
    1779          24 :     if (rvn->GetAcl()) {
    1780           0 :         acl.acl = rvn->GetAcl();
    1781           0 :         data_.match_p.m_out_acl_l.push_back(acl);
    1782             :     }
    1783             : 
    1784          24 :     if (rvn->GetMirrorAcl()) {
    1785           0 :         acl.acl = rvn->GetMirrorAcl();
    1786           0 :         data_.match_p.m_out_mirror_acl_l.push_back(acl);
    1787             :     }
    1788             : 
    1789          24 :     if (rvn->GetMirrorCfgAcl()) {
    1790           0 :         acl.acl = rvn->GetMirrorCfgAcl();
    1791           0 :         data_.match_p.m_out_mirror_acl_l.push_back(acl);
    1792             :     }
    1793         196 : }
    1794             : 
    1795         196 : void FlowEntry::GetVrfAssignAcl() {
    1796             :     // VRF-Assign rules valid only for routed packets
    1797         196 :     if (l3_flow() == false)
    1798         195 :         return;
    1799             : 
    1800         132 :     if (data_.intf_entry == NULL) {
    1801           0 :         return;
    1802             :     }
    1803             : 
    1804         132 :     if  (data_.intf_entry->type() != Interface::VM_INTERFACE) {
    1805           0 :         return;
    1806             :     }
    1807             : 
    1808         264 :     if (is_flags_set(FlowEntry::LinkLocalFlow) ||
    1809         264 :         is_flags_set(FlowEntry::Multicast) ||
    1810         264 :         is_flags_set(FlowEntry::BgpRouterService) ||
    1811         396 :         is_flags_set(FlowEntry::FabricControlFlow) ||
    1812         264 :         is_flags_set(FlowEntry::ReverseFlow)) {
    1813          66 :         return;
    1814             :     }
    1815             : 
    1816             :     const VmInterface *intf =
    1817          66 :         static_cast<const VmInterface *>(data_.intf_entry.get());
    1818             :     //If interface has a VRF assign rule, choose the acl and match the
    1819             :     //packet, else get the acl attached to VN and try matching the packet to
    1820             :     //network acl
    1821          66 :     const AclDBEntry* acl = NULL;
    1822          66 :     if (is_flags_set(FlowEntry::NatFlow) == false) {
    1823          23 :         acl = intf->vrf_assign_acl();
    1824             :     }
    1825             : 
    1826          66 :     if (acl == NULL) {
    1827          66 :         acl = data_.vn_entry.get()->GetAcl();
    1828             :     }
    1829          66 :     if (!acl) {
    1830          65 :         return;
    1831             :     }
    1832             : 
    1833           1 :     MatchAclParams m_acl;
    1834           1 :     m_acl.acl = acl;
    1835           1 :     data_.match_p.m_vrf_assign_acl_l.push_back(m_acl);
    1836           1 : }
    1837             : 
    1838         196 : void FlowEntry::GetSgList(const Interface *intf) {
    1839             :     // Dont apply network-policy for linklocal and multicast flows
    1840         392 :     if (is_flags_set(FlowEntry::LinkLocalFlow) ||
    1841         392 :         is_flags_set(FlowEntry::Multicast) ||
    1842         588 :         is_flags_set(FlowEntry::BgpRouterService) ||
    1843         392 :         is_flags_set(FlowEntry::FabricControlFlow)) {
    1844           0 :         return;
    1845             :     }
    1846             : 
    1847             :     // SG ACL's are reflexive. Skip SG for reverse flow
    1848         196 :     if (is_flags_set(FlowEntry::ReverseFlow)) {
    1849          98 :         return;
    1850             :     }
    1851             : 
    1852             :     // Get virtual-machine port for forward flow
    1853          98 :     const VmInterface *vm_port = NULL;
    1854          98 :     bool vgw_pass = false;
    1855          98 :     if (intf != NULL) {
    1856          98 :         if (intf->type() == Interface::INET) {
    1857           0 :             const InetInterface* inet_intf = static_cast<const InetInterface *>(intf);
    1858           0 :             if ((inet_intf != NULL) && (inet_intf->sub_type() == InetInterface::SIMPLE_GATEWAY)) {
    1859           0 :                 vgw_pass = true;
    1860             :             }
    1861             :         }
    1862          98 :         if (intf->type() == Interface::VM_INTERFACE)  {
    1863          98 :             vm_port = static_cast<const VmInterface *>(intf);
    1864          98 :             vgw_pass = true;
    1865             :         }
    1866             :     }
    1867             : 
    1868          98 :     if (!vgw_pass) {
    1869           0 :         return;
    1870             :     }
    1871             : 
    1872             :     // Get virtual-machine port for reverse flow
    1873          98 :     FlowEntry *rflow = reverse_flow_entry();
    1874          98 :     const VmInterface *reverse_vm_port = NULL;
    1875          98 :     if (rflow != NULL) {
    1876          98 :         if (rflow->data().intf_entry.get() != NULL) {
    1877          98 :             if (rflow->data().intf_entry->type() == Interface::VM_INTERFACE) {
    1878             :                 reverse_vm_port = static_cast<const VmInterface *>
    1879          98 :                     (rflow->data().intf_entry.get());
    1880             :             }
    1881             :         }
    1882             :     }
    1883             : 
    1884             :     // Get SG-Rules
    1885          98 :     if (is_flags_set(FlowEntry::LocalFlow)) {
    1886          24 :         GetLocalFlowSgList(vm_port, reverse_vm_port);
    1887             :     } else {
    1888          74 :         GetNonLocalFlowSgList(vm_port);
    1889             :     }
    1890             : }
    1891             : 
    1892         196 : void FlowEntry::GetApplicationPolicySet(const Interface *intf,
    1893             :         const FlowEntry *rflow) {
    1894         392 :     if (is_flags_set(FlowEntry::LinkLocalFlow) ||
    1895         392 :         is_flags_set(FlowEntry::Multicast) ||
    1896         588 :         is_flags_set(FlowEntry::BgpRouterService) ||
    1897         392 :         is_flags_set(FlowEntry::FabricControlFlow)) {
    1898           0 :         return;
    1899             :     }
    1900             : 
    1901         196 :     if (is_flags_set(FlowEntry::ReverseFlow)) {
    1902          98 :         return;
    1903             :     }
    1904             : 
    1905          98 :     const VmInterface *vm_port = NULL;
    1906          98 :     if (intf != NULL) {
    1907          98 :         if (intf->type() == Interface::VM_INTERFACE) {
    1908          98 :             vm_port = static_cast<const VmInterface *>(intf);
    1909             :         }
    1910             :     }
    1911             : 
    1912          98 :     if (vm_port != NULL) {
    1913          98 :         MatchAclParams acl;
    1914             :         FirewallPolicyList::const_iterator it =
    1915          98 :             vm_port->fw_policy_list().begin();
    1916          98 :         for(; it != vm_port->fw_policy_list().end(); it++) {
    1917           0 :             acl.acl = *it;
    1918           0 :             data_.match_p.aps_policy.m_acl_l.push_back(acl);
    1919           0 :             data_.match_p.aps_policy.rule_present = true;
    1920           0 :             data_.match_p.aps_policy.m_reverse_out_acl_l.push_back(acl);
    1921           0 :             data_.match_p.aps_policy.reverse_out_rule_present= true;
    1922             :         }
    1923             : 
    1924             :         // Get the ACL for FWAAS
    1925          98 :         it = vm_port->fwaas_fw_policy_list().begin();
    1926          98 :         for(; it != vm_port->fwaas_fw_policy_list().end(); it++) {
    1927           0 :             acl.acl = *it;
    1928           0 :             data_.match_p.fwaas_policy.m_acl_l.push_back(acl);
    1929           0 :             data_.match_p.fwaas_policy.rule_present = true;
    1930           0 :             data_.match_p.fwaas_policy.m_reverse_out_acl_l.push_back(acl);
    1931           0 :             data_.match_p.fwaas_policy.reverse_out_rule_present= true;
    1932             :         }
    1933          98 :     }
    1934             : 
    1935             :     // For local flows, we have to apply NW Policy from out-vn also
    1936          98 :     if (!is_flags_set(FlowEntry::LocalFlow) || rflow == NULL) {
    1937             :         // Not local flow
    1938          74 :         return;
    1939             :     }
    1940             : 
    1941          24 :     const Interface *r_intf = rflow->data_.intf_entry.get();
    1942          24 :     if (r_intf == NULL) {
    1943           0 :         return;
    1944             :     }
    1945             : 
    1946          24 :     vm_port = dynamic_cast<const VmInterface *>(r_intf);
    1947          24 :     if (vm_port != NULL) {
    1948          24 :         MatchAclParams acl;
    1949             :         FirewallPolicyList::const_iterator it =
    1950          24 :             vm_port->fw_policy_list().begin();
    1951          24 :         for(; it != vm_port->fw_policy_list().end(); it++) {
    1952           0 :             acl.acl = *it;
    1953           0 :             data_.match_p.aps_policy.m_out_acl_l.push_back(acl);
    1954           0 :             data_.match_p.aps_policy.out_rule_present = true;
    1955           0 :             data_.match_p.aps_policy.m_reverse_acl_l.push_back(acl);
    1956           0 :             data_.match_p.aps_policy.reverse_rule_present = true;
    1957             :         }
    1958             : 
    1959             :         // Get the ACL for FWAAS
    1960          24 :         it = vm_port->fwaas_fw_policy_list().begin();
    1961          24 :         for(; it != vm_port->fwaas_fw_policy_list().end(); it++) {
    1962           0 :             acl.acl = *it;
    1963           0 :             data_.match_p.fwaas_policy.m_out_acl_l.push_back(acl);
    1964           0 :             data_.match_p.fwaas_policy.out_rule_present = true;
    1965           0 :             data_.match_p.fwaas_policy.m_reverse_acl_l.push_back(acl);
    1966           0 :             data_.match_p.fwaas_policy.reverse_rule_present = true;
    1967             :         }
    1968          24 :     }
    1969             : }
    1970             : 
    1971             : // Ingress-ACL/Egress-ACL in interface with VM as reference point.
    1972             : //      Ingress : Packet to VM
    1973             : //      Egress  : Packet from VM
    1974             : // The direction stored in flow is defined with vrouter as reference point
    1975             : //      Ingress : Packet to Vrouter from VM
    1976             : //      Egress  : Packet from Vrouter to VM
    1977             : //
    1978             : // Function takes care of copying right rules
    1979         122 : static bool CopySgEntries(const VmInterface *vm_port, bool ingress_acl,
    1980             :                           std::list<MatchAclParams> &list) {
    1981             :     /* If policy is NOT enabled on VMI, do not copy SG rules */
    1982         122 :     if (!vm_port->policy_enabled()) {
    1983           0 :         return false;
    1984             :     }
    1985         122 :     bool ret = false;
    1986         122 :     for (VmInterface::SecurityGroupEntrySet::const_iterator it =
    1987         122 :          vm_port->sg_list().list_.begin();
    1988         154 :          it != vm_port->sg_list().list_.end(); ++it) {
    1989          32 :         if (it->sg_ == NULL)
    1990           0 :             continue;
    1991             : 
    1992          32 :         if (it->sg_->IsAclSet()) {
    1993          32 :             ret = true;
    1994             :         }
    1995          32 :         MatchAclParams acl;
    1996             :         // As per definition above,
    1997             :         //      get EgressACL if flow direction is Ingress
    1998             :         //      get IngressACL if flow direction is Egress
    1999          32 :         if (ingress_acl) {
    2000          10 :             acl.acl = it->sg_->GetEgressAcl();
    2001             :         } else {
    2002          22 :             acl.acl = it->sg_->GetIngressAcl();
    2003             :         }
    2004          32 :         if (acl.acl)
    2005          32 :             list.push_back(acl);
    2006          32 :     }
    2007             : 
    2008         122 :     return ret;
    2009             : }
    2010             : 
    2011          24 : void FlowEntry::GetLocalFlowSgList(const VmInterface *vm_port,
    2012             :                                    const VmInterface *reverse_vm_port) {
    2013             :     // Get SG-Rule for the forward flow
    2014          24 :     if (vm_port) {
    2015          24 :         data_.match_p.sg_policy.rule_present =
    2016          24 :             CopySgEntries(vm_port, true, data_.match_p.sg_policy.m_acl_l);
    2017             :     }
    2018             :     // For local flow, we need to simulate SG lookup at both ends.
    2019             :     // Assume packet is from VM-A to VM-B.
    2020             :     // If we apply Ingress-ACL from VM-A, then apply Egress-ACL from VM-B
    2021             :     // If we apply Egress-ACL from VM-A, then apply Ingress-ACL from VM-B
    2022          24 :     if (reverse_vm_port) {
    2023          24 :         data_.match_p.sg_policy.out_rule_present =
    2024          24 :             CopySgEntries(reverse_vm_port, false, data_.match_p.sg_policy.m_out_acl_l);
    2025             :     }
    2026          24 :     if (!is_flags_set(FlowEntry::TcpAckFlow)) {
    2027          24 :         return;
    2028             :     }
    2029             :     // TCP ACK workaround:
    2030             :     // Ideally TCP State machine should be run to age TCP flows
    2031             :     // Temporary workaound in place of state machine. For TCP ACK packets allow
    2032             :     // the flow if either forward or reverse flow is allowed
    2033             : 
    2034             :     // Copy the SG rules to be applied for reverse flow
    2035           0 :     if (vm_port) {
    2036           0 :         data_.match_p.sg_policy.reverse_out_rule_present =
    2037           0 :             CopySgEntries(vm_port, false,
    2038           0 :                           data_.match_p.sg_policy.m_reverse_out_acl_l);
    2039             :     }
    2040             : 
    2041           0 :     if (reverse_vm_port) {
    2042           0 :         data_.match_p.sg_policy.reverse_rule_present =
    2043           0 :             CopySgEntries(reverse_vm_port, true,
    2044           0 :                           data_.match_p.sg_policy.m_reverse_acl_l);
    2045             :     }
    2046             : }
    2047             : 
    2048          74 : void FlowEntry::GetNonLocalFlowSgList(const VmInterface *vm_port) {
    2049             :     // Get SG-Rule for the forward flow
    2050          74 :     bool ingress = is_flags_set(FlowEntry::IngressDir);
    2051          74 :     if (vm_port) {
    2052          74 :         data_.match_p.sg_policy.rule_present =
    2053          74 :             CopySgEntries(vm_port, ingress,
    2054          74 :                           data_.match_p.sg_policy.m_acl_l);
    2055             :     }
    2056             : 
    2057          74 :     data_.match_p.sg_policy.out_rule_present = false;
    2058             : 
    2059          74 :     if (!is_flags_set(FlowEntry::TcpAckFlow)) {
    2060          74 :         return;
    2061             :     }
    2062             : 
    2063             :     // TCP ACK workaround:
    2064             :     // Ideally TCP State machine should be run to age TCP flows
    2065             :     // Temporary workaound in place of state machine. For TCP ACK packets allow
    2066             :     // the flow if either forward or reverse flow is allowed
    2067             : 
    2068             :     // Copy the SG rules to be applied for reverse flow
    2069           0 :     if (vm_port) {
    2070           0 :         data_.match_p.sg_policy.reverse_out_rule_present =
    2071           0 :             CopySgEntries(vm_port, !ingress,
    2072           0 :                           data_.match_p.sg_policy.m_reverse_out_acl_l);
    2073             :     }
    2074           0 :     data_.match_p.sg_policy.reverse_rule_present = false;
    2075             : }
    2076             : 
    2077             : // For an L2-Flow, refresh the vn-list and sg-list from the route used for
    2078             : // flow
    2079           6 : void FlowEntry::UpdateL2RouteInfo() {
    2080             :     // Skip L3-Flows
    2081           6 :     if (l3_flow())
    2082           0 :         return;
    2083             : 
    2084           6 :     Agent *agent = flow_table()->agent();
    2085             :     // Get VRF for the flow. L2 flow have same in and out-vrf. So, use same
    2086             :     // vrf for both smac and dmac lookup
    2087           6 :     uint32_t vrf_id = data().flow_source_vrf;
    2088           6 :     const VrfEntry *vrf = agent->vrf_table()->FindVrfFromId(vrf_id);
    2089           6 :     if (vrf == NULL || vrf->IsDeleted()) {
    2090           0 :         return;
    2091             :     }
    2092             :     BridgeAgentRouteTable *table =
    2093           6 :         static_cast<BridgeAgentRouteTable *>(vrf->GetBridgeRouteTable());
    2094             : 
    2095             :     // Get route-info for smac
    2096           6 :     GetSourceRouteInfo(table->FindRoute(data().smac));
    2097             :     // Get route-info for dmac
    2098           6 :     GetDestRouteInfo(table->FindRoute(data().dmac));
    2099             : }
    2100             : 
    2101             : /////////////////////////////////////////////////////////////////////////////
    2102             : // Flow policy processing routines
    2103             : /////////////////////////////////////////////////////////////////////////////
    2104             : 
    2105             : // Set HBS information
    2106             : // |-------------------------------------------------------------------------|
    2107             : // |    Source     |    Destination: VMI                | Destination: Fabric|
    2108             : // |--------------------------------------------------------------------------
    2109             : // |     VMI       | L (src vif index < dst vif index)  |         L          |
    2110             : // |               | else R                             |                    |
    2111             : // |--------------------------------------------------------------------------
    2112             : // |     Fabric    |                R                   |         -          |
    2113             : // |-------------------------------------------------------------------------|
    2114             : //
    2115         313 : void FlowEntry::SetHbsInfofromAction() {
    2116             : 
    2117         313 :     if (!(data_.match_p.aps_policy.action_summary & (1 << TrafficAction::HBS))) {
    2118         313 :         reset_flags(HbfFlow);
    2119         313 :         SetHbsInterface(HBS_INTERFACE_INVALID);
    2120         313 :         return;
    2121             :     }
    2122             : 
    2123             :     const VmInterface *src_intf =
    2124           0 :         dynamic_cast<const VmInterface *>(intf_entry());
    2125           0 :     FlowEntry *rev_flow = reverse_flow_entry();
    2126             :     const VmInterface *dst_intf =
    2127           0 :         dynamic_cast<const VmInterface *>(rev_flow->intf_entry());
    2128             : 
    2129           0 :     if ( src_intf == NULL || dst_intf == NULL ) {
    2130           0 :         reset_flags(HbfFlow);
    2131           0 :         SetHbsInterface(HBS_INTERFACE_INVALID);
    2132           0 :         return;
    2133             :     }
    2134             : 
    2135             :     //Enable HBF flow flag
    2136           0 :     set_flags(HbfFlow);
    2137           0 :     if (is_flags_set(LocalFlow)) {
    2138             :         /* Handle Service Chain Traffic for local flow VM <--> SI*/
    2139             :         /* Case 1: Reset the HBS Action if flow source is service interface */
    2140           0 :         if (!src_intf->service_intf_type().empty()) {
    2141           0 :             reset_flags(HbfFlow);
    2142           0 :             SetHbsInterface(HBS_INTERFACE_INVALID);
    2143           0 :             return;
    2144             :         }
    2145             :         /* Case 2: Set appropriate interface left/right based on service interface type */
    2146           0 :         if (!dst_intf->service_intf_type().empty()) {
    2147           0 :             if (dst_intf->service_intf_type() == "left") {
    2148           0 :                 SetHbsInterface(HBS_INTERFACE_LEFT);
    2149           0 :             } else if (dst_intf->service_intf_type() == "right") {
    2150           0 :                 SetHbsInterface(HBS_INTERFACE_RIGHT);
    2151             :             }
    2152           0 :             return;
    2153             :         }
    2154             :         // VM <--> VM on same compute
    2155           0 :         (src_intf->id() < dst_intf->id()) ?
    2156           0 :             SetHbsInterface(HBS_INTERFACE_LEFT):
    2157           0 :             SetHbsInterface(HBS_INTERFACE_RIGHT);
    2158             :     } else {
    2159             :         /* Handle Service chain traffic entering the compute */
    2160           0 :         if ((!src_intf->service_intf_type().empty() ||
    2161           0 :              !dst_intf->service_intf_type().empty())) {
    2162           0 :             if (is_flags_set(IngressDir) == 0) {
    2163           0 :                 if (dst_intf->service_intf_type() == "left") {
    2164           0 :                     SetHbsInterface(HBS_INTERFACE_LEFT);
    2165           0 :                 } else if (dst_intf->service_intf_type() == "right") {
    2166           0 :                     SetHbsInterface(HBS_INTERFACE_RIGHT);
    2167             :                 }
    2168             :             } else {
    2169           0 :                 reset_flags(HbfFlow);
    2170           0 :                 SetHbsInterface(HBS_INTERFACE_INVALID);
    2171             :             }
    2172             :         } else {
    2173             :             // VM <--> VM on different compute
    2174           0 :             (is_flags_set(IngressDir)) ?
    2175           0 :                 SetHbsInterface(HBS_INTERFACE_LEFT):
    2176           0 :                 SetHbsInterface(HBS_INTERFACE_RIGHT);
    2177             :         }
    2178             :     }
    2179             : }
    2180             : 
    2181         198 : void FlowEntry::SetVrfAssignEntry() {
    2182         198 :     if (!(data_.match_p.vrf_assign_acl_action &
    2183             :          (1 << TrafficAction::VRF_TRANSLATE))) {
    2184             :         //If VRF assign was evaluated and the vrf translate
    2185             :         //action is not present in latest evaluation mark the
    2186             :         //flow as short flow
    2187         204 :         if (data_.vrf_assign_evaluated &&
    2188           6 :                 data_.match_p.action_info.vrf_translate_action_.vrf_name()
    2189          12 :                 != Agent::NullString()) {
    2190           0 :             MakeShortFlow(SHORT_VRF_CHANGE);
    2191             :         }
    2192         198 :         data_.vrf_assign_evaluated = true;
    2193         198 :         data_.acl_assigned_vrf_index_ = VrfEntry::kInvalidIndex;
    2194         198 :         return;
    2195             :     }
    2196             : 
    2197             :     std::string vrf_assigned_name =
    2198           0 :         data_.match_p.action_info.vrf_translate_action_.vrf_name();
    2199           0 :     std::list<MatchAclParams>::const_iterator acl_it;
    2200           0 :     for (acl_it = match_p().m_vrf_assign_acl_l.begin();
    2201           0 :          acl_it != match_p().m_vrf_assign_acl_l.end();
    2202           0 :          ++acl_it) {
    2203           0 :         std::string vrf = acl_it->action_info.vrf_translate_action_.vrf_name();
    2204           0 :         data_.match_p.action_info.vrf_translate_action_.set_vrf_name(vrf);
    2205             :         //Check if VRF assign acl says, network ACL and SG action
    2206             :         //to be ignored
    2207             :         bool ignore_acl =
    2208           0 :             acl_it->action_info.vrf_translate_action_.ignore_acl();
    2209             :         data_.match_p.action_info.vrf_translate_action_.set_ignore_acl
    2210           0 :             (ignore_acl);
    2211           0 :     }
    2212           0 :     if (data_.vrf_assign_evaluated && vrf_assigned_name !=
    2213           0 :         data_.match_p.action_info.vrf_translate_action_.vrf_name()) {
    2214           0 :         MakeShortFlow(SHORT_VRF_CHANGE);
    2215             :     }
    2216             : 
    2217           0 :     set_acl_assigned_vrf_index();
    2218           0 :     if (acl_assigned_vrf_index() == VrfEntry::kInvalidIndex) {
    2219           0 :         MakeShortFlow(SHORT_VRF_CHANGE);
    2220             :     }
    2221           0 :     data_.vrf_assign_evaluated = true;
    2222           0 : }
    2223             : 
    2224        1409 : uint32_t FlowEntry::MatchAcl(const PacketHeader &hdr,
    2225             :                              std::list<MatchAclParams> &acl,
    2226             :                              bool add_implicit_deny, bool add_implicit_allow,
    2227             :                              FlowPolicyInfo *info) {
    2228        1409 :     PktHandler *pkt_handler = Agent::GetInstance()->pkt()->pkt_handler();
    2229             : 
    2230             :     // If there are no ACL to match, make it pass
    2231        1409 :     if (acl.size() == 0 &&  add_implicit_allow) {
    2232        1378 :         if (info) {
    2233             :             /* We are setting UUIDs for linklocal and multicast flows here,
    2234             :              * because even if we move this to the place where acl association
    2235             :              * is being skipped, we still need checks for linklocal and
    2236             :              * multicast flows here to avoid its value being overwritten with
    2237             :              * IMPLICIT_ALLOW
    2238             :              */
    2239         884 :             if (is_flags_set(FlowEntry::LinkLocalFlow)) {
    2240           0 :                 info->uuid = FlowPolicyStateStr.at(LINKLOCAL_FLOW);
    2241         884 :             } else if (is_flags_set(FlowEntry::Multicast)) {
    2242           0 :                 info->uuid = FlowPolicyStateStr.at(MULTICAST_FLOW);
    2243         884 :             } else if (is_flags_set(FlowEntry::BgpRouterService)) {
    2244           0 :                 info->uuid = FlowPolicyStateStr.at(BGPROUTERSERVICE_FLOW);
    2245             :             } else {
    2246             :                 /* We need to make sure that info is not already populated
    2247             :                  * before setting it to IMPLICIT_ALLOW. This is required
    2248             :                  * because info could earlier be set by previous call to
    2249             :                  * MatchAcl. We should note here that same 'info' var is passed
    2250             :                  * for MatchAcl calls with in_acl and out_acl
    2251             :                  */
    2252         884 :                 if (!info->terminal && !info->other) {
    2253         884 :                     info->uuid = FlowPolicyStateStr.at(IMPLICIT_ALLOW);
    2254             :                 }
    2255             :             }
    2256             :         }
    2257        1378 :         return (1 << TrafficAction::PASS);
    2258             :     }
    2259             : 
    2260             :     // PASS default GW traffic, if it is ICMP or DNS
    2261          90 :     if ((hdr.protocol == IPPROTO_ICMP ||
    2262          28 :          (hdr.protocol == IPPROTO_UDP &&
    2263          28 :           (hdr.src_port == DNS_SERVER_PORT ||
    2264          62 :            hdr.dst_port == DNS_SERVER_PORT))) &&
    2265           3 :         (pkt_handler->IsGwPacket(data_.intf_entry.get(), hdr.dst_ip) ||
    2266           3 :          pkt_handler->IsGwPacket(data_.intf_entry.get(), hdr.src_ip))) {
    2267           0 :         if (info) {
    2268           0 :             info->uuid = FlowPolicyStateStr.at(DEFAULT_GW_ICMP_OR_DNS);
    2269             :         }
    2270           0 :         return (1 << TrafficAction::PASS);
    2271             :     }
    2272             : 
    2273          31 :     uint32_t action = 0;
    2274          31 :     for (std::list<MatchAclParams>::iterator it = acl.begin();
    2275          37 :          it != acl.end(); ++it) {
    2276          31 :         if (it->acl.get() == NULL) {
    2277           0 :             continue;
    2278             :         }
    2279             : 
    2280          31 :         if (it->acl->PacketMatch(hdr, *it, info)) {
    2281          25 :             action |= it->action_info.action;
    2282          25 :             if (it->action_info.action & (1 << TrafficAction::MIRROR)) {
    2283             :                 data_.match_p.action_info.mirror_l.insert
    2284           0 :                     (data_.match_p.action_info.mirror_l.end(),
    2285           0 :                      it->action_info.mirror_l.begin(),
    2286           0 :                      it->action_info.mirror_l.end());
    2287             :             }
    2288             : 
    2289          25 :             if (it->terminal_rule) {
    2290          25 :                 break;
    2291             :             }
    2292             :         }
    2293             :     }
    2294             : 
    2295             :     // If no acl matched, make it imlicit deny
    2296          31 :     if (action == 0 && add_implicit_deny) {
    2297           5 :         action = (1 << TrafficAction::DENY) |
    2298             :             (1 << TrafficAction::IMPLICIT_DENY);
    2299           5 :         if (info) {
    2300           5 :             info->uuid = FlowPolicyStateStr.at(IMPLICIT_DENY);
    2301           5 :             info->drop = true;
    2302             :         }
    2303             :     }
    2304             : 
    2305          31 :     return action;
    2306             : }
    2307             : 
    2308         464 : void FlowEntry::SetPacketHeader(PacketHeader *hdr) {
    2309         464 :     hdr->vrf = data_.vrf;
    2310         464 :     hdr->src_ip = key_.src_addr;
    2311         464 :     hdr->dst_ip = key_.dst_addr;
    2312         464 :     hdr->protocol = key_.protocol;
    2313         464 :     if (hdr->protocol == IPPROTO_UDP || hdr->protocol == IPPROTO_TCP) {
    2314         337 :         hdr->src_port = key_.src_port;
    2315         337 :         hdr->dst_port = key_.dst_port;
    2316             :     } else {
    2317         127 :         hdr->src_port = 0;
    2318         127 :         hdr->dst_port = 0;
    2319             :     }
    2320         464 :     hdr->src_policy_id = &(data_.source_vn_list);
    2321         464 :     hdr->dst_policy_id = &(data_.dest_vn_list);
    2322         464 :     hdr->src_sg_id_l = &(data_.source_sg_id_l);
    2323         464 :     hdr->dst_sg_id_l = &(data_.dest_sg_id_l);
    2324         464 :     hdr->src_tags_ = data_.source_tag_id_l;
    2325         464 :     hdr->dst_tags_ = data_.dest_tag_id_l;
    2326         464 :     hdr->family =  key_.family;
    2327         464 : }
    2328             : 
    2329             : // In case of NAT flows, the key fields can change.
    2330         254 : void FlowEntry::SetOutPacketHeader(PacketHeader *hdr) {
    2331         254 :     FlowEntry *rflow = reverse_flow_entry();
    2332         254 :     if (rflow == NULL)
    2333           0 :         return;
    2334             : 
    2335         254 :     hdr->vrf = rflow->data().vrf;
    2336         254 :     hdr->src_ip = rflow->key().dst_addr;
    2337         254 :     hdr->dst_ip = rflow->key().src_addr;
    2338         254 :     hdr->protocol = rflow->key().protocol;
    2339         254 :     if (hdr->protocol == IPPROTO_UDP || hdr->protocol == IPPROTO_TCP) {
    2340         179 :         hdr->src_port = rflow->key().dst_port;
    2341         179 :         hdr->dst_port = rflow->key().src_port;
    2342             :     } else {
    2343          75 :         hdr->src_port = 0;
    2344          75 :         hdr->dst_port = 0;
    2345             :     }
    2346         254 :     hdr->src_policy_id = &(rflow->data().dest_vn_list);
    2347         254 :     hdr->dst_policy_id = &(rflow->data().source_vn_list);
    2348         254 :     hdr->src_sg_id_l = &(rflow->data().dest_sg_id_l);
    2349         254 :     hdr->dst_sg_id_l = &(rflow->data().source_sg_id_l);
    2350         254 :     hdr->src_tags_ = rflow->data_.dest_tag_id_l;
    2351         254 :     hdr->dst_tags_ = rflow->data_.source_tag_id_l;
    2352         254 :     hdr->family = key_.family;
    2353             : }
    2354             : 
    2355         266 : void FlowEntry::SetAclInfo(SessionPolicy *sp, SessionPolicy *rsp,
    2356             :                            const FlowPolicyInfo &fwd_flow_info,
    2357             :                            const FlowPolicyInfo &rev_flow_info,
    2358             :                            bool tcp_rev, bool is_sg) {
    2359             : 
    2360         266 :     FlowEntry *rflow = reverse_flow_entry();
    2361         266 :     if (rflow == NULL) {
    2362           0 :         return;
    2363             :     }
    2364             : 
    2365         266 :     sp->rule_uuid_ = fwd_flow_info.uuid;
    2366         266 :     sp->acl_name_ = fwd_flow_info.acl_name;
    2367             : 
    2368         266 :     rsp->rule_uuid_ = rev_flow_info.uuid;
    2369         266 :     rsp->acl_name_ = rev_flow_info.acl_name;
    2370             : 
    2371             :     //If Forward flow SG rule says drop, copy corresponding
    2372             :     //ACE id to both forward and reverse flow
    2373         266 :     if (fwd_flow_info.drop) {
    2374          12 :         rsp->rule_uuid_ = fwd_flow_info.uuid;
    2375          12 :         rsp->acl_name_ = fwd_flow_info.acl_name;
    2376          12 :         return;
    2377             :     }
    2378             : 
    2379             :     //If reverse flow SG rule says drop, copy corresponding
    2380             :     //ACE id to both forward and reverse flow
    2381         254 :     if (rev_flow_info.drop) {
    2382           2 :         sp->rule_uuid_ = rev_flow_info.uuid;
    2383           2 :         sp->acl_name_ = rev_flow_info.acl_name;
    2384           2 :         return;
    2385             :     }
    2386             : 
    2387         252 :     if (tcp_rev == false) {
    2388         252 :         if (is_sg) {
    2389          84 :             if (data_.match_p.sg_policy.rule_present == false) {
    2390          74 :                 sp->rule_uuid_ = rev_flow_info.uuid;
    2391          74 :                 sp->acl_name_ = rev_flow_info.acl_name;
    2392             :             }
    2393             : 
    2394          84 :             if (data_.match_p.sg_policy.out_rule_present == false) {
    2395          80 :                 rsp->rule_uuid_ = fwd_flow_info.uuid;
    2396          80 :                 rsp->acl_name_ = fwd_flow_info.acl_name;
    2397             :             }
    2398             :         } else {
    2399         168 :             if (data_.match_p.aps_policy.rule_present == false) {
    2400         168 :                 sp->rule_uuid_ = rev_flow_info.uuid;
    2401         168 :                 sp->acl_name_ = rev_flow_info.acl_name;
    2402             :             }
    2403             : 
    2404         168 :             if (data_.match_p.aps_policy.out_rule_present == false) {
    2405         168 :                 rsp->rule_uuid_ = fwd_flow_info.uuid;
    2406         168 :                 rsp->acl_name_ = fwd_flow_info.acl_name;
    2407             :             }
    2408             :         }
    2409             :     }
    2410             : 
    2411         252 :     if (tcp_rev == true) {
    2412           0 :         if (sp->reverse_rule_present == false) {
    2413           0 :             rsp->rule_uuid_ = fwd_flow_info.uuid;
    2414           0 :             rsp->acl_name_ = fwd_flow_info.acl_name;
    2415             :         }
    2416             : 
    2417           0 :         if (sp->reverse_out_rule_present == false) {
    2418           0 :             sp->rule_uuid_ = rev_flow_info.uuid;
    2419           0 :             sp->acl_name_ = rev_flow_info.acl_name;
    2420             :         }
    2421             :     }
    2422             : }
    2423             : 
    2424         266 : void FlowEntry::SessionMatch(SessionPolicy *sp, SessionPolicy *rsp,
    2425             :                              bool is_sg) {
    2426             : 
    2427         266 :     FlowEntry *rflow = reverse_flow_entry();
    2428         266 :     const string value = FlowPolicyStateStr.at(NOT_EVALUATED);
    2429         266 :     FlowPolicyInfo acl_info(value);
    2430         266 :     FlowPolicyInfo out_acl_info(value);
    2431         266 :     FlowPolicyInfo rev_acl_info(value);
    2432         266 :     FlowPolicyInfo rev_out_acl_info(value);
    2433             : 
    2434         266 :     sp->rule_uuid_ = FlowEntry::FlowPolicyStateStr.at(FlowEntry::NOT_EVALUATED);
    2435         266 :     sp->acl_name_ = "";
    2436             : 
    2437         266 :     if (rsp) {
    2438             :         rsp->rule_uuid_ =
    2439         266 :             FlowEntry::FlowPolicyStateStr.at(FlowEntry::NOT_EVALUATED);
    2440         266 :         rsp->acl_name_ = "";
    2441             :     }
    2442             : 
    2443         266 :     PacketHeader hdr;
    2444         266 :     SetPacketHeader(&hdr);
    2445             : 
    2446             :     //Apply ACL configured on ingress interface
    2447         266 :     sp->action = MatchAcl(hdr, sp->m_acl_l, true, !sp->rule_present, &acl_info);
    2448             : 
    2449             :     //Apply ACL configured on egress interface
    2450         266 :     PacketHeader out_hdr;
    2451         266 :     if (ShouldDrop(sp->action) == false && rflow) {
    2452             :         // Key fields for lookup in out-acl can potentially change in case
    2453             :         // of NAT. Form ACL lookup based on post-NAT fields
    2454         254 :         SetOutPacketHeader(&out_hdr);
    2455         254 :         sp->out_action = MatchAcl(out_hdr, sp->m_out_acl_l, true,
    2456         254 :                                  !sp->out_rule_present, &out_acl_info);
    2457             :     }
    2458             : 
    2459             :     // For TCP-ACK packet, we allow packet if either forward or reverse
    2460             :     // flow says allow. So, continue matching reverse flow even if forward
    2461             :     // flow says drop
    2462         266 :     if (is_flags_set(FlowEntry::TcpAckFlow) && rflow) {
    2463           0 :         rflow->SetPacketHeader(&hdr);
    2464           0 :         sp->reverse_action = MatchAcl(hdr, sp->m_reverse_acl_l, true,
    2465           0 :                                      !sp->reverse_rule_present, &rev_acl_info);
    2466             : 
    2467           0 :         if (ShouldDrop(sp->reverse_action) == false) {
    2468             :             // Key fields for lookup in out-acl can potentially change in
    2469             :             // case of NAT. Form ACL lookup based on post-NAT fields
    2470           0 :             rflow->SetOutPacketHeader(&out_hdr);
    2471           0 :             sp->reverse_out_action = MatchAcl(out_hdr, sp->m_reverse_out_acl_l,
    2472           0 :                                              true, !sp->reverse_out_rule_present,
    2473             :                                              &rev_out_acl_info);
    2474             :         }
    2475             :     }
    2476             : 
    2477             :     // Compute summary SG action.
    2478             :     // For Non-TCP-ACK Flows
    2479             :     //     DROP if any of policy.action, out_action, policy.reverse_action or
    2480             :     //     policy.reverse_out_action says DROP
    2481             :     //     Only acl_info which is derived from sp->m_acl_l
    2482             :     //     and sp->m_out_acl_l will be populated. Pick the
    2483             :     //     UUID specified by acl_info for flow's SG rule UUID
    2484             :     // For TCP-ACK flows
    2485             :     //     ALLOW if either ((policy.action && out_action) ||
    2486             :     //                      (policy.reverse_action & policy.reverse_out_action))
    2487             :     //                      ALLOW
    2488             :     //     For flow's SG rule UUID use the following rules
    2489             :     //     --If both acl_info and rev_acl_info has drop set, pick the
    2490             :     //       UUID from acl_info.
    2491             :     //     --If either of acl_info or rev_acl_info does not have drop
    2492             :     //       set, pick the UUID from the one which does not have drop set.
    2493             :     //     --If both of them does not have drop set, pick it up from
    2494             :     //       acl_info
    2495             :     //
    2496         266 :     if (!is_flags_set(FlowEntry::TcpAckFlow)) {
    2497         266 :         sp->action_summary =
    2498         266 :             sp->action | sp->out_action | sp->reverse_action | sp->reverse_out_action;
    2499         266 :         SetAclInfo(sp, rsp, acl_info, out_acl_info, false, is_sg);
    2500           0 :     } else if (ShouldDrop(sp->action | sp->out_action) &&
    2501           0 :                ShouldDrop(sp->reverse_action | sp->reverse_out_action)) {
    2502             :             //If both ingress ACL and egress ACL of VMI denies the
    2503             :             //packet, then pick ingress ACE uuid to send to UVE
    2504           0 :             sp->action_summary = (1 << TrafficAction::DENY);
    2505           0 :             SetAclInfo(sp, rsp, acl_info, out_acl_info, false, is_sg);
    2506             :     } else {
    2507           0 :         sp->action_summary = (1 << TrafficAction::PASS);
    2508           0 :         if (sp->action & (1 << TrafficAction::HBS) ||
    2509           0 :             sp->out_action & (1 << TrafficAction::HBS) ||
    2510           0 :             sp->reverse_action & (1 << TrafficAction::HBS) ||
    2511           0 :             sp->reverse_out_action & (1 << TrafficAction::HBS)) {
    2512           0 :             sp->action_summary|=(1 << TrafficAction::HBS);
    2513             :         }
    2514           0 :         if (!ShouldDrop(sp->action | sp->out_action)) {
    2515           0 :             SetAclInfo(sp, rsp, acl_info, out_acl_info, false, is_sg);
    2516           0 :         } else if (!ShouldDrop(sp->reverse_action | sp->reverse_out_action)) {
    2517           0 :             SetAclInfo(sp, rsp, rev_out_acl_info, rev_acl_info, true, is_sg);
    2518             :         }
    2519             :     }
    2520         266 : }
    2521             : 
    2522             : // Apply Policy and SG rules for a flow.
    2523             : //
    2524             : // Special case of local flows:
    2525             : //     For local-flows, both VM are on same compute and we need to apply SG from
    2526             : //     both the ports. sg_policy.m_acl_l will contain ACL for port in forward flow and
    2527             : //     sg_policy.m_out_acl_l will have ACL from other port
    2528             : //
    2529             : //     If forward flow goes thru NAT, the key for matching ACL in
    2530             : //     sg_policy.m_out_acl_l can potentially change. The routine SetOutPacketHeader
    2531             : //     takes care of forming header after NAT
    2532             : //
    2533             : // Rules applied are based on flow type
    2534             : // Non-Local Forward Flow
    2535             : //      Network Policy.
    2536             : //      Out-Network Policy will be empty
    2537             : //      SG
    2538             : //      Out-SG will be empty
    2539             : // Non-Local Reverse Flow
    2540             : //      Network Policy.
    2541             : //      Out-Network Policy will be empty
    2542             : //      SG and out-SG from forward flow
    2543             : // Local Forward Flow
    2544             : //      Network Policy.
    2545             : //      Out-Network Policy
    2546             : //      SG
    2547             : //      Out-SG
    2548             : // Local Reverse Flow
    2549             : //      Network Policy.
    2550             : //      Out-Network Policy
    2551             : //      SG and out-SG from forward flow
    2552         230 : bool FlowEntry::DoPolicy() {
    2553         230 :     if (is_flags_set(FlowEntry::ShortFlow)) {
    2554          32 :         return true;
    2555             :     }
    2556         198 :     data_.match_p.action_info.Clear();
    2557         198 :     data_.match_p.policy_action = 0;
    2558         198 :     data_.match_p.out_policy_action = 0;
    2559         198 :     data_.match_p.mirror_action = 0;
    2560         198 :     data_.match_p.out_mirror_action = 0;
    2561             : 
    2562         198 :     data_.match_p.sg_policy.ResetAction();
    2563         198 :     data_.match_p.aps_policy.ResetAction();
    2564         198 :     data_.match_p.fwaas_policy.ResetAction();
    2565             : 
    2566         198 :     const string value = FlowPolicyStateStr.at(NOT_EVALUATED);
    2567         198 :     FlowPolicyInfo nw_acl_info(value);
    2568             : 
    2569         198 :     FlowEntry *rflow = reverse_flow_entry();
    2570         198 :     PacketHeader hdr;
    2571         198 :     SetPacketHeader(&hdr);
    2572             : 
    2573             :     //Calculate VRF assign entry, and ignore acl is set
    2574             :     //skip network and SG acl action is set
    2575         198 :     if (!is_flags_set(FlowEntry::ReverseFlow))
    2576             :     {
    2577          99 :         data_.match_p.vrf_assign_acl_action = MatchAcl(hdr, data_.match_p.m_vrf_assign_acl_l, false, true, NULL);
    2578             :     }
    2579             :     else
    2580             :     {
    2581          99 :         data_.match_p.vrf_assign_acl_action = rflow->data_.match_p.vrf_assign_acl_action;
    2582             :         data_.match_p.action_info.vrf_translate_action_ =
    2583          99 :             rflow->data_.match_p.action_info.vrf_translate_action_;
    2584             :     }
    2585             : 
    2586             :     // Mirror is valid even if packet is to be dropped. So, apply it first
    2587         198 :     data_.match_p.mirror_action = MatchAcl(hdr, data_.match_p.m_mirror_acl_l,
    2588             :                                            false, true, NULL);
    2589             : 
    2590             :     // Apply out-policy. Valid only for local-flow
    2591         396 :     data_.match_p.out_mirror_action = MatchAcl(hdr,
    2592         198 :                            data_.match_p.m_out_mirror_acl_l, false, true, NULL);
    2593             : 
    2594             :     // Apply network policy
    2595         198 :     if (!is_flags_set(FlowEntry::ReverseFlow)) {
    2596          99 :         data_.match_p.policy_action = MatchAcl(hdr, data_.match_p.m_acl_l, true,
    2597             :                                                 true, &nw_acl_info);
    2598          99 :         if (ShouldDrop(data_.match_p.policy_action))
    2599           1 :             goto done;
    2600          98 :         data_.match_p.out_policy_action = MatchAcl(hdr, data_.match_p.m_out_acl_l, 
    2601             :                                                     true, true, &nw_acl_info);
    2602          98 :         if (ShouldDrop(data_.match_p.out_policy_action))
    2603           0 :             goto done;
    2604             :     } 
    2605             :     else {
    2606          99 :         if (rflow) {
    2607         198 :             uint32_t r_policy_action = MatchAcl(hdr, 
    2608          99 :                                                 rflow->data_.match_p.m_acl_l, true, true, &nw_acl_info);
    2609          99 :             if (ShouldDrop(r_policy_action)) {
    2610           1 :                 data_.match_p.policy_action = rflow->data_.match_p.policy_action;
    2611           1 :                 goto done;
    2612             :             }
    2613         196 :             uint32_t r_out_policy_action = MatchAcl(hdr, 
    2614          98 :                                                     rflow->data_.match_p.m_out_acl_l, true, true, &nw_acl_info);
    2615          98 :             if (ShouldDrop(r_out_policy_action)) {
    2616           0 :                 data_.match_p.out_policy_action = rflow->data_.match_p.out_policy_action;
    2617           0 :                 goto done;
    2618             :             }
    2619             :         }
    2620             :     }
    2621             : 
    2622             :     // Apply sg policy
    2623         196 :     if (!is_flags_set(FlowEntry::ReverseFlow)) {
    2624          98 :         SessionPolicy *r_sg_policy = NULL;
    2625          98 :         SessionPolicy *r_aps_policy = NULL;
    2626          98 :         SessionPolicy *r_fwaas_policy = NULL;
    2627             : 
    2628          98 :         if (rflow) {
    2629          98 :             r_sg_policy = &(rflow->data_.match_p.sg_policy);
    2630          98 :             r_aps_policy = &(rflow->data_.match_p.aps_policy);
    2631          98 :             r_fwaas_policy = &(rflow->data_.match_p.fwaas_policy);
    2632             :         }
    2633             : 
    2634          98 :         SessionMatch(&data_.match_p.sg_policy, r_sg_policy, true);
    2635          98 :         if (ShouldDrop(data_.match_p.sg_policy.action_summary)) {
    2636          14 :             goto done;
    2637             :         }
    2638             : 
    2639          84 :         SessionMatch(&data_.match_p.fwaas_policy, r_fwaas_policy, false);
    2640          84 :         if (ShouldDrop(data_.match_p.fwaas_policy.action_summary)) {
    2641           0 :             goto done;
    2642             :         }
    2643             : 
    2644          84 :         SessionMatch(&data_.match_p.aps_policy, r_aps_policy, false);
    2645             :     } else {
    2646             :         // SG is reflexive ACL. For reverse-flow, copy SG action from
    2647             :         // forward flow
    2648          98 :         UpdateReflexiveAction();
    2649             :     }
    2650             : 
    2651         198 : done:
    2652         198 :     nw_ace_uuid_ = nw_acl_info.uuid;
    2653         198 :     if (!nw_acl_info.src_match_vn.empty())
    2654           2 :         data_.source_vn_match = nw_acl_info.src_match_vn;
    2655         198 :     if (!nw_acl_info.dst_match_vn.empty())
    2656           0 :         data_.dest_vn_match = nw_acl_info.dst_match_vn;
    2657             :     // Set mirror vrf after evaluation of actions
    2658         198 :     SetMirrorVrfFromAction();
    2659             :     //Set VRF assign action
    2660         198 :     SetVrfAssignEntry();
    2661             :     //Set HBS information
    2662         198 :     SetHbsInfofromAction();
    2663             :     // Summarize the actions based on lookups above
    2664         198 :     ActionRecompute();
    2665         198 :     return true;
    2666         198 : }
    2667             : 
    2668             : /////////////////////////////////////////////////////////////////////////////
    2669             : // Flow policy action compute routines
    2670             : /////////////////////////////////////////////////////////////////////////////
    2671         230 : void FlowEntry::ResyncFlow() {
    2672         230 :     DoPolicy();
    2673             : 
    2674             :     // If this is forward flow, update the SG action for reflexive entry
    2675         230 :     FlowEntry *rflow = (is_flags_set(FlowEntry::ReverseFlow) == false) ?
    2676         115 :         reverse_flow_entry() : NULL;
    2677             :     // Dont update reflexive entry for TcpAck Flows. Since it can flip
    2678             :     // Deny state for the reflexive entry.
    2679         230 :     if (!(is_flags_set(FlowEntry::TcpAckFlow)) && rflow) {
    2680             :         // Update action for reverse flow
    2681         115 :         rflow->UpdateReflexiveAction();
    2682             :         //Set HBS information
    2683         115 :         rflow->SetHbsInfofromAction();
    2684         115 :         rflow->ActionRecompute();
    2685             :     }
    2686         230 : }
    2687             : 
    2688             : const VrfEntry*
    2689           3 : FlowEntry::GetDestinationVrf() const {
    2690           3 :     const VrfEntry *vrf = NULL;
    2691           3 :     VrfTable *vrf_table = flow_table()->agent()->vrf_table();
    2692             : 
    2693           3 :     if (is_flags_set(FlowEntry::NatFlow) ||
    2694           0 :         match_p().action_info.action & (1 << TrafficAction::VRF_TRANSLATE)) {
    2695           3 :         vrf = vrf_table->FindVrfFromId(data().dest_vrf);
    2696             :     } else {
    2697           0 :         vrf = vrf_table->FindVrfFromId(data().vrf);
    2698             :     }
    2699           3 :     return vrf;
    2700             : }
    2701             : 
    2702         313 : bool FlowEntry::SetQosConfigIndex() {
    2703         313 :     uint32_t i = AgentQosConfigTable::kInvalidIndex;
    2704         313 :     MatchAclParamsList::const_iterator it;
    2705             : 
    2706             :     // For reverse flows, first check if we have our own QoS config
    2707             :     // (from interface), and only fall back to forward flow if not
    2708         313 :     if (is_flags_set(FlowEntry::ReverseFlow)) {
    2709             :         // First, check if reverse flow has its own QoS config from interface
    2710             :         const VmInterface *intf =
    2711         214 :             dynamic_cast<const VmInterface*>(data_.intf_entry.get());
    2712         214 :         if (intf && intf->qos_config()) {
    2713           0 :             i = intf->qos_config()->id();
    2714             :         }
    2715             : 
    2716             :         // If still no QoS config, copy from forward flow
    2717         214 :         if (i == AgentQosConfigTable::kInvalidIndex) {
    2718         214 :             FlowEntry *fwd_flow = reverse_flow_entry();
    2719         214 :             if (fwd_flow) {
    2720         214 :                 i = fwd_flow->data().qos_config_idx;
    2721             :             }
    2722             :         }
    2723             : 
    2724             :         // If we got a valid QoS config, use it and return early
    2725         214 :         if (i != AgentQosConfigTable::kInvalidIndex) {
    2726           0 :             if (i != data_.qos_config_idx) {
    2727           0 :                 data_.qos_config_idx = i;
    2728           0 :                 return true;
    2729             :             }
    2730           0 :             return false;
    2731             :         }
    2732             :         // If no QoS config found yet, continue with normal processing
    2733             :     }
    2734             : 
    2735             :     // Priority of QOS config for forward flows (and reverse flows that didn't find config above)
    2736             :     // 1> SG
    2737             :     // 2> Interface
    2738             :     // 3> ACL
    2739             :     // 4> VN (handled through ACLs)
    2740         313 :     if (data_.match_p.sg_policy.action & 1 << TrafficAction::APPLY_QOS) {
    2741           0 :         for (it = data_.match_p.sg_policy.m_acl_l.begin();
    2742           0 :                 it != data_.match_p.sg_policy.m_acl_l.end(); it++) {
    2743           0 :             if (it->action_info.action & 1 << TrafficAction::APPLY_QOS &&
    2744           0 :                     it->action_info.qos_config_action_.id()
    2745             :                     != AgentQosConfigTable::kInvalidIndex) {
    2746           0 :                 i = it->action_info.qos_config_action_.id();
    2747           0 :                 break;
    2748             :             }
    2749             :         }
    2750         313 :     } else if (data_.match_p.sg_policy.out_action & 1 << TrafficAction::APPLY_QOS) {
    2751           0 :         for (it = data_.match_p.sg_policy.m_out_acl_l.begin();
    2752           0 :                 it != data_.match_p.sg_policy.m_out_acl_l.end(); it++) {
    2753           0 :             if (it->action_info.action & 1 << TrafficAction::APPLY_QOS &&
    2754           0 :                     it->action_info.qos_config_action_.id() !=
    2755             :                     AgentQosConfigTable::kInvalidIndex) {
    2756           0 :                 i = it->action_info.qos_config_action_.id();
    2757           0 :                 break;
    2758             :             }
    2759             :         }
    2760         313 :     } else if (data_.match_p.policy_action & 1 << TrafficAction::APPLY_QOS) {
    2761           0 :         for (it = data_.match_p.m_acl_l.begin();
    2762           0 :                 it != data_.match_p.m_acl_l.end(); it++) {
    2763           0 :             if (it->action_info.action & 1 << TrafficAction::APPLY_QOS &&
    2764           0 :                     it->action_info.qos_config_action_.id() !=
    2765             :                     AgentQosConfigTable::kInvalidIndex) {
    2766           0 :                 i = it->action_info.qos_config_action_.id();
    2767           0 :                 break;
    2768             :             }
    2769             :         }
    2770         313 :     } else if (data_.match_p.out_policy_action & 1 << TrafficAction::APPLY_QOS) {
    2771           0 :         for (it = data_.match_p.m_out_acl_l.begin();
    2772           0 :                 it != data_.match_p.m_out_acl_l.end(); it++) {
    2773           0 :             if (it->action_info.action & 1 << TrafficAction::APPLY_QOS &&
    2774           0 :                     it->action_info.qos_config_action_.id() !=
    2775             :                     AgentQosConfigTable::kInvalidIndex) {
    2776           0 :                 i = it->action_info.qos_config_action_.id();
    2777           0 :                 break;
    2778             :             }
    2779             :         }
    2780             :     }
    2781             : 
    2782             :     const VmInterface *intf =
    2783         313 :         dynamic_cast<const VmInterface*>(data_.intf_entry.get());
    2784         313 :     if (intf && intf->qos_config()) {
    2785           0 :         if (intf->is_vn_qos_config() == false ||
    2786             :                 i == AgentQosConfigTable::kInvalidIndex) {
    2787           0 :             i = intf->qos_config()->id();
    2788             :         }
    2789             :     }
    2790             : 
    2791         313 :     if (i != data_.qos_config_idx) {
    2792           0 :         data_.qos_config_idx = i;
    2793           0 :         return true;
    2794             :     }
    2795             : 
    2796         313 :     return false;
    2797             : }
    2798             : 
    2799             : // Recompute FlowEntry action based on ACLs already set in the flow
    2800         313 : bool FlowEntry::ActionRecompute() {
    2801         313 :     uint32_t action = 0;
    2802         313 :     uint16_t drop_reason = DROP_UNKNOWN;
    2803         313 :     bool ret = false;
    2804             : 
    2805         313 :     action = data_.match_p.policy_action | data_.match_p.out_policy_action |
    2806         313 :         data_.match_p.sg_policy.action_summary |
    2807         313 :         data_.match_p.mirror_action | data_.match_p.out_mirror_action |
    2808         313 :         data_.match_p.aps_policy.action_summary |
    2809         313 :         data_.match_p.fwaas_policy.action_summary;
    2810             : 
    2811             :     //Only VRF assign acl, can specify action to
    2812             :     //translate VRF. VRF translate action specified
    2813             :     //by egress VN ACL or ingress VN ACL should be ignored
    2814         313 :     action &= ~(1 << TrafficAction::VRF_TRANSLATE);
    2815         313 :     action |= data_.match_p.vrf_assign_acl_action;
    2816             : 
    2817         313 :     if (action & (1 << TrafficAction::VRF_TRANSLATE) &&
    2818           0 :         data_.match_p.action_info.vrf_translate_action_.ignore_acl() == true) {
    2819             :         //In case of multi inline service chain, match condition generated on
    2820             :         //each of service instance interface takes higher priority than
    2821             :         //network ACL. Match condition on the interface would have ignore acl
    2822             :         //flag set to avoid applying two ACL for vrf translation
    2823           0 :         action = data_.match_p.vrf_assign_acl_action |
    2824           0 :             data_.match_p.sg_policy.action_summary | data_.match_p.mirror_action |
    2825           0 :             data_.match_p.out_mirror_action;
    2826             : 
    2827             :         //Pick mirror action from network ACL
    2828           0 :         if (data_.match_p.policy_action & (1 << TrafficAction::MIRROR) ||
    2829           0 :             data_.match_p.out_policy_action & (1 << TrafficAction::MIRROR)) {
    2830           0 :             action |= (1 << TrafficAction::MIRROR);
    2831             :         }
    2832             :     }
    2833             : 
    2834         313 :     action &= ~(1 << TrafficAction::HBS);
    2835         313 :     if (data_.match_p.aps_policy.action_summary & (1 << TrafficAction::HBS)) {
    2836           0 :         action |= (1 << TrafficAction::HBS);
    2837             :     }
    2838             : 
    2839         313 :     if (SetQosConfigIndex()) {
    2840           0 :         ret = true;
    2841             :     }
    2842             : 
    2843             :     // check for conflicting actions and remove allowed action
    2844         313 :     if (ShouldDrop(action)) {
    2845          41 :         action = (action & ~TrafficAction::DROP_FLAGS &
    2846             :                   ~TrafficAction::PASS_FLAGS);
    2847          41 :         action |= (1 << TrafficAction::DENY);
    2848          41 :         if (is_flags_set(FlowEntry::ShortFlow)) {
    2849           0 :             drop_reason = short_flow_reason_;
    2850          41 :         } else if (ShouldDrop(data_.match_p.policy_action)) {
    2851           2 :             drop_reason = DROP_POLICY;
    2852          39 :         } else if (ShouldDrop(data_.match_p.out_policy_action)) {
    2853           0 :             drop_reason = DROP_OUT_POLICY;
    2854          39 :         } else if (ShouldDrop(data_.match_p.sg_policy.action)) {
    2855          12 :             drop_reason = DROP_SG;
    2856          27 :         } else if (ShouldDrop(data_.match_p.sg_policy.out_action)) {
    2857           2 :             drop_reason = DROP_OUT_SG;
    2858          25 :         } else if (ShouldDrop(data_.match_p.sg_policy.reverse_action)) {
    2859           0 :             drop_reason = DROP_REVERSE_SG;
    2860          25 :         } else if (ShouldDrop(data_.match_p.sg_policy.reverse_out_action)) {
    2861           0 :             drop_reason = DROP_REVERSE_OUT_SG;
    2862          25 :         } else if (ShouldDrop(data_.match_p.aps_policy.action)) {
    2863           0 :             drop_reason = DROP_FIREWALL_POLICY;
    2864          25 :         } else if (ShouldDrop(data_.match_p.aps_policy.out_action)) {
    2865           0 :             drop_reason = DROP_OUT_FIREWALL_POLICY;
    2866          25 :         } else if (ShouldDrop(data_.match_p.aps_policy.reverse_action)) {
    2867           0 :             drop_reason = DROP_REVERSE_FIREWALL_POLICY;
    2868          25 :         } else if (ShouldDrop(data_.match_p.aps_policy.reverse_out_action)) {
    2869           0 :             drop_reason = DROP_REVERSE_OUT_FIREWALL_POLICY;
    2870          25 :         } else if (ShouldDrop(data_.match_p.fwaas_policy.action)) {
    2871           0 :             drop_reason = DROP_FWAAS_POLICY;
    2872          25 :         } else if (ShouldDrop(data_.match_p.fwaas_policy.out_action)) {
    2873           0 :             drop_reason = DROP_FWAAS_OUT_POLICY;
    2874          25 :         } else if (ShouldDrop(data_.match_p.fwaas_policy.reverse_action)) {
    2875           0 :             drop_reason = DROP_FWAAS_REVERSE_POLICY;
    2876          25 :         } else if (ShouldDrop(data_.match_p.fwaas_policy.reverse_out_action)) {
    2877           0 :             drop_reason = DROP_FWAAS_REVERSE_OUT_POLICY;
    2878             :         } else {
    2879          25 :             drop_reason = DROP_UNKNOWN;
    2880             :         }
    2881             :     }
    2882             : 
    2883         313 :     if (action & (1 << TrafficAction::TRAP)) {
    2884           0 :         action = (1 << TrafficAction::TRAP);
    2885             :     }
    2886             : 
    2887         313 :     if (action != data_.match_p.action_info.action) {
    2888         296 :         data_.match_p.action_info.action = action;
    2889         296 :         ret = true;
    2890             :     }
    2891         313 :     if (drop_reason != data_.drop_reason) {
    2892          16 :         data_.drop_reason = drop_reason;
    2893          16 :         ret = true;
    2894             :     }
    2895         313 :     return ret;
    2896             : }
    2897             : 
    2898             : // SetMirrorVrfFromAction
    2899             : // For this flow check for mirror action from dynamic ACLs or policy mirroring
    2900             : // assign the vrf from its Virtual Nework that ACL is used
    2901             : // If it is a local flow and out mirror action or policy is set
    2902             : // assign the vrf of the reverse flow, since ACL came from the reverse flow
    2903         198 : void FlowEntry::SetMirrorVrfFromAction() {
    2904         198 :     if (data_.match_p.mirror_action & (1 << TrafficAction::MIRROR) ||
    2905         198 :         data_.match_p.policy_action & (1 << TrafficAction::MIRROR)) {
    2906           0 :         const VnEntry *vn = vn_entry();
    2907           0 :         if (vn && vn->GetVrf()) {
    2908           0 :             SetMirrorVrf(vn->GetVrf()->vrf_id());
    2909             :         }
    2910             :     }
    2911         198 :     if (data_.match_p.out_mirror_action & (1 << TrafficAction::MIRROR) ||
    2912         198 :         data_.match_p.out_policy_action & (1 << TrafficAction::MIRROR)) {
    2913           0 :         FlowEntry *rflow = reverse_flow_entry_.get();
    2914           0 :         if (rflow) {
    2915           0 :             const VnEntry *rvn = rflow->vn_entry();
    2916           0 :             if (rvn && rvn->GetVrf()) {
    2917           0 :                 SetMirrorVrf(rvn->GetVrf()->vrf_id());
    2918             :             }
    2919             :         }
    2920             :     }
    2921         198 : }
    2922             : 
    2923          50 : void FlowEntry::MakeShortFlow(FlowShortReason reason) {
    2924          50 :     if (!is_flags_set(FlowEntry::ShortFlow)) {
    2925          34 :         set_flags(FlowEntry::ShortFlow);
    2926          34 :         short_flow_reason_ = reason;
    2927             :     }
    2928          66 :     if (reverse_flow_entry_ &&
    2929         116 :         !reverse_flow_entry_->is_flags_set(FlowEntry::ShortFlow)) {
    2930           0 :         reverse_flow_entry_->set_flags(FlowEntry::ShortFlow);
    2931           0 :         reverse_flow_entry_->short_flow_reason_ = reason;
    2932             :     }
    2933          50 : }
    2934             : 
    2935         213 : void FlowEntry::UpdateReflexiveAction() {
    2936         213 :     FlowEntry *rflow = reverse_flow_entry_.get();
    2937         213 :     SessionPolicy *r_sg_policy = NULL;
    2938         213 :     SessionPolicy *r_aps_policy = NULL;
    2939         213 :     SessionPolicy *r_fwaas_policy = NULL;
    2940             : 
    2941         213 :     if (rflow) {
    2942         213 :         r_sg_policy = &(rflow->data_.match_p.sg_policy);
    2943         213 :         r_aps_policy = &(rflow->data_.match_p.aps_policy);
    2944         213 :         r_fwaas_policy = &(rflow->data_.match_p.fwaas_policy);
    2945             :     }
    2946             : 
    2947         213 :     UpdateReflexiveAction(&data_.match_p.sg_policy, r_sg_policy);
    2948         213 :     UpdateReflexiveAction(&data_.match_p.aps_policy, r_aps_policy);
    2949         213 :     UpdateReflexiveAction(&data_.match_p.fwaas_policy, r_fwaas_policy);
    2950         213 : }
    2951             : 
    2952         639 : void FlowEntry::UpdateReflexiveAction(SessionPolicy *sp, SessionPolicy *rsp) {
    2953         639 :     sp->action = (1 << TrafficAction::PASS);
    2954         639 :     sp->out_action = (1 << TrafficAction::PASS);
    2955         639 :     sp->reverse_action = (1 << TrafficAction::PASS);;
    2956         639 :     sp->reverse_out_action = (1 << TrafficAction::PASS);
    2957         639 :     sp->action_summary = rsp->action_summary;
    2958             : 
    2959         639 :     if (ShouldDrop(sp->action_summary) == false) {
    2960         614 :         return;
    2961             :     }
    2962             : 
    2963          25 :     sp->action &= ~(TrafficAction::DROP_FLAGS);
    2964          25 :     sp->action |= (1 << TrafficAction::TRAP);
    2965             : }
    2966             : 
    2967             : /////////////////////////////////////////////////////////////////////////////
    2968             : // Routines to manage pending actions on a flow. The pending actions are used
    2969             : // to state-compress actions trigged due to update of,
    2970             : // - DBEntries like interface, ACL etc..
    2971             : // - Routes
    2972             : /////////////////////////////////////////////////////////////////////////////
    2973       10000 : FlowPendingAction::FlowPendingAction()  {
    2974       10000 :     Reset();
    2975       10000 : }
    2976             : 
    2977       10000 : FlowPendingAction::~FlowPendingAction() {
    2978       10000 : }
    2979             : 
    2980       30448 : void FlowPendingAction::Reset() {
    2981       30448 :     delete_ = false;
    2982       30448 :     recompute_ = false;
    2983       30448 :     recompute_dbentry_ = false;
    2984       30448 :     revaluate_ = false;
    2985       30448 : }
    2986             : 
    2987          77 : bool FlowPendingAction::SetDelete() {
    2988          77 :     if (delete_)
    2989          28 :         return false;
    2990             : 
    2991          49 :     delete_ = true;
    2992          49 :     return true;
    2993             : }
    2994             : 
    2995          49 : void FlowPendingAction::ResetDelete() {
    2996          49 :     delete_ = false;
    2997          49 :     recompute_ = false;
    2998          49 :     recompute_dbentry_ = false;
    2999          49 :     revaluate_ = false;
    3000          49 : }
    3001             : 
    3002          49 : bool FlowPendingAction::CanDelete() {
    3003          49 :     return delete_;
    3004             : }
    3005             : 
    3006          40 : bool FlowPendingAction::SetRecompute() {
    3007          40 :     if (delete_ || recompute_)
    3008           3 :         return false;
    3009             : 
    3010          37 :     recompute_ = true;
    3011          37 :     return true;
    3012             : }
    3013             : 
    3014          74 : void FlowPendingAction::ResetRecompute() {
    3015          74 :     recompute_ = false;
    3016          74 :     recompute_dbentry_ = false;
    3017          74 :     revaluate_ = false;
    3018          74 : }
    3019             : 
    3020          37 : bool FlowPendingAction::CanRecompute() {
    3021          37 :     if (delete_)
    3022           0 :         return false;
    3023             : 
    3024          37 :     return recompute_;
    3025             : }
    3026             : 
    3027         107 : bool FlowPendingAction::SetRecomputeDBEntry() {
    3028         107 :     if (delete_ || recompute_ || recompute_dbentry_)
    3029          17 :         return false;
    3030             : 
    3031          90 :     recompute_dbentry_ = true;
    3032          90 :     return true;
    3033             : }
    3034             : 
    3035          90 : void FlowPendingAction::ResetRecomputeDBEntry() {
    3036          90 :     recompute_dbentry_ = false;
    3037          90 :     revaluate_ = false;
    3038          90 : }
    3039             : 
    3040          90 : bool FlowPendingAction::CanRecomputeDBEntry() {
    3041          90 :     if (delete_ || recompute_)
    3042          42 :         return false;
    3043             : 
    3044          48 :     return recompute_dbentry_;
    3045             : }
    3046             : 
    3047          17 : bool FlowPendingAction::SetRevaluate() {
    3048          17 :     if (delete_ || recompute_ || recompute_dbentry_ || revaluate_)
    3049          12 :         return false;
    3050             : 
    3051           5 :     revaluate_ = true;
    3052           5 :     return true;
    3053             : }
    3054             : 
    3055           9 : void FlowPendingAction::ResetRevaluate() {
    3056           9 :     revaluate_ = false;
    3057           9 : }
    3058             : 
    3059           5 : bool FlowPendingAction::CanRevaluate() {
    3060           5 :     if (delete_ || recompute_ || recompute_dbentry_)
    3061           0 :         return false;
    3062             : 
    3063           5 :     return revaluate_;
    3064             : }
    3065             : 
    3066             : /////////////////////////////////////////////////////////////////////////////
    3067             : // Introspect routines
    3068             : /////////////////////////////////////////////////////////////////////////////
    3069           0 : void SetActionStr(const FlowAction &action_info,
    3070             :                   std::vector<ActionStr> &action_str_l) {
    3071           0 :     std::bitset<32> bs(action_info.action);
    3072           0 :     for (unsigned int i = 0; i < bs.size(); i++) {
    3073           0 :         if (bs[i]) {
    3074           0 :             ActionStr astr;
    3075             :             astr.action =
    3076           0 :                 TrafficAction::ActionToString((TrafficAction::Action)i);
    3077           0 :             action_str_l.push_back(astr);
    3078           0 :             if ((TrafficAction::Action)i == TrafficAction::MIRROR) {
    3079           0 :                 std::vector<MirrorActionSpec>::const_iterator m_it;
    3080           0 :                 for (m_it = action_info.mirror_l.begin();
    3081           0 :                      m_it != action_info.mirror_l.end();
    3082           0 :                      ++m_it) {
    3083           0 :                     ActionStr mstr;
    3084           0 :                     mstr.action += (*m_it).ip.to_string();
    3085           0 :                     mstr.action += " ";
    3086           0 :                     mstr.action += integerToString((*m_it).port);
    3087           0 :                     mstr.action += " ";
    3088           0 :                     mstr.action += (*m_it).vrf_name;
    3089           0 :                     mstr.action += " ";
    3090           0 :                     mstr.action += (*m_it).encap;
    3091           0 :                     action_str_l.push_back(mstr);
    3092           0 :                 }
    3093             :             }
    3094           0 :             if ((TrafficAction::Action)i == TrafficAction::VRF_TRANSLATE) {
    3095           0 :                 ActionStr vrf_action_str;
    3096             :                 vrf_action_str.action +=
    3097           0 :                     action_info.vrf_translate_action_.vrf_name();
    3098           0 :                 action_str_l.push_back(vrf_action_str);
    3099           0 :             }
    3100           0 :             if ((TrafficAction::Action)i == TrafficAction::HBS) {
    3101           0 :                 ActionStr hbf_action_str;
    3102           0 :                 hbf_action_str.action += "hbs";
    3103           0 :                 action_str_l.push_back(hbf_action_str);
    3104           0 :             }
    3105           0 :         }
    3106             :     }
    3107           0 : }
    3108             : 
    3109           0 : static void SetAclListAclAction(const std::list<MatchAclParams> &acl_l,
    3110             :                                 std::vector<AclAction> &acl_action_l,
    3111             :                                 std::string &acl_type) {
    3112           0 :     std::list<MatchAclParams>::const_iterator it;
    3113           0 :     for(it = acl_l.begin(); it != acl_l.end(); ++it) {
    3114           0 :         AclAction acl_action;
    3115           0 :         acl_action.set_acl_id(UuidToString((*it).acl->GetUuid()));
    3116           0 :         acl_action.set_acl_type(acl_type);
    3117           0 :         std::vector<ActionStr> action_str_l;
    3118           0 :         SetActionStr((*it).action_info, action_str_l);
    3119           0 :         acl_action.set_action_l(action_str_l);
    3120           0 :         acl_action_l.push_back(acl_action);
    3121           0 :     }
    3122           0 : }
    3123             : 
    3124           0 : void FlowEntry::SetAclAction(std::vector<AclAction> &acl_action_l) const {
    3125           0 :     const std::list<MatchAclParams> &acl_l = data_.match_p.m_acl_l;
    3126           0 :     std::string acl_type("nw policy");
    3127           0 :     SetAclListAclAction(acl_l, acl_action_l, acl_type);
    3128             : 
    3129           0 :     const std::list<MatchAclParams> &sg_acl_l = data_.match_p.sg_policy.m_acl_l;
    3130           0 :     acl_type = "sg";
    3131           0 :     SetAclListAclAction(sg_acl_l, acl_action_l, acl_type);
    3132             : 
    3133           0 :     const std::list<MatchAclParams> &m_acl_l = data_.match_p.m_mirror_acl_l;
    3134           0 :     acl_type = "dynamic";
    3135           0 :     SetAclListAclAction(m_acl_l, acl_action_l, acl_type);
    3136             : 
    3137           0 :     const std::list<MatchAclParams> &out_acl_l = data_.match_p.m_out_acl_l;
    3138           0 :     acl_type = "o nw policy";
    3139           0 :     SetAclListAclAction(out_acl_l, acl_action_l, acl_type);
    3140             : 
    3141           0 :     const std::list<MatchAclParams> &out_sg_acl_l =
    3142             :         data_.match_p.sg_policy.m_out_acl_l;
    3143           0 :     acl_type = "o sg";
    3144           0 :     SetAclListAclAction(out_sg_acl_l, acl_action_l, acl_type);
    3145             : 
    3146           0 :     const std::list<MatchAclParams> &out_m_acl_l =
    3147             :         data_.match_p.m_out_mirror_acl_l;
    3148           0 :     acl_type = "o dynamic";
    3149           0 :     SetAclListAclAction(out_m_acl_l, acl_action_l, acl_type);
    3150             : 
    3151           0 :     const std::list<MatchAclParams> &r_sg_l = data_.match_p.sg_policy.m_reverse_acl_l;
    3152           0 :     acl_type = "r sg";
    3153           0 :     SetAclListAclAction(r_sg_l, acl_action_l, acl_type);
    3154             : 
    3155           0 :     const std::list<MatchAclParams> &r_out_sg_l =
    3156             :         data_.match_p.sg_policy.m_reverse_out_acl_l;
    3157           0 :     acl_type = "r o sg";
    3158           0 :     SetAclListAclAction(r_out_sg_l, acl_action_l, acl_type);
    3159             : 
    3160           0 :     const std::list<MatchAclParams> &vrf_assign_acl_l =
    3161             :         data_.match_p.m_vrf_assign_acl_l;
    3162           0 :     acl_type = "vrf assign";
    3163           0 :     SetAclListAclAction(vrf_assign_acl_l, acl_action_l, acl_type);
    3164             : 
    3165           0 :     const std::list<MatchAclParams> &aps_l =
    3166             :         data_.match_p.aps_policy.m_acl_l;
    3167           0 :     acl_type = "fw acl";
    3168           0 :     SetAclListAclAction(aps_l, acl_action_l, acl_type);
    3169             : 
    3170           0 :     const std::list<MatchAclParams> &out_aps_l =
    3171             :         data_.match_p.aps_policy.m_out_acl_l;
    3172           0 :     acl_type = "reverse fw acl";
    3173           0 :     SetAclListAclAction(out_aps_l,
    3174             :                         acl_action_l, acl_type);
    3175             : 
    3176           0 :     const std::list<MatchAclParams> &fwaas_l =
    3177             :         data_.match_p.fwaas_policy.m_acl_l;
    3178           0 :     acl_type = "fwaas acl";
    3179           0 :     SetAclListAclAction(fwaas_l, acl_action_l, acl_type);
    3180             : 
    3181           0 :     const std::list<MatchAclParams> &out_fwaas_l =
    3182             :         data_.match_p.fwaas_policy.m_out_acl_l;
    3183           0 :     acl_type = "reverse fwaas acl";
    3184           0 :     SetAclListAclAction(out_fwaas_l,
    3185             :                         acl_action_l, acl_type);
    3186           0 : }
    3187             : 
    3188         251 : void FlowEntry::FillFlowInfo(FlowInfo &info) const {
    3189         251 :     info.set_gen_id(gen_id_);
    3190         251 :     info.set_flow_index(flow_handle_);
    3191         251 :     if (key_.family == Address::INET) {
    3192         251 :         info.set_source_ip(key_.src_addr.to_v4().to_ulong());
    3193         251 :         info.set_destination_ip(key_.dst_addr.to_v4().to_ulong());
    3194             :     } else {
    3195             :         uint64_t sip[2], dip[2];
    3196           0 :         Ip6AddressToU64Array(key_.src_addr.to_v6(), sip, 2);
    3197           0 :         Ip6AddressToU64Array(key_.dst_addr.to_v6(), dip, 2);
    3198           0 :         info.set_sip_upper(sip[0]);
    3199           0 :         info.set_sip_lower(sip[1]);
    3200           0 :         info.set_dip_upper(dip[0]);
    3201           0 :         info.set_dip_lower(dip[1]);
    3202           0 :         info.set_source_ip(0);
    3203           0 :         info.set_destination_ip(0);
    3204             :     }
    3205         251 :     info.set_source_port(key_.src_port);
    3206         251 :     info.set_destination_port(key_.dst_port);
    3207         251 :     info.set_protocol(key_.protocol);
    3208         251 :     info.set_hbs_intf_dir(hbs_intf_);
    3209         251 :     info.set_nh_id(key_.nh);
    3210         251 :     info.set_vrf(data_.vrf);
    3211         251 :     info.set_source_vn_list(data_.SourceVnList());
    3212         251 :     info.set_dest_vn_list(data_.DestinationVnList());
    3213         251 :     info.set_source_vn_match(data_.source_vn_match);
    3214         251 :     info.set_dest_vn_match(data_.dest_vn_match);
    3215         251 :     std::vector<uint32_t> v;
    3216         251 :     SecurityGroupList::const_iterator it;
    3217         251 :     for (it = data_.source_sg_id_l.begin();
    3218         263 :             it != data_.source_sg_id_l.end(); it++) {
    3219          12 :         v.push_back(*it);
    3220             :     }
    3221         251 :     info.set_source_sg_id_l(v);
    3222         251 :     v.clear();
    3223         263 :     for (it = data_.dest_sg_id_l.begin(); it != data_.dest_sg_id_l.end();
    3224          12 :          it++) {
    3225          12 :         v.push_back(*it);
    3226             :     }
    3227         251 :     info.set_dest_sg_id_l(v);
    3228             : 
    3229         251 :     uint32_t fe_action = data_.match_p.action_info.action;
    3230         251 :     if (fe_action & (1 << TrafficAction::DENY)) {
    3231           8 :         info.set_deny(true);
    3232         243 :     } else if (fe_action & (1 << TrafficAction::PASS)) {
    3233         217 :         info.set_allow(true);
    3234             :     }
    3235             : 
    3236         251 :     if (reverse_flow_entry_.get()) {
    3237         144 :         info.set_reverse_index(reverse_flow_entry_->flow_handle());
    3238             :     }
    3239             : 
    3240         251 :     if (is_flags_set(FlowEntry::NatFlow)) {
    3241         140 :         info.set_nat(true);
    3242         140 :         FlowEntry *nat_flow = reverse_flow_entry_.get();
    3243             :         // TODO : IPv6
    3244         140 :         if (nat_flow) {
    3245          74 :             if (key_.src_addr != nat_flow->key().dst_addr) {
    3246          37 :                 if (key_.family == Address::INET) {
    3247             :                     info.set_nat_source_ip
    3248          37 :                         (nat_flow->key().dst_addr.to_v4().to_ulong());
    3249             :                 } else {
    3250           0 :                     info.set_nat_source_ip(0);
    3251             :                 }
    3252             :             }
    3253             : 
    3254          74 :             if (key_.dst_addr != nat_flow->key().src_addr) {
    3255          37 :                 if (key_.family == Address::INET) {
    3256             :                     info.set_nat_destination_ip
    3257          37 :                         (nat_flow->key().src_addr.to_v4().to_ulong());
    3258             :                 } else {
    3259           0 :                     info.set_nat_destination_ip(0);
    3260             :                 }
    3261             :             }
    3262             : 
    3263          74 :             if (key_.src_port != nat_flow->key().dst_port)  {
    3264           0 :                 info.set_nat_source_port(nat_flow->key().dst_port);
    3265             :             }
    3266             : 
    3267          74 :             if (key_.dst_port != nat_flow->key().src_port) {
    3268           0 :                 info.set_nat_destination_port(nat_flow->key().src_port);
    3269             :             }
    3270          74 :             info.set_nat_protocol(nat_flow->key().protocol);
    3271          74 :             info.set_nat_vrf(data_.dest_vrf);
    3272          74 :             info.set_nat_mirror_vrf(nat_flow->data().mirror_vrf);
    3273             :         }
    3274             :     }
    3275             : 
    3276         251 :     if (data_.match_p.action_info.action & (1 << TrafficAction::MIRROR)) {
    3277           0 :         info.set_mirror(true);
    3278           0 :         std::vector<MirrorActionSpec>::const_iterator it;
    3279           0 :         std::vector<MirrorInfo> mirror_l;
    3280           0 :         for (it = data_.match_p.action_info.mirror_l.begin();
    3281           0 :              it != data_.match_p.action_info.mirror_l.end();
    3282           0 :              ++it) {
    3283           0 :             MirrorInfo mirror_info;
    3284           0 :             mirror_info.set_mirror_destination((*it).ip.to_string());
    3285           0 :             mirror_info.set_mirror_port((*it).port);
    3286           0 :             mirror_info.set_mirror_vrf((*it).vrf_name);
    3287           0 :             mirror_info.set_analyzer((*it).analyzer_name);
    3288           0 :             mirror_l.push_back(mirror_info);
    3289           0 :         }
    3290           0 :         info.set_mirror_l(mirror_l);
    3291           0 :     }
    3292         251 :     info.set_mirror_vrf(data_.mirror_vrf);
    3293         251 :     info.set_implicit_deny(ImplicitDenyFlow());
    3294         251 :     info.set_short_flow(is_flags_set(FlowEntry::ShortFlow));
    3295         414 :     if (is_flags_set(FlowEntry::EcmpFlow) &&
    3296         163 :             data_.component_nh_idx != CompositeNH::kInvalidComponentNHIdx) {
    3297          78 :         info.set_ecmp_index(data_.component_nh_idx);
    3298             :     }
    3299         251 :     if (is_flags_set(FlowEntry::Trap)) {
    3300           0 :         info.set_trap(true);
    3301             :     }
    3302         251 :     info.set_vrf_assign(acl_assigned_vrf());
    3303         251 :     info.set_l3_flow(l3_flow_);
    3304         251 :     info.set_smac(data_.smac.ToString());
    3305         251 :     info.set_dmac(data_.dmac.ToString());
    3306         251 :     info.set_short_flow_reason(FlowEntry::DropReasonStr(short_flow_reason_));
    3307         251 :     info.set_drop_reason(FlowEntry::DropReasonStr(data_.drop_reason));
    3308         251 :     if (flow_table_) {
    3309         251 :         info.set_table_id(flow_table_->table_index());
    3310             :     }
    3311             : 
    3312         251 :     if (rpf_nh()) {
    3313         239 :         info.set_rpf_nh(rpf_nh()->id());
    3314             :     } else {
    3315          12 :         info.set_rpf_nh(0xFFFFFFFF);
    3316             :     }
    3317         251 :     if (src_ip_nh()) {
    3318         239 :         info.set_src_ip_nh(src_ip_nh()->id());
    3319             :     } else {
    3320          12 :         info.set_src_ip_nh(0xFFFFFFFF);
    3321             :     }
    3322         251 : }
    3323             : 
    3324           0 : static void SetAclListAceId(const AclDBEntry *acl,
    3325             :                             const MatchAclParamsList &acl_l,
    3326             :                             std::vector<AceId> &ace_l) {
    3327           0 :     std::list<MatchAclParams>::const_iterator ma_it;
    3328           0 :     for (ma_it = acl_l.begin();
    3329           0 :          ma_it != acl_l.end();
    3330           0 :          ++ma_it) {
    3331           0 :         if ((*ma_it).acl != acl) {
    3332           0 :             continue;
    3333             :         }
    3334           0 :         AclEntryIDList::const_iterator ait;
    3335           0 :         for (ait = (*ma_it).ace_id_list.begin();
    3336           0 :              ait != (*ma_it).ace_id_list.end(); ++ ait) {
    3337           0 :             AceId ace_id;
    3338           0 :             ace_id.id = ait->id_;
    3339           0 :             ace_l.push_back(ace_id);
    3340           0 :         }
    3341             :     }
    3342           0 : }
    3343             : 
    3344           0 : void FlowEntry::SetAclFlowSandeshData(const AclDBEntry *acl,
    3345             :         FlowSandeshData &fe_sandesh_data, Agent *agent) const {
    3346           0 :     fe_sandesh_data.set_vrf(integerToString(data_.vrf));
    3347           0 :     fe_sandesh_data.set_src(key_.src_addr.to_string());
    3348           0 :     fe_sandesh_data.set_dst(key_.dst_addr.to_string());
    3349           0 :     fe_sandesh_data.set_src_port(key_.src_port);
    3350           0 :     fe_sandesh_data.set_dst_port(key_.dst_port);
    3351           0 :     fe_sandesh_data.set_protocol(key_.protocol);
    3352           0 :     fe_sandesh_data.set_ingress(is_flags_set(FlowEntry::IngressDir));
    3353           0 :     std::vector<ActionStr> action_str_l;
    3354           0 :     SetActionStr(data_.match_p.action_info, action_str_l);
    3355           0 :     fe_sandesh_data.set_action_l(action_str_l);
    3356             : 
    3357           0 :     std::vector<AclAction> acl_action_l;
    3358           0 :     SetAclAction(acl_action_l);
    3359           0 :     fe_sandesh_data.set_acl_action_l(acl_action_l);
    3360             : 
    3361           0 :     fe_sandesh_data.set_flow_handle(integerToString(flow_handle_));
    3362           0 :     if (!data_.origin_vn_src.empty()) {
    3363           0 :         fe_sandesh_data.set_source_vn(data_.origin_vn_src);
    3364             :     } else {
    3365           0 :         fe_sandesh_data.set_source_vn(data_.source_vn_match);
    3366             :     }
    3367           0 :     if (!data_.origin_vn_dst.empty()) {
    3368           0 :         fe_sandesh_data.set_dest_vn(data_.origin_vn_dst);
    3369             :     } else {
    3370           0 :         fe_sandesh_data.set_dest_vn(data_.dest_vn_match);
    3371             :     }
    3372           0 :     if (!data_.OriginVnSrcList().empty()) {
    3373           0 :         fe_sandesh_data.set_source_vn_list(data_.OriginVnSrcList());
    3374             :     } else {
    3375           0 :         fe_sandesh_data.set_source_vn_list(data_.SourceVnList());
    3376             :     }
    3377           0 :     if (!data_.OriginVnDstList().empty()) {
    3378           0 :         fe_sandesh_data.set_dest_vn_list(data_.OriginVnDstList());
    3379             :     } else {
    3380           0 :         fe_sandesh_data.set_dest_vn_list(data_.DestinationVnList());
    3381             :     }
    3382           0 :     std::vector<uint32_t> v;
    3383           0 :     SecurityGroupList::const_iterator it;
    3384           0 :     for (it = data_.source_sg_id_l.begin();
    3385           0 :             it != data_.source_sg_id_l.end(); it++) {
    3386           0 :         v.push_back(*it);
    3387             :     }
    3388           0 :     fe_sandesh_data.set_source_sg_id_l(v);
    3389           0 :     v.clear();
    3390           0 :     for (it = data_.dest_sg_id_l.begin(); it != data_.dest_sg_id_l.end();
    3391           0 :          it++) {
    3392           0 :         v.push_back(*it);
    3393             :     }
    3394           0 :     fe_sandesh_data.set_dest_sg_id_l(v);
    3395           0 :     fe_sandesh_data.set_flow_uuid(UuidToString(uuid()));
    3396           0 :     if (fsc_) {
    3397           0 :         const FlowExportInfo *info = fsc_->FindFlowExportInfo(this);
    3398           0 :         if (info) {
    3399           0 :             fe_sandesh_data.set_bytes(integerToString(info->bytes()));
    3400           0 :             fe_sandesh_data.set_packets(integerToString(info->packets()));
    3401           0 :             if (info->teardown_time()) {
    3402           0 :                 fe_sandesh_data.set_teardown_time(
    3403           0 :                     integerToString(UTCUsecToPTime(info->teardown_time())));
    3404             :             } else {
    3405           0 :                 fe_sandesh_data.set_teardown_time("");
    3406             :             }
    3407             :         }
    3408             :     }
    3409           0 :     fe_sandesh_data.set_current_time(integerToString(
    3410           0 :                 UTCUsecToPTime(UTCTimestampUsec())));
    3411             : 
    3412           0 :     SetAclListAceId(acl, data_.match_p.m_acl_l, fe_sandesh_data.ace_l);
    3413           0 :     SetAclListAceId(acl, data_.match_p.sg_policy.m_acl_l, fe_sandesh_data.ace_l);
    3414           0 :     SetAclListAceId(acl, data_.match_p.m_mirror_acl_l, fe_sandesh_data.ace_l);
    3415           0 :     SetAclListAceId(acl, data_.match_p.m_out_acl_l, fe_sandesh_data.ace_l);
    3416           0 :     SetAclListAceId(acl, data_.match_p.sg_policy.m_reverse_acl_l,
    3417           0 :                     fe_sandesh_data.ace_l);
    3418           0 :     SetAclListAceId(acl, data_.match_p.sg_policy.m_reverse_out_acl_l,
    3419           0 :                     fe_sandesh_data.ace_l);
    3420           0 :     SetAclListAceId(acl, data_.match_p.sg_policy.m_out_acl_l, fe_sandesh_data.ace_l);
    3421           0 :     SetAclListAceId(acl, data_.match_p.m_out_mirror_acl_l,
    3422           0 :                     fe_sandesh_data.ace_l);
    3423           0 :     SetAclListAceId(acl, data_.match_p.m_vrf_assign_acl_l,
    3424           0 :                     fe_sandesh_data.ace_l);
    3425           0 :     SetAclListAceId(acl, data_.match_p.aps_policy.m_acl_l,
    3426           0 :                     fe_sandesh_data.ace_l);
    3427           0 :     SetAclListAceId(acl, data_.match_p.aps_policy.m_out_acl_l,
    3428           0 :                     fe_sandesh_data.ace_l);
    3429           0 :     SetAclListAceId(acl, data_.match_p.fwaas_policy.m_acl_l,
    3430           0 :                     fe_sandesh_data.ace_l);
    3431           0 :     SetAclListAceId(acl, data_.match_p.fwaas_policy.m_out_acl_l,
    3432           0 :                     fe_sandesh_data.ace_l);
    3433             : 
    3434           0 :     fe_sandesh_data.set_reverse_flow(is_flags_set(FlowEntry::ReverseFlow) ?
    3435             :                                      "yes" : "no");
    3436           0 :     fe_sandesh_data.set_nat(is_flags_set(FlowEntry::NatFlow) ? "yes" : "no");
    3437           0 :     fe_sandesh_data.set_implicit_deny(ImplicitDenyFlow() ? "yes" : "no");
    3438           0 :     fe_sandesh_data.set_short_flow(is_flags_set(FlowEntry::ShortFlow) ?
    3439             :                                    "yes" : "no");
    3440           0 :     fe_sandesh_data.set_l3_flow(l3_flow_);
    3441           0 :     fe_sandesh_data.set_smac(data_.smac.ToString());
    3442           0 :     fe_sandesh_data.set_dmac(data_.dmac.ToString());
    3443           0 : }
    3444             : 
    3445           0 : string FlowEntry::KeyString() const {
    3446           0 :     std::ostringstream str;
    3447           0 :     int idx = flow_handle_ == FlowEntry::kInvalidFlowHandle ? -1 : flow_handle_;
    3448           0 :     str << " Idx : " << idx
    3449           0 :         << " Key : "
    3450           0 :         << key_.nh << " "
    3451           0 :         << key_.src_addr.to_string() << ":"
    3452           0 :         << key_.src_port << " "
    3453           0 :         << key_.dst_addr.to_string() << ":"
    3454           0 :         << key_.dst_port << " "
    3455           0 :         << (uint16_t)key_.protocol;
    3456           0 :     return str.str();
    3457           0 : }
    3458             : 
    3459           0 : static std::string EventToString(FlowEventLog::Event event,
    3460             :                                  std::string &event_str) {
    3461           0 :     switch (event) {
    3462           0 :     case FlowEventLog::FLOW_ADD:
    3463           0 :         event_str = "FlowAdd";
    3464           0 :         break;
    3465           0 :     case FlowEventLog::FLOW_UPDATE:
    3466           0 :         event_str = "FlowUpdate";
    3467           0 :         break;
    3468           0 :     case FlowEventLog::FLOW_DELETE:
    3469           0 :         event_str = "FlowDelete";
    3470           0 :         break;
    3471           0 :     case FlowEventLog::FLOW_EVICT:
    3472           0 :         event_str = "FlowEvict";
    3473           0 :         break;
    3474           0 :     case FlowEventLog::FLOW_HANDLE_ASSIGN:
    3475           0 :         event_str = "FlowHandleAssign";
    3476           0 :         break;
    3477           0 :     case FlowEventLog::FLOW_MSG_SKIP_EVICTED:
    3478           0 :         event_str = "FlowMessageSkippedEvictedFlow";
    3479           0 :         break;
    3480           0 :     default:
    3481           0 :         event_str = "Unknown";
    3482           0 :         break;
    3483             :     }
    3484           0 :     return event_str;
    3485             : }
    3486             : 
    3487           0 : void FlowEntry::SetEventSandeshData(SandeshFlowIndexInfo *info) {
    3488             :     KSyncFlowIndexManager *mgr =
    3489           0 :         flow_table_->agent()->ksync()->ksync_flow_index_manager();
    3490           0 :     info->set_trace_index(event_log_index_);
    3491           0 :     if (mgr->sm_log_count() == 0) {
    3492           0 :         return;
    3493             :     }
    3494           0 :     int start = 0;
    3495           0 :     int count = event_log_index_;
    3496           0 :     if (event_log_index_ >= mgr->sm_log_count()) {
    3497           0 :         start = event_log_index_ % mgr->sm_log_count();
    3498           0 :         count = mgr->sm_log_count();
    3499             :     }
    3500           0 :     std::vector<SandeshFlowIndexTrace> trace_list;
    3501           0 :     for (int i = 0; i < count; i++) {
    3502           0 :         SandeshFlowIndexTrace trace;
    3503           0 :         FlowEventLog *log = &event_logs_[((start + i) % mgr->sm_log_count())];
    3504           0 :         trace.set_timestamp(log->time_);
    3505           0 :         trace.set_flow_handle(log->flow_handle_);
    3506           0 :         trace.set_flow_gen_id(log->flow_gen_id_);
    3507           0 :         string event_str;
    3508           0 :         trace.set_event(EventToString(log->event_, event_str));
    3509           0 :         trace.set_ksync_hash_id(log->hash_id_);
    3510           0 :         trace.set_ksync_gen_id(log->gen_id_);
    3511           0 :         trace.set_vrouter_flow_handle(log->vrouter_flow_handle_);
    3512           0 :         trace.set_vrouter_gen_id(log->vrouter_gen_id_);
    3513           0 :         trace_list.push_back(trace);
    3514           0 :     }
    3515           0 :     info->set_flow_index_trace(trace_list);
    3516           0 : }
    3517             : 
    3518         564 : void FlowEntry::LogFlow(FlowEventLog::Event event, FlowTableKSyncEntry* ksync,
    3519             :                         uint32_t flow_handle, uint8_t gen_id) {
    3520             :     KSyncFlowIndexManager *mgr =
    3521         564 :         flow_table_->agent()->ksync()->ksync_flow_index_manager();
    3522         564 :     string event_str;
    3523         564 :     LOG(DEBUG, "Flow event = " << EventToString(event, event_str)
    3524             :         << " flow = " << (void *)this
    3525             :         << " flow->flow_handle = " << flow_handle_
    3526             :         << " flow->gen_id = " << (int)gen_id_
    3527             :         << " ksync = " << (void *)ksync
    3528             :         << " Ksync->hash_id = " << ((ksync != NULL) ? ksync->hash_id() : -1)
    3529             :         << " Ksync->gen_id = " << ((ksync != NULL) ? (int)ksync->gen_id() : 0)
    3530             :         << " new_flow_handle = " << flow_handle
    3531             :         << " new_gen_id = " << (int)gen_id);
    3532             : 
    3533         564 :     if (mgr->sm_log_count() == 0) {
    3534         564 :         return;
    3535             :     }
    3536             : 
    3537           0 :     if (event_logs_ == NULL) {
    3538           0 :         event_log_index_ = 0;
    3539           0 :         event_logs_.reset(new FlowEventLog[mgr->sm_log_count()]);
    3540             :     }
    3541             : 
    3542           0 :     FlowEventLog *log = &event_logs_[event_log_index_ % mgr->sm_log_count()];
    3543           0 :     event_log_index_++;
    3544             : 
    3545           0 :     log->time_ = ClockMonotonicUsec();
    3546           0 :     log->event_ = event;
    3547           0 :     log->flow_handle_ = flow_handle_;
    3548           0 :     log->flow_gen_id_ = gen_id_;
    3549           0 :     log->ksync_entry_ = ksync;
    3550           0 :     log->hash_id_ = (ksync != NULL) ? ksync->hash_id() : -1;
    3551           0 :     log->gen_id_ = (ksync != NULL) ? ksync->gen_id() : 0;
    3552           0 :     log->vrouter_flow_handle_ = flow_handle;
    3553           0 :     log->vrouter_gen_id_ = gen_id;
    3554         564 : }
    3555             : 
    3556         463 : const TagList &FlowEntry::local_tagset() const {
    3557         463 :     if (is_flags_set(FlowEntry::IngressDir)) {
    3558         199 :         return data_.source_tag_id_l;
    3559             :     }
    3560         264 :     return data_.dest_tag_id_l;
    3561             : }
    3562             : 
    3563         924 : const TagList &FlowEntry::remote_tagset() const {
    3564         924 :     if (is_flags_set(FlowEntry::IngressDir)) {
    3565         397 :         return data_.dest_tag_id_l;
    3566             :     }
    3567         527 :     return data_.source_tag_id_l;
    3568             : }
    3569             : 
    3570         462 : const std::string FlowEntry::BuildRemotePrefix(const FlowRouteRefMap &rt_list,
    3571             :                                                uint32_t vrf,
    3572             :                                                const IpAddress &ip) const {
    3573         462 :     int plen = -1;
    3574         462 :     FlowRouteRefMap::const_iterator it;
    3575         691 :     for (it = rt_list.begin(); it != rt_list.end(); it++) {
    3576         237 :         if (it->first == static_cast<int>(vrf)) {
    3577           8 :             plen = it->second;
    3578           8 :             break;
    3579             :         }
    3580             :     }
    3581         462 :     if (plen != -1) {
    3582          16 :         return ip.to_string() + "/" + integerToString(plen);
    3583             :     }
    3584         454 :     return "";
    3585             : }
    3586             : 
    3587             : /* Remote prefix is required only wnen remote_tagset is absent. Returns empty
    3588             :  * string as remote-prefix when remote-tagset is present */
    3589         462 : const std::string FlowEntry::RemotePrefix() const {
    3590         462 :      if (remote_tagset().size() > 0) {
    3591           0 :         return "";
    3592             :     }
    3593         462 :     if (is_flags_set(FlowEntry::IngressDir)) {
    3594         198 :         return BuildRemotePrefix(data_.flow_dest_plen_map,
    3595         198 :                                  data_.flow_dest_vrf, key_.dst_addr);
    3596             :     }
    3597         264 :     return BuildRemotePrefix(data_.flow_source_plen_map, data_.flow_source_vrf,
    3598         264 :                              key_.src_addr);
    3599             : }
    3600             : 
    3601         230 : void FlowEntry::FillUveVnAceInfo(FlowUveVnAcePolicyInfo *info) const {
    3602         230 :     const VnEntry *vn = vn_entry();
    3603         230 :     info->vn_ = vn? vn->GetName() : "";
    3604         230 :     info->nw_ace_uuid_ = nw_ace_uuid();
    3605         230 :     if (!info->vn_.empty() && !info->nw_ace_uuid_.empty()) {
    3606         226 :         info->is_valid_ = true;
    3607             :     }
    3608         230 : }
    3609             : 
    3610          33 : void FlowEntry::FillUveLocalRevFlowStatsInfo(FlowUveFwPolicyInfo *info,
    3611             :                                              bool added) const {
    3612          33 :     info->initiator_ = false;
    3613          33 :     info->local_vn_ = data_.source_vn_match;
    3614          33 :     info->remote_vn_ = data_.dest_vn_match;
    3615          33 :     info->local_tagset_ = local_tagset();
    3616          33 :     info->remote_tagset_ = remote_tagset();
    3617          33 :     info->fw_policy_ = fw_policy_name_uuid();
    3618          33 :     info->remote_prefix_ = RemotePrefix();
    3619          33 :     info->added_ = added;
    3620          33 :     if (is_flags_set(FlowEntry::ShortFlow)) {
    3621           3 :         info->short_flow_ = true;
    3622             :     } else {
    3623          30 :         info->short_flow_ = false;
    3624             :     }
    3625          33 :     FlowTable::GetFlowSandeshActionParams(data().match_p.action_info,
    3626          33 :                                           info->action_);
    3627          33 :     info->is_valid_ = true;
    3628          33 : }
    3629             : 
    3630         161 : void FlowEntry::FillUveFwdFlowStatsInfo(FlowUveFwPolicyInfo *info,
    3631             :                                         bool added) const {
    3632         161 :     if (is_flags_set(FlowEntry::IngressDir)) {
    3633          53 :         info->initiator_ = true;
    3634          53 :         info->local_vn_ = data_.source_vn_match;
    3635          53 :         info->remote_vn_ = data_.dest_vn_match;
    3636             :     } else {
    3637         108 :         info->initiator_ = false;
    3638         108 :         info->local_vn_ = data_.dest_vn_match;
    3639         108 :         info->remote_vn_ = data_.source_vn_match;
    3640             :     }
    3641         161 :     info->local_tagset_ = local_tagset();
    3642         161 :     info->remote_tagset_ = remote_tagset();
    3643         161 :     info->fw_policy_ = fw_policy_name_uuid();
    3644         161 :     info->remote_prefix_ = RemotePrefix();
    3645         161 :     info->added_ = added;
    3646         161 :     if (is_flags_set(FlowEntry::ShortFlow)) {
    3647          18 :         info->short_flow_ = true;
    3648             :     } else {
    3649         143 :         info->short_flow_ = false;
    3650             :     }
    3651         161 :     FlowTable::GetFlowSandeshActionParams(data().match_p.action_info,
    3652         161 :                                           info->action_);
    3653         161 :     info->is_valid_ = true;
    3654         161 : }
    3655             : 
    3656         327 : void FlowEntry::FillUveFwStatsInfo(FlowUveFwPolicyInfo *info,
    3657             :                                    bool added) const {
    3658             :     /* Endpoint statistics update is not required in the following
    3659             :      * cases
    3660             :      * 1. When flow has empty policy_set_acl_name. One example of this
    3661             :      *    case is when matching rule for flow is IMPLICIT_ALLOW
    3662             :      * 2. Link local flows
    3663             :      * 3. Reverse flows. We need session_count and not flow_count. So we
    3664             :      *    consider only forward flows.
    3665             :      *
    3666             :      * Also count is updated only for forward-flow as the count
    3667             :      * indicates session_count and NOT flow-count
    3668             :      */
    3669         493 :     if (is_flags_set(FlowEntry::ReverseFlow) &&
    3670         493 :         !is_flags_set(FlowEntry::LocalFlow)) {
    3671         133 :         return;
    3672             :     }
    3673         194 :     if (is_flags_set(FlowEntry::LocalFlow)) {
    3674          60 :         if (is_flags_set(FlowEntry::ReverseFlow)) {
    3675          33 :             FillUveLocalRevFlowStatsInfo(info, added);
    3676             :         } else {
    3677          27 :             FillUveFwdFlowStatsInfo(info, added);
    3678             :         }
    3679             :     } else {
    3680         134 :         FillUveFwdFlowStatsInfo(info, added);
    3681             :     }
    3682             : }
    3683             : 
    3684         599 : const std::string FlowEntry::fw_policy_uuid() const {
    3685         599 :     return data_.match_p.aps_policy.rule_uuid_;
    3686             : }
    3687             : 
    3688         463 : const std::string FlowEntry::fw_policy_name_uuid() const {
    3689             :     /* If policy-name is empty return only policy UUID. Policy-name will be
    3690             :      * empty when one of the implicit rules match */
    3691         463 :     if (data_.match_p.aps_policy.acl_name_.empty()) {
    3692         463 :         return fw_policy_uuid();
    3693             :     }
    3694           0 :     return data_.match_p.aps_policy.acl_name_ + ":" +
    3695           0 :         fw_policy_uuid();
    3696             : }
    3697             : 
    3698         288 : void FlowEntry::set_flow_mgmt_info(FlowEntryInfo *info) {
    3699         288 :     flow_mgmt_info_.reset(info);
    3700         288 : }
    3701             : 
    3702         224 : uint8_t FlowEntry::GetUnderlayGwIndex(uint32_t intf_in, const IpAddress &sip,
    3703             :                                   const IpAddress &dip, uint8_t proto, uint16_t sport,
    3704             :                                   uint16_t dport) const {
    3705         224 :     if ((!flow_table()->agent()->is_l3mh()) || (is_flags_set(FlowEntry::LocalFlow))) {
    3706         224 :         return -1;
    3707             :     }
    3708             : 
    3709           0 :     uint8_t underlay_gw_index = -1;
    3710           0 :     if (is_flags_set(FlowEntry::ReverseFlow)) {
    3711           0 :         FlowEntry *rflow = reverse_flow_entry_.get();
    3712           0 :         if (rflow != NULL) {
    3713           0 :             underlay_gw_index = rflow->data().underlay_gw_index_;
    3714             :         }
    3715           0 :         return underlay_gw_index;
    3716             :     }
    3717             : 
    3718             :     InetUnicastRouteEntry *rt = static_cast<InetUnicastRouteEntry *>
    3719           0 :         (FlowEntry::GetUcRoute(GetDestinationVrf(), dip));
    3720           0 :     const TunnelNH *tunnel_nh = rt != nullptr ?
    3721           0 :         dynamic_cast<const TunnelNH *>(rt->GetActiveNextHop()) : nullptr;
    3722             : 
    3723           0 :     if (!tunnel_nh && is_flags_set(FlowEntry::EcmpFlow) &&
    3724           0 :         data_.component_nh_idx != CompositeNH::kInvalidComponentNHIdx) {
    3725             :         // For composite nh set underlay gw index to component_nh_idx (same hash is used)
    3726           0 :         return (data_.component_nh_idx % (flow_table()->agent()->fabric_interface_name_list().size()));
    3727             :     }
    3728             : 
    3729             :     Interface *intf = flow_table()->agent()->interface_table()->
    3730           0 :             FindInterface(intf_in);
    3731           0 :     if (intf && intf->type() == Interface::PHYSICAL) {
    3732           0 :         underlay_gw_index = intf->id();
    3733           0 :         return underlay_gw_index;
    3734             :     } else {
    3735           0 :         std::size_t hash = 0;
    3736           0 :         hash = HashIp(hash, sip);
    3737           0 :         hash = HashIp(hash, dip);
    3738             : 
    3739           0 :         hash = HashCombine(hash, sport);
    3740           0 :         hash = HashCombine(hash, dport);
    3741           0 :         hash = HashCombine(hash, proto);
    3742           0 :         underlay_gw_index = hash % (flow_table()->agent()->fabric_interface_name_list().size());
    3743             :     }
    3744             : 
    3745           0 :     if (rt == nullptr) {
    3746           0 :         return -1;
    3747             :     }
    3748           0 :     if ( !(tunnel_nh && (tunnel_nh->IsValid()))) {
    3749           0 :          return -1;
    3750             :     }
    3751           0 :     uint8_t index = 0;
    3752           0 :     TunnelNH::EncapDataList encap_list = tunnel_nh->GetEncapDataList();
    3753           0 :     while (index < encap_list.size()) {
    3754           0 :         if (encap_list[index].get()->interface_.get() &&
    3755           0 :             underlay_gw_index == (encap_list[index].get()->interface_).get()->id()) {
    3756           0 :             underlay_gw_index = index;
    3757           0 :             break;
    3758             :         }
    3759           0 :         index++;
    3760             :     }
    3761             : 
    3762           0 :     if (tunnel_nh->IsEncapValid(underlay_gw_index)) {
    3763           0 :         return underlay_gw_index;
    3764           0 :     } else if ( ((underlay_gw_index +1) < (uint8_t)tunnel_nh->GetEncapDataList().size()) &&
    3765           0 :             tunnel_nh->IsEncapValid(underlay_gw_index +1)) {
    3766           0 :         return underlay_gw_index +1;
    3767           0 :     } else if (((underlay_gw_index +1) >= (uint8_t)tunnel_nh->GetEncapDataList().size()) &&
    3768           0 :             tunnel_nh->IsEncapValid(underlay_gw_index + 1 - tunnel_nh->GetEncapDataList().size())) {
    3769           0 :         return (underlay_gw_index + 1 - tunnel_nh->GetEncapDataList().size());
    3770             :     }
    3771           0 :     return -1;
    3772           0 : }
    3773             : 
    3774           0 : TcpPort::~TcpPort() {
    3775           0 :     socket_.close();
    3776           0 : }
    3777             : 
    3778           0 : uint16_t TcpPort::Bind() {
    3779           0 :     boost::system::error_code ec;
    3780           0 :     socket_.open(tcp::v4());
    3781           0 :     socket_.bind(tcp::endpoint(tcp::v4(), port_), ec);
    3782           0 :     if (ec.failed()) {
    3783           0 :         return 0;
    3784             :     }
    3785           0 :     port_ = socket_.local_endpoint(ec).port();
    3786           0 :     return port_;
    3787             : }
    3788             : 
    3789           0 : UdpPort::~UdpPort() {
    3790           0 :     socket_.close();
    3791           0 : }
    3792             : 
    3793           0 : uint16_t UdpPort::Bind() {
    3794           0 :     boost::system::error_code ec;
    3795           0 :     socket_.open(udp::v4());
    3796           0 :     socket_.bind(udp::endpoint(udp::v4(), port_), ec);
    3797           0 :     if (ec.failed()) {
    3798           0 :         return 0;
    3799             :     }
    3800           0 :     port_ = socket_.local_endpoint(ec).port();
    3801           0 :     return port_;
    3802             : }
    3803             : 
    3804           0 : bool PortCacheEntry::operator<(const PortCacheEntry &rhs) const {
    3805           0 :     return key_.IsLess(rhs.key_);
    3806             : }
    3807             : 
    3808           0 : void PortCacheEntry::MarkDelete() const {
    3809           0 :     stale_ = true;
    3810           0 :     delete_time_ = UTCTimestampUsec();
    3811           0 : }
    3812             : 
    3813           0 : bool PortCacheEntry::CanBeAged(uint64_t current_time, uint64_t timeout) const {
    3814           0 :     if (stale_ &&
    3815           0 :         current_time - delete_time_ >= timeout) {
    3816           0 :         return true;
    3817             :     }
    3818             : 
    3819           0 :     return false;
    3820             : }
    3821             : 
    3822           4 : PortCacheTable::PortCacheTable(PortTable *table) :
    3823           4 :      port_table_(table),
    3824           8 :      timer_(TimerManager::CreateTimer(
    3825           4 :                      *(table->agent()->event_manager())->io_service(),
    3826             :                      "FlowPortBindTimer",
    3827             :                      TaskScheduler::GetInstance()->GetTaskId(kTaskFlowMgmt), -1)),
    3828           4 :      hash_(0), timeout_(PortCacheTable::kAgingTimeout) {
    3829           4 :      timer_->Start(kCacheAging,
    3830             :                    boost::bind(&PortCacheTable::Age, this));
    3831           4 : }
    3832             : 
    3833           4 : PortCacheTable::~PortCacheTable() {
    3834           4 :     timer_->Cancel();
    3835           4 :     TimerManager::DeleteTimer(timer_);
    3836           4 : }
    3837             : 
    3838           2 : bool PortCacheTable::Age() {
    3839           2 :     if (tree_.size() == 0) {
    3840           2 :         return false;
    3841             :     }
    3842             : 
    3843           0 :     std::lock_guard<std::recursive_mutex> lock(port_table_->mutex());
    3844           0 :     uint16_t no_of_entries = tree_.size() / kCacheAging;
    3845           0 :     uint16_t entries_processed = 0;
    3846           0 :     uint64_t current_time = UTCTimestampUsec();
    3847             : 
    3848           0 :     PortCacheTree::iterator it = tree_.lower_bound(hash_);
    3849           0 :     while (it != tree_.end() && entries_processed <= no_of_entries) {
    3850             :         //Go thru each entry in particular hash bucket and identify
    3851             :         //if any of them can be released
    3852           0 :         PortCacheEntryList::iterator pcit = it->second.begin();
    3853           0 :         while (pcit != it->second.end() && entries_processed <= no_of_entries) {
    3854           0 :             PortCacheEntryList::iterator saved_pcit = pcit;
    3855           0 :             pcit++;
    3856           0 :             if (saved_pcit->CanBeAged(current_time, timeout_)) {
    3857             :                 //Release reference to port
    3858             :                 //check if port is empty, delete the port
    3859           0 :                 port_table_->Free(saved_pcit->key(), saved_pcit->port(), true);
    3860             :             }
    3861           0 :             entries_processed++;
    3862             :         }
    3863           0 :         it++;
    3864             :     }
    3865             : 
    3866           0 :     if (it == tree_.end()) {
    3867           0 :         hash_ = 0;
    3868             :     } else {
    3869           0 :         hash_ = it->first;
    3870           0 :         hash_++;
    3871             :     }
    3872             : 
    3873           0 :     return true;
    3874           0 : }
    3875             : 
    3876           0 : void PortCacheTable::StartTimer() {
    3877           0 :     timer_->Start(kCacheAging,
    3878             :                   boost::bind(&PortCacheTable::Age, this));
    3879           0 : }
    3880             : 
    3881           0 : void PortCacheTable::StopTimer() {
    3882           0 :     timer_->Cancel();
    3883           0 : }
    3884             : 
    3885           0 : void PortCacheTable::Add(const PortCacheEntry &cache_entry) {
    3886           0 :     uint16_t hash = port_table_->HashFlowKey(cache_entry.key());
    3887           0 :     tree_[hash].insert(cache_entry);
    3888             : 
    3889           0 :     if (tree_.size() == 1) {
    3890           0 :         StartTimer();
    3891             :     }
    3892           0 : }
    3893             : 
    3894           0 : void PortCacheTable::Delete(const PortCacheEntry &cache_entry) {
    3895           0 :     uint16_t hash = port_table_->HashFlowKey(cache_entry.key());
    3896           0 :     tree_[hash].erase(cache_entry);
    3897           0 :     if (tree_[hash].size() == 0) {
    3898           0 :         tree_.erase(hash);
    3899             :     }
    3900             : 
    3901           0 :     if (tree_.size() == 0) {
    3902           0 :         StopTimer();
    3903             :     }
    3904           0 : }
    3905             : 
    3906           0 : void PortCacheTable::MarkDelete(const PortCacheEntry &cache_entry) {
    3907           0 :     uint16_t hash = port_table_->HashFlowKey(cache_entry.key());
    3908             : 
    3909           0 :     PortCacheEntryList::iterator it = tree_[hash].find(cache_entry);
    3910           0 :     if (it != tree_[hash].end()) {
    3911           0 :         it->MarkDelete();
    3912             :     }
    3913           0 : }
    3914             : 
    3915             : const PortCacheEntry*
    3916           0 : PortCacheTable::Find(const FlowKey &key) const {
    3917           0 :     PortCacheEntry cache_entry(key, 0);
    3918           0 :     uint16_t hash = port_table_->HashFlowKey(cache_entry.key());
    3919             : 
    3920           0 :     PortCacheTree::const_iterator pct_it = tree_.find(hash);
    3921           0 :     if (pct_it == tree_.end()) {
    3922           0 :         return NULL;
    3923             :     }
    3924             : 
    3925           0 :     PortCacheEntryList::const_iterator it = pct_it->second.find(cache_entry);
    3926           0 :     if (it != pct_it->second.end()) {
    3927           0 :         return &(*it);
    3928             :     }
    3929             : 
    3930           0 :     return NULL;
    3931             : }
    3932             : 
    3933           0 : uint16_t PortTable::HashFlowKey(const FlowKey &key) {
    3934           0 :     std::size_t hash = 0;
    3935           0 :     boost::hash_combine(hash, key.dst_addr.to_v4().to_ulong());
    3936           0 :     boost::hash_combine(hash, key.dst_port);
    3937             : 
    3938           0 :     return (hash % hash_table_size_);
    3939             : }
    3940             : 
    3941           4 : PortTable::PortTable(Agent *agent, uint32_t hash_table_size, uint8_t protocol):
    3942           4 :     agent_(agent), protocol_(protocol), cache_(this),
    3943           4 :     hash_table_size_(hash_table_size) {
    3944       16388 :     for (uint32_t i = 0; i < hash_table_size; i++) {
    3945       16384 :          hash_table_.push_back(PortBitMapPtr(new PortBitMap()));
    3946             :     }
    3947           4 : }
    3948             : 
    3949           4 : PortTable::~PortTable() {
    3950           4 :     if (task_trigger_.get()) {
    3951           0 :         task_trigger_->Reset();
    3952             :     }
    3953           4 : }
    3954             : 
    3955           0 : uint16_t PortTable::Allocate(const FlowKey &key) {
    3956           0 :     if (key.protocol != IPPROTO_TCP && key.protocol != IPPROTO_UDP) {
    3957           0 :         return key.src_port;
    3958             :     }
    3959             : 
    3960           0 :     std::lock_guard<std::recursive_mutex> lock(mutex_);
    3961             :     //Check if the entry is present in flow cache tree
    3962           0 :     const PortCacheEntry *entry = cache_.Find(key);
    3963           0 :     if (entry) {
    3964           0 :         entry->set_stale(false);
    3965           0 :         return entry->port();
    3966             :     }
    3967             : 
    3968           0 :     uint16_t port_hash = HashFlowKey(key);
    3969           0 :     uint16_t port = kInvalidPort;
    3970             : 
    3971           0 :     PortBitMapPtr bit_map = hash_table_[port_hash];
    3972             : 
    3973             :     //Mark the port as used in bit map of hash
    3974           0 :     uint16_t index = bit_map->Insert(key);
    3975           0 :     if (index >= port_to_bit_index_.size()) {
    3976           0 :         bit_map->Remove(index);
    3977           0 :         return port;
    3978             :     }
    3979             :     //Using the index above get the actual port to be used
    3980           0 :     port = port_list_.At(index)->port();
    3981           0 :     PortCacheEntry cache_entry(key, port);
    3982             :     //Add to cache tree
    3983           0 :     cache_.Add(cache_entry);
    3984             : 
    3985           0 :     return port;
    3986           0 : }
    3987             : 
    3988             : PortTable::PortPtr
    3989           0 : PortTable::CreatePortEntry(uint16_t port_no) {
    3990           0 :     switch(protocol_) {
    3991           0 :     case IPPROTO_TCP:
    3992           0 :         return PortPtr(new TcpPort(*(agent_->event_manager()->io_service()),
    3993           0 :                                    port_no));
    3994             : 
    3995           0 :     case IPPROTO_UDP:
    3996           0 :         return PortPtr(new UdpPort(*(agent_->event_manager()->io_service()),
    3997           0 :                                    port_no));
    3998             :     }
    3999             : 
    4000           0 :     return PortPtr();
    4001             : }
    4002             : 
    4003           0 : void PortTable::Free(const FlowKey &key, uint16_t port, bool release) {
    4004           0 :     std::lock_guard<std::recursive_mutex> lock(mutex_);
    4005           0 :     PortCacheEntry cache_entry(key, kInvalidPort);
    4006           0 :     if (release) {
    4007             :         //Delete from cache entry
    4008           0 :         PortCacheEntry cache_entry(key, kInvalidPort);
    4009           0 :         cache_.Delete(cache_entry);
    4010             : 
    4011           0 :         uint16_t port_hash = HashFlowKey(key);
    4012           0 :         PortBitMapPtr bit_map = hash_table_[port_hash];
    4013           0 :         if (port_to_bit_index_.find(port) != port_to_bit_index_.end()) {
    4014             :             //Upon config change all the entries in bit map
    4015             :             //are implicitly deleted, hence a duplicate
    4016             :             //delete from flow table needs to be handled
    4017             :             //after cross check if key matches
    4018           0 :             FlowKey existing_key = bit_map->At(port_to_bit_index_[port]);
    4019           0 :             if (existing_key.IsEqual(key)) {
    4020           0 :                 bit_map->Remove(port_to_bit_index_[port]);
    4021             :             }
    4022             :         }
    4023           0 :     } else {
    4024             :         //Mark cache entry for deletion
    4025             :         //after aging timeout
    4026           0 :         cache_.MarkDelete(cache_entry);
    4027             :     }
    4028           0 : }
    4029             : 
    4030           0 : void PortTable::Relocate(uint16_t port_no) {
    4031           0 :     PortToBitIndexMap::iterator it = port_to_bit_index_.find(port_no);
    4032           0 :     assert(it != port_to_bit_index_.end());
    4033             : 
    4034           0 :     PortPtr port_ptr = port_list_.At(it->second);
    4035           0 :     DeleteAllFlow(port_no, it->second);
    4036           0 :     port_list_.Remove(it->second);
    4037           0 :     it->second = port_list_.Insert(port_ptr);
    4038           0 : }
    4039             : 
    4040           0 : void PortTable::AddPort(uint16_t port_no) {
    4041           0 :     PortToBitIndexMap::iterator it = port_to_bit_index_.find(port_no);
    4042             :     //Port number already present
    4043           0 :     if (port_no != kInvalidPort && it != port_to_bit_index_.end()) {
    4044           0 :         if (it->second >= port_config_.port_count) {
    4045           0 :             Relocate(port_no);
    4046             :         }
    4047           0 :         return;
    4048             :     }
    4049             : 
    4050           0 :     PortPtr port_ptr = CreatePortEntry(port_no);
    4051           0 :     if (port_ptr->Bind() || agent_->test_mode()) {
    4052           0 :         size_t index = port_list_.Insert(port_ptr);
    4053           0 :         port_to_bit_index_.insert((PortToBitIndexPair(port_ptr->port(),
    4054           0 :                                                       (uint16_t)index)));
    4055             :     }
    4056           0 : }
    4057             : 
    4058           0 : void PortTable::DeleteAllFlow(uint16_t port_no, uint16_t index) {
    4059           0 :     for (uint16_t i = 0; i < hash_table_size_; i++) {
    4060           0 :         FlowKey key = hash_table_[i]->At((size_t)index);
    4061           0 :         if (key.family == Address::UNSPEC) {
    4062           0 :             continue;
    4063             :         }
    4064           0 :         hash_table_[i]->Remove(index);
    4065           0 :         Free(key, port_no, true);
    4066             :         //Enqueue delete of flow
    4067           0 :         agent_->pkt()->get_flow_proto()->DeleteFlowRequest(key);
    4068             :     }
    4069           0 : }
    4070             : 
    4071           0 : void PortTable::DeletePort(uint16_t port_no) {
    4072           0 :     assert(port_no != kInvalidPort);
    4073             : 
    4074           0 :     PortToBitIndexMap::const_iterator it = port_to_bit_index_.find(port_no);
    4075           0 :     assert(it != port_to_bit_index_.end());
    4076           0 :     uint16_t index = it->second;
    4077             : 
    4078             :     //Delete all the flow using this port
    4079           0 :     DeleteAllFlow(port_no, index);
    4080             : 
    4081           0 :     port_list_.Remove(index);
    4082           0 :     port_to_bit_index_.erase(port_no);
    4083           0 : }
    4084             : 
    4085           0 : bool PortTable::IsValidPort(uint16_t port, uint16_t count) {
    4086           0 :     if (port_config_.port_range.size() != 0) {
    4087             :         std::vector<PortConfig::PortRange>::const_iterator it =
    4088           0 :             port_config_.port_range.begin();
    4089             :         //Go thru each range
    4090           0 :         for(; it != port_config_.port_range.end(); it++) {
    4091           0 :             if (port >= it->port_start && port <= it->port_end) {
    4092           0 :                 return true;
    4093             :             }
    4094             :         }
    4095             :     } else {
    4096           0 :         return (count < port_config_.port_count);
    4097             :     }
    4098             : 
    4099           0 :     return false;
    4100             : }
    4101             : 
    4102           0 : void PortTable::UpdatePortConfig(const PortConfig *pc) {
    4103           0 :     if (task_trigger_.get()) {
    4104           0 :         task_trigger_->Reset();
    4105             :     }
    4106             : 
    4107           0 :     PortConfig new_pc = *pc;
    4108             : 
    4109           0 :     int task_id = TaskScheduler::GetInstance()->GetTaskId(kTaskFlowEvent);
    4110             :     task_trigger_.reset
    4111           0 :         (new TaskTrigger(boost::bind(&PortTable::HandlePortConfig, this,
    4112           0 :                          new_pc), task_id, 0));
    4113           0 :     task_trigger_->Set();
    4114           0 : }
    4115             : 
    4116           0 : bool PortTable::HandlePortConfig(const PortConfig &pc) {
    4117           0 :     std::lock_guard<std::recursive_mutex> lock(mutex_);
    4118           0 :     uint16_t old_port_count = port_to_bit_index_.size();
    4119           0 :     port_config_ = pc;
    4120             : 
    4121           0 :     uint16_t count = 0;
    4122             : 
    4123           0 :     for (uint16_t index = 0; index < old_port_count; index++) {
    4124           0 :         PortPtr port = port_list_.At(index);
    4125           0 :         if (port.get() && IsValidPort(port->port(), count) == false) {
    4126           0 :             DeletePort(port->port());
    4127             :         } else {
    4128           0 :             count++;
    4129             :             //For relocating the port of index is higher than
    4130             :             //port count
    4131           0 :             AddPort(port->port());
    4132             :         }
    4133           0 :     }
    4134             : 
    4135           0 :     if (port_config_.port_range.size()) {
    4136             :         std::vector<PortConfig::PortRange>::const_iterator it =
    4137           0 :             port_config_.port_range.begin();
    4138             :         //Go thru each range
    4139           0 :         for(; it != port_config_.port_range.end(); it++) {
    4140             :             //Handle range of port
    4141           0 :             for (uint16_t port = it->port_start;
    4142           0 :                  it->port_end && port <= it->port_end;
    4143             :                  port++) {
    4144           0 :                 AddPort(port);
    4145             :             }
    4146             :         }
    4147             :     } else {
    4148             :         //Handle port count, port_count_ would be set only if range is
    4149             :         //not valid
    4150           0 :         for (uint16_t port = count; port < port_config_.port_count; port++) {
    4151           0 :             AddPort(0);
    4152             :         }
    4153             :     }
    4154           0 :     return true;
    4155           0 : }
    4156             : 
    4157           0 : uint16_t PortTable::GetPortIndex(uint16_t port) const {
    4158           0 :     PortToBitIndexMap::const_iterator it = port_to_bit_index_.find(port);
    4159           0 :     assert(it != port_to_bit_index_.end());
    4160           0 :     return it->second;
    4161             : }
    4162             : 
    4163           0 : void PortTable::GetFlowKeyList(uint16_t port,
    4164             :                                std::vector<FlowKey> &list) const {
    4165           0 :     std::lock_guard<std::recursive_mutex> lock(mutex_);
    4166           0 :     if (port_to_bit_index_.find(port) == port_to_bit_index_.end()) {
    4167           0 :         return;
    4168             :     }
    4169             : 
    4170           0 :     for (uint16_t hash = 0; hash < hash_table_size_; hash++) {
    4171           0 :         const PortBitMapPtr bit_map = hash_table_[hash];
    4172           0 :         FlowKey existing_key = bit_map->At(GetPortIndex(port));
    4173           0 :         if (existing_key.family != Address::UNSPEC) {
    4174           0 :             list.push_back(existing_key);
    4175             :         }
    4176           0 :     }
    4177           0 : }
    4178             : 
    4179           2 : PortTableManager::PortTableManager(Agent *agent, uint16_t hash_table_size):
    4180           0 :     agent_(agent) {
    4181             :     port_table_list_[IPPROTO_TCP] =
    4182           2 :         PortTablePtr(new PortTable(agent, hash_table_size, IPPROTO_TCP));
    4183             :     port_table_list_[IPPROTO_UDP] =
    4184           2 :         PortTablePtr(new PortTable(agent, hash_table_size, IPPROTO_UDP));
    4185           2 :     agent_->set_port_config_handler(&(PortTableManager::PortConfigHandler));
    4186           2 : }
    4187             : 
    4188         528 : PortTableManager::~PortTableManager() {
    4189         528 :     for (uint16_t proto = 0; proto < IPPROTO_MAX; proto++) {
    4190         526 :         port_table_list_[proto].reset();
    4191             :     }
    4192         530 : }
    4193           0 : uint16_t PortTableManager::Allocate(const FlowKey &key) {
    4194           0 :     if (key.protocol != IPPROTO_TCP && key.protocol != IPPROTO_UDP) {
    4195           0 :         return key.src_port;
    4196             :     }
    4197             : 
    4198           0 :     return port_table_list_[key.protocol]->Allocate(key);
    4199             : }
    4200             : 
    4201           0 : void PortTableManager::Free(const FlowKey &key, uint16_t port, bool evict) {
    4202           0 :     if (key.protocol != IPPROTO_TCP && key.protocol != IPPROTO_UDP) {
    4203           0 :         return;
    4204             :     }
    4205             : 
    4206           0 :     return port_table_list_[key.protocol]->Free(key, port, evict);
    4207             : }
    4208             : 
    4209           0 : void PortTableManager::UpdatePortConfig(uint8_t protocol, const PortConfig *pc) {
    4210           0 :     if (port_table_list_[protocol].get() == NULL) {
    4211           0 :         return;
    4212             :     }
    4213             : 
    4214           0 :     port_table_list_[protocol]->UpdatePortConfig(pc);
    4215             : }
    4216             : 
    4217           0 : void PortTableManager::PortConfigHandler(Agent *agent, uint8_t protocol,
    4218             :                                          const PortConfig *pc) {
    4219             :     agent->pkt()->get_flow_proto()->port_table_manager()->
    4220           0 :         UpdatePortConfig(protocol, pc);
    4221           0 : }

Generated by: LCOV version 1.14