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