back to topotato report
topotato coverage report
Current view: top level - ripngd - ripngd.c (source / functions) Hit Total Coverage
Test: aggregated run ( view descriptions ) Lines: 357 1314 27.2 %
Date: 2023-02-24 14:41:08 Functions: 32 70 45.7 %

          Line data    Source code
       1             : /* RIPng daemon
       2             :  * Copyright (C) 1998, 1999 Kunihiro Ishiguro
       3             :  *
       4             :  * This file is part of GNU Zebra.
       5             :  *
       6             :  * GNU Zebra is free software; you can redistribute it and/or modify it
       7             :  * under the terms of the GNU General Public License as published by the
       8             :  * Free Software Foundation; either version 2, or (at your option) any
       9             :  * later version.
      10             :  *
      11             :  * GNU Zebra is distributed in the hope that it will be useful, but
      12             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14             :  * General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU General Public License along
      17             :  * with this program; see the file COPYING; if not, write to the Free Software
      18             :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
      19             :  */
      20             : 
      21             : #include <zebra.h>
      22             : 
      23             : #include "prefix.h"
      24             : #include "filter.h"
      25             : #include "log.h"
      26             : #include "thread.h"
      27             : #include "memory.h"
      28             : #include "if.h"
      29             : #include "stream.h"
      30             : #include "agg_table.h"
      31             : #include "command.h"
      32             : #include "sockopt.h"
      33             : #include "distribute.h"
      34             : #include "plist.h"
      35             : #include "routemap.h"
      36             : #include "if_rmap.h"
      37             : #include "privs.h"
      38             : #include "lib_errors.h"
      39             : #include "northbound_cli.h"
      40             : #include "network.h"
      41             : 
      42             : #include "ripngd/ripngd.h"
      43             : #include "ripngd/ripng_route.h"
      44             : #include "ripngd/ripng_debug.h"
      45             : #include "ripngd/ripng_nexthop.h"
      46             : 
      47           3 : DEFINE_MGROUP(RIPNGD, "ripngd");
      48           3 : DEFINE_MTYPE_STATIC(RIPNGD, RIPNG, "RIPng structure");
      49           3 : DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_VRF_NAME, "RIPng VRF name");
      50           3 : DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_ROUTE, "RIPng route info");
      51             : 
      52             : enum { ripng_all_route,
      53             :        ripng_changed_route,
      54             : };
      55             : 
      56             : static void ripng_distribute_update(struct distribute_ctx *ctx,
      57             :                                     struct distribute *dist);
      58             : 
      59             : /* Prototypes. */
      60             : void ripng_output_process(struct interface *, struct sockaddr_in6 *, int);
      61             : static void ripng_instance_enable(struct ripng *ripng, struct vrf *vrf,
      62             :                                   int sock);
      63             : static void ripng_instance_disable(struct ripng *ripng);
      64             : static void ripng_triggered_update(struct thread *);
      65             : static void ripng_if_rmap_update(struct if_rmap_ctx *ctx,
      66             :                                  struct if_rmap *if_rmap);
      67             : 
      68             : /* Generate rb-tree of RIPng instances. */
      69           3 : static inline int ripng_instance_compare(const struct ripng *a,
      70             :                                          const struct ripng *b)
      71             : {
      72           3 :         return strcmp(a->vrf_name, b->vrf_name);
      73             : }
      74           3 : RB_GENERATE(ripng_instance_head, ripng, entry, ripng_instance_compare)
      75             : 
      76             : struct ripng_instance_head ripng_instances = RB_INITIALIZER(&ripng_instances);
      77             : 
      78             : /* RIPng next hop specification. */
      79             : struct ripng_nexthop {
      80             :         enum ripng_nexthop_type {
      81             :                 RIPNG_NEXTHOP_UNSPEC,
      82             :                 RIPNG_NEXTHOP_ADDRESS
      83             :         } flag;
      84             :         struct in6_addr address;
      85             : };
      86             : 
      87           2 : int ripng_route_rte(struct ripng_info *rinfo)
      88             : {
      89           2 :         return (rinfo->type == ZEBRA_ROUTE_RIPNG
      90           2 :                 && rinfo->sub_type == RIPNG_ROUTE_RTE);
      91             : }
      92             : 
      93             : /* Allocate new ripng information. */
      94           1 : struct ripng_info *ripng_info_new(void)
      95             : {
      96           1 :         struct ripng_info *new;
      97             : 
      98           0 :         new = XCALLOC(MTYPE_RIPNG_ROUTE, sizeof(struct ripng_info));
      99           1 :         return new;
     100             : }
     101             : 
     102             : /* Free ripng information. */
     103           1 : void ripng_info_free(struct ripng_info *rinfo)
     104             : {
     105           0 :         XFREE(MTYPE_RIPNG_ROUTE, rinfo);
     106           0 : }
     107             : 
     108           0 : struct ripng *ripng_info_get_instance(const struct ripng_info *rinfo)
     109             : {
     110           0 :         return agg_get_table_info(agg_get_table(rinfo->rp));
     111             : }
     112             : 
     113             : /* Create ripng socket. */
     114           1 : int ripng_make_socket(struct vrf *vrf)
     115             : {
     116           1 :         int ret;
     117           1 :         int sock;
     118           1 :         struct sockaddr_in6 ripaddr;
     119           1 :         const char *vrf_dev = NULL;
     120             : 
     121             :         /* Make datagram socket. */
     122           1 :         if (vrf->vrf_id != VRF_DEFAULT)
     123           0 :                 vrf_dev = vrf->name;
     124           2 :         frr_with_privs(&ripngd_privs) {
     125           1 :                 sock = vrf_socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP,
     126             :                                   vrf->vrf_id, vrf_dev);
     127           1 :                 if (sock < 0) {
     128           0 :                         flog_err_sys(EC_LIB_SOCKET,
     129             :                                      "Cannot create UDP socket: %s",
     130             :                                      safe_strerror(errno));
     131           0 :                         return -1;
     132             :                 }
     133             :         }
     134             : 
     135           1 :         sockopt_reuseaddr(sock);
     136           1 :         sockopt_reuseport(sock);
     137           1 :         setsockopt_so_recvbuf(sock, 8096);
     138           1 :         ret = setsockopt_ipv6_pktinfo(sock, 1);
     139           1 :         if (ret < 0)
     140           0 :                 goto error;
     141             : #ifdef IPTOS_PREC_INTERNETCONTROL
     142           1 :         ret = setsockopt_ipv6_tclass(sock, IPTOS_PREC_INTERNETCONTROL);
     143           1 :         if (ret < 0)
     144           0 :                 goto error;
     145             : #endif
     146           1 :         ret = setsockopt_ipv6_multicast_hops(sock, 255);
     147           1 :         if (ret < 0)
     148           0 :                 goto error;
     149           1 :         ret = setsockopt_ipv6_multicast_loop(sock, 0);
     150           1 :         if (ret < 0)
     151           0 :                 goto error;
     152           1 :         ret = setsockopt_ipv6_hoplimit(sock, 1);
     153           1 :         if (ret < 0)
     154           0 :                 goto error;
     155             : 
     156           1 :         memset(&ripaddr, 0, sizeof(ripaddr));
     157           1 :         ripaddr.sin6_family = AF_INET6;
     158             : #ifdef SIN6_LEN
     159             :         ripaddr.sin6_len = sizeof(struct sockaddr_in6);
     160             : #endif /* SIN6_LEN */
     161           1 :         ripaddr.sin6_port = htons(RIPNG_PORT_DEFAULT);
     162             : 
     163           2 :         frr_with_privs(&ripngd_privs) {
     164           1 :                 ret = bind(sock, (struct sockaddr *)&ripaddr, sizeof(ripaddr));
     165           1 :                 if (ret < 0) {
     166           0 :                         zlog_err("Can't bind ripng socket: %s.",
     167             :                                  safe_strerror(errno));
     168           0 :                         goto error;
     169             :                 }
     170             :         }
     171           1 :         return sock;
     172             : 
     173           0 : error:
     174           0 :         close(sock);
     175           0 :         return ret;
     176             : }
     177             : 
     178             : /* Send RIPng packet. */
     179           0 : int ripng_send_packet(caddr_t buf, int bufsize, struct sockaddr_in6 *to,
     180             :                       struct interface *ifp)
     181             : {
     182           0 :         struct ripng_interface *ri = ifp->info;
     183           0 :         struct ripng *ripng = ri->ripng;
     184           0 :         int ret;
     185           0 :         struct msghdr msg;
     186           0 :         struct iovec iov;
     187           0 :         struct cmsghdr *cmsgptr;
     188           0 :         char adata[256] = {};
     189           0 :         struct in6_pktinfo *pkt;
     190           0 :         struct sockaddr_in6 addr;
     191             : 
     192           0 :         if (IS_RIPNG_DEBUG_SEND) {
     193           0 :                 if (to)
     194           0 :                         zlog_debug("send to %pI6", &to->sin6_addr);
     195           0 :                 zlog_debug("  send interface %s", ifp->name);
     196           0 :                 zlog_debug("  send packet size %d", bufsize);
     197             :         }
     198             : 
     199           0 :         memset(&addr, 0, sizeof(addr));
     200           0 :         addr.sin6_family = AF_INET6;
     201             : #ifdef SIN6_LEN
     202             :         addr.sin6_len = sizeof(struct sockaddr_in6);
     203             : #endif /* SIN6_LEN */
     204           0 :         addr.sin6_flowinfo = htonl(RIPNG_PRIORITY_DEFAULT);
     205             : 
     206             :         /* When destination is specified. */
     207           0 :         if (to != NULL) {
     208           0 :                 addr.sin6_addr = to->sin6_addr;
     209           0 :                 addr.sin6_port = to->sin6_port;
     210             :         } else {
     211           0 :                 inet_pton(AF_INET6, RIPNG_GROUP, &addr.sin6_addr);
     212           0 :                 addr.sin6_port = htons(RIPNG_PORT_DEFAULT);
     213             :         }
     214             : 
     215           0 :         memset(&msg, 0, sizeof(msg));
     216           0 :         msg.msg_name = (void *)&addr;
     217           0 :         msg.msg_namelen = sizeof(struct sockaddr_in6);
     218           0 :         msg.msg_iov = &iov;
     219           0 :         msg.msg_iovlen = 1;
     220           0 :         msg.msg_control = adata;
     221           0 :         msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
     222             : 
     223           0 :         iov.iov_base = buf;
     224           0 :         iov.iov_len = bufsize;
     225             : 
     226           0 :         cmsgptr = (struct cmsghdr *)adata;
     227           0 :         cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
     228           0 :         cmsgptr->cmsg_level = IPPROTO_IPV6;
     229           0 :         cmsgptr->cmsg_type = IPV6_PKTINFO;
     230             : 
     231           0 :         pkt = (struct in6_pktinfo *)CMSG_DATA(cmsgptr);
     232           0 :         memset(&pkt->ipi6_addr, 0, sizeof(struct in6_addr));
     233           0 :         pkt->ipi6_ifindex = ifp->ifindex;
     234             : 
     235           0 :         ret = sendmsg(ripng->sock, &msg, 0);
     236             : 
     237           0 :         if (ret < 0) {
     238           0 :                 if (to)
     239           0 :                         flog_err_sys(EC_LIB_SOCKET,
     240             :                                      "RIPng send fail on %s to %pI6: %s",
     241             :                                      ifp->name, &to->sin6_addr,
     242             :                                      safe_strerror(errno));
     243             :                 else
     244           0 :                         flog_err_sys(EC_LIB_SOCKET, "RIPng send fail on %s: %s",
     245             :                                      ifp->name, safe_strerror(errno));
     246             :         }
     247             : 
     248           0 :         return ret;
     249             : }
     250             : 
     251             : /* Receive UDP RIPng packet from socket. */
     252           0 : static int ripng_recv_packet(int sock, uint8_t *buf, int bufsize,
     253             :                              struct sockaddr_in6 *from, ifindex_t *ifindex,
     254             :                              int *hoplimit)
     255             : {
     256           0 :         int ret;
     257           0 :         struct msghdr msg;
     258           0 :         struct iovec iov;
     259           0 :         struct cmsghdr *cmsgptr;
     260           0 :         struct in6_addr dst = {.s6_addr = {0}};
     261             : 
     262           0 :         memset(&dst, 0, sizeof(dst));
     263             : 
     264             :         /* Ancillary data.  This store cmsghdr and in6_pktinfo.  But at this
     265             :            point I can't determine size of cmsghdr */
     266           0 :         char adata[1024];
     267             : 
     268             :         /* Fill in message and iovec. */
     269           0 :         memset(&msg, 0, sizeof(msg));
     270           0 :         msg.msg_name = (void *)from;
     271           0 :         msg.msg_namelen = sizeof(struct sockaddr_in6);
     272           0 :         msg.msg_iov = &iov;
     273           0 :         msg.msg_iovlen = 1;
     274           0 :         msg.msg_control = (void *)adata;
     275           0 :         msg.msg_controllen = sizeof(adata);
     276           0 :         iov.iov_base = buf;
     277           0 :         iov.iov_len = bufsize;
     278             : 
     279             :         /* If recvmsg fail return minus value. */
     280           0 :         ret = recvmsg(sock, &msg, 0);
     281           0 :         if (ret < 0)
     282             :                 return ret;
     283             : 
     284           0 :         for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL;
     285           0 :              cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) {
     286             :                 /* I want interface index which this packet comes from. */
     287           0 :                 if (cmsgptr->cmsg_level == IPPROTO_IPV6
     288           0 :                     && cmsgptr->cmsg_type == IPV6_PKTINFO) {
     289           0 :                         struct in6_pktinfo *ptr;
     290             : 
     291           0 :                         ptr = (struct in6_pktinfo *)CMSG_DATA(cmsgptr);
     292           0 :                         *ifindex = ptr->ipi6_ifindex;
     293           0 :                         dst = ptr->ipi6_addr;
     294             : 
     295           0 :                         if (*ifindex == 0)
     296           0 :                                 zlog_warn(
     297             :                                         "Interface index returned by IPV6_PKTINFO is zero");
     298             :                 }
     299             : 
     300             :                 /* Incoming packet's multicast hop limit. */
     301           0 :                 if (cmsgptr->cmsg_level == IPPROTO_IPV6
     302           0 :                     && cmsgptr->cmsg_type == IPV6_HOPLIMIT) {
     303           0 :                         int *phoplimit = (int *)CMSG_DATA(cmsgptr);
     304           0 :                         *hoplimit = *phoplimit;
     305             :                 }
     306             :         }
     307             : 
     308             :         /* Hoplimit check shold be done when destination address is
     309             :            multicast address. */
     310           0 :         if (!IN6_IS_ADDR_MULTICAST(&dst))
     311           0 :                 *hoplimit = -1;
     312             : 
     313             :         return ret;
     314             : }
     315             : 
     316             : /* Dump rip packet */
     317           0 : void ripng_packet_dump(struct ripng_packet *packet, int size,
     318             :                        const char *sndrcv)
     319             : {
     320           0 :         caddr_t lim;
     321           0 :         struct rte *rte;
     322           0 :         const char *command_str;
     323             : 
     324             :         /* Set command string. */
     325           0 :         if (packet->command == RIPNG_REQUEST)
     326             :                 command_str = "request";
     327           0 :         else if (packet->command == RIPNG_RESPONSE)
     328             :                 command_str = "response";
     329             :         else
     330           0 :                 command_str = "unknown";
     331             : 
     332             :         /* Dump packet header. */
     333           0 :         zlog_debug("%s %s version %d packet size %d", sndrcv, command_str,
     334             :                    packet->version, size);
     335             : 
     336             :         /* Dump each routing table entry. */
     337           0 :         rte = packet->rte;
     338             : 
     339           0 :         for (lim = (caddr_t)packet + size; (caddr_t)rte < lim; rte++) {
     340           0 :                 if (rte->metric == RIPNG_METRIC_NEXTHOP)
     341           0 :                         zlog_debug("  nexthop %pI6/%d", &rte->addr,
     342             :                                    rte->prefixlen);
     343             :                 else
     344           0 :                         zlog_debug("  %pI6/%d metric %d tag %" ROUTE_TAG_PRI,
     345             :                                    &rte->addr, rte->prefixlen,
     346             :                                    rte->metric, (route_tag_t)ntohs(rte->tag));
     347             :         }
     348           0 : }
     349             : 
     350             : /* RIPng next hop address RTE (Route Table Entry). */
     351           0 : static void ripng_nexthop_rte(struct rte *rte, struct sockaddr_in6 *from,
     352             :                               struct ripng_nexthop *nexthop)
     353             : {
     354             :         /* Logging before checking RTE. */
     355           0 :         if (IS_RIPNG_DEBUG_RECV)
     356           0 :                 zlog_debug("RIPng nexthop RTE address %pI6 tag %" ROUTE_TAG_PRI
     357             :                            " prefixlen %d",
     358             :                            &rte->addr, (route_tag_t)ntohs(rte->tag),
     359             :                            rte->prefixlen);
     360             : 
     361             :         /* RFC2080 2.1.1 Next Hop:
     362             :          The route tag and prefix length in the next hop RTE must be
     363             :          set to zero on sending and ignored on receiption.  */
     364           0 :         if (ntohs(rte->tag) != 0)
     365           0 :                 zlog_warn(
     366             :                         "RIPng nexthop RTE with non zero tag value %" ROUTE_TAG_PRI
     367             :                         " from %pI6",
     368             :                         (route_tag_t)ntohs(rte->tag), &from->sin6_addr);
     369             : 
     370           0 :         if (rte->prefixlen != 0)
     371           0 :                 zlog_warn(
     372             :                         "RIPng nexthop RTE with non zero prefixlen value %d from %pI6",
     373             :                         rte->prefixlen, &from->sin6_addr);
     374             : 
     375             :         /* Specifying a value of 0:0:0:0:0:0:0:0 in the prefix field of a
     376             :          next hop RTE indicates that the next hop address should be the
     377             :          originator of the RIPng advertisement.  An address specified as a
     378             :          next hop must be a link-local address.  */
     379           0 :         if (IN6_IS_ADDR_UNSPECIFIED(&rte->addr)) {
     380           0 :                 nexthop->flag = RIPNG_NEXTHOP_UNSPEC;
     381           0 :                 memset(&nexthop->address, 0, sizeof(struct in6_addr));
     382           0 :                 return;
     383             :         }
     384             : 
     385           0 :         if (IN6_IS_ADDR_LINKLOCAL(&rte->addr)) {
     386           0 :                 nexthop->flag = RIPNG_NEXTHOP_ADDRESS;
     387           0 :                 IPV6_ADDR_COPY(&nexthop->address, &rte->addr);
     388           0 :                 return;
     389             :         }
     390             : 
     391             :         /* The purpose of the next hop RTE is to eliminate packets being
     392             :          routed through extra hops in the system.  It is particularly useful
     393             :          when RIPng is not being run on all of the routers on a network.
     394             :          Note that next hop RTE is "advisory".  That is, if the provided
     395             :          information is ignored, a possibly sub-optimal, but absolutely
     396             :          valid, route may be taken.  If the received next hop address is not
     397             :          a link-local address, it should be treated as 0:0:0:0:0:0:0:0.  */
     398           0 :         zlog_warn("RIPng nexthop RTE with non link-local address %pI6 from %pI6",
     399             :                   &rte->addr, &from->sin6_addr);
     400             : 
     401           0 :         nexthop->flag = RIPNG_NEXTHOP_UNSPEC;
     402           0 :         memset(&nexthop->address, 0, sizeof(struct in6_addr));
     403             : 
     404           0 :         return;
     405             : }
     406             : 
     407             : /* If ifp has same link-local address then return 1. */
     408           0 : static int ripng_lladdr_check(struct interface *ifp, struct in6_addr *addr)
     409             : {
     410           0 :         struct listnode *node;
     411           0 :         struct connected *connected;
     412           0 :         struct prefix *p;
     413             : 
     414           0 :         for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, connected)) {
     415           0 :                 p = connected->address;
     416             : 
     417           0 :                 if (p->family == AF_INET6
     418           0 :                     && IN6_IS_ADDR_LINKLOCAL(&p->u.prefix6)
     419           0 :                     && IN6_ARE_ADDR_EQUAL(&p->u.prefix6, addr))
     420             :                         return 1;
     421             :         }
     422             :         return 0;
     423             : }
     424             : 
     425             : /* RIPng route garbage collect timer. */
     426           0 : static void ripng_garbage_collect(struct thread *t)
     427             : {
     428           0 :         struct ripng_info *rinfo;
     429           0 :         struct agg_node *rp;
     430             : 
     431           0 :         rinfo = THREAD_ARG(t);
     432             : 
     433             :         /* Off timeout timer. */
     434           0 :         THREAD_OFF(rinfo->t_timeout);
     435             : 
     436             :         /* Get route_node pointer. */
     437           0 :         rp = rinfo->rp;
     438             : 
     439             :         /* Unlock route_node. */
     440           0 :         listnode_delete(rp->info, rinfo);
     441           0 :         if (list_isempty((struct list *)rp->info)) {
     442           0 :                 list_delete((struct list **)&rp->info);
     443           0 :                 agg_unlock_node(rp);
     444             :         }
     445             : 
     446             :         /* Free RIPng routing information. */
     447           0 :         ripng_info_free(rinfo);
     448           0 : }
     449             : 
     450             : static void ripng_timeout_update(struct ripng *ripng, struct ripng_info *rinfo);
     451             : 
     452             : /* Add new route to the ECMP list.
     453             :  * RETURN: the new entry added in the list, or NULL if it is not the first
     454             :  *         entry and ECMP is not allowed.
     455             :  */
     456           1 : struct ripng_info *ripng_ecmp_add(struct ripng *ripng,
     457             :                                   struct ripng_info *rinfo_new)
     458             : {
     459           1 :         struct agg_node *rp = rinfo_new->rp;
     460           1 :         struct ripng_info *rinfo = NULL;
     461           1 :         struct list *list = NULL;
     462             : 
     463           1 :         if (rp->info == NULL)
     464           1 :                 rp->info = list_new();
     465           1 :         list = (struct list *)rp->info;
     466             : 
     467             :         /* If ECMP is not allowed and some entry already exists in the list,
     468             :          * do nothing. */
     469           1 :         if (listcount(list) && !ripng->ecmp)
     470             :                 return NULL;
     471             : 
     472           1 :         rinfo = ripng_info_new();
     473           1 :         memcpy(rinfo, rinfo_new, sizeof(struct ripng_info));
     474           1 :         listnode_add(list, rinfo);
     475             : 
     476           1 :         if (ripng_route_rte(rinfo)) {
     477           0 :                 ripng_timeout_update(ripng, rinfo);
     478           0 :                 ripng_zebra_ipv6_add(ripng, rp);
     479             :         }
     480             : 
     481           1 :         ripng_aggregate_increment(rp, rinfo);
     482             : 
     483             :         /* Set the route change flag on the first entry. */
     484           1 :         rinfo = listgetdata(listhead(list));
     485           1 :         SET_FLAG(rinfo->flags, RIPNG_RTF_CHANGED);
     486             : 
     487             :         /* Signal the output process to trigger an update. */
     488           1 :         ripng_event(ripng, RIPNG_TRIGGERED_UPDATE, 0);
     489             : 
     490           1 :         return rinfo;
     491             : }
     492             : 
     493             : /* Replace the ECMP list with the new route.
     494             :  * RETURN: the new entry added in the list
     495             :  */
     496           0 : struct ripng_info *ripng_ecmp_replace(struct ripng *ripng,
     497             :                                       struct ripng_info *rinfo_new)
     498             : {
     499           0 :         struct agg_node *rp = rinfo_new->rp;
     500           0 :         struct list *list = (struct list *)rp->info;
     501           0 :         struct ripng_info *rinfo = NULL, *tmp_rinfo = NULL;
     502           0 :         struct listnode *node = NULL, *nextnode = NULL;
     503             : 
     504           0 :         if (list == NULL || listcount(list) == 0)
     505           0 :                 return ripng_ecmp_add(ripng, rinfo_new);
     506             : 
     507             :         /* Get the first entry */
     508           0 :         rinfo = listgetdata(listhead(list));
     509             : 
     510             :         /* Learnt route replaced by a local one. Delete it from zebra. */
     511           0 :         if (ripng_route_rte(rinfo) && !ripng_route_rte(rinfo_new))
     512           0 :                 if (CHECK_FLAG(rinfo->flags, RIPNG_RTF_FIB))
     513           0 :                         ripng_zebra_ipv6_delete(ripng, rp);
     514             : 
     515           0 :         if (rinfo->metric != RIPNG_METRIC_INFINITY)
     516           0 :                 ripng_aggregate_decrement_list(rp, list);
     517             : 
     518             :         /* Re-use the first entry, and delete the others. */
     519           0 :         for (ALL_LIST_ELEMENTS(list, node, nextnode, tmp_rinfo))
     520           0 :                 if (tmp_rinfo != rinfo) {
     521           0 :                         THREAD_OFF(tmp_rinfo->t_timeout);
     522           0 :                         THREAD_OFF(tmp_rinfo->t_garbage_collect);
     523           0 :                         list_delete_node(list, node);
     524           0 :                         ripng_info_free(tmp_rinfo);
     525             :                 }
     526             : 
     527           0 :         THREAD_OFF(rinfo->t_timeout);
     528           0 :         THREAD_OFF(rinfo->t_garbage_collect);
     529           0 :         memcpy(rinfo, rinfo_new, sizeof(struct ripng_info));
     530             : 
     531           0 :         if (ripng_route_rte(rinfo)) {
     532           0 :                 ripng_timeout_update(ripng, rinfo);
     533             :                 /* The ADD message implies an update. */
     534           0 :                 ripng_zebra_ipv6_add(ripng, rp);
     535             :         }
     536             : 
     537           0 :         ripng_aggregate_increment(rp, rinfo);
     538             : 
     539             :         /* Set the route change flag. */
     540           0 :         SET_FLAG(rinfo->flags, RIPNG_RTF_CHANGED);
     541             : 
     542             :         /* Signal the output process to trigger an update. */
     543           0 :         ripng_event(ripng, RIPNG_TRIGGERED_UPDATE, 0);
     544             : 
     545           0 :         return rinfo;
     546             : }
     547             : 
     548             : /* Delete one route from the ECMP list.
     549             :  * RETURN:
     550             :  *  null - the entry is freed, and other entries exist in the list
     551             :  *  the entry - the entry is the last one in the list; its metric is set
     552             :  *              to INFINITY, and the garbage collector is started for it
     553             :  */
     554           0 : struct ripng_info *ripng_ecmp_delete(struct ripng *ripng,
     555             :                                      struct ripng_info *rinfo)
     556             : {
     557           0 :         struct agg_node *rp = rinfo->rp;
     558           0 :         struct list *list = (struct list *)rp->info;
     559             : 
     560           0 :         THREAD_OFF(rinfo->t_timeout);
     561             : 
     562           0 :         if (rinfo->metric != RIPNG_METRIC_INFINITY)
     563           0 :                 ripng_aggregate_decrement(rp, rinfo);
     564             : 
     565           0 :         if (listcount(list) > 1) {
     566             :                 /* Some other ECMP entries still exist. Just delete this entry.
     567             :                  */
     568           0 :                 THREAD_OFF(rinfo->t_garbage_collect);
     569           0 :                 listnode_delete(list, rinfo);
     570           0 :                 if (ripng_route_rte(rinfo)
     571           0 :                     && CHECK_FLAG(rinfo->flags, RIPNG_RTF_FIB))
     572             :                         /* The ADD message implies the update. */
     573           0 :                         ripng_zebra_ipv6_add(ripng, rp);
     574           0 :                 ripng_info_free(rinfo);
     575           0 :                 rinfo = NULL;
     576             :         } else {
     577           0 :                 assert(rinfo == listgetdata(listhead(list)));
     578             : 
     579             :                 /* This is the only entry left in the list. We must keep it in
     580             :                  * the list for garbage collection time, with INFINITY metric.
     581             :                  */
     582             : 
     583           0 :                 rinfo->metric = RIPNG_METRIC_INFINITY;
     584           0 :                 RIPNG_TIMER_ON(rinfo->t_garbage_collect, ripng_garbage_collect,
     585             :                                ripng->garbage_time);
     586             : 
     587           0 :                 if (ripng_route_rte(rinfo)
     588           0 :                     && CHECK_FLAG(rinfo->flags, RIPNG_RTF_FIB))
     589           0 :                         ripng_zebra_ipv6_delete(ripng, rp);
     590             :         }
     591             : 
     592             :         /* Set the route change flag on the first entry. */
     593           0 :         rinfo = listgetdata(listhead(list));
     594           0 :         SET_FLAG(rinfo->flags, RIPNG_RTF_CHANGED);
     595             : 
     596             :         /* Signal the output process to trigger an update. */
     597           0 :         ripng_event(ripng, RIPNG_TRIGGERED_UPDATE, 0);
     598             : 
     599           0 :         return rinfo;
     600             : }
     601             : 
     602             : /* Timeout RIPng routes. */
     603           0 : static void ripng_timeout(struct thread *t)
     604             : {
     605           0 :         struct ripng_info *rinfo = THREAD_ARG(t);
     606           0 :         struct ripng *ripng = ripng_info_get_instance(rinfo);
     607             : 
     608           0 :         ripng_ecmp_delete(ripng, rinfo);
     609           0 : }
     610             : 
     611           0 : static void ripng_timeout_update(struct ripng *ripng, struct ripng_info *rinfo)
     612             : {
     613           0 :         if (rinfo->metric != RIPNG_METRIC_INFINITY) {
     614           0 :                 THREAD_OFF(rinfo->t_timeout);
     615           0 :                 thread_add_timer(master, ripng_timeout, rinfo,
     616             :                                  ripng->timeout_time, &rinfo->t_timeout);
     617             :         }
     618           0 : }
     619             : 
     620           0 : static int ripng_filter(int ripng_distribute, struct prefix_ipv6 *p,
     621             :                         struct ripng_interface *ri)
     622             : {
     623           0 :         struct distribute *dist;
     624           0 :         struct access_list *alist;
     625           0 :         struct prefix_list *plist;
     626           0 :         int distribute = ripng_distribute == RIPNG_FILTER_OUT
     627             :                                  ? DISTRIBUTE_V6_OUT
     628           0 :                                  : DISTRIBUTE_V6_IN;
     629           0 :         const char *inout = ripng_distribute == RIPNG_FILTER_OUT ? "out" : "in";
     630             : 
     631             :         /* Input distribute-list filtering. */
     632           0 :         if (ri->list[ripng_distribute]) {
     633           0 :                 if (access_list_apply(ri->list[ripng_distribute],
     634             :                                       (struct prefix *)p)
     635             :                     == FILTER_DENY) {
     636           0 :                         if (IS_RIPNG_DEBUG_PACKET)
     637           0 :                                 zlog_debug("%pFX filtered by distribute %s", p,
     638             :                                            inout);
     639           0 :                         return -1;
     640             :                 }
     641             :         }
     642           0 :         if (ri->prefix[ripng_distribute]) {
     643           0 :                 if (prefix_list_apply(ri->prefix[ripng_distribute],
     644             :                                       (struct prefix *)p)
     645             :                     == PREFIX_DENY) {
     646           0 :                         if (IS_RIPNG_DEBUG_PACKET)
     647           0 :                                 zlog_debug("%pFX filtered by prefix-list %s", p,
     648             :                                            inout);
     649           0 :                         return -1;
     650             :                 }
     651             :         }
     652             : 
     653             :         /* All interface filter check. */
     654           0 :         dist = distribute_lookup(ri->ripng->distribute_ctx, NULL);
     655           0 :         if (dist) {
     656           0 :                 if (dist->list[distribute]) {
     657           0 :                         alist = access_list_lookup(AFI_IP6,
     658             :                                                    dist->list[distribute]);
     659             : 
     660           0 :                         if (alist) {
     661           0 :                                 if (access_list_apply(alist, (struct prefix *)p)
     662             :                                     == FILTER_DENY) {
     663           0 :                                         if (IS_RIPNG_DEBUG_PACKET)
     664           0 :                                                 zlog_debug(
     665             :                                                         "%pFX filtered by distribute %s",
     666             :                                                         p, inout);
     667           0 :                                         return -1;
     668             :                                 }
     669             :                         }
     670             :                 }
     671           0 :                 if (dist->prefix[distribute]) {
     672           0 :                         plist = prefix_list_lookup(AFI_IP6,
     673             :                                                    dist->prefix[distribute]);
     674             : 
     675           0 :                         if (plist) {
     676           0 :                                 if (prefix_list_apply(plist, (struct prefix *)p)
     677             :                                     == PREFIX_DENY) {
     678           0 :                                         if (IS_RIPNG_DEBUG_PACKET)
     679           0 :                                                 zlog_debug(
     680             :                                                         "%pFX filtered by prefix-list %s",
     681             :                                                         p, inout);
     682           0 :                                         return -1;
     683             :                                 }
     684             :                         }
     685             :                 }
     686             :         }
     687             :         return 0;
     688             : }
     689             : 
     690             : /* Process RIPng route according to RFC2080. */
     691           0 : static void ripng_route_process(struct rte *rte, struct sockaddr_in6 *from,
     692             :                                 struct ripng_nexthop *ripng_nexthop,
     693             :                                 struct interface *ifp)
     694             : {
     695           0 :         int ret;
     696           0 :         struct prefix_ipv6 p;
     697           0 :         struct agg_node *rp;
     698           0 :         struct ripng_info *rinfo = NULL, newinfo;
     699           0 :         struct ripng_interface *ri;
     700           0 :         struct ripng *ripng;
     701           0 :         struct in6_addr *nexthop;
     702           0 :         int same = 0;
     703           0 :         struct list *list = NULL;
     704           0 :         struct listnode *node = NULL;
     705             : 
     706             :         /* Make prefix structure. */
     707           0 :         memset(&p, 0, sizeof(struct prefix_ipv6));
     708           0 :         p.family = AF_INET6;
     709             :         /* p.prefix = rte->addr; */
     710           0 :         IPV6_ADDR_COPY(&p.prefix, &rte->addr);
     711           0 :         p.prefixlen = rte->prefixlen;
     712             : 
     713             :         /* Make sure mask is applied. */
     714             :         /* XXX We have to check the prefix is valid or not before call
     715             :            apply_mask_ipv6. */
     716           0 :         apply_mask_ipv6(&p);
     717             : 
     718           0 :         ri = ifp->info;
     719           0 :         ripng = ri->ripng;
     720             : 
     721             :         /* Apply input filters. */
     722           0 :         ret = ripng_filter(RIPNG_FILTER_IN, &p, ri);
     723           0 :         if (ret < 0)
     724           0 :                 return;
     725             : 
     726           0 :         memset(&newinfo, 0, sizeof(newinfo));
     727           0 :         newinfo.type = ZEBRA_ROUTE_RIPNG;
     728           0 :         newinfo.sub_type = RIPNG_ROUTE_RTE;
     729           0 :         if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS)
     730           0 :                 newinfo.nexthop = ripng_nexthop->address;
     731             :         else
     732           0 :                 newinfo.nexthop = from->sin6_addr;
     733           0 :         newinfo.from = from->sin6_addr;
     734           0 :         newinfo.ifindex = ifp->ifindex;
     735           0 :         newinfo.metric = rte->metric;
     736           0 :         newinfo.metric_out = rte->metric; /* XXX */
     737           0 :         newinfo.tag = ntohs(rte->tag);    /* XXX */
     738             : 
     739             :         /* Modify entry. */
     740           0 :         if (ri->routemap[RIPNG_FILTER_IN]) {
     741           0 :                 ret = route_map_apply(ri->routemap[RIPNG_FILTER_IN],
     742             :                                       (struct prefix *)&p, &newinfo);
     743             : 
     744           0 :                 if (ret == RMAP_DENYMATCH) {
     745           0 :                         if (IS_RIPNG_DEBUG_PACKET)
     746           0 :                                 zlog_debug(
     747             :                                         "RIPng %pFX is filtered by route-map in",
     748             :                                         &p);
     749           0 :                         return;
     750             :                 }
     751             : 
     752             :                 /* Get back the object */
     753           0 :                 if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS) {
     754           0 :                         if (!IPV6_ADDR_SAME(&newinfo.nexthop,
     755             :                                             &ripng_nexthop->address)) {
     756             :                                 /* the nexthop get changed by the routemap */
     757           0 :                                 if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop))
     758           0 :                                         ripng_nexthop->address =
     759             :                                                 newinfo.nexthop;
     760             :                                 else
     761           0 :                                         ripng_nexthop->address = in6addr_any;
     762             :                         }
     763             :                 } else {
     764           0 :                         if (!IPV6_ADDR_SAME(&newinfo.nexthop,
     765             :                                             &from->sin6_addr)) {
     766             :                                 /* the nexthop get changed by the routemap */
     767           0 :                                 if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop)) {
     768           0 :                                         ripng_nexthop->flag =
     769             :                                                 RIPNG_NEXTHOP_ADDRESS;
     770           0 :                                         ripng_nexthop->address =
     771             :                                                 newinfo.nexthop;
     772             :                                 }
     773             :                         }
     774             :                 }
     775           0 :                 rte->tag = htons(newinfo.tag_out); /* XXX */
     776           0 :                 rte->metric =
     777           0 :                         newinfo.metric_out; /* XXX: the routemap uses the
     778             :                                                metric_out field */
     779             :         }
     780             : 
     781             :         /* Once the entry has been validated, update the metric by
     782             :          * adding the cost of the network on wich the message
     783             :          * arrived. If the result is greater than infinity, use infinity
     784             :          * (RFC2453 Sec. 3.9.2)
     785             :          **/
     786             : 
     787             :         /* Zebra ripngd can handle offset-list in. */
     788           0 :         ret = ripng_offset_list_apply_in(ripng, &p, ifp, &rte->metric);
     789             : 
     790             :         /* If offset-list does not modify the metric use interface's
     791             :          * one. */
     792           0 :         if (!ret)
     793           0 :                 rte->metric += ifp->metric ? ifp->metric : 1;
     794             : 
     795           0 :         if (rte->metric > RIPNG_METRIC_INFINITY)
     796           0 :                 rte->metric = RIPNG_METRIC_INFINITY;
     797             : 
     798             :         /* Set nexthop pointer. */
     799           0 :         if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS)
     800           0 :                 nexthop = &ripng_nexthop->address;
     801             :         else
     802           0 :                 nexthop = &from->sin6_addr;
     803             : 
     804             :         /* Lookup RIPng routing table. */
     805           0 :         rp = agg_node_get(ripng->table, (struct prefix *)&p);
     806             : 
     807           0 :         newinfo.rp = rp;
     808           0 :         newinfo.nexthop = *nexthop;
     809           0 :         newinfo.metric = rte->metric;
     810           0 :         newinfo.tag = ntohs(rte->tag);
     811             : 
     812             :         /* Check to see whether there is already RIPng route on the table. */
     813           0 :         if ((list = rp->info) != NULL)
     814           0 :                 for (ALL_LIST_ELEMENTS_RO(list, node, rinfo)) {
     815             :                         /* Need to compare with redistributed entry or local
     816             :                          * entry */
     817           0 :                         if (!ripng_route_rte(rinfo))
     818             :                                 break;
     819             : 
     820           0 :                         if (IPV6_ADDR_SAME(&rinfo->from, &from->sin6_addr)
     821           0 :                             && IPV6_ADDR_SAME(&rinfo->nexthop, nexthop))
     822             :                                 break;
     823             : 
     824           0 :                         if (!listnextnode(node)) {
     825             :                                 /* Not found in the list */
     826             : 
     827           0 :                                 if (rte->metric > rinfo->metric) {
     828             :                                         /* New route has a greater metric.
     829             :                                          * Discard it. */
     830           0 :                                         agg_unlock_node(rp);
     831           0 :                                         return;
     832             :                                 }
     833             : 
     834           0 :                                 if (rte->metric < rinfo->metric)
     835             :                                         /* New route has a smaller metric.
     836             :                                          * Replace the ECMP list
     837             :                                          * with the new one in below. */
     838             :                                         break;
     839             : 
     840             :                                 /* Metrics are same. Unless ECMP is disabled,
     841             :                                  * keep "rinfo" null and
     842             :                                  * the new route is added in the ECMP list in
     843             :                                  * below. */
     844           0 :                                 if (!ripng->ecmp)
     845             :                                         break;
     846             :                         }
     847             :                 }
     848             : 
     849           0 :         if (rinfo) {
     850             :                 /* Redistributed route check. */
     851           0 :                 if (rinfo->type != ZEBRA_ROUTE_RIPNG
     852           0 :                     && rinfo->metric != RIPNG_METRIC_INFINITY) {
     853           0 :                         agg_unlock_node(rp);
     854           0 :                         return;
     855             :                 }
     856             : 
     857             :                 /* Local static route. */
     858           0 :                 if (rinfo->type == ZEBRA_ROUTE_RIPNG
     859           0 :                     && ((rinfo->sub_type == RIPNG_ROUTE_STATIC)
     860           0 :                         || (rinfo->sub_type == RIPNG_ROUTE_DEFAULT))
     861           0 :                     && rinfo->metric != RIPNG_METRIC_INFINITY) {
     862           0 :                         agg_unlock_node(rp);
     863           0 :                         return;
     864             :                 }
     865             :         }
     866             : 
     867           0 :         if (!rinfo) {
     868             :                 /* Now, check to see whether there is already an explicit route
     869             :                    for the destination prefix.  If there is no such route, add
     870             :                    this route to the routing table, unless the metric is
     871             :                    infinity (there is no point in adding a route which
     872             :                    unusable). */
     873           0 :                 if (rte->metric != RIPNG_METRIC_INFINITY)
     874           0 :                         ripng_ecmp_add(ripng, &newinfo);
     875             :                 else
     876           0 :                         agg_unlock_node(rp);
     877             :         } else {
     878             :                 /* If there is an existing route, compare the next hop address
     879             :                    to the address of the router from which the datagram came.
     880             :                    If this datagram is from the same router as the existing
     881             :                    route, reinitialize the timeout.  */
     882           0 :                 same = (IN6_ARE_ADDR_EQUAL(&rinfo->from, &from->sin6_addr)
     883           0 :                         && (rinfo->ifindex == ifp->ifindex));
     884             : 
     885             :                 /*
     886             :                  * RFC 2080 - Section 2.4.2:
     887             :                  * "If the new metric is the same as the old one, examine the
     888             :                  * timeout
     889             :                  * for the existing route.  If it is at least halfway to the
     890             :                  * expiration
     891             :                  * point, switch to the new route.  This heuristic is optional,
     892             :                  * but
     893             :                  * highly recommended".
     894             :                  */
     895           0 :                 if (!ripng->ecmp && !same && rinfo->metric == rte->metric
     896           0 :                     && rinfo->t_timeout
     897           0 :                     && (thread_timer_remain_second(rinfo->t_timeout)
     898           0 :                         < (ripng->timeout_time / 2))) {
     899           0 :                         ripng_ecmp_replace(ripng, &newinfo);
     900             :                 }
     901             :                 /* Next, compare the metrics.  If the datagram is from the same
     902             :                    router as the existing route, and the new metric is different
     903             :                    than the old one; or, if the new metric is lower than the old
     904             :                    one; do the following actions: */
     905           0 :                 else if ((same && rinfo->metric != rte->metric)
     906           0 :                          || rte->metric < rinfo->metric) {
     907           0 :                         if (listcount(list) == 1) {
     908           0 :                                 if (newinfo.metric != RIPNG_METRIC_INFINITY)
     909           0 :                                         ripng_ecmp_replace(ripng, &newinfo);
     910             :                                 else
     911           0 :                                         ripng_ecmp_delete(ripng, rinfo);
     912             :                         } else {
     913           0 :                                 if (newinfo.metric < rinfo->metric)
     914           0 :                                         ripng_ecmp_replace(ripng, &newinfo);
     915             :                                 else /* newinfo.metric > rinfo->metric */
     916           0 :                                         ripng_ecmp_delete(ripng, rinfo);
     917             :                         }
     918             :                 } else /* same & no change */
     919           0 :                         ripng_timeout_update(ripng, rinfo);
     920             : 
     921             :                 /* Unlock tempolary lock of the route. */
     922           0 :                 agg_unlock_node(rp);
     923             :         }
     924             : }
     925             : 
     926             : /* Add redistributed route to RIPng table. */
     927           3 : void ripng_redistribute_add(struct ripng *ripng, int type, int sub_type,
     928             :                             struct prefix_ipv6 *p, ifindex_t ifindex,
     929             :                             struct in6_addr *nexthop, route_tag_t tag)
     930             : {
     931           3 :         struct agg_node *rp;
     932           3 :         struct ripng_info *rinfo = NULL, newinfo;
     933           3 :         struct list *list = NULL;
     934             : 
     935             :         /* Redistribute route  */
     936           3 :         if (IN6_IS_ADDR_LINKLOCAL(&p->prefix))
     937           2 :                 return;
     938           3 :         if (IN6_IS_ADDR_LOOPBACK(&p->prefix))
     939             :                 return;
     940             : 
     941           3 :         rp = agg_node_get(ripng->table, (struct prefix *)p);
     942             : 
     943           3 :         memset(&newinfo, 0, sizeof(newinfo));
     944           3 :         newinfo.type = type;
     945           3 :         newinfo.sub_type = sub_type;
     946           3 :         newinfo.ifindex = ifindex;
     947           3 :         newinfo.metric = 1;
     948           3 :         if (tag <= UINT16_MAX) /* RIPng only supports 16 bit tags */
     949           3 :                 newinfo.tag = tag;
     950           3 :         newinfo.rp = rp;
     951           3 :         if (nexthop && IN6_IS_ADDR_LINKLOCAL(nexthop))
     952           0 :                 newinfo.nexthop = *nexthop;
     953             : 
     954           3 :         if ((list = rp->info) != NULL && listcount(list) != 0) {
     955           2 :                 rinfo = listgetdata(listhead(list));
     956             : 
     957           2 :                 if (rinfo->type == ZEBRA_ROUTE_CONNECT
     958           2 :                     && rinfo->sub_type == RIPNG_ROUTE_INTERFACE
     959           2 :                     && rinfo->metric != RIPNG_METRIC_INFINITY) {
     960           2 :                         agg_unlock_node(rp);
     961           2 :                         return;
     962             :                 }
     963             : 
     964             :                 /* Manually configured RIPng route check.
     965             :                  * They have the precedence on all the other entries.
     966             :                  **/
     967           0 :                 if (rinfo->type == ZEBRA_ROUTE_RIPNG
     968           0 :                     && ((rinfo->sub_type == RIPNG_ROUTE_STATIC)
     969           0 :                         || (rinfo->sub_type == RIPNG_ROUTE_DEFAULT))) {
     970           0 :                         if (type != ZEBRA_ROUTE_RIPNG
     971           0 :                             || ((sub_type != RIPNG_ROUTE_STATIC)
     972           0 :                                 && (sub_type != RIPNG_ROUTE_DEFAULT))) {
     973           0 :                                 agg_unlock_node(rp);
     974           0 :                                 return;
     975             :                         }
     976             :                 }
     977             : 
     978           0 :                 ripng_ecmp_replace(ripng, &newinfo);
     979           0 :                 agg_unlock_node(rp);
     980             :         } else
     981           1 :                 ripng_ecmp_add(ripng, &newinfo);
     982             : 
     983           1 :         if (IS_RIPNG_DEBUG_EVENT) {
     984           1 :                 if (!nexthop)
     985           1 :                         zlog_debug(
     986             :                                 "Redistribute new prefix %pFX on the interface %s",
     987             :                                 p, ifindex2ifname(ifindex, ripng->vrf->vrf_id));
     988             :                 else
     989           0 :                         zlog_debug(
     990             :                                 "Redistribute new prefix %pFX with nexthop %pI6 on the interface %s",
     991             :                                 p, nexthop,
     992             :                                 ifindex2ifname(ifindex, ripng->vrf->vrf_id));
     993             :         }
     994             : 
     995           1 :         ripng_event(ripng, RIPNG_TRIGGERED_UPDATE, 0);
     996             : }
     997             : 
     998             : /* Delete redistributed route to RIPng table. */
     999           0 : void ripng_redistribute_delete(struct ripng *ripng, int type, int sub_type,
    1000             :                                struct prefix_ipv6 *p, ifindex_t ifindex)
    1001             : {
    1002           0 :         struct agg_node *rp;
    1003           0 :         struct ripng_info *rinfo;
    1004             : 
    1005           0 :         if (IN6_IS_ADDR_LINKLOCAL(&p->prefix))
    1006             :                 return;
    1007           0 :         if (IN6_IS_ADDR_LOOPBACK(&p->prefix))
    1008             :                 return;
    1009             : 
    1010           0 :         rp = agg_node_lookup(ripng->table, (struct prefix *)p);
    1011             : 
    1012           0 :         if (rp) {
    1013           0 :                 struct list *list = rp->info;
    1014             : 
    1015           0 :                 if (list != NULL && listcount(list) != 0) {
    1016           0 :                         rinfo = listgetdata(listhead(list));
    1017           0 :                         if (rinfo != NULL && rinfo->type == type
    1018           0 :                             && rinfo->sub_type == sub_type
    1019           0 :                             && rinfo->ifindex == ifindex) {
    1020             :                                 /* Perform poisoned reverse. */
    1021           0 :                                 rinfo->metric = RIPNG_METRIC_INFINITY;
    1022           0 :                                 RIPNG_TIMER_ON(rinfo->t_garbage_collect,
    1023             :                                                ripng_garbage_collect,
    1024             :                                                ripng->garbage_time);
    1025           0 :                                 THREAD_OFF(rinfo->t_timeout);
    1026             : 
    1027             :                                 /* Aggregate count decrement. */
    1028           0 :                                 ripng_aggregate_decrement(rp, rinfo);
    1029             : 
    1030           0 :                                 rinfo->flags |= RIPNG_RTF_CHANGED;
    1031             : 
    1032           0 :                                 if (IS_RIPNG_DEBUG_EVENT)
    1033           0 :                                         zlog_debug(
    1034             :                                                 "Poisone %pFX on the interface %s with an infinity metric [delete]",
    1035             :                                                 p,
    1036             :                                                 ifindex2ifname(
    1037             :                                                         ifindex,
    1038             :                                                         ripng->vrf->vrf_id));
    1039             : 
    1040           0 :                                 ripng_event(ripng, RIPNG_TRIGGERED_UPDATE, 0);
    1041             :                         }
    1042             :                 }
    1043           0 :                 agg_unlock_node(rp);
    1044             :         }
    1045             : }
    1046             : 
    1047             : /* Withdraw redistributed route. */
    1048           0 : void ripng_redistribute_withdraw(struct ripng *ripng, int type)
    1049             : {
    1050           0 :         struct agg_node *rp;
    1051           0 :         struct ripng_info *rinfo = NULL;
    1052           0 :         struct list *list = NULL;
    1053             : 
    1054           0 :         for (rp = agg_route_top(ripng->table); rp; rp = agg_route_next(rp))
    1055           0 :                 if ((list = rp->info) != NULL) {
    1056           0 :                         rinfo = listgetdata(listhead(list));
    1057           0 :                         if ((rinfo->type == type)
    1058           0 :                             && (rinfo->sub_type != RIPNG_ROUTE_INTERFACE)) {
    1059             :                                 /* Perform poisoned reverse. */
    1060           0 :                                 rinfo->metric = RIPNG_METRIC_INFINITY;
    1061           0 :                                 RIPNG_TIMER_ON(rinfo->t_garbage_collect,
    1062             :                                                ripng_garbage_collect,
    1063             :                                                ripng->garbage_time);
    1064           0 :                                 THREAD_OFF(rinfo->t_timeout);
    1065             : 
    1066             :                                 /* Aggregate count decrement. */
    1067           0 :                                 ripng_aggregate_decrement(rp, rinfo);
    1068             : 
    1069           0 :                                 rinfo->flags |= RIPNG_RTF_CHANGED;
    1070             : 
    1071           0 :                                 if (IS_RIPNG_DEBUG_EVENT) {
    1072           0 :                                         struct prefix_ipv6 *p =
    1073             :                                                 (struct prefix_ipv6 *)
    1074           0 :                                                         agg_node_get_prefix(rp);
    1075             : 
    1076           0 :                                         zlog_debug(
    1077             :                                                 "Poisone %pFX on the interface %s [withdraw]",
    1078             :                                                 p,
    1079             :                                                 ifindex2ifname(
    1080             :                                                         rinfo->ifindex,
    1081             :                                                         ripng->vrf->vrf_id));
    1082             :                                 }
    1083             : 
    1084           0 :                                 ripng_event(ripng, RIPNG_TRIGGERED_UPDATE, 0);
    1085             :                         }
    1086             :                 }
    1087           0 : }
    1088             : 
    1089             : /* RIP routing information. */
    1090           0 : static void ripng_response_process(struct ripng_packet *packet, int size,
    1091             :                                    struct sockaddr_in6 *from,
    1092             :                                    struct interface *ifp, int hoplimit)
    1093             : {
    1094           0 :         struct ripng_interface *ri = ifp->info;
    1095           0 :         struct ripng *ripng = ri->ripng;
    1096           0 :         caddr_t lim;
    1097           0 :         struct rte *rte;
    1098           0 :         struct ripng_nexthop nexthop;
    1099             : 
    1100             :         /* RFC2080 2.4.2  Response Messages:
    1101             :          The Response must be ignored if it is not from the RIPng port.  */
    1102           0 :         if (ntohs(from->sin6_port) != RIPNG_PORT_DEFAULT) {
    1103           0 :                 zlog_warn("RIPng packet comes from non RIPng port %d from %pI6",
    1104             :                           ntohs(from->sin6_port), &from->sin6_addr);
    1105           0 :                 ripng_peer_bad_packet(ripng, from);
    1106           0 :                 return;
    1107             :         }
    1108             : 
    1109             :         /* The datagram's IPv6 source address should be checked to see
    1110             :          whether the datagram is from a valid neighbor; the source of the
    1111             :          datagram must be a link-local address.  */
    1112           0 :         if (!IN6_IS_ADDR_LINKLOCAL(&from->sin6_addr)) {
    1113           0 :                 zlog_warn("RIPng packet comes from non link local address %pI6",
    1114             :                           &from->sin6_addr);
    1115           0 :                 ripng_peer_bad_packet(ripng, from);
    1116           0 :                 return;
    1117             :         }
    1118             : 
    1119             :         /* It is also worth checking to see whether the response is from one
    1120             :          of the router's own addresses.  Interfaces on broadcast networks
    1121             :          may receive copies of their own multicasts immediately.  If a
    1122             :          router processes its own output as new input, confusion is likely,
    1123             :          and such datagrams must be ignored. */
    1124           0 :         if (ripng_lladdr_check(ifp, &from->sin6_addr)) {
    1125           0 :                 zlog_warn(
    1126             :                         "RIPng packet comes from my own link local address %pI6",
    1127             :                         &from->sin6_addr);
    1128           0 :                 ripng_peer_bad_packet(ripng, from);
    1129           0 :                 return;
    1130             :         }
    1131             : 
    1132             :         /* As an additional check, periodic advertisements must have their
    1133             :          hop counts set to 255, and inbound, multicast packets sent from the
    1134             :          RIPng port (i.e. periodic advertisement or triggered update
    1135             :          packets) must be examined to ensure that the hop count is 255. */
    1136           0 :         if (hoplimit >= 0 && hoplimit != 255) {
    1137           0 :                 zlog_warn(
    1138             :                         "RIPng packet comes with non 255 hop count %d from %pI6",
    1139             :                         hoplimit, &from->sin6_addr);
    1140           0 :                 ripng_peer_bad_packet(ripng, from);
    1141           0 :                 return;
    1142             :         }
    1143             : 
    1144             :         /* Update RIPng peer. */
    1145           0 :         ripng_peer_update(ripng, from, packet->version);
    1146             : 
    1147             :         /* Reset nexthop. */
    1148           0 :         memset(&nexthop, 0, sizeof(nexthop));
    1149           0 :         nexthop.flag = RIPNG_NEXTHOP_UNSPEC;
    1150             : 
    1151             :         /* Set RTE pointer. */
    1152           0 :         rte = packet->rte;
    1153             : 
    1154           0 :         for (lim = ((caddr_t)packet) + size; (caddr_t)rte < lim; rte++) {
    1155             :                 /* First of all, we have to check this RTE is next hop RTE or
    1156             :                    not.  Next hop RTE is completely different with normal RTE so
    1157             :                    we need special treatment. */
    1158           0 :                 if (rte->metric == RIPNG_METRIC_NEXTHOP) {
    1159           0 :                         ripng_nexthop_rte(rte, from, &nexthop);
    1160           0 :                         continue;
    1161             :                 }
    1162             : 
    1163             :                 /* RTE information validation. */
    1164             : 
    1165             :                 /* - is the destination prefix valid (e.g., not a multicast
    1166             :                    prefix and not a link-local address) A link-local address
    1167             :                    should never be present in an RTE. */
    1168           0 :                 if (IN6_IS_ADDR_MULTICAST(&rte->addr)) {
    1169           0 :                         zlog_warn(
    1170             :                                 "Destination prefix is a multicast address %pI6/%d [%d]",
    1171             :                                 &rte->addr, rte->prefixlen, rte->metric);
    1172           0 :                         ripng_peer_bad_route(ripng, from);
    1173           0 :                         continue;
    1174             :                 }
    1175           0 :                 if (IN6_IS_ADDR_LINKLOCAL(&rte->addr)) {
    1176           0 :                         zlog_warn(
    1177             :                                 "Destination prefix is a link-local address %pI6/%d [%d]",
    1178             :                                 &rte->addr, rte->prefixlen, rte->metric);
    1179           0 :                         ripng_peer_bad_route(ripng, from);
    1180           0 :                         continue;
    1181             :                 }
    1182           0 :                 if (IN6_IS_ADDR_LOOPBACK(&rte->addr)) {
    1183           0 :                         zlog_warn(
    1184             :                                 "Destination prefix is a loopback address %pI6/%d [%d]",
    1185             :                                 &rte->addr, rte->prefixlen, rte->metric);
    1186           0 :                         ripng_peer_bad_route(ripng, from);
    1187           0 :                         continue;
    1188             :                 }
    1189             : 
    1190             :                 /* - is the prefix length valid (i.e., between 0 and 128,
    1191             :                    inclusive) */
    1192           0 :                 if (rte->prefixlen > IPV6_MAX_BITLEN) {
    1193           0 :                         zlog_warn("Invalid prefix length %pI6/%d from %pI6%%%s",
    1194             :                                   &rte->addr, rte->prefixlen,
    1195             :                                   &from->sin6_addr, ifp->name);
    1196           0 :                         ripng_peer_bad_route(ripng, from);
    1197           0 :                         continue;
    1198             :                 }
    1199             : 
    1200             :                 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
    1201           0 :                 if (!(rte->metric >= 1 && rte->metric <= 16)) {
    1202           0 :                         zlog_warn("Invalid metric %d from %pI6%%%s",
    1203             :                                   rte->metric, &from->sin6_addr, ifp->name);
    1204           0 :                         ripng_peer_bad_route(ripng, from);
    1205           0 :                         continue;
    1206             :                 }
    1207             : 
    1208             :                 /* Vincent: XXX Should we compute the direclty reachable nexthop
    1209             :                  * for our RIPng network ?
    1210             :                  **/
    1211             : 
    1212             :                 /* Routing table updates. */
    1213           0 :                 ripng_route_process(rte, from, &nexthop, ifp);
    1214             :         }
    1215             : }
    1216             : 
    1217             : /* Response to request message. */
    1218           0 : static void ripng_request_process(struct ripng_packet *packet, int size,
    1219             :                                   struct sockaddr_in6 *from,
    1220             :                                   struct interface *ifp)
    1221             : {
    1222           0 :         struct ripng *ripng;
    1223           0 :         caddr_t lim;
    1224           0 :         struct rte *rte;
    1225           0 :         struct prefix_ipv6 p;
    1226           0 :         struct agg_node *rp;
    1227           0 :         struct ripng_info *rinfo;
    1228           0 :         struct ripng_interface *ri;
    1229             : 
    1230             :         /* Does not reponse to the requests on the loopback interfaces */
    1231           0 :         if (if_is_loopback(ifp))
    1232           0 :                 return;
    1233             : 
    1234             :         /* Check RIPng process is enabled on this interface. */
    1235           0 :         ri = ifp->info;
    1236           0 :         if (!ri->running)
    1237             :                 return;
    1238           0 :         ripng = ri->ripng;
    1239             : 
    1240             :         /* When passive interface is specified, suppress responses */
    1241           0 :         if (ri->passive)
    1242             :                 return;
    1243             : 
    1244             :         /* RIPng peer update. */
    1245           0 :         ripng_peer_update(ripng, from, packet->version);
    1246             : 
    1247           0 :         lim = ((caddr_t)packet) + size;
    1248           0 :         rte = packet->rte;
    1249             : 
    1250             :         /* The Request is processed entry by entry.  If there are no
    1251             :            entries, no response is given. */
    1252           0 :         if (lim == (caddr_t)rte)
    1253             :                 return;
    1254             : 
    1255             :         /* There is one special case.  If there is exactly one entry in the
    1256             :            request, and it has a destination prefix of zero, a prefix length
    1257             :            of zero, and a metric of infinity (i.e., 16), then this is a
    1258             :            request to send the entire routing table.  In that case, a call
    1259             :            is made to the output process to send the routing table to the
    1260             :            requesting address/port. */
    1261           0 :         if (lim == ((caddr_t)(rte + 1)) && IN6_IS_ADDR_UNSPECIFIED(&rte->addr)
    1262           0 :             && rte->prefixlen == 0 && rte->metric == RIPNG_METRIC_INFINITY) {
    1263             :                 /* All route with split horizon */
    1264           0 :                 ripng_output_process(ifp, from, ripng_all_route);
    1265             :         } else {
    1266             :                 /* Except for this special case, processing is quite simple.
    1267             :                    Examine the list of RTEs in the Request one by one.  For each
    1268             :                    entry, look up the destination in the router's routing
    1269             :                    database and, if there is a route, put that route's metric in
    1270             :                    the metric field of the RTE.  If there is no explicit route
    1271             :                    to the specified destination, put infinity in the metric
    1272             :                    field.  Once all the entries have been filled in, change the
    1273             :                    command from Request to Response and send the datagram back
    1274             :                    to the requestor. */
    1275           0 :                 memset(&p, 0, sizeof(p));
    1276           0 :                 p.family = AF_INET6;
    1277             : 
    1278           0 :                 for (; ((caddr_t)rte) < lim; rte++) {
    1279           0 :                         p.prefix = rte->addr;
    1280           0 :                         p.prefixlen = rte->prefixlen;
    1281           0 :                         apply_mask_ipv6(&p);
    1282             : 
    1283           0 :                         rp = agg_node_lookup(ripng->table, (struct prefix *)&p);
    1284             : 
    1285           0 :                         if (rp) {
    1286           0 :                                 rinfo = listgetdata(
    1287             :                                         listhead((struct list *)rp->info));
    1288           0 :                                 rte->metric = rinfo->metric;
    1289           0 :                                 agg_unlock_node(rp);
    1290             :                         } else
    1291           0 :                                 rte->metric = RIPNG_METRIC_INFINITY;
    1292             :                 }
    1293           0 :                 packet->command = RIPNG_RESPONSE;
    1294             : 
    1295           0 :                 ripng_send_packet((caddr_t)packet, size, from, ifp);
    1296             :         }
    1297             : }
    1298             : 
    1299             : /* First entry point of reading RIPng packet. */
    1300           0 : static void ripng_read(struct thread *thread)
    1301             : {
    1302           0 :         struct ripng *ripng = THREAD_ARG(thread);
    1303           0 :         int len;
    1304           0 :         int sock;
    1305           0 :         struct sockaddr_in6 from;
    1306           0 :         struct ripng_packet *packet;
    1307           0 :         ifindex_t ifindex = 0;
    1308           0 :         struct interface *ifp;
    1309           0 :         int hoplimit = -1;
    1310             : 
    1311             :         /* Check ripng is active and alive. */
    1312           0 :         assert(ripng != NULL);
    1313           0 :         assert(ripng->sock >= 0);
    1314             : 
    1315             :         /* Fetch thread data and set read pointer to empty for event
    1316             :            managing.  `sock' sould be same as ripng->sock. */
    1317           0 :         sock = THREAD_FD(thread);
    1318             : 
    1319             :         /* Add myself to the next event. */
    1320           0 :         ripng_event(ripng, RIPNG_READ, sock);
    1321             : 
    1322             :         /* Read RIPng packet. */
    1323           0 :         len = ripng_recv_packet(sock, STREAM_DATA(ripng->ibuf),
    1324           0 :                                 STREAM_SIZE(ripng->ibuf), &from, &ifindex,
    1325             :                                 &hoplimit);
    1326           0 :         if (len < 0) {
    1327           0 :                 zlog_warn("RIPng recvfrom failed (VRF %s): %s.",
    1328             :                           ripng->vrf_name, safe_strerror(errno));
    1329           0 :                 return;
    1330             :         }
    1331             : 
    1332             :         /* Check RTE boundary.  RTE size (Packet length - RIPng header size
    1333             :            (4)) must be multiple size of one RTE size (20). */
    1334           0 :         if (((len - 4) % 20) != 0) {
    1335           0 :                 zlog_warn("RIPng invalid packet size %d from %pI6 (VRF %s)",
    1336             :                           len, &from.sin6_addr, ripng->vrf_name);
    1337           0 :                 ripng_peer_bad_packet(ripng, &from);
    1338           0 :                 return;
    1339             :         }
    1340             : 
    1341           0 :         packet = (struct ripng_packet *)STREAM_DATA(ripng->ibuf);
    1342           0 :         ifp = if_lookup_by_index(ifindex, ripng->vrf->vrf_id);
    1343             : 
    1344             :         /* RIPng packet received. */
    1345           0 :         if (IS_RIPNG_DEBUG_EVENT)
    1346           0 :                 zlog_debug(
    1347             :                         "RIPng packet received from %pI6 port %d on %s (VRF %s)",
    1348             :                         &from.sin6_addr, ntohs(from.sin6_port),
    1349             :                         ifp ? ifp->name : "unknown", ripng->vrf_name);
    1350             : 
    1351             :         /* Logging before packet checking. */
    1352           0 :         if (IS_RIPNG_DEBUG_RECV)
    1353           0 :                 ripng_packet_dump(packet, len, "RECV");
    1354             : 
    1355             :         /* Packet comes from unknown interface. */
    1356           0 :         if (ifp == NULL) {
    1357           0 :                 zlog_warn(
    1358             :                         "RIPng packet comes from unknown interface %d (VRF %s)",
    1359             :                         ifindex, ripng->vrf_name);
    1360           0 :                 return;
    1361             :         }
    1362             : 
    1363             :         /* Packet version mismatch checking. */
    1364           0 :         if (packet->version != ripng->version) {
    1365           0 :                 zlog_warn(
    1366             :                         "RIPng packet version %d doesn't fit to my version %d (VRF %s)",
    1367             :                         packet->version, ripng->version, ripng->vrf_name);
    1368           0 :                 ripng_peer_bad_packet(ripng, &from);
    1369           0 :                 return;
    1370             :         }
    1371             : 
    1372             :         /* Process RIPng packet. */
    1373           0 :         switch (packet->command) {
    1374           0 :         case RIPNG_REQUEST:
    1375           0 :                 ripng_request_process(packet, len, &from, ifp);
    1376           0 :                 break;
    1377           0 :         case RIPNG_RESPONSE:
    1378           0 :                 ripng_response_process(packet, len, &from, ifp, hoplimit);
    1379           0 :                 break;
    1380           0 :         default:
    1381           0 :                 zlog_warn("Invalid RIPng command %d (VRF %s)", packet->command,
    1382             :                           ripng->vrf_name);
    1383           0 :                 ripng_peer_bad_packet(ripng, &from);
    1384           0 :                 break;
    1385             :         }
    1386             : }
    1387             : 
    1388             : /* Walk down the RIPng routing table then clear changed flag. */
    1389           1 : static void ripng_clear_changed_flag(struct ripng *ripng)
    1390             : {
    1391           1 :         struct agg_node *rp;
    1392           1 :         struct ripng_info *rinfo = NULL;
    1393           1 :         struct list *list = NULL;
    1394           1 :         struct listnode *listnode = NULL;
    1395             : 
    1396           3 :         for (rp = agg_route_top(ripng->table); rp; rp = agg_route_next(rp))
    1397           1 :                 if ((list = rp->info) != NULL)
    1398           1 :                         for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) {
    1399           1 :                                 UNSET_FLAG(rinfo->flags, RIPNG_RTF_CHANGED);
    1400             :                                 /* This flag can be set only on the first entry.
    1401             :                                  */
    1402           1 :                                 break;
    1403             :                         }
    1404           1 : }
    1405             : 
    1406             : /* Regular update of RIPng route.  Send all routing formation to RIPng
    1407             :    enabled interface. */
    1408           0 : static void ripng_update(struct thread *t)
    1409             : {
    1410           0 :         struct ripng *ripng = THREAD_ARG(t);
    1411           0 :         struct interface *ifp;
    1412           0 :         struct ripng_interface *ri;
    1413             : 
    1414             :         /* Logging update event. */
    1415           0 :         if (IS_RIPNG_DEBUG_EVENT)
    1416           0 :                 zlog_debug("RIPng update timer expired!");
    1417             : 
    1418             :         /* Supply routes to each interface. */
    1419           0 :         FOR_ALL_INTERFACES (ripng->vrf, ifp) {
    1420           0 :                 ri = ifp->info;
    1421             : 
    1422           0 :                 if (if_is_loopback(ifp) || !if_is_up(ifp))
    1423           0 :                         continue;
    1424             : 
    1425           0 :                 if (!ri->running)
    1426           0 :                         continue;
    1427             : 
    1428             :                 /* When passive interface is specified, suppress announce to the
    1429             :                    interface. */
    1430           0 :                 if (ri->passive)
    1431           0 :                         continue;
    1432             : 
    1433             : #ifdef RIPNG_ADVANCED
    1434             :                 if (ri->ri_send == RIPNG_SEND_OFF) {
    1435             :                         if (IS_RIPNG_DEBUG_EVENT)
    1436             :                                 zlog_debug(
    1437             :                                         "[Event] RIPng send to if %d is suppressed by config",
    1438             :                                         ifp->ifindex);
    1439             :                         continue;
    1440             :                 }
    1441             : #endif /* RIPNG_ADVANCED */
    1442             : 
    1443           0 :                 ripng_output_process(ifp, NULL, ripng_all_route);
    1444             :         }
    1445             : 
    1446             :         /* Triggered updates may be suppressed if a regular update is due by
    1447             :            the time the triggered update would be sent. */
    1448           0 :         THREAD_OFF(ripng->t_triggered_interval);
    1449           0 :         ripng->trigger = 0;
    1450             : 
    1451             :         /* Reset flush event. */
    1452           0 :         ripng_event(ripng, RIPNG_UPDATE_EVENT, 0);
    1453           0 : }
    1454             : 
    1455             : /* Triggered update interval timer. */
    1456           0 : static void ripng_triggered_interval(struct thread *t)
    1457             : {
    1458           0 :         struct ripng *ripng = THREAD_ARG(t);
    1459             : 
    1460           0 :         if (ripng->trigger) {
    1461           0 :                 ripng->trigger = 0;
    1462           0 :                 ripng_triggered_update(t);
    1463             :         }
    1464           0 : }
    1465             : 
    1466             : /* Execute triggered update. */
    1467           1 : void ripng_triggered_update(struct thread *t)
    1468             : {
    1469           1 :         struct ripng *ripng = THREAD_ARG(t);
    1470           1 :         struct interface *ifp;
    1471           1 :         struct ripng_interface *ri;
    1472           1 :         int interval;
    1473             : 
    1474             :         /* Cancel interval timer. */
    1475           1 :         THREAD_OFF(ripng->t_triggered_interval);
    1476           1 :         ripng->trigger = 0;
    1477             : 
    1478             :         /* Logging triggered update. */
    1479           1 :         if (IS_RIPNG_DEBUG_EVENT)
    1480           1 :                 zlog_debug("RIPng triggered update!");
    1481             : 
    1482             :         /* Split Horizon processing is done when generating triggered
    1483             :            updates as well as normal updates (see section 2.6). */
    1484          10 :         FOR_ALL_INTERFACES (ripng->vrf, ifp) {
    1485           8 :                 ri = ifp->info;
    1486             : 
    1487           8 :                 if (if_is_loopback(ifp) || !if_is_up(ifp))
    1488           1 :                         continue;
    1489             : 
    1490           7 :                 if (!ri->running)
    1491           7 :                         continue;
    1492             : 
    1493             :                 /* When passive interface is specified, suppress announce to the
    1494             :                    interface. */
    1495           0 :                 if (ri->passive)
    1496           0 :                         continue;
    1497             : 
    1498           0 :                 ripng_output_process(ifp, NULL, ripng_changed_route);
    1499             :         }
    1500             : 
    1501             :         /* Once all of the triggered updates have been generated, the route
    1502             :            change flags should be cleared. */
    1503           1 :         ripng_clear_changed_flag(ripng);
    1504             : 
    1505             :         /* After a triggered update is sent, a timer should be set for a
    1506             :            random interval between 1 and 5 seconds.  If other changes that
    1507             :            would trigger updates occur before the timer expires, a single
    1508             :            update is triggered when the timer expires. */
    1509           1 :         interval = (frr_weak_random() % 5) + 1;
    1510             : 
    1511           1 :         thread_add_timer(master, ripng_triggered_interval, ripng, interval,
    1512             :                          &ripng->t_triggered_interval);
    1513           1 : }
    1514             : 
    1515             : /* Write routing table entry to the stream and return next index of
    1516             :    the routing table entry in the stream. */
    1517           0 : int ripng_write_rte(int num, struct stream *s, struct prefix_ipv6 *p,
    1518             :                     struct in6_addr *nexthop, uint16_t tag, uint8_t metric)
    1519             : {
    1520             :         /* RIPng packet header. */
    1521           0 :         if (num == 0) {
    1522           0 :                 stream_putc(s, RIPNG_RESPONSE);
    1523           0 :                 stream_putc(s, RIPNG_V1);
    1524           0 :                 stream_putw(s, 0);
    1525             :         }
    1526             : 
    1527             :         /* Write routing table entry. */
    1528           0 :         if (!nexthop) {
    1529           0 :                 assert(p);
    1530           0 :                 stream_write(s, (uint8_t *)&p->prefix, sizeof(struct in6_addr));
    1531             :         } else
    1532           0 :                 stream_write(s, (uint8_t *)nexthop, sizeof(struct in6_addr));
    1533           0 :         stream_putw(s, tag);
    1534           0 :         if (p)
    1535           0 :                 stream_putc(s, p->prefixlen);
    1536             :         else
    1537           0 :                 stream_putc(s, 0);
    1538           0 :         stream_putc(s, metric);
    1539             : 
    1540           0 :         return ++num;
    1541             : }
    1542             : 
    1543             : /* Send RESPONSE message to specified destination. */
    1544           0 : void ripng_output_process(struct interface *ifp, struct sockaddr_in6 *to,
    1545             :                           int route_type)
    1546             : {
    1547           0 :         struct ripng *ripng;
    1548           0 :         int ret;
    1549           0 :         struct agg_node *rp;
    1550           0 :         struct ripng_info *rinfo;
    1551           0 :         struct ripng_interface *ri;
    1552           0 :         struct ripng_aggregate *aggregate;
    1553           0 :         struct prefix_ipv6 *p;
    1554           0 :         struct list *ripng_rte_list;
    1555           0 :         struct list *list = NULL;
    1556           0 :         struct listnode *listnode = NULL;
    1557             : 
    1558           0 :         if (IS_RIPNG_DEBUG_EVENT) {
    1559           0 :                 if (to)
    1560           0 :                         zlog_debug("RIPng update routes to neighbor %pI6",
    1561             :                                    &to->sin6_addr);
    1562             :                 else
    1563           0 :                         zlog_debug("RIPng update routes on interface %s",
    1564             :                                    ifp->name);
    1565             :         }
    1566             : 
    1567             :         /* Get RIPng interface and instance. */
    1568           0 :         ri = ifp->info;
    1569           0 :         ripng = ri->ripng;
    1570             : 
    1571           0 :         ripng_rte_list = ripng_rte_new();
    1572             : 
    1573           0 :         for (rp = agg_route_top(ripng->table); rp; rp = agg_route_next(rp)) {
    1574           0 :                 if ((list = rp->info) != NULL
    1575           0 :                     && (rinfo = listgetdata(listhead(list))) != NULL
    1576           0 :                     && rinfo->suppress == 0) {
    1577             :                         /* If no route-map are applied, the RTE will be these
    1578             :                          * following
    1579             :                          * information.
    1580             :                          */
    1581           0 :                         p = (struct prefix_ipv6 *)agg_node_get_prefix(rp);
    1582           0 :                         rinfo->metric_out = rinfo->metric;
    1583           0 :                         rinfo->tag_out = rinfo->tag;
    1584           0 :                         memset(&rinfo->nexthop_out, 0,
    1585             :                                sizeof(rinfo->nexthop_out));
    1586             :                         /* In order to avoid some local loops,
    1587             :                          * if the RIPng route has a nexthop via this interface,
    1588             :                          * keep the nexthop,
    1589             :                          * otherwise set it to 0. The nexthop should not be
    1590             :                          * propagated
    1591             :                          * beyond the local broadcast/multicast area in order
    1592             :                          * to avoid an IGP multi-level recursive look-up.
    1593             :                          */
    1594           0 :                         if (rinfo->ifindex == ifp->ifindex)
    1595           0 :                                 rinfo->nexthop_out = rinfo->nexthop;
    1596             : 
    1597             :                         /* Apply output filters. */
    1598           0 :                         ret = ripng_filter(RIPNG_FILTER_OUT, p, ri);
    1599           0 :                         if (ret < 0)
    1600           0 :                                 continue;
    1601             : 
    1602             :                         /* Changed route only output. */
    1603           0 :                         if (route_type == ripng_changed_route
    1604           0 :                             && (!(rinfo->flags & RIPNG_RTF_CHANGED)))
    1605           0 :                                 continue;
    1606             : 
    1607             :                         /* Split horizon. */
    1608           0 :                         if (ri->split_horizon == RIPNG_SPLIT_HORIZON) {
    1609             :                                 /* We perform split horizon for RIPng routes. */
    1610           0 :                                 int suppress = 0;
    1611           0 :                                 struct ripng_info *tmp_rinfo = NULL;
    1612             : 
    1613           0 :                                 for (ALL_LIST_ELEMENTS_RO(list, listnode,
    1614             :                                                           tmp_rinfo))
    1615           0 :                                         if (tmp_rinfo->type == ZEBRA_ROUTE_RIPNG
    1616           0 :                                             && tmp_rinfo->ifindex
    1617           0 :                                                        == ifp->ifindex) {
    1618             :                                                 suppress = 1;
    1619             :                                                 break;
    1620             :                                         }
    1621           0 :                                 if (suppress)
    1622           0 :                                         continue;
    1623             :                         }
    1624             : 
    1625             :                         /* Preparation for route-map. */
    1626           0 :                         rinfo->metric_set = 0;
    1627             :                         /* nexthop_out,
    1628             :                          * metric_out
    1629             :                          * and tag_out are already initialized.
    1630             :                          */
    1631             : 
    1632             :                         /* Interface route-map */
    1633           0 :                         if (ri->routemap[RIPNG_FILTER_OUT]) {
    1634           0 :                                 ret = route_map_apply(
    1635             :                                         ri->routemap[RIPNG_FILTER_OUT],
    1636             :                                         (struct prefix *)p, rinfo);
    1637             : 
    1638           0 :                                 if (ret == RMAP_DENYMATCH) {
    1639           0 :                                         if (IS_RIPNG_DEBUG_PACKET)
    1640           0 :                                                 zlog_debug(
    1641             :                                                         "RIPng %pFX is filtered by route-map out",
    1642             :                                                         p);
    1643           0 :                                         continue;
    1644             :                                 }
    1645             :                         }
    1646             : 
    1647             :                         /* Redistribute route-map. */
    1648           0 :                         if (ripng->redist[rinfo->type].route_map.name) {
    1649           0 :                                 ret = route_map_apply(ripng->redist[rinfo->type]
    1650             :                                                               .route_map.map,
    1651             :                                                       (struct prefix *)p,
    1652             :                                                       rinfo);
    1653             : 
    1654           0 :                                 if (ret == RMAP_DENYMATCH) {
    1655           0 :                                         if (IS_RIPNG_DEBUG_PACKET)
    1656           0 :                                                 zlog_debug(
    1657             :                                                         "RIPng %pFX is filtered by route-map",
    1658             :                                                         p);
    1659           0 :                                         continue;
    1660             :                                 }
    1661             :                         }
    1662             : 
    1663             :                         /* When the route-map does not set metric. */
    1664           0 :                         if (!rinfo->metric_set) {
    1665             :                                 /* If the redistribute metric is set. */
    1666           0 :                                 if (ripng->redist[rinfo->type].metric_config
    1667           0 :                                     && rinfo->metric != RIPNG_METRIC_INFINITY) {
    1668           0 :                                         rinfo->metric_out =
    1669             :                                                 ripng->redist[rinfo->type]
    1670           0 :                                                         .metric;
    1671             :                                 } else {
    1672             :                                         /* If the route is not connected or
    1673             :                                            localy generated
    1674             :                                            one, use default-metric value */
    1675           0 :                                         if (rinfo->type != ZEBRA_ROUTE_RIPNG
    1676           0 :                                             && rinfo->type
    1677             :                                                        != ZEBRA_ROUTE_CONNECT
    1678           0 :                                             && rinfo->metric
    1679             :                                                        != RIPNG_METRIC_INFINITY)
    1680           0 :                                                 rinfo->metric_out =
    1681           0 :                                                         ripng->default_metric;
    1682             :                                 }
    1683             :                         }
    1684             : 
    1685             :                         /* Apply offset-list */
    1686           0 :                         if (rinfo->metric_out != RIPNG_METRIC_INFINITY)
    1687           0 :                                 ripng_offset_list_apply_out(ripng, p, ifp,
    1688             :                                                             &rinfo->metric_out);
    1689             : 
    1690           0 :                         if (rinfo->metric_out > RIPNG_METRIC_INFINITY)
    1691           0 :                                 rinfo->metric_out = RIPNG_METRIC_INFINITY;
    1692             : 
    1693             :                         /* Perform split-horizon with poisoned reverse
    1694             :                          * for RIPng routes.
    1695             :                          **/
    1696           0 :                         if (ri->split_horizon
    1697             :                             == RIPNG_SPLIT_HORIZON_POISONED_REVERSE) {
    1698           0 :                                 struct ripng_info *tmp_rinfo = NULL;
    1699             : 
    1700           0 :                                 for (ALL_LIST_ELEMENTS_RO(list, listnode,
    1701             :                                                           tmp_rinfo))
    1702           0 :                                         if ((tmp_rinfo->type
    1703             :                                              == ZEBRA_ROUTE_RIPNG)
    1704           0 :                                             && tmp_rinfo->ifindex
    1705           0 :                                                        == ifp->ifindex)
    1706           0 :                                                 rinfo->metric_out =
    1707             :                                                         RIPNG_METRIC_INFINITY;
    1708             :                         }
    1709             : 
    1710             :                         /* Add RTE to the list */
    1711           0 :                         ripng_rte_add(ripng_rte_list, p, rinfo, NULL);
    1712             :                 }
    1713             : 
    1714             :                 /* Process the aggregated RTE entry */
    1715           0 :                 if ((aggregate = rp->aggregate) != NULL && aggregate->count > 0
    1716           0 :                     && aggregate->suppress == 0) {
    1717             :                         /* If no route-map are applied, the RTE will be these
    1718             :                          * following
    1719             :                          * information.
    1720             :                          */
    1721           0 :                         p = (struct prefix_ipv6 *)agg_node_get_prefix(rp);
    1722           0 :                         aggregate->metric_set = 0;
    1723           0 :                         aggregate->metric_out = aggregate->metric;
    1724           0 :                         aggregate->tag_out = aggregate->tag;
    1725           0 :                         memset(&aggregate->nexthop_out, 0,
    1726             :                                sizeof(aggregate->nexthop_out));
    1727             : 
    1728             :                         /* Apply output filters.*/
    1729           0 :                         ret = ripng_filter(RIPNG_FILTER_OUT, p, ri);
    1730           0 :                         if (ret < 0)
    1731           0 :                                 continue;
    1732             : 
    1733             :                         /* Interface route-map */
    1734           0 :                         if (ri->routemap[RIPNG_FILTER_OUT]) {
    1735           0 :                                 struct ripng_info newinfo;
    1736             : 
    1737             :                                 /* let's cast the aggregate structure to
    1738             :                                  * ripng_info */
    1739           0 :                                 memset(&newinfo, 0, sizeof(struct ripng_info));
    1740             :                                 /* the nexthop is :: */
    1741           0 :                                 newinfo.metric = aggregate->metric;
    1742           0 :                                 newinfo.metric_out = aggregate->metric_out;
    1743           0 :                                 newinfo.tag = aggregate->tag;
    1744           0 :                                 newinfo.tag_out = aggregate->tag_out;
    1745             : 
    1746           0 :                                 ret = route_map_apply(
    1747             :                                         ri->routemap[RIPNG_FILTER_OUT],
    1748             :                                         (struct prefix *)p, &newinfo);
    1749             : 
    1750           0 :                                 if (ret == RMAP_DENYMATCH) {
    1751           0 :                                         if (IS_RIPNG_DEBUG_PACKET)
    1752           0 :                                                 zlog_debug(
    1753             :                                                         "RIPng %pFX is filtered by route-map out",
    1754             :                                                         p);
    1755           0 :                                         continue;
    1756             :                                 }
    1757             : 
    1758           0 :                                 aggregate->metric_out = newinfo.metric_out;
    1759           0 :                                 aggregate->tag_out = newinfo.tag_out;
    1760           0 :                                 if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop_out))
    1761           0 :                                         aggregate->nexthop_out =
    1762             :                                                 newinfo.nexthop_out;
    1763             :                         }
    1764             : 
    1765             :                         /* There is no redistribute routemap for the aggregated
    1766             :                          * RTE */
    1767             : 
    1768             :                         /* Changed route only output. */
    1769             :                         /* XXX, vincent, in order to increase time convergence,
    1770             :                          * it should be announced if a child has changed.
    1771             :                          */
    1772           0 :                         if (route_type == ripng_changed_route)
    1773           0 :                                 continue;
    1774             : 
    1775             :                         /* Apply offset-list */
    1776           0 :                         if (aggregate->metric_out != RIPNG_METRIC_INFINITY)
    1777           0 :                                 ripng_offset_list_apply_out(
    1778             :                                         ripng, p, ifp, &aggregate->metric_out);
    1779             : 
    1780           0 :                         if (aggregate->metric_out > RIPNG_METRIC_INFINITY)
    1781           0 :                                 aggregate->metric_out = RIPNG_METRIC_INFINITY;
    1782             : 
    1783             :                         /* Add RTE to the list */
    1784           0 :                         ripng_rte_add(ripng_rte_list, p, NULL, aggregate);
    1785             :                 }
    1786             :         }
    1787             : 
    1788             :         /* Flush the list */
    1789           0 :         ripng_rte_send(ripng_rte_list, ifp, to);
    1790           0 :         ripng_rte_free(ripng_rte_list);
    1791           0 : }
    1792             : 
    1793           0 : struct ripng *ripng_lookup_by_vrf_id(vrf_id_t vrf_id)
    1794             : {
    1795           0 :         struct vrf *vrf;
    1796             : 
    1797           0 :         vrf = vrf_lookup_by_id(vrf_id);
    1798           0 :         if (!vrf)
    1799             :                 return NULL;
    1800             : 
    1801           0 :         return vrf->info;
    1802             : }
    1803             : 
    1804           4 : struct ripng *ripng_lookup_by_vrf_name(const char *vrf_name)
    1805             : {
    1806           4 :         struct ripng ripng;
    1807             : 
    1808           4 :         ripng.vrf_name = (char *)vrf_name;
    1809             : 
    1810           4 :         return RB_FIND(ripng_instance_head, &ripng_instances, &ripng);
    1811             : }
    1812             : 
    1813             : /* Create new RIPng instance and set it to global variable. */
    1814           1 : struct ripng *ripng_create(const char *vrf_name, struct vrf *vrf, int socket)
    1815             : {
    1816           1 :         struct ripng *ripng;
    1817             : 
    1818             :         /* Allocaste RIPng instance. */
    1819           1 :         ripng = XCALLOC(MTYPE_RIPNG, sizeof(struct ripng));
    1820           1 :         ripng->vrf_name = XSTRDUP(MTYPE_RIPNG_VRF_NAME, vrf_name);
    1821             : 
    1822             :         /* Default version and timer values. */
    1823           1 :         ripng->version = RIPNG_V1;
    1824           1 :         ripng->update_time = yang_get_default_uint32(
    1825             :                 "%s/timers/update-interval", RIPNG_INSTANCE);
    1826           1 :         ripng->timeout_time = yang_get_default_uint32(
    1827             :                 "%s/timers/holddown-interval", RIPNG_INSTANCE);
    1828           1 :         ripng->garbage_time = yang_get_default_uint32(
    1829             :                 "%s/timers/flush-interval", RIPNG_INSTANCE);
    1830           2 :         ripng->default_metric =
    1831           1 :                 yang_get_default_uint8("%s/default-metric", RIPNG_INSTANCE);
    1832           1 :         ripng->ecmp = yang_get_default_bool("%s/allow-ecmp", RIPNG_INSTANCE);
    1833             : 
    1834             :         /* Make buffer.  */
    1835           1 :         ripng->ibuf = stream_new(RIPNG_MAX_PACKET_SIZE * 5);
    1836           1 :         ripng->obuf = stream_new(RIPNG_MAX_PACKET_SIZE);
    1837             : 
    1838             :         /* Initialize RIPng data structures. */
    1839           1 :         ripng->table = agg_table_init();
    1840           1 :         agg_set_table_info(ripng->table, ripng);
    1841           1 :         ripng->peer_list = list_new();
    1842           1 :         ripng->peer_list->cmp = (int (*)(void *, void *))ripng_peer_list_cmp;
    1843           1 :         ripng->peer_list->del = ripng_peer_list_del;
    1844           1 :         ripng->enable_if = vector_init(1);
    1845           1 :         ripng->enable_network = agg_table_init();
    1846           1 :         ripng->passive_interface = vector_init(1);
    1847           1 :         ripng->offset_list_master = list_new();
    1848           1 :         ripng->offset_list_master->cmp =
    1849             :                 (int (*)(void *, void *))offset_list_cmp;
    1850           1 :         ripng->offset_list_master->del =
    1851             :                 (void (*)(void *))ripng_offset_list_free;
    1852           1 :         ripng->distribute_ctx = distribute_list_ctx_create(vrf);
    1853           1 :         distribute_list_add_hook(ripng->distribute_ctx,
    1854             :                                  ripng_distribute_update);
    1855           1 :         distribute_list_delete_hook(ripng->distribute_ctx,
    1856             :                                     ripng_distribute_update);
    1857             : 
    1858             :         /* if rmap install. */
    1859           1 :         ripng->if_rmap_ctx = if_rmap_ctx_create(vrf_name);
    1860           1 :         if_rmap_hook_add(ripng->if_rmap_ctx, ripng_if_rmap_update);
    1861           1 :         if_rmap_hook_delete(ripng->if_rmap_ctx, ripng_if_rmap_update);
    1862             : 
    1863             :         /* Enable the routing instance if possible. */
    1864           1 :         if (vrf && vrf_is_enabled(vrf))
    1865           1 :                 ripng_instance_enable(ripng, vrf, socket);
    1866             :         else {
    1867           0 :                 ripng->vrf = NULL;
    1868           0 :                 ripng->sock = -1;
    1869             :         }
    1870             : 
    1871           1 :         RB_INSERT(ripng_instance_head, &ripng_instances, ripng);
    1872             : 
    1873           1 :         return ripng;
    1874             : }
    1875             : 
    1876             : /* Send RIPng request to the interface. */
    1877           0 : int ripng_request(struct interface *ifp)
    1878             : {
    1879           0 :         struct rte *rte;
    1880           0 :         struct ripng_packet ripng_packet;
    1881             : 
    1882             :         /* In default ripd doesn't send RIP_REQUEST to the loopback interface.
    1883             :          */
    1884           0 :         if (if_is_loopback(ifp))
    1885             :                 return 0;
    1886             : 
    1887             :         /* If interface is down, don't send RIP packet. */
    1888           0 :         if (!if_is_up(ifp))
    1889             :                 return 0;
    1890             : 
    1891           0 :         if (IS_RIPNG_DEBUG_EVENT)
    1892           0 :                 zlog_debug("RIPng send request to %s", ifp->name);
    1893             : 
    1894           0 :         memset(&ripng_packet, 0, sizeof(ripng_packet));
    1895           0 :         ripng_packet.command = RIPNG_REQUEST;
    1896           0 :         ripng_packet.version = RIPNG_V1;
    1897           0 :         rte = ripng_packet.rte;
    1898           0 :         rte->metric = RIPNG_METRIC_INFINITY;
    1899             : 
    1900           0 :         return ripng_send_packet((caddr_t)&ripng_packet, sizeof(ripng_packet),
    1901             :                                  NULL, ifp);
    1902             : }
    1903             : 
    1904             : 
    1905           1 : static int ripng_update_jitter(int time)
    1906             : {
    1907           2 :         return ((frr_weak_random() % (time + 1)) - (time / 2));
    1908             : }
    1909             : 
    1910           4 : void ripng_event(struct ripng *ripng, enum ripng_event event, int sock)
    1911             : {
    1912           4 :         int jitter = 0;
    1913             : 
    1914           4 :         switch (event) {
    1915           1 :         case RIPNG_READ:
    1916           1 :                 thread_add_read(master, ripng_read, ripng, sock,
    1917             :                                 &ripng->t_read);
    1918           1 :                 break;
    1919           1 :         case RIPNG_UPDATE_EVENT:
    1920           1 :                 THREAD_OFF(ripng->t_update);
    1921             : 
    1922             :                 /* Update timer jitter. */
    1923           1 :                 jitter = ripng_update_jitter(ripng->update_time);
    1924             : 
    1925           1 :                 thread_add_timer(master, ripng_update, ripng,
    1926             :                                  sock ? 2 : ripng->update_time + jitter,
    1927             :                                  &ripng->t_update);
    1928           1 :                 break;
    1929           2 :         case RIPNG_TRIGGERED_UPDATE:
    1930           2 :                 if (ripng->t_triggered_interval)
    1931           0 :                         ripng->trigger = 1;
    1932             :                 else
    1933           2 :                         thread_add_event(master, ripng_triggered_update, ripng,
    1934             :                                          0, &ripng->t_triggered_update);
    1935             :                 break;
    1936             :         case RIPNG_ZEBRA:
    1937             :         case RIPNG_REQUEST_EVENT:
    1938             :                 break;
    1939             :         }
    1940           4 : }
    1941             : 
    1942             : 
    1943             : /* Print out routes update time. */
    1944           0 : static void ripng_vty_out_uptime(struct vty *vty, struct ripng_info *rinfo)
    1945             : {
    1946           0 :         time_t clock;
    1947           0 :         struct tm tm;
    1948             : #define TIME_BUF 25
    1949           0 :         char timebuf[TIME_BUF];
    1950           0 :         struct thread *thread;
    1951             : 
    1952           0 :         if ((thread = rinfo->t_timeout) != NULL) {
    1953           0 :                 clock = thread_timer_remain_second(thread);
    1954           0 :                 gmtime_r(&clock, &tm);
    1955           0 :                 strftime(timebuf, TIME_BUF, "%M:%S", &tm);
    1956           0 :                 vty_out(vty, "%5s", timebuf);
    1957           0 :         } else if ((thread = rinfo->t_garbage_collect) != NULL) {
    1958           0 :                 clock = thread_timer_remain_second(thread);
    1959           0 :                 gmtime_r(&clock, &tm);
    1960           0 :                 strftime(timebuf, TIME_BUF, "%M:%S", &tm);
    1961           0 :                 vty_out(vty, "%5s", timebuf);
    1962             :         }
    1963           0 : }
    1964             : 
    1965           0 : static char *ripng_route_subtype_print(struct ripng_info *rinfo)
    1966             : {
    1967           0 :         static char str[3];
    1968           0 :         memset(str, 0, 3);
    1969             : 
    1970           0 :         if (rinfo->suppress)
    1971           0 :                 strlcat(str, "S", sizeof(str));
    1972             : 
    1973           0 :         switch (rinfo->sub_type) {
    1974           0 :         case RIPNG_ROUTE_RTE:
    1975           0 :                 strlcat(str, "n", sizeof(str));
    1976           0 :                 break;
    1977           0 :         case RIPNG_ROUTE_STATIC:
    1978           0 :                 strlcat(str, "s", sizeof(str));
    1979           0 :                 break;
    1980           0 :         case RIPNG_ROUTE_DEFAULT:
    1981           0 :                 strlcat(str, "d", sizeof(str));
    1982           0 :                 break;
    1983           0 :         case RIPNG_ROUTE_REDISTRIBUTE:
    1984           0 :                 strlcat(str, "r", sizeof(str));
    1985           0 :                 break;
    1986           0 :         case RIPNG_ROUTE_INTERFACE:
    1987           0 :                 strlcat(str, "i", sizeof(str));
    1988           0 :                 break;
    1989           0 :         default:
    1990           0 :                 strlcat(str, "?", sizeof(str));
    1991           0 :                 break;
    1992             :         }
    1993             : 
    1994           0 :         return str;
    1995             : }
    1996             : 
    1997           0 : DEFUN (show_ipv6_ripng,
    1998             :        show_ipv6_ripng_cmd,
    1999             :        "show ipv6 ripng [vrf NAME]",
    2000             :        SHOW_STR
    2001             :        IPV6_STR
    2002             :        "Show RIPng routes\n"
    2003             :        VRF_CMD_HELP_STR)
    2004             : {
    2005           0 :         struct ripng *ripng;
    2006           0 :         struct agg_node *rp;
    2007           0 :         struct ripng_info *rinfo;
    2008           0 :         struct ripng_aggregate *aggregate;
    2009           0 :         struct list *list = NULL;
    2010           0 :         struct listnode *listnode = NULL;
    2011           0 :         int len;
    2012           0 :         const char *vrf_name;
    2013           0 :         int idx = 0;
    2014             : 
    2015           0 :         if (argv_find(argv, argc, "vrf", &idx))
    2016           0 :                 vrf_name = argv[idx + 1]->arg;
    2017             :         else
    2018           0 :                 vrf_name = VRF_DEFAULT_NAME;
    2019             : 
    2020           0 :         ripng = ripng_lookup_by_vrf_name(vrf_name);
    2021           0 :         if (!ripng) {
    2022           0 :                 vty_out(vty, "%% RIPng instance not found\n");
    2023           0 :                 return CMD_SUCCESS;
    2024             :         }
    2025           0 :         if (!ripng->enabled) {
    2026           0 :                 vty_out(vty, "%% RIPng instance is disabled\n");
    2027           0 :                 return CMD_SUCCESS;
    2028             :         }
    2029             : 
    2030             :         /* Header of display. */
    2031           0 :         vty_out(vty,
    2032             :                 "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP\n"
    2033             :                 "Sub-codes:\n"
    2034             :                 "      (n) - normal, (s) - static, (d) - default, (r) - redistribute,\n"
    2035             :                 "      (i) - interface, (a/S) - aggregated/Suppressed\n\n"
    2036             :                 "   Network      Next Hop                      Via     Metric Tag Time\n");
    2037             : 
    2038           0 :         for (rp = agg_route_top(ripng->table); rp; rp = agg_route_next(rp)) {
    2039           0 :                 if ((aggregate = rp->aggregate) != NULL) {
    2040             : #ifdef DEBUG
    2041             :                         vty_out(vty, "R(a) %d/%d %pRN ", aggregate->count,
    2042             :                                 aggregate->suppress, rp);
    2043             : #else
    2044           0 :                         vty_out(vty, "R(a) %pRN ", rp);
    2045             : #endif /* DEBUG */
    2046           0 :                         vty_out(vty, "\n");
    2047           0 :                         vty_out(vty, "%*s", 18, " ");
    2048             : 
    2049           0 :                         vty_out(vty, "%*s", 28, " ");
    2050           0 :                         vty_out(vty, "self      %2d  %3" ROUTE_TAG_PRI "\n",
    2051           0 :                                 aggregate->metric, (route_tag_t)aggregate->tag);
    2052             :                 }
    2053             : 
    2054           0 :                 if ((list = rp->info) != NULL)
    2055           0 :                         for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) {
    2056             : #ifdef DEBUG
    2057             :                                 vty_out(vty, "%c(%s) 0/%d %pRN ",
    2058             :                                         zebra_route_char(rinfo->type),
    2059             :                                         ripng_route_subtype_print(rinfo),
    2060             :                                         rinfo->suppress, rp);
    2061             : #else
    2062           0 :                                 vty_out(vty, "%c(%s) %pRN ",
    2063           0 :                                         zebra_route_char(rinfo->type),
    2064             :                                         ripng_route_subtype_print(rinfo), rp);
    2065             : #endif /* DEBUG */
    2066           0 :                                 vty_out(vty, "\n");
    2067           0 :                                 vty_out(vty, "%*s", 18, " ");
    2068           0 :                                 len = vty_out(vty, "%pI6",
    2069             :                                               &rinfo->nexthop);
    2070             : 
    2071           0 :                                 len = 28 - len;
    2072           0 :                                 if (len > 0)
    2073           0 :                                         vty_out(vty, "%*s", len, " ");
    2074             : 
    2075             :                                 /* from */
    2076           0 :                                 if ((rinfo->type == ZEBRA_ROUTE_RIPNG)
    2077           0 :                                     && (rinfo->sub_type == RIPNG_ROUTE_RTE)) {
    2078           0 :                                         len = vty_out(
    2079             :                                                 vty, "%s",
    2080             :                                                 ifindex2ifname(
    2081             :                                                         rinfo->ifindex,
    2082           0 :                                                         ripng->vrf->vrf_id));
    2083           0 :                                 } else if (rinfo->metric
    2084             :                                            == RIPNG_METRIC_INFINITY) {
    2085           0 :                                         len = vty_out(vty, "kill");
    2086             :                                 } else
    2087           0 :                                         len = vty_out(vty, "self");
    2088             : 
    2089           0 :                                 len = 9 - len;
    2090           0 :                                 if (len > 0)
    2091           0 :                                         vty_out(vty, "%*s", len, " ");
    2092             : 
    2093           0 :                                 vty_out(vty, " %2d  %3" ROUTE_TAG_PRI "  ",
    2094           0 :                                         rinfo->metric, (route_tag_t)rinfo->tag);
    2095             : 
    2096             :                                 /* time */
    2097           0 :                                 if ((rinfo->type == ZEBRA_ROUTE_RIPNG)
    2098           0 :                                     && (rinfo->sub_type == RIPNG_ROUTE_RTE)) {
    2099             :                                         /* RTE from remote RIP routers */
    2100           0 :                                         ripng_vty_out_uptime(vty, rinfo);
    2101           0 :                                 } else if (rinfo->metric
    2102             :                                            == RIPNG_METRIC_INFINITY) {
    2103             :                                         /* poisonous reversed routes (gc) */
    2104           0 :                                         ripng_vty_out_uptime(vty, rinfo);
    2105             :                                 }
    2106             : 
    2107           0 :                                 vty_out(vty, "\n");
    2108             :                         }
    2109             :         }
    2110             : 
    2111             :         return CMD_SUCCESS;
    2112             : }
    2113             : 
    2114           1 : DEFUN (show_ipv6_ripng_status,
    2115             :        show_ipv6_ripng_status_cmd,
    2116             :        "show ipv6 ripng [vrf NAME] status",
    2117             :        SHOW_STR
    2118             :        IPV6_STR
    2119             :        "Show RIPng routes\n"
    2120             :        VRF_CMD_HELP_STR
    2121             :        "IPv6 routing protocol process parameters and statistics\n")
    2122             : {
    2123           1 :         struct ripng *ripng;
    2124           1 :         struct interface *ifp;
    2125           1 :         const char *vrf_name;
    2126           1 :         int idx = 0;
    2127             : 
    2128           1 :         if (argv_find(argv, argc, "vrf", &idx))
    2129           0 :                 vrf_name = argv[idx + 1]->arg;
    2130             :         else
    2131           1 :                 vrf_name = VRF_DEFAULT_NAME;
    2132             : 
    2133           1 :         ripng = ripng_lookup_by_vrf_name(vrf_name);
    2134           1 :         if (!ripng) {
    2135           0 :                 vty_out(vty, "%% RIPng instance not found\n");
    2136           0 :                 return CMD_SUCCESS;
    2137             :         }
    2138           1 :         if (!ripng->enabled) {
    2139           0 :                 vty_out(vty, "%% RIPng instance is disabled\n");
    2140           0 :                 return CMD_SUCCESS;
    2141             :         }
    2142             : 
    2143           1 :         vty_out(vty, "Routing Protocol is \"RIPng\"\n");
    2144           1 :         vty_out(vty, "  Sending updates every %u seconds with +/-50%%,",
    2145           1 :                 ripng->update_time);
    2146           1 :         vty_out(vty, " next due in %lu seconds\n",
    2147             :                 thread_timer_remain_second(ripng->t_update));
    2148           1 :         vty_out(vty, "  Timeout after %u seconds,", ripng->timeout_time);
    2149           1 :         vty_out(vty, " garbage collect after %u seconds\n",
    2150           1 :                 ripng->garbage_time);
    2151             : 
    2152             :         /* Filtering status show. */
    2153           1 :         config_show_distribute(vty, ripng->distribute_ctx);
    2154             : 
    2155             :         /* Default metric information. */
    2156           1 :         vty_out(vty, "  Default redistribution metric is %d\n",
    2157           1 :                 ripng->default_metric);
    2158             : 
    2159             :         /* Redistribute information. */
    2160           1 :         vty_out(vty, "  Redistributing:");
    2161           1 :         ripng_redistribute_write(vty, ripng);
    2162           1 :         vty_out(vty, "\n");
    2163             : 
    2164           1 :         vty_out(vty, "  Default version control: send version %d,",
    2165           1 :                 ripng->version);
    2166           1 :         vty_out(vty, " receive version %d \n", ripng->version);
    2167             : 
    2168           1 :         vty_out(vty, "    Interface        Send  Recv\n");
    2169             : 
    2170          10 :         FOR_ALL_INTERFACES (ripng->vrf, ifp) {
    2171           8 :                 struct ripng_interface *ri;
    2172             : 
    2173           8 :                 ri = ifp->info;
    2174             : 
    2175           8 :                 if (ri->enable_network || ri->enable_interface) {
    2176             : 
    2177           1 :                         vty_out(vty, "    %-17s%-3d   %-3d\n", ifp->name,
    2178           1 :                                 ripng->version, ripng->version);
    2179             :                 }
    2180             :         }
    2181             : 
    2182           1 :         vty_out(vty, "  Routing for Networks:\n");
    2183           1 :         ripng_network_write(vty, ripng);
    2184             : 
    2185           1 :         vty_out(vty, "  Routing Information Sources:\n");
    2186           1 :         vty_out(vty,
    2187             :                 "    Gateway          BadPackets BadRoutes  Distance Last Update\n");
    2188           1 :         ripng_peer_display(vty, ripng);
    2189             : 
    2190           1 :         return CMD_SUCCESS;
    2191             : }
    2192             : 
    2193             : /* Update ECMP routes to zebra when ECMP is disabled. */
    2194           0 : void ripng_ecmp_disable(struct ripng *ripng)
    2195             : {
    2196           0 :         struct agg_node *rp;
    2197           0 :         struct ripng_info *rinfo, *tmp_rinfo;
    2198           0 :         struct list *list;
    2199           0 :         struct listnode *node, *nextnode;
    2200             : 
    2201           0 :         if (!ripng)
    2202             :                 return;
    2203             : 
    2204           0 :         for (rp = agg_route_top(ripng->table); rp; rp = agg_route_next(rp))
    2205           0 :                 if ((list = rp->info) != NULL && listcount(list) > 1) {
    2206           0 :                         rinfo = listgetdata(listhead(list));
    2207           0 :                         if (!ripng_route_rte(rinfo))
    2208           0 :                                 continue;
    2209             : 
    2210             :                         /* Drop all other entries, except the first one. */
    2211           0 :                         for (ALL_LIST_ELEMENTS(list, node, nextnode, tmp_rinfo))
    2212           0 :                                 if (tmp_rinfo != rinfo) {
    2213           0 :                                         THREAD_OFF(tmp_rinfo->t_timeout);
    2214           0 :                                         THREAD_OFF(
    2215             :                                                 tmp_rinfo->t_garbage_collect);
    2216           0 :                                         list_delete_node(list, node);
    2217           0 :                                         ripng_info_free(tmp_rinfo);
    2218             :                                 }
    2219             : 
    2220             :                         /* Update zebra. */
    2221           0 :                         ripng_zebra_ipv6_add(ripng, rp);
    2222             : 
    2223             :                         /* Set the route change flag. */
    2224           0 :                         SET_FLAG(rinfo->flags, RIPNG_RTF_CHANGED);
    2225             : 
    2226             :                         /* Signal the output process to trigger an update. */
    2227           0 :                         ripng_event(ripng, RIPNG_TRIGGERED_UPDATE, 0);
    2228             :                 }
    2229             : }
    2230             : 
    2231             : /* RIPng configuration write function. */
    2232           0 : static int ripng_config_write(struct vty *vty)
    2233             : {
    2234           0 :         struct ripng *ripng;
    2235           0 :         int write = 0;
    2236             : 
    2237           0 :         RB_FOREACH(ripng, ripng_instance_head, &ripng_instances) {
    2238           0 :                 char xpath[XPATH_MAXLEN];
    2239           0 :                 struct lyd_node *dnode;
    2240             : 
    2241           0 :                 snprintf(xpath, sizeof(xpath),
    2242             :                          "/frr-ripngd:ripngd/instance[vrf='%s']",
    2243             :                          ripng->vrf_name);
    2244             : 
    2245           0 :                 dnode = yang_dnode_get(running_config->dnode, xpath);
    2246           0 :                 assert(dnode);
    2247             : 
    2248           0 :                 nb_cli_show_dnode_cmds(vty, dnode, false);
    2249             : 
    2250           0 :                 config_write_distribute(vty, ripng->distribute_ctx);
    2251           0 :                 config_write_if_rmap(vty, ripng->if_rmap_ctx);
    2252             : 
    2253           0 :                 vty_out(vty, "exit\n");
    2254             : 
    2255           0 :                 write = 1;
    2256             :         }
    2257             : 
    2258           0 :         return write;
    2259             : }
    2260             : 
    2261             : static int ripng_config_write(struct vty *vty);
    2262             : /* RIPng node structure. */
    2263             : static struct cmd_node cmd_ripng_node = {
    2264             :         .name = "ripng",
    2265             :         .node = RIPNG_NODE,
    2266             :         .parent_node = CONFIG_NODE,
    2267             :         .prompt = "%s(config-router)# ",
    2268             :         .config_write = ripng_config_write,
    2269             : };
    2270             : 
    2271           0 : static void ripng_distribute_update(struct distribute_ctx *ctx,
    2272             :                                     struct distribute *dist)
    2273             : {
    2274           0 :         struct interface *ifp;
    2275           0 :         struct ripng_interface *ri;
    2276           0 :         struct access_list *alist;
    2277           0 :         struct prefix_list *plist;
    2278             : 
    2279           0 :         if (!ctx->vrf || !dist->ifname)
    2280             :                 return;
    2281             : 
    2282           0 :         ifp = if_lookup_by_name(dist->ifname, ctx->vrf->vrf_id);
    2283           0 :         if (ifp == NULL)
    2284             :                 return;
    2285             : 
    2286           0 :         ri = ifp->info;
    2287             : 
    2288           0 :         if (dist->list[DISTRIBUTE_V6_IN]) {
    2289           0 :                 alist = access_list_lookup(AFI_IP6,
    2290             :                                            dist->list[DISTRIBUTE_V6_IN]);
    2291           0 :                 if (alist)
    2292           0 :                         ri->list[RIPNG_FILTER_IN] = alist;
    2293             :                 else
    2294           0 :                         ri->list[RIPNG_FILTER_IN] = NULL;
    2295             :         } else
    2296           0 :                 ri->list[RIPNG_FILTER_IN] = NULL;
    2297             : 
    2298           0 :         if (dist->list[DISTRIBUTE_V6_OUT]) {
    2299           0 :                 alist = access_list_lookup(AFI_IP6,
    2300             :                                            dist->list[DISTRIBUTE_V6_OUT]);
    2301           0 :                 if (alist)
    2302           0 :                         ri->list[RIPNG_FILTER_OUT] = alist;
    2303             :                 else
    2304           0 :                         ri->list[RIPNG_FILTER_OUT] = NULL;
    2305             :         } else
    2306           0 :                 ri->list[RIPNG_FILTER_OUT] = NULL;
    2307             : 
    2308           0 :         if (dist->prefix[DISTRIBUTE_V6_IN]) {
    2309           0 :                 plist = prefix_list_lookup(AFI_IP6,
    2310             :                                            dist->prefix[DISTRIBUTE_V6_IN]);
    2311           0 :                 if (plist)
    2312           0 :                         ri->prefix[RIPNG_FILTER_IN] = plist;
    2313             :                 else
    2314           0 :                         ri->prefix[RIPNG_FILTER_IN] = NULL;
    2315             :         } else
    2316           0 :                 ri->prefix[RIPNG_FILTER_IN] = NULL;
    2317             : 
    2318           0 :         if (dist->prefix[DISTRIBUTE_V6_OUT]) {
    2319           0 :                 plist = prefix_list_lookup(AFI_IP6,
    2320             :                                            dist->prefix[DISTRIBUTE_V6_OUT]);
    2321           0 :                 if (plist)
    2322           0 :                         ri->prefix[RIPNG_FILTER_OUT] = plist;
    2323             :                 else
    2324           0 :                         ri->prefix[RIPNG_FILTER_OUT] = NULL;
    2325             :         } else
    2326           0 :                 ri->prefix[RIPNG_FILTER_OUT] = NULL;
    2327             : }
    2328             : 
    2329          41 : void ripng_distribute_update_interface(struct interface *ifp)
    2330             : {
    2331          41 :         struct ripng_interface *ri = ifp->info;
    2332          41 :         struct ripng *ripng = ri->ripng;
    2333          41 :         struct distribute *dist;
    2334             : 
    2335          41 :         if (!ripng)
    2336             :                 return;
    2337          41 :         dist = distribute_lookup(ripng->distribute_ctx, ifp->name);
    2338          41 :         if (dist)
    2339           0 :                 ripng_distribute_update(ripng->distribute_ctx, dist);
    2340             : }
    2341             : 
    2342             : /* Update all interface's distribute list. */
    2343           0 : static void ripng_distribute_update_all(struct prefix_list *notused)
    2344             : {
    2345           0 :         struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
    2346           0 :         struct interface *ifp;
    2347             : 
    2348           0 :         FOR_ALL_INTERFACES (vrf, ifp)
    2349           0 :                 ripng_distribute_update_interface(ifp);
    2350           0 : }
    2351             : 
    2352           0 : static void ripng_distribute_update_all_wrapper(struct access_list *notused)
    2353             : {
    2354           0 :         ripng_distribute_update_all(NULL);
    2355           0 : }
    2356             : 
    2357             : /* delete all the added ripng routes. */
    2358           1 : void ripng_clean(struct ripng *ripng)
    2359             : {
    2360           1 :         ripng_interface_clean(ripng);
    2361             : 
    2362           1 :         if (ripng->enabled)
    2363           0 :                 ripng_instance_disable(ripng);
    2364             : 
    2365          32 :         for (int i = 0; i < ZEBRA_ROUTE_MAX; i++)
    2366          31 :                 if (ripng->redist[i].route_map.name)
    2367           0 :                         free(ripng->redist[i].route_map.name);
    2368             : 
    2369           1 :         agg_table_finish(ripng->table);
    2370           1 :         list_delete(&ripng->peer_list);
    2371           1 :         distribute_list_delete(&ripng->distribute_ctx);
    2372           1 :         if_rmap_ctx_delete(ripng->if_rmap_ctx);
    2373             : 
    2374           1 :         stream_free(ripng->ibuf);
    2375           1 :         stream_free(ripng->obuf);
    2376             : 
    2377           1 :         ripng_clean_network(ripng);
    2378           1 :         ripng_passive_interface_clean(ripng);
    2379           1 :         vector_free(ripng->enable_if);
    2380           1 :         agg_table_finish(ripng->enable_network);
    2381           1 :         vector_free(ripng->passive_interface);
    2382           1 :         list_delete(&ripng->offset_list_master);
    2383             : 
    2384           1 :         RB_REMOVE(ripng_instance_head, &ripng_instances, ripng);
    2385           1 :         XFREE(MTYPE_RIPNG_VRF_NAME, ripng->vrf_name);
    2386           1 :         XFREE(MTYPE_RIPNG, ripng);
    2387           1 : }
    2388             : 
    2389           0 : static void ripng_if_rmap_update(struct if_rmap_ctx *ctx,
    2390             :                                  struct if_rmap *if_rmap)
    2391             : {
    2392           0 :         struct interface *ifp = NULL;
    2393           0 :         struct ripng_interface *ri;
    2394           0 :         struct route_map *rmap;
    2395           0 :         struct vrf *vrf = NULL;
    2396             : 
    2397           0 :         if (ctx->name)
    2398           0 :                 vrf = vrf_lookup_by_name(ctx->name);
    2399           0 :         if (vrf)
    2400           0 :                 ifp = if_lookup_by_name(if_rmap->ifname, vrf->vrf_id);
    2401           0 :         if (ifp == NULL)
    2402           0 :                 return;
    2403             : 
    2404           0 :         ri = ifp->info;
    2405             : 
    2406           0 :         if (if_rmap->routemap[IF_RMAP_IN]) {
    2407           0 :                 rmap = route_map_lookup_by_name(if_rmap->routemap[IF_RMAP_IN]);
    2408           0 :                 if (rmap)
    2409           0 :                         ri->routemap[IF_RMAP_IN] = rmap;
    2410             :                 else
    2411           0 :                         ri->routemap[IF_RMAP_IN] = NULL;
    2412             :         } else
    2413           0 :                 ri->routemap[RIPNG_FILTER_IN] = NULL;
    2414             : 
    2415           0 :         if (if_rmap->routemap[IF_RMAP_OUT]) {
    2416           0 :                 rmap = route_map_lookup_by_name(if_rmap->routemap[IF_RMAP_OUT]);
    2417           0 :                 if (rmap)
    2418           0 :                         ri->routemap[IF_RMAP_OUT] = rmap;
    2419             :                 else
    2420           0 :                         ri->routemap[IF_RMAP_OUT] = NULL;
    2421             :         } else
    2422           0 :                 ri->routemap[RIPNG_FILTER_OUT] = NULL;
    2423             : }
    2424             : 
    2425          27 : void ripng_if_rmap_update_interface(struct interface *ifp)
    2426             : {
    2427          27 :         struct ripng_interface *ri = ifp->info;
    2428          27 :         struct ripng *ripng = ri->ripng;
    2429          27 :         struct if_rmap *if_rmap;
    2430          27 :         struct if_rmap_ctx *ctx;
    2431             : 
    2432          27 :         if (!ripng)
    2433             :                 return;
    2434          27 :         ctx = ripng->if_rmap_ctx;
    2435          27 :         if (!ctx)
    2436             :                 return;
    2437          27 :         if_rmap = if_rmap_lookup(ctx, ifp->name);
    2438          27 :         if (if_rmap)
    2439           0 :                 ripng_if_rmap_update(ctx, if_rmap);
    2440             : }
    2441             : 
    2442           0 : static void ripng_routemap_update_redistribute(struct ripng *ripng)
    2443             : {
    2444           0 :         for (int i = 0; i < ZEBRA_ROUTE_MAX; i++) {
    2445           0 :                 if (ripng->redist[i].route_map.name) {
    2446           0 :                         ripng->redist[i].route_map.map =
    2447           0 :                                 route_map_lookup_by_name(
    2448             :                                         ripng->redist[i].route_map.name);
    2449           0 :                         route_map_counter_increment(
    2450             :                                 ripng->redist[i].route_map.map);
    2451             :                 }
    2452             :         }
    2453           0 : }
    2454             : 
    2455           0 : static void ripng_routemap_update(const char *unused)
    2456             : {
    2457           0 :         struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
    2458           0 :         struct ripng *ripng;
    2459           0 :         struct interface *ifp;
    2460             : 
    2461           0 :         FOR_ALL_INTERFACES (vrf, ifp)
    2462           0 :                 ripng_if_rmap_update_interface(ifp);
    2463             : 
    2464           0 :         ripng = vrf->info;
    2465           0 :         if (ripng)
    2466           0 :                 ripng_routemap_update_redistribute(ripng);
    2467           0 : }
    2468             : 
    2469             : /* Link RIPng instance to VRF. */
    2470           1 : static void ripng_vrf_link(struct ripng *ripng, struct vrf *vrf)
    2471             : {
    2472           1 :         struct interface *ifp;
    2473             : 
    2474           1 :         ripng->vrf = vrf;
    2475           1 :         ripng->distribute_ctx->vrf = vrf;
    2476           1 :         vrf->info = ripng;
    2477             : 
    2478           2 :         FOR_ALL_INTERFACES (vrf, ifp)
    2479           0 :                 ripng_interface_sync(ifp);
    2480           1 : }
    2481             : 
    2482             : /* Unlink RIPng instance from VRF. */
    2483           1 : static void ripng_vrf_unlink(struct ripng *ripng, struct vrf *vrf)
    2484             : {
    2485           1 :         struct interface *ifp;
    2486             : 
    2487           1 :         ripng->vrf = NULL;
    2488           1 :         ripng->distribute_ctx->vrf = NULL;
    2489           1 :         vrf->info = NULL;
    2490             : 
    2491          10 :         FOR_ALL_INTERFACES (vrf, ifp)
    2492           8 :                 ripng_interface_sync(ifp);
    2493           1 : }
    2494             : 
    2495           1 : static void ripng_instance_enable(struct ripng *ripng, struct vrf *vrf,
    2496             :                                   int sock)
    2497             : {
    2498           1 :         ripng->sock = sock;
    2499             : 
    2500           1 :         ripng_vrf_link(ripng, vrf);
    2501           1 :         ripng->enabled = true;
    2502             : 
    2503             :         /* Resend all redistribute requests. */
    2504           1 :         ripng_redistribute_enable(ripng);
    2505             : 
    2506             :         /* Create read and timer thread. */
    2507           1 :         ripng_event(ripng, RIPNG_READ, ripng->sock);
    2508           1 :         ripng_event(ripng, RIPNG_UPDATE_EVENT, 1);
    2509             : 
    2510           1 :         ripng_zebra_vrf_register(vrf);
    2511           1 : }
    2512             : 
    2513           1 : static void ripng_instance_disable(struct ripng *ripng)
    2514             : {
    2515           1 :         struct vrf *vrf = ripng->vrf;
    2516           1 :         struct agg_node *rp;
    2517             : 
    2518             :         /* Clear RIPng routes */
    2519           3 :         for (rp = agg_route_top(ripng->table); rp; rp = agg_route_next(rp)) {
    2520           1 :                 struct ripng_aggregate *aggregate;
    2521           1 :                 struct list *list;
    2522             : 
    2523           1 :                 if ((list = rp->info) != NULL) {
    2524           1 :                         struct ripng_info *rinfo;
    2525           1 :                         struct listnode *listnode;
    2526             : 
    2527           1 :                         rinfo = listgetdata(listhead(list));
    2528           1 :                         if (ripng_route_rte(rinfo))
    2529           0 :                                 ripng_zebra_ipv6_delete(ripng, rp);
    2530             : 
    2531           3 :                         for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) {
    2532           1 :                                 THREAD_OFF(rinfo->t_timeout);
    2533           1 :                                 THREAD_OFF(rinfo->t_garbage_collect);
    2534           1 :                                 ripng_info_free(rinfo);
    2535             :                         }
    2536           1 :                         list_delete(&list);
    2537           1 :                         rp->info = NULL;
    2538           1 :                         agg_unlock_node(rp);
    2539             :                 }
    2540             : 
    2541           1 :                 if ((aggregate = rp->aggregate) != NULL) {
    2542           0 :                         ripng_aggregate_free(aggregate);
    2543           0 :                         rp->aggregate = NULL;
    2544           1 :                         agg_unlock_node(rp);
    2545             :                 }
    2546             :         }
    2547             : 
    2548             :         /* Flush all redistribute requests. */
    2549           1 :         ripng_redistribute_disable(ripng);
    2550             : 
    2551             :         /* Cancel the RIPng timers */
    2552           1 :         THREAD_OFF(ripng->t_update);
    2553           1 :         THREAD_OFF(ripng->t_triggered_update);
    2554           1 :         THREAD_OFF(ripng->t_triggered_interval);
    2555             : 
    2556             :         /* Cancel the read thread */
    2557           1 :         THREAD_OFF(ripng->t_read);
    2558             : 
    2559             :         /* Close the RIPng socket */
    2560           1 :         if (ripng->sock >= 0) {
    2561           1 :                 close(ripng->sock);
    2562           1 :                 ripng->sock = -1;
    2563             :         }
    2564             : 
    2565             :         /* Clear existing peers. */
    2566           1 :         list_delete_all_node(ripng->peer_list);
    2567             : 
    2568           1 :         ripng_zebra_vrf_deregister(vrf);
    2569             : 
    2570           1 :         ripng_vrf_unlink(ripng, vrf);
    2571           1 :         ripng->enabled = false;
    2572           1 : }
    2573             : 
    2574           1 : static int ripng_vrf_new(struct vrf *vrf)
    2575             : {
    2576           1 :         if (IS_RIPNG_DEBUG_EVENT)
    2577           0 :                 zlog_debug("%s: VRF created: %s(%u)", __func__, vrf->name,
    2578             :                            vrf->vrf_id);
    2579             : 
    2580           1 :         return 0;
    2581             : }
    2582             : 
    2583           1 : static int ripng_vrf_delete(struct vrf *vrf)
    2584             : {
    2585           1 :         struct ripng *ripng;
    2586             : 
    2587           1 :         if (IS_RIPNG_DEBUG_EVENT)
    2588           1 :                 zlog_debug("%s: VRF deleted: %s(%u)", __func__, vrf->name,
    2589             :                            vrf->vrf_id);
    2590             : 
    2591           1 :         ripng = ripng_lookup_by_vrf_name(vrf->name);
    2592           1 :         if (!ripng)
    2593             :                 return 0;
    2594             : 
    2595           1 :         ripng_clean(ripng);
    2596           1 :         return 0;
    2597             : }
    2598             : 
    2599           1 : static int ripng_vrf_enable(struct vrf *vrf)
    2600             : {
    2601           1 :         struct ripng *ripng;
    2602           1 :         int socket;
    2603             : 
    2604           1 :         ripng = ripng_lookup_by_vrf_name(vrf->name);
    2605           1 :         if (!ripng || ripng->enabled)
    2606             :                 return 0;
    2607             : 
    2608           0 :         if (IS_RIPNG_DEBUG_EVENT)
    2609           0 :                 zlog_debug("%s: VRF %s(%u) enabled", __func__, vrf->name,
    2610             :                            vrf->vrf_id);
    2611             : 
    2612             :         /* Activate the VRF RIPng instance. */
    2613           0 :         socket = ripng_make_socket(vrf);
    2614           0 :         if (socket < 0)
    2615             :                 return -1;
    2616             : 
    2617           0 :         ripng_instance_enable(ripng, vrf, socket);
    2618             : 
    2619           0 :         return 0;
    2620             : }
    2621             : 
    2622           1 : static int ripng_vrf_disable(struct vrf *vrf)
    2623             : {
    2624           1 :         struct ripng *ripng;
    2625             : 
    2626           1 :         ripng = ripng_lookup_by_vrf_name(vrf->name);
    2627           1 :         if (!ripng || !ripng->enabled)
    2628             :                 return 0;
    2629             : 
    2630           1 :         if (IS_RIPNG_DEBUG_EVENT)
    2631           1 :                 zlog_debug("%s: VRF %s(%u) disabled", __func__, vrf->name,
    2632             :                            vrf->vrf_id);
    2633             : 
    2634             :         /* Deactivate the VRF RIPng instance. */
    2635           1 :         if (ripng->enabled)
    2636           1 :                 ripng_instance_disable(ripng);
    2637             : 
    2638             :         return 0;
    2639             : }
    2640             : 
    2641           1 : void ripng_vrf_init(void)
    2642             : {
    2643           1 :         vrf_init(ripng_vrf_new, ripng_vrf_enable, ripng_vrf_disable,
    2644             :                  ripng_vrf_delete);
    2645             : 
    2646           1 :         vrf_cmd_init(NULL);
    2647           1 : }
    2648             : 
    2649           1 : void ripng_vrf_terminate(void)
    2650             : {
    2651           1 :         vrf_terminate();
    2652           1 : }
    2653             : 
    2654             : /* Initialize ripng structure and set commands. */
    2655           1 : void ripng_init(void)
    2656             : {
    2657             :         /* Install RIPNG_NODE. */
    2658           1 :         install_node(&cmd_ripng_node);
    2659             : 
    2660             :         /* Install ripng commands. */
    2661           1 :         install_element(VIEW_NODE, &show_ipv6_ripng_cmd);
    2662           1 :         install_element(VIEW_NODE, &show_ipv6_ripng_status_cmd);
    2663             : 
    2664           1 :         install_default(RIPNG_NODE);
    2665             : 
    2666           1 :         ripng_if_init();
    2667           1 :         ripng_debug_init();
    2668             : 
    2669             :         /* Access list install. */
    2670           1 :         access_list_init();
    2671           1 :         access_list_add_hook(ripng_distribute_update_all_wrapper);
    2672           1 :         access_list_delete_hook(ripng_distribute_update_all_wrapper);
    2673             : 
    2674             :         /* Prefix list initialize.*/
    2675           1 :         prefix_list_init();
    2676           1 :         prefix_list_add_hook(ripng_distribute_update_all);
    2677           1 :         prefix_list_delete_hook(ripng_distribute_update_all);
    2678             : 
    2679             :         /* Route-map for interface. */
    2680           1 :         ripng_route_map_init();
    2681             : 
    2682           1 :         route_map_add_hook(ripng_routemap_update);
    2683           1 :         route_map_delete_hook(ripng_routemap_update);
    2684             : 
    2685           1 :         if_rmap_init(RIPNG_NODE);
    2686           1 : }

Generated by: LCOV version v1.16-topotato