Coverage Report

Created: 2026-07-16 06:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/frr/zebra/connected.c
Line
Count
Source
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
 * Address linked list routine.
4
 * Copyright (C) 1997, 98 Kunihiro Ishiguro
5
 */
6
7
#include <zebra.h>
8
9
#include "prefix.h"
10
#include "linklist.h"
11
#include "if.h"
12
#include "table.h"
13
#include "rib.h"
14
#include "table.h"
15
#include "log.h"
16
#include "memory.h"
17
18
#include "vty.h"
19
#include "zebra/debug.h"
20
#include "zebra/zserv.h"
21
#include "zebra/redistribute.h"
22
#include "zebra/interface.h"
23
#include "zebra/connected.h"
24
#include "zebra/rtadv.h"
25
#include "zebra/zebra_mpls.h"
26
#include "zebra/zebra_errors.h"
27
#include "zebra/zebra_router.h"
28
29
/* communicate the withdrawal of a connected address */
30
static void connected_withdraw(struct connected *ifc)
31
0
{
32
0
  if (!ifc)
33
0
    return;
34
35
  /* Update interface address information to protocol daemon. */
36
0
  if (CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL)) {
37
0
    zebra_interface_address_delete_update(ifc->ifp, ifc);
38
39
0
    if (ifc->address->family == AF_INET)
40
0
      if_subnet_delete(ifc->ifp, ifc);
41
42
0
    connected_down(ifc->ifp, ifc);
43
44
0
    UNSET_FLAG(ifc->conf, ZEBRA_IFC_REAL);
45
0
  }
46
47
  /* The address is not in the kernel anymore, so clear the flag */
48
0
  UNSET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED);
49
50
0
  if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED)) {
51
0
    listnode_delete(ifc->ifp->connected, ifc);
52
0
    connected_free(&ifc);
53
0
  }
54
0
}
55
56
static void connected_announce(struct interface *ifp, struct connected *ifc)
57
0
{
58
0
  if (!ifc)
59
0
    return;
60
61
0
  if (!if_is_loopback(ifp) && ifc->address->family == AF_INET) {
62
0
    if (ifc->address->prefixlen == IPV4_MAX_BITLEN)
63
0
      SET_FLAG(ifc->flags, ZEBRA_IFA_UNNUMBERED);
64
0
    else
65
0
      UNSET_FLAG(ifc->flags, ZEBRA_IFA_UNNUMBERED);
66
0
  }
67
68
0
  listnode_add(ifp->connected, ifc);
69
70
  /* Update interface address information to protocol daemon. */
71
0
  if (ifc->address->family == AF_INET)
72
0
    if_subnet_add(ifp, ifc);
73
74
0
  zebra_interface_address_add_update(ifp, ifc);
75
76
0
  if (if_is_operative(ifp)) {
77
0
    connected_up(ifp, ifc);
78
0
  }
79
0
}
80
81
/* If same interface address is already exist... */
82
struct connected *connected_check(struct interface *ifp,
83
          union prefixconstptr pu)
84
0
{
85
0
  const struct prefix *p = pu.p;
86
0
  struct connected *ifc;
87
0
  struct listnode *node;
88
89
0
  for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc))
90
0
    if (prefix_same(ifc->address, p))
91
0
      return ifc;
92
93
0
  return NULL;
94
0
}
95
96
/* same, but with peer address */
97
struct connected *connected_check_ptp(struct interface *ifp,
98
              union prefixconstptr pu,
99
              union prefixconstptr du)
100
0
{
101
0
  const struct prefix *p = pu.p;
102
0
  const struct prefix *d = du.p;
103
0
  struct connected *ifc;
104
0
  struct listnode *node;
105
106
0
  for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
107
0
    if (!prefix_same(ifc->address, p))
108
0
      continue;
109
0
    if (!CONNECTED_PEER(ifc) && !d)
110
0
      return ifc;
111
0
    if (CONNECTED_PEER(ifc) && d
112
0
        && prefix_same(ifc->destination, d))
113
0
      return ifc;
114
0
  }
115
116
0
  return NULL;
