OpenSDN source code
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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 = NULL;
819  const OriginVnPath *orig_ovnpath = NULL;
820  const AsPath *orig_aspath = NULL;
821  RouteDistinguisher orig_rd;
822  if (orig_route) {
823  const BgpPath *orig_path = orig_route->BestPath();
824  const BgpAttr *orig_attr = NULL;
825  const ExtCommunity *ext_community = NULL;
826  if (orig_path)
827  orig_attr = orig_path->GetAttr();
828  if (orig_attr) {
829  orig_community = orig_attr->community();
830  ext_community = orig_attr->ext_community();
831  orig_ovnpath = orig_attr->origin_vn_path();
832  orig_rd = orig_attr->source_rd();
833  orig_aspath = orig_attr->as_path();
834  }
835  if (ext_community) {
836  BOOST_FOREACH(const ExtCommunity::ExtCommunityValue &comm,
837  ext_community->communities()) {
839  sgid_list.push_back(comm);
840  if (ExtCommunity::is_tag(comm))
841  tag_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  }
851 
852  BgpAttrDB *attr_db = server->attr_db();
853  CommunityDB *comm_db = server->comm_db();
854  CommunityPtr new_community = comm_db->AppendAndLocate(
855  orig_community, CommunityType::AcceptOwnNexthop);
856  ExtCommunityDB *extcomm_db = server->extcomm_db();
857  BgpMembershipManager *membership_mgr = server->membership_mgr();
858  OriginVnPathDB *ovnpath_db = server->ovnpath_db();
859  OriginVnPathPtr new_ovnpath;
860  if (server->autonomous_system() > AS2_MAX && vn_index > 0xffff) {
861  new_ovnpath = ovnpath_db->PrependAndLocate(orig_ovnpath,
862  origin_vn4_bytes);
863  new_ovnpath = ovnpath_db->PrependAndLocate(new_ovnpath.get(),
864  origin_vn_trans_bytes);
865  } else {
866  new_ovnpath = ovnpath_db->PrependAndLocate(
867  orig_ovnpath, origin_vn_bytes);
868  }
869 
870  ConnectedPathIdList new_path_ids;
871  for (Route::PathList::iterator it =
872  connected_route()->GetPathList().begin();
873  it != connected_route()->GetPathList().end(); ++it) {
874  BgpPath *connected_path = static_cast<BgpPath *>(it.operator->());
875 
876  // Infeasible paths are not considered
877  if (!connected_path->IsFeasible())
878  break;
879 
880  // take snapshot of all ECMP paths
881  if (connected_route()->BestPath()->PathCompare(*connected_path, true))
882  break;
883 
884  // Skip paths with duplicate forwarding information. This ensures
885  // that we generate only one path with any given next hop and label
886  // when there are multiple connected paths from the original source
887  // received via different peers e.g. directly via XMPP and via BGP.
888  if (connected_route()->DuplicateForwardingPath(connected_path))
889  continue;
890 
891  const BgpAttr *attr = connected_path->GetAttr();
892 
893  ExtCommunityPtr new_ext_community;
894 
895  // Strip any RouteTargets from the connected attributes.
896  new_ext_community = extcomm_db->ReplaceRTargetAndLocate(
898 
899  // Add the export route target list from the source routing instance
900  // when inserting into EVPN table. This is required for the case when
901  // service-chain routes are replicated to the BGP table to be used on
902  // the BMS. The TOR switch does not import the cooked-up RT of the
903  // service-RI. It only imports the RTs of the primary RI. Hence, we
904  // add the primary RIs RTs to the route.
905  // NOTE: There is an assumption that connected_ri on the head SI
906  // will always point to the primary RI. Need to change that if the
907  // assumption is not true.
908  // Also, we pick only the export route targets in the range used by
909  // schema transformer for non user-configured RTs.
910  if (is_sc_head() && bgptable->family() == Address::EVPN) {
911  ExtCommunity::ExtCommunityList export_list;
912  const RoutingInstance *conn_ri =
915  connected_->name()));
916  if (!conn_ri) {
917  // conn_ri is not expected to be found only in unit tests.
918  assert(bgp_log_test::unit_test());
919  conn_ri = connected_routing_instance();
920  }
921  BGP_LOG_STR(BgpMessage, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_TRACE,
922  "Adding primary RI " << conn_ri->name() << " route targets " <<
923  "to service-chain route for EVPN table " << bgptable->name());
924  BOOST_FOREACH(const RouteTarget &rtarget,
925  conn_ri->GetExportList()) {
927  rtarget.GetExtCommunity()) != 0) {
928  BGP_LOG_STR(BgpMessage, SandeshLevel::SYS_DEBUG,
929  BGP_LOG_FLAG_TRACE, "RT value " << rtarget.ToString());
930  export_list.push_back(rtarget.GetExtCommunity());
931  }
932  }
933  new_ext_community = extcomm_db->AppendAndLocate(
934  new_ext_community.get(), export_list);
935  }
936 
937  // Replace the SGID list with the list from the original route.
938  new_ext_community = extcomm_db->ReplaceSGIDListAndLocate(
939  new_ext_community.get(), sgid_list);
940 
941  // Replace the Tag list with the list from the original route.
942  new_ext_community = extcomm_db->ReplaceTagListAndLocate(
943  new_ext_community.get(), tag_list);
944 
945  // Replace SiteOfOrigin with value from original route if any.
946  if (soo.IsNull()) {
947  new_ext_community = extcomm_db->RemoveSiteOfOriginAndLocate(
948  new_ext_community.get());
949  } else {
950  new_ext_community = extcomm_db->ReplaceSiteOfOriginAndLocate(
951  new_ext_community.get(), soo.GetExtCommunity());
952  }
953 
954  // Inherit load balance attribute of orig_route if connected path
955  // does not have one already.
956  if (!LoadBalance::IsPresent(connected_path) && load_balance_present) {
957  new_ext_community = extcomm_db->AppendAndLocate(
958  new_ext_community.get(), load_balance.GetExtCommunity());
959  }
960 
961  // Replace the OriginVn with the value from the original route
962  // or the value associated with the dest routing instance.
963  if (server->autonomous_system() > AS2_MAX && vn_index > 0xffff) {
964  new_ext_community = extcomm_db->ReplaceOriginVnAndLocate(
965  new_ext_community.get(), origin_vn4_bytes);
966  new_ext_community = extcomm_db->AppendAndLocate(
967  new_ext_community.get(), origin_vn_trans_bytes);
968  } else {
969  new_ext_community = extcomm_db->ReplaceOriginVnAndLocate(
970  new_ext_community.get(), origin_vn_bytes);
971  }
972 
973  // Connected routes always have mpls (udp or gre) as encap.
974  // If updating service-chain route in the EVPN table, change
975  // tunnel encap to include VxLAN and MPLS. BMS only supports VxLAN.
976  // Vrouter has the choice of using VxLAN or MPLS based on config.
977  if (is_sc_head() && bgptable->family() == Address::EVPN) {
978  ExtCommunity::ExtCommunityList encaps_list;
979  vector<string> tunnel_encaps = boost::assign::list_of("vxlan");
980  BOOST_FOREACH(string encap, tunnel_encaps) {
981  encaps_list.push_back(TunnelEncap(encap).GetExtCommunity());
982  }
983  new_ext_community = extcomm_db->
984  ReplaceTunnelEncapsulationAndLocate(new_ext_community.get(),
985  encaps_list);
986  }
987 
988  // Replace extended community, community and origin vn path.
989  BgpAttrPtr new_attr = attr_db->ReplaceExtCommunityAndLocate(
990  attr, new_ext_community);
991  new_attr =
992  attr_db->ReplaceCommunityAndLocate(new_attr.get(), new_community);
993  new_attr = attr_db->ReplaceOriginVnPathAndLocate(new_attr.get(),
994  new_ovnpath);
995 
996  // Strip as_path if needed. This is required when the connected route is
997  // learnt via BGP. If retain_as_path knob is configured replace the
998  // AsPath with the value from the original route.
999  if (retain_as_path() && orig_aspath) {
1000  new_attr = attr_db->ReplaceAsPathAndLocate(new_attr.get(),
1001  orig_aspath);
1002  } else {
1003  new_attr = attr_db->ReplaceAsPathAndLocate(new_attr.get(),
1004  AsPathPtr());
1005  }
1006 
1007  // If the connected path is learnt via XMPP, construct RD based on
1008  // the id registered with source table instead of connected table.
1009  // This allows chaining of multiple in-network service instances
1010  // that are on the same compute node.
1011  const IPeer *peer = connected_path->GetPeer();
1012  if (src_ != connected_ && peer && peer->IsXmppPeer()) {
1013  int instance_id = -1;
1014  bool is_registered = membership_mgr->GetRegistrationInfo(peer,
1015  bgptable, &instance_id);
1016  if (!is_registered)
1017  continue;
1018  RouteDistinguisher connected_rd = attr->source_rd();
1019  if (connected_rd.Type() != RouteDistinguisher::TypeIpAddressBased)
1020  continue;
1021 
1022  RouteDistinguisher rd(connected_rd.GetAddress(), instance_id);
1023  new_attr = attr_db->ReplaceSourceRdAndLocate(new_attr.get(), rd);
1024  }
1025 
1026  // Replace the source rd if the connected path is a secondary path
1027  // of a primary path in the l3vpn table. Use the RD of the primary.
1028  if (connected_path->IsReplicated()) {
1029  const BgpSecondaryPath *spath =
1030  static_cast<const BgpSecondaryPath *>(connected_path);
1031  const RoutingInstance *ri = spath->src_table()->routing_instance();
1032  if (ri->IsMasterRoutingInstance()) {
1033  const VpnRouteT *vpn_route =
1034  static_cast<const VpnRouteT *>(spath->src_rt());
1035  new_attr = attr_db->ReplaceSourceRdAndLocate(new_attr.get(),
1036  vpn_route->GetPrefix().route_distinguisher());
1037  }
1038  }
1039 
1040  // Skip paths with Source RD same as source RD of the connected path
1041  if (!orig_rd.IsZero() && new_attr->source_rd() == orig_rd)
1042  continue;
1043 
1044  // Check whether we already have a path with the associated path id.
1045  uint32_t path_id =
1046  connected_path->GetAttr()->nexthop().to_v4().to_ulong();
1047  ProcessServiceChainPath(path_id, connected_path, new_attr,
1048  service_chain_route, partition,
1049  aggregate, bgptable);
1050  new_path_ids.insert(path_id);
1051  }
1052 
1053  // Remove stale paths.
1054  for (ConnectedPathIdList::const_iterator it = old_path_ids.begin();
1055  it != old_path_ids.end(); ++it) {
1056  uint32_t path_id = *it;
1057  if (new_path_ids.find(path_id) != new_path_ids.end())
1058  continue;
1059  service_chain_route->RemovePath(BgpPath::ServiceChain, NULL, path_id);
1060  partition->Notify(service_chain_route);
1061 
1062  BGP_LOG_STR(BgpMessage, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_TRACE,
1063  "Removed " << (aggregate ? "Aggregate" : "ExtConnected") <<
1064  " ServiceChain path " << service_chain_route->ToString() <<
1065  " path_id " << BgpPath::PathIdString(path_id) <<
1066  " in table " << bgptable->name());
1067 
1068  }
1069 
1070  // Delete the route if there's no paths.
1071  if (!service_chain_route->HasPaths())
1072  partition->Delete(service_chain_route);
1073 }
1074 
1075 template <typename T>
1077  BgpRoute *more_specific) {
1078  typename PrefixToRouteListMap::iterator it =
1079  prefix_to_routelist_map_.find(aggregate);
1080  assert(it != prefix_to_routelist_map_.end());
1081  bool ret = false;
1082  if (it->second.empty()) {
1083  // Add the aggregate for the first time
1084  ret = true;
1085  }
1086  it->second.insert(more_specific);
1087  return ret;
1088 }
1089 
1090 template <typename T>
1092  BgpRoute *more_specific) {
1093  typename PrefixToRouteListMap::iterator it =
1094  prefix_to_routelist_map_.find(aggregate);
1095  assert(it != prefix_to_routelist_map_.end());
1096  it->second.erase(more_specific);
1097  return it->second.empty();
1098 }
1099 
1100 template <typename T>
1101 void ServiceChain<T>::FillServiceChainInfo(ShowServicechainInfo *info) const {
1102  if (deleted()) {
1103  info->set_state("deleted");
1104  } else if (!IsConnectedRouteValid()) {
1105  info->set_state("down");
1106  } else if (!group_oper_state_up()) {
1107  info->set_state("group down");
1108  } else {
1109  info->set_state("active");
1110  }
1111 
1112  ConnectedRouteInfo connected_rt_info;
1113  connected_rt_info.set_service_chain_addr(
1114  service_chain_addr().to_string());
1115  if (connected_route()) {
1116  ShowRoute show_route;
1117  connected_route()->FillRouteInfo(connected_table(), &show_route);
1118  connected_rt_info.set_connected_rt(show_route);
1119  }
1120  info->set_connected_route(connected_rt_info);
1121 
1122  vector<PrefixToRouteListInfo> more_vec;
1123  for (typename PrefixToRouteListMap::const_iterator it =
1124  prefix_to_route_list_map()->begin();
1125  it != prefix_to_route_list_map()->end(); ++it) {
1126  PrefixToRouteListInfo prefix_list_info;
1127  prefix_list_info.set_prefix(it->first.ToString());
1128 
1129  BgpTable *bgptable = src_table();
1130  RouteT rt_key(it->first);
1131  BgpRoute *aggregate = static_cast<BgpRoute *>(bgptable->Find(&rt_key));
1132  if (aggregate) {
1133  prefix_list_info.set_aggregate(true);
1134  ShowRoute show_route;
1135  aggregate->FillRouteInfo(bgptable, &show_route);
1136  prefix_list_info.set_aggregate_rt(show_route);
1137  } else {
1138  prefix_list_info.set_aggregate(false);
1139  }
1140 
1141  vector<string> rt_list;
1142  for (RouteList::iterator rt_it = it->second.begin();
1143  rt_it != it->second.end(); ++rt_it) {
1144  rt_list.push_back((*rt_it)->ToString());
1145  }
1146  prefix_list_info.set_more_specific_list(rt_list);
1147  more_vec.push_back(prefix_list_info);
1148  }
1149  info->set_more_specifics(more_vec);
1150 
1151  vector<ExtConnectRouteInfo> ext_connecting_rt_info_list;
1152  for (ExtConnectRouteList::const_iterator it =
1153  ext_connecting_routes().begin();
1154  it != ext_connecting_routes().end(); ++it) {
1155  ExtConnectRouteInfo ext_rt_info;
1156  ext_rt_info.set_ext_rt_prefix((*it)->ToString());
1157  BgpTable *bgptable = src_table();
1158  RouteT *ext_route = static_cast<RouteT *>(*it);
1159  RouteT rt_key(ext_route->GetPrefix());
1160  BgpRoute *ext_connecting =
1161  static_cast<BgpRoute *>(bgptable->Find(&rt_key));
1162  if (ext_connecting) {
1163  ShowRoute show_route;
1164  ext_connecting->FillRouteInfo(bgptable, &show_route);
1165  ext_rt_info.set_ext_rt_svc_rt(show_route);
1166  }
1167  ext_connecting_rt_info_list.push_back(ext_rt_info);
1168  }
1169  info->set_ext_connecting_rt_info_list(ext_connecting_rt_info_list);
1170  info->set_aggregate_enable(aggregate_enable());
1171 }
1172 
1174  const string &name)
1175  : manager_(manager),
1176  name_(name),
1177  oper_state_up_(false) {
1178 }
1179 
1181  assert(chain_set_.empty());
1182 }
1183 
1184 //
1185 // Add a RoutingInstance to this ServiceChainGroup.
1186 // The caller must ensure that multiple bgp::ConfigHelper tasks do not
1187 // invoke this method in parallel.
1188 //
1190  CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
1191  chain_set_.insert(rtinstance);
1193 }
1194 
1195 //
1196 // Delete a RoutingInstance from this ServiceChainGroup.
1197 // The caller must ensure that multiple bgp::ConfigHelper tasks do not
1198 // invoke this method in parallel.
1199 //
1201  CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
1202  chain_set_.erase(rtinstance);
1204 }
1205 
1206 //
1207 // Update the operational state of this ServiceChainGroup.
1208 // It's considered to be up if all ServiceChains in the ServiceChainGroup
1209 // are up.
1210 // Trigger an update on the operational state of each ServiceChain if the
1211 // operational state of the ServiceChainGroup changed.
1212 //
1214  bool old_oper_state_up = oper_state_up_;
1215  oper_state_up_ = true;
1216  BOOST_FOREACH(RoutingInstance *rtinstance, chain_set_) {
1217  if (manager_->ServiceChainIsUp(rtinstance))
1218  continue;
1219  oper_state_up_ = false;
1220  break;
1221  }
1222 
1223  if (old_oper_state_up == oper_state_up_)
1224  return;
1225 
1226  BOOST_FOREACH(RoutingInstance *rtinstance, chain_set_) {
1228  }
1229 }
1230 
1239 template <typename T>
1241  return server_->condition_listener(GetSCFamily());
1242 }
1243 
1244 template <typename T>
1246  CHECK_CONCURRENCY("bgp::ServiceChain");
1247  BgpTable *table = NULL;
1248  BgpRoute *route = NULL;
1249  PrefixT aggregate_match = req->aggregate_match_;
1250  ServiceChainT *info = NULL;
1251 
1252  table = req->table_;
1253  route = req->rt_;
1254  info = static_cast<ServiceChainT *>(req->info_.get());
1255 
1256  // Table where the aggregate route needs to be added
1257  aggregate_match = req->aggregate_match_;
1258 
1259  ServiceChainState *state = NULL;
1260  if (route) {
1261  state = static_cast<ServiceChainState *>
1262  (listener_->GetMatchState(table, route, info));
1263  }
1264 
1265  switch (req->type_) {
1266  case ServiceChainRequestT::MORE_SPECIFIC_ADD_CHG: {
1267  assert(state);
1268  if (state->deleted()) {
1269  state->reset_deleted();
1270  }
1271  if (!info->AddMoreSpecific(aggregate_match, route))
1272  break;
1273  if (!info->IsConnectedRouteValid())
1274  break;
1275  if (!info->group_oper_state_up())
1276  break;
1277 
1278  typename ServiceChainT::ConnectedPathIdList path_ids;
1280  aggregate_match, NULL, path_ids, true);
1281  break;
1282  }
1283  case ServiceChainRequestT::MORE_SPECIFIC_DELETE: {
1284  assert(state);
1285  if (info->DeleteMoreSpecific(aggregate_match, route)) {
1286  // Delete the aggregate route
1287  info->DeleteServiceChainRoute(aggregate_match, true);
1288  }
1289  info->RemoveMatchState(route, state);
1290  break;
1291  }
1292  case ServiceChainRequestT::CONNECTED_ROUTE_ADD_CHG: {
1293  assert(state);
1294  if (route->IsDeleted() || !route->BestPath() ||
1295  !route->BestPath()->IsFeasible()) {
1296  break;
1297  }
1298  UpdateServiceChainGroup(info->group());
1299 
1300  if (state->deleted()) {
1301  state->reset_deleted();
1302  }
1303 
1304  // Store the old path id list and populate the new one.
1305  typename ServiceChainT::ConnectedPathIdList path_ids =
1306  info->GetConnectedPathIds();
1307  info->SetConnectedRoute(route);
1308 
1309  if (!info->group_oper_state_up())
1310  break;
1311 
1312  UpdateServiceChainRoutes(info, path_ids);
1313  break;
1314  }
1315  case ServiceChainRequestT::CONNECTED_ROUTE_DELETE: {
1316  assert(state);
1317  UpdateServiceChainGroup(info->group());
1318  DeleteServiceChainRoutes(info);
1319  info->RemoveMatchState(route, state);
1320  info->SetConnectedRoute(NULL);
1321  break;
1322  }
1323  case ServiceChainRequestT::EXT_CONNECT_ROUTE_ADD_CHG: {
1324  assert(state);
1325  if (state->deleted()) {
1326  state->reset_deleted();
1327  }
1328  info->ext_connecting_routes()->insert(route);
1329  if (!info->IsConnectedRouteValid())
1330  break;
1331  if (!info->group_oper_state_up())
1332  break;
1333  RouteT *ext_route = dynamic_cast<RouteT *>(route);
1334  typename ServiceChainT::ConnectedPathIdList path_ids;
1336  ext_route->GetPrefix(), ext_route, path_ids, false);
1337  break;
1338  }
1339  case ServiceChainRequestT::EXT_CONNECT_ROUTE_DELETE: {
1340  assert(state);
1341  if (info->ext_connecting_routes()->erase(route)) {
1342  RouteT *inet_route = dynamic_cast<RouteT *>(route);
1343  info->DeleteServiceChainRoute(inet_route->GetPrefix(), false);
1344  }
1345  info->RemoveMatchState(route, state);
1346  break;
1347  }
1348  case ServiceChainRequestT::UPDATE_ALL_ROUTES: {
1349  if (info->dest_table_unregistered())
1350  break;
1351  if (info->connected_table_unregistered())
1352  break;
1353  if (!info->connected_route())
1354  break;
1355  if (!info->group_oper_state_up())
1356  break;
1357 
1358  typename ServiceChainT::ConnectedPathIdList path_ids =
1359  info->GetConnectedPathIds();
1360  UpdateServiceChainRoutes(info, path_ids);
1361  break;
1362  }
1363  case ServiceChainRequestT::DELETE_ALL_ROUTES: {
1364  DeleteServiceChainRoutes(info);
1365  break;
1366  }
1367  case ServiceChainRequestT::STOP_CHAIN_DONE: {
1368  if (table == info->connected_table()) {
1370  if (!info->num_matchstate()) {
1371  listener_->UnregisterMatchCondition(table, info);
1372  }
1373  }
1374  if (table == info->dest_table()) {
1376  if (!info->num_matchstate()) {
1377  listener_->UnregisterMatchCondition(table, info);
1378  }
1379  }
1380  if (info->unregistered()) {
1381  chain_set_.erase(info->src_routing_instance());
1382  StartResolve();
1383  }
1384  RetryDelete();
1385  break;
1386  }
1387  default: {
1388  assert(false);
1389  break;
1390  }
1391  }
1392 
1393  if (state) {
1394  state->DecrementRefCnt();
1395  if (state->refcnt() == 0 && state->deleted()) {
1396  listener_->RemoveMatchState(table, route, info);
1397  delete state;
1398  if (!info->num_matchstate()) {
1399  if (info->dest_table_unregistered()) {
1400  listener_->UnregisterMatchCondition(
1401  info->dest_table(), info);
1402  }
1403  if (info->connected_table_unregistered()) {
1404  listener_->UnregisterMatchCondition(
1405  info->connected_table(), info);
1406  }
1407  if (info->unregistered()) {
1408  chain_set_.erase(info->src_routing_instance());
1409  StartResolve();
1410  }
1411  }
1412  }
1413  }
1414  delete req;
1415  return true;
1416 }
1417 
1418 template <typename T>
1420  : server_(server),
1421  listener_(GetListener()),
1422  resolve_trigger_(new TaskTrigger(
1423  bind(&ServiceChainMgr::ResolvePendingServiceChain, this),
1424  TaskScheduler::GetInstance()->GetTaskId("bgp::Config"), 0)),
1425  group_trigger_(new TaskTrigger(
1426  bind(&ServiceChainMgr::ProcessServiceChainGroups, this),
1427  TaskScheduler::GetInstance()->GetTaskId("bgp::ServiceChain"), 0)),
1428  aggregate_host_route_(false),
1429  deleter_(new DeleteActor(this)),
1430  server_delete_ref_(this, server->deleter()) {
1431  if (service_chain_task_id_ == -1) {
1433  service_chain_task_id_ = scheduler->GetTaskId("bgp::ServiceChain");
1434  }
1435 
1436  process_queue_.reset(
1438  bind(&ServiceChainMgr::RequestHandler, this, _1)));
1439 
1441  bind(&ServiceChainMgr::RoutingInstanceCallback, this, _1, _2));
1442 
1443  BgpMembershipManager *membership_mgr = server->membership_mgr();
1445  bind(&ServiceChainMgr::PeerRegistrationCallback, this, _1, _2, _3));
1446 }
1447 
1448 template <typename T>
1450  assert(group_set_.empty());
1451  assert(group_map_.empty());
1452 }
1453 
1454 template <typename T>
1456  process_queue_->Shutdown();
1457  RoutingInstanceMgr *ri_mgr = server_->routing_instance_mgr();
1458  ri_mgr->UnregisterInstanceOpCallback(id_);
1459  BgpMembershipManager *membership_mgr = server_->membership_mgr();
1460  membership_mgr->UnregisterPeerRegistrationCallback(registration_id_);
1461  server_delete_ref_.Reset(NULL);
1462 }
1463 
1464 template <typename T>
1466  deleter_->Delete();
1467 }
1468 
1469 template <typename T>
1471  if (!chain_set_.empty() || !pending_chains_.empty())
1472  return false;
1473  if (!group_set_.empty() || !group_map_.empty())
1474  return false;
1475  return true;
1476 }
1477 
1478 template <typename T>
1480  if (!deleter_->IsDeleted())
1481  return;
1482  deleter_->RetryDelete();
1483 }
1484 
1485 template <typename T>
1487  RoutingInstance *rtinstance) {
1488  if (ServiceChainIsPending(rtinstance)) {
1489  PendingChainState state = GetPendingServiceChain(rtinstance);
1490  return state.group;
1491  } else {
1492  const ServiceChain<T> *chain = FindServiceChain(rtinstance);
1493  return (chain ? chain->group() : NULL);
1494  }
1495 }
1496 
1497 template <typename T>
1499  const string &group_name) {
1500  GroupMap::iterator loc = group_map_.find(group_name);
1501  return (loc != group_map_.end() ? loc->second : NULL);
1502 }
1503 
1504 template <typename T>
1506  const string &group_name) {
1507  CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
1508 
1509  GroupMap::iterator loc = group_map_.find(group_name);
1510  ServiceChainGroup *group = (loc != group_map_.end()) ? loc->second : NULL;
1511  if (!group) {
1512  string temp_group_name(group_name);
1513  group = new ServiceChainGroup(this, temp_group_name);
1514  group_map_.insert(temp_group_name, group);
1515  }
1516  return group;
1517 }
1518 
1519 template <typename T>
1521  CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper", "bgp::ServiceChain");
1522 
1523  if (!group)
1524  return;
1525  group_set_.insert(group);
1526  group_trigger_->Set();
1527 }
1528 
1529 template <typename T>
1531  CHECK_CONCURRENCY("bgp::ServiceChain");
1532 
1533  BOOST_FOREACH(ServiceChainGroup *group, group_set_) {
1534  if (group->empty()) {
1535  string temp_group_name(group->name());
1536  group_map_.erase(temp_group_name);
1537  } else {
1538  group->UpdateOperState();
1539  }
1540  }
1541 
1542  group_set_.clear();
1543  RetryDelete();
1544  return true;
1545 }
1546 
1550 template <>
1552  return Address::INET;
1553 }
1554 
1555 template <>
1557  return Address::INET6;
1558 }
1559 
1560 template <>
1562  return Address::EVPN;
1563 }
1564 
1565 template <>
1567  return Address::EVPN;
1568 }
1569 
1573 template <>
1575  return Address::INET;
1576 }
1577 
1578 template <>
1580  return Address::INET6;
1581 }
1582 
1583 template <>
1585  return Address::INET;
1586 }
1587 
1588 template <>
1590  return Address::INET6;
1591 }
1592 
1596 template <>
1598  return SCAddress::INET;
1599 }
1600 
1601 template <>
1603  return SCAddress::INET6;
1604 }
1605 
1606 template <>
1608  return SCAddress::EVPN;
1609 }
1610 
1611 template <>
1613  return SCAddress::EVPN6;
1614 }
1615 
1616 template <>
1617 template <typename T>
1619  process_queue_->Enqueue(req);
1620 }
1621 
1622 template <typename T>
1624  string *reason) const {
1625  typename PendingChainList::const_iterator loc =
1626  pending_chains_.find(rtinstance);
1627  if (loc != pending_chains_.end()) {
1628  if (reason)
1629  *reason = loc->second.reason;
1630  return true;
1631  }
1632  return false;
1633 }
1634 
1635 template <typename T>
1637  if (ServiceChainIsPending(rtinstance))
1638  return false;
1639  const ServiceChain<T> *service_chain = FindServiceChain(rtinstance);
1640  if (!service_chain)
1641  return false;
1642  return service_chain->IsConnectedRouteValid();
1643 }
1644 
1645 template <typename T>
1647  ShowServicechainInfo *info) const {
1648  string pending_reason;
1649  if (ServiceChainIsPending(rtinstance, &pending_reason)) {
1650  info->set_state("pending");
1651  info->set_pending_reason(pending_reason);
1652  return true;
1653  }
1654  const ServiceChain<T> *service_chain = FindServiceChain(rtinstance);
1655  if (!service_chain)
1656  return false;
1657  service_chain->FillServiceChainInfo(info);
1658  return true;
1659 }
1660 
1661 
1662 
1663 template <typename T>
1665  const ServiceChainConfig &config) {
1666  CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
1667 
1668  // Verify whether the entry already exists.
1669  tbb::mutex::scoped_lock lock(mutex_);
1670  ServiceChainMap::iterator it = chain_set_.find(rtinstance);
1671  if (it != chain_set_.end()) {
1672  ServiceChainT *chain = static_cast<ServiceChainT *>(it->second.get());
1673  if (chain->CompareServiceChainConfig(config)) {
1674  BGP_LOG_STR(BgpMessage, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_TRACE,
1675  "No update in ServiceChain config : " << rtinstance->name());
1676  return true;
1677  }
1678 
1679  ServiceChainGroup *group = chain->group();
1680  if (group) {
1681  group->DeleteRoutingInstance(rtinstance);
1682  chain->clear_group();
1683  }
1684 
1685  // Update of ServiceChainConfig.
1686  // Add the routing instance to pending list so that service chain is
1687  // created after stop done callback for the current incarnation gets
1688  // invoked.
1689  if (config.service_chain_id.empty()) {
1690  group = NULL;
1691  } else {
1692  group = LocateServiceChainGroup(config.service_chain_id);
1693  group->AddRoutingInstance(rtinstance);
1694  }
1695  string reason = "Waiting for deletion of previous incarnation";
1696  AddPendingServiceChain(rtinstance, group, reason);
1697 
1698  // Wait for the delete complete callback.
1699  if (chain->deleted())
1700  return false;
1701 
1703  bind(&ServiceChainMgr::StopServiceChainDone, this, _1, _2);
1704  listener_->RemoveMatchCondition(chain->dest_table(), chain, cb);
1705  listener_->RemoveMatchCondition(chain->connected_table(), chain, cb);
1706  return true;
1707  }
1708 
1709  RoutingInstanceMgr *mgr = server_->routing_instance_mgr();
1711 
1712  // Dissociate from the old ServiceChainGroup.
1713  ServiceChainGroup *group = FindServiceChainGroup(rtinstance);
1714  if (group)
1715  group->DeleteRoutingInstance(rtinstance);
1716 
1717  // Delete from the pending list. The instance would already have been
1718  // removed from the pending list if this method is called when trying
1719  // to resolve items in the pending list. However, if this method is
1720  // called when processing a change in the service chain config, then
1721  // we may need to remove it from the pending list.
1722  DeletePendingServiceChain(rtinstance);
1723 
1724  // Locate the new ServiceChainGroup.
1725  if (config.service_chain_id.empty()) {
1726  group = NULL;
1727  } else {
1728  group = LocateServiceChainGroup(config.service_chain_id);
1729  group->AddRoutingInstance(rtinstance);
1730  }
1731 
1732  // Destination routing instance does not exist.
1733  if (!dest) {
1734  string reason = "Destination routing instance does not exist";
1735  AddPendingServiceChain(rtinstance, group, reason);
1736  return false;
1737  }
1738 
1739  // Destination routing instance is being deleted.
1740  if (dest->deleted()) {
1741  string reason = "Destination routing instance is being deleted";
1742  AddPendingServiceChain(rtinstance, group, reason);
1743  return false;
1744  }
1745 
1746  // Destination virtual network index is unknown.
1747  if (!dest->virtual_network_index()) {
1748  string reason = "Destination virtual network index is unknown";
1749  AddPendingServiceChain(rtinstance, group, reason);
1750  return false;
1751  }
1752 
1753  RoutingInstance *connected_ri = NULL;
1754  if (config.source_routing_instance == "") {
1755  connected_ri = rtinstance;
1756  assert(!rtinstance->deleted());
1757  } else {
1758  connected_ri = mgr->GetRoutingInstance(config.source_routing_instance);
1759  }
1760 
1761  // Connected routing instance does not exist.
1762  if (!connected_ri) {
1763  string reason = "Connected routing instance does not exist";
1764  AddPendingServiceChain(rtinstance, group, reason);
1765  return false;
1766  }
1767 
1768  // Connected routing instance is being deleted.
1769  if (connected_ri->deleted()) {
1770  string reason = "Connected routing instance is being deleted";
1771  AddPendingServiceChain(rtinstance, group, reason);
1772  return false;
1773  }
1774 
1775  // Add to pending queue if the service chain address is invalid.
1776  error_code ec;
1777  AddressT chain_addr =
1778  AddressT::from_string(config.service_chain_address, ec);
1779  if (ec.failed()) {
1780  string reason = "Service chain address is invalid";
1781  AddPendingServiceChain(rtinstance, group, reason);
1782  return false;
1783  }
1784 
1790  BgpTable *connected_table = NULL;
1791  connected_table = connected_ri->GetTable(GetConnectedFamily());
1792  assert(connected_table);
1793  BgpTable *dest_table = dest->GetTable(GetFamily());
1794  assert(dest_table);
1795 
1796  // Allocate the new service chain.
1797  ServiceChainPtr chain = ServiceChainPtr(new ServiceChainT(this, group,
1798  rtinstance, dest, connected_ri, config.prefix, chain_addr,
1799  config.sc_head, config.retain_as_path));
1800 
1801  if (aggregate_host_route()) {
1802  ServiceChainT *obj = static_cast<ServiceChainT *>(chain.get());
1803  obj->set_aggregate_enable();
1804  }
1805 
1806  // Add the new service chain request
1807  chain_set_.insert(make_pair(rtinstance, chain));
1808  listener_->AddMatchCondition(
1809  connected_table, chain.get(), BgpConditionListener::RequestDoneCb());
1810  listener_->AddMatchCondition(
1811  dest_table, chain.get(), BgpConditionListener::RequestDoneCb());
1812 
1813  return true;
1814 }
1815 
1816 template <typename T>
1818  const string &instance) const {
1819  RoutingInstance *rtinstance =
1820  server_->routing_instance_mgr()->GetRoutingInstance(instance);
1821  if (!rtinstance)
1822  return NULL;
1823  ServiceChainMap::const_iterator it = chain_set_.find(rtinstance);
1824  if (it == chain_set_.end())
1825  return NULL;
1826  ServiceChainT *chain = static_cast<ServiceChainT *>(it->second.get());
1827  return chain;
1828 }
1829 
1830 template <typename T>
1832  RoutingInstance *rtinstance) const {
1833  ServiceChainMap::const_iterator it = chain_set_.find(rtinstance);
1834  if (it == chain_set_.end())
1835  return NULL;
1836  ServiceChainT *chain = static_cast<ServiceChainT *>(it->second.get());
1837  return chain;
1838 }
1839 
1840 template <typename T>
1842  CHECK_CONCURRENCY("bgp::Config");
1843  for (typename PendingChainList::iterator it = pending_chains_.begin(), next;
1844  it != pending_chains_.end(); it = next) {
1845  next = it;
1846  ++next;
1847  RoutingInstance *rtinstance = it->first;
1848  ServiceChainGroup *group = it->second.group;
1849  if (group)
1850  group->DeleteRoutingInstance(rtinstance);
1851  pending_chains_.erase(it);
1852  const ServiceChainConfig *sc_config =
1853  rtinstance->config()->service_chain_info(GetSCFamily());
1854  if (sc_config)
1855  LocateServiceChain(rtinstance, *sc_config);
1856  }
1857  RetryDelete();
1858  return true;
1859 }
1860 
1861 template <typename T>
1864  StartResolve();
1865 }
1866 
1867 template <typename T>
1869  if (pending_chains_.empty())
1870  return;
1871  resolve_trigger_->Set();
1872 }
1873 
1874 template <typename T>
1876  ConditionMatch *info) {
1877  // Post the RequestDone event to ServiceChain task to take Action
1878  ServiceChainRequestT *req =
1879  new ServiceChainRequestT(ServiceChainRequestT::STOP_CHAIN_DONE, table,
1880  NULL, PrefixT(), ServiceChainPtr(info));
1881  Enqueue(req);
1882  return;
1883 }
1884 
1885 template <typename T>
1887  CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
1888 
1889  // Remove the routing instance from pending chains list.
1890  tbb::mutex::scoped_lock lock(mutex_);
1891  if (ServiceChainIsPending(rtinstance)) {
1892  ServiceChainGroup *group = FindServiceChainGroup(rtinstance);
1893  if (group)
1894  group->DeleteRoutingInstance(rtinstance);
1895  DeletePendingServiceChain(rtinstance);
1896  RetryDelete();
1897  }
1898 
1899  ServiceChainT *chain = FindServiceChain(rtinstance);
1900  if (!chain)
1901  return;
1902 
1903  ServiceChainGroup *group = chain->group();
1904  if (group) {
1905  group->DeleteRoutingInstance(rtinstance);
1906  chain->clear_group();
1907  }
1908 
1909  if (chain->deleted())
1910  return;
1911 
1913  bind(&ServiceChainMgr::StopServiceChainDone, this, _1, _2);
1914  listener_->RemoveMatchCondition(chain->dest_table(), chain, cb);
1915  listener_->RemoveMatchCondition(chain->connected_table(), chain, cb);
1916 }
1917 
1918 template <typename T>
1920  bool group_oper_state_up) {
1921  // Bail if there's no service chain for the instance.
1922  ServiceChainT *chain = FindServiceChain(rtinstance);
1923  if (!chain)
1924  return;
1925 
1926  // Update the state in the service chain.
1927  chain->set_group_oper_state_up(group_oper_state_up);
1928 
1929  // Post event to ServiceChain task to update/delete all routes.
1930  typename ServiceChainRequestT::RequestType req_type;
1931  if (group_oper_state_up) {
1932  req_type = ServiceChainRequestT::UPDATE_ALL_ROUTES;
1933  } else {
1934  req_type = ServiceChainRequestT::DELETE_ALL_ROUTES;
1935  }
1937  req_type, NULL, NULL, PrefixT(), ServiceChainPtr(chain));
1938  Enqueue(req);
1939 }
1940 
1941 template <typename T>
1943  const typename ServiceChainT::ConnectedPathIdList &old_path_ids) {
1944  // Update ServiceChain routes for aggregates.
1945  typename ServiceChainT::PrefixToRouteListMap *vn_prefix_list =
1946  chain->prefix_to_route_list_map();
1947  for (typename ServiceChainT::PrefixToRouteListMap::iterator it =
1948  vn_prefix_list->begin(); it != vn_prefix_list->end(); ++it) {
1949  if (!it->second.empty())
1950  chain->UpdateServiceChainRoute(it->first, NULL, old_path_ids, true);
1951  }
1952 
1953  // Update ServiceChain routes for external connecting routes.
1954  for (typename ServiceChainT::ExtConnectRouteList::iterator it =
1955  chain->ext_connecting_routes()->begin();
1956  it != chain->ext_connecting_routes()->end(); ++it) {
1957  RouteT *ext_route = static_cast<RouteT *>(*it);
1958  chain->UpdateServiceChainRoute(
1959  ext_route->GetPrefix(), ext_route, old_path_ids, false);
1960  }
1961 }
1962 
1963 template <typename T>
1965  // Delete ServiceChain routes for aggregates.
1966  typename ServiceChainT::PrefixToRouteListMap *vn_prefix_list =
1967  chain->prefix_to_route_list_map();
1968  for (typename ServiceChainT::PrefixToRouteListMap::iterator it =
1969  vn_prefix_list->begin(); it != vn_prefix_list->end(); ++it) {
1970  chain->DeleteServiceChainRoute(it->first, true);
1971  }
1972 
1973  // Delete ServiceChain routes for external connecting routes.
1974  for (typename ServiceChainT::ExtConnectRouteList::iterator it =
1975  chain->ext_connecting_routes()->begin();
1976  it != chain->ext_connecting_routes()->end(); ++it) {
1977  RouteT *ext_route = static_cast<RouteT *>(*it);
1978  chain->DeleteServiceChainRoute(ext_route->GetPrefix(), false);
1979  }
1980 }
1981 
1982 template <typename T>
1984  bool unregister) {
1985  CHECK_CONCURRENCY("bgp::PeerMembership");
1986 
1987  // Bail if it's not an XMPP peer.
1988  if (!peer->IsXmppPeer())
1989  return;
1990 
1991  // Bail if there's no service chain for the instance.
1992  ServiceChainT *chain = FindServiceChain(table->routing_instance());
1993  if (!chain)
1994  return;
1995 
1996  // Post event to ServiceChain task to update all routes.
1997  ServiceChainRequestT *req =
1998  new ServiceChainRequestT(ServiceChainRequestT::UPDATE_ALL_ROUTES, NULL,
1999  NULL, PrefixT(), ServiceChainPtr(chain));
2000  Enqueue(req);
2001 }
2002 
2003 template <typename T>
2005  resolve_trigger_->set_disable();
2006 }
2007 
2008 template <typename T>
2010  resolve_trigger_->set_enable();
2011 }
2012 
2013 template <typename T>
2015  group_trigger_->set_disable();
2016 }
2017 
2018 template <typename T>
2020  group_trigger_->set_enable();
2021 }
2022 
2023 template <typename T>
2025  uint32_t count = 0;
2026  for (ServiceChainMap::const_iterator it = chain_set_.begin();
2027  it != chain_set_.end(); ++it) {
2028  const ServiceChainT *chain =
2029  static_cast<const ServiceChainT *>(it->second.get());
2030  if (!chain->IsConnectedRouteValid())
2031  count++;
2032  }
2033  return count;
2034 }
2035 
2036 // Explicit instantiation of ServiceChainMgr for INET and INET6.
2037 template class ServiceChainMgr<ServiceChainInet>;
2038 template class ServiceChainMgr<ServiceChainInet6>;
2039 template class ServiceChainMgr<ServiceChainEvpn>;
2040 template class ServiceChainMgr<ServiceChainEvpn6>;
void FillRouteInfo(const BgpTable *table, ShowRouteBrief *show_route) const
Definition: bgp_route.cc:432
bool AddMoreSpecific(PrefixT aggregate, BgpRoute *more_specific)
const Community * community() const
Definition: bgp_attr.h:914
boost::intrusive_ptr< const AsPath > AsPathPtr
Definition: bgp_aspath.h:165
ExtCommunityPtr RemoveSiteOfOriginAndLocate(const ExtCommunity *src)
Definition: community.cc:787
boost::scoped_ptr< WorkQueue< ServiceChainRequestT * > > process_queue_
ExtCommunityPtr ReplaceSGIDListAndLocate(const ExtCommunity *src, const ExtCommunity::ExtCommunityList &sgid_list)
Definition: community.cc:757
virtual void EnableGroupTrigger()
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)
ServiceChainGroup(IServiceChainMgr *manager, const std::string &name)
ExtCommunityPtr AppendAndLocate(const ExtCommunity *src, const ExtCommunity::ExtCommunityList &list)
Definition: community.cc:696
ServiceChainT * FindServiceChain(const std::string &instance) const
ExtCommunityPtr ReplaceOriginVnAndLocate(const ExtCommunity *src, const ExtCommunity::ExtCommunityValue &origin_vn)
Definition: community.cc:884
ServiceChainMgr< T > * manager_
void Enqueue(ServiceChainRequestT *req)
std::set< BgpRoute * > RouteList
boost::array< uint8_t, 8 > ExtCommunityValue
Definition: community.h:152
const IpAddress & nexthop() const
Definition: bgp_attr.h:886
BgpTable * GetTable(Address::Family fmly)
Ip4Address addr() const
Definition: inet_route.h:24
void PeerRegistrationCallback(IPeer *peer, BgpTable *table, bool unregister)
bool dest_table_unregistered() const
const BgpPath * BestPath() const
Definition: bgp_route.cc:46
int RegisterInstanceOpCallback(RoutingInstanceCb cb)
The TaskScheduler keeps track of what tasks are currently schedulable. When a task is enqueued it is ...
Definition: task.h:178
const RouteTargetList & GetExportList() const
T::RouteT RouteT
RoutingInstance * GetRoutingInstance(const std::string &name)
void set_group_oper_state_up(bool up)
virtual bool MayDelete() const
bool IsNull() const
virtual void StopServiceChain(RoutingInstance *rtinstance)
virtual bool IsXmppPeer() const =0
void GetReplicationFamilyInfo(DBTablePartition *&partition, BgpRoute *&route, BgpTable *&table, PrefixT prefix, bool create)
const ExtConnectRouteList & ext_connecting_routes() const
int virtual_network_index() const
void UpdateServiceChainRoute(PrefixT prefix, const RouteT *orig_route, const ConnectedPathIdList &old_path_ids, bool aggregate)
boost::function< void(BgpTable *, ConditionMatch *)> RequestDoneCb
BgpAttrPtr ReplaceCommunityAndLocate(const BgpAttr *attr, CommunityPtr community)
Definition: bgp_attr.cc:1314
static bool is_security_group(const ExtCommunityValue &val)
Definition: community.h:304
virtual std::string ToString() const
DBEntry * Find(const DBEntry *entry)
bool IsConnectedRouteValid() const
static std::string PathIdString(uint32_t path_id)
Definition: bgp_path.cc:18
virtual bool ServiceChainIsPending(RoutingInstance *rtinstance, std::string *reason=NULL) const
const ConnectedPathIdList & GetConnectedPathIds()
BgpRoute * connected_route() const
BgpTable * connected_table() const
void FillServiceChainInfo(ShowServicechainInfo *info) const
ConditionMatchState * GetMatchState(BgpTable *table, BgpRoute *route, ConditionMatch *obj)
RoutingInstance * routing_instance()
Definition: bgp_table.h:148
Family
Definition: address.h:24
bool IsDeleted() const
Definition: db_entry.h:49
OriginVnPathPtr PrependAndLocate(const OriginVnPath *ovnpath, const OriginVnPath::OriginVnValue &value)
CommunityDB * comm_db()
Definition: bgp_server.h:184
virtual void UpdateServiceChain(RoutingInstance *rtinstance, bool group_oper_state_up)
std::string name() const
boost::asio::ip::address IpAddress
Definition: address.h:13
DeleteActor(ServiceChainMgr< T > *manager)
static std::string GetPrimaryRoutingInstanceName(const string &name_in)
bool unregistered() const
RoutingInstanceMgr * routing_instance_mgr()
Definition: bgp_server.h:102
const OriginVnPath * origin_vn_path() const
Definition: bgp_attr.h:916
void RemoveMatchState(BgpRoute *route, ServiceChainState *state)
virtual void DisableGroupTrigger()
BgpTable * dest_table() const
RoutingInstance * src_routing_instance() const
const std::string & name() const
ServiceChainSet chain_set_
virtual uint32_t GetDownServiceChainCount() const
const BgpPath * FindPath(BgpPath::PathSource src) const
Definition: bgp_route.cc:145
int vxlan_id() const
bool IsMoreSpecific(BgpRoute *route, PrefixT *aggregate_match) const
static bool is_site_of_origin(const ExtCommunityValue &val)
Definition: community.h:322
uint16_t Type() const
Definition: rd.cc:44
virtual void UpdateServiceChain(RoutingInstance *rtinstance, bool group_oper_state_up)=0
void Delete(DBEntryBase *)
const RouteDistinguisher & source_rd() const
Definition: bgp_attr.h:896
virtual Address::Family family() const =0
uint32_t GetFlags() const
Definition: bgp_path.h:100
Definition: ipeer.h:186
static bool IsPresent(const BgpPath *path)
virtual void UpdateServiceChainGroup(ServiceChainGroup *group)=0
bool GetRegistrationInfo(const IPeer *peer, const BgpTable *table, int *instance_id=NULL, uint64_t *subscription_gen_id=NULL) const
OriginVnPathDB * ovnpath_db()
Definition: bgp_server.h:188
BgpAttrPtr ReplaceExtCommunityAndLocate(const BgpAttr *attr, ExtCommunityPtr extcomm)
Definition: bgp_attr.cc:1330
int GetTaskId(const std::string &name)
Definition: task.cc:856
const bytes_type & GetExtCommunity() const
ServiceChainGroup * LocateServiceChainGroup(const std::string &group_name)
#define BGP_LOG_STR(obj, level, flags, arg)
Definition: bgp_log.h:89
ServiceChainMgr(BgpServer *server)
bool IsEvpnType5Route(BgpRoute *route) const
boost::intrusive_ptr< const OriginVnPath > OriginVnPathPtr
ServiceChainGroup * FindServiceChainGroup(RoutingInstance *rtinstance)
void StopServiceChainDone(BgpTable *table, ConditionMatch *info)
boost::intrusive_ptr< const BgpAttr > BgpAttrPtr
Definition: bgp_attr.h:991
PrefixToRouteListMap prefix_to_routelist_map_
T::AddressT AddressT
bool IsFeasible() const
Definition: bgp_path.h:92
bool IsAggregate(BgpRoute *route) const
void set_aggregate_enable()
void set_dest_table_unregistered()
PathSource GetSource() const
Definition: bgp_path.h:103
uint8_t type
Definition: load_balance.h:109
bool connected_table_unregistered() const
bool MayDelete() const
SCAddress::Family GetSCFamily() const
void DeleteRoutingInstance(RoutingInstance *rtinstance)
bool unit_test()
Definition: bgp_log.cc:53
const ServiceChainConfig * service_chain_info(SCAddress::Family family) const
Definition: bgp_config.cc:379
const ExtCommunityList & communities() const
Definition: community.h:180
ExtCommunityDB * extcomm_db()
Definition: bgp_server.h:187
std::vector< std::string > prefix
Definition: bgp_config.h:328
static TaskScheduler * GetInstance()
Definition: task.cc:547
Ip6Address addr() const
Definition: inet6_route.h:26
virtual void DisableResolveTrigger()
CommunityPtr AppendAndLocate(const Community *src, uint32_t value)
Definition: community.cc:131
virtual bool FillServiceChainInfo(RoutingInstance *rtinstance, ShowServicechainInfo *info) const
boost::intrusive_ptr< const ExtCommunity > ExtCommunityPtr
Definition: community.h:448
T::PrefixT PrefixT
static int GetOriginVnIndex(const BgpTable *table, const BgpRoute *route)
void UnregisterPeerRegistrationCallback(int id)
bool ContainsValue(uint32_t value) const
Definition: community.cc:113
uint8_t type() const
std::string routing_instance
Definition: bgp_config.h:327
#define CHECK_CONCURRENCY(...)
virtual BgpConditionListener * GetListener()
void SetMatchState(BgpTable *table, BgpRoute *route, ConditionMatch *obj, ConditionMatchState *state=NULL)
void UpdateServiceChainRouteInternal(const RouteT *orig_route, const ConnectedPathIdList &old_path_ids, BgpRoute *sc_route, DBTablePartition *partition, BgpTable *bgptable, bool aggregate)
virtual std::string ToString() const =0
PrefixToRouteListMap * prefix_to_route_list_map()
bool RequestHandler(ServiceChainRequestT *req)
IPeer * GetPeer()
Definition: bgp_path.h:76
BgpAttrPtr ReplaceSourceRdAndLocate(const BgpAttr *attr, const RouteDistinguisher &source_rd)
Definition: bgp_attr.cc:1362
const BgpInstanceConfig * config() const
bool IsVrfOriginated() const
Definition: bgp_path.h:68
BgpTable * src_table() const
virtual bool ServiceChainIsUp(RoutingInstance *rtinstance) const
const std::string & name() const
Definition: db_table.h:110
ServiceChainGroup * group() const
void ProcessServiceChainPath(uint32_t path_id, BgpPath *path, BgpAttrPtr attr, BgpRoute *&route, DBTablePartition *&partition, bool aggregate, BgpTable *bgptable)
std::string source_routing_instance
Definition: bgp_config.h:331
void ClearDelete()
Definition: db_entry.h:48
virtual bool LocateServiceChain(RoutingInstance *rtinstance, const ServiceChainConfig &config)
uint32_t GetLabel() const
Definition: bgp_path.h:89
const Ip4Prefix & GetPrefix() const
Definition: inet_route.h:70
void RoutingInstanceCallback(std::string name, int op)
void UnregisterInstanceOpCallback(int id)
boost::intrusive_ptr< const Community > CommunityPtr
Definition: community.h:109
const AsPath * as_path() const
Definition: bgp_attr.h:899
const bytes_type & GetExtCommunity() const
Definition: load_balance.h:119
void UpdateServiceChainGroup(ServiceChainGroup *group)
void InsertPath(BgpPath *path)
Definition: bgp_route.cc:60
void UpdateServiceChainRoutes(ServiceChainT *chain, const typename ServiceChainT::ConnectedPathIdList &old_path_ids)
virtual void EnableResolveTrigger()
virtual DBTablePartBase * GetTablePartition(const DBRequestKey *key)
Definition: db_table.cc:436
BgpServer * server()
Definition: bgp_table.cc:88
bool RemovePath(BgpPath::PathSource src, const IPeer *peer=NULL, uint32_t path_id=0)
Definition: bgp_route.cc:262
const EvpnPrefix & GetPrefix() const
ExtCommunityPtr ReplaceSiteOfOriginAndLocate(const ExtCommunity *src, const ExtCommunity::ExtCommunityValue &soo)
Definition: community.cc:800
static EvpnPrefix FromString(const std::string &str, boost::system::error_code *errorp=NULL)
ExtCommunityPtr ReplaceTagListAndLocate(const ExtCommunity *src, const ExtCommunity::ExtCommunityList &tag_list)
Definition: community.cc:772
bool IsMasterRoutingInstance() const
const ExtCommunity * ext_community() const
Definition: bgp_attr.h:915
void DeleteServiceChainRoutes(ServiceChainT *chain)
BgpAttrPtr ReplaceAsPathAndLocate(const BgpAttr *attr, AsPathPtr aspath)
Definition: bgp_attr.cc:1306
uint32_t GetAddress() const
Definition: rd.cc:48
int vn_index() const
Definition: origin_vn.cc:122
const BgpRoute * src_rt() const
Definition: bgp_path.h:186
#define BGP_LOG_FLAG_TRACE
Definition: bgp_log.h:43
BgpAttrDB * attr_db()
Definition: bgp_server.h:181
bool ResolvePendingServiceChain()
bool IsConnectedRoute(BgpRoute *route, bool is_conn_table=false) const
std::map< PrefixT, RouteList > PrefixToRouteListMap
std::vector< ExtCommunityValue > ExtCommunityList
Definition: community.h:153
static bool is_tag(const ExtCommunityValue &val)
Definition: community.h:378
bool HasPaths() const
Definition: bgp_route.h:27
const BgpAttr * GetAttr() const
Definition: bgp_path.h:87
Address::Family GetFamily() const
bool CompareServiceChainConfig(const ServiceChainConfig &config)
DBEntry * Find(const DBEntry *entry)
Definition: db_table.cc:469
std::string ToString() const
ServiceChainPtr info_
ConditionMatchPtr ServiceChainPtr
bool Contains(const OriginVnValue &value) const
void DeleteServiceChainRouteInternal(BgpRoute *service_chain_route, DBTablePartition *partition, BgpTable *bgptable, bool aggregate)
SCAddress::Family GetSCFamily() const
BgpMembershipManager * membership_mgr()
Definition: bgp_server.h:173
IServiceChainMgr * manager_
bool group_oper_state_up() const
virtual bool Match(BgpServer *server, BgpTable *table, BgpRoute *route, bool deleted)
Address::Family GetFamily() const
virtual void Add(DBEntry *entry)
T::AddressT AddressT
const Inet6Prefix & GetPrefix() const
Definition: inet6_route.h:80
const BgpTable * src_table() const
Definition: bgp_path.h:182
virtual bool ServiceChainIsUp(RoutingInstance *rtinstance) const =0
void Notify(DBEntryBase *entry)
bool empty() const
bool IsZero() const
Definition: rd.h:43
void AddRoutingInstance(RoutingInstance *rtinstance)
bool ProcessServiceChainGroups()
bool deleted() const
static uint32_t get_rtarget_val(const ExtCommunityValue &val)
Definition: community.h:278
uint32_t num_matchstate() const
const bytes_type & GetExtCommunity() const
BgpServer * server_
Address::Family GetConnectedFamily() const
boost::array< uint8_t, 8 > OriginVnValue
virtual bool IsReplicated() const
Definition: bgp_path.h:91
std::string service_chain_address
Definition: bgp_config.h:329
as_t autonomous_system() const
Definition: bgp_server.h:205
#define AS_TRANS
Definition: bgp_common.h:23
std::set< uint32_t > ConnectedPathIdList
BgpAttrPtr ReplaceOriginVnPathAndLocate(const BgpAttr *attr, OriginVnPathPtr ovnpath)
Definition: bgp_attr.cc:1338
int RegisterPeerRegistrationCallback(PeerRegistrationCallback callback)
static PhysicalDevice::ManagementProtocol FromString(const string &proto)
ExtCommunityPtr ReplaceRTargetAndLocate(const ExtCommunity *src, const ExtCommunity::ExtCommunityList &export_list)
Definition: community.cc:743
void SetConnectedRoute(BgpRoute *connected)
virtual bool IsValid() const
Definition: bgp_route.cc:338
void set_connected_table_unregistered()
bool DeleteMoreSpecific(PrefixT aggregate, BgpRoute *more_specific)
Address::Family family() const
std::string service_chain_id
Definition: bgp_config.h:332
const PathList & GetPathList() const
Definition: route.h:46
#define AS2_MAX
Definition: bgp_common.h:24
static bool is_load_balance(const ExtCommunityValue &val)
Definition: community.h:372
T::VpnRouteT VpnRouteT
void DeleteServiceChainRoute(PrefixT prefix, bool aggregate)
static bool is_origin_vn(const ExtCommunityValue &val)
Definition: community.h:193
virtual ~ServiceChainMgr()