]> git.proxmox.com Git - mirror_frr.git/blame - ripngd/ripng_interface.c
bgpd: fix werror warning for potentially uninitialized variable
[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 *
17 * You should have received a copy of the GNU General Public License
18 * along with GNU Zebra; see the file COPYING. If not, write to the Free
19 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
ac4d0be5 20 * 02111-1307, USA.
718e3744 21 */
22
23#include <zebra.h>
24
25#include "linklist.h"
26#include "if.h"
27#include "prefix.h"
28#include "memory.h"
29#include "network.h"
30#include "filter.h"
31#include "log.h"
32#include "stream.h"
33#include "zclient.h"
34#include "command.h"
35#include "table.h"
36#include "thread.h"
4d4653af 37#include "privs.h"
6a69b354 38#include "vrf.h"
718e3744 39
40#include "ripngd/ripngd.h"
41#include "ripngd/ripng_debug.h"
6b0655a2 42
718e3744 43/* If RFC2133 definition is used. */
44#ifndef IPV6_JOIN_GROUP
45#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
46#endif
47#ifndef IPV6_LEAVE_GROUP
48#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
49#endif
50
4d4653af 51extern struct zebra_privs_t ripngd_privs;
52
718e3744 53/* Static utility function. */
ac4d0be5 54static void ripng_enable_apply(struct interface *);
55static void ripng_passive_interface_apply(struct interface *);
56static int ripng_enable_if_lookup(const char *);
57static int ripng_enable_network_lookup2(struct connected *);
58static void ripng_enable_apply_all(void);
718e3744 59
60/* Join to the all rip routers multicast group. */
ac4d0be5 61static int ripng_multicast_join(struct interface *ifp)
718e3744 62{
ac4d0be5 63 int ret;
64 struct ipv6_mreq mreq;
65 int save_errno;
66
67 if (if_is_multicast(ifp)) {
68 memset(&mreq, 0, sizeof(mreq));
69 inet_pton(AF_INET6, RIPNG_GROUP, &mreq.ipv6mr_multiaddr);
70 mreq.ipv6mr_interface = ifp->ifindex;
71
72 /*
73 * NetBSD 1.6.2 requires root to join groups on gif(4).
74 * While this is bogus, privs are available and easy to use
75 * for this call as a workaround.
76 */
77 if (ripngd_privs.change(ZPRIVS_RAISE))
78 zlog_err("ripng_multicast_join: could not raise privs");
79
80 ret = setsockopt(ripng->sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
81 (char *)&mreq, sizeof(mreq));
82 save_errno = errno;
83
84 if (ripngd_privs.change(ZPRIVS_LOWER))
85 zlog_err("ripng_multicast_join: could not lower privs");
86
87 if (ret < 0 && save_errno == EADDRINUSE) {
88 /*
89 * Group is already joined. This occurs due to sloppy
90 * group
91 * management, in particular declining to leave the
92 * group on
93 * an interface that has just gone down.
94 */
95 zlog_warn("ripng join on %s EADDRINUSE (ignoring)\n",
96 ifp->name);
97 return 0; /* not an error */
98 }
99
100 if (ret < 0)
101 zlog_warn("can't setsockopt IPV6_JOIN_GROUP: %s",
102 safe_strerror(save_errno));
103
104 if (IS_RIPNG_DEBUG_EVENT)
105 zlog_debug(
106 "RIPng %s join to all-rip-routers multicast group",
107 ifp->name);
108
109 if (ret < 0)
110 return -1;
111 }
112 return 0;
718e3744 113}
114
115/* Leave from the all rip routers multicast group. */
ac4d0be5 116static int ripng_multicast_leave(struct interface *ifp)
718e3744 117{
ac4d0be5 118 int ret;
119 struct ipv6_mreq mreq;
120
121 if (if_is_multicast(ifp)) {
122 memset(&mreq, 0, sizeof(mreq));
123 inet_pton(AF_INET6, RIPNG_GROUP, &mreq.ipv6mr_multiaddr);
124 mreq.ipv6mr_interface = ifp->ifindex;
125
126 ret = setsockopt(ripng->sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
127 (char *)&mreq, sizeof(mreq));
128 if (ret < 0)
129 zlog_warn("can't setsockopt IPV6_LEAVE_GROUP: %s\n",
130 safe_strerror(errno));
131
132 if (IS_RIPNG_DEBUG_EVENT)
133 zlog_debug(
134 "RIPng %s leave from all-rip-routers multicast group",
135 ifp->name);
136
137 if (ret < 0)
138 return -1;
139 }
a94434b6 140
ac4d0be5 141 return 0;
a94434b6 142}
143
144/* How many link local IPv6 address could be used on the interface ? */
ac4d0be5 145static int ripng_if_ipv6_lladdress_check(struct interface *ifp)
a94434b6 146{
ac4d0be5 147 struct listnode *nn;
148 struct connected *connected;
149 int count = 0;
a94434b6 150
ac4d0be5 151 for (ALL_LIST_ELEMENTS_RO(ifp->connected, nn, connected)) {
152 struct prefix *p;
153 p = connected->address;
718e3744 154
ac4d0be5 155 if ((p->family == AF_INET6)
156 && IN6_IS_ADDR_LINKLOCAL(&p->u.prefix6))
157 count++;
158 }
718e3744 159
ac4d0be5 160 return count;
718e3744 161}
162
ac4d0be5 163static int ripng_if_down(struct interface *ifp)
718e3744 164{
ac4d0be5 165 struct route_node *rp;
166 struct ripng_info *rinfo;
167 struct ripng_interface *ri;
168 struct list *list = NULL;
169 struct listnode *listnode = NULL, *nextnode = NULL;
170
171 if (ripng)
172 for (rp = route_top(ripng->table); rp; rp = route_next(rp))
173 if ((list = rp->info) != NULL)
174 for (ALL_LIST_ELEMENTS(list, listnode, nextnode,
175 rinfo))
176 if (rinfo->ifindex == ifp->ifindex)
177 ripng_ecmp_delete(rinfo);
178
179 ri = ifp->info;
180
181 if (ri->running) {
182 if (IS_RIPNG_DEBUG_EVENT)
183 zlog_debug("turn off %s", ifp->name);
184
185 /* Leave from multicast group. */
186 ripng_multicast_leave(ifp);
187
188 ri->running = 0;
189 }
190
191 return 0;
718e3744 192}
193
194/* Inteface link up message processing. */
ac4d0be5 195int ripng_interface_up(int command, struct zclient *zclient,
196 zebra_size_t length, vrf_id_t vrf_id)
718e3744 197{
ac4d0be5 198 struct stream *s;
199 struct interface *ifp;
718e3744 200
ac4d0be5 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
ac4d0be5 206 if (ifp == NULL)
207 return 0;
718e3744 208
ac4d0be5 209 if (IS_RIPNG_DEBUG_ZEBRA)
210 zlog_debug(
211 "interface up %s index %d flags %llx metric %d mtu %d",
212 ifp->name, ifp->ifindex, (unsigned long long)ifp->flags,
213 ifp->metric, ifp->mtu6);
718e3744 214
ac4d0be5 215 /* Check if this interface is RIPng enabled or not. */
216 ripng_enable_apply(ifp);
718e3744 217
ac4d0be5 218 /* Check for a passive interface. */
219 ripng_passive_interface_apply(ifp);
718e3744 220
ac4d0be5 221 /* Apply distribute list to the all interface. */
222 ripng_distribute_update_interface(ifp);
718e3744 223
ac4d0be5 224 return 0;
718e3744 225}
226
227/* Inteface link down message processing. */
ac4d0be5 228int ripng_interface_down(int command, struct zclient *zclient,
229 zebra_size_t length, vrf_id_t vrf_id)
718e3744 230{
ac4d0be5 231 struct stream *s;
232 struct interface *ifp;
718e3744 233
ac4d0be5 234 /* zebra_interface_state_read() updates interface structure in iflist.
235 */
236 s = zclient->ibuf;
237 ifp = zebra_interface_state_read(s, vrf_id);
718e3744 238
ac4d0be5 239 if (ifp == NULL)
240 return 0;
718e3744 241
ac4d0be5 242 ripng_if_down(ifp);
718e3744 243
ac4d0be5 244 if (IS_RIPNG_DEBUG_ZEBRA)
245 zlog_debug(
246 "interface down %s index %d flags %#llx metric %d mtu %d",
247 ifp->name, ifp->ifindex, (unsigned long long)ifp->flags,
248 ifp->metric, ifp->mtu6);
718e3744 249
ac4d0be5 250 return 0;
718e3744 251}
252
253/* Inteface addition message from zebra. */
ac4d0be5 254int ripng_interface_add(int command, struct zclient *zclient,
255 zebra_size_t length, vrf_id_t vrf_id)
718e3744 256{
ac4d0be5 257 struct interface *ifp;
718e3744 258
ac4d0be5 259 ifp = zebra_interface_add_read(zclient->ibuf, vrf_id);
718e3744 260
ac4d0be5 261 if (IS_RIPNG_DEBUG_ZEBRA)
262 zlog_debug(
263 "RIPng interface add %s index %d flags %#llx metric %d mtu %d",
264 ifp->name, ifp->ifindex, (unsigned long long)ifp->flags,
265 ifp->metric, ifp->mtu6);
718e3744 266
ac4d0be5 267 /* Check is this interface is RIP enabled or not.*/
268 ripng_enable_apply(ifp);
718e3744 269
ac4d0be5 270 /* Apply distribute list to the interface. */
271 ripng_distribute_update_interface(ifp);
718e3744 272
ac4d0be5 273 /* Check interface routemap. */
274 ripng_if_rmap_update_interface(ifp);
718e3744 275
ac4d0be5 276 return 0;
718e3744 277}
278
ac4d0be5 279int ripng_interface_delete(int command, struct zclient *zclient,
280 zebra_size_t length, vrf_id_t vrf_id)
718e3744 281{
ac4d0be5 282 struct interface *ifp;
283 struct stream *s;
a94434b6 284
ac4d0be5 285 s = zclient->ibuf;
286 /* zebra_interface_state_read() updates interface structure in iflist
287 */
288 ifp = zebra_interface_state_read(s, vrf_id);
a94434b6 289
ac4d0be5 290 if (ifp == NULL)
291 return 0;
a94434b6 292
ac4d0be5 293 if (if_is_up(ifp)) {
294 ripng_if_down(ifp);
295 }
a94434b6 296
ac4d0be5 297 zlog_info("interface delete %s index %d flags %#llx metric %d mtu %d",
298 ifp->name, ifp->ifindex, (unsigned long long)ifp->flags,
299 ifp->metric, ifp->mtu6);
a94434b6 300
ac4d0be5 301 /* To support pseudo interface do not free interface structure. */
302 /* if_delete(ifp); */
303 ifp->ifindex = IFINDEX_DELETED;
718e3744 304
ac4d0be5 305 return 0;
a94434b6 306}
307
ac4d0be5 308void ripng_interface_clean(void)
6ac29a51 309{
ac4d0be5 310 struct listnode *node, *nnode;
311 struct interface *ifp;
312 struct ripng_interface *ri;
a94434b6 313
ac4d0be5 314 for (ALL_LIST_ELEMENTS(vrf_iflist(VRF_DEFAULT), node, nnode, ifp)) {
315 ri = ifp->info;
a94434b6 316
ac4d0be5 317 ri->enable_network = 0;
318 ri->enable_interface = 0;
319 ri->running = 0;
a94434b6 320
ac4d0be5 321 if (ri->t_wakeup) {
322 thread_cancel(ri->t_wakeup);
323 ri->t_wakeup = NULL;
324 }
325 }
326}
a94434b6 327
ac4d0be5 328void ripng_interface_reset(void)
329{
330 struct listnode *node;
331 struct interface *ifp;
332 struct ripng_interface *ri;
a94434b6 333
ac4d0be5 334 for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) {
335 ri = ifp->info;
a94434b6 336
ac4d0be5 337 ri->enable_network = 0;
338 ri->enable_interface = 0;
339 ri->running = 0;
a94434b6 340
ac4d0be5 341 ri->split_horizon = RIPNG_NO_SPLIT_HORIZON;
342 ri->split_horizon_default = RIPNG_NO_SPLIT_HORIZON;
a94434b6 343
ac4d0be5 344 ri->list[RIPNG_FILTER_IN] = NULL;
345 ri->list[RIPNG_FILTER_OUT] = NULL;
a94434b6 346
ac4d0be5 347 ri->prefix[RIPNG_FILTER_IN] = NULL;
348 ri->prefix[RIPNG_FILTER_OUT] = NULL;
a94434b6 349
ac4d0be5 350 if (ri->t_wakeup) {
351 thread_cancel(ri->t_wakeup);
352 ri->t_wakeup = NULL;
353 }
a94434b6 354
ac4d0be5 355 ri->passive = 0;
356 }
357}
a94434b6 358
ac4d0be5 359static void ripng_apply_address_add(struct connected *ifc)
360{
361 struct prefix_ipv6 address;
362 struct prefix *p;
363
364 if (!ripng)
365 return;
366
367 if (!if_is_up(ifc->ifp))
368 return;
369
370 p = ifc->address;
371
372 memset(&address, 0, sizeof(address));
373 address.family = p->family;
374 address.prefix = p->u.prefix6;
375 address.prefixlen = p->prefixlen;
376 apply_mask_ipv6(&address);
377
378 /* Check if this interface is RIP enabled or not
379 or Check if this address's prefix is RIP enabled */
380 if ((ripng_enable_if_lookup(ifc->ifp->name) >= 0)
381 || (ripng_enable_network_lookup2(ifc) >= 0))
382 ripng_redistribute_add(ZEBRA_ROUTE_CONNECT,
383 RIPNG_ROUTE_INTERFACE, &address,
384 ifc->ifp->ifindex, NULL, 0);
a94434b6 385}
386
ac4d0be5 387int ripng_interface_address_add(int command, struct zclient *zclient,
388 zebra_size_t length, vrf_id_t vrf_id)
718e3744 389{
ac4d0be5 390 struct connected *c;
391 struct prefix *p;
718e3744 392
ac4d0be5 393 c = zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_ADD,
394 zclient->ibuf, vrf_id);
718e3744 395
ac4d0be5 396 if (c == NULL)
397 return 0;
718e3744 398
ac4d0be5 399 p = c->address;
718e3744 400
ac4d0be5 401 if (p->family == AF_INET6) {
402 struct ripng_interface *ri = c->ifp->info;
a94434b6 403
ac4d0be5 404 if (IS_RIPNG_DEBUG_ZEBRA)
405 zlog_debug("RIPng connected address %s/%d add",
406 inet6_ntoa(p->u.prefix6), p->prefixlen);
a94434b6 407
ac4d0be5 408 /* Check is this prefix needs to be redistributed. */
409 ripng_apply_address_add(c);
a94434b6 410
ac4d0be5 411 /* Let's try once again whether the interface could be activated
412 */
413 if (!ri->running) {
414 /* Check if this interface is RIP enabled or not.*/
415 ripng_enable_apply(c->ifp);
a94434b6 416
ac4d0be5 417 /* Apply distribute list to the interface. */
418 ripng_distribute_update_interface(c->ifp);
718e3744 419
ac4d0be5 420 /* Check interface routemap. */
421 ripng_if_rmap_update_interface(c->ifp);
422 }
423 }
424
425 return 0;
718e3744 426}
427
ac4d0be5 428static void ripng_apply_address_del(struct connected *ifc)
429{
430 struct prefix_ipv6 address;
431 struct prefix *p;
a94434b6 432
ac4d0be5 433 if (!ripng)
434 return;
a94434b6 435
ac4d0be5 436 if (!if_is_up(ifc->ifp))
437 return;
a94434b6 438
ac4d0be5 439 p = ifc->address;
a94434b6 440
ac4d0be5 441 memset(&address, 0, sizeof(address));
442 address.family = p->family;
443 address.prefix = p->u.prefix6;
444 address.prefixlen = p->prefixlen;
445 apply_mask_ipv6(&address);
a94434b6 446
ac4d0be5 447 ripng_redistribute_delete(ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE,
448 &address, ifc->ifp->ifindex);
a94434b6 449}
450
ac4d0be5 451int ripng_interface_address_delete(int command, struct zclient *zclient,
452 zebra_size_t length, vrf_id_t vrf_id)
718e3744 453{
ac4d0be5 454 struct connected *ifc;
455 struct prefix *p;
456 char buf[INET6_ADDRSTRLEN];
457
458 ifc = zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_DELETE,
459 zclient->ibuf, vrf_id);
460
461 if (ifc) {
462 p = ifc->address;
463
464 if (p->family == AF_INET6) {
465 if (IS_RIPNG_DEBUG_ZEBRA)
466 zlog_debug(
467 "RIPng connected address %s/%d delete",
468 inet_ntop(AF_INET6, &p->u.prefix6, buf,
469 INET6_ADDRSTRLEN),
470 p->prefixlen);
471
472 /* Check wether this prefix needs to be removed. */
473 ripng_apply_address_del(ifc);
474 }
475 connected_free(ifc);
718e3744 476 }
718e3744 477
ac4d0be5 478 return 0;
718e3744 479}
6b0655a2 480
718e3744 481/* RIPng enable interface vector. */
482vector ripng_enable_if;
483
484/* RIPng enable network table. */
485struct route_table *ripng_enable_network;
486
487/* Lookup RIPng enable network. */
a94434b6 488/* Check wether the interface has at least a connected prefix that
489 * is within the ripng_enable_network table. */
ac4d0be5 490static int ripng_enable_network_lookup_if(struct interface *ifp)
718e3744 491{
ac4d0be5 492 struct listnode *node;
493 struct connected *connected;
494 struct prefix_ipv6 address;
495
496 for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, connected)) {
497 struct prefix *p;
498 struct route_node *node;
499
500 p = connected->address;
501
502 if (p->family == AF_INET6) {
503 address.family = AF_INET6;
504 address.prefix = p->u.prefix6;
505 address.prefixlen = IPV6_MAX_BITLEN;
506
507 node = route_node_match(ripng_enable_network,
508 (struct prefix *)&address);
509 if (node) {
510 route_unlock_node(node);
511 return 1;
512 }
513 }
514 }
515 return -1;
718e3744 516}
517
a94434b6 518/* Check wether connected is within the ripng_enable_network table. */
ac4d0be5 519static int ripng_enable_network_lookup2(struct connected *connected)
a94434b6 520{
ac4d0be5 521 struct prefix_ipv6 address;
522 struct prefix *p;
a94434b6 523
ac4d0be5 524 p = connected->address;
a94434b6 525
ac4d0be5 526 if (p->family == AF_INET6) {
527 struct route_node *node;
a94434b6 528
ac4d0be5 529 address.family = p->family;
530 address.prefix = p->u.prefix6;
531 address.prefixlen = IPV6_MAX_BITLEN;
a94434b6 532
ac4d0be5 533 /* LPM on p->family, p->u.prefix6/IPV6_MAX_BITLEN within
534 * ripng_enable_network */
535 node = route_node_match(ripng_enable_network,
536 (struct prefix *)&address);
a94434b6 537
ac4d0be5 538 if (node) {
539 route_unlock_node(node);
540 return 1;
541 }
542 }
a94434b6 543
ac4d0be5 544 return -1;
a94434b6 545}
546
718e3744 547/* Add RIPng enable network. */
ac4d0be5 548static int ripng_enable_network_add(struct prefix *p)
718e3744 549{
ac4d0be5 550 struct route_node *node;
718e3744 551
ac4d0be5 552 node = route_node_get(ripng_enable_network, p);
718e3744 553
ac4d0be5 554 if (node->info) {
555 route_unlock_node(node);
556 return -1;
557 } else
558 node->info = (void *)1;
718e3744 559
ac4d0be5 560 /* XXX: One should find a better solution than a generic one */
561 ripng_enable_apply_all();
a94434b6 562
ac4d0be5 563 return 1;
718e3744 564}
565
566/* Delete RIPng enable network. */
ac4d0be5 567static int ripng_enable_network_delete(struct prefix *p)
718e3744 568{
ac4d0be5 569 struct route_node *node;
718e3744 570
ac4d0be5 571 node = route_node_lookup(ripng_enable_network, p);
572 if (node) {
573 node->info = NULL;
718e3744 574
ac4d0be5 575 /* Unlock info lock. */
576 route_unlock_node(node);
718e3744 577
ac4d0be5 578 /* Unlock lookup lock. */
579 route_unlock_node(node);
718e3744 580
ac4d0be5 581 return 1;
582 }
583 return -1;
718e3744 584}
585
586/* Lookup function. */
ac4d0be5 587static int ripng_enable_if_lookup(const char *ifname)
718e3744 588{
ac4d0be5 589 unsigned int i;
590 char *str;
591
592 for (i = 0; i < vector_active(ripng_enable_if); i++)
593 if ((str = vector_slot(ripng_enable_if, i)) != NULL)
594 if (strcmp(str, ifname) == 0)
595 return i;
596 return -1;
718e3744 597}
598
599/* Add interface to ripng_enable_if. */
ac4d0be5 600static int ripng_enable_if_add(const char *ifname)
718e3744 601{
ac4d0be5 602 int ret;
718e3744 603
ac4d0be5 604 ret = ripng_enable_if_lookup(ifname);
605 if (ret >= 0)
606 return -1;
718e3744 607
ac4d0be5 608 vector_set(ripng_enable_if, strdup(ifname));
718e3744 609
ac4d0be5 610 ripng_enable_apply_all();
a94434b6 611
ac4d0be5 612 return 1;
718e3744 613}
614
615/* Delete interface from ripng_enable_if. */
ac4d0be5 616static int ripng_enable_if_delete(const char *ifname)
718e3744 617{
ac4d0be5 618 int index;
619 char *str;
718e3744 620
ac4d0be5 621 index = ripng_enable_if_lookup(ifname);
622 if (index < 0)
623 return -1;
718e3744 624
ac4d0be5 625 str = vector_slot(ripng_enable_if, index);
626 free(str);
627 vector_unset(ripng_enable_if, index);
718e3744 628
ac4d0be5 629 ripng_enable_apply_all();
a94434b6 630
ac4d0be5 631 return 1;
718e3744 632}
633
634/* Wake up interface. */
ac4d0be5 635static int ripng_interface_wakeup(struct thread *t)
718e3744 636{
ac4d0be5 637 struct interface *ifp;
638 struct ripng_interface *ri;
639
640 /* Get interface. */
641 ifp = THREAD_ARG(t);
718e3744 642
ac4d0be5 643 ri = ifp->info;
644 ri->t_wakeup = NULL;
718e3744 645
ac4d0be5 646 /* Join to multicast group. */
647 if (ripng_multicast_join(ifp) < 0) {
648 zlog_err("multicast join failed, interface %s not running",
649 ifp->name);
650 return 0;
651 }
718e3744 652
ac4d0be5 653 /* Set running flag. */
654 ri->running = 1;
718e3744 655
ac4d0be5 656 /* Send RIP request to the interface. */
657 ripng_request(ifp);
718e3744 658
ac4d0be5 659 return 0;
718e3744 660}
661
ac4d0be5 662static void ripng_connect_set(struct interface *ifp, int set)
a94434b6 663{
ac4d0be5 664 struct listnode *node, *nnode;
665 struct connected *connected;
666 struct prefix_ipv6 address;
667
668 for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, connected)) {
669 struct prefix *p;
670 p = connected->address;
671
672 if (p->family != AF_INET6)
673 continue;
674
675 address.family = AF_INET6;
676 address.prefix = p->u.prefix6;
677 address.prefixlen = p->prefixlen;
678 apply_mask_ipv6(&address);
679
680 if (set) {
681 /* Check once more wether this prefix is within a
682 * "network IF_OR_PREF" one */
683 if ((ripng_enable_if_lookup(connected->ifp->name) >= 0)
684 || (ripng_enable_network_lookup2(connected) >= 0))
685 ripng_redistribute_add(
686 ZEBRA_ROUTE_CONNECT,
687 RIPNG_ROUTE_INTERFACE, &address,
688 connected->ifp->ifindex, NULL, 0);
689 } else {
690 ripng_redistribute_delete(
691 ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE,
692 &address, connected->ifp->ifindex);
693 if (ripng_redistribute_check(ZEBRA_ROUTE_CONNECT))
694 ripng_redistribute_add(
695 ZEBRA_ROUTE_CONNECT,
696 RIPNG_ROUTE_REDISTRIBUTE, &address,
697 connected->ifp->ifindex, NULL, 0);
698 }
699 }
a94434b6 700}
701
718e3744 702/* Check RIPng is enabed on this interface. */
ac4d0be5 703void ripng_enable_apply(struct interface *ifp)
718e3744 704{
ac4d0be5 705 int ret;
706 struct ripng_interface *ri = NULL;
707
708 /* Check interface. */
709 if (!if_is_up(ifp))
710 return;
711
712 ri = ifp->info;
713
714 /* Is this interface a candidate for RIPng ? */
715 ret = ripng_enable_network_lookup_if(ifp);
716
717 /* If the interface is matched. */
718 if (ret > 0)
719 ri->enable_network = 1;
720 else
721 ri->enable_network = 0;
722
723 /* Check interface name configuration. */
724 ret = ripng_enable_if_lookup(ifp->name);
725 if (ret >= 0)
726 ri->enable_interface = 1;
727 else
728 ri->enable_interface = 0;
729
730 /* any candidate interface MUST have a link-local IPv6 address */
731 if ((!ripng_if_ipv6_lladdress_check(ifp))
732 && (ri->enable_network || ri->enable_interface)) {
733 ri->enable_network = 0;
734 ri->enable_interface = 0;
735 zlog_warn("Interface %s does not have any link-local address",
736 ifp->name);
718e3744 737 }
ac4d0be5 738
739 /* Update running status of the interface. */
740 if (ri->enable_network || ri->enable_interface) {
741 {
742 if (IS_RIPNG_DEBUG_EVENT)
743 zlog_debug("RIPng turn on %s", ifp->name);
744
745 /* Add interface wake up thread. */
746 if (!ri->t_wakeup)
747 ri->t_wakeup = thread_add_timer(
748 master, ripng_interface_wakeup, ifp, 1);
749
750 ripng_connect_set(ifp, 1);
751 }
752 } else {
753 if (ri->running) {
754 /* Might as well clean up the route table as well
755 * ripng_if_down sets to 0 ri->running, and displays
756 *"turn off %s"
757 **/
758 ripng_if_down(ifp);
759
760 ripng_connect_set(ifp, 0);
761 }
718e3744 762 }
718e3744 763}
764
765/* Set distribute list to all interfaces. */
ac4d0be5 766static void ripng_enable_apply_all(void)
718e3744 767{
ac4d0be5 768 struct interface *ifp;
769 struct listnode *node;
718e3744 770
ac4d0be5 771 for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp))
772 ripng_enable_apply(ifp);
718e3744 773}
6b0655a2 774
a94434b6 775/* Clear all network and neighbor configuration */
ac4d0be5 776void ripng_clean_network()
a94434b6 777{
ac4d0be5 778 unsigned int i;
779 char *str;
780 struct route_node *rn;
781
782 /* ripng_enable_network */
783 for (rn = route_top(ripng_enable_network); rn; rn = route_next(rn))
784 if (rn->info) {
785 rn->info = NULL;
786 route_unlock_node(rn);
787 }
788
789 /* ripng_enable_if */
790 for (i = 0; i < vector_active(ripng_enable_if); i++)
791 if ((str = vector_slot(ripng_enable_if, i)) != NULL) {
792 free(str);
793 vector_slot(ripng_enable_if, i) = NULL;
794 }
a94434b6 795}
6b0655a2 796
718e3744 797/* Vector to store passive-interface name. */
798vector Vripng_passive_interface;
799
800/* Utility function for looking up passive interface settings. */
ac4d0be5 801static int ripng_passive_interface_lookup(const char *ifname)
718e3744 802{
ac4d0be5 803 unsigned int i;
804 char *str;
805
806 for (i = 0; i < vector_active(Vripng_passive_interface); i++)
807 if ((str = vector_slot(Vripng_passive_interface, i)) != NULL)
808 if (strcmp(str, ifname) == 0)
809 return i;
810 return -1;
718e3744 811}
812
ac4d0be5 813void ripng_passive_interface_apply(struct interface *ifp)
718e3744 814{
ac4d0be5 815 int ret;
816 struct ripng_interface *ri;
718e3744 817
ac4d0be5 818 ri = ifp->info;
718e3744 819
ac4d0be5 820 ret = ripng_passive_interface_lookup(ifp->name);
821 if (ret < 0)
822 ri->passive = 0;
823 else
824 ri->passive = 1;
718e3744 825}
826
ac4d0be5 827static void ripng_passive_interface_apply_all(void)
718e3744 828{
ac4d0be5 829 struct interface *ifp;
830 struct listnode *node;
718e3744 831
ac4d0be5 832 for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp))
833 ripng_passive_interface_apply(ifp);
718e3744 834}
835
836/* Passive interface. */
ac4d0be5 837static int ripng_passive_interface_set(struct vty *vty, const char *ifname)
718e3744 838{
ac4d0be5 839 if (ripng_passive_interface_lookup(ifname) >= 0)
840 return CMD_WARNING;
718e3744 841
ac4d0be5 842 vector_set(Vripng_passive_interface, strdup(ifname));
718e3744 843
ac4d0be5 844 ripng_passive_interface_apply_all();
718e3744 845
ac4d0be5 846 return CMD_SUCCESS;
718e3744 847}
848
ac4d0be5 849static int ripng_passive_interface_unset(struct vty *vty, const char *ifname)
718e3744 850{
ac4d0be5 851 int i;
852 char *str;
718e3744 853
ac4d0be5 854 i = ripng_passive_interface_lookup(ifname);
855 if (i < 0)
856 return CMD_WARNING;
718e3744 857
ac4d0be5 858 str = vector_slot(Vripng_passive_interface, i);
859 free(str);
860 vector_unset(Vripng_passive_interface, i);
718e3744 861
ac4d0be5 862 ripng_passive_interface_apply_all();
718e3744 863
ac4d0be5 864 return CMD_SUCCESS;
718e3744 865}
866
867/* Free all configured RIP passive-interface settings. */
ac4d0be5 868void ripng_passive_interface_clean(void)
718e3744 869{
ac4d0be5 870 unsigned int i;
871 char *str;
872
873 for (i = 0; i < vector_active(Vripng_passive_interface); i++)
874 if ((str = vector_slot(Vripng_passive_interface, i)) != NULL) {
875 free(str);
876 vector_slot(Vripng_passive_interface, i) = NULL;
877 }
878 ripng_passive_interface_apply_all();
718e3744 879}
880
881/* Write RIPng enable network and interface to the vty. */
ac4d0be5 882int ripng_network_write(struct vty *vty, int config_mode)
718e3744 883{
ac4d0be5 884 unsigned int i;
885 const char *ifname;
886 struct route_node *node;
887 char buf[BUFSIZ];
888
889 /* Write enable network. */
890 for (node = route_top(ripng_enable_network); node;
891 node = route_next(node))
892 if (node->info) {
893 struct prefix *p = &node->p;
894 vty_out(vty, "%s%s/%d%s",
895 config_mode ? " network " : " ",
896 inet_ntop(p->family, &p->u.prefix, buf, BUFSIZ),
897 p->prefixlen, VTY_NEWLINE);
898 }
899
900 /* Write enable interface. */
901 for (i = 0; i < vector_active(ripng_enable_if); i++)
902 if ((ifname = vector_slot(ripng_enable_if, i)) != NULL)
903 vty_out(vty, "%s%s%s",
904 config_mode ? " network " : " ", ifname,
905 VTY_NEWLINE);
906
907 /* Write passive interface. */
908 if (config_mode)
909 for (i = 0; i < vector_active(Vripng_passive_interface); i++)
910 if ((ifname = vector_slot(Vripng_passive_interface, i))
911 != NULL)
912 vty_out(vty, " passive-interface %s%s", ifname,
913 VTY_NEWLINE);
914
915 return 0;
718e3744 916}
917
918/* RIPng enable on specified interface or matched network. */
919DEFUN (ripng_network,
920 ripng_network_cmd,
921 "network IF_OR_ADDR",
922 "RIPng enable on specified interface or network.\n"
923 "Interface or address")
924{
ac4d0be5 925 int idx_if_or_addr = 1;
926 int ret;
927 struct prefix p;
928
929 ret = str2prefix(argv[idx_if_or_addr]->arg, &p);
930
931 /* Given string is IPv6 network or interface name. */
932 if (ret)
933 ret = ripng_enable_network_add(&p);
934 else
935 ret = ripng_enable_if_add(argv[idx_if_or_addr]->arg);
936
937 if (ret < 0) {
938 vty_out(vty, "There is same network configuration %s%s",
939 argv[idx_if_or_addr]->arg, VTY_NEWLINE);
940 return CMD_WARNING;
941 }
942
943 return CMD_SUCCESS;
718e3744 944}
945
946/* RIPng enable on specified interface or matched network. */
947DEFUN (no_ripng_network,
948 no_ripng_network_cmd,
949 "no network IF_OR_ADDR",
950 NO_STR
951 "RIPng enable on specified interface or network.\n"
952 "Interface or address")
953{
ac4d0be5 954 int idx_if_or_addr = 2;
955 int ret;
956 struct prefix p;
957
958 ret = str2prefix(argv[idx_if_or_addr]->arg, &p);
959
960 /* Given string is interface name. */
961 if (ret)
962 ret = ripng_enable_network_delete(&p);
963 else
964 ret = ripng_enable_if_delete(argv[idx_if_or_addr]->arg);
965
966 if (ret < 0) {
967 vty_out(vty, "can't find network %s%s",
968 argv[idx_if_or_addr]->arg, VTY_NEWLINE);
969 return CMD_WARNING;
970 }
971
972 return CMD_SUCCESS;
a94434b6 973}
974
975DEFUN (ipv6_ripng_split_horizon,
976 ipv6_ripng_split_horizon_cmd,
977 "ipv6 ripng split-horizon",
978 IPV6_STR
979 "Routing Information Protocol\n"
980 "Perform split horizon\n")
981{
ac4d0be5 982 VTY_DECLVAR_CONTEXT(interface, ifp);
983 struct ripng_interface *ri;
a94434b6 984
ac4d0be5 985 ri = ifp->info;
a94434b6 986
ac4d0be5 987 ri->split_horizon = RIPNG_SPLIT_HORIZON;
988 return CMD_SUCCESS;
a94434b6 989}
990
991DEFUN (ipv6_ripng_split_horizon_poisoned_reverse,
992 ipv6_ripng_split_horizon_poisoned_reverse_cmd,
993 "ipv6 ripng split-horizon poisoned-reverse",
994 IPV6_STR
995 "Routing Information Protocol\n"
996 "Perform split horizon\n"
997 "With poisoned-reverse\n")
998{
ac4d0be5 999 VTY_DECLVAR_CONTEXT(interface, ifp);
1000 struct ripng_interface *ri;
a94434b6 1001
ac4d0be5 1002 ri = ifp->info;
a94434b6 1003
ac4d0be5 1004 ri->split_horizon = RIPNG_SPLIT_HORIZON_POISONED_REVERSE;
1005 return CMD_SUCCESS;
a94434b6 1006}
718e3744 1007
a94434b6 1008DEFUN (no_ipv6_ripng_split_horizon,
1009 no_ipv6_ripng_split_horizon_cmd,
481af2ed 1010 "no ipv6 ripng split-horizon [poisoned-reverse]",
a94434b6 1011 NO_STR
1012 IPV6_STR
1013 "Routing Information Protocol\n"
481af2ed
QY
1014 "Perform split horizon\n"
1015 "With poisoned-reverse\n")
a94434b6 1016{
ac4d0be5 1017 VTY_DECLVAR_CONTEXT(interface, ifp);
1018 struct ripng_interface *ri;
a94434b6 1019
ac4d0be5 1020 ri = ifp->info;
a94434b6 1021
ac4d0be5 1022 ri->split_horizon = RIPNG_NO_SPLIT_HORIZON;
1023 return CMD_SUCCESS;
718e3744 1024}
1025
1026DEFUN (ripng_passive_interface,
1027 ripng_passive_interface_cmd,
1028 "passive-interface IFNAME",
1029 "Suppress routing updates on an interface\n"
1030 "Interface name\n")
1031{
ac4d0be5 1032 int idx_ifname = 1;
1033 return ripng_passive_interface_set(vty, argv[idx_ifname]->arg);
718e3744 1034}
1035
1036DEFUN (no_ripng_passive_interface,
1037 no_ripng_passive_interface_cmd,
1038 "no passive-interface IFNAME",
1039 NO_STR
1040 "Suppress routing updates on an interface\n"
1041 "Interface name\n")
1042{
ac4d0be5 1043 int idx_ifname = 2;
1044 return ripng_passive_interface_unset(vty, argv[idx_ifname]->arg);
718e3744 1045}
6b0655a2 1046
ac4d0be5 1047static struct ripng_interface *ri_new(void)
718e3744 1048{
ac4d0be5 1049 struct ripng_interface *ri;
1050 ri = XCALLOC(MTYPE_IF, sizeof(struct ripng_interface));
a94434b6 1051
ac4d0be5 1052 /* Set default split-horizon behavior. If the interface is Frame
1053 Relay or SMDS is enabled, the default value for split-horizon is
1054 off. But currently Zebra does detect Frame Relay or SMDS
1055 interface. So all interface is set to split horizon. */
1056 ri->split_horizon_default = RIPNG_SPLIT_HORIZON;
1057 ri->split_horizon = ri->split_horizon_default;
a94434b6 1058
ac4d0be5 1059 return ri;
718e3744 1060}
1061
ac4d0be5 1062static int ripng_if_new_hook(struct interface *ifp)
718e3744 1063{
ac4d0be5 1064 ifp->info = ri_new();
1065 return 0;
718e3744 1066}
1067
a94434b6 1068/* Called when interface structure deleted. */
ac4d0be5 1069static int ripng_if_delete_hook(struct interface *ifp)
a94434b6 1070{
ac4d0be5 1071 XFREE(MTYPE_IF, ifp->info);
1072 ifp->info = NULL;
1073 return 0;
a94434b6 1074}
1075
718e3744 1076/* Configuration write function for ripngd. */
ac4d0be5 1077static int interface_config_write(struct vty *vty)
718e3744 1078{
ac4d0be5 1079 struct listnode *node;
1080 struct interface *ifp;
1081 struct ripng_interface *ri;
1082 int write = 0;
1083
1084 for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) {
1085 ri = ifp->info;
1086
1087 /* Do not display the interface if there is no
1088 * configuration about it.
1089 **/
1090 if ((!ifp->desc)
1091 && (ri->split_horizon == ri->split_horizon_default))
1092 continue;
1093
1094 vty_out(vty, "interface %s%s", ifp->name, VTY_NEWLINE);
1095 if (ifp->desc)
1096 vty_out(vty, " description %s%s", ifp->desc,
1097 VTY_NEWLINE);
1098
1099 /* Split horizon. */
1100 if (ri->split_horizon != ri->split_horizon_default) {
1101 switch (ri->split_horizon) {
1102 case RIPNG_SPLIT_HORIZON:
1103 vty_out(vty, " ipv6 ripng split-horizon%s",
1104 VTY_NEWLINE);
1105 break;
1106 case RIPNG_SPLIT_HORIZON_POISONED_REVERSE:
1107 vty_out(vty,
1108 " ipv6 ripng split-horizon poisoned-reverse%s",
1109 VTY_NEWLINE);
1110 break;
1111 case RIPNG_NO_SPLIT_HORIZON:
1112 default:
1113 vty_out(vty, " no ipv6 ripng split-horizon%s",
1114 VTY_NEWLINE);
1115 break;
1116 }
1117 }
1118
1119 vty_out(vty, "!%s", VTY_NEWLINE);
1120
1121 write++;
a94434b6 1122 }
ac4d0be5 1123 return write;
718e3744 1124}
1125
1126/* ripngd's interface node. */
ac4d0be5 1127static struct cmd_node interface_node = {
1128 INTERFACE_NODE, "%s(config-if)# ", 1 /* VTYSH */
718e3744 1129};
1130
1131/* Initialization of interface. */
ac4d0be5 1132void ripng_if_init()
718e3744 1133{
ac4d0be5 1134 /* Interface initialize. */
1135 if_add_hook(IF_NEW_HOOK, ripng_if_new_hook);
1136 if_add_hook(IF_DELETE_HOOK, ripng_if_delete_hook);
718e3744 1137
ac4d0be5 1138 /* RIPng enable network init. */
1139 ripng_enable_network = route_table_init();
718e3744 1140
ac4d0be5 1141 /* RIPng enable interface init. */
1142 ripng_enable_if = vector_init(1);
718e3744 1143
ac4d0be5 1144 /* RIPng passive interface. */
1145 Vripng_passive_interface = vector_init(1);
718e3744 1146
ac4d0be5 1147 /* Install interface node. */
1148 install_node(&interface_node, interface_config_write);
1149 if_cmd_init();
718e3744 1150
ac4d0be5 1151 install_element(RIPNG_NODE, &ripng_network_cmd);
1152 install_element(RIPNG_NODE, &no_ripng_network_cmd);
1153 install_element(RIPNG_NODE, &ripng_passive_interface_cmd);
1154 install_element(RIPNG_NODE, &no_ripng_passive_interface_cmd);
a94434b6 1155
ac4d0be5 1156 install_element(INTERFACE_NODE, &ipv6_ripng_split_horizon_cmd);
1157 install_element(INTERFACE_NODE,
1158 &ipv6_ripng_split_horizon_poisoned_reverse_cmd);
1159 install_element(INTERFACE_NODE, &no_ipv6_ripng_split_horizon_cmd);
718e3744 1160}