]> git.proxmox.com Git - mirror_frr.git/blob - zebra/rt_socket.c
Merge pull request #6943 from ton31337/fix/replace_sizeof_instead_of_constant_for_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 char prefix_buf[PREFIX_STRLEN];
84 enum blackhole_type bh_type = BLACKHOLE_UNSPEC;
85
86 prefix2str(p, prefix_buf, sizeof(prefix_buf));
87
88 /*
89 * We only have the ability to ADD or DELETE at this point
90 * in time.
91 */
92 if (cmd != RTM_ADD && cmd != RTM_DELETE) {
93 if (IS_ZEBRA_DEBUG_KERNEL)
94 zlog_debug("%s: %s odd command %s",
95 __func__, prefix_buf,
96 lookup_msg(rtm_type_str, cmd, NULL));
97 return 0;
98 }
99
100 memset(&sin_dest, 0, sizeof(sin_dest));
101 memset(&sin_gate, 0, sizeof(sin_gate));
102 memset(&sin_mask, 0, sizeof(sin_mask));
103
104 switch (p->family) {
105 case AF_INET:
106 sin_dest.sin.sin_family = AF_INET;
107 sin_dest.sin.sin_addr = p->u.prefix4;
108 sin_gate.sin.sin_family = AF_INET;
109 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
110 sin_dest.sin.sin_len = sizeof(struct sockaddr_in);
111 sin_gate.sin.sin_len = sizeof(struct sockaddr_in);
112 #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
113 break;
114 case AF_INET6:
115 sin_dest.sin6.sin6_family = AF_INET6;
116 sin_dest.sin6.sin6_addr = p->u.prefix6;
117 sin_gate.sin6.sin6_family = AF_INET6;
118 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
119 sin_dest.sin6.sin6_len = sizeof(struct sockaddr_in6);
120 sin_gate.sin6.sin6_len = sizeof(struct sockaddr_in6);
121 #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
122 break;
123 }
124
125 /* Make gateway. */
126 for (ALL_NEXTHOPS_PTR(ng, nexthop)) {
127 /*
128 * We only want to use the actual good nexthops
129 */
130 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE) ||
131 !CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
132 continue;
133
134 smplsp = NULL;
135 gate = false;
136 snprintf(gate_buf, sizeof(gate_buf), "NULL");
137
138 switch (nexthop->type) {
139 case NEXTHOP_TYPE_IPV4:
140 case NEXTHOP_TYPE_IPV4_IFINDEX:
141 sin_gate.sin.sin_addr = nexthop->gate.ipv4;
142 sin_gate.sin.sin_family = AF_INET;
143 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
144 sin_gate.sin.sin_len = sizeof(struct sockaddr_in);
145 #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
146 ifindex = nexthop->ifindex;
147 gate = true;
148 break;
149 case NEXTHOP_TYPE_IPV6:
150 case NEXTHOP_TYPE_IPV6_IFINDEX:
151 sin_gate.sin6.sin6_addr = nexthop->gate.ipv6;
152 sin_gate.sin6.sin6_family = AF_INET6;
153 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
154 sin_gate.sin6.sin6_len = sizeof(struct sockaddr_in6);
155 #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
156 ifindex = nexthop->ifindex;
157 /* Under kame set interface index to link local address */
158 #ifdef KAME
159
160 #define SET_IN6_LINKLOCAL_IFINDEX(a, i) \
161 do { \
162 (a).s6_addr[2] = ((i) >> 8) & 0xff; \
163 (a).s6_addr[3] = (i)&0xff; \
164 } while (0)
165
166 if (IN6_IS_ADDR_LINKLOCAL(&sin_gate.sin6.sin6_addr))
167 SET_IN6_LINKLOCAL_IFINDEX(
168 sin_gate.sin6.sin6_addr,
169 ifindex);
170 #endif /* KAME */
171
172 gate = true;
173 break;
174 case NEXTHOP_TYPE_IFINDEX:
175 ifindex = nexthop->ifindex;
176 break;
177 case NEXTHOP_TYPE_BLACKHOLE:
178 bh_type = nexthop->bh_type;
179 switch (p->family) {
180 case AF_INET: {
181 struct in_addr loopback;
182
183 loopback.s_addr = htonl(INADDR_LOOPBACK);
184 sin_gate.sin.sin_addr = loopback;
185 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
186 sin_gate.sin.sin_len =
187 sizeof(struct sockaddr_in);
188 #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
189 gate = true;
190 } break;
191 case AF_INET6: {
192 struct in6_addr loopback;
193
194 inet_pton(AF_INET6, "::1", &loopback);
195
196 sin_gate.sin6.sin6_addr = loopback;
197 sin_gate.sin6.sin6_family = AF_INET6;
198
199 #ifdef HAVE_STRUCTSOCKADDR_SA_LEN
200 sin_gate.sin6.sin6_len =
201 sizeof(struct sockaddr_in6);
202 #endif /* HAVE_STRUCTSOCKADDR_SA_LEN */
203 gate = true;
204 } break;
205 }
206 }
207
208 switch (p->family) {
209 case AF_INET:
210 masklen2ip(p->prefixlen, &sin_mask.sin.sin_addr);
211 sin_mask.sin.sin_family = AF_INET;
212 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
213 sin_mask.sin.sin_len = sizeof(struct sockaddr_in);
214 #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
215 break;
216 case AF_INET6:
217 masklen2ip6(p->prefixlen, &sin_mask.sin6.sin6_addr);
218 sin_mask.sin6.sin6_family = AF_INET6;
219 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
220 sin_mask.sin6.sin6_len = sizeof(struct sockaddr_in6);
221 #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
222 break;
223 }
224
225 #ifdef __OpenBSD__
226 if (nexthop->nh_label) {
227 if (kernel_rtm_add_labels(nexthop->nh_label,
228 &smpls) != 0)
229 continue;
230 smplsp = (union sockunion *)&smpls;
231 }
232 #endif
233 error = rtm_write(cmd, &sin_dest, &sin_mask,
234 gate ? &sin_gate : NULL, smplsp,
235 ifindex, bh_type, metric);
236
237 if (IS_ZEBRA_DEBUG_KERNEL) {
238 if (!gate) {
239 zlog_debug(
240 "%s: %s: attention! gate not found for re",
241 __func__, prefix_buf);
242 } else {
243 switch (p->family) {
244 case AF_INET:
245 inet_ntop(AF_INET,
246 &sin_gate.sin.sin_addr,
247 gate_buf, sizeof(gate_buf));
248 break;
249
250 case AF_INET6:
251 inet_ntop(AF_INET6,
252 &sin_gate.sin6.sin6_addr,
253 gate_buf, sizeof(gate_buf));
254 break;
255
256 default:
257 snprintf(gate_buf, sizeof(gate_buf),
258 "(invalid-af)");
259 break;
260 }
261 }
262 }
263 switch (error) {
264 /* We only flag nexthops as being in FIB if
265 * rtm_write() did its work. */
266 case ZEBRA_ERR_NOERROR:
267 nexthop_num++;
268 if (IS_ZEBRA_DEBUG_KERNEL)
269 zlog_debug("%s: %s: successfully did NH %s",
270 __func__, prefix_buf, gate_buf);
271 if (cmd == RTM_ADD)
272 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
273 break;
274
275 /* The only valid case for this error is
276 * kernel's failure to install a multipath
277 * route, which is common for FreeBSD. This
278 * should be ignored silently, but logged as an error
279 * otherwise.
280 */
281 case ZEBRA_ERR_RTEXIST:
282 if (cmd != RTM_ADD)
283 flog_err(EC_LIB_SYSTEM_CALL,
284 "%s: rtm_write() returned %d for command %d",
285 __func__, error, cmd);
286 continue;
287
288 /* Note any unexpected status returns */
289 default:
290 flog_err(
291 EC_LIB_SYSTEM_CALL,
292 "%s: %s: rtm_write() unexpectedly returned %d for command %s",
293 __func__, prefix_buf, error,
294 lookup_msg(rtm_type_str, cmd, NULL));
295 break;
296 }
297 } /* for (ALL_NEXTHOPS(...))*/
298
299 /* If there was no useful nexthop, then complain. */
300 if (nexthop_num == 0) {
301 if (IS_ZEBRA_DEBUG_KERNEL)
302 zlog_debug(
303 "%s: No useful nexthops were found in RIB prefix %s",
304 __func__, prefix_buf);
305 return 1;
306 }
307
308 return 0; /*XXX*/
309 }
310
311 /*
312 * Update or delete a prefix from the kernel,
313 * using info from a dataplane context struct.
314 */
315 enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx)
316 {
317 enum zebra_dplane_result res = ZEBRA_DPLANE_REQUEST_SUCCESS;
318 uint32_t type, old_type;
319
320 if (dplane_ctx_get_src(ctx) != NULL) {
321 zlog_err("route add: IPv6 sourcedest routes unsupported!");
322 return ZEBRA_DPLANE_REQUEST_FAILURE;
323 }
324
325 type = dplane_ctx_get_type(ctx);
326 old_type = dplane_ctx_get_old_type(ctx);
327
328 frr_with_privs(&zserv_privs) {
329
330 if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_DELETE) {
331 if (!RSYSTEM_ROUTE(type))
332 kernel_rtm(RTM_DELETE, dplane_ctx_get_dest(ctx),
333 dplane_ctx_get_ng(ctx),
334 dplane_ctx_get_metric(ctx));
335 } else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_INSTALL) {
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 if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_UPDATE) {
341 /* Must do delete and add separately -
342 * no update available
343 */
344 if (!RSYSTEM_ROUTE(old_type))
345 kernel_rtm(RTM_DELETE, dplane_ctx_get_dest(ctx),
346 dplane_ctx_get_old_ng(ctx),
347 dplane_ctx_get_old_metric(ctx));
348
349 if (!RSYSTEM_ROUTE(type))
350 kernel_rtm(RTM_ADD, dplane_ctx_get_dest(ctx),
351 dplane_ctx_get_ng(ctx),
352 dplane_ctx_get_metric(ctx));
353 } else {
354 zlog_err("Invalid routing socket update op %s (%u)",
355 dplane_op2str(dplane_ctx_get_op(ctx)),
356 dplane_ctx_get_op(ctx));
357 res = ZEBRA_DPLANE_REQUEST_FAILURE;
358 }
359 } /* Elevated privs */
360
361 return res;
362 }
363
364 enum zebra_dplane_result kernel_nexthop_update(struct zebra_dplane_ctx *ctx)
365 {
366 return ZEBRA_DPLANE_REQUEST_SUCCESS;
367 }
368
369 int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla,
370 int llalen, ns_id_t ns_id)
371 {
372 /* TODO */
373 return 0;
374 }
375
376 /* NYI on routing-socket platforms, but we've always returned 'success'... */
377 enum zebra_dplane_result kernel_neigh_update_ctx(struct zebra_dplane_ctx *ctx)
378 {
379 return ZEBRA_DPLANE_REQUEST_SUCCESS;
380 }
381
382 extern int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *mroute)
383 {
384 return 0;
385 }
386
387 /*
388 * Update MAC, using dataplane context object. No-op here for now.
389 */
390 enum zebra_dplane_result kernel_mac_update_ctx(struct zebra_dplane_ctx *ctx)
391 {
392 return ZEBRA_DPLANE_REQUEST_SUCCESS;
393 }
394
395 extern int kernel_interface_set_master(struct interface *master,
396 struct interface *slave)
397 {
398 return 0;
399 }
400
401 uint32_t kernel_get_speed(struct interface *ifp, int *error)
402 {
403 return ifp->speed;
404 }
405
406 int kernel_upd_mac_nh(uint32_t nh_id, struct in_addr vtep_ip)
407 {
408 return 0;
409 }
410
411 int kernel_del_mac_nh(uint32_t nh_id)
412 {
413 return 0;
414 }
415
416 int kernel_upd_mac_nhg(uint32_t nhg_id, uint32_t nh_cnt,
417 struct nh_grp *nh_ids)
418 {
419 return 0;
420 }
421
422 int kernel_del_mac_nhg(uint32_t nhg_id)
423 {
424 return 0;
425 }
426
427 #endif /* !HAVE_NETLINK */