]> git.proxmox.com Git - mirror_frr.git/blame - zebra/ioctl.c
bgpd: Refactor subgroup_announce_table() to reuse an existing helpers
[mirror_frr.git] / zebra / ioctl.c
CommitLineData
acddc0ed 1// SPDX-License-Identifier: GPL-2.0-or-later
718e3744 2/*
3 * Common ioctl functions.
4 * Copyright (C) 1997, 98 Kunihiro Ishiguro
718e3744 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"
edd7c245 14#include "privs.h"
174482ef 15#include "lib_errors.h"
718e3744 16
5e6a74d8 17#include "vty.h"
718e3744 18#include "zebra/rib.h"
19#include "zebra/rt.h"
5c78b3d0 20#include "zebra/interface.h"
364fed6b 21#include "zebra/zebra_errors.h"
0f1f6ce4 22#include "zebra/debug.h"
718e3744 23
55edb0d4
AS
24#ifdef HAVE_BSD_LINK_DETECT
25#include <net/if_media.h>
26#endif /* HAVE_BSD_LINK_DETECT*/
27
edd7c245 28extern struct zebra_privs_t zserv_privs;
29
718e3744 30/* clear and set interface name string */
d62a17ae 31void ifreq_set_name(struct ifreq *ifreq, struct interface *ifp)
718e3744 32{
0af35d90 33 strlcpy(ifreq->ifr_name, ifp->name, sizeof(ifreq->ifr_name));
718e3744 34}
35
388907d5 36#ifndef HAVE_NETLINK
718e3744 37/* call ioctl system call */
d7c0a89a 38int if_ioctl(unsigned long request, caddr_t buffer)
718e3744 39{
d62a17ae 40 int sock;
41 int ret;
42 int err = 0;
43
0cf6db21 44 frr_with_privs(&zserv_privs) {
01b9e3fd
DL
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;
d62a17ae 53 }
d62a17ae 54 close(sock);
55
56 if (ret < 0) {
57 errno = err;
58 return ret;
59 }
60 return 0;
718e3744 61}
388907d5 62#endif
718e3744 63
4db21619 64/* call ioctl system call */
d7c0a89a 65int vrf_if_ioctl(unsigned long request, caddr_t buffer, vrf_id_t vrf_id)
4db21619
PG
66{
67 int sock;
68 int ret;
69 int err = 0;
70
0cf6db21 71 frr_with_privs(&zserv_privs) {
01b9e3fd
DL
72 sock = vrf_socket(AF_INET, SOCK_DGRAM, 0, vrf_id, NULL);
73 if (sock < 0) {
74 zlog_err("Cannot create UDP socket: %s",
75 safe_strerror(errno));
76 exit(1);
77 }
78 ret = vrf_ioctl(vrf_id, sock, request, buffer);
79 if (ret < 0)
80 err = errno;
4db21619 81 }
4db21619
PG
82 close(sock);
83
84 if (ret < 0) {
85 errno = err;
86 return ret;
87 }
88 return 0;
89}
90
e86b71f1 91#ifndef HAVE_NETLINK
d7c0a89a 92static int if_ioctl_ipv6(unsigned long request, caddr_t buffer)
718e3744 93{
d62a17ae 94 int sock;
95 int ret;
96 int err = 0;
97
0cf6db21 98 frr_with_privs(&zserv_privs) {
01b9e3fd
DL
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 }
d62a17ae 105
01b9e3fd
DL
106 if ((ret = ioctl(sock, request, buffer)) < 0)
107 err = errno;
108 }
d62a17ae 109 close(sock);
110
111 if (ret < 0) {
112 errno = err;
113 return ret;
114 }
115 return 0;
718e3744 116}
718e3744 117
118/*
119 * get interface metric
120 * -- if value is not avaliable set -1
121 */
d62a17ae 122void if_get_metric(struct interface *ifp)
718e3744 123{
124#ifdef SIOCGIFMETRIC
ceacdc72 125 struct ifreq ifreq = {};
718e3744 126
d62a17ae 127 ifreq_set_name(&ifreq, ifp);
718e3744 128
096f7609 129 if (vrf_if_ioctl(SIOCGIFMETRIC, (caddr_t)&ifreq, ifp->vrf->vrf_id) < 0)
d62a17ae 130 return;
131 ifp->metric = ifreq.ifr_metric;
132 if (ifp->metric == 0)
133 ifp->metric = 1;
134#else /* SIOCGIFMETRIC */
135 ifp->metric = -1;
718e3744 136#endif /* SIOCGIFMETRIC */
137}
138
139/* get interface MTU */
d62a17ae 140void if_get_mtu(struct interface *ifp)
718e3744 141{
ceacdc72 142 struct ifreq ifreq = {};
718e3744 143
d62a17ae 144 ifreq_set_name(&ifreq, ifp);
718e3744 145
146#if defined(SIOCGIFMTU)
096f7609 147 if (vrf_if_ioctl(SIOCGIFMTU, (caddr_t)&ifreq, ifp->vrf->vrf_id) < 0) {
7c4910ce
DS
148 zlog_info("Can't lookup mtu by ioctl(SIOCGIFMTU) for %s(%u)",
149 ifp->name, ifp->vrf->vrf_id);
d62a17ae 150 ifp->mtu6 = ifp->mtu = -1;
151 return;
152 }
718e3744 153
d62a17ae 154 ifp->mtu6 = ifp->mtu = ifreq.ifr_mtu;
718e3744 155
d62a17ae 156 /* propogate */
157 zebra_interface_up_update(ifp);
f5e004f7 158
718e3744 159#else
7c4910ce
DS
160 zlog_info("Can't lookup mtu on this system for %s(%u)", ifp->name,
161 ifp->vrf->vrf_id);
d62a17ae 162 ifp->mtu6 = ifp->mtu = -1;
718e3744 163#endif
164}
388907d5 165#endif /* ! HAVE_NETLINK */
718e3744 166
64168803 167/*
0f1f6ce4
MS
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.
64168803
MS
171 */
172#ifndef HAVE_NETLINK
173
0f1f6ce4
MS
174/* Prototypes: these are placed in this block so that they're only seen
175 * on non-netlink platforms.
176 */
177static int if_set_prefix_ctx(const struct zebra_dplane_ctx *ctx);
178static int if_unset_prefix_ctx(const struct zebra_dplane_ctx *ctx);
179static int if_set_prefix6_ctx(const struct zebra_dplane_ctx *ctx);
180static int if_unset_prefix6_ctx(const struct zebra_dplane_ctx *ctx);
181
64168803
MS
182enum zebra_dplane_result kernel_address_update_ctx(
183 struct zebra_dplane_ctx *ctx)
184{
0f1f6ce4
MS
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);
64168803
MS
207}
208
0f1f6ce4
MS
209#ifdef HAVE_STRUCT_IFALIASREQ
210
211/*
212 * Helper for interface-addr install, non-netlink
213 */
214static int if_set_prefix_ctx(const struct zebra_dplane_ctx *ctx)
718e3744 215{
0f1f6ce4
MS
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));
fcb072cd 224 strlcpy((char *)&addreq.ifra_name, dplane_ctx_get_ifname(ctx),
0f1f6ce4
MS
225 sizeof(addreq.ifra_name));
226
6006b807 227 memset(&addr, 0, sizeof(addr));
0f1f6ce4
MS
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);
6006b807 237 memset(&mask, 0, sizeof(mask));
0f1f6ce4
MS
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
6006b807 247 memset(&mask, 0, sizeof(mask));
0f1f6ce4
MS
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
718e3744 260}
261
0f1f6ce4
MS
262/*
263 * Helper for interface-addr un-install, non-netlink
264 */
265static int if_unset_prefix_ctx(const struct zebra_dplane_ctx *ctx)
718e3744 266{
0f1f6ce4
MS
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));
fcb072cd 275 strlcpy((char *)&addreq.ifra_name, dplane_ctx_get_ifname(ctx),
0f1f6ce4
MS
276 sizeof(addreq.ifra_name));
277
6006b807 278 memset(&addr, 0, sizeof(addr));
0f1f6ce4
MS
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);
6006b807 288 memset(&mask, 0, sizeof(mask));
0f1f6ce4
MS
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
6006b807 298 memset(&mask, 0, sizeof(mask));
0f1f6ce4
MS
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;
718e3744 310}
718e3744 311#else
312/* Set up interface's address, netmask (and broadcas? ). Linux or
313 Solaris uses ifname:number semantics to set IP address aliases. */
39fa2825 314int if_set_prefix_ctx(const struct zebra_dplane_ctx *ctx)
718e3744 315{
d62a17ae 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
39fa2825 324 p = (struct prefix_ipv4 *)dplane_ctx_get_intf_addr(ctx);
d62a17ae 325
326 ifaddr = *p;
327
39fa2825
MS
328 strlcpy(ifreq.ifr_name, dplane_ctx_get_ifname(ctx),
329 sizeof(ifreq.ifr_name));
d62a17ae 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
39fa2825 341 if (dplane_ctx_intf_is_broadcast(ctx)) {
d62a17ae 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;
39fa2825 357 memcpy(&ifreq.ifr_addr, &mask, sizeof(struct sockaddr_in));
d62a17ae 358 ret = if_ioctl(SIOCSIFNETMASK, (caddr_t)&ifreq);
359 if (ret < 0)
360 return ret;
718e3744 361
d62a17ae 362 return 0;
718e3744 363}
364
365/* Set up interface's address, netmask (and broadcas? ). Linux or
366 Solaris uses ifname:number semantics to set IP address aliases. */
39fa2825 367int if_unset_prefix_ctx(const struct zebra_dplane_ctx *ctx)
718e3744 368{
d62a17ae 369 int ret;
370 struct ifreq ifreq;
371 struct sockaddr_in addr;
372 struct prefix_ipv4 *p;
718e3744 373
39fa2825 374 p = (struct prefix_ipv4 *)dplane_ctx_get_intf_addr(ctx);
718e3744 375
39fa2825
MS
376 strlcpy(ifreq.ifr_name, dplane_ctx_get_ifname(ctx),
377 sizeof(ifreq.ifr_name));
718e3744 378
6006b807 379 memset(&addr, 0, sizeof(addr));
d62a17ae 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;
718e3744 385
d62a17ae 386 return 0;
718e3744 387}
6f0e3f6e 388#endif /* HAVE_STRUCT_IFALIASREQ */
718e3744 389#endif /* HAVE_NETLINK */
390
391/* get interface flags */
d62a17ae 392void if_get_flags(struct interface *ifp)
718e3744 393{
d62a17ae 394 int ret;
ceacdc72
DS
395 struct ifreq ifreqflags = {};
396 struct ifreq ifreqdata = {};
718e3744 397
16dca7ce
B
398 ifreq_set_name(&ifreqflags, ifp);
399 ifreq_set_name(&ifreqdata, ifp);
718e3744 400
16dca7ce
B
401 ret = vrf_if_ioctl(SIOCGIFFLAGS, (caddr_t)&ifreqflags,
402 ifp->vrf->vrf_id);
d62a17ae 403 if (ret < 0) {
450971aa 404 flog_err_sys(EC_LIB_SYSTEM_CALL,
98f3df55
RM
405 "vrf_if_ioctl(SIOCGIFFLAGS %s) failed: %s",
406 ifp->name, safe_strerror(errno));
d62a17ae 407 return;
408 }
0b3f3d47 409
98f3df55
RM
410 if (!CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION))
411 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));
096f7609 431 ret = vrf_if_ioctl(SIOCGIFDATA, (caddr_t)&ifdr, ifp->vrf->vrf_id);
98f3df55
RM
432#else
433 struct if_data ifd = {.ifi_link_state = 0};
434 struct if_data *ifdata = &ifd;
435
16dca7ce
B
436 ifreqdata.ifr_data = (caddr_t)ifdata;
437 ret = vrf_if_ioctl(SIOCGIFDATA, (caddr_t)&ifreqdata, ifp->vrf->vrf_id);
98f3df55
RM
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)
16dca7ce 447 SET_FLAG(ifreqflags.ifr_flags, IFF_RUNNING);
98f3df55
RM
448 else if (ifdata->ifi_link_state == LINK_STATE_UNKNOWN)
449 /* BSD traditionally treats UNKNOWN as UP */
16dca7ce 450 SET_FLAG(ifreqflags.ifr_flags, IFF_RUNNING);
98f3df55 451 else
16dca7ce 452 UNSET_FLAG(ifreqflags.ifr_flags, IFF_RUNNING);
98f3df55
RM
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.
d62a17ae 465 */
98f3df55 466 struct ifmediareq ifmr = {.ifm_status = 0};
d62a17ae 467
98f3df55 468 strlcpy(ifmr.ifm_name, ifp->name, sizeof(ifmr.ifm_name));
d62a17ae 469
98f3df55
RM
470 if (if_ioctl(SIOCGIFMEDIA, (caddr_t)&ifmr) == -1) {
471 if (errno != EINVAL)
450971aa 472 flog_err_sys(EC_LIB_SYSTEM_CALL,
98f3df55
RM
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 */
16dca7ce 477 SET_FLAG(ifreqflags.ifr_flags, IFF_RUNNING);
98f3df55 478 else
16dca7ce 479 UNSET_FLAG(ifreqflags.ifr_flags, IFF_RUNNING);
d62a17ae 480 }
c543a173 481#endif /* HAVE_BSD_LINK_DETECT */
718e3744 482
98f3df55 483out:
16dca7ce 484 if_flags_update(ifp, (ifreqflags.ifr_flags & 0x0000ffff));
718e3744 485}
486
487/* Set interface flags */
d62a17ae 488int if_set_flags(struct interface *ifp, uint64_t flags)
718e3744 489{
d62a17ae 490 int ret;
491 struct ifreq ifreq;
718e3744 492
6006b807 493 memset(&ifreq, 0, sizeof(ifreq));
d62a17ae 494 ifreq_set_name(&ifreq, ifp);
718e3744 495
d62a17ae 496 ifreq.ifr_flags = ifp->flags;
497 ifreq.ifr_flags |= flags;
718e3744 498
096f7609 499 ret = vrf_if_ioctl(SIOCSIFFLAGS, (caddr_t)&ifreq, ifp->vrf->vrf_id);
718e3744 500
d62a17ae 501 if (ret < 0) {
7c4910ce
DS
502 zlog_info("can't set interface %s(%u) flags %" PRIu64,
503 ifp->name, ifp->vrf->vrf_id, flags);
d62a17ae 504 return ret;
505 }
506 return 0;
718e3744 507}
508
509/* Unset interface's flag. */
d62a17ae 510int if_unset_flags(struct interface *ifp, uint64_t flags)
718e3744 511{
d62a17ae 512 int ret;
513 struct ifreq ifreq;
718e3744 514
6006b807 515 memset(&ifreq, 0, sizeof(ifreq));
d62a17ae 516 ifreq_set_name(&ifreq, ifp);
718e3744 517
d62a17ae 518 ifreq.ifr_flags = ifp->flags;
519 ifreq.ifr_flags &= ~flags;
718e3744 520
096f7609 521 ret = vrf_if_ioctl(SIOCSIFFLAGS, (caddr_t)&ifreq, ifp->vrf->vrf_id);
718e3744 522
d62a17ae 523 if (ret < 0) {
7c4910ce
DS
524 zlog_warn("can't unset interface %s(%u) flags %" PRIu64,
525 ifp->name, ifp->vrf->vrf_id, flags);
d62a17ae 526 return ret;
527 }
528 return 0;
718e3744 529}
530
39fa2825 531#ifndef LINUX_IPV6 /* Netlink has its own code */
718e3744 532
6f0e3f6e 533#ifdef HAVE_STRUCT_IN6_ALIASREQ
718e3744 534#ifndef ND6_INFINITE_LIFETIME
535#define ND6_INFINITE_LIFETIME 0xffffffffL
536#endif /* ND6_INFINITE_LIFETIME */
0f1f6ce4
MS
537
538/*
539 * Helper for interface-addr install, non-netlink
540 */
541static 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));
39fa2825 552 strlcpy((char *)&addreq.ifra_name,
0f1f6ce4
MS
553 dplane_ctx_get_ifname(ctx), sizeof(addreq.ifra_name));
554
6006b807 555 memset(&addr, 0, sizeof(addr));
0f1f6ce4
MS
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
6006b807 563 memset(&mask, 0, sizeof(mask));
0f1f6ce4
MS
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 */
588static 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));
39fa2825 599 strlcpy((char *)&addreq.ifra_name,
0f1f6ce4
MS
600 dplane_ctx_get_ifname(ctx), sizeof(addreq.ifra_name));
601
6006b807 602 memset(&addr, 0, sizeof(addr));
0f1f6ce4
MS
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
6006b807 610 memset(&mask, 0, sizeof(mask));
0f1f6ce4
MS
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
6f0e3f6e 618#ifdef HAVE_STRUCT_IF6_ALIASREQ_IFRA_LIFETIME
d62a17ae 619 addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
620 addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
726f9b2b 621#endif
718e3744 622
d62a17ae 623 ret = if_ioctl_ipv6(SIOCDIFADDR_IN6, (caddr_t)&addreq);
624 if (ret < 0)
625 return ret;
626 return 0;
718e3744 627}
628#else
39fa2825
MS
629/* The old, pre-dataplane code here just returned, so we're retaining that
630 * choice.
631 */
632static int if_set_prefix6_ctx(const struct zebra_dplane_ctx *ctx)
718e3744 633{
d62a17ae 634 return 0;
718e3744 635}
636
39fa2825 637static int if_unset_prefix6_ctx(const struct zebra_dplane_ctx *ctx)
718e3744 638{
d62a17ae 639 return 0;
718e3744 640}
6f0e3f6e 641#endif /* HAVE_STRUCT_IN6_ALIASREQ */
718e3744 642
643#endif /* LINUX_IPV6 */