summaryrefslogtreecommitdiff
path: root/src/network/netdev
diff options
context:
space:
mode:
authorSusant Sahani <susant@redhat.com>2017-04-25 09:45:05 +0530
committerSusant Sahani <susant@redhat.com>2017-04-25 10:34:15 +0530
commit6598e04641a17cc56216f907be5a62535b433806 (patch)
tree6db29e35b7e4a734d44629873f13049a6fefdc68 /src/network/netdev
parentca5e80712e74457671f093b6e7e48516a917ea21 (diff)
networkd: Introduce GENEVE netdev
This work enables cration of geneve tunnel
Diffstat (limited to 'src/network/netdev')
-rw-r--r--src/network/netdev/geneve.c394
-rw-r--r--src/network/netdev/geneve.h119
-rw-r--r--src/network/netdev/netdev-gperf.gperf10
-rw-r--r--src/network/netdev/netdev.c3
-rw-r--r--src/network/netdev/netdev.h1
5 files changed, 527 insertions, 0 deletions
diff --git a/src/network/netdev/geneve.c b/src/network/netdev/geneve.c
new file mode 100644
index 0000000000..bb9807b556
--- /dev/null
+++ b/src/network/netdev/geneve.c
@@ -0,0 +1,394 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2017 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
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <net/if.h>
+
+#include "alloc-util.h"
+#include "conf-parser.h"
+#include "extract-word.h"
+#include "geneve.h"
+#include "parse-util.h"
+#include "sd-netlink.h"
+#include "string-util.h"
+#include "strv.h"
+#include "missing.h"
+#include "networkd-manager.h"
+
+#define GENEVE_FLOW_LABEL_MAX_MASK 0xFFFFFU
+#define DEFAULT_GENEVE_DESTINATION_PORT 6081
+
+/* callback for geneve netdev's created without a backing Link */
+static int geneve_netdev_create_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
+ _cleanup_netdev_unref_ NetDev *netdev = userdata;
+ int r;
+
+ assert(netdev->state != _NETDEV_STATE_INVALID);
+
+ r = sd_netlink_message_get_errno(m);
+ if (r == -EEXIST)
+ log_netdev_info(netdev, "Geneve netdev exists, using existing without changing its parameters");
+ else if (r < 0) {
+ log_netdev_warning_errno(netdev, r, "Geneve netdev could not be created: %m");
+ netdev_drop(netdev);
+
+ return 1;
+ }
+
+ log_netdev_debug(netdev, "Geneve created");
+
+ return 1;
+}
+
+static int netdev_geneve_create(NetDev *netdev) {
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
+ Geneve *v;
+ int r;
+
+ assert(netdev);
+
+ v = GENEVE(netdev);
+
+ r = sd_rtnl_message_new_link(netdev->manager->rtnl, &m, RTM_NEWLINK, 0);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not allocate RTM_NEWLINK message: %m");
+
+ r = sd_netlink_message_append_string(m, IFLA_IFNAME, netdev->ifname);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_IFNAME, attribute: %m");
+
+ if (netdev->mac) {
+ r = sd_netlink_message_append_ether_addr(m, IFLA_ADDRESS, netdev->mac);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_ADDRESS attribute: %m");
+ }
+
+ if (netdev->mtu) {
+ r = sd_netlink_message_append_u32(m, IFLA_MTU, netdev->mtu);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_MTU attribute: %m");
+ }
+
+ r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINKINFO attribute: %m");
+
+ r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, netdev_kind_to_string(netdev->kind));
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_INFO_DATA attribute: %m");
+
+ if (v->id <= GENEVE_VID_MAX) {
+ r = sd_netlink_message_append_u32(m, IFLA_GENEVE_ID, v->id);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_GENEVE_ID attribute: %m");
+ }
+
+ if (!in_addr_is_null(v->remote_family, &v->remote)) {
+
+ if (v->remote_family == AF_INET)
+ r = sd_netlink_message_append_in_addr(m, IFLA_GENEVE_REMOTE, &v->remote.in);
+ else
+ r = sd_netlink_message_append_in6_addr(m, IFLA_GENEVE_REMOTE6, &v->remote.in6);
+
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_GENEVE_GROUP attribute: %m");
+
+ }
+
+ if (v->ttl) {
+ r = sd_netlink_message_append_u8(m, IFLA_GENEVE_TTL, v->ttl);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_GENEVE_TTL attribute: %m");
+ }
+
+ r = sd_netlink_message_append_u8(m, IFLA_GENEVE_TOS, v->tos);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_GENEVE_TOS attribute: %m");
+
+ r = sd_netlink_message_append_u8(m, IFLA_GENEVE_UDP_CSUM, v->udpcsum);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_GENEVE_UDP_CSUM attribute: %m");
+
+ r = sd_netlink_message_append_u8(m, IFLA_GENEVE_UDP_ZERO_CSUM6_TX, v->udp6zerocsumtx);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_GENEVE_UDP_ZERO_CSUM6_TX attribute: %m");
+
+ r = sd_netlink_message_append_u8(m, IFLA_GENEVE_UDP_ZERO_CSUM6_RX, v->udp6zerocsumrx);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_GENEVE_UDP_ZERO_CSUM6_RX attribute: %m");
+
+ if (v->dest_port != DEFAULT_GENEVE_DESTINATION_PORT) {
+ r = sd_netlink_message_append_u16(m, IFLA_GENEVE_PORT, htobe16(v->dest_port));
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_GENEVE_PORT attribute: %m");
+ }
+
+ if (v->flow_label > 0) {
+ r = sd_netlink_message_append_u32(m, IFLA_GENEVE_LABEL, htobe32(v->flow_label));
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_GENEVE_LABEL attribute: %m");
+ }
+
+ r = sd_netlink_message_close_container(m);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_INFO_DATA attribute: %m");
+
+ r = sd_netlink_message_close_container(m);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINKINFO attribute: %m");
+
+ r = sd_netlink_call_async(netdev->manager->rtnl, m, geneve_netdev_create_handler, netdev, 0, NULL);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not send rtnetlink message: %m");
+
+ netdev_ref(netdev);
+
+ netdev->state = NETDEV_STATE_CREATING;
+
+ log_netdev_debug(netdev, "Creating");
+
+
+ return r;
+}
+
+int config_parse_geneve_vni(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) {
+ Geneve *v = userdata;
+ uint32_t f;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = safe_atou32(rvalue, &f);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse Geneve VNI '%s'.", rvalue);
+ return 0;
+ }
+
+ if (f > GENEVE_VID_MAX){
+ log_syntax(unit, LOG_ERR, filename, line, r, "Geneve VNI out is of range '%s'.", rvalue);
+ return 0;
+ }
+
+ v->id = f;
+
+ return 0;
+}
+
+int config_parse_geneve_tos(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) {
+ Geneve *v = userdata;
+ uint8_t f;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = safe_atou8(rvalue, &f);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse Geneve TOS '%s'.", rvalue);
+ return 0;
+ }
+
+ v->tos = f;
+
+ return 0;
+}
+
+int config_parse_geneve_ttl(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) {
+ Geneve *v = userdata;
+ uint8_t f;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = safe_atou8(rvalue, &f);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse Geneve TTL '%s'.", rvalue);
+ return 0;
+ }
+
+ if (f == 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Invalid Geneve TTL '%s'.", rvalue);
+ return 0;
+ }
+
+ v->ttl = f;
+
+ return 0;
+}
+
+int config_parse_geneve_address(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) {
+ Geneve *v = userdata;
+ union in_addr_union *addr = data, buffer;
+ int r, f;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = in_addr_from_string_auto(rvalue, &f, &buffer);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "geneve '%s' address is invalid, ignoring assignment: %s", lvalue, rvalue);
+ return 0;
+ }
+
+ r = in_addr_is_multicast(f, &buffer);
+ if (r > 0) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "geneve invalid multicast '%s' address, ignoring assignment: %s", lvalue, rvalue);
+ return 0;
+ }
+
+ v->remote_family = f;
+ *addr = buffer;
+
+ return 0;
+}
+
+int config_parse_geneve_destination_port(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) {
+ Geneve *v = userdata;
+ uint16_t port;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = parse_ip_port(rvalue, &port);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse Geneve destination port '%s'.", rvalue);
+ return 0;
+ }
+
+ v->dest_port = port;
+
+ return 0;
+}
+
+int config_parse_geneve_flow_label(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) {
+ Geneve *v = userdata;
+ uint32_t f;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = safe_atou32(rvalue, &f);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse Geneve flow label '%s'.", rvalue);
+ return 0;
+ }
+
+ if (f & ~GENEVE_FLOW_LABEL_MAX_MASK) {
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Geneve flow label '%s' not valid. Flow label range should be [0-1048575].", rvalue);
+ return 0;
+ }
+
+ v->flow_label = f;
+
+ return 0;
+}
+
+static void geneve_init(NetDev *netdev) {
+ Geneve *v;
+
+ assert(netdev);
+
+ v = GENEVE(netdev);
+
+ assert(v);
+
+ v->id = GENEVE_VID_MAX + 1;
+ v->dest_port = DEFAULT_GENEVE_DESTINATION_PORT;
+ v->udpcsum = false;
+ v->udp6zerocsumtx = false;
+ v->udp6zerocsumrx = false;
+}
+
+const NetDevVTable geneve_vtable = {
+ .object_size = sizeof(Geneve),
+ .init = geneve_init,
+ .sections = "Match\0NetDev\0GENEVE\0",
+ .create = netdev_geneve_create,
+ .create_type = NETDEV_CREATE_INDEPENDENT,
+};
diff --git a/src/network/netdev/geneve.h b/src/network/netdev/geneve.h
new file mode 100644
index 0000000000..3ba599aae6
--- /dev/null
+++ b/src/network/netdev/geneve.h
@@ -0,0 +1,119 @@
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2017 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
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+typedef struct Geneve Geneve;
+
+#include "in-addr-util.h"
+#include "netdev.h"
+#include "networkd-link.h"
+#include "networkd-network.h"
+#include "netdev.h"
+
+#define GENEVE_VID_MAX (1u << 24) - 1
+
+struct Geneve {
+ NetDev meta;
+
+ uint32_t id;
+ uint32_t flow_label;
+
+ int remote_family;
+
+ uint8_t tos;
+ uint8_t ttl;
+
+ uint16_t dest_port;
+
+ bool udpcsum;
+ bool udp6zerocsumtx;
+ bool udp6zerocsumrx;
+
+ union in_addr_union remote;
+};
+
+DEFINE_NETDEV_CAST(GENEVE, Geneve);
+extern const NetDevVTable geneve_vtable;
+
+int config_parse_geneve_vni(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);
+
+int config_parse_geneve_tos(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);
+
+int config_parse_geneve_ttl(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);
+
+int config_parse_geneve_address(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);
+
+int config_parse_geneve_destination_port(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);
+
+int config_parse_geneve_flow_label(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/netdev/netdev-gperf.gperf b/src/network/netdev/netdev-gperf.gperf
index 077fbc1d5c..a27a3d5562 100644
--- a/src/network/netdev/netdev-gperf.gperf
+++ b/src/network/netdev/netdev-gperf.gperf
@@ -4,6 +4,7 @@
#include "network-internal.h"
#include "netdev/bond.h"
#include "netdev/bridge.h"
+#include "netdev/geneve.h"
#include "netdev/ipvlan.h"
#include "netdev/macvlan.h"
#include "netdev/tunnel.h"
@@ -80,6 +81,15 @@ VXLAN.MaximumFDBEntries, config_parse_unsigned, 0,
VXLAN.PortRange, config_parse_port_range, 0, 0
VXLAN.DestinationPort, config_parse_destination_port, 0, offsetof(VxLan, dest_port)
VXLAN.FlowLabel, config_parse_flow_label, 0, 0
+GENEVE.Id, config_parse_geneve_vni, 0, offsetof(Geneve, id)
+GENEVE.Remote, config_parse_geneve_address, 0, offsetof(Geneve, remote)
+GENEVE.TOS, config_parse_geneve_tos, 0, offsetof(Geneve, tos)
+GENEVE.TTL, config_parse_geneve_ttl, 0, offsetof(Geneve, ttl)
+GENEVE.UDPChecksum, config_parse_bool, 0, offsetof(Geneve, udpcsum)
+GENEVE.UDP6ZeroCheckSumRx, config_parse_bool, 0, offsetof(Geneve, udp6zerocsumrx)
+GENEVE.UDP6ZeroCheckSumTx, config_parse_bool, 0, offsetof(Geneve, udp6zerocsumtx)
+GENEVE.DestinationPort, config_parse_geneve_destination_port, 0, offsetof(Geneve, dest_port)
+GENEVE.FlowLabel, config_parse_geneve_flow_label, 0, 0
Tun.OneQueue, config_parse_bool, 0, offsetof(TunTap, one_queue)
Tun.MultiQueue, config_parse_bool, 0, offsetof(TunTap, multi_queue)
Tun.PacketInfo, config_parse_bool, 0, offsetof(TunTap, packet_info)
diff --git a/src/network/netdev/netdev.c b/src/network/netdev/netdev.c
index 9b9e83d9db..3848c863c5 100644
--- a/src/network/netdev/netdev.c
+++ b/src/network/netdev/netdev.c
@@ -35,6 +35,7 @@
#include "netdev/bridge.h"
#include "netdev/bond.h"
+#include "netdev/geneve.h"
#include "netdev/vlan.h"
#include "netdev/macvlan.h"
#include "netdev/ipvlan.h"
@@ -69,6 +70,7 @@ const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX] = {
[NETDEV_KIND_IP6TNL] = &ip6tnl_vtable,
[NETDEV_KIND_VRF] = &vrf_vtable,
[NETDEV_KIND_VCAN] = &vcan_vtable,
+ [NETDEV_KIND_GENEVE] = &geneve_vtable,
};
static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
@@ -94,6 +96,7 @@ static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
[NETDEV_KIND_IP6TNL] = "ip6tnl",
[NETDEV_KIND_VRF] = "vrf",
[NETDEV_KIND_VCAN] = "vcan",
+ [NETDEV_KIND_GENEVE] = "geneve",
};
DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind);
diff --git a/src/network/netdev/netdev.h b/src/network/netdev/netdev.h
index 37c7431213..a961e2ac3b 100644
--- a/src/network/netdev/netdev.h
+++ b/src/network/netdev/netdev.h
@@ -57,6 +57,7 @@ typedef enum NetDevKind {
NETDEV_KIND_TAP,
NETDEV_KIND_VRF,
NETDEV_KIND_VCAN,
+ NETDEV_KIND_GENEVE,
_NETDEV_KIND_MAX,
_NETDEV_KIND_INVALID = -1
} NetDevKind;