2 * Common ioctl functions for Solaris.
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
34 #include "lib_errors.h"
36 #include "zebra/rib.h"
38 #include "zebra/interface.h"
39 #include "zebra/ioctl_solaris.h"
40 #include "zebra/zebra_errors.h"
41 #include "zebra/debug.h"
43 extern struct zebra_privs_t zserv_privs
;
46 static int if_set_prefix_ctx(const struct zebra_dplane_ctx
*ctx
);
47 static int if_unset_prefix_ctx(const struct zebra_dplane_ctx
*ctx
);
48 static int if_set_prefix6_ctx(const struct zebra_dplane_ctx
*ctx
);
49 static int if_unset_prefix6_ctx(const struct zebra_dplane_ctx
*ctx
);
51 /* clear and set interface name string */
52 void lifreq_set_name(struct lifreq
*lifreq
, const char *ifname
)
54 strlcpy(lifreq
->lifr_name
, ifname
, sizeof(lifreq
->lifr_name
));
57 int vrf_if_ioctl(unsigned long request
, caddr_t buffer
, vrf_id_t vrf_id
)
59 return if_ioctl(request
, buffer
);
62 /* call ioctl system call */
63 int if_ioctl(unsigned long request
, caddr_t buffer
)
69 frr_with_privs(&zserv_privs
) {
71 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
73 zlog_err("Cannot create UDP socket: %s",
74 safe_strerror(errno
));
78 if ((ret
= ioctl(sock
, request
, buffer
)) < 0)
93 int if_ioctl_ipv6(unsigned long request
, caddr_t buffer
)
99 frr_with_privs(&zserv_privs
) {
101 sock
= socket(AF_INET6
, SOCK_DGRAM
, 0);
103 zlog_err("Cannot create IPv6 datagram socket: %s",
104 safe_strerror(errno
));
108 if ((ret
= ioctl(sock
, request
, buffer
)) < 0)
124 * get interface metric
125 * -- if value is not avaliable set -1
127 void if_get_metric(struct interface
*ifp
)
129 struct lifreq lifreq
;
132 lifreq_set_name(&lifreq
, ifp
->name
);
134 if (ifp
->flags
& IFF_IPV4
)
135 ret
= AF_IOCTL(AF_INET
, SIOCGLIFMETRIC
, (caddr_t
)&lifreq
);
137 else if (ifp
->flags
& IFF_IPV6
)
138 ret
= AF_IOCTL(AF_INET6
, SIOCGLIFMETRIC
, (caddr_t
)&lifreq
);
139 #endif /* SOLARIS_IPV6 */
146 ifp
->metric
= lifreq
.lifr_metric
;
148 if (ifp
->metric
== 0)
152 /* get interface MTU */
153 void if_get_mtu(struct interface
*ifp
)
155 struct lifreq lifreq
;
159 if (ifp
->flags
& IFF_IPV4
) {
160 lifreq_set_name(&lifreq
, ifp
->name
);
161 ret
= AF_IOCTL(AF_INET
, SIOCGLIFMTU
, (caddr_t
)&lifreq
);
164 "Can't lookup mtu on %s by ioctl(SIOCGLIFMTU)",
168 ifp
->mtu
= lifreq
.lifr_metric
;
173 if (ifp
->flags
& IFF_IPV6
) {
174 memset(&lifreq
, 0, sizeof(lifreq
));
175 lifreq_set_name(&lifreq
, ifp
->name
);
177 ret
= AF_IOCTL(AF_INET6
, SIOCGLIFMTU
, (caddr_t
)&lifreq
);
180 "Can't lookup mtu6 on %s by ioctl(SIOCGIFMTU)",
184 ifp
->mtu6
= lifreq
.lifr_metric
;
190 zebra_interface_up_update(ifp
);
196 enum zebra_dplane_result
kernel_address_update_ctx(
197 struct zebra_dplane_ctx
*ctx
)
200 const struct prefix
*p
;
202 p
= dplane_ctx_get_intf_addr(ctx
);
204 if (dplane_ctx_get_op(ctx
) == DPLANE_OP_ADDR_INSTALL
) {
205 if (p
->family
== AF_INET
)
206 ret
= if_set_prefix_ctx(ctx
);
208 ret
= if_set_prefix6_ctx(ctx
);
209 } else if (dplane_ctx_get_op(ctx
) == DPLANE_OP_ADDR_UNINSTALL
) {
210 if (p
->family
== AF_INET
)
211 ret
= if_unset_prefix_ctx(ctx
);
213 ret
= if_unset_prefix6_ctx(ctx
);
215 if (IS_ZEBRA_DEBUG_DPLANE
)
216 zlog_debug("Invalid op in interface-addr install");
220 ZEBRA_DPLANE_REQUEST_SUCCESS
: ZEBRA_DPLANE_REQUEST_FAILURE
);
223 /* Set up interface's address, netmask (and broadcast? ).
224 Solaris uses ifname:number semantics to set IP address aliases. */
225 static int if_set_prefix_ctx(const struct zebra_dplane_ctx
*ctx
)
229 struct sockaddr_in addr
, broad
, mask
;
230 struct prefix_ipv4 ifaddr
;
231 struct prefix_ipv4
*p
;
233 p
= (struct prefix_ipv4
*)dplane_ctx_get_intf_addr(ctx
);
237 strlcpy(ifreq
.ifr_name
, dplane_ctx_get_ifname(ctx
),
238 sizeof(ifreq
.ifr_name
));
240 addr
.sin_addr
= p
->prefix
;
241 addr
.sin_family
= p
->family
;
242 memcpy(&ifreq
.ifr_addr
, &addr
, sizeof(struct sockaddr_in
));
244 ret
= if_ioctl(SIOCSIFADDR
, (caddr_t
)&ifreq
);
249 /* We need mask for make broadcast addr. */
250 masklen2ip(p
->prefixlen
, &mask
.sin_addr
);
252 if (dplane_ctx_intf_is_broadcast(ctx
)) {
253 apply_mask_ipv4(&ifaddr
);
254 addr
.sin_addr
= ifaddr
.prefix
;
256 broad
.sin_addr
.s_addr
=
257 (addr
.sin_addr
.s_addr
| ~mask
.sin_addr
.s_addr
);
258 broad
.sin_family
= p
->family
;
260 memcpy(&ifreq
.ifr_broadaddr
, &broad
,
261 sizeof(struct sockaddr_in
));
262 ret
= if_ioctl(SIOCSIFBRDADDR
, (caddr_t
)&ifreq
);
267 mask
.sin_family
= p
->family
;
269 memcpy(&mask
, &ifreq
.ifr_addr
, sizeof(mask
));
271 memcpy(&ifreq
.ifr_netmask
, &mask
, sizeof(struct sockaddr_in
));
273 ret
= if_ioctl(SIOCSIFNETMASK
, (caddr_t
)&ifreq
);
275 return ((ret
< 0) ? ret
: 0);
278 /* Set up interface's address, netmask (and broadcast).
279 Solaris uses ifname:number semantics to set IP address aliases. */
280 static int if_unset_prefix_ctx(const struct zebra_dplane_ctx
*ctx
)
284 struct sockaddr_in addr
;
285 struct prefix_ipv4
*p
;
287 p
= (struct prefix_ipv4
*)dplane_ctx_get_intf_addr(ctx
);
289 strlcpy(ifreq
.ifr_name
, dplane_ctx_get_ifname(ctx
),
290 sizeof(ifreq
.ifr_name
));
292 memset(&addr
, 0, sizeof(struct sockaddr_in
));
293 addr
.sin_family
= p
->family
;
294 memcpy(&ifreq
.ifr_addr
, &addr
, sizeof(struct sockaddr_in
));
296 ret
= if_ioctl(SIOCSIFADDR
, (caddr_t
)&ifreq
);
304 /* Get just the flags for the given name.
305 * Used by the normal 'if_get_flags' function, as well
306 * as the bootup interface-list code, which has to peek at per-address
307 * flags in order to figure out which ones should be ignored..
309 int if_get_flags_direct(const char *ifname
, uint64_t *flags
, unsigned int af
)
311 struct lifreq lifreq
;
314 lifreq_set_name(&lifreq
, ifname
);
316 ret
= AF_IOCTL(af
, SIOCGLIFFLAGS
, (caddr_t
)&lifreq
);
319 zlog_debug("%s: ifname %s, error %s (%d)", __func__
, ifname
,
320 safe_strerror(errno
), errno
);
322 *flags
= lifreq
.lifr_flags
;
327 /* get interface flags */
328 void if_get_flags(struct interface
*ifp
)
330 int ret4
= 0, ret6
= 0;
331 uint64_t newflags
= 0;
334 if (ifp
->flags
& IFF_IPV4
) {
335 ret4
= if_get_flags_direct(ifp
->name
, &tmpflags
, AF_INET
);
338 newflags
|= tmpflags
;
339 else if (errno
== ENXIO
) {
341 UNSET_FLAG(ifp
->flags
, IFF_UP
);
342 if_flags_update(ifp
, ifp
->flags
);
346 if (ifp
->flags
& IFF_IPV6
) {
347 ret6
= if_get_flags_direct(ifp
->name
, &tmpflags
, AF_INET6
);
350 newflags
|= tmpflags
;
351 else if (errno
== ENXIO
) {
353 UNSET_FLAG(ifp
->flags
, IFF_UP
);
354 if_flags_update(ifp
, ifp
->flags
);
358 /* only update flags if one of above succeeded */
360 if_flags_update(ifp
, newflags
);
363 /* Set interface flags */
364 int if_set_flags(struct interface
*ifp
, uint64_t flags
)
367 struct lifreq lifreq
;
369 lifreq_set_name(&lifreq
, ifp
->name
);
371 lifreq
.lifr_flags
= ifp
->flags
;
372 lifreq
.lifr_flags
|= flags
;
374 if (ifp
->flags
& IFF_IPV4
)
375 ret
= AF_IOCTL(AF_INET
, SIOCSLIFFLAGS
, (caddr_t
)&lifreq
);
376 else if (ifp
->flags
& IFF_IPV6
)
377 ret
= AF_IOCTL(AF_INET6
, SIOCSLIFFLAGS
, (caddr_t
)&lifreq
);
382 zlog_info("can't set interface flags on %s: %s", ifp
->name
,
383 safe_strerror(errno
));
390 /* Unset interface's flag. */
391 int if_unset_flags(struct interface
*ifp
, uint64_t flags
)
394 struct lifreq lifreq
;
396 lifreq_set_name(&lifreq
, ifp
->name
);
398 lifreq
.lifr_flags
= ifp
->flags
;
399 lifreq
.lifr_flags
&= ~flags
;
401 if (ifp
->flags
& IFF_IPV4
)
402 ret
= AF_IOCTL(AF_INET
, SIOCSLIFFLAGS
, (caddr_t
)&lifreq
);
403 else if (ifp
->flags
& IFF_IPV6
)
404 ret
= AF_IOCTL(AF_INET6
, SIOCSLIFFLAGS
, (caddr_t
)&lifreq
);
409 zlog_info("can't unset interface flags");
416 /* Interface's address add/delete functions. */
417 static int if_set_prefix6_ctx(const struct zebra_dplane_ctx
*ctx
)
419 char addrbuf
[PREFIX_STRLEN
];
421 prefix2str(dplane_ctx_get_intf_addr(ctx
), addrbuf
, sizeof(addrbuf
));
423 flog_warn(EC_LIB_DEVELOPMENT
, "Can't set %s on interface %s",
424 addrbuf
, dplane_ctx_get_ifname(ctx
));
429 static int if_unset_prefix6_ctx(const struct zebra_dplane_ctx
*ctx
)
431 char addrbuf
[PREFIX_STRLEN
];
433 prefix2str(dplane_ctx_get_intf_addr(ctx
), addrbuf
, sizeof(addrbuf
));
435 flog_warn(EC_LIB_DEVELOPMENT
, "Can't delete %s on interface %s",
436 addrbuf
, dplane_ctx_get_ifname(ctx
));