From 855ee1a1d272b599410212b40768a9c71f260e37 Mon Sep 17 00:00:00 2001 From: Susant Sahani Date: Sat, 17 Jan 2015 00:39:10 +0530 Subject: networkd: Introduce IP6 tunnel 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: 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 | 19 +++++- src/libsystemd/sd-rtnl/rtnl-types.c | 15 +++++ src/libsystemd/sd-rtnl/rtnl-types.h | 1 + src/network/networkd-netdev-gperf.gperf | 1 + src/network/networkd-netdev-tunnel.c | 113 +++++++++++++++++++++++++++++++- src/network/networkd-netdev-tunnel.h | 25 +++++++ src/network/networkd-netdev.c | 2 + src/network/networkd-netdev.h | 2 + src/network/networkd-network.c | 4 +- 9 files changed, 178 insertions(+), 4 deletions(-) diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml index ca50558644..f6e385a97a 100644 --- a/man/systemd.netdev.xml +++ b/man/systemd.netdev.xml @@ -331,7 +331,7 @@ The [Tunnel] section only applies for netdevs of kind ipip, sit, gre, gretap, - and vti and accepts the following keys: + vti and ip6tnl and accepts the following keys: @@ -373,6 +373,23 @@ A boolean. When true, enables Path MTU Discovery on the tunnel. + + Mode= + + IPv6 tunnels can have three mode + ip6ip6 + ip4ipv6, + any + + + + + + Mode= + + The mode specifies the ip6 tunnel protocol. Supported type are + + diff --git a/src/libsystemd/sd-rtnl/rtnl-types.c b/src/libsystemd/sd-rtnl/rtnl-types.c index 97b3ceec12..ef3aebf58c 100644 --- a/src/libsystemd/sd-rtnl/rtnl-types.c +++ b/src/libsystemd/sd-rtnl/rtnl-types.c @@ -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 = { diff --git a/src/libsystemd/sd-rtnl/rtnl-types.h b/src/libsystemd/sd-rtnl/rtnl-types.h index aacea19986..347a0adf97 100644 --- a/src/libsystemd/sd-rtnl/rtnl-types.h +++ b/src/libsystemd/sd-rtnl/rtnl-types.h @@ -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; diff --git a/src/network/networkd-netdev-gperf.gperf b/src/network/networkd-netdev-gperf.gperf index cb741b470d..963c47c3e5 100644 --- a/src/network/networkd-netdev-gperf.gperf +++ b/src/network/networkd-netdev-gperf.gperf @@ -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) diff --git a/src/network/networkd-netdev-tunnel.c b/src/network/networkd-netdev-tunnel.c index fde08fb1e6..f439bf91b5 100644 --- a/src/network/networkd-netdev-tunnel.c +++ b/src/network/networkd-netdev-tunnel.c @@ -3,7 +3,7 @@ /*** This file is part of systemd. - Copyright 2014 Susant Sahani + 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 #include #include +#include #include "sd-rtnl.h" #include "networkd-netdev-tunnel.h" @@ -33,6 +34,17 @@ #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, +}; diff --git a/src/network/networkd-netdev-tunnel.h b/src/network/networkd-netdev-tunnel.h index b6f6c9df76..1687f9e6ad 100644 --- a/src/network/networkd-netdev-tunnel.h +++ b/src/network/networkd-netdev-tunnel.h @@ -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); diff --git a/src/network/networkd-netdev.c b/src/network/networkd-netdev.c index 4e1fb43200..ed857023bc 100644 --- a/src/network/networkd-netdev.c +++ b/src/network/networkd-netdev.c @@ -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); diff --git a/src/network/networkd-netdev.h b/src/network/networkd-netdev.h index 3c447958a6..77d00d4a3b 100644 --- a/src/network/networkd-netdev.h +++ b/src/network/networkd-netdev.h @@ -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); diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 2b555efd5c..0f474d932d 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -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; -- cgit v1.2.3-54-g00ecf