]>
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 | |
096f7609 | 143 | if (vrf_if_ioctl(SIOCGIFMETRIC, (caddr_t)&ifreq, ifp->vrf->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) | |
096f7609 | 161 | if (vrf_if_ioctl(SIOCGIFMTU, (caddr_t)&ifreq, ifp->vrf->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; |
16dca7ce B |
413 | struct ifreq ifreqflags; |
414 | struct ifreq ifreqdata; | |
718e3744 | 415 | |
16dca7ce B |
416 | ifreq_set_name(&ifreqflags, ifp); |
417 | ifreq_set_name(&ifreqdata, ifp); | |
718e3744 | 418 | |
16dca7ce B |
419 | ret = vrf_if_ioctl(SIOCGIFFLAGS, (caddr_t)&ifreqflags, |
420 | ifp->vrf->vrf_id); | |
d62a17ae | 421 | if (ret < 0) { |
450971aa | 422 | flog_err_sys(EC_LIB_SYSTEM_CALL, |
98f3df55 RM |
423 | "vrf_if_ioctl(SIOCGIFFLAGS %s) failed: %s", |
424 | ifp->name, safe_strerror(errno)); | |
d62a17ae | 425 | return; |
426 | } | |
0b3f3d47 | 427 | |
98f3df55 RM |
428 | if (!CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION)) |
429 | goto out; | |
430 | ||
431 | /* Per-default, IFF_RUNNING is held high, unless link-detect | |
432 | * says otherwise - we abuse IFF_RUNNING inside zebra as a | |
433 | * link-state flag, following practice on Linux and Solaris | |
434 | * kernels | |
435 | */ | |
436 | ||
437 | #ifdef SIOCGIFDATA | |
438 | /* | |
439 | * BSD gets link state from ifi_link_link in struct if_data. | |
440 | * All BSD's have this in getifaddrs(3) ifa_data for AF_LINK | |
441 | * addresses. We can also access it via SIOCGIFDATA. | |
442 | */ | |
443 | ||
444 | #ifdef __NetBSD__ | |
445 | struct ifdatareq ifdr = {.ifdr_data.ifi_link_state = 0}; | |
446 | struct if_data *ifdata = &ifdr.ifdr_data; | |
447 | ||
448 | strlcpy(ifdr.ifdr_name, ifp->name, sizeof(ifdr.ifdr_name)); | |
096f7609 | 449 | ret = vrf_if_ioctl(SIOCGIFDATA, (caddr_t)&ifdr, ifp->vrf->vrf_id); |
98f3df55 RM |
450 | #else |
451 | struct if_data ifd = {.ifi_link_state = 0}; | |
452 | struct if_data *ifdata = &ifd; | |
453 | ||
16dca7ce B |
454 | ifreqdata.ifr_data = (caddr_t)ifdata; |
455 | ret = vrf_if_ioctl(SIOCGIFDATA, (caddr_t)&ifreqdata, ifp->vrf->vrf_id); | |
98f3df55 RM |
456 | #endif |
457 | ||
458 | if (ret == -1) | |
459 | /* Very unlikely. Did the interface disappear? */ | |
460 | flog_err_sys(EC_LIB_SYSTEM_CALL, | |
461 | "if_ioctl(SIOCGIFDATA %s) failed: %s", ifp->name, | |
462 | safe_strerror(errno)); | |
463 | else { | |
464 | if (ifdata->ifi_link_state >= LINK_STATE_UP) | |
16dca7ce | 465 | SET_FLAG(ifreqflags.ifr_flags, IFF_RUNNING); |
98f3df55 RM |
466 | else if (ifdata->ifi_link_state == LINK_STATE_UNKNOWN) |
467 | /* BSD traditionally treats UNKNOWN as UP */ | |
16dca7ce | 468 | SET_FLAG(ifreqflags.ifr_flags, IFF_RUNNING); |
98f3df55 | 469 | else |
16dca7ce | 470 | UNSET_FLAG(ifreqflags.ifr_flags, IFF_RUNNING); |
98f3df55 RM |
471 | } |
472 | ||
473 | #elif defined(HAVE_BSD_LINK_DETECT) | |
474 | /* | |
475 | * This is only needed for FreeBSD older than FreeBSD-13. | |
476 | * Valid and active media generally means the link state is | |
477 | * up, but this is not always the case. | |
478 | * For example, some BSD's with a net80211 interface in MONITOR | |
479 | * mode will treat the media as valid and active but the | |
480 | * link state is down - because we cannot send anything. | |
481 | * Also, virtual interfaces such as PPP, VLAN, etc generally | |
482 | * don't support media at all, so the ioctl will just fail. | |
d62a17ae | 483 | */ |
98f3df55 | 484 | struct ifmediareq ifmr = {.ifm_status = 0}; |
d62a17ae | 485 | |
98f3df55 | 486 | strlcpy(ifmr.ifm_name, ifp->name, sizeof(ifmr.ifm_name)); |
d62a17ae | 487 | |
98f3df55 RM |
488 | if (if_ioctl(SIOCGIFMEDIA, (caddr_t)&ifmr) == -1) { |
489 | if (errno != EINVAL) | |
450971aa | 490 | flog_err_sys(EC_LIB_SYSTEM_CALL, |
98f3df55 RM |
491 | "if_ioctl(SIOCGIFMEDIA %s) failed: %s", |
492 | ifp->name, safe_strerror(errno)); | |
493 | } else if (ifmr.ifm_status & IFM_AVALID) { /* media state is valid */ | |
494 | if (ifmr.ifm_status & IFM_ACTIVE) /* media is active */ | |
16dca7ce | 495 | SET_FLAG(ifreqflags.ifr_flags, IFF_RUNNING); |
98f3df55 | 496 | else |
16dca7ce | 497 | UNSET_FLAG(ifreqflags.ifr_flags, IFF_RUNNING); |
d62a17ae | 498 | } |
c543a173 | 499 | #endif /* HAVE_BSD_LINK_DETECT */ |
718e3744 | 500 | |
98f3df55 | 501 | out: |
16dca7ce | 502 | if_flags_update(ifp, (ifreqflags.ifr_flags & 0x0000ffff)); |
718e3744 | 503 | } |
504 | ||
505 | /* Set interface flags */ | |
d62a17ae | 506 | int if_set_flags(struct interface *ifp, uint64_t flags) |
718e3744 | 507 | { |
d62a17ae | 508 | int ret; |
509 | struct ifreq ifreq; | |
718e3744 | 510 | |
d62a17ae | 511 | memset(&ifreq, 0, sizeof(struct ifreq)); |
512 | ifreq_set_name(&ifreq, ifp); | |
718e3744 | 513 | |
d62a17ae | 514 | ifreq.ifr_flags = ifp->flags; |
515 | ifreq.ifr_flags |= flags; | |
718e3744 | 516 | |
096f7609 | 517 | ret = vrf_if_ioctl(SIOCSIFFLAGS, (caddr_t)&ifreq, ifp->vrf->vrf_id); |
718e3744 | 518 | |
d62a17ae | 519 | if (ret < 0) { |
520 | zlog_info("can't set interface flags"); | |
521 | return ret; | |
522 | } | |
523 | return 0; | |
718e3744 | 524 | } |
525 | ||
526 | /* Unset interface's flag. */ | |
d62a17ae | 527 | int if_unset_flags(struct interface *ifp, uint64_t flags) |
718e3744 | 528 | { |
d62a17ae | 529 | int ret; |
530 | struct ifreq ifreq; | |
718e3744 | 531 | |
d62a17ae | 532 | memset(&ifreq, 0, sizeof(struct ifreq)); |
533 | ifreq_set_name(&ifreq, ifp); | |
718e3744 | 534 | |
d62a17ae | 535 | ifreq.ifr_flags = ifp->flags; |
536 | ifreq.ifr_flags &= ~flags; | |
718e3744 | 537 | |
096f7609 | 538 | ret = vrf_if_ioctl(SIOCSIFFLAGS, (caddr_t)&ifreq, ifp->vrf->vrf_id); |
718e3744 | 539 | |
d62a17ae | 540 | if (ret < 0) { |
541 | zlog_info("can't unset interface flags"); | |
542 | return ret; | |
543 | } | |
544 | return 0; | |
718e3744 | 545 | } |
546 | ||
39fa2825 | 547 | #ifndef LINUX_IPV6 /* Netlink has its own code */ |
718e3744 | 548 | |
6f0e3f6e | 549 | #ifdef HAVE_STRUCT_IN6_ALIASREQ |
718e3744 | 550 | #ifndef ND6_INFINITE_LIFETIME |
551 | #define ND6_INFINITE_LIFETIME 0xffffffffL | |
552 | #endif /* ND6_INFINITE_LIFETIME */ | |
0f1f6ce4 MS |
553 | |
554 | /* | |
555 | * Helper for interface-addr install, non-netlink | |
556 | */ | |
557 | static int if_set_prefix6_ctx(const struct zebra_dplane_ctx *ctx) | |
558 | { | |
559 | int ret; | |
560 | struct in6_aliasreq addreq; | |
561 | struct sockaddr_in6 addr; | |
562 | struct sockaddr_in6 mask; | |
563 | struct prefix_ipv6 *p; | |
564 | ||
565 | p = (struct prefix_ipv6 *)dplane_ctx_get_intf_addr(ctx); | |
566 | ||
567 | memset(&addreq, 0, sizeof(addreq)); | |
39fa2825 | 568 | strlcpy((char *)&addreq.ifra_name, |
0f1f6ce4 MS |
569 | dplane_ctx_get_ifname(ctx), sizeof(addreq.ifra_name)); |
570 | ||
571 | memset(&addr, 0, sizeof(struct sockaddr_in6)); | |
572 | addr.sin6_addr = p->prefix; | |
573 | addr.sin6_family = p->family; | |
574 | #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN | |
575 | addr.sin6_len = sizeof(struct sockaddr_in6); | |
576 | #endif | |
577 | memcpy(&addreq.ifra_addr, &addr, sizeof(struct sockaddr_in6)); | |
578 | ||
579 | memset(&mask, 0, sizeof(struct sockaddr_in6)); | |
580 | masklen2ip6(p->prefixlen, &mask.sin6_addr); | |
581 | mask.sin6_family = p->family; | |
582 | #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN | |
583 | mask.sin6_len = sizeof(struct sockaddr_in6); | |
584 | #endif | |
585 | memcpy(&addreq.ifra_prefixmask, &mask, sizeof(struct sockaddr_in6)); | |
586 | ||
587 | addreq.ifra_lifetime.ia6t_vltime = 0xffffffff; | |
588 | addreq.ifra_lifetime.ia6t_pltime = 0xffffffff; | |
589 | ||
590 | #ifdef HAVE_STRUCT_IF6_ALIASREQ_IFRA_LIFETIME | |
591 | addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; | |
592 | addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; | |
593 | #endif | |
594 | ||
595 | ret = if_ioctl_ipv6(SIOCAIFADDR_IN6, (caddr_t)&addreq); | |
596 | if (ret < 0) | |
597 | return ret; | |
598 | return 0; | |
599 | } | |
600 | ||
601 | /* | |
602 | * Helper for interface-addr un-install, non-netlink | |
603 | */ | |
604 | static int if_unset_prefix6_ctx(const struct zebra_dplane_ctx *ctx) | |
605 | { | |
606 | int ret; | |
607 | struct in6_aliasreq addreq; | |
608 | struct sockaddr_in6 addr; | |
609 | struct sockaddr_in6 mask; | |
610 | struct prefix_ipv6 *p; | |
611 | ||
612 | p = (struct prefix_ipv6 *)dplane_ctx_get_intf_addr(ctx); | |
613 | ||
614 | memset(&addreq, 0, sizeof(addreq)); | |
39fa2825 | 615 | strlcpy((char *)&addreq.ifra_name, |
0f1f6ce4 MS |
616 | dplane_ctx_get_ifname(ctx), sizeof(addreq.ifra_name)); |
617 | ||
618 | memset(&addr, 0, sizeof(struct sockaddr_in6)); | |
619 | addr.sin6_addr = p->prefix; | |
620 | addr.sin6_family = p->family; | |
621 | #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN | |
622 | addr.sin6_len = sizeof(struct sockaddr_in6); | |
623 | #endif | |
624 | memcpy(&addreq.ifra_addr, &addr, sizeof(struct sockaddr_in6)); | |
625 | ||
626 | memset(&mask, 0, sizeof(struct sockaddr_in6)); | |
627 | masklen2ip6(p->prefixlen, &mask.sin6_addr); | |
628 | mask.sin6_family = p->family; | |
629 | #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN | |
630 | mask.sin6_len = sizeof(struct sockaddr_in6); | |
631 | #endif | |
632 | memcpy(&addreq.ifra_prefixmask, &mask, sizeof(struct sockaddr_in6)); | |
633 | ||
6f0e3f6e | 634 | #ifdef HAVE_STRUCT_IF6_ALIASREQ_IFRA_LIFETIME |
d62a17ae | 635 | addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; |
636 | addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; | |
726f9b2b | 637 | #endif |
718e3744 | 638 | |
d62a17ae | 639 | ret = if_ioctl_ipv6(SIOCDIFADDR_IN6, (caddr_t)&addreq); |
640 | if (ret < 0) | |
641 | return ret; | |
642 | return 0; | |
718e3744 | 643 | } |
644 | #else | |
39fa2825 MS |
645 | /* The old, pre-dataplane code here just returned, so we're retaining that |
646 | * choice. | |
647 | */ | |
648 | static int if_set_prefix6_ctx(const struct zebra_dplane_ctx *ctx) | |
718e3744 | 649 | { |
d62a17ae | 650 | return 0; |
718e3744 | 651 | } |
652 | ||
39fa2825 | 653 | static int if_unset_prefix6_ctx(const struct zebra_dplane_ctx *ctx) |
718e3744 | 654 | { |
d62a17ae | 655 | return 0; |
718e3744 | 656 | } |
6f0e3f6e | 657 | #endif /* HAVE_STRUCT_IN6_ALIASREQ */ |
718e3744 | 658 | |
659 | #endif /* LINUX_IPV6 */ |