diff options
Diffstat (limited to 'src/network/netdev/fou-tunnel.c')
-rw-r--r-- | src/network/netdev/fou-tunnel.c | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/src/network/netdev/fou-tunnel.c b/src/network/netdev/fou-tunnel.c new file mode 100644 index 0000000..65dad38 --- /dev/null +++ b/src/network/netdev/fou-tunnel.c @@ -0,0 +1,129 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include <arpa/inet.h> +#include <net/if.h> +#include <linux/ip.h> + +#include "conf-parser.h" +#include "missing.h" +#include "netdev/fou-tunnel.h" +#include "networkd-link.h" +#include "networkd-manager.h" +#include "parse-util.h" +#include "sd-netlink.h" +#include "string-table.h" +#include "string-util.h" +#include "util.h" + +static const char* const fou_encap_type_table[_NETDEV_FOO_OVER_UDP_ENCAP_MAX] = { + [NETDEV_FOO_OVER_UDP_ENCAP_DIRECT] = "FooOverUDP", + [NETDEV_FOO_OVER_UDP_ENCAP_GUE] = "GenericUDPEncapsulation", +}; + +DEFINE_STRING_TABLE_LOOKUP(fou_encap_type, FooOverUDPEncapType); +DEFINE_CONFIG_PARSE_ENUM(config_parse_fou_encap_type, fou_encap_type, FooOverUDPEncapType, + "Failed to parse Encapsulation="); + +static int netdev_fill_fou_tunnel_message(NetDev *netdev, sd_netlink_message **ret) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; + FouTunnel *t; + int r; + + assert(netdev); + + t = FOU(netdev); + + assert(t); + + r = sd_genl_message_new(netdev->manager->genl, SD_GENL_FOU, FOU_CMD_ADD, &m); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Failed to allocate generic netlink message: %m"); + + r = sd_netlink_message_append_u16(m, FOU_ATTR_PORT, htobe16(t->port)); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append FOU_ATTR_PORT attribute: %m"); + + r = sd_netlink_message_append_u8(m, FOU_ATTR_TYPE, FOU_ENCAP_GUE); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append FOU_ATTR_TYPE attribute: %m"); + + r = sd_netlink_message_append_u8(m, FOU_ATTR_AF, AF_INET); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append FOU_ATTR_AF attribute: %m"); + + r = sd_netlink_message_append_u8(m, FOU_ATTR_IPPROTO, t->fou_protocol); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append FOU_ATTR_IPPROTO attribute: %m"); + + *ret = m; + m = NULL; + + return 0; +} + +static int netdev_fou_tunnel_create(NetDev *netdev) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; + uint32_t serial; + FouTunnel *t; + int r; + + assert(netdev); + + t = FOU(netdev); + + assert(t); + + r = netdev_fill_fou_tunnel_message(netdev, &m); + if (r < 0) + return r; + + r = sd_netlink_send(netdev->manager->genl, m, &serial); + if (r < 0 && r != -EADDRINUSE) + return log_netdev_error_errno(netdev, r, "Failed to add FooOverUDP tunnel: %m"); + + return 0; +} + +static int netdev_fou_tunnel_verify(NetDev *netdev, const char *filename) { + FouTunnel *t; + + assert(netdev); + assert(filename); + + t = FOU(netdev); + + assert(t); + + if (t->fou_encap_type == NETDEV_FOO_OVER_UDP_ENCAP_DIRECT && t->fou_protocol <= 0) { + log_netdev_error(netdev, "FooOverUDP protocol not configured in %s. Rejecting configuration.", filename); + return -EINVAL; + } + + if (t->fou_encap_type == NETDEV_FOO_OVER_UDP_ENCAP_GUE && t->fou_protocol > 0) { + log_netdev_error(netdev, "FooOverUDP GUE can't be set with protocol configured in %s. Rejecting configuration.", filename); + return -EINVAL; + } + + return 0; +} + +static void fou_tunnel_init(NetDev *netdev) { + FouTunnel *t; + + assert(netdev); + + t = FOU(netdev); + + assert(t); + + t->fou_encap_type = NETDEV_FOO_OVER_UDP_ENCAP_DIRECT; +} + +const NetDevVTable foutnl_vtable = { + .object_size = sizeof(FouTunnel), + .init = fou_tunnel_init, + .sections = "Match\0NetDev\0FooOverUDP\0", + .create = netdev_fou_tunnel_create, + .create_type = NETDEV_CREATE_INDEPENDENT, + .config_verify = netdev_fou_tunnel_verify, +}; |