diff --git a/src/config/api-server/tests/test_crud_basic.py b/src/config/api-server/tests/test_crud_basic.py index 7ab4075d6df..3e0452c8792 100644 --- a/src/config/api-server/tests/test_crud_basic.py +++ b/src/config/api-server/tests/test_crud_basic.py @@ -415,6 +415,49 @@ def test_physical_router_credentials(self): if user_cred_read.password != '**Password Hidden**': raise Exception("ERROR: physical-router: password should be hidden") #end test_physical_router_credentials + + def test_bridge_domain_with_vmi_ref_multiple_bd(self): + vn1_name = self.id() + '-vn-1' + vn1 = VirtualNetwork(vn1_name) + logger.info('Creating VN %s', vn1_name) + self._vnc_lib.virtual_network_create(vn1) + + vmi_name = self.id() + '-port' + logger.info('Creating port %s', vmi_name) + vmi = VirtualMachineInterface(vmi_name, parent_obj=Project()) + vmi.add_virtual_network(vn1) + self._vnc_lib.virtual_machine_interface_create(vmi) + + bd1_name = self.id() + '-bd-1' + bd1 = BridgeDomain(bd1_name, parent_obj=vn1) + bd1.set_isid(200200) + logger.info('Creating Bridge Domain %s', bd1_name) + self._vnc_lib.bridge_domain_create(bd1) + + bd2_name = self.id() + '-bd-2' + bd2 = BridgeDomain(bd2_name, parent_obj=vn1) + bd2.set_isid(300300) + logger.info('Creating Bridge Domain %s', bd2_name) + self._vnc_lib.bridge_domain_create(bd2) + + bd_ref_data1 = BridgeDomainMembershipType(); + bd_ref_data1.set_vlan_tag(0); + + # VMI is referring to two bridge domain(bd1 and bd2) for vlan tag = 0 + vmi.add_bridge_domain(bd1, bd_ref_data1); + vmi.add_bridge_domain(bd2, bd_ref_data1); + with ExpectedException(BadRequest) as e: + self._vnc_lib.virtual_machine_interface_update(vmi) + + # Link the VMI to two bridge domain for different vlan tags(0, 1) + vmi_obj = self._vnc_lib.virtual_machine_interface_read(id=vmi.uuid) + bd_ref_data1 = BridgeDomainMembershipType(vlan_tag=1); + bd_ref_data2 = BridgeDomainMembershipType(vlan_tag=2); + vmi_obj.add_bridge_domain(bd1, bd_ref_data1); + vmi_obj.add_bridge_domain(bd2, bd_ref_data2); + self._vnc_lib.virtual_machine_interface_update(vmi_obj) + # end test_bridge_domain_with_vmi_ref_multiple_bd + # end class TestCrud class TestVncCfgApiServer(test_case.ApiServerTestCase): diff --git a/src/config/api-server/vnc_cfg_types.py b/src/config/api-server/vnc_cfg_types.py index f545d2da4aa..5813f3e3914 100644 --- a/src/config/api-server/vnc_cfg_types.py +++ b/src/config/api-server/vnc_cfg_types.py @@ -776,6 +776,30 @@ def _check_vrouter_link(cls, vmi_data, kvp_dict, obj_dict, db_conn): # end _check_vrouter_link + @classmethod + def _check_bridge_domain_vmi_association(cls, obj_dict, + db_conn, create): + bridge_domain_links = {} + bd_refs = obj_dict.get('bridge_domain_refs') or [] + for bd in bd_refs: + bd_fq_name = bd['to'] + bd_uuid = bd.get('uuid') + if not bd_uuid: + bd_uuid = db_conn.fq_name_to_uuid('bridge_domain', bd_fq_name) + + bdmt = bd['attr'] + vlan_tag = bdmt['vlan_tag'] + if vlan_tag in bridge_domain_links: + msg = "Virtual machine interface(%s) already refers to bridge "\ + "domain(%s) for vlan tag %d"\ + %(obj_dict['uuid'], bd_uuid, vlan_tag) + return (False, msg) + + bridge_domain_links[vlan_tag] = bd_uuid + + return (True, '') + # end _check_bridge_domain_vmi_association + @classmethod def pre_dbe_create(cls, tenant_name, obj_dict, db_conn): vn_dict = obj_dict['virtual_network_refs'][0] @@ -795,6 +819,11 @@ def pre_dbe_create(cls, tenant_name, obj_dict, db_conn): vn_dict = result + (ok, error) = cls._check_bridge_domain_vmi_association(obj_dict, + db_conn, True) + if not ok: + return (False, (400, error)) + inmac = None if 'virtual_machine_interface_mac_addresses' in obj_dict: mc = obj_dict['virtual_machine_interface_mac_addresses'] @@ -882,6 +911,11 @@ def pre_dbe_update(cls, id, fq_name, obj_dict, db_conn, if not ok: return ok, read_result + (ok, error) = cls._check_bridge_domain_vmi_association(obj_dict, + db_conn, False) + if not ok: + return (False, (400, error)) + # check if the vmi is a internal interface of a logical # router if (read_result.get('logical_router_back_refs') and diff --git a/src/schema/vnc_cfg.xsd b/src/schema/vnc_cfg.xsd index c3c15ce1232..ca263b24803 100644 --- a/src/schema/vnc_cfg.xsd +++ b/src/schema/vnc_cfg.xsd @@ -3030,8 +3030,8 @@ targetNamespace="http://www.contrailsystems.com/2012/VNC-CONFIG/0"> + 'virtual-network', 'bridge-domain', ['has'], 'optional', 'CRUD', + 'bridge-domains configured in a virtual network') -->