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