Add support for unaddressed port

Neutron could create a port without the IP address when the network doesn't
have a subnet. In this case, neutron will have no L3 knowledgee and we need
remove the L3 filter on it but reserve the L2 filter if there is.
This patch will make L2 agent verify the fixed_ips before converting the
security-group-rules into firewall rules, L3 rules in it will be removed.
And filter like arp-spoofing will be disabled for this port.

Partially Implements: blueprint vm-without-l3-address
Change-Id: I5cd1fdfa13a7e57258be7251768eaa8ba64d486e
This commit is contained in:
Yalei Wang 2015-08-07 22:43:30 +08:00
parent d6742d48b0
commit d4c52b7f5a
4 changed files with 47 additions and 47 deletions

View File

@ -45,6 +45,13 @@ LINUX_DEV_LEN = 14
comment_rule = iptables_manager.comment_rule comment_rule = iptables_manager.comment_rule
def port_needs_l3_security(port):
if port['fixed_ips'] or port.get('allowed_address_pairs'):
return True
else:
return False
class IptablesFirewallDriver(firewall.FirewallDriver): class IptablesFirewallDriver(firewall.FirewallDriver):
"""Driver which enforces security groups through iptables rules.""" """Driver which enforces security groups through iptables rules."""
IPTABLES_DIRECTION = {firewall.INGRESS_DIRECTION: 'physdev-out', IPTABLES_DIRECTION = {firewall.INGRESS_DIRECTION: 'physdev-out',
@ -367,6 +374,7 @@ class IptablesFirewallDriver(firewall.FirewallDriver):
mac_ipv6_pairs.append((mac, ip_address)) mac_ipv6_pairs.append((mac, ip_address))
def _spoofing_rule(self, port, ipv4_rules, ipv6_rules): def _spoofing_rule(self, port, ipv4_rules, ipv6_rules):
if port_needs_l3_security(port):
# Allow dhcp client packets # Allow dhcp client packets
ipv4_rules += [comment_rule('-p udp -m udp --sport 68 --dport 67 ' ipv4_rules += [comment_rule('-p udp -m udp --sport 68 --dport 67 '
'-j RETURN', comment=ic.DHCP_CLIENT)] '-j RETURN', comment=ic.DHCP_CLIENT)]
@ -376,8 +384,10 @@ class IptablesFirewallDriver(firewall.FirewallDriver):
comment=ic.IPV6_RA_DROP)] comment=ic.IPV6_RA_DROP)]
ipv6_rules += [comment_rule('-p icmpv6 -j RETURN', ipv6_rules += [comment_rule('-p icmpv6 -j RETURN',
comment=ic.IPV6_ICMP_ALLOW)] comment=ic.IPV6_ICMP_ALLOW)]
ipv6_rules += [comment_rule('-p udp -m udp --sport 546 --dport 547 ' ipv6_rules += [comment_rule('-p udp -m udp --sport 546 --dport '
'-j RETURN', comment=ic.DHCP_CLIENT)] '547 -j RETURN',
comment=ic.DHCP_CLIENT)]
mac_ipv4_pairs = [] mac_ipv4_pairs = []
mac_ipv6_pairs = [] mac_ipv6_pairs = []
@ -483,11 +493,14 @@ class IptablesFirewallDriver(firewall.FirewallDriver):
ipv6_iptables_rules) ipv6_iptables_rules)
elif direction == firewall.INGRESS_DIRECTION: elif direction == firewall.INGRESS_DIRECTION:
ipv6_iptables_rules += self._accept_inbound_icmpv6() ipv6_iptables_rules += self._accept_inbound_icmpv6()
if port_needs_l3_security(port):
# include IPv4 and IPv6 iptable rules from security group # include IPv4 and IPv6 iptable rules from security group
ipv4_iptables_rules += self._convert_sgr_to_iptables_rules( ipv4_iptables_rules += self._convert_sgr_to_iptables_rules(
ipv4_sg_rules) ipv4_sg_rules)
ipv6_iptables_rules += self._convert_sgr_to_iptables_rules( ipv6_iptables_rules += self._convert_sgr_to_iptables_rules(
ipv6_sg_rules) ipv6_sg_rules)
# finally add the rules to the port chain for a given direction # finally add the rules to the port chain for a given direction
self._add_rules_to_chain_v4v6(self._port_chain_name(port, direction), self._add_rules_to_chain_v4v6(self._port_chain_name(port, direction),
ipv4_iptables_rules, ipv4_iptables_rules,
@ -498,6 +511,7 @@ class IptablesFirewallDriver(firewall.FirewallDriver):
self._spoofing_rule(port, self._spoofing_rule(port,
ipv4_iptables_rules, ipv4_iptables_rules,
ipv6_iptables_rules) ipv6_iptables_rules)
if port_needs_l3_security(port):
self._drop_dhcp_rule(ipv4_iptables_rules, ipv6_iptables_rules) self._drop_dhcp_rule(ipv4_iptables_rules, ipv6_iptables_rules)
def _update_ipset_members(self, security_group_ids): def _update_ipset_members(self, security_group_ids):

View File

@ -30,6 +30,7 @@ from neutron.agent.common import ovs_lib
from neutron.agent.common import polling from neutron.agent.common import polling
from neutron.agent.common import utils from neutron.agent.common import utils
from neutron.agent.linux import ip_lib from neutron.agent.linux import ip_lib
from neutron.agent.linux.iptables_firewall import port_needs_l3_security
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.api.rpc.handlers import dvr_rpc from neutron.api.rpc.handlers import dvr_rpc
@ -807,6 +808,9 @@ class OVSNeutronAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin,
addresses |= {p['ip_address'] addresses |= {p['ip_address']
for p in port_details['allowed_address_pairs']} for p in port_details['allowed_address_pairs']}
if not port_needs_l3_security(port_details):
return
addresses = {ip for ip in addresses addresses = {ip for ip in addresses
if netaddr.IPNetwork(ip).version == 4} if netaddr.IPNetwork(ip).version == 4}
if any(netaddr.IPNetwork(ip).prefixlen == 0 for ip in addresses): if any(netaddr.IPNetwork(ip).prefixlen == 0 for ip in addresses):

View File

@ -1453,15 +1453,6 @@ class IptablesFirewallTestCase(BaseIptablesFirewallTestCase):
'--physdev-is-bridged ' '--physdev-is-bridged '
'-j $ifake_dev', '-j $ifake_dev',
comment=ic.SG_TO_VM_SG), comment=ic.SG_TO_VM_SG),
mock.call.add_rule(
'ifake_dev',
'-m state --state INVALID -j DROP', comment=None),
mock.call.add_rule(
'ifake_dev',
'-m state --state RELATED,ESTABLISHED -j RETURN',
comment=None),
mock.call.add_rule('ifake_dev', '-j $sg-fallback',
comment=None),
mock.call.add_chain('ofake_dev'), mock.call.add_chain('ofake_dev'),
mock.call.add_rule('FORWARD', mock.call.add_rule('FORWARD',
'-m physdev --physdev-in tapfake_dev ' '-m physdev --physdev-in tapfake_dev '
@ -1483,26 +1474,8 @@ class IptablesFirewallTestCase(BaseIptablesFirewallTestCase):
mock.call.add_rule( mock.call.add_rule(
'sfake_dev', '-j DROP', 'sfake_dev', '-j DROP',
comment=ic.PAIR_DROP), comment=ic.PAIR_DROP),
mock.call.add_rule(
'ofake_dev',
'-p udp -m udp --sport 68 --dport 67 -j RETURN',
comment=None),
mock.call.add_rule('ofake_dev', '-j $sfake_dev', mock.call.add_rule('ofake_dev', '-j $sfake_dev',
comment=None), comment=None),
mock.call.add_rule(
'ofake_dev',
'-p udp -m udp --sport 67 --dport 68 -j DROP',
comment=None),
mock.call.add_rule(
'ofake_dev',
'-m state --state INVALID -j DROP',
comment=None),
mock.call.add_rule(
'ofake_dev',
'-m state --state RELATED,ESTABLISHED -j RETURN',
comment=None),
mock.call.add_rule('ofake_dev', '-j $sg-fallback',
comment=None),
mock.call.add_rule('sg-chain', '-j ACCEPT')] mock.call.add_rule('sg-chain', '-j ACCEPT')]
self.v4filter_inst.assert_has_calls(calls) self.v4filter_inst.assert_has_calls(calls)

