LCOV - code coverage report
Current view: top level - vnsw/agent/vrouter/ksync - flowtable_ksync.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 0 523 0.0 %
Date: 2026-10-05 02:12:29 Functions: 0 45 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       3             :  */
       4             : 
       5             : #include <sys/socket.h>
       6             : #if defined(__linux__)
       7             : #include <linux/netlink.h>
       8             : #endif
       9             : #include <fcntl.h>
      10             : #include <sys/mman.h>
      11             : #include <sys/types.h>
      12             : #include <sys/ipc.h>
      13             : #include <sys/shm.h>
      14             : #include <asm/types.h>
      15             : #include <boost/asio.hpp>
      16             : #include <boost/asio/buffer.hpp>
      17             : 
      18             : #include <base/address_util.h>
      19             : #include <cmn/agent_cmn.h>
      20             : #include <ksync/ksync_index.h>
      21             : #include <ksync/ksync_entry.h>
      22             : #include <ksync/ksync_object.h>
      23             : #include <ksync/ksync_netlink.h>
      24             : #include <ksync/ksync_sock.h>
      25             : #include <ksync/ksync_netlink.h>
      26             : #include <ksync/ksync_types.h>
      27             : #include <vrouter/ksync/agent_ksync_types.h>
      28             : #include <vrouter/ksync/interface_ksync.h>
      29             : #include <vrouter/ksync/flowtable_ksync.h>
      30             : #include <filter/traffic_action.h>
      31             : #include <vr_types.h>
      32             : #include <nl_util.h>
      33             : #include <vr_flow.h>
      34             : #include <vr_genetlink.h>
      35             : #include <ksync/ksync_sock_user.h>
      36             : #include <vrouter/ksync/ksync_init.h>
      37             : 
      38             : #include <pkt/flow_proto.h>
      39             : #include <oper/agent_types.h>
      40             : #include <services/services_init.h>
      41             : #include <services/icmp_error_proto.h>
      42             : #include <uve/stats_collector.h>
      43             : 
      44             : const uint32_t KSyncFlowEntryFreeList::kInitCount;
      45             : const uint32_t KSyncFlowEntryFreeList::kTestInitCount;
      46             : const uint32_t KSyncFlowEntryFreeList::kGrowSize;
      47             : const uint32_t KSyncFlowEntryFreeList::kMinThreshold;
      48             : const uint32_t KSyncFlowEntryFreeList::kMaxThreshold;
      49             : 
      50             : using namespace boost::asio::ip;
      51             : 
      52           0 : static uint16_t GetDropReason(uint16_t dr) {
      53           0 :     switch (dr) {
      54           0 :     case FlowEntry::SHORT_UNAVIALABLE_INTERFACE:
      55           0 :         return VR_FLOW_DR_UNAVIALABLE_INTF;
      56           0 :     case FlowEntry::SHORT_IPV4_FWD_DIS:
      57           0 :         return VR_FLOW_DR_IPv4_FWD_DIS;
      58           0 :     case FlowEntry::SHORT_UNAVIALABLE_VRF:
      59           0 :         return VR_FLOW_DR_UNAVAILABLE_VRF;
      60           0 :     case FlowEntry::SHORT_NO_SRC_ROUTE:
      61           0 :         return VR_FLOW_DR_NO_SRC_ROUTE;
      62           0 :     case FlowEntry::SHORT_NO_DST_ROUTE:
      63           0 :         return VR_FLOW_DR_NO_DST_ROUTE;
      64           0 :     case FlowEntry::SHORT_AUDIT_ENTRY:
      65           0 :         return VR_FLOW_DR_AUDIT_ENTRY;
      66           0 :     case FlowEntry::SHORT_VRF_CHANGE:
      67           0 :         return VR_FLOW_DR_VRF_CHANGE;
      68           0 :     case FlowEntry::SHORT_NO_REVERSE_FLOW:
      69           0 :         return VR_FLOW_DR_NO_REVERSE_FLOW;
      70           0 :     case FlowEntry::SHORT_REVERSE_FLOW_CHANGE:
      71           0 :         return VR_FLOW_DR_REVERSE_FLOW_CHANGE;
      72           0 :     case FlowEntry::SHORT_NAT_CHANGE:
      73           0 :         return VR_FLOW_DR_NAT_CHANGE;
      74           0 :     case FlowEntry::SHORT_FLOW_LIMIT:
      75           0 :         return VR_FLOW_DR_FLOW_LIMIT;
      76           0 :     case FlowEntry::SHORT_LINKLOCAL_SRC_NAT:
      77           0 :         return VR_FLOW_DR_LINKLOCAL_SRC_NAT;
      78           0 :     case FlowEntry::SHORT_NO_MIRROR_ENTRY:
      79           0 :         return VR_FLOW_DR_NO_MIRROR_ENTRY;
      80           0 :     case FlowEntry::SHORT_SAME_FLOW_RFLOW_KEY:
      81           0 :         return VR_FLOW_DR_SAME_FLOW_RFLOW_KEY;
      82           0 :     case FlowEntry::SHORT_PORT_MAP_DROP:
      83           0 :         return VR_FLOW_DR_PORT_MAP_DROP;
      84           0 :     case FlowEntry::SHORT_NO_SRC_ROUTE_L2RPF:
      85           0 :         return VR_FLOW_DR_NO_SRC_ROUTE_L2RPF;
      86           0 :     case FlowEntry::SHORT_FAT_FLOW_NAT_CONFLICT:
      87           0 :         return VR_FLOW_DR_FAT_FLOW_NAT_CONFLICT;
      88           0 :     case FlowEntry::DROP_POLICY:
      89           0 :         return VR_FLOW_DR_POLICY;
      90           0 :     case FlowEntry::DROP_OUT_POLICY:
      91           0 :         return VR_FLOW_DR_OUT_POLICY;
      92           0 :     case FlowEntry::DROP_SG:
      93           0 :         return VR_FLOW_DR_SG;
      94           0 :     case FlowEntry::DROP_OUT_SG:
      95           0 :         return VR_FLOW_DR_OUT_SG;
      96           0 :     case FlowEntry::DROP_REVERSE_SG:
      97           0 :         return VR_FLOW_DR_REVERSE_SG;
      98           0 :     case FlowEntry::DROP_REVERSE_OUT_SG:
      99           0 :         return VR_FLOW_DR_REVERSE_OUT_SG;
     100           0 :     case FlowEntry::DROP_FIREWALL_POLICY:
     101           0 :         return VR_FLOW_DR_FW_POLICY;
     102           0 :     case FlowEntry::DROP_OUT_FIREWALL_POLICY:
     103           0 :         return VR_FLOW_DR_OUT_FW_POLICY;
     104           0 :     case FlowEntry::DROP_REVERSE_FIREWALL_POLICY:
     105           0 :         return VR_FLOW_DR_REVERSE_FW_POLICY;
     106           0 :     case FlowEntry::DROP_REVERSE_OUT_FIREWALL_POLICY:
     107           0 :         return VR_FLOW_DR_REVERSE_OUT_FW_POLICY;
     108           0 :     case FlowEntry::DROP_FWAAS_POLICY:
     109           0 :         return VR_FLOW_DR_FWAAS_POLICY;
     110           0 :     case FlowEntry::DROP_FWAAS_OUT_POLICY:
     111           0 :         return VR_FLOW_DR_OUT_FWAAS_POLICY;
     112           0 :     case FlowEntry::DROP_FWAAS_REVERSE_POLICY:
     113           0 :         return VR_FLOW_DR_REVERSE_FWAAS_POLICY;
     114           0 :     case FlowEntry::DROP_FWAAS_REVERSE_OUT_POLICY:
     115           0 :         return VR_FLOW_DR_REVERSE_OUT_FWAAS_POLICY;
     116           0 :     default:
     117           0 :         break;
     118             :     }
     119           0 :     return VR_FLOW_DR_UNKNOWN;
     120             : }
     121             : 
     122           0 : FlowTableKSyncEntry::FlowTableKSyncEntry(FlowTableKSyncObject *obj) {
     123           0 :     Reset();
     124           0 :     ksync_obj_ = obj;
     125           0 : }
     126             : 
     127           0 : FlowTableKSyncEntry::FlowTableKSyncEntry(FlowTableKSyncObject *obj,
     128           0 :                                          FlowEntry *flow, uint32_t hash_id) {
     129           0 :     Reset();
     130           0 :     Reset(flow, hash_id);
     131           0 :     ksync_obj_ = obj;
     132           0 : }
     133             : 
     134           0 : FlowTableKSyncEntry::~FlowTableKSyncEntry() {
     135           0 : }
     136             : 
     137           0 : void FlowTableKSyncEntry::Reset() {
     138           0 :     KSyncEntry::Reset();
     139           0 :     flow_entry_ = NULL;
     140           0 :     hash_id_ = FlowEntry::kInvalidFlowHandle;
     141           0 :     gen_id_ = 0;
     142           0 :     evict_gen_id_ = 0;
     143           0 :     vrouter_gen_id_ = 0;
     144           0 :     vrouter_hash_id_ = FlowEntry::kInvalidFlowHandle;
     145           0 :     old_reverse_flow_id_ = FlowEntry::kInvalidFlowHandle;
     146           0 :     old_action_ = 0;
     147           0 :     old_component_nh_idx_ = 0xFFFF;
     148           0 :     old_first_mirror_index_ = 0xFFFF;
     149           0 :     old_second_mirror_index_ = 0xFFFF;
     150           0 :     trap_flow_ = false;
     151           0 :     old_drop_reason_ = 0;
     152           0 :     ecmp_ = false;
     153           0 :     enable_rpf_ = true;
     154           0 :     src_nh_id_ = NextHopTable::kRpfDiscardIndex;
     155           0 :     last_event_ = FlowEvent::INVALID;
     156           0 :     token_.reset();
     157           0 :     ksync_response_info_.Reset();
     158           0 :     qos_config_idx = AgentQosConfigTable::kInvalidIndex;
     159           0 :     transaction_id_ = 0;
     160           0 :     underlay_gw_index = -1;
     161           0 : }
     162             : 
     163           0 : void FlowTableKSyncEntry::Reset(FlowEntry *flow, uint32_t hash_id) {
     164           0 :     flow_entry_ = flow;
     165           0 :     hash_id_ = hash_id;
     166           0 :     gen_id_ = flow->gen_id();
     167           0 :     transaction_id_ = flow->GetTransactionId();
     168           0 : }
     169             : 
     170           0 : KSyncObject *FlowTableKSyncEntry::GetObject() const {
     171           0 :     return ksync_obj_;
     172             : }
     173             : 
     174           0 : uint32_t FlowTableKSyncEntry::GetTableIndex() const {
     175             :     FlowTableKSyncObject *obj =
     176           0 :         static_cast<FlowTableKSyncObject *>(GetObject());
     177           0 :     return (obj->flow_table()->table_index());
     178             : }
     179           0 : void FlowTableKSyncEntry::ReleaseToken() {
     180           0 :     if (token_.get())
     181           0 :         token_.reset();
     182           0 : }
     183             : 
     184           0 : void FlowTableKSyncEntry::SetPcapData(FlowEntryPtr fe,
     185             :                                       std::vector<int8_t> &data) {
     186           0 :     data.clear();
     187           0 :     uint32_t addr = ksync_obj_->ksync()->agent()->router_id().to_ulong();
     188           0 :     data.push_back(FlowEntry::PCAP_CAPTURE_HOST);
     189           0 :     data.push_back(0x4);
     190           0 :     data.push_back(((addr >> 24) & 0xFF));
     191           0 :     data.push_back(((addr >> 16) & 0xFF));
     192           0 :     data.push_back(((addr >> 8) & 0xFF));
     193           0 :     data.push_back(((addr) & 0xFF));
     194             : 
     195           0 :     data.push_back(FlowEntry::PCAP_FLAGS);
     196           0 :     data.push_back(0x4);
     197             :     uint32_t action;
     198           0 :     action = fe->match_p().action_info.action;
     199           0 :     if (fe->is_flags_set(FlowEntry::IngressDir)) {
     200             :         // Set 31st bit for ingress
     201           0 :         action |= 0x40000000;
     202             :     }
     203           0 :     data.push_back((action >> 24) & 0xFF);
     204           0 :     data.push_back((action >> 16) & 0xFF);
     205           0 :     data.push_back((action >> 8) & 0xFF);
     206           0 :     data.push_back((action) & 0xFF);
     207             : 
     208           0 :     data.push_back(FlowEntry::PCAP_SOURCE_VN);
     209           0 :     data.push_back(fe->data().source_vn_match.size());
     210           0 :     data.insert(data.end(), fe->data().source_vn_match.begin(),
     211           0 :                 fe->data().source_vn_match.end());
     212           0 :     data.push_back(FlowEntry::PCAP_DEST_VN);
     213           0 :     data.push_back(fe->data().dest_vn_match.size());
     214           0 :     data.insert(data.end(), fe->data().dest_vn_match.begin(),
     215           0 :                 fe->data().dest_vn_match.end());
     216           0 :     data.push_back(FlowEntry::PCAP_TLV_END);
     217           0 :     data.push_back(0x0);
     218           0 : }
     219             : 
     220           0 : static void EncodeKSyncIp(vr_flow_req *req, const IpAddress &sip,
     221             :                           const IpAddress &dip) {
     222             :     uint64_t supper, dupper, slower, dlower;
     223             : 
     224             : 
     225           0 :     IpToU64(sip, dip, &supper, &slower, &dupper, &dlower);
     226           0 :     req->set_fr_flow_sip_l(slower);
     227           0 :     req->set_fr_flow_sip_u(supper);
     228           0 :     req->set_fr_flow_dip_l(dlower);
     229           0 :     req->set_fr_flow_dip_u(dupper);
     230             : 
     231           0 : }
     232             : 
     233           0 : int FlowTableKSyncEntry::Encode(sandesh_op::type op, char *buf, int buf_len) {
     234           0 :     vr_flow_req &req = ksync_obj_->flow_req();
     235             :     int encode_len;
     236             :     int error;
     237           0 :     uint16_t action = 0;
     238           0 :     uint16_t drop_reason = VR_FLOW_DR_UNKNOWN;
     239             : 
     240             :     // currently vrouter doesnot guarantee gen id to always start from 0
     241             :     // on vrouter-agent restart
     242             :     // TODO(prabhjot) need to move last gen id seen by vrouter in KSync
     243             :     // Index Manager
     244           0 :     if (gen_id_ != evict_gen_id_) {
     245             :         // skip sending update to vrouter for evicted entry
     246           0 :         flow_entry_->LogFlow(FlowEventLog::FLOW_MSG_SKIP_EVICTED, this,
     247           0 :                              hash_id_, evict_gen_id_);
     248           0 :         return 0;
     249             :     }
     250             : 
     251           0 :     req.set_fr_op(flow_op::FLOW_SET);
     252           0 :     req.set_fr_rid(0);
     253           0 :     req.set_fr_index(hash_id_);
     254           0 :     req.set_fr_gen_id(gen_id_);
     255           0 :     const FlowKey *fe_key = &flow_entry_->key();
     256           0 :     EncodeKSyncIp(&req, fe_key->src_addr, fe_key->dst_addr);
     257           0 :     req.set_fr_flow_proto(fe_key->protocol);
     258           0 :     req.set_fr_flow_sport(htons(fe_key->src_port));
     259           0 :     req.set_fr_flow_dport(htons(fe_key->dst_port));
     260           0 :     req.set_fr_flow_nh_id(fe_key->nh);
     261           0 :     if (flow_entry_->key().family == Address::INET)
     262           0 :         req.set_fr_family(AF_INET);
     263             :     else
     264           0 :         req.set_fr_family(AF_INET6);
     265           0 :     req.set_fr_flow_vrf(flow_entry_->data().vrf);
     266           0 :     uint16_t flags = 0;
     267           0 :     uint16_t flags1 = 0;
     268             : 
     269           0 :     if (op == sandesh_op::DEL) {
     270           0 :         if (hash_id_ == FlowEntry::kInvalidFlowHandle) {
     271           0 :             return 0;
     272             :         }
     273             : 
     274           0 :         req.set_fr_flags(0);
     275           0 :         req.set_fr_flags1(0);
     276             :         // Sync() is not called in case of delete. Copy the event to use
     277             :         // the right token
     278           0 :         last_event_ = (FlowEvent::Event)flow_entry_->last_event();
     279             :     } else {
     280           0 :         flags = VR_FLOW_FLAG_ACTIVE;
     281           0 :         uint32_t fe_action = flow_entry_->match_p().action_info.action;
     282           0 :         if ((fe_action) & (1 << TrafficAction::PASS)) {
     283           0 :             action = VR_FLOW_ACTION_FORWARD;
     284             :         }
     285             : 
     286           0 :         if ((fe_action) & (1 << TrafficAction::DENY)) {
     287           0 :             action = VR_FLOW_ACTION_DROP;
     288           0 :             drop_reason = GetDropReason(flow_entry_->data().drop_reason);
     289             :         }
     290             : 
     291           0 :         if (action == VR_FLOW_ACTION_FORWARD &&
     292           0 :             flow_entry_->is_flags_set(FlowEntry::NatFlow)) {
     293           0 :             action = VR_FLOW_ACTION_NAT;
     294             :         }
     295             : 
     296           0 :         if (action == VR_FLOW_ACTION_NAT &&
     297           0 :             flow_entry_->reverse_flow_entry() == NULL) {
     298           0 :             action = VR_FLOW_ACTION_DROP;
     299             :         }
     300             : 
     301           0 :         if ((fe_action) & (1 << TrafficAction::HBS)) {
     302           0 :             if (flow_entry_->is_flags_set(FlowEntry::HbfFlow)) {
     303           0 :                 if (flow_entry_->GetHbsInterface() ==
     304             :                     FlowEntry::HBS_INTERFACE_RIGHT) {
     305           0 :                     flags1 |= VR_FLOW_FLAG1_HBS_RIGHT;
     306             :                 } else {
     307           0 :                     flags1 |= VR_FLOW_FLAG1_HBS_LEFT;
     308             :                 }
     309             :             }
     310             :         }
     311             : 
     312           0 :         if ((fe_action) & (1 << TrafficAction::MIRROR)) {
     313           0 :             flags |= VR_FLOW_FLAG_MIRROR;
     314           0 :             req.set_fr_mir_id(-1);
     315           0 :             req.set_fr_sec_mir_id(-1);
     316           0 :             if (flow_entry_->match_p().action_info.mirror_l.size() >
     317             :                 FlowEntry::kMaxMirrorsPerFlow) {
     318           0 :                 FLOW_TRACE(Err, hash_id_,
     319             :                            "Don't support more than two mirrors/analyzers per "
     320             :                            "flow:" + integerToString
     321             :                            (flow_entry_->
     322             :                             data().match_p.action_info.mirror_l.size()));
     323             :             }
     324             :             // Lookup for fist and second mirror entries
     325           0 :             std::vector<MirrorActionSpec>::const_iterator it;
     326           0 :             it = flow_entry_->match_p().action_info.mirror_l.begin();
     327           0 :             MirrorKSyncObject* obj = ksync_obj_->ksync()->agent()->ksync()->
     328           0 :                                                           mirror_ksync_obj();
     329           0 :             uint16_t idx_1 = obj->GetIdx((*it).analyzer_name);
     330           0 :             req.set_fr_mir_id(idx_1);
     331           0 :             FLOW_TRACE(ModuleInfo, "Mirror index first: " +
     332             :                        integerToString(idx_1));
     333           0 :             ++it;
     334           0 :             if (it != flow_entry_->match_p().action_info.mirror_l.end()) {
     335           0 :                 uint16_t idx_2 = obj->GetIdx((*it).analyzer_name);
     336           0 :                 if (idx_1 != idx_2) {
     337           0 :                     req.set_fr_sec_mir_id(idx_2);
     338           0 :                     FLOW_TRACE(ModuleInfo, "Mirror index second: " +
     339             :                                integerToString(idx_2));
     340             :                 } else {
     341           0 :                     FLOW_TRACE(Err, hash_id_,
     342             :                                "Both Mirror indexes are same, hence didn't set "
     343             :                                "the second mirror dest.");
     344             :                 }
     345             :             }
     346           0 :             req.set_fr_mir_vrf(flow_entry_->data().mirror_vrf);
     347           0 :             req.set_fr_mir_sip(htonl(ksync_obj_->ksync()->agent()->
     348           0 :                                      router_id().to_ulong()));
     349           0 :             req.set_fr_mir_sport(htons(ksync_obj_->ksync()->agent()->
     350           0 :                                                             mirror_port()));
     351           0 :             std::vector<int8_t> pcap_data;
     352           0 :             SetPcapData(flow_entry_, pcap_data);
     353           0 :             req.set_fr_pcap_meta_data(pcap_data);
     354           0 :         }
     355             : 
     356           0 :         if (flow_entry_->data().component_nh_idx !=
     357             :                 (uint32_t)CompositeNH::kInvalidComponentNHIdx) {
     358           0 :             req.set_fr_ecmp_nh_index(flow_entry_->data().component_nh_idx);
     359             :         } else {
     360           0 :             req.set_fr_ecmp_nh_index(-1);
     361             :         }
     362             : 
     363           0 :         if (action == VR_FLOW_ACTION_NAT) {
     364           0 :             FlowEntry *nat_flow = flow_entry_->reverse_flow_entry();
     365           0 :             const FlowKey *nat_key = &nat_flow->key();
     366             : 
     367           0 :             if (flow_entry_->key().src_addr != nat_key->dst_addr) {
     368           0 :                 flags |= VR_FLOW_FLAG_SNAT;
     369             :             }
     370           0 :             if (flow_entry_->key().dst_addr != nat_key->src_addr) {
     371           0 :                 flags |= VR_FLOW_FLAG_DNAT;
     372             :             }
     373             : 
     374           0 :             if (flow_entry_->key().protocol == IPPROTO_TCP ||
     375           0 :                 flow_entry_->key().protocol == IPPROTO_UDP) {
     376           0 :                 if (flow_entry_->key().src_port != nat_key->dst_port) {
     377           0 :                     flags |= VR_FLOW_FLAG_SPAT;
     378             :                 }
     379           0 :                 if (flow_entry_->key().dst_port != nat_key->src_port) {
     380           0 :                     flags |= VR_FLOW_FLAG_DPAT;
     381             :                 }
     382             :             }
     383             : 
     384             :             //Link local, flag determines relaxed policy
     385           0 :             if (nat_flow->is_flags_set(FlowEntry::LinkLocalBindLocalSrcPort)) {
     386           0 :                 flags |= VR_FLOW_FLAG_LINK_LOCAL;
     387             :             }
     388             : 
     389             :             //Bgp service, flag determines relaxed policy
     390           0 :             if (nat_flow->is_flags_set(FlowEntry::BgpRouterService)) {
     391           0 :                 flags |= VR_FLOW_BGP_SERVICE;
     392             :             }
     393             : 
     394           0 :             if (nat_flow->allocated_port()) {
     395           0 :                 flags |= VR_FLOW_BGP_SERVICE;
     396             :             }
     397             : 
     398           0 :             flags |= VR_FLOW_FLAG_VRFT;
     399           0 :             req.set_fr_flow_dvrf(flow_entry_->data().dest_vrf);
     400           0 :         } else if (flow_entry_->is_flags_set(FlowEntry::AliasIpFlow)) {
     401           0 :             flags |= VR_FLOW_FLAG_VRFT;
     402           0 :             req.set_fr_flow_dvrf(flow_entry_->data().dest_vrf);
     403             :         }
     404             : 
     405           0 :         if (fe_action & (1 << TrafficAction::VRF_TRANSLATE)) {
     406           0 :             flags |= VR_FLOW_FLAG_VRFT;
     407           0 :             req.set_fr_flow_dvrf(flow_entry_->data().dest_vrf);
     408             :         }
     409             : 
     410           0 :         if (flow_entry_->is_flags_set(FlowEntry::Trap)) {
     411           0 :             action = VR_FLOW_ACTION_HOLD;
     412             :         }
     413             : 
     414           0 :         if (enable_rpf_) {
     415           0 :             req.set_fr_src_nh_index(src_nh_id_);
     416             :         } else {
     417             :             //Set to discard, vrouter ignores RPF check if
     418             :             //nexthop is set to discard
     419           0 :             req.set_fr_src_nh_index(0);
     420             :         }
     421             : 
     422           0 :         FlowEntry *rev_flow = flow_entry_->reverse_flow_entry();
     423           0 :         if (rev_flow) {
     424           0 :             flags |= VR_RFLOW_VALID;
     425           0 :             req.set_fr_rindex(rev_flow->flow_handle());
     426           0 :             if (rev_flow->flow_handle() == FlowEntry::kInvalidFlowHandle) {
     427           0 :                 const FlowKey &rkey = rev_flow->key();
     428           0 :                 req.set_fr_rflow_nh_id(rkey.nh);
     429             :                 uint64_t supper, dupper, slower, dlower;
     430             : 
     431           0 :                 IpToU64(rkey.src_addr, rkey.dst_addr, &supper, &slower,
     432             :                         &dupper, &dlower);
     433           0 :                 req.set_fr_rflow_sip_l(slower);
     434           0 :                 req.set_fr_rflow_sip_u(supper);
     435           0 :                 req.set_fr_rflow_dip_l(dlower);
     436           0 :                 req.set_fr_rflow_dip_u(dupper);
     437             : 
     438           0 :                 req.set_fr_rflow_sport(htons(rkey.src_port));
     439           0 :                 req.set_fr_rflow_dport(htons(rkey.dst_port));
     440             :             }
     441             :         }
     442             : 
     443           0 :         if (flow_entry_->IsShortFlow()) {
     444           0 :             action = VR_FLOW_ACTION_DROP;
     445             :         }
     446             : 
     447           0 :         req.set_fr_flags(flags);
     448           0 :         req.set_fr_flags1(flags1);
     449           0 :         req.set_fr_action(action);
     450           0 :         req.set_fr_drop_reason(drop_reason);
     451           0 :         req.set_fr_qos_id(qos_config_idx);
     452           0 :         req.set_fr_ttl(flow_entry_->data().ttl);
     453           0 :         req.set_fr_underlay_ecmp_index(underlay_gw_index);
     454             :     }
     455             : 
     456           0 :     FlowProto *proto = ksync_obj_->ksync()->agent()->pkt()->get_flow_proto();
     457           0 :     token_ = proto->GetToken(last_event_);
     458           0 :     encode_len = req.WriteBinary((uint8_t *)buf, buf_len, &error);
     459           0 :     return encode_len;
     460             : }
     461             : 
     462           0 : bool FlowTableKSyncEntry::Sync() {
     463           0 :     bool changed = false;
     464             : 
     465           0 :     last_event_ = (FlowEvent::Event)flow_entry_->last_event();
     466           0 :     FlowEntry *rev_flow = flow_entry_->reverse_flow_entry();
     467           0 :     if (rev_flow) {
     468           0 :         if (old_reverse_flow_id_ != rev_flow->flow_handle()) {
     469           0 :             if (old_reverse_flow_id_ != FlowEntry::kInvalidFlowHandle)
     470           0 :                 changed = true;
     471           0 :             old_reverse_flow_id_ = rev_flow->flow_handle();
     472             :         }
     473             :     }
     474             : 
     475           0 :     if (flow_entry_->match_p().action_info.action != old_action_) {
     476           0 :         old_action_ = flow_entry_->match_p().action_info.action;
     477           0 :         changed = true;
     478             :     }
     479             : 
     480           0 :     if (flow_entry_->data().drop_reason != old_drop_reason_) {
     481           0 :         old_drop_reason_ = flow_entry_->data().drop_reason;
     482           0 :         changed = true;
     483             :     }
     484           0 :     if (flow_entry_->data().component_nh_idx != old_component_nh_idx_) {
     485           0 :         old_component_nh_idx_ = flow_entry_->data().component_nh_idx;
     486           0 :         changed = true;
     487             :     }
     488             : 
     489           0 :     if (vrouter_gen_id_ != gen_id_) {
     490           0 :         vrouter_gen_id_ = gen_id_;
     491           0 :         changed = true;
     492             :     }
     493             : 
     494           0 :     if (vrouter_hash_id_ != hash_id_) {
     495           0 :         vrouter_hash_id_ = hash_id_;
     496           0 :         changed = true;
     497             :     }
     498             : 
     499           0 :     MirrorKSyncObject* obj = ksync_obj_->ksync()->mirror_ksync_obj();
     500             :     // Lookup for fist and second mirror entries
     501           0 :     std::vector<MirrorActionSpec>::const_iterator it;
     502           0 :     it = flow_entry_->match_p().action_info.mirror_l.begin();
     503           0 :     if (it != flow_entry_->match_p().action_info.mirror_l.end()) {
     504           0 :         uint16_t idx = obj->GetIdx((*it).analyzer_name);
     505           0 :         if (!((*it).analyzer_name.empty()) &&
     506             :             (idx == MirrorTable::kInvalidIndex)) {
     507             :             // runn timer to update flow entry
     508           0 :             ksync_obj_->UpdateUnresolvedFlowEntry(flow_entry_);
     509           0 :         } else if (old_first_mirror_index_ != idx) {
     510           0 :             old_first_mirror_index_ = idx;
     511           0 :             changed = true;
     512             :         }
     513           0 :         ++it;
     514           0 :         if (it != flow_entry_->match_p().action_info.mirror_l.end()) {
     515           0 :             idx = obj->GetIdx((*it).analyzer_name);
     516           0 :             if (!((*it).analyzer_name.empty()) &&
     517             :                 (idx == MirrorTable::kInvalidIndex)) {
     518             :                 // run time and to update  flow entry;
     519           0 :                 ksync_obj_->UpdateUnresolvedFlowEntry(flow_entry_);
     520           0 :             } else if (old_second_mirror_index_ != idx) {
     521           0 :                 old_second_mirror_index_ = idx;
     522           0 :                 changed = true;
     523             :             }
     524             :         }
     525             :     }
     526             : 
     527             :     //Trap reverse flow
     528           0 :     if (trap_flow_ != flow_entry_->is_flags_set(FlowEntry::Trap)) {
     529           0 :         trap_flow_ = flow_entry_->is_flags_set(FlowEntry::Trap);
     530           0 :         changed = true;
     531             :     }
     532             : 
     533           0 :     if (ecmp_ != flow_entry_->is_flags_set(FlowEntry::EcmpFlow)) {
     534           0 :         ecmp_ = flow_entry_->is_flags_set(FlowEntry::EcmpFlow);
     535           0 :         changed = true;
     536             :     }
     537             : 
     538           0 :     if (enable_rpf_ != flow_entry_->data().enable_rpf) {
     539           0 :         enable_rpf_ = flow_entry_->data().enable_rpf;
     540           0 :         changed = true;
     541             :     }
     542             : 
     543           0 :     uint32_t nh_id = NextHopTable::kRpfDiscardIndex;
     544           0 :     if (flow_entry_->data().rpf_nh.get()) {
     545           0 :         nh_id = flow_entry_->data().rpf_nh.get()->id();
     546             :     }
     547           0 :     if (src_nh_id_ != nh_id) {
     548           0 :         src_nh_id_ = nh_id;
     549           0 :         changed = true;
     550             :     }
     551             : 
     552           0 :     if (qos_config_idx != flow_entry_->data().qos_config_idx) {
     553           0 :         qos_config_idx = flow_entry_->data().qos_config_idx;
     554           0 :         changed = true;
     555             :     }
     556           0 :     if (transaction_id_ != flow_entry_->GetTransactionId()) {
     557           0 :         transaction_id_ = flow_entry_->GetTransactionId();
     558           0 :         changed = true;
     559             :     }
     560           0 :     if (underlay_gw_index != flow_entry_->data().underlay_gw_index_) {
     561           0 :         underlay_gw_index = flow_entry_->data().underlay_gw_index_;
     562           0 :         changed = true;
     563             :     }
     564           0 :     return changed;
     565             : }
     566             : 
     567           0 : KSyncEntry* FlowTableKSyncEntry::UnresolvedReference() {
     568             :     // KSync Flow being triggered from parallel threads due to
     569             :     // table partition doesnot allow safe usage of
     570             :     // UnresolvedReference. Please avoid any dependency handling
     571             :     // for KSync Flow
     572           0 :     return NULL;
     573             : }
     574             : 
     575           0 : int FlowTableKSyncEntry::AddMsg(char *buf, int buf_len) {
     576           0 :     return Encode(sandesh_op::ADD, buf, buf_len);
     577             : }
     578             : 
     579           0 : int FlowTableKSyncEntry::ChangeMsg(char *buf, int buf_len) {
     580           0 :     return Encode(sandesh_op::ADD, buf, buf_len);
     581             : }
     582             : 
     583           0 : int FlowTableKSyncEntry::DeleteMsg(char *buf, int buf_len) {
     584           0 :     return Encode(sandesh_op::DEL, buf, buf_len);
     585             : }
     586             : 
     587           0 : std::string FlowTableKSyncEntry::ToString() const {
     588           0 :     std::ostringstream str;
     589           0 :     const FlowKey *fe_key = &flow_entry_->key();
     590           0 :     str << "Flow : " << hash_id_
     591           0 :         << " with Source IP: " << fe_key->src_addr.to_string()
     592           0 :         << " Source port: " << fe_key->src_port
     593           0 :         << " Destination IP: " << fe_key->dst_addr.to_string()
     594           0 :         << " Destination port: " << fe_key->dst_port
     595           0 :         << " Protocol "<< (uint16_t)fe_key->protocol;
     596           0 :     return str.str();
     597           0 : }
     598             : 
     599           0 : bool FlowTableKSyncEntry::IsLess(const KSyncEntry &rhs) const {
     600           0 :     const FlowTableKSyncEntry &entry = static_cast
     601             :         <const FlowTableKSyncEntry &>(rhs);
     602             :     /*
     603             :      * Ksync Flow Table should have the same key as vrouter flow table,
     604             :      * so that all the flow entries present in vrouter can be represented
     605             :      * in Ksync. This will also ensure that the index change for a flow
     606             :      * entry will be sync'ed appropriately in vrouter.
     607             :      */
     608           0 :     if (hash_id_ != entry.hash_id_) {
     609           0 :         return hash_id_ < entry.hash_id_;
     610             :     }
     611           0 :     return flow_entry_ < entry.flow_entry_;
     612             : }
     613             : 
     614           0 : void FlowTableKSyncEntry::ErrorHandler(int err, uint32_t seq_no,
     615             :                                        KSyncEvent event) const {
     616           0 :     if (err == ENOSPC || err == EBADF) {
     617           0 :         KSYNC_ERROR(VRouterError, "VRouter operation failed. Error <", err,
     618             :                     ":", VrouterError(err), ">. Object <", ToString(),
     619             :                     ">. Operation <", AckOperationString(event),
     620             :                     ">. Message number :", seq_no);
     621             :     }
     622           0 :     return;
     623             : }
     624             : 
     625           0 : std::string FlowTableKSyncEntry::VrouterError(uint32_t error) const {
     626           0 :     if (error == EBADF)
     627           0 :         return "Flow gen id Mismatch";
     628           0 :     else if (error == ENOSPC)
     629           0 :         return "Flow Table bucket full";
     630           0 :     else if (error == EFAULT)
     631           0 :         return "Flow Key Mismatch with same gen id";
     632           0 :     else return KSyncEntry::VrouterError(error);
     633             : }
     634             : 
     635           0 : void FlowTableKSyncObject::UpdateUnresolvedFlowEntry(FlowEntryPtr flowptr) {
     636           0 :     FlowEntry *flow_entry = flowptr.get();
     637           0 :     if (!flow_entry->IsShortFlow() && !flow_entry->IsOnUnresolvedList()) {
     638           0 :         unresolved_flow_list_.push_back(flow_entry);
     639           0 :         flow_entry->SetUnResolvedList(true);
     640           0 :         StartTimer();
     641             :     }
     642           0 : }
     643             : /*
     644             :  * timer will be triggred once after adding unresolved entry.
     645             :  *  will be stoped once after list becomes empty.
     646             :  */
     647           0 : void FlowTableKSyncObject::StartTimer() {
     648           0 :     if (timer_ == NULL) {
     649           0 :         timer_ = TimerManager::CreateTimer(
     650           0 :                 *(ksync_->agent()->event_manager())->io_service(),
     651             :                 "flow dep sync timer",
     652           0 :                  ksync_->agent()->task_scheduler()->GetTaskId(kTaskFlowEvent),
     653           0 :                  flow_table()->table_index());
     654             :     }
     655           0 :     timer_->Start(kFlowDepSyncTimeout,
     656             :                   boost::bind(&FlowTableKSyncObject::TimerExpiry, this));
     657           0 : }
     658             : 
     659             : /*
     660             :  * This fuction will be triggred on 1 sec delay
     661             :  * if the entry marked deleted will not call the ksync update
     662             :  * if the number attempts are more than 4 times will mark the flow as shortflow
     663             :  */
     664             : 
     665           0 : bool FlowTableKSyncObject::TimerExpiry() {
     666           0 :     uint16_t count = 0;
     667           0 :     while (!unresolved_flow_list_.empty() && count < KFlowUnresolvedListYield) {
     668           0 :         FlowEntryPtr flow = unresolved_flow_list_.front();
     669           0 :         FlowEntry *flow_entry = flow.get();
     670           0 :         unresolved_flow_list_.pop_front();
     671           0 :         flow_entry->SetUnResolvedList(false);
     672           0 :         count++;
     673           0 :         if (!flow_entry->deleted()) {
     674           0 :             FlowProto *proto = ksync()->agent()->pkt()->get_flow_proto();
     675           0 :             proto->EnqueueUnResolvedFlowEntry(flow.get());
     676             :         }
     677           0 :     }
     678           0 :     if (!unresolved_flow_list_.empty())
     679           0 :         return true;
     680           0 :     return false;
     681             : }
     682             : 
     683           0 : FlowTableKSyncObject::FlowTableKSyncObject(KSync *ksync) :
     684           0 :     KSyncObject("KSync FlowTable"), ksync_(ksync), free_list_(this),
     685           0 :     timer_(NULL) {
     686           0 : }
     687             : 
     688           0 : FlowTableKSyncObject::FlowTableKSyncObject(KSync *ksync, int max_index) :
     689           0 :     KSyncObject("KSync FlowTable", max_index), ksync_(ksync), free_list_(this) {
     690           0 : }
     691             : 
     692           0 : FlowTableKSyncObject::~FlowTableKSyncObject() {
     693           0 :     TimerManager::DeleteTimer(timer_);
     694           0 : }
     695             : 
     696           0 : KSyncEntry *FlowTableKSyncObject::Alloc(const KSyncEntry *key, uint32_t index) {
     697           0 :     const FlowTableKSyncEntry *entry  =
     698             :         static_cast<const FlowTableKSyncEntry *>(key);
     699           0 :     return free_list_.Allocate(entry);
     700             : }
     701             : 
     702           0 : void FlowTableKSyncObject::Free(KSyncEntry *entry) {
     703           0 :     FlowTableKSyncEntry *ksync  = static_cast<FlowTableKSyncEntry *>(entry);
     704           0 :     free_list_.Free(ksync);
     705           0 : }
     706             : 
     707           0 : FlowTableKSyncEntry *FlowTableKSyncObject::Find(FlowEntry *key) {
     708           0 :     FlowTableKSyncEntry entry(this, key, key->flow_handle());
     709           0 :     KSyncObject *obj = static_cast<KSyncObject *>(this);
     710           0 :     return static_cast<FlowTableKSyncEntry *>(obj->Find(&entry));
     711           0 : }
     712             : 
     713           0 : void FlowTableKSyncObject::UpdateKey(KSyncEntry *entry, uint32_t flow_handle) {
     714           0 :     static_cast<FlowTableKSyncEntry *>(entry)->set_hash_id(flow_handle);
     715           0 : }
     716             : 
     717           0 : uint32_t FlowTableKSyncObject::GetKey(KSyncEntry *entry) {
     718           0 :     return static_cast<FlowTableKSyncEntry *>(entry)->hash_id();
     719             : }
     720             : 
     721           0 : void FlowTableKSyncObject::UpdateFlowHandle(FlowTableKSyncEntry *entry,
     722             :                                             uint32_t flow_handle) {
     723           0 :     ChangeKey(entry, flow_handle);
     724           0 : }
     725             : 
     726           0 : void FlowTableKSyncObject::Init() {
     727           0 : }
     728             : 
     729             : /////////////////////////////////////////////////////////////////////////////
     730             : // KSyncFlowEntryFreeList implementation
     731             : /////////////////////////////////////////////////////////////////////////////
     732           0 : KSyncFlowEntryFreeList::KSyncFlowEntryFreeList(FlowTableKSyncObject *object) :
     733           0 :     object_(object), max_count_(0), grow_pending_(false), total_alloc_(0),
     734           0 :     total_free_(0), free_list_() {
     735             : 
     736           0 :     uint32_t count = kInitCount;
     737           0 :     if (object->ksync()->agent()->test_mode()) {
     738           0 :         count = kTestInitCount;
     739             :     }
     740           0 :     while (max_count_ < count) {
     741           0 :         free_list_.push_back(*new FlowTableKSyncEntry(object_));
     742           0 :         max_count_++;
     743             :     }
     744           0 : }
     745             : 
     746           0 : KSyncFlowEntryFreeList::~KSyncFlowEntryFreeList() {
     747           0 :     while (free_list_.empty() == false) {
     748           0 :         FreeList::iterator it = free_list_.begin();
     749           0 :         FlowTableKSyncEntry *flow = &(*it);
     750           0 :         free_list_.erase(it);
     751           0 :         delete flow;
     752             :     }
     753           0 : }
     754             : 
     755             : // Allocate a chunk of FlowEntries
     756           0 : void KSyncFlowEntryFreeList::Grow() {
     757           0 :     grow_pending_ = false;
     758           0 :     if (free_list_.size() >= kMinThreshold)
     759           0 :         return;
     760             : 
     761           0 :     for (uint32_t i = 0; i < kGrowSize; i++) {
     762           0 :         free_list_.push_front(*new FlowTableKSyncEntry(object_));
     763           0 :         max_count_++;
     764             :     }
     765             : }
     766             : 
     767           0 : FlowTableKSyncEntry *KSyncFlowEntryFreeList::Allocate(const KSyncEntry *key) {
     768           0 :     const FlowTableKSyncEntry *flow_key  =
     769             :         static_cast<const FlowTableKSyncEntry *>(key);
     770           0 :     FlowTableKSyncEntry *flow = NULL;
     771           0 :     if (free_list_.size() == 0) {
     772           0 :         flow = new FlowTableKSyncEntry(object_);
     773           0 :         max_count_++;
     774             :     } else {
     775           0 :         FreeList::iterator it = free_list_.begin();
     776           0 :         flow = &(*it);
     777           0 :         free_list_.erase(it);
     778             :     }
     779             : 
     780           0 :     if (grow_pending_ == false && free_list_.size() < kMinThreshold) {
     781           0 :         grow_pending_ = true;
     782           0 :         FlowProto *proto = object_->ksync()->agent()->pkt()->get_flow_proto();
     783           0 :         proto->GrowFreeListRequest(flow_key->flow_entry()->flow_table());
     784             :     }
     785             : 
     786             :     // Do post allocation initialization
     787           0 :     flow->Reset(flow_key->flow_entry().get(), flow_key->hash_id());
     788           0 :     flow->set_evict_gen_id(flow_key->evict_gen_id_);
     789           0 :     total_alloc_++;
     790           0 :     return flow;
     791             : }
     792             : 
     793           0 : void KSyncFlowEntryFreeList::Free(FlowTableKSyncEntry *flow) {
     794           0 :     total_free_++;
     795           0 :     flow->Reset();
     796           0 :     if (free_list_.size() < kMaxThreshold)
     797           0 :         free_list_.push_back(*flow);
     798             :     else {
     799           0 :         delete flow;
     800           0 :         --max_count_;
     801             :     }
     802           0 : }
     803             : 
     804           0 : void FlowTableKSyncObject::GrowFreeList() {
     805           0 :     free_list_.Grow();
     806           0 : }
     807             : 
     808             : // We want to handle KSync transitions for flow from Flow task context.
     809             : // KSync allows the NetlinkAck API to be over-ridden for custom handling.
     810             : // Provide an implementation to enqueue an request
     811           0 : void FlowTableKSyncObject::NetlinkAck(KSyncEntry *entry,
     812             :                                       KSyncEntry::KSyncEvent event) {
     813           0 :     FlowProto *proto = ksync()->agent()->pkt()->get_flow_proto();
     814           0 :     const FlowTableKSyncEntry *flow_ksync_entry =
     815             :         static_cast<const FlowTableKSyncEntry *>(entry);
     816             :     const FlowKSyncResponseInfo *resp =
     817           0 :         flow_ksync_entry->ksync_response_info();
     818           0 :     proto->KSyncEventRequest(entry, event, resp->flow_handle_,
     819           0 :                              resp->gen_id_, resp->ksync_error_,
     820           0 :                              resp->evict_flow_bytes_, resp->evict_flow_packets_,
     821           0 :                              resp->evict_flow_oflow_,
     822             :                              flow_ksync_entry->get_transaction_id());
     823           0 : }
     824             : 
     825           0 : void FlowTableKSyncObject::GenerateKSyncEvent(FlowTableKSyncEntry *entry,
     826             :                                               KSyncEntry::KSyncEvent event) {
     827           0 :     KSyncObject::NetlinkAck(entry, event);
     828           0 : }

Generated by: LCOV version 1.14