Coverage Report

Created: 2026-03-21 06:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/frr/zebra/ioctl.c
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 */