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