diff --git a/neutron/cmd/sanity/checks.py b/neutron/cmd/sanity/checks.py index 87e17dace61..3825a680309 100644 --- a/neutron/cmd/sanity/checks.py +++ b/neutron/cmd/sanity/checks.py @@ -138,7 +138,7 @@ def icmpv6_header_match_supported(): table=ovs_const.ARP_SPOOF_TABLE, priority=1, dl_type=n_consts.ETHERTYPE_IPV6, - nw_proto=n_consts.PROTO_NUM_ICMP_V6, + nw_proto=n_consts.PROTO_NUM_IPV6_ICMP, icmp_type=n_consts.ICMPV6_TYPE_NA, nd_target='fdf8:f53b:82e4::10', actions="NORMAL") diff --git a/neutron/common/constants.py b/neutron/common/constants.py index b80d5c00254..1910ee66df5 100644 --- a/neutron/common/constants.py +++ b/neutron/common/constants.py @@ -125,14 +125,71 @@ SUBNET_ALLOCATION_EXT_ALIAS = 'subnet_allocation' ETHERTYPE_IPV6 = 0x86DD # Protocol names and numbers for Security Groups/Firewalls -PROTO_NAME_TCP = 'tcp' +PROTO_NAME_AH = 'ah' +PROTO_NAME_DCCP = 'dccp' +PROTO_NAME_EGP = 'egp' +PROTO_NAME_ESP = 'esp' +PROTO_NAME_GRE = 'gre' PROTO_NAME_ICMP = 'icmp' -PROTO_NAME_ICMP_V6 = 'icmpv6' +PROTO_NAME_IGMP = 'igmp' +PROTO_NAME_IPV6_ENCAP = 'ipv6-encap' +PROTO_NAME_IPV6_FRAG = 'ipv6-frag' +PROTO_NAME_IPV6_ICMP = 'ipv6-icmp' +PROTO_NAME_IPV6_NONXT = 'ipv6-nonxt' +PROTO_NAME_IPV6_OPTS = 'ipv6-opts' +PROTO_NAME_IPV6_ROUTE = 'ipv6-route' +PROTO_NAME_OSPF = 'ospf' +PROTO_NAME_PGM = 'pgm' +PROTO_NAME_RSVP = 'rsvp' +PROTO_NAME_SCTP = 'sctp' +PROTO_NAME_TCP = 'tcp' PROTO_NAME_UDP = 'udp' -PROTO_NUM_TCP = 6 +PROTO_NAME_UDPLITE = 'udplite' +PROTO_NAME_VRRP = 'vrrp' + +PROTO_NUM_AH = 51 +PROTO_NUM_DCCP = 33 +PROTO_NUM_EGP = 8 +PROTO_NUM_ESP = 50 +PROTO_NUM_GRE = 47 PROTO_NUM_ICMP = 1 -PROTO_NUM_ICMP_V6 = 58 +PROTO_NUM_IGMP = 2 +PROTO_NUM_IPV6_ENCAP = 41 +PROTO_NUM_IPV6_FRAG = 44 +PROTO_NUM_IPV6_ICMP = 58 +PROTO_NUM_IPV6_NONXT = 59 +PROTO_NUM_IPV6_OPTS = 60 +PROTO_NUM_IPV6_ROUTE = 43 +PROTO_NUM_OSPF = 89 +PROTO_NUM_PGM = 113 +PROTO_NUM_RSVP = 46 +PROTO_NUM_SCTP = 132 +PROTO_NUM_TCP = 6 PROTO_NUM_UDP = 17 +PROTO_NUM_UDPLITE = 136 +PROTO_NUM_VRRP = 112 + +IP_PROTOCOL_MAP = {PROTO_NAME_AH: PROTO_NUM_AH, + PROTO_NAME_DCCP: PROTO_NUM_DCCP, + PROTO_NAME_EGP: PROTO_NUM_EGP, + PROTO_NAME_ESP: PROTO_NUM_ESP, + PROTO_NAME_GRE: PROTO_NUM_GRE, + PROTO_NAME_ICMP: PROTO_NUM_ICMP, + PROTO_NAME_IGMP: PROTO_NUM_IGMP, + PROTO_NAME_IPV6_ENCAP: PROTO_NUM_IPV6_ENCAP, + PROTO_NAME_IPV6_FRAG: PROTO_NUM_IPV6_FRAG, + PROTO_NAME_IPV6_ICMP: PROTO_NUM_IPV6_ICMP, + PROTO_NAME_IPV6_NONXT: PROTO_NUM_IPV6_NONXT, + PROTO_NAME_IPV6_OPTS: PROTO_NUM_IPV6_OPTS, + PROTO_NAME_IPV6_ROUTE: PROTO_NUM_IPV6_ROUTE, + PROTO_NAME_OSPF: PROTO_NUM_OSPF, + PROTO_NAME_PGM: PROTO_NUM_PGM, + PROTO_NAME_RSVP: PROTO_NUM_RSVP, + PROTO_NAME_SCTP: PROTO_NUM_SCTP, + PROTO_NAME_TCP: PROTO_NUM_TCP, + PROTO_NAME_UDP: PROTO_NUM_UDP, + PROTO_NAME_UDPLITE: PROTO_NUM_UDPLITE, + PROTO_NAME_VRRP: PROTO_NUM_VRRP} # List of ICMPv6 types that should be allowed by default: # Multicast Listener Query (130), diff --git a/neutron/db/securitygroups_db.py b/neutron/db/securitygroups_db.py index f462f1453c2..42b8040fe47 100644 --- a/neutron/db/securitygroups_db.py +++ b/neutron/db/securitygroups_db.py @@ -38,11 +38,6 @@ from neutron.extensions import securitygroup as ext_sg LOG = logging.getLogger(__name__) -IP_PROTOCOL_MAP = {constants.PROTO_NAME_TCP: constants.PROTO_NUM_TCP, - constants.PROTO_NAME_UDP: constants.PROTO_NUM_UDP, - constants.PROTO_NAME_ICMP: constants.PROTO_NUM_ICMP, - constants.PROTO_NAME_ICMP_V6: constants.PROTO_NUM_ICMP_V6} - class SecurityGroup(model_base.HasStandardAttributes, model_base.BASEV2, model_base.HasId, model_base.HasTenant): @@ -420,7 +415,7 @@ class SecurityGroupDbMixin(ext_sg.SecurityGroupPluginBase): # problems with comparing int and string in PostgreSQL. Here this # string is converted to int to give an opportunity to use it as # before. - return int(IP_PROTOCOL_MAP.get(protocol, protocol)) + return int(constants.IP_PROTOCOL_MAP.get(protocol, protocol)) def _validate_port_range(self, rule): """Check that port_range is valid.""" @@ -452,7 +447,12 @@ class SecurityGroupDbMixin(ext_sg.SecurityGroupPluginBase): def _validate_ethertype_and_protocol(self, rule): """Check if given ethertype and protocol are valid or not""" - if rule['protocol'] == constants.PROTO_NAME_ICMP_V6: + if rule['protocol'] in [constants.PROTO_NAME_IPV6_ENCAP, + constants.PROTO_NAME_IPV6_FRAG, + constants.PROTO_NAME_IPV6_ICMP, + constants.PROTO_NAME_IPV6_NONXT, + constants.PROTO_NAME_IPV6_OPTS, + constants.PROTO_NAME_IPV6_ROUTE]: if rule['ethertype'] == constants.IPv4: raise ext_sg.SecurityGroupEthertypeConflictWithProtocol( ethertype=rule['ethertype'], protocol=rule['protocol']) diff --git a/neutron/db/securitygroups_rpc_base.py b/neutron/db/securitygroups_rpc_base.py index 7f151fef600..5cd22278c89 100644 --- a/neutron/db/securitygroups_rpc_base.py +++ b/neutron/db/securitygroups_rpc_base.py @@ -432,7 +432,7 @@ class SecurityGroupServerRpcMixin(sg_db.SecurityGroupDbMixin): for ra_ip in ra_ips: ra_rule = {'direction': 'ingress', 'ethertype': n_const.IPv6, - 'protocol': n_const.PROTO_NAME_ICMP_V6, + 'protocol': n_const.PROTO_NAME_IPV6_ICMP, 'source_ip_prefix': ra_ip, 'source_port_range_min': n_const.ICMPV6_TYPE_RA} port['security_group_rules'].append(ra_rule) diff --git a/neutron/extensions/securitygroup.py b/neutron/extensions/securitygroup.py index 9ae3806da24..c9172d62816 100644 --- a/neutron/extensions/securitygroup.py +++ b/neutron/extensions/securitygroup.py @@ -211,8 +211,7 @@ def _validate_name_not_default(data, valid_values=None): attr.validators['type:name_not_default'] = _validate_name_not_default -sg_supported_protocols = [None, const.PROTO_NAME_TCP, const.PROTO_NAME_UDP, - const.PROTO_NAME_ICMP, const.PROTO_NAME_ICMP_V6] +sg_supported_protocols = [None] + list(const.IP_PROTOCOL_MAP.keys()) sg_supported_ethertypes = ['IPv4', 'IPv6'] # Attribute Map diff --git a/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/ovs_ofctl/br_int.py b/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/ovs_ofctl/br_int.py index d0aca03d75d..a7c55fc5e30 100644 --- a/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/ovs_ofctl/br_int.py +++ b/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/ovs_ofctl/br_int.py @@ -116,14 +116,15 @@ class OVSIntegrationBridge(ovs_bridge.OVSAgentBridge): for ip in ip_addresses: self.install_normal( table_id=constants.ARP_SPOOF_TABLE, priority=2, - dl_type=const.ETHERTYPE_IPV6, nw_proto=const.PROTO_NUM_ICMP_V6, + dl_type=const.ETHERTYPE_IPV6, + nw_proto=const.PROTO_NUM_IPV6_ICMP, icmp_type=const.ICMPV6_TYPE_NA, nd_target=ip, in_port=port) # Now that the rules are ready, direct icmpv6 neighbor advertisement # traffic from the port into the anti-spoof table. self.add_flow(table=constants.LOCAL_SWITCHING, priority=10, dl_type=const.ETHERTYPE_IPV6, - nw_proto=const.PROTO_NUM_ICMP_V6, + nw_proto=const.PROTO_NUM_IPV6_ICMP, icmp_type=const.ICMPV6_TYPE_NA, in_port=port, actions=("resubmit(,%s)" % constants.ARP_SPOOF_TABLE)) @@ -147,7 +148,7 @@ class OVSIntegrationBridge(ovs_bridge.OVSAgentBridge): self.delete_flows(table_id=constants.LOCAL_SWITCHING, in_port=port, proto='arp') self.delete_flows(table_id=constants.LOCAL_SWITCHING, - in_port=port, nw_proto=const.PROTO_NUM_ICMP_V6, + in_port=port, nw_proto=const.PROTO_NUM_IPV6_ICMP, icmp_type=const.ICMPV6_TYPE_NA) self.delete_arp_spoofing_allow_rules(port) diff --git a/neutron/tests/unit/agent/test_securitygroups_rpc.py b/neutron/tests/unit/agent/test_securitygroups_rpc.py index 132b3aaacb0..a46c15dacd9 100644 --- a/neutron/tests/unit/agent/test_securitygroups_rpc.py +++ b/neutron/tests/unit/agent/test_securitygroups_rpc.py @@ -612,7 +612,7 @@ class SGServerRpcCallBackTestCase(test_sg.SecurityGroupDBTestCase): 'port_range_min': 23, 'source_ip_prefix': fake_prefix}, {'direction': 'ingress', - 'protocol': const.PROTO_NAME_ICMP_V6, + 'protocol': const.PROTO_NAME_IPV6_ICMP, 'ethertype': const.IPv6, 'source_ip_prefix': fake_gateway, 'source_port_range_min': const.ICMPV6_TYPE_RA}, @@ -727,7 +727,7 @@ class SGServerRpcCallBackTestCase(test_sg.SecurityGroupDBTestCase): 'security_group_id': sg1_id, 'port_range_min': 22}, {'direction': 'ingress', - 'protocol': const.PROTO_NAME_ICMP_V6, + 'protocol': const.PROTO_NAME_IPV6_ICMP, 'ethertype': const.IPv6, 'source_ip_prefix': gateway_lla_ip, 'source_port_range_min': const.ICMPV6_TYPE_RA}, @@ -801,7 +801,7 @@ class SGServerRpcCallBackTestCase(test_sg.SecurityGroupDBTestCase): 'security_group_id': sg1_id, 'port_range_min': 22}, {'direction': 'ingress', - 'protocol': const.PROTO_NAME_ICMP_V6, + 'protocol': const.PROTO_NAME_IPV6_ICMP, 'ethertype': const.IPv6, 'source_ip_prefix': gateway_lla_ip, 'source_port_range_min': const.ICMPV6_TYPE_RA}, @@ -870,7 +870,7 @@ class SGServerRpcCallBackTestCase(test_sg.SecurityGroupDBTestCase): 'security_group_id': sg1_id, 'port_range_min': 22}, {'direction': 'ingress', - 'protocol': const.PROTO_NAME_ICMP_V6, + 'protocol': const.PROTO_NAME_IPV6_ICMP, 'ethertype': const.IPv6, 'source_ip_prefix': gateway_lla_ip, 'source_port_range_min': const.ICMPV6_TYPE_RA}, @@ -926,7 +926,7 @@ class SGServerRpcCallBackTestCase(test_sg.SecurityGroupDBTestCase): 'security_group_id': sg1_id, 'port_range_min': 22}, {'direction': 'ingress', - 'protocol': const.PROTO_NAME_ICMP_V6, + 'protocol': const.PROTO_NAME_IPV6_ICMP, 'ethertype': const.IPv6, 'source_ip_prefix': fake_gateway, 'source_port_range_min': const.ICMPV6_TYPE_RA}, @@ -1032,7 +1032,7 @@ class SGServerRpcCallBackTestCase(test_sg.SecurityGroupDBTestCase): 'port_range_min': 23, 'dest_ip_prefix': fake_prefix}, {'direction': 'ingress', - 'protocol': const.PROTO_NAME_ICMP_V6, + 'protocol': const.PROTO_NAME_IPV6_ICMP, 'ethertype': const.IPv6, 'source_ip_prefix': fake_gateway, 'source_port_range_min': const.ICMPV6_TYPE_RA}, @@ -1097,7 +1097,7 @@ class SGServerRpcCallBackTestCase(test_sg.SecurityGroupDBTestCase): 'remote_group_id': sg2_id, 'security_group_id': sg1_id}, {'direction': 'ingress', - 'protocol': const.PROTO_NAME_ICMP_V6, + 'protocol': const.PROTO_NAME_IPV6_ICMP, 'ethertype': const.IPv6, 'source_ip_prefix': fake_gateway, 'source_port_range_min': const.ICMPV6_TYPE_RA}, diff --git a/neutron/tests/unit/db/test_securitygroups_db.py b/neutron/tests/unit/db/test_securitygroups_db.py index db98f4622c0..59e40c74d03 100644 --- a/neutron/tests/unit/db/test_securitygroups_db.py +++ b/neutron/tests/unit/db/test_securitygroups_db.py @@ -16,6 +16,7 @@ import testtools from neutron.callbacks import exceptions from neutron.callbacks import registry +from neutron.common import constants from neutron import context from neutron.db import common_db_mixin from neutron.db import securitygroups_db @@ -83,3 +84,22 @@ class SecurityGroupDbMixinTestCase(testlib_api.SqlTestCase): with testtools.ExpectedException( securitygroup.SecurityGroupRuleNotFound): self.mixin.delete_security_group_rule(self.ctx, 'foo_rule') + + def test_validate_ethertype_and_protocol(self): + fake_ipv4_rules = [{'protocol': constants.PROTO_NAME_IPV6_ICMP, + 'ethertype': constants.IPv4}, + {'protocol': constants.PROTO_NAME_IPV6_ENCAP, + 'ethertype': constants.IPv4}, + {'protocol': constants.PROTO_NAME_IPV6_ROUTE, + 'ethertype': constants.IPv4}, + {'protocol': constants.PROTO_NAME_IPV6_FRAG, + 'ethertype': constants.IPv4}, + {'protocol': constants.PROTO_NAME_IPV6_NONXT, + 'ethertype': constants.IPv4}, + {'protocol': constants.PROTO_NAME_IPV6_OPTS, + 'ethertype': constants.IPv4}] + # test wrong protocols + for rule in fake_ipv4_rules: + with testtools.ExpectedException( + securitygroup.SecurityGroupEthertypeConflictWithProtocol): + self.mixin._validate_ethertype_and_protocol(rule) diff --git a/neutron/tests/unit/extensions/test_securitygroup.py b/neutron/tests/unit/extensions/test_securitygroup.py index b94c4fd5833..25d90748491 100644 --- a/neutron/tests/unit/extensions/test_securitygroup.py +++ b/neutron/tests/unit/extensions/test_securitygroup.py @@ -427,7 +427,7 @@ class TestSecurityGroups(SecurityGroupDBTestCase): with self.security_group(name, description) as sg: security_group_id = sg['security_group']['id'] rule = self._build_security_group_rule( - security_group_id, 'ingress', const.PROTO_NAME_ICMP_V6) + security_group_id, 'ingress', const.PROTO_NAME_IPV6_ICMP) res = self._create_security_group_rule(self.fmt, rule) self.deserialize(self.fmt, res) self.assertEqual(webob.exc.HTTPBadRequest.code, res.status_int) @@ -813,7 +813,7 @@ class TestSecurityGroups(SecurityGroupDBTestCase): direction = "ingress" ethertype = const.IPv6 remote_ip_prefix = "2001::f401:56ff:fefe:d3dc/128" - protocol = const.PROTO_NAME_ICMP_V6 + protocol = const.PROTO_NAME_IPV6_ICMP # ICMPV6 type port_range_min = const.ICMPV6_TYPE_RA # ICMPV6 code @@ -1348,7 +1348,7 @@ class TestSecurityGroups(SecurityGroupDBTestCase): with self.security_group() as sg: rule = {'security_group_id': sg['security_group']['id'], 'direction': 'ingress', - 'ethertype': 'IPv4', + 'ethertype': const.IPv4, 'tenant_id': 'test-tenant'} res = self._create_security_group_rule( @@ -1363,11 +1363,11 @@ class TestSecurityGroups(SecurityGroupDBTestCase): with self.security_group() as sg: rule_v4 = {'security_group_id': sg['security_group']['id'], 'direction': 'ingress', - 'ethertype': 'IPv4', + 'ethertype': const.IPv4, 'tenant_id': 'test-tenant'} rule_v6 = {'security_group_id': sg['security_group']['id'], 'direction': 'ingress', - 'ethertype': 'IPv6', + 'ethertype': const.IPv6, 'tenant_id': 'test-tenant'} rules = {'security_group_rules': [rule_v4, rule_v6]} diff --git a/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/openflow/ovs_ofctl/test_br_int.py b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/openflow/ovs_ofctl/test_br_int.py index 8c77e185ceb..51892fd10c0 100644 --- a/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/openflow/ovs_ofctl/test_br_int.py +++ b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/openflow/ovs_ofctl/test_br_int.py @@ -194,17 +194,17 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase): expected = [ call.add_flow(dl_type=const.ETHERTYPE_IPV6, actions='normal', icmp_type=const.ICMPV6_TYPE_NA, - nw_proto=const.PROTO_NUM_ICMP_V6, + nw_proto=const.PROTO_NUM_IPV6_ICMP, nd_target='2001:db8::1', priority=2, table=24, in_port=8888), call.add_flow(dl_type=const.ETHERTYPE_IPV6, actions='normal', icmp_type=const.ICMPV6_TYPE_NA, - nw_proto=const.PROTO_NUM_ICMP_V6, + nw_proto=const.PROTO_NUM_IPV6_ICMP, nd_target='fdf8:f53b:82e4::1/128', priority=2, table=24, in_port=8888), call.add_flow(dl_type=const.ETHERTYPE_IPV6, icmp_type=const.ICMPV6_TYPE_NA, - nw_proto=const.PROTO_NUM_ICMP_V6, + nw_proto=const.PROTO_NUM_IPV6_ICMP, priority=10, table=0, in_port=8888, actions='resubmit(,24)') ] diff --git a/releasenotes/notes/add-ip-protocols-in-sg-60467a073e771aee.yaml b/releasenotes/notes/add-ip-protocols-in-sg-60467a073e771aee.yaml new file mode 100644 index 00000000000..3df503fdeaa --- /dev/null +++ b/releasenotes/notes/add-ip-protocols-in-sg-60467a073e771aee.yaml @@ -0,0 +1,7 @@ +--- +prelude: > + Add popular IP protocols to the security group code. End-users can + specify protocol names instead of protocol numbers in both RESTful + API and python-neutronclient CLI. +upgrade: + - Add popular IP protocols to security group code.