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