back to topotato report
topotato coverage report
Current view: top level - ripngd - ripng_interface.c (source / functions) Hit Total Coverage
Test: aggregated run ( view descriptions ) Lines: 229 419 54.7 %
Date: 2023-02-24 19:38:44 Functions: 26 40 65.0 %

          Line data    Source code
       1             : /*
       2             :  * Interface related function for RIPng.
       3             :  * Copyright (C) 1998 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 "linklist.h"
      25             : #include "if.h"
      26             : #include "prefix.h"
      27             : #include "memory.h"
      28             : #include "network.h"
      29             : #include "filter.h"
      30             : #include "log.h"
      31             : #include "stream.h"
      32             : #include "zclient.h"
      33             : #include "command.h"
      34             : #include "agg_table.h"
      35             : #include "thread.h"
      36             : #include "privs.h"
      37             : #include "vrf.h"
      38             : #include "lib_errors.h"
      39             : #include "northbound_cli.h"
      40             : 
      41             : #include "ripngd/ripngd.h"
      42             : #include "ripngd/ripng_debug.h"
      43             : 
      44             : /* If RFC2133 definition is used. */
      45             : #ifndef IPV6_JOIN_GROUP
      46             : #define IPV6_JOIN_GROUP  IPV6_ADD_MEMBERSHIP
      47             : #endif
      48             : #ifndef IPV6_LEAVE_GROUP
      49             : #define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
      50             : #endif
      51             : 
      52           3 : DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_IF, "ripng interface");
      53             : 
      54             : /* Static utility function. */
      55             : static void ripng_enable_apply(struct interface *);
      56             : static void ripng_passive_interface_apply(struct interface *);
      57             : static int ripng_enable_if_lookup(struct ripng *ripng, const char *ifname);
      58             : static int ripng_enable_network_lookup2(struct connected *);
      59             : static void ripng_enable_apply_all(struct ripng *ripng);
      60             : 
      61             : /* Join to the all rip routers multicast group. */
      62           0 : static int ripng_multicast_join(struct interface *ifp, int sock)
      63             : {
      64           0 :         int ret;
      65           0 :         struct ipv6_mreq mreq;
      66           0 :         int save_errno;
      67             : 
      68           0 :         if (if_is_multicast(ifp)) {
      69           0 :                 memset(&mreq, 0, sizeof(mreq));
      70           0 :                 inet_pton(AF_INET6, RIPNG_GROUP, &mreq.ipv6mr_multiaddr);
      71           0 :                 mreq.ipv6mr_interface = ifp->ifindex;
      72             : 
      73             :                 /*
      74             :                  * NetBSD 1.6.2 requires root to join groups on gif(4).
      75             :                  * While this is bogus, privs are available and easy to use
      76             :                  * for this call as a workaround.
      77             :                  */
      78           0 :                 frr_with_privs(&ripngd_privs) {
      79             : 
      80           0 :                         ret = setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
      81             :                                          (char *)&mreq, sizeof(mreq));
      82           0 :                         save_errno = errno;
      83             : 
      84             :                 }
      85             : 
      86           0 :                 if (ret < 0 && save_errno == EADDRINUSE) {
      87             :                         /*
      88             :                          * Group is already joined.  This occurs due to sloppy
      89             :                          * group
      90             :                          * management, in particular declining to leave the
      91             :                          * group on
      92             :                          * an interface that has just gone down.
      93             :                          */
      94           0 :                         zlog_warn("ripng join on %s EADDRINUSE (ignoring)",
      95             :                                   ifp->name);
      96           0 :                         return 0; /* not an error */
      97             :                 }
      98             : 
      99           0 :                 if (ret < 0)
     100           0 :                         zlog_warn("can't setsockopt IPV6_JOIN_GROUP: %s",
     101             :                                   safe_strerror(save_errno));
     102             : 
     103           0 :                 if (IS_RIPNG_DEBUG_EVENT)
     104           0 :                         zlog_debug(
     105             :                                 "RIPng %s join to all-rip-routers multicast group",
     106             :                                 ifp->name);
     107             : 
     108           0 :                 if (ret < 0)
     109             :                         return -1;
     110             :         }
     111             :         return 0;
     112             : }
     113             : 
     114             : /* Leave from the all rip routers multicast group. */
     115           0 : static int ripng_multicast_leave(struct interface *ifp, int sock)
     116             : {
     117           0 :         int ret;
     118           0 :         struct ipv6_mreq mreq;
     119             : 
     120           0 :         if (if_is_multicast(ifp)) {
     121           0 :                 memset(&mreq, 0, sizeof(mreq));
     122           0 :                 inet_pton(AF_INET6, RIPNG_GROUP, &mreq.ipv6mr_multiaddr);
     123           0 :                 mreq.ipv6mr_interface = ifp->ifindex;
     124             : 
     125           0 :                 ret = setsockopt(sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
     126             :                                  (char *)&mreq, sizeof(mreq));
     127           0 :                 if (ret < 0)
     128           0 :                         zlog_warn("can't setsockopt IPV6_LEAVE_GROUP: %s",
     129             :                                   safe_strerror(errno));
     130             : 
     131           0 :                 if (IS_RIPNG_DEBUG_EVENT)
     132           0 :                         zlog_debug(
     133             :                                 "RIPng %s leave from all-rip-routers multicast group",
     134             :                                 ifp->name);
     135             : 
     136           0 :                 if (ret < 0)
     137             :                         return -1;
     138             :         }
     139             : 
     140             :         return 0;
     141             : }
     142             : 
     143             : /* How many link local IPv6 address could be used on the interface ? */
     144          41 : static int ripng_if_ipv6_lladdress_check(struct interface *ifp)
     145             : {
     146          41 :         struct listnode *nn;
     147          41 :         struct connected *connected;
     148          41 :         int count = 0;
     149             : 
     150         131 :         for (ALL_LIST_ELEMENTS_RO(ifp->connected, nn, connected)) {
     151          49 :                 struct prefix *p;
     152          49 :                 p = connected->address;
     153             : 
     154          49 :                 if ((p->family == AF_INET6)
     155          16 :                     && IN6_IS_ADDR_LINKLOCAL(&p->u.prefix6))
     156           7 :                         count++;
     157             :         }
     158             : 
     159          41 :         return count;
     160             : }
     161             : 
     162           0 : static int ripng_if_down(struct interface *ifp)
     163             : {
     164           0 :         struct agg_node *rp;
     165           0 :         struct ripng_info *rinfo;
     166           0 :         struct ripng_interface *ri;
     167           0 :         struct ripng *ripng;
     168           0 :         struct list *list = NULL;
     169           0 :         struct listnode *listnode = NULL, *nextnode = NULL;
     170             : 
     171           0 :         ri = ifp->info;
     172             : 
     173           0 :         THREAD_OFF(ri->t_wakeup);
     174             : 
     175           0 :         ripng = ri->ripng;
     176             : 
     177           0 :         if (ripng)
     178           0 :                 for (rp = agg_route_top(ripng->table); rp;
     179           0 :                      rp = agg_route_next(rp))
     180           0 :                         if ((list = rp->info) != NULL)
     181           0 :                                 for (ALL_LIST_ELEMENTS(list, listnode, nextnode,
     182             :                                                        rinfo))
     183           0 :                                         if (rinfo->ifindex == ifp->ifindex)
     184           0 :                                                 ripng_ecmp_delete(ripng, rinfo);
     185             : 
     186             : 
     187           0 :         if (ri->running) {
     188           0 :                 if (IS_RIPNG_DEBUG_EVENT)
     189           0 :                         zlog_debug("turn off %s", ifp->name);
     190             : 
     191             :                 /* Leave from multicast group. */
     192           0 :                 if (ripng)
     193           0 :                         ripng_multicast_leave(ifp, ripng->sock);
     194             : 
     195           0 :                 ri->running = 0;
     196             :         }
     197             : 
     198           0 :         return 0;
     199             : }
     200             : 
     201             : /* Interface link up message processing. */
     202          14 : static int ripng_ifp_up(struct interface *ifp)
     203             : {
     204          14 :         if (IS_RIPNG_DEBUG_ZEBRA)
     205          14 :                 zlog_debug(
     206             :                         "interface up %s vrf %s(%u) index %d flags %llx metric %d mtu %d",
     207             :                         ifp->name, ifp->vrf->name, ifp->vrf->vrf_id,
     208             :                         ifp->ifindex, (unsigned long long)ifp->flags,
     209             :                         ifp->metric, ifp->mtu6);
     210             : 
     211          28 :         ripng_interface_sync(ifp);
     212             : 
     213             :         /* Check if this interface is RIPng enabled or not. */
     214          14 :         ripng_enable_apply(ifp);
     215             : 
     216             :         /* Check for a passive interface. */
     217          14 :         ripng_passive_interface_apply(ifp);
     218             : 
     219             :         /* Apply distribute list to the all interface. */
     220          14 :         ripng_distribute_update_interface(ifp);
     221             : 
     222          14 :         return 0;
     223             : }
     224             : 
     225             : /* Interface link down message processing. */
     226           0 : static int ripng_ifp_down(struct interface *ifp)
     227             : {
     228           0 :         ripng_interface_sync(ifp);
     229           0 :         ripng_if_down(ifp);
     230             : 
     231           0 :         if (IS_RIPNG_DEBUG_ZEBRA)
     232           0 :                 zlog_debug(
     233             :                         "interface down %s vrf %s(%u) index %d flags %#llx metric %d mtu %d",
     234             :                         ifp->name, ifp->vrf->name, ifp->vrf->vrf_id,
     235             :                         ifp->ifindex, (unsigned long long)ifp->flags,
     236             :                         ifp->metric, ifp->mtu6);
     237             : 
     238           0 :         return 0;
     239             : }
     240             : 
     241             : /* Interface addition message from zebra. */
     242          16 : static int ripng_ifp_create(struct interface *ifp)
     243             : {
     244          32 :         ripng_interface_sync(ifp);
     245             : 
     246          16 :         if (IS_RIPNG_DEBUG_ZEBRA)
     247          16 :                 zlog_debug(
     248             :                         "RIPng interface add %s vrf %s(%u) index %d flags %#llx metric %d mtu %d",
     249             :                         ifp->name, ifp->vrf->name, ifp->vrf->vrf_id,
     250             :                         ifp->ifindex, (unsigned long long)ifp->flags,
     251             :                         ifp->metric, ifp->mtu6);
     252             : 
     253             :         /* Check is this interface is RIP enabled or not.*/
     254          16 :         ripng_enable_apply(ifp);
     255             : 
     256             :         /* Apply distribute list to the interface. */
     257          16 :         ripng_distribute_update_interface(ifp);
     258             : 
     259             :         /* Check interface routemap. */
     260          16 :         ripng_if_rmap_update_interface(ifp);
     261             : 
     262          16 :         return 0;
     263             : }
     264             : 
     265           0 : static int ripng_ifp_destroy(struct interface *ifp)
     266             : {
     267           0 :         ripng_interface_sync(ifp);
     268           0 :         if (if_is_up(ifp)) {
     269           0 :                 ripng_if_down(ifp);
     270             :         }
     271             : 
     272           0 :         if (IS_RIPNG_DEBUG_ZEBRA)
     273           0 :                 zlog_debug(
     274             :                         "interface delete %s vrf %s(%u) index %d flags %#llx metric %d mtu %d",
     275             :                         ifp->name, ifp->vrf->name, ifp->vrf->vrf_id,
     276             :                         ifp->ifindex, (unsigned long long)ifp->flags,
     277             :                         ifp->metric, ifp->mtu6);
     278             : 
     279           0 :         return 0;
     280             : }
     281             : 
     282             : /* VRF update for an interface. */
     283           0 : int ripng_interface_vrf_update(ZAPI_CALLBACK_ARGS)
     284             : {
     285           0 :         struct interface *ifp;
     286           0 :         vrf_id_t new_vrf_id;
     287             : 
     288           0 :         ifp = zebra_interface_vrf_update_read(zclient->ibuf, vrf_id,
     289             :                                               &new_vrf_id);
     290           0 :         if (!ifp)
     291             :                 return 0;
     292             : 
     293           0 :         if (IS_RIPNG_DEBUG_ZEBRA) {
     294           0 :                 struct vrf *nvrf = vrf_lookup_by_id(new_vrf_id);
     295             : 
     296           0 :                 zlog_debug("interface %s VRF change vrf %s(%u) new vrf %s(%u)",
     297             :                            ifp->name, ifp->vrf->name, vrf_id, VRF_LOGNAME(nvrf),
     298             :                            new_vrf_id);
     299             :         }
     300             : 
     301           0 :         if_update_to_new_vrf(ifp, new_vrf_id);
     302           0 :         ripng_interface_sync(ifp);
     303             : 
     304             :         return 0;
     305             : }
     306             : 
     307           1 : void ripng_interface_clean(struct ripng *ripng)
     308             : {
     309           1 :         struct interface *ifp;
     310           1 :         struct ripng_interface *ri;
     311             : 
     312           1 :         FOR_ALL_INTERFACES (ripng->vrf, ifp) {
     313           0 :                 ri = ifp->info;
     314             : 
     315           0 :                 ri->enable_network = 0;
     316           0 :                 ri->enable_interface = 0;
     317           0 :                 ri->running = 0;
     318             : 
     319           0 :                 THREAD_OFF(ri->t_wakeup);
     320             :         }
     321           1 : }
     322             : 
     323          11 : static void ripng_apply_address_add(struct connected *ifc)
     324             : {
     325          11 :         struct ripng_interface *ri = ifc->ifp->info;
     326          11 :         struct ripng *ripng = ri->ripng;
     327          11 :         struct prefix_ipv6 address;
     328          11 :         struct prefix *p;
     329             : 
     330          11 :         if (!ripng)
     331           0 :                 return;
     332             : 
     333          11 :         if (!if_is_up(ifc->ifp))
     334             :                 return;
     335             : 
     336          11 :         p = ifc->address;
     337             : 
     338          11 :         memset(&address, 0, sizeof(address));
     339          11 :         address.family = p->family;
     340          11 :         address.prefix = p->u.prefix6;
     341          11 :         address.prefixlen = p->prefixlen;
     342          11 :         apply_mask_ipv6(&address);
     343             : 
     344             :         /* Check if this interface is RIP enabled or not
     345             :            or  Check if this address's prefix is RIP enabled */
     346          11 :         if ((ripng_enable_if_lookup(ripng, ifc->ifp->name) >= 0)
     347          11 :             || (ripng_enable_network_lookup2(ifc) >= 0))
     348           2 :                 ripng_redistribute_add(ripng, ZEBRA_ROUTE_CONNECT,
     349             :                                        RIPNG_ROUTE_INTERFACE, &address,
     350           2 :                                        ifc->ifp->ifindex, NULL, 0);
     351             : }
     352             : 
     353          27 : int ripng_interface_address_add(ZAPI_CALLBACK_ARGS)
     354             : {
     355          27 :         struct connected *c;
     356          27 :         struct prefix *p;
     357             : 
     358          27 :         c = zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_ADD,
     359             :                                          zclient->ibuf, vrf_id);
     360             : 
     361          27 :         if (c == NULL)
     362             :                 return 0;
     363             : 
     364          27 :         p = c->address;
     365             : 
     366          27 :         if (p->family == AF_INET6) {
     367          11 :                 struct ripng_interface *ri = c->ifp->info;
     368             : 
     369          11 :                 if (IS_RIPNG_DEBUG_ZEBRA)
     370          11 :                         zlog_debug("RIPng connected address %pFX add", p);
     371             : 
     372             :                 /* Check is this prefix needs to be redistributed. */
     373          11 :                 ripng_apply_address_add(c);
     374             : 
     375             :                 /* Let's try once again whether the interface could be activated
     376             :                  */
     377          11 :                 if (!ri->running) {
     378             :                         /* Check if this interface is RIP enabled or not.*/
     379          11 :                         ripng_enable_apply(c->ifp);
     380             : 
     381             :                         /* Apply distribute list to the interface. */
     382          11 :                         ripng_distribute_update_interface(c->ifp);
     383             : 
     384             :                         /* Check interface routemap. */
     385          11 :                         ripng_if_rmap_update_interface(c->ifp);
     386             :                 }
     387             :         }
     388             : 
     389             :         return 0;
     390             : }
     391             : 
     392           0 : static void ripng_apply_address_del(struct connected *ifc)
     393             : {
     394           0 :         struct ripng_interface *ri = ifc->ifp->info;
     395           0 :         struct ripng *ripng = ri->ripng;
     396           0 :         struct prefix_ipv6 address;
     397           0 :         struct prefix *p;
     398             : 
     399           0 :         if (!ripng)
     400           0 :                 return;
     401             : 
     402           0 :         if (!if_is_up(ifc->ifp))
     403             :                 return;
     404             : 
     405           0 :         p = ifc->address;
     406             : 
     407           0 :         memset(&address, 0, sizeof(address));
     408           0 :         address.family = p->family;
     409           0 :         address.prefix = p->u.prefix6;
     410           0 :         address.prefixlen = p->prefixlen;
     411           0 :         apply_mask_ipv6(&address);
     412             : 
     413           0 :         ripng_redistribute_delete(ripng, ZEBRA_ROUTE_CONNECT,
     414             :                                   RIPNG_ROUTE_INTERFACE, &address,
     415           0 :                                   ifc->ifp->ifindex);
     416             : }
     417             : 
     418           0 : int ripng_interface_address_delete(ZAPI_CALLBACK_ARGS)
     419             : {
     420           0 :         struct connected *ifc;
     421           0 :         struct prefix *p;
     422             : 
     423           0 :         ifc = zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_DELETE,
     424             :                                            zclient->ibuf, vrf_id);
     425             : 
     426           0 :         if (ifc) {
     427           0 :                 p = ifc->address;
     428             : 
     429           0 :                 if (p->family == AF_INET6) {
     430           0 :                         if (IS_RIPNG_DEBUG_ZEBRA)
     431           0 :                                 zlog_debug(
     432             :                                         "RIPng connected address %pFX delete",
     433             :                                         p);
     434             : 
     435             :                         /* Check whether this prefix needs to be removed. */
     436           0 :                         ripng_apply_address_del(ifc);
     437             :                 }
     438           0 :                 connected_free(&ifc);
     439             :         }
     440             : 
     441           0 :         return 0;
     442             : }
     443             : 
     444             : /* Lookup RIPng enable network. */
     445             : /* Check whether the interface has at least a connected prefix that
     446             :  * is within the ripng->enable_network table. */
     447          41 : static int ripng_enable_network_lookup_if(struct interface *ifp)
     448             : {
     449          41 :         struct ripng_interface *ri = ifp->info;
     450          41 :         struct ripng *ripng = ri->ripng;
     451          41 :         struct listnode *node;
     452          41 :         struct connected *connected;
     453          41 :         struct prefix_ipv6 address;
     454             : 
     455          41 :         if (!ripng)
     456             :                 return -1;
     457             : 
     458         124 :         for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, connected)) {
     459          48 :                 struct prefix *p;
     460          48 :                 struct agg_node *n;
     461             : 
     462          48 :                 p = connected->address;
     463             : 
     464          48 :                 if (p->family == AF_INET6) {
     465          15 :                         address.family = AF_INET6;
     466          15 :                         address.prefix = p->u.prefix6;
     467          15 :                         address.prefixlen = IPV6_MAX_BITLEN;
     468             : 
     469          15 :                         n = agg_node_match(ripng->enable_network,
     470             :                                            (struct prefix *)&address);
     471          15 :                         if (n) {
     472           6 :                                 agg_unlock_node(n);
     473           6 :                                 return 1;
     474             :                         }
     475             :                 }
     476             :         }
     477             :         return -1;
     478             : }
     479             : 
     480             : /* Check whether connected is within the ripng->enable_network table. */
     481          13 : static int ripng_enable_network_lookup2(struct connected *connected)
     482             : {
     483          13 :         struct ripng_interface *ri = connected->ifp->info;
     484          13 :         struct ripng *ripng = ri->ripng;
     485          13 :         struct prefix_ipv6 address;
     486          13 :         struct prefix *p;
     487             : 
     488          13 :         if (!ripng)
     489             :                 return -1;
     490             : 
     491          13 :         p = connected->address;
     492             : 
     493          13 :         if (p->family == AF_INET6) {
     494          13 :                 struct agg_node *node;
     495             : 
     496          13 :                 address.family = p->family;
     497          13 :                 address.prefix = p->u.prefix6;
     498          13 :                 address.prefixlen = IPV6_MAX_BITLEN;
     499             : 
     500             :                 /* LPM on p->family, p->u.prefix6/IPV6_MAX_BITLEN within
     501             :                  * ripng->enable_network */
     502          13 :                 node = agg_node_match(ripng->enable_network,
     503             :                                       (struct prefix *)&address);
     504             : 
     505          13 :                 if (node) {
     506           3 :                         agg_unlock_node(node);
     507           3 :                         return 1;
     508             :                 }
     509             :         }
     510             : 
     511             :         return -1;
     512             : }
     513             : 
     514             : /* Add RIPng enable network. */
     515           1 : int ripng_enable_network_add(struct ripng *ripng, struct prefix *p)
     516             : {
     517           1 :         struct agg_node *node;
     518             : 
     519           1 :         node = agg_node_get(ripng->enable_network, p);
     520             : 
     521           1 :         if (node->info) {
     522           0 :                 agg_unlock_node(node);
     523           0 :                 return NB_ERR_INCONSISTENCY;
     524             :         } else
     525           1 :                 node->info = (void *)1;
     526             : 
     527             :         /* XXX: One should find a better solution than a generic one */
     528           1 :         ripng_enable_apply_all(ripng);
     529             : 
     530           1 :         return NB_OK;
     531             : }
     532             : 
     533             : /* Delete RIPng enable network. */
     534           0 : int ripng_enable_network_delete(struct ripng *ripng, struct prefix *p)
     535             : {
     536           0 :         struct agg_node *node;
     537             : 
     538           0 :         node = agg_node_lookup(ripng->enable_network, p);
     539           0 :         if (node) {
     540           0 :                 node->info = NULL;
     541             : 
     542             :                 /* Unlock info lock. */
     543           0 :                 agg_unlock_node(node);
     544             : 
     545             :                 /* Unlock lookup lock. */
     546           0 :                 agg_unlock_node(node);
     547             : 
     548           0 :                 return NB_OK;
     549             :         }
     550             : 
     551             :         return NB_ERR_INCONSISTENCY;
     552             : }
     553             : 
     554             : /* Lookup function. */
     555          54 : static int ripng_enable_if_lookup(struct ripng *ripng, const char *ifname)
     556             : {
     557          54 :         unsigned int i;
     558          54 :         char *str;
     559             : 
     560          54 :         if (!ripng)
     561             :                 return -1;
     562             : 
     563          54 :         for (i = 0; i < vector_active(ripng->enable_if); i++)
     564           0 :                 if ((str = vector_slot(ripng->enable_if, i)) != NULL)
     565           0 :                         if (strcmp(str, ifname) == 0)
     566           0 :                                 return i;
     567             :         return -1;
     568             : }
     569             : 
     570           0 : int ripng_enable_if_add(struct ripng *ripng, const char *ifname)
     571             : {
     572           0 :         int ret;
     573             : 
     574           0 :         ret = ripng_enable_if_lookup(ripng, ifname);
     575           0 :         if (ret >= 0)
     576             :                 return NB_ERR_INCONSISTENCY;
     577             : 
     578           0 :         vector_set(ripng->enable_if, strdup(ifname));
     579             : 
     580           0 :         ripng_enable_apply_all(ripng);
     581             : 
     582           0 :         return NB_OK;
     583             : }
     584             : 
     585           0 : int ripng_enable_if_delete(struct ripng *ripng, const char *ifname)
     586             : {
     587           0 :         int index;
     588           0 :         char *str;
     589             : 
     590           0 :         index = ripng_enable_if_lookup(ripng, ifname);
     591           0 :         if (index < 0)
     592             :                 return NB_ERR_INCONSISTENCY;
     593             : 
     594           0 :         str = vector_slot(ripng->enable_if, index);
     595           0 :         free(str);
     596           0 :         vector_unset(ripng->enable_if, index);
     597             : 
     598           0 :         ripng_enable_apply_all(ripng);
     599             : 
     600           0 :         return NB_OK;
     601             : }
     602             : 
     603             : /* Wake up interface. */
     604           0 : static void ripng_interface_wakeup(struct thread *t)
     605             : {
     606           0 :         struct interface *ifp;
     607           0 :         struct ripng_interface *ri;
     608             : 
     609             :         /* Get interface. */
     610           0 :         ifp = THREAD_ARG(t);
     611             : 
     612           0 :         ri = ifp->info;
     613             : 
     614             :         /* Join to multicast group. */
     615           0 :         if (ripng_multicast_join(ifp, ri->ripng->sock) < 0) {
     616           0 :                 flog_err_sys(EC_LIB_SOCKET,
     617             :                              "multicast join failed, interface %s not running",
     618             :                              ifp->name);
     619           0 :                 return;
     620             :         }
     621             : 
     622             :         /* Set running flag. */
     623           0 :         ri->running = 1;
     624             : 
     625             :         /* Send RIP request to the interface. */
     626           0 :         ripng_request(ifp);
     627             : }
     628             : 
     629           1 : static void ripng_connect_set(struct interface *ifp, int set)
     630             : {
     631           1 :         struct ripng_interface *ri = ifp->info;
     632           1 :         struct ripng *ripng = ri->ripng;
     633           1 :         struct listnode *node, *nnode;
     634           1 :         struct connected *connected;
     635           1 :         struct prefix_ipv6 address;
     636             : 
     637           5 :         for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, connected)) {
     638           3 :                 struct prefix *p;
     639           3 :                 p = connected->address;
     640             : 
     641           3 :                 if (p->family != AF_INET6)
     642           1 :                         continue;
     643             : 
     644           2 :                 address.family = AF_INET6;
     645           2 :                 address.prefix = p->u.prefix6;
     646           2 :                 address.prefixlen = p->prefixlen;
     647           2 :                 apply_mask_ipv6(&address);
     648             : 
     649           2 :                 if (set) {
     650             :                         /* Check once more whether this prefix is within a
     651             :                          * "network IF_OR_PREF" one */
     652           2 :                         if ((ripng_enable_if_lookup(ripng, connected->ifp->name)
     653             :                              >= 0)
     654           2 :                             || (ripng_enable_network_lookup2(connected) >= 0))
     655           1 :                                 ripng_redistribute_add(
     656             :                                         ripng, ZEBRA_ROUTE_CONNECT,
     657             :                                         RIPNG_ROUTE_INTERFACE, &address,
     658           1 :                                         connected->ifp->ifindex, NULL, 0);
     659             :                 } else {
     660           0 :                         ripng_redistribute_delete(ripng, ZEBRA_ROUTE_CONNECT,
     661             :                                                   RIPNG_ROUTE_INTERFACE,
     662             :                                                   &address,
     663           0 :                                                   connected->ifp->ifindex);
     664           0 :                         if (ripng_redistribute_check(ripng,
     665             :                                                      ZEBRA_ROUTE_CONNECT))
     666           0 :                                 ripng_redistribute_add(
     667             :                                         ripng, ZEBRA_ROUTE_CONNECT,
     668             :                                         RIPNG_ROUTE_REDISTRIBUTE, &address,
     669           0 :                                         connected->ifp->ifindex, NULL, 0);
     670             :                 }
     671             :         }
     672           1 : }
     673             : 
     674             : /* Check RIPng is enabed on this interface. */
     675          41 : void ripng_enable_apply(struct interface *ifp)
     676             : {
     677          41 :         int ret;
     678          41 :         struct ripng_interface *ri = NULL;
     679             : 
     680             :         /* Check interface. */
     681          41 :         if (!if_is_up(ifp))
     682             :                 return;
     683             : 
     684          41 :         ri = ifp->info;
     685             : 
     686             :         /* Is this interface a candidate for RIPng ? */
     687          41 :         ret = ripng_enable_network_lookup_if(ifp);
     688             : 
     689             :         /* If the interface is matched. */
     690          41 :         if (ret > 0)
     691           6 :                 ri->enable_network = 1;
     692             :         else
     693          35 :                 ri->enable_network = 0;
     694             : 
     695             :         /* Check interface name configuration. */
     696          41 :         ret = ripng_enable_if_lookup(ri->ripng, ifp->name);
     697          41 :         if (ret >= 0)
     698           0 :                 ri->enable_interface = 1;
     699             :         else
     700          41 :                 ri->enable_interface = 0;
     701             : 
     702             :         /* any candidate interface MUST have a link-local IPv6 address */
     703          41 :         if ((!ripng_if_ipv6_lladdress_check(ifp))
     704          34 :             && (ri->enable_network || ri->enable_interface)) {
     705           5 :                 ri->enable_network = 0;
     706           5 :                 ri->enable_interface = 0;
     707           5 :                 zlog_warn("Interface %s does not have any link-local address",
     708             :                           ifp->name);
     709             :         }
     710             : 
     711             :         /* Update running status of the interface. */
     712          41 :         if (ri->enable_network || ri->enable_interface) {
     713           1 :                 zlog_info("RIPng INTERFACE ON %s", ifp->name);
     714             : 
     715             :                 /* Add interface wake up thread. */
     716           1 :                 thread_add_timer(master, ripng_interface_wakeup, ifp, 1,
     717             :                                  &ri->t_wakeup);
     718             : 
     719           1 :                 ripng_connect_set(ifp, 1);
     720             :         } else {
     721          40 :                 if (ri->running) {
     722             :                         /* Might as well clean up the route table as well
     723             :                          * ripng_if_down sets to 0 ri->running, and displays
     724             :                          *"turn off %s"
     725             :                          **/
     726           0 :                         ripng_if_down(ifp);
     727             : 
     728           0 :                         ripng_connect_set(ifp, 0);
     729             :                 }
     730             :         }
     731             : }
     732             : 
     733             : /* Set distribute list to all interfaces. */
     734           1 : static void ripng_enable_apply_all(struct ripng *ripng)
     735             : {
     736           1 :         struct interface *ifp;
     737             : 
     738           2 :         FOR_ALL_INTERFACES (ripng->vrf, ifp)
     739           0 :                 ripng_enable_apply(ifp);
     740           1 : }
     741             : 
     742             : /* Clear all network and neighbor configuration */
     743           1 : void ripng_clean_network(struct ripng *ripng)
     744             : {
     745           1 :         unsigned int i;
     746           1 :         char *str;
     747           1 :         struct agg_node *rn;
     748             : 
     749             :         /* ripng->enable_network */
     750           3 :         for (rn = agg_route_top(ripng->enable_network); rn;
     751           1 :              rn = agg_route_next(rn))
     752           1 :                 if (rn->info) {
     753           1 :                         rn->info = NULL;
     754           2 :                         agg_unlock_node(rn);
     755             :                 }
     756             : 
     757             :         /* ripng->enable_if */
     758           1 :         for (i = 0; i < vector_active(ripng->enable_if); i++)
     759           0 :                 if ((str = vector_slot(ripng->enable_if, i)) != NULL) {
     760           0 :                         free(str);
     761           0 :                         vector_slot(ripng->enable_if, i) = NULL;
     762             :                 }
     763           1 : }
     764             : 
     765             : /* Utility function for looking up passive interface settings. */
     766          14 : static int ripng_passive_interface_lookup(struct ripng *ripng,
     767             :                                           const char *ifname)
     768             : {
     769          14 :         unsigned int i;
     770          14 :         char *str;
     771             : 
     772          14 :         for (i = 0; i < vector_active(ripng->passive_interface); i++)
     773           0 :                 if ((str = vector_slot(ripng->passive_interface, i)) != NULL)
     774           0 :                         if (strcmp(str, ifname) == 0)
     775           0 :                                 return i;
     776             :         return -1;
     777             : }
     778             : 
     779          14 : void ripng_passive_interface_apply(struct interface *ifp)
     780             : {
     781          14 :         int ret;
     782          14 :         struct ripng_interface *ri;
     783          14 :         struct ripng *ripng;
     784             : 
     785          14 :         ri = ifp->info;
     786          14 :         ripng = ri->ripng;
     787          14 :         if (!ripng)
     788             :                 return;
     789             : 
     790          14 :         ret = ripng_passive_interface_lookup(ripng, ifp->name);
     791          14 :         if (ret < 0)
     792          14 :                 ri->passive = 0;
     793             :         else
     794           0 :                 ri->passive = 1;
     795             : }
     796             : 
     797           1 : static void ripng_passive_interface_apply_all(struct ripng *ripng)
     798             : {
     799           1 :         struct interface *ifp;
     800             : 
     801           1 :         FOR_ALL_INTERFACES (ripng->vrf, ifp)
     802           0 :                 ripng_passive_interface_apply(ifp);
     803           1 : }
     804             : 
     805             : /* Passive interface. */
     806           0 : int ripng_passive_interface_set(struct ripng *ripng, const char *ifname)
     807             : {
     808           0 :         if (ripng_passive_interface_lookup(ripng, ifname) >= 0)
     809             :                 return NB_ERR_INCONSISTENCY;
     810             : 
     811           0 :         vector_set(ripng->passive_interface, strdup(ifname));
     812             : 
     813           0 :         ripng_passive_interface_apply_all(ripng);
     814             : 
     815           0 :         return NB_OK;
     816             : }
     817             : 
     818           0 : int ripng_passive_interface_unset(struct ripng *ripng, const char *ifname)
     819             : {
     820           0 :         int i;
     821           0 :         char *str;
     822             : 
     823           0 :         i = ripng_passive_interface_lookup(ripng, ifname);
     824           0 :         if (i < 0)
     825             :                 return NB_ERR_INCONSISTENCY;
     826             : 
     827           0 :         str = vector_slot(ripng->passive_interface, i);
     828           0 :         free(str);
     829           0 :         vector_unset(ripng->passive_interface, i);
     830             : 
     831           0 :         ripng_passive_interface_apply_all(ripng);
     832             : 
     833           0 :         return NB_OK;
     834             : }
     835             : 
     836             : /* Free all configured RIP passive-interface settings. */
     837           1 : void ripng_passive_interface_clean(struct ripng *ripng)
     838             : {
     839           1 :         unsigned int i;
     840           1 :         char *str;
     841             : 
     842           1 :         for (i = 0; i < vector_active(ripng->passive_interface); i++)
     843           0 :                 if ((str = vector_slot(ripng->passive_interface, i)) != NULL) {
     844           0 :                         free(str);
     845           0 :                         vector_slot(ripng->passive_interface, i) = NULL;
     846             :                 }
     847           1 :         ripng_passive_interface_apply_all(ripng);
     848           1 : }
     849             : 
     850             : /* Write RIPng enable network and interface to the vty. */
     851           1 : int ripng_network_write(struct vty *vty, struct ripng *ripng)
     852             : {
     853           1 :         unsigned int i;
     854           1 :         const char *ifname;
     855           1 :         struct agg_node *node;
     856             : 
     857             :         /* Write enable network. */
     858           3 :         for (node = agg_route_top(ripng->enable_network); node;
     859           1 :              node = agg_route_next(node))
     860           1 :                 if (node->info)
     861           1 :                         vty_out(vty, "    %pRN\n", node);
     862             : 
     863             :         /* Write enable interface. */
     864           1 :         for (i = 0; i < vector_active(ripng->enable_if); i++)
     865           0 :                 if ((ifname = vector_slot(ripng->enable_if, i)) != NULL)
     866           0 :                         vty_out(vty, "    %s\n", ifname);
     867             : 
     868           1 :         return 0;
     869             : }
     870             : 
     871           8 : static struct ripng_interface *ri_new(void)
     872             : {
     873           8 :         struct ripng_interface *ri;
     874             : 
     875           8 :         ri = XCALLOC(MTYPE_RIPNG_IF, sizeof(struct ripng_interface));
     876             : 
     877             :         /* Set default split-horizon behavior.  If the interface is Frame
     878             :            Relay or SMDS is enabled, the default value for split-horizon is
     879             :            off.  But currently Zebra does detect Frame Relay or SMDS
     880             :            interface.  So all interface is set to split horizon.  */
     881          16 :         ri->split_horizon =
     882           8 :                 yang_get_default_enum("%s/split-horizon", RIPNG_IFACE);
     883             : 
     884           8 :         return ri;
     885             : }
     886             : 
     887          46 : void ripng_interface_sync(struct interface *ifp)
     888             : {
     889          46 :         struct ripng_interface *ri;
     890             : 
     891          46 :         ri = ifp->info;
     892          38 :         if (ri)
     893          46 :                 ri->ripng = ifp->vrf->info;
     894           8 : }
     895             : 
     896           8 : static int ripng_if_new_hook(struct interface *ifp)
     897             : {
     898           8 :         ifp->info = ri_new();
     899           8 :         ripng_interface_sync(ifp);
     900             : 
     901           8 :         return 0;
     902             : }
     903             : 
     904             : /* Called when interface structure deleted. */
     905           8 : static int ripng_if_delete_hook(struct interface *ifp)
     906             : {
     907           8 :         XFREE(MTYPE_RIPNG_IF, ifp->info);
     908           8 :         return 0;
     909             : }
     910             : 
     911             : /* Initialization of interface. */
     912           1 : void ripng_if_init(void)
     913             : {
     914             :         /* Interface initialize. */
     915           1 :         hook_register_prio(if_add, 0, ripng_if_new_hook);
     916           1 :         hook_register_prio(if_del, 0, ripng_if_delete_hook);
     917             : 
     918             :         /* Install interface node. */
     919           1 :         if_cmd_init_default();
     920           1 :         if_zapi_callbacks(ripng_ifp_create, ripng_ifp_up,
     921             :                           ripng_ifp_down, ripng_ifp_destroy);
     922           1 : }

Generated by: LCOV version v1.16-topotato