LCOV - code coverage report
Current view: top level - vnsw/agent/pkt - flow_handler.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 85 95 89.5 %
Date: 2026-11-09 02:10:49 Functions: 3 3 100.0 %
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             : #include <base/address.h>
       6             : #include <base/address_util.h>
       7             : #include "pkt/proto.h"
       8             : #include "pkt/proto_handler.h"
       9             : #include "pkt/pkt_init.h"
      10             : #include "pkt/pkt_handler.h"
      11             : #include "pkt/flow_table.h"
      12             : #include "pkt/flow_proto.h"
      13             : #include "pkt/flow_handler.h"
      14             : 
      15             : SandeshTraceBufferPtr PktFlowTraceBuf(SandeshTraceBufferCreate("FlowHandler", 5000));
      16             : 
      17         136 : static const VmEntry *InterfaceToVm(const Interface *intf) {
      18         136 :     if (intf->type() != Interface::VM_INTERFACE)
      19           1 :         return NULL;
      20             : 
      21         135 :     const VmInterface *vm_port = static_cast<const VmInterface *>(intf);
      22         135 :     return vm_port->vm();
      23             : }
      24             : 
      25             : // Compute L2/L3 forwarding mode for pacekt.
      26             : // Forwarding mode is L3 if,
      27             : // - Packet uses L3 label
      28             : // - Packet uses L2 Label and DMAC hits a route with L2-Receive NH
      29             : // Else forwarding mode is L2
      30          75 : bool FlowHandler::IsL3ModeFlow() const {
      31             :     const Interface *intf =
      32          75 :         agent_->interface_table()->FindInterface(pkt_info_->agent_hdr.ifindex);
      33             :     // here return true/false does not make any difference as flow processing
      34             :     // will be aborted due to invalid interface in subsequent processing.
      35          75 :     if (intf == NULL) {
      36           0 :         return false;
      37             :     }
      38          75 :     if (intf->type() == Interface::INET) {
      39           1 :         return true;
      40             :     }
      41             : 
      42          74 :     if (intf->type() == Interface::VM_INTERFACE) {
      43          21 :         const VmInterface *vm_intf =
      44             :             static_cast<const VmInterface *>(intf);
      45          21 :         if (vm_intf == agent_->vhost_interface()) {
      46           0 :             return true;
      47             :         }
      48             :     }
      49             : 
      50          74 :     if (pkt_info_->l3_label) {
      51          42 :         return true;
      52             :     }
      53             : 
      54          32 :     VrfTable *table = static_cast<VrfTable *>(agent_->vrf_table());
      55          32 :     VrfEntry *vrf = table->FindVrfFromId(pkt_info_->agent_hdr.vrf);
      56          32 :     if (vrf == NULL) {
      57           0 :         return false;
      58             :     }
      59             :     BridgeAgentRouteTable *l2_table = static_cast<BridgeAgentRouteTable *>
      60          32 :         (vrf->GetBridgeRouteTable());
      61             :     AgentRoute *rt = static_cast<AgentRoute *>
      62          32 :         (l2_table->FindRouteNoLock(pkt_info_->dmac));
      63          32 :     if (rt == NULL) {
      64           8 :         return false;
      65             :     }
      66             : 
      67          24 :     const NextHop *nh = rt->GetActiveNextHop();
      68          24 :     if (nh == NULL) {
      69           0 :         return false;
      70             :     }
      71             : 
      72          24 :     if (nh->GetType() == NextHop::L2_RECEIVE) {
      73          13 :         return true;
      74             :     }
      75          11 :     return false;
      76             : }
      77             : 
      78         112 : bool FlowHandler::Run() {
      79         112 :     PktControlInfo in;
      80         112 :     PktControlInfo out;
      81         112 :     PktFlowInfo info(agent_, pkt_info_,
      82         112 :                      flow_proto_->GetTable(flow_table_index_));
      83         112 :     std::unique_ptr<FlowTaskMsg> ipc;
      84         112 :     bool allow_reentrant = true;
      85         112 :     if (pkt_info_->type == PktType::INVALID) {
      86          75 :         info.SetPktInfo(pkt_info_);
      87          75 :         info.l3_flow = IsL3ModeFlow();
      88          37 :     } else if (pkt_info_->type == PktType::MESSAGE) {
      89             :         // we don't allow reentrancy to different partition if it is
      90             :         // a reevaluation for an existing flow which will only exist
      91             :         // in this partition
      92          37 :         allow_reentrant = false;
      93          37 :         ipc = std::unique_ptr<FlowTaskMsg>(static_cast<FlowTaskMsg *>(pkt_info_->ipc));
      94          37 :         pkt_info_->ipc = NULL;
      95          37 :         FlowEntry *fe = ipc->fe_ptr.get();
      96             :         // take lock on flow entry before accessing it, since we need to read
      97             :         // forward flow only take lock only on forward flow
      98          37 :         std::scoped_lock lock1(fe->mutex());
      99          37 :         assert(flow_table_index_ == fe->flow_table()->table_index());
     100             : 
     101          37 :         if (fe->deleted() || fe->is_flags_set(FlowEntry::ShortFlow)) {
     102           0 :             return true;
     103             :         }
     104             : 
     105             :         // We dont support revaluation of linklocal flows
     106          37 :         if (fe->is_flags_set(FlowEntry::LinkLocalFlow)) {
     107           0 :             return true;
     108             :         }
     109             : 
     110          37 :         info.flow_entry = fe;
     111          37 :         pkt_info_->agent_hdr.cmd = AGENT_TRAP_FLOW_MISS;
     112          37 :         pkt_info_->agent_hdr.cmd_param = fe->flow_handle();
     113          37 :         pkt_info_->agent_hdr.ifindex = fe->data().if_index_info;
     114          37 :         pkt_info_->tunnel = fe->data().tunnel_info;
     115          37 :         pkt_info_->agent_hdr.nh = fe->key().nh;
     116          37 :         pkt_info_->agent_hdr.vrf = fe->data().vrf;
     117          37 :         pkt_info_->family =
     118          37 :             fe->key().src_addr.is_v4() ? Address::INET : Address::INET6;
     119          37 :         pkt_info_->smac = fe->data().smac;
     120          37 :         pkt_info_->dmac = fe->data().dmac;
     121          37 :         pkt_info_->ip_saddr = fe->key().src_addr;
     122          37 :         pkt_info_->ip_daddr = fe->key().dst_addr;
     123          37 :         pkt_info_->ip_proto = fe->key().protocol;
     124          37 :         pkt_info_->sport = fe->key().src_port;
     125          37 :         pkt_info_->dport = fe->key().dst_port;
     126          37 :         pkt_info_->tcp_ack = fe->is_flags_set(FlowEntry::TcpAckFlow);
     127          37 :         pkt_info_->vrf = fe->data().vrf;
     128          37 :         pkt_info_->ttl = fe->data().ttl;
     129          37 :         info.l3_flow = fe->l3_flow();
     130          37 :         info.out_component_nh_idx = fe->data().component_nh_idx;
     131          37 :     }
     132             : 
     133         112 :     if (info.Process(pkt_info_.get(), &in, &out) == false) {
     134          15 :         info.short_flow = true;
     135             :     }
     136             : 
     137             :     // Flows that change port-numbers are always processed in thread-0.
     138             :     // Identify flows that change port and enqueue to thread-0
     139         164 :     if (allow_reentrant && ((pkt_info_->sport != info.nat_sport) ||
     140          52 :                             (pkt_info_->dport != info.nat_dport))) {
     141          24 :         if ((info.nat_sport != 0 || info.nat_dport != 0)) {
     142           0 :             if (flow_table_index_ != FlowTable::kPortNatFlowTableInstance) {
     143             :                 // Enqueue flow evaluation to
     144             :                 // FlowTable::kPortNatFlowTableInstance instance.
     145           0 :                 flow_proto_->EnqueueReentrant
     146           0 :                     (pkt_info_, FlowTable::kPortNatFlowTableInstance);
     147           0 :                 return true;
     148             :             }
     149             :         }
     150             :     }
     151             : 
     152         179 :     if (in.intf_ && ((in.intf_->type() != Interface::VM_INTERFACE) &&
     153          67 :                      (in.intf_->type() != Interface::INET))) {
     154          66 :         in.intf_ = NULL;
     155             :     }
     156             : 
     157         112 :     if (in.intf_ && out.intf_) {
     158          25 :         info.local_flow = true;
     159             :     }
     160             : 
     161         112 :     if (in.intf_) {
     162          45 :         in.vm_ = InterfaceToVm(in.intf_);
     163             :     }
     164             : 
     165         112 :     if (out.intf_) {
     166          91 :         out.vm_ = InterfaceToVm(out.intf_);
     167             :     }
     168             : 
     169         112 :     info.Add(pkt_info_.get(), &in, &out);
     170         112 :     return true;
     171         112 : }

Generated by: LCOV version 1.14