]>
Commit | Line | Data |
---|---|---|
718e3744 | 1 | /* |
2 | * Common ioctl functions. | |
3 | * Copyright (C) 1997, 98 Kunihiro Ishiguro | |
4 | * | |
5 | * This file is part of GNU Zebra. | |
6 | * | |
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 | |
10 | * later version. | |
11 | * | |
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. | |
16 | * | |
896014f4 DL |
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 | |
718e3744 | 20 | */ |
21 | ||
22 | #include <zebra.h> | |
23 | ||
24 | #include "linklist.h" | |
25 | #include "if.h" | |
26 | #include "prefix.h" | |
27 | #include "ioctl.h" | |
28 | #include "log.h" | |
edd7c245 | 29 | #include "privs.h" |
174482ef | 30 | #include "lib_errors.h" |
718e3744 | 31 | |
5e6a74d8 | 32 | #include "vty.h" |
718e3744 | 33 | #include "zebra/rib.h" |
34 | #include "zebra/rt.h" | |
5c78b3d0 | 35 | #include "zebra/interface.h" |
364fed6b | 36 | #include "zebra/zebra_errors.h" |
0f1f6ce4 | 37 | #include "zebra/debug.h" |
718e3744 | 38 | |
55edb0d4 AS |
39 | #ifdef HAVE_BSD_LINK_DETECT |
40 | #include <net/if_media.h> | |
41 | #endif /* HAVE_BSD_LINK_DETECT*/ | |
42 | ||
edd7c245 | 43 | extern struct zebra_privs_t zserv_privs; |
44 | ||
718e3744 | 45 | /* clear and set interface name string */ |
d62a17ae | 46 | void ifreq_set_name(struct ifreq *ifreq, struct interface *ifp) |
718e3744 | 47 | { |
0af35d90 | 48 | strlcpy(ifreq->ifr_name, ifp->name, sizeof(ifreq->ifr_name)); |
718e3744 | 49 | } |
50 | ||
51 | /* call ioctl system call */ | |
d7c0a89a | 52 | int if_ioctl(unsigned long request, caddr_t buffer) |
718e3744 | 53 | { |
d62a17ae | 54 | int sock; |
55 | int ret; | |
56 | int err = 0; | |
57 | ||
0cf6db21 | 58 | frr_with_privs(&zserv_privs) { |
01b9e3fd DL |
59 | sock = socket(AF_INET, SOCK_DGRAM, 0); |
60 | if (sock < 0) { | |
61 | zlog_err("Cannot create UDP socket: %s", | |
62 | safe_strerror(errno)); | |
63 | exit(1); | |
64 | } | |
65 | if ((ret = ioctl(sock, request, buffer)) < 0) | |
66 | err = errno; | |
d62a17ae | 67 | } |
d62a17ae | 68 | close(sock); |
69 | ||
70 | if (ret < 0) { | |
71 | errno = err; | |
72 | return ret; | |
73 | } | |
74 | return 0; | |
718e3744 | 75 | } |
76 | ||
4db21619 | 77 | /* call ioctl system call */ |
d7c0a89a | 78 | int vrf_if_ioctl(unsigned long request, caddr_t buffer, vrf_id_t vrf_id) |
4db21619 PG |
79 | { |
80 | int sock; | |
81 | int ret; | |
82 | int err = 0; | |
83 | ||
0cf6db21 | 84 | frr_with_privs(&zserv_privs) { |
01b9e3fd DL |
85 | sock = vrf_socket(AF_INET, SOCK_DGRAM, 0, vrf_id, NULL); |
86 | if (sock < 0) { | |
87 | zlog_err("Cannot create UDP socket: %s", | |
88 | safe_strerror(errno)); | |
89 | exit(1); | |
90 | } | |
91 | ret = vrf_ioctl(vrf_id, sock, request, buffer); | |
92 | if (ret < 0) | |
93 | err = errno; | |
4db21619 | 94 | } |
4db21619 PG |
95 | close(sock); |
96 | ||
97 | if (ret < 0) { | |
98 | errno = err; | |
99 | return ret; | |
100 | } | |
101 | return 0; | |
102 | } | |
103 | ||
e86b71f1 | 104 | #ifndef HAVE_NETLINK |
d7c0a89a | 105 | static int if_ioctl_ipv6(unsigned long request, caddr_t buffer) |
718e3744 | 106 | { |
d62a17ae | 107 | int sock; |
108 | int ret; | |
109 | int err = 0; | |
110 | ||
0cf6db21 | 111 | frr_with_privs(&zserv_privs) { |
01b9e3fd DL |
112 | sock = socket(AF_INET6, SOCK_DGRAM, 0); |
113 | if (sock < 0) { | |
114 | zlog_err("Cannot create IPv6 datagram socket: %s", | |
115 | safe_strerror(errno)); | |
116 | exit(1); | |
117 | } | |
d62a17ae | 118 | |
01b9e3fd DL |
119 | if ((ret = ioctl(sock, request, buffer)) < 0) |
120 | err = errno; | |
121 | } | |
d62a17ae | 122 | close(sock); |
123 | ||
124 | if (ret < 0) { | |
125 | errno = err; | |
126 | return ret; | |
127 | } | |
128 | return 0; | |
718e3744 | 129 | } |
e86b71f1 | 130 | #endif /* ! HAVE_NETLINK */ |
718e3744 | 131 | |
132 | /* | |
133 | * get interface metric | |
134 | * -- if value is not avaliable set -1 | |
135 | */ | |
d62a17ae | 136 | void if_get_metric(struct interface *ifp) |
718e3744 | 137 | { |
138 | #ifdef SIOCGIFMETRIC | |
d62a17ae | 139 | struct ifreq ifreq; |
718e3744 | 140 | |
d62a17ae | 141 | ifreq_set_name(&ifreq, ifp); |
718e3744 | 142 | |
a36898e7 | 143 | if (vrf_if_ioctl(SIOCGIFMETRIC, (caddr_t)&ifreq, ifp->vrf_id) < 0) |
d62a17ae | 144 | return; |
145 | ifp->metric = ifreq.ifr_metric; | |
146 | if (ifp->metric == 0) | |
147 | ifp->metric = 1; | |
148 | #else /* SIOCGIFMETRIC */ | |
149 | ifp->metric = -1; | |
718e3744 | 150 | #endif /* SIOCGIFMETRIC */ |
151 | } | |
152 | ||
153 | /* get interface MTU */ | |
d62a17ae | 154 | void if_get_mtu(struct interface *ifp) |
718e3744 | 155 | { |
d62a17ae | 156 | struct ifreq ifreq; |
718e3744 | 157 | |
d62a17ae | 158 | ifreq_set_name(&ifreq, ifp); |
718e3744 | 159 | |
160 | #if defined(SIOCGIFMTU) | |
a36898e7 | 161 | if (vrf_if_ioctl(SIOCGIFMTU, (caddr_t)&ifreq, ifp->vrf_id) < 0) { |
d62a17ae | 162 | zlog_info("Can't lookup mtu by ioctl(SIOCGIFMTU)"); |
163 | ifp->mtu6 = ifp->mtu = -1; | |
164 | return; | |
165 | } | |
718e3744 | 166 | |
d62a17ae | 167 | ifp->mtu6 = ifp->mtu = ifreq.ifr_mtu; |
718e3744 | 168 | |
d62a17ae | 169 | /* propogate */ |
170 | zebra_interface_up_update(ifp); | |
f5e004f7 | 171 | |
718e3744 | 172 | #else |
d62a17ae | 173 | zlog_info("Can't lookup mtu on this system"); |
174 | ifp->mtu6 = ifp->mtu = -1; | |
718e3744 | 175 | #endif |
176 | } | |
177 | ||
64168803 | 178 | /* |
0f1f6ce4 MS |
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. | |
64168803 MS |
182 | */ |
183 | #ifndef HAVE_NETLINK | |
184 | ||
0f1f6ce4 MS |
185 | /* Prototypes: these are placed in this block so that they're only seen |
186 | * on non-netlink platforms. | |
187 | */ | |
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); | |
192 | ||
64168803 MS |
193 | enum zebra_dplane_result kernel_address_update_ctx( |
194 | struct zebra_dplane_ctx *ctx) | |
195 | { | |
0f1f6ce4 MS |
196 | int ret = -1; |
197 | const struct prefix *p; | |
198 | ||
199 | p = dplane_ctx_get_intf_addr(ctx); | |
200 | ||
201 | if (dplane_ctx_get_op(ctx) == DPLANE_OP_ADDR_INSTALL) { | |
202 | if (p->family == AF_INET) | |
203 | ret = if_set_prefix_ctx(ctx); | |
204 | else | |
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); | |
209 | else | |
210 | ret = if_unset_prefix6_ctx(ctx); | |
211 | } else { | |
212 | if (IS_ZEBRA_DEBUG_DPLANE) | |
213 | zlog_debug("Invalid op in interface-addr install"); | |
214 | } | |
215 | ||
216 | return (ret == 0 ? | |
217 | ZEBRA_DPLANE_REQUEST_SUCCESS : ZEBRA_DPLANE_REQUEST_FAILURE); | |
64168803 MS |
218 | } |
219 | ||
220 | #endif /* !HAVE_NETLINK */ | |
221 | ||
718e3744 | 222 | #ifdef HAVE_NETLINK |
0f1f6ce4 MS |
223 | |
224 | /* TODO -- remove; no use of these apis with netlink any longer */ | |
225 | ||
226 | #else /* ! HAVE_NETLINK */ | |
227 | #ifdef HAVE_STRUCT_IFALIASREQ | |
228 | ||
229 | /* | |
230 | * Helper for interface-addr install, non-netlink | |
231 | */ | |
232 | static int if_set_prefix_ctx(const struct zebra_dplane_ctx *ctx) | |
718e3744 | 233 | { |
0f1f6ce4 MS |
234 | int ret; |
235 | struct ifaliasreq addreq; | |
236 | struct sockaddr_in addr, mask, peer; | |
237 | struct prefix_ipv4 *p; | |
238 | ||
239 | p = (struct prefix_ipv4 *)dplane_ctx_get_intf_addr(ctx); | |
240 | ||
241 | memset(&addreq, 0, sizeof(addreq)); | |
fcb072cd | 242 | strlcpy((char *)&addreq.ifra_name, dplane_ctx_get_ifname(ctx), |
0f1f6ce4 MS |
243 | sizeof(addreq.ifra_name)); |
244 | ||
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); | |
250 | #endif | |
251 | memcpy(&addreq.ifra_addr, &addr, sizeof(struct sockaddr_in)); | |
252 | ||
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); | |
260 | #endif | |
261 | memcpy(&addreq.ifra_broadaddr, &peer, | |
262 | sizeof(struct sockaddr_in)); | |
263 | } | |
264 | ||
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); | |
270 | #endif | |
271 | memcpy(&addreq.ifra_mask, &mask, sizeof(struct sockaddr_in)); | |
272 | ||
273 | ret = if_ioctl(SIOCAIFADDR, (caddr_t)&addreq); | |
274 | if (ret < 0) | |
275 | return ret; | |
276 | return 0; | |
277 | ||
718e3744 | 278 | } |
279 | ||
0f1f6ce4 MS |
280 | /* |
281 | * Helper for interface-addr un-install, non-netlink | |
282 | */ | |
283 | static int if_unset_prefix_ctx(const struct zebra_dplane_ctx *ctx) | |
718e3744 | 284 | { |
0f1f6ce4 MS |
285 | int ret; |
286 | struct ifaliasreq addreq; | |
287 | struct sockaddr_in addr, mask, peer; | |
288 | struct prefix_ipv4 *p; | |
289 | ||
290 | p = (struct prefix_ipv4 *)dplane_ctx_get_intf_addr(ctx); | |
291 | ||
292 | memset(&addreq, 0, sizeof(addreq)); | |
fcb072cd | 293 | strlcpy((char *)&addreq.ifra_name, dplane_ctx_get_ifname(ctx), |
0f1f6ce4 MS |
294 | sizeof(addreq.ifra_name)); |
295 | ||
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); | |
301 | #endif | |
302 | memcpy(&addreq.ifra_addr, &addr, sizeof(struct sockaddr_in)); | |
303 | ||
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); | |
311 | #endif | |
312 | memcpy(&addreq.ifra_broadaddr, &peer, | |
313 | sizeof(struct sockaddr_in)); | |
314 | } | |
315 | ||
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); | |
321 | #endif | |
322 | memcpy(&addreq.ifra_mask, &mask, sizeof(struct sockaddr_in)); | |
323 | ||
324 | ret = if_ioctl(SIOCDIFADDR, (caddr_t)&addreq); | |
325 | if (ret < 0) | |
326 | return ret; | |
327 | return 0; | |
718e3744 | 328 | } |
718e3744 | 329 | #else |
330 | /* Set up interface's address, netmask (and broadcas? ). Linux or | |
331 | Solaris uses ifname:number semantics to set IP address aliases. */ | |
39fa2825 | 332 | int if_set_prefix_ctx(const struct zebra_dplane_ctx *ctx) |
718e3744 | 333 | { |
d62a17ae | 334 | int ret; |
335 | struct ifreq ifreq; | |
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; | |
341 | ||
39fa2825 | 342 | p = (struct prefix_ipv4 *)dplane_ctx_get_intf_addr(ctx); |
d62a17ae | 343 | |
344 | ifaddr = *p; | |
345 | ||
39fa2825 MS |
346 | strlcpy(ifreq.ifr_name, dplane_ctx_get_ifname(ctx), |
347 | sizeof(ifreq.ifr_name)); | |
d62a17ae | 348 | |
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); | |
353 | if (ret < 0) | |
354 | return ret; | |
355 | ||
356 | /* We need mask for make broadcast addr. */ | |
357 | masklen2ip(p->prefixlen, &mask.sin_addr); | |
358 | ||
39fa2825 | 359 | if (dplane_ctx_intf_is_broadcast(ctx)) { |
d62a17ae | 360 | apply_mask_ipv4(&ifaddr); |
361 | addr.sin_addr = ifaddr.prefix; | |
362 | ||
363 | broad.sin_addr.s_addr = | |
364 | (addr.sin_addr.s_addr | ~mask.sin_addr.s_addr); | |
365 | broad.sin_family = p->family; | |
366 | ||
367 | memcpy(&ifreq.ifr_broadaddr, &broad, | |
368 | sizeof(struct sockaddr_in)); | |
369 | ret = if_ioctl(SIOCSIFBRDADDR, (caddr_t)&ifreq); | |
370 | if (ret < 0) | |
371 | return ret; | |
372 | } | |
373 | ||
374 | mask.sin_family = p->family; | |
39fa2825 | 375 | memcpy(&ifreq.ifr_addr, &mask, sizeof(struct sockaddr_in)); |
d62a17ae | 376 | ret = if_ioctl(SIOCSIFNETMASK, (caddr_t)&ifreq); |
377 | if (ret < 0) | |
378 | return ret; | |
718e3744 | 379 | |
d62a17ae | 380 | return 0; |
718e3744 | 381 | } |
382 | ||
383 | /* Set up interface's address, netmask (and broadcas? ). Linux or | |
384 | Solaris uses ifname:number semantics to set IP address aliases. */ | |
39fa2825 | 385 | int if_unset_prefix_ctx(const struct zebra_dplane_ctx *ctx) |
718e3744 | 386 | { |
d62a17ae | 387 | int ret; |
388 | struct ifreq ifreq; | |
389 | struct sockaddr_in addr; | |
390 | struct prefix_ipv4 *p; | |
718e3744 | 391 | |
39fa2825 | 392 | p = (struct prefix_ipv4 *)dplane_ctx_get_intf_addr(ctx); |
718e3744 | 393 | |
39fa2825 MS |
394 | strlcpy(ifreq.ifr_name, dplane_ctx_get_ifname(ctx), |
395 | sizeof(ifreq.ifr_name)); | |
718e3744 | 396 | |
d62a17ae | 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); | |
401 | if (ret < 0) | |
402 | return ret; | |
718e3744 | 403 | |
d62a17ae | 404 | return 0; |
718e3744 | 405 | } |
6f0e3f6e | 406 | #endif /* HAVE_STRUCT_IFALIASREQ */ |
718e3744 | 407 | #endif /* HAVE_NETLINK */ |
408 | ||
409 | /* get interface flags */ | |
d62a17ae | 410 | void if_get_flags(struct interface *ifp) |
718e3744 | 411 | { |
d62a17ae | 412 | int ret; |
413 | struct ifreq ifreq; | |
718e3744 | 414 | |
d62a17ae | 415 | ifreq_set_name(&ifreq, ifp); |
718e3744 | 416 | |
a36898e7 | 417 | ret = vrf_if_ioctl(SIOCGIFFLAGS, (caddr_t)&ifreq, ifp->vrf_id); |
d62a17ae | 418 | if (ret < 0) { |
450971aa | 419 | flog_err_sys(EC_LIB_SYSTEM_CALL, |
98f3df55 RM |
420 | "vrf_if_ioctl(SIOCGIFFLAGS %s) failed: %s", |
421 | ifp->name, safe_strerror(errno)); | |
d62a17ae | 422 | return; |
423 | } | |
0b3f3d47 | 424 | |
98f3df55 RM |
425 | if (!CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION)) |
426 | goto out; | |
427 | ||
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 | |
431 | * kernels | |
432 | */ | |
433 | ||
434 | #ifdef SIOCGIFDATA | |
435 | /* | |
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. | |
439 | */ | |
440 | ||
441 | #ifdef __NetBSD__ | |
442 | struct ifdatareq ifdr = {.ifdr_data.ifi_link_state = 0}; | |
443 | struct if_data *ifdata = &ifdr.ifdr_data; | |
444 | ||
445 | strlcpy(ifdr.ifdr_name, ifp->name, sizeof(ifdr.ifdr_name)); | |
446 | ret = vrf_if_ioctl(SIOCGIFDATA, (caddr_t)&ifdr, ifp->vrf_id); | |
447 | #else | |
448 | struct if_data ifd = {.ifi_link_state = 0}; | |
449 | struct if_data *ifdata = &ifd; | |
450 | ||
451 | ifreq.ifr_data = (caddr_t)ifdata; | |
452 | ret = vrf_if_ioctl(SIOCGIFDATA, (caddr_t)&ifreq, ifp->vrf_id); | |
453 | #endif | |
454 | ||
455 | if (ret == -1) | |
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)); | |
460 | else { | |
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); | |
466 | else | |
467 | UNSET_FLAG(ifreq.ifr_flags, IFF_RUNNING); | |
468 | } | |
469 | ||
470 | #elif defined(HAVE_BSD_LINK_DETECT) | |
471 | /* | |
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. | |
d62a17ae | 480 | */ |
98f3df55 | 481 | struct ifmediareq ifmr = {.ifm_status = 0}; |
d62a17ae | 482 | |
98f3df55 | 483 | strlcpy(ifmr.ifm_name, ifp->name, sizeof(ifmr.ifm_name)); |
d62a17ae | 484 | |
98f3df55 RM |
485 | if (if_ioctl(SIOCGIFMEDIA, (caddr_t)&ifmr) == -1) { |
486 | if (errno != EINVAL) | |
450971aa | 487 | flog_err_sys(EC_LIB_SYSTEM_CALL, |
98f3df55 RM |
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); | |
493 | else | |
494 | UNSET_FLAG(ifreq.ifr_flags, IFF_RUNNING); | |
d62a17ae | 495 | } |
c543a173 | 496 | #endif /* HAVE_BSD_LINK_DETECT */ |
718e3744 | 497 | |
98f3df55 | 498 | out: |
d62a17ae | 499 | if_flags_update(ifp, (ifreq.ifr_flags & 0x0000ffff)); |
718e3744 | 500 | } |
501 | ||
502 | /* Set interface flags */ | |
d62a17ae | 503 | int if_set_flags(struct interface *ifp, uint64_t flags) |
718e3744 | 504 | { |
d62a17ae | 505 | int ret; |
506 | struct ifreq ifreq; | |
718e3744 | 507 | |
d62a17ae | 508 | memset(&ifreq, 0, sizeof(struct ifreq)); |
509 | ifreq_set_name(&ifreq, ifp); | |
718e3744 | 510 | |
d62a17ae | 511 | ifreq.ifr_flags = ifp->flags; |
512 | ifreq.ifr_flags |= flags; | |
718e3744 | 513 | |
a36898e7 | 514 | ret = vrf_if_ioctl(SIOCSIFFLAGS, (caddr_t)&ifreq, ifp->vrf_id); |
718e3744 | 515 | |
d62a17ae | 516 | if (ret < 0) { |
517 | zlog_info("can't set interface flags"); | |
518 | return ret; | |
519 | } | |
520 | return 0; | |
718e3744 | 521 | } |
522 | ||
523 | /* Unset interface's flag. */ | |
d62a17ae | 524 | int if_unset_flags(struct interface *ifp, uint64_t flags) |
718e3744 | 525 | { |
d62a17ae | 526 | int ret; |
527 | struct ifreq ifreq; | |
718e3744 | 528 | |
d62a17ae | 529 | memset(&ifreq, 0, sizeof(struct ifreq)); |
530 | ifreq_set_name(&ifreq, ifp); | |
718e3744 | 531 | |
d62a17ae | 532 | ifreq.ifr_flags = ifp->flags; |
533 | ifreq.ifr_flags &= ~flags; | |
718e3744 | 534 | |
a36898e7 | 535 | ret = vrf_if_ioctl(SIOCSIFFLAGS, (caddr_t)&ifreq, ifp->vrf_id); |
718e3744 | 536 | |
d62a17ae | 537 | if (ret < 0) { |
538 | zlog_info("can't unset interface flags"); | |
539 | return ret; | |
540 | } | |
541 | return 0; | |
718e3744 | 542 | } |
543 | ||
39fa2825 | 544 | #ifndef LINUX_IPV6 /* Netlink has its own code */ |
718e3744 | 545 | |
6f0e3f6e | 546 | #ifdef HAVE_STRUCT_IN6_ALIASREQ |
718e3744 | 547 | #ifndef ND6_INFINITE_LIFETIME |
548 | #define ND6_INFINITE_LIFETIME 0xffffffffL | |
549 | #endif /* ND6_INFINITE_LIFETIME */ | |
0f1f6ce4 MS |
550 | |
551 | /* | |
552 | * Helper for interface-addr install, non-netlink | |
553 | */ | |
554 | static int if_set_prefix6_ctx(const struct zebra_dplane_ctx *ctx) | |
555 | { | |
556 | int ret; | |
557 | struct in6_aliasreq addreq; | |
558 | struct sockaddr_in6 addr; | |
559 | struct sockaddr_in6 mask; | |
560 | struct prefix_ipv6 *p; | |
561 | ||
562 | p = (struct prefix_ipv6 *)dplane_ctx_get_intf_addr(ctx); | |
563 | ||
564 | memset(&addreq, 0, sizeof(addreq)); | |
39fa2825 | 565 | strlcpy((char *)&addreq.ifra_name, |
0f1f6ce4 MS |
566 | dplane_ctx_get_ifname(ctx), sizeof(addreq.ifra_name)); |
567 | ||
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); | |
573 | #endif | |
574 | memcpy(&addreq.ifra_addr, &addr, sizeof(struct sockaddr_in6)); | |
575 | ||
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); | |
581 | #endif | |
582 | memcpy(&addreq.ifra_prefixmask, &mask, sizeof(struct sockaddr_in6)); | |
583 | ||
584 | addreq.ifra_lifetime.ia6t_vltime = 0xffffffff; | |
585 | addreq.ifra_lifetime.ia6t_pltime = 0xffffffff; | |
586 | ||
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; | |
590 | #endif | |
591 | ||
592 | ret = if_ioctl_ipv6(SIOCAIFADDR_IN6, (caddr_t)&addreq); | |
593 | if (ret < 0) | |
594 | return ret; | |
595 | return 0; | |
596 | } | |
597 | ||
598 | /* | |
599 | * Helper for interface-addr un-install, non-netlink | |
600 | */ | |
601 | static int if_unset_prefix6_ctx(const struct zebra_dplane_ctx *ctx) | |
602 | { | |
603 | int ret; | |
604 | struct in6_aliasreq addreq; | |
605 | struct sockaddr_in6 addr; | |
606 | struct sockaddr_in6 mask; | |
607 | struct prefix_ipv6 *p; | |
608 | ||
609 | p = (struct prefix_ipv6 *)dplane_ctx_get_intf_addr(ctx); | |
610 | ||
611 | memset(&addreq, 0, sizeof(addreq)); | |
39fa2825 | 612 | strlcpy((char *)&addreq.ifra_name, |
0f1f6ce4 MS |
613 | dplane_ctx_get_ifname(ctx), sizeof(addreq.ifra_name)); |
614 | ||
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); | |
620 | #endif | |
621 | memcpy(&addreq.ifra_addr, &addr, sizeof(struct sockaddr_in6)); | |
622 | ||
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); | |
628 | #endif | |
629 | memcpy(&addreq.ifra_prefixmask, &mask, sizeof(struct sockaddr_in6)); | |
630 | ||
6f0e3f6e | 631 | #ifdef HAVE_STRUCT_IF6_ALIASREQ_IFRA_LIFETIME |
d62a17ae | 632 | addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; |
633 | addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; | |
726f9b2b | 634 | #endif |
718e3744 | 635 | |
d62a17ae | 636 | ret = if_ioctl_ipv6(SIOCDIFADDR_IN6, (caddr_t)&addreq); |
637 | if (ret < 0) | |
638 | return ret; | |
639 | return 0; | |
718e3744 | 640 | } |
641 | #else | |
39fa2825 MS |
642 | /* The old, pre-dataplane code here just returned, so we're retaining that |
643 | * choice. | |
644 | */ | |
645 | static int if_set_prefix6_ctx(const struct zebra_dplane_ctx *ctx) | |
718e3744 | 646 | { |
d62a17ae | 647 | return 0; |
718e3744 | 648 | } |
649 | ||
39fa2825 | 650 | static int if_unset_prefix6_ctx(const struct zebra_dplane_ctx *ctx) |
718e3744 | 651 | { |
d62a17ae | 652 | return 0; |
718e3744 | 653 | } |
6f0e3f6e | 654 | #endif /* HAVE_STRUCT_IN6_ALIASREQ */ |
718e3744 | 655 | |
656 | #endif /* LINUX_IPV6 */ |