2 * Common ioctl functions.
3 * Copyright (C) 1997, 98 Kunihiro Ishiguro
5 * This file is part of GNU Zebra.
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
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.
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
30 #include "lib_errors.h"
33 #include "zebra/rib.h"
35 #include "zebra/interface.h"
36 #include "zebra/zebra_errors.h"
37 #include "zebra/debug.h"
39 #ifdef HAVE_BSD_LINK_DETECT
40 #include <net/if_media.h>
41 #endif /* HAVE_BSD_LINK_DETECT*/
43 extern struct zebra_privs_t zserv_privs
;
45 /* clear and set interface name string */
46 void ifreq_set_name(struct ifreq
*ifreq
, struct interface
*ifp
)
48 strlcpy(ifreq
->ifr_name
, ifp
->name
, sizeof(ifreq
->ifr_name
));
52 /* call ioctl system call */
53 int if_ioctl(unsigned long request
, caddr_t buffer
)
59 frr_with_privs(&zserv_privs
) {
60 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
62 zlog_err("Cannot create UDP socket: %s",
63 safe_strerror(errno
));
66 if ((ret
= ioctl(sock
, request
, buffer
)) < 0)
79 /* call ioctl system call */
80 int vrf_if_ioctl(unsigned long request
, caddr_t buffer
, vrf_id_t vrf_id
)
86 frr_with_privs(&zserv_privs
) {
87 sock
= vrf_socket(AF_INET
, SOCK_DGRAM
, 0, vrf_id
, NULL
);
89 zlog_err("Cannot create UDP socket: %s",
90 safe_strerror(errno
));
93 ret
= vrf_ioctl(vrf_id
, sock
, request
, buffer
);
107 static int if_ioctl_ipv6(unsigned long request
, caddr_t buffer
)
113 frr_with_privs(&zserv_privs
) {
114 sock
= socket(AF_INET6
, SOCK_DGRAM
, 0);
116 zlog_err("Cannot create IPv6 datagram socket: %s",
117 safe_strerror(errno
));
121 if ((ret
= ioctl(sock
, request
, buffer
)) < 0)
134 * get interface metric
135 * -- if value is not avaliable set -1
137 void if_get_metric(struct interface
*ifp
)
140 struct ifreq ifreq
= {};
142 ifreq_set_name(&ifreq
, ifp
);
144 if (vrf_if_ioctl(SIOCGIFMETRIC
, (caddr_t
)&ifreq
, ifp
->vrf
->vrf_id
) < 0)
146 ifp
->metric
= ifreq
.ifr_metric
;
147 if (ifp
->metric
== 0)
149 #else /* SIOCGIFMETRIC */
151 #endif /* SIOCGIFMETRIC */
154 /* get interface MTU */
155 void if_get_mtu(struct interface
*ifp
)
157 struct ifreq ifreq
= {};
159 ifreq_set_name(&ifreq
, ifp
);
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;
169 ifp
->mtu6
= ifp
->mtu
= ifreq
.ifr_mtu
;
172 zebra_interface_up_update(ifp
);
175 zlog_info("Can't lookup mtu on this system for %s(%u)", ifp
->name
,
177 ifp
->mtu6
= ifp
->mtu
= -1;
180 #endif /* ! HAVE_NETLINK */
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.
189 /* Prototypes: these are placed in this block so that they're only seen
190 * on non-netlink platforms.
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
);
197 enum zebra_dplane_result
kernel_address_update_ctx(
198 struct zebra_dplane_ctx
*ctx
)
201 const struct prefix
*p
;
203 p
= dplane_ctx_get_intf_addr(ctx
);
205 if (dplane_ctx_get_op(ctx
) == DPLANE_OP_ADDR_INSTALL
) {
206 if (p
->family
== AF_INET
)
207 ret
= if_set_prefix_ctx(ctx
);
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
);
214 ret
= if_unset_prefix6_ctx(ctx
);
216 if (IS_ZEBRA_DEBUG_DPLANE
)
217 zlog_debug("Invalid op in interface-addr install");
221 ZEBRA_DPLANE_REQUEST_SUCCESS
: ZEBRA_DPLANE_REQUEST_FAILURE
);
224 #ifdef HAVE_STRUCT_IFALIASREQ
227 * Helper for interface-addr install, non-netlink
229 static int if_set_prefix_ctx(const struct zebra_dplane_ctx
*ctx
)
232 struct ifaliasreq addreq
;
233 struct sockaddr_in addr
, mask
, peer
;
234 struct prefix_ipv4
*p
;
236 p
= (struct prefix_ipv4
*)dplane_ctx_get_intf_addr(ctx
);
238 memset(&addreq
, 0, sizeof(addreq
));
239 strlcpy((char *)&addreq
.ifra_name
, dplane_ctx_get_ifname(ctx
),
240 sizeof(addreq
.ifra_name
));
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
);
248 memcpy(&addreq
.ifra_addr
, &addr
, sizeof(struct sockaddr_in
));
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
);
258 memcpy(&addreq
.ifra_broadaddr
, &peer
,
259 sizeof(struct sockaddr_in
));
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
);
268 memcpy(&addreq
.ifra_mask
, &mask
, sizeof(struct sockaddr_in
));
270 ret
= if_ioctl(SIOCAIFADDR
, (caddr_t
)&addreq
);
278 * Helper for interface-addr un-install, non-netlink
280 static int if_unset_prefix_ctx(const struct zebra_dplane_ctx
*ctx
)
283 struct ifaliasreq addreq
;
284 struct sockaddr_in addr
, mask
, peer
;
285 struct prefix_ipv4
*p
;
287 p
= (struct prefix_ipv4
*)dplane_ctx_get_intf_addr(ctx
);
289 memset(&addreq
, 0, sizeof(addreq
));
290 strlcpy((char *)&addreq
.ifra_name
, dplane_ctx_get_ifname(ctx
),
291 sizeof(addreq
.ifra_name
));
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
);
299 memcpy(&addreq
.ifra_addr
, &addr
, sizeof(struct sockaddr_in
));
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
);
309 memcpy(&addreq
.ifra_broadaddr
, &peer
,
310 sizeof(struct sockaddr_in
));
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
);
319 memcpy(&addreq
.ifra_mask
, &mask
, sizeof(struct sockaddr_in
));
321 ret
= if_ioctl(SIOCDIFADDR
, (caddr_t
)&addreq
);
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
)
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
;
339 p
= (struct prefix_ipv4
*)dplane_ctx_get_intf_addr(ctx
);
343 strlcpy(ifreq
.ifr_name
, dplane_ctx_get_ifname(ctx
),
344 sizeof(ifreq
.ifr_name
));
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
);
353 /* We need mask for make broadcast addr. */
354 masklen2ip(p
->prefixlen
, &mask
.sin_addr
);
356 if (dplane_ctx_intf_is_broadcast(ctx
)) {
357 apply_mask_ipv4(&ifaddr
);
358 addr
.sin_addr
= ifaddr
.prefix
;
360 broad
.sin_addr
.s_addr
=
361 (addr
.sin_addr
.s_addr
| ~mask
.sin_addr
.s_addr
);
362 broad
.sin_family
= p
->family
;
364 memcpy(&ifreq
.ifr_broadaddr
, &broad
,
365 sizeof(struct sockaddr_in
));
366 ret
= if_ioctl(SIOCSIFBRDADDR
, (caddr_t
)&ifreq
);
371 mask
.sin_family
= p
->family
;
372 memcpy(&ifreq
.ifr_addr
, &mask
, sizeof(struct sockaddr_in
));
373 ret
= if_ioctl(SIOCSIFNETMASK
, (caddr_t
)&ifreq
);
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
)
386 struct sockaddr_in addr
;
387 struct prefix_ipv4
*p
;
389 p
= (struct prefix_ipv4
*)dplane_ctx_get_intf_addr(ctx
);
391 strlcpy(ifreq
.ifr_name
, dplane_ctx_get_ifname(ctx
),
392 sizeof(ifreq
.ifr_name
));
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
);
403 #endif /* HAVE_STRUCT_IFALIASREQ */
404 #endif /* HAVE_NETLINK */
406 /* get interface flags */
407 void if_get_flags(struct interface
*ifp
)
410 struct ifreq ifreqflags
= {};
411 struct ifreq ifreqdata
= {};
413 ifreq_set_name(&ifreqflags
, ifp
);
414 ifreq_set_name(&ifreqdata
, ifp
);
416 ret
= vrf_if_ioctl(SIOCGIFFLAGS
, (caddr_t
)&ifreqflags
,
419 flog_err_sys(EC_LIB_SYSTEM_CALL
,
420 "vrf_if_ioctl(SIOCGIFFLAGS %s) failed: %s",
421 ifp
->name
, safe_strerror(errno
));
425 if (!CHECK_FLAG(ifp
->status
, ZEBRA_INTERFACE_LINKDETECTION
))
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
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.
442 struct ifdatareq ifdr
= {.ifdr_data
.ifi_link_state
= 0};
443 struct if_data
*ifdata
= &ifdr
.ifdr_data
;
445 strlcpy(ifdr
.ifdr_name
, ifp
->name
, sizeof(ifdr
.ifdr_name
));
446 ret
= vrf_if_ioctl(SIOCGIFDATA
, (caddr_t
)&ifdr
, ifp
->vrf
->vrf_id
);
448 struct if_data ifd
= {.ifi_link_state
= 0};
449 struct if_data
*ifdata
= &ifd
;
451 ifreqdata
.ifr_data
= (caddr_t
)ifdata
;
452 ret
= vrf_if_ioctl(SIOCGIFDATA
, (caddr_t
)&ifreqdata
, ifp
->vrf
->vrf_id
);
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
));
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
);
467 UNSET_FLAG(ifreqflags
.ifr_flags
, IFF_RUNNING
);
470 #elif defined(HAVE_BSD_LINK_DETECT)
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.
481 struct ifmediareq ifmr
= {.ifm_status
= 0};
483 strlcpy(ifmr
.ifm_name
, ifp
->name
, sizeof(ifmr
.ifm_name
));
485 if (if_ioctl(SIOCGIFMEDIA
, (caddr_t
)&ifmr
) == -1) {
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
);
494 UNSET_FLAG(ifreqflags
.ifr_flags
, IFF_RUNNING
);
496 #endif /* HAVE_BSD_LINK_DETECT */
499 if_flags_update(ifp
, (ifreqflags
.ifr_flags
& 0x0000ffff));
502 /* Set interface flags */
503 int if_set_flags(struct interface
*ifp
, uint64_t flags
)
508 memset(&ifreq
, 0, sizeof(ifreq
));
509 ifreq_set_name(&ifreq
, ifp
);
511 ifreq
.ifr_flags
= ifp
->flags
;
512 ifreq
.ifr_flags
|= flags
;
514 ret
= vrf_if_ioctl(SIOCSIFFLAGS
, (caddr_t
)&ifreq
, ifp
->vrf
->vrf_id
);
517 zlog_info("can't set interface %s(%u) flags %" PRIu64
,
518 ifp
->name
, ifp
->vrf
->vrf_id
, flags
);
524 /* Unset interface's flag. */
525 int if_unset_flags(struct interface
*ifp
, uint64_t flags
)
530 memset(&ifreq
, 0, sizeof(ifreq
));
531 ifreq_set_name(&ifreq
, ifp
);
533 ifreq
.ifr_flags
= ifp
->flags
;
534 ifreq
.ifr_flags
&= ~flags
;
536 ret
= vrf_if_ioctl(SIOCSIFFLAGS
, (caddr_t
)&ifreq
, ifp
->vrf
->vrf_id
);
539 zlog_warn("can't unset interface %s(%u) flags %" PRIu64
,
540 ifp
->name
, ifp
->vrf
->vrf_id
, flags
);
546 #ifndef LINUX_IPV6 /* Netlink has its own code */
548 #ifdef HAVE_STRUCT_IN6_ALIASREQ
549 #ifndef ND6_INFINITE_LIFETIME
550 #define ND6_INFINITE_LIFETIME 0xffffffffL
551 #endif /* ND6_INFINITE_LIFETIME */
554 * Helper for interface-addr install, non-netlink
556 static int if_set_prefix6_ctx(const struct zebra_dplane_ctx
*ctx
)
559 struct in6_aliasreq addreq
;
560 struct sockaddr_in6 addr
;
561 struct sockaddr_in6 mask
;
562 struct prefix_ipv6
*p
;
564 p
= (struct prefix_ipv6
*)dplane_ctx_get_intf_addr(ctx
);
566 memset(&addreq
, 0, sizeof(addreq
));
567 strlcpy((char *)&addreq
.ifra_name
,
568 dplane_ctx_get_ifname(ctx
), sizeof(addreq
.ifra_name
));
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
);
576 memcpy(&addreq
.ifra_addr
, &addr
, sizeof(struct sockaddr_in6
));
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
);
584 memcpy(&addreq
.ifra_prefixmask
, &mask
, sizeof(struct sockaddr_in6
));
586 addreq
.ifra_lifetime
.ia6t_vltime
= 0xffffffff;
587 addreq
.ifra_lifetime
.ia6t_pltime
= 0xffffffff;
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
;
594 ret
= if_ioctl_ipv6(SIOCAIFADDR_IN6
, (caddr_t
)&addreq
);
601 * Helper for interface-addr un-install, non-netlink
603 static int if_unset_prefix6_ctx(const struct zebra_dplane_ctx
*ctx
)
606 struct in6_aliasreq addreq
;
607 struct sockaddr_in6 addr
;
608 struct sockaddr_in6 mask
;
609 struct prefix_ipv6
*p
;
611 p
= (struct prefix_ipv6
*)dplane_ctx_get_intf_addr(ctx
);
613 memset(&addreq
, 0, sizeof(addreq
));
614 strlcpy((char *)&addreq
.ifra_name
,
615 dplane_ctx_get_ifname(ctx
), sizeof(addreq
.ifra_name
));
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
);
623 memcpy(&addreq
.ifra_addr
, &addr
, sizeof(struct sockaddr_in6
));
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
);
631 memcpy(&addreq
.ifra_prefixmask
, &mask
, sizeof(struct sockaddr_in6
));
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
;
638 ret
= if_ioctl_ipv6(SIOCDIFADDR_IN6
, (caddr_t
)&addreq
);
644 /* The old, pre-dataplane code here just returned, so we're retaining that
647 static int if_set_prefix6_ctx(const struct zebra_dplane_ctx
*ctx
)
652 static int if_unset_prefix6_ctx(const struct zebra_dplane_ctx
*ctx
)
656 #endif /* HAVE_STRUCT_IN6_ALIASREQ */
658 #endif /* LINUX_IPV6 */