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