]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/netdev/fou-tunnel.c
strv: replace always-true condition with assertion
[thirdparty/systemd.git] / src / network / netdev / fou-tunnel.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
53cb501a 2
edda10f2 3/* Make sure the net/if.h header is included before any linux/ one */
53cb501a 4#include <net/if.h>
edda10f2 5#include <linux/fou.h>
9aa5d8ba 6#include <netinet/in.h>
53cb501a
SS
7#include <linux/ip.h>
8
9#include "conf-parser.h"
737f1405 10#include "fou-tunnel.h"
7df5c6ba 11#include "ip-protocol-list.h"
881c74bd 12#include "netlink-util.h"
53cb501a
SS
13#include "networkd-manager.h"
14#include "parse-util.h"
53cb501a
SS
15#include "string-table.h"
16#include "string-util.h"
53cb501a
SS
17
18static 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",
21};
22
23DEFINE_STRING_TABLE_LOOKUP(fou_encap_type, FooOverUDPEncapType);
e3bb989b
ZJS
24DEFINE_CONFIG_PARSE_ENUM(config_parse_fou_encap_type, fou_encap_type, FooOverUDPEncapType,
25 "Failed to parse Encapsulation=");
53cb501a 26
2f64865b 27static int netdev_fill_fou_tunnel_message(NetDev *netdev, sd_netlink_message *m) {
117843fe 28 FouTunnel *t = FOU(netdev);
3abf950f 29 uint8_t encap_type;
53cb501a
SS
30 int r;
31
53cb501a
SS
32 r = sd_netlink_message_append_u16(m, FOU_ATTR_PORT, htobe16(t->port));
33 if (r < 0)
2f64865b 34 return r;
53cb501a 35
8f02c9b0
SS
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));
38 if (r < 0)
2f64865b 39 return r;
8f02c9b0
SS
40 }
41
3abf950f
YW
42 switch (t->fou_encap_type) {
43 case NETDEV_FOO_OVER_UDP_ENCAP_DIRECT:
44 encap_type = FOU_ENCAP_DIRECT;
45 break;
46 case NETDEV_FOO_OVER_UDP_ENCAP_GUE:
47 encap_type = FOU_ENCAP_GUE;
48 break;
49 default:
04499a70 50 assert_not_reached();
3abf950f
YW
51 }
52
53 r = sd_netlink_message_append_u8(m, FOU_ATTR_TYPE, encap_type);
53cb501a 54 if (r < 0)
2f64865b 55 return r;
53cb501a
SS
56
57 r = sd_netlink_message_append_u8(m, FOU_ATTR_AF, AF_INET);
58 if (r < 0)
2f64865b 59 return r;
53cb501a
SS
60
61 r = sd_netlink_message_append_u8(m, FOU_ATTR_IPPROTO, t->fou_protocol);
62 if (r < 0)
2f64865b 63 return r;
53cb501a 64
4502a61c
SS
65 if (t->local_family == AF_INET) {
66 r = sd_netlink_message_append_in_addr(m, FOU_ATTR_LOCAL_V4, &t->local.in);
67 if (r < 0)
2f64865b 68 return r;
8f02c9b0 69 } else if (t->local_family == AF_INET6) {
4502a61c
SS
70 r = sd_netlink_message_append_in6_addr(m, FOU_ATTR_LOCAL_V6, &t->local.in6);
71 if (r < 0)
2f64865b 72 return r;
4502a61c
SS
73 }
74
75 if (t->peer_family == AF_INET) {
76 r = sd_netlink_message_append_in_addr(m, FOU_ATTR_PEER_V4, &t->peer.in);
77 if (r < 0)
2f64865b 78 return r;
8f02c9b0 79 } else if (t->peer_family == AF_INET6){
4502a61c
SS
80 r = sd_netlink_message_append_in6_addr(m, FOU_ATTR_PEER_V6, &t->peer.in6);
81 if (r < 0)
2f64865b 82 return r;
4502a61c
SS
83 }
84
2f64865b
ZJS
85 return 0;
86}
87
88static int netdev_create_fou_tunnel_message(NetDev *netdev, sd_netlink_message **ret) {
89 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
90 int r;
91
92 assert(netdev);
93
94 r = sd_genl_message_new(netdev->manager->genl, FOU_GENL_NAME, FOU_CMD_ADD, &m);
95 if (r < 0)
96 return log_netdev_error_errno(netdev, r, "Could not allocate netlink message: %m");
97
98 r = netdev_fill_fou_tunnel_message(netdev, m);
99 if (r < 0)
100 return log_netdev_error_errno(netdev, r, "Could not create netlink message: %m");
101
3abf950f 102 *ret = TAKE_PTR(m);
53cb501a
SS
103 return 0;
104}
105
881c74bd
YW
106static int fou_tunnel_create_handler(sd_netlink *rtnl, sd_netlink_message *m, NetDev *netdev) {
107 int r;
108
109 assert(netdev);
110 assert(netdev->state != _NETDEV_STATE_INVALID);
111
112 r = sd_netlink_message_get_errno(m);
113 if (r == -EEXIST)
114 log_netdev_info(netdev, "netdev exists, using existing without changing its parameters");
115 else if (r < 0) {
116 log_netdev_warning_errno(netdev, r, "netdev could not be created: %m");
8f65304c 117 netdev_enter_failed(netdev);
881c74bd
YW
118
119 return 1;
120 }
121
122 log_netdev_debug(netdev, "FooOverUDP tunnel is created");
123 return 1;
124}
125
53cb501a 126static int netdev_fou_tunnel_create(NetDev *netdev) {
7dd05e94 127 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
53cb501a
SS
128 int r;
129
10c353e1 130 assert(FOU(netdev));
53cb501a 131
2f64865b 132 r = netdev_create_fou_tunnel_message(netdev, &m);
53cb501a
SS
133 if (r < 0)
134 return r;
135
881c74bd
YW
136 r = netlink_call_async(netdev->manager->genl, NULL, m, fou_tunnel_create_handler,
137 netdev_destroy_callback, netdev);
138 if (r < 0)
139 return log_netdev_error_errno(netdev, r, "Failed to create FooOverUDP tunnel: %m");
53cb501a 140
881c74bd 141 netdev_ref(netdev);
53cb501a
SS
142 return 0;
143}
144
7df5c6ba
YW
145int config_parse_ip_protocol(
146 const char *unit,
147 const char *filename,
148 unsigned line,
149 const char *section,
150 unsigned section_line,
151 const char *lvalue,
152 int ltype,
153 const char *rvalue,
154 void *data,
155 void *userdata) {
156
7df5c6ba
YW
157 assert(filename);
158 assert(section);
159 assert(lvalue);
160 assert(rvalue);
7df5c6ba 161
a893c121
ZJS
162 uint8_t *proto = ASSERT_PTR(data);
163 int r;
164
165 r = parse_ip_protocol_full(rvalue, /* relaxed= */ true);
166 if (r < 0) {
167 log_syntax(unit, LOG_WARNING, filename, line, r,
168 "Failed to parse '%s=%s', ignoring: %m",
169 lvalue, rvalue);
7df5c6ba
YW
170 return 0;
171 }
172
a893c121
ZJS
173 if (r > UINT8_MAX) {
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.",
178 lvalue, rvalue);
3d58d732
ZJS
179 return 0;
180 }
181
a893c121 182 *proto = r;
7df5c6ba
YW
183 return 0;
184}
185
4502a61c
SS
186int config_parse_fou_tunnel_address(
187 const char *unit,
188 const char *filename,
189 unsigned line,
190 const char *section,
191 unsigned section_line,
192 const char *lvalue,
193 int ltype,
194 const char *rvalue,
195 void *data,
196 void *userdata) {
197
99534007 198 union in_addr_union *addr = ASSERT_PTR(data);
4502a61c
SS
199 FouTunnel *t = userdata;
200 int r, *f;
201
202 assert(filename);
203 assert(lvalue);
204 assert(rvalue);
4502a61c
SS
205
206 if (streq(lvalue, "Local"))
207 f = &t->local_family;
208 else
209 f = &t->peer_family;
210
211 r = in_addr_from_string_auto(rvalue, f, addr);
212 if (r < 0)
d96edb2c 213 log_syntax(unit, LOG_WARNING, filename, line, r,
fac21663 214 "FooOverUDP tunnel '%s' address is invalid, ignoring assignment: %s",
4502a61c
SS
215 lvalue, rvalue);
216
217 return 0;
218}
219
53cb501a 220static int netdev_fou_tunnel_verify(NetDev *netdev, const char *filename) {
53cb501a
SS
221 assert(filename);
222
117843fe 223 FouTunnel *t = FOU(netdev);
53cb501a 224
3abf950f
YW
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.",
230 filename);
231 break;
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.",
236 filename);
237 break;
238 default:
04499a70 239 assert_not_reached();
53cb501a
SS
240 }
241
8f02c9b0
SS
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.",
245 filename);
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.",
249 filename);
53cb501a
SS
250 return 0;
251}
252
253static void fou_tunnel_init(NetDev *netdev) {
117843fe 254 FouTunnel *t = FOU(netdev);
53cb501a
SS
255
256 t->fou_encap_type = NETDEV_FOO_OVER_UDP_ENCAP_DIRECT;
257}
258
259const NetDevVTable foutnl_vtable = {
260 .object_size = sizeof(FouTunnel),
261 .init = fou_tunnel_init,
130b812f 262 .sections = NETDEV_COMMON_SECTIONS "FooOverUDP\0",
53cb501a
SS
263 .create = netdev_fou_tunnel_create,
264 .create_type = NETDEV_CREATE_INDEPENDENT,
265 .config_verify = netdev_fou_tunnel_verify,
266};