117
0
}
118
119
/* Check if two ifc's describe the same address in the same state */
120
static int connected_same(struct connected *ifc1, struct connected *ifc2)
121
0
{
122
0
  if (ifc1->ifp != ifc2->ifp)
123
0
    return 0;
124
125
0
  if (ifc1->flags != ifc2->flags)
126
0
    return 0;
127
128
0
  if (ifc1->conf != ifc2->conf)
129
0
    return 0;
130
131
0
  if (ifc1->destination)
132
0
    if (!ifc2->destination)
133
0
      return 0;
134
0
  if (ifc2->destination)
135
0
    if (!ifc1->destination)
136
0
      return 0;
137
138
0
  if (ifc1->destination && ifc2->destination)
139
0
    if (!prefix_same(ifc1->destination, ifc2->destination))
140
0
      return 0;
141
142
0
  return 1;
143
0
}
144
145
/* Handle changes to addresses and send the neccesary announcements
146
 * to clients. */
147
static void connected_update(struct interface *ifp, struct connected *ifc)
148
0
{
149
0
  struct connected *current;
150
151
  /* Check same connected route. */
152
0
  current = connected_check_ptp(ifp, ifc->address, ifc->destination);
153
0
  if (current) {
154
0
    if (CHECK_FLAG(current->conf, ZEBRA_IFC_CONFIGURED))
155
0
      SET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED);
156
157
    /* Avoid spurious withdraws, this might be just the kernel
158
     * 'reflecting'
159
     * back an address we have already added.
160
     */
161
0
    if (connected_same(current, ifc)) {
162
      /* nothing to do */
163
0
      connected_free(&ifc);
164
0
      return;
165
0
    }
166
167
    /* Clear the configured flag on the old ifc, so it will be freed
168
     * by
169
     * connected withdraw. */
170
0
    UNSET_FLAG(current->conf, ZEBRA_IFC_CONFIGURED);
171
0
    connected_withdraw(
172
0
      current); /* implicit withdraw - freebsd does this */
173
0
  }
174
175
  /* If the connected is new or has changed, announce it, if it is usable
176
   */
177
0
  if (CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL))
178
0
    connected_announce(ifp, ifc);
179
0
}
180
181
/* Called from if_up(). */
182
void connected_up(struct interface *ifp, struct connected *ifc)
183
0
{
184
0
  afi_t afi;
185
0
  struct prefix p;
186
0
  struct nexthop nh = {
187
0
    .type = NEXTHOP_TYPE_IFINDEX,
188
0
    .ifindex = ifp->ifindex,
189
0
    .vrf_id = ifp->vrf->vrf_id,
190
0
  };
191
0
  struct zebra_vrf *zvrf;
192
0
  uint32_t metric;
193
0
  uint32_t flags = 0;
194
0
  uint32_t count = 0;
195
0
  struct listnode *cnode;
196
0
  struct connected *c;
197
198
0
  zvrf = ifp->vrf->info;
199
0
  if (!zvrf) {
200
0
    flog_err(
201
0
      EC_ZEBRA_VRF_NOT_FOUND,
202
0
      "%s: Received Up for interface but no associated zvrf: %s(%d)",
203
0
      __func__, ifp->vrf->name, ifp->vrf->vrf_id);
204
0
    return;
205
0
  }
206
0
  if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL))
207
0
    return;
208
209
  /* Ensure 'down' flag is cleared */
210
0
  UNSET_FLAG(ifc->conf, ZEBRA_IFC_DOWN);
211
212
0
  prefix_copy(&p, CONNECTED_PREFIX(ifc));
213
214
  /* Apply mask to the network. */
215
0
  apply_mask(&p);
216
217
0
  afi = family2afi(p.family);
218
219
0
  switch (afi) {
220
0
  case AFI_IP:
221
    /*
222
     * In case of connected address is 0.0.0.0/0 we treat it tunnel
223
     * address.
224
     */
225
0
    if (prefix_ipv4_any((struct prefix_ipv4 *)&p))
226
0
      return;
227
0
    break;
228
0
  case AFI_IP6:
229
#ifndef GNU_LINUX
230
    /* XXX: It is already done by rib_bogus_ipv6 within rib_add */
231
    if (IN6_IS_ADDR_UNSPECIFIED(&p.u.prefix6))
232
      return;
233
#endif
234
0
    break;
235
0
  case AFI_UNSPEC:
236
0
  case AFI_L2VPN:
237
0
  case AFI_MAX:
238
0
    flog_warn(EC_ZEBRA_CONNECTED_AFI_UNKNOWN,
239
0
        "Received unknown AFI: %s", afi2str(afi));
240
0
    return;
241
0
    break;
242
0
  }
