Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : */
4 :
5 : #include <boost/asio.hpp>
6 : #include <boost/bind/bind.hpp>
7 :
8 : #include <base/logging.h>
9 : #include <db/db_entry.h>
10 : #include <db/db_table.h>
11 : #include <db/db_table_partition.h>
12 : #include <ksync/ksync_index.h>
13 : #include <ksync/ksync_entry.h>
14 : #include <ksync/ksync_object.h>
15 : #include <ksync/ksync_netlink.h>
16 : #include <ksync/ksync_sock.h>
17 :
18 : #include "cmn/agent.h"
19 : #include "oper/interface_common.h"
20 : #include "oper/tunnel_nh.h"
21 : #include "oper/nexthop.h"
22 : #include "oper/route_common.h"
23 : #include "oper/mirror_table.h"
24 : #include "oper/agent_route_walker.h"
25 : #include "oper/hbf.h"
26 :
27 : #include "vrouter/ksync/interface_ksync.h"
28 : #include "vrouter/ksync/nexthop_ksync.h"
29 : #include "vrouter/ksync/route_ksync.h"
30 :
31 : #include "ksync_init.h"
32 : #include "vr_types.h"
33 : #include "vr_defs.h"
34 : #include "vr_nexthop.h"
35 : #include "vr_vrf_table.h"
36 :
37 : using namespace boost::placeholders;
38 :
39 0 : RouteKSyncEntry::RouteKSyncEntry(RouteKSyncObject* obj,
40 : const RouteKSyncEntry *entry,
41 0 : uint32_t index) :
42 0 : KSyncNetlinkDBEntry(index), ksync_obj_(obj),
43 0 : rt_type_(entry->rt_type_), vrf_id_(entry->vrf_id_),
44 0 : addr_(entry->addr_), src_addr_(entry->src_addr_), mac_(entry->mac_),
45 0 : prefix_len_(entry->prefix_len_), nh_(entry->nh_), label_(entry->label_),
46 0 : proxy_arp_(false), flood_dhcp_(entry->flood_dhcp_),
47 0 : address_string_(entry->address_string_),
48 0 : tunnel_type_(entry->tunnel_type_),
49 0 : wait_for_traffic_(entry->wait_for_traffic_),
50 0 : local_vm_peer_route_(entry->local_vm_peer_route_),
51 0 : flood_(entry->flood_), ethernet_tag_(entry->ethernet_tag_),
52 0 : layer2_control_word_(entry->layer2_control_word_),
53 0 : is_learnt_route_(entry->is_learnt_route_) {
54 0 : }
55 :
56 0 : RouteKSyncEntry::RouteKSyncEntry(RouteKSyncObject* obj, const AgentRoute *rt) :
57 0 : KSyncNetlinkDBEntry(kInvalidIndex), ksync_obj_(obj),
58 0 : vrf_id_(rt->vrf_id()), mac_(), nh_(NULL), label_(0), proxy_arp_(false),
59 0 : flood_dhcp_(false), tunnel_type_(TunnelType::DefaultType()),
60 0 : wait_for_traffic_(false), local_vm_peer_route_(false),
61 0 : flood_(false), ethernet_tag_(0), layer2_control_word_(false),
62 0 : is_learnt_route_(false) {
63 0 : boost::system::error_code ec;
64 0 : rt_type_ = rt->GetTableType();
65 0 : switch (rt_type_) {
66 0 : case Agent::INET4_UNICAST: {
67 0 : const InetUnicastRouteEntry *uc_rt =
68 : static_cast<const InetUnicastRouteEntry *>(rt);
69 0 : addr_ = uc_rt->prefix_address();
70 0 : src_addr_ = IpAddress::from_string("0.0.0.0", ec).to_v4();
71 0 : prefix_len_ = uc_rt->prefix_length();
72 0 : AgentPath *local_vm_path = uc_rt->FindLocalVmPortPath();
73 0 : if (local_vm_path && local_vm_path->IsDynamicLearntRoute()) {
74 0 : is_learnt_route_ = true;
75 : }
76 :
77 0 : break;
78 : }
79 0 : case Agent::INET6_UNICAST: {
80 0 : const InetUnicastRouteEntry *uc_rt =
81 : static_cast<const InetUnicastRouteEntry *>(rt);
82 0 : addr_ = uc_rt->prefix_address();
83 0 : src_addr_ = Ip6Address();
84 0 : prefix_len_ = uc_rt->prefix_length();
85 0 : break;
86 : }
87 0 : case Agent::INET4_MULTICAST: {
88 0 : const Inet4MulticastRouteEntry *mc_rt =
89 : static_cast<const Inet4MulticastRouteEntry *>(rt);
90 0 : addr_ = mc_rt->dest_ip_addr();
91 0 : src_addr_ = mc_rt->src_ip_addr();
92 0 : prefix_len_ = 32;
93 0 : break;
94 : }
95 0 : case Agent::BRIDGE: {
96 0 : const BridgeRouteEntry *l2_rt =
97 : static_cast<const BridgeRouteEntry *>(rt);
98 0 : mac_ = l2_rt->prefix_address();
99 0 : prefix_len_ = 0;
100 0 : break;
101 : }
102 0 : default: {
103 0 : assert(0);
104 : }
105 : }
106 0 : address_string_ = rt->GetAddressString();
107 0 : }
108 :
109 0 : RouteKSyncEntry::~RouteKSyncEntry() {
110 0 : }
111 :
112 0 : KSyncDBObject *RouteKSyncEntry::GetObject() const {
113 0 : return ksync_obj_;
114 : }
115 :
116 0 : bool RouteKSyncEntry::UcIsLess(const KSyncEntry &rhs) const {
117 0 : const RouteKSyncEntry &entry = static_cast<const RouteKSyncEntry &>(rhs);
118 0 : if (vrf_id_ != entry.vrf_id_) {
119 0 : return vrf_id_ < entry.vrf_id_;
120 : }
121 :
122 0 : if (addr_ != entry.addr_) {
123 0 : return addr_ < entry.addr_;
124 : }
125 :
126 0 : return (prefix_len_ < entry.prefix_len_);
127 : }
128 :
129 0 : bool RouteKSyncEntry::McIsLess(const KSyncEntry &rhs) const {
130 0 : const RouteKSyncEntry &entry = static_cast<const RouteKSyncEntry &>(rhs);
131 0 : if (vrf_id_ != entry.vrf_id_) {
132 0 : return vrf_id_ < entry.vrf_id_;
133 : }
134 :
135 0 : if (src_addr_ != entry.src_addr_) {
136 0 : return src_addr_ < entry.src_addr_;
137 : }
138 :
139 0 : return (addr_ < entry.addr_);
140 : }
141 :
142 0 : bool RouteKSyncEntry::L2IsLess(const KSyncEntry &rhs) const {
143 0 : const RouteKSyncEntry &entry = static_cast<const RouteKSyncEntry &>(rhs);
144 :
145 0 : if (vrf_id_ != entry.vrf_id_) {
146 0 : return vrf_id_ < entry.vrf_id_;
147 : }
148 :
149 0 : return mac_ < entry.mac_;
150 : }
151 :
152 0 : bool RouteKSyncEntry::IsLess(const KSyncEntry &rhs) const {
153 0 : const RouteKSyncEntry &entry = static_cast<const RouteKSyncEntry &>(rhs);
154 0 : if (rt_type_ != entry.rt_type_)
155 0 : return rt_type_ < entry.rt_type_;
156 :
157 : //First unicast
158 0 : if ((rt_type_ == Agent::INET4_UNICAST) ||
159 0 : (rt_type_ == Agent::INET6_UNICAST)) {
160 0 : return UcIsLess(rhs);
161 : }
162 :
163 0 : if (rt_type_ == Agent::BRIDGE) {
164 0 : return L2IsLess(rhs);
165 : }
166 :
167 0 : return McIsLess(rhs);
168 : }
169 :
170 0 : static std::string RouteTypeToString(Agent::RouteTableType type) {
171 0 : switch (type) {
172 0 : case Agent::INET4_UNICAST:
173 0 : return "INET4_UNICAST";
174 : break;
175 0 : case Agent::INET6_UNICAST:
176 0 : return "INET6_UNICAST";
177 : break;
178 0 : case Agent::INET4_MULTICAST:
179 0 : return "INET_MULTICAST";
180 : break;
181 0 : case Agent::BRIDGE:
182 0 : return "BRIDGE";
183 : break;
184 0 : default:
185 0 : break;
186 : }
187 :
188 0 : assert(0);
189 : return "";
190 : }
191 :
192 0 : std::string RouteKSyncEntry::ToString() const {
193 0 : std::stringstream s;
194 : NHKSyncEntry *nexthop;
195 0 : nexthop = nh();
196 :
197 0 : s << "Type : " << RouteTypeToString(rt_type_) << " ";
198 : const VrfEntry* vrf =
199 0 : ksync_obj_->ksync()->agent()->vrf_table()->FindVrfFromId(vrf_id_);
200 0 : if (vrf) {
201 0 : s << "Route Vrf : " << vrf->GetName() << " ";
202 : }
203 0 : s << address_string_ << "/" << prefix_len_ << " Type:" << rt_type_;
204 :
205 :
206 0 : s << " Label : " << label_;
207 0 : s << " Tunnel Type: " << tunnel_type_;
208 :
209 0 : if (nexthop) {
210 0 : s << nexthop->ToString();
211 : } else {
212 0 : s << " NextHop : <NULL>";
213 : }
214 :
215 0 : s << " Mac: " << mac_.ToString();
216 0 : s << " Flood DHCP:" << flood_dhcp_;
217 0 : return s.str();
218 0 : }
219 :
220 : // Check if NH points to a service-chain interface or a Gateway interface
221 0 : static bool IsGatewayOrServiceInterface(const NextHop *nh) {
222 0 : if (nh->GetType() != NextHop::INTERFACE &&
223 0 : nh->GetType() != NextHop::VLAN && nh->GetType() != NextHop::ARP)
224 0 : return false;
225 :
226 0 : const Interface *intf = NULL;
227 0 : if (nh->GetType() == NextHop::INTERFACE) {
228 0 : intf = (static_cast<const InterfaceNH *>(nh))->GetInterface();
229 0 : if (intf->type() == Interface::PACKET)
230 0 : return true;
231 0 : } else if (nh->GetType() == NextHop::VLAN) {
232 0 : intf = (static_cast<const VlanNH *>(nh))->GetInterface();
233 0 : } else if (nh->GetType() == NextHop::ARP) {
234 0 : intf = (static_cast<const ArpNH *>(nh))->GetInterface();
235 : }
236 :
237 0 : const VmInterface *vmi = dynamic_cast<const VmInterface *>(intf);
238 0 : if (vmi == NULL)
239 0 : return false;
240 :
241 0 : if (vmi->HasServiceVlan())
242 0 : return true;
243 0 : if (vmi->device_type() == VmInterface::LOCAL_DEVICE)
244 0 : return true;
245 :
246 0 : return false;
247 : }
248 :
249 : // Set the flood_ and proxy_arp_ flag for the route
250 : // flood_ flag says that ARP packets hitting route should be flooded
251 : // proxy_arp_ flag says VRouter should do proxy ARP
252 : //
253 : // The flags are set based on NH and Interface-type
254 0 : bool RouteKSyncEntry::BuildArpFlags(const DBEntry *e, const AgentPath *path,
255 : const MacAddress &mac) {
256 0 : bool ret = false;
257 :
258 : //Route flags for inet4 and inet6
259 0 : if ((rt_type_ != Agent::INET6_UNICAST) &&
260 0 : (rt_type_ != Agent::INET4_UNICAST))
261 0 : return false;
262 :
263 0 : Agent *agent = ksync_obj_->ksync()->agent();
264 0 : const InetUnicastRouteEntry *rt =
265 : static_cast<const InetUnicastRouteEntry *>(e);
266 :
267 : // Assume no flood and proxy_arp by default
268 0 : bool flood = false;
269 0 : bool proxy_arp = false;
270 0 : const NextHop *nh = rt->GetActiveNextHop();
271 :
272 0 : if (nh == NULL) {
273 0 : return false;
274 : }
275 0 : switch (nh->GetType()) {
276 0 : case NextHop::RESOLVE:
277 : // RESOLVE NH can be used by Gateway Interface or Fabric VRF
278 : // VRouter does not honour flood_ and proxy_arp_ flag for Fabric VRF
279 : // We dont want to flood ARP on Gateway Interface
280 0 : if (rt->vrf()->GetName() != agent->fabric_vrf_name()) {
281 0 : proxy_arp = true;
282 : }
283 0 : break;
284 :
285 :
286 0 : case NextHop::COMPOSITE:
287 : // ECMP flows have composite NH. We want to do routing for ECMP flows
288 : // So, set proxy_arp flag
289 0 : proxy_arp = true;
290 0 : break;
291 :
292 0 : case NextHop::TUNNEL:
293 : {
294 : // set proxy arp flag for MPLS VPN routes
295 : // these routes' nexthop is either labelled tunnel or
296 : // composite of labelled tunnel nexthops
297 0 : const TunnelNH *tunnel_nh = static_cast<const TunnelNH *>(nh);
298 0 : if (tunnel_nh->GetTunnelType().GetType() ==
299 : TunnelType::MPLS_OVER_MPLS) {
300 0 : proxy_arp = true;
301 0 : break;
302 : // other tunnel cases should be evaluated under
303 : // default case
304 : }
305 : }
306 :
307 : default:
308 :
309 0 : if (mac != MacAddress::ZeroMac()) {
310 : // Proxy-ARP without flood if mac-stitching is present
311 0 : proxy_arp = true;
312 0 : flood = false;
313 0 : break;
314 : }
315 :
316 : // MAC stitching not present.
317 : // If interface belongs to service-chain or Gateway, we want packet to
318 : // be routed. Following config ensures routing,
319 : // - Enable Proxy
320 : // - Disable Flood-bit
321 : // - Dont do MAC Stitching (in RouteNeedsMacBinding)
322 0 : if (IsGatewayOrServiceInterface(nh) == true) {
323 0 : proxy_arp = true;
324 0 : flood = false;
325 0 : break;
326 : }
327 :
328 0 : AgentPath *local_vm_path = rt->FindLocalVmPortPath();
329 0 : if (local_vm_path != NULL) {
330 0 : if (local_vm_path->is_health_check_service()) {
331 : // for local vm path exported by health check service
332 : // set proxy arp to be true to arp with vrouter MAC
333 0 : proxy_arp = true;
334 0 : flood = false;
335 : } else {
336 : // Local port without MAC stitching should only be a transition
337 : // case. In the meanwhile, flood ARP so that VM can respond
338 : // Note: In case VN is in L3 forwarding mode flags will be reset
339 : // This is done below when VN entry is extracted.
340 0 : proxy_arp_ = false;
341 0 : flood = true;
342 : }
343 : } else {
344 : // Non local-route. Set flags based on the route
345 0 : proxy_arp = rt->proxy_arp();
346 0 : flood = rt->ipam_host_route();
347 : }
348 0 : break;
349 : }
350 :
351 : // There is an exception for IPAM subnet routes.
352 : // IPAM subnet routes always result in flood of ARP even if the route
353 : // is ECMP (resulting from gateway routes)
354 0 : if (rt->ipam_subnet_route()) {
355 0 : proxy_arp = false;
356 0 : flood = true;
357 : }
358 :
359 : // If the route crosses a VN, we want packet to be routed. So, override
360 : // the flags set above and set only Proxy flag
361 : // When L2 forwarding mode is disabled, reset the proxy arp to true and flood
362 : // of arp to false.
363 0 : VnEntry *vn= rt->vrf()->vn();
364 0 : if (vn == NULL || !path->dest_vn_match(vn->GetName()) ||
365 0 : (path->dest_vn_list().size() > 1) ||
366 0 : (vn->bridging() == false)) {
367 0 : proxy_arp = true;
368 0 : flood = false;
369 : }
370 :
371 : //If VN is running in l2 mode, then any l3 route installed should
372 : //have flood flag set for ARP.
373 0 : if (vn && (vn->layer3_forwarding() == false)) {
374 0 : proxy_arp = false;
375 0 : flood = true;
376 : }
377 :
378 : // VRouter does not honour flood/proxy_arp flags for fabric-vrf
379 0 : if (rt->vrf()->GetName() == agent->fabric_vrf_name()) {
380 0 : if (mac != MacAddress() || nh->GetType() == NextHop::INTERFACE ||
381 0 : nh->GetType() == NextHop::COMPOSITE) {
382 0 : proxy_arp = true;
383 : } else {
384 0 : proxy_arp = false;
385 : }
386 0 : flood = false;
387 : }
388 :
389 0 : if (proxy_arp != proxy_arp_) {
390 0 : proxy_arp_ = proxy_arp;
391 0 : ret = true;
392 : }
393 :
394 0 : if (flood != flood_) {
395 0 : flood_ = flood;
396 0 : ret = true;
397 : }
398 0 : return ret;
399 : }
400 :
401 : //Uses internal API to extract path.
402 0 : const NextHop *RouteKSyncEntry::GetActiveNextHop(const AgentRoute *route) const {
403 0 : const AgentPath *path = GetActivePath(route);
404 0 : if (path == NULL)
405 0 : return NULL;
406 0 : return path->ComputeNextHop(ksync_obj_->ksync()->agent());
407 : }
408 :
409 : //Returns the usable path.
410 : //In case of bridge tables the path contains reference path which
411 : //has all the data. This path known as evpn_path is a level of indirection
412 : //to leaked path from MAC+IP route.
413 0 : const AgentPath *RouteKSyncEntry::GetActivePath(const AgentRoute *route) const {
414 0 : const AgentPath *path = route->GetActivePath();
415 0 : return path;
416 : }
417 :
418 0 : bool RouteKSyncEntry::Sync(DBEntry *e) {
419 0 : bool ret = false;
420 0 : Agent *agent = ksync_obj_->ksync()->agent();
421 0 : const AgentRoute *route = static_cast<AgentRoute *>(e);
422 :
423 0 : const AgentPath *path = GetActivePath(route);
424 0 : if (path->peer() == agent->local_vm_peer())
425 0 : local_vm_peer_route_ = true;
426 : else
427 0 : local_vm_peer_route_ = false;
428 :
429 0 : NHKSyncObject *nh_object = ksync_obj_->ksync()->nh_ksync_obj();
430 0 : NHKSyncEntry *old_nh = nh();
431 :
432 0 : const NextHop *tmp = NULL;
433 0 : tmp = GetActiveNextHop(route);
434 :
435 : // NHs should not be delete marked here. Interface NHs are an exception. If
436 : // an NH is found to be delete marked here, dont go ahead and initialize the
437 : // ksync entry with a delete marked NH. Make the route ksync entry use the
438 : // Discard NH's ksync entry until an update is received for the route.
439 0 : if (tmp == NULL ||
440 0 : ((tmp->GetType() != NextHop::INTERFACE) && tmp->IsDeleted())) {
441 0 : DiscardNHKey key;
442 0 : tmp = static_cast<NextHop *>(agent->nexthop_table()->
443 0 : FindActiveEntry(&key));
444 0 : }
445 0 : NHKSyncEntry nexthop(nh_object, tmp);
446 0 : nh_ = static_cast<NHKSyncEntry *>(nh_object->GetReference(&nexthop));
447 0 : if (old_nh != nh()) {
448 0 : ret = true;
449 : }
450 :
451 : //Bother for label for unicast and bridge routes
452 0 : if (rt_type_ != Agent::INET4_MULTICAST) {
453 0 : uint32_t old_label = label_;
454 :
455 0 : if (route->is_multicast()) {
456 0 : label_ = path->vxlan_id();
457 : } else {
458 0 : label_ = path->GetActiveLabel();
459 : }
460 0 : if (label_ != old_label) {
461 0 : ret = true;
462 : }
463 :
464 0 : if (tunnel_type_ != path->GetTunnelType()) {
465 0 : tunnel_type_ = path->GetTunnelType();
466 0 : ret = true;
467 : }
468 : }
469 :
470 0 : if (wait_for_traffic_ != route->WaitForTraffic()) {
471 0 : wait_for_traffic_ = route->WaitForTraffic();
472 0 : ret = true;
473 : }
474 :
475 0 : if (route->GetActivePath()) {
476 0 : if (layer2_control_word_ != route->GetActivePath()->layer2_control_word()) {
477 0 : layer2_control_word_ = route->GetActivePath()->layer2_control_word();
478 0 : ret = true;
479 : }
480 : }
481 :
482 0 : if (rt_type_ == Agent::INET4_UNICAST || rt_type_ == Agent::INET6_UNICAST) {
483 0 : VrfKSyncObject *obj = ksync_obj_->ksync()->vrf_ksync_obj();
484 0 : const InetUnicastRouteEntry *uc_rt =
485 : static_cast<const InetUnicastRouteEntry *>(e);
486 0 : MacAddress mac = MacAddress::ZeroMac();
487 0 : bool wait_for_traffic = false;
488 :
489 0 : if (obj->RouteNeedsMacBinding(uc_rt)) {
490 0 : mac = obj->GetIpMacBinding(uc_rt->vrf(), addr_, uc_rt);
491 0 : wait_for_traffic = obj->GetIpMacWaitForTraffic(uc_rt->vrf(), addr_);
492 : }
493 :
494 0 : if (wait_for_traffic_ == false &&
495 0 : wait_for_traffic_ != wait_for_traffic) {
496 0 : wait_for_traffic_ = wait_for_traffic;
497 0 : ret = true;
498 : }
499 :
500 0 : if (mac != mac_) {
501 0 : mac_ = mac;
502 0 : ret = true;
503 : }
504 :
505 0 : if (BuildArpFlags(e, path, mac_))
506 0 : ret = true;
507 : }
508 :
509 0 : if (rt_type_ == Agent::BRIDGE) {
510 0 : const BridgeRouteEntry *l2_rt =
511 : static_cast<const BridgeRouteEntry *>(route);
512 :
513 : //First search for v4
514 0 : const MacVmBindingPath *dhcp_path = l2_rt->FindMacVmBindingPath();
515 0 : bool flood_dhcp = true; // Flood DHCP if MacVmBindingPath is not present
516 0 : if (dhcp_path)
517 0 : flood_dhcp = dhcp_path->flood_dhcp();
518 :
519 0 : if (flood_dhcp_ != flood_dhcp) {
520 0 : flood_dhcp_ = flood_dhcp;
521 0 : ret = true;
522 : }
523 : }
524 :
525 0 : return ret;
526 0 : }
527 :
528 0 : void RouteKSyncEntry::FillObjectLog(sandesh_op::type type,
529 : KSyncRouteInfo &info) const {
530 0 : if (type == sandesh_op::ADD) {
531 0 : info.set_operation("ADD/CHANGE");
532 : } else {
533 0 : info.set_operation("DELETE");
534 : }
535 :
536 0 : info.set_addr(address_string_);
537 0 : info.set_plen(prefix_len_);
538 0 : info.set_vrf(vrf_id_);
539 :
540 0 : if (nh()) {
541 0 : info.set_nh_idx(nh()->nh_id());
542 0 : if (nh()->type() == NextHop::TUNNEL) {
543 0 : info.set_label(label_);
544 : }
545 : } else {
546 0 : info.set_nh_idx(NH_DISCARD_ID);
547 : }
548 :
549 0 : info.set_mac(mac_.ToString());
550 0 : info.set_type(RouteTypeToString(rt_type_));
551 0 : }
552 :
553 0 : int RouteKSyncEntry::Encode(sandesh_op::type op, uint8_t replace_plen,
554 : char *buf, int buf_len) {
555 0 : vr_route_req encoder;
556 : int encode_len;
557 0 : NHKSyncEntry *nexthop = nh();
558 :
559 0 : encoder.set_h_op(op);
560 0 : encoder.set_rtr_rid(0);
561 0 : encoder.set_rtr_vrf_id(vrf_id_);
562 0 : if (rt_type_ != Agent::BRIDGE) {
563 0 : if (addr_.is_v4()) {
564 0 : encoder.set_rtr_family(AF_INET);
565 0 : Ip4Address::bytes_type bytes = addr_.to_v4().to_bytes();
566 0 : std::vector<int8_t> rtr_prefix(bytes.begin(), bytes.end());
567 0 : encoder.set_rtr_prefix(rtr_prefix);
568 0 : } else if (addr_.is_v6()) {
569 0 : encoder.set_rtr_family(AF_INET6);
570 0 : Ip6Address::bytes_type bytes = addr_.to_v6().to_bytes();
571 0 : std::vector<int8_t> rtr_prefix(bytes.begin(), bytes.end());
572 0 : encoder.set_rtr_prefix(rtr_prefix);
573 0 : }
574 0 : encoder.set_rtr_prefix_len(prefix_len_);
575 0 : if (mac_ != MacAddress::ZeroMac()) {
576 0 : if ((addr_.is_v4() && prefix_len_ != 32) ||
577 0 : (addr_.is_v6() && prefix_len_ != 128)) {
578 0 : LOG(ERROR, "Unexpected MAC stitching for route "
579 : << ToString());
580 0 : mac_ = MacAddress::ZeroMac();
581 : }
582 : std::vector<int8_t> mac((int8_t *)mac_,
583 0 : (int8_t *)mac_ + mac_.size());
584 0 : encoder.set_rtr_mac(mac);
585 0 : }
586 : } else {
587 0 : encoder.set_rtr_family(AF_BRIDGE);
588 : //TODO add support for mac
589 : std::vector<int8_t> mac((int8_t *)mac_,
590 0 : (int8_t *)mac_ + mac_.size());
591 0 : encoder.set_rtr_mac(mac);
592 0 : }
593 :
594 0 : int label = 0;
595 0 : int flags = 0;
596 0 : if (rt_type_ != Agent::INET4_MULTICAST) {
597 : // if next hop is tunnel
598 : // or nexthop is composite and composite type is LU_ECMP, then
599 : // label is valid
600 0 : if (nexthop != NULL && ((nexthop->type() == NextHop::TUNNEL) ||
601 0 : ((nexthop->type() == NextHop::COMPOSITE) &&
602 0 : (nexthop->CompositeType() == Composite::LU_ECMP)))) {
603 0 : label = label_;
604 0 : flags |= VR_RT_LABEL_VALID_FLAG;
605 : }
606 : }
607 :
608 0 : if (rt_type_ == Agent::BRIDGE) {
609 0 : label = label_;
610 0 : if (nexthop != NULL && ((nexthop->type() == NextHop::COMPOSITE) ||
611 0 : (nexthop->type() == NextHop::TUNNEL))) {
612 0 : flags |= VR_BE_LABEL_VALID_FLAG;
613 : }
614 0 : if (flood_dhcp_) {
615 0 : flags |= VR_BE_FLOOD_DHCP_FLAG;
616 : }
617 0 : if (ksync_obj_->ksync()->agent()->tsn_no_forwarding_enabled()) {
618 0 : flags |= VR_BE_EVPN_CONTROL_PROCESSING_FLAG;
619 : }
620 : } else {
621 :
622 0 : if (proxy_arp_) {
623 0 : flags |= VR_RT_ARP_PROXY_FLAG;
624 : }
625 :
626 0 : if (wait_for_traffic_) {
627 0 : flags |= VR_RT_ARP_TRAP_FLAG;
628 : }
629 :
630 0 : if (flood_) {
631 0 : flags |= VR_RT_ARP_FLOOD_FLAG;
632 : }
633 :
634 0 : if (is_learnt_route_) {
635 0 : flags |= VR_RT_MAC_IP_LEARNT_FLAG;
636 : }
637 :
638 : }
639 :
640 0 : if (layer2_control_word_) {
641 0 : flags |= VR_BE_L2_CONTROL_DATA_FLAG;
642 : }
643 :
644 0 : encoder.set_rtr_label_flags(flags);
645 0 : encoder.set_rtr_label(label);
646 0 : if (nexthop != NULL) {
647 0 : encoder.set_rtr_nh_id(nexthop->nh_id());
648 : } else {
649 0 : encoder.set_rtr_nh_id(NH_DISCARD_ID);
650 : }
651 :
652 0 : if (op == sandesh_op::DEL) {
653 0 : encoder.set_rtr_replace_plen(replace_plen);
654 : }
655 :
656 0 : int error = 0;
657 0 : encode_len = encoder.WriteBinary((uint8_t *)buf, buf_len, &error);
658 0 : assert(error == 0);
659 0 : assert(encode_len <= buf_len);
660 0 : return encode_len;
661 0 : }
662 :
663 :
664 0 : int RouteKSyncEntry::AddMsg(char *buf, int buf_len) {
665 0 : KSyncRouteInfo info;
666 0 : FillObjectLog(sandesh_op::ADD, info);
667 0 : KSYNC_TRACE(Route, GetObject(), info);
668 0 : return Encode(sandesh_op::ADD, 0, buf, buf_len);
669 0 : }
670 :
671 0 : int RouteKSyncEntry::ChangeMsg(char *buf, int buf_len){
672 0 : KSyncRouteInfo info;
673 0 : FillObjectLog(sandesh_op::ADD, info);
674 0 : KSYNC_TRACE(Route, GetObject(), info);
675 :
676 0 : return Encode(sandesh_op::ADD, 0, buf, buf_len);
677 0 : }
678 :
679 0 : int RouteKSyncEntry::DeleteMsg(char *buf, int buf_len) {
680 :
681 0 : RouteKSyncEntry key(ksync_obj_, this, KSyncEntry::kInvalidIndex);
682 0 : KSyncEntry *found = NULL;
683 0 : RouteKSyncEntry *route = NULL;
684 0 : NHKSyncEntry *ksync_nh = NULL;
685 :
686 : // IF multicast or bridge delete unconditionally
687 0 : if ((rt_type_ == Agent::BRIDGE) ||
688 0 : (rt_type_ == Agent::INET4_MULTICAST)) {
689 0 : return DeleteInternal(nh(), NULL, buf, buf_len);
690 : }
691 :
692 : // For INET routes, we need to give replacement NH and prefixlen
693 0 : for (int plen = (prefix_len() - 1); plen >= 0; plen--) {
694 :
695 0 : if (addr_.is_v4()) {
696 0 : Ip4Address addr = Address::GetIp4SubnetAddress(addr_.to_v4(), plen);
697 0 : key.set_ip(addr);
698 0 : } else if (addr_.is_v6()) {
699 0 : Ip6Address addr = Address::GetIp6SubnetAddress(addr_.to_v6(), plen);
700 0 : key.set_ip(addr);
701 : }
702 :
703 0 : key.set_prefix_len(plen);
704 0 : found = GetObject()->Find(&key);
705 :
706 0 : if (found) {
707 0 : route = static_cast<RouteKSyncEntry *>(found);
708 0 : if (route->IsResolved()) {
709 0 : ksync_nh = route->nh();
710 0 : if(ksync_nh) {
711 0 : return DeleteInternal(ksync_nh, route, buf, buf_len);
712 : }
713 0 : ksync_nh = NULL;
714 : }
715 : }
716 : }
717 :
718 : /* If better route is not found, send discardNH for route */
719 0 : return DeleteInternal(NULL, NULL, buf, buf_len);
720 0 : }
721 :
722 0 : uint8_t RouteKSyncEntry::CopyReplacementData(NHKSyncEntry *nexthop,
723 : RouteKSyncEntry *new_rt) {
724 0 : uint8_t new_plen = 0;
725 0 : nh_ = nexthop;
726 0 : if (new_rt == NULL) {
727 0 : label_ = 0;
728 0 : proxy_arp_ = false;
729 0 : flood_ = false;
730 0 : wait_for_traffic_ = false;
731 : // mac_ is key for bridge entries and modifying it will corrut the
732 : // KSync tree. So, reset mac in case of non-bridge entries only
733 0 : if (rt_type_ != Agent::BRIDGE) {
734 0 : mac_ = MacAddress::ZeroMac();
735 : }
736 0 : is_learnt_route_ = false;
737 : } else {
738 0 : label_ = new_rt->label();
739 0 : new_plen = new_rt->prefix_len();
740 0 : proxy_arp_ = new_rt->proxy_arp();
741 0 : flood_ = new_rt->flood();
742 0 : wait_for_traffic_ = new_rt->wait_for_traffic();
743 0 : mac_ = new_rt->mac();
744 0 : is_learnt_route_ = new_rt->IsLearntRoute();
745 : }
746 0 : return new_plen;
747 : }
748 :
749 0 : int RouteKSyncEntry::DeleteInternal(NHKSyncEntry *nexthop,
750 : RouteKSyncEntry *new_rt,
751 : char *buf, int buf_len) {
752 0 : uint8_t replace_plen = CopyReplacementData(nexthop, new_rt);
753 0 : KSyncRouteInfo info;
754 0 : FillObjectLog(sandesh_op::DEL, info);
755 0 : KSYNC_TRACE(Route, GetObject(), info);
756 :
757 0 : return Encode(sandesh_op::DEL, replace_plen, buf, buf_len);
758 0 : }
759 :
760 0 : KSyncEntry *RouteKSyncEntry::UnresolvedReference() {
761 0 : NHKSyncEntry *nexthop = nh();
762 0 : if (!nexthop->IsResolvedAndInSync()) {
763 0 : return nexthop;
764 : }
765 :
766 0 : if ((rt_type_ == Agent::INET4_UNICAST) ||
767 0 : (rt_type_ == Agent::INET6_UNICAST)) {
768 0 : if (!mac_.IsZero()) {
769 : //Get Vrf and bridge ksync object
770 0 : VrfKSyncObject *vrf_obj = ksync_obj_->ksync()->vrf_ksync_obj();
771 : VrfEntry* vrf =
772 0 : ksync_obj_->ksync()->agent()->vrf_table()->FindVrfFromId(vrf_id_);
773 0 : if (vrf) {
774 : VrfKSyncObject::VrfState *state =
775 : static_cast<VrfKSyncObject::VrfState *>
776 0 : (vrf->GetState(vrf->get_table(),
777 : vrf_obj->vrf_listener_id()));
778 0 : RouteKSyncObject* bridge_ksync_obj = state->bridge_route_table_;
779 0 : BridgeRouteEntry tmp_l2_rt(vrf, mac_, Peer::EVPN_PEER, false);
780 0 : RouteKSyncEntry key(bridge_ksync_obj, &tmp_l2_rt);
781 : RouteKSyncEntry *mac_route_reference =
782 : static_cast<RouteKSyncEntry *>(bridge_ksync_obj->
783 0 : GetReference(&key));
784 : //Get the ksync entry for stitched mac
785 : //else mark dependancy on same.
786 0 : if (!mac_route_reference->IsResolved())
787 0 : return mac_route_reference;
788 0 : } else {
789 : // clear the mac_ to avoid failure in programming vrouter
790 0 : mac_ = MacAddress::ZeroMac();
791 : }
792 : }
793 : }
794 :
795 0 : return NULL;
796 : }
797 :
798 0 : RouteKSyncObject::RouteKSyncObject(KSync *ksync, AgentRouteTable *rt_table):
799 0 : KSyncDBObject("KSync Route"), ksync_(ksync), marked_delete_(false),
800 0 : table_delete_ref_(this, rt_table->deleter()) {
801 0 : rt_table_ = rt_table;
802 0 : RegisterDb(rt_table);
803 0 : }
804 :
805 0 : RouteKSyncObject::~RouteKSyncObject() {
806 0 : UnregisterDb(GetDBTable());
807 0 : table_delete_ref_.Reset(NULL);
808 0 : }
809 :
810 : KSyncDBObject::DBFilterResp
811 0 : RouteKSyncObject::DBEntryFilter(const DBEntry *entry,
812 : const KSyncDBEntry *ksync) {
813 0 : const AgentRoute *route = static_cast<const AgentRoute *>(entry);
814 : // Ignore Add/Change notifications when VRF is deleted
815 0 : if (route->vrf()->IsDeleted() == true) {
816 0 : return DBFilterIgnore;
817 : }
818 :
819 0 : if (route->GetActivePath()->inactive())
820 0 : return DBFilterIgnore;
821 0 : return DBFilterAccept;
822 : }
823 :
824 0 : KSyncEntry *RouteKSyncObject::Alloc(const KSyncEntry *entry, uint32_t index) {
825 0 : const RouteKSyncEntry *route = static_cast<const RouteKSyncEntry *>(entry);
826 0 : RouteKSyncEntry *ksync = new RouteKSyncEntry(this, route, index);
827 0 : return static_cast<KSyncEntry *>(ksync);
828 : }
829 :
830 0 : KSyncEntry *RouteKSyncObject::DBToKSyncEntry(const DBEntry *e) {
831 0 : const AgentRoute *route = static_cast<const AgentRoute *>(e);
832 0 : RouteKSyncEntry *key = new RouteKSyncEntry(this, route);
833 0 : return static_cast<KSyncEntry *>(key);
834 : }
835 :
836 0 : void RouteKSyncObject::Unregister() {
837 0 : if (IsEmpty() == true && marked_delete_ == true) {
838 0 : KSYNC_TRACE(Trace, this, "Destroying ksync object: "\
839 : + rt_table_->name());
840 0 : KSyncObjectManager::Unregister(this);
841 : }
842 0 : }
843 :
844 0 : void RouteKSyncObject::ManagedDelete() {
845 0 : marked_delete_ = true;
846 0 : Unregister();
847 0 : }
848 :
849 0 : void RouteKSyncObject::EmptyTable() {
850 0 : if (marked_delete_ == true) {
851 0 : Unregister();
852 : }
853 0 : }
854 :
855 0 : VrfKSyncEntry::VrfKSyncEntry(VrfKSyncObject *obj, const VrfEntry *entry) :
856 0 : KSyncNetlinkDBEntry(kInvalidIndex), ksync_obj_(obj),
857 0 : vrf_id_(entry->vrf_id()), hbf_rintf_(entry->hbf_rintf()),
858 0 : hbf_lintf_(entry->hbf_lintf()) {
859 0 : }
860 :
861 0 : VrfKSyncEntry::VrfKSyncEntry(VrfKSyncObject *obj,
862 : const VrfKSyncEntry *entry,
863 0 : uint32_t index) :
864 : KSyncNetlinkDBEntry(index),
865 0 : vrf_id_(entry->vrf_id()), hbf_rintf_(entry->hbf_rintf()),
866 0 : hbf_lintf_(entry->hbf_lintf()) {
867 0 : ksync_obj_ = static_cast<VrfKSyncObject*>(entry->GetObject());
868 0 : }
869 :
870 0 : VrfKSyncEntry::~VrfKSyncEntry() {
871 0 : }
872 :
873 0 : KSyncDBObject *VrfKSyncEntry::GetObject() const {
874 0 : return ksync_obj_;
875 : }
876 :
877 0 : bool VrfKSyncEntry::IsLess(const KSyncEntry &rhs) const {
878 0 : const VrfKSyncEntry &entry = static_cast<const VrfKSyncEntry &> (rhs);
879 :
880 0 : if (vrf_id_ == entry.vrf_id()) {
881 0 : if (hbf_rintf_ == entry.hbf_rintf()) {
882 0 : return (hbf_lintf_ < entry.hbf_lintf());
883 : } else {
884 0 : return (hbf_rintf_ < entry.hbf_rintf());
885 : }
886 : } else {
887 0 : return (vrf_id_ < entry.vrf_id());
888 : }
889 : }
890 :
891 0 : std::string VrfKSyncEntry::ToString() const {
892 0 : std::stringstream s;
893 0 : s << "Vrf id: " << vrf_id() << " hbf lintf: " << hbf_lintf() <<
894 0 : " hbf rintf: " << hbf_rintf();
895 0 : return s.str();
896 0 : }
897 :
898 0 : bool VrfKSyncEntry::Sync(DBEntry* e) {
899 0 : VrfEntry *vrf = static_cast<VrfEntry *>(e);
900 :
901 0 : if ((vrf->hbf_rintf() != hbf_rintf_) ||
902 0 : (vrf->hbf_lintf() != hbf_lintf_)) {
903 0 : hbf_rintf_ = vrf->hbf_rintf();
904 0 : hbf_lintf_ = vrf->hbf_lintf();
905 0 : return true;
906 : }
907 :
908 0 : return false;
909 : }
910 :
911 0 : int VrfKSyncEntry::Encode(sandesh_op::type op, uint8_t replace_plen,
912 : char *buf, int buf_len) {
913 0 : vr_vrf_req encoder;
914 : int encode_len;
915 :
916 0 : encoder.set_h_op(op);
917 0 : encoder.set_vrf_idx(vrf_id_);
918 0 : encoder.set_vrf_hbfr_vif_idx(hbf_rintf_);
919 0 : encoder.set_vrf_hbfl_vif_idx(hbf_lintf_);
920 0 : encoder.set_vrf_flags(VRF_FLAG_HBF_L_VALID|VRF_FLAG_HBF_R_VALID);
921 :
922 0 : std::stringstream ss;
923 0 : ss << "Encoding VrfKSyncEntry, vrf_id_ " << vrf_id_ <<
924 0 : " hbf_rintf_ " << hbf_rintf_ << " hbf_lintf_ " << hbf_lintf_;
925 0 : HBFTRACE(Trace, ss.str());
926 :
927 0 : int error = 0;
928 0 : encode_len = encoder.WriteBinary((uint8_t *)buf, buf_len, &error);
929 0 : assert(error == 0);
930 0 : assert(encode_len <= buf_len);
931 0 : return encode_len;
932 0 : }
933 :
934 0 : void VrfKSyncEntry::FillObjectLog(sandesh_op::type type,
935 : KSyncVrfInfo &info) const {
936 0 : if (type == sandesh_op::ADD) {
937 0 : info.set_operation("ADD/CHANGE");
938 : } else {
939 0 : info.set_operation("DELETE");
940 : }
941 :
942 0 : info.set_vrf_id(vrf_id_);
943 0 : info.set_hbf_rintf(hbf_rintf_);
944 0 : info.set_hbf_lintf(hbf_lintf_);
945 0 : }
946 :
947 0 : int VrfKSyncEntry::AddMsg(char *buf, int buf_len) {
948 0 : KSyncVrfInfo info;
949 0 : FillObjectLog(sandesh_op::ADD, info);
950 0 : KSYNC_TRACE(Vrf, GetObject(), info);
951 0 : return Encode(sandesh_op::ADD, 0, buf, buf_len);
952 0 : }
953 :
954 0 : int VrfKSyncEntry::ChangeMsg(char *buf, int buf_len){
955 0 : KSyncVrfInfo info;
956 0 : FillObjectLog(sandesh_op::ADD, info);
957 0 : KSYNC_TRACE(Vrf, GetObject(), info);
958 :
959 0 : return Encode(sandesh_op::ADD, 0, buf, buf_len);
960 0 : }
961 :
962 0 : int VrfKSyncEntry::DeleteMsg(char *buf, int buf_len) {
963 0 : KSyncVrfInfo info;
964 0 : FillObjectLog(sandesh_op::DEL, info);
965 0 : KSYNC_TRACE(Vrf, GetObject(), info);
966 :
967 0 : return Encode(sandesh_op::DEL, 0, buf, buf_len);
968 0 : }
969 :
970 0 : KSyncEntry *VrfKSyncEntry::UnresolvedReference() {
971 0 : return NULL; // TODO: check this
972 : }
973 :
974 0 : VrfKSyncObject::VrfState::VrfState(Agent *agent) :
975 0 : DBState(), seen_(false),
976 0 : evpn_rt_table_listener_id_(DBTableBase::kInvalidId) {
977 0 : ksync_route_walker_.reset(new KSyncRouteWalker(agent, this));
978 : agent->oper_db()->agent_route_walk_manager()->
979 0 : RegisterWalker(static_cast<AgentRouteWalker *>
980 : (ksync_route_walker_.get()));
981 0 : }
982 :
983 0 : KSyncEntry *VrfKSyncObject::Alloc(const KSyncEntry *entry, uint32_t index) {
984 0 : const VrfKSyncEntry *vrf = static_cast<const VrfKSyncEntry *>(entry);
985 0 : VrfKSyncEntry *ksync = new VrfKSyncEntry(this, vrf, index);
986 0 : return static_cast<KSyncEntry *>(ksync);
987 : }
988 :
989 0 : KSyncEntry *VrfKSyncObject::DBToKSyncEntry(const DBEntry* e) {
990 0 : const VrfEntry *vrf = static_cast<const VrfEntry *>(e);
991 0 : VrfKSyncEntry *key = new VrfKSyncEntry(this, vrf);
992 0 : return static_cast<KSyncEntry *>(key);
993 : }
994 :
995 0 : void VrfKSyncObject::VrfNotify(DBTablePartBase *partition, DBEntryBase *e) {
996 0 : VrfEntry *vrf = static_cast<VrfEntry *>(e);
997 : VrfState *state = static_cast<VrfState *>
998 0 : (vrf->GetState(partition->parent(), vrf_listener_id_));
999 0 : if (vrf->IsDeleted()) {
1000 0 : if (state) {
1001 0 : UnRegisterEvpnRouteTableListener(vrf, state);
1002 0 : vrf->ClearState(partition->parent(), vrf_listener_id_);
1003 0 : (static_cast<KSyncRouteWalker *>(state->ksync_route_walker_.get()))->EnqueueDelete();
1004 :
1005 0 : if (state->ksync_->IsDeleted() == false) {
1006 0 : if (state->ksync_->GetDBEntry() != NULL) {
1007 0 : state->ksync_->SetDBEntry(NULL);
1008 : }
1009 0 : NotifyEvent(state->ksync_, KSyncEntry::DEL_REQ);
1010 : }
1011 :
1012 0 : delete state;
1013 : }
1014 0 : return;
1015 : }
1016 :
1017 0 : if (state == NULL) {
1018 0 : state = new VrfState(ksync_->agent());
1019 0 : state->seen_ = true;
1020 :
1021 : // Create ksync entry for VRF
1022 : KSyncEntry *key;
1023 0 : key = DBToKSyncEntry(vrf);
1024 0 : state->ksync_ = static_cast<VrfKSyncEntry *>(CreateImpl(key));
1025 0 : delete key;
1026 0 : vrf->SetState(partition->parent(), vrf_listener_id_, state);
1027 0 : state->ksync_->SetDBEntry(vrf);
1028 0 : NotifyEvent(state->ksync_, KSyncEntry::ADD_CHANGE_REQ);
1029 :
1030 : // Get Inet4 Route table and register with KSync
1031 : AgentRouteTable *rt_table = static_cast<AgentRouteTable *>(vrf->
1032 0 : GetInet4UnicastRouteTable());
1033 0 : state->inet4_uc_route_table_ = new RouteKSyncObject(ksync_, rt_table);
1034 :
1035 : // Get Inet6 Route table and register with KSync
1036 : rt_table = static_cast<AgentRouteTable *>(vrf->
1037 0 : GetInet6UnicastRouteTable());
1038 0 : state->inet6_uc_route_table_ = new RouteKSyncObject(ksync_, rt_table);
1039 :
1040 : // Get Layer 2 Route table and register with KSync
1041 : rt_table = static_cast<AgentRouteTable *>(vrf->
1042 0 : GetBridgeRouteTable());
1043 0 : state->bridge_route_table_ = new RouteKSyncObject(ksync_, rt_table);
1044 :
1045 : //Now for multicast table. Ksync object for multicast table is
1046 : //not maintained in vrf list
1047 : //TODO Enhance ksyncobject for UC/MC, currently there is only one entry
1048 : //in MC so just use the UC object for time being.
1049 : rt_table = static_cast<AgentRouteTable *>(vrf->
1050 0 : GetInet4MulticastRouteTable());
1051 0 : state->inet4_mc_route_table_ = new RouteKSyncObject(ksync_, rt_table);
1052 :
1053 : //Add EVPN route table listener to update IP MAC binding table.
1054 : rt_table = static_cast<AgentRouteTable *>(vrf->
1055 0 : GetEvpnRouteTable());
1056 0 : KSYNC_TRACE(Trace, state->inet4_uc_route_table_,
1057 : "Subscribing to route table "\
1058 : + vrf->GetName());
1059 0 : if (state->evpn_rt_table_listener_id_ == DBTableBase::kInvalidId) {
1060 0 : state->evpn_rt_table_listener_id_ =
1061 0 : rt_table->Register(boost::bind(&VrfKSyncObject::EvpnRouteTableNotify,
1062 : this, _1, _2));
1063 : }
1064 0 : (static_cast<KSyncRouteWalker *>(state->ksync_route_walker_.get()))->
1065 0 : NotifyRoutes(vrf);
1066 : } else {
1067 0 : VrfKSyncEntry* ksync = state->ksync_;
1068 0 : if (ksync->Sync(vrf) || ksync->IsDeleted()) {
1069 0 : NotifyEvent(ksync, KSyncEntry::ADD_CHANGE_REQ);
1070 : }
1071 : }
1072 : }
1073 :
1074 0 : void VrfKSyncObject::EvpnRouteTableNotify(DBTablePartBase *partition,
1075 : DBEntryBase *e) {
1076 0 : const EvpnRouteEntry *evpn_rt = static_cast<const EvpnRouteEntry *>(e);
1077 :
1078 0 : if (evpn_rt->IsType5())
1079 0 : return;
1080 :
1081 0 : if (evpn_rt->IsDeleted()) {
1082 0 : DelIpMacBinding(evpn_rt->vrf(), evpn_rt->prefix_address(),
1083 : evpn_rt->mac(), evpn_rt->ethernet_tag());
1084 : } else {
1085 0 : AddIpMacBinding(evpn_rt->vrf(), evpn_rt->prefix_address(),
1086 : evpn_rt->mac(),
1087 : evpn_rt->ethernet_tag(),
1088 0 : evpn_rt->GetActivePath()->path_preference().preference(),
1089 0 : evpn_rt->WaitForTraffic());
1090 : }
1091 0 : return;
1092 : }
1093 :
1094 0 : void VrfKSyncObject::UnRegisterEvpnRouteTableListener(const VrfEntry *vrf,
1095 : VrfState *state) {
1096 0 : if (state->evpn_rt_table_listener_id_ == DBTableBase::kInvalidId)
1097 0 : return;
1098 :
1099 : AgentRouteTable *rt_table = static_cast<AgentRouteTable *>(vrf->
1100 0 : GetEvpnRouteTable());
1101 0 : rt_table->Unregister(state->evpn_rt_table_listener_id_);
1102 0 : state->evpn_rt_table_listener_id_ = DBTableBase::kInvalidId;
1103 : }
1104 :
1105 0 : VrfKSyncObject::VrfKSyncObject(KSync *ksync) :
1106 0 : KSyncDBObject("KSync Vrf"), ksync_(ksync), marked_delete_(false) {
1107 0 : vrf_table_ = ksync_->agent()->vrf_table();
1108 0 : }
1109 :
1110 0 : VrfKSyncObject::~VrfKSyncObject() {
1111 0 : }
1112 :
1113 0 : void VrfKSyncObject::RegisterDBClients() {
1114 0 : vrf_listener_id_ = ksync_->agent()->vrf_table()->Register
1115 0 : (boost::bind(&VrfKSyncObject::VrfNotify, this, _1, _2));
1116 0 : }
1117 :
1118 0 : void VrfKSyncObject::Shutdown() {
1119 0 : ksync_->agent()->vrf_table()->Unregister(vrf_listener_id_);
1120 0 : vrf_listener_id_ = -1;
1121 0 : }
1122 :
1123 0 : void vr_route_req::Process(SandeshContext *context) {
1124 0 : AgentSandeshContext *ioc = static_cast<AgentSandeshContext *>(context);
1125 0 : ioc->RouteMsgHandler(this);
1126 0 : }
1127 :
1128 0 : void vr_vrf_req::Process(SandeshContext *context) {
1129 0 : AgentSandeshContext *ioc = static_cast<AgentSandeshContext *>(context);
1130 0 : ioc->VrfMsgHandler(this);
1131 0 : }
1132 :
1133 : /****************************************************************************
1134 : * Methods to stitch IP and MAC addresses. The KSync object maintains mapping
1135 : * between IP <-> MAC in ip_mac_binding_ tree. The table is built based on
1136 : * Evpn routes.
1137 : *
1138 : * When an Inet route is notified, if it needs MAC Stitching, the MAC to
1139 : * stitch is found from the ip_mac_binding_ tree
1140 : *
1141 : * Any change to ip_mac_binding_ tree will also result in re-evaluation of
1142 : * Inet4/Inet6 route that may potentially have stitching changed
1143 : ****************************************************************************/
1144 :
1145 : // Compute if a route needs IP-MAC binding. A route needs IP-MAC binding if,
1146 : // 1. The NH points to interface or Tunnel-NH
1147 : // 2. NH does not belong to Service-Chain Interface
1148 : // 3. NH does not belong to Gateway Interface
1149 : // to interface or tunnel-nh
1150 0 : bool VrfKSyncObject::RouteNeedsMacBinding(const InetUnicastRouteEntry *rt) {
1151 0 : if (rt->prefix_address().is_v4() && rt->prefix_length() != 32)
1152 0 : return false;
1153 :
1154 0 : if (rt->prefix_address().is_v6() && rt->prefix_length() != 128)
1155 0 : return false;
1156 :
1157 0 : VnEntry *vn = NULL;
1158 0 : if (rt->vrf() != ksync_->agent()->fabric_vrf()) {
1159 : //Check if VN is enabled for bridging, if not then skip mac binding.
1160 0 : VnEntry *vn= rt->vrf()->vn();
1161 0 : if (vn == NULL || (vn->bridging() == false))
1162 0 : return false;
1163 : }
1164 :
1165 : // If the route crosses a VN, we want packet to be routed. So, override
1166 0 : const NextHop *nh = rt->GetActiveNextHop();
1167 0 : if (nh == NULL)
1168 0 : return false;
1169 :
1170 0 : if (nh->GetType() != NextHop::INTERFACE &&
1171 0 : nh->GetType() != NextHop::TUNNEL &&
1172 0 : nh->GetType() != NextHop::VLAN &&
1173 0 : nh->GetType() != NextHop::VRF &&
1174 0 : nh->GetType() != NextHop::ARP)
1175 0 : return false;
1176 :
1177 0 : if (IsGatewayOrServiceInterface(nh) == true)
1178 0 : return false;
1179 :
1180 0 : if (nh->GetType() == NextHop::ARP &&
1181 0 : rt->GetActivePath()->gw_ip() == Ip4Address(0)) {
1182 0 : return false;
1183 : }
1184 :
1185 0 : if (nh->GetType() == NextHop::ARP && nh->IsValid() == false) {
1186 0 : return false;
1187 : }
1188 :
1189 : //Is this a IPAM gateway? It may happen that better path is present pointing
1190 : //to tunnel. In this case IPAM gateway path will not be active path and
1191 : //identifying same will be missed. Stitching has to be avoided on non-TSN
1192 : //node.
1193 : //This has to be done only when layer3 forwarding is enabled on VN,
1194 : //else mac binding should be done irrespective of IPAM gateway.
1195 0 : if (vn && vn->layer3_forwarding()) {
1196 0 : const Agent *agent = ksync()->agent();
1197 0 : if (agent->tsn_enabled() == false) {
1198 0 : const AgentPath *path = rt->FindPath(agent->local_peer());
1199 0 : nh = path ? path->nexthop() : NULL;
1200 : }
1201 0 : if (nh && (IsGatewayOrServiceInterface(nh) == true))
1202 0 : return false;
1203 : }
1204 :
1205 0 : return true;
1206 : }
1207 :
1208 : // Notify change to KSync entry of InetUnicast Route
1209 0 : void VrfKSyncObject::NotifyUcRoute(VrfEntry *vrf, VrfState *state,
1210 : const IpAddress &ip) {
1211 0 : InetUnicastAgentRouteTable *table = NULL;
1212 0 : if (ip.is_v4()) {
1213 0 : table = vrf->GetInet4UnicastRouteTable();
1214 : } else {
1215 0 : table = vrf->GetInet6UnicastRouteTable();
1216 : }
1217 :
1218 0 : InetUnicastRouteEntry *rt = table->FindLPM(ip);
1219 0 : if (rt == NULL || rt->IsDeleted())
1220 0 : return;
1221 :
1222 0 : if (rt->GetTableType() == Agent::INET4_UNICAST) {
1223 0 : state->inet4_uc_route_table_->Notify(rt->get_table_partition(), rt);
1224 0 : } else if (rt->GetTableType() == Agent::INET6_UNICAST) {
1225 0 : state->inet6_uc_route_table_->Notify(rt->get_table_partition(), rt);
1226 : }
1227 : }
1228 :
1229 0 : void VrfKSyncObject::AddIpMacBinding(VrfEntry *vrf, const IpAddress &ip,
1230 : const MacAddress &mac,
1231 : uint32_t ethernet_tag,
1232 : uint32_t pref,
1233 : bool wait_for_traffic) {
1234 : VrfState *state = static_cast<VrfState *>
1235 0 : (vrf->GetState(vrf->get_table(), vrf_listener_id_));
1236 0 : if (state == NULL)
1237 0 : return;
1238 :
1239 : IpToMacBinding::iterator it =
1240 0 : state->ip_mac_binding_.find(std::make_pair(ip, ethernet_tag));
1241 :
1242 0 : PathPreference path_pref(0, pref, wait_for_traffic, false);
1243 0 : if (it == state->ip_mac_binding_.end()) {
1244 0 : MacBinding mac_binding(mac, path_pref);
1245 0 : state->ip_mac_binding_.insert(std::pair<IpToMacBindingKey, MacBinding>
1246 0 : (std::make_pair(ip, ethernet_tag), mac_binding));
1247 0 : } else {
1248 0 : it->second.set_mac(path_pref, mac);
1249 : }
1250 :
1251 0 : NotifyUcRoute(vrf, state, ip);
1252 0 : }
1253 :
1254 0 : void VrfKSyncObject::DelIpMacBinding(VrfEntry *vrf, const IpAddress &ip,
1255 : const MacAddress &mac,
1256 : uint32_t ethernet_tag) {
1257 : VrfState *state = static_cast<VrfState *>
1258 0 : (vrf->GetState(vrf->get_table(), vrf_listener_id_));
1259 0 : if (state == NULL)
1260 0 : return;
1261 :
1262 : IpToMacBinding::iterator it =
1263 0 : state->ip_mac_binding_.find(std::make_pair(ip, ethernet_tag));
1264 0 : if (it != state->ip_mac_binding_.end()) {
1265 0 : it->second.reset_mac(mac);
1266 0 : if (it->second.can_erase()) {
1267 0 : state->ip_mac_binding_.erase(std::make_pair(ip, ethernet_tag));
1268 : }
1269 : }
1270 0 : NotifyUcRoute(vrf, state, ip);
1271 : }
1272 :
1273 0 : bool VrfKSyncObject::GetIpMacWaitForTraffic(VrfEntry *vrf,
1274 : const IpAddress &ip) const {
1275 : VrfState *state = static_cast<VrfState *>
1276 0 : (vrf->GetState(vrf->get_table(), vrf_listener_id_));
1277 0 : if (state == NULL) {
1278 0 : return false;
1279 : }
1280 :
1281 : IpToMacBinding::const_iterator it =
1282 0 : state->ip_mac_binding_.lower_bound(std::make_pair(ip, 0));
1283 0 : if (it == state->ip_mac_binding_.end() ||
1284 0 : (it->first.first != ip)) {
1285 0 : return false;
1286 : }
1287 :
1288 0 : return it->second.WaitForTraffic();
1289 : }
1290 :
1291 0 : MacAddress VrfKSyncObject::GetIpMacBinding(VrfEntry *vrf,
1292 : const IpAddress &ip,
1293 : const InetUnicastRouteEntry *rt)
1294 : const {
1295 : VrfState *state = static_cast<VrfState *>
1296 0 : (vrf->GetState(vrf->get_table(), vrf_listener_id_));
1297 0 : if (state == NULL)
1298 0 : return MacAddress::ZeroMac();
1299 :
1300 0 : if (vrf->GetName() == ksync_->agent()->fabric_vrf_name()) {
1301 0 : if (rt->GetActivePath()->gw_ip() != Ip4Address(0)) {
1302 : const ArpNH *arp_nh =
1303 0 : dynamic_cast<const ArpNH *>(rt->GetActiveNextHop());
1304 0 : if (arp_nh) {
1305 0 : return arp_nh->GetMac();
1306 : }
1307 : }
1308 : }
1309 :
1310 : IpToMacBinding::const_iterator it =
1311 0 : state->ip_mac_binding_.lower_bound(std::make_pair(ip, 0));
1312 0 : if (it == state->ip_mac_binding_.end() ||
1313 0 : (it->first.first != ip)) {
1314 0 : return MacAddress::ZeroMac();
1315 : }
1316 :
1317 0 : return it->second.get_mac();
1318 : }
1319 :
1320 0 : KSyncRouteWalker::KSyncRouteWalker(Agent *agent, VrfKSyncObject::VrfState *state) :
1321 0 : AgentRouteWalker("ksyncroutewalker", agent), state_(state),
1322 0 : marked_for_deletion_(false) {
1323 0 : }
1324 :
1325 0 : KSyncRouteWalker::~KSyncRouteWalker() {
1326 0 : }
1327 :
1328 0 : bool IsStatePresent(AgentRoute *route, DBTableBase::ListenerId id,
1329 : DBTablePartBase *partition) {
1330 0 : DBState *state = route->GetState(partition->parent(), id);
1331 0 : return (state != NULL);
1332 : }
1333 :
1334 0 : void KSyncRouteWalker::EnqueueDelete() {
1335 0 : marked_for_deletion_ = true;
1336 0 : mgr()->ReleaseWalker(static_cast<AgentRouteWalker *>(this));
1337 0 : }
1338 :
1339 0 : bool KSyncRouteWalker::RouteWalkNotify(DBTablePartBase *partition,
1340 : DBEntryBase *e) {
1341 0 : if (marked_for_deletion_)
1342 0 : return true;
1343 :
1344 0 : AgentRoute *route = static_cast<AgentRoute *>(e);
1345 :
1346 0 : switch (route->GetTableType()) {
1347 0 : case Agent::INET4_UNICAST: {
1348 0 : if (IsStatePresent(route, state_->inet4_uc_route_table_->id(),
1349 0 : partition) == false) {
1350 0 : state_->inet4_uc_route_table_->Notify(partition, route);
1351 : }
1352 0 : break;
1353 : }
1354 0 : case Agent::INET6_UNICAST: {
1355 0 : if (IsStatePresent(route, state_->inet6_uc_route_table_->id(),
1356 0 : partition) == false) {
1357 0 : state_->inet6_uc_route_table_->Notify(partition, route);
1358 : }
1359 0 : break;
1360 : }
1361 0 : case Agent::INET4_MULTICAST: {
1362 0 : if (IsStatePresent(route, state_->inet4_mc_route_table_->id(),
1363 0 : partition) == false) {
1364 0 : state_->inet4_mc_route_table_->Notify(partition, route);
1365 : }
1366 0 : break;
1367 : }
1368 0 : case Agent::BRIDGE: {
1369 0 : if (IsStatePresent(route, state_->bridge_route_table_->id(),
1370 0 : partition) == false) {
1371 0 : state_->bridge_route_table_->Notify(partition, route);
1372 : }
1373 0 : break;
1374 : }
1375 0 : default: {
1376 0 : break;
1377 : }
1378 : }
1379 0 : return true;
1380 : }
1381 :
1382 0 : void KSyncRouteWalker::NotifyRoutes(VrfEntry *vrf) {
1383 0 : if (marked_for_deletion_ == false)
1384 0 : StartRouteWalk(vrf);
1385 0 : }
|