]>
Commit | Line | Data |
---|---|---|
53e1b683 | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
7951dea2 | 2 | |
9aa5d8ba | 3 | #include <netinet/in.h> |
01234e1f | 4 | #include <linux/fou.h> |
7951dea2 SS |
5 | #include <linux/ip.h> |
6 | #include <linux/if_tunnel.h> | |
855ee1a1 | 7 | #include <linux/ip6_tunnel.h> |
7951dea2 | 8 | |
80df8f25 YW |
9 | #include "sd-netlink.h" |
10 | ||
07630cea LP |
11 | #include "conf-parser.h" |
12 | #include "missing.h" | |
3affe303 | 13 | #include "netlink-util.h" |
0b1831c2 | 14 | #include "networkd-link.h" |
441e9ae4 | 15 | #include "netdev/tunnel.h" |
6bedfcbb | 16 | #include "parse-util.h" |
8b43440b | 17 | #include "string-table.h" |
07630cea | 18 | #include "string-util.h" |
7951dea2 SS |
19 | #include "util.h" |
20 | ||
855ee1a1 | 21 | #define DEFAULT_TNL_HOP_LIMIT 64 |
8e38570e | 22 | #define IP6_FLOWINFO_FLOWLABEL htobe32(0x000FFFFF) |
3a4f3e42 | 23 | #define IP6_TNL_F_ALLOW_LOCAL_REMOTE 0x40 |
855ee1a1 SS |
24 | |
25 | static const char* const ip6tnl_mode_table[_NETDEV_IP6_TNL_MODE_MAX] = { | |
26 | [NETDEV_IP6_TNL_MODE_IP6IP6] = "ip6ip6", | |
73b23bea | 27 | [NETDEV_IP6_TNL_MODE_IPIP6] = "ipip6", |
855ee1a1 SS |
28 | [NETDEV_IP6_TNL_MODE_ANYIP6] = "any", |
29 | }; | |
30 | ||
31 | DEFINE_STRING_TABLE_LOOKUP(ip6tnl_mode, Ip6TnlMode); | |
32 | DEFINE_CONFIG_PARSE_ENUM(config_parse_ip6tnl_mode, ip6tnl_mode, Ip6TnlMode, "Failed to parse ip6 tunnel Mode"); | |
33 | ||
9e64c1f8 YW |
34 | static int netdev_ipip_sit_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) { |
35 | Tunnel *t; | |
7951dea2 SS |
36 | int r; |
37 | ||
3be1d7e0 | 38 | assert(netdev); |
9e64c1f8 YW |
39 | |
40 | if (netdev->kind == NETDEV_KIND_IPIP) | |
41 | t = IPIP(netdev); | |
42 | else | |
43 | t = SIT(netdev); | |
44 | ||
7951dea2 | 45 | assert(m); |
aa9f1140 | 46 | assert(t); |
b7c2bb4c | 47 | assert(t->family == AF_INET); |
7951dea2 | 48 | |
4d7fa6de SS |
49 | if (link) { |
50 | r = sd_netlink_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex); | |
51 | if (r < 0) | |
52 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m"); | |
4d7fa6de | 53 | } |
7951dea2 | 54 | |
1c4baffc | 55 | r = sd_netlink_message_append_in_addr(m, IFLA_IPTUN_LOCAL, &t->local.in); |
5289f3ff SS |
56 | if (r < 0) |
57 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LOCAL attribute: %m"); | |
7951dea2 | 58 | |
1c4baffc | 59 | r = sd_netlink_message_append_in_addr(m, IFLA_IPTUN_REMOTE, &t->remote.in); |
5289f3ff SS |
60 | if (r < 0) |
61 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_REMOTE attribute: %m"); | |
7951dea2 | 62 | |
1c4baffc | 63 | r = sd_netlink_message_append_u8(m, IFLA_IPTUN_TTL, t->ttl); |
5289f3ff | 64 | if (r < 0) |
9e64c1f8 | 65 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_TTL attribute: %m"); |
9ae70211 | 66 | |
1c4baffc | 67 | r = sd_netlink_message_append_u8(m, IFLA_IPTUN_PMTUDISC, t->pmtudisc); |
5289f3ff SS |
68 | if (r < 0) |
69 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_PMTUDISC attribute: %m"); | |
9243e967 | 70 | |
4799d932 | 71 | if (t->fou_tunnel) { |
53cb501a SS |
72 | r = sd_netlink_message_append_u16(m, IFLA_IPTUN_ENCAP_TYPE, t->fou_encap_type); |
73 | if (r < 0) | |
74 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_ENCAP_TYPE attribute: %m"); | |
75 | ||
76 | r = sd_netlink_message_append_u16(m, IFLA_IPTUN_ENCAP_SPORT, htobe16(t->encap_src_port)); | |
77 | if (r < 0) | |
78 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_ENCAP_SPORT attribute: %m"); | |
79 | ||
80 | r = sd_netlink_message_append_u16(m, IFLA_IPTUN_ENCAP_DPORT, htobe16(t->fou_destination_port)); | |
81 | if (r < 0) | |
82 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_ENCAP_DPORT attribute: %m"); | |
83 | } | |
84 | ||
9e64c1f8 YW |
85 | if (netdev->kind == NETDEV_KIND_SIT) { |
86 | if (t->sixrd_prefixlen > 0) { | |
87 | r = sd_netlink_message_append_in6_addr(m, IFLA_IPTUN_6RD_PREFIX, &t->sixrd_prefix); | |
88 | if (r < 0) | |
89 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_6RD_PREFIX attribute: %m"); | |
90 | ||
91 | /* u16 is deliberate here, even though we're passing a netmask that can never be >128. The kernel is | |
92 | * expecting to receive the prefixlen as a u16. | |
93 | */ | |
94 | r = sd_netlink_message_append_u16(m, IFLA_IPTUN_6RD_PREFIXLEN, t->sixrd_prefixlen); | |
95 | if (r < 0) | |
96 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_6RD_PREFIXLEN attribute: %m"); | |
97 | } | |
d067cab3 | 98 | |
9e64c1f8 YW |
99 | if (t->isatap >= 0) { |
100 | uint16_t flags = 0; | |
918049ad | 101 | |
9e64c1f8 | 102 | SET_FLAG(flags, SIT_ISATAP, t->isatap); |
918049ad | 103 | |
9e64c1f8 YW |
104 | r = sd_netlink_message_append_u16(m, IFLA_IPTUN_FLAGS, flags); |
105 | if (r < 0) | |
106 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_FLAGS attribute: %m"); | |
107 | } | |
918049ad SS |
108 | } |
109 | ||
abf446af SS |
110 | return r; |
111 | } | |
112 | ||
a8b9a65c YW |
113 | static int netdev_gre_erspan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) { |
114 | uint32_t ikey = 0; | |
115 | uint32_t okey = 0; | |
116 | uint16_t iflags = 0; | |
117 | uint16_t oflags = 0; | |
1af2536a | 118 | Tunnel *t; |
8bb088c5 SS |
119 | int r; |
120 | ||
3be1d7e0 | 121 | assert(netdev); |
a8b9a65c | 122 | assert(m); |
1af2536a | 123 | |
a8b9a65c YW |
124 | switch (netdev->kind) { |
125 | case NETDEV_KIND_GRE: | |
5289f3ff | 126 | t = GRE(netdev); |
a8b9a65c YW |
127 | break; |
128 | case NETDEV_KIND_ERSPAN: | |
129 | t = ERSPAN(netdev); | |
130 | break; | |
131 | case NETDEV_KIND_GRETAP: | |
5289f3ff | 132 | t = GRETAP(netdev); |
a8b9a65c YW |
133 | break; |
134 | default: | |
135 | assert_not_reached("invalid netdev kind"); | |
136 | } | |
1af2536a | 137 | |
aa9f1140 | 138 | assert(t); |
b7c2bb4c | 139 | assert(t->family == AF_INET); |
8bb088c5 | 140 | |
4d7fa6de SS |
141 | if (link) { |
142 | r = sd_netlink_message_append_u32(m, IFLA_GRE_LINK, link->ifindex); | |
143 | if (r < 0) | |
144 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_LINK attribute: %m"); | |
145 | } | |
8bb088c5 | 146 | |
a8b9a65c YW |
147 | if (netdev->kind == NETDEV_KIND_ERSPAN) { |
148 | r = sd_netlink_message_append_u32(m, IFLA_GRE_ERSPAN_INDEX, t->erspan_index); | |
149 | if (r < 0) | |
150 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_ERSPAN_INDEX attribute: %m"); | |
151 | } | |
152 | ||
1c4baffc | 153 | r = sd_netlink_message_append_in_addr(m, IFLA_GRE_LOCAL, &t->local.in); |
5289f3ff SS |
154 | if (r < 0) |
155 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_LOCAL attribute: %m"); | |
8bb088c5 | 156 | |
1c4baffc | 157 | r = sd_netlink_message_append_in_addr(m, IFLA_GRE_REMOTE, &t->remote.in); |
5289f3ff | 158 | if (r < 0) |
1a9bc3d8 | 159 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_REMOTE attribute: %m"); |
8bb088c5 | 160 | |
1c4baffc | 161 | r = sd_netlink_message_append_u8(m, IFLA_GRE_TTL, t->ttl); |
5289f3ff SS |
162 | if (r < 0) |
163 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_TTL attribute: %m"); | |
8bb088c5 | 164 | |
1c4baffc | 165 | r = sd_netlink_message_append_u8(m, IFLA_GRE_TOS, t->tos); |
5289f3ff | 166 | if (r < 0) |
1a9bc3d8 | 167 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_TOS attribute: %m"); |
8bb088c5 | 168 | |
1c4baffc | 169 | r = sd_netlink_message_append_u8(m, IFLA_GRE_PMTUDISC, t->pmtudisc); |
5289f3ff SS |
170 | if (r < 0) |
171 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_PMTUDISC attribute: %m"); | |
9243e967 | 172 | |
2266864b SS |
173 | if (t->key != 0) { |
174 | ikey = okey = htobe32(t->key); | |
175 | iflags |= GRE_KEY; | |
176 | oflags |= GRE_KEY; | |
177 | } | |
178 | ||
179 | if (t->ikey != 0) { | |
180 | ikey = htobe32(t->ikey); | |
181 | iflags |= GRE_KEY; | |
182 | } | |
183 | ||
184 | if (t->okey != 0) { | |
185 | okey = htobe32(t->okey); | |
186 | oflags |= GRE_KEY; | |
187 | } | |
188 | ||
a8b9a65c | 189 | if (t->gre_erspan_sequence > 0) { |
2266864b SS |
190 | iflags |= GRE_SEQ; |
191 | oflags |= GRE_SEQ; | |
a8b9a65c | 192 | } else if (t->gre_erspan_sequence == 0) { |
2266864b SS |
193 | iflags &= ~GRE_SEQ; |
194 | oflags &= ~GRE_SEQ; | |
195 | } | |
196 | ||
197 | r = sd_netlink_message_append_u32(m, IFLA_GRE_IKEY, ikey); | |
198 | if (r < 0) | |
199 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_IKEY attribute: %m"); | |
200 | ||
201 | r = sd_netlink_message_append_u32(m, IFLA_GRE_OKEY, okey); | |
202 | if (r < 0) | |
203 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_OKEY attribute: %m"); | |
204 | ||
205 | r = sd_netlink_message_append_u16(m, IFLA_GRE_IFLAGS, iflags); | |
206 | if (r < 0) | |
207 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_IFLAGS attribute: %m"); | |
208 | ||
209 | r = sd_netlink_message_append_u16(m, IFLA_GRE_OFLAGS, oflags); | |
210 | if (r < 0) | |
211 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_OFLAGS, attribute: %m"); | |
212 | ||
4799d932 YW |
213 | if (t->fou_tunnel) { |
214 | r = sd_netlink_message_append_u16(m, IFLA_GRE_ENCAP_TYPE, t->fou_encap_type); | |
215 | if (r < 0) | |
216 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_ENCAP_TYPE attribute: %m"); | |
217 | ||
218 | r = sd_netlink_message_append_u16(m, IFLA_GRE_ENCAP_SPORT, htobe16(t->encap_src_port)); | |
219 | if (r < 0) | |
220 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_ENCAP_SPORT attribute: %m"); | |
221 | ||
222 | r = sd_netlink_message_append_u16(m, IFLA_GRE_ENCAP_DPORT, htobe16(t->fou_destination_port)); | |
223 | if (r < 0) | |
224 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_ENCAP_DPORT attribute: %m"); | |
225 | } | |
226 | ||
2266864b SS |
227 | return r; |
228 | } | |
229 | ||
1c4baffc | 230 | static int netdev_ip6gre_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) { |
b16492f8 SS |
231 | Tunnel *t; |
232 | int r; | |
233 | ||
234 | assert(netdev); | |
235 | ||
236 | if (netdev->kind == NETDEV_KIND_IP6GRE) | |
5289f3ff | 237 | t = IP6GRE(netdev); |
b16492f8 | 238 | else |
5289f3ff | 239 | t = IP6GRETAP(netdev); |
b16492f8 SS |
240 | |
241 | assert(t); | |
242 | assert(t->family == AF_INET6); | |
b16492f8 SS |
243 | assert(m); |
244 | ||
4d7fa6de SS |
245 | if (link) { |
246 | r = sd_netlink_message_append_u32(m, IFLA_GRE_LINK, link->ifindex); | |
247 | if (r < 0) | |
248 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_LINK attribute: %m"); | |
249 | } | |
b16492f8 | 250 | |
1c4baffc | 251 | r = sd_netlink_message_append_in6_addr(m, IFLA_GRE_LOCAL, &t->local.in6); |
5289f3ff SS |
252 | if (r < 0) |
253 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_LOCAL attribute: %m"); | |
b16492f8 | 254 | |
1c4baffc | 255 | r = sd_netlink_message_append_in6_addr(m, IFLA_GRE_REMOTE, &t->remote.in6); |
5289f3ff SS |
256 | if (r < 0) |
257 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_REMOTE attribute: %m"); | |
b16492f8 | 258 | |
1c4baffc | 259 | r = sd_netlink_message_append_u8(m, IFLA_GRE_TTL, t->ttl); |
5289f3ff SS |
260 | if (r < 0) |
261 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_TTL attribute: %m"); | |
b16492f8 | 262 | |
54a9d20c SS |
263 | if (t->ipv6_flowlabel != _NETDEV_IPV6_FLOWLABEL_INVALID) { |
264 | r = sd_netlink_message_append_u32(m, IFLA_GRE_FLOWINFO, t->ipv6_flowlabel); | |
265 | if (r < 0) | |
266 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_FLOWINFO attribute: %m"); | |
267 | } | |
268 | ||
269 | r = sd_netlink_message_append_u32(m, IFLA_GRE_FLAGS, t->flags); | |
270 | if (r < 0) | |
271 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_FLAGS attribute: %m"); | |
272 | ||
b16492f8 SS |
273 | return r; |
274 | } | |
275 | ||
3affe303 | 276 | static int netdev_vti_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) { |
1d710029 | 277 | uint32_t ikey, okey; |
59f62519 | 278 | Tunnel *t; |
1d710029 SS |
279 | int r; |
280 | ||
3affe303 | 281 | assert(netdev); |
1d710029 | 282 | assert(m); |
59f62519 SS |
283 | |
284 | if (netdev->kind == NETDEV_KIND_VTI) | |
285 | t = VTI(netdev); | |
286 | else | |
287 | t = VTI6(netdev); | |
288 | ||
1d710029 | 289 | assert(t); |
3affe303 YW |
290 | assert((netdev->kind == NETDEV_KIND_VTI && t->family == AF_INET) || |
291 | (netdev->kind == NETDEV_KIND_VTI6 && t->family == AF_INET6)); | |
292 | ||
293 | if (link) { | |
294 | r = sd_netlink_message_append_u32(m, IFLA_VTI_LINK, link->ifindex); | |
295 | if (r < 0) | |
296 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_VTI_LINK attribute: %m"); | |
297 | } | |
1d710029 SS |
298 | |
299 | if (t->key != 0) | |
300 | ikey = okey = htobe32(t->key); | |
301 | else { | |
302 | ikey = htobe32(t->ikey); | |
303 | okey = htobe32(t->okey); | |
304 | } | |
305 | ||
306 | r = sd_netlink_message_append_u32(m, IFLA_VTI_IKEY, ikey); | |
307 | if (r < 0) | |
308 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_VTI_IKEY attribute: %m"); | |
309 | ||
310 | r = sd_netlink_message_append_u32(m, IFLA_VTI_OKEY, okey); | |
311 | if (r < 0) | |
312 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_VTI_OKEY attribute: %m"); | |
313 | ||
3affe303 | 314 | r = netlink_message_append_in_addr_union(m, IFLA_VTI_LOCAL, t->family, &t->local); |
9011ce77 | 315 | if (r < 0) |
3affe303 | 316 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_VTI_LOCAL attribute: %m"); |
9011ce77 | 317 | |
3affe303 | 318 | r = netlink_message_append_in_addr_union(m, IFLA_VTI_REMOTE, t->family, &t->remote); |
9011ce77 | 319 | if (r < 0) |
3affe303 | 320 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_VTI_REMOTE attribute: %m"); |
9011ce77 SS |
321 | |
322 | return r; | |
323 | } | |
324 | ||
1c4baffc | 325 | static int netdev_ip6tnl_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) { |
855ee1a1 SS |
326 | Tunnel *t = IP6TNL(netdev); |
327 | uint8_t proto; | |
328 | int r; | |
329 | ||
330 | assert(netdev); | |
855ee1a1 SS |
331 | assert(m); |
332 | assert(t); | |
333 | assert(t->family == AF_INET6); | |
334 | ||
4d7fa6de SS |
335 | if (link) { |
336 | r = sd_netlink_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex); | |
337 | if (r < 0) | |
338 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m"); | |
339 | } | |
855ee1a1 | 340 | |
1c4baffc | 341 | r = sd_netlink_message_append_in6_addr(m, IFLA_IPTUN_LOCAL, &t->local.in6); |
5289f3ff SS |
342 | if (r < 0) |
343 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LOCAL attribute: %m"); | |
855ee1a1 | 344 | |
1c4baffc | 345 | r = sd_netlink_message_append_in6_addr(m, IFLA_IPTUN_REMOTE, &t->remote.in6); |
5289f3ff SS |
346 | if (r < 0) |
347 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_REMOTE attribute: %m"); | |
855ee1a1 | 348 | |
1c4baffc | 349 | r = sd_netlink_message_append_u8(m, IFLA_IPTUN_TTL, t->ttl); |
5289f3ff SS |
350 | if (r < 0) |
351 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_TTL attribute: %m"); | |
855ee1a1 | 352 | |
407af9dd SS |
353 | if (t->ipv6_flowlabel != _NETDEV_IPV6_FLOWLABEL_INVALID) { |
354 | r = sd_netlink_message_append_u32(m, IFLA_IPTUN_FLOWINFO, t->ipv6_flowlabel); | |
355 | if (r < 0) | |
356 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_FLOWINFO attribute: %m"); | |
357 | } | |
358 | ||
a9b70f9d | 359 | if (t->copy_dscp) |
ec2a3e3a SS |
360 | t->flags |= IP6_TNL_F_RCV_DSCP_COPY; |
361 | ||
3f7cc080 | 362 | if (t->allow_localremote >= 0) |
3a4f3e42 SS |
363 | SET_FLAG(t->flags, IP6_TNL_F_ALLOW_LOCAL_REMOTE, t->allow_localremote); |
364 | ||
b4828886 SS |
365 | if (t->encap_limit != IPV6_DEFAULT_TNL_ENCAP_LIMIT) { |
366 | r = sd_netlink_message_append_u8(m, IFLA_IPTUN_ENCAP_LIMIT, t->encap_limit); | |
367 | if (r < 0) | |
368 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_ENCAP_LIMIT attribute: %m"); | |
369 | } | |
370 | ||
407af9dd SS |
371 | r = sd_netlink_message_append_u32(m, IFLA_IPTUN_FLAGS, t->flags); |
372 | if (r < 0) | |
373 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_FLAGS attribute: %m"); | |
374 | ||
855ee1a1 SS |
375 | switch (t->ip6tnl_mode) { |
376 | case NETDEV_IP6_TNL_MODE_IP6IP6: | |
377 | proto = IPPROTO_IPV6; | |
378 | break; | |
379 | case NETDEV_IP6_TNL_MODE_IPIP6: | |
380 | proto = IPPROTO_IPIP; | |
381 | break; | |
382 | case NETDEV_IP6_TNL_MODE_ANYIP6: | |
383 | default: | |
384 | proto = 0; | |
385 | break; | |
386 | } | |
387 | ||
1c4baffc | 388 | r = sd_netlink_message_append_u8(m, IFLA_IPTUN_PROTO, proto); |
5289f3ff | 389 | if (r < 0) |
46242892 | 390 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_PROTO attribute: %m"); |
855ee1a1 SS |
391 | |
392 | return r; | |
393 | } | |
394 | ||
3be1d7e0 | 395 | static int netdev_tunnel_verify(NetDev *netdev, const char *filename) { |
aa9f1140 TG |
396 | Tunnel *t = NULL; |
397 | ||
7951dea2 | 398 | assert(netdev); |
3be1d7e0 | 399 | assert(filename); |
7951dea2 | 400 | |
aa9f1140 TG |
401 | switch (netdev->kind) { |
402 | case NETDEV_KIND_IPIP: | |
403 | t = IPIP(netdev); | |
404 | break; | |
405 | case NETDEV_KIND_SIT: | |
406 | t = SIT(netdev); | |
407 | break; | |
408 | case NETDEV_KIND_GRE: | |
409 | t = GRE(netdev); | |
410 | break; | |
1af2536a SS |
411 | case NETDEV_KIND_GRETAP: |
412 | t = GRETAP(netdev); | |
413 | break; | |
b16492f8 SS |
414 | case NETDEV_KIND_IP6GRE: |
415 | t = IP6GRE(netdev); | |
416 | break; | |
417 | case NETDEV_KIND_IP6GRETAP: | |
418 | t = IP6GRETAP(netdev); | |
419 | break; | |
aa9f1140 TG |
420 | case NETDEV_KIND_VTI: |
421 | t = VTI(netdev); | |
422 | break; | |
9011ce77 SS |
423 | case NETDEV_KIND_VTI6: |
424 | t = VTI6(netdev); | |
425 | break; | |
855ee1a1 SS |
426 | case NETDEV_KIND_IP6TNL: |
427 | t = IP6TNL(netdev); | |
428 | break; | |
2266864b SS |
429 | case NETDEV_KIND_ERSPAN: |
430 | t = ERSPAN(netdev); | |
431 | break; | |
aa9f1140 TG |
432 | default: |
433 | assert_not_reached("Invalid tunnel kind"); | |
434 | } | |
435 | ||
436 | assert(t); | |
437 | ||
bb9683e0 YW |
438 | if (IN_SET(netdev->kind, NETDEV_KIND_VTI, NETDEV_KIND_IPIP, NETDEV_KIND_SIT, NETDEV_KIND_GRE, NETDEV_KIND_GRETAP) && |
439 | t->family != AF_INET) | |
bd930cbd | 440 | return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL), |
bb9683e0 YW |
441 | "vti/ipip/sit/gre tunnel without a local/remote IPv4 address configured in %s. Ignoring", filename); |
442 | ||
443 | if (IN_SET(netdev->kind, NETDEV_KIND_GRETAP, NETDEV_KIND_ERSPAN) && | |
444 | (t->family != AF_INET || in_addr_is_null(t->family, &t->remote))) | |
445 | return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL), | |
446 | "gretap/erspan tunnel without a remote IPv4 address configured in %s. Ignoring", filename); | |
6f3d4dec | 447 | |
30dce346 | 448 | if (IN_SET(netdev->kind, NETDEV_KIND_VTI6, NETDEV_KIND_IP6TNL, NETDEV_KIND_IP6GRE, NETDEV_KIND_IP6GRETAP) && |
bb9683e0 YW |
449 | t->family != AF_INET6) |
450 | return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL), | |
451 | "vti6/ip6tnl/ip6gre tunnel without a local/remote IPv6 address configured in %s. Ignoring", filename); | |
452 | ||
453 | if (netdev->kind == NETDEV_KIND_IP6GRETAP && | |
454 | (t->family != AF_INET6 || in_addr_is_null(t->family, &t->remote))) | |
bd930cbd | 455 | return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL), |
bb9683e0 | 456 | "ip6gretap tunnel without a remote IPv6 address configured in %s. Ignoring", filename); |
6f3d4dec | 457 | |
40a922d0 | 458 | if (netdev->kind == NETDEV_KIND_IP6TNL && |
bd930cbd YW |
459 | t->ip6tnl_mode == _NETDEV_IP6_TNL_MODE_INVALID) |
460 | return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL), | |
461 | "ip6tnl without mode configured in %s. Ignoring", filename); | |
855ee1a1 | 462 | |
bd930cbd YW |
463 | if (t->fou_tunnel && t->fou_destination_port <= 0) |
464 | return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL), | |
465 | "FooOverUDP missing port configured in %s. Ignoring", filename); | |
53cb501a | 466 | |
bd930cbd YW |
467 | if (netdev->kind == NETDEV_KIND_ERSPAN && (t->erspan_index >= (1 << 20) || t->erspan_index == 0)) |
468 | return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL), "Invalid erspan index %d. Ignoring", t->erspan_index); | |
2266864b | 469 | |
7951dea2 SS |
470 | return 0; |
471 | } | |
6ef892fc TG |
472 | |
473 | int config_parse_tunnel_address(const char *unit, | |
474 | const char *filename, | |
475 | unsigned line, | |
476 | const char *section, | |
477 | unsigned section_line, | |
478 | const char *lvalue, | |
479 | int ltype, | |
480 | const char *rvalue, | |
481 | void *data, | |
482 | void *userdata) { | |
aa9f1140 | 483 | Tunnel *t = userdata; |
44e7b949 LP |
484 | union in_addr_union *addr = data, buffer; |
485 | int r, f; | |
6ef892fc TG |
486 | |
487 | assert(filename); | |
488 | assert(lvalue); | |
489 | assert(rvalue); | |
490 | assert(data); | |
491 | ||
6e47dbbc ZJS |
492 | /* This is used to parse addresses on both local and remote ends of the tunnel. |
493 | * Address families must match. | |
494 | * | |
495 | * "any" is a special value which means that the address is unspecified. | |
496 | */ | |
497 | ||
efd3c897 | 498 | if (streq(rvalue, "any")) { |
6e47dbbc ZJS |
499 | *addr = IN_ADDR_NULL; |
500 | ||
501 | /* As a special case, if both the local and remote addresses are | |
502 | * unspecified, also clear the address family. | |
503 | */ | |
504 | if (t->family != AF_UNSPEC && | |
d40b01e4 YW |
505 | in_addr_is_null(t->family, &t->local) != 0 && |
506 | in_addr_is_null(t->family, &t->remote) != 0) | |
6e47dbbc | 507 | t->family = AF_UNSPEC; |
6ef892fc | 508 | return 0; |
6e47dbbc | 509 | } |
6ef892fc | 510 | |
6e47dbbc ZJS |
511 | r = in_addr_from_string_auto(rvalue, &f, &buffer); |
512 | if (r < 0) { | |
513 | log_syntax(unit, LOG_ERR, filename, line, r, | |
514 | "Tunnel address \"%s\" invalid, ignoring assignment: %m", rvalue); | |
515 | return 0; | |
516 | } | |
efd3c897 | 517 | |
6e47dbbc ZJS |
518 | if (t->family != AF_UNSPEC && t->family != f) { |
519 | log_syntax(unit, LOG_ERR, filename, line, 0, | |
520 | "Tunnel addresses incompatible, ignoring assignment: %s", rvalue); | |
521 | return 0; | |
44e7b949 LP |
522 | } |
523 | ||
524 | t->family = f; | |
525 | *addr = buffer; | |
6ef892fc TG |
526 | return 0; |
527 | } | |
3be1d7e0 | 528 | |
1d710029 SS |
529 | int config_parse_tunnel_key(const char *unit, |
530 | const char *filename, | |
531 | unsigned line, | |
532 | const char *section, | |
533 | unsigned section_line, | |
534 | const char *lvalue, | |
535 | int ltype, | |
536 | const char *rvalue, | |
537 | void *data, | |
538 | void *userdata) { | |
539 | union in_addr_union buffer; | |
540 | Tunnel *t = userdata; | |
541 | uint32_t k; | |
542 | int r; | |
543 | ||
544 | assert(filename); | |
545 | assert(lvalue); | |
546 | assert(rvalue); | |
547 | assert(data); | |
548 | ||
549 | r = in_addr_from_string(AF_INET, rvalue, &buffer); | |
550 | if (r < 0) { | |
551 | r = safe_atou32(rvalue, &k); | |
552 | if (r < 0) { | |
553 | log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse tunnel key ignoring assignment: %s", rvalue); | |
554 | return 0; | |
555 | } | |
556 | } else | |
557 | k = be32toh(buffer.in.s_addr); | |
558 | ||
559 | if (streq(lvalue, "Key")) | |
560 | t->key = k; | |
561 | else if (streq(lvalue, "InputKey")) | |
562 | t->ikey = k; | |
563 | else | |
564 | t->okey = k; | |
565 | ||
566 | return 0; | |
567 | } | |
568 | ||
407af9dd SS |
569 | int config_parse_ipv6_flowlabel(const char* unit, |
570 | const char *filename, | |
571 | unsigned line, | |
572 | const char *section, | |
573 | unsigned section_line, | |
574 | const char *lvalue, | |
575 | int ltype, | |
576 | const char *rvalue, | |
577 | void *data, | |
578 | void *userdata) { | |
579 | IPv6FlowLabel *ipv6_flowlabel = data; | |
580 | Tunnel *t = userdata; | |
407af9dd SS |
581 | int k = 0; |
582 | int r; | |
583 | ||
584 | assert(filename); | |
585 | assert(lvalue); | |
586 | assert(rvalue); | |
587 | assert(ipv6_flowlabel); | |
588 | ||
6870b415 | 589 | if (streq(rvalue, "inherit")) { |
407af9dd SS |
590 | *ipv6_flowlabel = IP6_FLOWINFO_FLOWLABEL; |
591 | t->flags |= IP6_TNL_F_USE_ORIG_FLOWLABEL; | |
592 | } else { | |
6870b415 | 593 | r = config_parse_int(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &k, userdata); |
12ca818f LP |
594 | if (r < 0) |
595 | return r; | |
596 | ||
597 | if (k > 0xFFFFF) | |
598 | log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IPv6 flowlabel option, ignoring: %s", rvalue); | |
599 | else { | |
8e38570e | 600 | *ipv6_flowlabel = htobe32(k) & IP6_FLOWINFO_FLOWLABEL; |
12ca818f | 601 | t->flags &= ~IP6_TNL_F_USE_ORIG_FLOWLABEL; |
407af9dd SS |
602 | } |
603 | } | |
604 | ||
605 | return 0; | |
606 | } | |
607 | ||
b4828886 SS |
608 | int config_parse_encap_limit(const char* unit, |
609 | const char *filename, | |
610 | unsigned line, | |
611 | const char *section, | |
612 | unsigned section_line, | |
613 | const char *lvalue, | |
4d7fa6de | 614 | int ltype, |
b4828886 SS |
615 | const char *rvalue, |
616 | void *data, | |
617 | void *userdata) { | |
618 | Tunnel *t = userdata; | |
619 | int k = 0; | |
620 | int r; | |
621 | ||
622 | assert(filename); | |
623 | assert(lvalue); | |
624 | assert(rvalue); | |
625 | ||
626 | if (streq(rvalue, "none")) | |
627 | t->flags |= IP6_TNL_F_IGN_ENCAP_LIMIT; | |
628 | else { | |
629 | r = safe_atoi(rvalue, &k); | |
630 | if (r < 0) { | |
12ca818f | 631 | log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse Tunnel Encapsulation Limit option, ignoring: %s", rvalue); |
b4828886 SS |
632 | return 0; |
633 | } | |
634 | ||
635 | if (k > 255 || k < 0) | |
12ca818f | 636 | log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid Tunnel Encapsulation value, ignoring: %d", k); |
b4828886 SS |
637 | else { |
638 | t->encap_limit = k; | |
639 | t->flags &= ~IP6_TNL_F_IGN_ENCAP_LIMIT; | |
640 | } | |
641 | } | |
642 | ||
643 | return 0; | |
644 | } | |
645 | ||
d067cab3 DA |
646 | int config_parse_6rd_prefix(const char* unit, |
647 | const char *filename, | |
648 | unsigned line, | |
649 | const char *section, | |
650 | unsigned section_line, | |
651 | const char *lvalue, | |
652 | int ltype, | |
653 | const char *rvalue, | |
654 | void *data, | |
655 | void *userdata) { | |
656 | Tunnel *t = userdata; | |
657 | ||
658 | assert(filename); | |
659 | assert(lvalue); | |
660 | assert(rvalue); | |
661 | ||
662 | union in_addr_union p; | |
663 | uint8_t l; | |
664 | int r; | |
665 | ||
666 | r = in_addr_prefix_from_string(rvalue, AF_INET6, &p, &l); | |
667 | if (r < 0) { | |
668 | log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse 6rd prefix \"%s\", ignoring: %m", rvalue); | |
669 | return 0; | |
670 | } | |
671 | if (l == 0) { | |
672 | log_syntax(unit, LOG_ERR, filename, line, 0, "6rd prefix length of \"%s\" must be greater than zero, ignoring", rvalue); | |
673 | return 0; | |
674 | } | |
675 | ||
676 | t->sixrd_prefix = p.in6; | |
677 | t->sixrd_prefixlen = l; | |
678 | ||
679 | return 0; | |
680 | } | |
681 | ||
a27a0ad6 YW |
682 | static void ipip_sit_init(NetDev *n) { |
683 | Tunnel *t; | |
aa9f1140 TG |
684 | |
685 | assert(n); | |
aa9f1140 | 686 | |
a27a0ad6 YW |
687 | switch (n->kind) { |
688 | case NETDEV_KIND_IPIP: | |
689 | t = IPIP(n); | |
690 | break; | |
691 | case NETDEV_KIND_SIT: | |
692 | t = SIT(n); | |
693 | break; | |
694 | default: | |
695 | assert_not_reached("invalid netdev kind"); | |
696 | } | |
aa9f1140 | 697 | |
aa9f1140 TG |
698 | assert(t); |
699 | ||
700 | t->pmtudisc = true; | |
4799d932 | 701 | t->fou_encap_type = FOU_ENCAP_DIRECT; |
918049ad | 702 | t->isatap = -1; |
aa9f1140 TG |
703 | } |
704 | ||
705 | static void vti_init(NetDev *n) { | |
7185d805 | 706 | Tunnel *t; |
aa9f1140 TG |
707 | |
708 | assert(n); | |
9011ce77 SS |
709 | |
710 | if (n->kind == NETDEV_KIND_VTI) | |
7185d805 | 711 | t = VTI(n); |
9011ce77 SS |
712 | else |
713 | t = VTI6(n); | |
714 | ||
aa9f1140 TG |
715 | assert(t); |
716 | ||
717 | t->pmtudisc = true; | |
718 | } | |
719 | ||
a8b9a65c | 720 | static void gre_erspan_init(NetDev *n) { |
1af2536a | 721 | Tunnel *t; |
aa9f1140 TG |
722 | |
723 | assert(n); | |
1af2536a | 724 | |
a8b9a65c YW |
725 | switch (n->kind) { |
726 | case NETDEV_KIND_GRE: | |
1af2536a | 727 | t = GRE(n); |
a8b9a65c YW |
728 | break; |
729 | case NETDEV_KIND_ERSPAN: | |
730 | t = ERSPAN(n); | |
731 | break; | |
732 | case NETDEV_KIND_GRETAP: | |
1af2536a | 733 | t = GRETAP(n); |
a8b9a65c YW |
734 | break; |
735 | default: | |
736 | assert_not_reached("invalid netdev kind"); | |
737 | } | |
1af2536a | 738 | |
aa9f1140 TG |
739 | assert(t); |
740 | ||
741 | t->pmtudisc = true; | |
a8b9a65c | 742 | t->gre_erspan_sequence = -1; |
4799d932 | 743 | t->fou_encap_type = FOU_ENCAP_DIRECT; |
aa9f1140 TG |
744 | } |
745 | ||
b16492f8 SS |
746 | static void ip6gre_init(NetDev *n) { |
747 | Tunnel *t; | |
748 | ||
749 | assert(n); | |
750 | ||
751 | if (n->kind == NETDEV_KIND_IP6GRE) | |
752 | t = IP6GRE(n); | |
753 | else | |
754 | t = IP6GRETAP(n); | |
755 | ||
756 | assert(t); | |
757 | ||
758 | t->ttl = DEFAULT_TNL_HOP_LIMIT; | |
759 | } | |
760 | ||
855ee1a1 SS |
761 | static void ip6tnl_init(NetDev *n) { |
762 | Tunnel *t = IP6TNL(n); | |
763 | ||
764 | assert(n); | |
765 | assert(t); | |
766 | ||
767 | t->ttl = DEFAULT_TNL_HOP_LIMIT; | |
768 | t->encap_limit = IPV6_DEFAULT_TNL_ENCAP_LIMIT; | |
769 | t->ip6tnl_mode = _NETDEV_IP6_TNL_MODE_INVALID; | |
407af9dd | 770 | t->ipv6_flowlabel = _NETDEV_IPV6_FLOWLABEL_INVALID; |
3a4f3e42 | 771 | t->allow_localremote = -1; |
855ee1a1 SS |
772 | } |
773 | ||
3be1d7e0 | 774 | const NetDevVTable ipip_vtable = { |
aa9f1140 | 775 | .object_size = sizeof(Tunnel), |
a27a0ad6 | 776 | .init = ipip_sit_init, |
aa9f1140 | 777 | .sections = "Match\0NetDev\0Tunnel\0", |
9e64c1f8 | 778 | .fill_message_create = netdev_ipip_sit_fill_message_create, |
aa9f1140 | 779 | .create_type = NETDEV_CREATE_STACKED, |
3be1d7e0 TG |
780 | .config_verify = netdev_tunnel_verify, |
781 | }; | |
782 | ||
783 | const NetDevVTable sit_vtable = { | |
aa9f1140 | 784 | .object_size = sizeof(Tunnel), |
a27a0ad6 | 785 | .init = ipip_sit_init, |
aa9f1140 | 786 | .sections = "Match\0NetDev\0Tunnel\0", |
9e64c1f8 | 787 | .fill_message_create = netdev_ipip_sit_fill_message_create, |
aa9f1140 | 788 | .create_type = NETDEV_CREATE_STACKED, |
3be1d7e0 TG |
789 | .config_verify = netdev_tunnel_verify, |
790 | }; | |
791 | ||
792 | const NetDevVTable vti_vtable = { | |
aa9f1140 TG |
793 | .object_size = sizeof(Tunnel), |
794 | .init = vti_init, | |
795 | .sections = "Match\0NetDev\0Tunnel\0", | |
796 | .fill_message_create = netdev_vti_fill_message_create, | |
797 | .create_type = NETDEV_CREATE_STACKED, | |
3be1d7e0 TG |
798 | .config_verify = netdev_tunnel_verify, |
799 | }; | |
800 | ||
9011ce77 SS |
801 | const NetDevVTable vti6_vtable = { |
802 | .object_size = sizeof(Tunnel), | |
803 | .init = vti_init, | |
804 | .sections = "Match\0NetDev\0Tunnel\0", | |
3affe303 | 805 | .fill_message_create = netdev_vti_fill_message_create, |
9011ce77 SS |
806 | .create_type = NETDEV_CREATE_STACKED, |
807 | .config_verify = netdev_tunnel_verify, | |
808 | }; | |
809 | ||
3be1d7e0 | 810 | const NetDevVTable gre_vtable = { |
aa9f1140 | 811 | .object_size = sizeof(Tunnel), |
a8b9a65c | 812 | .init = gre_erspan_init, |
aa9f1140 | 813 | .sections = "Match\0NetDev\0Tunnel\0", |
a8b9a65c | 814 | .fill_message_create = netdev_gre_erspan_fill_message_create, |
aa9f1140 | 815 | .create_type = NETDEV_CREATE_STACKED, |
3be1d7e0 TG |
816 | .config_verify = netdev_tunnel_verify, |
817 | }; | |
1af2536a SS |
818 | |
819 | const NetDevVTable gretap_vtable = { | |
820 | .object_size = sizeof(Tunnel), | |
a8b9a65c | 821 | .init = gre_erspan_init, |
1af2536a | 822 | .sections = "Match\0NetDev\0Tunnel\0", |
a8b9a65c | 823 | .fill_message_create = netdev_gre_erspan_fill_message_create, |
1af2536a SS |
824 | .create_type = NETDEV_CREATE_STACKED, |
825 | .config_verify = netdev_tunnel_verify, | |
826 | }; | |
855ee1a1 | 827 | |
b16492f8 SS |
828 | const NetDevVTable ip6gre_vtable = { |
829 | .object_size = sizeof(Tunnel), | |
830 | .init = ip6gre_init, | |
831 | .sections = "Match\0NetDev\0Tunnel\0", | |
832 | .fill_message_create = netdev_ip6gre_fill_message_create, | |
833 | .create_type = NETDEV_CREATE_STACKED, | |
834 | .config_verify = netdev_tunnel_verify, | |
835 | }; | |
836 | ||
837 | const NetDevVTable ip6gretap_vtable = { | |
838 | .object_size = sizeof(Tunnel), | |
839 | .init = ip6gre_init, | |
840 | .sections = "Match\0NetDev\0Tunnel\0", | |
841 | .fill_message_create = netdev_ip6gre_fill_message_create, | |
842 | .create_type = NETDEV_CREATE_STACKED, | |
843 | .config_verify = netdev_tunnel_verify, | |
844 | }; | |
845 | ||
855ee1a1 SS |
846 | const NetDevVTable ip6tnl_vtable = { |
847 | .object_size = sizeof(Tunnel), | |
848 | .init = ip6tnl_init, | |
849 | .sections = "Match\0NetDev\0Tunnel\0", | |
850 | .fill_message_create = netdev_ip6tnl_fill_message_create, | |
851 | .create_type = NETDEV_CREATE_STACKED, | |
852 | .config_verify = netdev_tunnel_verify, | |
853 | }; | |
2266864b SS |
854 | |
855 | const NetDevVTable erspan_vtable = { | |
856 | .object_size = sizeof(Tunnel), | |
a8b9a65c | 857 | .init = gre_erspan_init, |
2266864b | 858 | .sections = "Match\0NetDev\0Tunnel\0", |
a8b9a65c | 859 | .fill_message_create = netdev_gre_erspan_fill_message_create, |
9282f75b | 860 | .create_type = NETDEV_CREATE_STACKED, |
2266864b SS |
861 | .config_verify = netdev_tunnel_verify, |
862 | }; |