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