Commit e8ee4a29 authored by Chris Luke's avatar Chris Luke Committed by Peter V. Saveliev

Add support for GRE over IPv6 (#320)

'ip6gre' is implemented in the kernel using the same IFLA_GRE_XXX
fields as GRE over IPv4, but with IPv6 instead of IPv4 addresses
in the 'local' and 'remote' slots.

This patch adds an NLA map for ip6gre with the appropriate support.
Since the field names would conflict with the existing IFLA_GRE
ones, these new items are prefixed IFLA_IP6GRE instead.

I did experiment with using the same, existing, NLA map for both
address families. Unfortunately the 'target' type requires the address
family to be specified in both directions; to and from the kernel.
This can be achieved when creating GRE links; however the only way
I see of reconstructing the addresses from the kernel is to add a
heuristic to the 'target' type to guess the family; this did not
feel like the correct approach.

In the end, the approach in this patch using new IFLA_IP6GRE NLA
entries appears the cleaner of the two.
parent a6049a32
......@@ -37,6 +37,7 @@ def _get_data_fields():
'tuntap_data',
'vxlan_data',
'gre_data',
'ip6gre_data',
'macvlan_data',
'macvtap_data',
'ipvlan_data',
......@@ -285,7 +286,8 @@ class Interface(Transactional):
data = linkinfo.get_attr('IFLA_INFO_DATA')
self['vlan_id'] = data.get_attr('IFLA_VLAN_ID')
if kind in ('vxlan', 'macvlan', 'macvtap', 'gre',
'gretap', 'ipvlan', 'bridge'):
'gretap', 'ipvlan', 'bridge',
'ip6gre', 'ip6gretap'):
data = linkinfo.get_attr('IFLA_INFO_DATA') or {}
for nla in data.get('attrs', []):
norm = ifinfmsg.nla2name(nla[0])
......
......@@ -1050,6 +1050,9 @@ class IPRouteMixin(object):
gre_iflags=32,
gre_oflags=32)
Support for GRE over IPv6 is also included; use `kind=ip6gre` and
`ip6gre_` as the prefix for its values.
► macvlan
Macvlan interfaces act like VLANs within OS. The macvlan driver
......
......@@ -444,6 +444,8 @@ class ifinfbase(object):
'macvtap': self.macvtap_data,
'gre': self.gre_data,
'gretap': self.gre_data,
'ip6gre': self.ip6gre_data,
'ip6gretap': self.ip6gre_data,
'bond': self.bond_data,
'veth': self.veth_data,
'tuntap': self.tuntap_data,
......@@ -534,6 +536,33 @@ class ifinfbase(object):
('IFLA_GRE_ENCAP_DPORT', 'be16'),
('IFLA_GRE_COLLECT_METADATA', 'flag'))
class ip6gre_data(nla):
# Ostensibly the same as ip6gre_data except that local
# and remote are ipv6 addrs.
# As of Linux 4.8,IFLA_GRE_COLLECT_METADATA has not been
# implemented for IPv6.
# Linux uses the same enum names for v6 and v4 (in if_tunnel.h);
# Here we name them IFLA_IP6GRE_xxx instead to avoid conflicts
# with gre_data above.
nla_map = (('IFLA_IP6GRE_UNSPEC', 'none'),
('IFLA_IP6GRE_LINK', 'uint32'),
('IFLA_IP6GRE_IFLAGS', 'uint16'),
('IFLA_IP6GRE_OFLAGS', 'uint16'),
('IFLA_IP6GRE_IKEY', 'be32'),
('IFLA_IP6GRE_OKEY', 'be32'),
('IFLA_IP6GRE_LOCAL', 'ip6addr'),
('IFLA_IP6GRE_REMOTE', 'ip6addr'),
('IFLA_IP6GRE_TTL', 'uint8'),
('IFLA_IP6GRE_TOS', 'uint8'),
('IFLA_IP6GRE_PMTUDISC', 'uint8'),
('IFLA_IP6GRE_ENCAP_LIMIT', 'uint8'),
('IFLA_IP6GRE_FLOWINFO', 'be32'),
('IFLA_IP6GRE_FLAGS', 'uint32'),
('IFLA_IP6GRE_ENCAP_TYPE', 'uint16'),
('IFLA_IP6GRE_ENCAP_FLAGS', 'uint16'),
('IFLA_IP6GRE_ENCAP_SPORT', 'be16'),
('IFLA_IP6GRE_ENCAP_DPORT', 'be16'))
class macvlan_data(macvx_data):
pass
......
......@@ -315,7 +315,8 @@ class IPLinkRequest(IPRequest):
linkinfo.append(['IFLA_INFO_KIND', value])
if value in ('vlan', 'bond', 'tuntap', 'veth',
'vxlan', 'macvlan', 'macvtap', 'gre',
'gretap', 'ipvlan', 'bridge', 'vrf'):
'gretap', 'ipvlan', 'bridge', 'vrf',
'ip6gre', 'ip6gretap'):
linkinfo.append(['IFLA_INFO_DATA', {'attrs': []}])
elif key == 'vlan_id':
nla = ['IFLA_VLAN_ID', value]
......@@ -361,6 +362,11 @@ class IPLinkRequest(IPRequest):
self.defer_nla(nla, ('IFLA_LINKINFO', 'IFLA_INFO_DATA'),
lambda x: x.get('kind', None) == 'gre' or
x.get('kind', None) == 'gretap')
elif key.startswith('ip6gre_'):
nla = [ifinfmsg.name2nla(key), value]
self.defer_nla(nla, ('IFLA_LINKINFO', 'IFLA_INFO_DATA'),
lambda x: x.get('kind', None) == 'ip6gre' or
x.get('kind', None) == 'ip6gretap')
elif key.startswith('vxlan_'):
nla = [ifinfmsg.name2nla(key), value]
self.defer_nla(nla, ('IFLA_LINKINFO', 'IFLA_INFO_DATA'),
......
......@@ -2104,6 +2104,66 @@ class TestExplicit(BasicSetup):
finally:
ip2.release()
@skip_if_not_supported
def test_create_ip6gre(self):
require_user('root')
ifL = self.get_ifname()
ifV = self.get_ifname()
with self.ip.create(kind='dummy', ifname=ifL) as i:
i.add_ip('2001:dba::1/64')
i.up()
self.ip.create(kind='ip6gre',
ifname=ifV,
ip6gre_local='2001:dba::1',
ip6gre_remote='2001:dba::2',
ip6gre_ttl=16).commit()
ip2 = IPDB()
ifdb = ip2.interfaces
try:
assert ifdb[ifV].ip6gre_local == '2001:dba::1'
assert ifdb[ifV].ip6gre_remote == '2001:dba::2'
assert ifdb[ifV].ip6gre_ttl == 16
except Exception:
raise
finally:
ip2.release()
@skip_if_not_supported
def test_create_ip6gretap(self):
require_user('root')
ifL = self.get_ifname()
ifV = self.get_ifname()
with self.ip.create(kind='dummy', ifname=ifL) as i:
i.add_ip('2001:dba::1/64')
i.up()
self.ip.create(kind='ip6gretap',
ifname=ifV,
ip6gre_local='2001:dba::1',
ip6gre_ikey=1,
ip6gre_okey=2,
ip6gre_iflags=0x0020,
ip6gre_oflags=0x0020,
ip6gre_ttl=16).commit()
ip2 = IPDB()
ifdb = ip2.interfaces
try:
assert ifdb[ifV].ip6gre_local == '2001:dba::1'
assert ifdb[ifV].ip6gre_ikey == 1
assert ifdb[ifV].ip6gre_okey == 2
assert ifdb[ifV].ip6gre_iflags == 0x0020
assert ifdb[ifV].ip6gre_oflags == 0x0020
assert ifdb[ifV].ip6gre_ttl == 16
except Exception:
raise
finally:
ip2.release()
@skip_if_not_supported
def test_create_vxlan(self):
require_user('root')
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment