networkd: Introduce IP6 tunnel
authorSusant Sahani <susant@redhat.com>
Fri, 16 Jan 2015 19:09:10 +0000 (00:39 +0530)
committerTom Gundersen <teg@jklm.no>
Thu, 22 Jan 2015 20:29:42 +0000 (21:29 +0100)
This patch enables networkd to create IP6 tunnels

example conf:

ipip6.netdev:
[NetDev]
Name=ipip6-tunnel
Kind=ip6tnl

[Tunnel]
Mode=ip4ipv6
Local=2a00:ffde:4567:edde::4987
Remote=2001:473:fece:cafe::5179

ipip6.network
[Match]
Name=wlan0

[Network]
Tunnel=ipip6-tunnel

23: ipip6-tunnel@wlan0: <POINTOPOINT,NOARP> mtu 1452 qdisc noop state
DOWN mode DEFAULT group default
    link/tunnel6 2a00:ffde:4567:edde::4987 peer 2001:473:fece:cafe::5179

man/systemd.netdev.xml
src/libsystemd/sd-rtnl/rtnl-types.c
src/libsystemd/sd-rtnl/rtnl-types.h
src/network/networkd-netdev-gperf.gperf
src/network/networkd-netdev-tunnel.c
src/network/networkd-netdev-tunnel.h
src/network/networkd-netdev.c
src/network/networkd-netdev.h
src/network/networkd-network.c

index ca50558..f6e385a 100644 (file)
 
                         <para>The <literal>[Tunnel]</literal> section only applies for netdevs of kind
                         <literal>ipip</literal>, <literal>sit</literal>, <literal>gre</literal>, <literal>gretap</literal>,
-                        and <literal>vti</literal> and accepts the following keys:</para>
+                        <literal>vti</literal> and <literal>ip6tnl</literal> and accepts the following keys:</para>
 
                         <variablelist class='network-directives'>
                                 <varlistentry>
                                                 <para>A boolean. When true, enables Path MTU Discovery on the tunnel.</para>
                                         </listitem>
                                 </varlistentry>
+                                <varlistentry>
+                                  <term><varname>Mode=</varname></term>
+                                  <listitem>
+                                    <para>IPv6 tunnels can have three mode
+                                    <literal>ip6ip6</literal>
+                                    <literal>ip4ipv6</literal>,
+                                    <literal>any</literal>
+                                    </para>
+                                  </listitem>
+                                </varlistentry>
+
+                                   <varlistentry>
+                                        <term><varname>Mode=</varname></term>
+                                        <listitem>
+                                                <para>The mode specifies the ip6 tunnel protocol. Supported type are </para>
+                                        </listitem>
+                                </varlistentry>
                         </variablelist>
         </refsect1>
         <refsect1>
index 97b3cee..ef3aebf 100644 (file)
@@ -153,6 +153,17 @@ static const NLType rtnl_link_info_data_ipvti_types[IFLA_VTI_MAX + 1] = {
         [IFLA_VTI_REMOTE]       = { .type = NLA_IN_ADDR  },
 };
 
+static const NLType rtnl_link_info_data_ip6tnl_types[IFLA_IPTUN_MAX + 1] = {
+        [IFLA_IPTUN_LINK]                = { .type = NLA_U32 },
+        [IFLA_IPTUN_LOCAL]               = { .type = NLA_IN_ADDR },
+        [IFLA_IPTUN_REMOTE]              = { .type = NLA_IN_ADDR },
+        [IFLA_IPTUN_TTL]                 = { .type = NLA_U8 },
+        [IFLA_IPTUN_FLAGS]               = { .type = NLA_U32 },
+        [IFLA_IPTUN_PROTO]               = { .type = NLA_U8 },
+        [IFLA_IPTUN_ENCAP_LIMIT]         = { .type = NLA_U8 },
+        [IFLA_IPTUN_FLOWINFO]            = { .type = NLA_U32},
+};
+
 /* these strings must match the .kind entries in the kernel */
 static const char* const nl_union_link_info_data_table[_NL_UNION_LINK_INFO_DATA_MAX] = {
         [NL_UNION_LINK_INFO_DATA_BOND] = "bond",
@@ -168,6 +179,7 @@ static const char* const nl_union_link_info_data_table[_NL_UNION_LINK_INFO_DATA_
         [NL_UNION_LINK_INFO_DATA_IPGRETAP_TUNNEL] = "gretap",
         [NL_UNION_LINK_INFO_DATA_SIT_TUNNEL] = "sit",
         [NL_UNION_LINK_INFO_DATA_VTI_TUNNEL] = "vti",
+        [NL_UNION_LINK_INFO_DATA_IP6TNL_TUNNEL] = "ip6tnl",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(nl_union_link_info_data, NLUnionLinkInfoData);
@@ -197,6 +209,9 @@ static const NLTypeSystem rtnl_link_info_data_type_systems[_NL_UNION_LINK_INFO_D
                                                   .types = rtnl_link_info_data_iptun_types },
         [NL_UNION_LINK_INFO_DATA_VTI_TUNNEL] =  { .max = ELEMENTSOF(rtnl_link_info_data_ipvti_types) - 1,
                                                   .types = rtnl_link_info_data_ipvti_types },
+        [NL_UNION_LINK_INFO_DATA_IP6TNL_TUNNEL] =  { .max = ELEMENTSOF(rtnl_link_info_data_ip6tnl_types) - 1,
+                                                     .types = rtnl_link_info_data_ip6tnl_types },
+
 };
 
 static const NLTypeSystemUnion rtnl_link_info_data_type_system_union = {
index aacea19..347a0ad 100644 (file)
@@ -78,6 +78,7 @@ typedef enum NLUnionLinkInfoData {
         NL_UNION_LINK_INFO_DATA_IPGRETAP_TUNNEL,
         NL_UNION_LINK_INFO_DATA_SIT_TUNNEL,
         NL_UNION_LINK_INFO_DATA_VTI_TUNNEL,
+        NL_UNION_LINK_INFO_DATA_IP6TNL_TUNNEL,
         _NL_UNION_LINK_INFO_DATA_MAX,
         _NL_UNION_LINK_INFO_DATA_INVALID = -1
 } NLUnionLinkInfoData;
index cb741b4..963c47c 100644 (file)
@@ -35,6 +35,7 @@ Tunnel.Remote,            config_parse_tunnel_address,        0,
 Tunnel.TOS,               config_parse_unsigned,              0,                             offsetof(Tunnel, tos)
 Tunnel.TTL,               config_parse_unsigned,              0,                             offsetof(Tunnel, ttl)
 Tunnel.DiscoverPathMTU,   config_parse_bool,                  0,                             offsetof(Tunnel, pmtudisc)
+Tunnel.Mode,              config_parse_ip6tnl_mode,           0,                             offsetof(Tunnel, ip6tnl_mode)
 Peer.Name,                config_parse_ifname,                0,                             offsetof(Veth, ifname_peer)
 Peer.MACAddress,          config_parse_hwaddr,                0,                             offsetof(Veth, mac_peer)
 VXLAN.Id,                 config_parse_uint64,                0,                             offsetof(VxLan, id)
index fde08fb..f439bf9 100644 (file)
@@ -3,7 +3,7 @@
 /***
     This file is part of systemd.
 
-    Copyright 2014 Susant Sahani <susant@redhat.com>
+    Copyright 2014 Susant Sahani
 
     systemd is free software; you can redistribute it and/or modify it
     under the terms of the GNU Lesser General Public License as published by
@@ -24,6 +24,7 @@
 #include <net/if.h>
 #include <linux/ip.h>
 #include <linux/if_tunnel.h>
+#include <linux/ip6_tunnel.h>
 
 #include "sd-rtnl.h"
 #include "networkd-netdev-tunnel.h"
 #include "missing.h"
 #include "conf-parser.h"
 
+#define DEFAULT_TNL_HOP_LIMIT   64
+
+static const char* const ip6tnl_mode_table[_NETDEV_IP6_TNL_MODE_MAX] = {
+        [NETDEV_IP6_TNL_MODE_IP6IP6] = "ip6ip6",
+        [NETDEV_IP6_TNL_MODE_IPIP6] = "ip4ipv6",
+        [NETDEV_IP6_TNL_MODE_ANYIP6] = "any",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(ip6tnl_mode, Ip6TnlMode);
+DEFINE_CONFIG_PARSE_ENUM(config_parse_ip6tnl_mode, ip6tnl_mode, Ip6TnlMode, "Failed to parse ip6 tunnel Mode");
+
 static int netdev_ipip_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_message *m) {
         Tunnel *t = IPIP(netdev);
         int r;
@@ -243,6 +255,73 @@ static int netdev_vti_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_me
         return r;
 }
 
+static int netdev_ip6tnl_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_message *m) {
+        Tunnel *t = IP6TNL(netdev);
+        uint8_t proto;
+        int r;
+
+        assert(netdev);
+        assert(link);
+        assert(m);
+        assert(t);
+        assert(t->family == AF_INET6);
+
+        r = sd_rtnl_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex);
+        if (r < 0) {
+                log_netdev_error(netdev,
+                                 "Could not append IFLA_IPTUN_LINK attribute: %s",
+                                 strerror(-r));
+                return r;
+        }
+
+        r = sd_rtnl_message_append_in6_addr(m, IFLA_IPTUN_LOCAL, &t->local.in6);
+        if (r < 0) {
+                log_netdev_error(netdev,
+                                 "Could not append IFLA_IPTUN_LOCAL attribute: %s",
+                                 strerror(-r));
+                return r;
+        }
+
+        r = sd_rtnl_message_append_in6_addr(m, IFLA_IPTUN_REMOTE, &t->remote.in6);
+        if (r < 0) {
+                log_netdev_error(netdev,
+                                 "Could not append IFLA_IPTUN_REMOTE attribute: %s",
+                                 strerror(-r));
+                return r;
+        }
+
+        r = sd_rtnl_message_append_u8(m, IFLA_IPTUN_TTL, t->ttl);
+        if (r < 0) {
+                log_netdev_error(netdev,
+                                 "Could not append IFLA_IPTUN_TTL attribute: %s",
+                                 strerror(-r));
+                return r;
+        }
+
+        switch (t->ip6tnl_mode) {
+        case NETDEV_IP6_TNL_MODE_IP6IP6:
+                proto = IPPROTO_IPV6;
+                break;
+        case NETDEV_IP6_TNL_MODE_IPIP6:
+                proto = IPPROTO_IPIP;
+                break;
+        case NETDEV_IP6_TNL_MODE_ANYIP6:
+        default:
+                proto = 0;
+                break;
+        }
+
+        r = sd_rtnl_message_append_u8(m, IFLA_IPTUN_PROTO, proto);
+        if (r < 0) {
+                log_netdev_error(netdev,
+                                 "Could not append IFLA_IPTUN_MODE attribute: %s",
+                                 strerror(-r));
+                return r;
+        }
+
+        return r;
+}
+
 static int netdev_tunnel_verify(NetDev *netdev, const char *filename) {
         Tunnel *t = NULL;
 
@@ -265,6 +344,9 @@ static int netdev_tunnel_verify(NetDev *netdev, const char *filename) {
         case NETDEV_KIND_VTI:
                 t = VTI(netdev);
                 break;
+        case NETDEV_KIND_IP6TNL:
+                t = IP6TNL(netdev);
+                break;
         default:
                 assert_not_reached("Invalid tunnel kind");
         }
@@ -276,11 +358,18 @@ static int netdev_tunnel_verify(NetDev *netdev, const char *filename) {
                return -EINVAL;
         }
 
-        if (t->family != AF_INET) {
+        if (t->family != AF_INET && t->family != AF_INET6) {
               log_warning("Tunnel with invalid address family configured in %s. Ignoring", filename);
               return -EINVAL;
         }
 
+        if (netdev->kind == NETDEV_KIND_IP6TNL) {
+                if (t->ip6tnl_mode == _NETDEV_IP6_TNL_MODE_INVALID) {
+                        log_warning("IP6 Tunnel without mode configured in %s. Ignoring", filename);
+                        return -EINVAL;
+                }
+        }
+
         return 0;
 }
 
@@ -362,6 +451,17 @@ static void gre_init(NetDev *n) {
         t->pmtudisc = true;
 }
 
+static void ip6tnl_init(NetDev *n) {
+        Tunnel *t = IP6TNL(n);
+
+        assert(n);
+        assert(t);
+
+        t->ttl = DEFAULT_TNL_HOP_LIMIT;
+        t->encap_limit = IPV6_DEFAULT_TNL_ENCAP_LIMIT;
+        t->ip6tnl_mode = _NETDEV_IP6_TNL_MODE_INVALID;
+}
+
 const NetDevVTable ipip_vtable = {
         .object_size = sizeof(Tunnel),
         .init = ipip_init,
@@ -406,3 +506,12 @@ const NetDevVTable gretap_vtable = {
         .create_type = NETDEV_CREATE_STACKED,
         .config_verify = netdev_tunnel_verify,
 };
+
+const NetDevVTable ip6tnl_vtable = {
+        .object_size = sizeof(Tunnel),
+        .init = ip6tnl_init,
+        .sections = "Match\0NetDev\0Tunnel\0",
+        .fill_message_create = netdev_ip6tnl_fill_message_create,
+        .create_type = NETDEV_CREATE_STACKED,
+        .config_verify = netdev_tunnel_verify,
+};
index b6f6c9d..1687f9e 100644 (file)
@@ -25,15 +25,30 @@ typedef struct Tunnel Tunnel;
 
 #include "networkd-netdev.h"
 
+typedef enum Ip6TnlMode {
+        NETDEV_IP6_TNL_MODE_IP6IP6,
+        NETDEV_IP6_TNL_MODE_IPIP6,
+        NETDEV_IP6_TNL_MODE_ANYIP6,
+        _NETDEV_IP6_TNL_MODE_MAX,
+        _NETDEV_IP6_TNL_MODE_INVALID = -1,
+} Ip6TnlMode;
+
 struct Tunnel {
         NetDev meta;
 
+        uint8_t encap_limit;
+
         int family;
 
         unsigned ttl;
         unsigned tos;
+        unsigned flags;
+
         union in_addr_union local;
         union in_addr_union remote;
+
+        Ip6TnlMode ip6tnl_mode;
+
         bool pmtudisc;
 };
 
@@ -42,3 +57,13 @@ extern const NetDevVTable sit_vtable;
 extern const NetDevVTable vti_vtable;
 extern const NetDevVTable gre_vtable;
 extern const NetDevVTable gretap_vtable;
+extern const NetDevVTable ip6tnl_vtable;
+
+const char *ip6tnl_mode_to_string(Ip6TnlMode d) _const_;
+Ip6TnlMode ip6tnl_mode_from_string(const char *d) _pure_;
+
+int config_parse_ip6tnl_mode(const char *unit, const char *filename,
+                             unsigned line, const char *section,
+                             unsigned section_line, const char *lvalue,
+                             int ltype, const char *rvalue, void *data,
+                             void *userdata);
index 4e1fb43..ed85702 100644 (file)
@@ -46,6 +46,7 @@ const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX] = {
         [NETDEV_KIND_DUMMY] = &dummy_vtable,
         [NETDEV_KIND_TUN] = &tun_vtable,
         [NETDEV_KIND_TAP] = &tap_vtable,
+        [NETDEV_KIND_IP6TNL] = &ip6tnl_vtable,
 };
 
 static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
@@ -64,6 +65,7 @@ static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
         [NETDEV_KIND_DUMMY] = "dummy",
         [NETDEV_KIND_TUN] = "tun",
         [NETDEV_KIND_TAP] = "tap",
+        [NETDEV_KIND_IP6TNL] = "ip6tnl",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind);
index 3c44795..77d00d4 100644 (file)
@@ -51,6 +51,7 @@ typedef enum NetDevKind {
         NETDEV_KIND_SIT,
         NETDEV_KIND_VETH,
         NETDEV_KIND_VTI,
+        NETDEV_KIND_IP6TNL,
         NETDEV_KIND_DUMMY,
         NETDEV_KIND_TUN,
         NETDEV_KIND_TAP,
@@ -167,6 +168,7 @@ DEFINE_CAST(GRE, Tunnel);
 DEFINE_CAST(GRETAP, Tunnel);
 DEFINE_CAST(SIT, Tunnel);
 DEFINE_CAST(VTI, Tunnel);
+DEFINE_CAST(IP6TNL, Tunnel);
 DEFINE_CAST(VETH, Veth);
 DEFINE_CAST(DUMMY, Dummy);
 DEFINE_CAST(TUN, TunTap);
index 2b555ef..0f474d9 100644 (file)
@@ -453,7 +453,9 @@ int config_parse_tunnel(const char *unit,
             netdev->kind != NETDEV_KIND_SIT &&
             netdev->kind != NETDEV_KIND_GRE &&
             netdev->kind != NETDEV_KIND_GRETAP &&
-            netdev->kind != NETDEV_KIND_VTI) {
+            netdev->kind != NETDEV_KIND_VTI &&
+            netdev->kind != NETDEV_KIND_IP6TNL
+            ) {
                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
                            "NetDev is not a tunnel, ignoring assignment: %s", rvalue);
                 return 0;