From 42df06e5752887154cd1e1a12b1d593c2e9b5f64 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Tue, 4 Jun 2013 10:31:22 -0300 Subject: platform, devices: add support for vxlan devices Since vxlan is new-ish, and vxlan IPv6 support in particular has only been in the kernel since 3.11, we include our own copy of the vxlan netlink constants rather than depending on the installed headers. --- include/NetworkManager.h | 1 + introspection/Makefile.am | 1 + introspection/nm-device-vxlan.xml | 122 +++++++++++++ src/Makefile.am | 3 + src/devices/nm-device-vxlan.c | 372 ++++++++++++++++++++++++++++++++++++++ src/devices/nm-device-vxlan.h | 69 +++++++ src/nm-manager.c | 4 + src/platform/nm-fake-platform.c | 7 + src/platform/nm-linux-platform.c | 115 ++++++++++++ src/platform/nm-platform.c | 11 ++ src/platform/nm-platform.h | 24 +++ src/platform/tests/platform.c | 49 +++++ 12 files changed, 778 insertions(+) create mode 100644 introspection/nm-device-vxlan.xml create mode 100644 src/devices/nm-device-vxlan.c create mode 100644 src/devices/nm-device-vxlan.h diff --git a/include/NetworkManager.h b/include/NetworkManager.h index 46747a6529..89b42aeb82 100644 --- a/include/NetworkManager.h +++ b/include/NetworkManager.h @@ -58,6 +58,7 @@ #define NM_DBUS_INTERFACE_DEVICE_VETH NM_DBUS_INTERFACE_DEVICE ".Veth" #define NM_DBUS_INTERFACE_DEVICE_TUN NM_DBUS_INTERFACE_DEVICE ".Tun" #define NM_DBUS_INTERFACE_DEVICE_MACVLAN NM_DBUS_INTERFACE_DEVICE ".Macvlan" +#define NM_DBUS_INTERFACE_DEVICE_VXLAN NM_DBUS_INTERFACE_DEVICE ".Vxlan" #define NM_DBUS_INTERFACE_DEVICE_GRE NM_DBUS_INTERFACE_DEVICE ".Gre" diff --git a/introspection/Makefile.am b/introspection/Makefile.am index 1cbb17e060..0301557917 100644 --- a/introspection/Makefile.am +++ b/introspection/Makefile.am @@ -20,6 +20,7 @@ EXTRA_DIST = \ nm-device-veth.xml \ nm-device-tun.xml \ nm-device-macvlan.xml \ + nm-device-vxlan.xml \ nm-device-gre.xml \ nm-device.xml \ nm-ip4-config.xml \ diff --git a/introspection/nm-device-vxlan.xml b/introspection/nm-device-vxlan.xml new file mode 100644 index 0000000000..053eea4d2d --- /dev/null +++ b/introspection/nm-device-vxlan.xml @@ -0,0 +1,122 @@ + + + + + + + + The object path of the parent device (if the VXLAN is not + purely internal to this host). + + + + + + The VXLAN Network Identifier (VNI). + + + + + + The IP (v4 or v6) multicast group used to communicate with other physical + hosts on this VXLAN. + + + + + + The local IPv4 or IPv6 address to use when sending VXLAN packets to other + physical hosts. + + + + + + The value to use in the IP ToS field for VXLAN packets sent to + other physical hosts. + + + + + + The value to use in the IP TTL field for VXLAN packets sent to + other physical hosts. + + + + + + True if the VXLAN dynamically learns remote IP addresses. + + + + + + The interval at which the kernel purges stale cached addresses + (in kernel jiffies, ie, centiseconds). + + + + + + The maximum number of entries that can be added to the VXLAN's + forwarding table. + + + + + + Destination port for outgoing VXLAN packets. + + + + + + The lowest source port number to use for outgoing VXLAN packets. + + + + + + The highest source port number to use for outgoing VXLAN packets. + + + + + + True if the VXLAN is implementing DOVE ARP proxying for remote + clients. + + + + + + True if the VXLAN is implementing DOVE route short-circuiting + of known remote IP addresses. + + + + + + True if the VXLAN will emit netlink notifications of L2 switch + misses. + + + + + + True if the VXLAN will emit netlink notifications of L3 switch + misses. + + + + + + + A dictionary mapping property names to variant boxed values + + + + + + diff --git a/src/Makefile.am b/src/Makefile.am index fd0bb6964c..121c367a4b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -88,6 +88,8 @@ nm_sources = \ devices/nm-device-veth.h \ devices/nm-device-vlan.c \ devices/nm-device-vlan.h \ + devices/nm-device-vxlan.c \ + devices/nm-device-vxlan.h \ devices/nm-device-wifi.c \ devices/nm-device-wifi.h \ \ @@ -302,6 +304,7 @@ glue_sources = \ nm-device-tun-glue.h \ nm-device-veth-glue.h \ nm-device-vlan-glue.h \ + nm-device-vxlan-glue.h \ nm-device-wifi-glue.h \ nm-dhcp4-config-glue.h \ nm-dhcp6-config-glue.h \ diff --git a/src/devices/nm-device-vxlan.c b/src/devices/nm-device-vxlan.c new file mode 100644 index 0000000000..0be57106e2 --- /dev/null +++ b/src/devices/nm-device-vxlan.c @@ -0,0 +1,372 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright 2013, 2014 Red Hat, Inc. + */ + +#include "config.h" + +#include + +#include "nm-device-vxlan.h" +#include "nm-device-private.h" +#include "nm-dbus-manager.h" +#include "nm-logging.h" +#include "nm-manager.h" +#include "nm-platform.h" +#include "nm-utils.h" + +#include "nm-device-vxlan-glue.h" + +G_DEFINE_TYPE (NMDeviceVxlan, nm_device_vxlan, NM_TYPE_DEVICE_GENERIC) + +#define NM_DEVICE_VXLAN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_VXLAN, NMDeviceVxlanPrivate)) + +typedef struct { + NMPlatformVxlanProperties props; +} NMDeviceVxlanPrivate; + +enum { + PROP_0, + PROP_PARENT, + PROP_ID, + PROP_GROUP, + PROP_LOCAL, + PROP_TOS, + PROP_TTL, + PROP_LEARNING, + PROP_AGEING, + PROP_LIMIT, + PROP_DST_PORT, + PROP_SRC_PORT_MIN, + PROP_SRC_PORT_MAX, + PROP_PROXY, + PROP_RSC, + PROP_L2MISS, + PROP_L3MISS, + + LAST_PROP +}; + +/**************************************************************/ + +static void +update_properties (NMDevice *device) +{ + NMDeviceVxlanPrivate *priv = NM_DEVICE_VXLAN_GET_PRIVATE (device); + GObject *object = G_OBJECT (device); + NMPlatformVxlanProperties props; + + if (!nm_platform_vxlan_get_properties (nm_device_get_ifindex (device), &props)) { + nm_log_warn (LOGD_HW, "(%s): could not read vxlan properties", + nm_device_get_iface (device)); + return; + } + + g_object_freeze_notify (object); + + if (priv->props.parent_ifindex != props.parent_ifindex) + g_object_notify (object, NM_DEVICE_VXLAN_PARENT); + if (priv->props.id != props.id) + g_object_notify (object, NM_DEVICE_VXLAN_ID); + if (priv->props.group != props.group) + g_object_notify (object, NM_DEVICE_VXLAN_GROUP); + if (priv->props.local != props.local) + g_object_notify (object, NM_DEVICE_VXLAN_LOCAL); + if (memcmp (&priv->props.group6, &props.group6, sizeof (props.group6)) != 0) + g_object_notify (object, NM_DEVICE_VXLAN_GROUP); + if (memcmp (&priv->props.local6, &props.local6, sizeof (props.local6)) != 0) + g_object_notify (object, NM_DEVICE_VXLAN_LOCAL); + if (priv->props.tos != props.tos) + g_object_notify (object, NM_DEVICE_VXLAN_TOS); + if (priv->props.ttl != props.ttl) + g_object_notify (object, NM_DEVICE_VXLAN_TTL); + if (priv->props.learning != props.learning) + g_object_notify (object, NM_DEVICE_VXLAN_LEARNING); + if (priv->props.ageing != props.ageing) + g_object_notify (object, NM_DEVICE_VXLAN_AGEING); + if (priv->props.limit != props.limit) + g_object_notify (object, NM_DEVICE_VXLAN_LIMIT); + if (priv->props.dst_port != props.dst_port) + g_object_notify (object, NM_DEVICE_VXLAN_DST_PORT); + if (priv->props.src_port_min != props.src_port_min) + g_object_notify (object, NM_DEVICE_VXLAN_SRC_PORT_MIN); + if (priv->props.src_port_max != props.src_port_max) + g_object_notify (object, NM_DEVICE_VXLAN_SRC_PORT_MAX); + if (priv->props.proxy != props.proxy) + g_object_notify (object, NM_DEVICE_VXLAN_PROXY); + if (priv->props.rsc != props.rsc) + g_object_notify (object, NM_DEVICE_VXLAN_RSC); + if (priv->props.l2miss != props.l2miss) + g_object_notify (object, NM_DEVICE_VXLAN_L2MISS); + if (priv->props.l3miss != props.l3miss) + g_object_notify (object, NM_DEVICE_VXLAN_L3MISS); + + memcpy (&priv->props, &props, sizeof (NMPlatformVxlanProperties)); + + g_object_thaw_notify (object); +} + +static void +link_changed (NMDevice *device, NMPlatformLink *info) +{ + NM_DEVICE_CLASS (nm_device_vxlan_parent_class)->link_changed (device, info); + update_properties (device); +} + +/**************************************************************/ + +NMDevice * +nm_device_vxlan_new (NMPlatformLink *platform_device) +{ + g_return_val_if_fail (platform_device != NULL, NULL); + + return (NMDevice *) g_object_new (NM_TYPE_DEVICE_VXLAN, + NM_DEVICE_PLATFORM_DEVICE, platform_device, + NM_DEVICE_TYPE_DESC, "Vxlan", + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_GENERIC, + NULL); +} + +static void +nm_device_vxlan_init (NMDeviceVxlan *self) +{ +} + +static void +constructed (GObject *object) +{ + update_properties (NM_DEVICE (object)); + + G_OBJECT_CLASS (nm_device_vxlan_parent_class)->constructed (object); +} + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + NMDeviceVxlanPrivate *priv = NM_DEVICE_VXLAN_GET_PRIVATE (object); + NMDevice *parent; + + switch (prop_id) { + case PROP_PARENT: + parent = nm_manager_get_device_by_ifindex (nm_manager_get (), priv->props.parent_ifindex); + g_value_set_boxed (value, parent ? nm_device_get_path (parent) : "/"); + break; + case PROP_ID: + g_value_set_uint (value, priv->props.id); + break; + case PROP_GROUP: + if (priv->props.group) + g_value_set_string (value, nm_utils_inet4_ntop (priv->props.group, NULL)); + else if (!IN6_IS_ADDR_UNSPECIFIED (&priv->props.group6)) + g_value_set_string (value, nm_utils_inet6_ntop (&priv->props.group6, NULL)); + break; + case PROP_LOCAL: + if (priv->props.local) + g_value_set_string (value, nm_utils_inet4_ntop (priv->props.local, NULL)); + else if (!IN6_IS_ADDR_UNSPECIFIED (&priv->props.local6)) + g_value_set_string (value, nm_utils_inet6_ntop (&priv->props.local6, NULL)); + break; + case PROP_TOS: + g_value_set_uchar (value, priv->props.tos); + break; + case PROP_TTL: + g_value_set_uchar (value, priv->props.ttl); + break; + case PROP_LEARNING: + g_value_set_boolean (value, priv->props.learning); + break; + case PROP_AGEING: + g_value_set_uint (value, priv->props.ageing); + break; + case PROP_LIMIT: + g_value_set_uint (value, priv->props.limit); + break; + case PROP_DST_PORT: + g_value_set_uint (value, priv->props.dst_port); + break; + case PROP_SRC_PORT_MIN: + g_value_set_uint (value, priv->props.src_port_min); + break; + case PROP_SRC_PORT_MAX: + g_value_set_uint (value, priv->props.src_port_max); + break; + case PROP_PROXY: + g_value_set_uint (value, priv->props.proxy); + break; + case PROP_RSC: + g_value_set_boolean (value, priv->props.rsc); + break; + case PROP_L2MISS: + g_value_set_boolean (value, priv->props.l2miss); + break; + case PROP_L3MISS: + g_value_set_boolean (value, priv->props.l3miss); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nm_device_vxlan_class_init (NMDeviceVxlanClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); + + g_type_class_add_private (klass, sizeof (NMDeviceVxlanPrivate)); + + object_class->constructed = constructed; + object_class->get_property = get_property; + + device_class->link_changed = link_changed; + + /* properties */ + g_object_class_install_property + (object_class, PROP_PARENT, + g_param_spec_boxed (NM_DEVICE_VXLAN_PARENT, + "Parent", + "Parent device", + DBUS_TYPE_G_OBJECT_PATH, + G_PARAM_READABLE)); + + g_object_class_install_property + (object_class, PROP_ID, + g_param_spec_uint (NM_DEVICE_VXLAN_ID, + "Id", + "Id", + 0, G_MAXUINT32, 0, + G_PARAM_READABLE)); + + g_object_class_install_property + (object_class, PROP_GROUP, + g_param_spec_string (NM_DEVICE_VXLAN_GROUP, + "Group", + "Group", + NULL, + G_PARAM_READABLE)); + + g_object_class_install_property + (object_class, PROP_LOCAL, + g_param_spec_string (NM_DEVICE_VXLAN_LOCAL, + "Local", + "Local", + NULL, + G_PARAM_READABLE)); + + g_object_class_install_property + (object_class, PROP_TOS, + g_param_spec_uchar (NM_DEVICE_VXLAN_TOS, + "ToS", + "ToS", + 0, 255, 0, + G_PARAM_READABLE)); + + g_object_class_install_property + (object_class, PROP_TTL, + g_param_spec_uchar (NM_DEVICE_VXLAN_TTL, + "TTL", + "TTL", + 0, 255, 0, + G_PARAM_READABLE)); + + g_object_class_install_property + (object_class, PROP_LEARNING, + g_param_spec_boolean (NM_DEVICE_VXLAN_LEARNING, + "Learning", + "Learning", + FALSE, + G_PARAM_READABLE)); + + g_object_class_install_property + (object_class, PROP_AGEING, + g_param_spec_uint (NM_DEVICE_VXLAN_AGEING, + "Ageing", + "Ageing", + 0, G_MAXUINT32, 0, + G_PARAM_READABLE)); + + g_object_class_install_property + (object_class, PROP_LIMIT, + g_param_spec_uint (NM_DEVICE_VXLAN_LIMIT, + "Limit", + "Limit", + 0, G_MAXUINT32, 0, + G_PARAM_READABLE)); + + g_object_class_install_property + (object_class, PROP_DST_PORT, + g_param_spec_uint (NM_DEVICE_VXLAN_DST_PORT, + "Destination port", + "Destination port", + 0, 65535, 0, + G_PARAM_READABLE)); + + g_object_class_install_property + (object_class, PROP_SRC_PORT_MIN, + g_param_spec_uint (NM_DEVICE_VXLAN_SRC_PORT_MIN, + "Source port min", + "Minimum source port", + 0, 65535, 0, + G_PARAM_READABLE)); + + g_object_class_install_property + (object_class, PROP_SRC_PORT_MAX, + g_param_spec_uint (NM_DEVICE_VXLAN_SRC_PORT_MAX, + "Source port max", + "Maximum source port", + 0, 65535, 0, + G_PARAM_READABLE)); + + g_object_class_install_property + (object_class, PROP_PROXY, + g_param_spec_boolean (NM_DEVICE_VXLAN_PROXY, + "Proxy", + "Proxy", + FALSE, + G_PARAM_READABLE)); + + g_object_class_install_property + (object_class, PROP_RSC, + g_param_spec_boolean (NM_DEVICE_VXLAN_RSC, + "RSC", + "RSC", + FALSE, + G_PARAM_READABLE)); + + g_object_class_install_property + (object_class, PROP_L2MISS, + g_param_spec_boolean (NM_DEVICE_VXLAN_L2MISS, + "L2miss", + "L2miss", + FALSE, + G_PARAM_READABLE)); + + g_object_class_install_property + (object_class, PROP_L3MISS, + g_param_spec_boolean (NM_DEVICE_VXLAN_L3MISS, + "L3miss", + "L3miss", + FALSE, + G_PARAM_READABLE)); + + nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), + G_TYPE_FROM_CLASS (klass), + &dbus_glib_nm_device_vxlan_object_info); +} diff --git a/src/devices/nm-device-vxlan.h b/src/devices/nm-device-vxlan.h new file mode 100644 index 0000000000..14b158deda --- /dev/null +++ b/src/devices/nm-device-vxlan.h @@ -0,0 +1,69 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright 2013, 2014 Red Hat, Inc. + */ + +#ifndef NM_DEVICE_VXLAN_H +#define NM_DEVICE_VXLAN_H + +#include + +#include "nm-device-generic.h" + +G_BEGIN_DECLS + +#define NM_TYPE_DEVICE_VXLAN (nm_device_vxlan_get_type ()) +#define NM_DEVICE_VXLAN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_VXLAN, NMDeviceVxlan)) +#define NM_DEVICE_VXLAN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_VXLAN, NMDeviceVxlanClass)) +#define NM_IS_DEVICE_VXLAN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_VXLAN)) +#define NM_IS_DEVICE_VXLAN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_VXLAN)) +#define NM_DEVICE_VXLAN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_VXLAN, NMDeviceVxlanClass)) + +#define NM_DEVICE_VXLAN_PARENT "parent" +#define NM_DEVICE_VXLAN_ID "id" +#define NM_DEVICE_VXLAN_GROUP "group" +#define NM_DEVICE_VXLAN_LOCAL "local" +#define NM_DEVICE_VXLAN_TOS "tos" +#define NM_DEVICE_VXLAN_TTL "ttl" +#define NM_DEVICE_VXLAN_LEARNING "learning" +#define NM_DEVICE_VXLAN_AGEING "ageing" +#define NM_DEVICE_VXLAN_LIMIT "limit" +#define NM_DEVICE_VXLAN_DST_PORT "dst-port" +#define NM_DEVICE_VXLAN_SRC_PORT_MIN "src-port-min" +#define NM_DEVICE_VXLAN_SRC_PORT_MAX "src-port-max" +#define NM_DEVICE_VXLAN_PROXY "proxy" +#define NM_DEVICE_VXLAN_RSC "rsc" +#define NM_DEVICE_VXLAN_L2MISS "l2miss" +#define NM_DEVICE_VXLAN_L3MISS "l3miss" + +typedef struct { + NMDeviceGeneric parent; +} NMDeviceVxlan; + +typedef struct { + NMDeviceGenericClass parent; + +} NMDeviceVxlanClass; + +GType nm_device_vxlan_get_type (void); + +NMDevice *nm_device_vxlan_new (NMPlatformLink *platform_device); + +G_END_DECLS + +#endif /* NM_DEVICE_VXLAN_H */ diff --git a/src/nm-manager.c b/src/nm-manager.c index b14a0daf45..26e65d84fe 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -52,6 +52,7 @@ #include "nm-device-veth.h" #include "nm-device-tun.h" #include "nm-device-macvlan.h" +#include "nm-device-vxlan.h" #include "nm-device-gre.h" #include "nm-setting-connection.h" #include "nm-setting-wireless.h" @@ -2155,6 +2156,9 @@ platform_link_added_cb (NMPlatform *platform, case NM_LINK_TYPE_MACVTAP: device = nm_device_macvlan_new (plink); break; + case NM_LINK_TYPE_VXLAN: + device = nm_device_vxlan_new (plink); + break; case NM_LINK_TYPE_GRE: case NM_LINK_TYPE_GRETAP: device = nm_device_gre_new (plink); diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c index cabaa8365d..90d181bb8f 100644 --- a/src/platform/nm-fake-platform.c +++ b/src/platform/nm-fake-platform.c @@ -666,6 +666,12 @@ macvlan_get_properties (NMPlatform *platform, int ifindex, NMPlatformMacvlanProp return FALSE; } +static gboolean +vxlan_get_properties (NMPlatform *platform, int ifindex, NMPlatformVxlanProperties *props) +{ + return FALSE; +} + static gboolean gre_get_properties (NMPlatform *platform, int ifindex, NMPlatformGreProperties *props) { @@ -1219,6 +1225,7 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass) platform_class->veth_get_properties = veth_get_properties; platform_class->tun_get_properties = tun_get_properties; platform_class->macvlan_get_properties = macvlan_get_properties; + platform_class->vxlan_get_properties = vxlan_get_properties; platform_class->gre_get_properties = gre_get_properties; platform_class->ip4_address_get_all = ip4_address_get_all; diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 59f3252bfa..ef519c8415 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -532,6 +532,8 @@ type_to_string (NMLinkType type) return "veth"; case NM_LINK_TYPE_VLAN: return "vlan"; + case NM_LINK_TYPE_VXLAN: + return "vxlan"; case NM_LINK_TYPE_BRIDGE: return "bridge"; case NM_LINK_TYPE_BOND: @@ -608,6 +610,7 @@ link_is_software (struct rtnl_link *rtnllink) !strcmp (type, "tun") || !strcmp (type, "veth") || !strcmp (type, "vlan") || + !strcmp (type, "vxlan") || !strcmp (type, "bridge") || !strcmp (type, "bond") || !strcmp (type, "team")) @@ -718,6 +721,8 @@ link_extract_type (NMPlatform *platform, struct rtnl_link *rtnllink, const char return_type (NM_LINK_TYPE_VETH, "veth"); else if (!strcmp (type, "vlan")) return_type (NM_LINK_TYPE_VLAN, "vlan"); + else if (!strcmp (type, "vxlan")) + return_type (NM_LINK_TYPE_VXLAN, "vxlan"); else if (!strcmp (type, "bridge")) return_type (NM_LINK_TYPE_BRIDGE, "bridge"); else if (!strcmp (type, "bond")) @@ -2362,6 +2367,115 @@ macvlan_get_properties (NMPlatform *platform, int ifindex, NMPlatformMacvlanProp return (err == 0); } +/* The installed kernel headers might not have VXLAN stuff at all, or + * they might have the original properties, but not PORT, GROUP6, or LOCAL6. + * So until we depend on kernel >= 3.11, we just ignore the actual enum + * in if_link.h and define the values ourselves. + */ +#define IFLA_VXLAN_UNSPEC 0 +#define IFLA_VXLAN_ID 1 +#define IFLA_VXLAN_GROUP 2 +#define IFLA_VXLAN_LINK 3 +#define IFLA_VXLAN_LOCAL 4 +#define IFLA_VXLAN_TTL 5 +#define IFLA_VXLAN_TOS 6 +#define IFLA_VXLAN_LEARNING 7 +#define IFLA_VXLAN_AGEING 8 +#define IFLA_VXLAN_LIMIT 9 +#define IFLA_VXLAN_PORT_RANGE 10 +#define IFLA_VXLAN_PROXY 11 +#define IFLA_VXLAN_RSC 12 +#define IFLA_VXLAN_L2MISS 13 +#define IFLA_VXLAN_L3MISS 14 +#define IFLA_VXLAN_PORT 15 +#define IFLA_VXLAN_GROUP6 16 +#define IFLA_VXLAN_LOCAL6 17 +#undef IFLA_VXLAN_MAX +#define IFLA_VXLAN_MAX IFLA_VXLAN_LOCAL6 + +static const struct nla_policy vxlan_info_policy[IFLA_VXLAN_MAX + 1] = { + [IFLA_VXLAN_ID] = { .type = NLA_U32 }, + [IFLA_VXLAN_GROUP] = { .type = NLA_U32 }, + [IFLA_VXLAN_GROUP6] = { .type = NLA_UNSPEC, + .minlen = sizeof (struct in6_addr) }, + [IFLA_VXLAN_LINK] = { .type = NLA_U32 }, + [IFLA_VXLAN_LOCAL] = { .type = NLA_U32 }, + [IFLA_VXLAN_LOCAL6] = { .type = NLA_UNSPEC, + .minlen = sizeof (struct in6_addr) }, + [IFLA_VXLAN_TOS] = { .type = NLA_U8 }, + [IFLA_VXLAN_TTL] = { .type = NLA_U8 }, + [IFLA_VXLAN_LEARNING] = { .type = NLA_U8 }, + [IFLA_VXLAN_AGEING] = { .type = NLA_U32 }, + [IFLA_VXLAN_LIMIT] = { .type = NLA_U32 }, + [IFLA_VXLAN_PORT_RANGE] = { .type = NLA_UNSPEC, + .minlen = sizeof (struct ifla_vxlan_port_range) }, + [IFLA_VXLAN_PROXY] = { .type = NLA_U8 }, + [IFLA_VXLAN_RSC] = { .type = NLA_U8 }, + [IFLA_VXLAN_L2MISS] = { .type = NLA_U8 }, + [IFLA_VXLAN_L3MISS] = { .type = NLA_U8 }, + [IFLA_VXLAN_PORT] = { .type = NLA_U16 }, +}; + +static int +vxlan_info_data_parser (struct nlattr *info_data, gpointer parser_data) +{ + NMPlatformVxlanProperties *props = parser_data; + struct nlattr *tb[IFLA_VXLAN_MAX + 1]; + struct ifla_vxlan_port_range *range; + int err; + + err = nla_parse_nested (tb, IFLA_VXLAN_MAX, info_data, + (struct nla_policy *) vxlan_info_policy); + if (err < 0) + return err; + + memset (props, 0, sizeof (*props)); + + props->parent_ifindex = tb[IFLA_VXLAN_LINK] ? nla_get_u32 (tb[IFLA_VXLAN_LINK]) : 0; + props->id = nla_get_u32 (tb[IFLA_VXLAN_ID]); + if (tb[IFLA_VXLAN_GROUP]) + props->group = nla_get_u32 (tb[IFLA_VXLAN_GROUP]); + if (tb[IFLA_VXLAN_LOCAL]) + props->local = nla_get_u32 (tb[IFLA_VXLAN_LOCAL]); + if (tb[IFLA_VXLAN_GROUP6]) + memcpy (&props->group6, nla_data (tb[IFLA_VXLAN_GROUP6]), sizeof (props->group6)); + if (tb[IFLA_VXLAN_LOCAL6]) + memcpy (&props->local6, nla_data (tb[IFLA_VXLAN_LOCAL6]), sizeof (props->local6)); + + props->ageing = nla_get_u32 (tb[IFLA_VXLAN_AGEING]); + props->limit = nla_get_u32 (tb[IFLA_VXLAN_LIMIT]); + props->tos = nla_get_u8 (tb[IFLA_VXLAN_TOS]); + props->ttl = nla_get_u8 (tb[IFLA_VXLAN_TTL]); + + props->dst_port = nla_get_u16 (tb[IFLA_VXLAN_PORT]); + range = nla_data (tb[IFLA_VXLAN_PORT_RANGE]); + props->src_port_min = range->low; + props->src_port_max = range->high; + + props->learning = !!nla_get_u8 (tb[IFLA_VXLAN_LEARNING]); + props->proxy = !!nla_get_u8 (tb[IFLA_VXLAN_PROXY]); + props->rsc = !!nla_get_u8 (tb[IFLA_VXLAN_RSC]); + props->l2miss = !!nla_get_u8 (tb[IFLA_VXLAN_L2MISS]); + props->l3miss = !!nla_get_u8 (tb[IFLA_VXLAN_L3MISS]); + + return 0; +} + +static gboolean +vxlan_get_properties (NMPlatform *platform, int ifindex, NMPlatformVxlanProperties *props) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + int err; + + err = nm_rtnl_link_parse_info_data (priv->nlh, ifindex, + vxlan_info_data_parser, props); + if (err != 0) { + warning ("(%s) could not read properties: %s", + link_get_name (platform, ifindex), nl_geterror (err)); + } + return (err == 0); +} + static const struct nla_policy gre_info_policy[IFLA_GRE_MAX + 1] = { [IFLA_GRE_LINK] = { .type = NLA_U32 }, [IFLA_GRE_IFLAGS] = { .type = NLA_U16 }, @@ -3185,6 +3299,7 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->veth_get_properties = veth_get_properties; platform_class->tun_get_properties = tun_get_properties; platform_class->macvlan_get_properties = macvlan_get_properties; + platform_class->vxlan_get_properties = vxlan_get_properties; platform_class->gre_get_properties = gre_get_properties; platform_class->ip4_address_get_all = ip4_address_get_all; diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 1b2125ae5c..6f7ec5e545 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -1178,6 +1178,17 @@ nm_platform_macvlan_get_properties (int ifindex, NMPlatformMacvlanProperties *pr return klass->macvlan_get_properties (platform, ifindex, props); } +gboolean +nm_platform_vxlan_get_properties (int ifindex, NMPlatformVxlanProperties *props) +{ + reset_error (); + + g_return_val_if_fail (ifindex > 0, FALSE); + g_return_val_if_fail (props != NULL, FALSE); + + return klass->vxlan_get_properties (platform, ifindex, props); +} + gboolean nm_platform_gre_get_properties (int ifindex, NMPlatformGreProperties *props) { diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 226542c578..1a7a44d319 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -104,6 +104,7 @@ typedef enum { NM_LINK_TYPE_TUN, NM_LINK_TYPE_VETH, NM_LINK_TYPE_VLAN, + NM_LINK_TYPE_VXLAN, /* Software types with slaves */ NM_LINK_TYPE_BRIDGE = 0x10000 | 0x20000, @@ -214,6 +215,27 @@ typedef struct { gboolean no_promisc; } NMPlatformMacvlanProperties; +typedef struct { + int parent_ifindex; + guint32 id; + in_addr_t group; + in_addr_t local; + struct in6_addr group6; + struct in6_addr local6; + guint8 tos; + guint8 ttl; + gboolean learning; + guint32 ageing; + guint32 limit; + guint16 dst_port; + guint16 src_port_min; + guint16 src_port_max; + gboolean proxy; + gboolean rsc; + gboolean l2miss; + gboolean l3miss; +} NMPlatformVxlanProperties; + typedef struct { int parent_ifindex; guint16 input_flags; @@ -317,6 +339,7 @@ typedef struct { gboolean (*veth_get_properties) (NMPlatform *, int ifindex, NMPlatformVethProperties *properties); gboolean (*tun_get_properties) (NMPlatform *, int ifindex, NMPlatformTunProperties *properties); gboolean (*macvlan_get_properties) (NMPlatform *, int ifindex, NMPlatformMacvlanProperties *props); + gboolean (*vxlan_get_properties) (NMPlatform *, int ifindex, NMPlatformVxlanProperties *props); gboolean (*gre_get_properties) (NMPlatform *, int ifindex, NMPlatformGreProperties *props); GArray * (*ip4_address_get_all) (NMPlatform *, int ifindex); @@ -445,6 +468,7 @@ gboolean nm_platform_infiniband_partition_add (int parent, int p_key); gboolean nm_platform_veth_get_properties (int ifindex, NMPlatformVethProperties *properties); gboolean nm_platform_tun_get_properties (int ifindex, NMPlatformTunProperties *properties); gboolean nm_platform_macvlan_get_properties (int ifindex, NMPlatformMacvlanProperties *props); +gboolean nm_platform_vxlan_get_properties (int ifindex, NMPlatformVxlanProperties *props); gboolean nm_platform_gre_get_properties (int ifindex, NMPlatformGreProperties *props); GArray *nm_platform_ip4_address_get_all (int ifindex); diff --git a/src/platform/tests/platform.c b/src/platform/tests/platform.c index 7ca2cb5258..d599096fea 100644 --- a/src/platform/tests/platform.c +++ b/src/platform/tests/platform.c @@ -403,6 +403,53 @@ do_macvlan_get_properties (char **argv) return TRUE; } +static gboolean +do_vxlan_get_properties (char **argv) +{ + int ifindex = parse_ifindex (*argv++); + NMPlatformVxlanProperties props; + char addrstr[INET6_ADDRSTRLEN]; + + if (!nm_platform_vxlan_get_properties (ifindex, &props)) + return FALSE; + + printf ("parent-ifindex: %u\n", props.parent_ifindex); + printf ("id: %u\n", props.id); + if (props.group) + inet_ntop (AF_INET, &props.group, addrstr, sizeof (addrstr)); + else if (props.group6.s6_addr[0]) + inet_ntop (AF_INET6, &props.group6, addrstr, sizeof (addrstr)); + else + strcpy (addrstr, "-"); + printf ("group: %s\n", addrstr); + if (props.local) + inet_ntop (AF_INET, &props.local, addrstr, sizeof (addrstr)); + else if (props.local6.s6_addr[0]) + inet_ntop (AF_INET6, &props.local6, addrstr, sizeof (addrstr)); + else + strcpy (addrstr, "-"); + printf ("local: %s\n", addrstr); + printf ("tos: %u\n", props.tos); + printf ("ttl: %u\n", props.ttl); + printf ("learning: "); + print_boolean (props.learning); + printf ("ageing: %u\n", props.ageing); + printf ("limit: %u\n", props.limit); + printf ("dst-port: %u\n", props.dst_port); + printf ("src-port-min: %u\n", props.src_port_min); + printf ("src-port-max: %u\n", props.src_port_max); + printf ("proxy: "); + print_boolean (props.proxy); + printf ("rsc: "); + print_boolean (props.rsc); + printf ("l2miss: "); + print_boolean (props.l2miss); + printf ("l3miss: "); + print_boolean (props.l3miss); + + return TRUE; +} + static gboolean do_gre_get_properties (char **argv) { @@ -762,6 +809,8 @@ static const command_t commands[] = { "" }, { "macvlan-get-properties", "get macvlan properties", do_macvlan_get_properties, 1, "" }, + { "vxlan-get-properties", "get vxlan properties", do_vxlan_get_properties, 1, + "" }, { "gre-get-properties", "get gre properties", do_gre_get_properties, 1, "" }, { "ip4-address-get-all", "print all IPv4 addresses", do_ip4_address_get_all, 1, "" }, -- cgit v1.2.3