/* SPDX-License-Identifier: LGPL-2.1+ */ #include #include #include #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, };