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