243
244
0
  metric = (ifc->metric < (uint32_t)METRIC_MAX) ?
245
0
        ifc->metric : ifp->metric;
246
247
  /*
248
   * Since we are hand creating the connected routes
249
   * in our main routing table, *if* we are working
250
   * in an offloaded environment then we need to
251
   * pretend like the route is offloaded so everything
252
   * else will work
253
   */
254
0
  if (zrouter.asic_offloaded)
255
0
    flags |= ZEBRA_FLAG_OFFLOADED;
256
257
  /*
258
   * It's possible to add the same network and mask
259
   * to an interface over and over.  This would
260
   * result in an equivalent number of connected
261
   * routes.  Just add one connected route in
262
   * for all the addresses on an interface that
263
   * resolve to the same network and mask
264
   */
265
0
  for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) {
266
0
    struct prefix cp;
267
268
0
    prefix_copy(&cp, CONNECTED_PREFIX(c));
269
0
    apply_mask(&cp);
270
271
0
    if (prefix_same(&cp, &p) &&
272
0
        !CHECK_FLAG(c->conf, ZEBRA_IFC_DOWN))
273
0
      count++;
274
275
0
    if (count >= 2)
276
0
      return;
277
0
  }
278
279
0
  rib_add(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT, 0,
280
0
    flags, &p, NULL, &nh, 0, zvrf->table_id, metric, 0, 0, 0,
281
0
    false);
282
283
0
  rib_add(afi, SAFI_MULTICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT, 0,
284
0
    flags, &p, NULL, &nh, 0, zvrf->table_id, metric, 0, 0, 0,
285
0
    false);
286
287
  /* Schedule LSP forwarding entries for processing, if appropriate. */
288
0
  if (zvrf->vrf->vrf_id == VRF_DEFAULT) {
289
0
    if (IS_ZEBRA_DEBUG_MPLS)
290
0
      zlog_debug(
291
0
        "%u: IF %s IP %pFX address add/up, scheduling MPLS processing",
292
0
        zvrf->vrf->vrf_id, ifp->name, &p);
293
0
    mpls_mark_lsps_for_processing(zvrf, &p);
294
0
  }
295
0
}
296
297
/* Add connected IPv4 route to the interface. */
298
void connected_add_ipv4(struct interface *ifp, int flags,
299
      const struct in_addr *addr, uint16_t prefixlen,
300
      const struct in_addr *dest, const char *label,
301
      uint32_t metric)
302
0
{
303
0
  struct prefix_ipv4 *p;
304
0
  struct connected *ifc;
305
306
0
  if (ipv4_martian(addr))
307
0
    return;
308
309
  /* Make connected structure. */
310
0
  ifc = connected_new();
311
0
  ifc->ifp = ifp;
312
0
  ifc->flags = flags;
313
0
  ifc->metric = metric;
314
  /* If we get a notification from the kernel,
315
   * we can safely assume the address is known to the kernel */
316
0
  SET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED);
317
0
  if (!if_is_operative(ifp))
318
0
    SET_FLAG(ifc->conf, ZEBRA_IFC_DOWN);
319
320
  /* Allocate new connected address. */
321
0
  p = prefix_ipv4_new();
322
0
  p->family = AF_INET;
323
0
  p->prefix = *addr;
324
0
  p->prefixlen =
325
0
    CHECK_FLAG(flags, ZEBRA_IFA_PEER) ? IPV4_MAX_BITLEN : prefixlen;
326
0
  ifc->address = (struct prefix *)p;
327
328
  /* If there is a peer address. */
