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
));
51 /* call ioctl system call */
52 int if_ioctl(unsigned long request
, caddr_t buffer
)
58 frr_with_privs(&zserv_privs
) {
59 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
61 zlog_err("Cannot create UDP socket: %s",
62 safe_strerror(errno
));
65 if ((ret
= ioctl(sock
, request
, buffer
)) < 0)
77 /* call ioctl system call */
78 int vrf_if_ioctl(unsigned long request
, caddr_t buffer
, vrf_id_t vrf_id
)
84 frr_with_privs(&zserv_privs
) {
85 sock
= vrf_socket(AF_INET
, SOCK_DGRAM
, 0, vrf_id
, NULL
);
87 zlog_err("Cannot create UDP socket: %s",
88 safe_strerror(errno
));
91 ret
= vrf_ioctl(vrf_id
, sock
, request
, buffer
);
105 static int if_ioctl_ipv6(unsigned long request
, caddr_t buffer
)
111 frr_with_privs(&zserv_privs
) {
112 sock
= socket(AF_INET6
, SOCK_DGRAM
, 0);
114 zlog_err("Cannot create IPv6 datagram socket: %s",
115 safe_strerror(errno
));
119 if ((ret
= ioctl(sock
, request
, buffer
)) < 0)
130 #endif /* ! HAVE_NETLINK */
133 * get interface metric
134 * -- if value is not avaliable set -1
136 void if_get_metric(struct interface
*ifp
)
141 ifreq_set_name(&ifreq
, ifp
);
143 if (vrf_if_ioctl(SIOCGIFMETRIC
, (caddr_t
)&ifreq
, ifp
->vrf_id
) < 0)
145 ifp
->metric
= ifreq
.ifr_metric
;
146 if (ifp
->metric
== 0)
148 #else /* SIOCGIFMETRIC */
150 #endif /* SIOCGIFMETRIC */
153 /* get interface MTU */
154 void if_get_mtu(struct interface
*ifp
)
158 ifreq_set_name(&ifreq
, ifp
);
160 #if defined(SIOCGIFMTU)
161 if (vrf_if_ioctl(SIOCGIFMTU
, (caddr_t
)&ifreq
, ifp
->vrf_id
) < 0) {
162 zlog_info("Can't lookup mtu by ioctl(SIOCGIFMTU)");
163 ifp
->mtu6
= ifp
->mtu
= -1;
167 ifp
->mtu6
= ifp
->mtu
= ifreq
.ifr_mtu
;
170 zebra_interface_up_update(ifp
);
173 zlog_info("Can't lookup mtu on this system");
174 ifp
->mtu6
= ifp
->mtu
= -1;
179 * Handler for interface address programming via the zebra dplane,
180 * for non-netlink platforms. This handler dispatches to per-platform
181 * helpers, based on the operation requested.
185 /* Prototypes: these are placed in this block so that they're only seen
186 * on non-netlink platforms.
188 static int if_set_prefix_ctx(const struct zebra_dplane_ctx
*ctx
);
189 static int if_unset_prefix_ctx(const struct zebra_dplane_ctx
*ctx
);
190 static int if_set_prefix6_ctx(const struct zebra_dplane_ctx
*ctx
);
191 static int if_unset_prefix6_ctx(const struct zebra_dplane_ctx
*ctx
);
193 enum zebra_dplane_result
kernel_address_update_ctx(
194 struct zebra_dplane_ctx
*ctx
)
197 const struct prefix
*p
;
199 p
= dplane_ctx_get_intf_addr(ctx
);
201 if (dplane_ctx_get_op(ctx
) == DPLANE_OP_ADDR_INSTALL
) {
202 if (p
->family
== AF_INET
)
203 ret
= if_set_prefix_ctx(ctx
);
205 ret
= if_set_prefix6_ctx(ctx
);
206 } else if (dplane_ctx_get_op(ctx
) == DPLANE_OP_ADDR_UNINSTALL
) {
207 if (p
->family
== AF_INET
)
208 ret
= if_unset_prefix_ctx(ctx
);
210 ret
= if_unset_prefix6_ctx(ctx
);
212 if (IS_ZEBRA_DEBUG_DPLANE
)
213 zlog_debug("Invalid op in interface-addr install");
217 ZEBRA_DPLANE_REQUEST_SUCCESS
: ZEBRA_DPLANE_REQUEST_FAILURE
);
220 #endif /* !HAVE_NETLINK */
224 /* TODO -- remove; no use of these apis with netlink any longer */
226 #else /* ! HAVE_NETLINK */
227 #ifdef HAVE_STRUCT_IFALIASREQ
230 * Helper for interface-addr install, non-netlink
232 static int if_set_prefix_ctx(const struct zebra_dplane_ctx
*ctx
)
235 struct ifaliasreq addreq
;
236 struct sockaddr_in addr
, mask
, peer
;
237 struct prefix_ipv4
*p
;
239 p
= (struct prefix_ipv4
*)dplane_ctx_get_intf_addr(ctx
);
241 memset(&addreq
, 0, sizeof(addreq
));
242 strlcpy((char *)&addreq
.ifra_name
, dplane_ctx_get_ifname(ctx
),
243 sizeof(addreq
.ifra_name
));
245 memset(&addr
, 0, sizeof(struct sockaddr_in
));
246 addr
.sin_addr
= p
->prefix
;
247 addr
.sin_family
= p
->family
;
248 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
249 addr
.sin_len
= sizeof(struct sockaddr_in
);
251 memcpy(&addreq
.ifra_addr
, &addr
, sizeof(struct sockaddr_in
));
253 if (dplane_ctx_intf_is_connected(ctx
)) {
254 p
= (struct prefix_ipv4
*)dplane_ctx_get_intf_dest(ctx
);
255 memset(&mask
, 0, sizeof(struct sockaddr_in
));
256 peer
.sin_addr
= p
->prefix
;
257 peer
.sin_family
= p
->family
;
258 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
259 peer
.sin_len
= sizeof(struct sockaddr_in
);
261 memcpy(&addreq
.ifra_broadaddr
, &peer
,
262 sizeof(struct sockaddr_in
));
265 memset(&mask
, 0, sizeof(struct sockaddr_in
));
266 masklen2ip(p
->prefixlen
, &mask
.sin_addr
);
267 mask
.sin_family
= p
->family
;
268 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
269 mask
.sin_len
= sizeof(struct sockaddr_in
);
271 memcpy(&addreq
.ifra_mask
, &mask
, sizeof(struct sockaddr_in
));
273 ret
= if_ioctl(SIOCAIFADDR
, (caddr_t
)&addreq
);
281 * Helper for interface-addr un-install, non-netlink
283 static int if_unset_prefix_ctx(const struct zebra_dplane_ctx
*ctx
)
286 struct ifaliasreq addreq
;
287 struct sockaddr_in addr
, mask
, peer
;
288 struct prefix_ipv4
*p
;
290 p
= (struct prefix_ipv4
*)dplane_ctx_get_intf_addr(ctx
);
292 memset(&addreq
, 0, sizeof(addreq
));
293 strlcpy((char *)&addreq
.ifra_name
, dplane_ctx_get_ifname(ctx
),
294 sizeof(addreq
.ifra_name
));
296 memset(&addr
, 0, sizeof(struct sockaddr_in
));
297 addr
.sin_addr
= p
->prefix
;
298 addr
.sin_family
= p
->family
;
299 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
300 addr
.sin_len
= sizeof(struct sockaddr_in
);
302 memcpy(&addreq
.ifra_addr
, &addr
, sizeof(struct sockaddr_in
));
304 if (dplane_ctx_intf_is_connected(ctx
)) {
305 p
= (struct prefix_ipv4
*)dplane_ctx_get_intf_dest(ctx
);
306 memset(&mask
, 0, sizeof(struct sockaddr_in
));
307 peer
.sin_addr
= p
->prefix
;
308 peer
.sin_family
= p
->family
;
309 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
310 peer
.sin_len
= sizeof(struct sockaddr_in
);
312 memcpy(&addreq
.ifra_broadaddr
, &peer
,
313 sizeof(struct sockaddr_in
));
316 memset(&mask
, 0, sizeof(struct sockaddr_in
));
317 masklen2ip(p
->prefixlen
, &mask
.sin_addr
);
318 mask
.sin_family
= p
->family
;
319 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
320 mask
.sin_len
= sizeof(struct sockaddr_in
);
322 memcpy(&addreq
.ifra_mask
, &mask
, sizeof(struct sockaddr_in
));
324 ret
= if_ioctl(SIOCDIFADDR
, (caddr_t
)&addreq
);
330 /* Set up interface's address, netmask (and broadcas? ). Linux or
331 Solaris uses ifname:number semantics to set IP address aliases. */
332 int if_set_prefix_ctx(const struct zebra_dplane_ctx
*ctx
)
336 struct sockaddr_in addr
;
337 struct sockaddr_in broad
;
338 struct sockaddr_in mask
;
339 struct prefix_ipv4 ifaddr
;
340 struct prefix_ipv4
*p
;
342 p
= (struct prefix_ipv4
*)dplane_ctx_get_intf_addr(ctx
);
346 strlcpy(ifreq
.ifr_name
, dplane_ctx_get_ifname(ctx
),
347 sizeof(ifreq
.ifr_name
));
349 addr
.sin_addr
= p
->prefix
;
350 addr
.sin_family
= p
->family
;
351 memcpy(&ifreq
.ifr_addr
, &addr
, sizeof(struct sockaddr_in
));
352 ret
= if_ioctl(SIOCSIFADDR
, (caddr_t
)&ifreq
);
356 /* We need mask for make broadcast addr. */
357 masklen2ip(p
->prefixlen
, &mask
.sin_addr
);
359 if (dplane_ctx_intf_is_broadcast(ctx
)) {
360 apply_mask_ipv4(&ifaddr
);
361 addr
.sin_addr
= ifaddr
.prefix
;
363 broad
.sin_addr
.s_addr
=
364 (addr
.sin_addr
.s_addr
| ~mask
.sin_addr
.s_addr
);
365 broad
.sin_family
= p
->family
;
367 memcpy(&ifreq
.ifr_broadaddr
, &broad
,
368 sizeof(struct sockaddr_in
));
369 ret
= if_ioctl(SIOCSIFBRDADDR
, (caddr_t
)&ifreq
);
374 mask
.sin_family
= p
->family
;
375 memcpy(&ifreq
.ifr_addr
, &mask
, sizeof(struct sockaddr_in
));
376 ret
= if_ioctl(SIOCSIFNETMASK
, (caddr_t
)&ifreq
);
383 /* Set up interface's address, netmask (and broadcas? ). Linux or
384 Solaris uses ifname:number semantics to set IP address aliases. */
385 int if_unset_prefix_ctx(const struct zebra_dplane_ctx
*ctx
)
389 struct sockaddr_in addr
;
390 struct prefix_ipv4
*p
;
392 p
= (struct prefix_ipv4
*)dplane_ctx_get_intf_addr(ctx
);
394 strlcpy(ifreq
.ifr_name
, dplane_ctx_get_ifname(ctx
),
395 sizeof(ifreq
.ifr_name
));
397 memset(&addr
, 0, sizeof(struct sockaddr_in
));
398 addr
.sin_family
= p
->family
;
399 memcpy(&ifreq
.ifr_addr
, &addr
, sizeof(struct sockaddr_in
));
400 ret
= if_ioctl(SIOCSIFADDR
, (caddr_t
)&ifreq
);
406 #endif /* HAVE_STRUCT_IFALIASREQ */
407 #endif /* HAVE_NETLINK */
409 /* get interface flags */
410 void if_get_flags(struct interface
*ifp
)
415 ifreq_set_name(&ifreq
, ifp
);
417 ret
= vrf_if_ioctl(SIOCGIFFLAGS
, (caddr_t
)&ifreq
, ifp
->vrf_id
);
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_id
);
448 struct if_data ifd
= {.ifi_link_state
= 0};
449 struct if_data
*ifdata
= &ifd
;
451 ifreq
.ifr_data
= (caddr_t
)ifdata
;
452 ret
= vrf_if_ioctl(SIOCGIFDATA
, (caddr_t
)&ifreq
, ifp
->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(ifreq
.ifr_flags
, IFF_RUNNING
);
463 else if (ifdata
->ifi_link_state
== LINK_STATE_UNKNOWN
)
464 /* BSD traditionally treats UNKNOWN as UP */
465 SET_FLAG(ifreq
.ifr_flags
, IFF_RUNNING
);
467 UNSET_FLAG(ifreq
.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(ifreq
.ifr_flags
, IFF_RUNNING
);
494 UNSET_FLAG(ifreq
.ifr_flags
, IFF_RUNNING
);
496 #endif /* HAVE_BSD_LINK_DETECT */
499 if_flags_update(ifp
, (ifreq
.ifr_flags
& 0x0000ffff));
502 /* Set interface flags */
503 int if_set_flags(struct interface
*ifp
, uint64_t flags
)
508 memset(&ifreq
, 0, sizeof(struct 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_id
);
517 zlog_info("can't set interface flags");
523 /* Unset interface's flag. */
524 int if_unset_flags(struct interface
*ifp
, uint64_t flags
)
529 memset(&ifreq
, 0, sizeof(struct ifreq
));
530 ifreq_set_name(&ifreq
, ifp
);
532 ifreq
.ifr_flags
= ifp
->flags
;
533 ifreq
.ifr_flags
&= ~flags
;
535 ret
= vrf_if_ioctl(SIOCSIFFLAGS
, (caddr_t
)&ifreq
, ifp
->vrf_id
);
538 zlog_info("can't unset interface flags");
544 #ifndef LINUX_IPV6 /* Netlink has its own code */
546 #ifdef HAVE_STRUCT_IN6_ALIASREQ
547 #ifndef ND6_INFINITE_LIFETIME
548 #define ND6_INFINITE_LIFETIME 0xffffffffL
549 #endif /* ND6_INFINITE_LIFETIME */
552 * Helper for interface-addr install, non-netlink
554 static int if_set_prefix6_ctx(const struct zebra_dplane_ctx
*ctx
)
557 struct in6_aliasreq addreq
;
558 struct sockaddr_in6 addr
;
559 struct sockaddr_in6 mask
;
560 struct prefix_ipv6
*p
;
562 p
= (struct prefix_ipv6
*)dplane_ctx_get_intf_addr(ctx
);
564 memset(&addreq
, 0, sizeof(addreq
));
565 strlcpy((char *)&addreq
.ifra_name
,
566 dplane_ctx_get_ifname(ctx
), sizeof(addreq
.ifra_name
));
568 memset(&addr
, 0, sizeof(struct sockaddr_in6
));
569 addr
.sin6_addr
= p
->prefix
;
570 addr
.sin6_family
= p
->family
;
571 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
572 addr
.sin6_len
= sizeof(struct sockaddr_in6
);
574 memcpy(&addreq
.ifra_addr
, &addr
, sizeof(struct sockaddr_in6
));
576 memset(&mask
, 0, sizeof(struct sockaddr_in6
));
577 masklen2ip6(p
->prefixlen
, &mask
.sin6_addr
);
578 mask
.sin6_family
= p
->family
;
579 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
580 mask
.sin6_len
= sizeof(struct sockaddr_in6
);
582 memcpy(&addreq
.ifra_prefixmask
, &mask
, sizeof(struct sockaddr_in6
));
584 addreq
.ifra_lifetime
.ia6t_vltime
= 0xffffffff;
585 addreq
.ifra_lifetime
.ia6t_pltime
= 0xffffffff;
587 #ifdef HAVE_STRUCT_IF6_ALIASREQ_IFRA_LIFETIME
588 addreq
.ifra_lifetime
.ia6t_pltime
= ND6_INFINITE_LIFETIME
;
589 addreq
.ifra_lifetime
.ia6t_vltime
= ND6_INFINITE_LIFETIME
;
592 ret
= if_ioctl_ipv6(SIOCAIFADDR_IN6
, (caddr_t
)&addreq
);
599 * Helper for interface-addr un-install, non-netlink
601 static int if_unset_prefix6_ctx(const struct zebra_dplane_ctx
*ctx
)
604 struct in6_aliasreq addreq
;
605 struct sockaddr_in6 addr
;
606 struct sockaddr_in6 mask
;
607 struct prefix_ipv6
*p
;
609 p
= (struct prefix_ipv6
*)dplane_ctx_get_intf_addr(ctx
);
611 memset(&addreq
, 0, sizeof(addreq
));
612 strlcpy((char *)&addreq
.ifra_name
,
613 dplane_ctx_get_ifname(ctx
), sizeof(addreq
.ifra_name
));
615 memset(&addr
, 0, sizeof(struct sockaddr_in6
));
616 addr
.sin6_addr
= p
->prefix
;
617 addr
.sin6_family
= p
->family
;
618 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
619 addr
.sin6_len
= sizeof(struct sockaddr_in6
);
621 memcpy(&addreq
.ifra_addr
, &addr
, sizeof(struct sockaddr_in6
));
623 memset(&mask
, 0, sizeof(struct sockaddr_in6
));
624 masklen2ip6(p
->prefixlen
, &mask
.sin6_addr
);
625 mask
.sin6_family
= p
->family
;
626 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
627 mask
.sin6_len
= sizeof(struct sockaddr_in6
);
629 memcpy(&addreq
.ifra_prefixmask
, &mask
, sizeof(struct sockaddr_in6
));
631 #ifdef HAVE_STRUCT_IF6_ALIASREQ_IFRA_LIFETIME
632 addreq
.ifra_lifetime
.ia6t_pltime
= ND6_INFINITE_LIFETIME
;
633 addreq
.ifra_lifetime
.ia6t_vltime
= ND6_INFINITE_LIFETIME
;
636 ret
= if_ioctl_ipv6(SIOCDIFADDR_IN6
, (caddr_t
)&addreq
);
642 /* The old, pre-dataplane code here just returned, so we're retaining that
645 static int if_set_prefix6_ctx(const struct zebra_dplane_ctx
*ctx
)
650 static int if_unset_prefix6_ctx(const struct zebra_dplane_ctx
*ctx
)
654 #endif /* HAVE_STRUCT_IN6_ALIASREQ */
656 #endif /* LINUX_IPV6 */