1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
5 #include <netinet/in.h>
8 #include "conf-parser.h"
9 #include "fou-tunnel.h"
10 #include "ip-protocol-list.h"
11 #include "netlink-util.h"
12 #include "networkd-manager.h"
13 #include "parse-util.h"
14 #include "string-table.h"
15 #include "string-util.h"
18 static const char* const fou_encap_type_table
[_NETDEV_FOO_OVER_UDP_ENCAP_MAX
] = {
19 [NETDEV_FOO_OVER_UDP_ENCAP_DIRECT
] = "FooOverUDP",
20 [NETDEV_FOO_OVER_UDP_ENCAP_GUE
] = "GenericUDPEncapsulation",
23 DEFINE_STRING_TABLE_LOOKUP(fou_encap_type
, FooOverUDPEncapType
);
24 DEFINE_CONFIG_PARSE_ENUM(config_parse_fou_encap_type
, fou_encap_type
, FooOverUDPEncapType
,
25 "Failed to parse Encapsulation=");
27 static int netdev_fill_fou_tunnel_message(NetDev
*netdev
, sd_netlink_message
**ret
) {
28 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
39 r
= sd_genl_message_new(netdev
->manager
->genl
, SD_GENL_FOU
, FOU_CMD_ADD
, &m
);
41 return log_netdev_error_errno(netdev
, r
, "Failed to allocate generic netlink message: %m");
43 r
= sd_netlink_message_append_u16(m
, FOU_ATTR_PORT
, htobe16(t
->port
));
45 return log_netdev_error_errno(netdev
, r
, "Could not append FOU_ATTR_PORT attribute: %m");
47 if (IN_SET(t
->peer_family
, AF_INET
, AF_INET6
)) {
48 r
= sd_netlink_message_append_u16(m
, FOU_ATTR_PEER_PORT
, htobe16(t
->peer_port
));
50 return log_netdev_error_errno(netdev
, r
, "Could not append FOU_ATTR_PEER_PORT attribute: %m");
53 switch (t
->fou_encap_type
) {
54 case NETDEV_FOO_OVER_UDP_ENCAP_DIRECT
:
55 encap_type
= FOU_ENCAP_DIRECT
;
57 case NETDEV_FOO_OVER_UDP_ENCAP_GUE
:
58 encap_type
= FOU_ENCAP_GUE
;
61 assert_not_reached("invalid encap type");
64 r
= sd_netlink_message_append_u8(m
, FOU_ATTR_TYPE
, encap_type
);
66 return log_netdev_error_errno(netdev
, r
, "Could not append FOU_ATTR_TYPE attribute: %m");
68 r
= sd_netlink_message_append_u8(m
, FOU_ATTR_AF
, AF_INET
);
70 return log_netdev_error_errno(netdev
, r
, "Could not append FOU_ATTR_AF attribute: %m");
72 r
= sd_netlink_message_append_u8(m
, FOU_ATTR_IPPROTO
, t
->fou_protocol
);
74 return log_netdev_error_errno(netdev
, r
, "Could not append FOU_ATTR_IPPROTO attribute: %m");
76 if (t
->local_family
== AF_INET
) {
77 r
= sd_netlink_message_append_in_addr(m
, FOU_ATTR_LOCAL_V4
, &t
->local
.in
);
79 return log_netdev_error_errno(netdev
, r
, "Could not append FOU_ATTR_LOCAL_V4 attribute: %m");
80 } else if (t
->local_family
== AF_INET6
) {
81 r
= sd_netlink_message_append_in6_addr(m
, FOU_ATTR_LOCAL_V6
, &t
->local
.in6
);
83 return log_netdev_error_errno(netdev
, r
, "Could not append FOU_ATTR_LOCAL_V6 attribute: %m");
86 if (t
->peer_family
== AF_INET
) {
87 r
= sd_netlink_message_append_in_addr(m
, FOU_ATTR_PEER_V4
, &t
->peer
.in
);
89 return log_netdev_error_errno(netdev
, r
, "Could not append FOU_ATTR_PEER_V4 attribute: %m");
90 } else if (t
->peer_family
== AF_INET6
){
91 r
= sd_netlink_message_append_in6_addr(m
, FOU_ATTR_PEER_V6
, &t
->peer
.in6
);
93 return log_netdev_error_errno(netdev
, r
, "Could not append FOU_ATTR_PEER_V6 attribute: %m");
100 static int fou_tunnel_create_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, NetDev
*netdev
) {
104 assert(netdev
->state
!= _NETDEV_STATE_INVALID
);
106 r
= sd_netlink_message_get_errno(m
);
108 log_netdev_info(netdev
, "netdev exists, using existing without changing its parameters");
110 log_netdev_warning_errno(netdev
, r
, "netdev could not be created: %m");
116 log_netdev_debug(netdev
, "FooOverUDP tunnel is created");
120 static int netdev_fou_tunnel_create(NetDev
*netdev
) {
121 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
127 r
= netdev_fill_fou_tunnel_message(netdev
, &m
);
131 r
= netlink_call_async(netdev
->manager
->genl
, NULL
, m
, fou_tunnel_create_handler
,
132 netdev_destroy_callback
, netdev
);
134 return log_netdev_error_errno(netdev
, r
, "Failed to create FooOverUDP tunnel: %m");
140 int config_parse_ip_protocol(
142 const char *filename
,
145 unsigned section_line
,
154 /* linux/fou.h defines the netlink field as one byte, so we need to reject protocols numbers that
155 * don't fit in one byte. */
164 r
= parse_ip_protocol(rvalue
);
168 r
= safe_atou(rvalue
, &protocol
);
170 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
171 "Failed to parse IP protocol '%s' for FooOverUDP tunnel, "
172 "ignoring assignment: %m", rvalue
);
176 if (protocol
> UINT8_MAX
) {
177 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
178 "IP protocol '%s' for FooOverUDP tunnel out of range, "
179 "ignoring assignment: %m", rvalue
);
187 int config_parse_fou_tunnel_address(
189 const char *filename
,
192 unsigned section_line
,
199 union in_addr_union
*addr
= data
;
200 FouTunnel
*t
= userdata
;
208 if (streq(lvalue
, "Local"))
209 f
= &t
->local_family
;
213 r
= in_addr_from_string_auto(rvalue
, f
, addr
);
215 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
216 "FooOverUDP tunnel '%s' address is invalid, ignoring assignment: %s",
222 static int netdev_fou_tunnel_verify(NetDev
*netdev
, const char *filename
) {
232 switch (t
->fou_encap_type
) {
233 case NETDEV_FOO_OVER_UDP_ENCAP_DIRECT
:
234 if (t
->fou_protocol
<= 0)
235 return log_netdev_error_errno(netdev
, SYNTHETIC_ERRNO(EINVAL
),
236 "FooOverUDP protocol not configured in %s. Rejecting configuration.",
239 case NETDEV_FOO_OVER_UDP_ENCAP_GUE
:
240 if (t
->fou_protocol
> 0)
241 return log_netdev_error_errno(netdev
, SYNTHETIC_ERRNO(EINVAL
),
242 "FooOverUDP GUE can't be set with protocol configured in %s. Rejecting configuration.",
246 assert_not_reached("Invalid fou encap type");
249 if (t
->peer_family
== AF_UNSPEC
&& t
->peer_port
> 0)
250 return log_netdev_error_errno(netdev
, SYNTHETIC_ERRNO(EINVAL
),
251 "FooOverUDP peer port is set but peer address not configured in %s. Rejecting configuration.",
253 else if (t
->peer_family
!= AF_UNSPEC
&& t
->peer_port
== 0)
254 return log_netdev_error_errno(netdev
, SYNTHETIC_ERRNO(EINVAL
),
255 "FooOverUDP peer port not set but peer address is configured in %s. Rejecting configuration.",
260 static void fou_tunnel_init(NetDev
*netdev
) {
269 t
->fou_encap_type
= NETDEV_FOO_OVER_UDP_ENCAP_DIRECT
;
272 const NetDevVTable foutnl_vtable
= {
273 .object_size
= sizeof(FouTunnel
),
274 .init
= fou_tunnel_init
,
275 .sections
= NETDEV_COMMON_SECTIONS
"FooOverUDP\0",
276 .create
= netdev_fou_tunnel_create
,
277 .create_type
= NETDEV_CREATE_INDEPENDENT
,
278 .config_verify
= netdev_fou_tunnel_verify
,