fad8f4098f
When Noop Firewall driver is used, Quantum security group actually does nothing in OVS and Linux Bridge plugin. It would be better to disable security group extension for such case to avoid confusion. By this we can determine whether quantum security group is enabled by checking the extension list. This commit changes OVS/LB/NEC/Ryu plugins with agent firewall_driver based security group implementation. Fixes bug #1124117 Change-Id: I2182289c1e27987b686f1adb7d6e2ad4e154caa2
1248 lines
55 KiB
Python
1248 lines
55 KiB
Python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
|
#
|
|
# Copyright 2012, Nachi Ueno, NTT MCL, Inc.
|
|
# All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
from contextlib import nested
|
|
|
|
import mock
|
|
from mock import call
|
|
import mox
|
|
from oslo.config import cfg
|
|
|
|
from quantum.agent import firewall as firewall_base
|
|
from quantum.agent.linux import iptables_manager
|
|
from quantum.agent import rpc as agent_rpc
|
|
from quantum.agent import securitygroups_rpc as sg_rpc
|
|
from quantum import context
|
|
from quantum.db import securitygroups_rpc_base as sg_db_rpc
|
|
from quantum.extensions import securitygroup as ext_sg
|
|
from quantum.openstack.common.rpc import proxy
|
|
from quantum.tests import base
|
|
from quantum.tests.unit import test_extension_security_group as test_sg
|
|
from quantum.tests.unit import test_iptables_firewall as test_fw
|
|
|
|
|
|
class FakeSGCallback(sg_db_rpc.SecurityGroupServerRpcCallbackMixin):
|
|
def get_port_from_device(self, device):
|
|
device = self.devices.get(device)
|
|
if device:
|
|
device['security_group_rules'] = []
|
|
device['security_group_source_groups'] = []
|
|
device['fixed_ips'] = [ip['ip_address']
|
|
for ip in device['fixed_ips']]
|
|
return device
|
|
|
|
|
|
class SGServerRpcCallBackMixinTestCase(test_sg.SecurityGroupDBTestCase):
|
|
def setUp(self):
|
|
super(SGServerRpcCallBackMixinTestCase, self).setUp()
|
|
self.rpc = FakeSGCallback()
|
|
|
|
def test_security_group_rules_for_devices_ipv4_ingress(self):
|
|
fake_prefix = test_fw.FAKE_PREFIX['IPv4']
|
|
with self.network() as n:
|
|
with nested(self.subnet(n),
|
|
self.security_group()) as (subnet_v4,
|
|
sg1):
|
|
sg1_id = sg1['security_group']['id']
|
|
rule1 = self._build_security_group_rule(
|
|
sg1_id,
|
|
'ingress', 'tcp', '22',
|
|
'22')
|
|
rule2 = self._build_security_group_rule(
|
|
sg1_id,
|
|
'ingress', 'tcp', '23',
|
|
'23', fake_prefix)
|
|
rules = {
|
|
'security_group_rules': [rule1['security_group_rule'],
|
|
rule2['security_group_rule']]}
|
|
res = self._create_security_group_rule(self.fmt, rules)
|
|
self.deserialize(self.fmt, res)
|
|
self.assertEqual(res.status_int, 201)
|
|
|
|
res1 = self._create_port(
|
|
self.fmt, n['network']['id'],
|
|
security_groups=[sg1_id])
|
|
ports_rest1 = self.deserialize(self.fmt, res1)
|
|
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': 'IPv4',
|
|
'security_group_id': sg1_id},
|
|
{'direction': 'egress', 'ethertype': 'IPv6',
|
|
'security_group_id': sg1_id},
|
|
{'direction': 'ingress',
|
|
'protocol': 'tcp', 'ethertype': 'IPv4',
|
|
'port_range_max': 22,
|
|
'security_group_id': sg1_id,
|
|
'port_range_min': 22},
|
|
{'direction': 'ingress', 'protocol': 'tcp',
|
|
'ethertype': 'IPv4',
|
|
'port_range_max': 23, 'security_group_id': sg1_id,
|
|
'port_range_min': 23,
|
|
'source_ip_prefix': fake_prefix},
|
|
]
|
|
self.assertEqual(port_rpc['security_group_rules'],
|
|
expected)
|
|
self._delete('ports', port_id1)
|
|
|
|
def test_security_group_rules_for_devices_ipv4_egress(self):
|
|
fake_prefix = test_fw.FAKE_PREFIX['IPv4']
|
|
with self.network() as n:
|
|
with nested(self.subnet(n),
|
|
self.security_group()) as (subnet_v4,
|
|
sg1):
|
|
sg1_id = sg1['security_group']['id']
|
|
rule1 = self._build_security_group_rule(
|
|
sg1_id,
|
|
'egress', 'tcp', '22',
|
|
'22')
|
|
rule2 = self._build_security_group_rule(
|
|
sg1_id,
|
|
'egress', 'udp', '23',
|
|
'23', fake_prefix)
|
|
rules = {
|
|
'security_group_rules': [rule1['security_group_rule'],
|
|
rule2['security_group_rule']]}
|
|
res = self._create_security_group_rule(self.fmt, rules)
|
|
self.deserialize(self.fmt, res)
|
|
self.assertEqual(res.status_int, 201)
|
|
|
|
res1 = self._create_port(
|
|
self.fmt, n['network']['id'],
|
|
security_groups=[sg1_id])
|
|
ports_rest1 = self.deserialize(self.fmt, res1)
|
|
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': 'IPv4',
|
|
'security_group_id': sg1_id},
|
|
{'direction': 'egress', 'ethertype': 'IPv6',
|
|
'security_group_id': sg1_id},
|
|
{'direction': 'egress',
|
|
'protocol': 'tcp', 'ethertype': 'IPv4',
|
|
'port_range_max': 22,
|
|
'security_group_id': sg1_id,
|
|
'port_range_min': 22},
|
|
{'direction': 'egress', 'protocol': 'udp',
|
|
'ethertype': 'IPv4',
|
|
'port_range_max': 23, 'security_group_id': sg1_id,
|
|
'port_range_min': 23,
|
|
'dest_ip_prefix': fake_prefix},
|
|
]
|
|
self.assertEqual(port_rpc['security_group_rules'],
|
|
expected)
|
|
self._delete('ports', port_id1)
|
|
|
|
def test_security_group_rules_for_devices_ipv4_source_group(self):
|
|
|
|
with self.network() as n:
|
|
with nested(self.subnet(n),
|
|
self.security_group(),
|
|
self.security_group()) as (subnet_v4,
|
|
sg1,
|
|
sg2):
|
|
sg1_id = sg1['security_group']['id']
|
|
sg2_id = sg2['security_group']['id']
|
|
rule1 = self._build_security_group_rule(
|
|
sg1_id,
|
|
'ingress', 'tcp', '24',
|
|
'25', remote_group_id=sg2['security_group']['id'])
|
|
rules = {
|
|
'security_group_rules': [rule1['security_group_rule']]}
|
|
res = self._create_security_group_rule(self.fmt, rules)
|
|
self.deserialize(self.fmt, res)
|
|
self.assertEqual(res.status_int, 201)
|
|
|
|
res1 = self._create_port(
|
|
self.fmt, n['network']['id'],
|
|
security_groups=[sg1_id,
|
|
sg2_id])
|
|
ports_rest1 = self.deserialize(self.fmt, res1)
|
|
port_id1 = ports_rest1['port']['id']
|
|
self.rpc.devices = {port_id1: ports_rest1['port']}
|
|
devices = [port_id1, 'no_exist_device']
|
|
|
|
res2 = self._create_port(
|
|
self.fmt, n['network']['id'],
|
|
security_groups=[sg2_id])
|
|
ports_rest2 = self.deserialize(self.fmt, res2)
|
|
port_id2 = ports_rest2['port']['id']
|
|
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': 'IPv4',
|
|
'security_group_id': sg1_id},
|
|
{'direction': 'egress', 'ethertype': 'IPv6',
|
|
'security_group_id': sg1_id},
|
|
{'direction': 'egress', 'ethertype': 'IPv4',
|
|
'security_group_id': sg2_id},
|
|
{'direction': 'egress', 'ethertype': 'IPv6',
|
|
'security_group_id': sg2_id},
|
|
{'direction': u'ingress',
|
|
'source_ip_prefix': u'10.0.0.3/32',
|
|
'protocol': u'tcp', 'ethertype': u'IPv4',
|
|
'port_range_max': 25, 'port_range_min': 24,
|
|
'remote_group_id': sg2_id,
|
|
'security_group_id': sg1_id},
|
|
]
|
|
self.assertEqual(port_rpc['security_group_rules'],
|
|
expected)
|
|
self._delete('ports', port_id1)
|
|
self._delete('ports', port_id2)
|
|
|
|
def test_security_group_rules_for_devices_ipv6_ingress(self):
|
|
fake_prefix = test_fw.FAKE_PREFIX['IPv6']
|
|
with self.network() as n:
|
|
with nested(self.subnet(n,
|
|
cidr=fake_prefix,
|
|
ip_version=6),
|
|
self.security_group()) as (subnet_v6,
|
|
sg1):
|
|
sg1_id = sg1['security_group']['id']
|
|
rule1 = self._build_security_group_rule(
|
|
sg1_id,
|
|
'ingress', 'tcp', '22',
|
|
'22',
|
|
ethertype='IPv6')
|
|
rule2 = self._build_security_group_rule(
|
|
sg1_id,
|
|
'ingress', 'udp', '23',
|
|
'23', fake_prefix,
|
|
ethertype='IPv6')
|
|
rules = {
|
|
'security_group_rules': [rule1['security_group_rule'],
|
|
rule2['security_group_rule']]}
|
|
res = self._create_security_group_rule(self.fmt, rules)
|
|
self.deserialize(self.fmt, res)
|
|
self.assertEqual(res.status_int, 201)
|
|
|
|
res1 = self._create_port(
|
|
self.fmt, n['network']['id'],
|
|
fixed_ips=[{'subnet_id': subnet_v6['subnet']['id']}],
|
|
security_groups=[sg1_id])
|
|
ports_rest1 = self.deserialize(self.fmt, res1)
|
|
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': 'IPv4',
|
|
'security_group_id': sg1_id},
|
|
{'direction': 'egress', 'ethertype': 'IPv6',
|
|
'security_group_id': sg1_id},
|
|
{'direction': 'ingress',
|
|
'protocol': 'tcp', 'ethertype': 'IPv6',
|
|
'port_range_max': 22,
|
|
'security_group_id': sg1_id,
|
|
'port_range_min': 22},
|
|
{'direction': 'ingress', 'protocol': 'udp',
|
|
'ethertype': 'IPv6',
|
|
'port_range_max': 23, 'security_group_id': sg1_id,
|
|
'port_range_min': 23,
|
|
'source_ip_prefix': fake_prefix},
|
|
]
|
|
self.assertEqual(port_rpc['security_group_rules'],
|
|
expected)
|
|
self._delete('ports', port_id1)
|
|
|
|
def test_security_group_rules_for_devices_ipv6_egress(self):
|
|
fake_prefix = test_fw.FAKE_PREFIX['IPv6']
|
|
with self.network() as n:
|
|
with nested(self.subnet(n,
|
|
cidr=fake_prefix,
|
|
ip_version=6),
|
|
self.security_group()) as (subnet_v6,
|
|
sg1):
|
|
sg1_id = sg1['security_group']['id']
|
|
rule1 = self._build_security_group_rule(
|
|
sg1_id,
|
|
'egress', 'tcp', '22',
|
|
'22',
|
|
ethertype='IPv6')
|
|
rule2 = self._build_security_group_rule(
|
|
sg1_id,
|
|
'egress', 'udp', '23',
|
|
'23', fake_prefix,
|
|
ethertype='IPv6')
|
|
rules = {
|
|
'security_group_rules': [rule1['security_group_rule'],
|
|
rule2['security_group_rule']]}
|
|
res = self._create_security_group_rule(self.fmt, rules)
|
|
self.deserialize(self.fmt, res)
|
|
self.assertEqual(res.status_int, 201)
|
|
|
|
res1 = self._create_port(
|
|
self.fmt, n['network']['id'],
|
|
fixed_ips=[{'subnet_id': subnet_v6['subnet']['id']}],
|
|
security_groups=[sg1_id])
|
|
ports_rest1 = self.deserialize(self.fmt, res1)
|
|
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': 'IPv4',
|
|
'security_group_id': sg1_id},
|
|
{'direction': 'egress', 'ethertype': 'IPv6',
|
|
'security_group_id': sg1_id},
|
|
{'direction': 'egress',
|
|
'protocol': 'tcp', 'ethertype': 'IPv6',
|
|
'port_range_max': 22,
|
|
'security_group_id': sg1_id,
|
|
'port_range_min': 22},
|
|
{'direction': 'egress', 'protocol': 'udp',
|
|
'ethertype': 'IPv6',
|
|
'port_range_max': 23, 'security_group_id': sg1_id,
|
|
'port_range_min': 23,
|
|
'dest_ip_prefix': fake_prefix},
|
|
]
|
|
self.assertEqual(port_rpc['security_group_rules'],
|
|
expected)
|
|
self._delete('ports', port_id1)
|
|
|
|
def test_security_group_rules_for_devices_ipv6_source_group(self):
|
|
fake_prefix = test_fw.FAKE_PREFIX['IPv6']
|
|
with self.network() as n:
|
|
with nested(self.subnet(n,
|
|
cidr=fake_prefix,
|
|
ip_version=6),
|
|
self.security_group(),
|
|
self.security_group()) as (subnet_v6,
|
|
sg1,
|
|
sg2):
|
|
sg1_id = sg1['security_group']['id']
|
|
sg2_id = sg2['security_group']['id']
|
|
rule1 = self._build_security_group_rule(
|
|
sg1_id,
|
|
'ingress', 'tcp', '24',
|
|
'25',
|
|
ethertype='IPv6',
|
|
remote_group_id=sg2['security_group']['id'])
|
|
rules = {
|
|
'security_group_rules': [rule1['security_group_rule']]}
|
|
res = self._create_security_group_rule(self.fmt, rules)
|
|
self.deserialize(self.fmt, res)
|
|
self.assertEqual(res.status_int, 201)
|
|
|
|
res1 = self._create_port(
|
|
self.fmt, n['network']['id'],
|
|
fixed_ips=[{'subnet_id': subnet_v6['subnet']['id']}],
|
|
security_groups=[sg1_id,
|
|
sg2_id])
|
|
ports_rest1 = self.deserialize(self.fmt, res1)
|
|
port_id1 = ports_rest1['port']['id']
|
|
self.rpc.devices = {port_id1: ports_rest1['port']}
|
|
devices = [port_id1, 'no_exist_device']
|
|
|
|
res2 = self._create_port(
|
|
self.fmt, n['network']['id'],
|
|
fixed_ips=[{'subnet_id': subnet_v6['subnet']['id']}],
|
|
security_groups=[sg2_id])
|
|
ports_rest2 = self.deserialize(self.fmt, res2)
|
|
port_id2 = ports_rest2['port']['id']
|
|
|
|
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': 'IPv4',
|
|
'security_group_id': sg1_id},
|
|
{'direction': 'egress', 'ethertype': 'IPv6',
|
|
'security_group_id': sg1_id},
|
|
{'direction': 'egress', 'ethertype': 'IPv4',
|
|
'security_group_id': sg2_id},
|
|
{'direction': 'egress', 'ethertype': 'IPv6',
|
|
'security_group_id': sg2_id},
|
|
{'direction': 'ingress',
|
|
'source_ip_prefix': 'fe80::3/128',
|
|
'protocol': 'tcp', 'ethertype': 'IPv6',
|
|
'port_range_max': 25, 'port_range_min': 24,
|
|
'remote_group_id': sg2_id,
|
|
'security_group_id': sg1_id},
|
|
]
|
|
self.assertEqual(port_rpc['security_group_rules'],
|
|
expected)
|
|
self._delete('ports', port_id1)
|
|
self._delete('ports', port_id2)
|
|
|
|
|
|
class SGServerRpcCallBackMixinTestCaseXML(SGServerRpcCallBackMixinTestCase):
|
|
fmt = 'xml'
|
|
|
|
|
|
class SGAgentRpcCallBackMixinTestCase(base.BaseTestCase):
|
|
def setUp(self):
|
|
super(SGAgentRpcCallBackMixinTestCase, self).setUp()
|
|
self.rpc = sg_rpc.SecurityGroupAgentRpcCallbackMixin()
|
|
self.rpc.sg_agent = mock.Mock()
|
|
|
|
def test_security_groups_rule_updated(self):
|
|
self.rpc.security_groups_rule_updated(None,
|
|
security_groups=['fake_sgid'])
|
|
self.rpc.sg_agent.assert_has_calls(
|
|
[call.security_groups_rule_updated(['fake_sgid'])])
|
|
|
|
def test_security_groups_member_updated(self):
|
|
self.rpc.security_groups_member_updated(None,
|
|
security_groups=['fake_sgid'])
|
|
self.rpc.sg_agent.assert_has_calls(
|
|
[call.security_groups_member_updated(['fake_sgid'])])
|
|
|
|
def test_security_groups_provider_updated(self):
|
|
self.rpc.security_groups_provider_updated(None)
|
|
self.rpc.sg_agent.assert_has_calls(
|
|
[call.security_groups_provider_updated()])
|
|
|
|
|
|
class SecurityGroupAgentRpcTestCase(base.BaseTestCase):
|
|
def setUp(self):
|
|
super(SecurityGroupAgentRpcTestCase, self).setUp()
|
|
self.agent = sg_rpc.SecurityGroupAgentRpcMixin()
|
|
self.agent.context = None
|
|
self.addCleanup(mock.patch.stopall)
|
|
mock.patch('quantum.agent.linux.iptables_manager').start()
|
|
self.agent.root_helper = 'sudo'
|
|
self.agent.init_firewall()
|
|
self.firewall = mock.Mock()
|
|
firewall_object = firewall_base.FirewallDriver()
|
|
self.firewall.defer_apply.side_effect = firewall_object.defer_apply
|
|
self.agent.firewall = self.firewall
|
|
rpc = mock.Mock()
|
|
self.agent.plugin_rpc = rpc
|
|
self.fake_device = {'device': 'fake_device',
|
|
'security_groups': ['fake_sgid1', 'fake_sgid2'],
|
|
'security_group_source_groups': ['fake_sgid2'],
|
|
'security_group_rules': [{'security_group_id':
|
|
'fake_sgid1',
|
|
'remote_group_id':
|
|
'fake_sgid2'}]}
|
|
fake_devices = {'fake_device': self.fake_device}
|
|
self.firewall.ports = fake_devices
|
|
rpc.security_group_rules_for_devices.return_value = fake_devices
|
|
|
|
def test_prepare_and_remove_devices_filter(self):
|
|
self.agent.prepare_devices_filter(['fake_device'])
|
|
self.agent.remove_devices_filter(['fake_device'])
|
|
# ignore device which is not filtered
|
|
self.firewall.assert_has_calls([call.defer_apply(),
|
|
call.prepare_port_filter(
|
|
self.fake_device),
|
|
call.defer_apply(),
|
|
call.remove_port_filter(
|
|
self.fake_device),
|
|
])
|
|
|
|
def test_security_groups_rule_updated(self):
|
|
self.agent.refresh_firewall = mock.Mock()
|
|
self.agent.prepare_devices_filter(['fake_port_id'])
|
|
self.agent.security_groups_rule_updated(['fake_sgid1', 'fake_sgid3'])
|
|
self.agent.refresh_firewall.assert_has_calls(
|
|
[call.refresh_firewall()])
|
|
|
|
def test_security_groups_rule_not_updated(self):
|
|
self.agent.refresh_firewall = mock.Mock()
|
|
self.agent.prepare_devices_filter(['fake_port_id'])
|
|
self.agent.security_groups_rule_updated(['fake_sgid3', 'fake_sgid4'])
|
|
self.agent.refresh_firewall.assert_has_calls([])
|
|
|
|
def test_security_groups_member_updated(self):
|
|
self.agent.refresh_firewall = mock.Mock()
|
|
self.agent.prepare_devices_filter(['fake_port_id'])
|
|
self.agent.security_groups_member_updated(['fake_sgid2', 'fake_sgid3'])
|
|
self.agent.refresh_firewall.assert_has_calls(
|
|
[call.refresh_firewall()])
|
|
|
|
def test_security_groups_member_not_updated(self):
|
|
self.agent.refresh_firewall = mock.Mock()
|
|
self.agent.prepare_devices_filter(['fake_port_id'])
|
|
self.agent.security_groups_member_updated(['fake_sgid3', 'fake_sgid4'])
|
|
self.agent.refresh_firewall.assert_has_calls([])
|
|
|
|
def test_security_groups_provider_updated(self):
|
|
self.agent.refresh_firewall = mock.Mock()
|
|
self.agent.security_groups_provider_updated()
|
|
self.agent.refresh_firewall.assert_has_calls(
|
|
[call.refresh_firewall()])
|
|
|
|
def test_refresh_firewall(self):
|
|
self.agent.prepare_devices_filter(['fake_port_id'])
|
|
self.agent.refresh_firewall()
|
|
calls = [call.defer_apply(),
|
|
call.prepare_port_filter(self.fake_device),
|
|
call.defer_apply(),
|
|
call.update_port_filter(self.fake_device)]
|
|
self.firewall.assert_has_calls(calls)
|
|
|
|
|
|
class FakeSGRpcApi(agent_rpc.PluginApi,
|
|
sg_rpc.SecurityGroupServerRpcApiMixin):
|
|
pass
|
|
|
|
|
|
class SecurityGroupServerRpcApiTestCase(base.BaseTestCase):
|
|
def setUp(self):
|
|
super(SecurityGroupServerRpcApiTestCase, self).setUp()
|
|
self.rpc = FakeSGRpcApi('fake_topic')
|
|
self.rpc.call = mock.Mock()
|
|
|
|
def test_security_group_rules_for_devices(self):
|
|
self.rpc.security_group_rules_for_devices(None, ['fake_device'])
|
|
self.rpc.call.assert_has_calls(
|
|
[call(None,
|
|
{'args':
|
|
{'devices': ['fake_device']},
|
|
'method':
|
|
'security_group_rules_for_devices'},
|
|
version=sg_rpc.SG_RPC_VERSION,
|
|
topic='fake_topic')])
|
|
|
|
|
|
class FakeSGNotifierAPI(proxy.RpcProxy,
|
|
sg_rpc.SecurityGroupAgentRpcApiMixin):
|
|
pass
|
|
|
|
|
|
class SecurityGroupAgentRpcApiTestCase(base.BaseTestCase):
|
|
def setUp(self):
|
|
super(SecurityGroupAgentRpcApiTestCase, self).setUp()
|
|
self.notifier = FakeSGNotifierAPI(topic='fake',
|
|
default_version='1.0')
|
|
self.notifier.fanout_cast = mock.Mock()
|
|
|
|
def test_security_groups_rule_updated(self):
|
|
self.notifier.security_groups_rule_updated(
|
|
None, security_groups=['fake_sgid'])
|
|
self.notifier.fanout_cast.assert_has_calls(
|
|
[call(None,
|
|
{'args':
|
|
{'security_groups': ['fake_sgid']},
|
|
'method': 'security_groups_rule_updated'},
|
|
version=sg_rpc.SG_RPC_VERSION,
|
|
topic='fake-security_group-update')])
|
|
|
|
def test_security_groups_member_updated(self):
|
|
self.notifier.security_groups_member_updated(
|
|
None, security_groups=['fake_sgid'])
|
|
self.notifier.fanout_cast.assert_has_calls(
|
|
[call(None,
|
|
{'args':
|
|
{'security_groups': ['fake_sgid']},
|
|
'method': 'security_groups_member_updated'},
|
|
version=sg_rpc.SG_RPC_VERSION,
|
|
topic='fake-security_group-update')])
|
|
|
|
def test_security_groups_rule_not_updated(self):
|
|
self.notifier.security_groups_rule_updated(
|
|
None, security_groups=[])
|
|
self.assertEqual(False, self.notifier.fanout_cast.called)
|
|
|
|
def test_security_groups_member_not_updated(self):
|
|
self.notifier.security_groups_member_updated(
|
|
None, security_groups=[])
|
|
self.assertEqual(False, self.notifier.fanout_cast.called)
|
|
|
|
#Note(nati) bn -> binary_name
|
|
# id -> device_id
|
|
|
|
PHYSDEV_RULE = '-m physdev --physdev-is-bridged'
|
|
|
|
IPTABLES_ARG = {'bn': iptables_manager.binary_name,
|
|
'physdev': PHYSDEV_RULE}
|
|
|
|
CHAINS_NAT = 'OUTPUT|POSTROUTING|PREROUTING|float-snat|snat'
|
|
IPTABLES_ARG['chains'] = CHAINS_NAT
|
|
|
|
IPTABLES_NAT = """:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:quantum-postrouting-bottom - [0:0]
|
|
-A PREROUTING -j %(bn)s-PREROUTING
|
|
-A OUTPUT -j %(bn)s-OUTPUT
|
|
-A POSTROUTING -j %(bn)s-POSTROUTING
|
|
-A POSTROUTING -j quantum-postrouting-bottom
|
|
-A quantum-postrouting-bottom -j %(bn)s-snat
|
|
-A %(bn)s-snat -j %(bn)s-float-snat
|
|
""" % IPTABLES_ARG
|
|
|
|
CHAINS_EMPTY = 'FORWARD|INPUT|OUTPUT|local|sg-chain|sg-fallback'
|
|
CHAINS_1 = CHAINS_EMPTY + '|i_port1|o_port1'
|
|
CHAINS_2 = CHAINS_1 + '|i_port2|o_port2'
|
|
|
|
IPTABLES_ARG['chains'] = CHAINS_1
|
|
|
|
IPTABLES_FILTER_1 = """:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:quantum-filter-top - [0:0]
|
|
-A FORWARD -j quantum-filter-top
|
|
-A OUTPUT -j quantum-filter-top
|
|
-A quantum-filter-top -j %(bn)s-local
|
|
-A INPUT -j %(bn)s-INPUT
|
|
-A OUTPUT -j %(bn)s-OUTPUT
|
|
-A FORWARD -j %(bn)s-FORWARD
|
|
-A %(bn)s-sg-fallback -j DROP
|
|
-A %(bn)s-FORWARD %(physdev)s --physdev-INGRESS tap_port1 -j %(bn)s-sg-chain
|
|
-A %(bn)s-sg-chain %(physdev)s --physdev-INGRESS tap_port1 -j %(bn)s-i_port1
|
|
-A %(bn)s-i_port1 -m state --state INVALID -j DROP
|
|
-A %(bn)s-i_port1 -m state --state ESTABLISHED,RELATED -j RETURN
|
|
-A %(bn)s-i_port1 -j RETURN -p udp --dport 68 --sport 67 -s 10.0.0.2
|
|
-A %(bn)s-i_port1 -j RETURN -p tcp --dport 22
|
|
-A %(bn)s-i_port1 -j %(bn)s-sg-fallback
|
|
-A %(bn)s-FORWARD %(physdev)s --physdev-EGRESS tap_port1 -j %(bn)s-sg-chain
|
|
-A %(bn)s-sg-chain %(physdev)s --physdev-EGRESS tap_port1 -j %(bn)s-o_port1
|
|
-A %(bn)s-INPUT %(physdev)s --physdev-EGRESS tap_port1 -j %(bn)s-o_port1
|
|
-A %(bn)s-o_port1 -m mac ! --mac-source 12:34:56:78:9a:bc -j DROP
|
|
-A %(bn)s-o_port1 -p udp --sport 68 --dport 67 -j RETURN
|
|
-A %(bn)s-o_port1 ! -s 10.0.0.3 -j DROP
|
|
-A %(bn)s-o_port1 -p udp --sport 67 --dport 68 -j DROP
|
|
-A %(bn)s-o_port1 -m state --state INVALID -j DROP
|
|
-A %(bn)s-o_port1 -m state --state ESTABLISHED,RELATED -j RETURN
|
|
-A %(bn)s-o_port1 -j RETURN
|
|
-A %(bn)s-o_port1 -j %(bn)s-sg-fallback
|
|
-A %(bn)s-sg-chain -j ACCEPT
|
|
""" % IPTABLES_ARG
|
|
|
|
IPTABLES_FILTER_1_2 = """:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:quantum-filter-top - [0:0]
|
|
-A FORWARD -j quantum-filter-top
|
|
-A OUTPUT -j quantum-filter-top
|
|
-A quantum-filter-top -j %(bn)s-local
|
|
-A INPUT -j %(bn)s-INPUT
|
|
-A OUTPUT -j %(bn)s-OUTPUT
|
|
-A FORWARD -j %(bn)s-FORWARD
|
|
-A %(bn)s-sg-fallback -j DROP
|
|
-A %(bn)s-FORWARD %(physdev)s --physdev-INGRESS tap_port1 -j %(bn)s-sg-chain
|
|
-A %(bn)s-sg-chain %(physdev)s --physdev-INGRESS tap_port1 -j %(bn)s-i_port1
|
|
-A %(bn)s-i_port1 -m state --state INVALID -j DROP
|
|
-A %(bn)s-i_port1 -m state --state ESTABLISHED,RELATED -j RETURN
|
|
-A %(bn)s-i_port1 -j RETURN -p udp --dport 68 --sport 67 -s 10.0.0.2
|
|
-A %(bn)s-i_port1 -j RETURN -p tcp --dport 22
|
|
-A %(bn)s-i_port1 -j RETURN -s 10.0.0.4
|
|
-A %(bn)s-i_port1 -j %(bn)s-sg-fallback
|
|
-A %(bn)s-FORWARD %(physdev)s --physdev-EGRESS tap_port1 -j %(bn)s-sg-chain
|
|
-A %(bn)s-sg-chain %(physdev)s --physdev-EGRESS tap_port1 -j %(bn)s-o_port1
|
|
-A %(bn)s-INPUT %(physdev)s --physdev-EGRESS tap_port1 -j %(bn)s-o_port1
|
|
-A %(bn)s-o_port1 -m mac ! --mac-source 12:34:56:78:9a:bc -j DROP
|
|
-A %(bn)s-o_port1 -p udp --sport 68 --dport 67 -j RETURN
|
|
-A %(bn)s-o_port1 ! -s 10.0.0.3 -j DROP
|
|
-A %(bn)s-o_port1 -p udp --sport 67 --dport 68 -j DROP
|
|
-A %(bn)s-o_port1 -m state --state INVALID -j DROP
|
|
-A %(bn)s-o_port1 -m state --state ESTABLISHED,RELATED -j RETURN
|
|
-A %(bn)s-o_port1 -j RETURN
|
|
-A %(bn)s-o_port1 -j %(bn)s-sg-fallback
|
|
-A %(bn)s-sg-chain -j ACCEPT
|
|
""" % IPTABLES_ARG
|
|
|
|
IPTABLES_ARG['chains'] = CHAINS_2
|
|
|
|
IPTABLES_FILTER_2 = """:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:quantum-filter-top - [0:0]
|
|
-A FORWARD -j quantum-filter-top
|
|
-A OUTPUT -j quantum-filter-top
|
|
-A quantum-filter-top -j %(bn)s-local
|
|
-A INPUT -j %(bn)s-INPUT
|
|
-A OUTPUT -j %(bn)s-OUTPUT
|
|
-A FORWARD -j %(bn)s-FORWARD
|
|
-A %(bn)s-sg-fallback -j DROP
|
|
-A %(bn)s-FORWARD %(physdev)s --physdev-INGRESS tap_port1 -j %(bn)s-sg-chain
|
|
-A %(bn)s-sg-chain %(physdev)s --physdev-INGRESS tap_port1 -j %(bn)s-i_port1
|
|
-A %(bn)s-i_port1 -m state --state INVALID -j DROP
|
|
-A %(bn)s-i_port1 -m state --state ESTABLISHED,RELATED -j RETURN
|
|
-A %(bn)s-i_port1 -j RETURN -p udp --dport 68 --sport 67 -s 10.0.0.2
|
|
-A %(bn)s-i_port1 -j RETURN -p tcp --dport 22
|
|
-A %(bn)s-i_port1 -j RETURN -s 10.0.0.4
|
|
-A %(bn)s-i_port1 -j %(bn)s-sg-fallback
|
|
-A %(bn)s-FORWARD %(physdev)s --physdev-EGRESS tap_port1 -j %(bn)s-sg-chain
|
|
-A %(bn)s-sg-chain %(physdev)s --physdev-EGRESS tap_port1 -j %(bn)s-o_port1
|
|
-A %(bn)s-INPUT %(physdev)s --physdev-EGRESS tap_port1 -j %(bn)s-o_port1
|
|
-A %(bn)s-o_port1 -m mac ! --mac-source 12:34:56:78:9a:bc -j DROP
|
|
-A %(bn)s-o_port1 -p udp --sport 68 --dport 67 -j RETURN
|
|
-A %(bn)s-o_port1 ! -s 10.0.0.3 -j DROP
|
|
-A %(bn)s-o_port1 -p udp --sport 67 --dport 68 -j DROP
|
|
-A %(bn)s-o_port1 -m state --state INVALID -j DROP
|
|
-A %(bn)s-o_port1 -m state --state ESTABLISHED,RELATED -j RETURN
|
|
-A %(bn)s-o_port1 -j RETURN
|
|
-A %(bn)s-o_port1 -j %(bn)s-sg-fallback
|
|
-A %(bn)s-FORWARD %(physdev)s --physdev-INGRESS tap_port2 -j %(bn)s-sg-chain
|
|
-A %(bn)s-sg-chain %(physdev)s --physdev-INGRESS tap_port2 -j %(bn)s-i_port2
|
|
-A %(bn)s-i_port2 -m state --state INVALID -j DROP
|
|
-A %(bn)s-i_port2 -m state --state ESTABLISHED,RELATED -j RETURN
|
|
-A %(bn)s-i_port2 -j RETURN -p udp --dport 68 --sport 67 -s 10.0.0.2
|
|
-A %(bn)s-i_port2 -j RETURN -p tcp --dport 22
|
|
-A %(bn)s-i_port2 -j RETURN -s 10.0.0.3
|
|
-A %(bn)s-i_port2 -j %(bn)s-sg-fallback
|
|
-A %(bn)s-FORWARD %(physdev)s --physdev-EGRESS tap_port2 -j %(bn)s-sg-chain
|
|
-A %(bn)s-sg-chain %(physdev)s --physdev-EGRESS tap_port2 -j %(bn)s-o_port2
|
|
-A %(bn)s-INPUT %(physdev)s --physdev-EGRESS tap_port2 -j %(bn)s-o_port2
|
|
-A %(bn)s-o_port2 -m mac ! --mac-source 12:34:56:78:9a:bd -j DROP
|
|
-A %(bn)s-o_port2 -p udp --sport 68 --dport 67 -j RETURN
|
|
-A %(bn)s-o_port2 ! -s 10.0.0.4 -j DROP
|
|
-A %(bn)s-o_port2 -p udp --sport 67 --dport 68 -j DROP
|
|
-A %(bn)s-o_port2 -m state --state INVALID -j DROP
|
|
-A %(bn)s-o_port2 -m state --state ESTABLISHED,RELATED -j RETURN
|
|
-A %(bn)s-o_port2 -j RETURN
|
|
-A %(bn)s-o_port2 -j %(bn)s-sg-fallback
|
|
-A %(bn)s-sg-chain -j ACCEPT
|
|
""" % IPTABLES_ARG
|
|
|
|
IPTABLES_FILTER_2_2 = """:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:quantum-filter-top - [0:0]
|
|
-A FORWARD -j quantum-filter-top
|
|
-A OUTPUT -j quantum-filter-top
|
|
-A quantum-filter-top -j %(bn)s-local
|
|
-A INPUT -j %(bn)s-INPUT
|
|
-A OUTPUT -j %(bn)s-OUTPUT
|
|
-A FORWARD -j %(bn)s-FORWARD
|
|
-A %(bn)s-sg-fallback -j DROP
|
|
-A %(bn)s-FORWARD %(physdev)s --physdev-INGRESS tap_port1 -j %(bn)s-sg-chain
|
|
-A %(bn)s-sg-chain %(physdev)s --physdev-INGRESS tap_port1 -j %(bn)s-i_port1
|
|
-A %(bn)s-i_port1 -m state --state INVALID -j DROP
|
|
-A %(bn)s-i_port1 -m state --state ESTABLISHED,RELATED -j RETURN
|
|
-A %(bn)s-i_port1 -j RETURN -p udp --dport 68 --sport 67 -s 10.0.0.2
|
|
-A %(bn)s-i_port1 -j RETURN -p tcp --dport 22
|
|
-A %(bn)s-i_port1 -j %(bn)s-sg-fallback
|
|
-A %(bn)s-FORWARD %(physdev)s --physdev-EGRESS tap_port1 -j %(bn)s-sg-chain
|
|
-A %(bn)s-sg-chain %(physdev)s --physdev-EGRESS tap_port1 -j %(bn)s-o_port1
|
|
-A %(bn)s-INPUT %(physdev)s --physdev-EGRESS tap_port1 -j %(bn)s-o_port1
|
|
-A %(bn)s-o_port1 -m mac ! --mac-source 12:34:56:78:9a:bc -j DROP
|
|
-A %(bn)s-o_port1 -p udp --sport 68 --dport 67 -j RETURN
|
|
-A %(bn)s-o_port1 ! -s 10.0.0.3 -j DROP
|
|
-A %(bn)s-o_port1 -p udp --sport 67 --dport 68 -j DROP
|
|
-A %(bn)s-o_port1 -m state --state INVALID -j DROP
|
|
-A %(bn)s-o_port1 -m state --state ESTABLISHED,RELATED -j RETURN
|
|
-A %(bn)s-o_port1 -j RETURN
|
|
-A %(bn)s-o_port1 -j %(bn)s-sg-fallback
|
|
-A %(bn)s-FORWARD %(physdev)s --physdev-INGRESS tap_port2 -j %(bn)s-sg-chain
|
|
-A %(bn)s-sg-chain %(physdev)s --physdev-INGRESS tap_port2 -j %(bn)s-i_port2
|
|
-A %(bn)s-i_port2 -m state --state INVALID -j DROP
|
|
-A %(bn)s-i_port2 -m state --state ESTABLISHED,RELATED -j RETURN
|
|
-A %(bn)s-i_port2 -j RETURN -p udp --dport 68 --sport 67 -s 10.0.0.2
|
|
-A %(bn)s-i_port2 -j RETURN -p tcp --dport 22
|
|
-A %(bn)s-i_port2 -j RETURN -s 10.0.0.3
|
|
-A %(bn)s-i_port2 -j %(bn)s-sg-fallback
|
|
-A %(bn)s-FORWARD %(physdev)s --physdev-EGRESS tap_port2 -j %(bn)s-sg-chain
|
|
-A %(bn)s-sg-chain %(physdev)s --physdev-EGRESS tap_port2 -j %(bn)s-o_port2
|
|
-A %(bn)s-INPUT %(physdev)s --physdev-EGRESS tap_port2 -j %(bn)s-o_port2
|
|
-A %(bn)s-o_port2 -m mac ! --mac-source 12:34:56:78:9a:bd -j DROP
|
|
-A %(bn)s-o_port2 -p udp --sport 68 --dport 67 -j RETURN
|
|
-A %(bn)s-o_port2 ! -s 10.0.0.4 -j DROP
|
|
-A %(bn)s-o_port2 -p udp --sport 67 --dport 68 -j DROP
|
|
-A %(bn)s-o_port2 -m state --state INVALID -j DROP
|
|
-A %(bn)s-o_port2 -m state --state ESTABLISHED,RELATED -j RETURN
|
|
-A %(bn)s-o_port2 -j RETURN
|
|
-A %(bn)s-o_port2 -j %(bn)s-sg-fallback
|
|
-A %(bn)s-sg-chain -j ACCEPT
|
|
""" % IPTABLES_ARG
|
|
|
|
IPTABLES_FILTER_2_3 = """:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:quantum-filter-top - [0:0]
|
|
-A FORWARD -j quantum-filter-top
|
|
-A OUTPUT -j quantum-filter-top
|
|
-A quantum-filter-top -j %(bn)s-local
|
|
-A INPUT -j %(bn)s-INPUT
|
|
-A OUTPUT -j %(bn)s-OUTPUT
|
|
-A FORWARD -j %(bn)s-FORWARD
|
|
-A %(bn)s-sg-fallback -j DROP
|
|
-A %(bn)s-FORWARD %(physdev)s --physdev-INGRESS tap_port1 -j %(bn)s-sg-chain
|
|
-A %(bn)s-sg-chain %(physdev)s --physdev-INGRESS tap_port1 -j %(bn)s-i_port1
|
|
-A %(bn)s-i_port1 -m state --state INVALID -j DROP
|
|
-A %(bn)s-i_port1 -m state --state ESTABLISHED,RELATED -j RETURN
|
|
-A %(bn)s-i_port1 -j RETURN -p udp --dport 68 --sport 67 -s 10.0.0.2
|
|
-A %(bn)s-i_port1 -j RETURN -p tcp --dport 22
|
|
-A %(bn)s-i_port1 -j RETURN -s 10.0.0.4
|
|
-A %(bn)s-i_port1 -j RETURN -p icmp
|
|
-A %(bn)s-i_port1 -j %(bn)s-sg-fallback
|
|
-A %(bn)s-FORWARD %(physdev)s --physdev-EGRESS tap_port1 -j %(bn)s-sg-chain
|
|
-A %(bn)s-sg-chain %(physdev)s --physdev-EGRESS tap_port1 -j %(bn)s-o_port1
|
|
-A %(bn)s-INPUT %(physdev)s --physdev-EGRESS tap_port1 -j %(bn)s-o_port1
|
|
-A %(bn)s-o_port1 -m mac ! --mac-source 12:34:56:78:9a:bc -j DROP
|
|
-A %(bn)s-o_port1 -p udp --sport 68 --dport 67 -j RETURN
|
|
-A %(bn)s-o_port1 ! -s 10.0.0.3 -j DROP
|
|
-A %(bn)s-o_port1 -p udp --sport 67 --dport 68 -j DROP
|
|
-A %(bn)s-o_port1 -m state --state INVALID -j DROP
|
|
-A %(bn)s-o_port1 -m state --state ESTABLISHED,RELATED -j RETURN
|
|
-A %(bn)s-o_port1 -j RETURN
|
|
-A %(bn)s-o_port1 -j %(bn)s-sg-fallback
|
|
-A %(bn)s-FORWARD %(physdev)s --physdev-INGRESS tap_port2 -j %(bn)s-sg-chain
|
|
-A %(bn)s-sg-chain %(physdev)s --physdev-INGRESS tap_port2 -j %(bn)s-i_port2
|
|
-A %(bn)s-i_port2 -m state --state INVALID -j DROP
|
|
-A %(bn)s-i_port2 -m state --state ESTABLISHED,RELATED -j RETURN
|
|
-A %(bn)s-i_port2 -j RETURN -p udp --dport 68 --sport 67 -s 10.0.0.2
|
|
-A %(bn)s-i_port2 -j RETURN -p tcp --dport 22
|
|
-A %(bn)s-i_port2 -j RETURN -s 10.0.0.3
|
|
-A %(bn)s-i_port2 -j RETURN -p icmp
|
|
-A %(bn)s-i_port2 -j %(bn)s-sg-fallback
|
|
-A %(bn)s-FORWARD %(physdev)s --physdev-EGRESS tap_port2 -j %(bn)s-sg-chain
|
|
-A %(bn)s-sg-chain %(physdev)s --physdev-EGRESS tap_port2 -j %(bn)s-o_port2
|
|
-A %(bn)s-INPUT %(physdev)s --physdev-EGRESS tap_port2 -j %(bn)s-o_port2
|
|
-A %(bn)s-o_port2 -m mac ! --mac-source 12:34:56:78:9a:bd -j DROP
|
|
-A %(bn)s-o_port2 -p udp --sport 68 --dport 67 -j RETURN
|
|
-A %(bn)s-o_port2 ! -s 10.0.0.4 -j DROP
|
|
-A %(bn)s-o_port2 -p udp --sport 67 --dport 68 -j DROP
|
|
-A %(bn)s-o_port2 -m state --state INVALID -j DROP
|
|
-A %(bn)s-o_port2 -m state --state ESTABLISHED,RELATED -j RETURN
|
|
-A %(bn)s-o_port2 -j RETURN
|
|
-A %(bn)s-o_port2 -j %(bn)s-sg-fallback
|
|
-A %(bn)s-sg-chain -j ACCEPT
|
|
""" % IPTABLES_ARG
|
|
|
|
IPTABLES_ARG['chains'] = CHAINS_EMPTY
|
|
IPTABLES_FILTER_EMPTY = """:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:quantum-filter-top - [0:0]
|
|
-A FORWARD -j quantum-filter-top
|
|
-A OUTPUT -j quantum-filter-top
|
|
-A quantum-filter-top -j %(bn)s-local
|
|
-A INPUT -j %(bn)s-INPUT
|
|
-A OUTPUT -j %(bn)s-OUTPUT
|
|
-A FORWARD -j %(bn)s-FORWARD
|
|
-A %(bn)s-sg-fallback -j DROP
|
|
""" % IPTABLES_ARG
|
|
|
|
IPTABLES_ARG['chains'] = CHAINS_1
|
|
IPTABLES_FILTER_V6_1 = """:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:quantum-filter-top - [0:0]
|
|
-A FORWARD -j quantum-filter-top
|
|
-A OUTPUT -j quantum-filter-top
|
|
-A quantum-filter-top -j %(bn)s-local
|
|
-A INPUT -j %(bn)s-INPUT
|
|
-A OUTPUT -j %(bn)s-OUTPUT
|
|
-A FORWARD -j %(bn)s-FORWARD
|
|
-A %(bn)s-sg-fallback -j DROP
|
|
-A %(bn)s-FORWARD %(physdev)s --physdev-INGRESS tap_port1 -j %(bn)s-sg-chain
|
|
-A %(bn)s-sg-chain %(physdev)s --physdev-INGRESS tap_port1 -j %(bn)s-i_port1
|
|
-A %(bn)s-i_port1 -m state --state INVALID -j DROP
|
|
-A %(bn)s-i_port1 -m state --state ESTABLISHED,RELATED -j RETURN
|
|
-A %(bn)s-i_port1 -j %(bn)s-sg-fallback
|
|
-A %(bn)s-FORWARD %(physdev)s --physdev-EGRESS tap_port1 -j %(bn)s-sg-chain
|
|
-A %(bn)s-sg-chain %(physdev)s --physdev-EGRESS tap_port1 -j %(bn)s-o_port1
|
|
-A %(bn)s-INPUT %(physdev)s --physdev-EGRESS tap_port1 -j %(bn)s-o_port1
|
|
-A %(bn)s-o_port1 -m mac ! --mac-source 12:34:56:78:9a:bc -j DROP
|
|
-A %(bn)s-o_port1 -p icmpv6 -j RETURN
|
|
-A %(bn)s-o_port1 -m state --state INVALID -j DROP
|
|
-A %(bn)s-o_port1 -m state --state ESTABLISHED,RELATED -j RETURN
|
|
-A %(bn)s-o_port1 -j %(bn)s-sg-fallback
|
|
-A %(bn)s-sg-chain -j ACCEPT
|
|
""" % IPTABLES_ARG
|
|
|
|
IPTABLES_ARG['chains'] = CHAINS_2
|
|
IPTABLES_FILTER_V6_2 = """:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:quantum-filter-top - [0:0]
|
|
-A FORWARD -j quantum-filter-top
|
|
-A OUTPUT -j quantum-filter-top
|
|
-A quantum-filter-top -j %(bn)s-local
|
|
-A INPUT -j %(bn)s-INPUT
|
|
-A OUTPUT -j %(bn)s-OUTPUT
|
|
-A FORWARD -j %(bn)s-FORWARD
|
|
-A %(bn)s-sg-fallback -j DROP
|
|
-A %(bn)s-FORWARD %(physdev)s --physdev-INGRESS tap_port1 -j %(bn)s-sg-chain
|
|
-A %(bn)s-sg-chain %(physdev)s --physdev-INGRESS tap_port1 -j %(bn)s-i_port1
|
|
-A %(bn)s-i_port1 -m state --state INVALID -j DROP
|
|
-A %(bn)s-i_port1 -m state --state ESTABLISHED,RELATED -j RETURN
|
|
-A %(bn)s-i_port1 -j %(bn)s-sg-fallback
|
|
-A %(bn)s-FORWARD %(physdev)s --physdev-EGRESS tap_port1 -j %(bn)s-sg-chain
|
|
-A %(bn)s-sg-chain %(physdev)s --physdev-EGRESS tap_port1 -j %(bn)s-o_port1
|
|
-A %(bn)s-INPUT %(physdev)s --physdev-EGRESS tap_port1 -j %(bn)s-o_port1
|
|
-A %(bn)s-o_port1 -m mac ! --mac-source 12:34:56:78:9a:bc -j DROP
|
|
-A %(bn)s-o_port1 -p icmpv6 -j RETURN
|
|
-A %(bn)s-o_port1 -m state --state INVALID -j DROP
|
|
-A %(bn)s-o_port1 -m state --state ESTABLISHED,RELATED -j RETURN
|
|
-A %(bn)s-o_port1 -j %(bn)s-sg-fallback
|
|
-A %(bn)s-FORWARD %(physdev)s --physdev-INGRESS tap_port2 -j %(bn)s-sg-chain
|
|
-A %(bn)s-sg-chain %(physdev)s --physdev-INGRESS tap_port2 -j %(bn)s-i_port2
|
|
-A %(bn)s-i_port2 -m state --state INVALID -j DROP
|
|
-A %(bn)s-i_port2 -m state --state ESTABLISHED,RELATED -j RETURN
|
|
-A %(bn)s-i_port2 -j %(bn)s-sg-fallback
|
|
-A %(bn)s-FORWARD %(physdev)s --physdev-EGRESS tap_port2 -j %(bn)s-sg-chain
|
|
-A %(bn)s-sg-chain %(physdev)s --physdev-EGRESS tap_port2 -j %(bn)s-o_port2
|
|
-A %(bn)s-INPUT %(physdev)s --physdev-EGRESS tap_port2 -j %(bn)s-o_port2
|
|
-A %(bn)s-o_port2 -m mac ! --mac-source 12:34:56:78:9a:bd -j DROP
|
|
-A %(bn)s-o_port2 -p icmpv6 -j RETURN
|
|
-A %(bn)s-o_port2 -m state --state INVALID -j DROP
|
|
-A %(bn)s-o_port2 -m state --state ESTABLISHED,RELATED -j RETURN
|
|
-A %(bn)s-o_port2 -j %(bn)s-sg-fallback
|
|
-A %(bn)s-sg-chain -j ACCEPT
|
|
""" % IPTABLES_ARG
|
|
|
|
IPTABLES_ARG['chains'] = CHAINS_EMPTY
|
|
IPTABLES_FILTER_V6_EMPTY = """:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:%(bn)s-(%(chains)s) - [0:0]
|
|
:quantum-filter-top - [0:0]
|
|
-A FORWARD -j quantum-filter-top
|
|
-A OUTPUT -j quantum-filter-top
|
|
-A quantum-filter-top -j %(bn)s-local
|
|
-A INPUT -j %(bn)s-INPUT
|
|
-A OUTPUT -j %(bn)s-OUTPUT
|
|
-A FORWARD -j %(bn)s-FORWARD
|
|
-A %(bn)s-sg-fallback -j DROP
|
|
""" % IPTABLES_ARG
|
|
|
|
FIREWALL_BASE_PACKAGE = 'quantum.agent.linux.iptables_firewall.'
|
|
FIREWALL_IPTABLES_DRIVER = FIREWALL_BASE_PACKAGE + 'IptablesFirewallDriver'
|
|
FIREWALL_HYBRID_DRIVER = (FIREWALL_BASE_PACKAGE +
|
|
'OVSHybridIptablesFirewallDriver')
|
|
FIREWALL_NOOP_DRIVER = 'quantum.agent.firewall.NoopFirewallDriver'
|
|
|
|
|
|
def set_firewall_driver(firewall_driver):
|
|
cfg.CONF.set_override('firewall_driver', firewall_driver,
|
|
group='SECURITYGROUP')
|
|
|
|
|
|
class TestSecurityGroupAgentWithIptables(base.BaseTestCase):
|
|
FIREWALL_DRIVER = FIREWALL_IPTABLES_DRIVER
|
|
PHYSDEV_INGRESS = 'physdev-out'
|
|
PHYSDEV_EGRESS = 'physdev-in'
|
|
|
|
def setUp(self):
|
|
super(TestSecurityGroupAgentWithIptables, self).setUp()
|
|
self.mox = mox.Mox()
|
|
agent_opts = [
|
|
cfg.StrOpt('root_helper', default='sudo'),
|
|
]
|
|
|
|
cfg.CONF.register_opts(agent_opts, "AGENT")
|
|
cfg.CONF.set_override(
|
|
'firewall_driver',
|
|
self.FIREWALL_DRIVER,
|
|
group='SECURITYGROUP')
|
|
self.addCleanup(mock.patch.stopall)
|
|
self.addCleanup(self.mox.UnsetStubs)
|
|
|
|
self.agent = sg_rpc.SecurityGroupAgentRpcMixin()
|
|
self.agent.context = None
|
|
|
|
self.root_helper = 'sudo'
|
|
self.agent.root_helper = 'sudo'
|
|
self.agent.init_firewall()
|
|
|
|
self.iptables = self.agent.firewall.iptables
|
|
self.mox.StubOutWithMock(self.iptables, "execute")
|
|
|
|
self.rpc = mock.Mock()
|
|
self.agent.plugin_rpc = self.rpc
|
|
rule1 = [{'direction': 'ingress',
|
|
'protocol': 'udp',
|
|
'ethertype': 'IPv4',
|
|
'source_ip_prefix': '10.0.0.2',
|
|
'source_port_range_min': 67,
|
|
'source_port_range_max': 67,
|
|
'port_range_min': 68,
|
|
'port_range_max': 68},
|
|
{'direction': 'ingress',
|
|
'protocol': 'tcp',
|
|
'ethertype': 'IPv4',
|
|
'port_range_min': 22,
|
|
'port_range_max': 22},
|
|
{'direction': 'egress',
|
|
'ethertype': 'IPv4'}]
|
|
rule2 = rule1[:]
|
|
rule2 += [{'direction': 'ingress',
|
|
'source_ip_prefix': '10.0.0.4',
|
|
'ethertype': 'IPv4'}]
|
|
rule3 = rule2[:]
|
|
rule3 += [{'direction': 'ingress',
|
|
'protocol': 'icmp',
|
|
'ethertype': 'IPv4'}]
|
|
rule4 = rule1[:]
|
|
rule4 += [{'direction': 'ingress',
|
|
'source_ip_prefix': '10.0.0.3',
|
|
'ethertype': 'IPv4'}]
|
|
rule5 = rule4[:]
|
|
rule5 += [{'direction': 'ingress',
|
|
'protocol': 'icmp',
|
|
'ethertype': 'IPv4'}]
|
|
self.devices1 = {'tap_port1': self._device('tap_port1',
|
|
'10.0.0.3',
|
|
'12:34:56:78:9a:bc',
|
|
rule1)}
|
|
self.devices2 = {'tap_port1': self._device('tap_port1',
|
|
'10.0.0.3',
|
|
'12:34:56:78:9a:bc',
|
|
rule2),
|
|
'tap_port2': self._device('tap_port2',
|
|
'10.0.0.4',
|
|
'12:34:56:78:9a:bd',
|
|
rule4)}
|
|
self.devices3 = {'tap_port1': self._device('tap_port1',
|
|
'10.0.0.3',
|
|
'12:34:56:78:9a:bc',
|
|
rule3),
|
|
'tap_port2': self._device('tap_port2',
|
|
'10.0.0.4',
|
|
'12:34:56:78:9a:bd',
|
|
rule5)}
|
|
|
|
def _device(self, device, ip, mac_address, rule):
|
|
return {'device': device,
|
|
'fixed_ips': [ip],
|
|
'mac_address': mac_address,
|
|
'security_groups': ['security_group1'],
|
|
'security_group_rules': rule,
|
|
'security_group_source_groups': [
|
|
'security_group1']}
|
|
|
|
def _regex(self, value):
|
|
value = value.replace('physdev-INGRESS', self.PHYSDEV_INGRESS)
|
|
value = value.replace('physdev-EGRESS', self.PHYSDEV_EGRESS)
|
|
value = value.replace('\n', '\\n')
|
|
value = value.replace('[', '\[')
|
|
value = value.replace(']', '\]')
|
|
return mox.Regex(value)
|
|
|
|
def _replay_iptables(self, v4_filter, v6_filter):
|
|
self.iptables.execute(
|
|
['iptables-save', '-t', 'filter'],
|
|
root_helper=self.root_helper).AndReturn('')
|
|
|
|
self.iptables.execute(
|
|
['iptables-restore'],
|
|
process_input=self._regex(v4_filter),
|
|
root_helper=self.root_helper).AndReturn('')
|
|
|
|
self.iptables.execute(
|
|
['iptables-save', '-t', 'nat'],
|
|
root_helper=self.root_helper).AndReturn('')
|
|
|
|
self.iptables.execute(
|
|
['iptables-restore'],
|
|
process_input=self._regex(IPTABLES_NAT),
|
|
root_helper=self.root_helper).AndReturn('')
|
|
|
|
self.iptables.execute(
|
|
['ip6tables-save', '-t', 'filter'],
|
|
root_helper=self.root_helper).AndReturn('')
|
|
|
|
self.iptables.execute(
|
|
['ip6tables-restore'],
|
|
process_input=self._regex(v6_filter),
|
|
root_helper=self.root_helper).AndReturn('')
|
|
|
|
def test_prepare_remove_port(self):
|
|
self.rpc.security_group_rules_for_devices.return_value = self.devices1
|
|
self._replay_iptables(IPTABLES_FILTER_1, IPTABLES_FILTER_V6_1)
|
|
self._replay_iptables(IPTABLES_FILTER_EMPTY, IPTABLES_FILTER_V6_EMPTY)
|
|
self.mox.ReplayAll()
|
|
|
|
self.agent.prepare_devices_filter(['tap_port1'])
|
|
self.agent.remove_devices_filter(['tap_port1'])
|
|
self.mox.VerifyAll()
|
|
|
|
def test_security_group_member_updated(self):
|
|
self.rpc.security_group_rules_for_devices.return_value = self.devices1
|
|
self._replay_iptables(IPTABLES_FILTER_1, IPTABLES_FILTER_V6_1)
|
|
self._replay_iptables(IPTABLES_FILTER_1_2, IPTABLES_FILTER_V6_1)
|
|
self._replay_iptables(IPTABLES_FILTER_2, IPTABLES_FILTER_V6_2)
|
|
self._replay_iptables(IPTABLES_FILTER_2_2, IPTABLES_FILTER_V6_2)
|
|
self._replay_iptables(IPTABLES_FILTER_1, IPTABLES_FILTER_V6_1)
|
|
self._replay_iptables(IPTABLES_FILTER_EMPTY, IPTABLES_FILTER_V6_EMPTY)
|
|
self.mox.ReplayAll()
|
|
|
|
self.agent.prepare_devices_filter(['tap_port1'])
|
|
self.rpc.security_group_rules_for_devices.return_value = self.devices2
|
|
self.agent.security_groups_member_updated(['security_group1'])
|
|
self.agent.prepare_devices_filter(['tap_port2'])
|
|
self.rpc.security_group_rules_for_devices.return_value = self.devices1
|
|
self.agent.security_groups_member_updated(['security_group1'])
|
|
self.agent.remove_devices_filter(['tap_port2'])
|
|
self.agent.remove_devices_filter(['tap_port1'])
|
|
|
|
self.mox.VerifyAll()
|
|
|
|
def test_security_group_rule_udpated(self):
|
|
self.rpc.security_group_rules_for_devices.return_value = self.devices2
|
|
self._replay_iptables(IPTABLES_FILTER_2, IPTABLES_FILTER_V6_2)
|
|
self._replay_iptables(IPTABLES_FILTER_2_3, IPTABLES_FILTER_V6_2)
|
|
self.mox.ReplayAll()
|
|
|
|
self.agent.prepare_devices_filter(['tap_port1', 'tap_port3'])
|
|
self.rpc.security_group_rules_for_devices.return_value = self.devices3
|
|
self.agent.security_groups_rule_updated(['security_group1'])
|
|
|
|
self.mox.VerifyAll()
|
|
|
|
|
|
class SGNotificationTestMixin():
|
|
def test_security_group_rule_updated(self):
|
|
name = 'webservers'
|
|
description = 'my webservers'
|
|
with self.security_group(name, description) as sg:
|
|
with self.security_group(name, description) as sg2:
|
|
security_group_id = sg['security_group']['id']
|
|
direction = "ingress"
|
|
remote_group_id = sg2['security_group']['id']
|
|
protocol = 'tcp'
|
|
port_range_min = 88
|
|
port_range_max = 88
|
|
with self.security_group_rule(security_group_id, direction,
|
|
protocol, port_range_min,
|
|
port_range_max,
|
|
remote_group_id=remote_group_id
|
|
):
|
|
pass
|
|
self.notifier.assert_has_calls(
|
|
[call.security_groups_rule_updated(mock.ANY,
|
|
[security_group_id]),
|
|
call.security_groups_rule_updated(mock.ANY,
|
|
[security_group_id])])
|
|
|
|
def test_security_group_member_updated(self):
|
|
with self.network() as n:
|
|
with self.subnet(n):
|
|
with self.security_group() as sg:
|
|
security_group_id = sg['security_group']['id']
|
|
res = self._create_port(self.fmt, n['network']['id'])
|
|
port = self.deserialize(self.fmt, res)
|
|
|
|
data = {'port': {'fixed_ips': port['port']['fixed_ips'],
|
|
'name': port['port']['name'],
|
|
ext_sg.SECURITYGROUPS:
|
|
[security_group_id]}}
|
|
|
|
req = self.new_update_request('ports', data,
|
|
port['port']['id'])
|
|
res = self.deserialize(self.fmt,
|
|
req.get_response(self.api))
|
|
self.assertEqual(res['port'][ext_sg.SECURITYGROUPS][0],
|
|
security_group_id)
|
|
self._delete('ports', port['port']['id'])
|
|
self.notifier.assert_has_calls(
|
|
[call.security_groups_member_updated(
|
|
mock.ANY, [mock.ANY]),
|
|
call.security_groups_member_updated(
|
|
mock.ANY, [security_group_id])])
|
|
|
|
|
|
class TestSecurityGroupAgentWithOVSIptables(
|
|
TestSecurityGroupAgentWithIptables):
|
|
|
|
FIREWALL_DRIVER = FIREWALL_HYBRID_DRIVER
|
|
|
|
def _regex(self, value):
|
|
#Note(nati): tap is prefixed on the device
|
|
# in the OVSHybridIptablesFirewallDriver
|
|
|
|
value = value.replace('tap_port', 'taptap_port')
|
|
value = value.replace('o_port', 'otap_port')
|
|
value = value.replace('i_port', 'itap_port')
|
|
return super(
|
|
TestSecurityGroupAgentWithOVSIptables,
|
|
self)._regex(value)
|
|
|
|
|
|
class TestSecurityGroupExtensionControl(base.BaseTestCase):
|
|
def test_firewall_enabled_noop_driver(self):
|
|
set_firewall_driver(FIREWALL_NOOP_DRIVER)
|
|
self.assertFalse(sg_rpc.is_firewall_enabled())
|
|
|
|
def test_firewall_enabled_iptables_driver(self):
|
|
set_firewall_driver(FIREWALL_IPTABLES_DRIVER)
|
|
self.assertTrue(sg_rpc.is_firewall_enabled())
|
|
|
|
def test_disable_security_group_extension_noop_driver(self):
|
|
set_firewall_driver(FIREWALL_NOOP_DRIVER)
|
|
exp_aliases = ['dummy1', 'dummy2']
|
|
ext_aliases = ['dummy1', 'security-group', 'dummy2']
|
|
sg_rpc.disable_security_group_extension_if_noop_driver(ext_aliases)
|
|
self.assertEqual(ext_aliases, exp_aliases)
|
|
|
|
def test_disable_security_group_extension_iptables_driver(self):
|
|
set_firewall_driver(FIREWALL_IPTABLES_DRIVER)
|
|
exp_aliases = ['dummy1', 'security-group', 'dummy2']
|
|
ext_aliases = ['dummy1', 'security-group', 'dummy2']
|
|
sg_rpc.disable_security_group_extension_if_noop_driver(ext_aliases)
|
|
self.assertEqual(ext_aliases, exp_aliases)
|