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