def test_ipvs_ipv4(self): """Tests the ipvs() method with an IPv4 vip""" self.input_config.update({'faucet_vips': ['10.0.0.254/24']}) vlan = VLAN(1, 1, self.input_config) self.assertEqual(vlan.ipvs(), [4])
def test_bgp_servers_change_bgp_ipvs_ipv6(self): """Tests the ipvs() method with an IPv4 BGP server""" self.input_config.update({'bgp_server_addresses': ['::1']}) vlan = VLAN(1, 1, self.input_config) self.assertEqual(vlan.bgp_ipvs(), [6])
def test_ipvs_ipv6(self): """Tests the ipvs() method with an IPv6 vip""" self.input_config.update({'faucet_vips': ['2001::1/16']}) vlan = VLAN(1, 1, self.input_config) self.assertEqual(vlan.ipvs(), [6])
def test_routes_by_ipv_both(self): """Tests the routes_by_ipv() and route_count_by_ipv() methods with both IPv4 and IPv6 routes""" vlan_config = { 'routes': [ {'route': {'ip_dst': '10.99.99.0/24', 'ip_gw': '10.0.0.1'}}, {'route': {'ip_dst': '10.99.98.0/24', 'ip_gw': '10.0.0.99'}}, {'route': {'ip_dst': '10.99.97.0/24', 'ip_gw': '10.0.0.99'}}, {'route': {'ip_dst': 'fc00::10:0/112', 'ip_gw': 'fc00::1:1'}}, {'route': {'ip_dst': 'fc00::20:0/112', 'ip_gw': 'fc00::1:99'}} ], } vlan = VLAN(1, 1, vlan_config) self.assertEqual(vlan.routes_by_ipv(4), { ip_network('10.99.99.0/24'): ip_address('10.0.0.1'), ip_network('10.99.98.0/24'): ip_address('10.0.0.99'), ip_network('10.99.97.0/24'): ip_address('10.0.0.99'), }) self.assertEqual(vlan.routes_by_ipv(6), { ip_network('fc00::10:0/112'): ip_address('fc00::1:1'), ip_network('fc00::20:0/112'): ip_address('fc00::1:99'), }) self.assertEqual(vlan.route_count_by_ipv(4), 3) self.assertEqual(vlan.route_count_by_ipv(6), 2)
def test_with_routes(self): """Tests a config with routes""" input_config = { 'routes': [{ 'route': { 'ip_dst': '10.99.99.0/24', 'ip_gw': '10.0.0.1' } }, { 'route': { 'ip_dst': '10.99.98.0/24', 'ip_gw': '10.0.0.99' } }], 'vid': 100 } expected_config = self.default_config expected_config.update(input_config) vlan = VLAN(1, 1, input_config) output_config = vlan.to_conf() self.assertEqual(output_config, expected_config)
def test_basic_config(self): """Tests the minimal config""" input_config = {'vid': 100} expected_config = self.default_config expected_config.update(input_config) vlan = VLAN(1, 1, input_config) output_config = vlan.to_conf() self.assertEqual(output_config, expected_config) key_exceptions = [ 'name', 'tagged', 'dyn_gws_by_ipv', 'dyn_host_cache_by_port', 'dp_id', 'bgp_neighbor_addresses', 'bgp_neighbor_as', 'dyn_routes_by_ipv', '_id', 'dyn_neigh_cache_by_ipv', 'dyn_ipvs', 'dyn_bgp_ipvs', 'dyn_host_cache', 'dyn_faucet_vips_by_ipv', 'dyn_bgp_neighbor_addresses_by_ipv', 'dyn_bgp_server_addresses_by_ipv', 'untagged' ] dict_keys = set(vlan.__dict__.keys()) conf_keys = set(vlan.to_conf().keys()) for exception in key_exceptions: dict_keys.remove(exception) self.assertEqual(dict_keys, conf_keys)
def test_ipvs_ipv4_ipv6(self): """Tests the ipvs() method with both IPv4 and IPv6 vips""" self.input_config.update( {'faucet_vips': ['2001::1/16', 'fe80::1/64', '10.0.0.254/24']}) vlan = VLAN(1, 1, self.input_config) self.assertEqual(set(vlan.ipvs()), set([4, 6]))
def test_ipvs_ipv4(self): """Tests the ipvs() method with an IPv4 vip""" vlan_config = {'faucet_vips': ['10.0.0.254/24']} vlan = VLAN(1, 1, vlan_config) self.assertIn(4, vlan.ipvs()) self.assertNotIn(6, vlan.ipvs())
def test_ipvs_ipv6(self): """Tests the ipvs() method with an IPv6 vip""" vlan_config = {'faucet_vips': ['2001::1/16']} vlan = VLAN(1, 1, vlan_config) self.assertIn(6, vlan.ipvs()) self.assertNotIn(4, vlan.ipvs())
def test_routes_by_ipv_none(self): """Tests the routes_by_ipv() and route_count_by_ipv() methods with no routes""" vlan = VLAN(1, 1, {}) self.assertEqual(vlan.routes_by_ipv(4), {}) self.assertEqual(vlan.routes_by_ipv(6), {}) self.assertEqual(vlan.route_count_by_ipv(4), 0) self.assertEqual(vlan.route_count_by_ipv(6), 0)
def test_bgp_servers_change_bgp_ipvs_ipv6(self): """Tests the ipvs() method with an IPv4 BGP server""" vlan_config = {'bgp_server_addresses': ['::1']} vlan = VLAN(1, 1, vlan_config) self.assertIn(6, vlan.bgp_ipvs()) self.assertNotIn(4, vlan.bgp_ipvs())
def test_ipvs_ipv4_ipv6(self): """Tests the ipvs() method with both IPv4 and IPv6 vips""" vlan_config = { 'faucet_vips': ['2001::1/16', 'fe80::1/64', '10.0.0.254/24'] } vlan = VLAN(1, 1, vlan_config) self.assertIn(4, vlan.ipvs()) self.assertIn(6, vlan.ipvs())
def test_bgp_servers_change_bgp_ipvs_ipv6(self): """Tests the ipvs() method with an IPv4 BGP server""" vlan_config = { 'bgp_server_addresses': ['::1'] } vlan = VLAN(1, 1, vlan_config) self.assertIn(6, vlan.bgp_ipvs()) self.assertNotIn(4, vlan.bgp_ipvs())
def test_ipvs_ipv4(self): """Tests the ipvs() method with an IPv4 vip""" vlan_config = { 'faucet_vips': ['10.0.0.254/24'] } vlan = VLAN(1, 1, vlan_config) self.assertIn(4, vlan.ipvs()) self.assertNotIn(6, vlan.ipvs())
def test_ipvs_ipv6(self): """Tests the ipvs() method with an IPv6 vip""" vlan_config = { 'faucet_vips': ['2001::1/16'] } vlan = VLAN(1, 1, vlan_config) self.assertIn(6, vlan.ipvs()) self.assertNotIn(4, vlan.ipvs())
def test_bgp_servers_change_bgp_ipvs_both(self): """Tests the ipvs() method with an IPv4 BGP server""" vlan_config = {'bgp_server_addresses': ['127.0.0.1', '::1']} vlan = VLAN(1, 1, vlan_config) self.assertIn(4, vlan.bgp_ipvs()) self.assertIn(6, vlan.bgp_ipvs()) self.assertIn(ip_address('127.0.0.1'), vlan.bgp_server_addresses_by_ipv(4)) self.assertIn(ip_address('::1'), vlan.bgp_server_addresses_by_ipv(6))
def test_bgp_servers_change_bgp_ipvs_both(self): """Tests the ipvs() method with an IPv4 BGP server""" vlan_config = { 'bgp_server_addresses': ['127.0.0.1', '::1'] } vlan = VLAN(1, 1, vlan_config) self.assertIn(4, vlan.bgp_ipvs()) self.assertIn(6, vlan.bgp_ipvs()) self.assertIn(ip_address('127.0.0.1'), vlan.bgp_server_addresses_by_ipv(4)) self.assertIn(ip_address('::1'), vlan.bgp_server_addresses_by_ipv(6))
def test_with_vips(self): """Tests a config with virtual IPs""" input_config = {'faucet_vips': ['10.0.0.254/24'], 'vid': 100} expected_config = self.default_config expected_config.update(input_config) vlan = VLAN(1, 1, input_config) output_config = vlan.to_conf() self.assertEqual(output_config, expected_config)
def test_bgp_servers_change_bgp_ipvs_both(self): """Tests the ipvs() method with an IPv4 BGP server""" self.input_config.update( {'bgp_server_addresses': ['127.0.0.1', '::1']}) vlan = VLAN(1, 1, self.input_config) self.assertEqual(vlan.bgp_ipvs(), [4, 6]) self.assertEqual(vlan.bgp_server_addresses_by_ipv(4), [ip_address('127.0.0.1')]) self.assertEqual(vlan.bgp_server_addresses_by_ipv(6), [ip_address('::1')])
def test_faucet_vips_by_ipv_both(self): """Tests the faucet_vips_by_ipv() method when there are both IPv4 and IPv6 vips""" self.input_config.update( {'faucet_vips': ['2001::1/16', 'fe80::1/64', '10.0.0.254/24']}) vlan = VLAN(1, 1, self.input_config) self.assertEqual(set(vlan.faucet_vips_by_ipv(4)), set([ip_interface('10.0.0.254/24')])) self.assertEqual( set(vlan.faucet_vips_by_ipv(6)), set([ip_interface('2001::1/16'), ip_interface('fe80::1/64')]))
def test_ipvs_ipv4_ipv6(self): """Tests the ipvs() method with both IPv4 and IPv6 vips""" vlan_config = { 'faucet_vips': [ '2001::1/16', 'fe80::1/64', '10.0.0.254/24' ] } vlan = VLAN(1, 1, vlan_config) self.assertIn(4, vlan.ipvs()) self.assertIn(6, vlan.ipvs())
def test_routes_by_ipv_both(self): """Tests the routes_by_ipv() and route_count_by_ipv() methods with both IPv4 and IPv6 routes""" vlan_config = { 'routes': [{ 'route': { 'ip_dst': '10.99.99.0/24', 'ip_gw': '10.0.0.1' } }, { 'route': { 'ip_dst': '10.99.98.0/24', 'ip_gw': '10.0.0.99' } }, { 'route': { 'ip_dst': '10.99.97.0/24', 'ip_gw': '10.0.0.99' } }, { 'route': { 'ip_dst': 'fc00::10:0/112', 'ip_gw': 'fc00::1:1' } }, { 'route': { 'ip_dst': 'fc00::20:0/112', 'ip_gw': 'fc00::1:99' } }], } vlan = VLAN(1, 1, vlan_config) self.assertEqual( vlan.routes_by_ipv(4), { ip_network('10.99.99.0/24'): ip_address('10.0.0.1'), ip_network('10.99.98.0/24'): ip_address('10.0.0.99'), ip_network('10.99.97.0/24'): ip_address('10.0.0.99'), }) self.assertEqual( vlan.routes_by_ipv(6), { ip_network('fc00::10:0/112'): ip_address('fc00::1:1'), ip_network('fc00::20:0/112'): ip_address('fc00::1:99'), }) self.assertEqual(vlan.route_count_by_ipv(4), 3) self.assertEqual(vlan.route_count_by_ipv(6), 2)
def _parse_dp(dp_key, dp_conf, acls_conf, meters_conf, routers_conf, vlans_conf): test_config_condition(not isinstance(dp_conf, dict), 'DP config must be dict') dp = DP(dp_key, dp_conf.get('dp_id', None), dp_conf) test_config_condition(dp.name != dp_key, ('DP key %s and DP name must match' % dp_key)) vlans = {} vids = set() for vlan_key, vlan_conf in vlans_conf.items(): vlan = VLAN(vlan_key, dp.dp_id, vlan_conf) test_config_condition( str(vlan_key) not in (str(vlan.vid), vlan.name), ('VLAN %s key must match VLAN name or VLAN VID' % vlan_key)) test_config_condition(not isinstance(vlan_key, (str, int)), ('VLAN %s key must not be type %s' % (vlan_key, type(vlan_key)))) test_config_condition(vlan.vid in vids, ('VLAN VID %u multiply configured' % vlan.vid)) vlans[vlan_key] = vlan vids.add(vlan.vid) _parse_acls(dp, acls_conf) _parse_routers(dp, routers_conf) _parse_meters(dp, meters_conf) _dp_add_ports(dp, dp_conf, dp.dp_id, vlans) return (dp, vlans)
def _parse_dp(dp_key, dp_conf, acls_conf, meters_conf, routers_conf, vlans_conf): test_config_condition(not isinstance(dp_conf, dict), '') dp = DP(dp_key, dp_conf.get('dp_id', None), dp_conf) test_config_condition(dp.name != dp_key, ('DP key %s and DP name must match' % dp_key)) dp_id = dp.dp_id vlans = {} vids = set() for vlan_key, vlan_conf in vlans_conf.items(): vlan = VLAN(vlan_key, dp_id, vlan_conf) test_config_condition( str(vlan_key) not in (str(vlan.vid), vlan.name), ('VLAN %s key must match VLAN name or VLAN VID' % vlan_key)) test_config_condition(vlan.vid in vids, ('VLAN VID %u multiply configured' % vlan.vid)) vlans[vlan_key] = vlan vids.add(vlan.vid) for acl_key, acl_conf in acls_conf.items(): acl = ACL(acl_key, dp_id, acl_conf) dp.add_acl(acl_key, acl) for router_key, router_conf in routers_conf.items(): router = Router(router_key, dp_id, router_conf) dp.add_router(router_key, router) for meter_key, meter_conf in meters_conf.items(): meter = Meter(meter_key, dp_id, meter_conf) dp.meters[meter_key] = meter _dp_add_ports(dp, dp_conf, dp_id, vlans) return dp
def _get_vlan_by_identifier(dp_id, vlan_ident, vlans): if vlan_ident in vlans: return vlans[vlan_ident] for vlan in list(vlans.values()): if vlan_ident == str(vlan.vid): return vlan # Create VLAN with VID, if not defined. return vlans.setdefault(vlan_ident, VLAN(vlan_ident, dp_id))
def _get_vlan_by_key(dp_id, vlan_key, vlans): test_config_condition(not isinstance(vlan_key, (str, int)), ( 'VLAN key must not be type %s' % type(vlan_key))) if vlan_key in vlans: return vlans[vlan_key] for vlan in vlans.values(): if vlan_key == str(vlan.vid): return vlan # Create VLAN with VID, if not defined. return vlans.setdefault(vlan_key, VLAN(vlan_key, dp_id))
def test_faucet_vips_by_ipv_both(self): """Tests the faucet_vips_by_ipv() method when there are both IPv4 and IPv6 vips""" vlan_config = { 'faucet_vips': [ '2001::1/16', 'fe80::1/64', '10.0.0.254/24' ] } vlan = VLAN(1, 1, vlan_config) self.assertEqual(set(vlan.faucet_vips_by_ipv(4)), set([ ip_interface('10.0.0.254/24') ])) self.assertEqual(set(vlan.faucet_vips_by_ipv(6)), set([ ip_interface('2001::1/16'), ip_interface('fe80::1/64') ]))
def _get_vlan_by_identifier(dp_id, vlan_ident, vlans): assert isinstance(vlan_ident, (str, int)), ('VLAN identifier must not be type %s' % type(vlan_ident)) if vlan_ident in vlans: return vlans[vlan_ident] for vlan in list(vlans.values()): if vlan_ident == str(vlan.vid): return vlan # Create VLAN with VID, if not defined. return vlans.setdefault(vlan_ident, VLAN(vlan_ident, dp_id))
def _get_vlan_by_identifier(dp_id, vlan_ident, vlans): if vlan_ident in vlans: return vlans[vlan_ident] for vlan in list(vlans.values()): if int(vlan_ident) == vlan.vid: return vlan try: vid = int(vlan_ident, 0) except ValueError: assert False, 'VLAN VID value (%s) is invalid' % vlan_ident return vlans.setdefault(vlan_ident, VLAN(vid, dp_id))
def _dp_parser_v2(logger, acls_conf, dps_conf, routers_conf, vlans_conf): dps = [] vid_dp = {} for identifier, dp_conf in list(dps_conf.items()): try: dp = DP(identifier, dp_conf) dp.sanity_check() dp_id = dp.dp_id vlans = {} for vid, vlan_conf in list(vlans_conf.items()): vlans[vid] = VLAN(vid, dp_id, vlan_conf) acls = [] for acl_ident, acl_conf in list(acls_conf.items()): acls.append((acl_ident, ACL(acl_ident, acl_conf))) routers = [] for router_ident, router_conf in list(routers_conf.items()): routers.append((router_ident, Router(router_ident, router_conf))) if routers: assert len(routers) == 1, 'only one router supported' router_ident, router = routers[0] assert set(router.vlans) == set( vlans.keys()), 'only global routing supported' dp.add_router(router_ident, router) ports_conf = dp_conf.pop('interfaces', {}) ports = {} # as users can config port vlan by using vlan name, we store vid in # Port instance instead of vlan name for data consistency for port_num, port_conf in list(ports_conf.items()): port = port_parser(dp_id, port_num, port_conf, vlans) ports[port_num] = port if port.native_vlan is not None: vlan = vlans[port.native_vlan] port.native_vlan = vlan.vid _dp_add_vlan(vid_dp, dp, vlan) if port.tagged_vlans is not None: tagged_vids = [] for v_identifier in port.tagged_vlans: vlan = vlans[v_identifier] tagged_vids.append(vlan.vid) _dp_add_vlan(vid_dp, dp, vlan) port.tagged_vlans = tagged_vids except AssertionError as err: logger.exception('Error in config file: %s', err) return None for port in list(ports.values()): dp.add_port(port) for acl_ident, acl in acls: dp.add_acl(acl_ident, acl) dps.append(dp) return dps
def _get_vlan_by_key(dp_id, vlan_key, vlans): try: if vlan_key in vlans: return vlans[vlan_key] except TypeError as err: raise InvalidConfigError(err) from err for vlan in vlans.values(): if vlan_key == vlan.vid: return vlan test_config_condition(not isinstance(vlan_key, int), ( 'Implicitly created VLAN %s must be an int (not %s)' % ( vlan_key, type(vlan_key)))) # Create VLAN with VID, if not defined. return vlans.setdefault(vlan_key, VLAN(vlan_key, dp_id))
def _get_vlan_by_identifier(dp_id, v_identifier, vlans): '''v_identifier can be a name or anything used to identify a vlan. v_identifier will be used as vid when vid is omitted in vlan config''' vid = v_identifier for vlan in list(vlans.values()): if v_identifier == vlan._id: vid = vlan.vid break if type(vid) == str: try: vid = int(vid, 0) except: assert False, 'vid value (%s) is invalid' % vid vlan = vlans.setdefault(v_identifier, VLAN(vid, dp_id)) return vlan
def _dp_parser_v2(dps_conf, acls_conf, meters_conf, routers_conf, vlans_conf, meta_dp_state): # pylint: disable=invalid-name dp_vlans = [] for dp_key, dp_conf in dps_conf.items(): try: dp, vlans = _parse_dp(dp_key, dp_conf, acls_conf, meters_conf, routers_conf, vlans_conf) dp_vlans.append((dp, vlans)) except InvalidConfigError as err: raise InvalidConfigError('DP %s: %s' % (dp_key, err)) # Some VLANs are created implicitly just by referencing them in tagged/native, # so we must make them available to all DPs. implicit_vids = set() for dp, vlans in dp_vlans: implicit_vids.update(set(vlans.keys()) - set(vlans_conf.keys())) dps = [] for dp, vlans in dp_vlans: for vlan_key in implicit_vids: if vlan_key not in vlans: vlans[vlan_key] = VLAN(vlan_key, dp.dp_id) dp.reset_refs(vlans=vlans) dps.append(dp) for dp in dps: dp.finalize_config(dps) for dp in dps: dp.resolve_stack_topology(dps, meta_dp_state) for dp in dps: dp.finalize() dpid_refs = set() for dp in dps: test_config_condition(dp.dp_id in dpid_refs, ('DPID %u is duplicated' % dp.dp_id)) dpid_refs.add(dp.dp_id) routers_referenced = set() for dp in dps: routers_referenced.update(dp.routers.keys()) for router in routers_conf: test_config_condition( router not in routers_referenced, ('router %s configured but not used by any DP' % router)) return dps
def test_ipvs_no_ips(self): """Tests the ipvs() method with no vips""" vlan = VLAN(1, 1, {}) self.assertEqual(len(vlan.ipvs()), 0)
def test_faucet_vips_by_ipv_none(self): """Tests the faucet_vips_by_ipv() method when there are no vips""" vlan = VLAN(1, 1, {}) self.assertEqual(len(vlan.faucet_vips_by_ipv(4)), 0) self.assertEqual(len(vlan.faucet_vips_by_ipv(6)), 0)
def test_modify_routes_static_v6(self): """Tests the add_route() and remove_route() methods, starting with configured static routes for IPv6""" vlan_config = { 'routes': [ { 'route': { 'ip_dst': 'fc00::30:0/112', 'ip_gw': 'fc00::1:99' } }, ], } vlan = VLAN(1, 1, vlan_config) self.assertEqual( vlan.routes_by_ipv(6), {ip_network('fc00::30:0/112'): ip_address('fc00::1:99')}) vlan.add_route(ip_network('fc00::10:0/112'), ip_address('fc00::1:1')) vlan.add_route(ip_network('fc00::20:0/112'), ip_address('fc00::1:99')) self.assertEqual( vlan.routes_by_ipv(6), { ip_network('fc00::10:0/112'): ip_address('fc00::1:1'), ip_network('fc00::20:0/112'): ip_address('fc00::1:99'), ip_network('fc00::30:0/112'): ip_address('fc00::1:99') }) self.assertEqual(vlan.route_count_by_ipv(6), 3) vlan.del_route(ip_network('fc00::10:0/112')) self.assertEqual( vlan.routes_by_ipv(6), { ip_network('fc00::30:0/112'): ip_address('fc00::1:99'), ip_network('fc00::20:0/112'): ip_address('fc00::1:99') }) self.assertEqual(vlan.route_count_by_ipv(6), 2) vlan.del_route(ip_network('fc00::20:0/112')) self.assertEqual(vlan.route_count_by_ipv(6), 1) self.assertEqual( vlan.routes_by_ipv(6), {ip_network('fc00::30:0/112'): ip_address('fc00::1:99')})
def test_modify_routes_static_v6(self): """Tests the add_route() and remove_route() methods, starting with configured static routes for IPv6""" vlan_config = { 'routes': [ {'route': {'ip_dst': 'fc00::30:0/112', 'ip_gw': 'fc00::1:99'}}, ], } vlan = VLAN(1, 1, vlan_config) self.assertEqual(vlan.routes_by_ipv(6), { ip_network('fc00::30:0/112'): ip_address('fc00::1:99') }) vlan.add_route(ip_network('fc00::10:0/112'), ip_address('fc00::1:1')) vlan.add_route(ip_network('fc00::20:0/112'), ip_address('fc00::1:99')) self.assertEqual(vlan.routes_by_ipv(6), { ip_network('fc00::10:0/112'): ip_address('fc00::1:1'), ip_network('fc00::20:0/112'): ip_address('fc00::1:99'), ip_network('fc00::30:0/112'): ip_address('fc00::1:99') }) self.assertEqual(vlan.route_count_by_ipv(6), 3) vlan.del_route(ip_network('fc00::10:0/112')) self.assertEqual(vlan.routes_by_ipv(6), { ip_network('fc00::30:0/112'): ip_address('fc00::1:99'), ip_network('fc00::20:0/112'): ip_address('fc00::1:99') }) self.assertEqual(vlan.route_count_by_ipv(6), 2) vlan.del_route(ip_network('fc00::20:0/112')) self.assertEqual(vlan.route_count_by_ipv(6), 1) self.assertEqual(vlan.routes_by_ipv(6), { ip_network('fc00::30:0/112'): ip_address('fc00::1:99') })
def test_modify_routes_static_v4(self): """Tests the add_route() and remove_route() methods, starting with configured static routes for IPv4""" vlan_config = { 'routes': [ {'route': {'ip_dst': '10.99.97.0/24', 'ip_gw': '10.0.0.99'}}, ], } vlan = VLAN(1, 1, vlan_config) self.assertEqual(vlan.routes_by_ipv(4), { ip_network('10.99.97.0/24'): ip_address('10.0.0.99') }) vlan.add_route(ip_network('10.99.99.0/24'), ip_address('10.0.0.1')) vlan.add_route(ip_network('10.99.98.0/24'), ip_address('10.0.0.99')) self.assertEqual(vlan.routes_by_ipv(4), { ip_network('10.99.99.0/24'): ip_address('10.0.0.1'), ip_network('10.99.98.0/24'): ip_address('10.0.0.99'), ip_network('10.99.97.0/24'): ip_address('10.0.0.99') }) self.assertEqual(vlan.route_count_by_ipv(4), 3) vlan.del_route(ip_network('10.99.99.0/24')) self.assertEqual(vlan.routes_by_ipv(4), { ip_network('10.99.97.0/24'): ip_address('10.0.0.99'), ip_network('10.99.98.0/24'): ip_address('10.0.0.99') }) self.assertEqual(vlan.route_count_by_ipv(4), 2) vlan.del_route(ip_network('10.99.98.0/24')) self.assertEqual(vlan.route_count_by_ipv(4), 1) self.assertEqual(vlan.routes_by_ipv(4), { ip_network('10.99.97.0/24'): ip_address('10.0.0.99') })
def test_modify_routes_v6(self): """Tests the add_route() and remove_route() methods with IPv4 routes""" vlan = VLAN(1, 1, {}) self.assertEqual(vlan.routes_by_ipv(6), {}) vlan.add_route(ip_network('fc00::10:0/112'), ip_address('fc00::1:1')) vlan.add_route(ip_network('fc00::20:0/112'), ip_address('fc00::1:99')) self.assertEqual(vlan.routes_by_ipv(6), { ip_network('fc00::10:0/112'): ip_address('fc00::1:1'), ip_network('fc00::20:0/112'): ip_address('fc00::1:99') }) self.assertEqual(vlan.route_count_by_ipv(6), 2) vlan.del_route(ip_network('fc00::10:0/112')) self.assertEqual(vlan.routes_by_ipv(6), { ip_network('fc00::20:0/112'): ip_address('fc00::1:99') }) self.assertEqual(vlan.route_count_by_ipv(6), 1) vlan.del_route(ip_network('fc00::20:0/112')) self.assertEqual(vlan.route_count_by_ipv(6), 0) self.assertEqual(vlan.routes_by_ipv(6), {})
def _dp_parser_v2(logger, acls_conf, dps_conf, meters_conf, routers_conf, vlans_conf): dps = [] vid_dp = collections.defaultdict(set) def _get_vlan_by_identifier(dp_id, vlan_ident, vlans): if vlan_ident in vlans: return vlans[vlan_ident] for vlan in list(vlans.values()): if int(vlan_ident) == vlan.vid: return vlan try: vid = int(vlan_ident, 0) except ValueError: assert False, 'VLAN VID value (%s) is invalid' % vlan_ident return vlans.setdefault(vlan_ident, VLAN(vid, dp_id)) def _dp_add_vlan(dp, vlan): if vlan not in dp.vlans: dp.add_vlan(vlan) vid_dp[vlan.vid].add(dp.name) if len(vid_dp[vlan.vid]) > 1: assert not vlan.bgp_routerid, ( 'DPs %s sharing a BGP speaker VLAN is unsupported' % (str.join(', ', vid_dp[vlan.vid]))) def _dp_parse_port(dp_id, p_identifier, port_conf, vlans): port = Port(p_identifier, port_conf) if port.native_vlan is not None: v_identifier = port.native_vlan vlan = _get_vlan_by_identifier(dp_id, v_identifier, vlans) port.native_vlan = vlan vlan.add_untagged(port) port_tagged_vlans = [ _get_vlan_by_identifier(dp_id, v_identifier, vlans) for v_identifier in port.tagged_vlans ] port.tagged_vlans = port_tagged_vlans for vlan in port.tagged_vlans: vlan.add_tagged(port) for vlan in port.vlans(): _dp_add_vlan(dp, vlan) return port def _dp_add_ports(dp, dp_conf, dp_id, vlans): ports_conf = dp_conf.pop('interfaces', {}) # as users can config port vlan by using vlan name, we store vid in # Port instance instead of vlan name for data consistency for port_num, port_conf in list(ports_conf.items()): port = _dp_parse_port(dp_id, port_num, port_conf, vlans) dp.add_port(port) try: for identifier, dp_conf in list(dps_conf.items()): dp = DP(identifier, dp_conf) dp.sanity_check() dp_id = dp.dp_id vlans = {} for vlan_ident, vlan_conf in list(vlans_conf.items()): vlans[vlan_ident] = VLAN(vlan_ident, dp_id, vlan_conf) acls = [] for acl_ident, acl_conf in list(acls_conf.items()): acls.append((acl_ident, ACL(acl_ident, acl_conf))) for router_ident, router_conf in list(routers_conf.items()): router = Router(router_ident, router_conf) dp.add_router(router_ident, router) for meter_ident, meter_conf in list(meters_conf.items()): dp.meters[meter_ident] = Meter(meter_ident, meter_conf) _dp_add_ports(dp, dp_conf, dp_id, vlans) for acl_ident, acl in acls: dp.add_acl(acl_ident, acl) dps.append(dp) for dp in dps: dp.finalize_config(dps) for dp in dps: dp.resolve_stack_topology(dps) except AssertionError as err: logger.exception('Error in config file: %s', err) return None return dps
def test_modify_routes_v4(self): """Tests the add_route() and remove_route() methods with IPv4 routes""" vlan = VLAN(1, 1, {}) self.assertEqual(vlan.routes_by_ipv(4), {}) vlan.add_route(ip_network('10.99.99.0/24'), ip_address('10.0.0.1')) vlan.add_route(ip_network('10.99.98.0/24'), ip_address('10.0.0.99')) self.assertEqual(vlan.routes_by_ipv(4), { ip_network('10.99.99.0/24'): ip_address('10.0.0.1'), ip_network('10.99.98.0/24'): ip_address('10.0.0.99') }) self.assertEqual(vlan.route_count_by_ipv(4), 2) vlan.del_route(ip_network('10.99.99.0/24')) self.assertEqual(vlan.routes_by_ipv(4), { ip_network('10.99.98.0/24'): ip_address('10.0.0.99') }) self.assertEqual(vlan.route_count_by_ipv(4), 1) vlan.del_route(ip_network('10.99.98.0/24')) self.assertEqual(vlan.route_count_by_ipv(4), 0) self.assertEqual(vlan.routes_by_ipv(4), {})
def _dp_parser_v2(acls_conf, dps_conf, meters_conf, routers_conf, vlans_conf): dps = [] def _get_vlan_by_key(dp_id, vlan_key, vlans): test_config_condition( not isinstance(vlan_key, (str, int)), ('VLAN key must not be type %s' % type(vlan_key))) if vlan_key in vlans: return vlans[vlan_key] for vlan in list(vlans.values()): if vlan_key == str(vlan.vid): return vlan # Create VLAN with VID, if not defined. return vlans.setdefault(vlan_key, VLAN(vlan_key, dp_id)) def _dp_parse_port(dp_id, port_key, port_conf, vlans): port = Port(port_key, dp_id, port_conf) test_config_condition( str(port_key) not in (str(port.number), port.name), ('Port key %s match port name or port number' % port_key)) def _dp_parse_native_port_vlan(): if port.native_vlan is not None: vlan = _get_vlan_by_key(dp_id, port.native_vlan, vlans) port.native_vlan = vlan def _dp_parse_tagged_port_vlans(): if port.tagged_vlans: port_tagged_vlans = [ _get_vlan_by_key(dp_id, vlan_key, vlans) for vlan_key in port.tagged_vlans ] port.tagged_vlans = port_tagged_vlans _dp_parse_native_port_vlan() _dp_parse_tagged_port_vlans() return port def _dp_add_ports(dp, dp_conf, dp_id, vlans): ports_conf = dp_conf.get('interfaces', {}) port_ranges_conf = dp_conf.get('interface_ranges', {}) # as users can config port vlan by using vlan name, we store vid in # Port instance instead of vlan name for data consistency test_config_condition(not isinstance(ports_conf, dict), ('Invalid syntax in interface config')) test_config_condition(not isinstance(port_ranges_conf, dict), ('Invalid syntax in interface ranges config')) port_num_to_port_conf = {} for port_key, port_conf in list(ports_conf.items()): test_config_condition(not isinstance(port_conf, dict), 'Invalid syntax in port config') if 'number' in port_conf: port_num = port_conf['number'] else: port_num = port_key try: port_num_to_port_conf[port_num] = (port_key, port_conf) except TypeError: raise InvalidConfigError('Invalid syntax in port config') for port_range, port_conf in list(port_ranges_conf.items()): # port range format: 1-6 OR 1-6,8-9 OR 1-3,5,7-9 test_config_condition(not isinstance(port_conf, dict), 'Invalid syntax in port config') port_nums = set() if 'number' in port_conf: del port_conf['number'] for range_ in re.findall(r'(\d+-\d+)', str(port_range)): start_num, end_num = [int(num) for num in range_.split('-')] test_config_condition(start_num >= end_num, ('Incorrect port range (%d - %d)' % (start_num, end_num))) port_nums.update(list(range(start_num, end_num + 1))) port_range = re.sub(range_, '', port_range) other_nums = [int(p) for p in re.findall(r'\d+', str(port_range))] port_nums.update(other_nums) test_config_condition(not port_nums, 'interface-ranges contain invalid config') for port_num in port_nums: if port_num in port_num_to_port_conf: # port range config has lower priority than individual port config for attr, value in list(port_conf.items()): port_num_to_port_conf[port_num][1].setdefault( attr, value) else: port_num_to_port_conf[port_num] = (port_num, port_conf) for port_num, port_conf in list(port_num_to_port_conf.values()): port = _dp_parse_port(dp_id, port_num, port_conf, vlans) dp.add_port(port) dp.reset_refs(vlans=vlans) for dp_key, dp_conf in list(dps_conf.items()): test_config_condition(not isinstance(dp_conf, dict), '') dp = DP(dp_key, dp_conf.get('dp_id', None), dp_conf) test_config_condition(dp.name != dp_key, ('DP key %s and DP name must match' % dp_key)) dp_id = dp.dp_id vlans = {} for vlan_key, vlan_conf in list(vlans_conf.items()): vlan = VLAN(vlan_key, dp_id, vlan_conf) vlans[vlan_key] = vlan test_config_condition( str(vlan_key) not in (str(vlan.vid), vlan.name), ('VLAN %s key must match VLAN name or VLAN VID' % vlan_key)) for acl_key, acl_conf in list(acls_conf.items()): acl = ACL(acl_key, dp_id, acl_conf) dp.add_acl(acl_key, acl) for router_key, router_conf in list(routers_conf.items()): router = Router(router_key, dp_id, router_conf) dp.add_router(router_key, router) for meter_key, meter_conf in list(meters_conf.items()): meter = Meter(meter_key, dp_id, meter_conf) dp.meters[meter_key] = meter _dp_add_ports(dp, dp_conf, dp_id, vlans) dps.append(dp) for dp in dps: dp.finalize_config(dps) for dp in dps: dp.resolve_stack_topology(dps) router_ref_dps = collections.defaultdict(set) for dp in dps: for router in list(dp.routers.keys()): router_ref_dps[router].add(dp) for router in list(routers_conf.keys()): test_config_condition( not router_ref_dps[router], ('router %s configured but not used by any DP' % router)) return dps