back to topotato report
topotato coverage report
Current view: top level - zebra - connected.c (source / functions) Hit Total Coverage
Test: test_bgp_ecmp_enhe.py::BGP_Unnumbered_ECMP Lines: 144 276 52.2 %
Date: 2023-11-16 17:19:14 Functions: 7 28 25.0 %

          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             : }

Generated by: LCOV version v1.16-topotato