diff --git a/src/config/schema-transformer/config_db.py b/src/config/schema-transformer/config_db.py
index 1ebb7bb9f89..6c378bfe29f 100644
--- a/src/config/schema-transformer/config_db.py
+++ b/src/config/schema-transformer/config_db.py
@@ -2495,21 +2495,33 @@ class BgpRouterST(DBBaseST):
def __init__(self, name, obj=None):
self.name = name
self.asn = None
+ self.bgp_as_a_service = None
self.update(obj)
# end __init__
def update(self, obj=None):
self.obj = obj or self.read_vnc_obj(fq_name=self.name)
self.set_params(self.obj.get_bgp_router_parameters())
+ self.update_single_ref('bgp_as_a_service', self.obj)
# end update
+ def delete_obj(self):
+ self.update_single_ref('bgp_as_a_service', {})
+ if self.router_type == 'bgpaas-client':
+ self._cassandra.free_bgpaas_port(self.source_port)
+ # end delete_ref
+
def set_params(self, params):
self.vendor = (params.vendor or 'contrail').lower()
self.identifier = params.identifier
- if self.vendor == 'contrail':
- self.update_global_asn(GlobalSystemConfigST.get_autonomous_system())
- else:
- self.update_autonomous_system(params.autonomous_system)
+ self.router_type = params.router_type
+ self.source_port = params.source_port
+ if self.router_type not in ('bgpaas-client', 'bgpaas-server'):
+ if self.vendor == 'contrail':
+ self.update_global_asn(
+ GlobalSystemConfigST.get_autonomous_system())
+ else:
+ self.update_autonomous_system(params.autonomous_system)
# end set_params
def update_global_asn(self, asn):
@@ -2531,7 +2543,62 @@ def update_autonomous_system(self, asn):
# end update_autonomous_system
def evaluate(self):
- self.update_peering()
+ if self.router_type == 'bgpaas-client':
+ bgpaas = BgpAsAServiceST.get(self.bgp_as_a_service)
+ ret = self.update_bgpaas_client(bgpaas)
+ if ret == -1:
+ if bgpaas:
+ bgpaas.obj.del_bgp_router(self.obj)
+ try:
+ self._vnc_lib.bgp_as_a_service_update(bgpaas.obj)
+ except NoIdError:
+ pass
+ self._vnc_lib.bgp_router_delete(id=self.obj.uuid)
+ elif ret:
+ self._vnc_lib.bgp_router_update(self.obj)
+ elif self.router_type != 'bgpaas-server':
+ self.update_peering()
+ # end evaluate
+
+ def update_bgpaas_client(self, bgpaas):
+ if not bgpaas:
+ return -1
+ for vmi_name, router in bgpaas.bgpaas_clients.items():
+ if router == self.name:
+ break
+ else:
+ return -1
+ if vmi_name not in bgpaas.virtual_machine_interfaces:
+ del bgpaas.bgpaas_clients[vmi_name]
+ return -1
+ vmi = VirtualMachineInterfaceST.get(vmi_name)
+ if vmi is None or vmi.virtual_network is None:
+ del bgpaas.bgpaas_clients[vmi_name]
+ return -1
+ vn = VirtualNetworkST.get(vmi.virtual_network)
+ if not vn or self.obj.get_parent_fq_name_str() != vn._default_ri_name:
+ del bgpaas.bgpaas_clients[vmi_name]
+ return -1
+ update = False
+ params = self.obj.get_bgp_router_parameters()
+ if self.asn != bgpaas.asn:
+ params.autonomous_system = bgpaas.asn
+ self.asn = bgpaas.asn
+ update = True
+ if params.address != bgpaas.ip_address:
+ params.address = bgpaas.ip_address
+ update = True
+ if params.identifier != bgpaas.ip_address:
+ params.identifier = bgpaas.ip_address
+ update = True
+ router_refs = self.obj.get_bgp_router_refs()
+ peering_attribs = router_refs[0]['attr']
+ if peering_attribs != bgpaas.peering_attribs:
+ self.obj.set_bgp_router_list([router_refs[0]['to']],
+ [bgpaas.peering_attribs])
+ update = True
+ return update
+ # end update_bgpaas_client
def update_peering(self):
if not GlobalSystemConfigST.get_ibgp_auto_mesh():
@@ -2582,6 +2649,102 @@ def handle_st_object_req(self):
# end class BgpRouterST
+class BgpAsAServiceST(DBBaseST):
+ _dict = {}
+ obj_type = 'bgp_as_a_service'
+
+ def __init__(self, name, obj=None):
+ self.name = name
+ self.obj = obj or self.read_vnc_obj(fq_name=name)
+ self.virtual_machine_interfaces = set()
+ self.bgp_routers = set()
+ self.bgpaas_clients = {}
+ self.update(self.obj)
+ # end __init__
+
+ def update(self, obj=None):
+ self.obj = obj or self.read_vnc_obj(fq_name=self.name)
+ self.ip_address = self.obj.get_bgpaas_ip_address()
+ self.asn = self.obj.get_autonomous_system()
+ session_attrib = self.obj.get_bgpaas_session_attributes()
+ bgp_session = BgpSession()
+ if session_attrib:
+ bgp_session.attributes=[self.session_attrib]
+ self.peering_attribs = BgpPeeringAttributes(session=[bgp_session])
+ self.update_multiple_refs('virtual_machine_interface', self.obj)
+ self.update_multiple_refs('bgp_router', self.obj)
+ # end update
+
+ def delete_obj(self):
+ self.update_multiple_refs('virtual_machine_interface', {})
+ self.update_multiple_refs('bgp_router', {})
+ # end delete_obj
+
+ def evaluate(self):
+ for name in (self.virtual_machine_interfaces -
+ set(self.bgpaas_clients.keys())):
+ self.create_bgp_router(name)
+ # end evaluate
+
+ def create_bgp_router(self, name):
+ vmi = VirtualMachineInterfaceST.get(name)
+ if not vmi:
+ self.virtual_machine_interfaces.discard(name)
+ return
+ vn = VirtualNetworkST.get(vmi.virtual_network)
+ if not vn:
+ return
+ ri = vn.get_primary_routing_instance()
+ if not ri:
+ return
+ router_fq_name = ri.obj.get_fq_name_str() + ':' + vmi.obj.name
+ if router_fq_name in BgpRouterST:
+ self.bgp_routers.add(router_fq_name)
+ self.bgpaas_clients[name] = router_fq_name
+ return
+ server_fq_name = ri.obj.get_fq_name_str() + ':bgpaas-server'
+ server_router = BgpRouterST.get(server_fq_name)
+ if not server_router:
+ server_router = BgpRouter('bgpaas-server', parent_obj=ri.obj)
+ params = BgpRouterParams(router_type='bgpaas-server')
+ server_router.set_bgp_router_parameters(params)
+ self._vnc_lib.bgp_router_create(server_router)
+ BgpRouterST.locate(server_fq_name, server_router)
+ else:
+ server_router = server_router.obj
+ bgp_router = BgpRouter(vmi.obj.name, parent_obj=ri.obj)
+ params = BgpRouterParams(
+ autonomous_system=self.asn,
+ ip_address=self.ip_address,
+ identifier=self.ip_address,
+ source_port=self._cassandra.alloc_bgpaas_port(router_fq_name),
+ router_type='bgpaas-client')
+ bgp_router.set_bgp_router_parameters(params)
+ bgp_router.set_bgp_router(server_router, self.peering_attribs)
+ self._vnc_lib.bgp_router_create(bgp_router)
+ bgpr = BgpRouterST.locate(router_fq_name, bgp_router)
+ self.obj.add_bgp_router(bgp_router)
+ self._vnc_lib.bgp_as_a_service_update(self.obj)
+ self.bgp_routers.add(router_fq_name)
+ bgpr.bgp_as_a_service = self.name
+ self.bgpaas_clients[name] = router_fq_name
+ # end create_bgp_router
+
+ def handle_st_object_req(self):
+ resp = DBBaseST.handle_st_object_req()
+ resp.obj_refs = [
+ sandesh.RefsList('virtual_machine_interface',
+ self.virtual_machine_interfaces),
+ sandesh.RefsList('bgp_router', self.bgp_routers)
+ ]
+ resp.properties = [
+ sandesh.PropList('ip_address', self.ip_address),
+ sandesh.PropList('asn', self.asn)
+ ]
+ return resp
+ # end handle_st_object_req
+# end class BgpAsAService
+
class VirtualMachineInterfaceST(DBBaseST):
_dict = {}
obj_type = 'virtual_machine_interface'
@@ -2593,6 +2756,7 @@ def __init__(self, name, obj=None):
self.virtual_network = None
self.virtual_machine = None
self.logical_router = None
+ self.bgp_as_a_service = None
self.uuid = None
self.instance_ips = set()
self.floating_ips = set()
@@ -2614,6 +2778,7 @@ def update(self, obj=None):
else:
self.update_single_ref('virtual_machine', self.obj)
self.update_single_ref('logical_router', self.obj)
+ self.update_single_ref('bgp_as_a_service', self.obj)
self.set_properties()
self.update_routing_instances(self.obj.get_routing_instance_refs())
# end update
@@ -2624,6 +2789,7 @@ def delete_obj(self):
self.update_single_ref('logical_router', {})
self.update_multiple_refs('instance_ip', {})
self.update_multiple_refs('floating_ip', {})
+ self.update_multiple_refs('bgp_as_a_service', {})
self.update_routing_instances([])
# end delete_obj
diff --git a/src/config/schema-transformer/db.py b/src/config/schema-transformer/db.py
index 5d72cf137de..4f14989c66b 100644
--- a/src/config/schema-transformer/db.py
+++ b/src/config/schema-transformer/db.py
@@ -35,6 +35,7 @@ class SchemaTransformerDB(VncCassandraClient):
_SERVICE_CHAIN_MAX_VLAN = 4093
_SERVICE_CHAIN_VLAN_ALLOC_PATH = "/id/service-chain/vlan/"
+ _BGPAAS_PORT_ALLOC_PATH = "/id/bgpaas/port/"
@classmethod
def get_db_info(cls):
@@ -99,6 +100,11 @@ def __init__(self, manager, zkclient):
zkclient, self._zk_path_pfx+self._BGP_RTGT_ALLOC_PATH,
self._BGP_RTGT_MAX_ID, common.BGP_RTGT_MIN_ID)
+ self._bgpaas_port_allocator = IndexAllocator(
+ zkclient, self._zk_path_pfx + self._BGPAAS_PORT_ALLOC_PATH,
+ self._args.bgpaas_port_end - self._args.bgpaas_port_start,
+ self._args.bgpaas_port_start)
+
self._sc_vlan_allocator_dict = {}
self._upgrade_vlan_alloc_path()
# end __init__
@@ -260,3 +266,13 @@ def alloc_vn_id(self, name):
def free_vn_id(self, vn_id):
self._vn_id_allocator.delete(vn_id)
+
+ def get_bgpaas_port(self, port):
+ return self._bgpaas_allocator.read(port)
+
+ def alloc_bgpaas_port(self, name):
+ return self._bgpaas_port_allocator.alloc(name)
+
+ def free_bgpaas_port(self, port):
+ self._bgpaas_port_allocator.delete(port)
+
diff --git a/src/config/schema-transformer/test/test_service.py b/src/config/schema-transformer/test/test_service.py
index aa2355797ae..21b6b7aed5a 100644
--- a/src/config/schema-transformer/test/test_service.py
+++ b/src/config/schema-transformer/test/test_service.py
@@ -238,6 +238,16 @@ def check_ri_is_present(self, fq_name):
def check_link_in_ifmap_graph(self, fq_name_str, links):
self._vnc_lib.routing_instance_read(fq_name)
+ @retries(5)
+ def wait_to_get_object(self, obj_class, obj_name):
+ if obj_name not in obj_class._dict:
+ raise Exception('%s not found' % obj_name)
+
+ @retries(5)
+ def wait_to_delete_object(self, obj_class, obj_name):
+ if obj_name in obj_class._dict:
+ raise Exception('%s still found' % obj_name)
+
@retries(5)
def wait_to_get_sc(self, left_vn=None, right_vn=None):
for sc in to_bgp.ServiceChain.values():
@@ -2157,4 +2167,43 @@ def test_misc(self):
#end test_misc
+ def test_bgpaas(self):
+ # create vn1
+ vn1_name = self.id() + 'vn1'
+ vn1_obj = self.create_virtual_network(vn1_name, '10.0.0.0/24')
+
+ project_name = ['default-domain', 'default-project']
+ project_obj = self._vnc_lib.project_read(fq_name=project_name)
+ port_name = self.id() + 'p1'
+ port_obj = VirtualMachineInterface(port_name, parent_obj=project_obj)
+ port_obj.add_virtual_network(vn1_obj)
+ self._vnc_lib.virtual_machine_interface_create(port_obj)
+
+ bgpaas_name = self.id() + 'bgp1'
+ bgpaas = BgpAsAService(bgpaas_name, parent_obj=project_obj)
+ bgpaas.add_virtual_machine_interface(port_obj)
+ self._vnc_lib.bgp_as_a_service_create(bgpaas)
+
+ self.wait_to_get_object(config_db.BgpAsAServiceST,
+ bgpaas.get_fq_name_str())
+ self.wait_to_get_object(config_db.BgpRouterST,
+ vn1_obj.get_fq_name_str() + ':' + vn1_name + ':' + port_name)
+
+ port2_name = self.id() + 'p2'
+ port2_obj = VirtualMachineInterface(port2_name, parent_obj=project_obj)
+ port2_obj.add_virtual_network(vn1_obj)
+ self._vnc_lib.virtual_machine_interface_create(port2_obj)
+ bgpaas.add_virtual_machine_interface(port2_obj)
+ self._vnc_lib.bgp_as_a_service_update(bgpaas)
+ self.wait_to_get_object(config_db.BgpRouterST,
+ vn1_obj.get_fq_name_str() + ':' + vn1_name + ':' + port2_name)
+
+ bgpaas.del_virtual_machine_interface(port_obj)
+ self._vnc_lib.bgp_as_a_service_update(bgpaas)
+ self.wait_to_delete_object(config_db.BgpRouterST,
+ vn1_obj.get_fq_name_str() + ':' + vn1_name + ':' + port_name)
+ self._vnc_lib.bgp_as_a_service_delete(id=bgpaas.uuid)
+ self.wait_to_delete_object(config_db.BgpRouterST,
+ vn1_obj.get_fq_name_str() + ':' + vn1_name + ':' + port2_name)
+ # end test_bgpaas
# end class TestRouteTable
diff --git a/src/config/schema-transformer/to_bgp.py b/src/config/schema-transformer/to_bgp.py
index f396f9d5526..9cd683f7dc0 100644
--- a/src/config/schema-transformer/to_bgp.py
+++ b/src/config/schema-transformer/to_bgp.py
@@ -65,12 +65,13 @@ class SchemaTransformer(object):
'self': ['virtual_network'],
},
'virtual_machine_interface': {
- 'self': ['virtual_machine', 'virtual_network'],
- 'virtual_network': ['virtual_machine'],
+ 'self': ['virtual_machine', 'virtual_network', 'bgp_as_a_service'],
+ 'virtual_network': ['virtual_machine', 'bgp_as_a_service'],
'logical_router': ['virtual_network'],
'instance_ip': ['virtual_machine'],
'floating_ip': ['virtual_machine'],
'virtual_machine': [],
+ 'bgp_as_a_service': [],
},
'virtual_network': {
'self': ['network_policy'],
@@ -112,6 +113,10 @@ class SchemaTransformer(object):
'instance_ip': {
'self': ['virtual_machine_interface'],
},
+ 'bgp_as_a_service': {
+ 'self': ['bgp_router'],
+ 'virtual_machine)interface': ['bgp_router']
+ },
'bgp_router': {
'self': [],
},
@@ -605,6 +610,8 @@ def parse_args(args_str):
'logging_conf': '',
'logger_class': None,
'sandesh_send_rate_limit': SandeshSystem.get_sandesh_send_rate_limit(),
+ 'bgpaas_port_start': '50000',
+ 'bgpaas_port_end': '50256',
}
secopts = {
'use_certs': False,
@@ -717,6 +724,10 @@ def parse_args(args_str):
parser.add_argument("--rabbit_password", help="password for rabbit")
parser.add_argument("--rabbit_ha_mode", action='store_true',
help="True if the rabbitmq cluster is mirroring all queue")
+ parser.add_argument("--bgpaas_port_start",
+ help="Start port for bgp-as-a-service proxy")
+ parser.add_argument("--bgpaas_port_end",
+ help="End port for bgp-as-a-service proxy")
args = parser.parse_args(remaining_argv)
if type(args.cassandra_server_list) is str:
diff --git a/src/schema/bgp_schema.xsd b/src/schema/bgp_schema.xsd
index 68fec9282ef..26e811260fe 100644
--- a/src/schema/bgp_schema.xsd
+++ b/src/schema/bgp_schema.xsd
@@ -20,6 +20,9 @@
Link('connection', 'routing-instance', 'routing-instance', ['ref']) -->
+
+
diff --git a/src/schema/vnc_cfg.xsd b/src/schema/vnc_cfg.xsd
index 74b437eb21b..ae346c0e085 100644
--- a/src/schema/vnc_cfg.xsd
+++ b/src/schema/vnc_cfg.xsd
@@ -1290,6 +1290,7 @@ targetNamespace="http://www.contrailsystems.com/2012/VNC-CONFIG/0">
+