]> git.proxmox.com Git - mirror_frr.git/blame - ripngd/ripngd.c
Merge pull request #5452 from mjstapp/fix_notify_nhg
[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;
274 msg.msg_controllen = sizeof adata;
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 =
1090 (struct prefix_ipv6 *)&rp->p;
1091
1092 zlog_debug(
1093 "Poisone %s/%d on the interface %s [withdraw]",
1094 inet6_ntoa(p->prefix),
1095 p->prefixlen,
dde7b15b
RW
1096 ifindex2ifname(
1097 rinfo->ifindex,
1098 ripng->vrf->vrf_id));
d62a17ae 1099 }
1100
5c84b9a5 1101 ripng_event(ripng, RIPNG_TRIGGERED_UPDATE, 0);
d62a17ae 1102 }
1103 }
1104}
718e3744 1105
d62a17ae 1106/* RIP routing information. */
1107static void ripng_response_process(struct ripng_packet *packet, int size,
1108 struct sockaddr_in6 *from,
1109 struct interface *ifp, int hoplimit)
1110{
5c84b9a5
RW
1111 struct ripng_interface *ri = ifp->info;
1112 struct ripng *ripng = ri->ripng;
d62a17ae 1113 caddr_t lim;
1114 struct rte *rte;
1115 struct ripng_nexthop nexthop;
1116
1117 /* RFC2080 2.4.2 Response Messages:
1118 The Response must be ignored if it is not from the RIPng port. */
1119 if (ntohs(from->sin6_port) != RIPNG_PORT_DEFAULT) {
1120 zlog_warn("RIPng packet comes from non RIPng port %d from %s",
1121 ntohs(from->sin6_port), inet6_ntoa(from->sin6_addr));
5c84b9a5 1122 ripng_peer_bad_packet(ripng, from);
d62a17ae 1123 return;
1124 }
718e3744 1125
d62a17ae 1126 /* The datagram's IPv6 source address should be checked to see
1127 whether the datagram is from a valid neighbor; the source of the
1128 datagram must be a link-local address. */
1129 if (!IN6_IS_ADDR_LINKLOCAL(&from->sin6_addr)) {
1130 zlog_warn("RIPng packet comes from non link local address %s",
1131 inet6_ntoa(from->sin6_addr));
5c84b9a5 1132 ripng_peer_bad_packet(ripng, from);
d62a17ae 1133 return;
1134 }
a94434b6 1135
d62a17ae 1136 /* It is also worth checking to see whether the response is from one
1137 of the router's own addresses. Interfaces on broadcast networks
1138 may receive copies of their own multicasts immediately. If a
1139 router processes its own output as new input, confusion is likely,
1140 and such datagrams must be ignored. */
1141 if (ripng_lladdr_check(ifp, &from->sin6_addr)) {
1142 zlog_warn(
1143 "RIPng packet comes from my own link local address %s",
1144 inet6_ntoa(from->sin6_addr));
5c84b9a5 1145 ripng_peer_bad_packet(ripng, from);
d62a17ae 1146 return;
1147 }
a94434b6 1148
d62a17ae 1149 /* As an additional check, periodic advertisements must have their
1150 hop counts set to 255, and inbound, multicast packets sent from the
1151 RIPng port (i.e. periodic advertisement or triggered update
1152 packets) must be examined to ensure that the hop count is 255. */
1153 if (hoplimit >= 0 && hoplimit != 255) {
1154 zlog_warn(
1155 "RIPng packet comes with non 255 hop count %d from %s",
1156 hoplimit, inet6_ntoa(from->sin6_addr));
5c84b9a5 1157 ripng_peer_bad_packet(ripng, from);
d62a17ae 1158 return;
1159 }
718e3744 1160
d62a17ae 1161 /* Update RIPng peer. */
5c84b9a5 1162 ripng_peer_update(ripng, from, packet->version);
a94434b6 1163
d62a17ae 1164 /* Reset nexthop. */
1165 memset(&nexthop, 0, sizeof(struct ripng_nexthop));
1166 nexthop.flag = RIPNG_NEXTHOP_UNSPEC;
718e3744 1167
d62a17ae 1168 /* Set RTE pointer. */
1169 rte = packet->rte;
718e3744 1170
d62a17ae 1171 for (lim = ((caddr_t)packet) + size; (caddr_t)rte < lim; rte++) {
1172 /* First of all, we have to check this RTE is next hop RTE or
1173 not. Next hop RTE is completely different with normal RTE so
1174 we need special treatment. */
1175 if (rte->metric == RIPNG_METRIC_NEXTHOP) {
1176 ripng_nexthop_rte(rte, from, &nexthop);
1177 continue;
1178 }
718e3744 1179
d62a17ae 1180 /* RTE information validation. */
1181
1182 /* - is the destination prefix valid (e.g., not a multicast
1183 prefix and not a link-local address) A link-local address
1184 should never be present in an RTE. */
1185 if (IN6_IS_ADDR_MULTICAST(&rte->addr)) {
1186 zlog_warn(
1187 "Destination prefix is a multicast address %s/%d [%d]",
1188 inet6_ntoa(rte->addr), rte->prefixlen,
1189 rte->metric);
5c84b9a5 1190 ripng_peer_bad_route(ripng, from);
d62a17ae 1191 continue;
1192 }
1193 if (IN6_IS_ADDR_LINKLOCAL(&rte->addr)) {
1194 zlog_warn(
1195 "Destination prefix is a link-local address %s/%d [%d]",
1196 inet6_ntoa(rte->addr), rte->prefixlen,
1197 rte->metric);
5c84b9a5 1198 ripng_peer_bad_route(ripng, from);
d62a17ae 1199 continue;
1200 }
1201 if (IN6_IS_ADDR_LOOPBACK(&rte->addr)) {
1202 zlog_warn(
1203 "Destination prefix is a loopback address %s/%d [%d]",
1204 inet6_ntoa(rte->addr), rte->prefixlen,
1205 rte->metric);
5c84b9a5 1206 ripng_peer_bad_route(ripng, from);
d62a17ae 1207 continue;
1208 }
718e3744 1209
d62a17ae 1210 /* - is the prefix length valid (i.e., between 0 and 128,
1211 inclusive) */
1212 if (rte->prefixlen > 128) {
1213 zlog_warn("Invalid prefix length %s/%d from %s%%%s",
1214 inet6_ntoa(rte->addr), rte->prefixlen,
1215 inet6_ntoa(from->sin6_addr), ifp->name);
5c84b9a5 1216 ripng_peer_bad_route(ripng, from);
d62a17ae 1217 continue;
1218 }
718e3744 1219
d62a17ae 1220 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
1221 if (!(rte->metric >= 1 && rte->metric <= 16)) {
1222 zlog_warn("Invalid metric %d from %s%%%s", rte->metric,
1223 inet6_ntoa(from->sin6_addr), ifp->name);
5c84b9a5 1224 ripng_peer_bad_route(ripng, from);
d62a17ae 1225 continue;
1226 }
718e3744 1227
d62a17ae 1228 /* Vincent: XXX Should we compute the direclty reachable nexthop
1229 * for our RIPng network ?
1230 **/
718e3744 1231
d62a17ae 1232 /* Routing table updates. */
1233 ripng_route_process(rte, from, &nexthop, ifp);
1234 }
718e3744 1235}
1236
1237/* Response to request message. */
d62a17ae 1238static void ripng_request_process(struct ripng_packet *packet, int size,
1239 struct sockaddr_in6 *from,
1240 struct interface *ifp)
1241{
5c84b9a5 1242 struct ripng *ripng;
d62a17ae 1243 caddr_t lim;
1244 struct rte *rte;
1245 struct prefix_ipv6 p;
fe08ba7e 1246 struct agg_node *rp;
d62a17ae 1247 struct ripng_info *rinfo;
1248 struct ripng_interface *ri;
1249
1250 /* Does not reponse to the requests on the loopback interfaces */
1251 if (if_is_loopback(ifp))
1252 return;
1253
1254 /* Check RIPng process is enabled on this interface. */
1255 ri = ifp->info;
1256 if (!ri->running)
1257 return;
5c84b9a5 1258 ripng = ri->ripng;
d62a17ae 1259
1260 /* When passive interface is specified, suppress responses */
1261 if (ri->passive)
1262 return;
1263
1264 /* RIPng peer update. */
5c84b9a5 1265 ripng_peer_update(ripng, from, packet->version);
d62a17ae 1266
1267 lim = ((caddr_t)packet) + size;
1268 rte = packet->rte;
1269
1270 /* The Request is processed entry by entry. If there are no
1271 entries, no response is given. */
1272 if (lim == (caddr_t)rte)
1273 return;
1274
1275 /* There is one special case. If there is exactly one entry in the
1276 request, and it has a destination prefix of zero, a prefix length
1277 of zero, and a metric of infinity (i.e., 16), then this is a
1278 request to send the entire routing table. In that case, a call
1279 is made to the output process to send the routing table to the
1280 requesting address/port. */
1281 if (lim == ((caddr_t)(rte + 1)) && IN6_IS_ADDR_UNSPECIFIED(&rte->addr)
1282 && rte->prefixlen == 0 && rte->metric == RIPNG_METRIC_INFINITY) {
1283 /* All route with split horizon */
1284 ripng_output_process(ifp, from, ripng_all_route);
1285 } else {
1286 /* Except for this special case, processing is quite simple.
1287 Examine the list of RTEs in the Request one by one. For each
1288 entry, look up the destination in the router's routing
1289 database and, if there is a route, put that route's metric in
1290 the metric field of the RTE. If there is no explicit route
1291 to the specified destination, put infinity in the metric
1292 field. Once all the entries have been filled in, change the
1293 command from Request to Response and send the datagram back
1294 to the requestor. */
1295 memset(&p, 0, sizeof(struct prefix_ipv6));
1296 p.family = AF_INET6;
1297
1298 for (; ((caddr_t)rte) < lim; rte++) {
1299 p.prefix = rte->addr;
1300 p.prefixlen = rte->prefixlen;
1301 apply_mask_ipv6(&p);
1302
fe08ba7e 1303 rp = agg_node_lookup(ripng->table, (struct prefix *)&p);
d62a17ae 1304
1305 if (rp) {
1306 rinfo = listgetdata(
1307 listhead((struct list *)rp->info));
1308 rte->metric = rinfo->metric;
fe08ba7e 1309 agg_unlock_node(rp);
d62a17ae 1310 } else
1311 rte->metric = RIPNG_METRIC_INFINITY;
1312 }
1313 packet->command = RIPNG_RESPONSE;
1314
1315 ripng_send_packet((caddr_t)packet, size, from, ifp);
1316 }
718e3744 1317}
1318
1319/* First entry point of reading RIPng packet. */
d62a17ae 1320static int ripng_read(struct thread *thread)
1321{
5c84b9a5 1322 struct ripng *ripng = THREAD_ARG(thread);
d62a17ae 1323 int len;
1324 int sock;
1325 struct sockaddr_in6 from;
1326 struct ripng_packet *packet;
1327 ifindex_t ifindex = 0;
1328 struct interface *ifp;
1329 int hoplimit = -1;
1330
1331 /* Check ripng is active and alive. */
1332 assert(ripng != NULL);
1333 assert(ripng->sock >= 0);
1334
1335 /* Fetch thread data and set read pointer to empty for event
1336 managing. `sock' sould be same as ripng->sock. */
1337 sock = THREAD_FD(thread);
1338 ripng->t_read = NULL;
1339
1340 /* Add myself to the next event. */
5c84b9a5 1341 ripng_event(ripng, RIPNG_READ, sock);
d62a17ae 1342
1343 /* Read RIPng packet. */
1344 len = ripng_recv_packet(sock, STREAM_DATA(ripng->ibuf),
1345 STREAM_SIZE(ripng->ibuf), &from, &ifindex,
1346 &hoplimit);
1347 if (len < 0) {
dde7b15b
RW
1348 zlog_warn("RIPng recvfrom failed (VRF %s): %s.",
1349 ripng->vrf_name, safe_strerror(errno));
d62a17ae 1350 return len;
1351 }
718e3744 1352
d62a17ae 1353 /* Check RTE boundary. RTE size (Packet length - RIPng header size
1354 (4)) must be multiple size of one RTE size (20). */
1355 if (((len - 4) % 20) != 0) {
dde7b15b
RW
1356 zlog_warn("RIPng invalid packet size %d from %s (VRF %s)", len,
1357 inet6_ntoa(from.sin6_addr), ripng->vrf_name);
5c84b9a5 1358 ripng_peer_bad_packet(ripng, &from);
d62a17ae 1359 return 0;
1360 }
718e3744 1361
d62a17ae 1362 packet = (struct ripng_packet *)STREAM_DATA(ripng->ibuf);
dde7b15b 1363 ifp = if_lookup_by_index(ifindex, ripng->vrf->vrf_id);
718e3744 1364
d62a17ae 1365 /* RIPng packet received. */
1366 if (IS_RIPNG_DEBUG_EVENT)
dde7b15b
RW
1367 zlog_debug(
1368 "RIPng packet received from %s port %d on %s (VRF %s)",
1369 inet6_ntoa(from.sin6_addr), ntohs(from.sin6_port),
1370 ifp ? ifp->name : "unknown", ripng->vrf_name);
718e3744 1371
d62a17ae 1372 /* Logging before packet checking. */
1373 if (IS_RIPNG_DEBUG_RECV)
1374 ripng_packet_dump(packet, len, "RECV");
718e3744 1375
d62a17ae 1376 /* Packet comes from unknown interface. */
1377 if (ifp == NULL) {
dde7b15b
RW
1378 zlog_warn(
1379 "RIPng packet comes from unknown interface %d (VRF %s)",
1380 ifindex, ripng->vrf_name);
d62a17ae 1381 return 0;
1382 }
718e3744 1383
d62a17ae 1384 /* Packet version mismatch checking. */
1385 if (packet->version != ripng->version) {
1386 zlog_warn(
dde7b15b
RW
1387 "RIPng packet version %d doesn't fit to my version %d (VRF %s)",
1388 packet->version, ripng->version, ripng->vrf_name);
5c84b9a5 1389 ripng_peer_bad_packet(ripng, &from);
d62a17ae 1390 return 0;
1391 }
718e3744 1392
d62a17ae 1393 /* Process RIPng packet. */
1394 switch (packet->command) {
1395 case RIPNG_REQUEST:
1396 ripng_request_process(packet, len, &from, ifp);
1397 break;
1398 case RIPNG_RESPONSE:
1399 ripng_response_process(packet, len, &from, ifp, hoplimit);
1400 break;
1401 default:
dde7b15b
RW
1402 zlog_warn("Invalid RIPng command %d (VRF %s)", packet->command,
1403 ripng->vrf_name);
5c84b9a5 1404 ripng_peer_bad_packet(ripng, &from);
d62a17ae 1405 break;
1406 }
1407 return 0;
718e3744 1408}
1409
1410/* Walk down the RIPng routing table then clear changed flag. */
5c84b9a5 1411static void ripng_clear_changed_flag(struct ripng *ripng)
718e3744 1412{
fe08ba7e 1413 struct agg_node *rp;
d62a17ae 1414 struct ripng_info *rinfo = NULL;
1415 struct list *list = NULL;
1416 struct listnode *listnode = NULL;
718e3744 1417
fe08ba7e 1418 for (rp = agg_route_top(ripng->table); rp; rp = agg_route_next(rp))
d62a17ae 1419 if ((list = rp->info) != NULL)
1420 for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) {
1421 UNSET_FLAG(rinfo->flags, RIPNG_RTF_CHANGED);
1422 /* This flag can be set only on the first entry.
1423 */
1424 break;
1425 }
718e3744 1426}
1427
1428/* Regular update of RIPng route. Send all routing formation to RIPng
1429 enabled interface. */
d62a17ae 1430static int ripng_update(struct thread *t)
718e3744 1431{
5c84b9a5 1432 struct ripng *ripng = THREAD_ARG(t);
d62a17ae 1433 struct interface *ifp;
1434 struct ripng_interface *ri;
718e3744 1435
d62a17ae 1436 /* Clear update timer thread. */
1437 ripng->t_update = NULL;
718e3744 1438
d62a17ae 1439 /* Logging update event. */
1440 if (IS_RIPNG_DEBUG_EVENT)
1441 zlog_debug("RIPng update timer expired!");
718e3744 1442
d62a17ae 1443 /* Supply routes to each interface. */
dde7b15b 1444 FOR_ALL_INTERFACES (ripng->vrf, ifp) {
d62a17ae 1445 ri = ifp->info;
718e3744 1446
d62a17ae 1447 if (if_is_loopback(ifp) || !if_is_up(ifp))
1448 continue;
718e3744 1449
d62a17ae 1450 if (!ri->running)
1451 continue;
718e3744 1452
d62a17ae 1453 /* When passive interface is specified, suppress announce to the
1454 interface. */
1455 if (ri->passive)
1456 continue;
718e3744 1457
1458#if RIPNG_ADVANCED
d62a17ae 1459 if (ri->ri_send == RIPNG_SEND_OFF) {
1460 if (IS_RIPNG_DEBUG_EVENT)
1461 zlog_debug(
1462 "[Event] RIPng send to if %d is suppressed by config",
1463 ifp->ifindex);
1464 continue;
1465 }
718e3744 1466#endif /* RIPNG_ADVANCED */
1467
d62a17ae 1468 ripng_output_process(ifp, NULL, ripng_all_route);
1469 }
718e3744 1470
d62a17ae 1471 /* Triggered updates may be suppressed if a regular update is due by
1472 the time the triggered update would be sent. */
1473 if (ripng->t_triggered_interval) {
1474 thread_cancel(ripng->t_triggered_interval);
1475 ripng->t_triggered_interval = NULL;
1476 }
1477 ripng->trigger = 0;
718e3744 1478
d62a17ae 1479 /* Reset flush event. */
5c84b9a5 1480 ripng_event(ripng, RIPNG_UPDATE_EVENT, 0);
718e3744 1481
d62a17ae 1482 return 0;
718e3744 1483}
1484
1485/* Triggered update interval timer. */
d62a17ae 1486static int ripng_triggered_interval(struct thread *t)
718e3744 1487{
5c84b9a5
RW
1488 struct ripng *ripng = THREAD_ARG(t);
1489
d62a17ae 1490 ripng->t_triggered_interval = NULL;
718e3744 1491
d62a17ae 1492 if (ripng->trigger) {
1493 ripng->trigger = 0;
1494 ripng_triggered_update(t);
1495 }
1496 return 0;
1497}
718e3744 1498
1499/* Execute triggered update. */
d62a17ae 1500int ripng_triggered_update(struct thread *t)
718e3744 1501{
5c84b9a5 1502 struct ripng *ripng = THREAD_ARG(t);
d62a17ae 1503 struct interface *ifp;
1504 struct ripng_interface *ri;
1505 int interval;
718e3744 1506
d62a17ae 1507 ripng->t_triggered_update = NULL;
718e3744 1508
d62a17ae 1509 /* Cancel interval timer. */
1510 if (ripng->t_triggered_interval) {
1511 thread_cancel(ripng->t_triggered_interval);
1512 ripng->t_triggered_interval = NULL;
1513 }
1514 ripng->trigger = 0;
718e3744 1515
d62a17ae 1516 /* Logging triggered update. */
1517 if (IS_RIPNG_DEBUG_EVENT)
1518 zlog_debug("RIPng triggered update!");
718e3744 1519
d62a17ae 1520 /* Split Horizon processing is done when generating triggered
1521 updates as well as normal updates (see section 2.6). */
dde7b15b 1522 FOR_ALL_INTERFACES (ripng->vrf, ifp) {
d62a17ae 1523 ri = ifp->info;
718e3744 1524
d62a17ae 1525 if (if_is_loopback(ifp) || !if_is_up(ifp))
1526 continue;
718e3744 1527
d62a17ae 1528 if (!ri->running)
1529 continue;
718e3744 1530
d62a17ae 1531 /* When passive interface is specified, suppress announce to the
1532 interface. */
1533 if (ri->passive)
1534 continue;
718e3744 1535
d62a17ae 1536 ripng_output_process(ifp, NULL, ripng_changed_route);
1537 }
718e3744 1538
d62a17ae 1539 /* Once all of the triggered updates have been generated, the route
1540 change flags should be cleared. */
5c84b9a5 1541 ripng_clear_changed_flag(ripng);
718e3744 1542
d62a17ae 1543 /* After a triggered update is sent, a timer should be set for a
1544 random interval between 1 and 5 seconds. If other changes that
1545 would trigger updates occur before the timer expires, a single
1546 update is triggered when the timer expires. */
1547 interval = (random() % 5) + 1;
718e3744 1548
d62a17ae 1549 ripng->t_triggered_interval = NULL;
5c84b9a5 1550 thread_add_timer(master, ripng_triggered_interval, ripng, interval,
d62a17ae 1551 &ripng->t_triggered_interval);
718e3744 1552
d62a17ae 1553 return 0;
718e3744 1554}
1555
1556/* Write routing table entry to the stream and return next index of
1557 the routing table entry in the stream. */
d62a17ae 1558int ripng_write_rte(int num, struct stream *s, struct prefix_ipv6 *p,
d7c0a89a 1559 struct in6_addr *nexthop, uint16_t tag, uint8_t metric)
d62a17ae 1560{
1561 /* RIPng packet header. */
1562 if (num == 0) {
1563 stream_putc(s, RIPNG_RESPONSE);
1564 stream_putc(s, RIPNG_V1);
1565 stream_putw(s, 0);
1566 }
718e3744 1567
d62a17ae 1568 /* Write routing table entry. */
b575a12c
A
1569 if (!nexthop) {
1570 assert(p);
d7c0a89a 1571 stream_write(s, (uint8_t *)&p->prefix, sizeof(struct in6_addr));
b575a12c 1572 } else
d7c0a89a 1573 stream_write(s, (uint8_t *)nexthop, sizeof(struct in6_addr));
d62a17ae 1574 stream_putw(s, tag);
1575 if (p)
1576 stream_putc(s, p->prefixlen);
1577 else
1578 stream_putc(s, 0);
1579 stream_putc(s, metric);
718e3744 1580
d62a17ae 1581 return ++num;
718e3744 1582}
1583
1584/* Send RESPONSE message to specified destination. */
d62a17ae 1585void ripng_output_process(struct interface *ifp, struct sockaddr_in6 *to,
1586 int route_type)
1587{
5c84b9a5 1588 struct ripng *ripng;
d62a17ae 1589 int ret;
fe08ba7e 1590 struct agg_node *rp;
d62a17ae 1591 struct ripng_info *rinfo;
1592 struct ripng_interface *ri;
1593 struct ripng_aggregate *aggregate;
1594 struct prefix_ipv6 *p;
1595 struct list *ripng_rte_list;
1596 struct list *list = NULL;
1597 struct listnode *listnode = NULL;
1598
1599 if (IS_RIPNG_DEBUG_EVENT) {
1600 if (to)
1601 zlog_debug("RIPng update routes to neighbor %s",
1602 inet6_ntoa(to->sin6_addr));
1603 else
1604 zlog_debug("RIPng update routes on interface %s",
1605 ifp->name);
1606 }
a94434b6 1607
5c84b9a5 1608 /* Get RIPng interface and instance. */
d62a17ae 1609 ri = ifp->info;
5c84b9a5 1610 ripng = ri->ripng;
d62a17ae 1611
1612 ripng_rte_list = ripng_rte_new();
1613
fe08ba7e 1614 for (rp = agg_route_top(ripng->table); rp; rp = agg_route_next(rp)) {
d62a17ae 1615 if ((list = rp->info) != NULL
1616 && (rinfo = listgetdata(listhead(list))) != NULL
1617 && rinfo->suppress == 0) {
1618 /* If no route-map are applied, the RTE will be these
1619 * following
0437e105 1620 * information.
d62a17ae 1621 */
1622 p = (struct prefix_ipv6 *)&rp->p;
1623 rinfo->metric_out = rinfo->metric;
1624 rinfo->tag_out = rinfo->tag;
1625 memset(&rinfo->nexthop_out, 0,
1626 sizeof(rinfo->nexthop_out));
1627 /* In order to avoid some local loops,
1628 * if the RIPng route has a nexthop via this interface,
1629 * keep the nexthop,
1630 * otherwise set it to 0. The nexthop should not be
1631 * propagated
1632 * beyond the local broadcast/multicast area in order
1633 * to avoid an IGP multi-level recursive look-up.
1634 */
1635 if (rinfo->ifindex == ifp->ifindex)
1636 rinfo->nexthop_out = rinfo->nexthop;
1637
1638 /* Apply output filters. */
1639 ret = ripng_filter(RIPNG_FILTER_OUT, p, ri);
1640 if (ret < 0)
1641 continue;
1642
1643 /* Changed route only output. */
1644 if (route_type == ripng_changed_route
1645 && (!(rinfo->flags & RIPNG_RTF_CHANGED)))
1646 continue;
1647
1648 /* Split horizon. */
1649 if (ri->split_horizon == RIPNG_SPLIT_HORIZON) {
1650 /* We perform split horizon for RIPng routes. */
1651 int suppress = 0;
1652 struct ripng_info *tmp_rinfo = NULL;
1653
1654 for (ALL_LIST_ELEMENTS_RO(list, listnode,
1655 tmp_rinfo))
1656 if (tmp_rinfo->type == ZEBRA_ROUTE_RIPNG
1657 && tmp_rinfo->ifindex
1658 == ifp->ifindex) {
1659 suppress = 1;
1660 break;
1661 }
1662 if (suppress)
1663 continue;
1664 }
1665
1666 /* Preparation for route-map. */
1667 rinfo->metric_set = 0;
1668 /* nexthop_out,
1669 * metric_out
1670 * and tag_out are already initialized.
1671 */
1672
1673 /* Interface route-map */
1674 if (ri->routemap[RIPNG_FILTER_OUT]) {
d62a17ae 1675 ret = route_map_apply(
1676 ri->routemap[RIPNG_FILTER_OUT],
1677 (struct prefix *)p, RMAP_RIPNG, rinfo);
1678
1679 if (ret == RMAP_DENYMATCH) {
1680 if (IS_RIPNG_DEBUG_PACKET)
1681 zlog_debug(
1682 "RIPng %s/%d is filtered by route-map out",
1683 inet6_ntoa(p->prefix),
1684 p->prefixlen);
1685 continue;
1686 }
1687 }
1688
1689 /* Redistribute route-map. */
f9120f71
RW
1690 if (ripng->redist[rinfo->type].route_map.name) {
1691 ret = route_map_apply(ripng->redist[rinfo->type]
1692 .route_map.map,
1693 (struct prefix *)p,
1694 RMAP_RIPNG, rinfo);
d62a17ae 1695
1696 if (ret == RMAP_DENYMATCH) {
1697 if (IS_RIPNG_DEBUG_PACKET)
1698 zlog_debug(
1699 "RIPng %s/%d is filtered by route-map",
1700 inet6_ntoa(p->prefix),
1701 p->prefixlen);
1702 continue;
1703 }
1704 }
1705
1706 /* When the route-map does not set metric. */
1707 if (!rinfo->metric_set) {
1708 /* If the redistribute metric is set. */
f9120f71 1709 if (ripng->redist[rinfo->type].metric_config
d62a17ae 1710 && rinfo->metric != RIPNG_METRIC_INFINITY) {
1711 rinfo->metric_out =
f9120f71 1712 ripng->redist[rinfo->type]
d62a17ae 1713 .metric;
1714 } else {
1715 /* If the route is not connected or
1716 localy generated
1717 one, use default-metric value */
1718 if (rinfo->type != ZEBRA_ROUTE_RIPNG
1719 && rinfo->type
1720 != ZEBRA_ROUTE_CONNECT
1721 && rinfo->metric
1722 != RIPNG_METRIC_INFINITY)
1723 rinfo->metric_out =
1724 ripng->default_metric;
1725 }
1726 }
1727
1728 /* Apply offset-list */
1729 if (rinfo->metric_out != RIPNG_METRIC_INFINITY)
5c84b9a5 1730 ripng_offset_list_apply_out(ripng, p, ifp,
d62a17ae 1731 &rinfo->metric_out);
1732
1733 if (rinfo->metric_out > RIPNG_METRIC_INFINITY)
1734 rinfo->metric_out = RIPNG_METRIC_INFINITY;
1735
1736 /* Perform split-horizon with poisoned reverse
1737 * for RIPng routes.
1738 **/
1739 if (ri->split_horizon
1740 == RIPNG_SPLIT_HORIZON_POISONED_REVERSE) {
1741 struct ripng_info *tmp_rinfo = NULL;
1742
1743 for (ALL_LIST_ELEMENTS_RO(list, listnode,
1744 tmp_rinfo))
1745 if ((tmp_rinfo->type
1746 == ZEBRA_ROUTE_RIPNG)
1747 && tmp_rinfo->ifindex
1748 == ifp->ifindex)
1749 rinfo->metric_out =
1750 RIPNG_METRIC_INFINITY;
1751 }
1752
1753 /* Add RTE to the list */
1754 ripng_rte_add(ripng_rte_list, p, rinfo, NULL);
718e3744 1755 }
a94434b6 1756
d62a17ae 1757 /* Process the aggregated RTE entry */
1758 if ((aggregate = rp->aggregate) != NULL && aggregate->count > 0
1759 && aggregate->suppress == 0) {
1760 /* If no route-map are applied, the RTE will be these
1761 * following
0437e105 1762 * information.
d62a17ae 1763 */
1764 p = (struct prefix_ipv6 *)&rp->p;
1765 aggregate->metric_set = 0;
1766 aggregate->metric_out = aggregate->metric;
1767 aggregate->tag_out = aggregate->tag;
1768 memset(&aggregate->nexthop_out, 0,
1769 sizeof(aggregate->nexthop_out));
1770
1771 /* Apply output filters.*/
1772 ret = ripng_filter(RIPNG_FILTER_OUT, p, ri);
1773 if (ret < 0)
1774 continue;
1775
1776 /* Interface route-map */
1777 if (ri->routemap[RIPNG_FILTER_OUT]) {
d62a17ae 1778 struct ripng_info newinfo;
1779
1780 /* let's cast the aggregate structure to
1781 * ripng_info */
1782 memset(&newinfo, 0, sizeof(struct ripng_info));
1783 /* the nexthop is :: */
1784 newinfo.metric = aggregate->metric;
1785 newinfo.metric_out = aggregate->metric_out;
1786 newinfo.tag = aggregate->tag;
1787 newinfo.tag_out = aggregate->tag_out;
1788
1789 ret = route_map_apply(
1790 ri->routemap[RIPNG_FILTER_OUT],
1791 (struct prefix *)p, RMAP_RIPNG,
1792 &newinfo);
1793
1794 if (ret == RMAP_DENYMATCH) {
1795 if (IS_RIPNG_DEBUG_PACKET)
1796 zlog_debug(
1797 "RIPng %s/%d is filtered by route-map out",
1798 inet6_ntoa(p->prefix),
1799 p->prefixlen);
1800 continue;
1801 }
1802
1803 aggregate->metric_out = newinfo.metric_out;
1804 aggregate->tag_out = newinfo.tag_out;
1805 if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop_out))
1806 aggregate->nexthop_out =
1807 newinfo.nexthop_out;
1808 }
1809
1810 /* There is no redistribute routemap for the aggregated
1811 * RTE */
1812
1813 /* Changed route only output. */
1814 /* XXX, vincent, in order to increase time convergence,
1815 * it should be announced if a child has changed.
1816 */
1817 if (route_type == ripng_changed_route)
1818 continue;
1819
1820 /* Apply offset-list */
1821 if (aggregate->metric_out != RIPNG_METRIC_INFINITY)
1822 ripng_offset_list_apply_out(
5c84b9a5 1823 ripng, p, ifp, &aggregate->metric_out);
d62a17ae 1824
1825 if (aggregate->metric_out > RIPNG_METRIC_INFINITY)
1826 aggregate->metric_out = RIPNG_METRIC_INFINITY;
1827
1828 /* Add RTE to the list */
1829 ripng_rte_add(ripng_rte_list, p, NULL, aggregate);
1830 }
718e3744 1831 }
1832
d62a17ae 1833 /* Flush the list */
1834 ripng_rte_send(ripng_rte_list, ifp, to);
1835 ripng_rte_free(ripng_rte_list);
718e3744 1836}
1837
5c84b9a5
RW
1838struct ripng *ripng_lookup_by_vrf_id(vrf_id_t vrf_id)
1839{
1840 struct vrf *vrf;
1841
1842 vrf = vrf_lookup_by_id(vrf_id);
1843 if (!vrf)
1844 return NULL;
1845
1846 return vrf->info;
1847}
1848
dde7b15b
RW
1849struct ripng *ripng_lookup_by_vrf_name(const char *vrf_name)
1850{
1851 struct ripng ripng;
1852
1853 ripng.vrf_name = (char *)vrf_name;
1854
1855 return RB_FIND(ripng_instance_head, &ripng_instances, &ripng);
1856}
1857
718e3744 1858/* Create new RIPng instance and set it to global variable. */
dde7b15b 1859struct ripng *ripng_create(const char *vrf_name, struct vrf *vrf, int socket)
718e3744 1860{
5c84b9a5 1861 struct ripng *ripng;
718e3744 1862
d62a17ae 1863 /* Allocaste RIPng instance. */
1864 ripng = XCALLOC(MTYPE_RIPNG, sizeof(struct ripng));
dde7b15b 1865 ripng->vrf_name = XSTRDUP(MTYPE_RIPNG_VRF_NAME, vrf_name);
718e3744 1866
d62a17ae 1867 /* Default version and timer values. */
1868 ripng->version = RIPNG_V1;
9a12e9e5
RW
1869 ripng->update_time = yang_get_default_uint32(
1870 "%s/timers/update-interval", RIPNG_INSTANCE);
1871 ripng->timeout_time = yang_get_default_uint32(
1872 "%s/timers/holddown-interval", RIPNG_INSTANCE);
1873 ripng->garbage_time = yang_get_default_uint32(
1874 "%s/timers/flush-interval", RIPNG_INSTANCE);
1875 ripng->default_metric =
1876 yang_get_default_uint8("%s/default-metric", RIPNG_INSTANCE);
1877 ripng->ecmp = yang_get_default_bool("%s/allow-ecmp", RIPNG_INSTANCE);
d62a17ae 1878
1879 /* Make buffer. */
1880 ripng->ibuf = stream_new(RIPNG_MAX_PACKET_SIZE * 5);
1881 ripng->obuf = stream_new(RIPNG_MAX_PACKET_SIZE);
1882
b0ba762f 1883 /* Initialize RIPng data structures. */
fe08ba7e 1884 ripng->table = agg_table_init();
5c84b9a5 1885 agg_set_table_info(ripng->table, ripng);
ecece94c
RW
1886 ripng->peer_list = list_new();
1887 ripng->peer_list->cmp = (int (*)(void *, void *))ripng_peer_list_cmp;
56bf1cb2 1888 ripng->peer_list->del = ripng_peer_list_del;
b0ba762f 1889 ripng->enable_if = vector_init(1);
29b94d58 1890 ripng->enable_network = agg_table_init();
0c32404f 1891 ripng->passive_interface = vector_init(1);
26c6be93
RW
1892 ripng->offset_list_master = list_new();
1893 ripng->offset_list_master->cmp =
1894 (int (*)(void *, void *))offset_list_cmp;
1895 ripng->offset_list_master->del =
6c4c3561 1896 (void (*)(void *))ripng_offset_list_free;
dde7b15b 1897 ripng->distribute_ctx = distribute_list_ctx_create(vrf);
03a38493
PG
1898 distribute_list_add_hook(ripng->distribute_ctx,
1899 ripng_distribute_update);
1900 distribute_list_delete_hook(ripng->distribute_ctx,
1901 ripng_distribute_update);
718e3744 1902
4b23867c 1903 /* if rmap install. */
8f88441d 1904 ripng->if_rmap_ctx = if_rmap_ctx_create(vrf_name);
4b23867c
PG
1905 if_rmap_hook_add(ripng->if_rmap_ctx, ripng_if_rmap_update);
1906 if_rmap_hook_delete(ripng->if_rmap_ctx, ripng_if_rmap_update);
5c84b9a5 1907
dde7b15b
RW
1908 /* Enable the routing instance if possible. */
1909 if (vrf && vrf_is_enabled(vrf))
1910 ripng_instance_enable(ripng, vrf, socket);
1911 else {
1912 ripng->vrf = NULL;
1913 ripng->sock = -1;
5c84b9a5
RW
1914 }
1915
dde7b15b
RW
1916 RB_INSERT(ripng_instance_head, &ripng_instances, ripng);
1917
5c84b9a5 1918 return ripng;
718e3744 1919}
1920
a94434b6 1921/* Send RIPng request to the interface. */
d62a17ae 1922int ripng_request(struct interface *ifp)
718e3744 1923{
d62a17ae 1924 struct rte *rte;
1925 struct ripng_packet ripng_packet;
718e3744 1926
d62a17ae 1927 /* In default ripd doesn't send RIP_REQUEST to the loopback interface.
1928 */
1929 if (if_is_loopback(ifp))
1930 return 0;
a94434b6 1931
d62a17ae 1932 /* If interface is down, don't send RIP packet. */
1933 if (!if_is_up(ifp))
1934 return 0;
a94434b6 1935
d62a17ae 1936 if (IS_RIPNG_DEBUG_EVENT)
1937 zlog_debug("RIPng send request to %s", ifp->name);
718e3744 1938
d62a17ae 1939 memset(&ripng_packet, 0, sizeof(ripng_packet));
1940 ripng_packet.command = RIPNG_REQUEST;
1941 ripng_packet.version = RIPNG_V1;
1942 rte = ripng_packet.rte;
1943 rte->metric = RIPNG_METRIC_INFINITY;
718e3744 1944
d62a17ae 1945 return ripng_send_packet((caddr_t)&ripng_packet, sizeof(ripng_packet),
1946 NULL, ifp);
718e3744 1947}
1948
6b0655a2 1949
d62a17ae 1950static int ripng_update_jitter(int time)
718e3744 1951{
d62a17ae 1952 return ((random() % (time + 1)) - (time / 2));
718e3744 1953}
1954
5c84b9a5 1955void ripng_event(struct ripng *ripng, enum ripng_event event, int sock)
718e3744 1956{
d62a17ae 1957 int jitter = 0;
718e3744 1958
d62a17ae 1959 switch (event) {
1960 case RIPNG_READ:
5c84b9a5
RW
1961 thread_add_read(master, ripng_read, ripng, sock,
1962 &ripng->t_read);
d62a17ae 1963 break;
1964 case RIPNG_UPDATE_EVENT:
1965 if (ripng->t_update) {
1966 thread_cancel(ripng->t_update);
1967 ripng->t_update = NULL;
1968 }
1969 /* Update timer jitter. */
1970 jitter = ripng_update_jitter(ripng->update_time);
1971
1972 ripng->t_update = NULL;
5c84b9a5 1973 thread_add_timer(master, ripng_update, ripng,
d62a17ae 1974 sock ? 2 : ripng->update_time + jitter,
1975 &ripng->t_update);
1976 break;
1977 case RIPNG_TRIGGERED_UPDATE:
1978 if (ripng->t_triggered_interval)
1979 ripng->trigger = 1;
1980 else
5c84b9a5 1981 thread_add_event(master, ripng_triggered_update, ripng,
d62a17ae 1982 0, &ripng->t_triggered_update);
1983 break;
1984 default:
1985 break;
1986 }
718e3744 1987}
6b0655a2 1988
718e3744 1989
718e3744 1990/* Print out routes update time. */
d62a17ae 1991static void ripng_vty_out_uptime(struct vty *vty, struct ripng_info *rinfo)
718e3744 1992{
d62a17ae 1993 time_t clock;
1994 struct tm *tm;
718e3744 1995#define TIME_BUF 25
d62a17ae 1996 char timebuf[TIME_BUF];
1997 struct thread *thread;
1998
1999 if ((thread = rinfo->t_timeout) != NULL) {
2000 clock = thread_timer_remain_second(thread);
2001 tm = gmtime(&clock);
2002 strftime(timebuf, TIME_BUF, "%M:%S", tm);
2003 vty_out(vty, "%5s", timebuf);
2004 } else if ((thread = rinfo->t_garbage_collect) != NULL) {
2005 clock = thread_timer_remain_second(thread);
2006 tm = gmtime(&clock);
2007 strftime(timebuf, TIME_BUF, "%M:%S", tm);
2008 vty_out(vty, "%5s", timebuf);
2009 }
718e3744 2010}
2011
d62a17ae 2012static char *ripng_route_subtype_print(struct ripng_info *rinfo)
2013{
2014 static char str[3];
2015 memset(str, 0, 3);
2016
2017 if (rinfo->suppress)
9736ba9e 2018 strlcat(str, "S", sizeof(str));
d62a17ae 2019
2020 switch (rinfo->sub_type) {
2021 case RIPNG_ROUTE_RTE:
9736ba9e 2022 strlcat(str, "n", sizeof(str));
d62a17ae 2023 break;
2024 case RIPNG_ROUTE_STATIC:
9736ba9e 2025 strlcat(str, "s", sizeof(str));
d62a17ae 2026 break;
2027 case RIPNG_ROUTE_DEFAULT:
9736ba9e 2028 strlcat(str, "d", sizeof(str));
d62a17ae 2029 break;
2030 case RIPNG_ROUTE_REDISTRIBUTE:
9736ba9e 2031 strlcat(str, "r", sizeof(str));
d62a17ae 2032 break;
2033 case RIPNG_ROUTE_INTERFACE:
9736ba9e 2034 strlcat(str, "i", sizeof(str));
d62a17ae 2035 break;
2036 default:
9736ba9e 2037 strlcat(str, "?", sizeof(str));
d62a17ae 2038 break;
2039 }
a94434b6 2040
d62a17ae 2041 return str;
a94434b6 2042}
2043
718e3744 2044DEFUN (show_ipv6_ripng,
2045 show_ipv6_ripng_cmd,
dde7b15b 2046 "show ipv6 ripng [vrf NAME]",
718e3744 2047 SHOW_STR
8d0f15fd 2048 IPV6_STR
dde7b15b
RW
2049 "Show RIPng routes\n"
2050 VRF_CMD_HELP_STR)
718e3744 2051{
5c84b9a5 2052 struct ripng *ripng;
fe08ba7e 2053 struct agg_node *rp;
d62a17ae 2054 struct ripng_info *rinfo;
2055 struct ripng_aggregate *aggregate;
2056 struct prefix_ipv6 *p;
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) {
2088 p = (struct prefix_ipv6 *)&rp->p;
718e3744 2089
2090#ifdef DEBUG
d62a17ae 2091 vty_out(vty, "R(a) %d/%d %s/%d ", aggregate->count,
2092 aggregate->suppress, inet6_ntoa(p->prefix),
2093 p->prefixlen);
718e3744 2094#else
d62a17ae 2095 vty_out(vty, "R(a) %s/%d ", inet6_ntoa(p->prefix),
2096 p->prefixlen);
718e3744 2097#endif /* DEBUG */
d62a17ae 2098 vty_out(vty, "\n");
2099 vty_out(vty, "%*s", 18, " ");
718e3744 2100
d62a17ae 2101 vty_out(vty, "%*s", 28, " ");
2102 vty_out(vty, "self %2d %3" ROUTE_TAG_PRI "\n",
2103 aggregate->metric, (route_tag_t)aggregate->tag);
2104 }
718e3744 2105
d62a17ae 2106 if ((list = rp->info) != NULL)
2107 for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) {
2108 p = (struct prefix_ipv6 *)&rp->p;
718e3744 2109
2110#ifdef DEBUG
d62a17ae 2111 vty_out(vty, "%c(%s) 0/%d %s/%d ",
2112 zebra_route_char(rinfo->type),
2113 ripng_route_subtype_print(rinfo),
2114 rinfo->suppress, inet6_ntoa(p->prefix),
2115 p->prefixlen);
718e3744 2116#else
d62a17ae 2117 vty_out(vty, "%c(%s) %s/%d ",
2118 zebra_route_char(rinfo->type),
2119 ripng_route_subtype_print(rinfo),
2120 inet6_ntoa(p->prefix), p->prefixlen);
718e3744 2121#endif /* DEBUG */
d62a17ae 2122 vty_out(vty, "\n");
2123 vty_out(vty, "%*s", 18, " ");
2124 len = vty_out(vty, "%s",
2125 inet6_ntoa(rinfo->nexthop));
2126
2127 len = 28 - len;
2128 if (len > 0)
51f7fe84 2129 vty_out(vty, "%*s", len, " ");
d62a17ae 2130
2131 /* from */
2132 if ((rinfo->type == ZEBRA_ROUTE_RIPNG)
2133 && (rinfo->sub_type == RIPNG_ROUTE_RTE)) {
2134 len = vty_out(
2135 vty, "%s",
dde7b15b
RW
2136 ifindex2ifname(
2137 rinfo->ifindex,
2138 ripng->vrf->vrf_id));
d62a17ae 2139 } else if (rinfo->metric
2140 == RIPNG_METRIC_INFINITY) {
2141 len = vty_out(vty, "kill");
2142 } else
2143 len = vty_out(vty, "self");
2144
2145 len = 9 - len;
2146 if (len > 0)
2147 vty_out(vty, "%*s", len, " ");
2148
2149 vty_out(vty, " %2d %3" ROUTE_TAG_PRI " ",
2150 rinfo->metric, (route_tag_t)rinfo->tag);
2151
2152 /* time */
2153 if ((rinfo->type == ZEBRA_ROUTE_RIPNG)
2154 && (rinfo->sub_type == RIPNG_ROUTE_RTE)) {
2155 /* RTE from remote RIP routers */
2156 ripng_vty_out_uptime(vty, rinfo);
2157 } else if (rinfo->metric
2158 == RIPNG_METRIC_INFINITY) {
2159 /* poisonous reversed routes (gc) */
2160 ripng_vty_out_uptime(vty, rinfo);
2161 }
2162
2163 vty_out(vty, "\n");
2164 }
718e3744 2165 }
718e3744 2166
d62a17ae 2167 return CMD_SUCCESS;
718e3744 2168}
2169
a94434b6 2170DEFUN (show_ipv6_ripng_status,
2171 show_ipv6_ripng_status_cmd,
dde7b15b 2172 "show ipv6 ripng [vrf NAME] status",
a94434b6 2173 SHOW_STR
8d0f15fd 2174 IPV6_STR
a94434b6 2175 "Show RIPng routes\n"
dde7b15b 2176 VRF_CMD_HELP_STR
a94434b6 2177 "IPv6 routing protocol process parameters and statistics\n")
2178{
5c84b9a5 2179 struct ripng *ripng;
d62a17ae 2180 struct interface *ifp;
dde7b15b
RW
2181 const char *vrf_name;
2182 int idx = 0;
a94434b6 2183
dde7b15b
RW
2184 if (argv_find(argv, argc, "vrf", &idx))
2185 vrf_name = argv[idx + 1]->arg;
2186 else
2187 vrf_name = VRF_DEFAULT_NAME;
2188
2189 ripng = ripng_lookup_by_vrf_name(vrf_name);
2190 if (!ripng) {
2191 vty_out(vty, "%% RIPng instance not found\n");
2192 return CMD_SUCCESS;
2193 }
2194 if (!ripng->enabled) {
2195 vty_out(vty, "%% RIPng instance is disabled\n");
d62a17ae 2196 return CMD_SUCCESS;
dde7b15b 2197 }
a94434b6 2198
d62a17ae 2199 vty_out(vty, "Routing Protocol is \"RIPng\"\n");
f8981ec5 2200 vty_out(vty, " Sending updates every %u seconds with +/-50%%,",
d62a17ae 2201 ripng->update_time);
2202 vty_out(vty, " next due in %lu seconds\n",
2203 thread_timer_remain_second(ripng->t_update));
f8981ec5
RW
2204 vty_out(vty, " Timeout after %u seconds,", ripng->timeout_time);
2205 vty_out(vty, " garbage collect after %u seconds\n",
d62a17ae 2206 ripng->garbage_time);
a94434b6 2207
d62a17ae 2208 /* Filtering status show. */
03a38493 2209 config_show_distribute(vty, ripng->distribute_ctx);
a94434b6 2210
d62a17ae 2211 /* Default metric information. */
2212 vty_out(vty, " Default redistribution metric is %d\n",
2213 ripng->default_metric);
a94434b6 2214
d62a17ae 2215 /* Redistribute information. */
2216 vty_out(vty, " Redistributing:");
5c84b9a5 2217 ripng_redistribute_write(vty, ripng);
d62a17ae 2218 vty_out(vty, "\n");
a94434b6 2219
d62a17ae 2220 vty_out(vty, " Default version control: send version %d,",
2221 ripng->version);
2222 vty_out(vty, " receive version %d \n", ripng->version);
a94434b6 2223
d62a17ae 2224 vty_out(vty, " Interface Send Recv\n");
a94434b6 2225
dde7b15b 2226 FOR_ALL_INTERFACES (ripng->vrf, ifp) {
d62a17ae 2227 struct ripng_interface *ri;
2228
2229 ri = ifp->info;
a94434b6 2230
d62a17ae 2231 if (ri->enable_network || ri->enable_interface) {
a94434b6 2232
d62a17ae 2233 vty_out(vty, " %-17s%-3d %-3d\n", ifp->name,
2234 ripng->version, ripng->version);
2235 }
a94434b6 2236 }
a94434b6 2237
d62a17ae 2238 vty_out(vty, " Routing for Networks:\n");
5c84b9a5 2239 ripng_network_write(vty, ripng);
a94434b6 2240
d62a17ae 2241 vty_out(vty, " Routing Information Sources:\n");
2242 vty_out(vty,
2243 " Gateway BadPackets BadRoutes Distance Last Update\n");
5c84b9a5 2244 ripng_peer_display(vty, ripng);
a94434b6 2245
d62a17ae 2246 return CMD_SUCCESS;
a94434b6 2247}
2248
718e3744 2249#if 0
2250/* RIPng update timer setup. */
2251DEFUN (ripng_update_timer,
2252 ripng_update_timer_cmd,
2253 "update-timer SECOND",
2254 "Set RIPng update timer in seconds\n"
2255 "Seconds\n")
2256{
2257 unsigned long update;
2258 char *endptr = NULL;
2259
2260 update = strtoul (argv[0], &endptr, 10);
2261 if (update == ULONG_MAX || *endptr != '\0')
2262 {
26a429fe 2263 vty_out (vty, "update timer value error\n");
f1a05de9 2264 return CMD_WARNING_CONFIG_FAILED;
718e3744 2265 }
2266
2267 ripng->update_time = update;
2268
2269 ripng_event (RIPNG_UPDATE_EVENT, 0);
2270 return CMD_SUCCESS;
2271}
2272
2273DEFUN (no_ripng_update_timer,
2274 no_ripng_update_timer_cmd,
2275 "no update-timer SECOND",
2276 NO_STR
2277 "Unset RIPng update timer in seconds\n"
2278 "Seconds\n")
2279{
2280 ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT;
2281 ripng_event (RIPNG_UPDATE_EVENT, 0);
2282 return CMD_SUCCESS;
2283}
2284
2285/* RIPng timeout timer setup. */
2286DEFUN (ripng_timeout_timer,
2287 ripng_timeout_timer_cmd,
2288 "timeout-timer SECOND",
2289 "Set RIPng timeout timer in seconds\n"
2290 "Seconds\n")
2291{
2292 unsigned long timeout;
2293 char *endptr = NULL;
2294
2295 timeout = strtoul (argv[0], &endptr, 10);
2296 if (timeout == ULONG_MAX || *endptr != '\0')
2297 {
26a429fe 2298 vty_out (vty, "timeout timer value error\n");
f1a05de9 2299 return CMD_WARNING_CONFIG_FAILED;
718e3744 2300 }
2301
2302 ripng->timeout_time = timeout;
2303
2304 return CMD_SUCCESS;
2305}
2306
2307DEFUN (no_ripng_timeout_timer,
2308 no_ripng_timeout_timer_cmd,
2309 "no timeout-timer SECOND",
2310 NO_STR
2311 "Unset RIPng timeout timer in seconds\n"
2312 "Seconds\n")
2313{
2314 ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT;
2315 return CMD_SUCCESS;
2316}
2317
2318/* RIPng garbage timer setup. */
2319DEFUN (ripng_garbage_timer,
2320 ripng_garbage_timer_cmd,
2321 "garbage-timer SECOND",
2322 "Set RIPng garbage timer in seconds\n"
2323 "Seconds\n")
2324{
2325 unsigned long garbage;
2326 char *endptr = NULL;
2327
2328 garbage = strtoul (argv[0], &endptr, 10);
2329 if (garbage == ULONG_MAX || *endptr != '\0')
2330 {
26a429fe 2331 vty_out (vty, "garbage timer value error\n");
f1a05de9 2332 return CMD_WARNING_CONFIG_FAILED;
718e3744 2333 }
2334
2335 ripng->garbage_time = garbage;
2336
2337 return CMD_SUCCESS;
2338}
2339
2340DEFUN (no_ripng_garbage_timer,
2341 no_ripng_garbage_timer_cmd,
2342 "no garbage-timer SECOND",
2343 NO_STR
2344 "Unset RIPng garbage timer in seconds\n"
2345 "Seconds\n")
2346{
2347 ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT;
2348 return CMD_SUCCESS;
2349}
2350#endif /* 0 */
2351
d7d73ffc 2352#if 0
dd4f9f99
DW
2353DEFUN (show_ipv6_protocols,
2354 show_ipv6_protocols_cmd,
718e3744 2355 "show ipv6 protocols",
2356 SHOW_STR
8d0f15fd 2357 IPV6_STR
d911a12a 2358 "Routing protocol information\n")
718e3744 2359{
2360 if (! ripng)
2361 return CMD_SUCCESS;
2362
26a429fe 2363 vty_out (vty, "Routing Protocol is \"ripng\"\n");
c258527b 2364
55f70b67
DL
2365 vty_out (vty, "Sending updates every %ld seconds, next due in %d seconds\n",
2366 ripng->update_time, 0);
718e3744 2367
55f70b67 2368 vty_out (vty, "Timerout after %ld seconds, garbage correct %ld\n",
718e3744 2369 ripng->timeout_time,
55f70b67 2370 ripng->garbage_time);
718e3744 2371
2372 vty_out (vty, "Outgoing update filter list for all interfaces is not set");
2373 vty_out (vty, "Incoming update filter list for all interfaces is not set");
2374
2375 return CMD_SUCCESS;
2376}
d7d73ffc 2377#endif
718e3744 2378
fac76f9c 2379/* Update ECMP routes to zebra when ECMP is disabled. */
5c84b9a5 2380void ripng_ecmp_disable(struct ripng *ripng)
d62a17ae 2381{
fe08ba7e 2382 struct agg_node *rp;
d62a17ae 2383 struct ripng_info *rinfo, *tmp_rinfo;
2384 struct list *list;
2385 struct listnode *node, *nextnode;
2386
2387 if (!ripng)
2388 return;
2389
fe08ba7e 2390 for (rp = agg_route_top(ripng->table); rp; rp = agg_route_next(rp))
d62a17ae 2391 if ((list = rp->info) != NULL && listcount(list) > 1) {
2392 rinfo = listgetdata(listhead(list));
2393 if (!ripng_route_rte(rinfo))
2394 continue;
2395
2396 /* Drop all other entries, except the first one. */
2397 for (ALL_LIST_ELEMENTS(list, node, nextnode, tmp_rinfo))
2398 if (tmp_rinfo != rinfo) {
2399 RIPNG_TIMER_OFF(tmp_rinfo->t_timeout);
2400 RIPNG_TIMER_OFF(
2401 tmp_rinfo->t_garbage_collect);
2402 list_delete_node(list, node);
2403 ripng_info_free(tmp_rinfo);
2404 }
2405
2406 /* Update zebra. */
5c84b9a5 2407 ripng_zebra_ipv6_add(ripng, rp);
d62a17ae 2408
2409 /* Set the route change flag. */
2410 SET_FLAG(rinfo->flags, RIPNG_RTF_CHANGED);
2411
2412 /* Signal the output process to trigger an update. */
5c84b9a5 2413 ripng_event(ripng, RIPNG_TRIGGERED_UPDATE, 0);
d62a17ae 2414 }
fac76f9c
FL
2415}
2416
718e3744 2417/* RIPng configuration write function. */
d62a17ae 2418static int ripng_config_write(struct vty *vty)
2419{
dde7b15b 2420 struct ripng *ripng;
d62a17ae 2421 int write = 0;
d62a17ae 2422
dde7b15b
RW
2423 RB_FOREACH(ripng, ripng_instance_head, &ripng_instances) {
2424 char xpath[XPATH_MAXLEN];
2425 struct lyd_node *dnode;
2426
2427 snprintf(xpath, sizeof(xpath),
2428 "/frr-ripngd:ripngd/instance[vrf='%s']",
2429 ripng->vrf_name);
2430
2431 dnode = yang_dnode_get(running_config->dnode, xpath);
2432 assert(dnode);
d62a17ae 2433
5c84b9a5 2434 nb_cli_show_dnode_cmds(vty, dnode, false);
718e3744 2435
dde7b15b 2436 config_write_distribute(vty, ripng->distribute_ctx);
4b23867c 2437 config_write_if_rmap(vty, ripng->if_rmap_ctx);
718e3744 2438
9a12e9e5 2439 write = 1;
d62a17ae 2440 }
9a12e9e5 2441
d62a17ae 2442 return write;
718e3744 2443}
2444
2445/* RIPng node structure. */
d62a17ae 2446static struct cmd_node cmd_ripng_node = {
9d303b37 2447 RIPNG_NODE, "%s(config-router)# ", 1,
718e3744 2448};
2449
03a38493
PG
2450static void ripng_distribute_update(struct distribute_ctx *ctx,
2451 struct distribute *dist)
d62a17ae 2452{
2453 struct interface *ifp;
2454 struct ripng_interface *ri;
2455 struct access_list *alist;
2456 struct prefix_list *plist;
2457
dde7b15b 2458 if (!ctx->vrf || !dist->ifname)
d62a17ae 2459 return;
2460
a36898e7 2461 ifp = if_lookup_by_name(dist->ifname, ctx->vrf->vrf_id);
d62a17ae 2462 if (ifp == NULL)
2463 return;
2464
2465 ri = ifp->info;
2466
2467 if (dist->list[DISTRIBUTE_V6_IN]) {
2468 alist = access_list_lookup(AFI_IP6,
2469 dist->list[DISTRIBUTE_V6_IN]);
2470 if (alist)
2471 ri->list[RIPNG_FILTER_IN] = alist;
2472 else
2473 ri->list[RIPNG_FILTER_IN] = NULL;
2474 } else
2475 ri->list[RIPNG_FILTER_IN] = NULL;
2476
2477 if (dist->list[DISTRIBUTE_V6_OUT]) {
2478 alist = access_list_lookup(AFI_IP6,
2479 dist->list[DISTRIBUTE_V6_OUT]);
2480 if (alist)
2481 ri->list[RIPNG_FILTER_OUT] = alist;
2482 else
2483 ri->list[RIPNG_FILTER_OUT] = NULL;
2484 } else
2485 ri->list[RIPNG_FILTER_OUT] = NULL;
2486
2487 if (dist->prefix[DISTRIBUTE_V6_IN]) {
2488 plist = prefix_list_lookup(AFI_IP6,
2489 dist->prefix[DISTRIBUTE_V6_IN]);
2490 if (plist)
2491 ri->prefix[RIPNG_FILTER_IN] = plist;
2492 else
2493 ri->prefix[RIPNG_FILTER_IN] = NULL;
2494 } else
2495 ri->prefix[RIPNG_FILTER_IN] = NULL;
2496
2497 if (dist->prefix[DISTRIBUTE_V6_OUT]) {
2498 plist = prefix_list_lookup(AFI_IP6,
2499 dist->prefix[DISTRIBUTE_V6_OUT]);
2500 if (plist)
2501 ri->prefix[RIPNG_FILTER_OUT] = plist;
2502 else
2503 ri->prefix[RIPNG_FILTER_OUT] = NULL;
2504 } else
2505 ri->prefix[RIPNG_FILTER_OUT] = NULL;
2506}
2507
2508void ripng_distribute_update_interface(struct interface *ifp)
2509{
dde7b15b
RW
2510 struct ripng_interface *ri = ifp->info;
2511 struct ripng *ripng = ri->ripng;
d62a17ae 2512 struct distribute *dist;
2513
03a38493
PG
2514 if (!ripng)
2515 return;
2516 dist = distribute_lookup(ripng->distribute_ctx, ifp->name);
d62a17ae 2517 if (dist)
03a38493 2518 ripng_distribute_update(ripng->distribute_ctx, dist);
718e3744 2519}
2520
2521/* Update all interface's distribute list. */
d62a17ae 2522static void ripng_distribute_update_all(struct prefix_list *notused)
718e3744 2523{
f4e14fdb 2524 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
d62a17ae 2525 struct interface *ifp;
718e3744 2526
451fda4f 2527 FOR_ALL_INTERFACES (vrf, ifp)
d62a17ae 2528 ripng_distribute_update_interface(ifp);
718e3744 2529}
c9e52be3 2530
d62a17ae 2531static void ripng_distribute_update_all_wrapper(struct access_list *notused)
c9e52be3 2532{
d62a17ae 2533 ripng_distribute_update_all(NULL);
c9e52be3 2534}
6b0655a2 2535
a94434b6 2536/* delete all the added ripng routes. */
5c84b9a5 2537void ripng_clean(struct ripng *ripng)
d62a17ae 2538{
dde7b15b
RW
2539 if (ripng->enabled)
2540 ripng_instance_disable(ripng);
a9caf6e9
RW
2541
2542 for (int i = 0; i < ZEBRA_ROUTE_MAX; i++)
f9120f71
RW
2543 if (ripng->redist[i].route_map.name)
2544 free(ripng->redist[i].route_map.name);
a94434b6 2545
a9caf6e9 2546 agg_table_finish(ripng->table);
56bf1cb2 2547 list_delete(&ripng->peer_list);
a9caf6e9 2548 distribute_list_delete(&ripng->distribute_ctx);
8f88441d 2549 if_rmap_ctx_delete(ripng->if_rmap_ctx);
0581e54d 2550
a9caf6e9
RW
2551 stream_free(ripng->ibuf);
2552 stream_free(ripng->obuf);
a94434b6 2553
5c84b9a5
RW
2554 ripng_clean_network(ripng);
2555 ripng_passive_interface_clean(ripng);
b0ba762f 2556 vector_free(ripng->enable_if);
29b94d58 2557 agg_table_finish(ripng->enable_network);
0c32404f 2558 vector_free(ripng->passive_interface);
26c6be93 2559 list_delete(&ripng->offset_list_master);
5c84b9a5 2560 ripng_interface_clean(ripng);
5c84b9a5 2561
dde7b15b
RW
2562 RB_REMOVE(ripng_instance_head, &ripng_instances, ripng);
2563 XFREE(MTYPE_RIPNG_VRF_NAME, ripng->vrf_name);
a9caf6e9 2564 XFREE(MTYPE_RIPNG, ripng);
a94434b6 2565}
2566
4b23867c
PG
2567static void ripng_if_rmap_update(struct if_rmap_ctx *ctx,
2568 struct if_rmap *if_rmap)
718e3744 2569{
aec0d756 2570 struct interface *ifp = NULL;
d62a17ae 2571 struct ripng_interface *ri;
2572 struct route_map *rmap;
aec0d756 2573 struct vrf *vrf = NULL;
718e3744 2574
aec0d756
PG
2575 if (ctx->name)
2576 vrf = vrf_lookup_by_name(ctx->name);
2577 if (vrf)
a36898e7 2578 ifp = if_lookup_by_name(if_rmap->ifname, vrf->vrf_id);
d62a17ae 2579 if (ifp == NULL)
2580 return;
718e3744 2581
d62a17ae 2582 ri = ifp->info;
718e3744 2583
d62a17ae 2584 if (if_rmap->routemap[IF_RMAP_IN]) {
2585 rmap = route_map_lookup_by_name(if_rmap->routemap[IF_RMAP_IN]);
2586 if (rmap)
2587 ri->routemap[IF_RMAP_IN] = rmap;
2588 else
2589 ri->routemap[IF_RMAP_IN] = NULL;
2590 } else
2591 ri->routemap[RIPNG_FILTER_IN] = NULL;
718e3744 2592
d62a17ae 2593 if (if_rmap->routemap[IF_RMAP_OUT]) {
2594 rmap = route_map_lookup_by_name(if_rmap->routemap[IF_RMAP_OUT]);
2595 if (rmap)
2596 ri->routemap[IF_RMAP_OUT] = rmap;
2597 else
2598 ri->routemap[IF_RMAP_OUT] = NULL;
2599 } else
2600 ri->routemap[RIPNG_FILTER_OUT] = NULL;
718e3744 2601}
2602
d62a17ae 2603void ripng_if_rmap_update_interface(struct interface *ifp)
718e3744 2604{
8f88441d
RW
2605 struct ripng_interface *ri = ifp->info;
2606 struct ripng *ripng = ri->ripng;
d62a17ae 2607 struct if_rmap *if_rmap;
4b23867c 2608 struct if_rmap_ctx *ctx;
718e3744 2609
4b23867c
PG
2610 if (!ripng)
2611 return;
2612 ctx = ripng->if_rmap_ctx;
2613 if (!ctx)
2614 return;
2615 if_rmap = if_rmap_lookup(ctx, ifp->name);
d62a17ae 2616 if (if_rmap)
4b23867c 2617 ripng_if_rmap_update(ctx, if_rmap);
718e3744 2618}
2619
5c84b9a5 2620static void ripng_routemap_update_redistribute(struct ripng *ripng)
718e3744 2621{
5c84b9a5 2622 for (int i = 0; i < ZEBRA_ROUTE_MAX; i++) {
8f88441d 2623 if (ripng->redist[i].route_map.name) {
f9120f71
RW
2624 ripng->redist[i].route_map.map =
2625 route_map_lookup_by_name(
2626 ripng->redist[i].route_map.name);
8f88441d
RW
2627 route_map_counter_increment(
2628 ripng->redist[i].route_map.map);
d62a17ae 2629 }
718e3744 2630 }
718e3744 2631}
2632
d62a17ae 2633static void ripng_routemap_update(const char *unused)
718e3744 2634{
f4e14fdb 2635 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
5c84b9a5 2636 struct ripng *ripng;
d62a17ae 2637 struct interface *ifp;
718e3744 2638
451fda4f 2639 FOR_ALL_INTERFACES (vrf, ifp)
d62a17ae 2640 ripng_if_rmap_update_interface(ifp);
718e3744 2641
5c84b9a5
RW
2642 ripng = vrf->info;
2643 if (ripng)
2644 ripng_routemap_update_redistribute(ripng);
718e3744 2645}
2646
dde7b15b
RW
2647/* Link RIPng instance to VRF. */
2648static void ripng_vrf_link(struct ripng *ripng, struct vrf *vrf)
2649{
2650 struct interface *ifp;
2651
2652 ripng->vrf = vrf;
2653 ripng->distribute_ctx->vrf = vrf;
2654 vrf->info = ripng;
2655
2656 FOR_ALL_INTERFACES (vrf, ifp)
2657 ripng_interface_sync(ifp);
2658}
2659
2660/* Unlink RIPng instance from VRF. */
2661static void ripng_vrf_unlink(struct ripng *ripng, struct vrf *vrf)
2662{
2663 struct interface *ifp;
2664
2665 ripng->vrf = NULL;
2666 ripng->distribute_ctx->vrf = NULL;
2667 vrf->info = NULL;
2668
2669 FOR_ALL_INTERFACES (vrf, ifp)
2670 ripng_interface_sync(ifp);
2671}
2672
2673static void ripng_instance_enable(struct ripng *ripng, struct vrf *vrf,
2674 int sock)
2675{
2676 ripng->sock = sock;
2677
2678 ripng_vrf_link(ripng, vrf);
2679 ripng->enabled = true;
2680
f9120f71
RW
2681 /* Resend all redistribute requests. */
2682 ripng_redistribute_enable(ripng);
2683
dde7b15b
RW
2684 /* Create read and timer thread. */
2685 ripng_event(ripng, RIPNG_READ, ripng->sock);
2686 ripng_event(ripng, RIPNG_UPDATE_EVENT, 1);
2687
2688 ripng_zebra_vrf_register(vrf);
2689}
2690
2691static void ripng_instance_disable(struct ripng *ripng)
2692{
2693 struct vrf *vrf = ripng->vrf;
2694 struct agg_node *rp;
2695
2696 /* Clear RIPng routes */
2697 for (rp = agg_route_top(ripng->table); rp; rp = agg_route_next(rp)) {
2698 struct ripng_aggregate *aggregate;
2699 struct list *list;
2700
2701 if ((list = rp->info) != NULL) {
2702 struct ripng_info *rinfo;
2703 struct listnode *listnode;
2704
2705 rinfo = listgetdata(listhead(list));
2706 if (ripng_route_rte(rinfo))
2707 ripng_zebra_ipv6_delete(ripng, rp);
2708
2709 for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) {
2710 RIPNG_TIMER_OFF(rinfo->t_timeout);
2711 RIPNG_TIMER_OFF(rinfo->t_garbage_collect);
2712 ripng_info_free(rinfo);
2713 }
2714 list_delete(&list);
2715 rp->info = NULL;
2716 agg_unlock_node(rp);
2717 }
2718
2719 if ((aggregate = rp->aggregate) != NULL) {
2720 ripng_aggregate_free(aggregate);
2721 rp->aggregate = NULL;
2722 agg_unlock_node(rp);
2723 }
2724 }
2725
f9120f71
RW
2726 /* Flush all redistribute requests. */
2727 ripng_redistribute_disable(ripng);
2728
dde7b15b
RW
2729 /* Cancel the RIPng timers */
2730 RIPNG_TIMER_OFF(ripng->t_update);
2731 RIPNG_TIMER_OFF(ripng->t_triggered_update);
2732 RIPNG_TIMER_OFF(ripng->t_triggered_interval);
2733
2734 /* Cancel the read thread */
2735 if (ripng->t_read) {
2736 thread_cancel(ripng->t_read);
2737 ripng->t_read = NULL;
2738 }
2739
2740 /* Close the RIPng socket */
2741 if (ripng->sock >= 0) {
2742 close(ripng->sock);
2743 ripng->sock = -1;
2744 }
2745
2746 /* Clear existing peers. */
2747 list_delete_all_node(ripng->peer_list);
2748
2749 ripng_zebra_vrf_deregister(vrf);
2750
2751 ripng_vrf_unlink(ripng, vrf);
2752 ripng->enabled = false;
2753}
2754
2755static int ripng_vrf_new(struct vrf *vrf)
2756{
2757 if (IS_RIPNG_DEBUG_EVENT)
2758 zlog_debug("%s: VRF created: %s(%u)", __func__, vrf->name,
2759 vrf->vrf_id);
2760
2761 return 0;
2762}
2763
2764static int ripng_vrf_delete(struct vrf *vrf)
2765{
2766 if (IS_RIPNG_DEBUG_EVENT)
2767 zlog_debug("%s: VRF deleted: %s(%u)", __func__, vrf->name,
2768 vrf->vrf_id);
2769
2770 return 0;
2771}
2772
2773static int ripng_vrf_enable(struct vrf *vrf)
2774{
2775 struct ripng *ripng;
2776 int socket;
2777
2778 ripng = ripng_lookup_by_vrf_name(vrf->name);
be2bad2e
PG
2779 if (!ripng) {
2780 char *old_vrf_name = NULL;
2781
2782 ripng = (struct ripng *)vrf->info;
2783 if (!ripng)
2784 return 0;
2785 /* update vrf name */
2786 if (ripng->vrf_name)
2787 old_vrf_name = ripng->vrf_name;
2788 ripng->vrf_name = XSTRDUP(MTYPE_RIPNG_VRF_NAME, vrf->name);
2789 /*
2790 * HACK: Change the RIPng VRF in the running configuration directly,
2791 * bypassing the northbound layer. This is necessary to avoid deleting
2792 * the RIPng and readding it in the new VRF, which would have
2793 * several implications.
2794 */
2795 if (yang_module_find("frr-ripngd") && old_vrf_name) {
2796 struct lyd_node *ripng_dnode;
2797
8685be73
RW
2798 ripng_dnode = yang_dnode_get(
2799 running_config->dnode,
2800 "/frr-ripngd:ripngd/instance[vrf='%s']/vrf",
2801 old_vrf_name);
2802 if (ripng_dnode) {
2803 yang_dnode_change_leaf(ripng_dnode, vrf->name);
2804 running_config->version++;
be2bad2e 2805 }
be2bad2e
PG
2806 }
2807 if (old_vrf_name)
2808 XFREE(MTYPE_RIPNG_VRF_NAME, old_vrf_name);
2809 }
2810
2811 if (ripng->enabled)
dde7b15b
RW
2812 return 0;
2813
2814 if (IS_RIPNG_DEBUG_EVENT)
2815 zlog_debug("%s: VRF %s(%u) enabled", __func__, vrf->name,
2816 vrf->vrf_id);
2817
2818 /* Activate the VRF RIPng instance. */
be2bad2e
PG
2819 socket = ripng_make_socket(vrf);
2820 if (socket < 0)
2821 return -1;
dde7b15b 2822
be2bad2e 2823 ripng_instance_enable(ripng, vrf, socket);
dde7b15b
RW
2824
2825 return 0;
2826}
2827
2828static int ripng_vrf_disable(struct vrf *vrf)
2829{
2830 struct ripng *ripng;
2831
2832 ripng = ripng_lookup_by_vrf_name(vrf->name);
2833 if (!ripng || !ripng->enabled)
2834 return 0;
2835
2836 if (IS_RIPNG_DEBUG_EVENT)
2837 zlog_debug("%s: VRF %s(%u) disabled", __func__, vrf->name,
2838 vrf->vrf_id);
2839
2840 /* Deactivate the VRF RIPng instance. */
2841 if (ripng->enabled)
2842 ripng_instance_disable(ripng);
2843
2844 return 0;
2845}
2846
2847void ripng_vrf_init(void)
2848{
2849 vrf_init(ripng_vrf_new, ripng_vrf_enable, ripng_vrf_disable,
66bc1c49 2850 ripng_vrf_delete, ripng_vrf_enable);
dde7b15b
RW
2851}
2852
2853void ripng_vrf_terminate(void)
2854{
2855 vrf_terminate();
2856}
2857
718e3744 2858/* Initialize ripng structure and set commands. */
4d762f26 2859void ripng_init(void)
718e3744 2860{
d62a17ae 2861 /* Install RIPNG_NODE. */
2862 install_node(&cmd_ripng_node, ripng_config_write);
718e3744 2863
d62a17ae 2864 /* Install ripng commands. */
2865 install_element(VIEW_NODE, &show_ipv6_ripng_cmd);
2866 install_element(VIEW_NODE, &show_ipv6_ripng_status_cmd);
718e3744 2867
d62a17ae 2868 install_default(RIPNG_NODE);
718e3744 2869
718e3744 2870#if 0
ee9216cf 2871 install_element (VIEW_NODE, &show_ipv6_protocols_cmd);
718e3744 2872 install_element (RIPNG_NODE, &ripng_update_timer_cmd);
2873 install_element (RIPNG_NODE, &no_ripng_update_timer_cmd);
2874 install_element (RIPNG_NODE, &ripng_timeout_timer_cmd);
2875 install_element (RIPNG_NODE, &no_ripng_timeout_timer_cmd);
2876 install_element (RIPNG_NODE, &ripng_garbage_timer_cmd);
2877 install_element (RIPNG_NODE, &no_ripng_garbage_timer_cmd);
2878#endif /* 0 */
2879
d62a17ae 2880 ripng_if_init();
2881 ripng_debug_init();
718e3744 2882
d62a17ae 2883 /* Access list install. */
2884 access_list_init();
2885 access_list_add_hook(ripng_distribute_update_all_wrapper);
2886 access_list_delete_hook(ripng_distribute_update_all_wrapper);
718e3744 2887
d62a17ae 2888 /* Prefix list initialize.*/
2889 prefix_list_init();
2890 prefix_list_add_hook(ripng_distribute_update_all);
2891 prefix_list_delete_hook(ripng_distribute_update_all);
718e3744 2892
d62a17ae 2893 /* Distribute list install. */
2894 distribute_list_init(RIPNG_NODE);
718e3744 2895
d62a17ae 2896 /* Route-map for interface. */
2897 ripng_route_map_init();
a94434b6 2898
d62a17ae 2899 route_map_add_hook(ripng_routemap_update);
2900 route_map_delete_hook(ripng_routemap_update);
718e3744 2901
d62a17ae 2902 if_rmap_init(RIPNG_NODE);
718e3744 2903}