Skip to content

Commit 7c7b020

Browse files
committed
Fix iptables mapping of 'ipip' protocol
Map 'ipip' to use the string 'ipencap' so the IptablesFirewallDriver class in neutron works correctly. Once neutron-lib is bumped this can be removed. Add tests for IP protocol 'ipip', '4' and '94' to make sure the IptablesFirewallDriver class in neutron treats them correctly. Long description below. This is one of those confusing edge cases and I think Linux is conspiring against us. Let me explain. 1) neutron-lib does correctly define the protocol name 'ipip' as 4. 2) The linux kernel uses the same in in.h: IPPROTO_IPIP = 4 IPPROTO_BEETPH = 94 (?) 3) iptables maps 'ipip' to 94 and 'ipencap' to 4. # for num in {0..255}; do iptables -A INPUT -p $num; done # iptables-save | grep -E 'ipip|ipencap' -A INPUT -p ipencap -A INPUT -p ipip 4) /etc/protocols does the same as iptables: grep -E 'ipencap|ipip' /etc/protocols ipencap 4 IP-ENCAP # IP encapsulated in IP (officially ``IP'') ipip 94 IPIP # IP-within-IP Encapsulation Protocol 5) getprotoby{name|number} does what /etc/protocols does: $ getprotobyname ipip struct protoent: (0x7fbbbcca9c60) p_name ipip p_aliases IPIP p_proto 94 $ getprotobynumber 4 struct protoent: (0x7fc51ad86be0) p_name ipencap p_aliases IP-ENCAP p_proto 4 Neutron actually builds a mapping based on the getprotoby* calls, so in the iptables case it winds-up doing the wrong thing. Partial-bug: #2054324 Change-Id: Icc84b54be07d39059723d6c233c03aa130102423 (cherry picked from commit 793dfb0)
1 parent d253552 commit 7c7b020

File tree

2 files changed

+40
-0
lines changed

2 files changed

+40
-0
lines changed

neutron/agent/linux/iptables_firewall.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -769,6 +769,10 @@ def _protocol_name_map(self):
769769
if not self._iptables_protocol_name_map:
770770
tmp_map = constants.IPTABLES_PROTOCOL_NAME_MAP.copy()
771771
tmp_map.update(self._local_protocol_name_map())
772+
# TODO(haleyb): remove once neutron-lib with fix is available
773+
# - 'ipip' uses 'ipencap' to match IPPROTO_IPIP from in.h,
774+
# which is IP-ENCAP/'4' in /etc/protocols (see bug #2054324)
775+
tmp_map[constants.PROTO_NAME_IPIP] = 'ipencap'
772776
self._iptables_protocol_name_map = tmp_map
773777
return self._iptables_protocol_name_map
774778

neutron/tests/unit/agent/linux/test_iptables_firewall.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,42 @@ def test_filter_ipv4_ingress_protocol_encap_by_num(self):
489489
egress = None
490490
self._test_prepare_port_filter(rule, ingress, egress)
491491

492+
def test_filter_ipv4_ingress_protocol_ipip(self):
493+
# 'ipip' via the API uses 'ipencap' to match what iptables-save
494+
# uses, which is IP-ENCAP/'4' from /etc/protocols (see bug #2054324)
495+
rule = {'ethertype': 'IPv4',
496+
'direction': 'ingress',
497+
'protocol': 'ipip'}
498+
ingress = mock.call.add_rule('ifake_dev',
499+
'-p ipencap -j RETURN',
500+
top=False, comment=None)
501+
egress = None
502+
self._test_prepare_port_filter(rule, ingress, egress)
503+
504+
def test_filter_ipv4_ingress_protocol_ipip_by_num(self):
505+
# '4' via the API uses 'ipencap' to match what iptables-save
506+
# uses, which is IP-ENCAP/'4' from /etc/protocols (see bug #2054324)
507+
rule = {'ethertype': 'IPv4',
508+
'direction': 'ingress',
509+
'protocol': '4'}
510+
ingress = mock.call.add_rule('ifake_dev',
511+
'-p ipencap -j RETURN',
512+
top=False, comment=None)
513+
egress = None
514+
self._test_prepare_port_filter(rule, ingress, egress)
515+
516+
def test_filter_ipv4_ingress_protocol_ipencap_by_num(self):
517+
# '94' via the API uses 'ipip' to match what iptables-save
518+
# uses, which is IPIP/'94' from /etc/protocols (see bug #2054324)
519+
rule = {'ethertype': 'IPv4',
520+
'direction': 'ingress',
521+
'protocol': '94'}
522+
ingress = mock.call.add_rule('ifake_dev',
523+
'-p ipip -j RETURN',
524+
top=False, comment=None)
525+
egress = None
526+
self._test_prepare_port_filter(rule, ingress, egress)
527+
492528
def test_filter_ipv4_ingress_protocol_999_local(self):
493529
# There is no protocol 999, so let's return a mapping
494530
# that says there is and make sure the rule is created

0 commit comments

Comments
 (0)