Merge "Permit ICMPv6 RAs only from known routers"
This commit is contained in:
commit
db232425e6
@ -241,8 +241,8 @@ class IptablesFirewallDriver(firewall.FirewallDriver):
|
|||||||
return ['-p udp -m udp --sport 67 --dport 68 -j DROP']
|
return ['-p udp -m udp --sport 67 --dport 68 -j DROP']
|
||||||
|
|
||||||
def _accept_inbound_icmpv6(self):
|
def _accept_inbound_icmpv6(self):
|
||||||
# Allow router advertisements, multicast listener
|
# Allow multicast listener, neighbor solicitation and
|
||||||
# and neighbor advertisement into the instance
|
# neighbor advertisement into the instance
|
||||||
icmpv6_rules = []
|
icmpv6_rules = []
|
||||||
for icmp6_type in constants.ICMPV6_ALLOWED_TYPES:
|
for icmp6_type in constants.ICMPV6_ALLOWED_TYPES:
|
||||||
icmpv6_rules += ['-p icmpv6 --icmpv6-type %s -j RETURN' %
|
icmpv6_rules += ['-p icmpv6 --icmpv6-type %s -j RETURN' %
|
||||||
|
@ -106,12 +106,14 @@ PROTO_NUM_UDP = 17
|
|||||||
# Multicast Listener Query (130),
|
# Multicast Listener Query (130),
|
||||||
# Multicast Listener Report (131),
|
# Multicast Listener Report (131),
|
||||||
# Multicast Listener Done (132),
|
# Multicast Listener Done (132),
|
||||||
# Router Advertisement (134),
|
|
||||||
# Neighbor Solicitation (135),
|
# Neighbor Solicitation (135),
|
||||||
# Neighbor Advertisement (136)
|
# Neighbor Advertisement (136)
|
||||||
ICMPV6_ALLOWED_TYPES = [130, 131, 132, 134, 135, 136]
|
ICMPV6_ALLOWED_TYPES = [130, 131, 132, 135, 136]
|
||||||
|
ICMPV6_TYPE_RA = 134
|
||||||
|
|
||||||
DHCPV6_STATEFUL = 'dhcpv6-stateful'
|
DHCPV6_STATEFUL = 'dhcpv6-stateful'
|
||||||
DHCPV6_STATELESS = 'dhcpv6-stateless'
|
DHCPV6_STATELESS = 'dhcpv6-stateless'
|
||||||
IPV6_SLAAC = 'slaac'
|
IPV6_SLAAC = 'slaac'
|
||||||
IPV6_MODES = [DHCPV6_STATEFUL, DHCPV6_STATELESS, IPV6_SLAAC]
|
IPV6_MODES = [DHCPV6_STATEFUL, DHCPV6_STATELESS, IPV6_SLAAC]
|
||||||
|
|
||||||
|
IPV6_LLA_PREFIX = 'fe80::/64'
|
||||||
|
@ -14,8 +14,10 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import netaddr
|
import netaddr
|
||||||
|
from sqlalchemy.orm import exc
|
||||||
|
|
||||||
from neutron.common import constants as q_const
|
from neutron.common import constants as q_const
|
||||||
|
from neutron.common import ipv6_utils as ipv6
|
||||||
from neutron.common import utils
|
from neutron.common import utils
|
||||||
from neutron.db import models_v2
|
from neutron.db import models_v2
|
||||||
from neutron.db import securitygroups_db as sg_db
|
from neutron.db import securitygroups_db as sg_db
|
||||||
@ -220,6 +222,67 @@ class SecurityGroupServerRpcCallbackMixin(object):
|
|||||||
ips[port['network_id']].append(ip)
|
ips[port['network_id']].append(ip)
|
||||||
return ips
|
return ips
|
||||||
|
|
||||||
|
def _select_ra_ips_for_network_ids(self, context, network_ids):
|
||||||
|
"""Select IP addresses to allow sending router advertisement from.
|
||||||
|
|
||||||
|
If OpenStack dnsmasq sends RA, get link local address of
|
||||||
|
gateway and allow RA from this Link Local address.
|
||||||
|
The gateway port link local address will only be obtained
|
||||||
|
when router is created before VM instance is booted and
|
||||||
|
subnet is attached to router.
|
||||||
|
|
||||||
|
If OpenStack doesn't send RA, allow RA from gateway IP.
|
||||||
|
Currently, the gateway IP needs to be link local to be able
|
||||||
|
to send RA to VM.
|
||||||
|
"""
|
||||||
|
if not network_ids:
|
||||||
|
return {}
|
||||||
|
ips = {}
|
||||||
|
for network_id in network_ids:
|
||||||
|
ips[network_id] = set([])
|
||||||
|
query = context.session.query(models_v2.Subnet)
|
||||||
|
subnets = query.filter(models_v2.Subnet.network_id.in_(network_ids))
|
||||||
|
for subnet in subnets:
|
||||||
|
gateway_ip = subnet['gateway_ip']
|
||||||
|
if subnet['ip_version'] != 6 or not gateway_ip:
|
||||||
|
continue
|
||||||
|
# TODO(xuhanp): Figure out how to call the following code
|
||||||
|
# each time router is created or updated.
|
||||||
|
if not netaddr.IPAddress(gateway_ip).is_link_local():
|
||||||
|
if subnet['ipv6_ra_mode']:
|
||||||
|
gateway_ip = self._get_lla_gateway_ip_for_subnet(context,
|
||||||
|
subnet)
|
||||||
|
else:
|
||||||
|
# TODO(xuhanp):Figure out how to allow gateway IP from
|
||||||
|
# existing device to be global address and figure out the
|
||||||
|
# link local address by other method.
|
||||||
|
continue
|
||||||
|
if gateway_ip:
|
||||||
|
ips[subnet['network_id']].add(gateway_ip)
|
||||||
|
|
||||||
|
return ips
|
||||||
|
|
||||||
|
def _get_lla_gateway_ip_for_subnet(self, context, subnet):
|
||||||
|
query = context.session.query(models_v2.Port)
|
||||||
|
query = query.join(models_v2.IPAllocation)
|
||||||
|
query = query.filter(
|
||||||
|
models_v2.IPAllocation.subnet_id == subnet['id'])
|
||||||
|
query = query.filter(
|
||||||
|
models_v2.IPAllocation.ip_address == subnet['gateway_ip'])
|
||||||
|
query = query.filter(models_v2.Port.device_owner ==
|
||||||
|
q_const.DEVICE_OWNER_ROUTER_INTF)
|
||||||
|
try:
|
||||||
|
gateway_port = query.one()
|
||||||
|
except (exc.NoResultFound, exc.MultipleResultsFound):
|
||||||
|
LOG.warn(_('No valid gateway port on subnet %s is '
|
||||||
|
'found for IPv6 RA'), subnet['id'])
|
||||||
|
return
|
||||||
|
mac_address = gateway_port['mac_address']
|
||||||
|
lla_ip = str(ipv6.get_ipv6_addr_by_EUI64(
|
||||||
|
q_const.IPV6_LLA_PREFIX,
|
||||||
|
mac_address))
|
||||||
|
return lla_ip
|
||||||
|
|
||||||
def _convert_remote_group_id_to_ip_prefix(self, context, ports):
|
def _convert_remote_group_id_to_ip_prefix(self, context, ports):
|
||||||
remote_group_ids = self._select_remote_group_ids(ports)
|
remote_group_ids = self._select_remote_group_ids(ports)
|
||||||
ips = self._select_ips_for_remote_group(context, remote_group_ids)
|
ips = self._select_ips_for_remote_group(context, remote_group_ids)
|
||||||
@ -274,17 +337,18 @@ class SecurityGroupServerRpcCallbackMixin(object):
|
|||||||
|
|
||||||
ra_rule = {'direction': 'ingress',
|
ra_rule = {'direction': 'ingress',
|
||||||
'ethertype': q_const.IPv6,
|
'ethertype': q_const.IPv6,
|
||||||
'protocol': 'icmp'}
|
'protocol': 'icmp',
|
||||||
ra_rule['source_ip_prefix'] = "%s/%s" % (ra_ip,
|
'source_ip_prefix': ra_ip,
|
||||||
IP_MASK[q_const.IPv6])
|
'source_port_range_min': q_const.ICMPV6_TYPE_RA}
|
||||||
port['security_group_rules'].append(ra_rule)
|
port['security_group_rules'].append(ra_rule)
|
||||||
|
|
||||||
def _apply_provider_rule(self, context, ports):
|
def _apply_provider_rule(self, context, ports):
|
||||||
network_ids = self._select_network_ids(ports)
|
network_ids = self._select_network_ids(ports)
|
||||||
ips = self._select_dhcp_ips_for_network_ids(context, network_ids)
|
ips_dhcp = self._select_dhcp_ips_for_network_ids(context, network_ids)
|
||||||
|
ips_ra = self._select_ra_ips_for_network_ids(context, network_ids)
|
||||||
for port in ports.values():
|
for port in ports.values():
|
||||||
self._add_ingress_ra_rule(port, ips)
|
self._add_ingress_ra_rule(port, ips_ra)
|
||||||
self._add_ingress_dhcp_rule(port, ips)
|
self._add_ingress_dhcp_rule(port, ips_dhcp)
|
||||||
|
|
||||||
def _security_group_rules_for_ports(self, context, ports):
|
def _security_group_rules_for_ports(self, context, ports):
|
||||||
rules_in_db = self._select_rules_for_ports(context, ports)
|
rules_in_db = self._select_rules_for_ports(context, ports)
|
||||||
|
@ -75,6 +75,18 @@ class TestOneConvergenceSGServerRpcCallBack(
|
|||||||
def test_security_group_rules_for_devices_ipv6_source_group(self):
|
def test_security_group_rules_for_devices_ipv6_source_group(self):
|
||||||
self.skipTest("NVSD Plugin does not support IPV6.")
|
self.skipTest("NVSD Plugin does not support IPV6.")
|
||||||
|
|
||||||
|
def test_security_group_ra_rules_for_devices_ipv6_gateway_global(self):
|
||||||
|
self.skipTest("NVSD Plugin does not support IPV6.")
|
||||||
|
|
||||||
|
def test_security_group_ra_rules_for_devices_ipv6_gateway_lla(self):
|
||||||
|
self.skipTest("NVSD Plugin does not support IPV6.")
|
||||||
|
|
||||||
|
def test_security_group_ra_rules_for_devices_ipv6_no_gateway_port(self):
|
||||||
|
self.skipTest("NVSD Plugin does not support IPV6.")
|
||||||
|
|
||||||
|
def test_security_group_rule_for_device_ipv6_multi_router_interfaces(self):
|
||||||
|
self.skipTest("NVSD Plugin does not support IPV6.")
|
||||||
|
|
||||||
|
|
||||||
class TestOneConvergenceSGServerRpcCallBackXML(
|
class TestOneConvergenceSGServerRpcCallBackXML(
|
||||||
OneConvergenceSecurityGroupsTestCase,
|
OneConvergenceSecurityGroupsTestCase,
|
||||||
@ -88,6 +100,18 @@ class TestOneConvergenceSGServerRpcCallBackXML(
|
|||||||
def test_security_group_rules_for_devices_ipv6_source_group(self):
|
def test_security_group_rules_for_devices_ipv6_source_group(self):
|
||||||
self.skipTest("NVSD Plugin does not support IPV6.")
|
self.skipTest("NVSD Plugin does not support IPV6.")
|
||||||
|
|
||||||
|
def test_security_group_ra_rules_for_devices_ipv6_gateway_global(self):
|
||||||
|
self.skipTest("NVSD Plugin does not support IPV6.")
|
||||||
|
|
||||||
|
def test_security_group_ra_rules_for_devices_ipv6_gateway_lla(self):
|
||||||
|
self.skipTest("NVSD Plugin does not support IPV6.")
|
||||||
|
|
||||||
|
def test_security_group_ra_rules_for_devices_ipv6_no_gateway_port(self):
|
||||||
|
self.skipTest("NVSD Plugin does not support IPV6.")
|
||||||
|
|
||||||
|
def test_security_group_rule_for_device_ipv6_multi_router_interfaces(self):
|
||||||
|
self.skipTest("NVSD Plugin does not support IPV6.")
|
||||||
|
|
||||||
|
|
||||||
class TestOneConvergenceSecurityGroups(OneConvergenceSecurityGroupsTestCase,
|
class TestOneConvergenceSecurityGroups(OneConvergenceSecurityGroupsTestCase,
|
||||||
test_sg.TestSecurityGroups,
|
test_sg.TestSecurityGroups,
|
||||||
|
@ -30,6 +30,7 @@ from neutron.agent.linux import iptables_manager
|
|||||||
from neutron.agent import rpc as agent_rpc
|
from neutron.agent import rpc as agent_rpc
|
||||||
from neutron.agent import securitygroups_rpc as sg_rpc
|
from neutron.agent import securitygroups_rpc as sg_rpc
|
||||||
from neutron.common import constants as const
|
from neutron.common import constants as const
|
||||||
|
from neutron.common import ipv6_utils as ipv6
|
||||||
from neutron import context
|
from neutron import context
|
||||||
from neutron.db import securitygroups_rpc_base as sg_db_rpc
|
from neutron.db import securitygroups_rpc_base as sg_db_rpc
|
||||||
from neutron.extensions import allowedaddresspairs as addr_pair
|
from neutron.extensions import allowedaddresspairs as addr_pair
|
||||||
@ -38,7 +39,14 @@ from neutron.manager import NeutronManager
|
|||||||
from neutron.openstack.common.rpc import proxy
|
from neutron.openstack.common.rpc import proxy
|
||||||
from neutron.tests import base
|
from neutron.tests import base
|
||||||
from neutron.tests.unit import test_extension_security_group as test_sg
|
from neutron.tests.unit import test_extension_security_group as test_sg
|
||||||
from neutron.tests.unit import test_iptables_firewall as test_fw
|
|
||||||
|
|
||||||
|
FAKE_PREFIX = {const.IPv4: '10.0.0.0/24',
|
||||||
|
const.IPv6: '2001:0db8::/64'}
|
||||||
|
FAKE_IP = {const.IPv4: '10.0.0.1',
|
||||||
|
const.IPv6: 'fe80::1',
|
||||||
|
'IPv6_GLOBAL': '2001:0db8::1',
|
||||||
|
'IPv6_LLA': 'fe80::123'}
|
||||||
|
|
||||||
|
|
||||||
class FakeSGCallback(sg_db_rpc.SecurityGroupServerRpcCallbackMixin):
|
class FakeSGCallback(sg_db_rpc.SecurityGroupServerRpcCallbackMixin):
|
||||||
@ -61,7 +69,7 @@ class SGServerRpcCallBackMixinTestCase(test_sg.SecurityGroupDBTestCase):
|
|||||||
self.rpc = FakeSGCallback()
|
self.rpc = FakeSGCallback()
|
||||||
|
|
||||||
def test_security_group_rules_for_devices_ipv4_ingress(self):
|
def test_security_group_rules_for_devices_ipv4_ingress(self):
|
||||||
fake_prefix = test_fw.FAKE_PREFIX[const.IPv4]
|
fake_prefix = FAKE_PREFIX[const.IPv4]
|
||||||
with self.network() as n:
|
with self.network() as n:
|
||||||
with nested(self.subnet(n),
|
with nested(self.subnet(n),
|
||||||
self.security_group()) as (subnet_v4,
|
self.security_group()) as (subnet_v4,
|
||||||
@ -119,7 +127,7 @@ class SGServerRpcCallBackMixinTestCase(test_sg.SecurityGroupDBTestCase):
|
|||||||
if ('allowed-address-pairs'
|
if ('allowed-address-pairs'
|
||||||
not in plugin_obj.supported_extension_aliases):
|
not in plugin_obj.supported_extension_aliases):
|
||||||
self.skipTest("Test depeneds on allowed-address-pairs extension")
|
self.skipTest("Test depeneds on allowed-address-pairs extension")
|
||||||
fake_prefix = test_fw.FAKE_PREFIX['IPv4']
|
fake_prefix = FAKE_PREFIX['IPv4']
|
||||||
with self.network() as n:
|
with self.network() as n:
|
||||||
with nested(self.subnet(n),
|
with nested(self.subnet(n),
|
||||||
self.security_group()) as (subnet_v4,
|
self.security_group()) as (subnet_v4,
|
||||||
@ -178,7 +186,7 @@ class SGServerRpcCallBackMixinTestCase(test_sg.SecurityGroupDBTestCase):
|
|||||||
self._delete('ports', port_id1)
|
self._delete('ports', port_id1)
|
||||||
|
|
||||||
def test_security_group_rules_for_devices_ipv4_egress(self):
|
def test_security_group_rules_for_devices_ipv4_egress(self):
|
||||||
fake_prefix = test_fw.FAKE_PREFIX[const.IPv4]
|
fake_prefix = FAKE_PREFIX[const.IPv4]
|
||||||
with self.network() as n:
|
with self.network() as n:
|
||||||
with nested(self.subnet(n),
|
with nested(self.subnet(n),
|
||||||
self.security_group()) as (subnet_v4,
|
self.security_group()) as (subnet_v4,
|
||||||
@ -291,9 +299,11 @@ class SGServerRpcCallBackMixinTestCase(test_sg.SecurityGroupDBTestCase):
|
|||||||
self._delete('ports', port_id2)
|
self._delete('ports', port_id2)
|
||||||
|
|
||||||
def test_security_group_rules_for_devices_ipv6_ingress(self):
|
def test_security_group_rules_for_devices_ipv6_ingress(self):
|
||||||
fake_prefix = test_fw.FAKE_PREFIX[const.IPv6]
|
fake_prefix = FAKE_PREFIX[const.IPv6]
|
||||||
|
fake_gateway = FAKE_IP[const.IPv6]
|
||||||
with self.network() as n:
|
with self.network() as n:
|
||||||
with nested(self.subnet(n,
|
with nested(self.subnet(n,
|
||||||
|
gateway_ip=fake_gateway,
|
||||||
cidr=fake_prefix,
|
cidr=fake_prefix,
|
||||||
ip_version=6),
|
ip_version=6),
|
||||||
self.security_group()) as (subnet_v6,
|
self.security_group()) as (subnet_v6,
|
||||||
@ -341,18 +351,271 @@ class SGServerRpcCallBackMixinTestCase(test_sg.SecurityGroupDBTestCase):
|
|||||||
{'direction': 'ingress',
|
{'direction': 'ingress',
|
||||||
'protocol': const.PROTO_NAME_UDP,
|
'protocol': const.PROTO_NAME_UDP,
|
||||||
'ethertype': const.IPv6,
|
'ethertype': const.IPv6,
|
||||||
'port_range_max': 23, 'security_group_id': sg1_id,
|
'port_range_max': 23,
|
||||||
|
'security_group_id': sg1_id,
|
||||||
'port_range_min': 23,
|
'port_range_min': 23,
|
||||||
'source_ip_prefix': fake_prefix},
|
'source_ip_prefix': fake_prefix},
|
||||||
|
{'direction': 'ingress',
|
||||||
|
'protocol': const.PROTO_NAME_ICMP,
|
||||||
|
'ethertype': const.IPv6,
|
||||||
|
'source_ip_prefix': fake_gateway,
|
||||||
|
'source_port_range_min': const.ICMPV6_TYPE_RA},
|
||||||
|
]
|
||||||
|
self.assertEqual(port_rpc['security_group_rules'],
|
||||||
|
expected)
|
||||||
|
self._delete('ports', port_id1)
|
||||||
|
|
||||||
|
def test_security_group_ra_rules_for_devices_ipv6_gateway_global(self):
|
||||||
|
fake_prefix = FAKE_PREFIX[const.IPv6]
|
||||||
|
fake_gateway = FAKE_IP['IPv6_GLOBAL']
|
||||||
|
with self.network() as n:
|
||||||
|
with nested(self.subnet(n,
|
||||||
|
gateway_ip=fake_gateway,
|
||||||
|
cidr=fake_prefix,
|
||||||
|
ip_version=6,
|
||||||
|
ipv6_ra_mode=const.IPV6_SLAAC),
|
||||||
|
self.security_group()) as (subnet_v6,
|
||||||
|
sg1):
|
||||||
|
sg1_id = sg1['security_group']['id']
|
||||||
|
rule1 = self._build_security_group_rule(
|
||||||
|
sg1_id,
|
||||||
|
'ingress', const.PROTO_NAME_TCP, '22',
|
||||||
|
'22',
|
||||||
|
ethertype=const.IPv6)
|
||||||
|
rules = {
|
||||||
|
'security_group_rules': [rule1['security_group_rule']]}
|
||||||
|
self._make_security_group_rule(self.fmt, rules)
|
||||||
|
|
||||||
|
# Create gateway port
|
||||||
|
gateway_res = self._make_port(
|
||||||
|
self.fmt, n['network']['id'],
|
||||||
|
fixed_ips=[{'subnet_id': subnet_v6['subnet']['id'],
|
||||||
|
'ip_address': fake_gateway}],
|
||||||
|
device_owner='network:router_interface')
|
||||||
|
gateway_mac = gateway_res['port']['mac_address']
|
||||||
|
gateway_port_id = gateway_res['port']['id']
|
||||||
|
gateway_lla_ip = str(ipv6.get_ipv6_addr_by_EUI64(
|
||||||
|
const.IPV6_LLA_PREFIX,
|
||||||
|
gateway_mac))
|
||||||
|
|
||||||
|
ports_rest1 = self._make_port(
|
||||||
|
self.fmt, n['network']['id'],
|
||||||
|
fixed_ips=[{'subnet_id': subnet_v6['subnet']['id']}],
|
||||||
|
security_groups=[sg1_id])
|
||||||
|
port_id1 = ports_rest1['port']['id']
|
||||||
|
self.rpc.devices = {port_id1: ports_rest1['port']}
|
||||||
|
devices = [port_id1, 'no_exist_device']
|
||||||
|
ctx = context.get_admin_context()
|
||||||
|
ports_rpc = self.rpc.security_group_rules_for_devices(
|
||||||
|
ctx, devices=devices)
|
||||||
|
port_rpc = ports_rpc[port_id1]
|
||||||
|
expected = [{'direction': 'egress', 'ethertype': const.IPv4,
|
||||||
|
'security_group_id': sg1_id},
|
||||||
|
{'direction': 'egress', 'ethertype': const.IPv6,
|
||||||
|
'security_group_id': sg1_id},
|
||||||
|
{'direction': 'ingress',
|
||||||
|
'protocol': const.PROTO_NAME_TCP,
|
||||||
|
'ethertype': const.IPv6,
|
||||||
|
'port_range_max': 22,
|
||||||
|
'security_group_id': sg1_id,
|
||||||
|
'port_range_min': 22},
|
||||||
|
{'direction': 'ingress',
|
||||||
|
'protocol': const.PROTO_NAME_ICMP,
|
||||||
|
'ethertype': const.IPv6,
|
||||||
|
'source_ip_prefix': gateway_lla_ip,
|
||||||
|
'source_port_range_min': const.ICMPV6_TYPE_RA},
|
||||||
|
]
|
||||||
|
self.assertEqual(port_rpc['security_group_rules'],
|
||||||
|
expected)
|
||||||
|
self._delete('ports', port_id1)
|
||||||
|
# Note(xuhanp): remove gateway port's fixed_ips or gateway port
|
||||||
|
# deletion will be prevented.
|
||||||
|
data = {'port': {'fixed_ips': []}}
|
||||||
|
req = self.new_update_request('ports', data, gateway_port_id)
|
||||||
|
self.deserialize(self.fmt, req.get_response(self.api))
|
||||||
|
self._delete('ports', gateway_port_id)
|
||||||
|
|
||||||
|
def test_security_group_rule_for_device_ipv6_multi_router_interfaces(self):
|
||||||
|
fake_prefix = FAKE_PREFIX[const.IPv6]
|
||||||
|
fake_gateway = FAKE_IP['IPv6_GLOBAL']
|
||||||
|
with self.network() as n:
|
||||||
|
with nested(self.subnet(n,
|
||||||
|
gateway_ip=fake_gateway,
|
||||||
|
cidr=fake_prefix,
|
||||||
|
ip_version=6,
|
||||||
|
ipv6_ra_mode=const.IPV6_SLAAC),
|
||||||
|
self.security_group()) as (subnet_v6,
|
||||||
|
sg1):
|
||||||
|
sg1_id = sg1['security_group']['id']
|
||||||
|
rule1 = self._build_security_group_rule(
|
||||||
|
sg1_id,
|
||||||
|
'ingress', const.PROTO_NAME_TCP, '22',
|
||||||
|
'22',
|
||||||
|
ethertype=const.IPv6)
|
||||||
|
rules = {
|
||||||
|
'security_group_rules': [rule1['security_group_rule']]}
|
||||||
|
self._make_security_group_rule(self.fmt, rules)
|
||||||
|
|
||||||
|
# Create gateway port
|
||||||
|
gateway_res = self._make_port(
|
||||||
|
self.fmt, n['network']['id'],
|
||||||
|
fixed_ips=[{'subnet_id': subnet_v6['subnet']['id'],
|
||||||
|
'ip_address': fake_gateway}],
|
||||||
|
device_owner='network:router_interface')
|
||||||
|
gateway_mac = gateway_res['port']['mac_address']
|
||||||
|
gateway_port_id = gateway_res['port']['id']
|
||||||
|
gateway_lla_ip = str(ipv6.get_ipv6_addr_by_EUI64(
|
||||||
|
const.IPV6_LLA_PREFIX,
|
||||||
|
gateway_mac))
|
||||||
|
# Create another router interface port
|
||||||
|
interface_res = self._make_port(
|
||||||
|
self.fmt, n['network']['id'],
|
||||||
|
fixed_ips=[{'subnet_id': subnet_v6['subnet']['id']}],
|
||||||
|
device_owner='network:router_interface')
|
||||||
|
interface_port_id = interface_res['port']['id']
|
||||||
|
|
||||||
|
ports_rest1 = self._make_port(
|
||||||
|
self.fmt, n['network']['id'],
|
||||||
|
fixed_ips=[{'subnet_id': subnet_v6['subnet']['id']}],
|
||||||
|
security_groups=[sg1_id])
|
||||||
|
port_id1 = ports_rest1['port']['id']
|
||||||
|
self.rpc.devices = {port_id1: ports_rest1['port']}
|
||||||
|
devices = [port_id1, 'no_exist_device']
|
||||||
|
ctx = context.get_admin_context()
|
||||||
|
ports_rpc = self.rpc.security_group_rules_for_devices(
|
||||||
|
ctx, devices=devices)
|
||||||
|
port_rpc = ports_rpc[port_id1]
|
||||||
|
expected = [{'direction': 'egress', 'ethertype': const.IPv4,
|
||||||
|
'security_group_id': sg1_id},
|
||||||
|
{'direction': 'egress', 'ethertype': const.IPv6,
|
||||||
|
'security_group_id': sg1_id},
|
||||||
|
{'direction': 'ingress',
|
||||||
|
'protocol': const.PROTO_NAME_TCP,
|
||||||
|
'ethertype': const.IPv6,
|
||||||
|
'port_range_max': 22,
|
||||||
|
'security_group_id': sg1_id,
|
||||||
|
'port_range_min': 22},
|
||||||
|
{'direction': 'ingress',
|
||||||
|
'protocol': const.PROTO_NAME_ICMP,
|
||||||
|
'ethertype': const.IPv6,
|
||||||
|
'source_ip_prefix': gateway_lla_ip,
|
||||||
|
'source_port_range_min': const.ICMPV6_TYPE_RA},
|
||||||
|
]
|
||||||
|
self.assertEqual(port_rpc['security_group_rules'],
|
||||||
|
expected)
|
||||||
|
self._delete('ports', port_id1)
|
||||||
|
data = {'port': {'fixed_ips': []}}
|
||||||
|
req = self.new_update_request('ports', data, gateway_port_id)
|
||||||
|
self.deserialize(self.fmt, req.get_response(self.api))
|
||||||
|
req = self.new_update_request('ports', data, interface_port_id)
|
||||||
|
self.deserialize(self.fmt, req.get_response(self.api))
|
||||||
|
self._delete('ports', gateway_port_id)
|
||||||
|
self._delete('ports', interface_port_id)
|
||||||
|
|
||||||
|
def test_security_group_ra_rules_for_devices_ipv6_gateway_lla(self):
|
||||||
|
fake_prefix = FAKE_PREFIX[const.IPv6]
|
||||||
|
fake_gateway = FAKE_IP['IPv6_LLA']
|
||||||
|
with self.network() as n:
|
||||||
|
with nested(self.subnet(n,
|
||||||
|
gateway_ip=fake_gateway,
|
||||||
|
cidr=fake_prefix,
|
||||||
|
ip_version=6,
|
||||||
|
ipv6_ra_mode=const.IPV6_SLAAC),
|
||||||
|
self.security_group()) as (subnet_v6,
|
||||||
|
sg1):
|
||||||
|
sg1_id = sg1['security_group']['id']
|
||||||
|
rule1 = self._build_security_group_rule(
|
||||||
|
sg1_id,
|
||||||
|
'ingress', const.PROTO_NAME_TCP, '22',
|
||||||
|
'22',
|
||||||
|
ethertype=const.IPv6)
|
||||||
|
rules = {
|
||||||
|
'security_group_rules': [rule1['security_group_rule']]}
|
||||||
|
self._make_security_group_rule(self.fmt, rules)
|
||||||
|
|
||||||
|
ports_rest1 = self._make_port(
|
||||||
|
self.fmt, n['network']['id'],
|
||||||
|
fixed_ips=[{'subnet_id': subnet_v6['subnet']['id']}],
|
||||||
|
security_groups=[sg1_id])
|
||||||
|
port_id1 = ports_rest1['port']['id']
|
||||||
|
self.rpc.devices = {port_id1: ports_rest1['port']}
|
||||||
|
devices = [port_id1, 'no_exist_device']
|
||||||
|
ctx = context.get_admin_context()
|
||||||
|
ports_rpc = self.rpc.security_group_rules_for_devices(
|
||||||
|
ctx, devices=devices)
|
||||||
|
port_rpc = ports_rpc[port_id1]
|
||||||
|
expected = [{'direction': 'egress', 'ethertype': const.IPv4,
|
||||||
|
'security_group_id': sg1_id},
|
||||||
|
{'direction': 'egress', 'ethertype': const.IPv6,
|
||||||
|
'security_group_id': sg1_id},
|
||||||
|
{'direction': 'ingress',
|
||||||
|
'protocol': const.PROTO_NAME_TCP,
|
||||||
|
'ethertype': const.IPv6,
|
||||||
|
'port_range_max': 22,
|
||||||
|
'security_group_id': sg1_id,
|
||||||
|
'port_range_min': 22},
|
||||||
|
{'direction': 'ingress',
|
||||||
|
'protocol': const.PROTO_NAME_ICMP,
|
||||||
|
'ethertype': const.IPv6,
|
||||||
|
'source_ip_prefix': fake_gateway,
|
||||||
|
'source_port_range_min': const.ICMPV6_TYPE_RA},
|
||||||
|
]
|
||||||
|
self.assertEqual(port_rpc['security_group_rules'],
|
||||||
|
expected)
|
||||||
|
self._delete('ports', port_id1)
|
||||||
|
|
||||||
|
def test_security_group_ra_rules_for_devices_ipv6_no_gateway_port(self):
|
||||||
|
fake_prefix = FAKE_PREFIX[const.IPv6]
|
||||||
|
with self.network() as n:
|
||||||
|
with nested(self.subnet(n,
|
||||||
|
gateway_ip=None,
|
||||||
|
cidr=fake_prefix,
|
||||||
|
ip_version=6,
|
||||||
|
ipv6_ra_mode=const.IPV6_SLAAC),
|
||||||
|
self.security_group()) as (subnet_v6,
|
||||||
|
sg1):
|
||||||
|
sg1_id = sg1['security_group']['id']
|
||||||
|
rule1 = self._build_security_group_rule(
|
||||||
|
sg1_id,
|
||||||
|
'ingress', const.PROTO_NAME_TCP, '22',
|
||||||
|
'22',
|
||||||
|
ethertype=const.IPv6)
|
||||||
|
rules = {
|
||||||
|
'security_group_rules': [rule1['security_group_rule']]}
|
||||||
|
self._make_security_group_rule(self.fmt, rules)
|
||||||
|
|
||||||
|
ports_rest1 = self._make_port(
|
||||||
|
self.fmt, n['network']['id'],
|
||||||
|
fixed_ips=[{'subnet_id': subnet_v6['subnet']['id']}],
|
||||||
|
security_groups=[sg1_id])
|
||||||
|
port_id1 = ports_rest1['port']['id']
|
||||||
|
self.rpc.devices = {port_id1: ports_rest1['port']}
|
||||||
|
devices = [port_id1, 'no_exist_device']
|
||||||
|
ctx = context.get_admin_context()
|
||||||
|
ports_rpc = self.rpc.security_group_rules_for_devices(
|
||||||
|
ctx, devices=devices)
|
||||||
|
port_rpc = ports_rpc[port_id1]
|
||||||
|
expected = [{'direction': 'egress', 'ethertype': const.IPv4,
|
||||||
|
'security_group_id': sg1_id},
|
||||||
|
{'direction': 'egress', 'ethertype': const.IPv6,
|
||||||
|
'security_group_id': sg1_id},
|
||||||
|
{'direction': 'ingress',
|
||||||
|
'protocol': const.PROTO_NAME_TCP,
|
||||||
|
'ethertype': const.IPv6,
|
||||||
|
'port_range_max': 22,
|
||||||
|
'security_group_id': sg1_id,
|
||||||
|
'port_range_min': 22},
|
||||||
]
|
]
|
||||||
self.assertEqual(port_rpc['security_group_rules'],
|
self.assertEqual(port_rpc['security_group_rules'],
|
||||||
expected)
|
expected)
|
||||||
self._delete('ports', port_id1)
|
self._delete('ports', port_id1)
|
||||||
|
|
||||||
def test_security_group_rules_for_devices_ipv6_egress(self):
|
def test_security_group_rules_for_devices_ipv6_egress(self):
|
||||||
fake_prefix = test_fw.FAKE_PREFIX[const.IPv6]
|
fake_prefix = FAKE_PREFIX[const.IPv6]
|
||||||
|
fake_gateway = FAKE_IP[const.IPv6]
|
||||||
with self.network() as n:
|
with self.network() as n:
|
||||||
with nested(self.subnet(n,
|
with nested(self.subnet(n,
|
||||||
|
gateway_ip=fake_gateway,
|
||||||
cidr=fake_prefix,
|
cidr=fake_prefix,
|
||||||
ip_version=6),
|
ip_version=6),
|
||||||
self.security_group()) as (subnet_v6,
|
self.security_group()) as (subnet_v6,
|
||||||
@ -371,15 +634,12 @@ class SGServerRpcCallBackMixinTestCase(test_sg.SecurityGroupDBTestCase):
|
|||||||
rules = {
|
rules = {
|
||||||
'security_group_rules': [rule1['security_group_rule'],
|
'security_group_rules': [rule1['security_group_rule'],
|
||||||
rule2['security_group_rule']]}
|
rule2['security_group_rule']]}
|
||||||
res = self._create_security_group_rule(self.fmt, rules)
|
self._make_security_group_rule(self.fmt, rules)
|
||||||
self.deserialize(self.fmt, res)
|
|
||||||
self.assertEqual(res.status_int, webob.exc.HTTPCreated.code)
|
|
||||||
|
|
||||||
res1 = self._create_port(
|
ports_rest1 = self._make_port(
|
||||||
self.fmt, n['network']['id'],
|
self.fmt, n['network']['id'],
|
||||||
fixed_ips=[{'subnet_id': subnet_v6['subnet']['id']}],
|
fixed_ips=[{'subnet_id': subnet_v6['subnet']['id']}],
|
||||||
security_groups=[sg1_id])
|
security_groups=[sg1_id])
|
||||||
ports_rest1 = self.deserialize(self.fmt, res1)
|
|
||||||
port_id1 = ports_rest1['port']['id']
|
port_id1 = ports_rest1['port']['id']
|
||||||
self.rpc.devices = {port_id1: ports_rest1['port']}
|
self.rpc.devices = {port_id1: ports_rest1['port']}
|
||||||
devices = [port_id1, 'no_exist_device']
|
devices = [port_id1, 'no_exist_device']
|
||||||
@ -405,15 +665,22 @@ class SGServerRpcCallBackMixinTestCase(test_sg.SecurityGroupDBTestCase):
|
|||||||
'security_group_id': sg1_id,
|
'security_group_id': sg1_id,
|
||||||
'port_range_min': 23,
|
'port_range_min': 23,
|
||||||
'dest_ip_prefix': fake_prefix},
|
'dest_ip_prefix': fake_prefix},
|
||||||
|
{'direction': 'ingress',
|
||||||
|
'protocol': const.PROTO_NAME_ICMP,
|
||||||
|
'ethertype': const.IPv6,
|
||||||
|
'source_ip_prefix': fake_gateway,
|
||||||
|
'source_port_range_min': const.ICMPV6_TYPE_RA},
|
||||||
]
|
]
|
||||||
self.assertEqual(port_rpc['security_group_rules'],
|
self.assertEqual(port_rpc['security_group_rules'],
|
||||||
expected)
|
expected)
|
||||||
self._delete('ports', port_id1)
|
self._delete('ports', port_id1)
|
||||||
|
|
||||||
def test_security_group_rules_for_devices_ipv6_source_group(self):
|
def test_security_group_rules_for_devices_ipv6_source_group(self):
|
||||||
fake_prefix = test_fw.FAKE_PREFIX[const.IPv6]
|
fake_prefix = FAKE_PREFIX[const.IPv6]
|
||||||
|
fake_gateway = FAKE_IP[const.IPv6]
|
||||||
with self.network() as n:
|
with self.network() as n:
|
||||||
with nested(self.subnet(n,
|
with nested(self.subnet(n,
|
||||||
|
gateway_ip=fake_gateway,
|
||||||
cidr=fake_prefix,
|
cidr=fake_prefix,
|
||||||
ip_version=6),
|
ip_version=6),
|
||||||
self.security_group(),
|
self.security_group(),
|
||||||
@ -430,25 +697,21 @@ class SGServerRpcCallBackMixinTestCase(test_sg.SecurityGroupDBTestCase):
|
|||||||
remote_group_id=sg2['security_group']['id'])
|
remote_group_id=sg2['security_group']['id'])
|
||||||
rules = {
|
rules = {
|
||||||
'security_group_rules': [rule1['security_group_rule']]}
|
'security_group_rules': [rule1['security_group_rule']]}
|
||||||
res = self._create_security_group_rule(self.fmt, rules)
|
self._make_security_group_rule(self.fmt, rules)
|
||||||
self.deserialize(self.fmt, res)
|
|
||||||
self.assertEqual(res.status_int, webob.exc.HTTPCreated.code)
|
|
||||||
|
|
||||||
res1 = self._create_port(
|
ports_rest1 = self._make_port(
|
||||||
self.fmt, n['network']['id'],
|
self.fmt, n['network']['id'],
|
||||||
fixed_ips=[{'subnet_id': subnet_v6['subnet']['id']}],
|
fixed_ips=[{'subnet_id': subnet_v6['subnet']['id']}],
|
||||||
security_groups=[sg1_id,
|
security_groups=[sg1_id,
|
||||||
sg2_id])
|
sg2_id])
|
||||||
ports_rest1 = self.deserialize(self.fmt, res1)
|
|
||||||
port_id1 = ports_rest1['port']['id']
|
port_id1 = ports_rest1['port']['id']
|
||||||
self.rpc.devices = {port_id1: ports_rest1['port']}
|
self.rpc.devices = {port_id1: ports_rest1['port']}
|
||||||
devices = [port_id1, 'no_exist_device']
|
devices = [port_id1, 'no_exist_device']
|
||||||
|
|
||||||
res2 = self._create_port(
|
ports_rest2 = self._make_port(
|
||||||
self.fmt, n['network']['id'],
|
self.fmt, n['network']['id'],
|
||||||
fixed_ips=[{'subnet_id': subnet_v6['subnet']['id']}],
|
fixed_ips=[{'subnet_id': subnet_v6['subnet']['id']}],
|
||||||
security_groups=[sg2_id])
|
security_groups=[sg2_id])
|
||||||
ports_rest2 = self.deserialize(self.fmt, res2)
|
|
||||||
port_id2 = ports_rest2['port']['id']
|
port_id2 = ports_rest2['port']['id']
|
||||||
|
|
||||||
ctx = context.get_admin_context()
|
ctx = context.get_admin_context()
|
||||||
@ -464,12 +727,17 @@ class SGServerRpcCallBackMixinTestCase(test_sg.SecurityGroupDBTestCase):
|
|||||||
{'direction': 'egress', 'ethertype': const.IPv6,
|
{'direction': 'egress', 'ethertype': const.IPv6,
|
||||||
'security_group_id': sg2_id},
|
'security_group_id': sg2_id},
|
||||||
{'direction': 'ingress',
|
{'direction': 'ingress',
|
||||||
'source_ip_prefix': 'fe80::3/128',
|
'source_ip_prefix': '2001:db8::2/128',
|
||||||
'protocol': const.PROTO_NAME_TCP,
|
'protocol': const.PROTO_NAME_TCP,
|
||||||
'ethertype': const.IPv6,
|
'ethertype': const.IPv6,
|
||||||
'port_range_max': 25, 'port_range_min': 24,
|
'port_range_max': 25, 'port_range_min': 24,
|
||||||
'remote_group_id': sg2_id,
|
'remote_group_id': sg2_id,
|
||||||
'security_group_id': sg1_id},
|
'security_group_id': sg1_id},
|
||||||
|
{'direction': 'ingress',
|
||||||
|
'protocol': const.PROTO_NAME_ICMP,
|
||||||
|
'ethertype': const.IPv6,
|
||||||
|
'source_ip_prefix': fake_gateway,
|
||||||
|
'source_port_range_min': const.ICMPV6_TYPE_RA},
|
||||||
]
|
]
|
||||||
self.assertEqual(port_rpc['security_group_rules'],
|
self.assertEqual(port_rpc['security_group_rules'],
|
||||||
expected)
|
expected)
|
||||||
@ -1304,7 +1572,6 @@ IPTABLES_FILTER_V6_1 = """# Generated by iptables_manager
|
|||||||
[0:0] -A %(bn)s-i_port1 -p icmpv6 --icmpv6-type 130 -j RETURN
|
[0:0] -A %(bn)s-i_port1 -p icmpv6 --icmpv6-type 130 -j RETURN
|
||||||
[0:0] -A %(bn)s-i_port1 -p icmpv6 --icmpv6-type 131 -j RETURN
|
[0:0] -A %(bn)s-i_port1 -p icmpv6 --icmpv6-type 131 -j RETURN
|
||||||
[0:0] -A %(bn)s-i_port1 -p icmpv6 --icmpv6-type 132 -j RETURN
|
[0:0] -A %(bn)s-i_port1 -p icmpv6 --icmpv6-type 132 -j RETURN
|
||||||
[0:0] -A %(bn)s-i_port1 -p icmpv6 --icmpv6-type 134 -j RETURN
|
|
||||||
[0:0] -A %(bn)s-i_port1 -p icmpv6 --icmpv6-type 135 -j RETURN
|
[0:0] -A %(bn)s-i_port1 -p icmpv6 --icmpv6-type 135 -j RETURN
|
||||||
[0:0] -A %(bn)s-i_port1 -p icmpv6 --icmpv6-type 136 -j RETURN
|
[0:0] -A %(bn)s-i_port1 -p icmpv6 --icmpv6-type 136 -j RETURN
|
||||||
[0:0] -A %(bn)s-i_port1 -m state --state INVALID -j DROP
|
[0:0] -A %(bn)s-i_port1 -m state --state INVALID -j DROP
|
||||||
@ -1355,7 +1622,6 @@ IPTABLES_FILTER_V6_2 = """# Generated by iptables_manager
|
|||||||
[0:0] -A %(bn)s-i_port1 -p icmpv6 --icmpv6-type 130 -j RETURN
|
[0:0] -A %(bn)s-i_port1 -p icmpv6 --icmpv6-type 130 -j RETURN
|
||||||
[0:0] -A %(bn)s-i_port1 -p icmpv6 --icmpv6-type 131 -j RETURN
|
[0:0] -A %(bn)s-i_port1 -p icmpv6 --icmpv6-type 131 -j RETURN
|
||||||
[0:0] -A %(bn)s-i_port1 -p icmpv6 --icmpv6-type 132 -j RETURN
|
[0:0] -A %(bn)s-i_port1 -p icmpv6 --icmpv6-type 132 -j RETURN
|
||||||
[0:0] -A %(bn)s-i_port1 -p icmpv6 --icmpv6-type 134 -j RETURN
|
|
||||||
[0:0] -A %(bn)s-i_port1 -p icmpv6 --icmpv6-type 135 -j RETURN
|
[0:0] -A %(bn)s-i_port1 -p icmpv6 --icmpv6-type 135 -j RETURN
|
||||||
[0:0] -A %(bn)s-i_port1 -p icmpv6 --icmpv6-type 136 -j RETURN
|
[0:0] -A %(bn)s-i_port1 -p icmpv6 --icmpv6-type 136 -j RETURN
|
||||||
[0:0] -A %(bn)s-i_port1 -m state --state INVALID -j DROP
|
[0:0] -A %(bn)s-i_port1 -m state --state INVALID -j DROP
|
||||||
@ -1378,7 +1644,6 @@ IPTABLES_FILTER_V6_2 = """# Generated by iptables_manager
|
|||||||
[0:0] -A %(bn)s-i_port2 -p icmpv6 --icmpv6-type 130 -j RETURN
|
[0:0] -A %(bn)s-i_port2 -p icmpv6 --icmpv6-type 130 -j RETURN
|
||||||
[0:0] -A %(bn)s-i_port2 -p icmpv6 --icmpv6-type 131 -j RETURN
|
[0:0] -A %(bn)s-i_port2 -p icmpv6 --icmpv6-type 131 -j RETURN
|
||||||
[0:0] -A %(bn)s-i_port2 -p icmpv6 --icmpv6-type 132 -j RETURN
|
[0:0] -A %(bn)s-i_port2 -p icmpv6 --icmpv6-type 132 -j RETURN
|
||||||
[0:0] -A %(bn)s-i_port2 -p icmpv6 --icmpv6-type 134 -j RETURN
|
|
||||||
[0:0] -A %(bn)s-i_port2 -p icmpv6 --icmpv6-type 135 -j RETURN
|
[0:0] -A %(bn)s-i_port2 -p icmpv6 --icmpv6-type 135 -j RETURN
|
||||||
[0:0] -A %(bn)s-i_port2 -p icmpv6 --icmpv6-type 136 -j RETURN
|
[0:0] -A %(bn)s-i_port2 -p icmpv6 --icmpv6-type 136 -j RETURN
|
||||||
[0:0] -A %(bn)s-i_port2 -m state --state INVALID -j DROP
|
[0:0] -A %(bn)s-i_port2 -m state --state INVALID -j DROP
|
||||||
|
Loading…
Reference in New Issue
Block a user