]> git.proxmox.com Git - mirror_frr.git/blame - ripngd/ripng_interface.c
Merge pull request #4333 from opensourcerouting/printfrr
[mirror_frr.git] / ripngd / ripng_interface.c
CommitLineData
718e3744 1/*
2 * Interface related function for RIPng.
3 * Copyright (C) 1998 Kunihiro Ishiguro
4 *
5 * This file is part of GNU Zebra.
6 *
7 * GNU Zebra is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2, or (at your option) any
10 * later version.
11 *
12 * GNU Zebra is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
896014f4
DL
17 * You should have received a copy of the GNU General Public License along
18 * with this program; see the file COPYING; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
718e3744 20 */
21
22#include <zebra.h>
23
24#include "linklist.h"
25#include "if.h"
26#include "prefix.h"
27#include "memory.h"
28#include "network.h"
29#include "filter.h"
30#include "log.h"
31#include "stream.h"
32#include "zclient.h"
33#include "command.h"
fe08ba7e 34#include "agg_table.h"
718e3744 35#include "thread.h"
4d4653af 36#include "privs.h"
6a69b354 37#include "vrf.h"
7f9a4fd7 38#include "lib_errors.h"
d406db4c 39#include "northbound_cli.h"
718e3744 40
41#include "ripngd/ripngd.h"
42#include "ripngd/ripng_debug.h"
6b0655a2 43
718e3744 44/* If RFC2133 definition is used. */
45#ifndef IPV6_JOIN_GROUP
46#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
47#endif
48#ifndef IPV6_LEAVE_GROUP
49#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
50#endif
51
52/* Static utility function. */
d62a17ae 53static void ripng_enable_apply(struct interface *);
54static void ripng_passive_interface_apply(struct interface *);
5c84b9a5 55static int ripng_enable_if_lookup(struct ripng *ripng, const char *ifname);
d62a17ae 56static int ripng_enable_network_lookup2(struct connected *);
5c84b9a5 57static void ripng_enable_apply_all(struct ripng *ripng);
718e3744 58
59/* Join to the all rip routers multicast group. */
5c84b9a5 60static int ripng_multicast_join(struct interface *ifp, int sock)
718e3744 61{
d62a17ae 62 int ret;
63 struct ipv6_mreq mreq;
64 int save_errno;
65
66 if (if_is_multicast(ifp)) {
67 memset(&mreq, 0, sizeof(mreq));
68 inet_pton(AF_INET6, RIPNG_GROUP, &mreq.ipv6mr_multiaddr);
69 mreq.ipv6mr_interface = ifp->ifindex;
70
71 /*
72 * NetBSD 1.6.2 requires root to join groups on gif(4).
73 * While this is bogus, privs are available and easy to use
74 * for this call as a workaround.
75 */
01b9e3fd 76 frr_elevate_privs(&ripngd_privs) {
d62a17ae 77
5c84b9a5 78 ret = setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
01b9e3fd
DL
79 (char *)&mreq, sizeof(mreq));
80 save_errno = errno;
d62a17ae 81
01b9e3fd 82 }
d62a17ae 83
84 if (ret < 0 && save_errno == EADDRINUSE) {
85 /*
86 * Group is already joined. This occurs due to sloppy
87 * group
88 * management, in particular declining to leave the
89 * group on
90 * an interface that has just gone down.
91 */
9165c5f5 92 zlog_warn("ripng join on %s EADDRINUSE (ignoring)",
d62a17ae 93 ifp->name);
94 return 0; /* not an error */
95 }
96
97 if (ret < 0)
98 zlog_warn("can't setsockopt IPV6_JOIN_GROUP: %s",
99 safe_strerror(save_errno));
100
101 if (IS_RIPNG_DEBUG_EVENT)
102 zlog_debug(
103 "RIPng %s join to all-rip-routers multicast group",
104 ifp->name);
105
106 if (ret < 0)
107 return -1;
108 }
109 return 0;
718e3744 110}
111
112/* Leave from the all rip routers multicast group. */
5c84b9a5 113static int ripng_multicast_leave(struct interface *ifp, int sock)
718e3744 114{
d62a17ae 115 int ret;
116 struct ipv6_mreq mreq;
117
118 if (if_is_multicast(ifp)) {
119 memset(&mreq, 0, sizeof(mreq));
120 inet_pton(AF_INET6, RIPNG_GROUP, &mreq.ipv6mr_multiaddr);
121 mreq.ipv6mr_interface = ifp->ifindex;
122
5c84b9a5 123 ret = setsockopt(sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
d62a17ae 124 (char *)&mreq, sizeof(mreq));
125 if (ret < 0)
9165c5f5 126 zlog_warn("can't setsockopt IPV6_LEAVE_GROUP: %s",
d62a17ae 127 safe_strerror(errno));
128
129 if (IS_RIPNG_DEBUG_EVENT)
130 zlog_debug(
131 "RIPng %s leave from all-rip-routers multicast group",
132 ifp->name);
133
134 if (ret < 0)
135 return -1;
136 }
a94434b6 137
d62a17ae 138 return 0;
a94434b6 139}
140
141/* How many link local IPv6 address could be used on the interface ? */
d62a17ae 142static int ripng_if_ipv6_lladdress_check(struct interface *ifp)
a94434b6 143{
d62a17ae 144 struct listnode *nn;
145 struct connected *connected;
146 int count = 0;
a94434b6 147
d62a17ae 148 for (ALL_LIST_ELEMENTS_RO(ifp->connected, nn, connected)) {
149 struct prefix *p;
150 p = connected->address;
718e3744 151
d62a17ae 152 if ((p->family == AF_INET6)
153 && IN6_IS_ADDR_LINKLOCAL(&p->u.prefix6))
154 count++;
155 }
718e3744 156
d62a17ae 157 return count;
718e3744 158}
159
d62a17ae 160static int ripng_if_down(struct interface *ifp)
718e3744 161{
fe08ba7e 162 struct agg_node *rp;
d62a17ae 163 struct ripng_info *rinfo;
164 struct ripng_interface *ri;
5c84b9a5 165 struct ripng *ripng;
d62a17ae 166 struct list *list = NULL;
167 struct listnode *listnode = NULL, *nextnode = NULL;
168
5c84b9a5
RW
169 ri = ifp->info;
170 ripng = ri->ripng;
171
d62a17ae 172 if (ripng)
fe08ba7e
DS
173 for (rp = agg_route_top(ripng->table); rp;
174 rp = agg_route_next(rp))
d62a17ae 175 if ((list = rp->info) != NULL)
176 for (ALL_LIST_ELEMENTS(list, listnode, nextnode,
177 rinfo))
178 if (rinfo->ifindex == ifp->ifindex)
5c84b9a5 179 ripng_ecmp_delete(ripng, rinfo);
d62a17ae 180
d62a17ae 181
182 if (ri->running) {
183 if (IS_RIPNG_DEBUG_EVENT)
184 zlog_debug("turn off %s", ifp->name);
185
186 /* Leave from multicast group. */
5c84b9a5 187 ripng_multicast_leave(ifp, ripng->sock);
d62a17ae 188
189 ri->running = 0;
190 }
191
192 return 0;
718e3744 193}
194
195/* Inteface link up message processing. */
121f9dee 196int ripng_interface_up(ZAPI_CALLBACK_ARGS)
718e3744 197{
d62a17ae 198 struct stream *s;
199 struct interface *ifp;
718e3744 200
d62a17ae 201 /* zebra_interface_state_read() updates interface structure in iflist.
202 */
203 s = zclient->ibuf;
204 ifp = zebra_interface_state_read(s, vrf_id);
718e3744 205
d62a17ae 206 if (ifp == NULL)
207 return 0;
718e3744 208
d62a17ae 209 if (IS_RIPNG_DEBUG_ZEBRA)
210 zlog_debug(
dde7b15b
RW
211 "interface up %s vrf %u index %d flags %llx metric %d mtu %d",
212 ifp->name, ifp->vrf_id, ifp->ifindex,
213 (unsigned long long)ifp->flags, ifp->metric, ifp->mtu6);
214
215 ripng_interface_sync(ifp);
718e3744 216
d62a17ae 217 /* Check if this interface is RIPng enabled or not. */
218 ripng_enable_apply(ifp);
718e3744 219
d62a17ae 220 /* Check for a passive interface. */
221 ripng_passive_interface_apply(ifp);
718e3744 222
d62a17ae 223 /* Apply distribute list to the all interface. */
224 ripng_distribute_update_interface(ifp);
718e3744 225
d62a17ae 226 return 0;
718e3744 227}
228
229/* Inteface link down message processing. */
121f9dee 230int ripng_interface_down(ZAPI_CALLBACK_ARGS)
718e3744 231{
d62a17ae 232 struct stream *s;
233 struct interface *ifp;
718e3744 234
d62a17ae 235 /* zebra_interface_state_read() updates interface structure in iflist.
236 */
237 s = zclient->ibuf;
238 ifp = zebra_interface_state_read(s, vrf_id);
718e3744 239
d62a17ae 240 if (ifp == NULL)
241 return 0;
718e3744 242
dde7b15b 243 ripng_interface_sync(ifp);
d62a17ae 244 ripng_if_down(ifp);
718e3744 245
d62a17ae 246 if (IS_RIPNG_DEBUG_ZEBRA)
247 zlog_debug(
dde7b15b
RW
248 "interface down %s vrf %u index %d flags %#llx metric %d mtu %d",
249 ifp->name, ifp->vrf_id, ifp->ifindex,
250 (unsigned long long)ifp->flags, ifp->metric, ifp->mtu6);
718e3744 251
d62a17ae 252 return 0;
718e3744 253}
254
255/* Inteface addition message from zebra. */
121f9dee 256int ripng_interface_add(ZAPI_CALLBACK_ARGS)
718e3744 257{
d62a17ae 258 struct interface *ifp;
718e3744 259
d62a17ae 260 ifp = zebra_interface_add_read(zclient->ibuf, vrf_id);
dde7b15b 261 ripng_interface_sync(ifp);
718e3744 262
d62a17ae 263 if (IS_RIPNG_DEBUG_ZEBRA)
264 zlog_debug(
dde7b15b
RW
265 "RIPng interface add %s vrf %u index %d flags %#llx metric %d mtu %d",
266 ifp->name, ifp->vrf_id, ifp->ifindex,
267 (unsigned long long)ifp->flags, ifp->metric, ifp->mtu6);
718e3744 268
d62a17ae 269 /* Check is this interface is RIP enabled or not.*/
270 ripng_enable_apply(ifp);
718e3744 271
d62a17ae 272 /* Apply distribute list to the interface. */
273 ripng_distribute_update_interface(ifp);
718e3744 274
d62a17ae 275 /* Check interface routemap. */
276 ripng_if_rmap_update_interface(ifp);
718e3744 277
d62a17ae 278 return 0;
718e3744 279}
280
121f9dee 281int ripng_interface_delete(ZAPI_CALLBACK_ARGS)
718e3744 282{
d62a17ae 283 struct interface *ifp;
284 struct stream *s;
a94434b6 285
d62a17ae 286 s = zclient->ibuf;
287 /* zebra_interface_state_read() updates interface structure in iflist
288 */
289 ifp = zebra_interface_state_read(s, vrf_id);
a94434b6 290
d62a17ae 291 if (ifp == NULL)
292 return 0;
a94434b6 293
dde7b15b 294 ripng_interface_sync(ifp);
d62a17ae 295 if (if_is_up(ifp)) {
296 ripng_if_down(ifp);
297 }
a94434b6 298
dde7b15b
RW
299 zlog_info(
300 "interface delete %s vrf %u index %d flags %#llx metric %d mtu %d",
301 ifp->name, ifp->vrf_id, ifp->ifindex,
302 (unsigned long long)ifp->flags, ifp->metric, ifp->mtu6);
a94434b6 303
d62a17ae 304 /* To support pseudo interface do not free interface structure. */
305 /* if_delete(ifp); */
ff880b78 306 if_set_index(ifp, IFINDEX_INTERNAL);
a94434b6 307
d62a17ae 308 return 0;
718e3744 309}
310
dde7b15b 311/* VRF update for an interface. */
121f9dee 312int ripng_interface_vrf_update(ZAPI_CALLBACK_ARGS)
dde7b15b
RW
313{
314 struct interface *ifp;
315 vrf_id_t new_vrf_id;
316
317 ifp = zebra_interface_vrf_update_read(zclient->ibuf, vrf_id,
318 &new_vrf_id);
319 if (!ifp)
320 return 0;
321
322 if (IS_RIPNG_DEBUG_ZEBRA)
323 zlog_debug("interface %s VRF change vrf_id %u new vrf id %u",
324 ifp->name, vrf_id, new_vrf_id);
325
326 if_update_to_new_vrf(ifp, new_vrf_id);
327 ripng_interface_sync(ifp);
328
329 return 0;
330}
331
5c84b9a5 332void ripng_interface_clean(struct ripng *ripng)
a94434b6 333{
d62a17ae 334 struct interface *ifp;
335 struct ripng_interface *ri;
a94434b6 336
dde7b15b 337 FOR_ALL_INTERFACES (ripng->vrf, ifp) {
d62a17ae 338 ri = ifp->info;
a94434b6 339
d62a17ae 340 ri->enable_network = 0;
341 ri->enable_interface = 0;
342 ri->running = 0;
a94434b6 343
d62a17ae 344 if (ri->t_wakeup) {
345 thread_cancel(ri->t_wakeup);
346 ri->t_wakeup = NULL;
347 }
348 }
349}
a94434b6 350
d62a17ae 351static void ripng_apply_address_add(struct connected *ifc)
352{
5c84b9a5
RW
353 struct ripng_interface *ri = ifc->ifp->info;
354 struct ripng *ripng = ri->ripng;
d62a17ae 355 struct prefix_ipv6 address;
356 struct prefix *p;
357
358 if (!ripng)
359 return;
360
361 if (!if_is_up(ifc->ifp))
362 return;
363
364 p = ifc->address;
365
366 memset(&address, 0, sizeof(address));
367 address.family = p->family;
368 address.prefix = p->u.prefix6;
369 address.prefixlen = p->prefixlen;
370 apply_mask_ipv6(&address);
371
372 /* Check if this interface is RIP enabled or not
373 or Check if this address's prefix is RIP enabled */
5c84b9a5 374 if ((ripng_enable_if_lookup(ripng, ifc->ifp->name) >= 0)
d62a17ae 375 || (ripng_enable_network_lookup2(ifc) >= 0))
5c84b9a5 376 ripng_redistribute_add(ripng, ZEBRA_ROUTE_CONNECT,
d62a17ae 377 RIPNG_ROUTE_INTERFACE, &address,
378 ifc->ifp->ifindex, NULL, 0);
a94434b6 379}
380
121f9dee 381int ripng_interface_address_add(ZAPI_CALLBACK_ARGS)
718e3744 382{
d62a17ae 383 struct connected *c;
384 struct prefix *p;
718e3744 385
d62a17ae 386 c = zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_ADD,
387 zclient->ibuf, vrf_id);
718e3744 388
d62a17ae 389 if (c == NULL)
390 return 0;
718e3744 391
d62a17ae 392 p = c->address;
718e3744 393
d62a17ae 394 if (p->family == AF_INET6) {
395 struct ripng_interface *ri = c->ifp->info;
a94434b6 396
d62a17ae 397 if (IS_RIPNG_DEBUG_ZEBRA)
398 zlog_debug("RIPng connected address %s/%d add",
399 inet6_ntoa(p->u.prefix6), p->prefixlen);
a94434b6 400
d62a17ae 401 /* Check is this prefix needs to be redistributed. */
402 ripng_apply_address_add(c);
a94434b6 403
d62a17ae 404 /* Let's try once again whether the interface could be activated
405 */
406 if (!ri->running) {
407 /* Check if this interface is RIP enabled or not.*/
408 ripng_enable_apply(c->ifp);
a94434b6 409
d62a17ae 410 /* Apply distribute list to the interface. */
411 ripng_distribute_update_interface(c->ifp);
718e3744 412
d62a17ae 413 /* Check interface routemap. */
414 ripng_if_rmap_update_interface(c->ifp);
415 }
416 }
417
418 return 0;
718e3744 419}
420
d62a17ae 421static void ripng_apply_address_del(struct connected *ifc)
422{
5c84b9a5
RW
423 struct ripng_interface *ri = ifc->ifp->info;
424 struct ripng *ripng = ri->ripng;
d62a17ae 425 struct prefix_ipv6 address;
426 struct prefix *p;
a94434b6 427
d62a17ae 428 if (!ripng)
429 return;
a94434b6 430
d62a17ae 431 if (!if_is_up(ifc->ifp))
432 return;
a94434b6 433
d62a17ae 434 p = ifc->address;
a94434b6 435
d62a17ae 436 memset(&address, 0, sizeof(address));
437 address.family = p->family;
438 address.prefix = p->u.prefix6;
439 address.prefixlen = p->prefixlen;
440 apply_mask_ipv6(&address);
a94434b6 441
5c84b9a5
RW
442 ripng_redistribute_delete(ripng, ZEBRA_ROUTE_CONNECT,
443 RIPNG_ROUTE_INTERFACE, &address,
444 ifc->ifp->ifindex);
a94434b6 445}
446
121f9dee 447int ripng_interface_address_delete(ZAPI_CALLBACK_ARGS)
718e3744 448{
d62a17ae 449 struct connected *ifc;
450 struct prefix *p;
451 char buf[INET6_ADDRSTRLEN];
452
453 ifc = zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_DELETE,
454 zclient->ibuf, vrf_id);
455
456 if (ifc) {
457 p = ifc->address;
458
459 if (p->family == AF_INET6) {
460 if (IS_RIPNG_DEBUG_ZEBRA)
461 zlog_debug(
462 "RIPng connected address %s/%d delete",
463 inet_ntop(AF_INET6, &p->u.prefix6, buf,
464 INET6_ADDRSTRLEN),
465 p->prefixlen);
466
467 /* Check wether this prefix needs to be removed. */
468 ripng_apply_address_del(ifc);
469 }
470 connected_free(ifc);
718e3744 471 }
718e3744 472
d62a17ae 473 return 0;
718e3744 474}
6b0655a2 475
718e3744 476/* Lookup RIPng enable network. */
a94434b6 477/* Check wether the interface has at least a connected prefix that
29b94d58 478 * is within the ripng->enable_network table. */
d62a17ae 479static int ripng_enable_network_lookup_if(struct interface *ifp)
718e3744 480{
5c84b9a5
RW
481 struct ripng_interface *ri = ifp->info;
482 struct ripng *ripng = ri->ripng;
d62a17ae 483 struct listnode *node;
484 struct connected *connected;
485 struct prefix_ipv6 address;
486
29b94d58
RW
487 if (!ripng)
488 return -1;
489
d62a17ae 490 for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, connected)) {
491 struct prefix *p;
fe08ba7e 492 struct agg_node *n;
d62a17ae 493
494 p = connected->address;
495
496 if (p->family == AF_INET6) {
497 address.family = AF_INET6;
498 address.prefix = p->u.prefix6;
499 address.prefixlen = IPV6_MAX_BITLEN;
500
29b94d58 501 n = agg_node_match(ripng->enable_network,
fe08ba7e 502 (struct prefix *)&address);
ee6f7757 503 if (n) {
fe08ba7e 504 agg_unlock_node(n);
d62a17ae 505 return 1;
506 }
507 }
508 }
509 return -1;
718e3744 510}
511
29b94d58 512/* Check wether connected is within the ripng->enable_network table. */
d62a17ae 513static int ripng_enable_network_lookup2(struct connected *connected)
a94434b6 514{
5c84b9a5
RW
515 struct ripng_interface *ri = connected->ifp->info;
516 struct ripng *ripng = ri->ripng;
d62a17ae 517 struct prefix_ipv6 address;
518 struct prefix *p;
a94434b6 519
29b94d58
RW
520 if (!ripng)
521 return -1;
522
d62a17ae 523 p = connected->address;
a94434b6 524
d62a17ae 525 if (p->family == AF_INET6) {
fe08ba7e 526 struct agg_node *node;
a94434b6 527
d62a17ae 528 address.family = p->family;
529 address.prefix = p->u.prefix6;
530 address.prefixlen = IPV6_MAX_BITLEN;
a94434b6 531
d62a17ae 532 /* LPM on p->family, p->u.prefix6/IPV6_MAX_BITLEN within
29b94d58
RW
533 * ripng->enable_network */
534 node = agg_node_match(ripng->enable_network,
fe08ba7e 535 (struct prefix *)&address);
a94434b6 536
d62a17ae 537 if (node) {
fe08ba7e 538 agg_unlock_node(node);
d62a17ae 539 return 1;
540 }
541 }
a94434b6 542
d62a17ae 543 return -1;
a94434b6 544}
545
718e3744 546/* Add RIPng enable network. */
5c84b9a5 547int ripng_enable_network_add(struct ripng *ripng, struct prefix *p)
718e3744 548{
fe08ba7e 549 struct agg_node *node;
718e3744 550
29b94d58 551 node = agg_node_get(ripng->enable_network, p);
718e3744 552
d62a17ae 553 if (node->info) {
fe08ba7e 554 agg_unlock_node(node);
cc48702b 555 return NB_ERR_INCONSISTENCY;
d62a17ae 556 } else
557 node->info = (void *)1;
718e3744 558
d62a17ae 559 /* XXX: One should find a better solution than a generic one */
5c84b9a5 560 ripng_enable_apply_all(ripng);
a94434b6 561
cc48702b 562 return NB_OK;
718e3744 563}
564
565/* Delete RIPng enable network. */
5c84b9a5 566int ripng_enable_network_delete(struct ripng *ripng, struct prefix *p)
718e3744 567{
fe08ba7e 568 struct agg_node *node;
718e3744 569
29b94d58 570 node = agg_node_lookup(ripng->enable_network, p);
d62a17ae 571 if (node) {
572 node->info = NULL;
718e3744 573
d62a17ae 574 /* Unlock info lock. */
fe08ba7e 575 agg_unlock_node(node);
718e3744 576
d62a17ae 577 /* Unlock lookup lock. */
fe08ba7e 578 agg_unlock_node(node);
718e3744 579
cc48702b 580 return NB_OK;
d62a17ae 581 }
cc48702b
RW
582
583 return NB_ERR_INCONSISTENCY;
718e3744 584}
585
586/* Lookup function. */
5c84b9a5 587static int ripng_enable_if_lookup(struct ripng *ripng, const char *ifname)
718e3744 588{
d62a17ae 589 unsigned int i;
590 char *str;
591
b0ba762f
RW
592 if (!ripng)
593 return -1;
594
595 for (i = 0; i < vector_active(ripng->enable_if); i++)
596 if ((str = vector_slot(ripng->enable_if, i)) != NULL)
d62a17ae 597 if (strcmp(str, ifname) == 0)
598 return i;
599 return -1;
718e3744 600}
601
5c84b9a5 602int ripng_enable_if_add(struct ripng *ripng, const char *ifname)
718e3744 603{
d62a17ae 604 int ret;
718e3744 605
5c84b9a5 606 ret = ripng_enable_if_lookup(ripng, ifname);
d62a17ae 607 if (ret >= 0)
cc48702b 608 return NB_ERR_INCONSISTENCY;
718e3744 609
b0ba762f 610 vector_set(ripng->enable_if, strdup(ifname));
718e3744 611
5c84b9a5 612 ripng_enable_apply_all(ripng);
a94434b6 613
cc48702b 614 return NB_OK;
718e3744 615}
616
5c84b9a5 617int ripng_enable_if_delete(struct ripng *ripng, const char *ifname)
718e3744 618{
d62a17ae 619 int index;
620 char *str;
718e3744 621
5c84b9a5 622 index = ripng_enable_if_lookup(ripng, ifname);
d62a17ae 623 if (index < 0)
cc48702b 624 return NB_ERR_INCONSISTENCY;
718e3744 625
b0ba762f 626 str = vector_slot(ripng->enable_if, index);
d62a17ae 627 free(str);
b0ba762f 628 vector_unset(ripng->enable_if, index);
718e3744 629
5c84b9a5 630 ripng_enable_apply_all(ripng);
a94434b6 631
cc48702b 632 return NB_OK;
718e3744 633}
634
635/* Wake up interface. */
d62a17ae 636static int ripng_interface_wakeup(struct thread *t)
718e3744 637{
d62a17ae 638 struct interface *ifp;
639 struct ripng_interface *ri;
718e3744 640
d62a17ae 641 /* Get interface. */
642 ifp = THREAD_ARG(t);
718e3744 643
d62a17ae 644 ri = ifp->info;
645 ri->t_wakeup = NULL;
718e3744 646
d62a17ae 647 /* Join to multicast group. */
5c84b9a5 648 if (ripng_multicast_join(ifp, ri->ripng->sock) < 0) {
450971aa 649 flog_err_sys(EC_LIB_SOCKET,
09c866e3
QY
650 "multicast join failed, interface %s not running",
651 ifp->name);
d62a17ae 652 return 0;
653 }
654
655 /* Set running flag. */
656 ri->running = 1;
718e3744 657
d62a17ae 658 /* Send RIP request to the interface. */
659 ripng_request(ifp);
718e3744 660
d62a17ae 661 return 0;
718e3744 662}
663
d62a17ae 664static void ripng_connect_set(struct interface *ifp, int set)
a94434b6 665{
5c84b9a5
RW
666 struct ripng_interface *ri = ifp->info;
667 struct ripng *ripng = ri->ripng;
d62a17ae 668 struct listnode *node, *nnode;
669 struct connected *connected;
670 struct prefix_ipv6 address;
671
672 for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, connected)) {
673 struct prefix *p;
674 p = connected->address;
675
676 if (p->family != AF_INET6)
677 continue;
678
679 address.family = AF_INET6;
680 address.prefix = p->u.prefix6;
681 address.prefixlen = p->prefixlen;
682 apply_mask_ipv6(&address);
683
684 if (set) {
685 /* Check once more wether this prefix is within a
686 * "network IF_OR_PREF" one */
5c84b9a5
RW
687 if ((ripng_enable_if_lookup(ripng, connected->ifp->name)
688 >= 0)
d62a17ae 689 || (ripng_enable_network_lookup2(connected) >= 0))
690 ripng_redistribute_add(
5c84b9a5 691 ripng, ZEBRA_ROUTE_CONNECT,
d62a17ae 692 RIPNG_ROUTE_INTERFACE, &address,
693 connected->ifp->ifindex, NULL, 0);
694 } else {
5c84b9a5
RW
695 ripng_redistribute_delete(ripng, ZEBRA_ROUTE_CONNECT,
696 RIPNG_ROUTE_INTERFACE,
697 &address,
698 connected->ifp->ifindex);
699 if (ripng_redistribute_check(ripng,
700 ZEBRA_ROUTE_CONNECT))
d62a17ae 701 ripng_redistribute_add(
5c84b9a5 702 ripng, ZEBRA_ROUTE_CONNECT,
d62a17ae 703 RIPNG_ROUTE_REDISTRIBUTE, &address,
704 connected->ifp->ifindex, NULL, 0);
705 }
706 }
a94434b6 707}
708
718e3744 709/* Check RIPng is enabed on this interface. */
d62a17ae 710void ripng_enable_apply(struct interface *ifp)
718e3744 711{
d62a17ae 712 int ret;
713 struct ripng_interface *ri = NULL;
714
715 /* Check interface. */
716 if (!if_is_up(ifp))
717 return;
718
719 ri = ifp->info;
720
721 /* Is this interface a candidate for RIPng ? */
722 ret = ripng_enable_network_lookup_if(ifp);
723
724 /* If the interface is matched. */
725 if (ret > 0)
726 ri->enable_network = 1;
727 else
728 ri->enable_network = 0;
729
730 /* Check interface name configuration. */
5c84b9a5 731 ret = ripng_enable_if_lookup(ri->ripng, ifp->name);
d62a17ae 732 if (ret >= 0)
733 ri->enable_interface = 1;
734 else
735 ri->enable_interface = 0;
736
737 /* any candidate interface MUST have a link-local IPv6 address */
738 if ((!ripng_if_ipv6_lladdress_check(ifp))
739 && (ri->enable_network || ri->enable_interface)) {
740 ri->enable_network = 0;
741 ri->enable_interface = 0;
742 zlog_warn("Interface %s does not have any link-local address",
743 ifp->name);
744 }
745
746 /* Update running status of the interface. */
747 if (ri->enable_network || ri->enable_interface) {
748 zlog_info("RIPng INTERFACE ON %s", ifp->name);
749
750 /* Add interface wake up thread. */
751 thread_add_timer(master, ripng_interface_wakeup, ifp, 1,
752 &ri->t_wakeup);
753
754 ripng_connect_set(ifp, 1);
755 } else {
756 if (ri->running) {
757 /* Might as well clean up the route table as well
758 * ripng_if_down sets to 0 ri->running, and displays
759 *"turn off %s"
760 **/
761 ripng_if_down(ifp);
762
763 ripng_connect_set(ifp, 0);
764 }
718e3744 765 }
718e3744 766}
767
768/* Set distribute list to all interfaces. */
5c84b9a5 769static void ripng_enable_apply_all(struct ripng *ripng)
718e3744 770{
d62a17ae 771 struct interface *ifp;
718e3744 772
dde7b15b 773 FOR_ALL_INTERFACES (ripng->vrf, ifp)
d62a17ae 774 ripng_enable_apply(ifp);
718e3744 775}
6b0655a2 776
a94434b6 777/* Clear all network and neighbor configuration */
5c84b9a5 778void ripng_clean_network(struct ripng *ripng)
a94434b6 779{
d62a17ae 780 unsigned int i;
781 char *str;
fe08ba7e 782 struct agg_node *rn;
d62a17ae 783
29b94d58
RW
784 /* ripng->enable_network */
785 for (rn = agg_route_top(ripng->enable_network); rn;
fe08ba7e 786 rn = agg_route_next(rn))
d62a17ae 787 if (rn->info) {
788 rn->info = NULL;
fe08ba7e 789 agg_unlock_node(rn);
d62a17ae 790 }
791
b0ba762f
RW
792 /* ripng->enable_if */
793 for (i = 0; i < vector_active(ripng->enable_if); i++)
794 if ((str = vector_slot(ripng->enable_if, i)) != NULL) {
d62a17ae 795 free(str);
b0ba762f 796 vector_slot(ripng->enable_if, i) = NULL;
d62a17ae 797 }
a94434b6 798}
6b0655a2 799
718e3744 800/* Utility function for looking up passive interface settings. */
5c84b9a5
RW
801static int ripng_passive_interface_lookup(struct ripng *ripng,
802 const char *ifname)
718e3744 803{
d62a17ae 804 unsigned int i;
805 char *str;
806
0c32404f
RW
807 for (i = 0; i < vector_active(ripng->passive_interface); i++)
808 if ((str = vector_slot(ripng->passive_interface, i)) != NULL)
d62a17ae 809 if (strcmp(str, ifname) == 0)
810 return i;
811 return -1;
718e3744 812}
813
d62a17ae 814void ripng_passive_interface_apply(struct interface *ifp)
718e3744 815{
d62a17ae 816 int ret;
817 struct ripng_interface *ri;
5c84b9a5 818 struct ripng *ripng;
718e3744 819
d62a17ae 820 ri = ifp->info;
5c84b9a5
RW
821 ripng = ri->ripng;
822 if (!ripng)
823 return;
718e3744 824
5c84b9a5 825 ret = ripng_passive_interface_lookup(ripng, ifp->name);
d62a17ae 826 if (ret < 0)
827 ri->passive = 0;
828 else
829 ri->passive = 1;
718e3744 830}
831
5c84b9a5 832static void ripng_passive_interface_apply_all(struct ripng *ripng)
718e3744 833{
d62a17ae 834 struct interface *ifp;
718e3744 835
dde7b15b 836 FOR_ALL_INTERFACES (ripng->vrf, ifp)
d62a17ae 837 ripng_passive_interface_apply(ifp);
718e3744 838}
839
840/* Passive interface. */
5c84b9a5 841int ripng_passive_interface_set(struct ripng *ripng, const char *ifname)
718e3744 842{
5c84b9a5 843 if (ripng_passive_interface_lookup(ripng, ifname) >= 0)
22e8c7ae 844 return NB_ERR_INCONSISTENCY;
718e3744 845
0c32404f 846 vector_set(ripng->passive_interface, strdup(ifname));
718e3744 847
5c84b9a5 848 ripng_passive_interface_apply_all(ripng);
718e3744 849
22e8c7ae 850 return NB_OK;
718e3744 851}
852
5c84b9a5 853int ripng_passive_interface_unset(struct ripng *ripng, const char *ifname)
718e3744 854{
d62a17ae 855 int i;
856 char *str;
718e3744 857
5c84b9a5 858 i = ripng_passive_interface_lookup(ripng, ifname);
d62a17ae 859 if (i < 0)
22e8c7ae 860 return NB_ERR_INCONSISTENCY;
718e3744 861
0c32404f 862 str = vector_slot(ripng->passive_interface, i);
d62a17ae 863 free(str);
0c32404f 864 vector_unset(ripng->passive_interface, i);
718e3744 865
5c84b9a5 866 ripng_passive_interface_apply_all(ripng);
718e3744 867
22e8c7ae 868 return NB_OK;
718e3744 869}
870
871/* Free all configured RIP passive-interface settings. */
5c84b9a5 872void ripng_passive_interface_clean(struct ripng *ripng)
718e3744 873{
d62a17ae 874 unsigned int i;
875 char *str;
876
0c32404f
RW
877 for (i = 0; i < vector_active(ripng->passive_interface); i++)
878 if ((str = vector_slot(ripng->passive_interface, i)) != NULL) {
d62a17ae 879 free(str);
0c32404f 880 vector_slot(ripng->passive_interface, i) = NULL;
d62a17ae 881 }
5c84b9a5 882 ripng_passive_interface_apply_all(ripng);
718e3744 883}
884
885/* Write RIPng enable network and interface to the vty. */
5c84b9a5 886int ripng_network_write(struct vty *vty, struct ripng *ripng)
718e3744 887{
d62a17ae 888 unsigned int i;
889 const char *ifname;
fe08ba7e 890 struct agg_node *node;
d62a17ae 891 char buf[BUFSIZ];
892
893 /* Write enable network. */
29b94d58 894 for (node = agg_route_top(ripng->enable_network); node;
fe08ba7e 895 node = agg_route_next(node))
d62a17ae 896 if (node->info) {
897 struct prefix *p = &node->p;
22e8c7ae 898 vty_out(vty, " %s/%d\n",
d62a17ae 899 inet_ntop(p->family, &p->u.prefix, buf, BUFSIZ),
900 p->prefixlen);
901 }
902
903 /* Write enable interface. */
b0ba762f
RW
904 for (i = 0; i < vector_active(ripng->enable_if); i++)
905 if ((ifname = vector_slot(ripng->enable_if, i)) != NULL)
22e8c7ae 906 vty_out(vty, " %s\n", ifname);
d62a17ae 907
908 return 0;
718e3744 909}
910
d62a17ae 911static struct ripng_interface *ri_new(void)
718e3744 912{
d62a17ae 913 struct ripng_interface *ri;
5c84b9a5 914
d62a17ae 915 ri = XCALLOC(MTYPE_IF, sizeof(struct ripng_interface));
a94434b6 916
d62a17ae 917 /* Set default split-horizon behavior. If the interface is Frame
918 Relay or SMDS is enabled, the default value for split-horizon is
919 off. But currently Zebra does detect Frame Relay or SMDS
920 interface. So all interface is set to split horizon. */
d406db4c
RW
921 ri->split_horizon =
922 yang_get_default_enum("%s/split-horizon", RIPNG_IFACE);
a94434b6 923
d62a17ae 924 return ri;
718e3744 925}
926
dde7b15b
RW
927void ripng_interface_sync(struct interface *ifp)
928{
929 struct vrf *vrf;
930
931 vrf = vrf_lookup_by_id(ifp->vrf_id);
932 if (vrf) {
933 struct ripng_interface *ri;
934
935 ri = ifp->info;
936 if (ri)
937 ri->ripng = vrf->info;
938 }
939}
940
d62a17ae 941static int ripng_if_new_hook(struct interface *ifp)
718e3744 942{
d62a17ae 943 ifp->info = ri_new();
dde7b15b
RW
944 ripng_interface_sync(ifp);
945
d62a17ae 946 return 0;
718e3744 947}
948
a94434b6 949/* Called when interface structure deleted. */
d62a17ae 950static int ripng_if_delete_hook(struct interface *ifp)
a94434b6 951{
d62a17ae 952 XFREE(MTYPE_IF, ifp->info);
953 ifp->info = NULL;
954 return 0;
a94434b6 955}
956
718e3744 957/* Configuration write function for ripngd. */
d62a17ae 958static int interface_config_write(struct vty *vty)
718e3744 959{
dde7b15b 960 struct vrf *vrf;
d62a17ae 961 int write = 0;
962
dde7b15b
RW
963 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
964 struct interface *ifp;
d62a17ae 965
dde7b15b
RW
966 FOR_ALL_INTERFACES (vrf, ifp) {
967 struct lyd_node *dnode;
d62a17ae 968
dde7b15b
RW
969 dnode = yang_dnode_get(
970 running_config->dnode,
971 "/frr-interface:lib/interface[name='%s'][vrf='%s']",
972 ifp->name, vrf->name);
973 if (dnode == NULL)
974 continue;
d62a17ae 975
dde7b15b
RW
976 write = 1;
977 nb_cli_show_dnode_cmds(vty, dnode, false);
978 }
a94434b6 979 }
d406db4c 980
d62a17ae 981 return write;
718e3744 982}
983
984/* ripngd's interface node. */
d62a17ae 985static struct cmd_node interface_node = {
986 INTERFACE_NODE, "%s(config-if)# ", 1 /* VTYSH */
718e3744 987};
988
989/* Initialization of interface. */
4d762f26 990void ripng_if_init(void)
718e3744 991{
d62a17ae 992 /* Interface initialize. */
ce19a04a
DL
993 hook_register_prio(if_add, 0, ripng_if_new_hook);
994 hook_register_prio(if_del, 0, ripng_if_delete_hook);
718e3744 995
d62a17ae 996 /* Install interface node. */
997 install_node(&interface_node, interface_config_write);
998 if_cmd_init();
718e3744 999}