]> git.proxmox.com Git - mirror_frr.git/blob - zebra/rt_socket.c
Merge pull request #13649 from donaldsharp/unlock_the_node_or_else
[mirror_frr.git] / zebra / rt_socket.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Kernel routing table updates by routing socket.
4 * Copyright (C) 1997, 98 Kunihiro Ishiguro
5 */
6
7 #include <zebra.h>
8
9 #ifndef HAVE_NETLINK
10
11 #ifdef __OpenBSD__
12 #include <netmpls/mpls.h>
13 #endif
14
15 #include "if.h"
16 #include "prefix.h"
17 #include "sockunion.h"
18 #include "log.h"
19 #include "privs.h"
20 #include "vxlan.h"
21 #include "lib_errors.h"
22
23 #include "zebra/debug.h"
24 #include "zebra/rib.h"
25 #include "zebra/rt.h"
26 #include "zebra/kernel_socket.h"
27 #include "zebra/zebra_mpls.h"
28 #include "zebra/zebra_errors.h"
29
30 extern struct zebra_privs_t zserv_privs;
31
32 #ifdef __OpenBSD__
33 static int kernel_rtm_add_labels(struct mpls_label_stack *nh_label,
34 struct sockaddr_mpls *smpls)
35 {
36 if (nh_label->num_labels > 1) {
37 flog_warn(EC_ZEBRA_MAX_LABELS_PUSH,
38 "%s: can't push %u labels at once (maximum is 1)",
39 __func__, nh_label->num_labels);
40 return -1;
41 }
42
43 memset(smpls, 0, sizeof(*smpls));
44 smpls->smpls_len = sizeof(*smpls);
45 smpls->smpls_family = AF_MPLS;
46 smpls->smpls_label = htonl(nh_label->label[0] << MPLS_LABEL_OFFSET);
47
48 return 0;
49 }
50 #endif
51
52 /* Interface between zebra message and rtm message. */
53 static int kernel_rtm(int cmd, const struct prefix *p,
54 const struct nexthop_group *ng, uint32_t metric)
55
56 {
57 union sockunion sin_dest, sin_mask, sin_gate;
58 #ifdef __OpenBSD__
59 struct sockaddr_mpls smpls;
60 #endif
61 union sockunion *smplsp = NULL;
62 struct nexthop *nexthop;
63 int nexthop_num = 0;
64 ifindex_t ifindex = 0;
65 bool gate = false;
66 int error;
67 char gate_buf[INET6_BUFSIZ];
68 enum blackhole_type bh_type = BLACKHOLE_UNSPEC;
69
70 /*
71 * We only have the ability to ADD or DELETE at this point
72 * in time.
73 */
74 if (cmd != RTM_ADD && cmd != RTM_DELETE) {
75 if (IS_ZEBRA_DEBUG_KERNEL)
76 zlog_debug("%s: %pFX odd command %s", __func__, p,
77 lookup_msg(rtm_type_str, cmd, NULL));
78 return 0;
79 }
80
81 memset(&sin_dest, 0, sizeof(sin_dest));
82 memset(&sin_gate, 0, sizeof(sin_gate));
83 memset(&sin_mask, 0, sizeof(sin_mask));
84
85 switch (p->family) {
86 case AF_INET:
87 sin_dest.sin.sin_family = AF_INET;
88 sin_dest.sin.sin_addr = p->u.prefix4;
89 sin_gate.sin.sin_family = AF_INET;
90 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
91 sin_dest.sin.sin_len = sizeof(struct sockaddr_in);
92 sin_gate.sin.sin_len = sizeof(struct sockaddr_in);
93 #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
94 break;
95 case AF_INET6:
96 sin_dest.sin6.sin6_family = AF_INET6;
97 sin_dest.sin6.sin6_addr = p->u.prefix6;
98 sin_gate.sin6.sin6_family = AF_INET6;
99 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
100 sin_dest.sin6.sin6_len = sizeof(struct sockaddr_in6);
101 sin_gate.sin6.sin6_len = sizeof(struct sockaddr_in6);
102 #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
103 break;
104 }
105
106 /* Make gateway. */
107 for (ALL_NEXTHOPS_PTR(ng, nexthop)) {
108 /*
109 * We only want to use the actual good nexthops
110 */
111 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE) ||
112 !CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
113 continue;
114
115 smplsp = NULL;
116 gate = false;
117 snprintf(gate_buf, sizeof(gate_buf), "NULL");
118
119 switch (nexthop->type) {
120 case NEXTHOP_TYPE_IPV4:
121 case NEXTHOP_TYPE_IPV4_IFINDEX:
122 sin_gate.sin.sin_addr = nexthop->gate.ipv4;
123 sin_gate.sin.sin_family = AF_INET;
124 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
125 sin_gate.sin.sin_len = sizeof(struct sockaddr_in);
126 #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
127 ifindex = nexthop->ifindex;
128 gate = true;
129 break;
130 case NEXTHOP_TYPE_IPV6:
131 case NEXTHOP_TYPE_IPV6_IFINDEX:
132 sin_gate.sin6.sin6_addr = nexthop->gate.ipv6;
133 sin_gate.sin6.sin6_family = AF_INET6;
134 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
135 sin_gate.sin6.sin6_len = sizeof(struct sockaddr_in6);
136 #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
137 ifindex = nexthop->ifindex;
138 /* Under kame set interface index to link local address */
139 #ifdef KAME
140
141 #define SET_IN6_LINKLOCAL_IFINDEX(a, i) \
142 do { \
143 (a).s6_addr[2] = ((i) >> 8) & 0xff; \
144 (a).s6_addr[3] = (i)&0xff; \
145 } while (0)
146
147 if (IN6_IS_ADDR_LINKLOCAL(&sin_gate.sin6.sin6_addr))
148 SET_IN6_LINKLOCAL_IFINDEX(
149 sin_gate.sin6.sin6_addr,
150 ifindex);
151 #endif /* KAME */
152
153 gate = true;
154 break;
155 case NEXTHOP_TYPE_IFINDEX:
156 ifindex = nexthop->ifindex;
157 break;
158 case NEXTHOP_TYPE_BLACKHOLE:
159 bh_type = nexthop->bh_type;
160 switch (p->family) {
161 case AF_INET: {
162 struct in_addr loopback;
163
164 loopback.s_addr = htonl(INADDR_LOOPBACK);
165 sin_gate.sin.sin_addr = loopback;
166 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
167 sin_gate.sin.sin_len =
168 sizeof(struct sockaddr_in);
169 #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
170 gate = true;
171 } break;
172 case AF_INET6: {
173 struct in6_addr loopback;
174
175 inet_pton(AF_INET6, "::1", &loopback);
176
177 sin_gate.sin6.sin6_addr = loopback;
178 sin_gate.sin6.sin6_family = AF_INET6;
179
180 #ifdef HAVE_STRUCTSOCKADDR_SA_LEN
181 sin_gate.sin6.sin6_len =
182 sizeof(struct sockaddr_in6);
183 #endif /* HAVE_STRUCTSOCKADDR_SA_LEN */
184 gate = true;
185 } break;
186 }
187 }
188
189 switch (p->family) {
190 case AF_INET:
191 masklen2ip(p->prefixlen, &sin_mask.sin.sin_addr);
192 sin_mask.sin.sin_family = AF_INET;
193 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
194 sin_mask.sin.sin_len = sizeof(struct sockaddr_in);
195 #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
196 break;
197 case AF_INET6:
198 masklen2ip6(p->prefixlen, &sin_mask.sin6.sin6_addr);
199 sin_mask.sin6.sin6_family = AF_INET6;
200 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
201 sin_mask.sin6.sin6_len = sizeof(struct sockaddr_in6);
202 #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
203 break;
204 }
205
206 #ifdef __OpenBSD__
207 if (nexthop->nh_label) {
208 if (kernel_rtm_add_labels(nexthop->nh_label,
209 &smpls) != 0)
210 continue;
211 smplsp = (union sockunion *)&smpls;
212 }
213 #endif
214 error = rtm_write(cmd, &sin_dest, &sin_mask,
215 gate ? &sin_gate : NULL, smplsp,
216 ifindex, bh_type, metric);
217
218 if (IS_ZEBRA_DEBUG_KERNEL) {
219 if (!gate) {
220 zlog_debug(
221 "%s: %pFX: attention! gate not found for re",
222 __func__, p);
223 } else {
224 switch (p->family) {
225 case AF_INET:
226 inet_ntop(AF_INET,
227 &sin_gate.sin.sin_addr,
228 gate_buf, sizeof(gate_buf));
229 break;
230
231 case AF_INET6:
232 inet_ntop(AF_INET6,
233 &sin_gate.sin6.sin6_addr,
234 gate_buf, sizeof(gate_buf));
235 break;
236
237 default:
238 snprintf(gate_buf, sizeof(gate_buf),
239 "(invalid-af)");
240 break;
241 }
242 }
243 }
244 switch (error) {
245 /* We only flag nexthops as being in FIB if
246 * rtm_write() did its work. */
247 case ZEBRA_ERR_NOERROR:
248 nexthop_num++;
249 if (IS_ZEBRA_DEBUG_KERNEL)
250 zlog_debug("%s: %pFX: successfully did NH %s",
251 __func__, p, gate_buf);
252 if (cmd == RTM_ADD)
253 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
254 break;
255
256 /* The only valid case for this error is
257 * kernel's failure to install a multipath
258 * route, which is common for FreeBSD. This
259 * should be ignored silently, but logged as an error
260 * otherwise.
261 */
262 case ZEBRA_ERR_RTEXIST:
263 if (cmd != RTM_ADD)
264 flog_err(EC_LIB_SYSTEM_CALL,
265 "%s: rtm_write() returned %d for command %d",
266 __func__, error, cmd);
267 continue;
268
269 /* Note any unexpected status returns */
270 case ZEBRA_ERR_RTNOEXIST:
271 if (cmd != RTM_DELETE)
272 flog_err(EC_LIB_SYSTEM_CALL,
273 "%s: rtm_write() returned %d for command %d",
274 __func__, error, cmd);
275 break;
276 default:
277 flog_err(
278 EC_LIB_SYSTEM_CALL,
279 "%s: %pFX: rtm_write() unexpectedly returned %d for command %s",
280 __func__, p, error,
281 lookup_msg(rtm_type_str, cmd, NULL));
282 break;
283 }
284 } /* for (ALL_NEXTHOPS(...))*/
285
286 /* If there was no useful nexthop, then complain. */
287 if (nexthop_num == 0) {
288 if (IS_ZEBRA_DEBUG_KERNEL)
289 zlog_debug(
290 "%s: No useful nexthops were found in RIB prefix %pFX",
291 __func__, p);
292 return 1;
293 }
294
295 return 0; /*XXX*/
296 }
297
298 /*
299 * Update or delete a prefix from the kernel,
300 * using info from a dataplane context struct.
301 */
302 enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx)
303 {
304 enum zebra_dplane_result res = ZEBRA_DPLANE_REQUEST_SUCCESS;
305 uint32_t type, old_type;
306
307 if (dplane_ctx_get_src(ctx) != NULL) {
308 zlog_err("route add: IPv6 sourcedest routes unsupported!");
309 return ZEBRA_DPLANE_REQUEST_FAILURE;
310 }
311
312 type = dplane_ctx_get_type(ctx);
313 old_type = dplane_ctx_get_old_type(ctx);
314
315 frr_with_privs(&zserv_privs) {
316
317 if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_DELETE) {
318 if (!RSYSTEM_ROUTE(type))
319 kernel_rtm(RTM_DELETE, dplane_ctx_get_dest(ctx),
320 dplane_ctx_get_ng(ctx),
321 dplane_ctx_get_metric(ctx));
322 } else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_INSTALL) {
323 if (!RSYSTEM_ROUTE(type))
324 kernel_rtm(RTM_ADD, dplane_ctx_get_dest(ctx),
325 dplane_ctx_get_ng(ctx),
326 dplane_ctx_get_metric(ctx));
327 } else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_UPDATE) {
328 /* Must do delete and add separately -
329 * no update available
330 */
331 if (!RSYSTEM_ROUTE(old_type))
332 kernel_rtm(RTM_DELETE, dplane_ctx_get_dest(ctx),
333 dplane_ctx_get_old_ng(ctx),
334 dplane_ctx_get_old_metric(ctx));
335
336 if (!RSYSTEM_ROUTE(type))
337 kernel_rtm(RTM_ADD, dplane_ctx_get_dest(ctx),
338 dplane_ctx_get_ng(ctx),
339 dplane_ctx_get_metric(ctx));
340 } else {
341 zlog_err("Invalid routing socket update op %s (%u)",
342 dplane_op2str(dplane_ctx_get_op(ctx)),
343 dplane_ctx_get_op(ctx));
344 res = ZEBRA_DPLANE_REQUEST_FAILURE;
345 }
346 } /* Elevated privs */
347
348 return res;
349 }
350
351 enum zebra_dplane_result kernel_nexthop_update(struct zebra_dplane_ctx *ctx)
352 {
353 return ZEBRA_DPLANE_REQUEST_SUCCESS;
354 }
355
356 int kernel_neigh_register(vrf_id_t vrf_id, struct zserv *client, bool reg)
357 {
358 /* TODO */
359 return 0;
360 }
361
362 int kernel_neigh_update(int add, int ifindex, void *addr, char *lla, int llalen,
363 ns_id_t ns_id, uint8_t family, bool permanent)
364 {
365 /* TODO */
366 return 0;
367 }
368
369 /* NYI on routing-socket platforms, but we've always returned 'success'... */
370 enum zebra_dplane_result kernel_neigh_update_ctx(struct zebra_dplane_ctx *ctx)
371 {
372 return ZEBRA_DPLANE_REQUEST_SUCCESS;
373 }
374
375 extern int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *mroute)
376 {
377 return 0;
378 }
379
380 /*
381 * Update MAC, using dataplane context object. No-op here for now.
382 */
383 enum zebra_dplane_result kernel_mac_update_ctx(struct zebra_dplane_ctx *ctx)
384 {
385 return ZEBRA_DPLANE_REQUEST_SUCCESS;
386 }
387
388 extern int kernel_interface_set_master(struct interface *master,
389 struct interface *slave)
390 {
391 return 0;
392 }
393
394 uint32_t kernel_get_speed(struct interface *ifp, int *error)
395 {
396 return ifp->speed;
397 }
398
399 int kernel_upd_mac_nh(uint32_t nh_id, struct in_addr vtep_ip)
400 {
401 return 0;
402 }
403
404 int kernel_del_mac_nh(uint32_t nh_id)
405 {
406 return 0;
407 }
408
409 int kernel_upd_mac_nhg(uint32_t nhg_id, uint32_t nh_cnt,
410 struct nh_grp *nh_ids)
411 {
412 return 0;
413 }
414
415 int kernel_del_mac_nhg(uint32_t nhg_id)
416 {
417 return 0;
418 }
419
420 #endif /* !HAVE_NETLINK */