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