]> git.proxmox.com Git - mirror_frr.git/blame - ripngd/ripngd.c
Merge pull request #13060 from opensourcerouting/feature/allow_peering_with_127.0.0.1
[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"
24a58196 11#include "frrevent.h"
718e3744 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);
e6685141 49static void ripng_triggered_update(struct event *);
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. */
e6685141 411static void ripng_garbage_collect(struct event *t)
718e3744 412{
d62a17ae 413 struct ripng_info *rinfo;
fe08ba7e 414 struct agg_node *rp;
718e3744 415
e16d030c 416 rinfo = EVENT_ARG(t);
718e3744 417
d62a17ae 418 /* Off timeout timer. */
e16d030c 419 EVENT_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) {
e16d030c
DS
506 EVENT_OFF(tmp_rinfo->t_timeout);
507 EVENT_OFF(tmp_rinfo->t_garbage_collect);
d62a17ae 508 list_delete_node(list, node);
509 ripng_info_free(tmp_rinfo);
510 }
c880b636 511
e16d030c
DS
512 EVENT_OFF(rinfo->t_timeout);
513 EVENT_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
e16d030c 545 EVENT_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 */
e16d030c 553 EVENT_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. */
e6685141 588static void ripng_timeout(struct event *t)
c880b636 589{
e16d030c 590 struct ripng_info *rinfo = EVENT_ARG(t);
5c84b9a5
RW
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) {
e16d030c 599 EVENT_OFF(rinfo->t_timeout);
907a2395
DS
600 event_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 */
4f830a07
DS
880 if (!ripng->ecmp && !same && rinfo->metric == rte->metric &&
881 rinfo->t_timeout &&
882 (event_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: */
4f830a07
DS
890 else if ((same && rinfo->metric != rte->metric) ||
891 rte->metric < rinfo->metric) {
d62a17ae 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);
e16d030c 1010 EVENT_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);
e16d030c 1049 EVENT_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. */
e6685141 1285static void ripng_read(struct event *thread)
d62a17ae 1286{
e16d030c 1287 struct ripng *ripng = EVENT_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. */
e16d030c 1302 sock = EVENT_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. */
e6685141 1393static void ripng_update(struct event *t)
718e3744 1394{
e16d030c 1395 struct ripng *ripng = EVENT_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. */
e16d030c 1433 EVENT_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. */
e6685141 1441static void ripng_triggered_interval(struct event *t)
718e3744 1442{
e16d030c 1443 struct ripng *ripng = EVENT_ARG(t);
5c84b9a5 1444
d62a17ae 1445 if (ripng->trigger) {
1446 ripng->trigger = 0;
1447 ripng_triggered_update(t);
1448 }
d62a17ae 1449}
718e3744 1450
1451/* Execute triggered update. */
e6685141 1452void ripng_triggered_update(struct event *t)
718e3744 1453{
e16d030c 1454 struct ripng *ripng = EVENT_ARG(t);
d62a17ae 1455 struct interface *ifp;
1456 struct ripng_interface *ri;
1457 int interval;
718e3744 1458
d62a17ae 1459 /* Cancel interval timer. */
e16d030c 1460 EVENT_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
907a2395
DS
1496 event_add_timer(master, ripng_triggered_interval, ripng, interval,
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:
907a2395 1901 event_add_read(master, ripng_read, ripng, sock, &ripng->t_read);
d62a17ae 1902 break;
1903 case RIPNG_UPDATE_EVENT:
e16d030c 1904 EVENT_OFF(ripng->t_update);
b3d6bc6e 1905
d62a17ae 1906 /* Update timer jitter. */
1907 jitter = ripng_update_jitter(ripng->update_time);
1908
907a2395
DS
1909 event_add_timer(master, ripng_update, ripng,
1910 sock ? 2 : ripng->update_time + jitter,
1911 &ripng->t_update);
d62a17ae 1912 break;
1913 case RIPNG_TRIGGERED_UPDATE:
1914 if (ripng->t_triggered_interval)
1915 ripng->trigger = 1;
1916 else
907a2395
DS
1917 event_add_event(master, ripng_triggered_update, ripng,
1918 0, &ripng->t_triggered_update);
d62a17ae 1919 break;
01e02202
DS
1920 case RIPNG_ZEBRA:
1921 case RIPNG_REQUEST_EVENT:
d62a17ae 1922 break;
1923 }
718e3744 1924}
6b0655a2 1925
718e3744 1926
718e3744 1927/* Print out routes update time. */
d62a17ae 1928static void ripng_vty_out_uptime(struct vty *vty, struct ripng_info *rinfo)
718e3744 1929{
d62a17ae 1930 time_t clock;
a2700b50 1931 struct tm tm;
718e3744 1932#define TIME_BUF 25
d62a17ae 1933 char timebuf[TIME_BUF];
e6685141 1934 struct event *thread;
d62a17ae 1935
1936 if ((thread = rinfo->t_timeout) != NULL) {
4f830a07 1937 clock = event_timer_remain_second(thread);
a2700b50
MS
1938 gmtime_r(&clock, &tm);
1939 strftime(timebuf, TIME_BUF, "%M:%S", &tm);
d62a17ae 1940 vty_out(vty, "%5s", timebuf);
1941 } else if ((thread = rinfo->t_garbage_collect) != NULL) {
4f830a07 1942 clock = event_timer_remain_second(thread);
a2700b50
MS
1943 gmtime_r(&clock, &tm);
1944 strftime(timebuf, TIME_BUF, "%M:%S", &tm);
d62a17ae 1945 vty_out(vty, "%5s", timebuf);
1946 }
718e3744 1947}
1948
d62a17ae 1949static char *ripng_route_subtype_print(struct ripng_info *rinfo)
1950{
1951 static char str[3];
1952 memset(str, 0, 3);
1953
1954 if (rinfo->suppress)
9736ba9e 1955 strlcat(str, "S", sizeof(str));
d62a17ae 1956
1957 switch (rinfo->sub_type) {
1958 case RIPNG_ROUTE_RTE:
9736ba9e 1959 strlcat(str, "n", sizeof(str));
d62a17ae 1960 break;
1961 case RIPNG_ROUTE_STATIC:
9736ba9e 1962 strlcat(str, "s", sizeof(str));
d62a17ae 1963 break;
1964 case RIPNG_ROUTE_DEFAULT:
9736ba9e 1965 strlcat(str, "d", sizeof(str));
d62a17ae 1966 break;
1967 case RIPNG_ROUTE_REDISTRIBUTE:
9736ba9e 1968 strlcat(str, "r", sizeof(str));
d62a17ae 1969 break;
1970 case RIPNG_ROUTE_INTERFACE:
9736ba9e 1971 strlcat(str, "i", sizeof(str));
d62a17ae 1972 break;
1973 default:
9736ba9e 1974 strlcat(str, "?", sizeof(str));
d62a17ae 1975 break;
1976 }
a94434b6 1977
d62a17ae 1978 return str;
a94434b6 1979}
1980
718e3744 1981DEFUN (show_ipv6_ripng,
1982 show_ipv6_ripng_cmd,
dde7b15b 1983 "show ipv6 ripng [vrf NAME]",
718e3744 1984 SHOW_STR
8d0f15fd 1985 IPV6_STR
dde7b15b
RW
1986 "Show RIPng routes\n"
1987 VRF_CMD_HELP_STR)
718e3744 1988{
5c84b9a5 1989 struct ripng *ripng;
fe08ba7e 1990 struct agg_node *rp;
d62a17ae 1991 struct ripng_info *rinfo;
1992 struct ripng_aggregate *aggregate;
d62a17ae 1993 struct list *list = NULL;
1994 struct listnode *listnode = NULL;
1995 int len;
dde7b15b
RW
1996 const char *vrf_name;
1997 int idx = 0;
d62a17ae 1998
dde7b15b
RW
1999 if (argv_find(argv, argc, "vrf", &idx))
2000 vrf_name = argv[idx + 1]->arg;
2001 else
2002 vrf_name = VRF_DEFAULT_NAME;
2003
2004 ripng = ripng_lookup_by_vrf_name(vrf_name);
2005 if (!ripng) {
2006 vty_out(vty, "%% RIPng instance not found\n");
2007 return CMD_SUCCESS;
2008 }
2009 if (!ripng->enabled) {
2010 vty_out(vty, "%% RIPng instance is disabled\n");
d62a17ae 2011 return CMD_SUCCESS;
dde7b15b 2012 }
d62a17ae 2013
2014 /* Header of display. */
2015 vty_out(vty,
2016 "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP\n"
2017 "Sub-codes:\n"
2018 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,\n"
2019 " (i) - interface, (a/S) - aggregated/Suppressed\n\n"
2020 " Network Next Hop Via Metric Tag Time\n");
2021
fe08ba7e 2022 for (rp = agg_route_top(ripng->table); rp; rp = agg_route_next(rp)) {
d62a17ae 2023 if ((aggregate = rp->aggregate) != NULL) {
718e3744 2024#ifdef DEBUG
26a3ffd6
DS
2025 vty_out(vty, "R(a) %d/%d %pRN ", aggregate->count,
2026 aggregate->suppress, rp);
718e3744 2027#else
26a3ffd6 2028 vty_out(vty, "R(a) %pRN ", rp);
718e3744 2029#endif /* DEBUG */
d62a17ae 2030 vty_out(vty, "\n");
2031 vty_out(vty, "%*s", 18, " ");
718e3744 2032
d62a17ae 2033 vty_out(vty, "%*s", 28, " ");
2034 vty_out(vty, "self %2d %3" ROUTE_TAG_PRI "\n",
2035 aggregate->metric, (route_tag_t)aggregate->tag);
2036 }
718e3744 2037
d62a17ae 2038 if ((list = rp->info) != NULL)
2039 for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) {
718e3744 2040#ifdef DEBUG
26a3ffd6 2041 vty_out(vty, "%c(%s) 0/%d %pRN ",
d62a17ae 2042 zebra_route_char(rinfo->type),
2043 ripng_route_subtype_print(rinfo),
26a3ffd6 2044 rinfo->suppress, rp);
718e3744 2045#else
26a3ffd6 2046 vty_out(vty, "%c(%s) %pRN ",
d62a17ae 2047 zebra_route_char(rinfo->type),
26a3ffd6 2048 ripng_route_subtype_print(rinfo), rp);
718e3744 2049#endif /* DEBUG */
d62a17ae 2050 vty_out(vty, "\n");
2051 vty_out(vty, "%*s", 18, " ");
2e5b3f37
MS
2052 len = vty_out(vty, "%pI6",
2053 &rinfo->nexthop);
d62a17ae 2054
2055 len = 28 - len;
2056 if (len > 0)
51f7fe84 2057 vty_out(vty, "%*s", len, " ");
d62a17ae 2058
2059 /* from */
2060 if ((rinfo->type == ZEBRA_ROUTE_RIPNG)
2061 && (rinfo->sub_type == RIPNG_ROUTE_RTE)) {
2062 len = vty_out(
2063 vty, "%s",
dde7b15b
RW
2064 ifindex2ifname(
2065 rinfo->ifindex,
2066 ripng->vrf->vrf_id));
d62a17ae 2067 } else if (rinfo->metric
2068 == RIPNG_METRIC_INFINITY) {
2069 len = vty_out(vty, "kill");
2070 } else
2071 len = vty_out(vty, "self");
2072
2073 len = 9 - len;
2074 if (len > 0)
2075 vty_out(vty, "%*s", len, " ");
2076
2077 vty_out(vty, " %2d %3" ROUTE_TAG_PRI " ",
2078 rinfo->metric, (route_tag_t)rinfo->tag);
2079
2080 /* time */
2081 if ((rinfo->type == ZEBRA_ROUTE_RIPNG)
2082 && (rinfo->sub_type == RIPNG_ROUTE_RTE)) {
2083 /* RTE from remote RIP routers */
2084 ripng_vty_out_uptime(vty, rinfo);
2085 } else if (rinfo->metric
2086 == RIPNG_METRIC_INFINITY) {
2087 /* poisonous reversed routes (gc) */
2088 ripng_vty_out_uptime(vty, rinfo);
2089 }
2090
2091 vty_out(vty, "\n");
2092 }
718e3744 2093 }
718e3744 2094
d62a17ae 2095 return CMD_SUCCESS;
718e3744 2096}
2097
a94434b6 2098DEFUN (show_ipv6_ripng_status,
2099 show_ipv6_ripng_status_cmd,
dde7b15b 2100 "show ipv6 ripng [vrf NAME] status",
a94434b6 2101 SHOW_STR
8d0f15fd 2102 IPV6_STR
a94434b6 2103 "Show RIPng routes\n"
dde7b15b 2104 VRF_CMD_HELP_STR
a94434b6 2105 "IPv6 routing protocol process parameters and statistics\n")
2106{
5c84b9a5 2107 struct ripng *ripng;
d62a17ae 2108 struct interface *ifp;
dde7b15b
RW
2109 const char *vrf_name;
2110 int idx = 0;
a94434b6 2111
dde7b15b
RW
2112 if (argv_find(argv, argc, "vrf", &idx))
2113 vrf_name = argv[idx + 1]->arg;
2114 else
2115 vrf_name = VRF_DEFAULT_NAME;
2116
2117 ripng = ripng_lookup_by_vrf_name(vrf_name);
2118 if (!ripng) {
2119 vty_out(vty, "%% RIPng instance not found\n");
2120 return CMD_SUCCESS;
2121 }
2122 if (!ripng->enabled) {
2123 vty_out(vty, "%% RIPng instance is disabled\n");
d62a17ae 2124 return CMD_SUCCESS;
dde7b15b 2125 }
a94434b6 2126
d62a17ae 2127 vty_out(vty, "Routing Protocol is \"RIPng\"\n");
f8981ec5 2128 vty_out(vty, " Sending updates every %u seconds with +/-50%%,",
d62a17ae 2129 ripng->update_time);
2130 vty_out(vty, " next due in %lu seconds\n",
4f830a07 2131 event_timer_remain_second(ripng->t_update));
f8981ec5
RW
2132 vty_out(vty, " Timeout after %u seconds,", ripng->timeout_time);
2133 vty_out(vty, " garbage collect after %u seconds\n",
d62a17ae 2134 ripng->garbage_time);
a94434b6 2135
d62a17ae 2136 /* Filtering status show. */
03a38493 2137 config_show_distribute(vty, ripng->distribute_ctx);
a94434b6 2138
d62a17ae 2139 /* Default metric information. */
2140 vty_out(vty, " Default redistribution metric is %d\n",
2141 ripng->default_metric);
a94434b6 2142
d62a17ae 2143 /* Redistribute information. */
2144 vty_out(vty, " Redistributing:");
5c84b9a5 2145 ripng_redistribute_write(vty, ripng);
d62a17ae 2146 vty_out(vty, "\n");
a94434b6 2147
d62a17ae 2148 vty_out(vty, " Default version control: send version %d,",
2149 ripng->version);
2150 vty_out(vty, " receive version %d \n", ripng->version);
a94434b6 2151
d62a17ae 2152 vty_out(vty, " Interface Send Recv\n");
a94434b6 2153
dde7b15b 2154 FOR_ALL_INTERFACES (ripng->vrf, ifp) {
d62a17ae 2155 struct ripng_interface *ri;
2156
2157 ri = ifp->info;
a94434b6 2158
d62a17ae 2159 if (ri->enable_network || ri->enable_interface) {
a94434b6 2160
d62a17ae 2161 vty_out(vty, " %-17s%-3d %-3d\n", ifp->name,
2162 ripng->version, ripng->version);
2163 }
a94434b6 2164 }
a94434b6 2165
d62a17ae 2166 vty_out(vty, " Routing for Networks:\n");
5c84b9a5 2167 ripng_network_write(vty, ripng);
a94434b6 2168
d62a17ae 2169 vty_out(vty, " Routing Information Sources:\n");
2170 vty_out(vty,
2171 " Gateway BadPackets BadRoutes Distance Last Update\n");
5c84b9a5 2172 ripng_peer_display(vty, ripng);
a94434b6 2173
d62a17ae 2174 return CMD_SUCCESS;
a94434b6 2175}
2176
fac76f9c 2177/* Update ECMP routes to zebra when ECMP is disabled. */
5c84b9a5 2178void ripng_ecmp_disable(struct ripng *ripng)
d62a17ae 2179{
fe08ba7e 2180 struct agg_node *rp;
d62a17ae 2181 struct ripng_info *rinfo, *tmp_rinfo;
2182 struct list *list;
2183 struct listnode *node, *nextnode;
2184
2185 if (!ripng)
2186 return;
2187
fe08ba7e 2188 for (rp = agg_route_top(ripng->table); rp; rp = agg_route_next(rp))
d62a17ae 2189 if ((list = rp->info) != NULL && listcount(list) > 1) {
2190 rinfo = listgetdata(listhead(list));
2191 if (!ripng_route_rte(rinfo))
2192 continue;
2193
2194 /* Drop all other entries, except the first one. */
2195 for (ALL_LIST_ELEMENTS(list, node, nextnode, tmp_rinfo))
2196 if (tmp_rinfo != rinfo) {
e16d030c
DS
2197 EVENT_OFF(tmp_rinfo->t_timeout);
2198 EVENT_OFF(tmp_rinfo->t_garbage_collect);
d62a17ae 2199 list_delete_node(list, node);
2200 ripng_info_free(tmp_rinfo);
2201 }
2202
2203 /* Update zebra. */
5c84b9a5 2204 ripng_zebra_ipv6_add(ripng, rp);
d62a17ae 2205
2206 /* Set the route change flag. */
2207 SET_FLAG(rinfo->flags, RIPNG_RTF_CHANGED);
2208
2209 /* Signal the output process to trigger an update. */
5c84b9a5 2210 ripng_event(ripng, RIPNG_TRIGGERED_UPDATE, 0);
d62a17ae 2211 }
fac76f9c
FL
2212}
2213
718e3744 2214/* RIPng configuration write function. */
d62a17ae 2215static int ripng_config_write(struct vty *vty)
2216{
dde7b15b 2217 struct ripng *ripng;
d62a17ae 2218 int write = 0;
d62a17ae 2219
dde7b15b
RW
2220 RB_FOREACH(ripng, ripng_instance_head, &ripng_instances) {
2221 char xpath[XPATH_MAXLEN];
2222 struct lyd_node *dnode;
2223
2224 snprintf(xpath, sizeof(xpath),
2225 "/frr-ripngd:ripngd/instance[vrf='%s']",
2226 ripng->vrf_name);
2227
2228 dnode = yang_dnode_get(running_config->dnode, xpath);
2229 assert(dnode);
d62a17ae 2230
5c84b9a5 2231 nb_cli_show_dnode_cmds(vty, dnode, false);
718e3744 2232
dde7b15b 2233 config_write_distribute(vty, ripng->distribute_ctx);
4b23867c 2234 config_write_if_rmap(vty, ripng->if_rmap_ctx);
718e3744 2235
07679ad9
IR
2236 vty_out(vty, "exit\n");
2237
9a12e9e5 2238 write = 1;
d62a17ae 2239 }
9a12e9e5 2240
d62a17ae 2241 return write;
718e3744 2242}
2243
612c2c15 2244static int ripng_config_write(struct vty *vty);
718e3744 2245/* RIPng node structure. */
d62a17ae 2246static struct cmd_node cmd_ripng_node = {
f4b8291f 2247 .name = "ripng",
62b346ee 2248 .node = RIPNG_NODE,
24389580 2249 .parent_node = CONFIG_NODE,
62b346ee 2250 .prompt = "%s(config-router)# ",
612c2c15 2251 .config_write = ripng_config_write,
718e3744 2252};
2253
03a38493
PG
2254static void ripng_distribute_update(struct distribute_ctx *ctx,
2255 struct distribute *dist)
d62a17ae 2256{
2257 struct interface *ifp;
2258 struct ripng_interface *ri;
2259 struct access_list *alist;
2260 struct prefix_list *plist;
2261
dde7b15b 2262 if (!ctx->vrf || !dist->ifname)
d62a17ae 2263 return;
2264
a36898e7 2265 ifp = if_lookup_by_name(dist->ifname, ctx->vrf->vrf_id);
d62a17ae 2266 if (ifp == NULL)
2267 return;
2268
2269 ri = ifp->info;
2270
2271 if (dist->list[DISTRIBUTE_V6_IN]) {
2272 alist = access_list_lookup(AFI_IP6,
2273 dist->list[DISTRIBUTE_V6_IN]);
2274 if (alist)
2275 ri->list[RIPNG_FILTER_IN] = alist;
2276 else
2277 ri->list[RIPNG_FILTER_IN] = NULL;
2278 } else
2279 ri->list[RIPNG_FILTER_IN] = NULL;
2280
2281 if (dist->list[DISTRIBUTE_V6_OUT]) {
2282 alist = access_list_lookup(AFI_IP6,
2283 dist->list[DISTRIBUTE_V6_OUT]);
2284 if (alist)
2285 ri->list[RIPNG_FILTER_OUT] = alist;
2286 else
2287 ri->list[RIPNG_FILTER_OUT] = NULL;
2288 } else
2289 ri->list[RIPNG_FILTER_OUT] = NULL;
2290
2291 if (dist->prefix[DISTRIBUTE_V6_IN]) {
2292 plist = prefix_list_lookup(AFI_IP6,
2293 dist->prefix[DISTRIBUTE_V6_IN]);
2294 if (plist)
2295 ri->prefix[RIPNG_FILTER_IN] = plist;
2296 else
2297 ri->prefix[RIPNG_FILTER_IN] = NULL;
2298 } else
2299 ri->prefix[RIPNG_FILTER_IN] = NULL;
2300
2301 if (dist->prefix[DISTRIBUTE_V6_OUT]) {
2302 plist = prefix_list_lookup(AFI_IP6,
2303 dist->prefix[DISTRIBUTE_V6_OUT]);
2304 if (plist)
2305 ri->prefix[RIPNG_FILTER_OUT] = plist;
2306 else
2307 ri->prefix[RIPNG_FILTER_OUT] = NULL;
2308 } else
2309 ri->prefix[RIPNG_FILTER_OUT] = NULL;
2310}
2311
2312void ripng_distribute_update_interface(struct interface *ifp)
2313{
dde7b15b
RW
2314 struct ripng_interface *ri = ifp->info;
2315 struct ripng *ripng = ri->ripng;
d62a17ae 2316 struct distribute *dist;
2317
03a38493
PG
2318 if (!ripng)
2319 return;
2320 dist = distribute_lookup(ripng->distribute_ctx, ifp->name);
d62a17ae 2321 if (dist)
03a38493 2322 ripng_distribute_update(ripng->distribute_ctx, dist);
718e3744 2323}
2324
2325/* Update all interface's distribute list. */
d62a17ae 2326static void ripng_distribute_update_all(struct prefix_list *notused)
718e3744 2327{
f4e14fdb 2328 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
d62a17ae 2329 struct interface *ifp;
718e3744 2330
451fda4f 2331 FOR_ALL_INTERFACES (vrf, ifp)
d62a17ae 2332 ripng_distribute_update_interface(ifp);
718e3744 2333}
c9e52be3 2334
d62a17ae 2335static void ripng_distribute_update_all_wrapper(struct access_list *notused)
c9e52be3 2336{
d62a17ae 2337 ripng_distribute_update_all(NULL);
c9e52be3 2338}
6b0655a2 2339
a94434b6 2340/* delete all the added ripng routes. */
5c84b9a5 2341void ripng_clean(struct ripng *ripng)
d62a17ae 2342{
eb6b3885
IR
2343 ripng_interface_clean(ripng);
2344
dde7b15b
RW
2345 if (ripng->enabled)
2346 ripng_instance_disable(ripng);
a9caf6e9
RW
2347
2348 for (int i = 0; i < ZEBRA_ROUTE_MAX; i++)
f9120f71
RW
2349 if (ripng->redist[i].route_map.name)
2350 free(ripng->redist[i].route_map.name);
a94434b6 2351
a9caf6e9 2352 agg_table_finish(ripng->table);
56bf1cb2 2353 list_delete(&ripng->peer_list);
a9caf6e9 2354 distribute_list_delete(&ripng->distribute_ctx);
8f88441d 2355 if_rmap_ctx_delete(ripng->if_rmap_ctx);
0581e54d 2356
a9caf6e9
RW
2357 stream_free(ripng->ibuf);
2358 stream_free(ripng->obuf);
a94434b6 2359
5c84b9a5
RW
2360 ripng_clean_network(ripng);
2361 ripng_passive_interface_clean(ripng);
b0ba762f 2362 vector_free(ripng->enable_if);
29b94d58 2363 agg_table_finish(ripng->enable_network);
0c32404f 2364 vector_free(ripng->passive_interface);
26c6be93 2365 list_delete(&ripng->offset_list_master);
5c84b9a5 2366
dde7b15b
RW
2367 RB_REMOVE(ripng_instance_head, &ripng_instances, ripng);
2368 XFREE(MTYPE_RIPNG_VRF_NAME, ripng->vrf_name);
a9caf6e9 2369 XFREE(MTYPE_RIPNG, ripng);
a94434b6 2370}
2371
4b23867c
PG
2372static void ripng_if_rmap_update(struct if_rmap_ctx *ctx,
2373 struct if_rmap *if_rmap)
718e3744 2374{
aec0d756 2375 struct interface *ifp = NULL;
d62a17ae 2376 struct ripng_interface *ri;
2377 struct route_map *rmap;
aec0d756 2378 struct vrf *vrf = NULL;
718e3744 2379
aec0d756
PG
2380 if (ctx->name)
2381 vrf = vrf_lookup_by_name(ctx->name);
2382 if (vrf)
a36898e7 2383 ifp = if_lookup_by_name(if_rmap->ifname, vrf->vrf_id);
d62a17ae 2384 if (ifp == NULL)
2385 return;
718e3744 2386
d62a17ae 2387 ri = ifp->info;
718e3744 2388
d62a17ae 2389 if (if_rmap->routemap[IF_RMAP_IN]) {
2390 rmap = route_map_lookup_by_name(if_rmap->routemap[IF_RMAP_IN]);
2391 if (rmap)
2392 ri->routemap[IF_RMAP_IN] = rmap;
2393 else
2394 ri->routemap[IF_RMAP_IN] = NULL;
2395 } else
2396 ri->routemap[RIPNG_FILTER_IN] = NULL;
718e3744 2397
d62a17ae 2398 if (if_rmap->routemap[IF_RMAP_OUT]) {
2399 rmap = route_map_lookup_by_name(if_rmap->routemap[IF_RMAP_OUT]);
2400 if (rmap)
2401 ri->routemap[IF_RMAP_OUT] = rmap;
2402 else
2403 ri->routemap[IF_RMAP_OUT] = NULL;
2404 } else
2405 ri->routemap[RIPNG_FILTER_OUT] = NULL;
718e3744 2406}
2407
d62a17ae 2408void ripng_if_rmap_update_interface(struct interface *ifp)
718e3744 2409{
8f88441d
RW
2410 struct ripng_interface *ri = ifp->info;
2411 struct ripng *ripng = ri->ripng;
d62a17ae 2412 struct if_rmap *if_rmap;
4b23867c 2413 struct if_rmap_ctx *ctx;
718e3744 2414
4b23867c
PG
2415 if (!ripng)
2416 return;
2417 ctx = ripng->if_rmap_ctx;
2418 if (!ctx)
2419 return;
2420 if_rmap = if_rmap_lookup(ctx, ifp->name);
d62a17ae 2421 if (if_rmap)
4b23867c 2422 ripng_if_rmap_update(ctx, if_rmap);
718e3744 2423}
2424
5c84b9a5 2425static void ripng_routemap_update_redistribute(struct ripng *ripng)
718e3744 2426{
5c84b9a5 2427 for (int i = 0; i < ZEBRA_ROUTE_MAX; i++) {
8f88441d 2428 if (ripng->redist[i].route_map.name) {
f9120f71
RW
2429 ripng->redist[i].route_map.map =
2430 route_map_lookup_by_name(
2431 ripng->redist[i].route_map.name);
8f88441d
RW
2432 route_map_counter_increment(
2433 ripng->redist[i].route_map.map);
d62a17ae 2434 }
718e3744 2435 }
718e3744 2436}
2437
d62a17ae 2438static void ripng_routemap_update(const char *unused)
718e3744 2439{
f4e14fdb 2440 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
5c84b9a5 2441 struct ripng *ripng;
d62a17ae 2442 struct interface *ifp;
718e3744 2443
451fda4f 2444 FOR_ALL_INTERFACES (vrf, ifp)
d62a17ae 2445 ripng_if_rmap_update_interface(ifp);
718e3744 2446
5c84b9a5
RW
2447 ripng = vrf->info;
2448 if (ripng)
2449 ripng_routemap_update_redistribute(ripng);
718e3744 2450}
2451
dde7b15b
RW
2452/* Link RIPng instance to VRF. */
2453static void ripng_vrf_link(struct ripng *ripng, struct vrf *vrf)
2454{
2455 struct interface *ifp;
2456
2457 ripng->vrf = vrf;
2458 ripng->distribute_ctx->vrf = vrf;
2459 vrf->info = ripng;
2460
2461 FOR_ALL_INTERFACES (vrf, ifp)
2462 ripng_interface_sync(ifp);
2463}
2464
2465/* Unlink RIPng instance from VRF. */
2466static void ripng_vrf_unlink(struct ripng *ripng, struct vrf *vrf)
2467{
2468 struct interface *ifp;
2469
2470 ripng->vrf = NULL;
2471 ripng->distribute_ctx->vrf = NULL;
2472 vrf->info = NULL;
2473
2474 FOR_ALL_INTERFACES (vrf, ifp)
2475 ripng_interface_sync(ifp);
2476}
2477
2478static void ripng_instance_enable(struct ripng *ripng, struct vrf *vrf,
2479 int sock)
2480{
2481 ripng->sock = sock;
2482
2483 ripng_vrf_link(ripng, vrf);
2484 ripng->enabled = true;
2485
f9120f71
RW
2486 /* Resend all redistribute requests. */
2487 ripng_redistribute_enable(ripng);
2488
dde7b15b
RW
2489 /* Create read and timer thread. */
2490 ripng_event(ripng, RIPNG_READ, ripng->sock);
2491 ripng_event(ripng, RIPNG_UPDATE_EVENT, 1);
2492
2493 ripng_zebra_vrf_register(vrf);
2494}
2495
2496static void ripng_instance_disable(struct ripng *ripng)
2497{
2498 struct vrf *vrf = ripng->vrf;
2499 struct agg_node *rp;
2500
2501 /* Clear RIPng routes */
2502 for (rp = agg_route_top(ripng->table); rp; rp = agg_route_next(rp)) {
2503 struct ripng_aggregate *aggregate;
2504 struct list *list;
2505
2506 if ((list = rp->info) != NULL) {
2507 struct ripng_info *rinfo;
2508 struct listnode *listnode;
2509
2510 rinfo = listgetdata(listhead(list));
2511 if (ripng_route_rte(rinfo))
2512 ripng_zebra_ipv6_delete(ripng, rp);
2513
2514 for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) {
e16d030c
DS
2515 EVENT_OFF(rinfo->t_timeout);
2516 EVENT_OFF(rinfo->t_garbage_collect);
dde7b15b
RW
2517 ripng_info_free(rinfo);
2518 }
2519 list_delete(&list);
2520 rp->info = NULL;
2521 agg_unlock_node(rp);
2522 }
2523
2524 if ((aggregate = rp->aggregate) != NULL) {
2525 ripng_aggregate_free(aggregate);
2526 rp->aggregate = NULL;
2527 agg_unlock_node(rp);
2528 }
2529 }
2530
f9120f71
RW
2531 /* Flush all redistribute requests. */
2532 ripng_redistribute_disable(ripng);
2533
dde7b15b 2534 /* Cancel the RIPng timers */
e16d030c
DS
2535 EVENT_OFF(ripng->t_update);
2536 EVENT_OFF(ripng->t_triggered_update);
2537 EVENT_OFF(ripng->t_triggered_interval);
dde7b15b
RW
2538
2539 /* Cancel the read thread */
e16d030c 2540 EVENT_OFF(ripng->t_read);
dde7b15b
RW
2541
2542 /* Close the RIPng socket */
2543 if (ripng->sock >= 0) {
2544 close(ripng->sock);
2545 ripng->sock = -1;
2546 }
2547
2548 /* Clear existing peers. */
2549 list_delete_all_node(ripng->peer_list);
2550
2551 ripng_zebra_vrf_deregister(vrf);
2552
2553 ripng_vrf_unlink(ripng, vrf);
2554 ripng->enabled = false;
2555}
2556
2557static int ripng_vrf_new(struct vrf *vrf)
2558{
2559 if (IS_RIPNG_DEBUG_EVENT)
2560 zlog_debug("%s: VRF created: %s(%u)", __func__, vrf->name,
2561 vrf->vrf_id);
2562
2563 return 0;
2564}
2565
2566static int ripng_vrf_delete(struct vrf *vrf)
2567{
b1d29673
DS
2568 struct ripng *ripng;
2569
dde7b15b
RW
2570 if (IS_RIPNG_DEBUG_EVENT)
2571 zlog_debug("%s: VRF deleted: %s(%u)", __func__, vrf->name,
2572 vrf->vrf_id);
2573
b1d29673
DS
2574 ripng = ripng_lookup_by_vrf_name(vrf->name);
2575 if (!ripng)
2576 return 0;
2577
2578 ripng_clean(ripng);
dde7b15b
RW
2579 return 0;
2580}
2581
2582static int ripng_vrf_enable(struct vrf *vrf)
2583{
2584 struct ripng *ripng;
2585 int socket;
2586
2587 ripng = ripng_lookup_by_vrf_name(vrf->name);
ac2cb9bf 2588 if (!ripng || ripng->enabled)
dde7b15b
RW
2589 return 0;
2590
2591 if (IS_RIPNG_DEBUG_EVENT)
2592 zlog_debug("%s: VRF %s(%u) enabled", __func__, vrf->name,
2593 vrf->vrf_id);
2594
2595 /* Activate the VRF RIPng instance. */
be2bad2e
PG
2596 socket = ripng_make_socket(vrf);
2597 if (socket < 0)
2598 return -1;
dde7b15b 2599
be2bad2e 2600 ripng_instance_enable(ripng, vrf, socket);
dde7b15b
RW
2601
2602 return 0;
2603}
2604
2605static int ripng_vrf_disable(struct vrf *vrf)
2606{
2607 struct ripng *ripng;
2608
2609 ripng = ripng_lookup_by_vrf_name(vrf->name);
2610 if (!ripng || !ripng->enabled)
2611 return 0;
2612
2613 if (IS_RIPNG_DEBUG_EVENT)
2614 zlog_debug("%s: VRF %s(%u) disabled", __func__, vrf->name,
2615 vrf->vrf_id);
2616
2617 /* Deactivate the VRF RIPng instance. */
2618 if (ripng->enabled)
2619 ripng_instance_disable(ripng);
2620
2621 return 0;
2622}
2623
2624void ripng_vrf_init(void)
2625{
2626 vrf_init(ripng_vrf_new, ripng_vrf_enable, ripng_vrf_disable,
ac2cb9bf 2627 ripng_vrf_delete);
f5eef2d5 2628
cfc369c4 2629 vrf_cmd_init(NULL);
dde7b15b
RW
2630}
2631
2632void ripng_vrf_terminate(void)
2633{
2634 vrf_terminate();
2635}
2636
718e3744 2637/* Initialize ripng structure and set commands. */
4d762f26 2638void ripng_init(void)
718e3744 2639{
d62a17ae 2640 /* Install RIPNG_NODE. */
612c2c15 2641 install_node(&cmd_ripng_node);
718e3744 2642
d62a17ae 2643 /* Install ripng commands. */
2644 install_element(VIEW_NODE, &show_ipv6_ripng_cmd);
2645 install_element(VIEW_NODE, &show_ipv6_ripng_status_cmd);
718e3744 2646
d62a17ae 2647 install_default(RIPNG_NODE);
718e3744 2648
d62a17ae 2649 ripng_if_init();
2650 ripng_debug_init();
718e3744 2651
d62a17ae 2652 /* Access list install. */
2653 access_list_init();
2654 access_list_add_hook(ripng_distribute_update_all_wrapper);
2655 access_list_delete_hook(ripng_distribute_update_all_wrapper);
718e3744 2656
d62a17ae 2657 /* Prefix list initialize.*/
2658 prefix_list_init();
2659 prefix_list_add_hook(ripng_distribute_update_all);
2660 prefix_list_delete_hook(ripng_distribute_update_all);
718e3744 2661
d62a17ae 2662 /* Route-map for interface. */
2663 ripng_route_map_init();
a94434b6 2664
d62a17ae 2665 route_map_add_hook(ripng_routemap_update);
2666 route_map_delete_hook(ripng_routemap_update);
718e3744 2667
d62a17ae 2668 if_rmap_init(RIPNG_NODE);
718e3744 2669}