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