329
0
  if (CONNECTED_PEER(ifc)) {
330
    /* validate the destination address */
331
0
    if (dest) {
332
0
      p = prefix_ipv4_new();
333
0
      p->family = AF_INET;
334
0
      p->prefix = *dest;
335
0
      p->prefixlen = prefixlen;
336
0
      ifc->destination = (struct prefix *)p;
337
338
0
      if (IPV4_ADDR_SAME(addr, dest))
339
0
        flog_warn(
340
0
          EC_ZEBRA_IFACE_SAME_LOCAL_AS_PEER,
341
0
          "interface %s has same local and peer address %pI4, routing protocols may malfunction",
342
0
          ifp->name, addr);
343
0
    } else {
344
0
      zlog_debug(
345
0
        "%s called for interface %s with peer flag set, but no peer address supplied",
346
0
        __func__, ifp->name);
347
0
      UNSET_FLAG(ifc->flags, ZEBRA_IFA_PEER);
348
0
    }
349
0
  }
350
351
  /* no destination address was supplied */
352
0
  if (!dest && (prefixlen == IPV4_MAX_BITLEN) && if_is_pointopoint(ifp))
353
0
    zlog_debug(
354
0
      "PtP interface %s with addr %pI4/%d needs a peer address",
355
0
      ifp->name, addr, prefixlen);
356
357
  /* Label of this address. */
358
0
  if (label)
359
0
    ifc->label = XSTRDUP(MTYPE_CONNECTED_LABEL, label);
360
361
  /* For all that I know an IPv4 address is always ready when we receive
362
   * the notification. So it should be safe to set the REAL flag here. */
363
0
  SET_FLAG(ifc->conf, ZEBRA_IFC_REAL);
364
365
0
  connected_update(ifp, ifc);
366
0
}
367
368
void connected_down(struct interface *ifp, struct connected *ifc)
369
0
{
370
0
  afi_t afi;
371
0
  struct prefix p;
372
0
  struct nexthop nh = {
373
0
    .type = NEXTHOP_TYPE_IFINDEX,
374
0
    .ifindex = ifp->ifindex,
375
0
    .vrf_id = ifp->vrf->vrf_id,
376
0
  };
377
0
  struct zebra_vrf *zvrf;
378
0
  uint32_t count = 0;
379
0
  struct listnode *cnode;
380
0
  struct connected *c;
381
382
0
  zvrf = ifp->vrf->info;
383
0
  if (!zvrf) {
384
0
    flog_err(
385
0
      EC_ZEBRA_VRF_NOT_FOUND,
386
0
      "%s: Received Down for interface but no associated zvrf: %s(%d)",
387
0
      __func__, ifp->vrf->name, ifp->vrf->vrf_id);
388
0
    return;
389
0
  }
390
391
0
  if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL))
392
0
    return;
393
394
  /* Skip if we've already done this; this can happen if we have a
395
   * config change that takes an interface down, then we receive kernel
396
   * notifications about the downed interface and its addresses.
397
   */
398
0
  if (CHECK_FLAG(ifc->conf, ZEBRA_IFC_DOWN)) {
399
0
    if (IS_ZEBRA_DEBUG_RIB)
400
0
      zlog_debug("%s: ifc %p, %pFX already DOWN",
401
0
           __func__, ifc, ifc->address);
402
0
    return;
403
0
  }
404
405
0
  prefix_copy(&p, CONNECTED_PREFIX(ifc));
406
407
  /* Apply mask to the network. */
408
0
  apply_mask(&p);
409
410
0
  afi = family2afi(p.family);
411
412
0
  switch (afi) {
413
0
  case AFI_IP:
414
    /*
415
     * In case of connected address is 0.0.0.0/0 we treat it tunnel
416
     *  address.
417
     */
418
0
    if (prefix_ipv4_any((struct prefix_ipv4 *)&p))
419
0
      return;
420
0
    break;
421
0
  case AFI_IP6:
422
0
    if (IN6_IS_ADDR_UNSPECIFIED(&p.u.prefix6))
423
0
      return;
424
0
    break;
425
0
  case AFI_UNSPEC:
426
0
  case AFI_L2VPN:
427
0
  case AFI_MAX:
428
0
    zlog_warn("Unknown AFI: %s", afi2str(afi));
429
0
    break;
430
0
  }
