Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : */
4 :
5 : #include <boost/uuid/uuid_io.hpp>
6 : #include <boost/lexical_cast.hpp>
7 : #include <boost/foreach.hpp>
8 : #include <cmn/agent_cmn.h>
9 : #include <route/route.h>
10 : #include <init/agent_param.h>
11 :
12 : #include <vnc_cfg_types.h>
13 : #include <agent_types.h>
14 :
15 : #include <filter/acl.h>
16 :
17 : #include <oper/peer.h>
18 : #include <oper/vrf.h>
19 : #include <oper/interface_common.h>
20 : #include <oper/nexthop.h>
21 : #include <oper/tunnel_nh.h>
22 : #include <oper/vn.h>
23 : #include <oper/mirror_table.h>
24 : #include <oper/vxlan.h>
25 : #include <oper/mpls.h>
26 : #include <oper/route_common.h>
27 : #include <oper/ecmp_load_balance.h>
28 : #include <oper/agent_sandesh.h>
29 : #include <oper/tsn_elector.h>
30 :
31 : using namespace std;
32 : using namespace boost::asio;
33 :
34 : //Helpers
35 0 : bool RebakeLabel(MplsTable *table, uint32_t label, NextHop *nh) {
36 0 : bool ret = false;
37 0 : if (label != MplsTable::kInvalidLabel) {
38 0 : MplsLabelKey key(label);
39 0 : MplsLabel *mpls = static_cast<MplsLabel *>(table->
40 0 : FindActiveEntry(&key));
41 0 : if (mpls && mpls->ChangeNH(nh)) {
42 0 : ret = true;
43 : //Send notify of change
44 0 : mpls->get_table_partition()->Notify(mpls);
45 : }
46 0 : }
47 0 : return ret;
48 : }
49 :
50 : //AgentPath
51 19 : AgentPath::AgentPath(const Peer *peer, AgentRoute *rt):
52 19 : Path(), peer_(peer), nh_(NULL), label_(MplsTable::kInvalidLabel),
53 19 : vxlan_id_(VxLanTable::kInvalidvxlan_id), dest_vn_list_(),
54 19 : origin_vn_(""), sync_(false), force_policy_(false), sg_list_(),
55 19 : tunnel_dest_(0), tunnel_bmap_(TunnelType::AllType()),
56 19 : tunnel_type_(TunnelType::ComputeType(TunnelType::AllType())),
57 19 : vrf_name_(""), gw_ip_(), unresolved_(true),
58 19 : is_subnet_discard_(false), dependant_rt_(rt), path_preference_(),
59 19 : local_ecmp_mpls_label_(rt), composite_nh_key_(NULL), subnet_service_ip_(),
60 19 : arp_mac_(), arp_interface_(NULL), arp_valid_(false),
61 38 : ecmp_suppressed_(false), is_local_(false), is_health_check_service_(false),
62 19 : peer_sequence_number_(0), etree_leaf_(false), layer2_control_word_(false),
63 57 : inactive_(false), copy_local_path_(false), parent_rt_(rt), dependent_table_(NULL) {
64 19 : }
65 :
66 35 : AgentPath::~AgentPath() {
67 19 : clear_sg_list();
68 35 : }
69 :
70 0 : uint32_t AgentPath::GetTunnelBmap() const {
71 0 : TunnelType::Type type = TunnelType::ComputeType(tunnel_bmap_);
72 0 : if ((type == (1 << TunnelType::VXLAN)) && (vxlan_id_ != 0)) {
73 0 : return (1 << TunnelType::VXLAN);
74 : } else {
75 0 : return tunnel_bmap_;
76 : }
77 : }
78 :
79 51 : uint32_t AgentPath::GetActiveLabel() const {
80 51 : if (tunnel_type_ == TunnelType::VXLAN) {
81 0 : return vxlan_id_;
82 : } else {
83 51 : return label_;
84 : }
85 : }
86 :
87 253 : NextHop* AgentPath::nexthop() const {
88 253 : return nh_.get();
89 : }
90 :
91 376 : const NextHop* AgentPath::ComputeNextHop(Agent *agent) const {
92 376 : if (nh_) {
93 304 : return nh_.get();
94 : }
95 :
96 72 : if (unresolved_ == true) {
97 45 : DiscardNH key;
98 45 : return static_cast<NextHop *>
99 45 : (agent->nexthop_table()->FindActiveEntry(&key));
100 45 : }
101 :
102 : // Send back discard NH if dependant_rt_ is not set
103 27 : if (dependant_rt_.get() == NULL) {
104 0 : DiscardNH key;
105 0 : return static_cast<NextHop *>
106 0 : (agent->nexthop_table()->FindActiveEntry(&key));
107 0 : }
108 :
109 : //Indirect route's path, get direct route's NH
110 27 : const NextHop *nh = dependant_rt_.get()->GetActiveNextHop();
111 27 : if (nh == NULL) {
112 0 : DiscardNH key;
113 0 : return static_cast<NextHop *>
114 0 : (agent->nexthop_table()->FindActiveEntry(&key));
115 0 : }
116 27 : return nh;
117 : }
118 :
119 21 : bool AgentPath::ChangeNH(Agent *agent, NextHop *nh) {
120 : // If NH is not found, point route to discard NH
121 21 : bool ret = false;
122 21 : if (nh == NULL) {
123 0 : nh = agent->nexthop_table()->discard_nh();
124 : }
125 :
126 21 : if (nh_ != nh) {
127 15 : nh_ = nh;
128 15 : if (nh && nh->GetType() == NextHop::TUNNEL) {
129 0 : TunnelNH *tunnel_nh = static_cast<TunnelNH *>(nh);
130 0 : tunnel_dest_ = *tunnel_nh->GetDip();
131 : }
132 15 : ret = true;
133 : }
134 :
135 21 : if (peer_ && (peer_->GetType() == Peer::ECMP_PEER) &&
136 0 : (label_ != MplsTable::kInvalidLabel)) {
137 0 : if (RebakeLabel(agent->mpls_table(), label_, nh))
138 0 : ret = true;
139 : }
140 :
141 21 : if (PostChangeNH(agent, nh)) {
142 0 : ret = true;
143 : }
144 21 : return ret;
145 : }
146 :
147 21 : bool AgentPath::PostChangeNH(Agent *agent, NextHop *nh) {
148 21 : return false;
149 : }
150 :
151 0 : bool AgentPath::RebakeAllTunnelNHinCompositeNH(const AgentRoute *sync_route) {
152 0 : if (nh_->GetType() != NextHop::COMPOSITE){
153 0 : return false;
154 : }
155 :
156 : Agent *agent =
157 0 : static_cast<AgentRouteTable *>(sync_route->get_table())->agent();
158 0 : CompositeNH *cnh = static_cast<CompositeNH *>(nh_.get());
159 :
160 : //Compute new tunnel type
161 : TunnelType::Type new_tunnel_type;
162 : //Only MPLS types are supported for multicast
163 0 : if ((sync_route->is_multicast()) && (peer_->GetType() ==
164 : Peer::MULTICAST_FABRIC_TREE_BUILDER)) {
165 0 : new_tunnel_type = TunnelType::ComputeType(TunnelType::MplsType());
166 0 : if (new_tunnel_type == TunnelType::VXLAN) {
167 0 : new_tunnel_type = TunnelType::MPLS_GRE;
168 : }
169 : } else {
170 0 : new_tunnel_type = TunnelType::ComputeType(tunnel_bmap_);
171 : }
172 :
173 0 : CompositeNH *new_composite_nh = NULL;
174 0 : new_composite_nh = cnh->ChangeTunnelType(agent, new_tunnel_type);
175 0 : if (ChangeNH(agent, new_composite_nh)) {
176 : //Update composite NH key list to reflect new type
177 0 : if (composite_nh_key_)
178 0 : composite_nh_key_->ChangeTunnelType(new_tunnel_type);
179 0 : return true;
180 : }
181 0 : return false;
182 : }
183 :
184 46 : bool AgentPath::UpdateNHPolicy(Agent *agent) {
185 46 : bool ret = false;
186 46 : if (nh_.get() == NULL || nh_->GetType() != NextHop::INTERFACE) {
187 32 : return ret;
188 : }
189 :
190 14 : const InterfaceNH *intf_nh = static_cast<const InterfaceNH *>(nh_.get());
191 14 : if (intf_nh->GetInterface()->type() != Interface::VM_INTERFACE) {
192 0 : return ret;
193 : }
194 :
195 : const VmInterface *vm_port =
196 14 : static_cast<const VmInterface *>(intf_nh->GetInterface());
197 :
198 14 : bool policy = vm_port->policy_enabled();
199 14 : if (force_policy_) {
200 0 : policy = true;
201 : }
202 :
203 14 : NextHop *nh = NULL;
204 14 : if (intf_nh->PolicyEnabled() != policy) {
205 : //Make path point to policy enabled interface
206 : InterfaceNHKey key(new VmInterfaceKey(AgentKey::ADD_DEL_CHANGE,
207 0 : vm_port->GetUuid(),
208 0 : vm_port->name()),
209 0 : policy, intf_nh->GetFlags(),
210 0 : intf_nh->GetDMac());
211 0 : nh = static_cast<NextHop *>
212 0 : (agent->nexthop_table()->FindActiveEntry(&key));
213 : // If NH is not found, point route to discard NH
214 0 : if (nh == NULL) {
215 0 : LOG(DEBUG, "Interface NH for <"
216 : << boost::lexical_cast<std::string>(vm_port->GetUuid())
217 : << " : policy = " << policy);
218 0 : nh = agent->nexthop_table()->discard_nh();
219 : }
220 0 : if (ChangeNH(agent, nh) == true) {
221 0 : ret = true;
222 : }
223 0 : }
224 :
225 14 : return ret;
226 : }
227 :
228 46 : bool AgentPath::UpdateTunnelType(Agent *agent, const AgentRoute *sync_route) {
229 : //Return if there is no change in tunnel type for non Composite NH.
230 : //For composite NH component needs to be traversed.
231 : // if tunnel type is MPLS over MPLS, transport tunnel
232 : // type might be changed ( mpls over gre or mpls over udp)
233 : // so check nh transport tunnel type and trigger update if there
234 : // is any change
235 138 : if ((tunnel_type_ != TunnelType::MPLS_OVER_MPLS) &&
236 125 : (tunnel_type_ == TunnelType::ComputeType(tunnel_bmap_)) &&
237 79 : (nh_.get() && nh_.get()->GetType() != NextHop::COMPOSITE)) {
238 35 : return false;
239 : }
240 :
241 11 : tunnel_type_ = TunnelType::ComputeType(tunnel_bmap_);
242 11 : if (tunnel_type_ == TunnelType::VXLAN &&
243 0 : vxlan_id_ == VxLanTable::kInvalidvxlan_id) {
244 0 : tunnel_type_ = TunnelType::ComputeType(TunnelType::MplsType());
245 : }
246 11 : DBRequest nh_req(DBRequest::DB_ENTRY_ADD_CHANGE);
247 11 : const TunnelNH *tunnel_nh = static_cast<const TunnelNH*>(nh_.get());
248 11 : if (nh_.get() && nh_->GetType() == NextHop::TUNNEL) {
249 0 : if (tunnel_nh->GetTunnelType().GetType() == TunnelType::MPLS_OVER_MPLS) {
250 : const LabelledTunnelNH *label_tunnel_nh =
251 0 : static_cast<const LabelledTunnelNH*>(nh_.get());
252 : // check if transport tunnel type is changed
253 0 : if (label_tunnel_nh->GetTransportTunnelType() ==
254 0 : TunnelType::ComputeType(TunnelType::MplsType())) {
255 0 : return false;
256 : }
257 : LabelledTunnelNHKey *tnh_key =
258 0 : new LabelledTunnelNHKey(agent->fabric_vrf_name(),
259 0 : *(label_tunnel_nh->GetSip()),
260 0 : *(label_tunnel_nh->GetDip()),
261 : false, tunnel_type_,
262 0 : label_tunnel_nh->rewrite_dmac(),
263 0 : label_tunnel_nh->GetTransportLabel());
264 0 : nh_req.key.reset(tnh_key);
265 0 : nh_req.data.reset(new TunnelNHData());
266 0 : agent->nexthop_table()->Process(nh_req);
267 :
268 : LabelledTunnelNHKey nh_key(agent->fabric_vrf_name(),
269 0 : *(label_tunnel_nh->GetSip()),
270 0 : tunnel_dest_, false, tunnel_type_,
271 : label_tunnel_nh->rewrite_dmac(),
272 0 : label_tunnel_nh->GetTransportLabel());
273 0 : NextHop *nh = static_cast<NextHop *>
274 0 : (agent->nexthop_table()->FindActiveEntry(&nh_key));
275 0 : ChangeNH(agent, nh);
276 0 : } else {
277 :
278 : TunnelNHKey *tnh_key =
279 0 : new TunnelNHKey(agent->fabric_vrf_name(), *(tunnel_nh->GetSip()),
280 0 : tunnel_dest_, false, tunnel_type_);
281 0 : nh_req.key.reset(tnh_key);
282 0 : nh_req.data.reset(new TunnelNHData());
283 0 : agent->nexthop_table()->Process(nh_req);
284 :
285 0 : TunnelNHKey nh_key(agent->fabric_vrf_name(), *(tunnel_nh->GetSip()),
286 0 : tunnel_dest_, false, tunnel_type_);
287 0 : NextHop *nh = static_cast<NextHop *>
288 0 : (agent->nexthop_table()->FindActiveEntry(&nh_key));
289 0 : ChangeNH(agent, nh);
290 0 : }
291 : }
292 :
293 11 : if (nh_.get() && nh_->GetType() == NextHop::COMPOSITE) {
294 0 : RebakeAllTunnelNHinCompositeNH(sync_route);
295 : }
296 11 : return true;
297 11 : }
298 :
299 0 : void AgentPath::ImportPrevActiveNH(Agent *agent, NextHop *nh)
300 : {
301 0 : if (nh_ == nh) {
302 0 : return;
303 : }
304 : // change NH ,
305 : // assumptions here is that composite nh grid order would be different
306 : // but elements would be same , so importing previous active nh
307 : // would make sure the holes are already set in proper order
308 : // ex: previous nh order A,B, C, new path nh order would be BCA
309 : // ex2: previous nh order _,B,C, new path nh order is just B,C
310 0 : ChangeNH(agent, nh);
311 : // will there be a race condition while removing the active path,
312 : // adding new component nh?
313 : // this can be handled by calling reorder composite nh method
314 0 : if (composite_nh_key_ == NULL) {
315 0 : return;
316 : }
317 : boost::scoped_ptr<CompositeNHKey> composite_nh_key(
318 0 : composite_nh_key_->Clone());
319 0 : bool comp_nh_policy = false;
320 : //TODO: optimize here , compare compositenh_key from path and nh?
321 0 : ReorderCompositeNH(agent, composite_nh_key.get(), comp_nh_policy, NULL);
322 0 : composite_nh_key->SetPolicy(comp_nh_policy);
323 0 : ChangeCompositeNH(agent, composite_nh_key.get());
324 :
325 0 : }
326 :
327 46 : bool AgentPath::ResolveGwNextHops(Agent *agent, const AgentRoute *sync_route) {
328 :
329 46 : if (tunnel_type_ != TunnelType::MPLS_OVER_MPLS) {
330 46 : return false;
331 : }
332 0 : if (ecmp_member_list_.size() == 0) {
333 0 : return false;
334 : }
335 0 : NextHop *nh = NULL;
336 0 : InetUnicastAgentRouteTable *table = NULL;
337 : table = static_cast<InetUnicastAgentRouteTable *>
338 0 : (agent->fabric_inet4_mpls_table());
339 0 : assert(table != NULL);
340 : //if ecmp member list size is one then it is non ecmp route sync
341 0 : if (ecmp_member_list_.size() == 1) {
342 0 : AgentPathEcmpComponentPtr member = ecmp_member_list_[0];
343 0 : InetUnicastRouteEntry *uc_rt = table->FindRoute(member->GetGwIpAddr());
344 : const NextHop *anh;
345 0 : if (uc_rt == NULL || uc_rt->prefix_length() == 0 || (anh = uc_rt->GetActiveNextHop()) == NULL) {
346 0 : set_unresolved(true);
347 0 : member->UpdateDependentRoute(NULL);
348 0 : member->SetUnresolved(true);
349 : } else {
350 0 : set_unresolved(false);
351 0 : table->RemoveUnresolvedRoute(GetParentRoute());
352 : DBEntryBase::KeyPtr key =
353 0 : anh->GetDBRequestKey();
354 : const NextHopKey *nh_key =
355 0 : static_cast<const NextHopKey*>(key.get());
356 0 : nh = static_cast<NextHop *>(agent->nexthop_table()->
357 0 : FindActiveEntry(nh_key));
358 0 : assert(nh !=NULL);
359 : //Reset to new gateway route, no nexthop for indirect route
360 0 : member->UpdateDependentRoute(uc_rt);
361 0 : member->SetUnresolved(false);
362 0 : set_nexthop(NULL);
363 0 : }
364 0 : if (nh != NULL) {
365 0 : ChangeNH(agent, nh);
366 : }
367 0 : } else {
368 : // this flag is set if atleast one member is unresolved
369 0 : bool path_unresolved = false;
370 : // if this flag is false , then
371 : // composite NH is created with one compoenent NH as discard
372 : // and avoid reording teh existing composite NH
373 : // this flag is set to true if atleast one member is resolved
374 0 : bool is_ecmp_member_resolved = false;
375 0 : ComponentNHKeyList comp_nh_list;
376 0 : bool comp_nh_policy = false;
377 : AgentPathEcmpComponentPtrList::const_iterator ecmp_member_it =
378 0 : ecmp_member_list_.begin();
379 0 : while (ecmp_member_it != ecmp_member_list_.end()) {
380 : InetUnicastRouteEntry *uc_rt =
381 0 : table->FindRoute((*ecmp_member_it)->GetGwIpAddr());
382 : const NextHop *anh;
383 0 : if (uc_rt == NULL || uc_rt->prefix_length() == 0 || (anh = uc_rt->GetActiveNextHop()) == NULL) {
384 0 : (*ecmp_member_it)->UpdateDependentRoute(NULL);
385 0 : (*ecmp_member_it)->SetUnresolved(true);
386 0 : if (!path_unresolved) {
387 0 : path_unresolved = true;
388 : DBEntryBase::KeyPtr key =
389 0 : agent->nexthop_table()->discard_nh()->GetDBRequestKey();
390 : NextHopKey *nh_key =
391 0 : static_cast<NextHopKey *>(key.release());
392 0 : std::unique_ptr<const NextHopKey> nh_key_ptr(nh_key);
393 : ComponentNHKeyPtr component_nh_key(new ComponentNHKey(
394 0 : (*ecmp_member_it)->GetLabel(),
395 0 : std::move(nh_key_ptr)));
396 0 : comp_nh_list.push_back(component_nh_key);
397 0 : }
398 : } else {
399 0 : is_ecmp_member_resolved = true;
400 : DBEntryBase::KeyPtr key =
401 0 : anh->GetDBRequestKey();
402 0 : NextHopKey *nh_key = static_cast<NextHopKey *>(key.release());
403 0 : if (nh_key->GetType() != NextHop::COMPOSITE) {
404 : //By default all component members of composite NH
405 : //will be policy disabled, except for component NH
406 : //of type composite
407 0 : nh_key->SetPolicy(false);
408 : }
409 0 : std::unique_ptr<const NextHopKey> nh_key_ptr(nh_key);
410 : ComponentNHKeyPtr component_nh_key(new
411 0 : ComponentNHKey((*ecmp_member_it)->GetLabel(),
412 0 : std::move(nh_key_ptr)));
413 0 : comp_nh_list.push_back(component_nh_key);
414 : //Reset to new gateway route, no nexthop for indirect route
415 0 : (*ecmp_member_it)->UpdateDependentRoute(uc_rt);
416 0 : (*ecmp_member_it)->SetUnresolved(false);
417 0 : }
418 0 : ecmp_member_it++;
419 : }
420 0 : DBRequest nh_req(DBRequest::DB_ENTRY_ADD_CHANGE);
421 0 : nh_req.key.reset(new CompositeNHKey(Composite::ECMP, comp_nh_policy,
422 0 : comp_nh_list, vrf_name_));
423 0 : nh_req.data.reset(new CompositeNHData());
424 : CompositeNHKey *comp_key =
425 0 : static_cast<CompositeNHKey *>(nh_req.key.get());
426 0 : bool new_comp_nh_policy = false;
427 0 : if ((is_ecmp_member_resolved == false) ||
428 0 : ReorderCompositeNH(agent, comp_key, new_comp_nh_policy,
429 0 : sync_route->FindLocalVmPortPath())) {
430 0 : comp_key->SetPolicy(new_comp_nh_policy);
431 0 : ChangeCompositeNH(agent, comp_key);
432 : }
433 :
434 0 : set_unresolved(path_unresolved);
435 0 : }
436 :
437 :
438 0 : return true;
439 : }
440 46 : bool AgentPath::Sync(AgentRoute *sync_route) {
441 46 : bool ret = false;
442 46 : bool unresolved = false;
443 :
444 : Agent *agent = static_cast<AgentRouteTable *>
445 46 : (sync_route->get_table())->agent();
446 :
447 : // Check if there is change in policy on the interface
448 : // If yes update the path to point to policy enabled NH
449 46 : if (UpdateNHPolicy(agent)) {
450 0 : ret = true;
451 : }
452 46 : if (ResolveGwNextHops(agent, sync_route)) {
453 0 : return true;
454 : }
455 : //Handle tunnel type change
456 46 : if (UpdateTunnelType(agent, sync_route)) {
457 11 : ret = true;
458 : }
459 :
460 : //Check if there was a change in local ecmp composite nexthop
461 82 : if (nh_ && nh_->GetType() == NextHop::COMPOSITE &&
462 82 : composite_nh_key_.get() != NULL && (copy_local_path_ ||
463 0 : local_ecmp_mpls_label_.get() != NULL)) {
464 0 : boost::scoped_ptr<CompositeNHKey> composite_nh_key(composite_nh_key_->Clone());
465 0 : bool comp_nh_policy = false;
466 0 : if (ReorderCompositeNH(agent, composite_nh_key.get(), comp_nh_policy,
467 0 : sync_route->FindLocalVmPortPath())) {
468 0 : composite_nh_key->SetPolicy(comp_nh_policy);
469 0 : if (ChangeCompositeNH(agent, composite_nh_key.get())) {
470 0 : ret = true;
471 : }
472 : }
473 0 : }
474 :
475 46 : if (nh_ && nh_->GetType() == NextHop::ARP) {
476 2 : if (CopyArpData()) {
477 0 : ret = true;
478 : }
479 : }
480 :
481 46 : if (vrf_name_ == Agent::NullString()) {
482 36 : return ret;
483 : }
484 :
485 : // check dependant route change
486 : // this is needed only for inet routes
487 10 : InetUnicastAgentRouteTable *table = NULL;
488 10 : table = dynamic_cast<InetUnicastAgentRouteTable *>
489 10 : (sync_route->get_table());
490 10 : if (table == NULL) {
491 0 : return ret;
492 : }
493 :
494 10 : InetUnicastRouteEntry *rt = NULL;
495 :
496 10 : rt = table->FindRoute(gw_ip_);
497 10 : if (rt == sync_route) {
498 3 : rt = NULL;
499 : }
500 : const NextHop *anh;
501 10 : if (rt == NULL || rt->prefix_length() == 0) {
502 3 : if (agent->params()->subnet_hosts_resolvable() == false &&
503 0 : agent->fabric_vrf_name() == vrf_name_) {
504 0 : unresolved = false;
505 0 : assert(gw_ip_.is_v4());
506 0 : table->AddArpReq(vrf_name_, gw_ip_.to_v4(), vrf_name_,
507 : agent->vhost_interface(), false,
508 0 : dest_vn_list_, sg_list_, tag_list_);
509 : } else {
510 3 : unresolved = true;
511 : }
512 7 : } else if ((anh = rt->GetActiveNextHop()) == NULL) {
513 0 : if (agent->params()->subnet_hosts_resolvable() == false &&
514 0 : agent->fabric_vrf_name() == vrf_name_) {
515 0 : unresolved = false;
516 0 : assert(gw_ip_.is_v4());
517 0 : table->AddArpReq(vrf_name_, gw_ip_.to_v4(), vrf_name_,
518 : agent->vhost_interface(), false,
519 0 : dest_vn_list_, sg_list_, tag_list_);
520 : } else {
521 0 : unresolved = true;
522 : }
523 7 : } else if (anh->GetType() == NextHop::RESOLVE) {
524 2 : const ResolveNH *nh =
525 : static_cast<const ResolveNH *>(anh);
526 2 : std::string nexthop_vrf = nh->get_interface()->vrf()->GetName();
527 2 : if (nh->get_interface()->vrf()->forwarding_vrf()) {
528 2 : nexthop_vrf = nh->get_interface()->vrf()->forwarding_vrf()->GetName();
529 : }
530 :
531 2 : assert(gw_ip_.is_v4());
532 2 : table->AddArpReq(vrf_name_, gw_ip_.to_v4(), nexthop_vrf,
533 2 : nh->get_interface(), nh->PolicyEnabled(), dest_vn_list_,
534 2 : sg_list_, tag_list_);
535 2 : unresolved = true;
536 2 : } else {
537 5 : unresolved = false;
538 : }
539 :
540 10 : if (unresolved_ != unresolved) {
541 1 : unresolved_ = unresolved;
542 1 : ret = true;
543 : }
544 :
545 : // Reset to new gateway route, no nexthop for indirect route
546 10 : if (dependant_rt_.get() != rt) {
547 3 : dependant_rt_.reset(rt);
548 3 : ret = true;
549 3 : if (rt) {
550 : TunnelType::TypeBmap dep_bmap =
551 2 : dependant_rt_->GetActivePath()->tunnel_bmap();
552 2 : if (tunnel_bmap_ & 1 << TunnelType::NATIVE) {
553 2 : dep_bmap |= (1 << TunnelType::NATIVE);
554 : }
555 2 : set_tunnel_bmap(dep_bmap);
556 : }
557 : }
558 10 : return ret;
559 : }
560 :
561 5 : bool AgentPath::IsLess(const AgentPath &r_path) const {
562 5 : if (peer()->GetType() == r_path.peer()->GetType()) {
563 0 : if (path_preference() != r_path.path_preference()) {
564 : //If right path has lesser preference, then
565 : //it should be after the current entry
566 : //Hence the reverse check
567 0 : return (r_path.path_preference() < path_preference());
568 : }
569 : }
570 :
571 5 : return peer()->IsLess(r_path.peer());
572 : }
573 :
574 946 : const AgentPath *AgentPath::UsablePath() const {
575 946 : return this;
576 : }
577 :
578 3 : void AgentPath::set_nexthop(NextHop *nh) {
579 3 : nh_ = nh;
580 3 : }
581 :
582 4 : bool AgentPath::CopyArpData() {
583 4 : bool ret = false;
584 4 : if (nh_ && nh_->GetType() == NextHop::ARP) {
585 4 : const ArpNH *arp_nh = static_cast<const ArpNH *>(nh_.get());
586 4 : if (arp_mac() != arp_nh->GetMac()) {
587 0 : set_arp_mac(arp_nh->GetMac());
588 0 : ret = true;
589 : }
590 :
591 4 : if (arp_interface() != arp_nh->GetInterface()) {
592 1 : set_arp_interface(arp_nh->GetInterface());
593 1 : ret = true;
594 : }
595 :
596 4 : if (arp_valid() != arp_nh->IsValid()) {
597 0 : set_arp_valid(arp_nh->IsValid());
598 0 : ret = true;
599 : }
600 : }
601 4 : return ret;
602 : }
603 :
604 0 : bool AgentPath::CopyNdpData() {
605 0 : bool ret = false;
606 0 : if (nh_ && nh_->GetType() == NextHop::NDP) {
607 0 : const NdpNH *ndp_nh = static_cast<const NdpNH *>(nh_.get());
608 0 : if (arp_mac() != ndp_nh->GetMac()) {
609 0 : set_arp_mac(ndp_nh->GetMac());
610 0 : ret = true;
611 : }
612 :
613 0 : if (arp_interface() != ndp_nh->GetInterface()) {
614 0 : set_arp_interface(ndp_nh->GetInterface());
615 0 : ret = true;
616 : }
617 :
618 0 : if (arp_valid() != ndp_nh->IsValid()) {
619 0 : set_arp_valid(ndp_nh->IsValid());
620 0 : ret = true;
621 : }
622 : }
623 0 : return ret;
624 : }
625 :
626 1 : EvpnDerivedPath::EvpnDerivedPath(const EvpnPeer *evpn_peer,
627 : const IpAddress &ip_addr,
628 : uint32_t ethernet_tag,
629 1 : const std::string &parent) :
630 : AgentPath(evpn_peer, NULL),
631 2 : ip_addr_(ip_addr), ethernet_tag_(ethernet_tag),
632 1 : parent_(parent){
633 1 : }
634 :
635 1 : bool EvpnDerivedPath::IsLess(const AgentPath &r_path) const {
636 1 : const EvpnDerivedPath *r_evpn_path =
637 1 : dynamic_cast<const EvpnDerivedPath *>(&r_path);
638 1 : if (r_evpn_path != NULL) {
639 0 : if (r_evpn_path->ip_addr() != ip_addr_) {
640 0 : return (ip_addr_ < r_evpn_path->ip_addr());
641 : }
642 : }
643 :
644 1 : return peer()->IsLess(r_path.peer());
645 : }
646 :
647 17 : const NextHop *EvpnDerivedPath::ComputeNextHop(Agent *agent) const {
648 17 : return nexthop();
649 : }
650 :
651 4 : EvpnDerivedPathData::EvpnDerivedPathData(const EvpnRouteEntry *evpn_rt) :
652 : AgentRouteData(AgentRouteData::ADD_DEL_CHANGE,
653 4 : evpn_rt->is_multicast(), 0),
654 4 : ethernet_tag_(evpn_rt->ethernet_tag()), ip_addr_(evpn_rt->prefix_address()),
655 8 : reference_path_(evpn_rt->GetActivePath()), ecmp_suppressed_(false) {
656 : // For debuging add peer of active path in parent as well
657 4 : std::stringstream s;
658 4 : s << evpn_rt->ToString();
659 4 : s << " ";
660 4 : if (reference_path_ && reference_path_->peer())
661 3 : s << reference_path_->peer()->GetName();
662 4 : parent_ = s.str();
663 4 : }
664 :
665 1 : AgentPath *EvpnDerivedPathData::CreateAgentPath(const Peer *peer,
666 : AgentRoute *rt) const {
667 1 : const EvpnPeer *evpn_peer = dynamic_cast<const EvpnPeer *>(peer);
668 1 : assert(evpn_peer != NULL);
669 1 : return (new EvpnDerivedPath(evpn_peer, ip_addr_, ethernet_tag_,
670 1 : parent_));
671 : }
672 :
673 3 : bool EvpnDerivedPathData::AddChangePathExtended(Agent *agent, AgentPath *path,
674 : const AgentRoute *rt) {
675 3 : bool ret = false;
676 3 : EvpnDerivedPath *evpn_path = dynamic_cast<EvpnDerivedPath *>(path);
677 3 : assert(evpn_path != NULL);
678 :
679 3 : evpn_path->set_tunnel_dest(reference_path_->tunnel_dest());
680 3 : uint32_t label = reference_path_->label();
681 3 : if (evpn_path->label() != label) {
682 1 : evpn_path->set_label(label);
683 1 : ret = true;
684 : }
685 :
686 3 : uint32_t vxlan_id = reference_path_->vxlan_id();
687 3 : if (evpn_path->vxlan_id() != vxlan_id) {
688 0 : evpn_path->set_vxlan_id(vxlan_id);
689 0 : ret = true;
690 : }
691 :
692 3 : uint32_t tunnel_bmap = reference_path_->tunnel_bmap();
693 3 : if (evpn_path->tunnel_bmap() != tunnel_bmap) {
694 0 : evpn_path->set_tunnel_bmap(tunnel_bmap);
695 0 : ret = true;
696 : }
697 :
698 3 : TunnelType::Type tunnel_type = reference_path_->tunnel_type();
699 3 : if (evpn_path->tunnel_type() != tunnel_type) {
700 0 : evpn_path->set_tunnel_type(tunnel_type);
701 0 : ret = true;
702 : }
703 :
704 3 : PathPreference pref = reference_path_->path_preference();
705 3 : if (evpn_path->path_preference() != pref) {
706 : // Take path preference from parent path
707 0 : evpn_path->set_path_preference(pref);
708 0 : ret = true;
709 : }
710 :
711 6 : if (evpn_path->nexthop() !=
712 3 : reference_path_->nexthop()) {
713 1 : evpn_path->set_nexthop(reference_path_->nexthop());
714 1 : ret = true;
715 : }
716 :
717 3 : const SecurityGroupList &sg_list = reference_path_->sg_list();
718 3 : if (evpn_path->sg_list() != sg_list) {
719 0 : evpn_path->set_sg_list(sg_list);
720 0 : ret = true;
721 : }
722 :
723 3 : const TagList &tag_list = reference_path_->tag_list();
724 3 : if (evpn_path->tag_list() != tag_list) {
725 0 : evpn_path->set_tag_list(tag_list);
726 0 : ret = true;
727 : }
728 :
729 3 : const VnListType &dest_vn_list = reference_path_->dest_vn_list();
730 3 : if (evpn_path->dest_vn_list() != dest_vn_list) {
731 1 : evpn_path->set_dest_vn_list(dest_vn_list);
732 1 : ret = true;
733 : }
734 :
735 3 : if (evpn_path->ecmp_suppressed() != ecmp_suppressed_) {
736 0 : evpn_path->set_ecmp_suppressed(ecmp_suppressed_);
737 0 : ret = true;
738 : }
739 :
740 3 : if (evpn_path->etree_leaf() != reference_path_->etree_leaf()) {
741 0 : evpn_path->set_etree_leaf(reference_path_->etree_leaf());
742 0 : ret = true;
743 : }
744 :
745 3 : if (evpn_path->ResyncControlWord(rt)) {
746 0 : ret = true;
747 : }
748 :
749 3 : path->set_unresolved(false);
750 :
751 3 : return ret;
752 3 : }
753 :
754 1 : bool EvpnDerivedPathData::CanDeletePath(Agent *agent, AgentPath *path,
755 : const AgentRoute *rt) const {
756 : const EvpnDerivedPath *evpn_path =
757 1 : dynamic_cast<const EvpnDerivedPath *>(path);
758 1 : assert(evpn_path != NULL);
759 :
760 1 : if (evpn_path->ethernet_tag() != ethernet_tag())
761 0 : return false;
762 :
763 1 : return (evpn_path->ip_addr() == ip_addr());
764 : }
765 :
766 0 : bool HostRoute::AddChangePathExtended(Agent *agent, AgentPath *path,
767 : const AgentRoute *rt) {
768 0 : bool ret = false;
769 0 : NextHop *nh = NULL;
770 :
771 0 : InterfaceNHKey key(intf_.Clone(), policy_, InterfaceNHFlags::INET4,
772 0 : agent->pkt_interface_mac());
773 0 : nh = static_cast<NextHop *>(agent->nexthop_table()->FindActiveEntry(&key));
774 0 : VnListType dest_vn_list;
775 0 : dest_vn_list.insert(dest_vn_name_);
776 0 : if (path->dest_vn_list() != dest_vn_list) {
777 0 : path->set_dest_vn_list(dest_vn_list);
778 0 : ret = true;
779 : }
780 :
781 0 : path->set_unresolved(false);
782 0 : if (path->ChangeNH(agent, nh) == true)
783 0 : ret = true;
784 :
785 0 : return ret;
786 0 : }
787 :
788 0 : bool HostRoute::UpdateRoute(AgentRoute *rt) {
789 0 : InetUnicastRouteEntry *uc_rt =
790 : static_cast<InetUnicastRouteEntry *>(rt);
791 0 : AgentRouteTable *table = static_cast<AgentRouteTable *>(rt->get_table());
792 0 : if ((table->GetTableType() != Agent::INET4_UNICAST) &&
793 0 : (table->GetTableType() != Agent::INET6_UNICAST))
794 0 : return false;
795 :
796 0 : return uc_rt->UpdateRouteFlags(false, false, true);
797 : }
798 :
799 4 : bool L2ReceiveRoute::AddChangePathExtended(Agent *agent, AgentPath *path,
800 : const AgentRoute *rt) {
801 4 : bool ret = false;
802 :
803 4 : path->set_unresolved(false);
804 :
805 4 : VnListType dest_vn_list;
806 4 : dest_vn_list.insert(dest_vn_name_);
807 4 : if (path->dest_vn_list() != dest_vn_list) {
808 4 : path->set_dest_vn_list(dest_vn_list);
809 4 : ret = true;
810 : }
811 :
812 4 : if (path->label() != mpls_label_) {
813 4 : path->set_label(mpls_label_);
814 4 : ret = true;
815 : }
816 :
817 4 : if (path->vxlan_id() != vxlan_id_) {
818 0 : path->set_vxlan_id(vxlan_id_);
819 0 : ret = true;
820 : }
821 :
822 4 : if (path->path_preference().ConfigChanged(path_preference_)) {
823 0 : path->set_path_preference(path_preference_);
824 0 : ret = true;
825 : }
826 :
827 4 : if (path->peer() && path->peer()->GetType() == Peer::BGP_PEER) {
828 : //Copy entire path preference for BGP peer path,
829 : //since allowed-address pair config doesn't modify
830 : //preference on BGP path
831 0 : if (path->path_preference() != path_preference_) {
832 0 : path->set_path_preference(path_preference_);
833 0 : ret = true;
834 : }
835 : }
836 :
837 4 : if (path->ChangeNH(agent, agent->nexthop_table()->l2_receive_nh()) == true)
838 4 : ret = true;
839 :
840 4 : return ret;
841 4 : }
842 :
843 0 : bool InetInterfaceRoute::UpdateRoute(AgentRoute *rt) {
844 0 : AgentRouteTable *table = static_cast<AgentRouteTable *>(rt->get_table());
845 0 : if ((table->GetTableType() != Agent::INET4_UNICAST) &&
846 0 : (table->GetTableType() != Agent::INET6_UNICAST))
847 0 : return false;
848 :
849 0 : InetUnicastRouteEntry *uc_rt = static_cast<InetUnicastRouteEntry *>(rt);
850 :
851 0 : return uc_rt->UpdateRouteFlags(false, false, true);
852 : }
853 :
854 0 : bool InetInterfaceRoute::AddChangePathExtended(Agent *agent, AgentPath *path,
855 : const AgentRoute *rt) {
856 0 : bool ret = false;
857 0 : NextHop *nh = NULL;
858 : InterfaceNHKey key(intf_.Clone(), false, InterfaceNHFlags::INET4,
859 0 : agent->pkt_interface_mac());
860 0 : nh = static_cast<NextHop *>(agent->nexthop_table()->FindActiveEntry(&key));
861 0 : if (path->dest_vn_list() != dest_vn_list_) {
862 0 : path->set_dest_vn_list(dest_vn_list_);
863 0 : ret = true;
864 : }
865 :
866 0 : if (path->label() != label_) {
867 0 : path->set_label(label_);
868 0 : ret = true;
869 : }
870 :
871 0 : path->set_tunnel_bmap(tunnel_bmap_);
872 0 : TunnelType::Type tunnel_type = TunnelType::ComputeType(tunnel_bmap_);
873 0 : if (tunnel_type != path->tunnel_type()) {
874 0 : path->set_tunnel_type(tunnel_type);
875 0 : ret = true;
876 : }
877 :
878 0 : path->set_unresolved(false);
879 0 : if (path->ChangeNH(agent, nh) == true)
880 0 : ret = true;
881 :
882 0 : return ret;
883 0 : }
884 :
885 0 : bool DropRoute::AddChangePathExtended(Agent *agent, AgentPath *path,
886 : const AgentRoute *rt) {
887 0 : bool ret = false;
888 :
889 0 : VnListType dest_vn_list;
890 0 : dest_vn_list.insert(vn_);
891 0 : if (path->dest_vn_list() != dest_vn_list) {
892 0 : path->set_dest_vn_list(dest_vn_list);
893 0 : ret = true;
894 : }
895 :
896 0 : NextHop *nh = agent->nexthop_table()->discard_nh();
897 0 : path->set_unresolved(false);
898 0 : if (path->ChangeNH(agent, nh) == true) {
899 0 : ret = true;
900 : }
901 :
902 0 : return ret;
903 0 : }
904 :
905 7 : bool LocalVmRoute::AddChangePathExtended(Agent *agent, AgentPath *path,
906 : const AgentRoute *rt) {
907 7 : bool ret = false;
908 7 : NextHop *nh = NULL;
909 7 : SecurityGroupList path_sg_list;
910 7 : TagList path_tag_list;
911 7 : CommunityList path_communities;
912 :
913 : //TODO Based on key table type pick up interface
914 7 : VmInterfaceKey intf_key(AgentKey::ADD_DEL_CHANGE, intf_.uuid_, intf_.name_);
915 7 : VmInterface *vm_port = static_cast<VmInterface *>
916 7 : (agent->interface_table()->FindActiveEntry(&intf_key));
917 :
918 7 : bool policy = false;
919 7 : if (vm_port) {
920 : // Use policy based NH if policy enabled on interface
921 7 : if (vm_port->policy_enabled()) {
922 0 : policy = true;
923 0 : ret = true;
924 : }
925 : }
926 :
927 7 : if (native_encap_) {
928 6 : tunnel_bmap_ |= (1 << TunnelType::NATIVE);
929 : }
930 :
931 7 : if (tunnel_bmap_ != path->tunnel_bmap()) {
932 3 : path->set_tunnel_bmap(tunnel_bmap_);
933 3 : ret = true;
934 : }
935 :
936 7 : TunnelType::Type new_tunnel_type = TunnelType::ComputeType(tunnel_bmap_);
937 7 : if (new_tunnel_type == TunnelType::VXLAN &&
938 0 : vxlan_id_ == VxLanTable::kInvalidvxlan_id) {
939 0 : new_tunnel_type = TunnelType::ComputeType(TunnelType::MplsType());
940 : }
941 :
942 7 : if (path->tunnel_type() != new_tunnel_type) {
943 0 : path->set_tunnel_type(new_tunnel_type);
944 0 : ret = true;
945 : }
946 :
947 : // If policy force-enabled in request, enable policy
948 7 : path->set_force_policy(force_policy_);
949 7 : if (force_policy_) {
950 0 : policy = true;
951 : }
952 :
953 7 : MacAddress mac = MacAddress::ZeroMac();
954 7 : if (vm_port) {
955 7 : mac = vm_port->vm_mac();
956 : const InetUnicastRouteEntry *ip_rt =
957 7 : dynamic_cast<const InetUnicastRouteEntry *>(rt);
958 7 : if (ip_rt) {
959 6 : mac = vm_port->GetIpMac(ip_rt->prefix_address(), ip_rt->prefix_length());
960 : }
961 : const EvpnRouteEntry *evpn_rt =
962 7 : dynamic_cast<const EvpnRouteEntry *>(rt);
963 7 : if (evpn_rt && vm_port->mac_ip_learning_enable()) {
964 0 : mac = evpn_rt->mac();
965 : }
966 : }
967 7 : if (vm_port && vm_port->mac_ip_learning_enable()) {
968 0 : MplsLabel *mpls = agent->mpls_table()->FindMplsLabel(mpls_label_);
969 0 : if (mpls != NULL) {
970 0 : const InterfaceNH *label_nh = dynamic_cast<const InterfaceNH *>(mpls->nexthop());
971 0 : if (label_nh) {
972 0 : const MacAddress nh_dmac = label_nh->GetDMac();
973 0 : if (mac == vm_port->vm_mac() && nh_dmac != vm_port->vm_mac()) {
974 0 : mac = nh_dmac;
975 : }
976 : }
977 : }
978 : }
979 7 : InterfaceNHKey key(intf_.Clone(), policy, flags_, mac);
980 7 : nh = static_cast<NextHop *>(agent->nexthop_table()->FindActiveEntry(&key));
981 :
982 7 : if (path->label() != mpls_label_) {
983 4 : path->set_label(mpls_label_);
984 4 : ret = true;
985 : }
986 :
987 7 : if (path->vxlan_id() != vxlan_id_) {
988 0 : path->set_vxlan_id(vxlan_id_);
989 0 : ret = true;
990 : }
991 :
992 7 : if (path->dest_vn_list() != dest_vn_list_) {
993 4 : path->set_dest_vn_list(dest_vn_list_);
994 4 : ret = true;
995 : }
996 :
997 7 : path_sg_list = path->sg_list();
998 7 : if (path_sg_list != sg_list_) {
999 0 : path->set_sg_list(sg_list_);
1000 0 : ret = true;
1001 : }
1002 :
1003 7 : path_tag_list = path->tag_list();
1004 7 : if (path_tag_list != tag_list_) {
1005 0 : path->set_tag_list(tag_list_);
1006 0 : ret = true;
1007 : }
1008 :
1009 7 : path_communities = path->communities();
1010 7 : if (path_communities != communities_) {
1011 0 : path->set_communities(communities_);
1012 0 : ret = true;
1013 : }
1014 :
1015 : //Priority and sequence no of path are updated from path
1016 : //preference state machine
1017 : //Path preference value enqueued here would be copied
1018 : //only if
1019 : //1> ecmp field is set to true, meaning path would be
1020 : // active-active
1021 : //2> static preference is set, meaning external entity
1022 : // would specify the preference of this path(ex LBaaS)
1023 : //3> Change in priority when static preference is set
1024 14 : if (path->path_preference().ConfigChanged(path_preference_) ||
1025 7 : path->peer() == agent->fabric_rt_export_peer()) {
1026 0 : path->set_path_preference(path_preference_);
1027 0 : ret = true;
1028 : }
1029 :
1030 7 : if (path->peer() && path->peer()->GetType() == Peer::BGP_PEER) {
1031 : //Copy entire path preference for BGP peer path,
1032 : //since allowed-address pair config doesn't modify
1033 : //preference on BGP path
1034 0 : if (path->path_preference() != path_preference_) {
1035 0 : path->set_path_preference(path_preference_);
1036 0 : ret = true;
1037 : }
1038 : }
1039 :
1040 : // When BGP path was added, the policy flag in BGP path was based on
1041 : // interface config at that instance. If the policy flag changes in
1042 : // path for "Local Peer", we should change policy flag on BGP peer
1043 : // also. Check if policy has changed and enable SYNC of all path in
1044 : // this case
1045 : // Ideally his is needed only for LocalPath. But, having code for all
1046 : // paths does not have any problem
1047 7 : bool old_policy = false;
1048 7 : bool new_policy = false;
1049 7 : if (path->ComputeNextHop(agent) && path->ComputeNextHop(agent)->PolicyEnabled())
1050 0 : old_policy = true;
1051 7 : if (nh && nh->PolicyEnabled())
1052 0 : new_policy = true;
1053 7 : if (old_policy != new_policy) {
1054 0 : sync_route_ = true;
1055 : }
1056 :
1057 7 : if (path->subnet_service_ip() != subnet_service_ip_) {
1058 0 : path->set_subnet_service_ip(subnet_service_ip_);
1059 0 : ret = true;
1060 : }
1061 :
1062 7 : path->set_unresolved(false);
1063 7 : path->SyncRoute(sync_route_);
1064 :
1065 7 : if (ecmp_load_balance_ != path->ecmp_load_balance()) {
1066 0 : path->set_ecmp_load_balance(ecmp_load_balance_);
1067 0 : ret = true;
1068 : }
1069 :
1070 7 : if (path->ChangeNH(agent, nh) == true)
1071 4 : ret = true;
1072 :
1073 7 : if (is_local_ != path->is_local()) {
1074 0 : path->set_is_local(is_local_);
1075 0 : ret = true;
1076 : }
1077 :
1078 7 : if (is_health_check_service_ != path->is_health_check_service()) {
1079 0 : path->set_is_health_check_service(is_health_check_service_);
1080 0 : ret = true;
1081 : }
1082 :
1083 7 : if (etree_leaf_ != path->etree_leaf()) {
1084 0 : path->set_etree_leaf(etree_leaf_);
1085 0 : ret = true;
1086 : }
1087 :
1088 7 : if (native_vrf_id_ != path->native_vrf_id()) {
1089 4 : path->set_native_vrf_id(native_vrf_id_);
1090 4 : ret = true;
1091 : }
1092 7 : path->SetDynamicLearntRouteFlag(is_learnt_route_);
1093 :
1094 7 : return ret;
1095 7 : }
1096 :
1097 7 : bool LocalVmRoute::UpdateRoute(AgentRoute *rt) {
1098 7 : AgentRouteTable *table = static_cast<AgentRouteTable *>(rt->get_table());
1099 8 : if ((table->GetTableType() != Agent::INET4_UNICAST) &&
1100 1 : (table->GetTableType() != Agent::INET6_UNICAST)) {
1101 1 : return false;
1102 : }
1103 :
1104 : /* Route Reflect will not have the field populated and we do not
1105 : * want to override the route type for reflected routes */
1106 6 : if (intf_route_type().empty()) {
1107 5 : return false;
1108 : }
1109 :
1110 1 : if (intf_route_type().compare(rt->intf_route_type()) != 0) {
1111 0 : rt->set_intf_route_type(intf_route_type());
1112 0 : return true;
1113 : }
1114 :
1115 1 : return false;
1116 : }
1117 :
1118 :
1119 0 : bool PBBRoute::AddChangePathExtended(Agent *agent, AgentPath *path,
1120 : const AgentRoute *rt) {
1121 0 : bool ret = false;
1122 0 : NextHop *nh = NULL;
1123 0 : SecurityGroupList path_sg_list;
1124 0 : TagList path_tag_list;
1125 0 : CommunityList path_communities;
1126 :
1127 0 : VrfEntry *vrf = static_cast<VrfEntry *>
1128 0 : (agent->vrf_table()->FindActiveEntry(&vrf_key_));
1129 :
1130 0 : if (vrf != NULL) {
1131 : //Create PBB NH
1132 0 : DBRequest nh_req(DBRequest::DB_ENTRY_ADD_CHANGE);
1133 0 : nh_req.key.reset(new PBBNHKey(vrf_key_.name_, dmac_, isid_));
1134 0 : nh_req.data.reset(new PBBNHData());
1135 0 : agent->nexthop_table()->Process(nh_req);
1136 :
1137 0 : PBBNHKey pbb_nh_key(vrf_key_.name_, dmac_, isid_);
1138 0 : nh = static_cast<NextHop *>(agent->nexthop_table()->
1139 0 : FindActiveEntry(&pbb_nh_key));
1140 0 : }
1141 :
1142 0 : if (path->dest_vn_list() != dest_vn_list_) {
1143 0 : path->set_dest_vn_list(dest_vn_list_);
1144 0 : ret = true;
1145 : }
1146 :
1147 0 : path_sg_list = path->sg_list();
1148 0 : if (path_sg_list != sg_list_) {
1149 0 : path->set_sg_list(sg_list_);
1150 0 : ret = true;
1151 : }
1152 :
1153 0 : path_tag_list = path->tag_list();
1154 0 : if (path_tag_list != tag_list_) {
1155 0 : path->set_tag_list(tag_list_);
1156 0 : ret = true;
1157 : }
1158 :
1159 : //Copy over entire path preference structure, whenever there is a
1160 :
1161 0 : if (path->ChangeNH(agent, nh) == true) {
1162 0 : ret = true;
1163 : }
1164 :
1165 0 : path->set_unresolved(false);
1166 0 : return ret;
1167 0 : }
1168 :
1169 0 : bool VlanNhRoute::AddChangePathExtended(Agent *agent, AgentPath *path,
1170 : const AgentRoute *rt) {
1171 0 : bool ret = false;
1172 0 : NextHop *nh = NULL;
1173 0 : SecurityGroupList path_sg_list;
1174 0 : TagList path_tag_list;
1175 :
1176 0 : assert(intf_.type_ == Interface::VM_INTERFACE);
1177 0 : VlanNHKey key(intf_.uuid_, tag_);
1178 :
1179 0 : nh = static_cast<NextHop *>(agent->nexthop_table()->FindActiveEntry(&key));
1180 0 : if (nh) {
1181 0 : assert(nh->GetType() == NextHop::VLAN);
1182 : }
1183 :
1184 0 : if (path->label() != label_) {
1185 0 : path->set_label(label_);
1186 0 : ret = true;
1187 : }
1188 :
1189 0 : if (path->dest_vn_list() != dest_vn_list_) {
1190 0 : path->set_dest_vn_list(dest_vn_list_);
1191 0 : ret = true;
1192 : }
1193 :
1194 0 : path_sg_list = path->sg_list();
1195 0 : if (path_sg_list != sg_list_) {
1196 0 : path->set_sg_list(sg_list_);
1197 0 : ret = true;
1198 : }
1199 :
1200 0 : path_tag_list = path->tag_list();
1201 0 : if (path_tag_list != tag_list_) {
1202 0 : path->set_tag_list(tag_list_);
1203 0 : ret = true;
1204 : }
1205 :
1206 : //Copy over entire path preference structure, whenever there is a
1207 :
1208 : //Copy over entire path preference structure, whenever there is a
1209 : //transition from active-active to active-backup struture
1210 0 : if (path->path_preference().ConfigChanged(path_preference_)) {
1211 0 : path->set_path_preference(path_preference_);
1212 0 : ret = true;
1213 : }
1214 :
1215 0 : path->set_tunnel_bmap(tunnel_bmap_);
1216 0 : TunnelType::Type tunnel_type = TunnelType::ComputeType(tunnel_bmap_);
1217 0 : if (tunnel_type != path->tunnel_type()) {
1218 0 : path->set_tunnel_type(tunnel_type);
1219 0 : ret = true;
1220 : }
1221 :
1222 0 : path->set_unresolved(false);
1223 0 : if (path->ChangeNH(agent, nh) == true) {
1224 0 : ret = true;
1225 : }
1226 :
1227 0 : return ret;
1228 0 : }
1229 :
1230 1 : bool ResolveRoute::AddChangePathExtended(Agent *agent, AgentPath *path,
1231 : const AgentRoute *rt) {
1232 1 : bool ret = false;
1233 1 : NextHop *nh = NULL;
1234 1 : ResolveNHKey key(intf_key_.get(), policy_);
1235 :
1236 1 : nh = static_cast<NextHop *>(agent->nexthop_table()->FindActiveEntry(&key));
1237 1 : path->set_unresolved(false);
1238 :
1239 1 : VnListType dest_vn_list;
1240 1 : dest_vn_list.insert(dest_vn_name_);
1241 1 : if (path->dest_vn_list() != dest_vn_list) {
1242 1 : path->set_dest_vn_list(dest_vn_list);
1243 1 : ret = true;
1244 : }
1245 :
1246 1 : if (path->label() != label_) {
1247 0 : path->set_label(label_);
1248 0 : ret = true;
1249 : }
1250 :
1251 1 : if (path->sg_list() != path_sg_list_) {
1252 0 : path->set_sg_list(path_sg_list_);
1253 0 : ret = true;
1254 : }
1255 :
1256 : //By default resolve route on gateway interface
1257 : //is supported with MPLSoGRE or MplsoUdp port
1258 1 : path->set_tunnel_bmap(TunnelType::MplsType());
1259 : TunnelType::Type new_tunnel_type =
1260 1 : TunnelType::ComputeType(TunnelType::MplsType());
1261 1 : if (path->tunnel_type() != new_tunnel_type) {
1262 0 : path->set_tunnel_type(new_tunnel_type);
1263 : }
1264 :
1265 1 : if (path->ChangeNH(agent, nh) == true)
1266 1 : ret = true;
1267 :
1268 1 : return ret;
1269 1 : }
1270 :
1271 6 : bool ReceiveRoute::AddChangePathExtended(Agent *agent, AgentPath *path,
1272 : const AgentRoute *rt) {
1273 6 : bool ret = false;
1274 6 : NextHop *nh = NULL;
1275 :
1276 : //TODO check if it needs to know table type
1277 6 : ReceiveNHKey key(intf_->Clone(), policy_);
1278 6 : nh = static_cast<NextHop *>(agent->nexthop_table()->FindActiveEntry(&key));
1279 6 : path->set_unresolved(false);
1280 :
1281 6 : VnListType dest_vn_list;
1282 6 : dest_vn_list.insert(vn_);
1283 6 : if (path->dest_vn_list() != dest_vn_list) {
1284 4 : path->set_dest_vn_list(dest_vn_list);
1285 4 : ret = true;
1286 : }
1287 :
1288 6 : if (path->label() != label_) {
1289 4 : path->set_label(label_);
1290 4 : ret = true;
1291 : }
1292 :
1293 6 : path->set_tunnel_bmap(tunnel_bmap_);
1294 :
1295 6 : if (path->ChangeNH(agent, nh) == true)
1296 4 : ret = true;
1297 :
1298 6 : return ret;
1299 6 : }
1300 :
1301 6 : bool ReceiveRoute::UpdateRoute(AgentRoute *rt) {
1302 6 : AgentRouteTable *table = static_cast<AgentRouteTable *>(rt->get_table());
1303 8 : if ((table->GetTableType() != Agent::INET4_UNICAST) &&
1304 2 : (table->GetTableType() != Agent::INET6_UNICAST))
1305 1 : return false;
1306 :
1307 5 : InetUnicastRouteEntry *uc_rt =
1308 : static_cast<InetUnicastRouteEntry *>(rt);
1309 :
1310 : // Receive route can be a /32 route of multicast-subnet route
1311 : // proxy_arp_ is set only for host route. So, set ipam_host_route_ if
1312 : // proxy_arp_ enabled
1313 5 : return uc_rt->UpdateRouteFlags(false, ipam_host_route_, proxy_arp_);
1314 : }
1315 :
1316 0 : MulticastRoutePath::MulticastRoutePath(const Peer *peer) :
1317 0 : AgentPath(peer, NULL), original_nh_(),
1318 0 : evpn_label_(MplsTable::kInvalidLabel),
1319 0 : fabric_label_(MplsTable::kInvalidLabel) {
1320 0 : }
1321 :
1322 0 : bool MulticastRoutePath::PostChangeNH(Agent *agent, NextHop *nh) {
1323 0 : bool ret = false;
1324 0 : if (!peer())
1325 0 : return false;
1326 :
1327 0 : if (peer()->GetType() != Peer::MULTICAST_PEER)
1328 0 : return false;
1329 :
1330 : //Bake for label in path
1331 0 : if (RebakeLabel(agent->mpls_table(), label(), nh))
1332 0 : ret = true;
1333 :
1334 : //If path label is not same as evpn label, then rebake evpn label
1335 0 : if ((label() != evpn_label_) &&
1336 0 : RebakeLabel(agent->mpls_table(), evpn_label_, nh))
1337 0 : ret = true;
1338 :
1339 : //If path label is not same as fmg label, then rebake fmg label
1340 0 : if ((label() != fabric_label_) &&
1341 0 : RebakeLabel(agent->mpls_table(), fabric_label_, nh))
1342 0 : ret = true;
1343 :
1344 0 : return ret;
1345 : }
1346 :
1347 0 : NextHop *MulticastRoutePath::UpdateNH(Agent *agent,
1348 : CompositeNH *cnh,
1349 : const TsnElector *te) {
1350 0 : ComponentNHKeyList new_component_nh_key_list;
1351 0 : for (ComponentNHKeyList::const_iterator it =
1352 0 : cnh->component_nh_key_list().begin();
1353 0 : it != cnh->component_nh_key_list().end(); it++) {
1354 0 : if ((*it) == NULL)
1355 0 : continue;
1356 : const TunnelNHKey *tunnel_nh_key =
1357 0 : static_cast<const TunnelNHKey *>((*it)->nh_key());
1358 0 : if (std::find(te->ManagedPhysicalDevices().begin(),
1359 0 : te->ManagedPhysicalDevices().end(),
1360 0 : tunnel_nh_key->dip().to_string()) !=
1361 0 : te->ManagedPhysicalDevices().end()) {
1362 0 : new_component_nh_key_list.push_back(*it);
1363 : }
1364 : }
1365 0 : set_original_nh(cnh);
1366 0 : DBRequest nh_req(DBRequest::DB_ENTRY_ADD_CHANGE);
1367 0 : nh_req.key.reset(new CompositeNHKey(Composite::EVPN, false,
1368 : new_component_nh_key_list,
1369 0 : cnh->vrf()->GetName()));
1370 0 : nh_req.data.reset(new CompositeNHData(cnh->pbb_nh(),
1371 0 : cnh->learning_enabled(), false));
1372 0 : agent->nexthop_table()->Process(nh_req);
1373 0 : NextHop *new_nh = static_cast<NextHop *>(agent->nexthop_table()->
1374 0 : FindActiveEntry(nh_req.key.get()));
1375 0 : assert(new_nh);
1376 0 : return new_nh;
1377 0 : }
1378 :
1379 0 : AgentPath *MulticastRoute::CreateAgentPath(const Peer *peer,
1380 : AgentRoute *rt) const {
1381 0 : return (new MulticastRoutePath(peer));
1382 : }
1383 :
1384 0 : bool MulticastRoute::AddChangePathExtended(Agent *agent, AgentPath *path,
1385 : const AgentRoute *rt) {
1386 0 : bool ret = false;
1387 0 : NextHop *nh = NULL;
1388 :
1389 0 : agent->nexthop_table()->Process(composite_nh_req_);
1390 0 : nh = static_cast<NextHop *>(agent->nexthop_table()->
1391 0 : FindActiveEntry(composite_nh_req_.key.get()));
1392 0 : assert(nh);
1393 :
1394 0 : if (agent->params()->agent_mode() == AgentParam::TSN_NO_FORWARDING_AGENT) {
1395 : MulticastRoutePath *multicast_path =
1396 0 : dynamic_cast<MulticastRoutePath *>(path);
1397 0 : multicast_path->set_original_nh(nh);
1398 0 : const TsnElector *te = agent->oper_db()->tsn_elector();
1399 0 : CompositeNH *cnh = dynamic_cast<CompositeNH *>(nh);
1400 0 : if (cnh && (cnh->composite_nh_type() == Composite::EVPN)) {
1401 0 : if (te->IsMaster() == false)
1402 0 : path->set_inactive(true);
1403 0 : nh = multicast_path->UpdateNH(agent, cnh, te);
1404 : }
1405 : }
1406 0 : ret = MulticastRoute::CopyPathParameters(agent,
1407 : path,
1408 0 : vn_name_,
1409 : false,
1410 : vxlan_id_,
1411 0 : ((label_ == MplsTable::kInvalidLabel) ? path->label() : label_),
1412 : tunnel_type_,
1413 0 : nh, rt, ha_stale_);
1414 0 : return ret;
1415 : }
1416 :
1417 0 : bool MulticastRoute::CopyPathParameters(Agent *agent,
1418 : AgentPath *path,
1419 : const std::string &vn_name,
1420 : bool unresolved,
1421 : uint32_t vxlan_id,
1422 : uint32_t label,
1423 : uint32_t tunnel_type,
1424 : NextHop *nh,
1425 : const AgentRoute *rt,
1426 : bool ha_stale) {
1427 0 : VnListType dest_vn_list;
1428 0 : dest_vn_list.insert(vn_name);
1429 0 : path->set_dest_vn_list(dest_vn_list);
1430 0 : path->set_unresolved(unresolved);
1431 0 : path->set_vxlan_id(vxlan_id);
1432 0 : if ((path->peer() != agent->local_vm_peer()) &&
1433 0 : (path->peer() != agent->local_peer()))
1434 0 : path->set_label(label);
1435 :
1436 : //Setting of tunnel is only for simulated TOR.
1437 0 : path->set_tunnel_bmap(tunnel_type);
1438 : TunnelType::Type new_tunnel_type =
1439 0 : TunnelType::ComputeType(tunnel_type);
1440 0 : if (new_tunnel_type == TunnelType::VXLAN &&
1441 : vxlan_id == VxLanTable::kInvalidvxlan_id) {
1442 0 : new_tunnel_type = TunnelType::ComputeType(TunnelType::MplsType());
1443 : }
1444 :
1445 0 : if (path->tunnel_type() != new_tunnel_type) {
1446 0 : path->set_tunnel_type(new_tunnel_type);
1447 : }
1448 :
1449 0 : uint32_t old_pref = path->path_preference().preference();
1450 0 : if (ha_stale) {
1451 0 : if (old_pref != PathPreference::HA_STALE) {
1452 0 : path->path_preference_non_const().set_preference(PathPreference::HA_STALE);
1453 : }
1454 : } else {
1455 0 : if (old_pref != PathPreference::LOW) {
1456 0 : path->path_preference_non_const().set_preference(PathPreference::LOW);
1457 : }
1458 : }
1459 :
1460 0 : path->ChangeNH(agent, nh);
1461 :
1462 0 : path->ResyncControlWord(rt);
1463 :
1464 0 : return true;
1465 0 : }
1466 :
1467 0 : bool MulticastRoute::CanDeletePath(Agent *agent, AgentPath *path,
1468 : const AgentRoute *rt) const {
1469 0 : return (vxlan_id() == path->vxlan_id());
1470 : }
1471 :
1472 0 : bool PathPreferenceData::AddChangePathExtended(Agent *agent, AgentPath *path,
1473 : const AgentRoute *rt) {
1474 0 : bool ret = false;
1475 : //ECMP flag will not be changed by path preference module,
1476 : //hence retain value in path
1477 0 : if (!path) {
1478 0 : return ret;
1479 : }
1480 :
1481 0 : path_preference_.set_ecmp(path->path_preference().ecmp());
1482 0 : path_preference_.set_dependent_ip(path->path_preference().dependent_ip());
1483 0 : path_preference_.set_vrf(path->path_preference().vrf());
1484 0 : if (path &&
1485 0 : path->path_preference() != path_preference_) {
1486 0 : path->set_path_preference(path_preference_);
1487 0 : ret = true;
1488 : }
1489 0 : return ret;
1490 : }
1491 :
1492 : // Subnet Route route data
1493 0 : IpamSubnetRoute::IpamSubnetRoute(DBRequest &nh_req,
1494 0 : const std::string &dest_vn_name) :
1495 : AgentRouteData(AgentRouteData::ADD_DEL_CHANGE, false, 0),
1496 0 : dest_vn_name_(dest_vn_name) {
1497 0 : nh_req_.Swap(&nh_req);
1498 0 : }
1499 :
1500 0 : bool IpamSubnetRoute::AddChangePathExtended(Agent *agent, AgentPath *path,
1501 : const AgentRoute *rt) {
1502 0 : agent->nexthop_table()->Process(nh_req_);
1503 0 : NextHop *nh = static_cast<NextHop *>(agent->nexthop_table()->
1504 0 : FindActiveEntry(nh_req_.key.get()));
1505 0 : assert(nh);
1506 :
1507 0 : bool ret = false;
1508 :
1509 0 : if (path->ChangeNH(agent, nh) == true) {
1510 0 : ret = true;
1511 : }
1512 0 : path->set_is_subnet_discard(true);
1513 :
1514 0 : VnListType dest_vn_list;
1515 0 : dest_vn_list.insert(dest_vn_name_);
1516 0 : if (path->dest_vn_list() != dest_vn_list) {
1517 0 : path->set_dest_vn_list(dest_vn_list);
1518 0 : ret = true;
1519 : }
1520 :
1521 : //Resync of subnet route is needed for identifying if arp flood flag
1522 : //needs to be enabled for all the smaller subnets present w.r.t. this subnet
1523 : //route.
1524 0 : AgentRouteTable *table = static_cast<AgentRouteTable *>(rt->get_table());
1525 0 : assert((table->GetTableType() == Agent::INET4_UNICAST) ||
1526 : (table->GetTableType() == Agent::INET6_UNICAST));
1527 :
1528 0 : InetUnicastAgentRouteTable *uc_rt_table =
1529 : static_cast<InetUnicastAgentRouteTable *>(table);
1530 0 : const InetUnicastRouteEntry *uc_rt =
1531 : static_cast<const InetUnicastRouteEntry *>(rt);
1532 0 : uc_rt_table->ResyncSubnetRoutes(uc_rt, true);
1533 0 : return ret;
1534 0 : }
1535 :
1536 0 : bool IpamSubnetRoute::UpdateRoute(AgentRoute *rt) {
1537 0 : InetUnicastRouteEntry *uc_rt = static_cast<InetUnicastRouteEntry *>(rt);
1538 :
1539 0 : return uc_rt->UpdateRouteFlags(true, false, false);
1540 : }
1541 :
1542 : ///////////////////////////////////////////////
1543 : // Sandesh routines below (route_sandesh.cc)
1544 : //////////////////////////////////////////////
1545 : //TODO make it generic
1546 0 : void UnresolvedNH::HandleRequest() const {
1547 :
1548 0 : VrfEntry *vrf = Agent::GetInstance()->vrf_table()->FindVrfFromId(0);
1549 0 : if (!vrf) {
1550 0 : ErrorResp *resp = new ErrorResp();
1551 0 : resp->set_context(context());
1552 0 : resp->Response();
1553 0 : return;
1554 : }
1555 :
1556 0 : int count = 0;
1557 0 : std::string empty("");
1558 : AgentRouteTable *rt_table = static_cast<AgentRouteTable *>
1559 0 : (vrf->GetInet4UnicastRouteTable());
1560 0 : NhListResp *resp = new NhListResp();
1561 :
1562 : //TODO - Convert inet4ucroutetable to agentroutetable
1563 0 : AgentRouteTable::UnresolvedNHTree::const_iterator it;
1564 0 : it = rt_table->unresolved_nh_begin();
1565 0 : for (;it != rt_table->unresolved_nh_end(); it++) {
1566 0 : count++;
1567 0 : const NextHop *nh = *it;
1568 0 : nh->DBEntrySandesh(resp, empty);
1569 0 : if (count == 1) {
1570 0 : resp->set_context(context()+"$");
1571 0 : resp->Response();
1572 0 : count = 0;
1573 0 : resp = new NhListResp();
1574 : }
1575 : }
1576 :
1577 0 : resp->set_context(context());
1578 0 : resp->Response();
1579 0 : return;
1580 0 : }
1581 :
1582 : //TODO IMplement filltrace in path class
1583 78 : void AgentRoute::FillTrace(RouteInfo &rt_info, Trace event,
1584 : const AgentPath *path) const {
1585 78 : Agent *agent = static_cast<AgentRouteTable *>(get_table())->agent();
1586 78 : rt_info.set_ip(ToString());
1587 78 : rt_info.set_vrf(vrf()->GetName());
1588 :
1589 78 : switch(event) {
1590 15 : case ADD:{
1591 15 : rt_info.set_op("ADD");
1592 15 : break;
1593 : }
1594 :
1595 15 : case DEL: {
1596 15 : rt_info.set_op("DELETE");
1597 15 : break;
1598 : }
1599 :
1600 48 : case ADD_PATH:
1601 : case DELETE_PATH:
1602 : case STALE_PATH:
1603 : case CHANGE_PATH: {
1604 48 : if (event == ADD_PATH) {
1605 19 : rt_info.set_op("PATH ADD");
1606 29 : } else if (event == CHANGE_PATH) {
1607 10 : rt_info.set_op("PATH CHANGE");
1608 19 : } else if (event == DELETE_PATH) {
1609 19 : rt_info.set_op("PATH DELETE");
1610 0 : } else if (event == STALE_PATH) {
1611 0 : rt_info.set_op("PATH STALE");
1612 : }
1613 :
1614 48 : if (path == NULL) {
1615 0 : rt_info.set_nh_type("<NULL>");
1616 0 : break;
1617 : }
1618 :
1619 48 : if (path->peer()) {
1620 48 : rt_info.set_peer(path->peer()->GetName());
1621 : }
1622 48 : rt_info.set_ecmp(path->path_preference().ecmp());
1623 48 : const NextHop *nh = path->ComputeNextHop(agent);
1624 48 : if (nh == NULL) {
1625 0 : rt_info.set_nh_type("<NULL>");
1626 0 : break;
1627 : }
1628 :
1629 48 : switch (nh->GetType()) {
1630 0 : case NextHop::TUNNEL: {
1631 0 : const TunnelNH *tun = static_cast<const TunnelNH *>(nh);
1632 0 : rt_info.set_nh_type("TUNNEL");
1633 0 : rt_info.set_dest_server(tun->GetDip()->to_string());
1634 0 : rt_info.set_dest_server_vrf(tun->GetVrf()->GetName());
1635 0 : break;
1636 : }
1637 :
1638 4 : case NextHop::ARP:{
1639 4 : rt_info.set_nh_type("DIRECT");
1640 4 : break;
1641 : }
1642 :
1643 0 : case NextHop::NDP:{
1644 0 : rt_info.set_nh_type("DIRECT");
1645 0 : break;
1646 : }
1647 :
1648 15 : case NextHop::INTERFACE: {
1649 15 : const InterfaceNH *intf_nh = static_cast<const InterfaceNH *>(nh);
1650 15 : rt_info.set_nh_type("INTERFACE");
1651 15 : rt_info.set_intf(intf_nh->GetInterface()->name());
1652 15 : break;
1653 : }
1654 :
1655 10 : case NextHop::RECEIVE: {
1656 10 : const ReceiveNH *rcv_nh = static_cast<const ReceiveNH *>(nh);
1657 10 : rt_info.set_nh_type("RECEIVE");
1658 10 : rt_info.set_intf(rcv_nh->GetInterface()->name());
1659 10 : break;
1660 : }
1661 :
1662 9 : case NextHop::DISCARD: {
1663 9 : rt_info.set_nh_type("DISCARD");
1664 9 : break;
1665 : }
1666 :
1667 0 : case NextHop::VLAN: {
1668 0 : rt_info.set_nh_type("VLAN");
1669 0 : break;
1670 : }
1671 :
1672 2 : case NextHop::RESOLVE: {
1673 2 : rt_info.set_nh_type("RESOLVE");
1674 2 : break;
1675 : }
1676 :
1677 0 : case NextHop::COMPOSITE: {
1678 0 : rt_info.set_nh_type("COMPOSITE");
1679 0 : break;
1680 : }
1681 :
1682 8 : case NextHop::L2_RECEIVE: {
1683 8 : rt_info.set_nh_type("L2_RECEIVE");
1684 8 : break;
1685 : }
1686 :
1687 0 : case NextHop::PBB: {
1688 0 : const PBBNH *pbb_nh = static_cast<const PBBNH *>(nh);
1689 0 : rt_info.set_nh_type("PBB");
1690 0 : rt_info.set_mac(pbb_nh->dest_bmac().ToString());
1691 0 : if (pbb_nh->vrf()) {
1692 0 : rt_info.set_dest_server_vrf(pbb_nh->vrf()->GetName());
1693 : }
1694 0 : break;
1695 : }
1696 :
1697 0 : case NextHop::VRF: {
1698 0 : const VrfNH *vrf_nh = static_cast<const VrfNH *>(nh);
1699 0 : rt_info.set_nh_type("VRF");
1700 0 : rt_info.set_vrf_nh_name(vrf_nh->GetVrf()->GetName());
1701 0 : break;
1702 : }
1703 :
1704 0 : default:
1705 0 : assert(0);
1706 : break;
1707 : }
1708 48 : break;
1709 : }
1710 : }
1711 78 : }
1712 :
1713 48 : void AgentPath::GetDestinationVnList(std::vector<std::string> *vn_list) const {
1714 48 : for (VnListType::const_iterator vnit = dest_vn_list().begin();
1715 96 : vnit != dest_vn_list().end(); ++vnit) {
1716 48 : vn_list->push_back(*vnit);
1717 : }
1718 48 : }
1719 :
1720 0 : void AgentPath::SetSandeshData(PathSandeshData &pdata) const {
1721 0 : const NextHop *nh = nexthop();
1722 0 : if (nh != NULL) {
1723 0 : nh->SetNHSandeshData(pdata.nh);
1724 : }
1725 0 : pdata.set_peer(const_cast<Peer *>(peer())->GetName());
1726 0 : std::vector<std::string> vn_list;
1727 0 : GetDestinationVnList(&vn_list);
1728 0 : pdata.set_dest_vn_list(vn_list);
1729 0 : pdata.set_origin_vn(origin_vn());
1730 0 : pdata.set_unresolved(unresolved() ? "true" : "false");
1731 :
1732 0 : if (!gw_ip().is_unspecified()) {
1733 0 : pdata.set_gw_ip(gw_ip().to_string());
1734 0 : pdata.set_vrf(vrf_name());
1735 : }
1736 :
1737 0 : if (ecmp_suppressed()) {
1738 0 : pdata.set_ecmp_suppressed(true);
1739 : }
1740 :
1741 0 : pdata.set_sg_list(sg_list());
1742 0 : pdata.set_communities(communities());
1743 0 : pdata.set_tag_list(tag_list());
1744 0 : pdata.set_vxlan_id(vxlan_id());
1745 0 : pdata.set_label(label());
1746 0 : if (nh != NULL && nh->GetType() == NextHop::PBB) {
1747 0 : const PBBNH *pbb_nh = static_cast<const PBBNH *>(nh);
1748 0 : if (pbb_nh->child_nh() != NULL) {
1749 0 : const TunnelNH *tun_nh = dynamic_cast<const TunnelNH *>(pbb_nh->child_nh());
1750 0 : if (tun_nh != NULL) {
1751 0 : pdata.set_active_tunnel_type((tun_nh->GetTunnelType()).ToString());
1752 : }
1753 : }
1754 : } else {
1755 0 : pdata.set_active_tunnel_type(
1756 0 : TunnelType(tunnel_type()).ToString());
1757 : }
1758 0 : pdata.set_supported_tunnel_type(
1759 0 : TunnelType::GetString(tunnel_bmap()));
1760 0 : PathPreferenceSandeshData path_preference_data;
1761 0 : path_preference_data.set_sequence(path_preference_.sequence());
1762 0 : path_preference_data.set_preference(path_preference_.preference());
1763 0 : path_preference_data.set_ecmp(path_preference_.is_ecmp());
1764 0 : if ((peer()->GetType() != Peer::BGP_PEER) && (peer()->GetType() != Peer::ECMP_PEER )) {
1765 0 : path_preference_data.set_wait_for_traffic(
1766 0 : path_preference_.wait_for_traffic());
1767 : }
1768 0 : if (path_preference_.dependent_ip().is_unspecified() == false) {
1769 0 : std::ostringstream str;
1770 0 : str << path_preference_.vrf() << " : " <<path_preference_.dependent_ip().to_string();
1771 0 : path_preference_data.set_dependent_ip(str.str());
1772 0 : }
1773 0 : pdata.set_path_preference_data(path_preference_data);
1774 0 : pdata.set_active_label(GetActiveLabel());
1775 0 : if (peer()->GetType() == Peer::MAC_VM_BINDING_PEER) {
1776 0 : const MacVmBindingPath *dhcp_path =
1777 : static_cast<const MacVmBindingPath *>(this);
1778 0 : pdata.set_flood_dhcp(dhcp_path->flood_dhcp() ? "true" : "false");
1779 0 : pdata.set_vm_name(dhcp_path->vm_interface()->ToString());
1780 : }
1781 0 : std::vector<std::string> string_vector;
1782 0 : ecmp_load_balance_.GetStringVector(string_vector);
1783 : std::vector<std::string>::iterator string_vector_iter =
1784 0 : string_vector.begin();
1785 0 : std::stringstream ss;
1786 0 : while (string_vector_iter != string_vector.end()) {
1787 0 : ss << (*string_vector_iter);
1788 0 : ss << ",";
1789 0 : string_vector_iter++;
1790 : }
1791 0 : pdata.set_ecmp_hashing_fields(ss.str());
1792 0 : pdata.set_peer_sequence_number(peer_sequence_number());
1793 0 : const BgpPeer *bgp_peer = dynamic_cast<const BgpPeer *>(peer());
1794 0 : bool is_stale = false;
1795 0 : if (bgp_peer) {
1796 0 : if (peer_sequence_number() < bgp_peer->ChannelSequenceNumber())
1797 0 : is_stale = true;
1798 : }
1799 0 : pdata.set_stale(is_stale);
1800 0 : pdata.set_etree_leaf(etree_leaf());
1801 0 : pdata.set_layer2_control_word(layer2_control_word());
1802 0 : pdata.set_inactive(inactive());
1803 0 : }
1804 :
1805 0 : void AgentPath::set_local_ecmp_mpls_label(MplsLabel *mpls) {
1806 0 : local_ecmp_mpls_label_.reset(mpls);
1807 0 : }
1808 :
1809 0 : bool AgentPath::dest_vn_match(const std::string &vn) const {
1810 0 : if (dest_vn_list_.find(vn) != dest_vn_list_.end())
1811 0 : return true;
1812 0 : return false;
1813 : }
1814 :
1815 0 : const MplsLabel* AgentPath::local_ecmp_mpls_label() const {
1816 0 : return local_ecmp_mpls_label_.get();
1817 : }
1818 :
1819 : //In case of composite NH in fabric VRF, if BGP path has router
1820 : //id of compute node then copy the ECMP peer or local VM peer path
1821 : //to composite NH.
1822 : //In case of overlay mode MPLS label was used to frame local nexthop
1823 : //list which is not feasible in this fabric VRF
1824 0 : void AgentPath::CopyLocalPath(CompositeNHKey *composite_nh_key,
1825 : const AgentPath *local_path) {
1826 :
1827 0 : if (local_path == NULL) {
1828 0 : return;
1829 : }
1830 :
1831 0 : DBEntryBase::KeyPtr key_nh = local_path->nexthop()->GetDBRequestKey();
1832 0 : NextHopKey *nh_key = static_cast<NextHopKey *>(key_nh.get());
1833 0 : nh_key->SetPolicy(false);
1834 0 : std::unique_ptr<const NextHopKey> nh_key_p(nh_key->Clone());
1835 :
1836 0 : ComponentNHKeyList comp_nh_list;
1837 0 : if (nh_key_p->GetType() == NextHop::COMPOSITE) {
1838 : //Append the list of component NH list from local ecmp peer
1839 0 : const CompositeNHKey *comp_nh_key =
1840 : static_cast<const CompositeNHKey *>(nh_key);
1841 0 : comp_nh_list = comp_nh_key->component_nh_key_list();
1842 : } else {
1843 : //Append the interface NH to composite NH list
1844 0 : ComponentNHKeyPtr new_comp_nh(new ComponentNHKey(0, std::move(nh_key_p)));
1845 0 : comp_nh_list.push_back(new_comp_nh);
1846 0 : }
1847 :
1848 0 : composite_nh_key->ReplaceLocalNexthop(comp_nh_list);
1849 0 : }
1850 :
1851 0 : bool AgentPath::ReorderCompositeNH(Agent *agent,
1852 : CompositeNHKey *composite_nh_key,
1853 : bool &comp_nh_policy,
1854 : const AgentPath *path) {
1855 0 : if (copy_local_path_) {
1856 0 : CopyLocalPath(composite_nh_key, path);
1857 : }
1858 :
1859 : //Find local composite mpls label, if present
1860 : //This has to be done, before expanding component NH
1861 0 : BOOST_FOREACH(ComponentNHKeyPtr component_nh_key,
1862 : composite_nh_key->component_nh_key_list()) {
1863 0 : if (component_nh_key.get() == NULL ||
1864 0 : component_nh_key->nh_key()->GetType() != NextHop::COMPOSITE) {
1865 0 : continue;
1866 : }
1867 : const CompositeNHKey *composite_key =
1868 0 : static_cast<const CompositeNHKey *>(component_nh_key->nh_key());
1869 : // composite NH, check composite nh type
1870 : // if it is not local ecmp , skip processing
1871 0 : if (composite_key->composite_nh_type() !=
1872 : Composite::LOCAL_ECMP) {
1873 0 : continue;
1874 : }
1875 : //Get mpls label allocated for this composite NH
1876 : MplsLabel *mpls = agent->mpls_table()->
1877 0 : FindMplsLabel(component_nh_key->label());
1878 0 : if (!mpls) {
1879 : //If a mpls label is deleted,
1880 : //wait for bgp to update latest list
1881 0 : local_ecmp_mpls_label_.reset(mpls);
1882 0 : return false;
1883 : }
1884 :
1885 0 : if (mpls == local_ecmp_mpls_label_.get()) {
1886 0 : break;
1887 : }
1888 0 : local_ecmp_mpls_label_.reset(mpls);
1889 : //Check if MPLS is pointing to same NH as mentioned in key list.
1890 : //It may so happen that by the time this request is serviced(say in
1891 : //case of remote route add from CN), mpls label ahs been re-used for
1892 : //some other purpose. If it is so then ignore the request and wait for
1893 : //another update.
1894 0 : const NextHopKey *nh_key_1 = component_nh_key->nh_key();
1895 0 : DBEntryBase::KeyPtr key = mpls->nexthop()->GetDBRequestKey();
1896 0 : const NextHopKey *nh_key_2 = static_cast<const NextHopKey*>(key.get());
1897 0 : if (nh_key_1->IsEqual(*nh_key_2) == false) {
1898 0 : return false;
1899 : }
1900 0 : break;
1901 0 : }
1902 :
1903 : //Make a copy of composite NH, so that aggregarate mpls
1904 : //label allocated for local composite ecmp is maintained
1905 : //as data in path
1906 0 : CompositeNHKey *comp_key = composite_nh_key->Clone();
1907 : //Reorder the keys so that, existing component NH maintain
1908 : //there previous position
1909 : //For example take a composite NH with members A, B, C
1910 : //in that exact order,If B gets deleted,
1911 : //the new composite NH created should be A <NULL> C in that order,
1912 : //irrespective of the order user passed it in
1913 0 : comp_nh_policy = composite_nh_key->Reorder(agent, label_,
1914 0 : ComputeNextHop(agent));
1915 : //Copy the unchanged component NH list to path data
1916 0 : set_composite_nh_key(comp_key);
1917 0 : return true;
1918 : }
1919 :
1920 0 : bool AgentPath::ChangeCompositeNH(Agent *agent,
1921 : CompositeNHKey *composite_nh_key) {
1922 0 : DBRequest nh_req(DBRequest::DB_ENTRY_ADD_CHANGE);
1923 0 : nh_req.key.reset(composite_nh_key->Clone());
1924 0 : nh_req.data.reset(new CompositeNHData());
1925 :
1926 0 : NextHop *nh = static_cast<NextHop *>(agent->nexthop_table()->
1927 0 : FindActiveEntry(composite_nh_key));
1928 0 : if (!nh) {
1929 0 : agent->nexthop_table()->Process(nh_req);
1930 0 : nh = static_cast<NextHop *>(agent->nexthop_table()->
1931 0 : FindActiveEntry(composite_nh_key));
1932 : }
1933 :
1934 : // NH can be NULL in the following scenario
1935 : // when VMI is deleted and it is the only member of VRF
1936 : // and VMI is part of AAP, then local ecmp route path
1937 : // is deleted from route and vrf delete would trigger route deletions
1938 : // in the VRF. while deleting the active path, import Nh from prev active
1939 : // path function copies the previous active path's NH to current active path
1940 : // and recalucalate composite NH based on composite nh key of current
1941 : // active path. if component nh key element of composite nh key is
1942 : // interface nh key which is already deleted then processing nh req would
1943 : // result NULL, in that case return false.
1944 : //assert(nh);
1945 0 : if (nh == NULL) {
1946 0 : return false;
1947 : }
1948 :
1949 0 : if (ChangeNH(agent, nh) == true) {
1950 0 : return true;
1951 : }
1952 0 : return false;
1953 0 : }
1954 :
1955 0 : const Ip4Address *AgentPath::NexthopIp(Agent *agent) const {
1956 0 : if (peer_ == NULL) {
1957 0 : return agent->router_ip_ptr();
1958 : }
1959 :
1960 0 : return peer_->NexthopIp(agent, this);
1961 : }
1962 :
1963 1 : MacVmBindingPath::MacVmBindingPath(const Peer *peer) :
1964 1 : AgentPath(peer, NULL), vm_interface_(NULL), flood_dhcp_(false) {
1965 1 : }
1966 :
1967 10 : bool MacVmBindingPath::IsLess(const AgentPath &r_path) const {
1968 10 : return peer()->IsLess(r_path.peer());
1969 : }
1970 :
1971 2 : const NextHop *MacVmBindingPath::ComputeNextHop(Agent *agent) const {
1972 2 : return nexthop();
1973 : }
1974 :
1975 1 : AgentPath *MacVmBindingPathData::CreateAgentPath(const Peer *peer,
1976 : AgentRoute *rt) const {
1977 1 : const Peer *mac_vm_binding_peer =
1978 : dynamic_cast<const Peer *>(peer);
1979 1 : assert(mac_vm_binding_peer != NULL);
1980 1 : return (new MacVmBindingPath(mac_vm_binding_peer));
1981 : }
1982 :
1983 1 : bool MacVmBindingPathData::AddChangePathExtended(Agent *agent, AgentPath *path,
1984 : const AgentRoute *rt) {
1985 1 : bool ret = false;
1986 : MacVmBindingPath *dhcp_path =
1987 1 : dynamic_cast<MacVmBindingPath *>(path);
1988 :
1989 1 : NextHop *nh = agent->nexthop_table()->discard_nh();
1990 1 : if (path->ChangeNH(agent, nh) == true)
1991 1 : ret = true;
1992 :
1993 1 : if (dhcp_path->flood_dhcp() != flood_dhcp_) {
1994 0 : dhcp_path->set_flood_dhcp(flood_dhcp_);
1995 0 : ret = true;
1996 : }
1997 :
1998 1 : if (dhcp_path->vm_interface() != vm_intf_) {
1999 1 : dhcp_path->set_vm_interface(vm_intf_);
2000 1 : ret = true;
2001 : }
2002 :
2003 1 : return ret;
2004 : }
2005 :
2006 0 : void AgentPath::UpdateEcmpHashFields(const Agent *agent,
2007 : const EcmpLoadBalance &ecmp_load_balance,
2008 : DBRequest &nh_req) {
2009 :
2010 0 : NextHop *nh = NULL;
2011 0 : nh = static_cast<NextHop *>(agent->nexthop_table()->
2012 0 : FindActiveEntry(nh_req.key.get()));
2013 0 : CompositeNH *cnh = dynamic_cast< CompositeNH *>(nh);
2014 0 : if (cnh) {
2015 0 : ecmp_hash_fields_.CalculateChangeInEcmpFields(ecmp_load_balance,
2016 : cnh->CompEcmpHashFields());
2017 : } else {
2018 0 : agent->nexthop_table()->Process(nh_req);
2019 0 : nh = static_cast<NextHop *>(agent->nexthop_table()->
2020 0 : FindActiveEntry(nh_req.key.get()));
2021 0 : CompositeNH *cnh = static_cast< CompositeNH *>(nh);
2022 0 : if (cnh) {
2023 0 : ecmp_hash_fields_.CalculateChangeInEcmpFields(ecmp_load_balance,
2024 : cnh->CompEcmpHashFields());
2025 : }
2026 : }
2027 0 : }
2028 :
2029 0 : void AgentPath::ResetEcmpHashFields() {
2030 0 : ecmp_hash_fields_.Reset();
2031 0 : }
2032 :
2033 3 : bool AgentPath::ResyncControlWord(const AgentRoute *rt) {
2034 : const BridgeRouteEntry *bridge_rt =
2035 3 : dynamic_cast<const BridgeRouteEntry *>(rt);
2036 3 : if (!bridge_rt || rt->vrf() == NULL) {
2037 0 : return false;
2038 : }
2039 :
2040 3 : if (layer2_control_word() != bridge_rt->vrf()->layer2_control_word()) {
2041 0 : set_layer2_control_word(bridge_rt->vrf()->layer2_control_word());
2042 0 : return true;
2043 : }
2044 :
2045 3 : return false;
2046 : }
2047 :
2048 0 : EvpnRoutingPath::EvpnRoutingPath(const Peer *peer,
2049 : AgentRoute *rt,
2050 0 : VrfEntryConstRef routing_vrf) :
2051 0 : AgentPath(peer, rt), routing_vrf_(routing_vrf) {
2052 0 : l3_vrf_vxlan_id_ = routing_vrf.get()->vxlan_id();
2053 0 : }
2054 :
2055 0 : EvpnRoutingPath::~EvpnRoutingPath() {
2056 0 : }
2057 :
2058 0 : const VrfEntry *EvpnRoutingPath::routing_vrf() const {
2059 0 : return routing_vrf_.get();
2060 : }
2061 :
2062 0 : void EvpnRoutingPath::set_routing_vrf(const VrfEntry *vrf) {
2063 0 : routing_vrf_.reset(vrf);
2064 0 : }
2065 :
2066 0 : void EvpnRoutingPath::DeleteEvpnType5Route(Agent *agent,
2067 : const AgentRoute *rt) const {
2068 0 : const VrfEntry *l3_vrf = routing_vrf_.get();
2069 0 : if (!l3_vrf)
2070 0 : return;
2071 :
2072 : const InetUnicastRouteEntry *inet_rt =
2073 0 : dynamic_cast<const InetUnicastRouteEntry *>(rt);
2074 0 : if (!inet_rt) {
2075 0 : return;
2076 : }
2077 : const EvpnAgentRouteTable *evpn_table =
2078 0 : static_cast<EvpnAgentRouteTable *>(l3_vrf->GetEvpnRouteTable());
2079 0 : evpn_table->Delete(agent->local_vm_export_peer(), l3_vrf->GetName(),
2080 0 : MacAddress(), inet_rt->prefix_address(),
2081 0 : l3_vrf_vxlan_id_);
2082 : }
2083 :
2084 0 : EvpnRoutingData::EvpnRoutingData(DBRequest &nh_req,
2085 : const SecurityGroupList &sg_list,
2086 : const CommunityList &communities,
2087 : const PathPreference &path_preference,
2088 : const EcmpLoadBalance &ecmp_load_balance,
2089 : const TagList &tag_list,
2090 : VrfEntryConstRef vrf_entry,
2091 : uint32_t vxlan_id,
2092 : const VnListType& vn_list,
2093 0 : const std::string& origin_vn):
2094 : AgentRouteData(AgentRouteData::ADD_DEL_CHANGE, false, 0),
2095 0 : sg_list_(sg_list),
2096 0 : communities_(communities),
2097 0 : path_preference_(path_preference),
2098 0 : ecmp_load_balance_(ecmp_load_balance),
2099 0 : tag_list_(tag_list),
2100 0 : routing_vrf_(vrf_entry), vxlan_id_(vxlan_id),
2101 0 : dest_vn_list_(vn_list),
2102 0 : origin_vn_(origin_vn) {
2103 0 : nh_req_.Swap(&nh_req);
2104 0 : }
2105 :
2106 0 : AgentPath *EvpnRoutingData::CreateAgentPath(const Peer *peer,
2107 : AgentRoute *rt) const {
2108 0 : return (new EvpnRoutingPath(peer, rt, routing_vrf_));
2109 : }
2110 :
2111 0 : bool EvpnRoutingData::AddChangePathExtended(Agent *agent,
2112 : AgentPath *path,
2113 : const AgentRoute *rt) {
2114 0 : bool ret = false;
2115 0 : EvpnRoutingPath *evpn_path = static_cast<EvpnRoutingPath *>(path);
2116 :
2117 : //Process nexthop
2118 0 : agent->nexthop_table()->Process(nh_req_);
2119 0 : NextHop *nh = static_cast<NextHop *>(agent->nexthop_table()->
2120 0 : FindActiveEntry(nh_req_.key.get()));
2121 :
2122 0 : InterfaceNH *intf_nh = dynamic_cast<InterfaceNH *>(nh);
2123 0 : if (intf_nh) {
2124 0 : intf_nh->set_delete_on_zero_refcount(true);
2125 : }
2126 0 : if (routing_vrf_.get() != evpn_path->routing_vrf()) {
2127 : //Remove from old vrf
2128 0 : evpn_path->DeleteEvpnType5Route(agent, rt);
2129 0 : evpn_path->set_routing_vrf(routing_vrf_.get());
2130 0 : ret = true;
2131 : }
2132 :
2133 0 : if (path->ChangeNH(agent, nh) == true) {
2134 0 : ret = true;
2135 : }
2136 :
2137 0 : if (sg_list_ != path->sg_list()) {
2138 0 : path->set_sg_list(sg_list_);
2139 0 : ret = true;
2140 : }
2141 :
2142 : /* Setting the origin_vn in the route path */
2143 0 : if (path->origin_vn() != origin_vn_) {
2144 0 : path->set_origin_vn(origin_vn_);
2145 0 : ret = true;
2146 : }
2147 :
2148 : // Set dest vn
2149 0 : path->set_dest_vn_list(dest_vn_list_);
2150 :
2151 0 : if (communities_ != path->communities()) {
2152 0 : path->set_communities(communities_);
2153 0 : ret =true;
2154 : }
2155 :
2156 0 : if (path_preference_ != path->path_preference()) {
2157 0 : path->set_path_preference(path_preference_);
2158 0 : ret = true;
2159 : }
2160 :
2161 0 : if (ecmp_load_balance_ != path->ecmp_load_balance()) {
2162 0 : path->set_ecmp_load_balance(ecmp_load_balance_);
2163 0 : ret =true;
2164 : }
2165 :
2166 0 : if (tag_list_ != path->tag_list()) {
2167 0 : path->set_tag_list(tag_list_);
2168 0 : ret =true;
2169 : }
2170 :
2171 0 : path->set_tunnel_type(TunnelType::VXLAN);
2172 0 : path->set_tunnel_bmap(TunnelType::VxlanType());
2173 0 : path->set_vxlan_id(vxlan_id_);
2174 :
2175 0 : return ret;
2176 : }
2177 :
2178 0 : bool EvpnRoutingData::CanDeletePath(Agent *agent, AgentPath *path,
2179 : const AgentRoute *rt) const {
2180 0 : EvpnRoutingPath *evpn_path = dynamic_cast<EvpnRoutingPath *>(path);
2181 0 : if (!evpn_path) {
2182 0 : return true;
2183 : }
2184 0 : if (rt->vrf() != evpn_path->routing_vrf()) {
2185 : //Remove from old vrf
2186 0 : evpn_path->DeleteEvpnType5Route(agent, rt);
2187 : }
2188 0 : return true;
2189 : }
2190 0 : bool EvpnRoutingData::UpdateRoute(AgentRoute *rt) {
2191 : InetUnicastRouteEntry *uc_rt =
2192 0 : dynamic_cast<InetUnicastRouteEntry *>(rt);
2193 0 : if (!uc_rt) {
2194 0 : return false;
2195 : }
2196 0 : return uc_rt->UpdateRouteFlags(false, false, true);
2197 : }
2198 0 : AgentPathEcmpComponent::AgentPathEcmpComponent(IpAddress addr, uint32_t label,
2199 0 : AgentRoute *rt):
2200 0 : addr_(addr), label_(label), dependent_rt_(rt) {}
2201 :
|