1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 /* Make sure the net/if.h header is included before any linux/ one */
6 #include <netinet/in.h>
9 #include "conf-parser.h"
10 #include "fou-tunnel.h"
11 #include "ip-protocol-list.h"
12 #include "netlink-util.h"
13 #include "networkd-manager.h"
14 #include "parse-util.h"
15 #include "string-table.h"
16 #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
*m
) {
28 FouTunnel
*t
= FOU(netdev
);
32 r
= sd_netlink_message_append_u16(m
, FOU_ATTR_PORT
, htobe16(t
->port
));
36 if (IN_SET(t
->peer_family
, AF_INET
, AF_INET6
)) {
37 r
= sd_netlink_message_append_u16(m
, FOU_ATTR_PEER_PORT
, htobe16(t
->peer_port
));
42 switch (t
->fou_encap_type
) {
43 case NETDEV_FOO_OVER_UDP_ENCAP_DIRECT
:
44 encap_type
= FOU_ENCAP_DIRECT
;
46 case NETDEV_FOO_OVER_UDP_ENCAP_GUE
:
47 encap_type
= FOU_ENCAP_GUE
;
53 r
= sd_netlink_message_append_u8(m
, FOU_ATTR_TYPE
, encap_type
);
57 r
= sd_netlink_message_append_u8(m
, FOU_ATTR_AF
, AF_INET
);
61 r
= sd_netlink_message_append_u8(m
, FOU_ATTR_IPPROTO
, t
->fou_protocol
);
65 if (t
->local_family
== AF_INET
) {
66 r
= sd_netlink_message_append_in_addr(m
, FOU_ATTR_LOCAL_V4
, &t
->local
.in
);
69 } else if (t
->local_family
== AF_INET6
) {
70 r
= sd_netlink_message_append_in6_addr(m
, FOU_ATTR_LOCAL_V6
, &t
->local
.in6
);
75 if (t
->peer_family
== AF_INET
) {
76 r
= sd_netlink_message_append_in_addr(m
, FOU_ATTR_PEER_V4
, &t
->peer
.in
);
79 } else if (t
->peer_family
== AF_INET6
){
80 r
= sd_netlink_message_append_in6_addr(m
, FOU_ATTR_PEER_V6
, &t
->peer
.in6
);
88 static int netdev_create_fou_tunnel_message(NetDev
*netdev
, sd_netlink_message
**ret
) {
89 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
94 r
= sd_genl_message_new(netdev
->manager
->genl
, FOU_GENL_NAME
, FOU_CMD_ADD
, &m
);
96 return log_netdev_error_errno(netdev
, r
, "Could not allocate netlink message: %m");
98 r
= netdev_fill_fou_tunnel_message(netdev
, m
);
100 return log_netdev_error_errno(netdev
, r
, "Could not create netlink message: %m");
106 static int fou_tunnel_create_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, NetDev
*netdev
) {
110 assert(netdev
->state
!= _NETDEV_STATE_INVALID
);
112 r
= sd_netlink_message_get_errno(m
);
114 log_netdev_info(netdev
, "netdev exists, using existing without changing its parameters");
116 log_netdev_warning_errno(netdev
, r
, "netdev could not be created: %m");
117 netdev_enter_failed(netdev
);
122 log_netdev_debug(netdev
, "FooOverUDP tunnel is created");
126 static int netdev_fou_tunnel_create(NetDev
*netdev
) {
127 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
132 r
= netdev_create_fou_tunnel_message(netdev
, &m
);
136 r
= netlink_call_async(netdev
->manager
->genl
, NULL
, m
, fou_tunnel_create_handler
,
137 netdev_destroy_callback
, netdev
);
139 return log_netdev_error_errno(netdev
, r
, "Failed to create FooOverUDP tunnel: %m");
145 int config_parse_ip_protocol(
147 const char *filename
,
150 unsigned section_line
,
162 uint8_t *proto
= ASSERT_PTR(data
);
165 r
= parse_ip_protocol_full(rvalue
, /* relaxed= */ true);
167 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
168 "Failed to parse '%s=%s', ignoring: %m",
174 /* linux/fou.h defines the netlink field as one byte, so we need to reject
175 * protocols numbers that don't fit in one byte. */
176 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
177 "Invalid '%s=%s', allowed range is 0..255, ignoring.",
186 int config_parse_fou_tunnel_address(
188 const char *filename
,
191 unsigned section_line
,
198 union in_addr_union
*addr
= ASSERT_PTR(data
);
199 FouTunnel
*t
= userdata
;
206 if (streq(lvalue
, "Local"))
207 f
= &t
->local_family
;
211 r
= in_addr_from_string_auto(rvalue
, f
, addr
);
213 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
214 "FooOverUDP tunnel '%s' address is invalid, ignoring assignment: %s",
220 static int netdev_fou_tunnel_verify(NetDev
*netdev
, const char *filename
) {
223 FouTunnel
*t
= FOU(netdev
);
225 switch (t
->fou_encap_type
) {
226 case NETDEV_FOO_OVER_UDP_ENCAP_DIRECT
:
227 if (t
->fou_protocol
<= 0)
228 return log_netdev_error_errno(netdev
, SYNTHETIC_ERRNO(EINVAL
),
229 "FooOverUDP protocol not configured in %s. Rejecting configuration.",
232 case NETDEV_FOO_OVER_UDP_ENCAP_GUE
:
233 if (t
->fou_protocol
> 0)
234 return log_netdev_error_errno(netdev
, SYNTHETIC_ERRNO(EINVAL
),
235 "FooOverUDP GUE can't be set with protocol configured in %s. Rejecting configuration.",
239 assert_not_reached();
242 if (t
->peer_family
== AF_UNSPEC
&& t
->peer_port
> 0)
243 return log_netdev_error_errno(netdev
, SYNTHETIC_ERRNO(EINVAL
),
244 "FooOverUDP peer port is set but peer address not configured in %s. Rejecting configuration.",
246 else if (t
->peer_family
!= AF_UNSPEC
&& t
->peer_port
== 0)
247 return log_netdev_error_errno(netdev
, SYNTHETIC_ERRNO(EINVAL
),
248 "FooOverUDP peer port not set but peer address is configured in %s. Rejecting configuration.",
253 static void fou_tunnel_init(NetDev
*netdev
) {
254 FouTunnel
*t
= FOU(netdev
);
256 t
->fou_encap_type
= NETDEV_FOO_OVER_UDP_ENCAP_DIRECT
;
259 const NetDevVTable foutnl_vtable
= {
260 .object_size
= sizeof(FouTunnel
),
261 .init
= fou_tunnel_init
,
262 .sections
= NETDEV_COMMON_SECTIONS
"FooOverUDP\0",
263 .create
= netdev_fou_tunnel_create
,
264 .create_type
= NETDEV_CREATE_INDEPENDENT
,
265 .config_verify
= netdev_fou_tunnel_verify
,