431
432
  /* Mark the address as 'down' */
433
0
  SET_FLAG(ifc->conf, ZEBRA_IFC_DOWN);
434
435
  /*
436
   * It's possible to have X number of addresses
437
   * on a interface that all resolve to the same
438
   * network and mask.  Find them and just
439
   * allow the deletion when are removing the last
440
   * one.
441
   */
442
0
  for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) {
443
0
    struct prefix cp;
444
445
0
    prefix_copy(&cp, CONNECTED_PREFIX(c));
446
0
    apply_mask(&cp);
447
448
0
    if (prefix_same(&p, &cp) &&
449
0
        !CHECK_FLAG(c->conf, ZEBRA_IFC_DOWN))
450
0
      count++;
451
452
0
    if (count >= 1)
453
0
      return;
454
0
  }
455
456
  /*
457
   * Same logic as for connected_up(): push the changes into the
458
   * head.
459
   */
460
0
  rib_delete(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT, 0,
461
0
       0, &p, NULL, &nh, 0, zvrf->table_id, 0, 0, false);
462
463
0
  rib_delete(afi, SAFI_MULTICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT,
464
0
       0, 0, &p, NULL, &nh, 0, zvrf->table_id, 0, 0, false);
465
466
  /* Schedule LSP forwarding entries for processing, if appropriate. */
467
0
  if (zvrf->vrf->vrf_id == VRF_DEFAULT) {
468
0
    if (IS_ZEBRA_DEBUG_MPLS)
469
0
      zlog_debug(
470
0
        "%u: IF %s IP %pFX address down, scheduling MPLS processing",
471
0
        zvrf->vrf->vrf_id, ifp->name, &p);
472
0
    mpls_mark_lsps_for_processing(zvrf, &p);
473
0
  }
474
0
}
475
476
static void connected_delete_helper(struct connected *ifc, struct prefix *p)
477
0
{
478
0
  struct interface *ifp;
479
480
0
  if (!ifc)
481
0
    return;
482
0
  ifp = ifc->ifp;
483
484
0
  connected_withdraw(ifc);
485
486
  /* Schedule LSP forwarding entries for processing, if appropriate. */
487
0
  if (ifp->vrf->vrf_id == VRF_DEFAULT) {
488
0
    if (IS_ZEBRA_DEBUG_MPLS)
489
0
      zlog_debug(
490
0
        "%u: IF %s IP %pFX address delete, scheduling MPLS processing",
491
0
        ifp->vrf->vrf_id, ifp->name, p);
492
0
    mpls_mark_lsps_for_processing(ifp->vrf->info, p);
493
0
  }
494
0
}
495
496
/* Delete connected IPv4 route to the interface. */
497
void connected_delete_ipv4(struct interface *ifp, int flags,
498
         const struct in_addr *addr, uint16_t prefixlen,
499
         const struct in_addr *dest)
500
0
{
501
0
  struct prefix p, d;
502
0
  struct connected *ifc;
503
504
0
  memset(&p, 0, sizeof(p));
505
0
  p.family = AF_INET;
506
0
  p.u.prefix4 = *addr;
507
0
  p.prefixlen =
508
0
    CHECK_FLAG(flags, ZEBRA_IFA_PEER) ? IPV4_MAX_BITLEN : prefixlen;
509
510
0
  if (dest) {
511
0
    memset(&d, 0, sizeof(d));
512
0
    d.family = AF_INET;
513
0
    d.u.prefix4 = *dest;
514
0
    d.prefixlen = prefixlen;
515
0
    ifc = connected_check_ptp(ifp, &p, &d);
516
0
  } else
517
0
    ifc = connected_check_ptp(ifp, &p, NULL);
518
519
0
  connected_delete_helper(ifc, &p);
520
0
}
521
522
/* Add connected IPv6 route to the interface. */
523
void connected_add_ipv6(struct interface *ifp, int flags,
524
      const struct in6_addr *addr,
525
      const struct in6_addr *dest, uint16_t prefixlen,
526
      const char *label, uint32_t metric)