View File

@ -1102,7 +1102,7 @@ class TestOvsNeutronAgent(object):
self.assertTrue(int_br.delete_arp_spoofing_protection.called) self.assertTrue(int_br.delete_arp_spoofing_protection.called)
self.assertFalse(int_br.install_arp_spoofing_protection.called) self.assertFalse(int_br.install_arp_spoofing_protection.called)
def test_arp_spoofing_basic_rule_setup(self): def test_arp_spoofing_basic_rule_setup_without_ip(self):
vif = FakeVif() vif = FakeVif()
fake_details = {'fixed_ips': []} fake_details = {'fixed_ips': []}
self.agent.prevent_arp_spoofing = True self.agent.prevent_arp_spoofing = True
@ -1111,9 +1111,18 @@ class TestOvsNeutronAgent(object):
self.assertEqual( self.assertEqual(
[mock.call(port=vif.ofport)], [mock.call(port=vif.ofport)],
int_br.delete_arp_spoofing_protection.mock_calls) int_br.delete_arp_spoofing_protection.mock_calls)
self.assertFalse(int_br.install_arp_spoofing_protection.called)
def test_arp_spoofing_basic_rule_setup_fixed_ip(self):
vif = FakeVif()
fake_details = {'fixed_ips': [{'ip_address': '192.168.44.100'}]}
self.agent.prevent_arp_spoofing = True
int_br = mock.create_autospec(self.agent.int_br)
self.agent.setup_arp_spoofing_protection(int_br, vif, fake_details)
self.assertEqual( self.assertEqual(
[mock.call(ip_addresses=set(), port=vif.ofport)], [mock.call(port=vif.ofport)],
int_br.install_arp_spoofing_protection.mock_calls) int_br.delete_arp_spoofing_protection.mock_calls)
self.assertTrue(int_br.install_arp_spoofing_protection.called)
def test_arp_spoofing_fixed_and_allowed_addresses(self): def test_arp_spoofing_fixed_and_allowed_addresses(self):
vif = FakeVif() vif = FakeVif()