Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : * Copyright Contributors to the OpenSDN project
4 : */
5 :
6 : #include <sys/socket.h>
7 : #if defined(__linux__)
8 : #include <linux/netlink.h>
9 : #endif
10 : #include <fcntl.h>
11 : #include <sys/mman.h>
12 : #include <sys/types.h>
13 : #include <sys/ipc.h>
14 : #include <sys/shm.h>
15 : #include <asm/types.h>
16 : #include <boost/asio.hpp>
17 : #include <boost/asio/buffer.hpp>
18 :
19 : #include <base/address_util.h>
20 : #include <cmn/agent_cmn.h>
21 : #include <ksync/ksync_index.h>
22 : #include <ksync/ksync_entry.h>
23 : #include <ksync/ksync_object.h>
24 : #include <ksync/ksync_netlink.h>
25 : #include <ksync/ksync_sock.h>
26 : #include <ksync/ksync_netlink.h>
27 : #include <ksync/ksync_types.h>
28 : #include <vrouter/ksync/agent_ksync_types.h>
29 : #include <vrouter/ksync/interface_ksync.h>
30 : #include <vrouter/ksync/flowtable_ksync.h>
31 : #include <filter/traffic_action.h>
32 : #include <vr_types.h>
33 : #include <nl_util.h>
34 : #include <vr_flow.h>
35 : #include <vr_genetlink.h>
36 : #include <ksync/ksync_sock_user.h>
37 : #include <vrouter/ksync/ksync_init.h>
38 :
39 : #include <pkt/flow_proto.h>
40 : #include <oper/agent_types.h>
41 : #include <services/services_init.h>
42 : #include <services/icmp_error_proto.h>
43 : #include <uve/stats_collector.h>
44 :
45 : const uint32_t KSyncFlowEntryFreeList::kInitCount;
46 : const uint32_t KSyncFlowEntryFreeList::kTestInitCount;
47 : const uint32_t KSyncFlowEntryFreeList::kGrowSize;
48 : const uint32_t KSyncFlowEntryFreeList::kMinThreshold;
49 : const uint32_t KSyncFlowEntryFreeList::kMaxThreshold;
50 :
51 : using namespace boost::asio::ip;
52 :
53 30 : static uint16_t GetDropReason(uint16_t dr) {
54 30 : switch (dr) {
55 0 : case FlowEntry::SHORT_UNAVIALABLE_INTERFACE:
56 0 : return VR_FLOW_DR_UNAVIALABLE_INTF;
57 0 : case FlowEntry::SHORT_IPV4_FWD_DIS:
58 0 : return VR_FLOW_DR_IPv4_FWD_DIS;
59 0 : case FlowEntry::SHORT_UNAVIALABLE_VRF:
60 0 : return VR_FLOW_DR_UNAVAILABLE_VRF;
61 0 : case FlowEntry::SHORT_NO_SRC_ROUTE:
62 0 : return VR_FLOW_DR_NO_SRC_ROUTE;
63 0 : case FlowEntry::SHORT_NO_DST_ROUTE:
64 0 : return VR_FLOW_DR_NO_DST_ROUTE;
65 0 : case FlowEntry::SHORT_AUDIT_ENTRY:
66 0 : return VR_FLOW_DR_AUDIT_ENTRY;
67 0 : case FlowEntry::SHORT_VRF_CHANGE:
68 0 : return VR_FLOW_DR_VRF_CHANGE;
69 0 : case FlowEntry::SHORT_NO_REVERSE_FLOW:
70 0 : return VR_FLOW_DR_NO_REVERSE_FLOW;
71 0 : case FlowEntry::SHORT_REVERSE_FLOW_CHANGE:
72 0 : return VR_FLOW_DR_REVERSE_FLOW_CHANGE;
73 0 : case FlowEntry::SHORT_NAT_CHANGE:
74 0 : return VR_FLOW_DR_NAT_CHANGE;
75 0 : case FlowEntry::SHORT_FLOW_LIMIT:
76 0 : return VR_FLOW_DR_FLOW_LIMIT;
77 0 : case FlowEntry::SHORT_LINKLOCAL_SRC_NAT:
78 0 : return VR_FLOW_DR_LINKLOCAL_SRC_NAT;
79 0 : case FlowEntry::SHORT_NO_MIRROR_ENTRY:
80 0 : return VR_FLOW_DR_NO_MIRROR_ENTRY;
81 0 : case FlowEntry::SHORT_SAME_FLOW_RFLOW_KEY:
82 0 : return VR_FLOW_DR_SAME_FLOW_RFLOW_KEY;
83 0 : case FlowEntry::SHORT_PORT_MAP_DROP:
84 0 : return VR_FLOW_DR_PORT_MAP_DROP;
85 0 : case FlowEntry::SHORT_NO_SRC_ROUTE_L2RPF:
86 0 : return VR_FLOW_DR_NO_SRC_ROUTE_L2RPF;
87 0 : case FlowEntry::SHORT_FAT_FLOW_NAT_CONFLICT:
88 0 : return VR_FLOW_DR_FAT_FLOW_NAT_CONFLICT;
89 2 : case FlowEntry::DROP_POLICY:
90 2 : return VR_FLOW_DR_POLICY;
91 0 : case FlowEntry::DROP_OUT_POLICY:
92 0 : return VR_FLOW_DR_OUT_POLICY;
93 12 : case FlowEntry::DROP_SG:
94 12 : return VR_FLOW_DR_SG;
95 2 : case FlowEntry::DROP_OUT_SG:
96 2 : return VR_FLOW_DR_OUT_SG;
97 0 : case FlowEntry::DROP_REVERSE_SG:
98 0 : return VR_FLOW_DR_REVERSE_SG;
99 0 : case FlowEntry::DROP_REVERSE_OUT_SG:
100 0 : return VR_FLOW_DR_REVERSE_OUT_SG;
101 0 : case FlowEntry::DROP_FIREWALL_POLICY:
102 0 : return VR_FLOW_DR_FW_POLICY;
103 0 : case FlowEntry::DROP_OUT_FIREWALL_POLICY:
104 0 : return VR_FLOW_DR_OUT_FW_POLICY;
105 0 : case FlowEntry::DROP_REVERSE_FIREWALL_POLICY:
106 0 : return VR_FLOW_DR_REVERSE_FW_POLICY;
107 0 : case FlowEntry::DROP_REVERSE_OUT_FIREWALL_POLICY:
108 0 : return VR_FLOW_DR_REVERSE_OUT_FW_POLICY;
109 0 : case FlowEntry::DROP_FWAAS_POLICY:
110 0 : return VR_FLOW_DR_FWAAS_POLICY;
111 0 : case FlowEntry::DROP_FWAAS_OUT_POLICY:
112 0 : return VR_FLOW_DR_OUT_FWAAS_POLICY;
113 0 : case FlowEntry::DROP_FWAAS_REVERSE_POLICY:
114 0 : return VR_FLOW_DR_REVERSE_FWAAS_POLICY;
115 0 : case FlowEntry::DROP_FWAAS_REVERSE_OUT_POLICY:
116 0 : return VR_FLOW_DR_REVERSE_OUT_FWAAS_POLICY;
117 14 : default:
118 14 : break;
119 : }
120 14 : return VR_FLOW_DR_UNKNOWN;
121 : }
122 :
123 10000 : FlowTableKSyncEntry::FlowTableKSyncEntry(FlowTableKSyncObject *obj) {
124 10000 : Reset();
125 10000 : ksync_obj_ = obj;
126 10000 : }
127 :
128 148 : FlowTableKSyncEntry::FlowTableKSyncEntry(FlowTableKSyncObject *obj,
129 148 : FlowEntry *flow, uint32_t hash_id) {
130 148 : Reset();
131 148 : Reset(flow, hash_id);
132 148 : ksync_obj_ = obj;
133 148 : }
134 :
135 20148 : FlowTableKSyncEntry::~FlowTableKSyncEntry() {
136 20148 : }
137 :
138 10296 : void FlowTableKSyncEntry::Reset() {
139 10296 : KSyncEntry::Reset();
140 10296 : flow_entry_ = NULL;
141 10296 : hash_id_ = FlowEntry::kInvalidFlowHandle;
142 10296 : gen_id_ = 0;
143 10296 : evict_gen_id_ = 0;
144 10296 : vrouter_gen_id_ = 0;
145 10296 : vrouter_hash_id_ = FlowEntry::kInvalidFlowHandle;
146 10296 : old_reverse_flow_id_ = FlowEntry::kInvalidFlowHandle;
147 10296 : old_action_ = 0;
148 10296 : old_component_nh_idx_ = 0xFFFF;
149 10296 : old_first_mirror_index_ = 0xFFFF;
150 10296 : old_second_mirror_index_ = 0xFFFF;
151 10296 : trap_flow_ = false;
152 10296 : old_drop_reason_ = 0;
153 10296 : ecmp_ = false;
154 10296 : enable_rpf_ = true;
155 10296 : src_nh_id_ = NextHopTable::kRpfDiscardIndex;
156 10296 : last_event_ = FlowEvent::INVALID;
157 10296 : token_.reset();
158 10296 : ksync_response_info_.Reset();
159 10296 : qos_config_idx = AgentQosConfigTable::kInvalidIndex;
160 10296 : transaction_id_ = 0;
161 10296 : underlay_gw_index = -1;
162 10296 : }
163 :
164 296 : void FlowTableKSyncEntry::Reset(FlowEntry *flow, uint32_t hash_id) {
165 296 : flow_entry_ = flow;
166 296 : hash_id_ = hash_id;
167 296 : gen_id_ = flow->gen_id();
168 296 : transaction_id_ = flow->GetTransactionId();
169 296 : }
170 :
171 2264 : KSyncObject *FlowTableKSyncEntry::GetObject() const {
172 2264 : return ksync_obj_;
173 : }
174 :
175 756 : uint32_t FlowTableKSyncEntry::GetTableIndex() const {
176 : FlowTableKSyncObject *obj =
177 756 : static_cast<FlowTableKSyncObject *>(GetObject());
178 756 : return (obj->flow_table()->table_index());
179 : }
180 378 : void FlowTableKSyncEntry::ReleaseToken() {
181 378 : if (token_.get())
182 378 : token_.reset();
183 378 : }
184 :
185 0 : void FlowTableKSyncEntry::SetPcapData(FlowEntryPtr fe,
186 : std::vector<int8_t> &data) {
187 0 : data.clear();
188 0 : uint32_t addr = ksync_obj_->ksync()->agent()->router_id().to_ulong();
189 0 : data.push_back(FlowEntry::PCAP_CAPTURE_HOST);
190 0 : data.push_back(0x4);
191 0 : data.push_back(((addr >> 24) & 0xFF));
192 0 : data.push_back(((addr >> 16) & 0xFF));
193 0 : data.push_back(((addr >> 8) & 0xFF));
194 0 : data.push_back(((addr) & 0xFF));
195 :
196 0 : data.push_back(FlowEntry::PCAP_FLAGS);
197 0 : data.push_back(0x4);
198 : uint32_t action;
199 0 : action = fe->match_p().action_info.action;
200 0 : if (fe->is_flags_set(FlowEntry::IngressDir)) {
201 : // Set 31st bit for ingress
202 0 : action |= 0x40000000;
203 : }
204 0 : data.push_back((action >> 24) & 0xFF);
205 0 : data.push_back((action >> 16) & 0xFF);
206 0 : data.push_back((action >> 8) & 0xFF);
207 0 : data.push_back((action) & 0xFF);
208 :
209 0 : data.push_back(FlowEntry::PCAP_SOURCE_VN);
210 0 : data.push_back(fe->data().source_vn_match.size());
211 0 : data.insert(data.end(), fe->data().source_vn_match.begin(),
212 0 : fe->data().source_vn_match.end());
213 0 : data.push_back(FlowEntry::PCAP_DEST_VN);
214 0 : data.push_back(fe->data().dest_vn_match.size());
215 0 : data.insert(data.end(), fe->data().dest_vn_match.begin(),
216 0 : fe->data().dest_vn_match.end());
217 0 : data.push_back(FlowEntry::PCAP_TLV_END);
218 0 : data.push_back(0x0);
219 0 : }
220 :
221 378 : static void EncodeKSyncIp(vr_flow_req *req, const IpAddress &sip,
222 : const IpAddress &dip) {
223 : uint64_t supper, dupper, slower, dlower;
224 :
225 :
226 378 : IpToU64(sip, dip, &supper, &slower, &dupper, &dlower);
227 378 : req->set_fr_flow_sip_l(slower);
228 378 : req->set_fr_flow_sip_u(supper);
229 378 : req->set_fr_flow_dip_l(dlower);
230 378 : req->set_fr_flow_dip_u(dupper);
231 :
232 378 : }
233 :
234 378 : int FlowTableKSyncEntry::Encode(sandesh_op::type op, char *buf, int buf_len) {
235 378 : vr_flow_req &req = ksync_obj_->flow_req();
236 : int encode_len;
237 : int error;
238 378 : uint16_t action = 0;
239 378 : uint16_t drop_reason = VR_FLOW_DR_UNKNOWN;
240 :
241 : // currently vrouter doesnot guarantee gen id to always start from 0
242 : // on vrouter-agent restart
243 : // TODO(prabhjot) need to move last gen id seen by vrouter in KSync
244 : // Index Manager
245 378 : if (gen_id_ != evict_gen_id_) {
246 : // skip sending update to vrouter for evicted entry
247 0 : flow_entry_->LogFlow(FlowEventLog::FLOW_MSG_SKIP_EVICTED, this,
248 0 : hash_id_, evict_gen_id_);
249 0 : return 0;
250 : }
251 :
252 378 : req.set_fr_op(flow_op::FLOW_SET);
253 378 : req.set_fr_rid(0);
254 378 : req.set_fr_index(hash_id_);
255 378 : req.set_fr_gen_id(gen_id_);
256 378 : const FlowKey *fe_key = &flow_entry_->key();
257 378 : EncodeKSyncIp(&req, fe_key->src_addr, fe_key->dst_addr);
258 378 : req.set_fr_flow_proto(fe_key->protocol);
259 378 : req.set_fr_flow_sport(htons(fe_key->src_port));
260 378 : req.set_fr_flow_dport(htons(fe_key->dst_port));
261 378 : req.set_fr_flow_nh_id(fe_key->nh);
262 378 : if (flow_entry_->key().family == Address::INET)
263 378 : req.set_fr_family(AF_INET);
264 : else
265 0 : req.set_fr_family(AF_INET6);
266 378 : req.set_fr_flow_vrf(flow_entry_->data().vrf);
267 378 : uint16_t flags = 0;
268 378 : uint16_t flags1 = 0;
269 :
270 378 : if (op == sandesh_op::DEL) {
271 148 : if (hash_id_ == FlowEntry::kInvalidFlowHandle) {
272 0 : return 0;
273 : }
274 :
275 148 : req.set_fr_flags(0);
276 148 : req.set_fr_flags1(0);
277 : // Sync() is not called in case of delete. Copy the event to use
278 : // the right token
279 148 : last_event_ = (FlowEvent::Event)flow_entry_->last_event();
280 : } else {
281 230 : flags = VR_FLOW_FLAG_ACTIVE;
282 230 : uint32_t fe_action = flow_entry_->match_p().action_info.action;
283 230 : if ((fe_action) & (1 << TrafficAction::PASS)) {
284 168 : action = VR_FLOW_ACTION_FORWARD;
285 : }
286 :
287 230 : if ((fe_action) & (1 << TrafficAction::DENY)) {
288 30 : action = VR_FLOW_ACTION_DROP;
289 30 : drop_reason = GetDropReason(flow_entry_->data().drop_reason);
290 : }
291 :
292 398 : if (action == VR_FLOW_ACTION_FORWARD &&
293 398 : flow_entry_->is_flags_set(FlowEntry::NatFlow)) {
294 86 : action = VR_FLOW_ACTION_NAT;
295 : }
296 :
297 316 : if (action == VR_FLOW_ACTION_NAT &&
298 86 : flow_entry_->reverse_flow_entry() == NULL) {
299 0 : action = VR_FLOW_ACTION_DROP;
300 : }
301 :
302 230 : if ((fe_action) & (1 << TrafficAction::HBS)) {
303 0 : if (flow_entry_->is_flags_set(FlowEntry::HbfFlow)) {
304 0 : if (flow_entry_->GetHbsInterface() ==
305 : FlowEntry::HBS_INTERFACE_RIGHT) {
306 0 : flags1 |= VR_FLOW_FLAG1_HBS_RIGHT;
307 : } else {
308 0 : flags1 |= VR_FLOW_FLAG1_HBS_LEFT;
309 : }
310 : }
311 : }
312 :
313 230 : if ((fe_action) & (1 << TrafficAction::MIRROR)) {
314 0 : flags |= VR_FLOW_FLAG_MIRROR;
315 0 : req.set_fr_mir_id(-1);
316 0 : req.set_fr_sec_mir_id(-1);
317 0 : if (flow_entry_->match_p().action_info.mirror_l.size() >
318 : FlowEntry::kMaxMirrorsPerFlow) {
319 0 : FLOW_TRACE(Err, hash_id_,
320 : "Don't support more than two mirrors/analyzers per "
321 : "flow:" + integerToString
322 : (flow_entry_->
323 : data().match_p.action_info.mirror_l.size()));
324 : }
325 : // Lookup for fist and second mirror entries
326 0 : std::vector<MirrorActionSpec>::const_iterator it;
327 0 : it = flow_entry_->match_p().action_info.mirror_l.begin();
328 0 : MirrorKSyncObject* obj = ksync_obj_->ksync()->agent()->ksync()->
329 0 : mirror_ksync_obj();
330 0 : uint16_t idx_1 = obj->GetIdx((*it).analyzer_name);
331 0 : req.set_fr_mir_id(idx_1);
332 0 : FLOW_TRACE(ModuleInfo, "Mirror index first: " +
333 : integerToString(idx_1));
334 0 : ++it;
335 0 : if (it != flow_entry_->match_p().action_info.mirror_l.end()) {
336 0 : uint16_t idx_2 = obj->GetIdx((*it).analyzer_name);
337 0 : if (idx_1 != idx_2) {
338 0 : req.set_fr_sec_mir_id(idx_2);
339 0 : FLOW_TRACE(ModuleInfo, "Mirror index second: " +
340 : integerToString(idx_2));
341 : } else {
342 0 : FLOW_TRACE(Err, hash_id_,
343 : "Both Mirror indexes are same, hence didn't set "
344 : "the second mirror dest.");
345 : }
346 : }
347 0 : req.set_fr_mir_vrf(flow_entry_->data().mirror_vrf);
348 0 : req.set_fr_mir_sip(htonl(ksync_obj_->ksync()->agent()->
349 0 : router_id().to_ulong()));
350 0 : req.set_fr_mir_sport(htons(ksync_obj_->ksync()->agent()->
351 0 : mirror_port()));
352 0 : std::vector<int8_t> pcap_data;
353 0 : SetPcapData(flow_entry_, pcap_data);
354 0 : req.set_fr_pcap_meta_data(pcap_data);
355 0 : }
356 :
357 230 : if (flow_entry_->data().component_nh_idx !=
358 : (uint32_t)CompositeNH::kInvalidComponentNHIdx) {
359 48 : req.set_fr_ecmp_nh_index(flow_entry_->data().component_nh_idx);
360 : } else {
361 182 : req.set_fr_ecmp_nh_index(-1);
362 : }
363 :
364 230 : if (action == VR_FLOW_ACTION_NAT) {
365 86 : FlowEntry *nat_flow = flow_entry_->reverse_flow_entry();
366 86 : const FlowKey *nat_key = &nat_flow->key();
367 :
368 86 : if (flow_entry_->key().src_addr != nat_key->dst_addr) {
369 43 : flags |= VR_FLOW_FLAG_SNAT;
370 : }
371 86 : if (flow_entry_->key().dst_addr != nat_key->src_addr) {
372 43 : flags |= VR_FLOW_FLAG_DNAT;
373 : }
374 :
375 172 : if (flow_entry_->key().protocol == IPPROTO_TCP ||
376 86 : flow_entry_->key().protocol == IPPROTO_UDP) {
377 64 : if (flow_entry_->key().src_port != nat_key->dst_port) {
378 0 : flags |= VR_FLOW_FLAG_SPAT;
379 : }
380 64 : if (flow_entry_->key().dst_port != nat_key->src_port) {
381 0 : flags |= VR_FLOW_FLAG_DPAT;
382 : }
383 : }
384 :
385 : //Link local, flag determines relaxed policy
386 86 : if (nat_flow->is_flags_set(FlowEntry::LinkLocalBindLocalSrcPort)) {
387 0 : flags |= VR_FLOW_FLAG_LINK_LOCAL;
388 : }
389 :
390 : //Bgp service, flag determines relaxed policy
391 86 : if (nat_flow->is_flags_set(FlowEntry::BgpRouterService)) {
392 0 : flags |= VR_FLOW_BGP_SERVICE;
393 : }
394 :
395 86 : if (nat_flow->allocated_port()) {
396 0 : flags |= VR_FLOW_BGP_SERVICE;
397 : }
398 :
399 86 : flags |= VR_FLOW_FLAG_VRFT;
400 86 : req.set_fr_flow_dvrf(flow_entry_->data().dest_vrf);
401 144 : } else if (flow_entry_->is_flags_set(FlowEntry::AliasIpFlow)) {
402 0 : flags |= VR_FLOW_FLAG_VRFT;
403 0 : req.set_fr_flow_dvrf(flow_entry_->data().dest_vrf);
404 : }
405 :
406 230 : if (fe_action & (1 << TrafficAction::VRF_TRANSLATE)) {
407 0 : flags |= VR_FLOW_FLAG_VRFT;
408 0 : req.set_fr_flow_dvrf(flow_entry_->data().dest_vrf);
409 : }
410 :
411 230 : if (flow_entry_->is_flags_set(FlowEntry::Trap)) {
412 0 : action = VR_FLOW_ACTION_HOLD;
413 : }
414 :
415 230 : if (enable_rpf_) {
416 230 : req.set_fr_src_nh_index(src_nh_id_);
417 : } else {
418 : //Set to discard, vrouter ignores RPF check if
419 : //nexthop is set to discard
420 0 : req.set_fr_src_nh_index(0);
421 : }
422 :
423 230 : FlowEntry *rev_flow = flow_entry_->reverse_flow_entry();
424 230 : if (rev_flow) {
425 230 : flags |= VR_RFLOW_VALID;
426 230 : req.set_fr_rindex(rev_flow->flow_handle());
427 230 : if (rev_flow->flow_handle() == FlowEntry::kInvalidFlowHandle) {
428 77 : const FlowKey &rkey = rev_flow->key();
429 77 : req.set_fr_rflow_nh_id(rkey.nh);
430 : uint64_t supper, dupper, slower, dlower;
431 :
432 77 : IpToU64(rkey.src_addr, rkey.dst_addr, &supper, &slower,
433 : &dupper, &dlower);
434 77 : req.set_fr_rflow_sip_l(slower);
435 77 : req.set_fr_rflow_sip_u(supper);
436 77 : req.set_fr_rflow_dip_l(dlower);
437 77 : req.set_fr_rflow_dip_u(dupper);
438 :
439 77 : req.set_fr_rflow_sport(htons(rkey.src_port));
440 77 : req.set_fr_rflow_dport(htons(rkey.dst_port));
441 : }
442 : }
443 :
444 230 : if (flow_entry_->IsShortFlow()) {
445 32 : action = VR_FLOW_ACTION_DROP;
446 : }
447 :
448 230 : req.set_fr_flags(flags);
449 230 : req.set_fr_flags1(flags1);
450 230 : req.set_fr_action(action);
451 230 : req.set_fr_drop_reason(drop_reason);
452 230 : req.set_fr_qos_id(qos_config_idx);
453 230 : req.set_fr_ttl(flow_entry_->data().ttl);
454 230 : req.set_fr_underlay_ecmp_index(underlay_gw_index);
455 : }
456 :
457 378 : FlowProto *proto = ksync_obj_->ksync()->agent()->pkt()->get_flow_proto();
458 378 : token_ = proto->GetToken(last_event_);
459 378 : encode_len = req.WriteBinary((uint8_t *)buf, buf_len, &error);
460 378 : return encode_len;
461 : }
462 :
463 307 : bool FlowTableKSyncEntry::Sync() {
464 307 : bool changed = false;
465 :
466 307 : last_event_ = (FlowEvent::Event)flow_entry_->last_event();
467 307 : FlowEntry *rev_flow = flow_entry_->reverse_flow_entry();
468 307 : if (rev_flow) {
469 307 : if (old_reverse_flow_id_ != rev_flow->flow_handle()) {
470 160 : if (old_reverse_flow_id_ != FlowEntry::kInvalidFlowHandle)
471 6 : changed = true;
472 160 : old_reverse_flow_id_ = rev_flow->flow_handle();
473 : }
474 : }
475 :
476 307 : if (flow_entry_->match_p().action_info.action != old_action_) {
477 190 : old_action_ = flow_entry_->match_p().action_info.action;
478 190 : changed = true;
479 : }
480 :
481 307 : if (flow_entry_->data().drop_reason != old_drop_reason_) {
482 28 : old_drop_reason_ = flow_entry_->data().drop_reason;
483 28 : changed = true;
484 : }
485 307 : if (flow_entry_->data().component_nh_idx != old_component_nh_idx_) {
486 153 : old_component_nh_idx_ = flow_entry_->data().component_nh_idx;
487 153 : changed = true;
488 : }
489 :
490 307 : if (vrouter_gen_id_ != gen_id_) {
491 17 : vrouter_gen_id_ = gen_id_;
492 17 : changed = true;
493 : }
494 :
495 307 : if (vrouter_hash_id_ != hash_id_) {
496 90 : vrouter_hash_id_ = hash_id_;
497 90 : changed = true;
498 : }
499 :
500 307 : MirrorKSyncObject* obj = ksync_obj_->ksync()->mirror_ksync_obj();
501 : // Lookup for fist and second mirror entries
502 307 : std::vector<MirrorActionSpec>::const_iterator it;
503 307 : it = flow_entry_->match_p().action_info.mirror_l.begin();
504 307 : if (it != flow_entry_->match_p().action_info.mirror_l.end()) {
505 0 : uint16_t idx = obj->GetIdx((*it).analyzer_name);
506 0 : if (!((*it).analyzer_name.empty()) &&
507 : (idx == MirrorTable::kInvalidIndex)) {
508 : // runn timer to update flow entry
509 0 : ksync_obj_->UpdateUnresolvedFlowEntry(flow_entry_);
510 0 : } else if (old_first_mirror_index_ != idx) {
511 0 : old_first_mirror_index_ = idx;
512 0 : changed = true;
513 : }
514 0 : ++it;
515 0 : if (it != flow_entry_->match_p().action_info.mirror_l.end()) {
516 0 : idx = obj->GetIdx((*it).analyzer_name);
517 0 : if (!((*it).analyzer_name.empty()) &&
518 : (idx == MirrorTable::kInvalidIndex)) {
519 : // run time and to update flow entry;
520 0 : ksync_obj_->UpdateUnresolvedFlowEntry(flow_entry_);
521 0 : } else if (old_second_mirror_index_ != idx) {
522 0 : old_second_mirror_index_ = idx;
523 0 : changed = true;
524 : }
525 : }
526 : }
527 :
528 : //Trap reverse flow
529 307 : if (trap_flow_ != flow_entry_->is_flags_set(FlowEntry::Trap)) {
530 0 : trap_flow_ = flow_entry_->is_flags_set(FlowEntry::Trap);
531 0 : changed = true;
532 : }
533 :
534 307 : if (ecmp_ != flow_entry_->is_flags_set(FlowEntry::EcmpFlow)) {
535 110 : ecmp_ = flow_entry_->is_flags_set(FlowEntry::EcmpFlow);
536 110 : changed = true;
537 : }
538 :
539 307 : if (enable_rpf_ != flow_entry_->data().enable_rpf) {
540 0 : enable_rpf_ = flow_entry_->data().enable_rpf;
541 0 : changed = true;
542 : }
543 :
544 307 : uint32_t nh_id = NextHopTable::kRpfDiscardIndex;
545 307 : if (flow_entry_->data().rpf_nh.get()) {
546 288 : nh_id = flow_entry_->data().rpf_nh.get()->id();
547 : }
548 307 : if (src_nh_id_ != nh_id) {
549 164 : src_nh_id_ = nh_id;
550 164 : changed = true;
551 : }
552 :
553 307 : if (qos_config_idx != flow_entry_->data().qos_config_idx) {
554 0 : qos_config_idx = flow_entry_->data().qos_config_idx;
555 0 : changed = true;
556 : }
557 307 : if (transaction_id_ != flow_entry_->GetTransactionId()) {
558 76 : transaction_id_ = flow_entry_->GetTransactionId();
559 76 : changed = true;
560 : }
561 307 : if (underlay_gw_index != flow_entry_->data().underlay_gw_index_) {
562 0 : underlay_gw_index = flow_entry_->data().underlay_gw_index_;
563 0 : changed = true;
564 : }
565 307 : return changed;
566 : }
567 :
568 307 : KSyncEntry* FlowTableKSyncEntry::UnresolvedReference() {
569 : // KSync Flow being triggered from parallel threads due to
570 : // table partition doesnot allow safe usage of
571 : // UnresolvedReference. Please avoid any dependency handling
572 : // for KSync Flow
573 307 : return NULL;
574 : }
575 :
576 148 : int FlowTableKSyncEntry::AddMsg(char *buf, int buf_len) {
577 148 : return Encode(sandesh_op::ADD, buf, buf_len);
578 : }
579 :
580 82 : int FlowTableKSyncEntry::ChangeMsg(char *buf, int buf_len) {
581 82 : return Encode(sandesh_op::ADD, buf, buf_len);
582 : }
583 :
584 148 : int FlowTableKSyncEntry::DeleteMsg(char *buf, int buf_len) {
585 148 : return Encode(sandesh_op::DEL, buf, buf_len);
586 : }
587 :
588 0 : std::string FlowTableKSyncEntry::ToString() const {
589 0 : std::ostringstream str;
590 0 : const FlowKey *fe_key = &flow_entry_->key();
591 0 : str << "Flow : " << hash_id_
592 0 : << " with Source IP: " << fe_key->src_addr.to_string()
593 0 : << " Source port: " << fe_key->src_port
594 0 : << " Destination IP: " << fe_key->dst_addr.to_string()
595 0 : << " Destination port: " << fe_key->dst_port
596 0 : << " Protocol "<< (uint16_t)fe_key->protocol;
597 0 : return str.str();
598 0 : }
599 :
600 2884 : bool FlowTableKSyncEntry::IsLess(const KSyncEntry &rhs) const {
601 2884 : const FlowTableKSyncEntry &entry = static_cast
602 : <const FlowTableKSyncEntry &>(rhs);
603 : /*
604 : * Ksync Flow Table should have the same key as vrouter flow table,
605 : * so that all the flow entries present in vrouter can be represented
606 : * in Ksync. This will also ensure that the index change for a flow
607 : * entry will be sync'ed appropriately in vrouter.
608 : */
609 2884 : if (hash_id_ != entry.hash_id_) {
610 2272 : return hash_id_ < entry.hash_id_;
611 : }
612 612 : return flow_entry_ < entry.flow_entry_;
613 : }
614 :
615 0 : void FlowTableKSyncEntry::ErrorHandler(int err, uint32_t seq_no,
616 : KSyncEvent event) const {
617 0 : if (err == ENOSPC || err == EBADF) {
618 0 : KSYNC_ERROR(VRouterError, "VRouter operation failed. Error <", err,
619 : ":", VrouterError(err), ">. Object <", ToString(),
620 : ">. Operation <", AckOperationString(event),
621 : ">. Message number :", seq_no);
622 : }
623 0 : return;
624 : }
625 :
626 0 : std::string FlowTableKSyncEntry::VrouterError(uint32_t error) const {
627 0 : if (error == EBADF)
628 0 : return "Flow gen id Mismatch";
629 0 : else if (error == ENOSPC)
630 0 : return "Flow Table bucket full";
631 0 : else if (error == EFAULT)
632 0 : return "Flow Key Mismatch with same gen id";
633 0 : else return KSyncEntry::VrouterError(error);
634 : }
635 :
636 0 : void FlowTableKSyncObject::UpdateUnresolvedFlowEntry(FlowEntryPtr flowptr) {
637 0 : FlowEntry *flow_entry = flowptr.get();
638 0 : if (!flow_entry->IsShortFlow() && !flow_entry->IsOnUnresolvedList()) {
639 0 : unresolved_flow_list_.push_back(flow_entry);
640 0 : flow_entry->SetUnResolvedList(true);
641 0 : StartTimer();
642 : }
643 0 : }
644 : /*
645 : * timer will be triggred once after adding unresolved entry.
646 : * will be stoped once after list becomes empty.
647 : */
648 0 : void FlowTableKSyncObject::StartTimer() {
649 0 : if (timer_ == NULL) {
650 0 : timer_ = TimerManager::CreateTimer(
651 0 : *(ksync_->agent()->event_manager())->io_service(),
652 : "flow dep sync timer",
653 0 : ksync_->agent()->task_scheduler()->GetTaskId(kTaskFlowEvent),
654 0 : flow_table()->table_index());
655 : }
656 0 : timer_->Start(kFlowDepSyncTimeout,
657 : boost::bind(&FlowTableKSyncObject::TimerExpiry, this));
658 0 : }
659 :
660 : /*
661 : * This fuction will be triggred on 1 sec delay
662 : * if the entry marked deleted will not call the ksync update
663 : * if the number attempts are more than 4 times will mark the flow as shortflow
664 : */
665 :
666 0 : bool FlowTableKSyncObject::TimerExpiry() {
667 0 : uint16_t count = 0;
668 0 : while (!unresolved_flow_list_.empty() && count < KFlowUnresolvedListYield) {
669 0 : FlowEntryPtr flow = unresolved_flow_list_.front();
670 0 : FlowEntry *flow_entry = flow.get();
671 0 : unresolved_flow_list_.pop_front();
672 0 : flow_entry->SetUnResolvedList(false);
673 0 : count++;
674 0 : if (!flow_entry->deleted()) {
675 0 : FlowProto *proto = ksync()->agent()->pkt()->get_flow_proto();
676 0 : proto->EnqueueUnResolvedFlowEntry(flow.get());
677 : }
678 0 : }
679 0 : if (!unresolved_flow_list_.empty())
680 0 : return true;
681 0 : return false;
682 : }
683 :
684 2 : FlowTableKSyncObject::FlowTableKSyncObject(KSync *ksync) :
685 2 : KSyncObject("KSync FlowTable"), ksync_(ksync), free_list_(this),
686 4 : timer_(NULL) {
687 2 : }
688 :
689 0 : FlowTableKSyncObject::FlowTableKSyncObject(KSync *ksync, int max_index) :
690 0 : KSyncObject("KSync FlowTable", max_index), ksync_(ksync), free_list_(this) {
691 0 : }
692 :
693 4 : FlowTableKSyncObject::~FlowTableKSyncObject() {
694 2 : TimerManager::DeleteTimer(timer_);
695 4 : }
696 :
697 148 : KSyncEntry *FlowTableKSyncObject::Alloc(const KSyncEntry *key, uint32_t index) {
698 148 : const FlowTableKSyncEntry *entry =
699 : static_cast<const FlowTableKSyncEntry *>(key);
700 148 : return free_list_.Allocate(entry);
701 : }
702 :
703 148 : void FlowTableKSyncObject::Free(KSyncEntry *entry) {
704 148 : FlowTableKSyncEntry *ksync = static_cast<FlowTableKSyncEntry *>(entry);
705 148 : free_list_.Free(ksync);
706 148 : }
707 :
708 0 : FlowTableKSyncEntry *FlowTableKSyncObject::Find(FlowEntry *key) {
709 0 : FlowTableKSyncEntry entry(this, key, key->flow_handle());
710 0 : KSyncObject *obj = static_cast<KSyncObject *>(this);
711 0 : return static_cast<FlowTableKSyncEntry *>(obj->Find(&entry));
712 0 : }
713 :
714 77 : void FlowTableKSyncObject::UpdateKey(KSyncEntry *entry, uint32_t flow_handle) {
715 77 : static_cast<FlowTableKSyncEntry *>(entry)->set_hash_id(flow_handle);
716 77 : }
717 :
718 77 : uint32_t FlowTableKSyncObject::GetKey(KSyncEntry *entry) {
719 77 : return static_cast<FlowTableKSyncEntry *>(entry)->hash_id();
720 : }
721 :
722 77 : void FlowTableKSyncObject::UpdateFlowHandle(FlowTableKSyncEntry *entry,
723 : uint32_t flow_handle) {
724 77 : ChangeKey(entry, flow_handle);
725 77 : }
726 :
727 0 : void FlowTableKSyncObject::Init() {
728 0 : }
729 :
730 : /////////////////////////////////////////////////////////////////////////////
731 : // KSyncFlowEntryFreeList implementation
732 : /////////////////////////////////////////////////////////////////////////////
733 2 : KSyncFlowEntryFreeList::KSyncFlowEntryFreeList(FlowTableKSyncObject *object) :
734 2 : object_(object), max_count_(0), grow_pending_(false), total_alloc_(0),
735 2 : total_free_(0), free_list_() {
736 :
737 2 : uint32_t count = kInitCount;
738 2 : if (object->ksync()->agent()->test_mode()) {
739 2 : count = kTestInitCount;
740 : }
741 10002 : while (max_count_ < count) {
742 10000 : free_list_.push_back(*new FlowTableKSyncEntry(object_));
743 10000 : max_count_++;
744 : }
745 2 : }
746 :
747 2 : KSyncFlowEntryFreeList::~KSyncFlowEntryFreeList() {
748 10002 : while (free_list_.empty() == false) {
749 10000 : FreeList::iterator it = free_list_.begin();
750 10000 : FlowTableKSyncEntry *flow = &(*it);
751 20000 : free_list_.erase(it);
752 10000 : delete flow;
753 : }
754 2 : }
755 :
756 : // Allocate a chunk of FlowEntries
757 0 : void KSyncFlowEntryFreeList::Grow() {
758 0 : grow_pending_ = false;
759 0 : if (free_list_.size() >= kMinThreshold)
760 0 : return;
761 :
762 0 : for (uint32_t i = 0; i < kGrowSize; i++) {
763 0 : free_list_.push_front(*new FlowTableKSyncEntry(object_));
764 0 : max_count_++;
765 : }
766 : }
767 :
768 148 : FlowTableKSyncEntry *KSyncFlowEntryFreeList::Allocate(const KSyncEntry *key) {
769 148 : const FlowTableKSyncEntry *flow_key =
770 : static_cast<const FlowTableKSyncEntry *>(key);
771 148 : FlowTableKSyncEntry *flow = NULL;
772 148 : if (free_list_.size() == 0) {
773 0 : flow = new FlowTableKSyncEntry(object_);
774 0 : max_count_++;
775 : } else {
776 148 : FreeList::iterator it = free_list_.begin();
777 148 : flow = &(*it);
778 296 : free_list_.erase(it);
779 : }
780 :
781 148 : if (grow_pending_ == false && free_list_.size() < kMinThreshold) {
782 0 : grow_pending_ = true;
783 0 : FlowProto *proto = object_->ksync()->agent()->pkt()->get_flow_proto();
784 0 : proto->GrowFreeListRequest(flow_key->flow_entry()->flow_table());
785 : }
786 :
787 : // Do post allocation initialization
788 148 : flow->Reset(flow_key->flow_entry().get(), flow_key->hash_id());
789 148 : flow->set_evict_gen_id(flow_key->evict_gen_id_);
790 148 : total_alloc_++;
791 148 : return flow;
792 : }
793 :
794 148 : void KSyncFlowEntryFreeList::Free(FlowTableKSyncEntry *flow) {
795 148 : total_free_++;
796 148 : flow->Reset();
797 148 : if (free_list_.size() < kMaxThreshold)
798 148 : free_list_.push_back(*flow);
799 : else {
800 0 : delete flow;
801 0 : --max_count_;
802 : }
803 148 : }
804 :
805 0 : void FlowTableKSyncObject::GrowFreeList() {
806 0 : free_list_.Grow();
807 0 : }
808 :
809 : // We want to handle KSync transitions for flow from Flow task context.
810 : // KSync allows the NetlinkAck API to be over-ridden for custom handling.
811 : // Provide an implementation to enqueue an request
812 378 : void FlowTableKSyncObject::NetlinkAck(KSyncEntry *entry,
813 : KSyncEntry::KSyncEvent event) {
814 378 : FlowProto *proto = ksync()->agent()->pkt()->get_flow_proto();
815 378 : const FlowTableKSyncEntry *flow_ksync_entry =
816 : static_cast<const FlowTableKSyncEntry *>(entry);
817 : const FlowKSyncResponseInfo *resp =
818 378 : flow_ksync_entry->ksync_response_info();
819 378 : proto->KSyncEventRequest(entry, event, resp->flow_handle_,
820 378 : resp->gen_id_, resp->ksync_error_,
821 378 : resp->evict_flow_bytes_, resp->evict_flow_packets_,
822 378 : resp->evict_flow_oflow_,
823 : flow_ksync_entry->get_transaction_id());
824 378 : }
825 :
826 378 : void FlowTableKSyncObject::GenerateKSyncEvent(FlowTableKSyncEntry *entry,
827 : KSyncEntry::KSyncEvent event) {
828 378 : KSyncObject::NetlinkAck(entry, event);
829 378 : }
|