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 : }