OpenSDN source code
service_chaining.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3  */
4 
6 
7 #include <boost/foreach.hpp>
8 #include <boost/assign/list_of.hpp>
9 
10 #include <algorithm>
11 
12 #include "base/task_annotations.h"
13 #include "base/task_trigger.h"
14 #include "bgp/bgp_config.h"
15 #include "bgp/bgp_log.h"
16 #include "bgp/bgp_membership.h"
17 #include "bgp/bgp_server.h"
24 #include "bgp/routing-instance/service_chaining_types.h"
26 #include "net/community_type.h"
27 
28 using boost::bind;
29 using boost::system::error_code;
30 using std::make_pair;
31 using std::sort;
32 using std::string;
33 using std::vector;
34 
35 template<>
37 template<>
39 template<>
41 template<>
43 
44 static int GetOriginVnIndex(const BgpTable *table, const BgpRoute *route) {
45  const BgpPath *path = route->BestPath();
46  if (!path)
47  return 0;
48 
49  const BgpAttr *attr = path->GetAttr();
50  const ExtCommunity *ext_community = attr->ext_community();
51  if (ext_community) {
52  BOOST_FOREACH(const ExtCommunity::ExtCommunityValue &comm,
53  ext_community->communities()) {
54  if (!ExtCommunity::is_origin_vn(comm))
55  continue;
56  OriginVn origin_vn(comm);
57  return origin_vn.vn_index();
58  }
59  }
60  if (path->IsVrfOriginated())
61  return table->routing_instance()->virtual_network_index();
62  return 0;
63 }
64 
85 template<typename T>
87  BgpRoute *&route, BgpTable *&table, PrefixT prefix, bool create) {
93  RoutingInstance *src_ri = src_routing_instance();
94  IpAddress addr = prefix.addr();
95  int plen = prefix.prefixlen();
96  if (GetSCFamily() == SCAddress::EVPN) {
100  table = src_ri->GetTable(Address::INET);
101  Ip4Prefix inet_prefix = Ip4Prefix(addr.to_v4(), plen);
102  InetRoute inet_route(inet_prefix);
103  partition = static_cast<DBTablePartition *>
104  (table->GetTablePartition(&inet_route));
105  route = static_cast<BgpRoute *>(partition->Find(&inet_route));
106  if (create) {
110  if (route == NULL) {
111  route = new InetRoute(inet_prefix);
112  partition->Add(route);
113  } else {
114  route->ClearDelete();
115  }
116  }
117  } else if (GetSCFamily() == SCAddress::EVPN6) {
121  table = src_ri->GetTable(Address::INET6);
122  Inet6Prefix inet6_prefix = Inet6Prefix(addr.to_v6(), plen);
123  Inet6Route inet6_route(inet6_prefix);
124  partition = static_cast<DBTablePartition *>
125  (table->GetTablePartition(&inet6_route));
126  route = static_cast<BgpRoute *>(partition->Find(&inet6_route));
127  if (create) {
131  if (route == NULL) {
132  route = new Inet6Route(inet6_prefix);
133  partition->Add(route);
134  } else {
135  route->ClearDelete();
136  }
137  }
138  } else {
143  table = src_ri->GetTable(Address::EVPN);
144  string type_rd_tag("5-0:0-0-");
145  string prefix_str = type_rd_tag + addr.to_string() + "/" +
146  boost::lexical_cast<std::string>(plen);
147  EvpnPrefix evpn_prefix(EvpnPrefix::FromString(prefix_str));
148  EvpnRoute evpn_route(evpn_prefix);
149  partition = static_cast<DBTablePartition *>
150  (table->GetTablePartition(&evpn_route));
151  route = static_cast<BgpRoute *>(partition->Find(&evpn_route));
152  if (create) {
156  if (route == NULL) {
157  route = new EvpnRoute(evpn_prefix);
158  partition->Add(route);
159  } else {
160  route->ClearDelete();
161  }
162  }
163  }
164 }
165 
178 template<typename T>
180  BgpAttrPtr attr, BgpRoute *&route, DBTablePartition *&partition,
181  bool aggregate, BgpTable *bgptable) {
182  BgpPath *existing_path =
183  route->FindPath(BgpPath::ServiceChain, NULL, path_id);
184  uint32_t label = path->GetLabel();
185  bool path_updated = false;
186 
191  if (bgptable->family() == Address::EVPN) {
192  const RoutingInstance *conn_ri =
195  connected_->name()));
196  if (!conn_ri) {
197  // conn_ri is not expected to be found only in unit tests.
198  assert(bgp_log_test::unit_test());
199  conn_ri = connected_routing_instance();
200  }
201  label = conn_ri->vxlan_id();
202  if (!label) {
203  label = conn_ri->virtual_network_index();
204  }
205  }
206 
210  if (existing_path != NULL) {
211  // Existing path can be reused.
212  if ((attr.get() == existing_path->GetAttr()) &&
213  (path->GetLabel() == existing_path->GetLabel()) &&
214  (path->GetFlags() == existing_path->GetFlags())) {
215  return;
216  }
217 
221  path_updated = true;
222  route->RemovePath(BgpPath::ServiceChain, NULL, path_id);
223  }
224 
229  BgpPath *new_path =
230  new BgpPath(path_id, BgpPath::ServiceChain, attr.get(),
231  path->GetFlags(), label);
232  route->InsertPath(new_path);
233  partition->Notify(route);
234 
235  BGP_LOG_STR(BgpMessage, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_TRACE,
236  (path_updated ? "Updated " : "Added ") <<
237  (aggregate ? "Aggregate" : "ExtConnected") <<
238  " ServiceChain path " << route->ToString() <<
239  " path_id " << BgpPath::PathIdString(path_id) <<
240  " in table " << bgptable->name() <<
241  " .Path label: " << label);
242 }
243 
244 template <typename T>
246 public:
247  explicit DeleteActor(ServiceChainMgr<T> *manager)
248  : LifetimeActor(manager->server_->lifetime_manager()),
249  manager_(manager) {
250  }
251  virtual bool MayDelete() const {
252  return manager_->MayDelete();
253  }
254  virtual void Shutdown() {
255  }
256  virtual void Destroy() {
257  manager_->Terminate();
258  }
259 
260 private:
262 };
263 
264 template <typename T>
267  RoutingInstance *connected, const vector<string> &subnets, AddressT addr,
268  bool head, bool retain_as_path)
269  : manager_(manager),
270  group_(group),
271  src_(src),
272  dest_(dest),
273  connected_(connected),
274  connected_route_(NULL),
275  service_chain_addr_(addr),
276  group_oper_state_up_(group ? false : true),
277  connected_table_unregistered_(false),
278  dest_table_unregistered_(false),
279  aggregate_(false),
280  sc_head_(head),
281  retain_as_path_(retain_as_path),
282  src_table_delete_ref_(this, src_table()->deleter()),
283  dest_table_delete_ref_(this, dest_table()->deleter()),
284  connected_table_delete_ref_(this, connected_table()->deleter()) {
285  for (vector<string>::const_iterator it = subnets.begin();
286  it != subnets.end(); ++it) {
287  string prefix = *it;
288  error_code ec;
293  if (GetFamily() == Address::EVPN) {
294  prefix = "5-0:0-0-" + prefix;
295  EvpnPrefix subnet = EvpnPrefix::FromString(prefix, &ec);
296  if (GetSCFamily() == SCAddress::EVPN) {
297  if (subnet.family() == Address::INET6) {
298  continue;
299  }
300  } else {
301  if (subnet.family() != Address::INET6) {
302  continue;
303  }
304  }
305  }
306  PrefixT ipam_subnet = PrefixT::FromString(prefix, &ec);
307  if (ec.failed())
308  continue;
309  prefix_to_routelist_map_[ipam_subnet] = RouteList();
310  }
311 }
312 
313 template <typename T>
315  return src_->GetTable(GetFamily());
316 }
317 
318 template <typename T>
320  return connected_->GetTable(GetConnectedFamily());
321 }
322 
323 template <typename T>
325  return dest_->GetTable(GetFamily());
326 }
327 
328 //
329 // Compare this ServiceChain against the ServiceChainConfig.
330 // Return true if the configuration has not changed, false otherwise.
331 //
332 template <typename T>
334  const ServiceChainConfig &config) {
335  if (deleted())
336  return false;
337  if (dest_->name() != config.routing_instance)
338  return false;
339  if (connected_->name() != config.source_routing_instance)
340  return false;
341  if (service_chain_addr_.to_string() != config.service_chain_address)
342  return false;
343  if (!group_ && !config.service_chain_id.empty())
344  return false;
345  if (group_ && config.service_chain_id.empty())
346  return false;
347  if (group_ && group_->name() != config.service_chain_id)
348  return false;
349 
350  if (prefix_to_routelist_map_.size() != config.prefix.size())
351  return false;
352  for (vector<string>::const_iterator it = config.prefix.begin();
353  it != config.prefix.end(); ++it) {
354  error_code ec;
355  PrefixT ipam_subnet = PrefixT::FromString(*it, &ec);
356  if (prefix_to_routelist_map_.find(ipam_subnet) ==
357  prefix_to_routelist_map_.end()) {
358  return false;
359  }
360  }
361  return true;
362 }
363 
364 //
365 // Match function called from BgpConditionListener
366 // Concurrency : db::DBTable
367 // For the purpose of route aggregation, two condition needs to be matched
368 // 1. More specific route present in any of the Dest BgpTable partition
369 // 2. Connected route(for nexthop) present in Src BgpTable
370 //
371 template <typename T>
372 bool ServiceChain<T>::Match(BgpServer *server, BgpTable *table, BgpRoute *route,
373  bool deleted) {
374  CHECK_CONCURRENCY("db::DBTable");
375 
377  PrefixT aggregate_match;
378 
379  if (table == dest_table() && !dest_table_unregistered()) {
380  // For EVPN service-chaining, we are only interested in Type 5 routes
381  // from the destination table. Ignore any other route.
382  if (GetFamily() == Address::EVPN) {
383  if (!IsEvpnType5Route(route)) {
384  return (false);
385  }
386  }
387 
388  // Skip connected routes
389  if (IsConnectedRoute(route)) {
390  return false;
391  }
392 
393  // Skip aggregate routes
394  if (aggregate_enable() && IsAggregate(route))
395  return false;
396 
397  if (aggregate_enable() && IsMoreSpecific(route, &aggregate_match)) {
398  // More specific
399  if (deleted) {
400  type = ServiceChainRequestT::MORE_SPECIFIC_DELETE;
401  } else {
402  type = ServiceChainRequestT::MORE_SPECIFIC_ADD_CHG;
403  }
404  } else {
405  // External connecting routes
406  if (!deleted) {
407  if (!route->BestPath() || !route->BestPath()->IsFeasible()) {
408  deleted = true;
409  } else {
410  const BgpAttr *attr = route->BestPath()->GetAttr();
411  const Community *comm = attr ? attr->community() : NULL;
412  if (comm) {
415  deleted = true;
416  }
417 
418  int vn_index = GetOriginVnIndex(table, route);
419  int src_vn_index = src_->virtual_network_index();
420  int dest_vn_index = dest_->virtual_network_index();
421  if (!vn_index || dest_vn_index != vn_index) {
422  if (src_vn_index == vn_index)
423  deleted = true;
424  if (!dest_->virtual_network_allow_transit())
425  deleted = true;
426  if (!dest_vn_index)
427  deleted = true;
428  }
429 
430  const OriginVnPath *ovnpath =
431  attr ? attr->origin_vn_path() : NULL;
432  if (ovnpath && ovnpath->Contains(
433  server->autonomous_system(), src_vn_index)) {
434  deleted = true;
435  }
436  }
437  }
438 
439  if (deleted) {
440  type = ServiceChainRequestT::EXT_CONNECT_ROUTE_DELETE;
441  } else {
442  type = ServiceChainRequestT::EXT_CONNECT_ROUTE_ADD_CHG;
443  }
444  }
445  } else if ((table == connected_table()) &&
446  !connected_table_unregistered() &&
447  IsConnectedRoute(route, true)) {
448  // Connected routes from source table
449  if (!deleted) {
450  if (!route->IsValid() ||
451  route->BestPath()->GetSource() != BgpPath::BGP_XMPP) {
452  deleted = true;
453  }
454  }
455 
456  // Connected route for service chain
457  if (deleted) {
458  type = ServiceChainRequestT::CONNECTED_ROUTE_DELETE;
459  } else {
460  type = ServiceChainRequestT::CONNECTED_ROUTE_ADD_CHG;
461  }
462  } else {
463  return false;
464  }
465 
466  BgpConditionListener *listener = manager_->GetListener();
467  ServiceChainState *state = static_cast<ServiceChainState *>(
468  listener->GetMatchState(table, route, this));
469  if (!deleted) {
470  // MatchState is added to the Route to ensure that DBEntry is not
471  // deleted before the ServiceChain module processes the WorkQueue
472  // request.
473  if (!state) {
474  state = new ServiceChainState(ServiceChainPtr(this));
475  listener->SetMatchState(table, route, this, state);
476  }
477  } else {
478  // MatchState is set on all the Routes that matches the conditions
479  // Retrieve to check and ignore delete of unseen Add Match
480  if (state == NULL) {
481  // Not seen ADD ignore DELETE
482  return false;
483  }
484  }
485 
486  // The MatchState reference is taken to ensure that the route is not
487  // deleted when request is still present in the queue
488  // This is to handle the case where MatchState already exists and
489  // deleted entry gets reused or reused entry gets deleted.
490  state->IncrementRefCnt();
491 
492  // Post the Match result to ServiceChain task to take Action
493  // More_Specific_Present + Connected_Route_exists ==> Add Aggregate Route
494  // and stitch the nexthop from connected route
496  type, table, route, aggregate_match, ServiceChainPtr(this));
497  manager_->Enqueue(req);
498  return true;
499 }
500 
501 template <typename T>
503  return (string("ServiceChain " ) + service_chain_addr_.to_string());
504 }
505 
506 template <typename T>
508  connected_route_ = connected;
509  connected_path_ids_.clear();
510  if (!connected_route_)
511  return;
512 
513  for (Route::PathList::iterator it = connected->GetPathList().begin();
514  it != connected->GetPathList().end(); ++it) {
515  BgpPath *path = static_cast<BgpPath *>(it.operator->());
516 
517  // Infeasible paths are not considered.
518  if (!path->IsFeasible())
519  break;
520 
521  // Bail if it's not ECMP with the best path.
522  if (connected_route_->BestPath()->PathCompare(*path, true))
523  break;
524 
525  // Use nexthop attribute of connected path as path id.
526  uint32_t path_id = path->GetAttr()->nexthop().to_v4().to_ulong();
527  connected_path_ids_.insert(path_id);
528  }
529 }
530 
531 template <typename T>
533  return (connected_route_ && connected_route_->IsValid());
534 }
535 
536 template <typename T>
538  PrefixT *aggregate_match) const {
539  const RouteT *ip_route = static_cast<RouteT *>(route);
540  const PrefixT &ip_prefix = ip_route->GetPrefix();
541  for (typename PrefixToRouteListMap::const_iterator it =
542  prefix_to_route_list_map()->begin();
543  it != prefix_to_route_list_map()->end(); ++it) {
544  if (ip_prefix.IsMoreSpecific(it->first)) {
545  *aggregate_match = it->first;
546  return true;
547  }
548  }
549  return false;
550 }
551 
552 template <typename T>
554  RouteT *ip_route = dynamic_cast<RouteT *>(route);
555  for (typename PrefixToRouteListMap::const_iterator it =
556  prefix_to_route_list_map()->begin();
557  it != prefix_to_route_list_map()->end(); ++it) {
558  if (it->first == ip_route->GetPrefix())
559  return true;
560  }
561  return false;
562 }
563 
569 template <typename T>
571  bool is_conn_table) const {
572  if (is_conn_table && GetFamily() == Address::EVPN) {
573  if (GetConnectedFamily() == Address::INET) {
574  InetRoute *inet_route = dynamic_cast<InetRoute *>(route);
575  return (service_chain_addr() == inet_route->GetPrefix().addr());
576  } else {
577  Inet6Route *inet6_route = dynamic_cast<Inet6Route *>(route);
578  return (service_chain_addr() == inet6_route->GetPrefix().addr());
579  }
580  } else {
584  RouteT *ip_route = dynamic_cast<RouteT *>(route);
585  return (service_chain_addr() == ip_route->GetPrefix().addr());
586  }
587 }
588 
595 template <typename T>
597  if (GetFamily() != Address::EVPN) {
598  return false;
599  }
600 
601  EvpnRoute *evpn_route = static_cast<EvpnRoute *>(route);
602  EvpnPrefix prefix = evpn_route->GetPrefix();
603  if (prefix.type() != EvpnPrefix::IpPrefixRoute) {
604  return false;
605  }
606  if (GetSCFamily() == SCAddress::EVPN &&
607  prefix.family() == Address::INET6) {
608  return false;
609  }
610  if (GetSCFamily() == SCAddress::EVPN6 &&
611  prefix.family() == Address::INET) {
612  return false;
613  }
614  return true;
615 }
616 
617 template <typename T>
619  ServiceChainState *state) {
620  if (deleted() || route->IsDeleted()) {
621  // At this point we are ready to release the MatchState on the DBEntry
622  // So mark it as deleted.. Actual removal of the state is done when
623  // ref count is 0
624  state->set_deleted();
625  }
626 }
627 
628 /*
629  * To support BMS to VM service-chaining, we could have traffic being
630  * chained between different address-families. This entails the need for
631  * replicating the service-chain route across address-families.
632  * The different possibilities are listed below.
633  * ---------------------------------------------------
634  * | service-chain info |
635  * ----------------------------------------------------------------------
636  * Traffic direction | Destination AF Source AF Replication Table |
637  * ----------------------------------------------------------------------
638  * VM(v4) --> BMS | EVPN INET InetTable |
639  * VM(v6) --> BMS | EVPN INET6 Inet6Table |
640  * BMS --> VM (v4) | INET INET EvpnTable |
641  * BMS --> VM (v6) | INET6 INET6 EvpnTable |
642  * ----------------------------------------------------------------------
643  *
644  * This is only done at the RI belonging to the head SI in the service
645  * chain. At the RIs belonging to other SIs in the chain, we always
646  * install the route only in the INET or INET6 table and not in the EVPN
647  * table. This is because, at the RI belonging to the first SI in the
648  * service-chain, we may need to originate a Type 5 route if a BMS happens
649  * to be connected to it.
650  */
651 template <typename T>
652 void ServiceChain<T>::DeleteServiceChainRoute(PrefixT prefix, bool aggregate) {
653 
654  CHECK_CONCURRENCY("bgp::ServiceChain");
655 
656  /*
657  * For deletion within the same AF.
658  * At the RIs belonging to SIs NOT at the head of the service-chain, do
659  * not need to delete EVPN SC routes since only INET or INET6 routes
660  * would have been installed.
661  */
662  if (is_sc_head() || GetFamily() != Address::EVPN) {
663  BgpTable *bgptable = src_table();
664  RouteT rt_key(prefix);
665  DBTablePartition *partition =
666  static_cast<DBTablePartition *>(bgptable->
667  GetTablePartition(&rt_key));
668  BgpRoute *service_chain_route =
669  static_cast<BgpRoute *>(partition->Find(&rt_key));
670 
671  if (service_chain_route && !service_chain_route->IsDeleted()) {
672  DeleteServiceChainRouteInternal(service_chain_route, partition,
673  bgptable, aggregate);
674  }
675  }
676 
677  /*
678  * For deletion from replication table.
679  * At the RIs belonging to SIs NOT at the head of the service-chain, do
680  * not need to delete SC routes in the EVPN table since they would have
681  * been installed only in the INET or INET6 table..
682  */
683  if (is_sc_head() || GetFamily() == Address::EVPN) {
684  BgpTable *repl_table;
685  BgpRoute *repl_sc_route;
686  DBTablePartition *repl_partition;
687  GetReplicationFamilyInfo(repl_partition, repl_sc_route, repl_table,
688  prefix, false);
689  if (repl_sc_route && !repl_sc_route->IsDeleted()) {
690  DeleteServiceChainRouteInternal(repl_sc_route, repl_partition,
691  repl_table, aggregate);
692  }
693  }
694 }
695 
696 template <typename T>
698  BgpRoute *service_chain_route,
699  DBTablePartition *partition,
700  BgpTable *bgptable,
701  bool aggregate) {
702  CHECK_CONCURRENCY("bgp::ServiceChain");
703 
704  for (ConnectedPathIdList::const_iterator it = GetConnectedPathIds().begin();
705  it != GetConnectedPathIds().end(); ++it) {
706  uint32_t path_id = *it;
707  service_chain_route->RemovePath(BgpPath::ServiceChain, NULL, path_id);
708  BGP_LOG_STR(BgpMessage, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_TRACE,
709  "Removed " << (aggregate ? "Aggregate" : "ExtConnected") <<
710  " ServiceChain path " << service_chain_route->ToString() <<
711  " path_id " << BgpPath::PathIdString(path_id) <<
712  " in table " << bgptable->name());
713  }
714 
715  if (!service_chain_route->HasPaths()) {
716  partition->Delete(service_chain_route);
717  } else {
718  partition->Notify(service_chain_route);
719  }
720 }
721 
722 /*
723  * To support BMS to VM service-chaining, we could have traffic being
724  * chained between different address-families. This entails the need for
725  * replicating the service-chain route across address-families.
726  * The different possibilities are listed below.
727  * ---------------------------------------------------
728  * | service-chain info |
729  * ----------------------------------------------------------------------
730  * Traffic direction | Destination AF Source AF Replication Table |
731  * ----------------------------------------------------------------------
732  * VM(v4) --> BMS | EVPN INET InetTable |
733  * VM(v6) --> BMS | EVPN INET6 Inet6Table |
734  * BMS --> VM (v4) | INET INET EvpnTable |
735  * BMS --> VM (v6) | INET6 INET6 EvpnTable |
736  * ----------------------------------------------------------------------
737  *
738  * This is only done at the RI belonging to the head SI in the service
739  * chain. At the RIs belonging to other SIs in the chain, we always
740  * install the route only in the INET or INET6 table and not in the EVPN
741  * table. This is because, at the RI belonging to the first SI in the
742  * service-chain, we may need to originate a Type 5 route if a BMS happens
743  * to be connected to it.
744  */
745 template <typename T>
747  const RouteT *orig_route, const ConnectedPathIdList &old_path_ids,
748  bool aggregate) {
749 
750  CHECK_CONCURRENCY("bgp::ServiceChain");
751 
752  /*
753  * For re-origination within the same AF.
754  * At the RIs belonging to SIs NOT at the head of the service-chain, do
755  * not install EVPN SC routes. Only install INET or INET6 routes.
756  */
757  if (is_sc_head() || GetFamily() != Address::EVPN) {
758  BgpTable *bgptable = src_table();
759  RouteT rt_key(prefix);
760  DBTablePartition *partition =
761  static_cast<DBTablePartition *>
762  (bgptable->GetTablePartition(&rt_key));
763  BgpRoute *service_chain_route =
764  static_cast<BgpRoute *>(partition->Find(&rt_key));
765 
766  if (service_chain_route == NULL) {
767  service_chain_route = new RouteT(prefix);
768  partition->Add(service_chain_route);
769  } else {
770  service_chain_route->ClearDelete();
771  }
772 
773  UpdateServiceChainRouteInternal(orig_route, old_path_ids,
774  service_chain_route, partition,
775  bgptable, aggregate);
776  }
777 
778  /*
779  * For re-origination to replication table.
780  * At the RIs belonging to SIs NOT at the head of the service-chain, do
781  * not install SC routes in the EVPN table. Only install INET or INET6
782  * routes.
783  */
784  if (is_sc_head() || GetFamily() == Address::EVPN) {
785  BgpTable *repl_table;
786  BgpRoute *repl_sc_route;
787  DBTablePartition *repl_partition;
788  GetReplicationFamilyInfo(repl_partition, repl_sc_route, repl_table,
789  prefix, true);
790  UpdateServiceChainRouteInternal(orig_route, old_path_ids,
791  repl_sc_route, repl_partition,
792  repl_table, aggregate);
793  }
794 }
795 
796 template <typename T>
798  const ConnectedPathIdList &old_path_ids, BgpRoute *service_chain_route,
799  DBTablePartition *partition, BgpTable *bgptable, bool aggregate) {
800  CHECK_CONCURRENCY("bgp::ServiceChain");
801 
802  int vn_index = dest_routing_instance()->virtual_network_index();
803  BgpServer *server = dest_routing_instance()->server();
804  OriginVn origin_vn(server->autonomous_system(), vn_index);
805  OriginVn origin_vn4(server->autonomous_system(), AS_TRANS);
806  OriginVn origin_vn_trans(AS_TRANS, vn_index);
807  const OriginVnPath::OriginVnValue origin_vn_bytes = origin_vn.GetExtCommunity();
808  const OriginVnPath::OriginVnValue origin_vn_trans_bytes =
809  origin_vn_trans.GetExtCommunity();
810  const OriginVnPath::OriginVnValue origin_vn4_bytes =
811  origin_vn4.GetExtCommunity();
812 
813  SiteOfOrigin soo;
816  LoadBalance load_balance;
817  bool load_balance_present = false;
818  const Community *orig_community = nullptr;
819  const OriginVnPath *orig_ovnpath = nullptr;
820  const AsPath *orig_aspath = nullptr;
821  RouteDistinguisher orig_rd;
822  if (orig_route) {
823  const BgpPath *orig_path = orig_route->BestPath();
824  const BgpAttr *orig_attr = nullptr;
825  const ExtCommunity *ext_community = nullptr;
826  const LargeCommunity *large_community = nullptr;
827  if (orig_path != nullptr)
828  orig_attr = orig_path->GetAttr();
829  if (orig_attr != nullptr) {
830  orig_community = orig_attr->community();
831  ext_community = orig_attr->ext_community();
832  large_community = orig_attr->large_community();
833  orig_ovnpath = orig_attr->origin_vn_path();
834  orig_rd = orig_attr->source_rd();
835  orig_aspath = orig_attr->as_path();
836  }
837  if (ext_community != nullptr) {
838  for(const ExtCommunity::ExtCommunityValue &comm:
839  ext_community->communities()) {
841  sgid_list.push_back(comm);
842  if (ExtCommunity::is_site_of_origin(comm) && soo.IsNull())
843  soo = SiteOfOrigin(comm);
844  if (ExtCommunity::is_load_balance(comm)) {
845  load_balance = LoadBalance(comm);
846  load_balance_present = true;
847  }
848  }
849  }
850  if (large_community != nullptr) {
851  for(const auto &comm : large_community->communities()) {
852  if (LargeCommunity::is_tag(comm)) {
853  tag_list.push_back(comm);
854  }
855  }
856  }
857  }
858 
859  BgpAttrDB *attr_db = server->attr_db();
860  CommunityDB *comm_db = server->comm_db();
861  CommunityPtr new_community = comm_db->AppendAndLocate(
862  orig_community, CommunityType::AcceptOwnNexthop);
863  ExtCommunityDB *extcomm_db = server->extcomm_db();
864  LargeCommunityDB *largecomm_db = server->largecomm_db();
865  BgpMembershipManager *membership_mgr = server->membership_mgr();
866  OriginVnPathDB *ovnpath_db = server->ovnpath_db();
867  OriginVnPathPtr new_ovnpath;
868  if (server->autonomous_system() > AS2_MAX && vn_index > 0xffff) {
869  new_ovnpath = ovnpath_db->PrependAndLocate(orig_ovnpath,
870  origin_vn4_bytes);
871  new_ovnpath = ovnpath_db->PrependAndLocate(new_ovnpath.get(),
872  origin_vn_trans_bytes);
873  } else {
874  new_ovnpath = ovnpath_db->PrependAndLocate(
875  orig_ovnpath, origin_vn_bytes);
876  }
877 
878  ConnectedPathIdList new_path_ids;
879  for (Route::PathList::iterator it =
880  connected_route()->GetPathList().begin();
881  it != connected_route()->GetPathList().end(); ++it) {
882  BgpPath *connected_path = static_cast<BgpPath *>(it.operator->());
883 
884  // Infeasible paths are not considered
885  if (!connected_path->IsFeasible())
886  break;
887 
888  // take snapshot of all ECMP paths
889  if (connected_route()->BestPath()->PathCompare(*connected_path, true))
890  break;
891 
892  // Skip paths with duplicate forwarding information. This ensures
893  // that we generate only one path with any given next hop and label
894  // when there are multiple connected paths from the original source
895  // received via different peers e.g. directly via XMPP and via BGP.
896  if (connected_route()->DuplicateForwardingPath(connected_path))
897  continue;
898 
899  const BgpAttr *attr = connected_path->GetAttr();
900 
901  ExtCommunityPtr new_ext_community;
902  LargeCommunityPtr new_large_community;
903 
904  // Strip any RouteTargets from the connected attributes.
905  new_ext_community = extcomm_db->ReplaceRTargetAndLocate(
907 
908  // Add the export route target list from the source routing instance
909  // when inserting into EVPN table. This is required for the case when
910  // service-chain routes are replicated to the BGP table to be used on
911  // the BMS. The TOR switch does not import the cooked-up RT of the
912  // service-RI. It only imports the RTs of the primary RI. Hence, we
913  // add the primary RIs RTs to the route.
914  // NOTE: There is an assumption that connected_ri on the head SI
915  // will always point to the primary RI. Need to change that if the
916  // assumption is not true.
917  // Also, we pick only the export route targets in the range used by
918  // schema transformer for non user-configured RTs.
919  if (is_sc_head() && bgptable->family() == Address::EVPN) {
920  ExtCommunity::ExtCommunityList export_list;
921  const RoutingInstance *conn_ri =
924  connected_->name()));
925  if (!conn_ri) {
926  // conn_ri is not expected to be found only in unit tests.
927  assert(bgp_log_test::unit_test());
928  conn_ri = connected_routing_instance();
929  }
930  BGP_LOG_STR(BgpMessage, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_TRACE,
931  "Adding primary RI " << conn_ri->name() << " route targets " <<
932  "to service-chain route for EVPN table " << bgptable->name());
933  BOOST_FOREACH(const RouteTarget &rtarget,
934  conn_ri->GetExportList()) {
936  rtarget.GetExtCommunity()) != 0) {
937  BGP_LOG_STR(BgpMessage, SandeshLevel::SYS_DEBUG,
938  BGP_LOG_FLAG_TRACE, "RT value " << rtarget.ToString());
939  export_list.push_back(rtarget.GetExtCommunity());
940  }
941  }
942  new_ext_community = extcomm_db->AppendAndLocate(
943  new_ext_community.get(), export_list);
944  }
945 
946  // Replace the SGID list with the list from the original route.
947  new_ext_community = extcomm_db->ReplaceSGIDListAndLocate(
948  new_ext_community.get(), sgid_list);
949 
950  // Replace the Tag list with the list from the original route.
951  new_large_community = largecomm_db->ReplaceTagListAndLocate(
952  new_large_community.get(), tag_list);
953 
954  // Replace SiteOfOrigin with value from original route if any.
955  if (soo.IsNull()) {
956  new_ext_community = extcomm_db->RemoveSiteOfOriginAndLocate(
957  new_ext_community.get());
958  } else {
959  new_ext_community = extcomm_db->ReplaceSiteOfOriginAndLocate(
960  new_ext_community.get(), soo.GetExtCommunity());
961  }
962 
963  // Inherit load balance attribute of orig_route if connected path
964  // does not have one already.
965  if (!LoadBalance::IsPresent(connected_path) && load_balance_present) {
966  new_ext_community = extcomm_db->AppendAndLocate(
967  new_ext_community.get(), load_balance.GetExtCommunity());
968  }
969 
970  // Replace the OriginVn with the value from the original route
971  // or the value associated with the dest routing instance.
972  if (server->autonomous_system() > AS2_MAX && vn_index > 0xffff) {
973  new_ext_community = extcomm_db->ReplaceOriginVnAndLocate(
974  new_ext_community.get(), origin_vn4_bytes);
975  new_ext_community = extcomm_db->AppendAndLocate(
976  new_ext_community.get(), origin_vn_trans_bytes);
977  } else {
978  new_ext_community = extcomm_db->ReplaceOriginVnAndLocate(
979  new_ext_community.get(), origin_vn_bytes);
980  }
981 
982  // Connected routes always have mpls (udp or gre) as encap.
983  // If updating service-chain route in the EVPN table, change
984  // tunnel encap to include VxLAN and MPLS. BMS only supports VxLAN.
985  // Vrouter has the choice of using VxLAN or MPLS based on config.
986  if (is_sc_head() && bgptable->family() == Address::EVPN) {
987  ExtCommunity::ExtCommunityList encaps_list;
988  vector<string> tunnel_encaps = boost::assign::list_of("vxlan");
989  BOOST_FOREACH(string encap, tunnel_encaps) {
990  encaps_list.push_back(TunnelEncap(encap).GetExtCommunity());
991  }
992  new_ext_community = extcomm_db->
993  ReplaceTunnelEncapsulationAndLocate(new_ext_community.get(),
994  encaps_list);
995  }
996 
997  // Replace extended community, community and origin vn path.
998  BgpAttrPtr new_attr = attr_db->ReplaceExtCommunityAndLocate(
999  attr, new_ext_community);
1000  new_attr =
1001  attr_db->ReplaceLargeCommunityAndLocate(new_attr.get(),
1002  new_large_community);
1003  new_attr =
1004  attr_db->ReplaceCommunityAndLocate(new_attr.get(), new_community);
1005  new_attr = attr_db->ReplaceOriginVnPathAndLocate(new_attr.get(),
1006  new_ovnpath);
1007 
1008  // Strip as_path if needed. This is required when the connected route is
1009  // learnt via BGP. If retain_as_path knob is configured replace the
1010  // AsPath with the value from the original route.
1011  if (retain_as_path() && orig_aspath) {
1012  new_attr = attr_db->ReplaceAsPathAndLocate(new_attr.get(),
1013  orig_aspath);
1014  } else {
1015  new_attr = attr_db->ReplaceAsPathAndLocate(new_attr.get(),
1016  AsPathPtr());
1017  }
1018 
1019  // If the connected path is learnt via XMPP, construct RD based on
1020  // the id registered with source table instead of connected table.
1021  // This allows chaining of multiple in-network service instances
1022  // that are on the same compute node.
1023  const IPeer *peer = connected_path->GetPeer();
1024  if (src_ != connected_ && peer && peer->IsXmppPeer()) {
1025  int instance_id = -1;
1026  bool is_registered = membership_mgr->GetRegistrationInfo(peer,
1027  bgptable, &instance_id);
1028  if (!is_registered)
1029  continue;
1030  RouteDistinguisher connected_rd = attr->source_rd();
1031  if (connected_rd.Type() != RouteDistinguisher::TypeIpAddressBased)
1032  continue;
1033 
1034  RouteDistinguisher rd(connected_rd.GetAddress(), instance_id);
1035  new_attr = attr_db->ReplaceSourceRdAndLocate(new_attr.get(), rd);
1036  }
1037 
1038  // Replace the source rd if the connected path is a secondary path
1039  // of a primary path in the l3vpn table. Use the RD of the primary.
1040  if (connected_path->IsReplicated()) {
1041  const BgpSecondaryPath *spath =
1042  static_cast<const BgpSecondaryPath *>(connected_path);
1043  const RoutingInstance *ri = spath->src_table()->routing_instance();
1044  if (ri->IsMasterRoutingInstance()) {
1045  const VpnRouteT *vpn_route =
1046  static_cast<const VpnRouteT *>(spath->src_rt());
1047  new_attr = attr_db->ReplaceSourceRdAndLocate(new_attr.get(),
1048  vpn_route->GetPrefix().route_distinguisher());
1049  }
1050  }
1051 
1052  // Skip paths with Source RD same as source RD of the connected path
1053  if (!orig_rd.IsZero() && new_attr->source_rd() == orig_rd)
1054  continue;
1055 
1056  // Check whether we already have a path with the associated path id.
1057  uint32_t path_id =
1058  connected_path->GetAttr()->nexthop().to_v4().to_ulong();
1059  ProcessServiceChainPath(path_id, connected_path, new_attr,
1060  service_chain_route, partition,
1061  aggregate, bgptable);
1062  new_path_ids.insert(path_id);
1063  }
1064 
1065  // Remove stale paths.
1066  for (ConnectedPathIdList::const_iterator it = old_path_ids.begin();
1067  it != old_path_ids.end(); ++it) {
1068  uint32_t path_id = *it;
1069  if (new_path_ids.find(path_id) != new_path_ids.end())
1070  continue;
1071  service_chain_route->RemovePath(BgpPath::ServiceChain, NULL, path_id);
1072  partition->Notify(service_chain_route);
1073 
1074  BGP_LOG_STR(BgpMessage, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_TRACE,
1075  "Removed " << (aggregate ? "Aggregate" : "ExtConnected") <<
1076  " ServiceChain path " << service_chain_route->ToString() <<
1077  " path_id " << BgpPath::PathIdString(path_id) <<
1078  " in table " << bgptable->name());
1079 
1080  }
1081 
1082  // Delete the route if there's no paths.
1083  if (!service_chain_route->HasPaths())
1084  partition->Delete(service_chain_route);
1085 }
1086 
1087 template <typename T>
1089  BgpRoute *more_specific) {
1090  typename PrefixToRouteListMap::iterator it =
1091  prefix_to_routelist_map_.find(aggregate);
1092  assert(it != prefix_to_routelist_map_.end());
1093  bool ret = false;
1094  if (it->second.empty()) {
1095  // Add the aggregate for the first time
1096  ret = true;
1097  }
1098  it->second.insert(more_specific);
1099  return ret;
1100 }
1101 
1102 template <typename T>
1104  BgpRoute *more_specific) {
1105  typename PrefixToRouteListMap::iterator it =
1106  prefix_to_routelist_map_.find(aggregate);
1107  assert(it != prefix_to_routelist_map_.end());
1108  it->second.erase(more_specific);
1109  return it->second.empty();
1110 }
1111 
1112 template <typename T>
1113 void ServiceChain<T>::FillServiceChainInfo(ShowServicechainInfo *info) const {
1114  if (deleted()) {
1115  info->set_state("deleted");
1116  } else if (!IsConnectedRouteValid()) {
1117  info->set_state("down");
1118  } else if (!group_oper_state_up()) {
1119  info->set_state("group down");
1120  } else {
1121  info->set_state("active");
1122  }
1123 
1124  ConnectedRouteInfo connected_rt_info;
1125  connected_rt_info.set_service_chain_addr(
1126  service_chain_addr().to_string());
1127  if (connected_route()) {
1128  ShowRoute show_route;
1129  connected_route()->FillRouteInfo(connected_table(), &show_route);
1130  connected_rt_info.set_connected_rt(show_route);
1131  }
1132  info->set_connected_route(connected_rt_info);
1133 
1134  vector<PrefixToRouteListInfo> more_vec;
1135  for (typename PrefixToRouteListMap::const_iterator it =
1136  prefix_to_route_list_map()->begin();
1137  it != prefix_to_route_list_map()->end(); ++it) {
1138  PrefixToRouteListInfo prefix_list_info;
1139  prefix_list_info.set_prefix(it->first.ToString());
1140 
1141  BgpTable *bgptable = src_table();
1142  RouteT rt_key(it->first);
1143  BgpRoute *aggregate = static_cast<BgpRoute *>(bgptable->Find(&rt_key));
1144  if (aggregate) {
1145  prefix_list_info.set_aggregate(true);
1146  ShowRoute show_route;
1147  aggregate->FillRouteInfo(bgptable, &show_route);
1148  prefix_list_info.set_aggregate_rt(show_route);
1149  } else {
1150  prefix_list_info.set_aggregate(false);
1151  }
1152 
1153  vector<string> rt_list;
1154  for (RouteList::iterator rt_it = it->second.begin();
1155  rt_it != it->second.end(); ++rt_it) {
1156  rt_list.push_back((*rt_it)->ToString());
1157  }
1158  prefix_list_info.set_more_specific_list(rt_list);
1159  more_vec.push_back(prefix_list_info);
1160  }
1161  info->set_more_specifics(more_vec);
1162 
1163  vector<ExtConnectRouteInfo> ext_connecting_rt_info_list;
1164  for (ExtConnectRouteList::const_iterator it =
1165  ext_connecting_routes().begin();
1166  it != ext_connecting_routes().end(); ++it) {
1167  ExtConnectRouteInfo ext_rt_info;
1168  ext_rt_info.set_ext_rt_prefix((*it)->ToString());
1169  BgpTable *bgptable = src_table();
1170  RouteT *ext_route = static_cast<RouteT *>(*it);
1171  RouteT rt_key(ext_route->GetPrefix());
1172  BgpRoute *ext_connecting =
1173  static_cast<BgpRoute *>(bgptable->Find(&rt_key));
1174  if (ext_connecting) {
1175  ShowRoute show_route;
1176  ext_connecting->FillRouteInfo(bgptable, &show_route);
1177  ext_rt_info.set_ext_rt_svc_rt(show_route);
1178  }
1179  ext_connecting_rt_info_list.push_back(ext_rt_info);
1180  }
1181  info->set_ext_connecting_rt_info_list(ext_connecting_rt_info_list);
1182  info->set_aggregate_enable(aggregate_enable());
1183 }
1184 
1186  const string &name)
1187  : manager_(manager),
1188  name_(name),
1189  oper_state_up_(false) {
1190 }
1191 
1193  assert(chain_set_.empty());
1194 }
1195 
1196 //
1197 // Add a RoutingInstance to this ServiceChainGroup.
1198 // The caller must ensure that multiple bgp::ConfigHelper tasks do not
1199 // invoke this method in parallel.
1200 //
1202  CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
1203  chain_set_.insert(rtinstance);
1205 }
1206 
1207 //
1208 // Delete a RoutingInstance from this ServiceChainGroup.
1209 // The caller must ensure that multiple bgp::ConfigHelper tasks do not
1210 // invoke this method in parallel.
1211 //
1213  CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
1214  chain_set_.erase(rtinstance);
1216 }
1217 
1218 //
1219 // Update the operational state of this ServiceChainGroup.
1220 // It's considered to be up if all ServiceChains in the ServiceChainGroup
1221 // are up.
1222 // Trigger an update on the operational state of each ServiceChain if the
1223 // operational state of the ServiceChainGroup changed.
1224 //
1226  bool old_oper_state_up = oper_state_up_;
1227  oper_state_up_ = true;
1228  BOOST_FOREACH(RoutingInstance *rtinstance, chain_set_) {
1229  if (manager_->ServiceChainIsUp(rtinstance))
1230  continue;
1231  oper_state_up_ = false;
1232  break;
1233  }
1234 
1235  if (old_oper_state_up == oper_state_up_)
1236  return;
1237 
1238  BOOST_FOREACH(RoutingInstance *rtinstance, chain_set_) {
1240  }
1241 }
1242 
1251 template <typename T>
1253  return server_->condition_listener(GetSCFamily());
1254 }
1255 
1256 template <typename T>
1258  CHECK_CONCURRENCY("bgp::ServiceChain");
1259  BgpTable *table = NULL;
1260  BgpRoute *route = NULL;
1261  PrefixT aggregate_match = req->aggregate_match_;
1262  ServiceChainT *info = NULL;
1263 
1264  table = req->table_;
1265  route = req->rt_;
1266  info = static_cast<ServiceChainT *>(req->info_.get());
1267 
1268  // Table where the aggregate route needs to be added
1269  aggregate_match = req->aggregate_match_;
1270 
1271  ServiceChainState *state = NULL;
1272  if (route) {
1273  state = static_cast<ServiceChainState *>
1274  (listener_->GetMatchState(table, route, info));
1275  }
1276 
1277  switch (req->type_) {
1278  case ServiceChainRequestT::MORE_SPECIFIC_ADD_CHG: {
1279  assert(state);
1280  if (state->deleted()) {
1281  state->reset_deleted();
1282  }
1283  if (!info->AddMoreSpecific(aggregate_match, route))
1284  break;
1285  if (!info->IsConnectedRouteValid())
1286  break;
1287  if (!info->group_oper_state_up())
1288  break;
1289 
1290  typename ServiceChainT::ConnectedPathIdList path_ids;
1292  aggregate_match, NULL, path_ids, true);
1293  break;
1294  }
1295  case ServiceChainRequestT::MORE_SPECIFIC_DELETE: {
1296  assert(state);
1297  if (info->DeleteMoreSpecific(aggregate_match, route)) {
1298  // Delete the aggregate route
1299  info->DeleteServiceChainRoute(aggregate_match, true);
1300  }
1301  info->RemoveMatchState(route, state);
1302  break;
1303  }
1304  case ServiceChainRequestT::CONNECTED_ROUTE_ADD_CHG: {
1305  assert(state);
1306  if (route->IsDeleted() || !route->BestPath() ||
1307  !route->BestPath()->IsFeasible()) {
1308  break;
1309  }
1310  UpdateServiceChainGroup(info->group());
1311 
1312  if (state->deleted()) {
1313  state->reset_deleted();
1314  }
1315 
1316  // Store the old path id list and populate the new one.
1317  typename ServiceChainT::ConnectedPathIdList path_ids =
1318  info->GetConnectedPathIds();
1319  info->SetConnectedRoute(route);
1320 
1321  if (!info->group_oper_state_up())
1322  break;
1323 
1324  UpdateServiceChainRoutes(info, path_ids);
1325  break;
1326  }
1327  case ServiceChainRequestT::CONNECTED_ROUTE_DELETE: {
1328  assert(state);
1329  UpdateServiceChainGroup(info->group());
1330  DeleteServiceChainRoutes(info);
1331  info->RemoveMatchState(route, state);
1332  info->SetConnectedRoute(NULL);
1333  break;
1334  }
1335  case ServiceChainRequestT::EXT_CONNECT_ROUTE_ADD_CHG: {
1336  assert(state);
1337  if (state->deleted()) {
1338  state->reset_deleted();
1339  }
1340  info->ext_connecting_routes()->insert(route);
1341  if (!info->IsConnectedRouteValid())
1342  break;
1343  if (!info->group_oper_state_up())
1344  break;
1345  RouteT *ext_route = dynamic_cast<RouteT *>(route);
1346  typename ServiceChainT::ConnectedPathIdList path_ids;
1348  ext_route->GetPrefix(), ext_route, path_ids, false);
1349  break;
1350  }
1351  case ServiceChainRequestT::EXT_CONNECT_ROUTE_DELETE: {
1352  assert(state);
1353  if (info->ext_connecting_routes()->erase(route)) {
1354  RouteT *inet_route = dynamic_cast<RouteT *>(route);
1355  info->DeleteServiceChainRoute(inet_route->GetPrefix(), false);
1356  }
1357  info->RemoveMatchState(route, state);
1358  break;
1359  }
1360  case ServiceChainRequestT::UPDATE_ALL_ROUTES: {
1361  if (info->dest_table_unregistered())
1362  break;
1363  if (info->connected_table_unregistered())
1364  break;
1365  if (!info->connected_route())
1366  break;
1367  if (!info->group_oper_state_up())
1368  break;
1369 
1370  typename ServiceChainT::ConnectedPathIdList path_ids =
1371  info->GetConnectedPathIds();
1372  UpdateServiceChainRoutes(info, path_ids);
1373  break;
1374  }
1375  case ServiceChainRequestT::DELETE_ALL_ROUTES: {
1376  DeleteServiceChainRoutes(info);
1377  break;
1378  }
1379  case ServiceChainRequestT::STOP_CHAIN_DONE: {
1380  if (table == info->connected_table()) {
1382  if (!info->num_matchstate()) {
1383  listener_->UnregisterMatchCondition(table, info);
1384  }
1385  }
1386  if (table == info->dest_table()) {
1388  if (!info->num_matchstate()) {
1389  listener_->UnregisterMatchCondition(table, info);
1390  }
1391  }
1392  if (info->unregistered()) {
1393  chain_set_.erase(info->src_routing_instance());
1394  StartResolve();
1395  }
1396  RetryDelete();
1397  break;
1398  }
1399  default: {
1400  assert(false);
1401  break;
1402  }
1403  }
1404 
1405  if (state) {
1406  state->DecrementRefCnt();
1407  if (state->refcnt() == 0 && state->deleted()) {
1408  listener_->RemoveMatchState(table, route, info);
1409  delete state;
1410  if (!info->num_matchstate()) {
1411  if (info->dest_table_unregistered()) {
1412  listener_->UnregisterMatchCondition(
1413  info->dest_table(), info);
1414  }
1415  if (info->connected_table_unregistered()) {
1416  listener_->UnregisterMatchCondition(
1417  info->connected_table(), info);
1418  }
1419  if (info->unregistered()) {
1420  chain_set_.erase(info->src_routing_instance());
1421  StartResolve();
1422  }
1423  }
1424  }
1425  }
1426  delete req;
1427  return true;
1428 }
1429 
1430 template <typename T>
1432  : server_(server),
1433  listener_(GetListener()),
1434  resolve_trigger_(new TaskTrigger(
1435  bind(&ServiceChainMgr::ResolvePendingServiceChain, this),
1436  TaskScheduler::GetInstance()->GetTaskId("bgp::Config"), 0)),
1437  group_trigger_(new TaskTrigger(
1438  bind(&ServiceChainMgr::ProcessServiceChainGroups, this),
1439  TaskScheduler::GetInstance()->GetTaskId("bgp::ServiceChain"), 0)),
1440  aggregate_host_route_(false),
1441  deleter_(new DeleteActor(this)),
1442  server_delete_ref_(this, server->deleter()) {
1443  if (service_chain_task_id_ == -1) {
1445  service_chain_task_id_ = scheduler->GetTaskId("bgp::ServiceChain");
1446  }
1447 
1448  process_queue_.reset(
1450  bind(&ServiceChainMgr::RequestHandler, this, _1)));
1451 
1453  bind(&ServiceChainMgr::RoutingInstanceCallback, this, _1, _2));
1454 
1455  BgpMembershipManager *membership_mgr = server->membership_mgr();
1457  bind(&ServiceChainMgr::PeerRegistrationCallback, this, _1, _2, _3));
1458 }
1459 
1460 template <typename T>
1462  assert(group_set_.empty());
1463  assert(group_map_.empty());
1464 }
1465 
1466 template <typename T>
1468  process_queue_->Shutdown();
1469  RoutingInstanceMgr *ri_mgr = server_->routing_instance_mgr();
1470  ri_mgr->UnregisterInstanceOpCallback(id_);
1471  BgpMembershipManager *membership_mgr = server_->membership_mgr();
1472  membership_mgr->UnregisterPeerRegistrationCallback(registration_id_);
1473  server_delete_ref_.Reset(NULL);
1474 }
1475 
1476 template <typename T>
1478  deleter_->Delete();
1479 }
1480 
1481 template <typename T>
1483  if (!chain_set_.empty() || !pending_chains_.empty())
1484  return false;
1485  if (!group_set_.empty() || !group_map_.empty())
1486  return false;
1487  return true;
1488 }
1489 
1490 template <typename T>
1492  if (!deleter_->IsDeleted())
1493  return;
1494  deleter_->RetryDelete();
1495 }
1496 
1497 template <typename T>
1499  RoutingInstance *rtinstance) {
1500  if (ServiceChainIsPending(rtinstance)) {
1501  PendingChainState state = GetPendingServiceChain(rtinstance);
1502  return state.group;
1503  } else {
1504  const ServiceChain<T> *chain = FindServiceChain(rtinstance);
1505  return (chain ? chain->group() : NULL);
1506  }
1507 }
1508 
1509 template <typename T>
1511  const string &group_name) {
1512  GroupMap::iterator loc = group_map_.find(group_name);
1513  return (loc != group_map_.end() ? loc->second : NULL);
1514 }
1515 
1516 template <typename T>
1518  const string &group_name) {
1519  CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
1520 
1521  GroupMap::iterator loc = group_map_.find(group_name);
1522  ServiceChainGroup *group = (loc != group_map_.end()) ? loc->second : NULL;
1523  if (!group) {
1524  string temp_group_name(group_name);
1525  group = new ServiceChainGroup(this, temp_group_name);
1526  group_map_.insert(temp_group_name, group);
1527  }
1528  return group;
1529 }
1530 
1531 template <typename T>
1533  CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper", "bgp::ServiceChain");
1534 
1535  if (!group)
1536  return;
1537  group_set_.insert(group);
1538  group_trigger_->Set();
1539 }
1540 
1541 template <typename T>
1543  CHECK_CONCURRENCY("bgp::ServiceChain");
1544 
1545  BOOST_FOREACH(ServiceChainGroup *group, group_set_) {
1546  if (group->empty()) {
1547  string temp_group_name(group->name());
1548  group_map_.erase(temp_group_name);
1549  } else {
1550  group->UpdateOperState();
1551  }
1552  }
1553 
1554  group_set_.clear();
1555  RetryDelete();
1556  return true;
1557 }
1558 
1562 template <>
1564  return Address::INET;
1565 }
1566 
1567 template <>
1569  return Address::INET6;
1570 }
1571 
1572 template <>
1574  return Address::EVPN;
1575 }
1576 
1577 template <>
1579  return Address::EVPN;
1580 }
1581 
1585 template <>
1587  return Address::INET;
1588 }
1589 
1590 template <>
1592  return Address::INET6;
1593 }
1594 
1595 template <>
1597  return Address::INET;
1598 }
1599 
1600 template <>
1602  return Address::INET6;
1603 }
1604 
1608 template <>
1610  return SCAddress::INET;
1611 }
1612 
1613 template <>
1615  return SCAddress::INET6;
1616 }
1617 
1618 template <>
1620  return SCAddress::EVPN;
1621 }
1622 
1623 template <>
1625  return SCAddress::EVPN6;
1626 }
1627 
1628 template <>
1629 template <typename T>
1631  process_queue_->Enqueue(req);
1632 }
1633 
1634 template <typename T>
1636  string *reason) const {
1637  typename PendingChainList::const_iterator loc =
1638  pending_chains_.find(rtinstance);
1639  if (loc != pending_chains_.end()) {
1640  if (reason)
1641  *reason = loc->second.reason;
1642  return true;
1643  }
1644  return false;
1645 }
1646 
1647 template <typename T>
1649  if (ServiceChainIsPending(rtinstance))
1650  return false;
1651  const ServiceChain<T> *service_chain = FindServiceChain(rtinstance);
1652  if (!service_chain)
1653  return false;
1654  return service_chain->IsConnectedRouteValid();
1655 }
1656 
1657 template <typename T>
1659  ShowServicechainInfo *info) const {
1660  string pending_reason;
1661  if (ServiceChainIsPending(rtinstance, &pending_reason)) {
1662  info->set_state("pending");
1663  info->set_pending_reason(pending_reason);
1664  return true;
1665  }
1666  const ServiceChain<T> *service_chain = FindServiceChain(rtinstance);
1667  if (!service_chain)
1668  return false;
1669  service_chain->FillServiceChainInfo(info);
1670  return true;
1671 }
1672 
1673 
1674 
1675 template <typename T>
1677  const ServiceChainConfig &config) {
1678  CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
1679 
1680  // Verify whether the entry already exists.
1681  std::scoped_lock lock(mutex_);
1682  ServiceChainMap::iterator it = chain_set_.find(rtinstance);
1683  if (it != chain_set_.end()) {
1684  ServiceChainT *chain = static_cast<ServiceChainT *>(it->second.get());
1685  if (chain->CompareServiceChainConfig(config)) {
1686  BGP_LOG_STR(BgpMessage, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_TRACE,
1687  "No update in ServiceChain config : " << rtinstance->name());
1688  return true;
1689  }
1690 
1691  ServiceChainGroup *group = chain->group();
1692  if (group) {
1693  group->DeleteRoutingInstance(rtinstance);
1694  chain->clear_group();
1695  }
1696 
1697  // Update of ServiceChainConfig.
1698  // Add the routing instance to pending list so that service chain is
1699  // created after stop done callback for the current incarnation gets
1700  // invoked.
1701  if (config.service_chain_id.empty()) {
1702  group = NULL;
1703  } else {
1704  group = LocateServiceChainGroup(config.service_chain_id);
1705  group->AddRoutingInstance(rtinstance);
1706  }
1707  string reason = "Waiting for deletion of previous incarnation";
1708  AddPendingServiceChain(rtinstance, group, reason);
1709 
1710  // Wait for the delete complete callback.
1711  if (chain->deleted())
1712  return false;
1713 
1715  bind(&ServiceChainMgr::StopServiceChainDone, this, _1, _2);
1716  listener_->RemoveMatchCondition(chain->dest_table(), chain, cb);
1717  listener_->RemoveMatchCondition(chain->connected_table(), chain, cb);
1718  return true;
1719  }
1720 
1721  RoutingInstanceMgr *mgr = server_->routing_instance_mgr();
1723 
1724  // Dissociate from the old ServiceChainGroup.
1725  ServiceChainGroup *group = FindServiceChainGroup(rtinstance);
1726  if (group)
1727  group->DeleteRoutingInstance(rtinstance);
1728 
1729  // Delete from the pending list. The instance would already have been
1730  // removed from the pending list if this method is called when trying
1731  // to resolve items in the pending list. However, if this method is
1732  // called when processing a change in the service chain config, then
1733  // we may need to remove it from the pending list.
1734  DeletePendingServiceChain(rtinstance);
1735 
1736  // Locate the new ServiceChainGroup.
1737  if (config.service_chain_id.empty()) {
1738  group = NULL;
1739  } else {
1740  group = LocateServiceChainGroup(config.service_chain_id);
1741  group->AddRoutingInstance(rtinstance);
1742  }
1743 
1744  // Destination routing instance does not exist.
1745  if (!dest) {
1746  string reason = "Destination routing instance does not exist";
1747  AddPendingServiceChain(rtinstance, group, reason);
1748  return false;
1749  }
1750 
1751  // Destination routing instance is being deleted.
1752  if (dest->deleted()) {
1753  string reason = "Destination routing instance is being deleted";
1754  AddPendingServiceChain(rtinstance, group, reason);
1755  return false;
1756  }
1757 
1758  // Destination virtual network index is unknown.
1759  if (!dest->virtual_network_index()) {
1760  string reason = "Destination virtual network index is unknown";
1761  AddPendingServiceChain(rtinstance, group, reason);
1762  return false;
1763  }
1764 
1765  RoutingInstance *connected_ri = NULL;
1766  if (config.source_routing_instance == "") {
1767  connected_ri = rtinstance;
1768  assert(!rtinstance->deleted());
1769  } else {
1770  connected_ri = mgr->GetRoutingInstance(config.source_routing_instance);
1771  }
1772 
1773  // Connected routing instance does not exist.
1774  if (!connected_ri) {
1775  string reason = "Connected routing instance does not exist";
1776  AddPendingServiceChain(rtinstance, group, reason);
1777  return false;
1778  }
1779 
1780  // Connected routing instance is being deleted.
1781  if (connected_ri->deleted()) {
1782  string reason = "Connected routing instance is being deleted";
1783  AddPendingServiceChain(rtinstance, group, reason);
1784  return false;
1785  }
1786 
1787  // Add to pending queue if the service chain address is invalid.
1788  error_code ec;
1789  AddressT chain_addr =
1790  AddressT::from_string(config.service_chain_address, ec);
1791  if (ec.failed()) {
1792  string reason = "Service chain address is invalid";
1793  AddPendingServiceChain(rtinstance, group, reason);
1794  return false;
1795  }
1796 
1802  BgpTable *connected_table = NULL;
1803  connected_table = connected_ri->GetTable(GetConnectedFamily());
1804  assert(connected_table);
1805  BgpTable *dest_table = dest->GetTable(GetFamily());
1806  assert(dest_table);
1807 
1808  // Allocate the new service chain.
1809  ServiceChainPtr chain = ServiceChainPtr(new ServiceChainT(this, group,
1810  rtinstance, dest, connected_ri, config.prefix, chain_addr,
1811  config.sc_head, config.retain_as_path));
1812 
1813  if (aggregate_host_route()) {
1814  ServiceChainT *obj = static_cast<ServiceChainT *>(chain.get());
1815  obj->set_aggregate_enable();
1816  }
1817 
1818  // Add the new service chain request
1819  chain_set_.insert(make_pair(rtinstance, chain));
1820  listener_->AddMatchCondition(
1821  connected_table, chain.get(), BgpConditionListener::RequestDoneCb());
1822  listener_->AddMatchCondition(
1823  dest_table, chain.get(), BgpConditionListener::RequestDoneCb());
1824 
1825  return true;
1826 }
1827 
1828 template <typename T>
1830  const string &instance) const {
1831  RoutingInstance *rtinstance =
1832  server_->routing_instance_mgr()->GetRoutingInstance(instance);
1833  if (!rtinstance)
1834  return NULL;
1835  ServiceChainMap::const_iterator it = chain_set_.find(rtinstance);
1836  if (it == chain_set_.end())
1837  return NULL;
1838  ServiceChainT *chain = static_cast<ServiceChainT *>(it->second.get());
1839  return chain;
1840 }
1841 
1842 template <typename T>
1844  RoutingInstance *rtinstance) const {
1845  ServiceChainMap::const_iterator it = chain_set_.find(rtinstance);
1846  if (it == chain_set_.end())
1847  return NULL;
1848  ServiceChainT *chain = static_cast<ServiceChainT *>(it->second.get());
1849  return chain;
1850 }
1851 
1852 template <typename T>
1854  CHECK_CONCURRENCY("bgp::Config");
1855  for (typename PendingChainList::iterator it = pending_chains_.begin(), next;
1856  it != pending_chains_.end(); it = next) {
1857  next = it;
1858  ++next;
1859  RoutingInstance *rtinstance = it->first;
1860  ServiceChainGroup *group = it->second.group;
1861  if (group)
1862  group->DeleteRoutingInstance(rtinstance);
1863  pending_chains_.erase(it);
1864  const ServiceChainConfig *sc_config =
1865  rtinstance->config()->service_chain_info(GetSCFamily());
1866  if (sc_config)
1867  LocateServiceChain(rtinstance, *sc_config);
1868  }
1869  RetryDelete();
1870  return true;
1871 }
1872 
1873 template <typename T>
1876  StartResolve();
1877 }
1878 
1879 template <typename T>
1881  if (pending_chains_.empty())
1882  return;
1883  resolve_trigger_->Set();
1884 }
1885 
1886 template <typename T>
1888  ConditionMatch *info) {
1889  // Post the RequestDone event to ServiceChain task to take Action
1890  ServiceChainRequestT *req =
1891  new ServiceChainRequestT(ServiceChainRequestT::STOP_CHAIN_DONE, table,
1892  NULL, PrefixT(), ServiceChainPtr(info));
1893  Enqueue(req);
1894  return;
1895 }
1896 
1897 template <typename T>
1899  CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
1900 
1901  // Remove the routing instance from pending chains list.
1902  std::scoped_lock lock(mutex_);
1903  if (ServiceChainIsPending(rtinstance)) {
1904  ServiceChainGroup *group = FindServiceChainGroup(rtinstance);
1905  if (group)
1906  group->DeleteRoutingInstance(rtinstance);
1907  DeletePendingServiceChain(rtinstance);
1908  RetryDelete();
1909  }
1910 
1911  ServiceChainT *chain = FindServiceChain(rtinstance);
1912  if (!chain)
1913  return;
1914 
1915  ServiceChainGroup *group = chain->group();
1916  if (group) {
1917  group->DeleteRoutingInstance(rtinstance);
1918  chain->clear_group();
1919  }
1920 
1921  if (chain->deleted())
1922  return;
1923 
1925  bind(&ServiceChainMgr::StopServiceChainDone, this, _1, _2);
1926  listener_->RemoveMatchCondition(chain->dest_table(), chain, cb);
1927  listener_->RemoveMatchCondition(chain->connected_table(), chain, cb);
1928 }
1929 
1930 template <typename T>
1932  bool group_oper_state_up) {
1933  // Bail if there's no service chain for the instance.
1934  ServiceChainT *chain = FindServiceChain(rtinstance);
1935  if (!chain)
1936  return;
1937 
1938  // Update the state in the service chain.
1939  chain->set_group_oper_state_up(group_oper_state_up);
1940 
1941  // Post event to ServiceChain task to update/delete all routes.
1942  typename ServiceChainRequestT::RequestType req_type;
1943  if (group_oper_state_up) {
1944  req_type = ServiceChainRequestT::UPDATE_ALL_ROUTES;
1945  } else {
1946  req_type = ServiceChainRequestT::DELETE_ALL_ROUTES;
1947  }
1949  req_type, NULL, NULL, PrefixT(), ServiceChainPtr(chain));
1950  Enqueue(req);
1951 }
1952 
1953 template <typename T>
1955  const typename ServiceChainT::ConnectedPathIdList &old_path_ids) {
1956  // Update ServiceChain routes for aggregates.
1957  typename ServiceChainT::PrefixToRouteListMap *vn_prefix_list =
1958  chain->prefix_to_route_list_map();
1959  for (typename ServiceChainT::PrefixToRouteListMap::iterator it =
1960  vn_prefix_list->begin(); it != vn_prefix_list->end(); ++it) {
1961  if (!it->second.empty())
1962  chain->UpdateServiceChainRoute(it->first, NULL, old_path_ids, true);
1963  }
1964 
1965  // Update ServiceChain routes for external connecting routes.
1966  for (typename ServiceChainT::ExtConnectRouteList::iterator it =
1967  chain->ext_connecting_routes()->begin();
1968  it != chain->ext_connecting_routes()->end(); ++it) {
1969  RouteT *ext_route = static_cast<RouteT *>(*it);
1970  chain->UpdateServiceChainRoute(
1971  ext_route->GetPrefix(), ext_route, old_path_ids, false);
1972  }
1973 }
1974 
1975 template <typename T>
1977  // Delete ServiceChain routes for aggregates.
1978  typename ServiceChainT::PrefixToRouteListMap *vn_prefix_list =
1979  chain->prefix_to_route_list_map();
1980  for (typename ServiceChainT::PrefixToRouteListMap::iterator it =
1981  vn_prefix_list->begin(); it != vn_prefix_list->end(); ++it) {
1982  chain->DeleteServiceChainRoute(it->first, true);
1983  }
1984 
1985  // Delete ServiceChain routes for external connecting routes.
1986  for (typename ServiceChainT::ExtConnectRouteList::iterator it =
1987  chain->ext_connecting_routes()->begin();
1988  it != chain->ext_connecting_routes()->end(); ++it) {
1989  RouteT *ext_route = static_cast<RouteT *>(*it);
1990  chain->DeleteServiceChainRoute(ext_route->GetPrefix(), false);
1991  }
1992 }
1993 
1994 template <typename T>
1996  bool unregister) {
1997  CHECK_CONCURRENCY("bgp::PeerMembership");
1998 
1999  // Bail if it's not an XMPP peer.
2000  if (!peer->IsXmppPeer())
2001  return;
2002 
2003  // Bail if there's no service chain for the instance.
2004  ServiceChainT *chain = FindServiceChain(table->routing_instance());
2005  if (!chain)
2006  return;
2007 
2008  // Post event to ServiceChain task to update all routes.
2009  ServiceChainRequestT *req =
2010  new ServiceChainRequestT(ServiceChainRequestT::UPDATE_ALL_ROUTES, NULL,
2011  NULL, PrefixT(), ServiceChainPtr(chain));
2012  Enqueue(req);
2013 }
2014 
2015 template <typename T>
2017  resolve_trigger_->set_disable();
2018 }
2019 
2020 template <typename T>
2022  resolve_trigger_->set_enable();
2023 }
2024 
2025 template <typename T>
2027  group_trigger_->set_disable();
2028 }
2029 
2030 template <typename T>
2032  group_trigger_->set_enable();
2033 }
2034 
2035 template <typename T>
2037  uint32_t count = 0;
2038  for (ServiceChainMap::const_iterator it = chain_set_.begin();
2039  it != chain_set_.end(); ++it) {
2040  const ServiceChainT *chain =
2041  static_cast<const ServiceChainT *>(it->second.get());
2042  if (!chain->IsConnectedRouteValid())
2043  count++;
2044  }
2045  return count;
2046 }
2047 
2048 // Explicit instantiation of ServiceChainMgr for INET and INET6.
2049 template class ServiceChainMgr<ServiceChainInet>;
2050 template class ServiceChainMgr<ServiceChainInet6>;
2051 template class ServiceChainMgr<ServiceChainEvpn>;
2052 template class ServiceChainMgr<ServiceChainEvpn6>;
boost::asio::ip::address IpAddress
Definition: address.h:13
boost::intrusive_ptr< const AsPath > AsPathPtr
Definition: bgp_aspath.h:165
boost::intrusive_ptr< const BgpAttr > BgpAttrPtr
Definition: bgp_attr.h:998
#define AS_TRANS
Definition: bgp_common.h:23
#define AS2_MAX
Definition: bgp_common.h:24
#define BGP_LOG_FLAG_TRACE
Definition: bgp_log.h:43
#define BGP_LOG_STR(obj, level, flags, arg)
Definition: bgp_log.h:89
boost::intrusive_ptr< const OriginVnPath > OriginVnPathPtr
Family
Definition: address.h:24
@ INET
Definition: address.h:26
@ EVPN
Definition: address.h:31
@ INET6
Definition: address.h:27
BgpAttrPtr ReplaceAsPathAndLocate(const BgpAttr *attr, AsPathPtr aspath)
Definition: bgp_attr.cc:1342
BgpAttrPtr ReplaceExtCommunityAndLocate(const BgpAttr *attr, ExtCommunityPtr extcomm)
Definition: bgp_attr.cc:1366
BgpAttrPtr ReplaceSourceRdAndLocate(const BgpAttr *attr, const RouteDistinguisher &source_rd)
Definition: bgp_attr.cc:1406
BgpAttrPtr ReplaceOriginVnPathAndLocate(const BgpAttr *attr, OriginVnPathPtr ovnpath)
Definition: bgp_attr.cc:1382
BgpAttrPtr ReplaceLargeCommunityAndLocate(const BgpAttr *attr, LargeCommunityPtr largecomm)
Definition: bgp_attr.cc:1374
BgpAttrPtr ReplaceCommunityAndLocate(const BgpAttr *attr, CommunityPtr community)
Definition: bgp_attr.cc:1350
const LargeCommunity * large_community() const
Definition: bgp_attr.h:918
const AsPath * as_path() const
Definition: bgp_attr.h:901
const OriginVnPath * origin_vn_path() const
Definition: bgp_attr.h:921
const Community * community() const
Definition: bgp_attr.h:916
const RouteDistinguisher & source_rd() const
Definition: bgp_attr.h:898
const IpAddress & nexthop() const
Definition: bgp_attr.h:888
const ExtCommunity * ext_community() const
Definition: bgp_attr.h:917
boost::function< void(BgpTable *, ConditionMatch *)> RequestDoneCb
void SetMatchState(BgpTable *table, BgpRoute *route, ConditionMatch *obj, ConditionMatchState *state=NULL)
ConditionMatchState * GetMatchState(BgpTable *table, BgpRoute *route, ConditionMatch *obj)
const ServiceChainConfig * service_chain_info(SCAddress::Family family) const
Definition: bgp_config.cc:379
void UnregisterPeerRegistrationCallback(int id)
int RegisterPeerRegistrationCallback(PeerRegistrationCallback callback)
bool GetRegistrationInfo(const IPeer *peer, const BgpTable *table, int *instance_id=NULL, uint64_t *subscription_gen_id=NULL) const
bool IsVrfOriginated() const
Definition: bgp_path.h:68
uint32_t GetLabel() const
Definition: bgp_path.h:89
uint32_t GetFlags() const
Definition: bgp_path.h:100
IPeer * GetPeer()
Definition: bgp_path.h:76
static std::string PathIdString(uint32_t path_id)
Definition: bgp_path.cc:18
virtual bool IsReplicated() const
Definition: bgp_path.h:91
bool IsFeasible() const
Definition: bgp_path.h:92
@ ServiceChain
Definition: bgp_path.h:40
@ BGP_XMPP
Definition: bgp_path.h:39
const BgpAttr * GetAttr() const
Definition: bgp_path.h:87
PathSource GetSource() const
Definition: bgp_path.h:103
const BgpPath * FindPath(BgpPath::PathSource src) const
Definition: bgp_route.cc:146
bool RemovePath(BgpPath::PathSource src, const IPeer *peer=NULL, uint32_t path_id=0)
Definition: bgp_route.cc:263
const BgpPath * BestPath() const
Definition: bgp_route.cc:47
virtual bool IsValid() const
Definition: bgp_route.cc:339
void FillRouteInfo(const BgpTable *table, ShowRouteBrief *show_route) const
Definition: bgp_route.cc:433
void InsertPath(BgpPath *path)
Definition: bgp_route.cc:61
bool HasPaths() const
Definition: bgp_route.h:28
const BgpRoute * src_rt() const
Definition: bgp_path.h:186
const BgpTable * src_table() const
Definition: bgp_path.h:182
ExtCommunityDB * extcomm_db()
Definition: bgp_server.h:193
RoutingInstanceMgr * routing_instance_mgr()
Definition: bgp_server.h:106
as_t autonomous_system() const
Definition: bgp_server.h:212
OriginVnPathDB * ovnpath_db()
Definition: bgp_server.h:195
BgpAttrDB * attr_db()
Definition: bgp_server.h:187
CommunityDB * comm_db()
Definition: bgp_server.h:190
BgpMembershipManager * membership_mgr()
Definition: bgp_server.h:179
LargeCommunityDB * largecomm_db()
Definition: bgp_server.h:194
BgpServer * server()
Definition: bgp_table.cc:87
RoutingInstance * routing_instance()
Definition: bgp_table.h:147
virtual Address::Family family() const =0
CommunityPtr AppendAndLocate(const Community *src, uint32_t value)
Definition: community.cc:133
bool ContainsValue(uint32_t value) const
Definition: community.cc:115
uint32_t num_matchstate() const
virtual std::string ToString() const =0
void ClearDelete()
Definition: db_entry.h:47
bool IsDeleted() const
Definition: db_entry.h:48
const std::string & name() const
Definition: db_table.h:110
void Notify(DBEntryBase *entry)
void Delete(DBEntryBase *)
virtual void Add(DBEntry *entry)
DBEntry * Find(const DBEntry *entry)
DBEntry * Find(const DBEntry *entry)
Definition: db_table.cc:495
virtual DBTablePartBase * GetTablePartition(const DBRequestKey *key)
Definition: db_table.cc:462
uint8_t type() const
static EvpnPrefix FromString(const std::string &str, boost::system::error_code *errorp=NULL)
Address::Family family() const
const EvpnPrefix & GetPrefix() const
ExtCommunityPtr AppendAndLocate(const ExtCommunity *src, const ExtCommunity::ExtCommunityList &list)
Definition: community.cc:765
ExtCommunityPtr RemoveSiteOfOriginAndLocate(const ExtCommunity *src)
Definition: community.cc:856
ExtCommunityPtr ReplaceSGIDListAndLocate(const ExtCommunity *src, const ExtCommunity::ExtCommunityList &sgid_list)
Definition: community.cc:826
ExtCommunityPtr ReplaceSiteOfOriginAndLocate(const ExtCommunity *src, const ExtCommunity::ExtCommunityValue &soo)
Definition: community.cc:869
ExtCommunityPtr ReplaceOriginVnAndLocate(const ExtCommunity *src, const ExtCommunity::ExtCommunityValue &origin_vn)
Definition: community.cc:953
ExtCommunityPtr ReplaceRTargetAndLocate(const ExtCommunity *src, const ExtCommunity::ExtCommunityList &export_list)
Definition: community.cc:812
std::vector< ExtCommunityValue > ExtCommunityList
Definition: community.h:155
boost::array< uint8_t, 8 > ExtCommunityValue
Definition: community.h:154
const ExtCommunityList & communities() const
Definition: community.h:182
static bool is_load_balance(const ExtCommunityValue &val)
Definition: community.h:374
static bool is_security_group(const ExtCommunityValue &val)
Definition: community.h:306
static bool is_origin_vn(const ExtCommunityValue &val)
Definition: community.h:195
static uint32_t get_rtarget_val(const ExtCommunityValue &val)
Definition: community.h:280
static bool is_site_of_origin(const ExtCommunityValue &val)
Definition: community.h:324
Definition: ipeer.h:186
virtual bool IsXmppPeer() const =0
virtual void UpdateServiceChainGroup(ServiceChainGroup *group)=0
virtual void UpdateServiceChain(RoutingInstance *rtinstance, bool group_oper_state_up)=0
virtual bool ServiceChainIsUp(RoutingInstance *rtinstance) const =0
Ip6Address addr() const
Definition: inet6_route.h:26
const Inet6Prefix & GetPrefix() const
Definition: inet6_route.h:80
const Ip4Prefix & GetPrefix() const
Definition: inet_route.h:70
Ip4Address addr() const
Definition: inet_route.h:24
This class represents a database for managing LargeCommunity objects. It is used to store,...
Definition: community.h:702
LargeCommunityPtr ReplaceTagListAndLocate(const LargeCommunity *src, const LargeCommunity::LargeCommunityList &tag_list)
Replace all tags in a LargeCommunity with a new tag list.
Definition: community.cc:1239
This class represents an array of BGP Large Community values. A LargeCommunity consists of one or mor...
Definition: community.h:556
const LargeCommunityList & communities() const
Get the list of Large Community values.
Definition: community.h:594
std::vector< LargeCommunityValue > LargeCommunityList
A list (vector) of LargeCommunityValue items.
Definition: community.h:562
static bool is_tag(const LargeCommunityValue &val)
Check if the LargeCommunity value is tag.
Definition: community.h:621
static bool IsPresent(const BgpPath *path)
const bytes_type & GetExtCommunity() const
Definition: load_balance.h:119
OriginVnPathPtr PrependAndLocate(const OriginVnPath *ovnpath, const OriginVnPath::OriginVnValue &value)
boost::array< uint8_t, 8 > OriginVnValue
bool Contains(const OriginVnValue &value) const
int vn_index() const
Definition: origin_vn.cc:122
const bytes_type & GetExtCommunity() const
Definition: origin_vn.h:33
uint16_t Type() const
Definition: rd.cc:44
uint32_t GetAddress() const
Definition: rd.cc:48
bool IsZero() const
Definition: rd.h:43
@ TypeIpAddressBased
Definition: rd.h:18
std::string ToString() const
const bytes_type & GetExtCommunity() const
const PathList & GetPathList() const
Definition: route.h:46
RoutingInstance * GetRoutingInstance(const std::string &name)
void UnregisterInstanceOpCallback(int id)
static std::string GetPrimaryRoutingInstanceName(const string &name_in)
int RegisterInstanceOpCallback(RoutingInstanceCb cb)
const std::string & name() const
bool deleted() const
int virtual_network_index() const
const BgpInstanceConfig * config() const
const RouteTargetList & GetExportList() const
BgpTable * GetTable(Address::Family fmly)
bool IsMasterRoutingInstance() const
ServiceChainGroup(IServiceChainMgr *manager, const std::string &name)
void DeleteRoutingInstance(RoutingInstance *rtinstance)
void AddRoutingInstance(RoutingInstance *rtinstance)
ServiceChainSet chain_set_
IServiceChainMgr * manager_
std::string name() const
DeleteActor(ServiceChainMgr< T > *manager)
ServiceChainMgr< T > * manager_
virtual bool MayDelete() const
BgpServer * server_
void UpdateServiceChainGroup(ServiceChainGroup *group)
virtual BgpConditionListener * GetListener()
void UpdateServiceChainRoutes(ServiceChainT *chain, const typename ServiceChainT::ConnectedPathIdList &old_path_ids)
void DeleteServiceChainRoutes(ServiceChainT *chain)
ServiceChainGroup * LocateServiceChainGroup(const std::string &group_name)
Address::Family GetConnectedFamily() const
SCAddress::Family GetSCFamily() const
virtual uint32_t GetDownServiceChainCount() const
virtual void StopServiceChain(RoutingInstance *rtinstance)
bool ProcessServiceChainGroups()
virtual void DisableGroupTrigger()
ServiceChainT * FindServiceChain(const std::string &instance) const
virtual void EnableGroupTrigger()
virtual void EnableResolveTrigger()
virtual bool LocateServiceChain(RoutingInstance *rtinstance, const ServiceChainConfig &config)
virtual ~ServiceChainMgr()
T::AddressT AddressT
ServiceChainGroup * FindServiceChainGroup(RoutingInstance *rtinstance)
void StopServiceChainDone(BgpTable *table, ConditionMatch *info)
ServiceChainMgr(BgpServer *server)
static int service_chain_task_id_
bool ResolvePendingServiceChain()
void RoutingInstanceCallback(std::string name, int op)
void Enqueue(ServiceChainRequestT *req)
bool RequestHandler(ServiceChainRequestT *req)
virtual void DisableResolveTrigger()
void PeerRegistrationCallback(IPeer *peer, BgpTable *table, bool unregister)
virtual void UpdateServiceChain(RoutingInstance *rtinstance, bool group_oper_state_up)
virtual bool FillServiceChainInfo(RoutingInstance *rtinstance, ShowServicechainInfo *info) const
boost::scoped_ptr< WorkQueue< ServiceChainRequestT * > > process_queue_
virtual bool ServiceChainIsPending(RoutingInstance *rtinstance, std::string *reason=NULL) const
virtual bool ServiceChainIsUp(RoutingInstance *rtinstance) const
Address::Family GetFamily() const
bool MayDelete() const
ServiceChainPtr info_
bool group_oper_state_up() const
const ConnectedPathIdList & GetConnectedPathIds()
SCAddress::Family GetSCFamily() const
bool dest_table_unregistered() const
bool IsEvpnType5Route(BgpRoute *route) const
virtual std::string ToString() const
void set_dest_table_unregistered()
PrefixToRouteListMap * prefix_to_route_list_map()
std::set< uint32_t > ConnectedPathIdList
bool AddMoreSpecific(PrefixT aggregate, BgpRoute *more_specific)
bool CompareServiceChainConfig(const ServiceChainConfig &config)
void DeleteServiceChainRouteInternal(BgpRoute *service_chain_route, DBTablePartition *partition, BgpTable *bgptable, bool aggregate)
void UpdateServiceChainRouteInternal(const RouteT *orig_route, const ConnectedPathIdList &old_path_ids, BgpRoute *sc_route, DBTablePartition *partition, BgpTable *bgptable, bool aggregate)
BgpRoute * connected_route() const
T::PrefixT PrefixT
void RemoveMatchState(BgpRoute *route, ServiceChainState *state)
T::RouteT RouteT
void UpdateServiceChainRoute(PrefixT prefix, const RouteT *orig_route, const ConnectedPathIdList &old_path_ids, bool aggregate)
PrefixToRouteListMap prefix_to_routelist_map_
bool unregistered() const
virtual bool Match(BgpServer *server, BgpTable *table, BgpRoute *route, bool deleted)
std::map< PrefixT, RouteList > PrefixToRouteListMap
void SetConnectedRoute(BgpRoute *connected)
T::AddressT AddressT
void FillServiceChainInfo(ShowServicechainInfo *info) const
bool DeleteMoreSpecific(PrefixT aggregate, BgpRoute *more_specific)
const ExtConnectRouteList & ext_connecting_routes() const
void ProcessServiceChainPath(uint32_t path_id, BgpPath *path, BgpAttrPtr attr, BgpRoute *&route, DBTablePartition *&partition, bool aggregate, BgpTable *bgptable)
BgpTable * dest_table() const
void set_group_oper_state_up(bool up)
void GetReplicationFamilyInfo(DBTablePartition *&partition, BgpRoute *&route, BgpTable *&table, PrefixT prefix, bool create)
BgpTable * connected_table() const
bool IsConnectedRoute(BgpRoute *route, bool is_conn_table=false) const
bool IsMoreSpecific(BgpRoute *route, PrefixT *aggregate_match) const
RoutingInstance * src_routing_instance() const
void set_connected_table_unregistered()
BgpTable * src_table() const
bool IsConnectedRouteValid() const
std::set< BgpRoute * > RouteList
ServiceChain(ServiceChainMgrT *manager, ServiceChainGroup *group, RoutingInstance *src, RoutingInstance *dest, RoutingInstance *connected, const std::vector< std::string > &subnets, AddressT addr, bool head, bool retain_as_path)
T::VpnRouteT VpnRouteT
bool IsAggregate(BgpRoute *route) const
ServiceChainGroup * group() const
Address::Family GetFamily() const
bool connected_table_unregistered() const
void DeleteServiceChainRoute(PrefixT prefix, bool aggregate)
void set_aggregate_enable()
const bytes_type & GetExtCommunity() const
bool IsNull() const
The TaskScheduler keeps track of what tasks are currently schedulable. When a task is enqueued it is ...
Definition: task.h:304
int GetTaskId(const std::string &name)
Definition: task.cc:861
static TaskScheduler * GetInstance()
Definition: task.cc:554
boost::intrusive_ptr< const LargeCommunity > LargeCommunityPtr
Defines a type for automatic storage of a LargeCommunity instance.
Definition: community.h:686
boost::intrusive_ptr< const Community > CommunityPtr
Definition: community.h:111
boost::intrusive_ptr< const ExtCommunity > ExtCommunityPtr
Definition: community.h:450
uint8_t type
Definition: load_balance.h:2
bool unit_test()
Definition: bgp_log.cc:53
static PhysicalDevice::ManagementProtocol FromString(const string &proto)
static int GetOriginVnIndex(const BgpTable *table, const BgpRoute *route)
ConditionMatchPtr ServiceChainPtr
std::vector< std::string > prefix
Definition: bgp_config.h:328
std::string source_routing_instance
Definition: bgp_config.h:331
std::string service_chain_id
Definition: bgp_config.h:332
std::string service_chain_address
Definition: bgp_config.h:329
std::string routing_instance
Definition: bgp_config.h:327
#define CHECK_CONCURRENCY(...)