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