From fc619a29c9c6cd9fe52aa3f68032a8bfe3f52f85 Mon Sep 17 00:00:00 2001 From: Xu Han Peng Date: Tue, 1 Jul 2014 16:57:51 +0800 Subject: [PATCH] Allow DHCPv6 reply from server to client Add security group rule to allow DHCPv6 reply from dhcp server link local addres port 547 to client port 546. Change-Id: I5fd9561e855b1d3999649934977af659d5ca221f Closes-Bug: 1335984 --- neutron/db/securitygroups_rpc_base.py | 33 ++++++++++--------- neutron/tests/unit/bigswitch/test_base.py | 1 + .../tests/unit/test_security_groups_rpc.py | 24 +++++++++++++- 3 files changed, 42 insertions(+), 16 deletions(-) diff --git a/neutron/db/securitygroups_rpc_base.py b/neutron/db/securitygroups_rpc_base.py index 6555850dde..8f87a8c804 100644 --- a/neutron/db/securitygroups_rpc_base.py +++ b/neutron/db/securitygroups_rpc_base.py @@ -27,13 +27,11 @@ from neutron.openstack.common import log as logging LOG = logging.getLogger(__name__) -IP_MASK = {q_const.IPv4: 32, - q_const.IPv6: 128} - - DIRECTION_IP_PREFIX = {'ingress': 'source_ip_prefix', 'egress': 'dest_ip_prefix'} +DHCP_RULE_PORT = {4: (67, 68, q_const.IPv4), 6: (547, 546, q_const.IPv6)} + class SecurityGroupServerRpcMixin(sg_db.SecurityGroupDbMixin): """Mixin class to add agent-based security group implementation.""" @@ -282,7 +280,14 @@ class SecurityGroupServerRpcMixin(sg_db.SecurityGroupDbMixin): ips[network_id] = [] for port, ip in query: - ips[port['network_id']].append(ip) + if (netaddr.IPAddress(ip).version == 6 + and not netaddr.IPAddress(ip).is_link_local()): + mac_address = port['mac_address'] + ip = str(ipv6.get_ipv6_addr_by_EUI64(q_const.IPV6_LLA_PREFIX, + mac_address)) + if ip not in ips[port['network_id']]: + ips[port['network_id']].append(ip) + return ips def _select_ra_ips_for_network_ids(self, context, network_ids): @@ -376,18 +381,16 @@ class SecurityGroupServerRpcMixin(sg_db.SecurityGroupDbMixin): def _add_ingress_dhcp_rule(self, port, ips): dhcp_ips = ips.get(port['network_id']) for dhcp_ip in dhcp_ips: - if not netaddr.IPAddress(dhcp_ip).version == 4: - return - + source_port, dest_port, ethertype = DHCP_RULE_PORT[ + netaddr.IPAddress(dhcp_ip).version] dhcp_rule = {'direction': 'ingress', - 'ethertype': q_const.IPv4, + 'ethertype': ethertype, 'protocol': 'udp', - 'port_range_min': 68, - 'port_range_max': 68, - 'source_port_range_min': 67, - 'source_port_range_max': 67} - dhcp_rule['source_ip_prefix'] = "%s/%s" % (dhcp_ip, - IP_MASK[q_const.IPv4]) + 'port_range_min': dest_port, + 'port_range_max': dest_port, + 'source_port_range_min': source_port, + 'source_port_range_max': source_port, + 'source_ip_prefix': dhcp_ip} port['security_group_rules'].append(dhcp_rule) def _add_ingress_ra_rule(self, port, ips): diff --git a/neutron/tests/unit/bigswitch/test_base.py b/neutron/tests/unit/bigswitch/test_base.py index e31760e4ff..422c5b95d4 100644 --- a/neutron/tests/unit/bigswitch/test_base.py +++ b/neutron/tests/unit/bigswitch/test_base.py @@ -52,6 +52,7 @@ class BigSwitchTestBase(object): # The mock interferes with HTTP(S) connection caching cfg.CONF.set_override('cache_connections', False, 'RESTPROXY') cfg.CONF.set_override('service_plugins', ['bigswitch_l3']) + cfg.CONF.set_override('add_meta_server_route', False, 'RESTPROXY') def setup_patches(self): self.plugin_notifier_p = mock.patch(NOTIFIER) diff --git a/neutron/tests/unit/test_security_groups_rpc.py b/neutron/tests/unit/test_security_groups_rpc.py index c841bf322e..ee6e2f72be 100644 --- a/neutron/tests/unit/test_security_groups_rpc.py +++ b/neutron/tests/unit/test_security_groups_rpc.py @@ -44,7 +44,8 @@ FAKE_PREFIX = {const.IPv4: '10.0.0.0/24', FAKE_IP = {const.IPv4: '10.0.0.1', const.IPv6: 'fe80::1', 'IPv6_GLOBAL': '2001:0db8::1', - 'IPv6_LLA': 'fe80::123'} + 'IPv6_LLA': 'fe80::123', + 'IPv6_DHCP': '2001:db8::3'} TEST_PLUGIN_CLASS = ('neutron.tests.unit.test_security_groups_rpc.' @@ -483,6 +484,18 @@ class SGServerRpcCallBackTestCase(test_sg.SecurityGroupDBTestCase): self.deserialize(self.fmt, res) self.assertEqual(res.status_int, webob.exc.HTTPCreated.code) + dhcp_port = self._create_port( + self.fmt, n['network']['id'], + fixed_ips=[{'subnet_id': subnet_v6['subnet']['id'], + 'ip_address': FAKE_IP['IPv6_DHCP']}], + device_owner=const.DEVICE_OWNER_DHCP, + security_groups=[sg1_id]) + dhcp_rest = self.deserialize(self.fmt, dhcp_port) + dhcp_mac = dhcp_rest['port']['mac_address'] + dhcp_lla_ip = str(ipv6.get_ipv6_addr_by_EUI64( + const.IPV6_LLA_PREFIX, + dhcp_mac)) + res1 = self._create_port( self.fmt, n['network']['id'], fixed_ips=[{'subnet_id': subnet_v6['subnet']['id']}], @@ -495,6 +508,7 @@ class SGServerRpcCallBackTestCase(test_sg.SecurityGroupDBTestCase): ports_rpc = self.rpc.security_group_rules_for_devices( ctx, devices=devices) port_rpc = ports_rpc[port_id1] + source_port, dest_port, ethertype = sg_db_rpc.DHCP_RULE_PORT[6] expected = [{'direction': 'egress', 'ethertype': const.IPv4, 'security_group_id': sg1_id}, {'direction': 'egress', 'ethertype': const.IPv6, @@ -517,6 +531,14 @@ class SGServerRpcCallBackTestCase(test_sg.SecurityGroupDBTestCase): 'ethertype': const.IPv6, 'source_ip_prefix': fake_gateway, 'source_port_range_min': const.ICMPV6_TYPE_RA}, + {'direction': 'ingress', + 'ethertype': ethertype, + 'port_range_max': dest_port, + 'port_range_min': dest_port, + 'protocol': const.PROTO_NAME_UDP, + 'source_ip_prefix': dhcp_lla_ip, + 'source_port_range_max': source_port, + 'source_port_range_min': source_port} ] self.assertEqual(port_rpc['security_group_rules'], expected)