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