Line data Source code
1 : /*
2 : * Copyright (c) 2015 Juniper Networks, Inc. All rights reserved.
3 : */
4 :
5 : #include <atomic>
6 : #include <vector>
7 : #include <bitset>
8 : #include <arpa/inet.h>
9 : #include <netinet/in.h>
10 : #include <base/os.h>
11 : #include <string>
12 :
13 : #include <boost/date_time/posix_time/posix_time.hpp>
14 : #include <boost/assign/list_of.hpp>
15 : #include <boost/unordered_map.hpp>
16 : #include <sandesh/sandesh_trace.h>
17 : #include <base/address_util.h>
18 : #include <pkt/flow_table.h>
19 : #include <vrouter/flow_stats/flow_stats_collector.h>
20 : #include <vrouter/ksync/ksync_init.h>
21 : #include <vrouter/ksync/ksync_flow_index_manager.h>
22 :
23 : #include <route/route.h>
24 : #include <cmn/agent_cmn.h>
25 : #include <oper/interface_common.h>
26 : #include <oper/nexthop.h>
27 : #include <oper/tunnel_nh.h>
28 :
29 : #include <init/agent_param.h>
30 : #include <cmn/agent_cmn.h>
31 : #include <cmn/agent_stats.h>
32 : #include <oper/route_common.h>
33 : #include <oper/vrf.h>
34 : #include <oper/vm.h>
35 : #include <oper/sg.h>
36 : #include <oper/qos_config.h>
37 : #include <oper/global_vrouter.h>
38 :
39 : #include <filter/packet_header.h>
40 : #include <filter/acl.h>
41 :
42 : #include <pkt/proto.h>
43 : #include <pkt/proto_handler.h>
44 : #include <pkt/pkt_handler.h>
45 : #include <pkt/flow_proto.h>
46 : #include <pkt/pkt_types.h>
47 : #include <pkt/pkt_sandesh_flow.h>
48 : #include <pkt/flow_mgmt/flow_entry_info.h>
49 : #include <pkt/flow_mgmt.h>
50 : #include <pkt/flow_event.h>
51 : #include <pkt/flow_entry.h>
52 : #include <uve/flow_uve_stats_request.h>
53 :
54 : using namespace boost::asio::ip;
55 : using boost::uuids::nil_uuid;
56 : const std::map<FlowEntry::FlowPolicyState, const char*>
57 : FlowEntry::FlowPolicyStateStr = boost::assign::map_list_of
58 : (NOT_EVALUATED, "00000000-0000-0000-0000-000000000000")
59 : (IMPLICIT_ALLOW, "00000000-0000-0000-0000-000000000001")
60 : (IMPLICIT_DENY, "00000000-0000-0000-0000-000000000002")
61 : (DEFAULT_GW_ICMP_OR_DNS, "00000000-0000-0000-0000-000000000003")
62 : (LINKLOCAL_FLOW, "00000000-0000-0000-0000-000000000004")
63 : (MULTICAST_FLOW, "00000000-0000-0000-0000-000000000005")
64 : (NON_IP_FLOW, "00000000-0000-0000-0000-000000000006")
65 : (BGPROUTERSERVICE_FLOW, "00000000-0000-0000-0000-000000000007");
66 :
67 : const std::map<uint16_t, const char*>
68 : FlowEntry::FlowDropReasonStr = boost::assign::map_list_of
69 : ((uint16_t)DROP_UNKNOWN, "UNKNOWN")
70 : ((uint16_t)SHORT_UNAVIALABLE_INTERFACE,
71 : "Short flow Interface unavialable")
72 : ((uint16_t)SHORT_IPV4_FWD_DIS, "Short flow Ipv4 forwarding disabled")
73 : ((uint16_t)SHORT_UNAVIALABLE_VRF,
74 : "Short flow VRF unavailable")
75 : ((uint16_t)SHORT_NO_SRC_ROUTE, "Short flow No Source route")
76 : ((uint16_t)SHORT_NO_DST_ROUTE, "Short flow No Destination route")
77 : ((uint16_t)SHORT_AUDIT_ENTRY, "Short flow Audit Entry")
78 : ((uint16_t)SHORT_VRF_CHANGE, "Short flow VRF CHANGE")
79 : ((uint16_t)SHORT_NO_REVERSE_FLOW, "Short flow No Reverse flow")
80 : ((uint16_t)SHORT_REVERSE_FLOW_CHANGE,
81 : "Short flow Reverse flow change")
82 : ((uint16_t)SHORT_NAT_CHANGE, "Short flow NAT Changed")
83 : ((uint16_t)SHORT_FLOW_LIMIT, "Short flow Flow Limit Reached")
84 : ((uint16_t)SHORT_LINKLOCAL_SRC_NAT,
85 : "Short flow Linklocal source NAT failed")
86 : ((uint16_t)SHORT_FAILED_VROUTER_INSTALL,
87 : "Short flow vrouter install failed")
88 : ((uint16_t)SHORT_INVALID_L2_FLOW, "Short flow invalid L2 flow")
89 : ((uint16_t)SHORT_FLOW_ON_TSN, "Short flow TSN flow")
90 : ((uint16_t)SHORT_NO_MIRROR_ENTRY, "Short flow No mirror entry ")
91 : ((uint16_t)SHORT_SAME_FLOW_RFLOW_KEY,"Short flow same flow and rflow")
92 : ((uint16_t)DROP_POLICY, "Flow drop Policy")
93 : ((uint16_t)DROP_OUT_POLICY, "Flow drop Out Policy")
94 : ((uint16_t)DROP_SG, "Flow drop SG")
95 : ((uint16_t)DROP_OUT_SG, "Flow drop OUT SG")
96 : ((uint16_t)DROP_REVERSE_SG, "Flow drop REVERSE SG")
97 : ((uint16_t)DROP_REVERSE_OUT_SG, "Flow drop REVERSE OUT SG")
98 : ((uint16_t)DROP_FIREWALL_POLICY, "Flow drop Firewall Policy")
99 : ((uint16_t)DROP_OUT_FIREWALL_POLICY, "Flow drop OUT Firewall Policy")
100 : ((uint16_t)DROP_REVERSE_FIREWALL_POLICY, "Flow drop REVERSE Firewall Policy")
101 : ((uint16_t)DROP_REVERSE_OUT_FIREWALL_POLICY, "Flow drop REVERSE OUT Firewall Policy")
102 : ((uint16_t)SHORT_NO_SRC_ROUTE_L2RPF, "Short flow No Source route for RPF NH")
103 : ((uint16_t)SHORT_FAT_FLOW_NAT_CONFLICT, "Short flow Conflicting config for NAT and FAT flow")
104 : ((uint16_t)DROP_FWAAS_POLICY, "Flow drop FWAAS Policy")
105 : ((uint16_t)DROP_FWAAS_OUT_POLICY, "Flow drop OUT FWAAS Policy")
106 : ((uint16_t)DROP_FWAAS_REVERSE_POLICY, "Flow drop REVERSE FWAAS Policy")
107 : ((uint16_t)DROP_FWAAS_REVERSE_OUT_POLICY, "Flow drop REVERSE OUT FWAAS Policy")
108 : ((uint16_t)SHORT_L3MH_PHY_INTF_DOWN, "Short flow l3mh compute physical interface flap");
109 :
110 : std::atomic<int> FlowEntry::alloc_count_;
111 : SecurityGroupList FlowEntry::default_sg_list_;
112 :
113 : /////////////////////////////////////////////////////////////////////////////
114 : // VmFlowRef
115 : /////////////////////////////////////////////////////////////////////////////
116 : const int VmFlowRef::kInvalidFd;
117 20000 : VmFlowRef::VmFlowRef() :
118 20000 : vm_(NULL), fd_(kInvalidFd), port_(0), flow_(NULL) {
119 20000 : }
120 :
121 0 : VmFlowRef::VmFlowRef(const VmFlowRef &rhs) {
122 :
123 0 : fd_ = VmFlowRef::kInvalidFd;
124 0 : port_ = 0;
125 0 : flow_ = NULL;
126 :
127 : // UPDATE on linklocal flows is not supported. So, fd_ should be invalid
128 0 : assert(fd_ == VmFlowRef::kInvalidFd);
129 0 : assert(rhs.fd_ == VmFlowRef::kInvalidFd);
130 0 : SetVm(rhs.vm_.get());
131 0 : }
132 :
133 20000 : VmFlowRef:: ~VmFlowRef() {
134 20000 : Reset(true);
135 20000 : }
136 :
137 188 : void VmFlowRef::Init(FlowEntry *flow) {
138 188 : flow_ = flow;
139 188 : }
140 :
141 100 : void VmFlowRef::operator=(const VmFlowRef &rhs) {
142 100 : assert(rhs.fd_ == VmFlowRef::kInvalidFd);
143 100 : assert(rhs.port_ == 0);
144 : // For linklocal flows, we should have called Move already. It would
145 : // reset vm_. Validate it
146 100 : if (fd_ != VmFlowRef::kInvalidFd)
147 0 : assert(rhs.vm_.get() == NULL);
148 100 : }
149 :
150 : // Move is called from Copy() routine when flow is evicted by vrouter and a
151 : // new flow-add is received by agent. Use the fd_ and port_ from new flow
152 : // since reverse flow will be setup based on these
153 0 : void VmFlowRef::Move(VmFlowRef *rhs) {
154 : // Release the old values
155 0 : Reset(false);
156 :
157 0 : fd_ = rhs->fd_;
158 0 : port_ = rhs->port_;
159 0 : SetVm(rhs->vm_.get());
160 :
161 : // Ownership for fd_ is transferred. Reset RHS fields
162 : // Reset VM first before resetting fd_
163 0 : rhs->SetVm(NULL);
164 0 : rhs->fd_ = VmFlowRef::kInvalidFd;
165 0 : rhs->port_ = 0;
166 0 : }
167 :
168 80476 : void VmFlowRef::Reset(bool reset_flow) {
169 80476 : FreeRef();
170 80476 : FreeFd();
171 80476 : vm_.reset(NULL);
172 80476 : if (reset_flow)
173 80376 : flow_ = NULL;
174 80476 : }
175 :
176 80612 : void VmFlowRef::FreeRef() {
177 80612 : if (vm_.get() == NULL)
178 80476 : return;
179 :
180 136 : vm_->update_flow_count(-1);
181 136 : if (fd_ != kInvalidFd) {
182 0 : vm_->update_linklocal_flow_count(-1);
183 : }
184 : }
185 :
186 80476 : void VmFlowRef::FreeFd() {
187 80476 : if (fd_ == kInvalidFd) {
188 80476 : assert(port_ == 0);
189 80476 : return;
190 : }
191 :
192 0 : FlowProto *proto = flow_->flow_table()->agent()->pkt()->get_flow_proto();
193 0 : proto->update_linklocal_flow_count(-1);
194 0 : flow_->flow_table()->DelLinkLocalFlowInfo(fd_);
195 0 : close(fd_);
196 :
197 0 : fd_ = kInvalidFd;
198 0 : port_ = 0;
199 : }
200 :
201 188 : void VmFlowRef::SetVm(const VmEntry *vm) {
202 188 : if (vm == vm_.get())
203 52 : return;
204 136 : FreeRef();
205 :
206 136 : vm_.reset(vm);
207 136 : if (vm == NULL)
208 0 : return;
209 :
210 : // update per-vm flow accounting
211 136 : vm->update_flow_count(1);
212 136 : if (fd_ != kInvalidFd) {
213 0 : vm_->update_linklocal_flow_count(1);
214 : }
215 :
216 136 : return;
217 : }
218 :
219 0 : bool VmFlowRef::AllocateFd(Agent *agent, uint8_t l3_proto) {
220 0 : if (fd_ != kInvalidFd)
221 0 : return true;
222 :
223 0 : port_ = 0;
224 : // Short flows are always dropped. Dont allocate FD for short flow
225 0 : if (flow_->IsShortFlow())
226 0 : return false;
227 :
228 0 : if (l3_proto == IPPROTO_TCP) {
229 0 : fd_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
230 0 : } else if (l3_proto == IPPROTO_UDP) {
231 0 : fd_ = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
232 : }
233 :
234 0 : if (fd_ == kInvalidFd) {
235 0 : return false;
236 : }
237 :
238 : // Update agent accounting info
239 0 : agent->pkt()->get_flow_proto()->update_linklocal_flow_count(1);
240 0 : flow_->flow_table()->AddLinkLocalFlowInfo(fd_, flow_->flow_handle(),
241 0 : flow_->key(), UTCTimestampUsec());
242 :
243 : // allow the socket to be reused upon close
244 0 : if (l3_proto == IPPROTO_TCP) {
245 0 : int optval = 1;
246 0 : setsockopt(fd_, SOL_SOCKET, SO_REUSEADDR,
247 : (const char*)&optval, sizeof(optval));
248 : }
249 :
250 : struct sockaddr_in address;
251 0 : memset(&address, 0, sizeof(address));
252 0 : address.sin_family = AF_INET;
253 0 : if (::bind(fd_, (struct sockaddr*) &address, sizeof(address)) < 0) {
254 0 : FreeFd();
255 0 : return false;
256 : }
257 :
258 : struct sockaddr_in bound_to;
259 0 : socklen_t len = sizeof(bound_to);
260 0 : if (getsockname(fd_, (struct sockaddr*) &bound_to, &len) < 0) {
261 0 : FreeFd();
262 0 : return false;
263 : }
264 :
265 0 : port_ = ntohs(bound_to.sin_port);
266 0 : return true;
267 : }
268 :
269 : /////////////////////////////////////////////////////////////////////////////
270 : // FlowData constructor/destructor
271 : /////////////////////////////////////////////////////////////////////////////
272 10000 : FlowData::FlowData() {
273 10000 : Reset();
274 10000 : }
275 :
276 10000 : FlowData::~FlowData() {
277 10000 : }
278 :
279 30188 : void FlowData::Reset() {
280 30188 : smac = MacAddress();
281 30188 : dmac = MacAddress();
282 30188 : source_vn_list.clear();
283 30188 : source_vn_match = "";
284 30188 : dest_vn_match = "";
285 30188 : dest_vn_list.clear();
286 30188 : origin_vn_dst_list.clear();
287 30188 : origin_vn_src_list.clear();
288 30188 : origin_vn_src = "";
289 30188 : origin_vn_dst = "";
290 30188 : source_sg_id_l.clear();
291 30188 : dest_sg_id_l.clear();
292 30188 : flow_source_vrf = VrfEntry::kInvalidIndex;
293 30188 : flow_dest_vrf = VrfEntry::kInvalidIndex;
294 30188 : match_p.Reset();
295 30188 : vn_entry.reset(NULL);
296 30188 : intf_entry.reset(NULL);
297 30188 : in_vm_entry.Reset(true);
298 30188 : out_vm_entry.Reset(true);
299 30188 : src_ip_nh.reset(NULL);
300 30188 : vrf = VrfEntry::kInvalidIndex;
301 30188 : mirror_vrf = VrfEntry::kInvalidIndex;
302 30188 : dest_vrf = 0;
303 30188 : component_nh_idx = (uint32_t)CompositeNH::kInvalidComponentNHIdx;
304 30188 : source_plen = 0;
305 30188 : dest_plen = 0;
306 30188 : drop_reason = 0;
307 30188 : vrf_assign_evaluated = false;
308 30188 : if_index_info = 0;
309 30188 : tunnel_info.Reset();
310 30188 : flow_source_plen_map.clear();
311 30188 : flow_dest_plen_map.clear();
312 30188 : enable_rpf = true;
313 30188 : rpf_nh.reset(NULL);
314 30188 : rpf_plen = Address::kMaxV4PrefixLen;
315 30188 : rpf_vrf = VrfEntry::kInvalidIndex;
316 30188 : disable_validation = false;
317 30188 : vm_cfg_name = "";
318 30188 : bgp_as_a_service_sport = 0;
319 30188 : bgp_as_a_service_dport = 0;
320 30188 : acl_assigned_vrf_index_ = VrfEntry::kInvalidIndex;
321 30188 : qos_config_idx = AgentQosConfigTable::kInvalidIndex;
322 30188 : ttl = 0;
323 30188 : src_policy_vrf = VrfEntry::kInvalidIndex;
324 30188 : src_policy_plen = 0;
325 30188 : dst_policy_vrf = VrfEntry::kInvalidIndex;
326 30188 : dst_policy_plen = 0;
327 30188 : allocated_port_ = 0;
328 30188 : underlay_gw_index_ = -1;
329 30188 : }
330 :
331 148 : static std::vector<std::string> MakeList(const VnListType &ilist) {
332 148 : std::vector<std::string> olist;
333 148 : for (VnListType::const_iterator it = ilist.begin();
334 296 : it != ilist.end(); ++it) {
335 148 : olist.push_back(*it);
336 : }
337 148 : return olist;
338 0 : }
339 :
340 74 : std::vector<std::string> FlowData::SourceVnList() const {
341 74 : return MakeList(source_vn_list);
342 : }
343 :
344 74 : std::vector<std::string> FlowData::DestinationVnList() const {
345 74 : return MakeList(dest_vn_list);
346 : }
347 :
348 0 : std::vector<std::string> FlowData::OriginVnSrcList() const {
349 0 : return MakeList(origin_vn_src_list);
350 : }
351 :
352 0 : std::vector<std::string> FlowData::OriginVnDstList() const {
353 0 : return MakeList(origin_vn_dst_list);
354 : }
355 :
356 : /////////////////////////////////////////////////////////////////////////////
357 : // MatchPolicy constructor/destructor
358 : /////////////////////////////////////////////////////////////////////////////
359 10000 : MatchPolicy::MatchPolicy() {
360 10000 : Reset();
361 10000 : }
362 :
363 10000 : MatchPolicy::~MatchPolicy() {
364 10000 : }
365 :
366 40188 : void MatchPolicy::Reset() {
367 40188 : m_acl_l.clear();
368 40188 : policy_action = 0;
369 40188 : m_out_acl_l.clear();
370 40188 : out_policy_action = 0;
371 40188 : sg_policy.Reset();
372 40188 : m_mirror_acl_l.clear();
373 40188 : mirror_action = 0;
374 40188 : m_out_mirror_acl_l.clear();
375 40188 : out_mirror_action = 0;
376 40188 : m_vrf_assign_acl_l.clear();
377 40188 : vrf_assign_acl_action = 0;
378 40188 : aps_policy.Reset();
379 40188 : fwaas_policy.Reset();
380 40188 : action_info.Clear();
381 40188 : }
382 :
383 120564 : void SessionPolicy::Reset() {
384 120564 : m_out_acl_l.clear();
385 120564 : out_rule_present = false;
386 120564 : out_action = 0;
387 :
388 120564 : m_acl_l.clear();
389 120564 : rule_present = false;
390 120564 : action = 0;
391 :
392 120564 : m_reverse_acl_l.clear();
393 120564 : reverse_rule_present = false;
394 120564 : reverse_action = 0;
395 :
396 120564 : m_reverse_out_acl_l.clear();
397 120564 : reverse_out_rule_present = false;
398 120564 : reverse_out_action = 0;
399 :
400 120564 : action_summary = 0;
401 120564 : rule_uuid_ = FlowEntry::FlowPolicyStateStr.at(FlowEntry::NOT_EVALUATED);
402 120564 : acl_name_ = "";
403 120564 : }
404 :
405 300 : void SessionPolicy::ResetRuleMatchInfo() {
406 300 : rule_uuid_ = FlowEntry::FlowPolicyStateStr.at(FlowEntry::NOT_EVALUATED);
407 300 : acl_name_ = "";
408 300 : }
409 :
410 234 : void SessionPolicy::ResetAction() {
411 234 : out_action = 0;
412 234 : action = 0;
413 234 : reverse_action = 0;
414 234 : reverse_out_action = 0;
415 234 : action_summary = 0;
416 234 : }
417 :
418 300 : void SessionPolicy::ResetPolicy() {
419 300 : rule_present = false;
420 300 : m_acl_l.clear();
421 :
422 300 : out_rule_present = false;
423 300 : m_out_acl_l.clear();
424 :
425 300 : reverse_rule_present = false;
426 300 : m_reverse_acl_l.clear();
427 :
428 300 : reverse_out_rule_present = false;
429 300 : m_reverse_out_acl_l.clear();
430 300 : ResetRuleMatchInfo();
431 300 : }
432 :
433 : /////////////////////////////////////////////////////////////////////////////
434 : // FlowEventLog constructor/destructor
435 : /////////////////////////////////////////////////////////////////////////////
436 0 : FlowEventLog::FlowEventLog() : time_(0), event_(EVENT_MAXIMUM),
437 0 : flow_handle_(FlowEntry::kInvalidFlowHandle), flow_gen_id_(0),
438 0 : ksync_entry_(NULL), hash_id_(FlowEntry::kInvalidFlowHandle), gen_id_(0),
439 0 : vrouter_flow_handle_(FlowEntry::kInvalidFlowHandle), vrouter_gen_id_(0) {
440 0 : }
441 :
442 0 : FlowEventLog::~FlowEventLog() {
443 0 : }
444 :
445 : /////////////////////////////////////////////////////////////////////////////
446 : // FlowEntry constructor/destructor
447 : /////////////////////////////////////////////////////////////////////////////
448 10000 : FlowEntry::FlowEntry(FlowTable *flow_table) :
449 20000 : flow_table_(flow_table), flags_(0),
450 10000 : tunnel_type_(TunnelType::INVALID),
451 10000 : fip_vmi_(AgentKey::ADD_DEL_CHANGE, nil_uuid(), ""),
452 20000 : flow_mgmt_request_(NULL), flow_mgmt_info_() {
453 : // ksync entry is set to NULL only on constructor and on flow delete
454 : // it should not have any other explicit set to NULL
455 10000 : ksync_entry_ = NULL;
456 10000 : Reset();
457 10000 : alloc_count_++;
458 10000 : }
459 :
460 30000 : FlowEntry::~FlowEntry() {
461 10000 : assert(refcount_ == 0);
462 10000 : Reset();
463 10000 : alloc_count_--;
464 20000 : }
465 :
466 20188 : void FlowEntry::Reset() {
467 20188 : assert(ksync_entry_ == NULL);
468 20188 : uuid_ = flow_table_->rand_gen();
469 20188 : egress_uuid_ = flow_table_->rand_gen();
470 20188 : if (is_flags_set(FlowEntry::IngressDir)) {
471 : const VmInterface *vm_intf =
472 68 : dynamic_cast<const VmInterface *>(intf_entry());
473 68 : if (vm_intf) {
474 68 : vm_intf->update_flow_count(-2);
475 : }
476 : }
477 20188 : data_.Reset();
478 20188 : l3_flow_ = true;
479 20188 : gen_id_ = 0;
480 20188 : flow_handle_ = kInvalidFlowHandle;
481 20188 : reverse_flow_entry_ = NULL;
482 20188 : deleted_ = false;
483 20188 : flags_ = 0;
484 20188 : hbs_intf_ = FlowEntry::HBS_INTERFACE_INVALID;
485 20188 : short_flow_reason_ = SHORT_UNKNOWN;
486 20188 : peer_vrouter_ = "";
487 20188 : tunnel_type_ = TunnelType::INVALID;
488 20188 : on_tree_ = false;
489 20188 : fip_ = 0;
490 20188 : fip_vmi_ = VmInterfaceKey(AgentKey::ADD_DEL_CHANGE, nil_uuid(), "");
491 20188 : refcount_ = 0;
492 20188 : nw_ace_uuid_ = FlowPolicyStateStr.at(NOT_EVALUATED);
493 20188 : fsc_ = NULL;
494 20188 : trace_ = false;
495 20188 : event_logs_.reset();
496 20188 : event_log_index_ = 0;
497 20188 : last_event_ = FlowEvent::INVALID;
498 20188 : flow_retry_attempts_ = 0;
499 20188 : is_flow_on_unresolved_list = false;
500 20188 : pending_actions_.Reset();
501 20188 : assert(flow_mgmt_request_ == NULL);
502 20188 : assert(flow_mgmt_info_.get() == NULL);
503 20188 : transaction_id_ = 0;
504 20188 : }
505 :
506 94 : void FlowEntry::Reset(const FlowKey &k) {
507 94 : Reset();
508 94 : key_ = k;
509 94 : }
510 :
511 2 : void FlowEntry::Init() {
512 2 : alloc_count_ = 0;
513 2 : }
514 :
515 94 : FlowEntry *FlowEntry::Allocate(const FlowKey &key, FlowTable *flow_table) {
516 : // flow_table will be NULL for some UT cases
517 : FlowEntry *flow;
518 94 : if (flow_table == NULL) {
519 0 : flow = new FlowEntry(flow_table);
520 0 : flow->Reset(key);
521 : } else {
522 94 : flow = flow_table->free_list()->Allocate(key);
523 : }
524 :
525 94 : flow->data_.in_vm_entry.Init(flow);
526 94 : flow->data_.out_vm_entry.Init(flow);
527 94 : return flow;
528 : }
529 :
530 : // selectively copy fields from RHS
531 : // When flow is being updated, rhs will be new flow allocated in PktFlowInfo
532 50 : void FlowEntry::Copy(FlowEntry *rhs, bool update) {
533 50 : if (update) {
534 50 : rhs->data_.in_vm_entry.Reset(false);
535 50 : rhs->data_.out_vm_entry.Reset(false);
536 : } else {
537 : // The operator= below will call VmFlowRef operator=. In case of flow
538 : // eviction, we want to move ownership from rhs to lhs. However rhs is
539 : // const ref in operator so, invode Move API to transfer ownership
540 0 : data_.in_vm_entry.Move(&rhs->data_.in_vm_entry);
541 0 : data_.out_vm_entry.Move(&rhs->data_.out_vm_entry);
542 : }
543 50 : data_ = rhs->data_;
544 50 : flags_ = rhs->flags_;
545 50 : hbs_intf_ = rhs->hbs_intf_;
546 50 : short_flow_reason_ = rhs->short_flow_reason_;
547 50 : nw_ace_uuid_ = rhs->nw_ace_uuid_;
548 50 : peer_vrouter_ = rhs->peer_vrouter_;
549 50 : tunnel_type_ = rhs->tunnel_type_;
550 50 : fip_ = rhs->fip_;
551 50 : fip_vmi_ = rhs->fip_vmi_;
552 50 : last_event_ = rhs->last_event_;
553 50 : flow_retry_attempts_ = rhs->flow_retry_attempts_;
554 50 : trace_ = rhs->trace_;
555 50 : if (update == false) {
556 0 : gen_id_ = rhs->gen_id_;
557 0 : flow_handle_ = rhs->flow_handle_;
558 : /* Flow Entry is being re-used. Generate a new UUID for it. */
559 0 : uuid_ = flow_table_->rand_gen();
560 0 : egress_uuid_ = flow_table_->rand_gen();
561 : }
562 50 : }
563 :
564 : /////////////////////////////////////////////////////////////////////////////
565 : // Routines to initialize FlowEntry from PktControlInfo
566 : /////////////////////////////////////////////////////////////////////////////
567 2922 : void intrusive_ptr_add_ref(FlowEntry *fe) {
568 2922 : fe->refcount_++;
569 2924 : }
570 :
571 2917 : void intrusive_ptr_release(FlowEntry *fe) {
572 2917 : FlowTable *flow_table = fe->flow_table();
573 2915 : int prev = fe->refcount_.fetch_sub(1);
574 2915 : if (prev == 1) {
575 138 : if (fe->on_tree()) {
576 88 : if (flow_table->ConcurrencyCheck(flow_table->flow_task_id())
577 88 : == false) {
578 44 : FlowEntryPtr ref(fe);
579 44 : FlowProto *proto=flow_table->agent()->pkt()->get_flow_proto();
580 44 : proto->ForceEnqueueFreeFlowReference(ref);
581 44 : return;
582 44 : }
583 : FlowTable::FlowEntryMap::iterator it =
584 44 : flow_table->flow_entry_map_.find(fe->key());
585 44 : assert(it != flow_table->flow_entry_map_.end());
586 44 : flow_table->flow_entry_map_.erase(it);
587 44 : flow_table->agent()->stats()->decr_flow_count();
588 : }
589 94 : flow_table->free_list()->Free(fe);
590 : }
591 : }
592 :
593 : // Helper Functions
594 0 : static std::size_t HashCombine(std::size_t hash, uint64_t val) {
595 0 : boost::hash_combine(hash, val);
596 0 : return hash;
597 : }
598 :
599 0 : static std::size_t HashIp(std::size_t hash, const IpAddress &ip) {
600 0 : if (ip.is_v6()) {
601 : uint64_t val[2];
602 0 : Ip6AddressToU64Array(ip.to_v6(), val, 2);
603 0 : hash = HashCombine(hash, val[0]);
604 0 : hash = HashCombine(hash, val[1]);
605 0 : } else if (ip.is_v4()) {
606 0 : hash = HashCombine(hash, ip.to_v4().to_ulong());
607 : } else {
608 0 : assert(0);
609 : }
610 0 : return hash;
611 : }
612 94 : bool FlowEntry::InitFlowCmn(const PktFlowInfo *info, const PktControlInfo *ctrl,
613 : const PktControlInfo *rev_ctrl,
614 : FlowEntry *rflow) {
615 94 : reverse_flow_entry_ = rflow;
616 94 : reset_flags(FlowEntry::ReverseFlow);
617 94 : peer_vrouter_ = info->peer_vrouter;
618 94 : tunnel_type_ = info->tunnel_type;
619 :
620 94 : if (info->linklocal_flow) {
621 0 : set_flags(FlowEntry::LinkLocalFlow);
622 : } else {
623 94 : reset_flags(FlowEntry::LinkLocalFlow);
624 : }
625 94 : if (info->nat_done) {
626 0 : set_flags(FlowEntry::NatFlow);
627 : } else {
628 94 : reset_flags(FlowEntry::NatFlow);
629 : }
630 94 : if (info->short_flow) {
631 20 : set_flags(FlowEntry::ShortFlow);
632 20 : short_flow_reason_ = info->short_flow_reason;
633 : } else {
634 74 : reset_flags(FlowEntry::ShortFlow);
635 74 : short_flow_reason_ = SHORT_UNKNOWN;
636 : }
637 94 : if (info->local_flow) {
638 42 : set_flags(FlowEntry::LocalFlow);
639 : } else {
640 52 : reset_flags(FlowEntry::LocalFlow);
641 : }
642 :
643 94 : if (info->tcp_ack) {
644 0 : set_flags(FlowEntry::TcpAckFlow);
645 : } else {
646 94 : reset_flags(FlowEntry::TcpAckFlow);
647 : }
648 94 : if (info->bgp_router_service_flow) {
649 0 : set_flags(FlowEntry::BgpRouterService);
650 0 : data_.bgp_as_a_service_sport = info->nat_sport;
651 0 : data_.bgp_as_a_service_dport = info->nat_dport;
652 : } else {
653 94 : reset_flags(FlowEntry::BgpRouterService);
654 94 : data_.bgp_as_a_service_sport = 0;
655 94 : data_.bgp_as_a_service_dport = 0;
656 : }
657 :
658 94 : if (info->alias_ip_flow) {
659 0 : set_flags(FlowEntry::AliasIpFlow);
660 : } else {
661 94 : reset_flags(FlowEntry::AliasIpFlow);
662 : }
663 :
664 94 : if (info->underlay_flow) {
665 0 : set_flags(FlowEntry::FabricFlow);
666 : } else {
667 94 : reset_flags(FlowEntry::FabricFlow);
668 : }
669 :
670 94 : if (IsFabricControlFlow()) {
671 0 : set_flags(FlowEntry::FabricControlFlow);
672 : } else {
673 94 : reset_flags(FlowEntry::FabricControlFlow);
674 : }
675 :
676 94 : data_.intf_entry = ctrl->intf_ ? ctrl->intf_ : rev_ctrl->intf_;
677 94 : data_.vn_entry = ctrl->vn_ ? ctrl->vn_ : rev_ctrl->vn_;
678 94 : data_.in_vm_entry.SetVm(ctrl->vm_);
679 94 : data_.out_vm_entry.SetVm(rev_ctrl->vm_);
680 94 : l3_flow_ = info->l3_flow;
681 94 : data_.acl_assigned_vrf_index_ = VrfEntry::kInvalidIndex;
682 :
683 94 : return true;
684 : }
685 :
686 47 : void FlowEntry::InitFwdFlow(const PktFlowInfo *info, const PktInfo *pkt,
687 : const PktControlInfo *ctrl,
688 : const PktControlInfo *rev_ctrl,
689 : FlowEntry *rflow, Agent *agent) {
690 47 : gen_id_ = pkt->GetAgentHdr().cmd_param_5;
691 47 : flow_handle_ = pkt->GetAgentHdr().cmd_param;
692 47 : if (InitFlowCmn(info, ctrl, rev_ctrl, rflow) == false) {
693 0 : return;
694 : }
695 47 : if (info->linklocal_bind_local_port) {
696 0 : set_flags(FlowEntry::LinkLocalBindLocalSrcPort);
697 : } else {
698 47 : reset_flags(FlowEntry::LinkLocalBindLocalSrcPort);
699 : }
700 47 : uint32_t intf_in = pkt->GetAgentHdr().ifindex;
701 47 : data_.vm_cfg_name = InterfaceIdToVmCfgName(agent, intf_in);
702 :
703 47 : if (info->port_allocated) {
704 0 : data_.allocated_port_ = info->nat_sport;
705 : }
706 :
707 47 : if (info->ingress) {
708 27 : set_flags(FlowEntry::IngressDir);
709 : } else {
710 20 : reset_flags(FlowEntry::IngressDir);
711 : }
712 47 : data_.disable_validation = info->disable_validation;
713 47 : if (ctrl->rt_ != NULL) {
714 40 : RpfInit(ctrl->rt_, pkt->ip_saddr);
715 : }
716 47 : data_.ttl = info->ttl;
717 47 : if (info->bgp_router_service_flow) {
718 0 : if (info->ttl == 1) {
719 0 : data_.ttl = BGP_SERVICE_TTL_FWD_FLOW;
720 : }
721 : }
722 :
723 47 : data_.flow_source_vrf = info->flow_source_vrf;
724 47 : data_.flow_dest_vrf = info->flow_dest_vrf;
725 47 : data_.flow_source_plen_map = info->flow_source_plen_map;
726 47 : data_.flow_dest_plen_map = info->flow_dest_plen_map;
727 47 : data_.dest_vrf = info->dest_vrf;
728 47 : data_.vrf = pkt->vrf;
729 47 : data_.if_index_info = pkt->agent_hdr.ifindex;
730 47 : data_.tunnel_info = pkt->tunnel;
731 :
732 47 : if (info->ecmp) {
733 0 : set_flags(FlowEntry::EcmpFlow);
734 : } else {
735 47 : reset_flags(FlowEntry::EcmpFlow);
736 : }
737 :
738 47 : data_.component_nh_idx = info->out_component_nh_idx;
739 47 : reset_flags(FlowEntry::Trap);
740 47 : if (ctrl->rt_ && ctrl->rt_->is_multicast()) {
741 0 : set_flags(FlowEntry::Multicast);
742 : }
743 47 : if (rev_ctrl->rt_ && rev_ctrl->rt_->is_multicast()) {
744 0 : set_flags(FlowEntry::Multicast);
745 : }
746 :
747 47 : data_.src_policy_vrf = info->src_policy_vrf;
748 47 : data_.dst_policy_vrf = info->dst_policy_vrf;
749 :
750 47 : reset_flags(FlowEntry::UnknownUnicastFlood);
751 47 : if (info->flood_unknown_unicast) {
752 0 : set_flags(FlowEntry::UnknownUnicastFlood);
753 0 : if (info->ingress) {
754 0 : GetSourceRouteInfo(ctrl->rt_);
755 : } else {
756 0 : GetSourceRouteInfo(rev_ctrl->rt_);
757 : }
758 0 : data_.dest_vn_list = data_.source_vn_list;
759 : } else {
760 47 : GetSourceRouteInfo(ctrl->rt_);
761 47 : GetDestRouteInfo(rev_ctrl->rt_);
762 : }
763 :
764 47 : data_.smac = pkt->smac;
765 47 : data_.dmac = pkt->dmac;
766 :
767 47 : if (is_flags_set(FlowEntry::IngressDir)) {
768 : const VmInterface *vm_intf =
769 27 : dynamic_cast<const VmInterface *>(intf_entry());
770 27 : if (vm_intf) {
771 27 : vm_intf->update_flow_count(2);
772 : }
773 : }
774 :
775 47 : data_.underlay_gw_index_ = GetUnderlayGwIndex(intf_in,
776 47 : info->pkt->ip_saddr, info->pkt->ip_daddr,
777 47 : info->pkt->ip_proto, info->pkt->sport, info->pkt->dport);
778 : }
779 :
780 47 : void FlowEntry::InitRevFlow(const PktFlowInfo *info, const PktInfo *pkt,
781 : const PktControlInfo *ctrl,
782 : const PktControlInfo *rev_ctrl,
783 : FlowEntry *rflow, Agent *agent) {
784 : uint32_t intf_in;
785 47 : if (InitFlowCmn(info, ctrl, rev_ctrl, rflow) == false) {
786 0 : return;
787 : }
788 47 : set_flags(FlowEntry::ReverseFlow);
789 47 : if (ctrl->intf_) {
790 41 : intf_in = ctrl->intf_->id();
791 : } else {
792 6 : intf_in = Interface::kInvalidIndex;
793 : }
794 47 : data_.vm_cfg_name = InterfaceIdToVmCfgName(agent, intf_in);
795 :
796 : // Compute reverse flow fields
797 47 : reset_flags(FlowEntry::IngressDir);
798 47 : if (ctrl->intf_) {
799 41 : if (info->ComputeDirection(ctrl->intf_)) {
800 41 : set_flags(FlowEntry::IngressDir);
801 : } else {
802 0 : reset_flags(FlowEntry::IngressDir);
803 : }
804 : }
805 47 : data_.disable_validation = info->disable_validation;
806 47 : if (ctrl->rt_ != NULL) {
807 44 : RpfInit(ctrl->rt_, pkt->ip_daddr);
808 : }
809 :
810 47 : if (info->bgp_router_service_flow) {
811 0 : if ((info->ttl == 1)|| (info->ttl == BGP_SERVICE_TTL_FWD_FLOW)) {
812 0 : data_.ttl = BGP_SERVICE_TTL_REV_FLOW;
813 : }
814 : }
815 :
816 47 : data_.flow_source_vrf = info->flow_dest_vrf;
817 47 : data_.flow_dest_vrf = info->flow_source_vrf;
818 47 : data_.flow_source_plen_map = info->flow_dest_plen_map;
819 47 : data_.flow_dest_plen_map = info->flow_source_plen_map;
820 47 : data_.vrf = info->dest_vrf;
821 :
822 47 : if (!info->nat_done) {
823 47 : data_.dest_vrf = info->flow_source_vrf;
824 : } else {
825 0 : data_.dest_vrf = info->nat_dest_vrf;
826 : }
827 47 : if (info->ecmp) {
828 0 : set_flags(FlowEntry::EcmpFlow);
829 : } else {
830 47 : reset_flags(FlowEntry::EcmpFlow);
831 : }
832 47 : data_.component_nh_idx = CompositeNH::kInvalidComponentNHIdx;
833 :
834 47 : data_.src_policy_vrf = info->dst_policy_vrf;
835 47 : data_.dst_policy_vrf = info->src_policy_vrf;
836 :
837 47 : reset_flags(FlowEntry::UnknownUnicastFlood);
838 47 : if (info->flood_unknown_unicast) {
839 0 : set_flags(FlowEntry::UnknownUnicastFlood);
840 0 : if (info->ingress) {
841 0 : GetSourceRouteInfo(rev_ctrl->rt_);
842 : } else {
843 0 : GetSourceRouteInfo(ctrl->rt_);
844 : }
845 : //Set source VN and dest VN to be same
846 : //since flooding happens only for layer2 routes
847 : //SG id would be left empty, user who wants
848 : //unknown unicast to happen should modify the
849 : //SG to allow such traffic
850 0 : data_.dest_vn_list = data_.source_vn_list;
851 : } else {
852 47 : GetSourceRouteInfo(ctrl->rt_);
853 47 : GetDestRouteInfo(rev_ctrl->rt_);
854 : }
855 :
856 47 : data_.smac = pkt->dmac;
857 47 : data_.dmac = pkt->smac;
858 :
859 47 : if (is_flags_set(FlowEntry::IngressDir)) {
860 : const VmInterface *vm_intf =
861 41 : dynamic_cast<const VmInterface *>(intf_entry());
862 41 : if (vm_intf) {
863 41 : vm_intf->update_flow_count(2);
864 : }
865 : }
866 :
867 47 : data_.underlay_gw_index_ = GetUnderlayGwIndex(intf_in,
868 47 : info->pkt->ip_saddr, info->pkt->ip_daddr,
869 47 : info->pkt->ip_proto, info->pkt->sport, info->pkt->dport);
870 : }
871 :
872 0 : void FlowEntry::InitAuditFlow(uint32_t flow_idx, uint8_t gen_id) {
873 0 : gen_id_ = gen_id;
874 0 : flow_handle_ = flow_idx;
875 0 : set_flags(FlowEntry::ShortFlow);
876 0 : short_flow_reason_ = SHORT_AUDIT_ENTRY;
877 0 : data_.source_vn_list = FlowHandler::UnknownVnList();
878 0 : data_.dest_vn_list = FlowHandler::UnknownVnList();
879 0 : data_.origin_vn_src_list = FlowHandler::UnknownVnList();
880 0 : data_.origin_vn_dst_list = FlowHandler::UnknownVnList();
881 0 : data_.source_sg_id_l = default_sg_list();
882 0 : data_.dest_sg_id_l = default_sg_list();
883 0 : }
884 :
885 :
886 : // Fabric control flows are following,
887 : // - XMPP connection to control node
888 : // - SSH connection to vhost
889 : // - Ping to vhost
890 : // - Introspect to vhost
891 : // - Port-IPC connection to vhost
892 : // - Contrail-Status UVE
893 : // TODO : Review this
894 94 : bool FlowEntry::IsFabricControlFlow() const {
895 94 : Agent *agent = flow_table()->agent();
896 94 : if (agent->get_vhost_disable_policy()) {
897 0 : return false;
898 : }
899 :
900 94 : if (key_.dst_addr.is_v4() == false) {
901 0 : return false;
902 : }
903 :
904 94 : if (IsNatFlow()) {
905 0 : return false;
906 : }
907 :
908 94 : if (key_.protocol == IPPROTO_TCP) {
909 0 : if (key_.src_addr == agent->router_id()) {
910 0 : for (int i = 0; i < MAX_XMPP_SERVERS; i++) {
911 0 : if (key_.dst_addr.to_string() !=
912 0 : agent->controller_ifmap_xmpp_server(i))
913 0 : continue;
914 0 : if (key_.dst_port == agent->controller_ifmap_xmpp_port(i)) {
915 0 : return true;
916 : }
917 : }
918 :
919 0 : for (int i = 0; i < MAX_XMPP_SERVERS; i++) {
920 0 : if (key_.dst_addr.to_string() !=
921 0 : agent->dns_server(i))
922 0 : continue;
923 0 : if (key_.dst_port == ContrailPorts::DnsXmpp()) {
924 0 : return true;
925 : }
926 :
927 0 : if (key_.dst_port == agent->dns_server_port(i)) {
928 0 : return true;
929 : }
930 : }
931 :
932 0 : std::ostringstream collector;
933 0 : collector << key_.dst_addr.to_string() << ":" <<
934 0 : ContrailPorts::CollectorPort();
935 : std::vector<string>::const_iterator it =
936 0 : agent->GetCollectorlist().begin();
937 0 : for(; it != agent->GetCollectorlist().end(); it++) {
938 0 : if (collector.str() == *it) {
939 0 : return true;
940 : }
941 : }
942 :
943 0 : Ip4Address metadata_fabric_ip;
944 0 : uint16_t metadata_fabric_port = 0;
945 0 : IpAddress local_ip;
946 0 : uint16_t local_port = 0;
947 0 : std::string nova_hostname;
948 : agent->oper_db()->global_vrouter()->
949 0 : FindLinkLocalService(GlobalVrouter::kMetadataService,
950 : &local_ip, &local_port,
951 : &nova_hostname,
952 : &metadata_fabric_ip,
953 : &metadata_fabric_port);
954 0 : if (key_.dst_addr.to_v4() == metadata_fabric_ip &&
955 0 : key_.dst_port == metadata_fabric_port) {
956 0 : return true;
957 : }
958 0 : }
959 :
960 :
961 0 : if (key_.dst_addr == agent->router_id()) {
962 0 : return (key_.dst_port == 22);
963 : }
964 :
965 0 : if (key_.src_addr == agent->router_id()) {
966 0 : return (key_.src_port == 22);
967 : }
968 0 : return false;
969 : }
970 :
971 94 : if (key_.protocol == IPPROTO_ICMP) {
972 0 : return (key_.src_addr == agent->router_id() ||
973 0 : key_.dst_addr == agent->router_id());
974 : }
975 :
976 94 : return false;
977 : }
978 :
979 : /////////////////////////////////////////////////////////////////////////////
980 : // Utility routines
981 : /////////////////////////////////////////////////////////////////////////////
982 : // Find L2 Route for the MAC address.
983 78 : AgentRoute *FlowEntry::GetL2Route(const VrfEntry *vrf,
984 : const MacAddress &mac) {
985 : BridgeAgentRouteTable *table = static_cast<BridgeAgentRouteTable *>
986 78 : (vrf->GetBridgeRouteTable());
987 78 : return table->FindRouteNoLock(mac);
988 : }
989 :
990 154 : AgentRoute *FlowEntry::GetUcRoute(const VrfEntry *entry,
991 : const IpAddress &addr) {
992 154 : AgentRoute *rt = NULL;
993 154 : if (addr.is_v4()) {
994 154 : InetUnicastRouteEntry key(NULL, addr, 32, false);
995 154 : rt = entry->GetUcRoute(key);
996 154 : } else {
997 0 : InetUnicastRouteEntry key(NULL, addr, 128, false);
998 0 : rt = entry->GetUcRoute(key);
999 0 : }
1000 154 : if (rt != NULL && rt->IsRPFInvalid()) {
1001 7 : return NULL;
1002 : }
1003 147 : return rt;
1004 : }
1005 :
1006 9 : AgentRoute *FlowEntry::GetEvpnRoute(const VrfEntry *vrf,
1007 : const MacAddress &mac,
1008 : const IpAddress &ip,
1009 : uint32_t ethernet_tag) {
1010 : EvpnAgentRouteTable *table = static_cast<EvpnAgentRouteTable *>(
1011 9 : vrf->GetEvpnRouteTable());
1012 9 : return table->FindRouteNoLock(mac, ip,
1013 : EvpnAgentRouteTable::ComputeHostIpPlen(ip),
1014 9 : ethernet_tag);
1015 : }
1016 :
1017 0 : uint32_t FlowEntry::reverse_flow_fip() const {
1018 0 : FlowEntry *rflow = reverse_flow_entry_.get();
1019 0 : if (rflow) {
1020 0 : return rflow->fip();
1021 : }
1022 0 : return 0;
1023 : }
1024 :
1025 0 : VmInterfaceKey FlowEntry::reverse_flow_vmi() const {
1026 0 : FlowEntry *rflow = reverse_flow_entry_.get();
1027 0 : if (rflow) {
1028 0 : return rflow->fip_vmi();
1029 : }
1030 0 : return VmInterfaceKey(AgentKey::ADD_DEL_CHANGE, nil_uuid(), "");
1031 : }
1032 :
1033 0 : void FlowEntry::UpdateFipStatsInfo(uint32_t fip, uint32_t id, Agent *agent) {
1034 0 : fip_ = fip;
1035 0 : fip_vmi_ = InterfaceIdToKey(agent, id);
1036 0 : }
1037 :
1038 22 : void FlowEntry::set_flow_handle(uint32_t flow_handle, uint8_t gen_id) {
1039 22 : if (flow_handle_ != flow_handle) {
1040 22 : assert(flow_handle_ == kInvalidFlowHandle);
1041 22 : flow_handle_ = flow_handle;
1042 : }
1043 22 : gen_id_ = gen_id;
1044 22 : }
1045 :
1046 74 : const std::string& FlowEntry::acl_assigned_vrf() const {
1047 74 : return data_.match_p.action_info.vrf_translate_action_.vrf_name();
1048 : }
1049 :
1050 0 : void FlowEntry::set_acl_assigned_vrf_index() {
1051 0 : VrfKey vrf_key(data_.match_p.action_info.vrf_translate_action_.vrf_name());
1052 0 : const VrfEntry *vrf = static_cast<const VrfEntry *>(
1053 0 : flow_table()->agent()->vrf_table()->FindActiveEntry(&vrf_key));
1054 0 : if (vrf) {
1055 0 : data_.acl_assigned_vrf_index_ = vrf->vrf_id();
1056 0 : bool set_dest_vrf = true;
1057 0 : if (is_flags_set(FlowEntry::NatFlow) &&
1058 0 : reverse_flow_entry() &&
1059 0 : key().dst_addr != reverse_flow_entry()->key().src_addr) {
1060 : //Packet is getting DNATed, VRF assign ACL action
1061 : //is applied on floating-ip VN and the destination VRF should
1062 : //be retained as interface VRF
1063 0 : set_dest_vrf = false;
1064 : }
1065 :
1066 0 : if (set_dest_vrf) {
1067 0 : data_.dest_vrf = vrf->vrf_id();
1068 : }
1069 0 : return;
1070 : }
1071 0 : data_.acl_assigned_vrf_index_ = VrfEntry::kInvalidIndex;
1072 0 : }
1073 :
1074 0 : uint32_t FlowEntry::acl_assigned_vrf_index() const {
1075 0 : return data_.acl_assigned_vrf_index_;
1076 : }
1077 :
1078 94 : void FlowEntry::RevFlowDepInfo(RevFlowDepParams *params) {
1079 94 : params->sip_ = key().src_addr;
1080 94 : FlowEntry *rev_flow = reverse_flow_entry();
1081 94 : if (rev_flow) {
1082 94 : params->rev_uuid_ = rev_flow->uuid();
1083 94 : params->vm_cfg_name_ = rev_flow->data().vm_cfg_name;
1084 94 : params->sg_uuid_ = rev_flow->sg_rule_uuid();
1085 94 : params->rev_egress_uuid_ = rev_flow->egress_uuid();
1086 94 : params->nw_ace_uuid_ = rev_flow->nw_ace_uuid();
1087 94 : params->drop_reason_ = rev_flow->data().drop_reason;
1088 94 : params->action_info_ = rev_flow->data().match_p.action_info;
1089 94 : if (rev_flow->intf_entry()) {
1090 : const VmInterface *vmi =
1091 94 : dynamic_cast<const VmInterface *>(rev_flow->intf_entry());
1092 94 : if (vmi) {
1093 94 : params->vmi_uuid_ = UuidToString(vmi->vmi_cfg_uuid());
1094 : } else {
1095 0 : params->vmi_uuid_ = UuidToString(rev_flow->intf_entry()->
1096 0 : GetUuid());
1097 : }
1098 : }
1099 :
1100 94 : if (key().family != Address::INET) {
1101 0 : return;
1102 : }
1103 94 : if (is_flags_set(FlowEntry::NatFlow) &&
1104 94 : is_flags_set(FlowEntry::IngressDir)) {
1105 0 : const FlowKey *nat_key = &rev_flow->key();
1106 0 : if (key().src_addr != nat_key->dst_addr) {
1107 0 : params->sip_ = nat_key->dst_addr;
1108 : }
1109 : }
1110 : }
1111 : }
1112 :
1113 1180 : bool FlowEntry::ShouldDrop(uint32_t action) {
1114 1180 : if (action & TrafficAction::DROP_FLAGS)
1115 118 : return true;
1116 :
1117 1062 : if (action & TrafficAction::IMPLICIT_DENY_FLAGS)
1118 0 : return true;
1119 :
1120 1062 : return false;
1121 : }
1122 :
1123 : /////////////////////////////////////////////////////////////////////////////
1124 : // Flow RPF
1125 : //
1126 : // VRouter enforces RPF check based on RPF-NH programmed in the flow. The RPF
1127 : // NH can be of two types,
1128 : // - Unicast NH :
1129 : // In this case, VRouter matches with incoming interface/tunnel-src with
1130 : // RPF NH the flow
1131 : //
1132 : // - ECMP NH :
1133 : // In this case, VRouter picks an ECMP component-nh and matches with incoming
1134 : // interface/tunnel-src. The index for component-nh is got from reverse flow.
1135 : //
1136 : // RPF-NH cases
1137 : // ------------
1138 : // 1. Baremetals
1139 : // Agent is not aware of IP address assigned for baremetals. So, RPF check
1140 : // for baremetals is based on the L2-Route
1141 : //
1142 : // 2. Layer-2 Flows
1143 : // If agent know the Inet route for source-ip in packet, RPF is based on
1144 : // the Inet route for source-ip. There are some exceptions for this rule,
1145 : // - If Inet route for source-ip is ECMP, then RPF is based on layer-2 route
1146 : // - If Inet route for source-ip is not-host route, then RPF is based on
1147 : // layer-2 routes
1148 : //
1149 : // If packet is from BMS (egress flow), its possible that agent does not
1150 : // know IP address for BMS. In such case, RPF is based on L2-Route
1151 : //
1152 : // 3. Layer-3 Flows from VMI
1153 : // RPF check will be based on the InterfaceNH for VMI
1154 : //
1155 : // 4. Layer-3 Flows from Fabric with unicast-NH
1156 : // The unicast-nh is used as RPF-NH
1157 : //
1158 : // 5. Layer-3 Flows from Fabric with composite-NH
1159 : // VRouter picks NH from flow and the ecmp-index from reverse flow.
1160 : //
1161 : // The ecmp-index in reverse is computed based on route for dest-ip in
1162 : // VRF got post VRF translation if any
1163 : //
1164 : // Note, the RPF must be picked post VRF translation since order of members
1165 : // in Composite-NH may vary across VRF
1166 : //
1167 : // Route Tracking
1168 : // --------------
1169 : // Flow Management should track the route for ip1 in vrf4 to update RPF-NH
1170 : //
1171 : // RPF Computation
1172 : // ---------------
1173 : // RPF computation happens in two stages
1174 : // 1. FlowEntry creation (RpfInit):
1175 : // Called during FlowEntry init. Computes src_ip_nh for flow.
1176 : //
1177 : // For layer-2 flows, RPF-NH Is same as src_ip_nh
1178 : // For Non-ECMP layer-3 flows, RPF-NH is same as src_ip_nh
1179 : // For ECMP layer-3 flows, RPF-NH must be computed only after VRF
1180 : // translation is computed for reverse flow.
1181 : //
1182 : // 2. Post ACL processing (RpfUpdate):
1183 : // Post ACL processing, all VRF translation rules are identified.
1184 : // The RPF-NH is computed in this method.
1185 : /////////////////////////////////////////////////////////////////////////////
1186 : // Utility method to set rpf_vrf and rpf_plen fields
1187 137 : static void SetRpfFieldsInternal(FlowEntry *flow, const AgentRoute *rt) {
1188 : // If there is no route, we should track default route
1189 137 : if (rt == NULL) {
1190 0 : flow->data().rpf_vrf = flow->data().vrf;
1191 0 : flow->data().rpf_plen = 0;
1192 0 : return;
1193 : }
1194 :
1195 : const InetUnicastRouteEntry *inet_rt =
1196 137 : dynamic_cast<const InetUnicastRouteEntry *>(rt);
1197 137 : if (inet_rt) {
1198 73 : flow->data().rpf_vrf = inet_rt->vrf()->vrf_id();
1199 73 : flow->data().rpf_plen = inet_rt->prefix_length();
1200 73 : return;
1201 : }
1202 :
1203 64 : if (!flow->l3_flow()) {
1204 64 : flow->data().rpf_vrf = rt->vrf()->vrf_id();
1205 : /*
1206 : * For L2 flows also plen is found using GetUCRoute
1207 : * plen is stored in L2 route entry
1208 : * this changed to address CEM-27722
1209 : */
1210 : const BridgeRouteEntry *bridge_rt =
1211 64 : dynamic_cast<const BridgeRouteEntry *>(rt);
1212 64 : if (bridge_rt != NULL) {
1213 64 : BridgeRouteEntry *temp = const_cast<BridgeRouteEntry *>(bridge_rt);
1214 64 : flow->data().rpf_plen = temp->prefix_length();
1215 : }
1216 64 : return;
1217 : }
1218 : // Route is not INET. Dont track any route
1219 0 : flow->data().rpf_vrf = VrfEntry::kInvalidIndex;
1220 0 : flow->data().rpf_plen = 0;
1221 0 : return;
1222 : }
1223 :
1224 : // Utility method to set src_ip_nh fields
1225 137 : void FlowEntry::RpfSetSrcIpNhFields(const AgentRoute *rt,
1226 : const NextHop *src_ip_nh) {
1227 137 : data_.src_ip_nh.reset(src_ip_nh);
1228 137 : SetRpfFieldsInternal(this, rt);
1229 137 : return;
1230 : }
1231 :
1232 0 : void FlowEntry::RpfSetRpfNhFields(const NextHop *rpf_nh) {
1233 0 : data_.rpf_nh.reset(rpf_nh);
1234 0 : }
1235 :
1236 : // Utility method to set rpf_nh fields
1237 0 : void FlowEntry::RpfSetRpfNhFields(const AgentRoute *rt, const NextHop *rpf_nh) {
1238 0 : data_.rpf_nh.reset(rpf_nh);
1239 0 : SetRpfFieldsInternal(this, rt);
1240 0 : return;
1241 : }
1242 :
1243 : // This method is called when flow is initialized. The RPF-NH cannot be
1244 : // computed at this stage since we dont know if reverse flow has VRF
1245 : // translation or not.
1246 : // This method only sets src_ip_nh field
1247 : //
1248 : // In case of layer-3 flow "rt" is inet route for source-ip in source-vrf
1249 : // In case of layer-2 flow "rt" is l2 route for smac in source-vrf
1250 84 : void FlowEntry::RpfInit(const AgentRoute *rt, const IpAddress &sip) {
1251 : // Set src_ip_nh based on rt first
1252 84 : RpfSetSrcIpNhFields(rt, rt->GetActiveNextHop());
1253 :
1254 : // RPF enabled?
1255 84 : bool rpf_enable = true;
1256 84 : if (data_.vn_entry && data_.vn_entry->enable_rpf() == false)
1257 0 : rpf_enable = false;
1258 84 : if (data_.disable_validation)
1259 0 : rpf_enable = false;
1260 :
1261 : // The src_ip_nh can change below only for l2 flows
1262 : // For l3-flow, rt will already be a INET route
1263 84 : if (l3_flow())
1264 20 : return;
1265 :
1266 : // For layer-2 flows, we use l2-route for RPF in following cases
1267 : // 1. Interface is of type BAREMETAL (ToR/TSN only)
1268 : //
1269 : // 2. ECMP is not supported for l2-flows. If src-ip lookup resulted in
1270 : // ECMP-NH fallback to the original l2-route
1271 : //
1272 : // 3. In case of OVS, ToR will export layer-2 route and MX will export a
1273 : // layer-3 subnet route covering all the ToRs. In this case, when ToR
1274 : // send layer-2 packet the layer-3 route will point to MX and RPF fails.
1275 : // Assuming MX only gives subnet-route, use inet-route only if its
1276 : // host-route
1277 : // 4. Its an egress flow and there is no route for IP address
1278 : const VmInterface *vmi =
1279 64 : dynamic_cast<const VmInterface *>(intf_entry());
1280 64 : if (vmi && vmi->vmi_type() == VmInterface::BAREMETAL) {
1281 3 : return;
1282 : }
1283 :
1284 61 : VrfEntry *vrf = rt->vrf();
1285 : const InetUnicastRouteEntry *src_ip_rt =
1286 : static_cast<InetUnicastRouteEntry *>
1287 61 : (FlowEntry::GetUcRoute(vrf, sip));
1288 :
1289 61 : if (src_ip_rt == NULL) {
1290 : // For egress flow, with no l3-route then do rpf based on l2-route
1291 : // For ingress flow, with no l3-route, make it short flow
1292 6 : if (rpf_enable && IsIngressFlow()) {
1293 2 : set_flags(FlowEntry::ShortFlow);
1294 2 : short_flow_reason_ = SHORT_NO_SRC_ROUTE_L2RPF;
1295 : }
1296 6 : return;
1297 : }
1298 :
1299 55 : if (src_ip_rt->IsHostRoute() == false)
1300 0 : return;
1301 :
1302 55 : const NextHop *src_ip_nh = src_ip_rt->GetActiveNextHop();
1303 55 : if ((src_ip_nh != NULL) && src_ip_nh->GetType() == NextHop::COMPOSITE)
1304 2 : return;
1305 :
1306 53 : RpfSetSrcIpNhFields(src_ip_rt, src_ip_nh);
1307 53 : return;
1308 : }
1309 :
1310 : // Should src_ip_nh be treated as RPF-NH
1311 100 : bool FlowEntry::RpfFromSrcIpNh() const {
1312 : // For l2-flows, src_ip_nh is same as RPF-NH
1313 100 : if (l3_flow() == false)
1314 78 : return true;
1315 :
1316 : // Dont bother about RPF for short-flows
1317 22 : if (is_flags_set(FlowEntry::ShortFlow))
1318 4 : return true;
1319 :
1320 : // rpf-nh can change only in case of composite
1321 18 : if (data_.src_ip_nh->GetType() != NextHop::COMPOSITE)
1322 18 : return true;
1323 :
1324 0 : const FlowEntry *rflow = reverse_flow_entry();
1325 0 : if (rflow == NULL) {
1326 0 : FlowInfo flow_info;
1327 0 : FillFlowInfo(flow_info);
1328 0 : FLOW_TRACE(Trace, "Invalid reverse flow for setting ECMP index",
1329 : flow_info);
1330 0 : return true;
1331 0 : }
1332 :
1333 0 : return false;
1334 : }
1335 :
1336 0 : void FlowEntry::RpfComputeIngress() {
1337 0 : const NextHop *nh = NULL;
1338 : // If we are here, its guaranteed that src_ip_nh is composite
1339 : const CompositeNH *cnh =
1340 0 : dynamic_cast<const CompositeNH *>(data_.src_ip_nh.get());
1341 0 : assert(cnh != NULL);
1342 :
1343 : // Use flow_key_nh if VMI is part of composite. Else its guaranteed
1344 : // that RPF will fail for flow. So, use discard-nh for RPF
1345 : const VmInterface *vmi =
1346 0 : dynamic_cast<const VmInterface *>(intf_entry());
1347 0 : if (cnh->HasVmInterface(vmi)) {
1348 0 : nh = vmi->flow_key_nh();
1349 : } else {
1350 0 : nh = data_.src_ip_nh.get();
1351 : }
1352 :
1353 : // Change only the RPF-NH. The vrf and plen dont change here
1354 0 : RpfSetRpfNhFields(nh);
1355 0 : return;
1356 : }
1357 :
1358 0 : void FlowEntry::RpfComputeEgress() {
1359 0 : const FlowEntry *rflow = reverse_flow_entry();
1360 :
1361 : // RPF-NH can change only if VRF in forward flow and translated VRF in
1362 : // reverse flow are different
1363 0 : if (rflow->data().flow_dest_vrf == data_.vrf) {
1364 0 : RpfSetRpfNhFields(data_.src_ip_nh.get());
1365 0 : return;
1366 : }
1367 :
1368 : // Find destination VRF from reverse flow
1369 0 : const VrfEntry *vrf = rflow->GetDestinationVrf();
1370 0 : if (vrf == NULL) {
1371 0 : FlowInfo flow_info;
1372 0 : FillFlowInfo(flow_info);
1373 0 : FLOW_TRACE(Trace, "Error setting RPF NH. Destination VRF not found "
1374 : "in reverse flow", flow_info);
1375 0 : return;
1376 0 : }
1377 :
1378 : InetUnicastRouteEntry *rt = static_cast<InetUnicastRouteEntry *>
1379 0 : (FlowEntry::GetUcRoute(vrf, key().src_addr));
1380 0 : if (!rt) {
1381 0 : FlowInfo flow_info;
1382 0 : FillFlowInfo(flow_info);
1383 0 : FLOW_TRACE(Trace, "Error setting RPF NH. Route not found in "
1384 : "destination vrf", flow_info);
1385 0 : return;
1386 0 : }
1387 :
1388 0 : RpfSetRpfNhFields(rt, rt->GetActiveNextHop());
1389 0 : return;
1390 : }
1391 :
1392 : // Computes RPF-NH for flow based on ip_src_nh
1393 : // Must be called after policy lookup is done
1394 100 : void FlowEntry::RpfUpdate() {
1395 : // Is RPF check enabled?
1396 100 : data_.enable_rpf = true;
1397 100 : if (data_.vn_entry) {
1398 100 : data_.enable_rpf = data_.vn_entry->enable_rpf();
1399 : }
1400 :
1401 100 : if (data_.disable_validation) {
1402 0 : data_.enable_rpf = false;
1403 : }
1404 :
1405 100 : if (data_.enable_rpf == false) {
1406 0 : data_.rpf_nh = NULL;
1407 0 : return;
1408 : }
1409 :
1410 100 : if (RpfFromSrcIpNh()) {
1411 100 : data_.rpf_nh = data_.src_ip_nh;
1412 100 : return;
1413 : }
1414 :
1415 0 : if (is_flags_set(FlowEntry::IngressDir)) {
1416 0 : RpfComputeIngress();
1417 : } else {
1418 0 : RpfComputeEgress();
1419 : }
1420 : }
1421 :
1422 100 : bool FlowEntry::IsClientFlow() {
1423 : /*
1424 : * If the flow is Local + Ingress + Forward
1425 : * then it will be considered as client session
1426 : */
1427 142 : if ((is_flags_set(FlowEntry::LocalFlow)) &&
1428 142 : (is_flags_set(FlowEntry::IngressDir)) &&
1429 142 : (!(is_flags_set(FlowEntry::ReverseFlow)))) {
1430 21 : return true;
1431 : }
1432 : /*
1433 : * If the flow is (Ingress + Forward) OR
1434 : * (Egress + Reverse)
1435 : * then it will be consideres as client session
1436 : */
1437 79 : if (is_flags_set(FlowEntry::IngressDir)) {
1438 33 : if (!(is_flags_set(FlowEntry::ReverseFlow))) {
1439 12 : return true;
1440 : }
1441 : } else {
1442 46 : if (is_flags_set(FlowEntry::ReverseFlow)) {
1443 0 : return true;
1444 : }
1445 : }
1446 67 : return false;
1447 : }
1448 :
1449 67 : bool FlowEntry::IsServerFlow() {
1450 : /*
1451 : * If the flow is Local + Ingress + Reverse
1452 : * then it will be considered as server session
1453 : */
1454 88 : if ((is_flags_set(FlowEntry::LocalFlow)) &&
1455 88 : (is_flags_set(FlowEntry::IngressDir)) &&
1456 88 : (is_flags_set(FlowEntry::ReverseFlow))) {
1457 21 : return true;
1458 : }
1459 : /*
1460 : * If the flow is (Egress + Forward) OR
1461 : * (Ingress + Reverse)
1462 : * then it will be consideres as server session
1463 : */
1464 46 : if (!(is_flags_set(FlowEntry::IngressDir))) {
1465 46 : if (!(is_flags_set(FlowEntry::ReverseFlow))) {
1466 46 : return true;
1467 : }
1468 : } else {
1469 0 : if (is_flags_set(FlowEntry::ReverseFlow)) {
1470 0 : return true;
1471 : }
1472 : }
1473 0 : return false;
1474 : }
1475 : /////////////////////////////////////////////////////////////////////////////
1476 : // Flow entry fileds updation routines
1477 : /////////////////////////////////////////////////////////////////////////////
1478 162 : std::string FlowEntry::DropReasonStr(uint16_t reason) {
1479 : std::map<uint16_t, const char*>::const_iterator it =
1480 162 : FlowDropReasonStr.find(reason);
1481 162 : if (it != FlowDropReasonStr.end()) {
1482 162 : return string(it->second);
1483 : }
1484 0 : return "UNKNOWN";
1485 : }
1486 :
1487 : // Get src-vn/sg-id/plen from route
1488 : // src-vn and sg-id are used for policy lookup
1489 : // plen is used to track the routes to use by flow_mgmt module
1490 100 : void FlowEntry::GetSourceRouteInfo(const AgentRoute *rt) {
1491 100 : Agent *agent = flow_table()->agent();
1492 : const InetUnicastRouteEntry *inet_rt =
1493 100 : dynamic_cast<const InetUnicastRouteEntry *>(rt);
1494 :
1495 100 : if (inet_rt && is_flags_set(FlowEntry::FabricFlow)) {
1496 : const VrfEntry *policy_vrf =
1497 : static_cast<const VrfEntry *>(agent->
1498 0 : vrf_table()->FindVrfFromId(data_.src_policy_vrf));
1499 :
1500 : //Policy lookup needs to happen in Policy VRF
1501 0 : AgentRoute *new_rt = GetUcRoute(policy_vrf,
1502 0 : inet_rt->prefix_address());
1503 0 : data_.src_policy_plen = 0;
1504 0 : if (new_rt) {
1505 0 : rt = new_rt;
1506 0 : inet_rt = dynamic_cast<const InetUnicastRouteEntry *>(new_rt);
1507 0 : data_.src_policy_plen = inet_rt->prefix_length();
1508 0 : data_.src_policy_vrf = inet_rt->vrf()->vrf_id();
1509 : }
1510 : }
1511 :
1512 100 : const AgentPath *path = NULL;
1513 100 : if (rt) {
1514 90 : path = rt->GetActivePath();
1515 : }
1516 100 : if (path == NULL) {
1517 10 : data_.source_vn_list = FlowHandler::UnknownVnList();
1518 10 : data_.source_vn_match = FlowHandler::UnknownVn();
1519 10 : data_.source_sg_id_l = default_sg_list();
1520 10 : data_.source_plen = 0;
1521 10 : data_.origin_vn_src_list = FlowHandler::UnknownVnList();
1522 10 : data_.origin_vn_src = FlowHandler::UnknownVn();
1523 : } else {
1524 90 : data_.source_vn_list = path->dest_vn_list();
1525 90 : if (path->dest_vn_list().size())
1526 90 : data_.source_vn_match = *path->dest_vn_list().begin();
1527 90 : data_.origin_vn_src = path->origin_vn();
1528 90 : if (!path->origin_vn().empty()) {
1529 0 : data_.origin_vn_src_list.insert(path->origin_vn());
1530 : }
1531 90 : data_.source_sg_id_l = path->sg_list();
1532 90 : data_.source_plen = rt->prefix_length();
1533 90 : data_.source_tag_id_l = path->tag_list();
1534 : }
1535 : /* Handle case when default route NextHop points to vrf */
1536 100 : if (rt) {
1537 90 : const NextHop *anh = rt->GetActiveNextHop();
1538 90 : if (anh && anh->GetType() == NextHop::VRF) {
1539 0 : const VrfNH *nh =
1540 : static_cast<const VrfNH *>(anh);
1541 0 : AgentRoute *new_rt = GetUcRoute(nh->GetVrf(), key_.src_addr);
1542 0 : if (new_rt) {
1543 0 : path = new_rt->GetActivePath();
1544 0 : if (path) {
1545 0 : data_.origin_vn_src = path->origin_vn();
1546 0 : if (!path->origin_vn().empty()) {
1547 0 : data_.origin_vn_src_list.insert(path->origin_vn());
1548 : }
1549 : }
1550 : }
1551 : }
1552 : }
1553 :
1554 100 : }
1555 :
1556 : // Get dst-vn/sg-id/plen from route
1557 : // dst-vn and sg-id are used for policy lookup
1558 : // plen is used to track the routes to use by flow_mgmt module
1559 100 : void FlowEntry::GetDestRouteInfo(const AgentRoute *rt) {
1560 100 : Agent *agent = flow_table()->agent();
1561 100 : const AgentPath *path = NULL;
1562 100 : if (rt) {
1563 90 : path = rt->GetActivePath();
1564 : }
1565 :
1566 : const InetUnicastRouteEntry *inet_rt =
1567 100 : dynamic_cast<const InetUnicastRouteEntry *>(rt);
1568 100 : if (inet_rt && is_flags_set(FlowEntry::FabricFlow)) {
1569 0 : data_.dst_policy_plen = 0;
1570 : const VrfEntry *policy_vrf =
1571 : static_cast<const VrfEntry *>(agent->
1572 0 : vrf_table()->FindVrfFromId(data_.dst_policy_vrf));
1573 :
1574 : AgentRoute *new_rt =
1575 0 : GetUcRoute(policy_vrf, inet_rt->prefix_address());
1576 0 : if (new_rt) {
1577 0 : rt = new_rt;
1578 0 : inet_rt = dynamic_cast<const InetUnicastRouteEntry *>(rt);
1579 0 : data_.dst_policy_plen = inet_rt->prefix_length();
1580 0 : data_.dst_policy_vrf = inet_rt->vrf()->vrf_id();
1581 : }
1582 : }
1583 :
1584 100 : if (rt) {
1585 90 : path = rt->GetActivePath();
1586 : }
1587 :
1588 100 : if (path == NULL) {
1589 10 : data_.dest_vn_list = FlowHandler::UnknownVnList();
1590 10 : data_.dest_vn_match = FlowHandler::UnknownVn();
1591 10 : data_.dest_sg_id_l = default_sg_list();
1592 10 : data_.dest_plen = 0;
1593 10 : data_.origin_vn_dst_list = FlowHandler::UnknownVnList();
1594 10 : data_.origin_vn_dst = FlowHandler::UnknownVn();
1595 : } else {
1596 90 : data_.dest_vn_list = path->dest_vn_list();
1597 90 : if (path->dest_vn_list().size())
1598 90 : data_.dest_vn_match = *path->dest_vn_list().begin();
1599 90 : data_.origin_vn_dst = path->origin_vn();
1600 90 : if (!path->origin_vn().empty()) {
1601 0 : data_.origin_vn_dst_list.insert(path->origin_vn());
1602 : }
1603 90 : data_.dest_sg_id_l = path->sg_list();
1604 90 : data_.dest_plen = rt->prefix_length();
1605 90 : data_.dest_tag_id_l = path->tag_list();
1606 : }
1607 :
1608 : /* Handle case when default route NextHop points to vrf */
1609 100 : if (rt) {
1610 90 : const NextHop *anh = rt->GetActiveNextHop();
1611 90 : if (anh && anh->GetType() == NextHop::VRF) {
1612 0 : const VrfNH *nh =
1613 : static_cast<const VrfNH *>(anh);
1614 0 : AgentRoute *new_rt = GetUcRoute(nh->GetVrf(), key_.dst_addr);
1615 0 : if (new_rt) {
1616 0 : path = new_rt->GetActivePath();
1617 0 : if (path) {
1618 0 : data_.origin_vn_dst = path->origin_vn();
1619 0 : if (!path->origin_vn().empty()) {
1620 0 : data_.origin_vn_dst_list.insert(path->origin_vn());
1621 : }
1622 : }
1623 : }
1624 : }
1625 : }
1626 100 : }
1627 :
1628 0 : VmInterfaceKey FlowEntry::InterfaceIdToKey(Agent *agent, uint32_t id) {
1629 0 : if (id != Interface::kInvalidIndex) {
1630 0 : Interface *itf = agent->interface_table()->FindInterface(id);
1631 0 : if (itf && (itf->type() == Interface::VM_INTERFACE)) {
1632 : return VmInterfaceKey(AgentKey::ADD_DEL_CHANGE, itf->GetUuid(),
1633 0 : itf->name());
1634 : }
1635 : }
1636 0 : return VmInterfaceKey(AgentKey::ADD_DEL_CHANGE, nil_uuid(), "");
1637 : }
1638 :
1639 0 : uint32_t FlowEntry::InterfaceKeyToId(Agent *agent, const VmInterfaceKey &key) {
1640 0 : const Interface *intf = dynamic_cast<const Interface*>
1641 0 : (agent->interface_table()->FindActiveEntry(&key));
1642 0 : if (intf) {
1643 0 : return intf->id();
1644 : }
1645 0 : return Interface::kInvalidIndex;
1646 : }
1647 :
1648 94 : const std::string FlowEntry::InterfaceIdToVmCfgName(Agent *agent, uint32_t id) {
1649 94 : if (id != Interface::kInvalidIndex) {
1650 88 : const VmInterface *itf = dynamic_cast <const VmInterface *>
1651 88 : (agent->interface_table()->FindInterface(id));
1652 88 : if (itf) {
1653 68 : const VmEntry *vm = itf->vm();
1654 68 : if (vm) {
1655 68 : return vm->GetCfgName();
1656 : }
1657 : }
1658 : }
1659 26 : return "";
1660 : }
1661 : /////////////////////////////////////////////////////////////////////////////
1662 : // Routines to compute ACL to be applied (including network-policy, SG and
1663 : // VRF-Assign Rules
1664 : /////////////////////////////////////////////////////////////////////////////
1665 100 : void FlowEntry::ResetPolicy() {
1666 : /* Reset acl list*/
1667 100 : data_.match_p.m_acl_l.clear();
1668 100 : data_.match_p.m_out_acl_l.clear();
1669 100 : data_.match_p.m_mirror_acl_l.clear();
1670 100 : data_.match_p.m_out_mirror_acl_l.clear();
1671 : /* Reset sg acl list*/
1672 100 : data_.match_p.sg_policy.ResetPolicy();
1673 100 : data_.match_p.aps_policy.ResetPolicy();
1674 100 : data_.match_p.fwaas_policy.ResetPolicy();
1675 100 : data_.match_p.m_vrf_assign_acl_l.clear();
1676 100 : }
1677 :
1678 : // Rebuild all the policy rules to be applied
1679 100 : void FlowEntry::GetPolicyInfo(const VnEntry *vn, const FlowEntry *rflow) {
1680 100 : if (vn == NULL) {
1681 0 : return;
1682 : }
1683 :
1684 : // Reset old values first
1685 100 : ResetPolicy();
1686 :
1687 : // Short flows means there is some information missing for the flow. Skip
1688 : // getting policy information for short flow. When the information is
1689 : // complete, GetPolicyInfo is called again
1690 100 : if (is_flags_set(FlowEntry::ShortFlow)) {
1691 22 : return;
1692 : }
1693 :
1694 : // ACL supported on VMPORT interfaces only
1695 78 : if (data_.intf_entry == NULL)
1696 0 : return;
1697 :
1698 78 : bool vgw_pass = true;
1699 78 : if (data_.intf_entry->type() == Interface::INET) {
1700 0 : vgw_pass = false;
1701 0 : InetInterface* inet_intf = (InetInterface*)(data_.intf_entry).get();
1702 0 : if ((inet_intf != NULL) && (inet_intf->sub_type() == InetInterface::SIMPLE_GATEWAY))
1703 0 : vgw_pass = true;
1704 : }
1705 78 : if ((data_.intf_entry->type() != Interface::VM_INTERFACE) && !vgw_pass)
1706 0 : return;
1707 :
1708 : // Get Network policy/mirror cfg policy/mirror policies
1709 78 : GetPolicy(vn, rflow);
1710 :
1711 : // Get Sg list
1712 78 : GetSgList(data_.intf_entry.get());
1713 :
1714 : //Get VRF translate ACL
1715 78 : GetVrfAssignAcl();
1716 :
1717 : //Get Application policy set ACL
1718 78 : GetApplicationPolicySet(data_.intf_entry.get(), rflow);
1719 :
1720 : }
1721 :
1722 100 : void FlowEntry::GetPolicyInfo() {
1723 100 : GetPolicyInfo(data_.vn_entry.get(), reverse_flow_entry());
1724 100 : }
1725 :
1726 0 : void FlowEntry::GetPolicyInfo(const VnEntry *vn) {
1727 0 : GetPolicyInfo(vn, reverse_flow_entry());
1728 0 : }
1729 :
1730 0 : void FlowEntry::GetPolicyInfo(const FlowEntry *rflow) {
1731 0 : GetPolicyInfo(data_.vn_entry.get(), rflow);
1732 0 : }
1733 :
1734 78 : void FlowEntry::GetPolicy(const VnEntry *vn, const FlowEntry *rflow) {
1735 78 : if (vn == NULL)
1736 58 : return;
1737 :
1738 78 : MatchAclParams acl;
1739 :
1740 : // Get Mirror configuration first
1741 78 : if (vn->GetMirrorAcl()) {
1742 0 : acl.acl = vn->GetMirrorAcl();
1743 0 : data_.match_p.m_mirror_acl_l.push_back(acl);
1744 : }
1745 :
1746 78 : if (vn->GetMirrorCfgAcl()) {
1747 0 : acl.acl = vn->GetMirrorCfgAcl();
1748 0 : data_.match_p.m_mirror_acl_l.push_back(acl);
1749 : }
1750 :
1751 : // Dont apply network-policy for linklocal, bgp router service
1752 : // and subnet broadcast flow
1753 156 : if (is_flags_set(FlowEntry::LinkLocalFlow) ||
1754 156 : is_flags_set(FlowEntry::Multicast) ||
1755 156 : is_flags_set(FlowEntry::BgpRouterService) ||
1756 234 : is_flags_set(FlowEntry::FabricControlFlow) ||
1757 156 : is_flags_set(FlowEntry::ReverseFlow)) {
1758 39 : return;
1759 : }
1760 :
1761 39 : if (vn->GetAcl()) {
1762 0 : acl.acl = vn->GetAcl();
1763 0 : data_.match_p.m_acl_l.push_back(acl);
1764 : }
1765 :
1766 39 : const VnEntry *rvn = NULL;
1767 : // For local flows, we have to apply NW Policy from out-vn also
1768 39 : if (!is_flags_set(FlowEntry::LocalFlow) || rflow == NULL) {
1769 : // Not local flow
1770 19 : return;
1771 : }
1772 :
1773 20 : rvn = rflow->vn_entry();
1774 20 : if (rvn == NULL) {
1775 0 : return;
1776 : }
1777 :
1778 20 : if (rvn->GetAcl()) {
1779 0 : acl.acl = rvn->GetAcl();
1780 0 : data_.match_p.m_out_acl_l.push_back(acl);
1781 : }
1782 :
1783 20 : if (rvn->GetMirrorAcl()) {
1784 0 : acl.acl = rvn->GetMirrorAcl();
1785 0 : data_.match_p.m_out_mirror_acl_l.push_back(acl);
1786 : }
1787 :
1788 20 : if (rvn->GetMirrorCfgAcl()) {
1789 0 : acl.acl = rvn->GetMirrorCfgAcl();
1790 0 : data_.match_p.m_out_mirror_acl_l.push_back(acl);
1791 : }
1792 78 : }
1793 :
1794 78 : void FlowEntry::GetVrfAssignAcl() {
1795 : // VRF-Assign rules valid only for routed packets
1796 78 : if (l3_flow() == false)
1797 78 : return;
1798 :
1799 18 : if (data_.intf_entry == NULL) {
1800 0 : return;
1801 : }
1802 :
1803 18 : if (data_.intf_entry->type() != Interface::VM_INTERFACE) {
1804 0 : return;
1805 : }
1806 :
1807 36 : if (is_flags_set(FlowEntry::LinkLocalFlow) ||
1808 36 : is_flags_set(FlowEntry::Multicast) ||
1809 36 : is_flags_set(FlowEntry::BgpRouterService) ||
1810 54 : is_flags_set(FlowEntry::FabricControlFlow) ||
1811 36 : is_flags_set(FlowEntry::ReverseFlow)) {
1812 9 : return;
1813 : }
1814 :
1815 : const VmInterface *intf =
1816 9 : static_cast<const VmInterface *>(data_.intf_entry.get());
1817 : //If interface has a VRF assign rule, choose the acl and match the
1818 : //packet, else get the acl attached to VN and try matching the packet to
1819 : //network acl
1820 9 : const AclDBEntry* acl = NULL;
1821 9 : if (is_flags_set(FlowEntry::NatFlow) == false) {
1822 9 : acl = intf->vrf_assign_acl();
1823 : }
1824 :
1825 9 : if (acl == NULL) {
1826 9 : acl = data_.vn_entry.get()->GetAcl();
1827 : }
1828 9 : if (!acl) {
1829 9 : return;
1830 : }
1831 :
1832 0 : MatchAclParams m_acl;
1833 0 : m_acl.acl = acl;
1834 0 : data_.match_p.m_vrf_assign_acl_l.push_back(m_acl);
1835 0 : }
1836 :
1837 78 : void FlowEntry::GetSgList(const Interface *intf) {
1838 : // Dont apply network-policy for linklocal and multicast flows
1839 156 : if (is_flags_set(FlowEntry::LinkLocalFlow) ||
1840 156 : is_flags_set(FlowEntry::Multicast) ||
1841 234 : is_flags_set(FlowEntry::BgpRouterService) ||
1842 156 : is_flags_set(FlowEntry::FabricControlFlow)) {
1843 0 : return;
1844 : }
1845 :
1846 : // SG ACL's are reflexive. Skip SG for reverse flow
1847 78 : if (is_flags_set(FlowEntry::ReverseFlow)) {
1848 39 : return;
1849 : }
1850 :
1851 : // Get virtual-machine port for forward flow
1852 39 : const VmInterface *vm_port = NULL;
1853 39 : bool vgw_pass = false;
1854 39 : if (intf != NULL) {
1855 39 : if (intf->type() == Interface::INET) {
1856 0 : const InetInterface* inet_intf = static_cast<const InetInterface *>(intf);
1857 0 : if ((inet_intf != NULL) && (inet_intf->sub_type() == InetInterface::SIMPLE_GATEWAY)) {
1858 0 : vgw_pass = true;
1859 : }
1860 : }
1861 39 : if (intf->type() == Interface::VM_INTERFACE) {
1862 39 : vm_port = static_cast<const VmInterface *>(intf);
1863 39 : vgw_pass = true;
1864 : }
1865 : }
1866 :
1867 39 : if (!vgw_pass) {
1868 0 : return;
1869 : }
1870 :
1871 : // Get virtual-machine port for reverse flow
1872 39 : FlowEntry *rflow = reverse_flow_entry();
1873 39 : const VmInterface *reverse_vm_port = NULL;
1874 39 : if (rflow != NULL) {
1875 39 : if (rflow->data().intf_entry.get() != NULL) {
1876 39 : if (rflow->data().intf_entry->type() == Interface::VM_INTERFACE) {
1877 : reverse_vm_port = static_cast<const VmInterface *>
1878 39 : (rflow->data().intf_entry.get());
1879 : }
1880 : }
1881 : }
1882 :
1883 : // Get SG-Rules
1884 39 : if (is_flags_set(FlowEntry::LocalFlow)) {
1885 20 : GetLocalFlowSgList(vm_port, reverse_vm_port);
1886 : } else {
1887 19 : GetNonLocalFlowSgList(vm_port);
1888 : }
1889 : }
1890 :
1891 78 : void FlowEntry::GetApplicationPolicySet(const Interface *intf,
1892 : const FlowEntry *rflow) {
1893 156 : if (is_flags_set(FlowEntry::LinkLocalFlow) ||
1894 156 : is_flags_set(FlowEntry::Multicast) ||
1895 234 : is_flags_set(FlowEntry::BgpRouterService) ||
1896 156 : is_flags_set(FlowEntry::FabricControlFlow)) {
1897 0 : return;
1898 : }
1899 :
1900 78 : if (is_flags_set(FlowEntry::ReverseFlow)) {
1901 39 : return;
1902 : }
1903 :
1904 39 : const VmInterface *vm_port = NULL;
1905 39 : if (intf != NULL) {
1906 39 : if (intf->type() == Interface::VM_INTERFACE) {
1907 39 : vm_port = static_cast<const VmInterface *>(intf);
1908 : }
1909 : }
1910 :
1911 39 : if (vm_port != NULL) {
1912 39 : MatchAclParams acl;
1913 : FirewallPolicyList::const_iterator it =
1914 39 : vm_port->fw_policy_list().begin();
1915 39 : for(; it != vm_port->fw_policy_list().end(); it++) {
1916 0 : acl.acl = *it;
1917 0 : data_.match_p.aps_policy.m_acl_l.push_back(acl);
1918 0 : data_.match_p.aps_policy.rule_present = true;
1919 0 : data_.match_p.aps_policy.m_reverse_out_acl_l.push_back(acl);
1920 0 : data_.match_p.aps_policy.reverse_out_rule_present= true;
1921 : }
1922 :
1923 : // Get the ACL for FWAAS
1924 39 : it = vm_port->fwaas_fw_policy_list().begin();
1925 39 : for(; it != vm_port->fwaas_fw_policy_list().end(); it++) {
1926 0 : acl.acl = *it;
1927 0 : data_.match_p.fwaas_policy.m_acl_l.push_back(acl);
1928 0 : data_.match_p.fwaas_policy.rule_present = true;
1929 0 : data_.match_p.fwaas_policy.m_reverse_out_acl_l.push_back(acl);
1930 0 : data_.match_p.fwaas_policy.reverse_out_rule_present= true;
1931 : }
1932 39 : }
1933 :
1934 : // For local flows, we have to apply NW Policy from out-vn also
1935 39 : if (!is_flags_set(FlowEntry::LocalFlow) || rflow == NULL) {
1936 : // Not local flow
1937 19 : return;
1938 : }
1939 :
1940 20 : const Interface *r_intf = rflow->data_.intf_entry.get();
1941 20 : if (r_intf == NULL) {
1942 0 : return;
1943 : }
1944 :
1945 20 : vm_port = dynamic_cast<const VmInterface *>(r_intf);
1946 20 : if (vm_port != NULL) {
1947 20 : MatchAclParams acl;
1948 : FirewallPolicyList::const_iterator it =
1949 20 : vm_port->fw_policy_list().begin();
1950 20 : for(; it != vm_port->fw_policy_list().end(); it++) {
1951 0 : acl.acl = *it;
1952 0 : data_.match_p.aps_policy.m_out_acl_l.push_back(acl);
1953 0 : data_.match_p.aps_policy.out_rule_present = true;
1954 0 : data_.match_p.aps_policy.m_reverse_acl_l.push_back(acl);
1955 0 : data_.match_p.aps_policy.reverse_rule_present = true;
1956 : }
1957 :
1958 : // Get the ACL for FWAAS
1959 20 : it = vm_port->fwaas_fw_policy_list().begin();
1960 20 : for(; it != vm_port->fwaas_fw_policy_list().end(); it++) {
1961 0 : acl.acl = *it;
1962 0 : data_.match_p.fwaas_policy.m_out_acl_l.push_back(acl);
1963 0 : data_.match_p.fwaas_policy.out_rule_present = true;
1964 0 : data_.match_p.fwaas_policy.m_reverse_acl_l.push_back(acl);
1965 0 : data_.match_p.fwaas_policy.reverse_rule_present = true;
1966 : }
1967 20 : }
1968 : }
1969 :
1970 : // Ingress-ACL/Egress-ACL in interface with VM as reference point.
1971 : // Ingress : Packet to VM
1972 : // Egress : Packet from VM
1973 : // The direction stored in flow is defined with vrouter as reference point
1974 : // Ingress : Packet to Vrouter from VM
1975 : // Egress : Packet from Vrouter to VM
1976 : //
1977 : // Function takes care of copying right rules
1978 59 : static bool CopySgEntries(const VmInterface *vm_port, bool ingress_acl,
1979 : std::list<MatchAclParams> &list) {
1980 : /* If policy is NOT enabled on VMI, do not copy SG rules */
1981 59 : if (!vm_port->policy_enabled()) {
1982 0 : return false;
1983 : }
1984 59 : bool ret = false;
1985 59 : for (VmInterface::SecurityGroupEntrySet::const_iterator it =
1986 59 : vm_port->sg_list().list_.begin();
1987 91 : it != vm_port->sg_list().list_.end(); ++it) {
1988 32 : if (it->sg_ == NULL)
1989 0 : continue;
1990 :
1991 32 : if (it->sg_->IsAclSet()) {
1992 32 : ret = true;
1993 : }
1994 32 : MatchAclParams acl;
1995 : // As per definition above,
1996 : // get EgressACL if flow direction is Ingress
1997 : // get IngressACL if flow direction is Egress
1998 32 : if (ingress_acl) {
1999 10 : acl.acl = it->sg_->GetEgressAcl();
2000 : } else {
2001 22 : acl.acl = it->sg_->GetIngressAcl();
2002 : }
2003 32 : if (acl.acl)
2004 32 : list.push_back(acl);
2005 32 : }
2006 :
2007 59 : return ret;
2008 : }
2009 :
2010 20 : void FlowEntry::GetLocalFlowSgList(const VmInterface *vm_port,
2011 : const VmInterface *reverse_vm_port) {
2012 : // Get SG-Rule for the forward flow
2013 20 : if (vm_port) {
2014 20 : data_.match_p.sg_policy.rule_present =
2015 20 : CopySgEntries(vm_port, true, data_.match_p.sg_policy.m_acl_l);
2016 : }
2017 : // For local flow, we need to simulate SG lookup at both ends.
2018 : // Assume packet is from VM-A to VM-B.
2019 : // If we apply Ingress-ACL from VM-A, then apply Egress-ACL from VM-B
2020 : // If we apply Egress-ACL from VM-A, then apply Ingress-ACL from VM-B
2021 20 : if (reverse_vm_port) {
2022 20 : data_.match_p.sg_policy.out_rule_present =
2023 20 : CopySgEntries(reverse_vm_port, false, data_.match_p.sg_policy.m_out_acl_l);
2024 : }
2025 20 : if (!is_flags_set(FlowEntry::TcpAckFlow)) {
2026 20 : return;
2027 : }
2028 : // TCP ACK workaround:
2029 : // Ideally TCP State machine should be run to age TCP flows
2030 : // Temporary workaound in place of state machine. For TCP ACK packets allow
2031 : // the flow if either forward or reverse flow is allowed
2032 :
2033 : // Copy the SG rules to be applied for reverse flow
2034 0 : if (vm_port) {
2035 0 : data_.match_p.sg_policy.reverse_out_rule_present =
2036 0 : CopySgEntries(vm_port, false,
2037 0 : data_.match_p.sg_policy.m_reverse_out_acl_l);
2038 : }
2039 :
2040 0 : if (reverse_vm_port) {
2041 0 : data_.match_p.sg_policy.reverse_rule_present =
2042 0 : CopySgEntries(reverse_vm_port, true,
2043 0 : data_.match_p.sg_policy.m_reverse_acl_l);
2044 : }
2045 : }
2046 :
2047 19 : void FlowEntry::GetNonLocalFlowSgList(const VmInterface *vm_port) {
2048 : // Get SG-Rule for the forward flow
2049 19 : bool ingress = is_flags_set(FlowEntry::IngressDir);
2050 19 : if (vm_port) {
2051 19 : data_.match_p.sg_policy.rule_present =
2052 19 : CopySgEntries(vm_port, ingress,
2053 19 : data_.match_p.sg_policy.m_acl_l);
2054 : }
2055 :
2056 19 : data_.match_p.sg_policy.out_rule_present = false;
2057 :
2058 19 : if (!is_flags_set(FlowEntry::TcpAckFlow)) {
2059 19 : return;
2060 : }
2061 :
2062 : // TCP ACK workaround:
2063 : // Ideally TCP State machine should be run to age TCP flows
2064 : // Temporary workaound in place of state machine. For TCP ACK packets allow
2065 : // the flow if either forward or reverse flow is allowed
2066 :
2067 : // Copy the SG rules to be applied for reverse flow
2068 0 : if (vm_port) {
2069 0 : data_.match_p.sg_policy.reverse_out_rule_present =
2070 0 : CopySgEntries(vm_port, !ingress,
2071 0 : data_.match_p.sg_policy.m_reverse_out_acl_l);
2072 : }
2073 0 : data_.match_p.sg_policy.reverse_rule_present = false;
2074 : }
2075 :
2076 : // For an L2-Flow, refresh the vn-list and sg-list from the route used for
2077 : // flow
2078 6 : void FlowEntry::UpdateL2RouteInfo() {
2079 : // Skip L3-Flows
2080 6 : if (l3_flow())
2081 0 : return;
2082 :
2083 6 : Agent *agent = flow_table()->agent();
2084 : // Get VRF for the flow. L2 flow have same in and out-vrf. So, use same
2085 : // vrf for both smac and dmac lookup
2086 6 : uint32_t vrf_id = data().flow_source_vrf;
2087 6 : const VrfEntry *vrf = agent->vrf_table()->FindVrfFromId(vrf_id);
2088 6 : if (vrf == NULL || vrf->IsDeleted()) {
2089 0 : return;
2090 : }
2091 : BridgeAgentRouteTable *table =
2092 6 : static_cast<BridgeAgentRouteTable *>(vrf->GetBridgeRouteTable());
2093 :
2094 : // Get route-info for smac
2095 6 : GetSourceRouteInfo(table->FindRoute(data().smac));
2096 : // Get route-info for dmac
2097 6 : GetDestRouteInfo(table->FindRoute(data().dmac));
2098 : }
2099 :
2100 : /////////////////////////////////////////////////////////////////////////////
2101 : // Flow policy processing routines
2102 : /////////////////////////////////////////////////////////////////////////////
2103 :
2104 : // Set HBS information
2105 : // |-------------------------------------------------------------------------|
2106 : // | Source | Destination: VMI | Destination: Fabric|
2107 : // |--------------------------------------------------------------------------
2108 : // | VMI | L (src vif index < dst vif index) | L |
2109 : // | | else R | |
2110 : // |--------------------------------------------------------------------------
2111 : // | Fabric | R | - |
2112 : // |-------------------------------------------------------------------------|
2113 : //
2114 128 : void FlowEntry::SetHbsInfofromAction() {
2115 :
2116 128 : if (!(data_.match_p.aps_policy.action_summary & (1 << TrafficAction::HBS))) {
2117 128 : reset_flags(HbfFlow);
2118 128 : SetHbsInterface(HBS_INTERFACE_INVALID);
2119 128 : return;
2120 : }
2121 :
2122 : const VmInterface *src_intf =
2123 0 : dynamic_cast<const VmInterface *>(intf_entry());
2124 0 : FlowEntry *rev_flow = reverse_flow_entry();
2125 : const VmInterface *dst_intf =
2126 0 : dynamic_cast<const VmInterface *>(rev_flow->intf_entry());
2127 :
2128 0 : if ( src_intf == NULL || dst_intf == NULL ) {
2129 0 : reset_flags(HbfFlow);
2130 0 : SetHbsInterface(HBS_INTERFACE_INVALID);
2131 0 : return;
2132 : }
2133 :
2134 : //Enable HBF flow flag
2135 0 : set_flags(HbfFlow);
2136 0 : if (is_flags_set(LocalFlow)) {
2137 : /* Handle Service Chain Traffic for local flow VM <--> SI*/
2138 : /* Case 1: Reset the HBS Action if flow source is service interface */
2139 0 : if (!src_intf->service_intf_type().empty()) {
2140 0 : reset_flags(HbfFlow);
2141 0 : SetHbsInterface(HBS_INTERFACE_INVALID);
2142 0 : return;
2143 : }
2144 : /* Case 2: Set appropriate interface left/right based on service interface type */
2145 0 : if (!dst_intf->service_intf_type().empty()) {
2146 0 : if (dst_intf->service_intf_type() == "left") {
2147 0 : SetHbsInterface(HBS_INTERFACE_LEFT);
2148 0 : } else if (dst_intf->service_intf_type() == "right") {
2149 0 : SetHbsInterface(HBS_INTERFACE_RIGHT);
2150 : }
2151 0 : return;
2152 : }
2153 : // VM <--> VM on same compute
2154 0 : (src_intf->id() < dst_intf->id()) ?
2155 0 : SetHbsInterface(HBS_INTERFACE_LEFT):
2156 0 : SetHbsInterface(HBS_INTERFACE_RIGHT);
2157 : } else {
2158 : /* Handle Service chain traffic entering the compute */
2159 0 : if ((!src_intf->service_intf_type().empty() ||
2160 0 : !dst_intf->service_intf_type().empty())) {
2161 0 : if (is_flags_set(IngressDir) == 0) {
2162 0 : if (dst_intf->service_intf_type() == "left") {
2163 0 : SetHbsInterface(HBS_INTERFACE_LEFT);
2164 0 : } else if (dst_intf->service_intf_type() == "right") {
2165 0 : SetHbsInterface(HBS_INTERFACE_RIGHT);
2166 : }
2167 : } else {
2168 0 : reset_flags(HbfFlow);
2169 0 : SetHbsInterface(HBS_INTERFACE_INVALID);
2170 : }
2171 : } else {
2172 : // VM <--> VM on different compute
2173 0 : (is_flags_set(IngressDir)) ?
2174 0 : SetHbsInterface(HBS_INTERFACE_LEFT):
2175 0 : SetHbsInterface(HBS_INTERFACE_RIGHT);
2176 : }
2177 : }
2178 : }
2179 :
2180 78 : void FlowEntry::SetVrfAssignEntry() {
2181 78 : if (!(data_.match_p.vrf_assign_acl_action &
2182 : (1 << TrafficAction::VRF_TRANSLATE))) {
2183 : //If VRF assign was evaluated and the vrf translate
2184 : //action is not present in latest evaluation mark the
2185 : //flow as short flow
2186 84 : if (data_.vrf_assign_evaluated &&
2187 6 : data_.match_p.action_info.vrf_translate_action_.vrf_name()
2188 12 : != Agent::NullString()) {
2189 0 : MakeShortFlow(SHORT_VRF_CHANGE);
2190 : }
2191 78 : data_.vrf_assign_evaluated = true;
2192 78 : data_.acl_assigned_vrf_index_ = VrfEntry::kInvalidIndex;
2193 78 : return;
2194 : }
2195 :
2196 : std::string vrf_assigned_name =
2197 0 : data_.match_p.action_info.vrf_translate_action_.vrf_name();
2198 0 : std::list<MatchAclParams>::const_iterator acl_it;
2199 0 : for (acl_it = match_p().m_vrf_assign_acl_l.begin();
2200 0 : acl_it != match_p().m_vrf_assign_acl_l.end();
2201 0 : ++acl_it) {
2202 0 : std::string vrf = acl_it->action_info.vrf_translate_action_.vrf_name();
2203 0 : data_.match_p.action_info.vrf_translate_action_.set_vrf_name(vrf);
2204 : //Check if VRF assign acl says, network ACL and SG action
2205 : //to be ignored
2206 : bool ignore_acl =
2207 0 : acl_it->action_info.vrf_translate_action_.ignore_acl();
2208 : data_.match_p.action_info.vrf_translate_action_.set_ignore_acl
2209 0 : (ignore_acl);
2210 0 : }
2211 0 : if (data_.vrf_assign_evaluated && vrf_assigned_name !=
2212 0 : data_.match_p.action_info.vrf_translate_action_.vrf_name()) {
2213 0 : MakeShortFlow(SHORT_VRF_CHANGE);
2214 : }
2215 :
2216 0 : set_acl_assigned_vrf_index();
2217 0 : if (acl_assigned_vrf_index() == VrfEntry::kInvalidIndex) {
2218 0 : MakeShortFlow(SHORT_VRF_CHANGE);
2219 : }
2220 0 : data_.vrf_assign_evaluated = true;
2221 0 : }
2222 :
2223 517 : uint32_t FlowEntry::MatchAcl(const PacketHeader &hdr,
2224 : std::list<MatchAclParams> &acl,
2225 : bool add_implicit_deny, bool add_implicit_allow,
2226 : FlowPolicyInfo *info) {
2227 517 : PktHandler *pkt_handler = Agent::GetInstance()->pkt()->pkt_handler();
2228 :
2229 : // If there are no ACL to match, make it pass
2230 517 : if (acl.size() == 0 && add_implicit_allow) {
2231 489 : if (info) {
2232 : /* We are setting UUIDs for linklocal and multicast flows here,
2233 : * because even if we move this to the place where acl association
2234 : * is being skipped, we still need checks for linklocal and
2235 : * multicast flows here to avoid its value being overwritten with
2236 : * IMPLICIT_ALLOW
2237 : */
2238 294 : if (is_flags_set(FlowEntry::LinkLocalFlow)) {
2239 0 : info->uuid = FlowPolicyStateStr.at(LINKLOCAL_FLOW);
2240 294 : } else if (is_flags_set(FlowEntry::Multicast)) {
2241 0 : info->uuid = FlowPolicyStateStr.at(MULTICAST_FLOW);
2242 294 : } else if (is_flags_set(FlowEntry::BgpRouterService)) {
2243 0 : info->uuid = FlowPolicyStateStr.at(BGPROUTERSERVICE_FLOW);
2244 : } else {
2245 : /* We need to make sure that info is not already populated
2246 : * before setting it to IMPLICIT_ALLOW. This is required
2247 : * because info could earlier be set by previous call to
2248 : * MatchAcl. We should note here that same 'info' var is passed
2249 : * for MatchAcl calls with in_acl and out_acl
2250 : */
2251 294 : if (!info->terminal && !info->other) {
2252 294 : info->uuid = FlowPolicyStateStr.at(IMPLICIT_ALLOW);
2253 : }
2254 : }
2255 : }
2256 489 : return (1 << TrafficAction::PASS);
2257 : }
2258 :
2259 : // PASS default GW traffic, if it is ICMP or DNS
2260 84 : if ((hdr.protocol == IPPROTO_ICMP ||
2261 28 : (hdr.protocol == IPPROTO_UDP &&
2262 28 : (hdr.src_port == DNS_SERVER_PORT ||
2263 56 : hdr.dst_port == DNS_SERVER_PORT))) &&
2264 0 : (pkt_handler->IsGwPacket(data_.intf_entry.get(), hdr.dst_ip) ||
2265 0 : pkt_handler->IsGwPacket(data_.intf_entry.get(), hdr.src_ip))) {
2266 0 : if (info) {
2267 0 : info->uuid = FlowPolicyStateStr.at(DEFAULT_GW_ICMP_OR_DNS);
2268 : }
2269 0 : return (1 << TrafficAction::PASS);
2270 : }
2271 :
2272 28 : uint32_t action = 0;
2273 28 : for (std::list<MatchAclParams>::iterator it = acl.begin();
2274 31 : it != acl.end(); ++it) {
2275 28 : if (it->acl.get() == NULL) {
2276 0 : continue;
2277 : }
2278 :
2279 28 : if (it->acl->PacketMatch(hdr, *it, info)) {
2280 25 : action |= it->action_info.action;
2281 25 : if (it->action_info.action & (1 << TrafficAction::MIRROR)) {
2282 : data_.match_p.action_info.mirror_l.insert
2283 0 : (data_.match_p.action_info.mirror_l.end(),
2284 0 : it->action_info.mirror_l.begin(),
2285 0 : it->action_info.mirror_l.end());
2286 : }
2287 :
2288 25 : if (it->terminal_rule) {
2289 25 : break;
2290 : }
2291 : }
2292 : }
2293 :
2294 : // If no acl matched, make it imlicit deny
2295 28 : if (action == 0 && add_implicit_deny) {
2296 3 : action = (1 << TrafficAction::DENY) |
2297 : (1 << TrafficAction::IMPLICIT_DENY);
2298 3 : if (info) {
2299 3 : info->uuid = FlowPolicyStateStr.at(IMPLICIT_DENY);
2300 3 : info->drop = true;
2301 : }
2302 : }
2303 :
2304 28 : return action;
2305 : }
2306 :
2307 167 : void FlowEntry::SetPacketHeader(PacketHeader *hdr) {
2308 167 : hdr->vrf = data_.vrf;
2309 167 : hdr->src_ip = key_.src_addr;
2310 167 : hdr->dst_ip = key_.dst_addr;
2311 167 : hdr->protocol = key_.protocol;
2312 167 : if (hdr->protocol == IPPROTO_UDP || hdr->protocol == IPPROTO_TCP) {
2313 167 : hdr->src_port = key_.src_port;
2314 167 : hdr->dst_port = key_.dst_port;
2315 : } else {
2316 0 : hdr->src_port = 0;
2317 0 : hdr->dst_port = 0;
2318 : }
2319 167 : hdr->src_policy_id = &(data_.source_vn_list);
2320 167 : hdr->dst_policy_id = &(data_.dest_vn_list);
2321 167 : hdr->src_sg_id_l = &(data_.source_sg_id_l);
2322 167 : hdr->dst_sg_id_l = &(data_.dest_sg_id_l);
2323 167 : hdr->src_tags_ = data_.source_tag_id_l;
2324 167 : hdr->dst_tags_ = data_.dest_tag_id_l;
2325 167 : hdr->family = key_.family;
2326 167 : }
2327 :
2328 : // In case of NAT flows, the key fields can change.
2329 77 : void FlowEntry::SetOutPacketHeader(PacketHeader *hdr) {
2330 77 : FlowEntry *rflow = reverse_flow_entry();
2331 77 : if (rflow == NULL)
2332 0 : return;
2333 :
2334 77 : hdr->vrf = rflow->data().vrf;
2335 77 : hdr->src_ip = rflow->key().dst_addr;
2336 77 : hdr->dst_ip = rflow->key().src_addr;
2337 77 : hdr->protocol = rflow->key().protocol;
2338 77 : if (hdr->protocol == IPPROTO_UDP || hdr->protocol == IPPROTO_TCP) {
2339 77 : hdr->src_port = rflow->key().dst_port;
2340 77 : hdr->dst_port = rflow->key().src_port;
2341 : } else {
2342 0 : hdr->src_port = 0;
2343 0 : hdr->dst_port = 0;
2344 : }
2345 77 : hdr->src_policy_id = &(rflow->data().dest_vn_list);
2346 77 : hdr->dst_policy_id = &(rflow->data().source_vn_list);
2347 77 : hdr->src_sg_id_l = &(rflow->data().dest_sg_id_l);
2348 77 : hdr->dst_sg_id_l = &(rflow->data().source_sg_id_l);
2349 77 : hdr->src_tags_ = rflow->data_.dest_tag_id_l;
2350 77 : hdr->dst_tags_ = rflow->data_.source_tag_id_l;
2351 77 : hdr->family = key_.family;
2352 : }
2353 :
2354 89 : void FlowEntry::SetAclInfo(SessionPolicy *sp, SessionPolicy *rsp,
2355 : const FlowPolicyInfo &fwd_flow_info,
2356 : const FlowPolicyInfo &rev_flow_info,
2357 : bool tcp_rev, bool is_sg) {
2358 :
2359 89 : FlowEntry *rflow = reverse_flow_entry();
2360 89 : if (rflow == NULL) {
2361 0 : return;
2362 : }
2363 :
2364 89 : sp->rule_uuid_ = fwd_flow_info.uuid;
2365 89 : sp->acl_name_ = fwd_flow_info.acl_name;
2366 :
2367 89 : rsp->rule_uuid_ = rev_flow_info.uuid;
2368 89 : rsp->acl_name_ = rev_flow_info.acl_name;
2369 :
2370 : //If Forward flow SG rule says drop, copy corresponding
2371 : //ACE id to both forward and reverse flow
2372 89 : if (fwd_flow_info.drop) {
2373 12 : rsp->rule_uuid_ = fwd_flow_info.uuid;
2374 12 : rsp->acl_name_ = fwd_flow_info.acl_name;
2375 12 : return;
2376 : }
2377 :
2378 : //If reverse flow SG rule says drop, copy corresponding
2379 : //ACE id to both forward and reverse flow
2380 77 : if (rev_flow_info.drop) {
2381 2 : sp->rule_uuid_ = rev_flow_info.uuid;
2382 2 : sp->acl_name_ = rev_flow_info.acl_name;
2383 2 : return;
2384 : }
2385 :
2386 75 : if (tcp_rev == false) {
2387 75 : if (is_sg) {
2388 25 : if (data_.match_p.sg_policy.rule_present == false) {
2389 15 : sp->rule_uuid_ = rev_flow_info.uuid;
2390 15 : sp->acl_name_ = rev_flow_info.acl_name;
2391 : }
2392 :
2393 25 : if (data_.match_p.sg_policy.out_rule_present == false) {
2394 21 : rsp->rule_uuid_ = fwd_flow_info.uuid;
2395 21 : rsp->acl_name_ = fwd_flow_info.acl_name;
2396 : }
2397 : } else {
2398 50 : if (data_.match_p.aps_policy.rule_present == false) {
2399 50 : sp->rule_uuid_ = rev_flow_info.uuid;
2400 50 : sp->acl_name_ = rev_flow_info.acl_name;
2401 : }
2402 :
2403 50 : if (data_.match_p.aps_policy.out_rule_present == false) {
2404 50 : rsp->rule_uuid_ = fwd_flow_info.uuid;
2405 50 : rsp->acl_name_ = fwd_flow_info.acl_name;
2406 : }
2407 : }
2408 : }
2409 :
2410 75 : if (tcp_rev == true) {
2411 0 : if (sp->reverse_rule_present == false) {
2412 0 : rsp->rule_uuid_ = fwd_flow_info.uuid;
2413 0 : rsp->acl_name_ = fwd_flow_info.acl_name;
2414 : }
2415 :
2416 0 : if (sp->reverse_out_rule_present == false) {
2417 0 : sp->rule_uuid_ = rev_flow_info.uuid;
2418 0 : sp->acl_name_ = rev_flow_info.acl_name;
2419 : }
2420 : }
2421 : }
2422 :
2423 89 : void FlowEntry::SessionMatch(SessionPolicy *sp, SessionPolicy *rsp,
2424 : bool is_sg) {
2425 :
2426 89 : FlowEntry *rflow = reverse_flow_entry();
2427 89 : const string value = FlowPolicyStateStr.at(NOT_EVALUATED);
2428 89 : FlowPolicyInfo acl_info(value);
2429 89 : FlowPolicyInfo out_acl_info(value);
2430 89 : FlowPolicyInfo rev_acl_info(value);
2431 89 : FlowPolicyInfo rev_out_acl_info(value);
2432 :
2433 89 : sp->rule_uuid_ = FlowEntry::FlowPolicyStateStr.at(FlowEntry::NOT_EVALUATED);
2434 89 : sp->acl_name_ = "";
2435 :
2436 89 : if (rsp) {
2437 : rsp->rule_uuid_ =
2438 89 : FlowEntry::FlowPolicyStateStr.at(FlowEntry::NOT_EVALUATED);
2439 89 : rsp->acl_name_ = "";
2440 : }
2441 :
2442 89 : PacketHeader hdr;
2443 89 : SetPacketHeader(&hdr);
2444 :
2445 : //Apply ACL configured on ingress interface
2446 89 : sp->action = MatchAcl(hdr, sp->m_acl_l, true, !sp->rule_present, &acl_info);
2447 :
2448 : //Apply ACL configured on egress interface
2449 89 : PacketHeader out_hdr;
2450 89 : if (ShouldDrop(sp->action) == false && rflow) {
2451 : // Key fields for lookup in out-acl can potentially change in case
2452 : // of NAT. Form ACL lookup based on post-NAT fields
2453 77 : SetOutPacketHeader(&out_hdr);
2454 77 : sp->out_action = MatchAcl(out_hdr, sp->m_out_acl_l, true,
2455 77 : !sp->out_rule_present, &out_acl_info);
2456 : }
2457 :
2458 : // For TCP-ACK packet, we allow packet if either forward or reverse
2459 : // flow says allow. So, continue matching reverse flow even if forward
2460 : // flow says drop
2461 89 : if (is_flags_set(FlowEntry::TcpAckFlow) && rflow) {
2462 0 : rflow->SetPacketHeader(&hdr);
2463 0 : sp->reverse_action = MatchAcl(hdr, sp->m_reverse_acl_l, true,
2464 0 : !sp->reverse_rule_present, &rev_acl_info);
2465 :
2466 0 : if (ShouldDrop(sp->reverse_action) == false) {
2467 : // Key fields for lookup in out-acl can potentially change in
2468 : // case of NAT. Form ACL lookup based on post-NAT fields
2469 0 : rflow->SetOutPacketHeader(&out_hdr);
2470 0 : sp->reverse_out_action = MatchAcl(out_hdr, sp->m_reverse_out_acl_l,
2471 0 : true, !sp->reverse_out_rule_present,
2472 : &rev_out_acl_info);
2473 : }
2474 : }
2475 :
2476 : // Compute summary SG action.
2477 : // For Non-TCP-ACK Flows
2478 : // DROP if any of policy.action, out_action, policy.reverse_action or
2479 : // policy.reverse_out_action says DROP
2480 : // Only acl_info which is derived from sp->m_acl_l
2481 : // and sp->m_out_acl_l will be populated. Pick the
2482 : // UUID specified by acl_info for flow's SG rule UUID
2483 : // For TCP-ACK flows
2484 : // ALLOW if either ((policy.action && out_action) ||
2485 : // (policy.reverse_action & policy.reverse_out_action))
2486 : // ALLOW
2487 : // For flow's SG rule UUID use the following rules
2488 : // --If both acl_info and rev_acl_info has drop set, pick the
2489 : // UUID from acl_info.
2490 : // --If either of acl_info or rev_acl_info does not have drop
2491 : // set, pick the UUID from the one which does not have drop set.
2492 : // --If both of them does not have drop set, pick it up from
2493 : // acl_info
2494 : //
2495 89 : if (!is_flags_set(FlowEntry::TcpAckFlow)) {
2496 89 : sp->action_summary =
2497 89 : sp->action | sp->out_action | sp->reverse_action | sp->reverse_out_action;
2498 89 : SetAclInfo(sp, rsp, acl_info, out_acl_info, false, is_sg);
2499 0 : } else if (ShouldDrop(sp->action | sp->out_action) &&
2500 0 : ShouldDrop(sp->reverse_action | sp->reverse_out_action)) {
2501 : //If both ingress ACL and egress ACL of VMI denies the
2502 : //packet, then pick ingress ACE uuid to send to UVE
2503 0 : sp->action_summary = (1 << TrafficAction::DENY);
2504 0 : SetAclInfo(sp, rsp, acl_info, out_acl_info, false, is_sg);
2505 : } else {
2506 0 : sp->action_summary = (1 << TrafficAction::PASS);
2507 0 : if (sp->action & (1 << TrafficAction::HBS) ||
2508 0 : sp->out_action & (1 << TrafficAction::HBS) ||
2509 0 : sp->reverse_action & (1 << TrafficAction::HBS) ||
2510 0 : sp->reverse_out_action & (1 << TrafficAction::HBS)) {
2511 0 : sp->action_summary|=(1 << TrafficAction::HBS);
2512 : }
2513 0 : if (!ShouldDrop(sp->action | sp->out_action)) {
2514 0 : SetAclInfo(sp, rsp, acl_info, out_acl_info, false, is_sg);
2515 0 : } else if (!ShouldDrop(sp->reverse_action | sp->reverse_out_action)) {
2516 0 : SetAclInfo(sp, rsp, rev_out_acl_info, rev_acl_info, true, is_sg);
2517 : }
2518 : }
2519 89 : }
2520 :
2521 : // Apply Policy and SG rules for a flow.
2522 : //
2523 : // Special case of local flows:
2524 : // For local-flows, both VM are on same compute and we need to apply SG from
2525 : // both the ports. sg_policy.m_acl_l will contain ACL for port in forward flow and
2526 : // sg_policy.m_out_acl_l will have ACL from other port
2527 : //
2528 : // If forward flow goes thru NAT, the key for matching ACL in
2529 : // sg_policy.m_out_acl_l can potentially change. The routine SetOutPacketHeader
2530 : // takes care of forming header after NAT
2531 : //
2532 : // Rules applied are based on flow type
2533 : // Non-Local Forward Flow
2534 : // Network Policy.
2535 : // Out-Network Policy will be empty
2536 : // SG
2537 : // Out-SG will be empty
2538 : // Non-Local Reverse Flow
2539 : // Network Policy.
2540 : // Out-Network Policy will be empty
2541 : // SG and out-SG from forward flow
2542 : // Local Forward Flow
2543 : // Network Policy.
2544 : // Out-Network Policy
2545 : // SG
2546 : // Out-SG
2547 : // Local Reverse Flow
2548 : // Network Policy.
2549 : // Out-Network Policy
2550 : // SG and out-SG from forward flow
2551 100 : bool FlowEntry::DoPolicy() {
2552 100 : if (is_flags_set(FlowEntry::ShortFlow)) {
2553 22 : return true;
2554 : }
2555 78 : data_.match_p.action_info.Clear();
2556 78 : data_.match_p.policy_action = 0;
2557 78 : data_.match_p.out_policy_action = 0;
2558 78 : data_.match_p.mirror_action = 0;
2559 78 : data_.match_p.out_mirror_action = 0;
2560 :
2561 78 : data_.match_p.sg_policy.ResetAction();
2562 78 : data_.match_p.aps_policy.ResetAction();
2563 78 : data_.match_p.fwaas_policy.ResetAction();
2564 :
2565 78 : const string value = FlowPolicyStateStr.at(NOT_EVALUATED);
2566 78 : FlowPolicyInfo nw_acl_info(value);
2567 :
2568 78 : FlowEntry *rflow = reverse_flow_entry();
2569 78 : PacketHeader hdr;
2570 78 : SetPacketHeader(&hdr);
2571 :
2572 : //Calculate VRF assign entry, and ignore acl is set
2573 : //skip network and SG acl action is set
2574 78 : if (!is_flags_set(FlowEntry::ReverseFlow))
2575 : {
2576 39 : data_.match_p.vrf_assign_acl_action = MatchAcl(hdr, data_.match_p.m_vrf_assign_acl_l, false, true, NULL);
2577 : }
2578 : else
2579 : {
2580 39 : data_.match_p.vrf_assign_acl_action = rflow->data_.match_p.vrf_assign_acl_action;
2581 : data_.match_p.action_info.vrf_translate_action_ =
2582 39 : rflow->data_.match_p.action_info.vrf_translate_action_;
2583 : }
2584 :
2585 : // Mirror is valid even if packet is to be dropped. So, apply it first
2586 78 : data_.match_p.mirror_action = MatchAcl(hdr, data_.match_p.m_mirror_acl_l,
2587 : false, true, NULL);
2588 :
2589 : // Apply out-policy. Valid only for local-flow
2590 156 : data_.match_p.out_mirror_action = MatchAcl(hdr,
2591 78 : data_.match_p.m_out_mirror_acl_l, false, true, NULL);
2592 :
2593 : // Apply network policy
2594 78 : if (!is_flags_set(FlowEntry::ReverseFlow)) {
2595 39 : data_.match_p.policy_action = MatchAcl(hdr, data_.match_p.m_acl_l, true,
2596 : true, &nw_acl_info);
2597 39 : if (ShouldDrop(data_.match_p.policy_action))
2598 0 : goto done;
2599 39 : data_.match_p.out_policy_action = MatchAcl(hdr, data_.match_p.m_out_acl_l,
2600 : true, true, &nw_acl_info);
2601 39 : if (ShouldDrop(data_.match_p.out_policy_action))
2602 0 : goto done;
2603 : }
2604 : else {
2605 39 : if (rflow) {
2606 78 : uint32_t r_policy_action = MatchAcl(hdr,
2607 39 : rflow->data_.match_p.m_acl_l, true, true, &nw_acl_info);
2608 39 : if (ShouldDrop(r_policy_action)) {
2609 0 : data_.match_p.policy_action = rflow->data_.match_p.policy_action;
2610 0 : goto done;
2611 : }
2612 78 : uint32_t r_out_policy_action = MatchAcl(hdr,
2613 39 : rflow->data_.match_p.m_out_acl_l, true, true, &nw_acl_info);
2614 39 : if (ShouldDrop(r_out_policy_action)) {
2615 0 : data_.match_p.out_policy_action = rflow->data_.match_p.out_policy_action;
2616 0 : goto done;
2617 : }
2618 : }
2619 : }
2620 :
2621 : // Apply sg policy
2622 78 : if (!is_flags_set(FlowEntry::ReverseFlow)) {
2623 39 : SessionPolicy *r_sg_policy = NULL;
2624 39 : SessionPolicy *r_aps_policy = NULL;
2625 39 : SessionPolicy *r_fwaas_policy = NULL;
2626 :
2627 39 : if (rflow) {
2628 39 : r_sg_policy = &(rflow->data_.match_p.sg_policy);
2629 39 : r_aps_policy = &(rflow->data_.match_p.aps_policy);
2630 39 : r_fwaas_policy = &(rflow->data_.match_p.fwaas_policy);
2631 : }
2632 :
2633 39 : SessionMatch(&data_.match_p.sg_policy, r_sg_policy, true);
2634 39 : if (ShouldDrop(data_.match_p.sg_policy.action_summary)) {
2635 14 : goto done;
2636 : }
2637 :
2638 25 : SessionMatch(&data_.match_p.fwaas_policy, r_fwaas_policy, false);
2639 25 : if (ShouldDrop(data_.match_p.fwaas_policy.action_summary)) {
2640 0 : goto done;
2641 : }
2642 :
2643 25 : SessionMatch(&data_.match_p.aps_policy, r_aps_policy, false);
2644 : } else {
2645 : // SG is reflexive ACL. For reverse-flow, copy SG action from
2646 : // forward flow
2647 39 : UpdateReflexiveAction();
2648 : }
2649 :
2650 78 : done:
2651 78 : nw_ace_uuid_ = nw_acl_info.uuid;
2652 78 : if (!nw_acl_info.src_match_vn.empty())
2653 0 : data_.source_vn_match = nw_acl_info.src_match_vn;
2654 78 : if (!nw_acl_info.dst_match_vn.empty())
2655 0 : data_.dest_vn_match = nw_acl_info.dst_match_vn;
2656 : // Set mirror vrf after evaluation of actions
2657 78 : SetMirrorVrfFromAction();
2658 : //Set VRF assign action
2659 78 : SetVrfAssignEntry();
2660 : //Set HBS information
2661 78 : SetHbsInfofromAction();
2662 : // Summarize the actions based on lookups above
2663 78 : ActionRecompute();
2664 78 : return true;
2665 78 : }
2666 :
2667 : /////////////////////////////////////////////////////////////////////////////
2668 : // Flow policy action compute routines
2669 : /////////////////////////////////////////////////////////////////////////////
2670 100 : void FlowEntry::ResyncFlow() {
2671 100 : DoPolicy();
2672 :
2673 : // If this is forward flow, update the SG action for reflexive entry
2674 100 : FlowEntry *rflow = (is_flags_set(FlowEntry::ReverseFlow) == false) ?
2675 50 : reverse_flow_entry() : NULL;
2676 : // Dont update reflexive entry for TcpAck Flows. Since it can flip
2677 : // Deny state for the reflexive entry.
2678 100 : if (!(is_flags_set(FlowEntry::TcpAckFlow)) && rflow) {
2679 : // Update action for reverse flow
2680 50 : rflow->UpdateReflexiveAction();
2681 : //Set HBS information
2682 50 : rflow->SetHbsInfofromAction();
2683 50 : rflow->ActionRecompute();
2684 : }
2685 100 : }
2686 :
2687 : const VrfEntry*
2688 0 : FlowEntry::GetDestinationVrf() const {
2689 0 : const VrfEntry *vrf = NULL;
2690 0 : VrfTable *vrf_table = flow_table()->agent()->vrf_table();
2691 :
2692 0 : if (is_flags_set(FlowEntry::NatFlow) ||
2693 0 : match_p().action_info.action & (1 << TrafficAction::VRF_TRANSLATE)) {
2694 0 : vrf = vrf_table->FindVrfFromId(data().dest_vrf);
2695 : } else {
2696 0 : vrf = vrf_table->FindVrfFromId(data().vrf);
2697 : }
2698 0 : return vrf;
2699 : }
2700 :
2701 128 : bool FlowEntry::SetQosConfigIndex() {
2702 128 : uint32_t i = AgentQosConfigTable::kInvalidIndex;
2703 128 : MatchAclParamsList::const_iterator it;
2704 :
2705 : // For reverse flows, first check if we have our own QoS config
2706 : // (from interface), and only fall back to forward flow if not
2707 128 : if (is_flags_set(FlowEntry::ReverseFlow)) {
2708 : // First, check if reverse flow has its own QoS config from interface
2709 : const VmInterface *intf =
2710 89 : dynamic_cast<const VmInterface*>(data_.intf_entry.get());
2711 89 : if (intf && intf->qos_config()) {
2712 0 : i = intf->qos_config()->id();
2713 : }
2714 :
2715 : // If still no QoS config, copy from forward flow
2716 89 : if (i == AgentQosConfigTable::kInvalidIndex) {
2717 89 : FlowEntry *fwd_flow = reverse_flow_entry();
2718 89 : if (fwd_flow) {
2719 89 : i = fwd_flow->data().qos_config_idx;
2720 : }
2721 : }
2722 :
2723 : // If we got a valid QoS config, use it and return early
2724 89 : if (i != AgentQosConfigTable::kInvalidIndex) {
2725 0 : if (i != data_.qos_config_idx) {
2726 0 : data_.qos_config_idx = i;
2727 0 : return true;
2728 : }
2729 0 : return false;
2730 : }
2731 : // If no QoS config found yet, continue with normal processing
2732 : }
2733 :
2734 : // Priority of QOS config for forward flows (and reverse flows that didn't find config above)
2735 : // 1> SG
2736 : // 2> Interface
2737 : // 3> ACL
2738 : // 4> VN (handled through ACLs)
2739 128 : if (data_.match_p.sg_policy.action & 1 << TrafficAction::APPLY_QOS) {
2740 0 : for (it = data_.match_p.sg_policy.m_acl_l.begin();
2741 0 : it != data_.match_p.sg_policy.m_acl_l.end(); it++) {
2742 0 : if (it->action_info.action & 1 << TrafficAction::APPLY_QOS &&
2743 0 : it->action_info.qos_config_action_.id()
2744 : != AgentQosConfigTable::kInvalidIndex) {
2745 0 : i = it->action_info.qos_config_action_.id();
2746 0 : break;
2747 : }
2748 : }
2749 128 : } else if (data_.match_p.sg_policy.out_action & 1 << TrafficAction::APPLY_QOS) {
2750 0 : for (it = data_.match_p.sg_policy.m_out_acl_l.begin();
2751 0 : it != data_.match_p.sg_policy.m_out_acl_l.end(); it++) {
2752 0 : if (it->action_info.action & 1 << TrafficAction::APPLY_QOS &&
2753 0 : it->action_info.qos_config_action_.id() !=
2754 : AgentQosConfigTable::kInvalidIndex) {
2755 0 : i = it->action_info.qos_config_action_.id();
2756 0 : break;
2757 : }
2758 : }
2759 128 : } else if (data_.match_p.policy_action & 1 << TrafficAction::APPLY_QOS) {
2760 0 : for (it = data_.match_p.m_acl_l.begin();
2761 0 : it != data_.match_p.m_acl_l.end(); it++) {
2762 0 : if (it->action_info.action & 1 << TrafficAction::APPLY_QOS &&
2763 0 : it->action_info.qos_config_action_.id() !=
2764 : AgentQosConfigTable::kInvalidIndex) {
2765 0 : i = it->action_info.qos_config_action_.id();
2766 0 : break;
2767 : }
2768 : }
2769 128 : } else if (data_.match_p.out_policy_action & 1 << TrafficAction::APPLY_QOS) {
2770 0 : for (it = data_.match_p.m_out_acl_l.begin();
2771 0 : it != data_.match_p.m_out_acl_l.end(); it++) {
2772 0 : if (it->action_info.action & 1 << TrafficAction::APPLY_QOS &&
2773 0 : it->action_info.qos_config_action_.id() !=
2774 : AgentQosConfigTable::kInvalidIndex) {
2775 0 : i = it->action_info.qos_config_action_.id();
2776 0 : break;
2777 : }
2778 : }
2779 : }
2780 :
2781 : const VmInterface *intf =
2782 128 : dynamic_cast<const VmInterface*>(data_.intf_entry.get());
2783 128 : if (intf && intf->qos_config()) {
2784 0 : if (intf->is_vn_qos_config() == false ||
2785 : i == AgentQosConfigTable::kInvalidIndex) {
2786 0 : i = intf->qos_config()->id();
2787 : }
2788 : }
2789 :
2790 128 : if (i != data_.qos_config_idx) {
2791 0 : data_.qos_config_idx = i;
2792 0 : return true;
2793 : }
2794 :
2795 128 : return false;
2796 : }
2797 :
2798 : // Recompute FlowEntry action based on ACLs already set in the flow
2799 128 : bool FlowEntry::ActionRecompute() {
2800 128 : uint32_t action = 0;
2801 128 : uint16_t drop_reason = DROP_UNKNOWN;
2802 128 : bool ret = false;
2803 :
2804 128 : action = data_.match_p.policy_action | data_.match_p.out_policy_action |
2805 128 : data_.match_p.sg_policy.action_summary |
2806 128 : data_.match_p.mirror_action | data_.match_p.out_mirror_action |
2807 128 : data_.match_p.aps_policy.action_summary |
2808 128 : data_.match_p.fwaas_policy.action_summary;
2809 :
2810 : //Only VRF assign acl, can specify action to
2811 : //translate VRF. VRF translate action specified
2812 : //by egress VN ACL or ingress VN ACL should be ignored
2813 128 : action &= ~(1 << TrafficAction::VRF_TRANSLATE);
2814 128 : action |= data_.match_p.vrf_assign_acl_action;
2815 :
2816 128 : if (action & (1 << TrafficAction::VRF_TRANSLATE) &&
2817 0 : data_.match_p.action_info.vrf_translate_action_.ignore_acl() == true) {
2818 : //In case of multi inline service chain, match condition generated on
2819 : //each of service instance interface takes higher priority than
2820 : //network ACL. Match condition on the interface would have ignore acl
2821 : //flag set to avoid applying two ACL for vrf translation
2822 0 : action = data_.match_p.vrf_assign_acl_action |
2823 0 : data_.match_p.sg_policy.action_summary | data_.match_p.mirror_action |
2824 0 : data_.match_p.out_mirror_action;
2825 :
2826 : //Pick mirror action from network ACL
2827 0 : if (data_.match_p.policy_action & (1 << TrafficAction::MIRROR) ||
2828 0 : data_.match_p.out_policy_action & (1 << TrafficAction::MIRROR)) {
2829 0 : action |= (1 << TrafficAction::MIRROR);
2830 : }
2831 : }
2832 :
2833 128 : action &= ~(1 << TrafficAction::HBS);
2834 128 : if (data_.match_p.aps_policy.action_summary & (1 << TrafficAction::HBS)) {
2835 0 : action |= (1 << TrafficAction::HBS);
2836 : }
2837 :
2838 128 : if (SetQosConfigIndex()) {
2839 0 : ret = true;
2840 : }
2841 :
2842 : // check for conflicting actions and remove allowed action
2843 128 : if (ShouldDrop(action)) {
2844 39 : action = (action & ~TrafficAction::DROP_FLAGS &
2845 : ~TrafficAction::PASS_FLAGS);
2846 39 : action |= (1 << TrafficAction::DENY);
2847 39 : if (is_flags_set(FlowEntry::ShortFlow)) {
2848 0 : drop_reason = short_flow_reason_;
2849 39 : } else if (ShouldDrop(data_.match_p.policy_action)) {
2850 0 : drop_reason = DROP_POLICY;
2851 39 : } else if (ShouldDrop(data_.match_p.out_policy_action)) {
2852 0 : drop_reason = DROP_OUT_POLICY;
2853 39 : } else if (ShouldDrop(data_.match_p.sg_policy.action)) {
2854 12 : drop_reason = DROP_SG;
2855 27 : } else if (ShouldDrop(data_.match_p.sg_policy.out_action)) {
2856 2 : drop_reason = DROP_OUT_SG;
2857 25 : } else if (ShouldDrop(data_.match_p.sg_policy.reverse_action)) {
2858 0 : drop_reason = DROP_REVERSE_SG;
2859 25 : } else if (ShouldDrop(data_.match_p.sg_policy.reverse_out_action)) {
2860 0 : drop_reason = DROP_REVERSE_OUT_SG;
2861 25 : } else if (ShouldDrop(data_.match_p.aps_policy.action)) {
2862 0 : drop_reason = DROP_FIREWALL_POLICY;
2863 25 : } else if (ShouldDrop(data_.match_p.aps_policy.out_action)) {
2864 0 : drop_reason = DROP_OUT_FIREWALL_POLICY;
2865 25 : } else if (ShouldDrop(data_.match_p.aps_policy.reverse_action)) {
2866 0 : drop_reason = DROP_REVERSE_FIREWALL_POLICY;
2867 25 : } else if (ShouldDrop(data_.match_p.aps_policy.reverse_out_action)) {
2868 0 : drop_reason = DROP_REVERSE_OUT_FIREWALL_POLICY;
2869 25 : } else if (ShouldDrop(data_.match_p.fwaas_policy.action)) {
2870 0 : drop_reason = DROP_FWAAS_POLICY;
2871 25 : } else if (ShouldDrop(data_.match_p.fwaas_policy.out_action)) {
2872 0 : drop_reason = DROP_FWAAS_OUT_POLICY;
2873 25 : } else if (ShouldDrop(data_.match_p.fwaas_policy.reverse_action)) {
2874 0 : drop_reason = DROP_FWAAS_REVERSE_POLICY;
2875 25 : } else if (ShouldDrop(data_.match_p.fwaas_policy.reverse_out_action)) {
2876 0 : drop_reason = DROP_FWAAS_REVERSE_OUT_POLICY;
2877 : } else {
2878 25 : drop_reason = DROP_UNKNOWN;
2879 : }
2880 : }
2881 :
2882 128 : if (action & (1 << TrafficAction::TRAP)) {
2883 0 : action = (1 << TrafficAction::TRAP);
2884 : }
2885 :
2886 128 : if (action != data_.match_p.action_info.action) {
2887 117 : data_.match_p.action_info.action = action;
2888 117 : ret = true;
2889 : }
2890 128 : if (drop_reason != data_.drop_reason) {
2891 14 : data_.drop_reason = drop_reason;
2892 14 : ret = true;
2893 : }
2894 128 : return ret;
2895 : }
2896 :
2897 : // SetMirrorVrfFromAction
2898 : // For this flow check for mirror action from dynamic ACLs or policy mirroring
2899 : // assign the vrf from its Virtual Nework that ACL is used
2900 : // If it is a local flow and out mirror action or policy is set
2901 : // assign the vrf of the reverse flow, since ACL came from the reverse flow
2902 78 : void FlowEntry::SetMirrorVrfFromAction() {
2903 78 : if (data_.match_p.mirror_action & (1 << TrafficAction::MIRROR) ||
2904 78 : data_.match_p.policy_action & (1 << TrafficAction::MIRROR)) {
2905 0 : const VnEntry *vn = vn_entry();
2906 0 : if (vn && vn->GetVrf()) {
2907 0 : SetMirrorVrf(vn->GetVrf()->vrf_id());
2908 : }
2909 : }
2910 78 : if (data_.match_p.out_mirror_action & (1 << TrafficAction::MIRROR) ||
2911 78 : data_.match_p.out_policy_action & (1 << TrafficAction::MIRROR)) {
2912 0 : FlowEntry *rflow = reverse_flow_entry_.get();
2913 0 : if (rflow) {
2914 0 : const VnEntry *rvn = rflow->vn_entry();
2915 0 : if (rvn && rvn->GetVrf()) {
2916 0 : SetMirrorVrf(rvn->GetVrf()->vrf_id());
2917 : }
2918 : }
2919 : }
2920 78 : }
2921 :
2922 11 : void FlowEntry::MakeShortFlow(FlowShortReason reason) {
2923 11 : if (!is_flags_set(FlowEntry::ShortFlow)) {
2924 0 : set_flags(FlowEntry::ShortFlow);
2925 0 : short_flow_reason_ = reason;
2926 : }
2927 22 : if (reverse_flow_entry_ &&
2928 33 : !reverse_flow_entry_->is_flags_set(FlowEntry::ShortFlow)) {
2929 0 : reverse_flow_entry_->set_flags(FlowEntry::ShortFlow);
2930 0 : reverse_flow_entry_->short_flow_reason_ = reason;
2931 : }
2932 11 : }
2933 :
2934 89 : void FlowEntry::UpdateReflexiveAction() {
2935 89 : FlowEntry *rflow = reverse_flow_entry_.get();
2936 89 : SessionPolicy *r_sg_policy = NULL;
2937 89 : SessionPolicy *r_aps_policy = NULL;
2938 89 : SessionPolicy *r_fwaas_policy = NULL;
2939 :
2940 89 : if (rflow) {
2941 89 : r_sg_policy = &(rflow->data_.match_p.sg_policy);
2942 89 : r_aps_policy = &(rflow->data_.match_p.aps_policy);
2943 89 : r_fwaas_policy = &(rflow->data_.match_p.fwaas_policy);
2944 : }
2945 :
2946 89 : UpdateReflexiveAction(&data_.match_p.sg_policy, r_sg_policy);
2947 89 : UpdateReflexiveAction(&data_.match_p.aps_policy, r_aps_policy);
2948 89 : UpdateReflexiveAction(&data_.match_p.fwaas_policy, r_fwaas_policy);
2949 89 : }
2950 :
2951 267 : void FlowEntry::UpdateReflexiveAction(SessionPolicy *sp, SessionPolicy *rsp) {
2952 267 : sp->action = (1 << TrafficAction::PASS);
2953 267 : sp->out_action = (1 << TrafficAction::PASS);
2954 267 : sp->reverse_action = (1 << TrafficAction::PASS);;
2955 267 : sp->reverse_out_action = (1 << TrafficAction::PASS);
2956 267 : sp->action_summary = rsp->action_summary;
2957 :
2958 267 : if (ShouldDrop(sp->action_summary) == false) {
2959 242 : return;
2960 : }
2961 :
2962 25 : sp->action &= ~(TrafficAction::DROP_FLAGS);
2963 25 : sp->action |= (1 << TrafficAction::TRAP);
2964 : }
2965 :
2966 : /////////////////////////////////////////////////////////////////////////////
2967 : // Routines to manage pending actions on a flow. The pending actions are used
2968 : // to state-compress actions trigged due to update of,
2969 : // - DBEntries like interface, ACL etc..
2970 : // - Routes
2971 : /////////////////////////////////////////////////////////////////////////////
2972 10000 : FlowPendingAction::FlowPendingAction() {
2973 10000 : Reset();
2974 10000 : }
2975 :
2976 10000 : FlowPendingAction::~FlowPendingAction() {
2977 10000 : }
2978 :
2979 30188 : void FlowPendingAction::Reset() {
2980 30188 : delete_ = false;
2981 30188 : recompute_ = false;
2982 30188 : recompute_dbentry_ = false;
2983 30188 : revaluate_ = false;
2984 30188 : }
2985 :
2986 58 : bool FlowPendingAction::SetDelete() {
2987 58 : if (delete_)
2988 21 : return false;
2989 :
2990 37 : delete_ = true;
2991 37 : return true;
2992 : }
2993 :
2994 37 : void FlowPendingAction::ResetDelete() {
2995 37 : delete_ = false;
2996 37 : recompute_ = false;
2997 37 : recompute_dbentry_ = false;
2998 37 : revaluate_ = false;
2999 37 : }
3000 :
3001 37 : bool FlowPendingAction::CanDelete() {
3002 37 : return delete_;
3003 : }
3004 :
3005 27 : bool FlowPendingAction::SetRecompute() {
3006 27 : if (delete_ || recompute_)
3007 2 : return false;
3008 :
3009 25 : recompute_ = true;
3010 25 : return true;
3011 : }
3012 :
3013 50 : void FlowPendingAction::ResetRecompute() {
3014 50 : recompute_ = false;
3015 50 : recompute_dbentry_ = false;
3016 50 : revaluate_ = false;
3017 50 : }
3018 :
3019 25 : bool FlowPendingAction::CanRecompute() {
3020 25 : if (delete_)
3021 0 : return false;
3022 :
3023 25 : return recompute_;
3024 : }
3025 :
3026 71 : bool FlowPendingAction::SetRecomputeDBEntry() {
3027 71 : if (delete_ || recompute_ || recompute_dbentry_)
3028 12 : return false;
3029 :
3030 59 : recompute_dbentry_ = true;
3031 59 : return true;
3032 : }
3033 :
3034 59 : void FlowPendingAction::ResetRecomputeDBEntry() {
3035 59 : recompute_dbentry_ = false;
3036 59 : revaluate_ = false;
3037 59 : }
3038 :
3039 59 : bool FlowPendingAction::CanRecomputeDBEntry() {
3040 59 : if (delete_ || recompute_)
3041 26 : return false;
3042 :
3043 33 : return recompute_dbentry_;
3044 : }
3045 :
3046 15 : bool FlowPendingAction::SetRevaluate() {
3047 15 : if (delete_ || recompute_ || recompute_dbentry_ || revaluate_)
3048 12 : return false;
3049 :
3050 3 : revaluate_ = true;
3051 3 : return true;
3052 : }
3053 :
3054 6 : void FlowPendingAction::ResetRevaluate() {
3055 6 : revaluate_ = false;
3056 6 : }
3057 :
3058 3 : bool FlowPendingAction::CanRevaluate() {
3059 3 : if (delete_ || recompute_ || recompute_dbentry_)
3060 0 : return false;
3061 :
3062 3 : return revaluate_;
3063 : }
3064 :
3065 : /////////////////////////////////////////////////////////////////////////////
3066 : // Introspect routines
3067 : /////////////////////////////////////////////////////////////////////////////
3068 0 : void SetActionStr(const FlowAction &action_info,
3069 : std::vector<ActionStr> &action_str_l) {
3070 0 : std::bitset<32> bs(action_info.action);
3071 0 : for (unsigned int i = 0; i < bs.size(); i++) {
3072 0 : if (bs[i]) {
3073 0 : ActionStr astr;
3074 : astr.action =
3075 0 : TrafficAction::ActionToString((TrafficAction::Action)i);
3076 0 : action_str_l.push_back(astr);
3077 0 : if ((TrafficAction::Action)i == TrafficAction::MIRROR) {
3078 0 : std::vector<MirrorActionSpec>::const_iterator m_it;
3079 0 : for (m_it = action_info.mirror_l.begin();
3080 0 : m_it != action_info.mirror_l.end();
3081 0 : ++m_it) {
3082 0 : ActionStr mstr;
3083 0 : mstr.action += (*m_it).ip.to_string();
3084 0 : mstr.action += " ";
3085 0 : mstr.action += integerToString((*m_it).port);
3086 0 : mstr.action += " ";
3087 0 : mstr.action += (*m_it).vrf_name;
3088 0 : mstr.action += " ";
3089 0 : mstr.action += (*m_it).encap;
3090 0 : action_str_l.push_back(mstr);
3091 0 : }
3092 : }
3093 0 : if ((TrafficAction::Action)i == TrafficAction::VRF_TRANSLATE) {
3094 0 : ActionStr vrf_action_str;
3095 : vrf_action_str.action +=
3096 0 : action_info.vrf_translate_action_.vrf_name();
3097 0 : action_str_l.push_back(vrf_action_str);
3098 0 : }
3099 0 : if ((TrafficAction::Action)i == TrafficAction::HBS) {
3100 0 : ActionStr hbf_action_str;
3101 0 : hbf_action_str.action += "hbs";
3102 0 : action_str_l.push_back(hbf_action_str);
3103 0 : }
3104 0 : }
3105 : }
3106 0 : }
3107 :
3108 0 : static void SetAclListAclAction(const std::list<MatchAclParams> &acl_l,
3109 : std::vector<AclAction> &acl_action_l,
3110 : std::string &acl_type) {
3111 0 : std::list<MatchAclParams>::const_iterator it;
3112 0 : for(it = acl_l.begin(); it != acl_l.end(); ++it) {
3113 0 : AclAction acl_action;
3114 0 : acl_action.set_acl_id(UuidToString((*it).acl->GetUuid()));
3115 0 : acl_action.set_acl_type(acl_type);
3116 0 : std::vector<ActionStr> action_str_l;
3117 0 : SetActionStr((*it).action_info, action_str_l);
3118 0 : acl_action.set_action_l(action_str_l);
3119 0 : acl_action_l.push_back(acl_action);
3120 0 : }
3121 0 : }
3122 :
3123 0 : void FlowEntry::SetAclAction(std::vector<AclAction> &acl_action_l) const {
3124 0 : const std::list<MatchAclParams> &acl_l = data_.match_p.m_acl_l;
3125 0 : std::string acl_type("nw policy");
3126 0 : SetAclListAclAction(acl_l, acl_action_l, acl_type);
3127 :
3128 0 : const std::list<MatchAclParams> &sg_acl_l = data_.match_p.sg_policy.m_acl_l;
3129 0 : acl_type = "sg";
3130 0 : SetAclListAclAction(sg_acl_l, acl_action_l, acl_type);
3131 :
3132 0 : const std::list<MatchAclParams> &m_acl_l = data_.match_p.m_mirror_acl_l;
3133 0 : acl_type = "dynamic";
3134 0 : SetAclListAclAction(m_acl_l, acl_action_l, acl_type);
3135 :
3136 0 : const std::list<MatchAclParams> &out_acl_l = data_.match_p.m_out_acl_l;
3137 0 : acl_type = "o nw policy";
3138 0 : SetAclListAclAction(out_acl_l, acl_action_l, acl_type);
3139 :
3140 0 : const std::list<MatchAclParams> &out_sg_acl_l =
3141 : data_.match_p.sg_policy.m_out_acl_l;
3142 0 : acl_type = "o sg";
3143 0 : SetAclListAclAction(out_sg_acl_l, acl_action_l, acl_type);
3144 :
3145 0 : const std::list<MatchAclParams> &out_m_acl_l =
3146 : data_.match_p.m_out_mirror_acl_l;
3147 0 : acl_type = "o dynamic";
3148 0 : SetAclListAclAction(out_m_acl_l, acl_action_l, acl_type);
3149 :
3150 0 : const std::list<MatchAclParams> &r_sg_l = data_.match_p.sg_policy.m_reverse_acl_l;
3151 0 : acl_type = "r sg";
3152 0 : SetAclListAclAction(r_sg_l, acl_action_l, acl_type);
3153 :
3154 0 : const std::list<MatchAclParams> &r_out_sg_l =
3155 : data_.match_p.sg_policy.m_reverse_out_acl_l;
3156 0 : acl_type = "r o sg";
3157 0 : SetAclListAclAction(r_out_sg_l, acl_action_l, acl_type);
3158 :
3159 0 : const std::list<MatchAclParams> &vrf_assign_acl_l =
3160 : data_.match_p.m_vrf_assign_acl_l;
3161 0 : acl_type = "vrf assign";
3162 0 : SetAclListAclAction(vrf_assign_acl_l, acl_action_l, acl_type);
3163 :
3164 0 : const std::list<MatchAclParams> &aps_l =
3165 : data_.match_p.aps_policy.m_acl_l;
3166 0 : acl_type = "fw acl";
3167 0 : SetAclListAclAction(aps_l, acl_action_l, acl_type);
3168 :
3169 0 : const std::list<MatchAclParams> &out_aps_l =
3170 : data_.match_p.aps_policy.m_out_acl_l;
3171 0 : acl_type = "reverse fw acl";
3172 0 : SetAclListAclAction(out_aps_l,
3173 : acl_action_l, acl_type);
3174 :
3175 0 : const std::list<MatchAclParams> &fwaas_l =
3176 : data_.match_p.fwaas_policy.m_acl_l;
3177 0 : acl_type = "fwaas acl";
3178 0 : SetAclListAclAction(fwaas_l, acl_action_l, acl_type);
3179 :
3180 0 : const std::list<MatchAclParams> &out_fwaas_l =
3181 : data_.match_p.fwaas_policy.m_out_acl_l;
3182 0 : acl_type = "reverse fwaas acl";
3183 0 : SetAclListAclAction(out_fwaas_l,
3184 : acl_action_l, acl_type);
3185 0 : }
3186 :
3187 74 : void FlowEntry::FillFlowInfo(FlowInfo &info) const {
3188 74 : info.set_gen_id(gen_id_);
3189 74 : info.set_flow_index(flow_handle_);
3190 74 : if (key_.family == Address::INET) {
3191 74 : info.set_source_ip(key_.src_addr.to_v4().to_ulong());
3192 74 : info.set_destination_ip(key_.dst_addr.to_v4().to_ulong());
3193 : } else {
3194 : uint64_t sip[2], dip[2];
3195 0 : Ip6AddressToU64Array(key_.src_addr.to_v6(), sip, 2);
3196 0 : Ip6AddressToU64Array(key_.dst_addr.to_v6(), dip, 2);
3197 0 : info.set_sip_upper(sip[0]);
3198 0 : info.set_sip_lower(sip[1]);
3199 0 : info.set_dip_upper(dip[0]);
3200 0 : info.set_dip_lower(dip[1]);
3201 0 : info.set_source_ip(0);
3202 0 : info.set_destination_ip(0);
3203 : }
3204 74 : info.set_source_port(key_.src_port);
3205 74 : info.set_destination_port(key_.dst_port);
3206 74 : info.set_protocol(key_.protocol);
3207 74 : info.set_hbs_intf_dir(hbs_intf_);
3208 74 : info.set_nh_id(key_.nh);
3209 74 : info.set_vrf(data_.vrf);
3210 74 : info.set_source_vn_list(data_.SourceVnList());
3211 74 : info.set_dest_vn_list(data_.DestinationVnList());
3212 74 : info.set_source_vn_match(data_.source_vn_match);
3213 74 : info.set_dest_vn_match(data_.dest_vn_match);
3214 74 : std::vector<uint32_t> v;
3215 74 : SecurityGroupList::const_iterator it;
3216 74 : for (it = data_.source_sg_id_l.begin();
3217 83 : it != data_.source_sg_id_l.end(); it++) {
3218 9 : v.push_back(*it);
3219 : }
3220 74 : info.set_source_sg_id_l(v);
3221 74 : v.clear();
3222 83 : for (it = data_.dest_sg_id_l.begin(); it != data_.dest_sg_id_l.end();
3223 9 : it++) {
3224 9 : v.push_back(*it);
3225 : }
3226 74 : info.set_dest_sg_id_l(v);
3227 :
3228 74 : uint32_t fe_action = data_.match_p.action_info.action;
3229 74 : if (fe_action & (1 << TrafficAction::DENY)) {
3230 6 : info.set_deny(true);
3231 68 : } else if (fe_action & (1 << TrafficAction::PASS)) {
3232 44 : info.set_allow(true);
3233 : }
3234 :
3235 74 : if (reverse_flow_entry_.get()) {
3236 44 : info.set_reverse_index(reverse_flow_entry_->flow_handle());
3237 : }
3238 :
3239 74 : if (is_flags_set(FlowEntry::NatFlow)) {
3240 0 : info.set_nat(true);
3241 0 : FlowEntry *nat_flow = reverse_flow_entry_.get();
3242 : // TODO : IPv6
3243 0 : if (nat_flow) {
3244 0 : if (key_.src_addr != nat_flow->key().dst_addr) {
3245 0 : if (key_.family == Address::INET) {
3246 : info.set_nat_source_ip
3247 0 : (nat_flow->key().dst_addr.to_v4().to_ulong());
3248 : } else {
3249 0 : info.set_nat_source_ip(0);
3250 : }
3251 : }
3252 :
3253 0 : if (key_.dst_addr != nat_flow->key().src_addr) {
3254 0 : if (key_.family == Address::INET) {
3255 : info.set_nat_destination_ip
3256 0 : (nat_flow->key().src_addr.to_v4().to_ulong());
3257 : } else {
3258 0 : info.set_nat_destination_ip(0);
3259 : }
3260 : }
3261 :
3262 0 : if (key_.src_port != nat_flow->key().dst_port) {
3263 0 : info.set_nat_source_port(nat_flow->key().dst_port);
3264 : }
3265 :
3266 0 : if (key_.dst_port != nat_flow->key().src_port) {
3267 0 : info.set_nat_destination_port(nat_flow->key().src_port);
3268 : }
3269 0 : info.set_nat_protocol(nat_flow->key().protocol);
3270 0 : info.set_nat_vrf(data_.dest_vrf);
3271 0 : info.set_nat_mirror_vrf(nat_flow->data().mirror_vrf);
3272 : }
3273 : }
3274 :
3275 74 : if (data_.match_p.action_info.action & (1 << TrafficAction::MIRROR)) {
3276 0 : info.set_mirror(true);
3277 0 : std::vector<MirrorActionSpec>::const_iterator it;
3278 0 : std::vector<MirrorInfo> mirror_l;
3279 0 : for (it = data_.match_p.action_info.mirror_l.begin();
3280 0 : it != data_.match_p.action_info.mirror_l.end();
3281 0 : ++it) {
3282 0 : MirrorInfo mirror_info;
3283 0 : mirror_info.set_mirror_destination((*it).ip.to_string());
3284 0 : mirror_info.set_mirror_port((*it).port);
3285 0 : mirror_info.set_mirror_vrf((*it).vrf_name);
3286 0 : mirror_info.set_analyzer((*it).analyzer_name);
3287 0 : mirror_l.push_back(mirror_info);
3288 0 : }
3289 0 : info.set_mirror_l(mirror_l);
3290 0 : }
3291 74 : info.set_mirror_vrf(data_.mirror_vrf);
3292 74 : info.set_implicit_deny(ImplicitDenyFlow());
3293 74 : info.set_short_flow(is_flags_set(FlowEntry::ShortFlow));
3294 74 : if (is_flags_set(FlowEntry::EcmpFlow) &&
3295 0 : data_.component_nh_idx != CompositeNH::kInvalidComponentNHIdx) {
3296 0 : info.set_ecmp_index(data_.component_nh_idx);
3297 : }
3298 74 : if (is_flags_set(FlowEntry::Trap)) {
3299 0 : info.set_trap(true);
3300 : }
3301 74 : info.set_vrf_assign(acl_assigned_vrf());
3302 74 : info.set_l3_flow(l3_flow_);
3303 74 : info.set_smac(data_.smac.ToString());
3304 74 : info.set_dmac(data_.dmac.ToString());
3305 74 : info.set_short_flow_reason(FlowEntry::DropReasonStr(short_flow_reason_));
3306 74 : info.set_drop_reason(FlowEntry::DropReasonStr(data_.drop_reason));
3307 74 : if (flow_table_) {
3308 74 : info.set_table_id(flow_table_->table_index());
3309 : }
3310 :
3311 74 : if (rpf_nh()) {
3312 64 : info.set_rpf_nh(rpf_nh()->id());
3313 : } else {
3314 10 : info.set_rpf_nh(0xFFFFFFFF);
3315 : }
3316 74 : if (src_ip_nh()) {
3317 64 : info.set_src_ip_nh(src_ip_nh()->id());
3318 : } else {
3319 10 : info.set_src_ip_nh(0xFFFFFFFF);
3320 : }
3321 74 : }
3322 :
3323 0 : static void SetAclListAceId(const AclDBEntry *acl,
3324 : const MatchAclParamsList &acl_l,
3325 : std::vector<AceId> &ace_l) {
3326 0 : std::list<MatchAclParams>::const_iterator ma_it;
3327 0 : for (ma_it = acl_l.begin();
3328 0 : ma_it != acl_l.end();
3329 0 : ++ma_it) {
3330 0 : if ((*ma_it).acl != acl) {
3331 0 : continue;
3332 : }
3333 0 : AclEntryIDList::const_iterator ait;
3334 0 : for (ait = (*ma_it).ace_id_list.begin();
3335 0 : ait != (*ma_it).ace_id_list.end(); ++ ait) {
3336 0 : AceId ace_id;
3337 0 : ace_id.id = ait->id_;
3338 0 : ace_l.push_back(ace_id);
3339 0 : }
3340 : }
3341 0 : }
3342 :
3343 0 : void FlowEntry::SetAclFlowSandeshData(const AclDBEntry *acl,
3344 : FlowSandeshData &fe_sandesh_data, Agent *agent) const {
3345 0 : fe_sandesh_data.set_vrf(integerToString(data_.vrf));
3346 0 : fe_sandesh_data.set_src(key_.src_addr.to_string());
3347 0 : fe_sandesh_data.set_dst(key_.dst_addr.to_string());
3348 0 : fe_sandesh_data.set_src_port(key_.src_port);
3349 0 : fe_sandesh_data.set_dst_port(key_.dst_port);
3350 0 : fe_sandesh_data.set_protocol(key_.protocol);
3351 0 : fe_sandesh_data.set_ingress(is_flags_set(FlowEntry::IngressDir));
3352 0 : std::vector<ActionStr> action_str_l;
3353 0 : SetActionStr(data_.match_p.action_info, action_str_l);
3354 0 : fe_sandesh_data.set_action_l(action_str_l);
3355 :
3356 0 : std::vector<AclAction> acl_action_l;
3357 0 : SetAclAction(acl_action_l);
3358 0 : fe_sandesh_data.set_acl_action_l(acl_action_l);
3359 :
3360 0 : fe_sandesh_data.set_flow_handle(integerToString(flow_handle_));
3361 0 : if (!data_.origin_vn_src.empty()) {
3362 0 : fe_sandesh_data.set_source_vn(data_.origin_vn_src);
3363 : } else {
3364 0 : fe_sandesh_data.set_source_vn(data_.source_vn_match);
3365 : }
3366 0 : if (!data_.origin_vn_dst.empty()) {
3367 0 : fe_sandesh_data.set_dest_vn(data_.origin_vn_dst);
3368 : } else {
3369 0 : fe_sandesh_data.set_dest_vn(data_.dest_vn_match);
3370 : }
3371 0 : if (!data_.OriginVnSrcList().empty()) {
3372 0 : fe_sandesh_data.set_source_vn_list(data_.OriginVnSrcList());
3373 : } else {
3374 0 : fe_sandesh_data.set_source_vn_list(data_.SourceVnList());
3375 : }
3376 0 : if (!data_.OriginVnDstList().empty()) {
3377 0 : fe_sandesh_data.set_dest_vn_list(data_.OriginVnDstList());
3378 : } else {
3379 0 : fe_sandesh_data.set_dest_vn_list(data_.DestinationVnList());
3380 : }
3381 0 : std::vector<uint32_t> v;
3382 0 : SecurityGroupList::const_iterator it;
3383 0 : for (it = data_.source_sg_id_l.begin();
3384 0 : it != data_.source_sg_id_l.end(); it++) {
3385 0 : v.push_back(*it);
3386 : }
3387 0 : fe_sandesh_data.set_source_sg_id_l(v);
3388 0 : v.clear();
3389 0 : for (it = data_.dest_sg_id_l.begin(); it != data_.dest_sg_id_l.end();
3390 0 : it++) {
3391 0 : v.push_back(*it);
3392 : }
3393 0 : fe_sandesh_data.set_dest_sg_id_l(v);
3394 0 : fe_sandesh_data.set_flow_uuid(UuidToString(uuid()));
3395 0 : if (fsc_) {
3396 0 : const FlowExportInfo *info = fsc_->FindFlowExportInfo(this);
3397 0 : if (info) {
3398 0 : fe_sandesh_data.set_bytes(integerToString(info->bytes()));
3399 0 : fe_sandesh_data.set_packets(integerToString(info->packets()));
3400 0 : if (info->teardown_time()) {
3401 0 : fe_sandesh_data.set_teardown_time(
3402 0 : integerToString(UTCUsecToPTime(info->teardown_time())));
3403 : } else {
3404 0 : fe_sandesh_data.set_teardown_time("");
3405 : }
3406 : }
3407 : }
3408 0 : fe_sandesh_data.set_current_time(integerToString(
3409 0 : UTCUsecToPTime(UTCTimestampUsec())));
3410 :
3411 0 : SetAclListAceId(acl, data_.match_p.m_acl_l, fe_sandesh_data.ace_l);
3412 0 : SetAclListAceId(acl, data_.match_p.sg_policy.m_acl_l, fe_sandesh_data.ace_l);
3413 0 : SetAclListAceId(acl, data_.match_p.m_mirror_acl_l, fe_sandesh_data.ace_l);
3414 0 : SetAclListAceId(acl, data_.match_p.m_out_acl_l, fe_sandesh_data.ace_l);
3415 0 : SetAclListAceId(acl, data_.match_p.sg_policy.m_reverse_acl_l,
3416 0 : fe_sandesh_data.ace_l);
3417 0 : SetAclListAceId(acl, data_.match_p.sg_policy.m_reverse_out_acl_l,
3418 0 : fe_sandesh_data.ace_l);
3419 0 : SetAclListAceId(acl, data_.match_p.sg_policy.m_out_acl_l, fe_sandesh_data.ace_l);
3420 0 : SetAclListAceId(acl, data_.match_p.m_out_mirror_acl_l,
3421 0 : fe_sandesh_data.ace_l);
3422 0 : SetAclListAceId(acl, data_.match_p.m_vrf_assign_acl_l,
3423 0 : fe_sandesh_data.ace_l);
3424 0 : SetAclListAceId(acl, data_.match_p.aps_policy.m_acl_l,
3425 0 : fe_sandesh_data.ace_l);
3426 0 : SetAclListAceId(acl, data_.match_p.aps_policy.m_out_acl_l,
3427 0 : fe_sandesh_data.ace_l);
3428 0 : SetAclListAceId(acl, data_.match_p.fwaas_policy.m_acl_l,
3429 0 : fe_sandesh_data.ace_l);
3430 0 : SetAclListAceId(acl, data_.match_p.fwaas_policy.m_out_acl_l,
3431 0 : fe_sandesh_data.ace_l);
3432 :
3433 0 : fe_sandesh_data.set_reverse_flow(is_flags_set(FlowEntry::ReverseFlow) ?
3434 : "yes" : "no");
3435 0 : fe_sandesh_data.set_nat(is_flags_set(FlowEntry::NatFlow) ? "yes" : "no");
3436 0 : fe_sandesh_data.set_implicit_deny(ImplicitDenyFlow() ? "yes" : "no");
3437 0 : fe_sandesh_data.set_short_flow(is_flags_set(FlowEntry::ShortFlow) ?
3438 : "yes" : "no");
3439 0 : fe_sandesh_data.set_l3_flow(l3_flow_);
3440 0 : fe_sandesh_data.set_smac(data_.smac.ToString());
3441 0 : fe_sandesh_data.set_dmac(data_.dmac.ToString());
3442 0 : }
3443 :
3444 0 : string FlowEntry::KeyString() const {
3445 0 : std::ostringstream str;
3446 0 : int idx = flow_handle_ == FlowEntry::kInvalidFlowHandle ? -1 : flow_handle_;
3447 0 : str << " Idx : " << idx
3448 0 : << " Key : "
3449 0 : << key_.nh << " "
3450 0 : << key_.src_addr.to_string() << ":"
3451 0 : << key_.src_port << " "
3452 0 : << key_.dst_addr.to_string() << ":"
3453 0 : << key_.dst_port << " "
3454 0 : << (uint16_t)key_.protocol;
3455 0 : return str.str();
3456 0 : }
3457 :
3458 0 : static std::string EventToString(FlowEventLog::Event event,
3459 : std::string &event_str) {
3460 0 : switch (event) {
3461 0 : case FlowEventLog::FLOW_ADD:
3462 0 : event_str = "FlowAdd";
3463 0 : break;
3464 0 : case FlowEventLog::FLOW_UPDATE:
3465 0 : event_str = "FlowUpdate";
3466 0 : break;
3467 0 : case FlowEventLog::FLOW_DELETE:
3468 0 : event_str = "FlowDelete";
3469 0 : break;
3470 0 : case FlowEventLog::FLOW_EVICT:
3471 0 : event_str = "FlowEvict";
3472 0 : break;
3473 0 : case FlowEventLog::FLOW_HANDLE_ASSIGN:
3474 0 : event_str = "FlowHandleAssign";
3475 0 : break;
3476 0 : case FlowEventLog::FLOW_MSG_SKIP_EVICTED:
3477 0 : event_str = "FlowMessageSkippedEvictedFlow";
3478 0 : break;
3479 0 : default:
3480 0 : event_str = "Unknown";
3481 0 : break;
3482 : }
3483 0 : return event_str;
3484 : }
3485 :
3486 0 : void FlowEntry::SetEventSandeshData(SandeshFlowIndexInfo *info) {
3487 : KSyncFlowIndexManager *mgr =
3488 0 : flow_table_->agent()->ksync()->ksync_flow_index_manager();
3489 0 : info->set_trace_index(event_log_index_);
3490 0 : if (mgr->sm_log_count() == 0) {
3491 0 : return;
3492 : }
3493 0 : int start = 0;
3494 0 : int count = event_log_index_;
3495 0 : if (event_log_index_ >= mgr->sm_log_count()) {
3496 0 : start = event_log_index_ % mgr->sm_log_count();
3497 0 : count = mgr->sm_log_count();
3498 : }
3499 0 : std::vector<SandeshFlowIndexTrace> trace_list;
3500 0 : for (int i = 0; i < count; i++) {
3501 0 : SandeshFlowIndexTrace trace;
3502 0 : FlowEventLog *log = &event_logs_[((start + i) % mgr->sm_log_count())];
3503 0 : trace.set_timestamp(log->time_);
3504 0 : trace.set_flow_handle(log->flow_handle_);
3505 0 : trace.set_flow_gen_id(log->flow_gen_id_);
3506 0 : string event_str;
3507 0 : trace.set_event(EventToString(log->event_, event_str));
3508 0 : trace.set_ksync_hash_id(log->hash_id_);
3509 0 : trace.set_ksync_gen_id(log->gen_id_);
3510 0 : trace.set_vrouter_flow_handle(log->vrouter_flow_handle_);
3511 0 : trace.set_vrouter_gen_id(log->vrouter_gen_id_);
3512 0 : trace_list.push_back(trace);
3513 0 : }
3514 0 : info->set_flow_index_trace(trace_list);
3515 0 : }
3516 :
3517 188 : void FlowEntry::LogFlow(FlowEventLog::Event event, FlowTableKSyncEntry* ksync,
3518 : uint32_t flow_handle, uint8_t gen_id) {
3519 : KSyncFlowIndexManager *mgr =
3520 188 : flow_table_->agent()->ksync()->ksync_flow_index_manager();
3521 188 : string event_str;
3522 188 : LOG(DEBUG, "Flow event = " << EventToString(event, event_str)
3523 : << " flow = " << (void *)this
3524 : << " flow->flow_handle = " << flow_handle_
3525 : << " flow->gen_id = " << (int)gen_id_
3526 : << " ksync = " << (void *)ksync
3527 : << " Ksync->hash_id = " << ((ksync != NULL) ? ksync->hash_id() : -1)
3528 : << " Ksync->gen_id = " << ((ksync != NULL) ? (int)ksync->gen_id() : 0)
3529 : << " new_flow_handle = " << flow_handle
3530 : << " new_gen_id = " << (int)gen_id);
3531 :
3532 188 : if (mgr->sm_log_count() == 0) {
3533 188 : return;
3534 : }
3535 :
3536 0 : if (event_logs_ == NULL) {
3537 0 : event_log_index_ = 0;
3538 0 : event_logs_.reset(new FlowEventLog[mgr->sm_log_count()]);
3539 : }
3540 :
3541 0 : FlowEventLog *log = &event_logs_[event_log_index_ % mgr->sm_log_count()];
3542 0 : event_log_index_++;
3543 :
3544 0 : log->time_ = ClockMonotonicUsec();
3545 0 : log->event_ = event;
3546 0 : log->flow_handle_ = flow_handle_;
3547 0 : log->flow_gen_id_ = gen_id_;
3548 0 : log->ksync_entry_ = ksync;
3549 0 : log->hash_id_ = (ksync != NULL) ? ksync->hash_id() : -1;
3550 0 : log->gen_id_ = (ksync != NULL) ? ksync->gen_id() : 0;
3551 0 : log->vrouter_flow_handle_ = flow_handle;
3552 0 : log->vrouter_gen_id_ = gen_id;
3553 188 : }
3554 :
3555 190 : const TagList &FlowEntry::local_tagset() const {
3556 190 : if (is_flags_set(FlowEntry::IngressDir)) {
3557 115 : return data_.source_tag_id_l;
3558 : }
3559 75 : return data_.dest_tag_id_l;
3560 : }
3561 :
3562 380 : const TagList &FlowEntry::remote_tagset() const {
3563 380 : if (is_flags_set(FlowEntry::IngressDir)) {
3564 230 : return data_.dest_tag_id_l;
3565 : }
3566 150 : return data_.source_tag_id_l;
3567 : }
3568 :
3569 190 : const std::string FlowEntry::BuildRemotePrefix(const FlowRouteRefMap &rt_list,
3570 : uint32_t vrf,
3571 : const IpAddress &ip) const {
3572 190 : int plen = -1;
3573 190 : FlowRouteRefMap::const_iterator it;
3574 222 : for (it = rt_list.begin(); it != rt_list.end(); it++) {
3575 32 : if (it->first == static_cast<int>(vrf)) {
3576 0 : plen = it->second;
3577 0 : break;
3578 : }
3579 : }
3580 190 : if (plen != -1) {
3581 0 : return ip.to_string() + "/" + integerToString(plen);
3582 : }
3583 190 : return "";
3584 : }
3585 :
3586 : /* Remote prefix is required only wnen remote_tagset is absent. Returns empty
3587 : * string as remote-prefix when remote-tagset is present */
3588 190 : const std::string FlowEntry::RemotePrefix() const {
3589 190 : if (remote_tagset().size() > 0) {
3590 0 : return "";
3591 : }
3592 190 : if (is_flags_set(FlowEntry::IngressDir)) {
3593 115 : return BuildRemotePrefix(data_.flow_dest_plen_map,
3594 115 : data_.flow_dest_vrf, key_.dst_addr);
3595 : }
3596 75 : return BuildRemotePrefix(data_.flow_source_plen_map, data_.flow_source_vrf,
3597 75 : key_.src_addr);
3598 : }
3599 :
3600 100 : void FlowEntry::FillUveVnAceInfo(FlowUveVnAcePolicyInfo *info) const {
3601 100 : const VnEntry *vn = vn_entry();
3602 100 : info->vn_ = vn? vn->GetName() : "";
3603 100 : info->nw_ace_uuid_ = nw_ace_uuid();
3604 100 : if (!info->vn_.empty() && !info->nw_ace_uuid_.empty()) {
3605 100 : info->is_valid_ = true;
3606 : }
3607 100 : }
3608 :
3609 27 : void FlowEntry::FillUveLocalRevFlowStatsInfo(FlowUveFwPolicyInfo *info,
3610 : bool added) const {
3611 27 : info->initiator_ = false;
3612 27 : info->local_vn_ = data_.source_vn_match;
3613 27 : info->remote_vn_ = data_.dest_vn_match;
3614 27 : info->local_tagset_ = local_tagset();
3615 27 : info->remote_tagset_ = remote_tagset();
3616 27 : info->fw_policy_ = fw_policy_name_uuid();
3617 27 : info->remote_prefix_ = RemotePrefix();
3618 27 : info->added_ = added;
3619 27 : if (is_flags_set(FlowEntry::ShortFlow)) {
3620 2 : info->short_flow_ = true;
3621 : } else {
3622 25 : info->short_flow_ = false;
3623 : }
3624 27 : FlowTable::GetFlowSandeshActionParams(data().match_p.action_info,
3625 27 : info->action_);
3626 27 : info->is_valid_ = true;
3627 27 : }
3628 :
3629 51 : void FlowEntry::FillUveFwdFlowStatsInfo(FlowUveFwPolicyInfo *info,
3630 : bool added) const {
3631 51 : if (is_flags_set(FlowEntry::IngressDir)) {
3632 28 : info->initiator_ = true;
3633 28 : info->local_vn_ = data_.source_vn_match;
3634 28 : info->remote_vn_ = data_.dest_vn_match;
3635 : } else {
3636 23 : info->initiator_ = false;
3637 23 : info->local_vn_ = data_.dest_vn_match;
3638 23 : info->remote_vn_ = data_.source_vn_match;
3639 : }
3640 51 : info->local_tagset_ = local_tagset();
3641 51 : info->remote_tagset_ = remote_tagset();
3642 51 : info->fw_policy_ = fw_policy_name_uuid();
3643 51 : info->remote_prefix_ = RemotePrefix();
3644 51 : info->added_ = added;
3645 51 : if (is_flags_set(FlowEntry::ShortFlow)) {
3646 11 : info->short_flow_ = true;
3647 : } else {
3648 40 : info->short_flow_ = false;
3649 : }
3650 51 : FlowTable::GetFlowSandeshActionParams(data().match_p.action_info,
3651 51 : info->action_);
3652 51 : info->is_valid_ = true;
3653 51 : }
3654 :
3655 107 : void FlowEntry::FillUveFwStatsInfo(FlowUveFwPolicyInfo *info,
3656 : bool added) const {
3657 : /* Endpoint statistics update is not required in the following
3658 : * cases
3659 : * 1. When flow has empty policy_set_acl_name. One example of this
3660 : * case is when matching rule for flow is IMPLICIT_ALLOW
3661 : * 2. Link local flows
3662 : * 3. Reverse flows. We need session_count and not flow_count. So we
3663 : * consider only forward flows.
3664 : *
3665 : * Also count is updated only for forward-flow as the count
3666 : * indicates session_count and NOT flow-count
3667 : */
3668 163 : if (is_flags_set(FlowEntry::ReverseFlow) &&
3669 163 : !is_flags_set(FlowEntry::LocalFlow)) {
3670 29 : return;
3671 : }
3672 78 : if (is_flags_set(FlowEntry::LocalFlow)) {
3673 49 : if (is_flags_set(FlowEntry::ReverseFlow)) {
3674 27 : FillUveLocalRevFlowStatsInfo(info, added);
3675 : } else {
3676 22 : FillUveFwdFlowStatsInfo(info, added);
3677 : }
3678 : } else {
3679 29 : FillUveFwdFlowStatsInfo(info, added);
3680 : }
3681 : }
3682 :
3683 259 : const std::string FlowEntry::fw_policy_uuid() const {
3684 259 : return data_.match_p.aps_policy.rule_uuid_;
3685 : }
3686 :
3687 190 : const std::string FlowEntry::fw_policy_name_uuid() const {
3688 : /* If policy-name is empty return only policy UUID. Policy-name will be
3689 : * empty when one of the implicit rules match */
3690 190 : if (data_.match_p.aps_policy.acl_name_.empty()) {
3691 190 : return fw_policy_uuid();
3692 : }
3693 0 : return data_.match_p.aps_policy.acl_name_ + ":" +
3694 0 : fw_policy_uuid();
3695 : }
3696 :
3697 88 : void FlowEntry::set_flow_mgmt_info(FlowEntryInfo *info) {
3698 88 : flow_mgmt_info_.reset(info);
3699 88 : }
3700 :
3701 94 : uint8_t FlowEntry::GetUnderlayGwIndex(uint32_t intf_in, const IpAddress &sip,
3702 : const IpAddress &dip, uint8_t proto, uint16_t sport,
3703 : uint16_t dport) const {
3704 94 : if ((!flow_table()->agent()->is_l3mh()) || (is_flags_set(FlowEntry::LocalFlow))) {
3705 94 : return -1;
3706 : }
3707 :
3708 0 : uint8_t underlay_gw_index = -1;
3709 0 : if (is_flags_set(FlowEntry::ReverseFlow)) {
3710 0 : FlowEntry *rflow = reverse_flow_entry_.get();
3711 0 : if (rflow != NULL) {
3712 0 : underlay_gw_index = rflow->data().underlay_gw_index_;
3713 : }
3714 0 : return underlay_gw_index;
3715 : }
3716 :
3717 : InetUnicastRouteEntry *rt = static_cast<InetUnicastRouteEntry *>
3718 0 : (FlowEntry::GetUcRoute(GetDestinationVrf(), dip));
3719 0 : const TunnelNH *tunnel_nh = rt != nullptr ?
3720 0 : dynamic_cast<const TunnelNH *>(rt->GetActiveNextHop()) : nullptr;
3721 :
3722 0 : if (!tunnel_nh && is_flags_set(FlowEntry::EcmpFlow) &&
3723 0 : data_.component_nh_idx != CompositeNH::kInvalidComponentNHIdx) {
3724 : // For composite nh set underlay gw index to component_nh_idx (same hash is used)
3725 0 : return (data_.component_nh_idx % (flow_table()->agent()->fabric_interface_name_list().size()));
3726 : }
3727 :
3728 : Interface *intf = flow_table()->agent()->interface_table()->
3729 0 : FindInterface(intf_in);
3730 0 : if (intf && intf->type() == Interface::PHYSICAL) {
3731 0 : underlay_gw_index = intf->id();
3732 0 : return underlay_gw_index;
3733 : } else {
3734 0 : std::size_t hash = 0;
3735 0 : hash = HashIp(hash, sip);
3736 0 : hash = HashIp(hash, dip);
3737 :
3738 0 : hash = HashCombine(hash, sport);
3739 0 : hash = HashCombine(hash, dport);
3740 0 : hash = HashCombine(hash, proto);
3741 0 : underlay_gw_index = hash % (flow_table()->agent()->fabric_interface_name_list().size());
3742 : }
3743 :
3744 0 : if (rt == nullptr) {
3745 0 : return -1;
3746 : }
3747 0 : if ( !(tunnel_nh && (tunnel_nh->IsValid()))) {
3748 0 : return -1;
3749 : }
3750 0 : uint8_t index = 0;
3751 0 : TunnelNH::EncapDataList encap_list = tunnel_nh->GetEncapDataList();
3752 0 : while (index < encap_list.size()) {
3753 0 : if (encap_list[index].get()->interface_.get() &&
3754 0 : underlay_gw_index == (encap_list[index].get()->interface_).get()->id()) {
3755 0 : underlay_gw_index = index;
3756 0 : break;
3757 : }
3758 0 : index++;
3759 : }
3760 :
3761 0 : if (tunnel_nh->IsEncapValid(underlay_gw_index)) {
3762 0 : return underlay_gw_index;
3763 0 : } else if ( ((underlay_gw_index +1) < (uint8_t)tunnel_nh->GetEncapDataList().size()) &&
3764 0 : tunnel_nh->IsEncapValid(underlay_gw_index +1)) {
3765 0 : return underlay_gw_index +1;
3766 0 : } else if (((underlay_gw_index +1) >= (uint8_t)tunnel_nh->GetEncapDataList().size()) &&
3767 0 : tunnel_nh->IsEncapValid(underlay_gw_index + 1 - tunnel_nh->GetEncapDataList().size())) {
3768 0 : return (underlay_gw_index + 1 - tunnel_nh->GetEncapDataList().size());
3769 : }
3770 0 : return -1;
3771 0 : }
3772 :
3773 0 : TcpPort::~TcpPort() {
3774 0 : socket_.close();
3775 0 : }
3776 :
3777 0 : uint16_t TcpPort::Bind() {
3778 0 : boost::system::error_code ec;
3779 0 : socket_.open(tcp::v4());
3780 0 : socket_.bind(tcp::endpoint(tcp::v4(), port_), ec);
3781 0 : if (ec.failed()) {
3782 0 : return 0;
3783 : }
3784 0 : port_ = socket_.local_endpoint(ec).port();
3785 0 : return port_;
3786 : }
3787 :
3788 0 : UdpPort::~UdpPort() {
3789 0 : socket_.close();
3790 0 : }
3791 :
3792 0 : uint16_t UdpPort::Bind() {
3793 0 : boost::system::error_code ec;
3794 0 : socket_.open(udp::v4());
3795 0 : socket_.bind(udp::endpoint(udp::v4(), port_), ec);
3796 0 : if (ec.failed()) {
3797 0 : return 0;
3798 : }
3799 0 : port_ = socket_.local_endpoint(ec).port();
3800 0 : return port_;
3801 : }
3802 :
3803 0 : bool PortCacheEntry::operator<(const PortCacheEntry &rhs) const {
3804 0 : return key_.IsLess(rhs.key_);
3805 : }
3806 :
3807 0 : void PortCacheEntry::MarkDelete() const {
3808 0 : stale_ = true;
3809 0 : delete_time_ = UTCTimestampUsec();
3810 0 : }
3811 :
3812 0 : bool PortCacheEntry::CanBeAged(uint64_t current_time, uint64_t timeout) const {
3813 0 : if (stale_ &&
3814 0 : current_time - delete_time_ >= timeout) {
3815 0 : return true;
3816 : }
3817 :
3818 0 : return false;
3819 : }
3820 :
3821 4 : PortCacheTable::PortCacheTable(PortTable *table) :
3822 4 : port_table_(table),
3823 8 : timer_(TimerManager::CreateTimer(
3824 4 : *(table->agent()->event_manager())->io_service(),
3825 : "FlowPortBindTimer",
3826 : TaskScheduler::GetInstance()->GetTaskId(kTaskFlowMgmt), -1)),
3827 4 : hash_(0), timeout_(PortCacheTable::kAgingTimeout) {
3828 4 : timer_->Start(kCacheAging,
3829 : boost::bind(&PortCacheTable::Age, this));
3830 4 : }
3831 :
3832 4 : PortCacheTable::~PortCacheTable() {
3833 4 : timer_->Cancel();
3834 4 : TimerManager::DeleteTimer(timer_);
3835 4 : }
3836 :
3837 4 : bool PortCacheTable::Age() {
3838 4 : if (tree_.size() == 0) {
3839 4 : return false;
3840 : }
3841 :
3842 0 : std::lock_guard<std::recursive_mutex> lock(port_table_->mutex());
3843 0 : uint16_t no_of_entries = tree_.size() / kCacheAging;
3844 0 : uint16_t entries_processed = 0;
3845 0 : uint64_t current_time = UTCTimestampUsec();
3846 :
3847 0 : PortCacheTree::iterator it = tree_.lower_bound(hash_);
3848 0 : while (it != tree_.end() && entries_processed <= no_of_entries) {
3849 : //Go thru each entry in particular hash bucket and identify
3850 : //if any of them can be released
3851 0 : PortCacheEntryList::iterator pcit = it->second.begin();
3852 0 : while (pcit != it->second.end() && entries_processed <= no_of_entries) {
3853 0 : PortCacheEntryList::iterator saved_pcit = pcit;
3854 0 : pcit++;
3855 0 : if (saved_pcit->CanBeAged(current_time, timeout_)) {
3856 : //Release reference to port
3857 : //check if port is empty, delete the port
3858 0 : port_table_->Free(saved_pcit->key(), saved_pcit->port(), true);
3859 : }
3860 0 : entries_processed++;
3861 : }
3862 0 : it++;
3863 : }
3864 :
3865 0 : if (it == tree_.end()) {
3866 0 : hash_ = 0;
3867 : } else {
3868 0 : hash_ = it->first;
3869 0 : hash_++;
3870 : }
3871 :
3872 0 : return true;
3873 0 : }
3874 :
3875 0 : void PortCacheTable::StartTimer() {
3876 0 : timer_->Start(kCacheAging,
3877 : boost::bind(&PortCacheTable::Age, this));
3878 0 : }
3879 :
3880 0 : void PortCacheTable::StopTimer() {
3881 0 : timer_->Cancel();
3882 0 : }
3883 :
3884 0 : void PortCacheTable::Add(const PortCacheEntry &cache_entry) {
3885 0 : uint16_t hash = port_table_->HashFlowKey(cache_entry.key());
3886 0 : tree_[hash].insert(cache_entry);
3887 :
3888 0 : if (tree_.size() == 1) {
3889 0 : StartTimer();
3890 : }
3891 0 : }
3892 :
3893 0 : void PortCacheTable::Delete(const PortCacheEntry &cache_entry) {
3894 0 : uint16_t hash = port_table_->HashFlowKey(cache_entry.key());
3895 0 : tree_[hash].erase(cache_entry);
3896 0 : if (tree_[hash].size() == 0) {
3897 0 : tree_.erase(hash);
3898 : }
3899 :
3900 0 : if (tree_.size() == 0) {
3901 0 : StopTimer();
3902 : }
3903 0 : }
3904 :
3905 0 : void PortCacheTable::MarkDelete(const PortCacheEntry &cache_entry) {
3906 0 : uint16_t hash = port_table_->HashFlowKey(cache_entry.key());
3907 :
3908 0 : PortCacheEntryList::iterator it = tree_[hash].find(cache_entry);
3909 0 : if (it != tree_[hash].end()) {
3910 0 : it->MarkDelete();
3911 : }
3912 0 : }
3913 :
3914 : const PortCacheEntry*
3915 0 : PortCacheTable::Find(const FlowKey &key) const {
3916 0 : PortCacheEntry cache_entry(key, 0);
3917 0 : uint16_t hash = port_table_->HashFlowKey(cache_entry.key());
3918 :
3919 0 : PortCacheTree::const_iterator pct_it = tree_.find(hash);
3920 0 : if (pct_it == tree_.end()) {
3921 0 : return NULL;
3922 : }
3923 :
3924 0 : PortCacheEntryList::const_iterator it = pct_it->second.find(cache_entry);
3925 0 : if (it != pct_it->second.end()) {
3926 0 : return &(*it);
3927 : }
3928 :
3929 0 : return NULL;
3930 : }
3931 :
3932 0 : uint16_t PortTable::HashFlowKey(const FlowKey &key) {
3933 0 : std::size_t hash = 0;
3934 0 : boost::hash_combine(hash, key.dst_addr.to_v4().to_ulong());
3935 0 : boost::hash_combine(hash, key.dst_port);
3936 :
3937 0 : return (hash % hash_table_size_);
3938 : }
3939 :
3940 4 : PortTable::PortTable(Agent *agent, uint32_t hash_table_size, uint8_t protocol):
3941 4 : agent_(agent), protocol_(protocol), cache_(this),
3942 4 : hash_table_size_(hash_table_size) {
3943 16388 : for (uint32_t i = 0; i < hash_table_size; i++) {
3944 16384 : hash_table_.push_back(PortBitMapPtr(new PortBitMap()));
3945 : }
3946 4 : }
3947 :
3948 4 : PortTable::~PortTable() {
3949 4 : if (task_trigger_.get()) {
3950 0 : task_trigger_->Reset();
3951 : }
3952 4 : }
3953 :
3954 0 : uint16_t PortTable::Allocate(const FlowKey &key) {
3955 0 : if (key.protocol != IPPROTO_TCP && key.protocol != IPPROTO_UDP) {
3956 0 : return key.src_port;
3957 : }
3958 :
3959 0 : std::lock_guard<std::recursive_mutex> lock(mutex_);
3960 : //Check if the entry is present in flow cache tree
3961 0 : const PortCacheEntry *entry = cache_.Find(key);
3962 0 : if (entry) {
3963 0 : entry->set_stale(false);
3964 0 : return entry->port();
3965 : }
3966 :
3967 0 : uint16_t port_hash = HashFlowKey(key);
3968 0 : uint16_t port = kInvalidPort;
3969 :
3970 0 : PortBitMapPtr bit_map = hash_table_[port_hash];
3971 :
3972 : //Mark the port as used in bit map of hash
3973 0 : uint16_t index = bit_map->Insert(key);
3974 0 : if (index >= port_to_bit_index_.size()) {
3975 0 : bit_map->Remove(index);
3976 0 : return port;
3977 : }
3978 : //Using the index above get the actual port to be used
3979 0 : port = port_list_.At(index)->port();
3980 0 : PortCacheEntry cache_entry(key, port);
3981 : //Add to cache tree
3982 0 : cache_.Add(cache_entry);
3983 :
3984 0 : return port;
3985 0 : }
3986 :
3987 : PortTable::PortPtr
3988 0 : PortTable::CreatePortEntry(uint16_t port_no) {
3989 0 : switch(protocol_) {
3990 0 : case IPPROTO_TCP:
3991 0 : return PortPtr(new TcpPort(*(agent_->event_manager()->io_service()),
3992 0 : port_no));
3993 :
3994 0 : case IPPROTO_UDP:
3995 0 : return PortPtr(new UdpPort(*(agent_->event_manager()->io_service()),
3996 0 : port_no));
3997 : }
3998 :
3999 0 : return PortPtr();
4000 : }
4001 :
4002 0 : void PortTable::Free(const FlowKey &key, uint16_t port, bool release) {
4003 0 : std::lock_guard<std::recursive_mutex> lock(mutex_);
4004 0 : PortCacheEntry cache_entry(key, kInvalidPort);
4005 0 : if (release) {
4006 : //Delete from cache entry
4007 0 : PortCacheEntry cache_entry(key, kInvalidPort);
4008 0 : cache_.Delete(cache_entry);
4009 :
4010 0 : uint16_t port_hash = HashFlowKey(key);
4011 0 : PortBitMapPtr bit_map = hash_table_[port_hash];
4012 0 : if (port_to_bit_index_.find(port) != port_to_bit_index_.end()) {
4013 : //Upon config change all the entries in bit map
4014 : //are implicitly deleted, hence a duplicate
4015 : //delete from flow table needs to be handled
4016 : //after cross check if key matches
4017 0 : FlowKey existing_key = bit_map->At(port_to_bit_index_[port]);
4018 0 : if (existing_key.IsEqual(key)) {
4019 0 : bit_map->Remove(port_to_bit_index_[port]);
4020 : }
4021 : }
4022 0 : } else {
4023 : //Mark cache entry for deletion
4024 : //after aging timeout
4025 0 : cache_.MarkDelete(cache_entry);
4026 : }
4027 0 : }
4028 :
4029 0 : void PortTable::Relocate(uint16_t port_no) {
4030 0 : PortToBitIndexMap::iterator it = port_to_bit_index_.find(port_no);
4031 0 : assert(it != port_to_bit_index_.end());
4032 :
4033 0 : PortPtr port_ptr = port_list_.At(it->second);
4034 0 : DeleteAllFlow(port_no, it->second);
4035 0 : port_list_.Remove(it->second);
4036 0 : it->second = port_list_.Insert(port_ptr);
4037 0 : }
4038 :
4039 0 : void PortTable::AddPort(uint16_t port_no) {
4040 0 : PortToBitIndexMap::iterator it = port_to_bit_index_.find(port_no);
4041 : //Port number already present
4042 0 : if (port_no != kInvalidPort && it != port_to_bit_index_.end()) {
4043 0 : if (it->second >= port_config_.port_count) {
4044 0 : Relocate(port_no);
4045 : }
4046 0 : return;
4047 : }
4048 :
4049 0 : PortPtr port_ptr = CreatePortEntry(port_no);
4050 0 : if (port_ptr->Bind() || agent_->test_mode()) {
4051 0 : size_t index = port_list_.Insert(port_ptr);
4052 0 : port_to_bit_index_.insert((PortToBitIndexPair(port_ptr->port(),
4053 0 : (uint16_t)index)));
4054 : }
4055 0 : }
4056 :
4057 0 : void PortTable::DeleteAllFlow(uint16_t port_no, uint16_t index) {
4058 0 : for (uint16_t i = 0; i < hash_table_size_; i++) {
4059 0 : FlowKey key = hash_table_[i]->At((size_t)index);
4060 0 : if (key.family == Address::UNSPEC) {
4061 0 : continue;
4062 : }
4063 0 : hash_table_[i]->Remove(index);
4064 0 : Free(key, port_no, true);
4065 : //Enqueue delete of flow
4066 0 : agent_->pkt()->get_flow_proto()->DeleteFlowRequest(key);
4067 : }
4068 0 : }
4069 :
4070 0 : void PortTable::DeletePort(uint16_t port_no) {
4071 0 : assert(port_no != kInvalidPort);
4072 :
4073 0 : PortToBitIndexMap::const_iterator it = port_to_bit_index_.find(port_no);
4074 0 : assert(it != port_to_bit_index_.end());
4075 0 : uint16_t index = it->second;
4076 :
4077 : //Delete all the flow using this port
4078 0 : DeleteAllFlow(port_no, index);
4079 :
4080 0 : port_list_.Remove(index);
4081 0 : port_to_bit_index_.erase(port_no);
4082 0 : }
4083 :
4084 0 : bool PortTable::IsValidPort(uint16_t port, uint16_t count) {
4085 0 : if (port_config_.port_range.size() != 0) {
4086 : std::vector<PortConfig::PortRange>::const_iterator it =
4087 0 : port_config_.port_range.begin();
4088 : //Go thru each range
4089 0 : for(; it != port_config_.port_range.end(); it++) {
4090 0 : if (port >= it->port_start && port <= it->port_end) {
4091 0 : return true;
4092 : }
4093 : }
4094 : } else {
4095 0 : return (count < port_config_.port_count);
4096 : }
4097 :
4098 0 : return false;
4099 : }
4100 :
4101 0 : void PortTable::UpdatePortConfig(const PortConfig *pc) {
4102 0 : if (task_trigger_.get()) {
4103 0 : task_trigger_->Reset();
4104 : }
4105 :
4106 0 : PortConfig new_pc = *pc;
4107 :
4108 0 : int task_id = TaskScheduler::GetInstance()->GetTaskId(kTaskFlowEvent);
4109 : task_trigger_.reset
4110 0 : (new TaskTrigger(boost::bind(&PortTable::HandlePortConfig, this,
4111 0 : new_pc), task_id, 0));
4112 0 : task_trigger_->Set();
4113 0 : }
4114 :
4115 0 : bool PortTable::HandlePortConfig(const PortConfig &pc) {
4116 0 : std::lock_guard<std::recursive_mutex> lock(mutex_);
4117 0 : uint16_t old_port_count = port_to_bit_index_.size();
4118 0 : port_config_ = pc;
4119 :
4120 0 : uint16_t count = 0;
4121 :
4122 0 : for (uint16_t index = 0; index < old_port_count; index++) {
4123 0 : PortPtr port = port_list_.At(index);
4124 0 : if (port.get() && IsValidPort(port->port(), count) == false) {
4125 0 : DeletePort(port->port());
4126 : } else {
4127 0 : count++;
4128 : //For relocating the port of index is higher than
4129 : //port count
4130 0 : AddPort(port->port());
4131 : }
4132 0 : }
4133 :
4134 0 : if (port_config_.port_range.size()) {
4135 : std::vector<PortConfig::PortRange>::const_iterator it =
4136 0 : port_config_.port_range.begin();
4137 : //Go thru each range
4138 0 : for(; it != port_config_.port_range.end(); it++) {
4139 : //Handle range of port
4140 0 : for (uint16_t port = it->port_start;
4141 0 : it->port_end && port <= it->port_end;
4142 : port++) {
4143 0 : AddPort(port);
4144 : }
4145 : }
4146 : } else {
4147 : //Handle port count, port_count_ would be set only if range is
4148 : //not valid
4149 0 : for (uint16_t port = count; port < port_config_.port_count; port++) {
4150 0 : AddPort(0);
4151 : }
4152 : }
4153 0 : return true;
4154 0 : }
4155 :
4156 0 : uint16_t PortTable::GetPortIndex(uint16_t port) const {
4157 0 : PortToBitIndexMap::const_iterator it = port_to_bit_index_.find(port);
4158 0 : assert(it != port_to_bit_index_.end());
4159 0 : return it->second;
4160 : }
4161 :
4162 0 : void PortTable::GetFlowKeyList(uint16_t port,
4163 : std::vector<FlowKey> &list) const {
4164 0 : std::lock_guard<std::recursive_mutex> lock(mutex_);
4165 0 : if (port_to_bit_index_.find(port) == port_to_bit_index_.end()) {
4166 0 : return;
4167 : }
4168 :
4169 0 : for (uint16_t hash = 0; hash < hash_table_size_; hash++) {
4170 0 : const PortBitMapPtr bit_map = hash_table_[hash];
4171 0 : FlowKey existing_key = bit_map->At(GetPortIndex(port));
4172 0 : if (existing_key.family != Address::UNSPEC) {
4173 0 : list.push_back(existing_key);
4174 : }
4175 0 : }
4176 0 : }
4177 :
4178 2 : PortTableManager::PortTableManager(Agent *agent, uint16_t hash_table_size):
4179 0 : agent_(agent) {
4180 : port_table_list_[IPPROTO_TCP] =
4181 2 : PortTablePtr(new PortTable(agent, hash_table_size, IPPROTO_TCP));
4182 : port_table_list_[IPPROTO_UDP] =
4183 2 : PortTablePtr(new PortTable(agent, hash_table_size, IPPROTO_UDP));
4184 2 : agent_->set_port_config_handler(&(PortTableManager::PortConfigHandler));
4185 2 : }
4186 :
4187 528 : PortTableManager::~PortTableManager() {
4188 528 : for (uint16_t proto = 0; proto < IPPROTO_MAX; proto++) {
4189 526 : port_table_list_[proto].reset();
4190 : }
4191 530 : }
4192 0 : uint16_t PortTableManager::Allocate(const FlowKey &key) {
4193 0 : if (key.protocol != IPPROTO_TCP && key.protocol != IPPROTO_UDP) {
4194 0 : return key.src_port;
4195 : }
4196 :
4197 0 : return port_table_list_[key.protocol]->Allocate(key);
4198 : }
4199 :
4200 0 : void PortTableManager::Free(const FlowKey &key, uint16_t port, bool evict) {
4201 0 : if (key.protocol != IPPROTO_TCP && key.protocol != IPPROTO_UDP) {
4202 0 : return;
4203 : }
4204 :
4205 0 : return port_table_list_[key.protocol]->Free(key, port, evict);
4206 : }
4207 :
4208 0 : void PortTableManager::UpdatePortConfig(uint8_t protocol, const PortConfig *pc) {
4209 0 : if (port_table_list_[protocol].get() == NULL) {
4210 0 : return;
4211 : }
4212 :
4213 0 : port_table_list_[protocol]->UpdatePortConfig(pc);
4214 : }
4215 :
4216 0 : void PortTableManager::PortConfigHandler(Agent *agent, uint8_t protocol,
4217 : const PortConfig *pc) {
4218 : agent->pkt()->get_flow_proto()->port_table_manager()->
4219 0 : UpdatePortConfig(protocol, pc);
4220 0 : }
|