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 --- 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 +- 6 files changed, 144 insertions(+), 3 deletions(-) (limited to 'src/network') 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