diff --git a/neutron/agent/linux/openvswitch_firewall/firewall.py b/neutron/agent/linux/openvswitch_firewall/firewall.py index daf119735c3..d5cd184a63e 100644 --- a/neutron/agent/linux/openvswitch_firewall/firewall.py +++ b/neutron/agent/linux/openvswitch_firewall/firewall.py @@ -40,6 +40,7 @@ from neutron.agent.linux.openvswitch_firewall import constants as ovsfw_consts from neutron.agent.linux.openvswitch_firewall import exceptions from neutron.agent.linux.openvswitch_firewall import iptables from neutron.agent.linux.openvswitch_firewall import rules +from neutron.common import utils as n_utils LOG = logging.getLogger(__name__) CONJ_ID_REGEX = re.compile(r"conj_id=(\d+),") @@ -543,7 +544,8 @@ class OVSFirewallDriver(firewall.FirewallDriver): applied """ - self.permitted_ethertypes = cfg.CONF.SECURITYGROUP.permitted_ethertypes + self.permitted_ethertypes = n_utils.parse_permitted_ethertypes( + cfg.CONF.SECURITYGROUP.permitted_ethertypes) self.int_br = self.initialize_bridge(integration_bridge) self._initialize_sg() self._update_cookie = None @@ -1178,24 +1180,14 @@ class OVSFirewallDriver(firewall.FirewallDriver): # Allow custom ethertypes for permitted_ethertype in self.permitted_ethertypes: - if permitted_ethertype[:2] == '0x': - try: - hex_ethertype = hex(int(permitted_ethertype, base=16)) - action = ('resubmit(,%d)' % - ovs_consts.ACCEPTED_EGRESS_TRAFFIC_NORMAL_TABLE) - self._add_flow( - table=ovs_consts.BASE_EGRESS_TABLE, - priority=95, - dl_type=hex_ethertype, - reg_port=port.ofport, - actions=action - ) - continue - except ValueError: - pass - LOG.warning("Custom ethertype %(permitted_ethertype)s is not " - "a hexadecimal number.", - {'permitted_ethertype': permitted_ethertype}) + action = ('resubmit(,%d)' % + ovs_consts.ACCEPTED_EGRESS_TRAFFIC_NORMAL_TABLE) + self._add_flow( + table=ovs_consts.BASE_EGRESS_TABLE, + priority=95, + dl_type=permitted_ethertype, + reg_port=port.ofport, + actions=action) # Drop all remaining egress connections self._add_flow( @@ -1390,22 +1382,12 @@ class OVSFirewallDriver(firewall.FirewallDriver): # Allow custom ethertypes for permitted_ethertype in self.permitted_ethertypes: - if permitted_ethertype[:2] == '0x': - try: - hex_ethertype = hex(int(permitted_ethertype, base=16)) - self._add_flow( - table=ovs_consts.BASE_INGRESS_TABLE, - priority=100, - dl_type=hex_ethertype, - reg_port=port.ofport, - actions='output:{:d}'.format(port.ofport) - ) - continue - except ValueError: - pass - LOG.warning('Custom ethertype %(permitted_ethertype)s is not ' - 'a hexadecimal number.', - {'permitted_ethertype': permitted_ethertype}) + self._add_flow( + table=ovs_consts.BASE_INGRESS_TABLE, + priority=100, + dl_type=permitted_ethertype, + reg_port=port.ofport, + actions='output:{:d}'.format(port.ofport)) self._initialize_ingress_ipv6_icmp(port) diff --git a/neutron/common/utils.py b/neutron/common/utils.py index 1b2b4dd19f4..4c240584f11 100644 --- a/neutron/common/utils.py +++ b/neutron/common/utils.py @@ -1088,3 +1088,23 @@ def sign_instance_id(conf, instance_id): secret = encodeutils.to_utf8(secret) instance_id = encodeutils.to_utf8(instance_id) return hmac.new(secret, instance_id, hashlib.sha256).hexdigest() + + +def parse_permitted_ethertypes(permitted_ethertypes): + ret = set() + for pe in permitted_ethertypes: + if pe[:2].lower() != '0x': + LOG.warning('Custom ethertype %s is not a hexadecimal number.', pe) + continue + + try: + value = hex(int(pe, 16)) + if value in ret: + LOG.warning('Custom ethertype %s is repeated', pe) + else: + ret.add(value) + except ValueError: + LOG.warning('Custom ethertype %s is not a hexadecimal number.', pe) + continue + + return ret diff --git a/neutron/tests/unit/common/test_utils.py b/neutron/tests/unit/common/test_utils.py index 5c110c60298..4453fcf1707 100644 --- a/neutron/tests/unit/common/test_utils.py +++ b/neutron/tests/unit/common/test_utils.py @@ -656,3 +656,24 @@ class SignatureTestCase(base.BaseTestCase): '773ba44693c7553d6ee20f61ea5d2757a9a4f4a44d2841ae4e95b52e4cd62db4', utils.sign_instance_id(conf, 'foo') ) + + +class ParsePermittedEthertypesTestCase(base.BaseTestCase): + + @mock.patch.object(utils, 'LOG') + def test_parse_permitted_ethertypes(self, mock_log): + permitted_ethertypes = ['0x1234', + '0x1234', + '0x5678', + '0XCAfe', + '1112', + '0x123R'] + ret = utils.parse_permitted_ethertypes(permitted_ethertypes) + self.assertEqual({'0x1234', '0x5678', '0xcafe'}, ret) + calls = [mock.call('Custom ethertype %s is repeated', '0x1234'), + mock.call('Custom ethertype %s is not a hexadecimal number.', + '1112'), + mock.call('Custom ethertype %s is not a hexadecimal number.', + '0x123R'), + ] + mock_log.warning.assert_has_calls(calls)