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
, ifp
->vrf_id
) < 0)
147 ifp
->metric
= ifreq
.ifr_metric
;
148 if (ifp
->metric
== 0)
150 #else /* SIOCGIFMETRIC */
152 #endif /* SIOCGIFMETRIC */
155 /* get interface MTU */
156 void if_get_mtu(struct interface
*ifp
)
160 ifreq_set_name(&ifreq
, ifp
);
162 #if defined(SIOCGIFMTU)
163 if (vrf_if_ioctl(SIOCGIFMTU
, (caddr_t
)&ifreq
, ifp
->vrf_id
) < 0) {
164 zlog_info("Can't lookup mtu by ioctl(SIOCGIFMTU)");
165 ifp
->mtu6
= ifp
->mtu
= -1;
170 ifp
->mtu6
= ifp
->mtu
= ifreq
.ifr_metric
;
172 ifp
->mtu6
= ifp
->mtu
= ifreq
.ifr_mtu
;
176 zebra_interface_up_update(ifp
);
179 zlog_info("Can't lookup mtu on this system");
180 ifp
->mtu6
= ifp
->mtu
= -1;
185 * Handler for interface address programming via the zebra dplane,
186 * for non-netlink platforms. This handler dispatches to per-platform
187 * helpers, based on the operation requested.
191 /* Prototypes: these are placed in this block so that they're only seen
192 * on non-netlink platforms.
194 static int if_set_prefix_ctx(const struct zebra_dplane_ctx
*ctx
);
195 static int if_unset_prefix_ctx(const struct zebra_dplane_ctx
*ctx
);
196 static int if_set_prefix6_ctx(const struct zebra_dplane_ctx
*ctx
);
197 static int if_unset_prefix6_ctx(const struct zebra_dplane_ctx
*ctx
);
199 enum zebra_dplane_result
kernel_address_update_ctx(
200 struct zebra_dplane_ctx
*ctx
)
203 const struct prefix
*p
;
205 p
= dplane_ctx_get_intf_addr(ctx
);
207 if (dplane_ctx_get_op(ctx
) == DPLANE_OP_ADDR_INSTALL
) {
208 if (p
->family
== AF_INET
)
209 ret
= if_set_prefix_ctx(ctx
);
211 ret
= if_set_prefix6_ctx(ctx
);
212 } else if (dplane_ctx_get_op(ctx
) == DPLANE_OP_ADDR_UNINSTALL
) {
213 if (p
->family
== AF_INET
)
214 ret
= if_unset_prefix_ctx(ctx
);
216 ret
= if_unset_prefix6_ctx(ctx
);
218 if (IS_ZEBRA_DEBUG_DPLANE
)
219 zlog_debug("Invalid op in interface-addr install");
223 ZEBRA_DPLANE_REQUEST_SUCCESS
: ZEBRA_DPLANE_REQUEST_FAILURE
);
226 #endif /* !HAVE_NETLINK */
230 /* TODO -- remove; no use of these apis with netlink any longer */
232 #else /* ! HAVE_NETLINK */
233 #ifdef HAVE_STRUCT_IFALIASREQ
236 * Helper for interface-addr install, non-netlink
238 static int if_set_prefix_ctx(const struct zebra_dplane_ctx
*ctx
)
241 struct ifaliasreq addreq
;
242 struct sockaddr_in addr
, mask
, peer
;
243 struct prefix_ipv4
*p
;
245 p
= (struct prefix_ipv4
*)dplane_ctx_get_intf_addr(ctx
);
247 memset(&addreq
, 0, sizeof(addreq
));
248 strlcpy((char *)&addreq
.ifra_name
, dplane_ctx_get_ifname(ctx
),
249 sizeof(addreq
.ifra_name
));
251 memset(&addr
, 0, sizeof(struct sockaddr_in
));
252 addr
.sin_addr
= p
->prefix
;
253 addr
.sin_family
= p
->family
;
254 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
255 addr
.sin_len
= sizeof(struct sockaddr_in
);
257 memcpy(&addreq
.ifra_addr
, &addr
, sizeof(struct sockaddr_in
));
259 if (dplane_ctx_intf_is_connected(ctx
)) {
260 p
= (struct prefix_ipv4
*)dplane_ctx_get_intf_dest(ctx
);
261 memset(&mask
, 0, sizeof(struct sockaddr_in
));
262 peer
.sin_addr
= p
->prefix
;
263 peer
.sin_family
= p
->family
;
264 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
265 peer
.sin_len
= sizeof(struct sockaddr_in
);
267 memcpy(&addreq
.ifra_broadaddr
, &peer
,
268 sizeof(struct sockaddr_in
));
271 memset(&mask
, 0, sizeof(struct sockaddr_in
));
272 masklen2ip(p
->prefixlen
, &mask
.sin_addr
);
273 mask
.sin_family
= p
->family
;
274 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
275 mask
.sin_len
= sizeof(struct sockaddr_in
);
277 memcpy(&addreq
.ifra_mask
, &mask
, sizeof(struct sockaddr_in
));
279 ret
= if_ioctl(SIOCAIFADDR
, (caddr_t
)&addreq
);
287 * Helper for interface-addr un-install, non-netlink
289 static int if_unset_prefix_ctx(const struct zebra_dplane_ctx
*ctx
)
292 struct ifaliasreq addreq
;
293 struct sockaddr_in addr
, mask
, peer
;
294 struct prefix_ipv4
*p
;
296 p
= (struct prefix_ipv4
*)dplane_ctx_get_intf_addr(ctx
);
298 memset(&addreq
, 0, sizeof(addreq
));
299 strlcpy((char *)&addreq
.ifra_name
, dplane_ctx_get_ifname(ctx
),
300 sizeof(addreq
.ifra_name
));
302 memset(&addr
, 0, sizeof(struct sockaddr_in
));
303 addr
.sin_addr
= p
->prefix
;
304 addr
.sin_family
= p
->family
;
305 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
306 addr
.sin_len
= sizeof(struct sockaddr_in
);
308 memcpy(&addreq
.ifra_addr
, &addr
, sizeof(struct sockaddr_in
));
310 if (dplane_ctx_intf_is_connected(ctx
)) {
311 p
= (struct prefix_ipv4
*)dplane_ctx_get_intf_dest(ctx
);
312 memset(&mask
, 0, sizeof(struct sockaddr_in
));
313 peer
.sin_addr
= p
->prefix
;
314 peer
.sin_family
= p
->family
;
315 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
316 peer
.sin_len
= sizeof(struct sockaddr_in
);
318 memcpy(&addreq
.ifra_broadaddr
, &peer
,
319 sizeof(struct sockaddr_in
));
322 memset(&mask
, 0, sizeof(struct sockaddr_in
));
323 masklen2ip(p
->prefixlen
, &mask
.sin_addr
);
324 mask
.sin_family
= p
->family
;
325 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
326 mask
.sin_len
= sizeof(struct sockaddr_in
);
328 memcpy(&addreq
.ifra_mask
, &mask
, sizeof(struct sockaddr_in
));
330 ret
= if_ioctl(SIOCDIFADDR
, (caddr_t
)&addreq
);
336 /* Set up interface's address, netmask (and broadcas? ). Linux or
337 Solaris uses ifname:number semantics to set IP address aliases. */
338 int if_set_prefix_ctx(const struct zebra_dplane_ctx
*ctx
)
342 struct sockaddr_in addr
;
343 struct sockaddr_in broad
;
344 struct sockaddr_in mask
;
345 struct prefix_ipv4 ifaddr
;
346 struct prefix_ipv4
*p
;
348 p
= (struct prefix_ipv4
*)dplane_ctx_get_intf_addr(ctx
);
352 strlcpy(ifreq
.ifr_name
, dplane_ctx_get_ifname(ctx
),
353 sizeof(ifreq
.ifr_name
));
355 addr
.sin_addr
= p
->prefix
;
356 addr
.sin_family
= p
->family
;
357 memcpy(&ifreq
.ifr_addr
, &addr
, sizeof(struct sockaddr_in
));
358 ret
= if_ioctl(SIOCSIFADDR
, (caddr_t
)&ifreq
);
362 /* We need mask for make broadcast addr. */
363 masklen2ip(p
->prefixlen
, &mask
.sin_addr
);
365 if (dplane_ctx_intf_is_broadcast(ctx
)) {
366 apply_mask_ipv4(&ifaddr
);
367 addr
.sin_addr
= ifaddr
.prefix
;
369 broad
.sin_addr
.s_addr
=
370 (addr
.sin_addr
.s_addr
| ~mask
.sin_addr
.s_addr
);
371 broad
.sin_family
= p
->family
;
373 memcpy(&ifreq
.ifr_broadaddr
, &broad
,
374 sizeof(struct sockaddr_in
));
375 ret
= if_ioctl(SIOCSIFBRDADDR
, (caddr_t
)&ifreq
);
380 mask
.sin_family
= p
->family
;
382 memcpy(&mask
, &ifreq
.ifr_addr
, sizeof(mask
));
384 memcpy(&ifreq
.ifr_addr
, &mask
, sizeof(struct sockaddr_in
));
386 ret
= if_ioctl(SIOCSIFNETMASK
, (caddr_t
)&ifreq
);
393 /* Set up interface's address, netmask (and broadcas? ). Linux or
394 Solaris uses ifname:number semantics to set IP address aliases. */
395 int if_unset_prefix_ctx(const struct zebra_dplane_ctx
*ctx
)
399 struct sockaddr_in addr
;
400 struct prefix_ipv4
*p
;
402 p
= (struct prefix_ipv4
*)dplane_ctx_get_intf_addr(ctx
);
404 strlcpy(ifreq
.ifr_name
, dplane_ctx_get_ifname(ctx
),
405 sizeof(ifreq
.ifr_name
));
407 memset(&addr
, 0, sizeof(struct sockaddr_in
));
408 addr
.sin_family
= p
->family
;
409 memcpy(&ifreq
.ifr_addr
, &addr
, sizeof(struct sockaddr_in
));
410 ret
= if_ioctl(SIOCSIFADDR
, (caddr_t
)&ifreq
);
416 #endif /* HAVE_STRUCT_IFALIASREQ */
417 #endif /* HAVE_NETLINK */
419 /* get interface flags */
420 void if_get_flags(struct interface
*ifp
)
424 #ifdef HAVE_BSD_LINK_DETECT
425 struct ifmediareq ifmr
;
426 #endif /* HAVE_BSD_LINK_DETECT */
428 ifreq_set_name(&ifreq
, ifp
);
430 ret
= vrf_if_ioctl(SIOCGIFFLAGS
, (caddr_t
)&ifreq
, ifp
->vrf_id
);
432 flog_err_sys(EC_LIB_SYSTEM_CALL
,
433 "vrf_if_ioctl(SIOCGIFFLAGS) failed: %s",
434 safe_strerror(errno
));
437 #ifdef HAVE_BSD_LINK_DETECT /* Detect BSD link-state at start-up */
439 /* Per-default, IFF_RUNNING is held high, unless link-detect says
440 * otherwise - we abuse IFF_RUNNING inside zebra as a link-state flag,
441 * following practice on Linux and Solaris kernels
443 SET_FLAG(ifreq
.ifr_flags
, IFF_RUNNING
);
445 if (CHECK_FLAG(ifp
->status
, ZEBRA_INTERFACE_LINKDETECTION
)) {
446 (void)memset(&ifmr
, 0, sizeof(ifmr
));
447 strlcpy(ifmr
.ifm_name
, ifp
->name
, sizeof(ifmr
.ifm_name
));
449 /* Seems not all interfaces implement this ioctl */
450 if (if_ioctl(SIOCGIFMEDIA
, (caddr_t
)&ifmr
) == -1 &&
452 flog_err_sys(EC_LIB_SYSTEM_CALL
,
453 "if_ioctl(SIOCGIFMEDIA) failed: %s",
454 safe_strerror(errno
));
455 else if (ifmr
.ifm_status
& IFM_AVALID
) /* Link state is valid */
457 if (ifmr
.ifm_status
& IFM_ACTIVE
)
458 SET_FLAG(ifreq
.ifr_flags
, IFF_RUNNING
);
460 UNSET_FLAG(ifreq
.ifr_flags
, IFF_RUNNING
);
463 #endif /* HAVE_BSD_LINK_DETECT */
465 if_flags_update(ifp
, (ifreq
.ifr_flags
& 0x0000ffff));
468 /* Set interface flags */
469 int if_set_flags(struct interface
*ifp
, uint64_t flags
)
474 memset(&ifreq
, 0, sizeof(struct ifreq
));
475 ifreq_set_name(&ifreq
, ifp
);
477 ifreq
.ifr_flags
= ifp
->flags
;
478 ifreq
.ifr_flags
|= flags
;
480 ret
= vrf_if_ioctl(SIOCSIFFLAGS
, (caddr_t
)&ifreq
, ifp
->vrf_id
);
483 zlog_info("can't set interface flags");
489 /* Unset interface's flag. */
490 int if_unset_flags(struct interface
*ifp
, uint64_t flags
)
495 memset(&ifreq
, 0, sizeof(struct ifreq
));
496 ifreq_set_name(&ifreq
, ifp
);
498 ifreq
.ifr_flags
= ifp
->flags
;
499 ifreq
.ifr_flags
&= ~flags
;
501 ret
= vrf_if_ioctl(SIOCSIFFLAGS
, (caddr_t
)&ifreq
, ifp
->vrf_id
);
504 zlog_info("can't unset interface flags");
510 #ifndef LINUX_IPV6 /* Netlink has its own code */
512 #ifdef HAVE_STRUCT_IN6_ALIASREQ
513 #ifndef ND6_INFINITE_LIFETIME
514 #define ND6_INFINITE_LIFETIME 0xffffffffL
515 #endif /* ND6_INFINITE_LIFETIME */
518 * Helper for interface-addr install, non-netlink
520 static int if_set_prefix6_ctx(const struct zebra_dplane_ctx
*ctx
)
523 struct in6_aliasreq addreq
;
524 struct sockaddr_in6 addr
;
525 struct sockaddr_in6 mask
;
526 struct prefix_ipv6
*p
;
528 p
= (struct prefix_ipv6
*)dplane_ctx_get_intf_addr(ctx
);
530 memset(&addreq
, 0, sizeof(addreq
));
531 strlcpy((char *)&addreq
.ifra_name
,
532 dplane_ctx_get_ifname(ctx
), sizeof(addreq
.ifra_name
));
534 memset(&addr
, 0, sizeof(struct sockaddr_in6
));
535 addr
.sin6_addr
= p
->prefix
;
536 addr
.sin6_family
= p
->family
;
537 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
538 addr
.sin6_len
= sizeof(struct sockaddr_in6
);
540 memcpy(&addreq
.ifra_addr
, &addr
, sizeof(struct sockaddr_in6
));
542 memset(&mask
, 0, sizeof(struct sockaddr_in6
));
543 masklen2ip6(p
->prefixlen
, &mask
.sin6_addr
);
544 mask
.sin6_family
= p
->family
;
545 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
546 mask
.sin6_len
= sizeof(struct sockaddr_in6
);
548 memcpy(&addreq
.ifra_prefixmask
, &mask
, sizeof(struct sockaddr_in6
));
550 addreq
.ifra_lifetime
.ia6t_vltime
= 0xffffffff;
551 addreq
.ifra_lifetime
.ia6t_pltime
= 0xffffffff;
553 #ifdef HAVE_STRUCT_IF6_ALIASREQ_IFRA_LIFETIME
554 addreq
.ifra_lifetime
.ia6t_pltime
= ND6_INFINITE_LIFETIME
;
555 addreq
.ifra_lifetime
.ia6t_vltime
= ND6_INFINITE_LIFETIME
;
558 ret
= if_ioctl_ipv6(SIOCAIFADDR_IN6
, (caddr_t
)&addreq
);
565 * Helper for interface-addr un-install, non-netlink
567 static int if_unset_prefix6_ctx(const struct zebra_dplane_ctx
*ctx
)
570 struct in6_aliasreq addreq
;
571 struct sockaddr_in6 addr
;
572 struct sockaddr_in6 mask
;
573 struct prefix_ipv6
*p
;
575 p
= (struct prefix_ipv6
*)dplane_ctx_get_intf_addr(ctx
);
577 memset(&addreq
, 0, sizeof(addreq
));
578 strlcpy((char *)&addreq
.ifra_name
,
579 dplane_ctx_get_ifname(ctx
), sizeof(addreq
.ifra_name
));
581 memset(&addr
, 0, sizeof(struct sockaddr_in6
));
582 addr
.sin6_addr
= p
->prefix
;
583 addr
.sin6_family
= p
->family
;
584 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
585 addr
.sin6_len
= sizeof(struct sockaddr_in6
);
587 memcpy(&addreq
.ifra_addr
, &addr
, sizeof(struct sockaddr_in6
));
589 memset(&mask
, 0, sizeof(struct sockaddr_in6
));
590 masklen2ip6(p
->prefixlen
, &mask
.sin6_addr
);
591 mask
.sin6_family
= p
->family
;
592 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
593 mask
.sin6_len
= sizeof(struct sockaddr_in6
);
595 memcpy(&addreq
.ifra_prefixmask
, &mask
, sizeof(struct sockaddr_in6
));
597 #ifdef HAVE_STRUCT_IF6_ALIASREQ_IFRA_LIFETIME
598 addreq
.ifra_lifetime
.ia6t_pltime
= ND6_INFINITE_LIFETIME
;
599 addreq
.ifra_lifetime
.ia6t_vltime
= ND6_INFINITE_LIFETIME
;
602 ret
= if_ioctl_ipv6(SIOCDIFADDR_IN6
, (caddr_t
)&addreq
);
608 /* The old, pre-dataplane code here just returned, so we're retaining that
611 static int if_set_prefix6_ctx(const struct zebra_dplane_ctx
*ctx
)
616 static int if_unset_prefix6_ctx(const struct zebra_dplane_ctx
*ctx
)
620 #endif /* HAVE_STRUCT_IN6_ALIASREQ */
622 #endif /* LINUX_IPV6 */
624 #endif /* !SUNOS_5 */