Line data Source code
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 0 : static void connected_withdraw(struct connected *ifc)
31 : {
32 0 : if (!ifc)
33 : 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 : }
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 : }
54 : }
55 :
56 18 : static void connected_announce(struct interface *ifp, struct connected *ifc)
57 : {
58 18 : if (!ifc)
59 : return;
60 :
61 18 : if (!if_is_loopback(ifp) && ifc->address->family == AF_INET) {
62 2 : if (ifc->address->prefixlen == IPV4_MAX_BITLEN)
63 0 : SET_FLAG(ifc->flags, ZEBRA_IFA_UNNUMBERED);
64 : else
65 2 : UNSET_FLAG(ifc->flags, ZEBRA_IFA_UNNUMBERED);
66 : }
67 :
68 18 : listnode_add(ifp->connected, ifc);
69 :
70 : /* Update interface address information to protocol daemon. */
71 18 : if (ifc->address->family == AF_INET)
72 4 : if_subnet_add(ifp, ifc);
73 :
74 18 : zebra_interface_address_add_update(ifp, ifc);
75 :
76 18 : if (if_is_operative(ifp)) {
77 17 : connected_up(ifp, ifc);
78 : }
79 : }
80 :
81 : /* If same interface address is already exist... */
82 0 : struct connected *connected_check(struct interface *ifp,
83 : union prefixconstptr pu)
84 : {
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 : return NULL;
94 : }
95 :
96 : /* same, but with peer address */
97 18 : struct connected *connected_check_ptp(struct interface *ifp,
98 : union prefixconstptr pu,
99 : union prefixconstptr du)
100 : {
101 18 : const struct prefix *p = pu.p;
102 18 : const struct prefix *d = du.p;
103 18 : struct connected *ifc;
104 18 : struct listnode *node;
105 :
106 48 : for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
107 12 : if (!prefix_same(ifc->address, p))
108 12 : 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 : }
115 :
116 : return NULL;
117 : }
118 :
119 : /* Check if two ifc's describe the same address in the same state */
120 0 : static int connected_same(struct connected *ifc1, struct connected *ifc2)
121 : {
122 0 : if (ifc1->ifp != ifc2->ifp)
123 : return 0;
124 :
125 0 : if (ifc1->flags != ifc2->flags)
126 : return 0;
127 :
128 0 : if (ifc1->conf != ifc2->conf)
129 : return 0;
130 :
131 0 : if (ifc1->destination)
132 0 : if (!ifc2->destination)
133 : return 0;
134 0 : if (ifc2->destination)
135 0 : if (!ifc1->destination)
136 : return 0;
137 :
138 0 : if (ifc1->destination && ifc2->destination)
139 0 : if (!prefix_same(ifc1->destination, ifc2->destination))
140 : return 0;
141 :
142 : return 1;
143 : }
144 :
145 : /* Handle changes to addresses and send the neccesary announcements
146 : * to clients. */
147 18 : static void connected_update(struct interface *ifp, struct connected *ifc)
148 : {
149 18 : struct connected *current;
150 :
151 : /* Check same connected route. */
152 18 : current = connected_check_ptp(ifp, ifc->address, ifc->destination);
153 18 : 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 : }
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 : current); /* implicit withdraw - freebsd does this */
173 : }
174 :
175 : /* If the connected is new or has changed, announce it, if it is usable
176 : */
177 18 : if (CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL))
178 18 : connected_announce(ifp, ifc);
179 : }
180 :
181 : /* Called from if_up(). */
182 22 : void connected_up(struct interface *ifp, struct connected *ifc)
183 : {
184 22 : afi_t afi;
185 22 : struct prefix p;
186 22 : struct nexthop nh = {
187 : .type = NEXTHOP_TYPE_IFINDEX,
188 22 : .ifindex = ifp->ifindex,
189 22 : .vrf_id = ifp->vrf->vrf_id,
190 : };
191 22 : struct zebra_vrf *zvrf;
192 22 : uint32_t metric;
193 22 : uint32_t flags = 0;
194 22 : uint32_t count = 0;
195 22 : struct listnode *cnode;
196 22 : struct connected *c;
197 :
198 22 : zvrf = ifp->vrf->info;
199 22 : if (!zvrf) {
200 0 : flog_err(
201 : EC_ZEBRA_VRF_NOT_FOUND,
202 : "%s: Received Up for interface but no associated zvrf: %s(%d)",
203 : __func__, ifp->vrf->name, ifp->vrf->vrf_id);
204 0 : return;
205 : }
206 22 : if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL))
207 : return;
208 :
209 : /* Ensure 'down' flag is cleared */
210 22 : UNSET_FLAG(ifc->conf, ZEBRA_IFC_DOWN);
211 :
212 22 : prefix_copy(&p, CONNECTED_PREFIX(ifc));
213 :
214 : /* Apply mask to the network. */
215 22 : apply_mask(&p);
216 :
217 22 : afi = family2afi(p.family);
218 :
219 22 : switch (afi) {
220 5 : case AFI_IP:
221 : /*
222 : * In case of connected address is 0.0.0.0/0 we treat it tunnel
223 : * address.
224 : */
225 5 : if (prefix_ipv4_any((struct prefix_ipv4 *)&p))
226 : return;
227 : break;
228 : 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 : break;
235 0 : case AFI_UNSPEC:
236 : case AFI_L2VPN:
237 : case AFI_MAX:
238 0 : flog_warn(EC_ZEBRA_CONNECTED_AFI_UNKNOWN,
239 : "Received unknown AFI: %s", afi2str(afi));
240 0 : return;
241 22 : break;
242 : }
243 :
244 44 : metric = (ifc->metric < (uint32_t)METRIC_MAX) ?
245 22 : 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 22 : 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 80 : for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) {
266 36 : struct prefix cp;
267 :
268 36 : prefix_copy(&cp, CONNECTED_PREFIX(c));
269 36 : apply_mask(&cp);
270 :
271 36 : if (prefix_same(&cp, &p) &&
272 22 : !CHECK_FLAG(c->conf, ZEBRA_IFC_DOWN))
273 22 : count++;
274 :
275 36 : if (count >= 2)
276 0 : return;
277 : }
278 :
279 22 : rib_add(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT, 0,
280 : flags, &p, NULL, &nh, 0, zvrf->table_id, metric, 0, 0, 0,
281 : false);
282 :
283 22 : rib_add(afi, SAFI_MULTICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT, 0,
284 : flags, &p, NULL, &nh, 0, zvrf->table_id, metric, 0, 0, 0,
285 : false);
286 :
287 : /* Schedule LSP forwarding entries for processing, if appropriate. */
288 22 : if (zvrf->vrf->vrf_id == VRF_DEFAULT) {
289 22 : if (IS_ZEBRA_DEBUG_MPLS)
290 0 : zlog_debug(
291 : "%u: IF %s IP %pFX address add/up, scheduling MPLS processing",
292 : zvrf->vrf->vrf_id, ifp->name, &p);
293 22 : mpls_mark_lsps_for_processing(zvrf, &p);
294 : }
295 : }
296 :
297 : /* Add connected IPv4 route to the interface. */
298 6 : 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 : {
303 6 : struct prefix_ipv4 *p;
304 6 : struct connected *ifc;
305 :
306 6 : if (ipv4_martian(addr))
307 : return;
308 :
309 : /* Make connected structure. */
310 4 : ifc = connected_new();
311 4 : ifc->ifp = ifp;
312 4 : ifc->flags = flags;
313 4 : 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 4 : SET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED);
317 4 : if (!if_is_operative(ifp))
318 0 : SET_FLAG(ifc->conf, ZEBRA_IFC_DOWN);
319 :
320 : /* Allocate new connected address. */
321 4 : p = prefix_ipv4_new();
322 4 : p->family = AF_INET;
323 4 : p->prefix = *addr;
324 8 : p->prefixlen =
325 4 : CHECK_FLAG(flags, ZEBRA_IFA_PEER) ? IPV4_MAX_BITLEN : prefixlen;
326 4 : ifc->address = (struct prefix *)p;
327 :
328 : /* If there is a peer address. */
329 4 : 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 : EC_ZEBRA_IFACE_SAME_LOCAL_AS_PEER,
341 : "interface %s has same local and peer address %pI4, routing protocols may malfunction",
342 : ifp->name, addr);
343 : } else {
344 0 : zlog_debug(
345 : "%s called for interface %s with peer flag set, but no peer address supplied",
346 : __func__, ifp->name);
347 0 : UNSET_FLAG(ifc->flags, ZEBRA_IFA_PEER);
348 : }
349 : }
350 :
351 : /* no destination address was supplied */
352 4 : if (!dest && (prefixlen == IPV4_MAX_BITLEN) && if_is_pointopoint(ifp))
353 0 : zlog_debug(
354 : "PtP interface %s with addr %pI4/%d needs a peer address",
355 : ifp->name, addr, prefixlen);
356 :
357 : /* Label of this address. */
358 4 : 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 4 : SET_FLAG(ifc->conf, ZEBRA_IFC_REAL);
364 :
365 4 : connected_update(ifp, ifc);
366 : }
367 :
368 4 : void connected_down(struct interface *ifp, struct connected *ifc)
369 : {
370 4 : afi_t afi;
371 4 : struct prefix p;
372 4 : struct nexthop nh = {
373 : .type = NEXTHOP_TYPE_IFINDEX,
374 4 : .ifindex = ifp->ifindex,
375 4 : .vrf_id = ifp->vrf->vrf_id,
376 : };
377 4 : struct zebra_vrf *zvrf;
378 4 : uint32_t count = 0;
379 4 : struct listnode *cnode;
380 4 : struct connected *c;
381 :
382 4 : zvrf = ifp->vrf->info;
383 4 : if (!zvrf) {
384 0 : flog_err(
385 : EC_ZEBRA_VRF_NOT_FOUND,
386 : "%s: Received Down for interface but no associated zvrf: %s(%d)",
387 : __func__, ifp->vrf->name, ifp->vrf->vrf_id);
388 0 : return;
389 : }
390 :
391 4 : if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL))
392 : 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 4 : 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 : __func__, ifc, ifc->address);
402 0 : return;
403 : }
404 :
405 4 : prefix_copy(&p, CONNECTED_PREFIX(ifc));
406 :
407 : /* Apply mask to the network. */
408 4 : apply_mask(&p);
409 :
410 4 : afi = family2afi(p.family);
411 :
412 4 : switch (afi) {
413 1 : case AFI_IP:
414 : /*
415 : * In case of connected address is 0.0.0.0/0 we treat it tunnel
416 : * address.
417 : */
418 1 : if (prefix_ipv4_any((struct prefix_ipv4 *)&p))
419 : return;
420 : break;
421 3 : case AFI_IP6:
422 3 : if (IN6_IS_ADDR_UNSPECIFIED(&p.u.prefix6))
423 : return;
424 : break;
425 0 : case AFI_UNSPEC:
426 : case AFI_L2VPN:
427 : case AFI_MAX:
428 0 : zlog_warn("Unknown AFI: %s", afi2str(afi));
429 0 : break;
430 : }
431 :
432 : /* Mark the address as 'down' */
433 4 : 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 14 : for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) {
443 6 : struct prefix cp;
444 :
445 6 : prefix_copy(&cp, CONNECTED_PREFIX(c));
446 6 : apply_mask(&cp);
447 :
448 6 : if (prefix_same(&p, &cp) &&
449 4 : !CHECK_FLAG(c->conf, ZEBRA_IFC_DOWN))
450 6 : count++;
451 :
452 6 : if (count >= 1)
453 0 : return;
454 : }
455 :
456 : /*
457 : * Same logic as for connected_up(): push the changes into the
458 : * head.
459 : */
460 4 : rib_delete(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT, 0,
461 : 0, &p, NULL, &nh, 0, zvrf->table_id, 0, 0, false);
462 :
463 4 : rib_delete(afi, SAFI_MULTICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT,
464 : 0, 0, &p, NULL, &nh, 0, zvrf->table_id, 0, 0, false);
465 :
466 : /* Schedule LSP forwarding entries for processing, if appropriate. */
467 4 : if (zvrf->vrf->vrf_id == VRF_DEFAULT) {
468 4 : if (IS_ZEBRA_DEBUG_MPLS)
469 0 : zlog_debug(
470 : "%u: IF %s IP %pFX address down, scheduling MPLS processing",
471 : zvrf->vrf->vrf_id, ifp->name, &p);
472 4 : mpls_mark_lsps_for_processing(zvrf, &p);
473 : }
474 : }
475 :
476 0 : static void connected_delete_helper(struct connected *ifc, struct prefix *p)
477 : {
478 0 : struct interface *ifp;
479 :
480 0 : if (!ifc)
481 : 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 : "%u: IF %s IP %pFX address delete, scheduling MPLS processing",
491 : ifp->vrf->vrf_id, ifp->name, p);
492 0 : mpls_mark_lsps_for_processing(ifp->vrf->info, p);
493 : }
494 : }
495 :
496 : /* Delete connected IPv4 route to the interface. */
497 0 : 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 : {
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 : } 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 16 : 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 : {
528 16 : struct prefix_ipv6 *p;
529 16 : struct connected *ifc;
530 :
531 16 : if (ipv6_martian(addr))
532 : return;
533 :
534 : /* Make connected structure. */
535 14 : ifc = connected_new();
536 14 : ifc->ifp = ifp;
537 14 : ifc->flags = flags;
538 14 : 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 14 : SET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED);
542 14 : if (!if_is_operative(ifp))
543 1 : SET_FLAG(ifc->conf, ZEBRA_IFC_DOWN);
544 :
545 : /* Allocate new connected address. */
546 14 : p = prefix_ipv6_new();
547 14 : p->family = AF_INET6;
548 14 : IPV6_ADDR_COPY(&p->prefix, addr);
549 14 : p->prefixlen = prefixlen;
550 14 : ifc->address = (struct prefix *)p;
551 :
552 : /* Add global ipv6 address to the RA prefix list */
553 14 : if (!IN6_IS_ADDR_LINKLOCAL(&p->prefix))
554 8 : rtadv_add_prefix(ifp->info, p);
555 :
556 14 : 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 : } else {
563 14 : if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_PEER)) {
564 0 : zlog_debug(
565 : "%s called for interface %s with peer flag set, but no peer address supplied",
566 : __func__, ifp->name);
567 0 : UNSET_FLAG(ifc->flags, ZEBRA_IFA_PEER);
568 : }
569 : }
570 :
571 : /* Label of this address. */
572 14 : 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 14 : SET_FLAG(ifc->conf, ZEBRA_IFC_REAL);
585 14 : connected_update(ifp, ifc);
586 : }
587 :
588 0 : void connected_delete_ipv6(struct interface *ifp,
589 : const struct in6_addr *address,
590 : const struct in6_addr *dest, uint16_t prefixlen)
591 : {
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 : } else
611 0 : ifc = connected_check_ptp(ifp, &p, NULL);
612 :
613 0 : connected_delete_helper(ifc, &p);
614 0 : }
615 :
616 0 : int connected_is_unnumbered(struct interface *ifp)
617 : {
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 : ZEBRA_IFA_UNNUMBERED);
626 : }
627 : return 0;
628 : }
|