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: 264 523 50.5 %
Date: 2026-08-03 02:19:58 Functions: 32 45 71.1 %
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          28 : static uint16_t GetDropReason(uint16_t dr) {
      53          28 :     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          12 :     case FlowEntry::DROP_SG:
      93          12 :         return VR_FLOW_DR_SG;
      94           2 :     case FlowEntry::DROP_OUT_SG:
      95           2 :         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          14 :     default:
     117          14 :         break;
     118             :     }
     119          14 :     return VR_FLOW_DR_UNKNOWN;
     120             : }
     121             : 
     122       15000 : FlowTableKSyncEntry::FlowTableKSyncEntry(FlowTableKSyncObject *obj) {
     123       15000 :     Reset();
     124       15000 :     ksync_obj_ = obj;
     125       15000 : }
     126             : 
     127          44 : FlowTableKSyncEntry::FlowTableKSyncEntry(FlowTableKSyncObject *obj,
     128          44 :                                          FlowEntry *flow, uint32_t hash_id) {
     129          44 :     Reset();
     130          44 :     Reset(flow, hash_id);
     131          44 :     ksync_obj_ = obj;
     132          44 : }
     133             : 
     134       30044 : FlowTableKSyncEntry::~FlowTableKSyncEntry() {
     135       30044 : }
     136             : 
     137       15088 : void FlowTableKSyncEntry::Reset() {
     138       15088 :     KSyncEntry::Reset();
     139       15088 :     flow_entry_ = NULL;
     140       15088 :     hash_id_ = FlowEntry::kInvalidFlowHandle;
     141       15088 :     gen_id_ = 0;
     142       15088 :     evict_gen_id_ = 0;
     143       15088 :     vrouter_gen_id_ = 0;
     144       15088 :     vrouter_hash_id_ = FlowEntry::kInvalidFlowHandle;
     145       15088 :     old_reverse_flow_id_ = FlowEntry::kInvalidFlowHandle;
     146       15088 :     old_action_ = 0;
     147       15088 :     old_component_nh_idx_ = 0xFFFF;
     148       15088 :     old_first_mirror_index_ = 0xFFFF;
     149       15088 :     old_second_mirror_index_ = 0xFFFF;
     150       15088 :     trap_flow_ = false;
     151       15088 :     old_drop_reason_ = 0;
     152       15088 :     ecmp_ = false;
     153       15088 :     enable_rpf_ = true;
     154       15088 :     src_nh_id_ = NextHopTable::kRpfDiscardIndex;
     155       15088 :     last_event_ = FlowEvent::INVALID;
     156       15088 :     token_.reset();
     157       15088 :     ksync_response_info_.Reset();
     158       15088 :     qos_config_idx = AgentQosConfigTable::kInvalidIndex;
     159       15088 :     transaction_id_ = 0;
     160       15088 :     underlay_gw_index = -1;
     161       15088 : }
     162             : 
     163          88 : void FlowTableKSyncEntry::Reset(FlowEntry *flow, uint32_t hash_id) {
     164          88 :     flow_entry_ = flow;
     165          88 :     hash_id_ = hash_id;
     166          88 :     gen_id_ = flow->gen_id();
     167          88 :     transaction_id_ = flow->GetTransactionId();
     168          88 : }
     169             : 
     170         864 : KSyncObject *FlowTableKSyncEntry::GetObject() const {
     171         864 :     return ksync_obj_;
     172             : }
     173             : 
     174         288 : uint32_t FlowTableKSyncEntry::GetTableIndex() const {
     175             :     FlowTableKSyncObject *obj =
     176         288 :         static_cast<FlowTableKSyncObject *>(GetObject());
     177         288 :     return (obj->flow_table()->table_index());
     178             : }
     179         144 : void FlowTableKSyncEntry::ReleaseToken() {
     180         144 :     if (token_.get())
     181         144 :         token_.reset();
     182         144 : }
     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         144 : static void EncodeKSyncIp(vr_flow_req *req, const IpAddress &sip,
     221             :                           const IpAddress &dip) {
     222             :     uint64_t supper, dupper, slower, dlower;
     223             : 
     224             : 
     225         144 :     IpToU64(sip, dip, &supper, &slower, &dupper, &dlower);
     226         144 :     req->set_fr_flow_sip_l(slower);
     227         144 :     req->set_fr_flow_sip_u(supper);
     228         144 :     req->set_fr_flow_dip_l(dlower);
     229         144 :     req->set_fr_flow_dip_u(dupper);
     230             : 
     231         144 : }
     232             : 
     233         144 : int FlowTableKSyncEntry::Encode(sandesh_op::type op, char *buf, int buf_len) {
     234         144 :     vr_flow_req &req = ksync_obj_->flow_req();
     235             :     int encode_len;
     236             :     int error;
     237         144 :     uint16_t action = 0;
     238         144 :     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         144 :     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         144 :     req.set_fr_op(flow_op::FLOW_SET);
     252         144 :     req.set_fr_rid(0);
     253         144 :     req.set_fr_index(hash_id_);
     254         144 :     req.set_fr_gen_id(gen_id_);
     255         144 :     const FlowKey *fe_key = &flow_entry_->key();
     256         144 :     EncodeKSyncIp(&req, fe_key->src_addr, fe_key->dst_addr);
     257         144 :     req.set_fr_flow_proto(fe_key->protocol);
     258         144 :     req.set_fr_flow_sport(htons(fe_key->src_port));
     259         144 :     req.set_fr_flow_dport(htons(fe_key->dst_port));
     260         144 :     req.set_fr_flow_nh_id(fe_key->nh);
     261         144 :     if (flow_entry_->key().family == Address::INET)
     262         144 :         req.set_fr_family(AF_INET);
     263             :     else
     264           0 :         req.set_fr_family(AF_INET6);
     265         144 :     req.set_fr_flow_vrf(flow_entry_->data().vrf);
     266         144 :     uint16_t flags = 0;
     267         144 :     uint16_t flags1 = 0;
     268             : 
     269         144 :     if (op == sandesh_op::DEL) {
     270          44 :         if (hash_id_ == FlowEntry::kInvalidFlowHandle) {
     271           0 :             return 0;
     272             :         }
     273             : 
     274          44 :         req.set_fr_flags(0);
     275          44 :         req.set_fr_flags1(0);
     276             :         // Sync() is not called in case of delete. Copy the event to use
     277             :         // the right token
     278          44 :         last_event_ = (FlowEvent::Event)flow_entry_->last_event();
     279             :     } else {
     280         100 :         flags = VR_FLOW_FLAG_ACTIVE;
     281         100 :         uint32_t fe_action = flow_entry_->match_p().action_info.action;
     282         100 :         if ((fe_action) & (1 << TrafficAction::PASS)) {
     283          50 :             action = VR_FLOW_ACTION_FORWARD;
     284             :         }
     285             : 
     286         100 :         if ((fe_action) & (1 << TrafficAction::DENY)) {
     287          28 :             action = VR_FLOW_ACTION_DROP;
     288          28 :             drop_reason = GetDropReason(flow_entry_->data().drop_reason);
     289             :         }
     290             : 
     291         150 :         if (action == VR_FLOW_ACTION_FORWARD &&
     292         150 :             flow_entry_->is_flags_set(FlowEntry::NatFlow)) {
     293           0 :             action = VR_FLOW_ACTION_NAT;
     294             :         }
     295             : 
     296         100 :         if (action == VR_FLOW_ACTION_NAT &&
     297           0 :             flow_entry_->reverse_flow_entry() == NULL) {
     298           0 :             action = VR_FLOW_ACTION_DROP;
     299             :         }
     300             : 
     301         100 :         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         100 :         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         100 :         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         100 :             req.set_fr_ecmp_nh_index(-1);
     361             :         }
     362             : 
     363         100 :         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         100 :         } 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         100 :         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         100 :         if (flow_entry_->is_flags_set(FlowEntry::Trap)) {
     411           0 :             action = VR_FLOW_ACTION_HOLD;
     412             :         }
     413             : 
     414         100 :         if (enable_rpf_) {
     415         100 :             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         100 :         FlowEntry *rev_flow = flow_entry_->reverse_flow_entry();
     423         100 :         if (rev_flow) {
     424         100 :             flags |= VR_RFLOW_VALID;
     425         100 :             req.set_fr_rindex(rev_flow->flow_handle());
     426         100 :             if (rev_flow->flow_handle() == FlowEntry::kInvalidFlowHandle) {
     427          22 :                 const FlowKey &rkey = rev_flow->key();
     428          22 :                 req.set_fr_rflow_nh_id(rkey.nh);
     429             :                 uint64_t supper, dupper, slower, dlower;
     430             : 
     431          22 :                 IpToU64(rkey.src_addr, rkey.dst_addr, &supper, &slower,
     432             :                         &dupper, &dlower);
     433          22 :                 req.set_fr_rflow_sip_l(slower);
     434          22 :                 req.set_fr_rflow_sip_u(supper);
     435          22 :                 req.set_fr_rflow_dip_l(dlower);
     436          22 :                 req.set_fr_rflow_dip_u(dupper);
     437             : 
     438          22 :                 req.set_fr_rflow_sport(htons(rkey.src_port));
     439          22 :                 req.set_fr_rflow_dport(htons(rkey.dst_port));
     440             :             }
     441             :         }
     442             : 
     443         100 :         if (flow_entry_->IsShortFlow()) {
     444          22 :             action = VR_FLOW_ACTION_DROP;
     445             :         }
     446             : 
     447         100 :         req.set_fr_flags(flags);
     448         100 :         req.set_fr_flags1(flags1);
     449         100 :         req.set_fr_action(action);
     450         100 :         req.set_fr_drop_reason(drop_reason);
     451         100 :         req.set_fr_qos_id(qos_config_idx);
     452         100 :         req.set_fr_ttl(flow_entry_->data().ttl);
     453         100 :         req.set_fr_underlay_ecmp_index(underlay_gw_index);
     454             :     }
     455             : 
     456         144 :     FlowProto *proto = ksync_obj_->ksync()->agent()->pkt()->get_flow_proto();
     457         144 :     token_ = proto->GetToken(last_event_);
     458         144 :     encode_len = req.WriteBinary((uint8_t *)buf, buf_len, &error);
     459         144 :     return encode_len;
     460             : }
     461             : 
     462         122 : bool FlowTableKSyncEntry::Sync() {
     463         122 :     bool changed = false;
     464             : 
     465         122 :     last_event_ = (FlowEvent::Event)flow_entry_->last_event();
     466         122 :     FlowEntry *rev_flow = flow_entry_->reverse_flow_entry();
     467         122 :     if (rev_flow) {
     468         122 :         if (old_reverse_flow_id_ != rev_flow->flow_handle()) {
     469          44 :             if (old_reverse_flow_id_ != FlowEntry::kInvalidFlowHandle)
     470           0 :                 changed = true;
     471          44 :             old_reverse_flow_id_ = rev_flow->flow_handle();
     472             :         }
     473             :     }
     474             : 
     475         122 :     if (flow_entry_->match_p().action_info.action != old_action_) {
     476          78 :         old_action_ = flow_entry_->match_p().action_info.action;
     477          78 :         changed = true;
     478             :     }
     479             : 
     480         122 :     if (flow_entry_->data().drop_reason != old_drop_reason_) {
     481          24 :         old_drop_reason_ = flow_entry_->data().drop_reason;
     482          24 :         changed = true;
     483             :     }
     484         122 :     if (flow_entry_->data().component_nh_idx != old_component_nh_idx_) {
     485          44 :         old_component_nh_idx_ = flow_entry_->data().component_nh_idx;
     486          44 :         changed = true;
     487             :     }
     488             : 
     489         122 :     if (vrouter_gen_id_ != gen_id_) {
     490           7 :         vrouter_gen_id_ = gen_id_;
     491           7 :         changed = true;
     492             :     }
     493             : 
     494         122 :     if (vrouter_hash_id_ != hash_id_) {
     495          29 :         vrouter_hash_id_ = hash_id_;
     496          29 :         changed = true;
     497             :     }
     498             : 
     499         122 :     MirrorKSyncObject* obj = ksync_obj_->ksync()->mirror_ksync_obj();
     500             :     // Lookup for fist and second mirror entries
     501         122 :     std::vector<MirrorActionSpec>::const_iterator it;
     502         122 :     it = flow_entry_->match_p().action_info.mirror_l.begin();
     503         122 :     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         122 :     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         122 :     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         122 :     if (enable_rpf_ != flow_entry_->data().enable_rpf) {
     539           0 :         enable_rpf_ = flow_entry_->data().enable_rpf;
     540           0 :         changed = true;
     541             :     }
     542             : 
     543         122 :     uint32_t nh_id = NextHopTable::kRpfDiscardIndex;
     544         122 :     if (flow_entry_->data().rpf_nh.get()) {
     545         109 :         nh_id = flow_entry_->data().rpf_nh.get()->id();
     546             :     }
     547         122 :     if (src_nh_id_ != nh_id) {
     548          51 :         src_nh_id_ = nh_id;
     549          51 :         changed = true;
     550             :     }
     551             : 
     552         122 :     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         122 :     if (transaction_id_ != flow_entry_->GetTransactionId()) {
     557          50 :         transaction_id_ = flow_entry_->GetTransactionId();
     558          50 :         changed = true;
     559             :     }
     560         122 :     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         122 :     return changed;
     565             : }
     566             : 
     567         122 : 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         122 :     return NULL;
     573             : }
     574             : 
     575          44 : int FlowTableKSyncEntry::AddMsg(char *buf, int buf_len) {
     576          44 :     return Encode(sandesh_op::ADD, buf, buf_len);
     577             : }
     578             : 
     579          56 : int FlowTableKSyncEntry::ChangeMsg(char *buf, int buf_len) {
     580          56 :     return Encode(sandesh_op::ADD, buf, buf_len);
     581             : }
     582             : 
     583          44 : int FlowTableKSyncEntry::DeleteMsg(char *buf, int buf_len) {
     584          44 :     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         815 : bool FlowTableKSyncEntry::IsLess(const KSyncEntry &rhs) const {
     600         815 :     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         815 :     if (hash_id_ != entry.hash_id_) {
     609         683 :         return hash_id_ < entry.hash_id_;
     610             :     }
     611         132 :     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           3 : FlowTableKSyncObject::FlowTableKSyncObject(KSync *ksync) :
     684           3 :     KSyncObject("KSync FlowTable"), ksync_(ksync), free_list_(this),
     685           6 :     timer_(NULL) {
     686           3 : }
     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           6 : FlowTableKSyncObject::~FlowTableKSyncObject() {
     693           3 :     TimerManager::DeleteTimer(timer_);
     694           6 : }
     695             : 
     696          44 : KSyncEntry *FlowTableKSyncObject::Alloc(const KSyncEntry *key, uint32_t index) {
     697          44 :     const FlowTableKSyncEntry *entry  =
     698             :         static_cast<const FlowTableKSyncEntry *>(key);
     699          44 :     return free_list_.Allocate(entry);
     700             : }
     701             : 
     702          44 : void FlowTableKSyncObject::Free(KSyncEntry *entry) {
     703          44 :     FlowTableKSyncEntry *ksync  = static_cast<FlowTableKSyncEntry *>(entry);
     704          44 :     free_list_.Free(ksync);
     705          44 : }
     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          22 : void FlowTableKSyncObject::UpdateKey(KSyncEntry *entry, uint32_t flow_handle) {
     714          22 :     static_cast<FlowTableKSyncEntry *>(entry)->set_hash_id(flow_handle);
     715          22 : }
     716             : 
     717          22 : uint32_t FlowTableKSyncObject::GetKey(KSyncEntry *entry) {
     718          22 :     return static_cast<FlowTableKSyncEntry *>(entry)->hash_id();
     719             : }
     720             : 
     721          22 : void FlowTableKSyncObject::UpdateFlowHandle(FlowTableKSyncEntry *entry,
     722             :                                             uint32_t flow_handle) {
     723          22 :     ChangeKey(entry, flow_handle);
     724          22 : }
     725             : 
     726           0 : void FlowTableKSyncObject::Init() {
     727           0 : }
     728             : 
     729             : /////////////////////////////////////////////////////////////////////////////
     730             : // KSyncFlowEntryFreeList implementation
     731             : /////////////////////////////////////////////////////////////////////////////
     732           3 : KSyncFlowEntryFreeList::KSyncFlowEntryFreeList(FlowTableKSyncObject *object) :
     733           3 :     object_(object), max_count_(0), grow_pending_(false), total_alloc_(0),
     734           3 :     total_free_(0), free_list_() {
     735             : 
     736           3 :     uint32_t count = kInitCount;
     737           3 :     if (object->ksync()->agent()->test_mode()) {
     738           3 :         count = kTestInitCount;
     739             :     }
     740       15003 :     while (max_count_ < count) {
     741       15000 :         free_list_.push_back(*new FlowTableKSyncEntry(object_));
     742       15000 :         max_count_++;
     743             :     }
     744           3 : }
     745             : 
     746           3 : KSyncFlowEntryFreeList::~KSyncFlowEntryFreeList() {
     747       15003 :     while (free_list_.empty() == false) {
     748       15000 :         FreeList::iterator it = free_list_.begin();
     749       15000 :         FlowTableKSyncEntry *flow = &(*it);
     750       30000 :         free_list_.erase(it);
     751       15000 :         delete flow;
     752             :     }
     753           3 : }
     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          44 : FlowTableKSyncEntry *KSyncFlowEntryFreeList::Allocate(const KSyncEntry *key) {
     768          44 :     const FlowTableKSyncEntry *flow_key  =
     769             :         static_cast<const FlowTableKSyncEntry *>(key);
     770          44 :     FlowTableKSyncEntry *flow = NULL;
     771          44 :     if (free_list_.size() == 0) {
     772           0 :         flow = new FlowTableKSyncEntry(object_);
     773           0 :         max_count_++;
     774             :     } else {
     775          44 :         FreeList::iterator it = free_list_.begin();
     776          44 :         flow = &(*it);
     777          88 :         free_list_.erase(it);
     778             :     }
     779             : 
     780          44 :     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          44 :     flow->Reset(flow_key->flow_entry().get(), flow_key->hash_id());
     788          44 :     flow->set_evict_gen_id(flow_key->evict_gen_id_);
     789          44 :     total_alloc_++;
     790          44 :     return flow;
     791             : }
     792             : 
     793          44 : void KSyncFlowEntryFreeList::Free(FlowTableKSyncEntry *flow) {
     794          44 :     total_free_++;
     795          44 :     flow->Reset();
     796          44 :     if (free_list_.size() < kMaxThreshold)
     797          44 :         free_list_.push_back(*flow);
     798             :     else {
     799           0 :         delete flow;
     800           0 :         --max_count_;
     801             :     }
     802          44 : }
     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         144 : void FlowTableKSyncObject::NetlinkAck(KSyncEntry *entry,
     812             :                                       KSyncEntry::KSyncEvent event) {
     813         144 :     FlowProto *proto = ksync()->agent()->pkt()->get_flow_proto();
     814         144 :     const FlowTableKSyncEntry *flow_ksync_entry =
     815             :         static_cast<const FlowTableKSyncEntry *>(entry);
     816             :     const FlowKSyncResponseInfo *resp =
     817         144 :         flow_ksync_entry->ksync_response_info();
     818         144 :     proto->KSyncEventRequest(entry, event, resp->flow_handle_,
     819         144 :                              resp->gen_id_, resp->ksync_error_,
     820         144 :                              resp->evict_flow_bytes_, resp->evict_flow_packets_,
     821         144 :                              resp->evict_flow_oflow_,
     822             :                              flow_ksync_entry->get_transaction_id());
     823         144 : }
     824             : 
     825         144 : void FlowTableKSyncObject::GenerateKSyncEvent(FlowTableKSyncEntry *entry,
     826             :                                               KSyncEntry::KSyncEvent event) {
     827         144 :     KSyncObject::NetlinkAck(entry, event);
     828         144 : }

Generated by: LCOV version 1.14