Skip to content

Commit

Permalink
Schema transformer changes for Bgp as a service
Browse files Browse the repository at this point in the history
Added schema transformer changes and unit test cases for BGP as a service

Change-Id: Ia2739bdfcde9e161179463952d0f2cbec6653dca
Partial-Bug: 1518047
  • Loading branch information
Sachin Bansal committed Dec 5, 2015
1 parent 2560515 commit 5987bd2
Show file tree
Hide file tree
Showing 6 changed files with 253 additions and 7 deletions.
176 changes: 171 additions & 5 deletions src/config/schema-transformer/config_db.py
Expand Up @@ -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):
Expand All @@ -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():
Expand Down Expand Up @@ -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'
Expand All @@ -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()
Expand All @@ -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
Expand All @@ -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

Expand Down
16 changes: 16 additions & 0 deletions src/config/schema-transformer/db.py
Expand Up @@ -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):
Expand Down Expand Up @@ -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__
Expand Down Expand Up @@ -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)

49 changes: 49 additions & 0 deletions src/config/schema-transformer/test/test_service.py
Expand Up @@ -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():
Expand Down Expand Up @@ -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
15 changes: 13 additions & 2 deletions src/config/schema-transformer/to_bgp.py
Expand Up @@ -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'],
Expand Down Expand Up @@ -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': [],
},
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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:
Expand Down
3 changes: 3 additions & 0 deletions src/schema/bgp_schema.xsd
Expand Up @@ -20,6 +20,9 @@
Link('connection', 'routing-instance', 'routing-instance', ['ref']) -->
<!--#IFMAP-SEMANTICS-IDL
Link('instance-target', 'routing-instance', 'route-target', ['ref']) -->
<xsd:element name="bgpaas-bgp-router"/>
<!--#IFMAP-SEMANTICS-IDL
Link('bgpaas-bgp-router', 'bgp-as-a-service', 'bgp-router', ['ref']) -->

<xsd:element name="route-aggregate" type="ifmap:IdentityType"/>

Expand Down
1 change: 1 addition & 0 deletions src/schema/vnc_cfg.xsd
Expand Up @@ -1290,6 +1290,7 @@ targetNamespace="http://www.contrailsystems.com/2012/VNC-CONFIG/0">
<xsd:element name="bgp-as-a-service" type="ifmap:IdentityType"/>
<!--#IFMAP-SEMANTICS-IDL
Link('project-bgpaas', 'project', 'bgp-as-a-service', ['has']) -->
<xsd:element name="bgpaas-virtual-machine-interface"/>
<!--#IFMAP-SEMANTICS-IDL
Link('bgpaas-virtual-machine-interface', 'bgp-as-a-service',
'virtual-machine-interface', ['ref']) -->
Expand Down

0 comments on commit 5987bd2

Please sign in to comment.