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"
41 #ifdef HAVE_BSD_LINK_DETECT
42 #include <net/if_media.h>
43 #endif /* HAVE_BSD_LINK_DETECT*/
45 extern struct zebra_privs_t zserv_privs
;
47 /* clear and set interface name string */
48 void ifreq_set_name(struct ifreq
*ifreq
, struct interface
*ifp
)
50 strlcpy(ifreq
->ifr_name
, ifp
->name
, sizeof(ifreq
->ifr_name
));
53 /* call ioctl system call */
54 int if_ioctl(unsigned long request
, caddr_t buffer
)
60 frr_elevate_privs(&zserv_privs
) {
61 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
63 zlog_err("Cannot create UDP socket: %s",
64 safe_strerror(errno
));
67 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_elevate_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_elevate_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)
132 #endif /* ! HAVE_NETLINK */
135 * get interface metric
136 * -- if value is not avaliable set -1
138 void if_get_metric(struct interface
*ifp
)
143 ifreq_set_name(&ifreq
, ifp
);
145 if (vrf_if_ioctl(SIOCGIFMETRIC
, (caddr_t
)&ifreq
,
146 vrf_to_id(ifp
->vrf
)) < 0)
148 ifp
->metric
= ifreq
.ifr_metric
;
149 if (ifp
->metric
== 0)
151 #else /* SIOCGIFMETRIC */
153 #endif /* SIOCGIFMETRIC */
156 /* get interface MTU */
157 void if_get_mtu(struct interface
*ifp
)
161 ifreq_set_name(&ifreq
, ifp
);
163 #if defined(SIOCGIFMTU)
164 if (vrf_if_ioctl(SIOCGIFMTU
, (caddr_t
)&ifreq
,
165 vrf_to_id(ifp
->vrf
)) < 0) {
166 zlog_info("Can't lookup mtu by ioctl(SIOCGIFMTU)");
167 ifp
->mtu6
= ifp
->mtu
= -1;
172 ifp
->mtu6
= ifp
->mtu
= ifreq
.ifr_metric
;
174 ifp
->mtu6
= ifp
->mtu
= ifreq
.ifr_mtu
;
178 zebra_interface_up_update(ifp
);
181 zlog_info("Can't lookup mtu on this system");
182 ifp
->mtu6
= ifp
->mtu
= -1;
187 * Handler for interface address programming via the zebra dplane,
188 * for non-netlink platforms. This handler dispatches to per-platform
189 * helpers, based on the operation requested.
193 /* Prototypes: these are placed in this block so that they're only seen
194 * on non-netlink platforms.
196 static int if_set_prefix_ctx(const struct zebra_dplane_ctx
*ctx
);
197 static int if_unset_prefix_ctx(const struct zebra_dplane_ctx
*ctx
);
198 static int if_set_prefix6_ctx(const struct zebra_dplane_ctx
*ctx
);
199 static int if_unset_prefix6_ctx(const struct zebra_dplane_ctx
*ctx
);
201 enum zebra_dplane_result
kernel_address_update_ctx(
202 struct zebra_dplane_ctx
*ctx
)
205 const struct prefix
*p
;
207 p
= dplane_ctx_get_intf_addr(ctx
);
209 if (dplane_ctx_get_op(ctx
) == DPLANE_OP_ADDR_INSTALL
) {
210 if (p
->family
== AF_INET
)
211 ret
= if_set_prefix_ctx(ctx
);
213 ret
= if_set_prefix6_ctx(ctx
);
214 } else if (dplane_ctx_get_op(ctx
) == DPLANE_OP_ADDR_UNINSTALL
) {
215 if (p
->family
== AF_INET
)
216 ret
= if_unset_prefix_ctx(ctx
);
218 ret
= if_unset_prefix6_ctx(ctx
);
220 if (IS_ZEBRA_DEBUG_DPLANE
)
221 zlog_debug("Invalid op in interface-addr install");
225 ZEBRA_DPLANE_REQUEST_SUCCESS
: ZEBRA_DPLANE_REQUEST_FAILURE
);
228 #endif /* !HAVE_NETLINK */
232 /* TODO -- remove; no use of these apis with netlink any longer */
234 #else /* ! HAVE_NETLINK */
235 #ifdef HAVE_STRUCT_IFALIASREQ
238 * Helper for interface-addr install, non-netlink
240 static int if_set_prefix_ctx(const struct zebra_dplane_ctx
*ctx
)
243 struct ifaliasreq addreq
;
244 struct sockaddr_in addr
, mask
, peer
;
245 struct prefix_ipv4
*p
;
247 p
= (struct prefix_ipv4
*)dplane_ctx_get_intf_addr(ctx
);
249 memset(&addreq
, 0, sizeof(addreq
));
250 strlcpy((char *)&addreq
.ifra_name
, dplane_ctx_get_ifname(ctx
),
251 sizeof(addreq
.ifra_name
));
253 memset(&addr
, 0, sizeof(struct sockaddr_in
));
254 addr
.sin_addr
= p
->prefix
;
255 addr
.sin_family
= p
->family
;
256 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
257 addr
.sin_len
= sizeof(struct sockaddr_in
);
259 memcpy(&addreq
.ifra_addr
, &addr
, sizeof(struct sockaddr_in
));
261 if (dplane_ctx_intf_is_connected(ctx
)) {
262 p
= (struct prefix_ipv4
*)dplane_ctx_get_intf_dest(ctx
);
263 memset(&mask
, 0, sizeof(struct sockaddr_in
));
264 peer
.sin_addr
= p
->prefix
;
265 peer
.sin_family
= p
->family
;
266 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
267 peer
.sin_len
= sizeof(struct sockaddr_in
);
269 memcpy(&addreq
.ifra_broadaddr
, &peer
,
270 sizeof(struct sockaddr_in
));
273 memset(&mask
, 0, sizeof(struct sockaddr_in
));
274 masklen2ip(p
->prefixlen
, &mask
.sin_addr
);
275 mask
.sin_family
= p
->family
;
276 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
277 mask
.sin_len
= sizeof(struct sockaddr_in
);
279 memcpy(&addreq
.ifra_mask
, &mask
, sizeof(struct sockaddr_in
));
281 ret
= if_ioctl(SIOCAIFADDR
, (caddr_t
)&addreq
);
289 * Helper for interface-addr un-install, non-netlink
291 static int if_unset_prefix_ctx(const struct zebra_dplane_ctx
*ctx
)
294 struct ifaliasreq addreq
;
295 struct sockaddr_in addr
, mask
, peer
;
296 struct prefix_ipv4
*p
;
298 p
= (struct prefix_ipv4
*)dplane_ctx_get_intf_addr(ctx
);
300 memset(&addreq
, 0, sizeof(addreq
));
301 strlcpy((char *)&addreq
.ifra_name
, dplane_ctx_get_ifname(ctx
),
302 sizeof(addreq
.ifra_name
));
304 memset(&addr
, 0, sizeof(struct sockaddr_in
));
305 addr
.sin_addr
= p
->prefix
;
306 addr
.sin_family
= p
->family
;
307 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
308 addr
.sin_len
= sizeof(struct sockaddr_in
);
310 memcpy(&addreq
.ifra_addr
, &addr
, sizeof(struct sockaddr_in
));
312 if (dplane_ctx_intf_is_connected(ctx
)) {
313 p
= (struct prefix_ipv4
*)dplane_ctx_get_intf_dest(ctx
);
314 memset(&mask
, 0, sizeof(struct sockaddr_in
));
315 peer
.sin_addr
= p
->prefix
;
316 peer
.sin_family
= p
->family
;
317 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
318 peer
.sin_len
= sizeof(struct sockaddr_in
);
320 memcpy(&addreq
.ifra_broadaddr
, &peer
,
321 sizeof(struct sockaddr_in
));
324 memset(&mask
, 0, sizeof(struct sockaddr_in
));
325 masklen2ip(p
->prefixlen
, &mask
.sin_addr
);
326 mask
.sin_family
= p
->family
;
327 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
328 mask
.sin_len
= sizeof(struct sockaddr_in
);
330 memcpy(&addreq
.ifra_mask
, &mask
, sizeof(struct sockaddr_in
));
332 ret
= if_ioctl(SIOCDIFADDR
, (caddr_t
)&addreq
);
338 /* Set up interface's address, netmask (and broadcas? ). Linux or
339 Solaris uses ifname:number semantics to set IP address aliases. */
340 int if_set_prefix_ctx(const struct zebra_dplane_ctx
*ctx
)
344 struct sockaddr_in addr
;
345 struct sockaddr_in broad
;
346 struct sockaddr_in mask
;
347 struct prefix_ipv4 ifaddr
;
348 struct prefix_ipv4
*p
;
350 p
= (struct prefix_ipv4
*)dplane_ctx_get_intf_addr(ctx
);
354 strlcpy(ifreq
.ifr_name
, dplane_ctx_get_ifname(ctx
),
355 sizeof(ifreq
.ifr_name
));
357 addr
.sin_addr
= p
->prefix
;
358 addr
.sin_family
= p
->family
;
359 memcpy(&ifreq
.ifr_addr
, &addr
, sizeof(struct sockaddr_in
));
360 ret
= if_ioctl(SIOCSIFADDR
, (caddr_t
)&ifreq
);
364 /* We need mask for make broadcast addr. */
365 masklen2ip(p
->prefixlen
, &mask
.sin_addr
);
367 if (dplane_ctx_intf_is_broadcast(ctx
)) {
368 apply_mask_ipv4(&ifaddr
);
369 addr
.sin_addr
= ifaddr
.prefix
;
371 broad
.sin_addr
.s_addr
=
372 (addr
.sin_addr
.s_addr
| ~mask
.sin_addr
.s_addr
);
373 broad
.sin_family
= p
->family
;
375 memcpy(&ifreq
.ifr_broadaddr
, &broad
,
376 sizeof(struct sockaddr_in
));
377 ret
= if_ioctl(SIOCSIFBRDADDR
, (caddr_t
)&ifreq
);
382 mask
.sin_family
= p
->family
;
384 memcpy(&mask
, &ifreq
.ifr_addr
, sizeof(mask
));
386 memcpy(&ifreq
.ifr_addr
, &mask
, sizeof(struct sockaddr_in
));
388 ret
= if_ioctl(SIOCSIFNETMASK
, (caddr_t
)&ifreq
);
395 /* Set up interface's address, netmask (and broadcas? ). Linux or
396 Solaris uses ifname:number semantics to set IP address aliases. */
397 int if_unset_prefix_ctx(const struct zebra_dplane_ctx
*ctx
)
401 struct sockaddr_in addr
;
402 struct prefix_ipv4
*p
;
404 p
= (struct prefix_ipv4
*)dplane_ctx_get_intf_addr(ctx
);
406 strlcpy(ifreq
.ifr_name
, dplane_ctx_get_ifname(ctx
),
407 sizeof(ifreq
.ifr_name
));
409 memset(&addr
, 0, sizeof(struct sockaddr_in
));
410 addr
.sin_family
= p
->family
;
411 memcpy(&ifreq
.ifr_addr
, &addr
, sizeof(struct sockaddr_in
));
412 ret
= if_ioctl(SIOCSIFADDR
, (caddr_t
)&ifreq
);
418 #endif /* HAVE_STRUCT_IFALIASREQ */
419 #endif /* HAVE_NETLINK */
421 /* get interface flags */
422 void if_get_flags(struct interface
*ifp
)
426 #ifdef HAVE_BSD_LINK_DETECT
427 struct ifmediareq ifmr
;
428 #endif /* HAVE_BSD_LINK_DETECT */
430 ifreq_set_name(&ifreq
, ifp
);
432 ret
= vrf_if_ioctl(SIOCGIFFLAGS
, (caddr_t
)&ifreq
, vrf_to_id(ifp
->vrf
));
434 flog_err_sys(EC_LIB_SYSTEM_CALL
,
435 "vrf_if_ioctl(SIOCGIFFLAGS) failed: %s",
436 safe_strerror(errno
));
439 #ifdef HAVE_BSD_LINK_DETECT /* Detect BSD link-state at start-up */
441 /* Per-default, IFF_RUNNING is held high, unless link-detect says
442 * otherwise - we abuse IFF_RUNNING inside zebra as a link-state flag,
443 * following practice on Linux and Solaris kernels
445 SET_FLAG(ifreq
.ifr_flags
, IFF_RUNNING
);
447 if (CHECK_FLAG(ifp
->status
, ZEBRA_INTERFACE_LINKDETECTION
)) {
448 (void)memset(&ifmr
, 0, sizeof(ifmr
));
449 strlcpy(ifmr
.ifm_name
, ifp
->name
, sizeof(ifmr
.ifm_name
));
451 /* Seems not all interfaces implement this ioctl */
452 if (if_ioctl(SIOCGIFMEDIA
, (caddr_t
)&ifmr
) == -1 &&
454 flog_err_sys(EC_LIB_SYSTEM_CALL
,
455 "if_ioctl(SIOCGIFMEDIA) failed: %s",
456 safe_strerror(errno
));
457 else if (ifmr
.ifm_status
& IFM_AVALID
) /* Link state is valid */
459 if (ifmr
.ifm_status
& IFM_ACTIVE
)
460 SET_FLAG(ifreq
.ifr_flags
, IFF_RUNNING
);
462 UNSET_FLAG(ifreq
.ifr_flags
, IFF_RUNNING
);
465 #endif /* HAVE_BSD_LINK_DETECT */
467 if_flags_update(ifp
, (ifreq
.ifr_flags
& 0x0000ffff));
470 /* Set interface flags */
471 int if_set_flags(struct interface
*ifp
, uint64_t flags
)
476 memset(&ifreq
, 0, sizeof(struct ifreq
));
477 ifreq_set_name(&ifreq
, ifp
);
479 ifreq
.ifr_flags
= ifp
->flags
;
480 ifreq
.ifr_flags
|= flags
;
482 ret
= vrf_if_ioctl(SIOCSIFFLAGS
, (caddr_t
)&ifreq
, vrf_to_id(ifp
->vrf
));
485 zlog_info("can't set interface flags");
491 /* Unset interface's flag. */
492 int if_unset_flags(struct interface
*ifp
, uint64_t flags
)
497 memset(&ifreq
, 0, sizeof(struct ifreq
));
498 ifreq_set_name(&ifreq
, ifp
);
500 ifreq
.ifr_flags
= ifp
->flags
;
501 ifreq
.ifr_flags
&= ~flags
;
503 ret
= vrf_if_ioctl(SIOCSIFFLAGS
, (caddr_t
)&ifreq
, vrf_to_id(ifp
->vrf
));
506 zlog_info("can't unset interface flags");
512 #ifndef LINUX_IPV6 /* Netlink has its own code */
514 #ifdef HAVE_STRUCT_IN6_ALIASREQ
515 #ifndef ND6_INFINITE_LIFETIME
516 #define ND6_INFINITE_LIFETIME 0xffffffffL
517 #endif /* ND6_INFINITE_LIFETIME */
520 * Helper for interface-addr install, non-netlink
522 static int if_set_prefix6_ctx(const struct zebra_dplane_ctx
*ctx
)
525 struct in6_aliasreq addreq
;
526 struct sockaddr_in6 addr
;
527 struct sockaddr_in6 mask
;
528 struct prefix_ipv6
*p
;
530 p
= (struct prefix_ipv6
*)dplane_ctx_get_intf_addr(ctx
);
532 memset(&addreq
, 0, sizeof(addreq
));
533 strlcpy((char *)&addreq
.ifra_name
,
534 dplane_ctx_get_ifname(ctx
), sizeof(addreq
.ifra_name
));
536 memset(&addr
, 0, sizeof(struct sockaddr_in6
));
537 addr
.sin6_addr
= p
->prefix
;
538 addr
.sin6_family
= p
->family
;
539 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
540 addr
.sin6_len
= sizeof(struct sockaddr_in6
);
542 memcpy(&addreq
.ifra_addr
, &addr
, sizeof(struct sockaddr_in6
));
544 memset(&mask
, 0, sizeof(struct sockaddr_in6
));
545 masklen2ip6(p
->prefixlen
, &mask
.sin6_addr
);
546 mask
.sin6_family
= p
->family
;
547 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
548 mask
.sin6_len
= sizeof(struct sockaddr_in6
);
550 memcpy(&addreq
.ifra_prefixmask
, &mask
, sizeof(struct sockaddr_in6
));
552 addreq
.ifra_lifetime
.ia6t_vltime
= 0xffffffff;
553 addreq
.ifra_lifetime
.ia6t_pltime
= 0xffffffff;
555 #ifdef HAVE_STRUCT_IF6_ALIASREQ_IFRA_LIFETIME
556 addreq
.ifra_lifetime
.ia6t_pltime
= ND6_INFINITE_LIFETIME
;
557 addreq
.ifra_lifetime
.ia6t_vltime
= ND6_INFINITE_LIFETIME
;
560 ret
= if_ioctl_ipv6(SIOCAIFADDR_IN6
, (caddr_t
)&addreq
);
567 * Helper for interface-addr un-install, non-netlink
569 static int if_unset_prefix6_ctx(const struct zebra_dplane_ctx
*ctx
)
572 struct in6_aliasreq addreq
;
573 struct sockaddr_in6 addr
;
574 struct sockaddr_in6 mask
;
575 struct prefix_ipv6
*p
;
577 p
= (struct prefix_ipv6
*)dplane_ctx_get_intf_addr(ctx
);
579 memset(&addreq
, 0, sizeof(addreq
));
580 strlcpy((char *)&addreq
.ifra_name
,
581 dplane_ctx_get_ifname(ctx
), sizeof(addreq
.ifra_name
));
583 memset(&addr
, 0, sizeof(struct sockaddr_in6
));
584 addr
.sin6_addr
= p
->prefix
;
585 addr
.sin6_family
= p
->family
;
586 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
587 addr
.sin6_len
= sizeof(struct sockaddr_in6
);
589 memcpy(&addreq
.ifra_addr
, &addr
, sizeof(struct sockaddr_in6
));
591 memset(&mask
, 0, sizeof(struct sockaddr_in6
));
592 masklen2ip6(p
->prefixlen
, &mask
.sin6_addr
);
593 mask
.sin6_family
= p
->family
;
594 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
595 mask
.sin6_len
= sizeof(struct sockaddr_in6
);
597 memcpy(&addreq
.ifra_prefixmask
, &mask
, sizeof(struct sockaddr_in6
));
599 #ifdef HAVE_STRUCT_IF6_ALIASREQ_IFRA_LIFETIME
600 addreq
.ifra_lifetime
.ia6t_pltime
= ND6_INFINITE_LIFETIME
;
601 addreq
.ifra_lifetime
.ia6t_vltime
= ND6_INFINITE_LIFETIME
;
604 ret
= if_ioctl_ipv6(SIOCDIFADDR_IN6
, (caddr_t
)&addreq
);
610 /* The old, pre-dataplane code here just returned, so we're retaining that
613 static int if_set_prefix6_ctx(const struct zebra_dplane_ctx
*ctx
)
618 static int if_unset_prefix6_ctx(const struct zebra_dplane_ctx
*ctx
)
622 #endif /* HAVE_STRUCT_IN6_ALIASREQ */
624 #endif /* LINUX_IPV6 */
626 #endif /* !SUNOS_5 */