Line | Count | Source |
1 | | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | | /* |
3 | | * Common ioctl functions. |
4 | | * Copyright (C) 1997, 98 Kunihiro Ishiguro |
5 | | */ |
6 | | |
7 | | #include <zebra.h> |
8 | | |
9 | | #include "linklist.h" |
10 | | #include "if.h" |
11 | | #include "prefix.h" |
12 | | #include "ioctl.h" |
13 | | #include "log.h" |
14 | | #include "privs.h" |
15 | | #include "lib_errors.h" |
16 | | |
17 | | #include "vty.h" |
18 | | #include "zebra/rib.h" |
19 | | #include "zebra/rt.h" |
20 | | #include "zebra/interface.h" |
21 | | #include "zebra/zebra_errors.h" |
22 | | #include "zebra/debug.h" |
23 | | |
24 | | #ifdef HAVE_BSD_LINK_DETECT |
25 | | #include <net/if_media.h> |
26 | | #endif /* HAVE_BSD_LINK_DETECT*/ |
27 | | |
28 | | extern struct zebra_privs_t zserv_privs; |
29 | | |
30 | | /* clear and set interface name string */ |
31 | | void ifreq_set_name(struct ifreq *ifreq, struct interface *ifp) |
32 | 0 | { |
33 | 0 | strlcpy(ifreq->ifr_name, ifp->name, sizeof(ifreq->ifr_name)); |
34 | 0 | } |
35 | | |
36 | | #ifndef HAVE_NETLINK |
37 | | /* call ioctl system call */ |
38 | | int if_ioctl(unsigned long request, caddr_t buffer) |
39 | | { |
40 | | int sock; |
41 | | int ret; |
42 | | int err = 0; |
43 | | |
44 | | frr_with_privs(&zserv_privs) { |
45 | | sock = socket(AF_INET, SOCK_DGRAM, 0); |
46 | | if (sock < 0) { |
47 | | zlog_err("Cannot create UDP socket: %s", |
48 | | safe_strerror(errno)); |
49 | | exit(1); |
50 | | } |
51 | | if ((ret = ioctl(sock, request, buffer)) < 0) |
52 | | err = errno; |
53 | | } |
54 | | close(sock); |
55 | | |
56 | | if (ret < 0) { |
57 | | errno = err; |
58 | | return ret; |
59 | | } |
60 | | return 0; |
61 | | } |
62 | | #endif |
63 | | |
64 | | /* call ioctl system call */ |
65 | | int vrf_if_ioctl(unsigned long request, caddr_t buffer, vrf_id_t vrf_id) |
66 | 0 | { |
67 | 0 | int sock; |
68 | 0 | int ret; |
69 | 0 | int err = 0; |
70 | |
|
71 | 0 | frr_with_privs(&zserv_privs) { |
72 | 0 | sock = vrf_socket(AF_INET, SOCK_DGRAM, 0, vrf_id, NULL); |
73 | 0 | if (sock < 0) { |
74 | 0 | zlog_err("Cannot create UDP socket: %s", |
75 | 0 | safe_strerror(errno)); |
76 | 0 | exit(1); |
77 | 0 | } |
78 | 0 | ret = vrf_ioctl(vrf_id, sock, request, buffer); |
79 | 0 | if (ret < 0) |
80 | 0 | err = errno; |
81 | 0 | } |
82 | 0 | close(sock); |
83 | |
|
84 | 0 | if (ret < 0) { |
85 | 0 | errno = err; |
86 | 0 | return ret; |
87 | 0 | } |
88 | 0 | return 0; |
89 | 0 | } |
90 | | |
91 | | #ifndef HAVE_NETLINK |
92 | | static int if_ioctl_ipv6(unsigned long request, caddr_t buffer) |
93 | | { |
94 | | int sock; |
95 | | int ret; |
96 | | int err = 0; |
97 | | |
98 | | frr_with_privs(&zserv_privs) { |
99 | | sock = socket(AF_INET6, SOCK_DGRAM, 0); |
100 | | if (sock < 0) { |
101 | | zlog_err("Cannot create IPv6 datagram socket: %s", |
102 | | safe_strerror(errno)); |
103 | | exit(1); |
104 | | } |
105 | | |
106 | | if ((ret = ioctl(sock, request, buffer)) < 0) |
107 | | err = errno; |
108 | | } |
109 | | close(sock); |
110 | | |
111 | | if (ret < 0) { |
112 | | errno = err; |
113 | | return ret; |
114 | | } |
115 | | return 0; |
116 | | } |
117 | | |
118 | | /* |
119 | | * get interface metric |
120 | | * -- if value is not avaliable set -1 |
121 | | */ |
122 | | void if_get_metric(struct interface *ifp) |
123 | | { |
124 | | #ifdef SIOCGIFMETRIC |
125 | | struct ifreq ifreq = {}; |
126 | | |
127 | | ifreq_set_name(&ifreq, ifp); |
128 | | |
129 | | if (vrf_if_ioctl(SIOCGIFMETRIC, (caddr_t)&ifreq, ifp->vrf->vrf_id) < 0) |
130 | | return; |
131 | | ifp->metric = ifreq.ifr_metric; |
132 | | if (ifp->metric == 0) |
133 | | ifp->metric = 1; |
134 | | #else /* SIOCGIFMETRIC */ |
135 | | ifp->metric = -1; |
136 | | #endif /* SIOCGIFMETRIC */ |
137 | | } |
138 | | |
139 | | /* get interface MTU */ |
140 | | void if_get_mtu(struct interface *ifp) |
141 | | { |
142 | | struct ifreq ifreq = {}; |
143 | | |
144 | | ifreq_set_name(&ifreq, ifp); |
145 | | |
146 | | #if defined(SIOCGIFMTU) |
147 | | if (vrf_if_ioctl(SIOCGIFMTU, (caddr_t)&ifreq, ifp->vrf->vrf_id) < 0) { |
148 | | zlog_info("Can't lookup mtu by ioctl(SIOCGIFMTU) for %s(%u)", |
149 | | ifp->name, ifp->vrf->vrf_id); |
150 | | ifp->mtu6 = ifp->mtu = -1; |
151 | | return; |
152 | | } |
153 | | |
154 | | ifp->mtu6 = ifp->mtu = ifreq.ifr_mtu; |
155 | | |
156 | | /* propogate */ |
157 | | zebra_interface_up_update(ifp); |
158 | | |
159 | | #else |
160 | | zlog_info("Can't lookup mtu on this system for %s(%u)", ifp->name, |
161 | | ifp->vrf->vrf_id); |
162 | | ifp->mtu6 = ifp->mtu = -1; |
163 | | #endif |
164 | | } |
165 | | #endif /* ! HAVE_NETLINK */ |
166 | | |
167 | | /* |
168 | | * Handler for interface address programming via the zebra dplane, |
169 | | * for non-netlink platforms. This handler dispatches to per-platform |
170 | | * helpers, based on the operation requested. |
171 | | */ |
172 | | #ifndef HAVE_NETLINK |
173 | | |
174 | | /* Prototypes: these are placed in this block so that they're only seen |
175 | | * on non-netlink platforms. |
176 | | */ |
177 | | static int if_set_prefix_ctx(const struct zebra_dplane_ctx *ctx); |
178 | | static int if_unset_prefix_ctx(const struct zebra_dplane_ctx *ctx); |
179 | | static int if_set_prefix6_ctx(const struct zebra_dplane_ctx *ctx); |
180 | | static int if_unset_prefix6_ctx(const struct zebra_dplane_ctx *ctx); |
181 | | |
182 | | enum zebra_dplane_result kernel_address_update_ctx( |
183 | | struct zebra_dplane_ctx *ctx) |
184 | | { |
185 | | int ret = -1; |
186 | | const struct prefix *p; |
187 | | |
188 | | p = dplane_ctx_get_intf_addr(ctx); |
189 | | |
190 | | if (dplane_ctx_get_op(ctx) == DPLANE_OP_ADDR_INSTALL) { |
191 | | if (p->family == AF_INET) |
192 | | ret = if_set_prefix_ctx(ctx); |
193 | | else |
194 | | ret = if_set_prefix6_ctx(ctx); |
195 | | } else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ADDR_UNINSTALL) { |
196 | | if (p->family == AF_INET) |
197 | | ret = if_unset_prefix_ctx(ctx); |
198 | | else |
199 | | ret = if_unset_prefix6_ctx(ctx); |
200 | | } else { |
201 | | if (IS_ZEBRA_DEBUG_DPLANE) |
202 | | zlog_debug("Invalid op in interface-addr install"); |
203 | | } |
204 | | |
205 | | return (ret == 0 ? |
206 | | ZEBRA_DPLANE_REQUEST_SUCCESS : ZEBRA_DPLANE_REQUEST_FAILURE); |
207 | | } |
208 | | |
209 | | #ifdef HAVE_STRUCT_IFALIASREQ |
210 | | |
211 | | /* |
212 | | * Helper for interface-addr install, non-netlink |
213 | | */ |
214 | | static int if_set_prefix_ctx(const struct zebra_dplane_ctx *ctx) |
215 | | { |
216 | | int ret; |
217 | | struct ifaliasreq addreq; |
218 | | struct sockaddr_in addr, mask, peer; |
219 | | struct prefix_ipv4 *p; |
220 | | |
221 | | p = (struct prefix_ipv4 *)dplane_ctx_get_intf_addr(ctx); |
222 | | |
223 | | memset(&addreq, 0, sizeof(addreq)); |
224 | | strlcpy((char *)&addreq.ifra_name, dplane_ctx_get_ifname(ctx), |
225 | | sizeof(addreq.ifra_name)); |
226 | | |
227 | | memset(&addr, 0, sizeof(addr)); |
228 | | addr.sin_addr = p->prefix; |
229 | | addr.sin_family = p->family; |
230 | | #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN |
231 | | addr.sin_len = sizeof(struct sockaddr_in); |
232 | | #endif |
233 | | memcpy(&addreq.ifra_addr, &addr, sizeof(struct sockaddr_in)); |
234 | | |
235 | | if (dplane_ctx_intf_is_connected(ctx)) { |
236 | | p = (struct prefix_ipv4 *)dplane_ctx_get_intf_dest(ctx); |
237 | | memset(&mask, 0, sizeof(mask)); |
238 | | peer.sin_addr = p->prefix; |
239 | | peer.sin_family = p->family; |
240 | | #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN |
241 | | peer.sin_len = sizeof(struct sockaddr_in); |
242 | | #endif |
243 | | memcpy(&addreq.ifra_broadaddr, &peer, |
244 | | sizeof(struct sockaddr_in)); |
245 | | } |
246 | | |
247 | | memset(&mask, 0, sizeof(mask)); |
248 | | masklen2ip(p->prefixlen, &mask.sin_addr); |
249 | | mask.sin_family = p->family; |
250 | | #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN |
251 | | mask.sin_len = sizeof(struct sockaddr_in); |
252 | | #endif |
253 | | memcpy(&addreq.ifra_mask, &mask, sizeof(struct sockaddr_in)); |
254 | | |
255 | | ret = if_ioctl(SIOCAIFADDR, (caddr_t)&addreq); |
256 | | if (ret < 0) |
257 | | return ret; |
258 | | return 0; |
259 | | |
260 | | } |
261 | | |
262 | | /* |
263 | | * Helper for interface-addr un-install, non-netlink |
264 | | */ |
265 | | static int if_unset_prefix_ctx(const struct zebra_dplane_ctx *ctx) |
266 | | { |
267 | | int ret; |
268 | | struct ifaliasreq addreq; |
269 | | struct sockaddr_in addr, mask, peer; |
270 | | struct prefix_ipv4 *p; |
271 | | |
272 | | p = (struct prefix_ipv4 *)dplane_ctx_get_intf_addr(ctx); |
273 | | |
274 | | memset(&addreq, 0, sizeof(addreq)); |
275 | | strlcpy((char *)&addreq.ifra_name, dplane_ctx_get_ifname(ctx), |
276 | | sizeof(addreq.ifra_name)); |
277 | | |
278 | | memset(&addr, 0, sizeof(addr)); |
279 | | addr.sin_addr = p->prefix; |
280 | | addr.sin_family = p->family; |
281 | | #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN |
282 | | addr.sin_len = sizeof(struct sockaddr_in); |
283 | | #endif |
284 | | memcpy(&addreq.ifra_addr, &addr, sizeof(struct sockaddr_in)); |
285 | | |
286 | | if (dplane_ctx_intf_is_connected(ctx)) { |
287 | | p = (struct prefix_ipv4 *)dplane_ctx_get_intf_dest(ctx); |
288 | | memset(&mask, 0, sizeof(mask)); |
289 | | peer.sin_addr = p->prefix; |
290 | | peer.sin_family = p->family; |
291 | | #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN |
292 | | peer.sin_len = sizeof(struct sockaddr_in); |
293 | | #endif |
294 | | memcpy(&addreq.ifra_broadaddr, &peer, |
295 | | sizeof(struct sockaddr_in)); |
296 | | } |
297 | | |
298 | | memset(&mask, 0, sizeof(mask)); |
299 | | masklen2ip(p->prefixlen, &mask.sin_addr); |
300 | | mask.sin_family = p->family; |
301 | | #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN |
302 | | mask.sin_len = sizeof(struct sockaddr_in); |
303 | | #endif |
304 | | memcpy(&addreq.ifra_mask, &mask, sizeof(struct sockaddr_in)); |
305 | | |
306 | | ret = if_ioctl(SIOCDIFADDR, (caddr_t)&addreq); |
307 | | if (ret < 0) |
308 | | return ret; |
309 | | return 0; |
310 | | } |
311 | | #else |
312 | | /* Set up interface's address, netmask (and broadcas? ). Linux or |
313 | | Solaris uses ifname:number semantics to set IP address aliases. */ |
314 | | int if_set_prefix_ctx(const struct zebra_dplane_ctx *ctx) |
315 | | { |
316 | | int ret; |
317 | | struct ifreq ifreq; |
318 | | struct sockaddr_in addr; |
319 | | struct sockaddr_in broad; |
320 | | struct sockaddr_in mask; |
321 | | struct prefix_ipv4 ifaddr; |
322 | | struct prefix_ipv4 *p; |
323 | | |
324 | | p = (struct prefix_ipv4 *)dplane_ctx_get_intf_addr(ctx); |
325 | | |
326 | | ifaddr = *p; |
327 | | |
328 | | strlcpy(ifreq.ifr_name, dplane_ctx_get_ifname(ctx), |
329 | | sizeof(ifreq.ifr_name)); |
330 | | |
331 | | addr.sin_addr = p->prefix; |
332 | | addr.sin_family = p->family; |
333 | | memcpy(&ifreq.ifr_addr, &addr, sizeof(struct sockaddr_in)); |
334 | | ret = if_ioctl(SIOCSIFADDR, (caddr_t)&ifreq); |
335 | | if (ret < 0) |
336 | | return ret; |
337 | | |
338 | | /* We need mask for make broadcast addr. */ |
339 | | masklen2ip(p->prefixlen, &mask.sin_addr); |
340 | | |
341 | | if (dplane_ctx_intf_is_broadcast(ctx)) { |
342 | | apply_mask_ipv4(&ifaddr); |
343 | | addr.sin_addr = ifaddr.prefix; |
344 | | |
345 | | broad.sin_addr.s_addr = |
346 | | (addr.sin_addr.s_addr | ~mask.sin_addr.s_addr); |
347 | | broad.sin_family = p->family; |
348 | | |
349 | | memcpy(&ifreq.ifr_broadaddr, &broad, |
350 | | sizeof(struct sockaddr_in)); |
351 | | ret = if_ioctl(SIOCSIFBRDADDR, (caddr_t)&ifreq); |
352 | | if (ret < 0) |
353 | | return ret; |
354 | | } |
355 | | |
356 | | mask.sin_family = p->family; |
357 | | memcpy(&ifreq.ifr_addr, &mask, sizeof(struct sockaddr_in)); |
358 | | ret = if_ioctl(SIOCSIFNETMASK, (caddr_t)&ifreq); |
359 | | if (ret < 0) |
360 | | return ret; |
361 | | |
362 | | return 0; |
363 | | } |
364 | | |
365 | | /* Set up interface's address, netmask (and broadcas? ). Linux or |
366 | | Solaris uses ifname:number semantics to set IP address aliases. */ |
367 | | int if_unset_prefix_ctx(const struct zebra_dplane_ctx *ctx) |
368 | | { |
369 | | int ret; |
370 | | struct ifreq ifreq; |
371 | | struct sockaddr_in addr; |
372 | | struct prefix_ipv4 *p; |
373 | | |
374 | | p = (struct prefix_ipv4 *)dplane_ctx_get_intf_addr(ctx); |
375 | | |
376 | | strlcpy(ifreq.ifr_name, dplane_ctx_get_ifname(ctx), |
377 | | sizeof(ifreq.ifr_name)); |
378 | | |
379 | | memset(&addr, 0, sizeof(addr)); |
380 | | addr.sin_family = p->family; |
381 | | memcpy(&ifreq.ifr_addr, &addr, sizeof(struct sockaddr_in)); |
382 | | ret = if_ioctl(SIOCSIFADDR, (caddr_t)&ifreq); |
383 | | if (ret < 0) |
384 | | return ret; |
385 | | |
386 | | return 0; |
387 | | } |
388 | | #endif /* HAVE_STRUCT_IFALIASREQ */ |
389 | | #endif /* HAVE_NETLINK */ |
390 | | |
391 | | /* get interface flags */ |
392 | | void if_get_flags(struct interface *ifp) |
393 | 0 | { |
394 | 0 | int ret; |
395 | 0 | struct ifreq ifreqflags = {}; |
396 | 0 | struct ifreq ifreqdata = {}; |
397 | |
|
398 | 0 | ifreq_set_name(&ifreqflags, ifp); |
399 | 0 | ifreq_set_name(&ifreqdata, ifp); |
400 | |
|
401 | 0 | ret = vrf_if_ioctl(SIOCGIFFLAGS, (caddr_t)&ifreqflags, |
402 | 0 | ifp->vrf->vrf_id); |
403 | 0 | if (ret < 0) { |
404 | 0 | flog_err_sys(EC_LIB_SYSTEM_CALL, |
405 | 0 | "vrf_if_ioctl(SIOCGIFFLAGS %s) failed: %s", |
406 | 0 | ifp->name, safe_strerror(errno)); |
407 | 0 | return; |
408 | 0 | } |
409 | | |
410 | 0 | if (!CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION)) |
411 | 0 | goto out; |
412 | | |
413 | | /* Per-default, IFF_RUNNING is held high, unless link-detect |
414 | | * says otherwise - we abuse IFF_RUNNING inside zebra as a |
415 | | * link-state flag, following practice on Linux and Solaris |
416 | | * kernels |
417 | | */ |
418 | | |
419 | | #ifdef SIOCGIFDATA |
420 | | /* |
421 | | * BSD gets link state from ifi_link_link in struct if_data. |
422 | | * All BSD's have this in getifaddrs(3) ifa_data for AF_LINK |
423 | | * addresses. We can also access it via SIOCGIFDATA. |
424 | | */ |
425 | | |
426 | | #ifdef __NetBSD__ |
427 | | struct ifdatareq ifdr = {.ifdr_data.ifi_link_state = 0}; |
428 | | struct if_data *ifdata = &ifdr.ifdr_data; |
429 | | |
430 | | strlcpy(ifdr.ifdr_name, ifp->name, sizeof(ifdr.ifdr_name)); |
431 | | ret = vrf_if_ioctl(SIOCGIFDATA, (caddr_t)&ifdr, ifp->vrf->vrf_id); |
432 | | #else |
433 | | struct if_data ifd = {.ifi_link_state = 0}; |
434 | | struct if_data *ifdata = &ifd; |
435 | | |
436 | | ifreqdata.ifr_data = (caddr_t)ifdata; |
437 | | ret = vrf_if_ioctl(SIOCGIFDATA, (caddr_t)&ifreqdata, ifp->vrf->vrf_id); |
438 | | #endif |
439 | | |
440 | | if (ret == -1) |
441 | | /* Very unlikely. Did the interface disappear? */ |
442 | | flog_err_sys(EC_LIB_SYSTEM_CALL, |
443 | | "if_ioctl(SIOCGIFDATA %s) failed: %s", ifp->name, |
444 | | safe_strerror(errno)); |
445 | | else { |
446 | | if (ifdata->ifi_link_state >= LINK_STATE_UP) |
447 | | SET_FLAG(ifreqflags.ifr_flags, IFF_RUNNING); |
448 | | else if (ifdata->ifi_link_state == LINK_STATE_UNKNOWN) |
449 | | /* BSD traditionally treats UNKNOWN as UP */ |
450 | | SET_FLAG(ifreqflags.ifr_flags, IFF_RUNNING); |
451 | | else |
452 | | UNSET_FLAG(ifreqflags.ifr_flags, IFF_RUNNING); |
453 | | } |
454 | | |
455 | | #elif defined(HAVE_BSD_LINK_DETECT) |
456 | | /* |
457 | | * This is only needed for FreeBSD older than FreeBSD-13. |
458 | | * Valid and active media generally means the link state is |
459 | | * up, but this is not always the case. |
460 | | * For example, some BSD's with a net80211 interface in MONITOR |
461 | | * mode will treat the media as valid and active but the |
462 | | * link state is down - because we cannot send anything. |
463 | | * Also, virtual interfaces such as PPP, VLAN, etc generally |
464 | | * don't support media at all, so the ioctl will just fail. |
465 | | */ |
466 | | struct ifmediareq ifmr = {.ifm_status = 0}; |
467 | | |
468 | | strlcpy(ifmr.ifm_name, ifp->name, sizeof(ifmr.ifm_name)); |
469 | | |
470 | | if (if_ioctl(SIOCGIFMEDIA, (caddr_t)&ifmr) == -1) { |
471 | | if (errno != EINVAL) |
472 | | flog_err_sys(EC_LIB_SYSTEM_CALL, |
473 | | "if_ioctl(SIOCGIFMEDIA %s) failed: %s", |
474 | | ifp->name, safe_strerror(errno)); |
475 | | } else if (ifmr.ifm_status & IFM_AVALID) { /* media state is valid */ |
476 | | if (ifmr.ifm_status & IFM_ACTIVE) /* media is active */ |
477 | | SET_FLAG(ifreqflags.ifr_flags, IFF_RUNNING); |
478 | | else |
479 | | UNSET_FLAG(ifreqflags.ifr_flags, IFF_RUNNING); |
480 | | } |
481 | | #endif /* HAVE_BSD_LINK_DETECT */ |
482 | | |
483 | 0 | out: |
484 | 0 | if_flags_update(ifp, (ifreqflags.ifr_flags & 0x0000ffff)); |
485 | 0 | } |
486 | | |
487 | | /* Set interface flags */ |
488 | | int if_set_flags(struct interface *ifp, uint64_t flags) |
489 | 0 | { |
490 | 0 | int ret; |
491 | 0 | struct ifreq ifreq; |
492 | |
|
493 | 0 | memset(&ifreq, 0, sizeof(ifreq)); |
494 | 0 | ifreq_set_name(&ifreq, ifp); |
495 | |
|
496 | 0 | ifreq.ifr_flags = ifp->flags; |
497 | 0 | ifreq.ifr_flags |= flags; |
498 | |
|
499 | 0 | ret = vrf_if_ioctl(SIOCSIFFLAGS, (caddr_t)&ifreq, ifp->vrf->vrf_id); |
500 | |
|
501 | 0 | if (ret < 0) { |
502 | 0 | zlog_info("can't set interface %s(%u) flags %" PRIu64, |
503 | 0 | ifp->name, ifp->vrf->vrf_id, flags); |
504 | 0 | return ret; |
505 | 0 | } |
506 | 0 | return 0; |
507 | 0 | } |
508 | | |
509 | | /* Unset interface's flag. */ |
510 | | int if_unset_flags(struct interface *ifp, uint64_t flags) |
511 | 0 | { |
512 | 0 | int ret; |
513 | 0 | struct ifreq ifreq; |
514 | |
|
515 | 0 | memset(&ifreq, 0, sizeof(ifreq)); |
516 | 0 | ifreq_set_name(&ifreq, ifp); |
517 | |
|
518 | 0 | ifreq.ifr_flags = ifp->flags; |
519 | 0 | ifreq.ifr_flags &= ~flags; |
520 | |
|
521 | 0 | ret = vrf_if_ioctl(SIOCSIFFLAGS, (caddr_t)&ifreq, ifp->vrf->vrf_id); |
522 | |
|
523 | 0 | if (ret < 0) { |
524 | 0 | zlog_warn("can't unset interface %s(%u) flags %" PRIu64, |
525 | 0 | ifp->name, ifp->vrf->vrf_id, flags); |
526 | 0 | return ret; |
527 | 0 | } |
528 | 0 | return 0; |
529 | 0 | } |
530 | | |
531 | | #ifndef LINUX_IPV6 /* Netlink has its own code */ |
532 | | |
533 | | #ifdef HAVE_STRUCT_IN6_ALIASREQ |
534 | | #ifndef ND6_INFINITE_LIFETIME |
535 | | #define ND6_INFINITE_LIFETIME 0xffffffffL |
536 | | #endif /* ND6_INFINITE_LIFETIME */ |
537 | | |
538 | | /* |
539 | | * Helper for interface-addr install, non-netlink |
540 | | */ |
541 | | static int if_set_prefix6_ctx(const struct zebra_dplane_ctx *ctx) |
542 | | { |
543 | | int ret; |
544 | | struct in6_aliasreq addreq; |
545 | | struct sockaddr_in6 addr; |
546 | | struct sockaddr_in6 mask; |
547 | | struct prefix_ipv6 *p; |
548 | | |
549 | | p = (struct prefix_ipv6 *)dplane_ctx_get_intf_addr(ctx); |
550 | | |
551 | | memset(&addreq, 0, sizeof(addreq)); |
552 | | strlcpy((char *)&addreq.ifra_name, |
553 | | dplane_ctx_get_ifname(ctx), sizeof(addreq.ifra_name)); |
554 | | |
555 | | memset(&addr, 0, sizeof(addr)); |
556 | | addr.sin6_addr = p->prefix; |
557 | | addr.sin6_family = p->family; |
558 | | #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN |
559 | | addr.sin6_len = sizeof(struct sockaddr_in6); |
560 | | #endif |
561 | | memcpy(&addreq.ifra_addr, &addr, sizeof(struct sockaddr_in6)); |
562 | | |
563 | | memset(&mask, 0, sizeof(mask)); |
564 | | masklen2ip6(p->prefixlen, &mask.sin6_addr); |
565 | | mask.sin6_family = p->family; |
566 | | #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN |
567 | | mask.sin6_len = sizeof(struct sockaddr_in6); |
568 | | #endif |
569 | | memcpy(&addreq.ifra_prefixmask, &mask, sizeof(struct sockaddr_in6)); |
570 | | |
571 | | addreq.ifra_lifetime.ia6t_vltime = 0xffffffff; |
572 | | addreq.ifra_lifetime.ia6t_pltime = 0xffffffff; |
573 | | |
574 | | #ifdef HAVE_STRUCT_IF6_ALIASREQ_IFRA_LIFETIME |
575 | | addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; |
576 | | addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; |
577 | | #endif |
578 | | |
579 | | ret = if_ioctl_ipv6(SIOCAIFADDR_IN6, (caddr_t)&addreq); |
580 | | if (ret < 0) |
581 | | return ret; |
582 | | return 0; |
583 | | } |
584 | | |
585 | | /* |
586 | | * Helper for interface-addr un-install, non-netlink |
587 | | */ |
588 | | static int if_unset_prefix6_ctx(const struct zebra_dplane_ctx *ctx) |
589 | | { |
590 | | int ret; |
591 | | struct in6_aliasreq addreq; |
592 | | struct sockaddr_in6 addr; |
593 | | struct sockaddr_in6 mask; |
594 | | struct prefix_ipv6 *p; |
595 | | |
596 | | p = (struct prefix_ipv6 *)dplane_ctx_get_intf_addr(ctx); |
597 | | |
598 | | memset(&addreq, 0, sizeof(addreq)); |
599 | | strlcpy((char *)&addreq.ifra_name, |
600 | | dplane_ctx_get_ifname(ctx), sizeof(addreq.ifra_name)); |
601 | | |
602 | | memset(&addr, 0, sizeof(addr)); |
603 | | addr.sin6_addr = p->prefix; |
604 | | addr.sin6_family = p->family; |
605 | | #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN |
606 | | addr.sin6_len = sizeof(struct sockaddr_in6); |
607 | | #endif |
608 | | memcpy(&addreq.ifra_addr, &addr, sizeof(struct sockaddr_in6)); |
609 | | |
610 | | memset(&mask, 0, sizeof(mask)); |
611 | | masklen2ip6(p->prefixlen, &mask.sin6_addr); |
612 | | mask.sin6_family = p->family; |
613 | | #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN |
614 | | mask.sin6_len = sizeof(struct sockaddr_in6); |
615 | | #endif |
616 | | memcpy(&addreq.ifra_prefixmask, &mask, sizeof(struct sockaddr_in6)); |
617 | | |
618 | | #ifdef HAVE_STRUCT_IF6_ALIASREQ_IFRA_LIFETIME |
619 | | addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; |
620 | | addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; |
621 | | #endif |
622 | | |
623 | | ret = if_ioctl_ipv6(SIOCDIFADDR_IN6, (caddr_t)&addreq); |
624 | | if (ret < 0) |
625 | | return ret; |
626 | | return 0; |
627 | | } |
628 | | #else |
629 | | /* The old, pre-dataplane code here just returned, so we're retaining that |
630 | | * choice. |
631 | | */ |
632 | | static int if_set_prefix6_ctx(const struct zebra_dplane_ctx *ctx) |
633 | | { |
634 | | return 0; |
635 | | } |
636 | | |
637 | | static int if_unset_prefix6_ctx(const struct zebra_dplane_ctx *ctx) |
638 | | { |
639 | | return 0; |
640 | | } |
641 | | #endif /* HAVE_STRUCT_IN6_ALIASREQ */ |
642 | | |
643 | | #endif /* LINUX_IPV6 */ |