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

Generated by: LCOV version 1.14