1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Interface related function for RIPng.
4 * Copyright (C) 1998 Kunihiro Ishiguro
19 #include "agg_table.h"
23 #include "lib_errors.h"
24 #include "northbound_cli.h"
26 #include "ripngd/ripngd.h"
27 #include "ripngd/ripng_debug.h"
29 /* If RFC2133 definition is used. */
30 #ifndef IPV6_JOIN_GROUP
31 #define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
33 #ifndef IPV6_LEAVE_GROUP
34 #define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
37 DEFINE_MTYPE_STATIC(RIPNGD
, RIPNG_IF
, "ripng interface");
39 /* Static utility function. */
40 static void ripng_enable_apply(struct interface
*);
41 static void ripng_passive_interface_apply(struct interface
*);
42 static int ripng_enable_if_lookup(struct ripng
*ripng
, const char *ifname
);
43 static int ripng_enable_network_lookup2(struct connected
*);
44 static void ripng_enable_apply_all(struct ripng
*ripng
);
46 /* Join to the all rip routers multicast group. */
47 static int ripng_multicast_join(struct interface
*ifp
, int sock
)
50 struct ipv6_mreq mreq
;
53 if (if_is_multicast(ifp
)) {
54 memset(&mreq
, 0, sizeof(mreq
));
55 inet_pton(AF_INET6
, RIPNG_GROUP
, &mreq
.ipv6mr_multiaddr
);
56 mreq
.ipv6mr_interface
= ifp
->ifindex
;
59 * NetBSD 1.6.2 requires root to join groups on gif(4).
60 * While this is bogus, privs are available and easy to use
61 * for this call as a workaround.
63 frr_with_privs(&ripngd_privs
) {
65 ret
= setsockopt(sock
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
,
66 (char *)&mreq
, sizeof(mreq
));
71 if (ret
< 0 && save_errno
== EADDRINUSE
) {
73 * Group is already joined. This occurs due to sloppy
75 * management, in particular declining to leave the
77 * an interface that has just gone down.
79 zlog_warn("ripng join on %s EADDRINUSE (ignoring)",
81 return 0; /* not an error */
85 zlog_warn("can't setsockopt IPV6_JOIN_GROUP: %s",
86 safe_strerror(save_errno
));
88 if (IS_RIPNG_DEBUG_EVENT
)
90 "RIPng %s join to all-rip-routers multicast group",
99 /* Leave from the all rip routers multicast group. */
100 static int ripng_multicast_leave(struct interface
*ifp
, int sock
)
103 struct ipv6_mreq mreq
;
105 if (if_is_multicast(ifp
)) {
106 memset(&mreq
, 0, sizeof(mreq
));
107 inet_pton(AF_INET6
, RIPNG_GROUP
, &mreq
.ipv6mr_multiaddr
);
108 mreq
.ipv6mr_interface
= ifp
->ifindex
;
110 ret
= setsockopt(sock
, IPPROTO_IPV6
, IPV6_LEAVE_GROUP
,
111 (char *)&mreq
, sizeof(mreq
));
113 zlog_warn("can't setsockopt IPV6_LEAVE_GROUP: %s",
114 safe_strerror(errno
));
116 if (IS_RIPNG_DEBUG_EVENT
)
118 "RIPng %s leave from all-rip-routers multicast group",
128 /* How many link local IPv6 address could be used on the interface ? */
129 static int ripng_if_ipv6_lladdress_check(struct interface
*ifp
)
132 struct connected
*connected
;
135 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, nn
, connected
)) {
137 p
= connected
->address
;
139 if ((p
->family
== AF_INET6
)
140 && IN6_IS_ADDR_LINKLOCAL(&p
->u
.prefix6
))
147 static int ripng_if_down(struct interface
*ifp
)
150 struct ripng_info
*rinfo
;
151 struct ripng_interface
*ri
;
153 struct list
*list
= NULL
;
154 struct listnode
*listnode
= NULL
, *nextnode
= NULL
;
158 EVENT_OFF(ri
->t_wakeup
);
163 for (rp
= agg_route_top(ripng
->table
); rp
;
164 rp
= agg_route_next(rp
))
165 if ((list
= rp
->info
) != NULL
)
166 for (ALL_LIST_ELEMENTS(list
, listnode
, nextnode
,
168 if (rinfo
->ifindex
== ifp
->ifindex
)
169 ripng_ecmp_delete(ripng
, rinfo
);
173 if (IS_RIPNG_DEBUG_EVENT
)
174 zlog_debug("turn off %s", ifp
->name
);
176 /* Leave from multicast group. */
178 ripng_multicast_leave(ifp
, ripng
->sock
);
186 /* Interface link up message processing. */
187 static int ripng_ifp_up(struct interface
*ifp
)
189 if (IS_RIPNG_DEBUG_ZEBRA
)
191 "interface up %s vrf %s(%u) index %d flags %llx metric %d mtu %d",
192 ifp
->name
, ifp
->vrf
->name
, ifp
->vrf
->vrf_id
,
193 ifp
->ifindex
, (unsigned long long)ifp
->flags
,
194 ifp
->metric
, ifp
->mtu6
);
196 ripng_interface_sync(ifp
);
198 /* Check if this interface is RIPng enabled or not. */
199 ripng_enable_apply(ifp
);
201 /* Check for a passive interface. */
202 ripng_passive_interface_apply(ifp
);
204 /* Apply distribute list to the all interface. */
205 ripng_distribute_update_interface(ifp
);
210 /* Interface link down message processing. */
211 static int ripng_ifp_down(struct interface
*ifp
)
213 ripng_interface_sync(ifp
);
216 if (IS_RIPNG_DEBUG_ZEBRA
)
218 "interface down %s vrf %s(%u) index %d flags %#llx metric %d mtu %d",
219 ifp
->name
, ifp
->vrf
->name
, ifp
->vrf
->vrf_id
,
220 ifp
->ifindex
, (unsigned long long)ifp
->flags
,
221 ifp
->metric
, ifp
->mtu6
);
226 /* Interface addition message from zebra. */
227 static int ripng_ifp_create(struct interface
*ifp
)
229 ripng_interface_sync(ifp
);
231 if (IS_RIPNG_DEBUG_ZEBRA
)
233 "RIPng interface add %s vrf %s(%u) index %d flags %#llx metric %d mtu %d",
234 ifp
->name
, ifp
->vrf
->name
, ifp
->vrf
->vrf_id
,
235 ifp
->ifindex
, (unsigned long long)ifp
->flags
,
236 ifp
->metric
, ifp
->mtu6
);
238 /* Check is this interface is RIP enabled or not.*/
239 ripng_enable_apply(ifp
);
241 /* Apply distribute list to the interface. */
242 ripng_distribute_update_interface(ifp
);
244 /* Check interface routemap. */
245 ripng_if_rmap_update_interface(ifp
);
250 static int ripng_ifp_destroy(struct interface
*ifp
)
252 ripng_interface_sync(ifp
);
257 if (IS_RIPNG_DEBUG_ZEBRA
)
259 "interface delete %s vrf %s(%u) index %d flags %#llx metric %d mtu %d",
260 ifp
->name
, ifp
->vrf
->name
, ifp
->vrf
->vrf_id
,
261 ifp
->ifindex
, (unsigned long long)ifp
->flags
,
262 ifp
->metric
, ifp
->mtu6
);
267 /* VRF update for an interface. */
268 int ripng_interface_vrf_update(ZAPI_CALLBACK_ARGS
)
270 struct interface
*ifp
;
273 ifp
= zebra_interface_vrf_update_read(zclient
->ibuf
, vrf_id
,
278 if (IS_RIPNG_DEBUG_ZEBRA
) {
279 struct vrf
*nvrf
= vrf_lookup_by_id(new_vrf_id
);
281 zlog_debug("interface %s VRF change vrf %s(%u) new vrf %s(%u)",
282 ifp
->name
, ifp
->vrf
->name
, vrf_id
, VRF_LOGNAME(nvrf
),
286 if_update_to_new_vrf(ifp
, new_vrf_id
);
287 ripng_interface_sync(ifp
);
292 void ripng_interface_clean(struct ripng
*ripng
)
294 struct interface
*ifp
;
295 struct ripng_interface
*ri
;
297 FOR_ALL_INTERFACES (ripng
->vrf
, ifp
) {
300 ri
->enable_network
= 0;
301 ri
->enable_interface
= 0;
304 EVENT_OFF(ri
->t_wakeup
);
308 static void ripng_apply_address_add(struct connected
*ifc
)
310 struct ripng_interface
*ri
= ifc
->ifp
->info
;
311 struct ripng
*ripng
= ri
->ripng
;
312 struct prefix_ipv6 address
;
318 if (!if_is_up(ifc
->ifp
))
323 memset(&address
, 0, sizeof(address
));
324 address
.family
= p
->family
;
325 address
.prefix
= p
->u
.prefix6
;
326 address
.prefixlen
= p
->prefixlen
;
327 apply_mask_ipv6(&address
);
329 /* Check if this interface is RIP enabled or not
330 or Check if this address's prefix is RIP enabled */
331 if ((ripng_enable_if_lookup(ripng
, ifc
->ifp
->name
) >= 0)
332 || (ripng_enable_network_lookup2(ifc
) >= 0))
333 ripng_redistribute_add(ripng
, ZEBRA_ROUTE_CONNECT
,
334 RIPNG_ROUTE_INTERFACE
, &address
,
335 ifc
->ifp
->ifindex
, NULL
, 0);
338 int ripng_interface_address_add(ZAPI_CALLBACK_ARGS
)
343 c
= zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_ADD
,
344 zclient
->ibuf
, vrf_id
);
351 if (p
->family
== AF_INET6
) {
352 struct ripng_interface
*ri
= c
->ifp
->info
;
354 if (IS_RIPNG_DEBUG_ZEBRA
)
355 zlog_debug("RIPng connected address %pFX add", p
);
357 /* Check is this prefix needs to be redistributed. */
358 ripng_apply_address_add(c
);
360 /* Let's try once again whether the interface could be activated
363 /* Check if this interface is RIP enabled or not.*/
364 ripng_enable_apply(c
->ifp
);
366 /* Apply distribute list to the interface. */
367 ripng_distribute_update_interface(c
->ifp
);
369 /* Check interface routemap. */
370 ripng_if_rmap_update_interface(c
->ifp
);
377 static void ripng_apply_address_del(struct connected
*ifc
)
379 struct ripng_interface
*ri
= ifc
->ifp
->info
;
380 struct ripng
*ripng
= ri
->ripng
;
381 struct prefix_ipv6 address
;
387 if (!if_is_up(ifc
->ifp
))
392 memset(&address
, 0, sizeof(address
));
393 address
.family
= p
->family
;
394 address
.prefix
= p
->u
.prefix6
;
395 address
.prefixlen
= p
->prefixlen
;
396 apply_mask_ipv6(&address
);
398 ripng_redistribute_delete(ripng
, ZEBRA_ROUTE_CONNECT
,
399 RIPNG_ROUTE_INTERFACE
, &address
,
403 int ripng_interface_address_delete(ZAPI_CALLBACK_ARGS
)
405 struct connected
*ifc
;
408 ifc
= zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_DELETE
,
409 zclient
->ibuf
, vrf_id
);
414 if (p
->family
== AF_INET6
) {
415 if (IS_RIPNG_DEBUG_ZEBRA
)
417 "RIPng connected address %pFX delete",
420 /* Check whether this prefix needs to be removed. */
421 ripng_apply_address_del(ifc
);
423 connected_free(&ifc
);
429 /* Lookup RIPng enable network. */
430 /* Check whether the interface has at least a connected prefix that
431 * is within the ripng->enable_network table. */
432 static int ripng_enable_network_lookup_if(struct interface
*ifp
)
434 struct ripng_interface
*ri
= ifp
->info
;
435 struct ripng
*ripng
= ri
->ripng
;
436 struct listnode
*node
;
437 struct connected
*connected
;
438 struct prefix_ipv6 address
;
443 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, connected
)) {
447 p
= connected
->address
;
449 if (p
->family
== AF_INET6
) {
450 address
.family
= AF_INET6
;
451 address
.prefix
= p
->u
.prefix6
;
452 address
.prefixlen
= IPV6_MAX_BITLEN
;
454 n
= agg_node_match(ripng
->enable_network
,
455 (struct prefix
*)&address
);
465 /* Check whether connected is within the ripng->enable_network table. */
466 static int ripng_enable_network_lookup2(struct connected
*connected
)
468 struct ripng_interface
*ri
= connected
->ifp
->info
;
469 struct ripng
*ripng
= ri
->ripng
;
470 struct prefix_ipv6 address
;
476 p
= connected
->address
;
478 if (p
->family
== AF_INET6
) {
479 struct agg_node
*node
;
481 address
.family
= p
->family
;
482 address
.prefix
= p
->u
.prefix6
;
483 address
.prefixlen
= IPV6_MAX_BITLEN
;
485 /* LPM on p->family, p->u.prefix6/IPV6_MAX_BITLEN within
486 * ripng->enable_network */
487 node
= agg_node_match(ripng
->enable_network
,
488 (struct prefix
*)&address
);
491 agg_unlock_node(node
);
499 /* Add RIPng enable network. */
500 int ripng_enable_network_add(struct ripng
*ripng
, struct prefix
*p
)
502 struct agg_node
*node
;
504 node
= agg_node_get(ripng
->enable_network
, p
);
507 agg_unlock_node(node
);
508 return NB_ERR_INCONSISTENCY
;
510 node
->info
= (void *)1;
512 /* XXX: One should find a better solution than a generic one */
513 ripng_enable_apply_all(ripng
);
518 /* Delete RIPng enable network. */
519 int ripng_enable_network_delete(struct ripng
*ripng
, struct prefix
*p
)
521 struct agg_node
*node
;
523 node
= agg_node_lookup(ripng
->enable_network
, p
);
527 /* Unlock info lock. */
528 agg_unlock_node(node
);
530 /* Unlock lookup lock. */
531 agg_unlock_node(node
);
536 return NB_ERR_INCONSISTENCY
;
539 /* Lookup function. */
540 static int ripng_enable_if_lookup(struct ripng
*ripng
, const char *ifname
)
548 for (i
= 0; i
< vector_active(ripng
->enable_if
); i
++)
549 if ((str
= vector_slot(ripng
->enable_if
, i
)) != NULL
)
550 if (strcmp(str
, ifname
) == 0)
555 int ripng_enable_if_add(struct ripng
*ripng
, const char *ifname
)
559 ret
= ripng_enable_if_lookup(ripng
, ifname
);
561 return NB_ERR_INCONSISTENCY
;
563 vector_set(ripng
->enable_if
, strdup(ifname
));
565 ripng_enable_apply_all(ripng
);
570 int ripng_enable_if_delete(struct ripng
*ripng
, const char *ifname
)
575 index
= ripng_enable_if_lookup(ripng
, ifname
);
577 return NB_ERR_INCONSISTENCY
;
579 str
= vector_slot(ripng
->enable_if
, index
);
581 vector_unset(ripng
->enable_if
, index
);
583 ripng_enable_apply_all(ripng
);
588 /* Wake up interface. */
589 static void ripng_interface_wakeup(struct event
*t
)
591 struct interface
*ifp
;
592 struct ripng_interface
*ri
;
599 /* Join to multicast group. */
600 if (ripng_multicast_join(ifp
, ri
->ripng
->sock
) < 0) {
601 flog_err_sys(EC_LIB_SOCKET
,
602 "multicast join failed, interface %s not running",
607 /* Set running flag. */
610 /* Send RIP request to the interface. */
614 static void ripng_connect_set(struct interface
*ifp
, int set
)
616 struct ripng_interface
*ri
= ifp
->info
;
617 struct ripng
*ripng
= ri
->ripng
;
618 struct listnode
*node
, *nnode
;
619 struct connected
*connected
;
620 struct prefix_ipv6 address
;
622 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nnode
, connected
)) {
624 p
= connected
->address
;
626 if (p
->family
!= AF_INET6
)
629 address
.family
= AF_INET6
;
630 address
.prefix
= p
->u
.prefix6
;
631 address
.prefixlen
= p
->prefixlen
;
632 apply_mask_ipv6(&address
);
635 /* Check once more whether this prefix is within a
636 * "network IF_OR_PREF" one */
637 if ((ripng_enable_if_lookup(ripng
, connected
->ifp
->name
)
639 || (ripng_enable_network_lookup2(connected
) >= 0))
640 ripng_redistribute_add(
641 ripng
, ZEBRA_ROUTE_CONNECT
,
642 RIPNG_ROUTE_INTERFACE
, &address
,
643 connected
->ifp
->ifindex
, NULL
, 0);
645 ripng_redistribute_delete(ripng
, ZEBRA_ROUTE_CONNECT
,
646 RIPNG_ROUTE_INTERFACE
,
648 connected
->ifp
->ifindex
);
649 if (ripng_redistribute_check(ripng
,
650 ZEBRA_ROUTE_CONNECT
))
651 ripng_redistribute_add(
652 ripng
, ZEBRA_ROUTE_CONNECT
,
653 RIPNG_ROUTE_REDISTRIBUTE
, &address
,
654 connected
->ifp
->ifindex
, NULL
, 0);
659 /* Check RIPng is enabed on this interface. */
660 void ripng_enable_apply(struct interface
*ifp
)
663 struct ripng_interface
*ri
= NULL
;
665 /* Check interface. */
671 /* Is this interface a candidate for RIPng ? */
672 ret
= ripng_enable_network_lookup_if(ifp
);
674 /* If the interface is matched. */
676 ri
->enable_network
= 1;
678 ri
->enable_network
= 0;
680 /* Check interface name configuration. */
681 ret
= ripng_enable_if_lookup(ri
->ripng
, ifp
->name
);
683 ri
->enable_interface
= 1;
685 ri
->enable_interface
= 0;
687 /* any candidate interface MUST have a link-local IPv6 address */
688 if ((!ripng_if_ipv6_lladdress_check(ifp
))
689 && (ri
->enable_network
|| ri
->enable_interface
)) {
690 ri
->enable_network
= 0;
691 ri
->enable_interface
= 0;
692 zlog_warn("Interface %s does not have any link-local address",
696 /* Update running status of the interface. */
697 if (ri
->enable_network
|| ri
->enable_interface
) {
698 zlog_info("RIPng INTERFACE ON %s", ifp
->name
);
700 /* Add interface wake up thread. */
701 event_add_timer(master
, ripng_interface_wakeup
, ifp
, 1,
704 ripng_connect_set(ifp
, 1);
707 /* Might as well clean up the route table as well
708 * ripng_if_down sets to 0 ri->running, and displays
713 ripng_connect_set(ifp
, 0);
718 /* Set distribute list to all interfaces. */
719 static void ripng_enable_apply_all(struct ripng
*ripng
)
721 struct interface
*ifp
;
723 FOR_ALL_INTERFACES (ripng
->vrf
, ifp
)
724 ripng_enable_apply(ifp
);
727 /* Clear all network and neighbor configuration */
728 void ripng_clean_network(struct ripng
*ripng
)
734 /* ripng->enable_network */
735 for (rn
= agg_route_top(ripng
->enable_network
); rn
;
736 rn
= agg_route_next(rn
))
742 /* ripng->enable_if */
743 for (i
= 0; i
< vector_active(ripng
->enable_if
); i
++)
744 if ((str
= vector_slot(ripng
->enable_if
, i
)) != NULL
) {
746 vector_slot(ripng
->enable_if
, i
) = NULL
;
750 /* Utility function for looking up passive interface settings. */
751 static int ripng_passive_interface_lookup(struct ripng
*ripng
,
757 for (i
= 0; i
< vector_active(ripng
->passive_interface
); i
++)
758 if ((str
= vector_slot(ripng
->passive_interface
, i
)) != NULL
)
759 if (strcmp(str
, ifname
) == 0)
764 void ripng_passive_interface_apply(struct interface
*ifp
)
767 struct ripng_interface
*ri
;
775 ret
= ripng_passive_interface_lookup(ripng
, ifp
->name
);
782 static void ripng_passive_interface_apply_all(struct ripng
*ripng
)
784 struct interface
*ifp
;
786 FOR_ALL_INTERFACES (ripng
->vrf
, ifp
)
787 ripng_passive_interface_apply(ifp
);
790 /* Passive interface. */
791 int ripng_passive_interface_set(struct ripng
*ripng
, const char *ifname
)
793 if (ripng_passive_interface_lookup(ripng
, ifname
) >= 0)
794 return NB_ERR_INCONSISTENCY
;
796 vector_set(ripng
->passive_interface
, strdup(ifname
));
798 ripng_passive_interface_apply_all(ripng
);
803 int ripng_passive_interface_unset(struct ripng
*ripng
, const char *ifname
)
808 i
= ripng_passive_interface_lookup(ripng
, ifname
);
810 return NB_ERR_INCONSISTENCY
;
812 str
= vector_slot(ripng
->passive_interface
, i
);
814 vector_unset(ripng
->passive_interface
, i
);
816 ripng_passive_interface_apply_all(ripng
);
821 /* Free all configured RIP passive-interface settings. */
822 void ripng_passive_interface_clean(struct ripng
*ripng
)
827 for (i
= 0; i
< vector_active(ripng
->passive_interface
); i
++)
828 if ((str
= vector_slot(ripng
->passive_interface
, i
)) != NULL
) {
830 vector_slot(ripng
->passive_interface
, i
) = NULL
;
832 ripng_passive_interface_apply_all(ripng
);
835 /* Write RIPng enable network and interface to the vty. */
836 int ripng_network_write(struct vty
*vty
, struct ripng
*ripng
)
840 struct agg_node
*node
;
842 /* Write enable network. */
843 for (node
= agg_route_top(ripng
->enable_network
); node
;
844 node
= agg_route_next(node
))
846 vty_out(vty
, " %pRN\n", node
);
848 /* Write enable interface. */
849 for (i
= 0; i
< vector_active(ripng
->enable_if
); i
++)
850 if ((ifname
= vector_slot(ripng
->enable_if
, i
)) != NULL
)
851 vty_out(vty
, " %s\n", ifname
);
856 static struct ripng_interface
*ri_new(void)
858 struct ripng_interface
*ri
;
860 ri
= XCALLOC(MTYPE_RIPNG_IF
, sizeof(struct ripng_interface
));
862 /* Set default split-horizon behavior. If the interface is Frame
863 Relay or SMDS is enabled, the default value for split-horizon is
864 off. But currently Zebra does detect Frame Relay or SMDS
865 interface. So all interface is set to split horizon. */
867 yang_get_default_enum("%s/split-horizon", RIPNG_IFACE
);
872 void ripng_interface_sync(struct interface
*ifp
)
874 struct ripng_interface
*ri
;
878 ri
->ripng
= ifp
->vrf
->info
;
881 static int ripng_if_new_hook(struct interface
*ifp
)
883 ifp
->info
= ri_new();
884 ripng_interface_sync(ifp
);
889 /* Called when interface structure deleted. */
890 static int ripng_if_delete_hook(struct interface
*ifp
)
892 XFREE(MTYPE_RIPNG_IF
, ifp
->info
);
896 /* Initialization of interface. */
897 void ripng_if_init(void)
899 /* Interface initialize. */
900 hook_register_prio(if_add
, 0, ripng_if_new_hook
);
901 hook_register_prio(if_del
, 0, ripng_if_delete_hook
);
903 /* Install interface node. */
904 if_cmd_init_default();
905 if_zapi_callbacks(ripng_ifp_create
, ripng_ifp_up
,
906 ripng_ifp_down
, ripng_ifp_destroy
);