527
0
{
528
0
  struct prefix_ipv6 *p;
529
0
  struct connected *ifc;
530
531
0
  if (ipv6_martian(addr))
532
0
    return;
533
534
  /* Make connected structure. */
535
0
  ifc = connected_new();
536
0
  ifc->ifp = ifp;
537
0
  ifc->flags = flags;
538
0
  ifc->metric = metric;
539
  /* If we get a notification from the kernel,
540
   * we can safely assume the address is known to the kernel */
541
0
  SET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED);
542
0
  if (!if_is_operative(ifp))
543
0
    SET_FLAG(ifc->conf, ZEBRA_IFC_DOWN);
544
545
  /* Allocate new connected address. */
546
0
  p = prefix_ipv6_new();
547
0
  p->family = AF_INET6;
548
0
  IPV6_ADDR_COPY(&p->prefix, addr);
549
0
  p->prefixlen = prefixlen;
550
0
  ifc->address = (struct prefix *)p;
551
552
  /* Add global ipv6 address to the RA prefix list */
553
0
  if (!IN6_IS_ADDR_LINKLOCAL(&p->prefix))
554
0
    rtadv_add_prefix(ifp->info, p);
555
556
0
  if (dest) {
557
0
    p = prefix_ipv6_new();
558
0
    p->family = AF_INET6;
559
0
    IPV6_ADDR_COPY(&p->prefix, dest);
560
0
    p->prefixlen = prefixlen;
561
0
    ifc->destination = (struct prefix *)p;
562
0
  } else {
563
0
    if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_PEER)) {
564
0
      zlog_debug(
565
0
        "%s called for interface %s with peer flag set, but no peer address supplied",
566
0
        __func__, ifp->name);
567
0
      UNSET_FLAG(ifc->flags, ZEBRA_IFA_PEER);
568
0
    }
569
0
  }
570
571
  /* Label of this address. */
572
0
  if (label)
573
0
    ifc->label = XSTRDUP(MTYPE_CONNECTED_LABEL, label);
574
575
  /* On Linux, we only get here when DAD is complete, therefore we can set
576
   * ZEBRA_IFC_REAL.
577
   *
578
   * On BSD, there currently doesn't seem to be a way to check for
579
   * completion of
580
   * DAD, so we replicate the old behaviour and set ZEBRA_IFC_REAL,
581
   * although DAD
582
   * might still be running.
583
   */
584
0
  SET_FLAG(ifc->conf, ZEBRA_IFC_REAL);
585
0
  connected_update(ifp, ifc);
586
0
}
587
588
void connected_delete_ipv6(struct interface *ifp,
589
         const struct in6_addr *address,
590
         const struct in6_addr *dest, uint16_t prefixlen)
591
0
{
592
0
  struct prefix p, d;
593
0
  struct connected *ifc;
594
595
0
  memset(&p, 0, sizeof(p));
596
0
  p.family = AF_INET6;
597
0
  memcpy(&p.u.prefix6, address, sizeof(struct in6_addr));
598
0
  p.prefixlen = prefixlen;
599
600
  /* Delete global ipv6 address from RA prefix list */
601
0
  if (!IN6_IS_ADDR_LINKLOCAL(&p.u.prefix6))
602
0
    rtadv_delete_prefix(ifp->info, &p);
603
604
0
  if (dest) {
605
0
    memset(&d, 0, sizeof(d));
606
0
    d.family = AF_INET6;
607
0
    IPV6_ADDR_COPY(&d.u.prefix6, dest);
608
0
    d.prefixlen = prefixlen;
609
0
    ifc = connected_check_ptp(ifp, &p, &d);
610
0
  } else
611
0
    ifc = connected_check_ptp(ifp, &p, NULL);
612
613
0
  connected_delete_helper(ifc, &p);
614
0
}
615
616
int connected_is_unnumbered(struct interface *ifp)
617
0
{
618
0
  struct connected *connected;
619
0
  struct listnode *node;
620
621
0
  for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, connected)) {
622
0
    if (CHECK_FLAG(connected->conf, ZEBRA_IFC_REAL)
623
0
        && connected->address->family == AF_INET)
624
0
      return CHECK_FLAG(connected->flags,
625
0
            ZEBRA_IFA_UNNUMBERED);
626
0
  }
627
0
  return 0;
628
0
}