Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0-or-later
2 : /*
3 : * Common ioctl functions.
4 : * Copyright (C) 1997, 98 Kunihiro Ishiguro
5 : */
6 :
7 : #include <zebra.h>
8 :
9 : #include "linklist.h"
10 : #include "if.h"
11 : #include "prefix.h"
12 : #include "ioctl.h"
13 : #include "log.h"
14 : #include "privs.h"
15 : #include "lib_errors.h"
16 :
17 : #include "vty.h"
18 : #include "zebra/rib.h"
19 : #include "zebra/rt.h"
20 : #include "zebra/interface.h"
21 : #include "zebra/zebra_errors.h"
22 : #include "zebra/debug.h"
23 :
24 : #ifdef HAVE_BSD_LINK_DETECT
25 : #include <net/if_media.h>
26 : #endif /* HAVE_BSD_LINK_DETECT*/
27 :
28 : extern struct zebra_privs_t zserv_privs;
29 :
30 : /* clear and set interface name string */
31 0 : void ifreq_set_name(struct ifreq *ifreq, struct interface *ifp)
32 : {
33 0 : strlcpy(ifreq->ifr_name, ifp->name, sizeof(ifreq->ifr_name));
34 0 : }
35 :
36 : #ifndef HAVE_NETLINK
37 : /* call ioctl system call */
38 : int if_ioctl(unsigned long request, caddr_t buffer)
39 : {
40 : int sock;
41 : int ret;
42 : int err = 0;
43 :
44 : frr_with_privs(&zserv_privs) {
45 : sock = socket(AF_INET, SOCK_DGRAM, 0);
46 : if (sock < 0) {
47 : zlog_err("Cannot create UDP socket: %s",
48 : safe_strerror(errno));
49 : exit(1);
50 : }
51 : if ((ret = ioctl(sock, request, buffer)) < 0)
52 : err = errno;
53 : }
54 : close(sock);
55 :
56 : if (ret < 0) {
57 : errno = err;
58 : return ret;
59 : }
60 : return 0;
61 : }
62 : #endif
63 :
64 : /* call ioctl system call */
65 0 : int vrf_if_ioctl(unsigned long request, caddr_t buffer, vrf_id_t vrf_id)
66 : {
67 0 : int sock;
68 0 : int ret;
69 0 : int err = 0;
70 :
71 0 : frr_with_privs(&zserv_privs) {
72 0 : sock = vrf_socket(AF_INET, SOCK_DGRAM, 0, vrf_id, NULL);
73 0 : if (sock < 0) {
74 0 : zlog_err("Cannot create UDP socket: %s",
75 : safe_strerror(errno));
76 0 : exit(1);
77 : }
78 0 : ret = vrf_ioctl(vrf_id, sock, request, buffer);
79 0 : if (ret < 0)
80 0 : err = errno;
81 : }
82 0 : close(sock);
83 :
84 0 : if (ret < 0) {
85 0 : errno = err;
86 0 : return ret;
87 : }
88 : return 0;
89 : }
90 :
91 : #ifndef HAVE_NETLINK
92 : static int if_ioctl_ipv6(unsigned long request, caddr_t buffer)
93 : {
94 : int sock;
95 : int ret;
96 : int err = 0;
97 :
98 : frr_with_privs(&zserv_privs) {
99 : sock = socket(AF_INET6, SOCK_DGRAM, 0);
100 : if (sock < 0) {
101 : zlog_err("Cannot create IPv6 datagram socket: %s",
102 : safe_strerror(errno));
103 : exit(1);
104 : }
105 :
106 : if ((ret = ioctl(sock, request, buffer)) < 0)
107 : err = errno;
108 : }
109 : close(sock);
110 :
111 : if (ret < 0) {
112 : errno = err;
113 : return ret;
114 : }
115 : return 0;
116 : }
117 :
118 : /*
119 : * get interface metric
120 : * -- if value is not avaliable set -1
121 : */
122 : void if_get_metric(struct interface *ifp)
123 : {
124 : #ifdef SIOCGIFMETRIC
125 : struct ifreq ifreq = {};
126 :
127 : ifreq_set_name(&ifreq, ifp);
128 :
129 : if (vrf_if_ioctl(SIOCGIFMETRIC, (caddr_t)&ifreq, ifp->vrf->vrf_id) < 0)
130 : return;
131 : ifp->metric = ifreq.ifr_metric;
132 : if (ifp->metric == 0)
133 : ifp->metric = 1;
134 : #else /* SIOCGIFMETRIC */
135 : ifp->metric = -1;
136 : #endif /* SIOCGIFMETRIC */
137 : }
138 :
139 : /* get interface MTU */
140 : void if_get_mtu(struct interface *ifp)
141 : {
142 : struct ifreq ifreq = {};
143 :
144 : ifreq_set_name(&ifreq, ifp);
145 :
146 : #if defined(SIOCGIFMTU)
147 : if (vrf_if_ioctl(SIOCGIFMTU, (caddr_t)&ifreq, ifp->vrf->vrf_id) < 0) {
148 : zlog_info("Can't lookup mtu by ioctl(SIOCGIFMTU) for %s(%u)",
149 : ifp->name, ifp->vrf->vrf_id);
150 : ifp->mtu6 = ifp->mtu = -1;
151 : return;
152 : }
153 :
154 : ifp->mtu6 = ifp->mtu = ifreq.ifr_mtu;
155 :
156 : /* propogate */
157 : zebra_interface_up_update(ifp);
158 :
159 : #else
160 : zlog_info("Can't lookup mtu on this system for %s(%u)", ifp->name,
161 : ifp->vrf->vrf_id);
162 : ifp->mtu6 = ifp->mtu = -1;
163 : #endif
164 : }
165 : #endif /* ! HAVE_NETLINK */
166 :
167 : /*
168 : * Handler for interface address programming via the zebra dplane,
169 : * for non-netlink platforms. This handler dispatches to per-platform
170 : * helpers, based on the operation requested.
171 : */
172 : #ifndef HAVE_NETLINK
173 :
174 : /* Prototypes: these are placed in this block so that they're only seen
175 : * on non-netlink platforms.
176 : */
177 : static int if_set_prefix_ctx(const struct zebra_dplane_ctx *ctx);
178 : static int if_unset_prefix_ctx(const struct zebra_dplane_ctx *ctx);
179 : static int if_set_prefix6_ctx(const struct zebra_dplane_ctx *ctx);
180 : static int if_unset_prefix6_ctx(const struct zebra_dplane_ctx *ctx);
181 :
182 : enum zebra_dplane_result kernel_address_update_ctx(
183 : struct zebra_dplane_ctx *ctx)
184 : {
185 : int ret = -1;
186 : const struct prefix *p;
187 :
188 : p = dplane_ctx_get_intf_addr(ctx);
189 :
190 : if (dplane_ctx_get_op(ctx) == DPLANE_OP_ADDR_INSTALL) {
191 : if (p->family == AF_INET)
192 : ret = if_set_prefix_ctx(ctx);
193 : else
194 : ret = if_set_prefix6_ctx(ctx);
195 : } else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ADDR_UNINSTALL) {
196 : if (p->family == AF_INET)
197 : ret = if_unset_prefix_ctx(ctx);
198 : else
199 : ret = if_unset_prefix6_ctx(ctx);
200 : } else {
201 : if (IS_ZEBRA_DEBUG_DPLANE)
202 : zlog_debug("Invalid op in interface-addr install");
203 : }
204 :
205 : return (ret == 0 ?
206 : ZEBRA_DPLANE_REQUEST_SUCCESS : ZEBRA_DPLANE_REQUEST_FAILURE);
207 : }
208 :
209 : #ifdef HAVE_STRUCT_IFALIASREQ
210 :
211 : /*
212 : * Helper for interface-addr install, non-netlink
213 : */
214 : static int if_set_prefix_ctx(const struct zebra_dplane_ctx *ctx)
215 : {
216 : int ret;
217 : struct ifaliasreq addreq;
218 : struct sockaddr_in addr, mask, peer;
219 : struct prefix_ipv4 *p;
220 :
221 : p = (struct prefix_ipv4 *)dplane_ctx_get_intf_addr(ctx);
222 :
223 : memset(&addreq, 0, sizeof(addreq));
224 : strlcpy((char *)&addreq.ifra_name, dplane_ctx_get_ifname(ctx),
225 : sizeof(addreq.ifra_name));
226 :
227 : memset(&addr, 0, sizeof(addr));
228 : addr.sin_addr = p->prefix;
229 : addr.sin_family = p->family;
230 : #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
231 : addr.sin_len = sizeof(struct sockaddr_in);
232 : #endif
233 : memcpy(&addreq.ifra_addr, &addr, sizeof(struct sockaddr_in));
234 :
235 : if (dplane_ctx_intf_is_connected(ctx)) {
236 : p = (struct prefix_ipv4 *)dplane_ctx_get_intf_dest(ctx);
237 : memset(&mask, 0, sizeof(mask));
238 : peer.sin_addr = p->prefix;
239 : peer.sin_family = p->family;
240 : #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
241 : peer.sin_len = sizeof(struct sockaddr_in);
242 : #endif
243 : memcpy(&addreq.ifra_broadaddr, &peer,
244 : sizeof(struct sockaddr_in));
245 : }
246 :
247 : memset(&mask, 0, sizeof(mask));
248 : masklen2ip(p->prefixlen, &mask.sin_addr);
249 : mask.sin_family = p->family;
250 : #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
251 : mask.sin_len = sizeof(struct sockaddr_in);
252 : #endif
253 : memcpy(&addreq.ifra_mask, &mask, sizeof(struct sockaddr_in));
254 :
255 : ret = if_ioctl(SIOCAIFADDR, (caddr_t)&addreq);
256 : if (ret < 0)
257 : return ret;
258 : return 0;
259 :
260 : }
261 :
262 : /*
263 : * Helper for interface-addr un-install, non-netlink
264 : */
265 : static int if_unset_prefix_ctx(const struct zebra_dplane_ctx *ctx)
266 : {
267 : int ret;
268 : struct ifaliasreq addreq;
269 : struct sockaddr_in addr, mask, peer;
270 : struct prefix_ipv4 *p;
271 :
272 : p = (struct prefix_ipv4 *)dplane_ctx_get_intf_addr(ctx);
273 :
274 : memset(&addreq, 0, sizeof(addreq));
275 : strlcpy((char *)&addreq.ifra_name, dplane_ctx_get_ifname(ctx),
276 : sizeof(addreq.ifra_name));
277 :
278 : memset(&addr, 0, sizeof(addr));
279 : addr.sin_addr = p->prefix;
280 : addr.sin_family = p->family;
281 : #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
282 : addr.sin_len = sizeof(struct sockaddr_in);
283 : #endif
284 : memcpy(&addreq.ifra_addr, &addr, sizeof(struct sockaddr_in));
285 :
286 : if (dplane_ctx_intf_is_connected(ctx)) {
287 : p = (struct prefix_ipv4 *)dplane_ctx_get_intf_dest(ctx);
288 : memset(&mask, 0, sizeof(mask));
289 : peer.sin_addr = p->prefix;
290 : peer.sin_family = p->family;
291 : #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
292 : peer.sin_len = sizeof(struct sockaddr_in);
293 : #endif
294 : memcpy(&addreq.ifra_broadaddr, &peer,
295 : sizeof(struct sockaddr_in));
296 : }
297 :
298 : memset(&mask, 0, sizeof(mask));
299 : masklen2ip(p->prefixlen, &mask.sin_addr);
300 : mask.sin_family = p->family;
301 : #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
302 : mask.sin_len = sizeof(struct sockaddr_in);
303 : #endif
304 : memcpy(&addreq.ifra_mask, &mask, sizeof(struct sockaddr_in));
305 :
306 : ret = if_ioctl(SIOCDIFADDR, (caddr_t)&addreq);
307 : if (ret < 0)
308 : return ret;
309 : return 0;
310 : }
311 : #else
312 : /* Set up interface's address, netmask (and broadcas? ). Linux or
313 : Solaris uses ifname:number semantics to set IP address aliases. */
314 : int if_set_prefix_ctx(const struct zebra_dplane_ctx *ctx)
315 : {
316 : int ret;
317 : struct ifreq ifreq;
318 : struct sockaddr_in addr;
319 : struct sockaddr_in broad;
320 : struct sockaddr_in mask;
321 : struct prefix_ipv4 ifaddr;
322 : struct prefix_ipv4 *p;
323 :
324 : p = (struct prefix_ipv4 *)dplane_ctx_get_intf_addr(ctx);
325 :
326 : ifaddr = *p;
327 :
328 : strlcpy(ifreq.ifr_name, dplane_ctx_get_ifname(ctx),
329 : sizeof(ifreq.ifr_name));
330 :
331 : addr.sin_addr = p->prefix;
332 : addr.sin_family = p->family;
333 : memcpy(&ifreq.ifr_addr, &addr, sizeof(struct sockaddr_in));
334 : ret = if_ioctl(SIOCSIFADDR, (caddr_t)&ifreq);
335 : if (ret < 0)
336 : return ret;
337 :
338 : /* We need mask for make broadcast addr. */
339 : masklen2ip(p->prefixlen, &mask.sin_addr);
340 :
341 : if (dplane_ctx_intf_is_broadcast(ctx)) {
342 : apply_mask_ipv4(&ifaddr);
343 : addr.sin_addr = ifaddr.prefix;
344 :
345 : broad.sin_addr.s_addr =
346 : (addr.sin_addr.s_addr | ~mask.sin_addr.s_addr);
347 : broad.sin_family = p->family;
348 :
349 : memcpy(&ifreq.ifr_broadaddr, &broad,
350 : sizeof(struct sockaddr_in));
351 : ret = if_ioctl(SIOCSIFBRDADDR, (caddr_t)&ifreq);
352 : if (ret < 0)
353 : return ret;
354 : }
355 :
356 : mask.sin_family = p->family;
357 : memcpy(&ifreq.ifr_addr, &mask, sizeof(struct sockaddr_in));
358 : ret = if_ioctl(SIOCSIFNETMASK, (caddr_t)&ifreq);
359 : if (ret < 0)
360 : return ret;
361 :
362 : return 0;
363 : }
364 :
365 : /* Set up interface's address, netmask (and broadcas? ). Linux or
366 : Solaris uses ifname:number semantics to set IP address aliases. */
367 : int if_unset_prefix_ctx(const struct zebra_dplane_ctx *ctx)
368 : {
369 : int ret;
370 : struct ifreq ifreq;
371 : struct sockaddr_in addr;
372 : struct prefix_ipv4 *p;
373 :
374 : p = (struct prefix_ipv4 *)dplane_ctx_get_intf_addr(ctx);
375 :
376 : strlcpy(ifreq.ifr_name, dplane_ctx_get_ifname(ctx),
377 : sizeof(ifreq.ifr_name));
378 :
379 : memset(&addr, 0, sizeof(addr));
380 : addr.sin_family = p->family;
381 : memcpy(&ifreq.ifr_addr, &addr, sizeof(struct sockaddr_in));
382 : ret = if_ioctl(SIOCSIFADDR, (caddr_t)&ifreq);
383 : if (ret < 0)
384 : return ret;
385 :
386 : return 0;
387 : }
388 : #endif /* HAVE_STRUCT_IFALIASREQ */
389 : #endif /* HAVE_NETLINK */
390 :
391 : /* get interface flags */
392 0 : void if_get_flags(struct interface *ifp)
393 : {
394 0 : int ret;
395 0 : struct ifreq ifreqflags = {};
396 0 : struct ifreq ifreqdata = {};
397 :
398 0 : ifreq_set_name(&ifreqflags, ifp);
399 0 : ifreq_set_name(&ifreqdata, ifp);
400 :
401 0 : ret = vrf_if_ioctl(SIOCGIFFLAGS, (caddr_t)&ifreqflags,
402 0 : ifp->vrf->vrf_id);
403 0 : if (ret < 0) {
404 0 : flog_err_sys(EC_LIB_SYSTEM_CALL,
405 : "vrf_if_ioctl(SIOCGIFFLAGS %s) failed: %s",
406 : ifp->name, safe_strerror(errno));
407 0 : return;
408 : }
409 :
410 0 : if (!CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION))
411 : goto out;
412 :
413 : /* Per-default, IFF_RUNNING is held high, unless link-detect
414 : * says otherwise - we abuse IFF_RUNNING inside zebra as a
415 : * link-state flag, following practice on Linux and Solaris
416 : * kernels
417 : */
418 :
419 : #ifdef SIOCGIFDATA
420 : /*
421 : * BSD gets link state from ifi_link_link in struct if_data.
422 : * All BSD's have this in getifaddrs(3) ifa_data for AF_LINK
423 : * addresses. We can also access it via SIOCGIFDATA.
424 : */
425 :
426 : #ifdef __NetBSD__
427 : struct ifdatareq ifdr = {.ifdr_data.ifi_link_state = 0};
428 : struct if_data *ifdata = &ifdr.ifdr_data;
429 :
430 : strlcpy(ifdr.ifdr_name, ifp->name, sizeof(ifdr.ifdr_name));
431 : ret = vrf_if_ioctl(SIOCGIFDATA, (caddr_t)&ifdr, ifp->vrf->vrf_id);
432 : #else
433 : struct if_data ifd = {.ifi_link_state = 0};
434 : struct if_data *ifdata = &ifd;
435 :
436 : ifreqdata.ifr_data = (caddr_t)ifdata;
437 : ret = vrf_if_ioctl(SIOCGIFDATA, (caddr_t)&ifreqdata, ifp->vrf->vrf_id);
438 : #endif
439 :
440 : if (ret == -1)
441 : /* Very unlikely. Did the interface disappear? */
442 : flog_err_sys(EC_LIB_SYSTEM_CALL,
443 : "if_ioctl(SIOCGIFDATA %s) failed: %s", ifp->name,
444 : safe_strerror(errno));
445 : else {
446 : if (ifdata->ifi_link_state >= LINK_STATE_UP)
447 : SET_FLAG(ifreqflags.ifr_flags, IFF_RUNNING);
448 : else if (ifdata->ifi_link_state == LINK_STATE_UNKNOWN)
449 : /* BSD traditionally treats UNKNOWN as UP */
450 : SET_FLAG(ifreqflags.ifr_flags, IFF_RUNNING);
451 : else
452 : UNSET_FLAG(ifreqflags.ifr_flags, IFF_RUNNING);
453 : }
454 :
455 : #elif defined(HAVE_BSD_LINK_DETECT)
456 : /*
457 : * This is only needed for FreeBSD older than FreeBSD-13.
458 : * Valid and active media generally means the link state is
459 : * up, but this is not always the case.
460 : * For example, some BSD's with a net80211 interface in MONITOR
461 : * mode will treat the media as valid and active but the
462 : * link state is down - because we cannot send anything.
463 : * Also, virtual interfaces such as PPP, VLAN, etc generally
464 : * don't support media at all, so the ioctl will just fail.
465 : */
466 : struct ifmediareq ifmr = {.ifm_status = 0};
467 :
468 : strlcpy(ifmr.ifm_name, ifp->name, sizeof(ifmr.ifm_name));
469 :
470 : if (if_ioctl(SIOCGIFMEDIA, (caddr_t)&ifmr) == -1) {
471 : if (errno != EINVAL)
472 : flog_err_sys(EC_LIB_SYSTEM_CALL,
473 : "if_ioctl(SIOCGIFMEDIA %s) failed: %s",
474 : ifp->name, safe_strerror(errno));
475 : } else if (ifmr.ifm_status & IFM_AVALID) { /* media state is valid */
476 : if (ifmr.ifm_status & IFM_ACTIVE) /* media is active */
477 : SET_FLAG(ifreqflags.ifr_flags, IFF_RUNNING);
478 : else
479 : UNSET_FLAG(ifreqflags.ifr_flags, IFF_RUNNING);
480 : }
481 : #endif /* HAVE_BSD_LINK_DETECT */
482 :
483 0 : out:
484 0 : if_flags_update(ifp, (ifreqflags.ifr_flags & 0x0000ffff));
485 : }
486 :
487 : /* Set interface flags */
488 0 : int if_set_flags(struct interface *ifp, uint64_t flags)
489 : {
490 0 : int ret;
491 0 : struct ifreq ifreq;
492 :
493 0 : memset(&ifreq, 0, sizeof(ifreq));
494 0 : ifreq_set_name(&ifreq, ifp);
495 :
496 0 : ifreq.ifr_flags = ifp->flags;
497 0 : ifreq.ifr_flags |= flags;
498 :
499 0 : ret = vrf_if_ioctl(SIOCSIFFLAGS, (caddr_t)&ifreq, ifp->vrf->vrf_id);
500 :
501 0 : if (ret < 0) {
502 0 : zlog_info("can't set interface %s(%u) flags %" PRIu64,
503 : ifp->name, ifp->vrf->vrf_id, flags);
504 0 : return ret;
505 : }
506 : return 0;
507 : }
508 :
509 : /* Unset interface's flag. */
510 0 : int if_unset_flags(struct interface *ifp, uint64_t flags)
511 : {
512 0 : int ret;
513 0 : struct ifreq ifreq;
514 :
515 0 : memset(&ifreq, 0, sizeof(ifreq));
516 0 : ifreq_set_name(&ifreq, ifp);
517 :
518 0 : ifreq.ifr_flags = ifp->flags;
519 0 : ifreq.ifr_flags &= ~flags;
520 :
521 0 : ret = vrf_if_ioctl(SIOCSIFFLAGS, (caddr_t)&ifreq, ifp->vrf->vrf_id);
522 :
523 0 : if (ret < 0) {
524 0 : zlog_warn("can't unset interface %s(%u) flags %" PRIu64,
525 : ifp->name, ifp->vrf->vrf_id, flags);
526 0 : return ret;
527 : }
528 : return 0;
529 : }
530 :
531 : #ifndef LINUX_IPV6 /* Netlink has its own code */
532 :
533 : #ifdef HAVE_STRUCT_IN6_ALIASREQ
534 : #ifndef ND6_INFINITE_LIFETIME
535 : #define ND6_INFINITE_LIFETIME 0xffffffffL
536 : #endif /* ND6_INFINITE_LIFETIME */
537 :
538 : /*
539 : * Helper for interface-addr install, non-netlink
540 : */
541 : static int if_set_prefix6_ctx(const struct zebra_dplane_ctx *ctx)
542 : {
543 : int ret;
544 : struct in6_aliasreq addreq;
545 : struct sockaddr_in6 addr;
546 : struct sockaddr_in6 mask;
547 : struct prefix_ipv6 *p;
548 :
549 : p = (struct prefix_ipv6 *)dplane_ctx_get_intf_addr(ctx);
550 :
551 : memset(&addreq, 0, sizeof(addreq));
552 : strlcpy((char *)&addreq.ifra_name,
553 : dplane_ctx_get_ifname(ctx), sizeof(addreq.ifra_name));
554 :
555 : memset(&addr, 0, sizeof(addr));
556 : addr.sin6_addr = p->prefix;
557 : addr.sin6_family = p->family;
558 : #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
559 : addr.sin6_len = sizeof(struct sockaddr_in6);
560 : #endif
561 : memcpy(&addreq.ifra_addr, &addr, sizeof(struct sockaddr_in6));
562 :
563 : memset(&mask, 0, sizeof(mask));
564 : masklen2ip6(p->prefixlen, &mask.sin6_addr);
565 : mask.sin6_family = p->family;
566 : #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
567 : mask.sin6_len = sizeof(struct sockaddr_in6);
568 : #endif
569 : memcpy(&addreq.ifra_prefixmask, &mask, sizeof(struct sockaddr_in6));
570 :
571 : addreq.ifra_lifetime.ia6t_vltime = 0xffffffff;
572 : addreq.ifra_lifetime.ia6t_pltime = 0xffffffff;
573 :
574 : #ifdef HAVE_STRUCT_IF6_ALIASREQ_IFRA_LIFETIME
575 : addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
576 : addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
577 : #endif
578 :
579 : ret = if_ioctl_ipv6(SIOCAIFADDR_IN6, (caddr_t)&addreq);
580 : if (ret < 0)
581 : return ret;
582 : return 0;
583 : }
584 :
585 : /*
586 : * Helper for interface-addr un-install, non-netlink
587 : */
588 : static int if_unset_prefix6_ctx(const struct zebra_dplane_ctx *ctx)
589 : {
590 : int ret;
591 : struct in6_aliasreq addreq;
592 : struct sockaddr_in6 addr;
593 : struct sockaddr_in6 mask;
594 : struct prefix_ipv6 *p;
595 :
596 : p = (struct prefix_ipv6 *)dplane_ctx_get_intf_addr(ctx);
597 :
598 : memset(&addreq, 0, sizeof(addreq));
599 : strlcpy((char *)&addreq.ifra_name,
600 : dplane_ctx_get_ifname(ctx), sizeof(addreq.ifra_name));
601 :
602 : memset(&addr, 0, sizeof(addr));
603 : addr.sin6_addr = p->prefix;
604 : addr.sin6_family = p->family;
605 : #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
606 : addr.sin6_len = sizeof(struct sockaddr_in6);
607 : #endif
608 : memcpy(&addreq.ifra_addr, &addr, sizeof(struct sockaddr_in6));
609 :
610 : memset(&mask, 0, sizeof(mask));
611 : masklen2ip6(p->prefixlen, &mask.sin6_addr);
612 : mask.sin6_family = p->family;
613 : #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
614 : mask.sin6_len = sizeof(struct sockaddr_in6);
615 : #endif
616 : memcpy(&addreq.ifra_prefixmask, &mask, sizeof(struct sockaddr_in6));
617 :
618 : #ifdef HAVE_STRUCT_IF6_ALIASREQ_IFRA_LIFETIME
619 : addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
620 : addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
621 : #endif
622 :
623 : ret = if_ioctl_ipv6(SIOCDIFADDR_IN6, (caddr_t)&addreq);
624 : if (ret < 0)
625 : return ret;
626 : return 0;
627 : }
628 : #else
629 : /* The old, pre-dataplane code here just returned, so we're retaining that
630 : * choice.
631 : */
632 : static int if_set_prefix6_ctx(const struct zebra_dplane_ctx *ctx)
633 : {
634 : return 0;
635 : }
636 :
637 : static int if_unset_prefix6_ctx(const struct zebra_dplane_ctx *ctx)
638 : {
639 : return 0;
640 : }
641 : #endif /* HAVE_STRUCT_IN6_ALIASREQ */
642 :
643 : #endif /* LINUX_IPV6 */
|