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