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