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