Line data Source code
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 0 : void ifreq_set_name(struct ifreq *ifreq, struct interface *ifp)
47 : {
48 0 : strlcpy(ifreq->ifr_name, ifp->name, sizeof(ifreq->ifr_name));
49 0 : }
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 0 : int vrf_if_ioctl(unsigned long request, caddr_t buffer, vrf_id_t vrf_id)
81 : {
82 0 : int sock;
83 0 : int ret;
84 0 : int err = 0;
85 :
86 0 : frr_with_privs(&zserv_privs) {
87 0 : sock = vrf_socket(AF_INET, SOCK_DGRAM, 0, vrf_id, NULL);
88 0 : if (sock < 0) {
89 0 : zlog_err("Cannot create UDP socket: %s",
90 : safe_strerror(errno));
91 0 : exit(1);
92 : }
93 0 : ret = vrf_ioctl(vrf_id, sock, request, buffer);
94 0 : if (ret < 0)
95 0 : err = errno;
96 : }
97 0 : close(sock);
98 :
99 0 : if (ret < 0) {
100 0 : errno = err;
101 0 : 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 0 : void if_get_flags(struct interface *ifp)
408 : {
409 0 : int ret;
410 0 : struct ifreq ifreqflags = {};
411 0 : struct ifreq ifreqdata = {};
412 :
413 0 : ifreq_set_name(&ifreqflags, ifp);
414 0 : ifreq_set_name(&ifreqdata, ifp);
415 :
416 0 : ret = vrf_if_ioctl(SIOCGIFFLAGS, (caddr_t)&ifreqflags,
417 0 : ifp->vrf->vrf_id);
418 0 : if (ret < 0) {
419 0 : flog_err_sys(EC_LIB_SYSTEM_CALL,
420 : "vrf_if_ioctl(SIOCGIFFLAGS %s) failed: %s",
421 : ifp->name, safe_strerror(errno));
422 0 : return;
423 : }
424 :
425 0 : 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 0 : out:
499 0 : if_flags_update(ifp, (ifreqflags.ifr_flags & 0x0000ffff));
500 : }
501 :
502 : /* Set interface flags */
503 0 : int if_set_flags(struct interface *ifp, uint64_t flags)
504 : {
505 0 : int ret;
506 0 : struct ifreq ifreq;
507 :
508 0 : memset(&ifreq, 0, sizeof(ifreq));
509 0 : ifreq_set_name(&ifreq, ifp);
510 :
511 0 : ifreq.ifr_flags = ifp->flags;
512 0 : ifreq.ifr_flags |= flags;
513 :
514 0 : ret = vrf_if_ioctl(SIOCSIFFLAGS, (caddr_t)&ifreq, ifp->vrf->vrf_id);
515 :
516 0 : if (ret < 0) {
517 0 : zlog_info("can't set interface %s(%u) flags %" PRIu64,
518 : ifp->name, ifp->vrf->vrf_id, flags);
519 0 : return ret;
520 : }
521 : return 0;
522 : }
523 :
524 : /* Unset interface's flag. */
525 0 : int if_unset_flags(struct interface *ifp, uint64_t flags)
526 : {
527 0 : int ret;
528 0 : struct ifreq ifreq;
529 :
530 0 : memset(&ifreq, 0, sizeof(ifreq));
531 0 : ifreq_set_name(&ifreq, ifp);
532 :
533 0 : ifreq.ifr_flags = ifp->flags;
534 0 : ifreq.ifr_flags &= ~flags;
535 :
536 0 : ret = vrf_if_ioctl(SIOCSIFFLAGS, (caddr_t)&ifreq, ifp->vrf->vrf_id);
537 :
538 0 : if (ret < 0) {
539 0 : zlog_warn("can't unset interface %s(%u) flags %" PRIu64,
540 : ifp->name, ifp->vrf->vrf_id, flags);
541 0 : 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 */
|