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