3 * Copyright (C) 2008 Everton da Silva Marques
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; see the file COPYING; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
33 #include "pim_instance.h"
34 #include "pim_zebra.h"
35 #include "pim_iface.h"
37 #include "pim_mroute.h"
41 #include "pim_neighbor.h"
42 #include "pim_ifchannel.h"
45 #include "pim_ssmpingd.h"
48 #include "pim_jp_agg.h"
50 static void pim_if_igmp_join_del_all(struct interface
*ifp
);
51 static int igmp_join_sock(const char *ifname
, ifindex_t ifindex
,
52 struct in_addr group_addr
,
53 struct in_addr source_addr
);
55 void pim_if_init(struct pim_instance
*pim
)
59 for (i
= 0; i
< MAXVIFS
; i
++)
60 pim
->iface_vif_index
[i
] = 0;
63 void pim_if_terminate(struct pim_instance
*pim
)
65 // Nothing to do at this moment
69 static void *if_list_clean(struct pim_interface
*pim_ifp
)
71 struct pim_ifchannel
*ch
;
73 if (pim_ifp
->igmp_join_list
)
74 list_delete_and_null(&pim_ifp
->igmp_join_list
);
76 if (pim_ifp
->igmp_socket_list
)
77 list_delete_and_null(&pim_ifp
->igmp_socket_list
);
79 if (pim_ifp
->pim_neighbor_list
)
80 list_delete_and_null(&pim_ifp
->pim_neighbor_list
);
82 if (pim_ifp
->upstream_switch_list
)
83 list_delete_and_null(&pim_ifp
->upstream_switch_list
);
85 if (pim_ifp
->sec_addr_list
)
86 list_delete_and_null(&pim_ifp
->sec_addr_list
);
88 while (!RB_EMPTY(pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
)) {
89 ch
= RB_ROOT(pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
);
91 pim_ifchannel_delete(ch
);
94 XFREE(MTYPE_PIM_INTERFACE
, pim_ifp
);
99 static void pim_sec_addr_free(struct pim_secondary_addr
*sec_addr
)
101 XFREE(MTYPE_PIM_SEC_ADDR
, sec_addr
);
104 static int pim_sec_addr_comp(const void *p1
, const void *p2
)
106 const struct pim_secondary_addr
*sec1
= p1
;
107 const struct pim_secondary_addr
*sec2
= p2
;
109 if (sec1
->addr
.family
== AF_INET
&& sec2
->addr
.family
== AF_INET6
)
112 if (sec1
->addr
.family
== AF_INET6
&& sec2
->addr
.family
== AF_INET
)
115 if (sec1
->addr
.family
== AF_INET
) {
116 if (ntohl(sec1
->addr
.u
.prefix4
.s_addr
)
117 < ntohl(sec2
->addr
.u
.prefix4
.s_addr
))
120 if (ntohl(sec1
->addr
.u
.prefix4
.s_addr
)
121 > ntohl(sec2
->addr
.u
.prefix4
.s_addr
))
124 return memcmp(&sec1
->addr
.u
.prefix6
, &sec2
->addr
.u
.prefix6
,
125 sizeof(struct in6_addr
));
131 struct pim_interface
*pim_if_new(struct interface
*ifp
, int igmp
, int pim
)
133 struct pim_interface
*pim_ifp
;
138 pim_ifp
= XCALLOC(MTYPE_PIM_INTERFACE
, sizeof(*pim_ifp
));
140 zlog_err("PIM XCALLOC(%zu) failure", sizeof(*pim_ifp
));
144 pim_ifp
->options
= 0;
145 pim_ifp
->pim
= pim_get_pim_instance(ifp
->vrf_id
);
146 pim_ifp
->mroute_vif_index
= -1;
148 pim_ifp
->igmp_version
= IGMP_DEFAULT_VERSION
;
149 pim_ifp
->igmp_default_robustness_variable
=
150 IGMP_DEFAULT_ROBUSTNESS_VARIABLE
;
151 pim_ifp
->igmp_default_query_interval
= IGMP_GENERAL_QUERY_INTERVAL
;
152 pim_ifp
->igmp_query_max_response_time_dsec
=
153 IGMP_QUERY_MAX_RESPONSE_TIME_DSEC
;
154 pim_ifp
->igmp_specific_query_max_response_time_dsec
=
155 IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC
;
158 RFC 3376: 8.3. Query Response Interval
159 The number of seconds represented by the [Query Response Interval]
160 must be less than the [Query Interval].
162 zassert(pim_ifp
->igmp_query_max_response_time_dsec
163 < pim_ifp
->igmp_default_query_interval
);
166 PIM_IF_DO_PIM(pim_ifp
->options
);
168 PIM_IF_DO_IGMP(pim_ifp
->options
);
170 PIM_IF_DO_IGMP_LISTEN_ALLROUTERS(pim_ifp
->options
);
172 pim_ifp
->igmp_join_list
= NULL
;
173 pim_ifp
->igmp_socket_list
= NULL
;
174 pim_ifp
->pim_neighbor_list
= NULL
;
175 pim_ifp
->upstream_switch_list
= NULL
;
176 pim_ifp
->pim_generation_id
= 0;
178 /* list of struct igmp_sock */
179 pim_ifp
->igmp_socket_list
= list_new();
180 if (!pim_ifp
->igmp_socket_list
) {
181 zlog_err("%s: failure: igmp_socket_list=list_new()",
182 __PRETTY_FUNCTION__
);
183 return if_list_clean(pim_ifp
);
185 pim_ifp
->igmp_socket_list
->del
= (void (*)(void *))igmp_sock_free
;
187 /* list of struct pim_neighbor */
188 pim_ifp
->pim_neighbor_list
= list_new();
189 if (!pim_ifp
->pim_neighbor_list
) {
190 zlog_err("%s: failure: pim_neighbor_list=list_new()",
191 __PRETTY_FUNCTION__
);
192 return if_list_clean(pim_ifp
);
194 pim_ifp
->pim_neighbor_list
->del
= (void (*)(void *))pim_neighbor_free
;
196 pim_ifp
->upstream_switch_list
= list_new();
197 if (!pim_ifp
->upstream_switch_list
) {
198 zlog_err("%s: failure: upstream_switch_list=list_new()",
199 __PRETTY_FUNCTION__
);
200 return if_list_clean(pim_ifp
);
202 pim_ifp
->upstream_switch_list
->del
=
203 (void (*)(void *))pim_jp_agg_group_list_free
;
204 pim_ifp
->upstream_switch_list
->cmp
= pim_jp_agg_group_list_cmp
;
206 pim_ifp
->sec_addr_list
= list_new();
207 if (!pim_ifp
->sec_addr_list
) {
208 zlog_err("%s: failure: secondary addresslist",
209 __PRETTY_FUNCTION__
);
210 return if_list_clean(pim_ifp
);
212 pim_ifp
->sec_addr_list
->del
= (void (*)(void *))pim_sec_addr_free
;
213 pim_ifp
->sec_addr_list
->cmp
=
214 (int (*)(void *, void *))pim_sec_addr_comp
;
216 RB_INIT(pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
);
227 void pim_if_delete(struct interface
*ifp
)
229 struct pim_interface
*pim_ifp
;
230 struct pim_ifchannel
*ch
;
236 if (pim_ifp
->igmp_join_list
) {
237 pim_if_igmp_join_del_all(ifp
);
240 pim_ifchannel_delete_all(ifp
);
241 igmp_sock_delete_all(ifp
);
243 pim_neighbor_delete_all(ifp
, "Interface removed from configuration");
247 list_delete_and_null(&pim_ifp
->igmp_socket_list
);
248 list_delete_and_null(&pim_ifp
->pim_neighbor_list
);
249 list_delete_and_null(&pim_ifp
->upstream_switch_list
);
250 list_delete_and_null(&pim_ifp
->sec_addr_list
);
252 if (pim_ifp
->boundary_oil_plist
)
253 XFREE(MTYPE_PIM_INTERFACE
, pim_ifp
->boundary_oil_plist
);
255 while (!RB_EMPTY(pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
)) {
256 ch
= RB_ROOT(pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
);
258 pim_ifchannel_delete(ch
);
261 XFREE(MTYPE_PIM_INTERFACE
, pim_ifp
);
266 void pim_if_update_could_assert(struct interface
*ifp
)
268 struct pim_interface
*pim_ifp
;
269 struct pim_ifchannel
*ch
;
274 RB_FOREACH (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
) {
275 pim_ifchannel_update_could_assert(ch
);
279 static void pim_if_update_my_assert_metric(struct interface
*ifp
)
281 struct pim_interface
*pim_ifp
;
282 struct pim_ifchannel
*ch
;
287 RB_FOREACH (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
) {
288 pim_ifchannel_update_my_assert_metric(ch
);
292 static void pim_addr_change(struct interface
*ifp
)
294 struct pim_interface
*pim_ifp
;
299 pim_if_dr_election(ifp
); /* router's own DR Priority (addr) changes --
301 pim_if_update_join_desired(pim_ifp
); /* depends on DR */
302 pim_if_update_could_assert(ifp
); /* depends on DR */
303 pim_if_update_my_assert_metric(ifp
); /* depends on could_assert */
304 pim_if_update_assert_tracking_desired(
305 ifp
); /* depends on DR, join_desired */
308 RFC 4601: 4.3.1. Sending Hello Messages
310 1) Before an interface goes down or changes primary IP address, a
311 Hello message with a zero HoldTime should be sent immediately
312 (with the old IP address if the IP address changed).
313 -- FIXME See CAVEAT C13
315 2) After an interface has changed its IP address, it MUST send a
316 Hello message with its new IP address.
319 3) If an interface changes one of its secondary IP addresses, a
320 Hello message with an updated Address_List option and a non-zero
321 HoldTime should be sent immediately.
322 -- FIXME See TODO T31
324 pim_ifp
->pim_ifstat_hello_sent
= 0; /* reset hello counter */
325 if (pim_ifp
->pim_sock_fd
< 0)
327 pim_hello_restart_now(ifp
); /* send hello and restart timer */
330 static int detect_primary_address_change(struct interface
*ifp
,
331 int force_prim_as_any
,
334 struct pim_interface
*pim_ifp
= ifp
->info
;
335 struct in_addr new_prim_addr
;
338 if (force_prim_as_any
)
339 new_prim_addr
.s_addr
= INADDR_ANY
;
341 new_prim_addr
= pim_find_primary_addr(ifp
);
343 changed
= new_prim_addr
.s_addr
!= pim_ifp
->primary_address
.s_addr
;
345 if (PIM_DEBUG_ZEBRA
) {
346 char new_prim_str
[INET_ADDRSTRLEN
];
347 char old_prim_str
[INET_ADDRSTRLEN
];
348 pim_inet4_dump("<new?>", new_prim_addr
, new_prim_str
,
349 sizeof(new_prim_str
));
350 pim_inet4_dump("<old?>", pim_ifp
->primary_address
, old_prim_str
,
351 sizeof(old_prim_str
));
352 zlog_debug("%s: old=%s new=%s on interface %s: %s",
353 __PRETTY_FUNCTION__
, old_prim_str
, new_prim_str
,
354 ifp
->name
, changed
? "changed" : "unchanged");
358 pim_ifp
->primary_address
= new_prim_addr
;
364 static struct pim_secondary_addr
*
365 pim_sec_addr_find(struct pim_interface
*pim_ifp
, struct prefix
*addr
)
367 struct pim_secondary_addr
*sec_addr
;
368 struct listnode
*node
;
370 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->sec_addr_list
, node
, sec_addr
)) {
371 if (prefix_cmp(&sec_addr
->addr
, addr
)) {
379 static void pim_sec_addr_del(struct pim_interface
*pim_ifp
,
380 struct pim_secondary_addr
*sec_addr
)
382 listnode_delete(pim_ifp
->sec_addr_list
, sec_addr
);
383 pim_sec_addr_free(sec_addr
);
386 static int pim_sec_addr_add(struct pim_interface
*pim_ifp
, struct prefix
*addr
)
389 struct pim_secondary_addr
*sec_addr
;
391 sec_addr
= pim_sec_addr_find(pim_ifp
, addr
);
393 sec_addr
->flags
&= ~PIM_SEC_ADDRF_STALE
;
397 sec_addr
= XCALLOC(MTYPE_PIM_SEC_ADDR
, sizeof(*sec_addr
));
402 sec_addr
->addr
= *addr
;
403 listnode_add_sort(pim_ifp
->sec_addr_list
, sec_addr
);
408 static int pim_sec_addr_del_all(struct pim_interface
*pim_ifp
)
412 if (!list_isempty(pim_ifp
->sec_addr_list
)) {
414 /* remove all nodes and free up the list itself */
415 list_delete_all_node(pim_ifp
->sec_addr_list
);
421 static int pim_sec_addr_update(struct interface
*ifp
)
423 struct pim_interface
*pim_ifp
= ifp
->info
;
424 struct connected
*ifc
;
425 struct listnode
*node
;
426 struct listnode
*nextnode
;
427 struct pim_secondary_addr
*sec_addr
;
430 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->sec_addr_list
, node
,
432 sec_addr
->flags
|= PIM_SEC_ADDRF_STALE
;
435 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, ifc
)) {
436 struct prefix
*p
= ifc
->address
;
438 if (PIM_INADDR_IS_ANY(p
->u
.prefix4
)) {
442 if (pim_ifp
->primary_address
.s_addr
== p
->u
.prefix4
.s_addr
) {
443 /* don't add the primary address into the secondary
448 if (pim_sec_addr_add(pim_ifp
, p
)) {
453 /* Drop stale entries */
454 for (ALL_LIST_ELEMENTS(pim_ifp
->sec_addr_list
, node
, nextnode
,
456 if (sec_addr
->flags
& PIM_SEC_ADDRF_STALE
) {
457 pim_sec_addr_del(pim_ifp
, sec_addr
);
465 static int detect_secondary_address_change(struct interface
*ifp
,
466 int force_prim_as_any
,
469 struct pim_interface
*pim_ifp
= ifp
->info
;
472 if (force_prim_as_any
) {
473 /* if primary address is being forced to zero just flush the
474 * secondary address list */
475 changed
= pim_sec_addr_del_all(pim_ifp
);
477 /* re-evaluate the secondary address list */
478 changed
= pim_sec_addr_update(ifp
);
484 static void detect_address_change(struct interface
*ifp
, int force_prim_as_any
,
488 struct pim_interface
*pim_ifp
;
494 if (detect_primary_address_change(ifp
, force_prim_as_any
, caller
)) {
498 if (detect_secondary_address_change(ifp
, force_prim_as_any
, caller
)) {
504 if (!PIM_IF_TEST_PIM(pim_ifp
->options
)) {
508 pim_addr_change(ifp
);
511 /* XXX: if we have unnumbered interfaces we need to run detect address
512 * address change on all of them when the lo address changes */
515 int pim_update_source_set(struct interface
*ifp
, struct in_addr source
)
517 struct pim_interface
*pim_ifp
= ifp
->info
;
520 return PIM_IFACE_NOT_FOUND
;
523 if (pim_ifp
->update_source
.s_addr
== source
.s_addr
) {
524 return PIM_UPDATE_SOURCE_DUP
;
527 pim_ifp
->update_source
= source
;
528 detect_address_change(ifp
, 0 /* force_prim_as_any */,
529 __PRETTY_FUNCTION__
);
534 void pim_if_addr_add(struct connected
*ifc
)
536 struct pim_interface
*pim_ifp
;
537 struct interface
*ifp
;
538 struct in_addr ifaddr
;
548 if (!if_is_operative(ifp
))
551 if (PIM_DEBUG_ZEBRA
) {
553 prefix2str(ifc
->address
, buf
, BUFSIZ
);
554 zlog_debug("%s: %s ifindex=%d connected IP address %s %s",
555 __PRETTY_FUNCTION__
, ifp
->name
, ifp
->ifindex
, buf
,
556 CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
)
561 ifaddr
= ifc
->address
->u
.prefix4
;
563 detect_address_change(ifp
, 0, __PRETTY_FUNCTION__
);
565 // if (ifc->address->family != AF_INET)
568 if (PIM_IF_TEST_IGMP(pim_ifp
->options
)) {
569 struct igmp_sock
*igmp
;
571 /* lookup IGMP socket */
572 igmp
= pim_igmp_sock_lookup_ifaddr(pim_ifp
->igmp_socket_list
,
575 /* if addr new, add IGMP socket */
576 if (ifc
->address
->family
== AF_INET
)
577 pim_igmp_sock_add(pim_ifp
->igmp_socket_list
,
581 /* Replay Static IGMP groups */
582 if (pim_ifp
->igmp_join_list
) {
583 struct listnode
*node
;
584 struct listnode
*nextnode
;
585 struct igmp_join
*ij
;
588 for (ALL_LIST_ELEMENTS(pim_ifp
->igmp_join_list
, node
,
590 /* Close socket and reopen with Source and Group
593 join_fd
= igmp_join_sock(
594 ifp
->name
, ifp
->ifindex
, ij
->group_addr
,
597 char group_str
[INET_ADDRSTRLEN
];
598 char source_str
[INET_ADDRSTRLEN
];
599 pim_inet4_dump("<grp?>", ij
->group_addr
,
603 "<src?>", ij
->source_addr
,
604 source_str
, sizeof(source_str
));
606 "%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s",
607 __PRETTY_FUNCTION__
, group_str
,
608 source_str
, ifp
->name
);
611 ij
->sock_fd
= join_fd
;
616 if (PIM_IF_TEST_PIM(pim_ifp
->options
)) {
618 if (PIM_INADDR_ISNOT_ANY(pim_ifp
->primary_address
)) {
620 /* Interface has a valid socket ? */
621 if (pim_ifp
->pim_sock_fd
< 0) {
622 if (pim_sock_add(ifp
)) {
624 "Failure creating PIM socket for interface %s",
628 struct pim_nexthop_cache
*pnc
= NULL
;
630 struct zclient
*zclient
= NULL
;
632 zclient
= pim_zebra_zclient_get();
633 /* RP config might come prior to (local RP's interface)
635 In this case, pnc would not have pim enabled
637 Once Interface is UP and pim info is available,
639 with RNH address to receive update and add the
640 interface as nexthop. */
641 memset(&rpf
, 0, sizeof(struct pim_rpf
));
642 rpf
.rpf_addr
.family
= AF_INET
;
643 rpf
.rpf_addr
.prefixlen
= IPV4_MAX_BITLEN
;
644 rpf
.rpf_addr
.u
.prefix4
= ifc
->address
->u
.prefix4
;
645 pnc
= pim_nexthop_cache_find(pim_ifp
->pim
, &rpf
);
647 pim_sendmsg_zebra_rnh(pim_ifp
->pim
, zclient
,
649 ZEBRA_NEXTHOP_REGISTER
);
654 PIM or IGMP is enabled on interface, and there is at least one
655 address assigned, then try to create a vif_index.
657 if (pim_ifp
->mroute_vif_index
< 0) {
660 pim_ifchannel_scan_forward_start(ifp
);
663 static void pim_if_addr_del_igmp(struct connected
*ifc
)
665 struct pim_interface
*pim_ifp
= ifc
->ifp
->info
;
666 struct igmp_sock
*igmp
;
667 struct in_addr ifaddr
;
669 if (ifc
->address
->family
!= AF_INET
) {
670 /* non-IPv4 address */
675 /* IGMP not enabled on interface */
679 ifaddr
= ifc
->address
->u
.prefix4
;
681 /* lookup IGMP socket */
682 igmp
= pim_igmp_sock_lookup_ifaddr(pim_ifp
->igmp_socket_list
, ifaddr
);
684 /* if addr found, del IGMP socket */
685 igmp_sock_delete(igmp
);
689 static void pim_if_addr_del_pim(struct connected
*ifc
)
691 struct pim_interface
*pim_ifp
= ifc
->ifp
->info
;
693 if (ifc
->address
->family
!= AF_INET
) {
694 /* non-IPv4 address */
699 /* PIM not enabled on interface */
703 if (PIM_INADDR_ISNOT_ANY(pim_ifp
->primary_address
)) {
704 /* Interface keeps a valid primary address */
708 if (pim_ifp
->pim_sock_fd
< 0) {
709 /* Interface does not hold a valid socket any longer */
714 pim_sock_delete() closes the socket, stops read and timer threads,
715 and kills all neighbors.
717 pim_sock_delete(ifc
->ifp
,
718 "last address has been removed from interface");
721 void pim_if_addr_del(struct connected
*ifc
, int force_prim_as_any
)
723 struct interface
*ifp
;
729 if (PIM_DEBUG_ZEBRA
) {
731 prefix2str(ifc
->address
, buf
, BUFSIZ
);
732 zlog_debug("%s: %s ifindex=%d disconnected IP address %s %s",
733 __PRETTY_FUNCTION__
, ifp
->name
, ifp
->ifindex
, buf
,
734 CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
)
739 detect_address_change(ifp
, force_prim_as_any
, __PRETTY_FUNCTION__
);
741 pim_if_addr_del_igmp(ifc
);
742 pim_if_addr_del_pim(ifc
);
745 void pim_if_addr_add_all(struct interface
*ifp
)
747 struct connected
*ifc
;
748 struct listnode
*node
;
749 struct listnode
*nextnode
;
752 struct pim_interface
*pim_ifp
= ifp
->info
;
755 /* PIM/IGMP enabled ? */
759 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
760 struct prefix
*p
= ifc
->address
;
762 if (p
->family
!= AF_INET
)
766 pim_if_addr_add(ifc
);
769 if (!v4_addrs
&& v6_addrs
&& !if_is_loopback(ifp
)) {
770 if (PIM_IF_TEST_PIM(pim_ifp
->options
)) {
772 /* Interface has a valid primary address ? */
773 if (PIM_INADDR_ISNOT_ANY(pim_ifp
->primary_address
)) {
775 /* Interface has a valid socket ? */
776 if (pim_ifp
->pim_sock_fd
< 0) {
777 if (pim_sock_add(ifp
)) {
779 "Failure creating PIM socket for interface %s",
787 * PIM or IGMP is enabled on interface, and there is at least one
788 * address assigned, then try to create a vif_index.
790 if (pim_ifp
->mroute_vif_index
< 0) {
793 pim_ifchannel_scan_forward_start(ifp
);
795 pim_rp_setup(pim_ifp
->pim
);
796 pim_rp_check_on_if_add(pim_ifp
);
799 void pim_if_addr_del_all(struct interface
*ifp
)
801 struct connected
*ifc
;
802 struct listnode
*node
;
803 struct listnode
*nextnode
;
804 struct vrf
*vrf
= vrf_lookup_by_id(ifp
->vrf_id
);
805 struct pim_instance
*pim
;
811 /* PIM/IGMP enabled ? */
815 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
816 struct prefix
*p
= ifc
->address
;
818 if (p
->family
!= AF_INET
)
821 pim_if_addr_del(ifc
, 1 /* force_prim_as_any=true */);
825 pim_i_am_rp_re_evaluate(pim
);
828 void pim_if_addr_del_all_igmp(struct interface
*ifp
)
830 struct connected
*ifc
;
831 struct listnode
*node
;
832 struct listnode
*nextnode
;
834 /* PIM/IGMP enabled ? */
838 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
839 struct prefix
*p
= ifc
->address
;
841 if (p
->family
!= AF_INET
)
844 pim_if_addr_del_igmp(ifc
);
848 void pim_if_addr_del_all_pim(struct interface
*ifp
)
850 struct connected
*ifc
;
851 struct listnode
*node
;
852 struct listnode
*nextnode
;
854 /* PIM/IGMP enabled ? */
858 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
859 struct prefix
*p
= ifc
->address
;
861 if (p
->family
!= AF_INET
)
864 pim_if_addr_del_pim(ifc
);
868 struct in_addr
pim_find_primary_addr(struct interface
*ifp
)
870 struct connected
*ifc
;
871 struct listnode
*node
;
872 struct in_addr addr
= {0};
875 struct pim_interface
*pim_ifp
= ifp
->info
;
876 struct vrf
*vrf
= vrf_lookup_by_id(ifp
->vrf_id
);
881 if (pim_ifp
&& PIM_INADDR_ISNOT_ANY(pim_ifp
->update_source
)) {
882 return pim_ifp
->update_source
;
885 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, ifc
)) {
886 struct prefix
*p
= ifc
->address
;
888 if (p
->family
!= AF_INET
) {
893 if (PIM_INADDR_IS_ANY(p
->u
.prefix4
)) {
895 "%s: null IPv4 address connected to interface %s",
896 __PRETTY_FUNCTION__
, ifp
->name
);
902 if (CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
))
909 * If we have no v4_addrs and v6 is configured
910 * We probably are using unnumbered
911 * So let's grab the loopbacks v4 address
912 * and use that as the primary address
914 if (!v4_addrs
&& v6_addrs
&& !if_is_loopback(ifp
)) {
915 struct interface
*lo_ifp
;
916 // DBS - Come back and check here
917 if (ifp
->vrf_id
== VRF_DEFAULT
)
918 lo_ifp
= if_lookup_by_name("lo", vrf
->vrf_id
);
920 lo_ifp
= if_lookup_by_name(vrf
->name
, vrf
->vrf_id
);
923 return pim_find_primary_addr(lo_ifp
);
926 addr
.s_addr
= PIM_NET_INADDR_ANY
;
931 static int pim_iface_next_vif_index(struct interface
*ifp
)
933 struct pim_interface
*pim_ifp
= ifp
->info
;
934 struct pim_instance
*pim
= pim_ifp
->pim
;
938 * The pimreg vif is always going to be in index 0
941 if (ifp
->ifindex
== PIM_OIF_PIM_REGISTER_VIF
)
944 for (i
= 1; i
< MAXVIFS
; i
++) {
945 if (pim
->iface_vif_index
[i
] == 0)
952 pim_if_add_vif() uses ifindex as vif_index
954 see also pim_if_find_vifindex_by_ifindex()
956 int pim_if_add_vif(struct interface
*ifp
)
958 struct pim_interface
*pim_ifp
= ifp
->info
;
959 struct in_addr ifaddr
;
960 unsigned char flags
= 0;
964 if (pim_ifp
->mroute_vif_index
> 0) {
965 zlog_warn("%s: vif_index=%d > 0 on interface %s ifindex=%d",
966 __PRETTY_FUNCTION__
, pim_ifp
->mroute_vif_index
,
967 ifp
->name
, ifp
->ifindex
);
971 if (ifp
->ifindex
< 0) {
972 zlog_warn("%s: ifindex=%d < 1 on interface %s",
973 __PRETTY_FUNCTION__
, ifp
->ifindex
, ifp
->name
);
977 ifaddr
= pim_ifp
->primary_address
;
978 if (ifp
->ifindex
!= PIM_OIF_PIM_REGISTER_VIF
979 && PIM_INADDR_IS_ANY(ifaddr
)) {
981 "%s: could not get address for interface %s ifindex=%d",
982 __PRETTY_FUNCTION__
, ifp
->name
, ifp
->ifindex
);
986 pim_ifp
->mroute_vif_index
= pim_iface_next_vif_index(ifp
);
988 if (pim_ifp
->mroute_vif_index
>= MAXVIFS
) {
990 "%s: Attempting to configure more than MAXVIFS=%d on pim enabled interface %s",
991 __PRETTY_FUNCTION__
, MAXVIFS
, ifp
->name
);
995 if (ifp
->ifindex
== PIM_OIF_PIM_REGISTER_VIF
)
996 flags
= VIFF_REGISTER
;
997 #ifdef VIFF_USE_IFINDEX
999 flags
= VIFF_USE_IFINDEX
;
1002 if (pim_mroute_add_vif(ifp
, ifaddr
, flags
)) {
1003 /* pim_mroute_add_vif reported error */
1007 pim_ifp
->pim
->iface_vif_index
[pim_ifp
->mroute_vif_index
] = 1;
1011 int pim_if_del_vif(struct interface
*ifp
)
1013 struct pim_interface
*pim_ifp
= ifp
->info
;
1015 if (pim_ifp
->mroute_vif_index
< 1) {
1016 zlog_warn("%s: vif_index=%d < 1 on interface %s ifindex=%d",
1017 __PRETTY_FUNCTION__
, pim_ifp
->mroute_vif_index
,
1018 ifp
->name
, ifp
->ifindex
);
1022 pim_mroute_del_vif(ifp
);
1027 pim_ifp
->pim
->iface_vif_index
[pim_ifp
->mroute_vif_index
] = 0;
1029 pim_ifp
->mroute_vif_index
= -1;
1035 struct interface
*pim_if_find_by_vif_index(struct pim_instance
*pim
,
1036 ifindex_t vif_index
)
1038 struct interface
*ifp
;
1040 FOR_ALL_INTERFACES (pim
->vrf
, ifp
) {
1042 struct pim_interface
*pim_ifp
;
1043 pim_ifp
= ifp
->info
;
1045 if (vif_index
== pim_ifp
->mroute_vif_index
)
1054 pim_if_add_vif() uses ifindex as vif_index
1056 int pim_if_find_vifindex_by_ifindex(struct pim_instance
*pim
, ifindex_t ifindex
)
1058 struct pim_interface
*pim_ifp
;
1059 struct interface
*ifp
;
1061 ifp
= if_lookup_by_index(ifindex
, pim
->vrf_id
);
1062 if (!ifp
|| !ifp
->info
)
1064 pim_ifp
= ifp
->info
;
1066 return pim_ifp
->mroute_vif_index
;
1069 int pim_if_lan_delay_enabled(struct interface
*ifp
)
1071 struct pim_interface
*pim_ifp
;
1073 pim_ifp
= ifp
->info
;
1075 zassert(pim_ifp
->pim_number_of_nonlandelay_neighbors
>= 0);
1077 return pim_ifp
->pim_number_of_nonlandelay_neighbors
== 0;
1080 uint16_t pim_if_effective_propagation_delay_msec(struct interface
*ifp
)
1082 if (pim_if_lan_delay_enabled(ifp
)) {
1083 struct pim_interface
*pim_ifp
;
1084 pim_ifp
= ifp
->info
;
1085 return pim_ifp
->pim_neighbors_highest_propagation_delay_msec
;
1087 return PIM_DEFAULT_PROPAGATION_DELAY_MSEC
;
1091 uint16_t pim_if_effective_override_interval_msec(struct interface
*ifp
)
1093 if (pim_if_lan_delay_enabled(ifp
)) {
1094 struct pim_interface
*pim_ifp
;
1095 pim_ifp
= ifp
->info
;
1096 return pim_ifp
->pim_neighbors_highest_override_interval_msec
;
1098 return PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC
;
1102 int pim_if_t_override_msec(struct interface
*ifp
)
1104 int effective_override_interval_msec
;
1105 int t_override_msec
;
1107 effective_override_interval_msec
=
1108 pim_if_effective_override_interval_msec(ifp
);
1110 t_override_msec
= random() % (effective_override_interval_msec
+ 1);
1112 return t_override_msec
;
1115 uint16_t pim_if_jp_override_interval_msec(struct interface
*ifp
)
1117 return pim_if_effective_propagation_delay_msec(ifp
)
1118 + pim_if_effective_override_interval_msec(ifp
);
1122 RFC 4601: 4.1.6. State Summarization Macros
1124 The function NBR( I, A ) uses information gathered through PIM Hello
1125 messages to map the IP address A of a directly connected PIM
1126 neighbor router on interface I to the primary IP address of the same
1127 router (Section 4.3.4). The primary IP address of a neighbor is the
1128 address that it uses as the source of its PIM Hello messages.
1130 struct pim_neighbor
*pim_if_find_neighbor(struct interface
*ifp
,
1131 struct in_addr addr
)
1133 struct listnode
*neighnode
;
1134 struct pim_neighbor
*neigh
;
1135 struct pim_interface
*pim_ifp
;
1140 pim_ifp
= ifp
->info
;
1142 zlog_warn("%s: multicast not enabled on interface %s",
1143 __PRETTY_FUNCTION__
, ifp
->name
);
1149 p
.prefixlen
= IPV4_MAX_PREFIXLEN
;
1151 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
, neighnode
,
1154 /* primary address ? */
1155 if (neigh
->source_addr
.s_addr
== addr
.s_addr
)
1158 /* secondary address ? */
1159 if (pim_neighbor_find_secondary(neigh
, &p
))
1163 if (PIM_DEBUG_PIM_TRACE
) {
1164 char addr_str
[INET_ADDRSTRLEN
];
1165 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
1167 "%s: neighbor not found for address %s on interface %s",
1168 __PRETTY_FUNCTION__
, addr_str
, ifp
->name
);
1174 long pim_if_t_suppressed_msec(struct interface
*ifp
)
1176 struct pim_interface
*pim_ifp
;
1177 long t_suppressed_msec
;
1178 uint32_t ramount
= 0;
1180 pim_ifp
= ifp
->info
;
1183 /* join suppression disabled ? */
1184 if (PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp
->options
))
1187 /* t_suppressed = t_periodic * rand(1.1, 1.4) */
1188 ramount
= 1100 + (random() % (1400 - 1100 + 1));
1189 t_suppressed_msec
= qpim_t_periodic
* ramount
;
1191 return t_suppressed_msec
;
1194 static void igmp_join_free(struct igmp_join
*ij
)
1196 XFREE(MTYPE_PIM_IGMP_JOIN
, ij
);
1199 static struct igmp_join
*igmp_join_find(struct list
*join_list
,
1200 struct in_addr group_addr
,
1201 struct in_addr source_addr
)
1203 struct listnode
*node
;
1204 struct igmp_join
*ij
;
1208 for (ALL_LIST_ELEMENTS_RO(join_list
, node
, ij
)) {
1209 if ((group_addr
.s_addr
== ij
->group_addr
.s_addr
)
1210 && (source_addr
.s_addr
== ij
->source_addr
.s_addr
))
1217 static int igmp_join_sock(const char *ifname
, ifindex_t ifindex
,
1218 struct in_addr group_addr
, struct in_addr source_addr
)
1222 join_fd
= pim_socket_raw(IPPROTO_IGMP
);
1227 if (pim_socket_join_source(join_fd
, ifindex
, group_addr
, source_addr
,
1236 static struct igmp_join
*igmp_join_new(struct interface
*ifp
,
1237 struct in_addr group_addr
,
1238 struct in_addr source_addr
)
1240 struct pim_interface
*pim_ifp
;
1241 struct igmp_join
*ij
;
1244 pim_ifp
= ifp
->info
;
1247 join_fd
= igmp_join_sock(ifp
->name
, ifp
->ifindex
, group_addr
,
1250 char group_str
[INET_ADDRSTRLEN
];
1251 char source_str
[INET_ADDRSTRLEN
];
1252 pim_inet4_dump("<grp?>", group_addr
, group_str
,
1254 pim_inet4_dump("<src?>", source_addr
, source_str
,
1255 sizeof(source_str
));
1257 "%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s",
1258 __PRETTY_FUNCTION__
, group_str
, source_str
, ifp
->name
);
1262 ij
= XCALLOC(MTYPE_PIM_IGMP_JOIN
, sizeof(*ij
));
1264 char group_str
[INET_ADDRSTRLEN
];
1265 char source_str
[INET_ADDRSTRLEN
];
1266 pim_inet4_dump("<grp?>", group_addr
, group_str
,
1268 pim_inet4_dump("<src?>", source_addr
, source_str
,
1269 sizeof(source_str
));
1271 "%s: XCALLOC(%zu) failure for IGMP group %s source %s on interface %s",
1272 __PRETTY_FUNCTION__
, sizeof(*ij
), group_str
, source_str
,
1278 ij
->sock_fd
= join_fd
;
1279 ij
->group_addr
= group_addr
;
1280 ij
->source_addr
= source_addr
;
1281 ij
->sock_creation
= pim_time_monotonic_sec();
1283 listnode_add(pim_ifp
->igmp_join_list
, ij
);
1288 ferr_r
pim_if_igmp_join_add(struct interface
*ifp
, struct in_addr group_addr
,
1289 struct in_addr source_addr
)
1291 struct pim_interface
*pim_ifp
;
1292 struct igmp_join
*ij
;
1294 pim_ifp
= ifp
->info
;
1296 return ferr_cfg_invalid("multicast not enabled on interface %s",
1300 if (!pim_ifp
->igmp_join_list
) {
1301 pim_ifp
->igmp_join_list
= list_new();
1302 if (!pim_ifp
->igmp_join_list
) {
1303 return ferr_cfg_invalid("Insufficient memory");
1305 pim_ifp
->igmp_join_list
->del
= (void (*)(void *))igmp_join_free
;
1308 ij
= igmp_join_find(pim_ifp
->igmp_join_list
, group_addr
, source_addr
);
1310 /* This interface has already been configured to join this IGMP group
1316 ij
= igmp_join_new(ifp
, group_addr
, source_addr
);
1318 return ferr_cfg_invalid(
1319 "Failure to create new join data structure, see log file for more information");
1322 if (PIM_DEBUG_IGMP_EVENTS
) {
1323 char group_str
[INET_ADDRSTRLEN
];
1324 char source_str
[INET_ADDRSTRLEN
];
1325 pim_inet4_dump("<grp?>", group_addr
, group_str
,
1327 pim_inet4_dump("<src?>", source_addr
, source_str
,
1328 sizeof(source_str
));
1330 "%s: issued static igmp join for channel (S,G)=(%s,%s) on interface %s",
1331 __PRETTY_FUNCTION__
, source_str
, group_str
, ifp
->name
);
1338 int pim_if_igmp_join_del(struct interface
*ifp
, struct in_addr group_addr
,
1339 struct in_addr source_addr
)
1341 struct pim_interface
*pim_ifp
;
1342 struct igmp_join
*ij
;
1344 pim_ifp
= ifp
->info
;
1346 zlog_warn("%s: multicast not enabled on interface %s",
1347 __PRETTY_FUNCTION__
, ifp
->name
);
1351 if (!pim_ifp
->igmp_join_list
) {
1352 zlog_warn("%s: no IGMP join on interface %s",
1353 __PRETTY_FUNCTION__
, ifp
->name
);
1357 ij
= igmp_join_find(pim_ifp
->igmp_join_list
, group_addr
, source_addr
);
1359 char group_str
[INET_ADDRSTRLEN
];
1360 char source_str
[INET_ADDRSTRLEN
];
1361 pim_inet4_dump("<grp?>", group_addr
, group_str
,
1363 pim_inet4_dump("<src?>", source_addr
, source_str
,
1364 sizeof(source_str
));
1366 "%s: could not find IGMP group %s source %s on interface %s",
1367 __PRETTY_FUNCTION__
, group_str
, source_str
, ifp
->name
);
1371 if (close(ij
->sock_fd
)) {
1372 char group_str
[INET_ADDRSTRLEN
];
1373 char source_str
[INET_ADDRSTRLEN
];
1374 pim_inet4_dump("<grp?>", group_addr
, group_str
,
1376 pim_inet4_dump("<src?>", source_addr
, source_str
,
1377 sizeof(source_str
));
1379 "%s: failure closing sock_fd=%d for IGMP group %s source %s on interface %s: errno=%d: %s",
1380 __PRETTY_FUNCTION__
, ij
->sock_fd
, group_str
, source_str
,
1381 ifp
->name
, errno
, safe_strerror(errno
));
1384 listnode_delete(pim_ifp
->igmp_join_list
, ij
);
1386 if (listcount(pim_ifp
->igmp_join_list
) < 1) {
1387 list_delete_and_null(&pim_ifp
->igmp_join_list
);
1388 pim_ifp
->igmp_join_list
= 0;
1394 static void pim_if_igmp_join_del_all(struct interface
*ifp
)
1396 struct pim_interface
*pim_ifp
;
1397 struct listnode
*node
;
1398 struct listnode
*nextnode
;
1399 struct igmp_join
*ij
;
1401 pim_ifp
= ifp
->info
;
1403 zlog_warn("%s: multicast not enabled on interface %s",
1404 __PRETTY_FUNCTION__
, ifp
->name
);
1408 if (!pim_ifp
->igmp_join_list
)
1411 for (ALL_LIST_ELEMENTS(pim_ifp
->igmp_join_list
, node
, nextnode
, ij
))
1412 pim_if_igmp_join_del(ifp
, ij
->group_addr
, ij
->source_addr
);
1418 Transitions from "I am Assert Loser" State
1420 Current Winner's GenID Changes or NLT Expires
1422 The Neighbor Liveness Timer associated with the current winner
1423 expires or we receive a Hello message from the current winner
1424 reporting a different GenID from the one it previously reported.
1425 This indicates that the current winner's interface or router has
1426 gone down (and may have come back up), and so we must assume it no
1427 longer knows it was the winner.
1429 void pim_if_assert_on_neighbor_down(struct interface
*ifp
,
1430 struct in_addr neigh_addr
)
1432 struct pim_interface
*pim_ifp
;
1433 struct pim_ifchannel
*ch
;
1435 pim_ifp
= ifp
->info
;
1438 RB_FOREACH (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
) {
1439 /* Is (S,G,I) assert loser ? */
1440 if (ch
->ifassert_state
!= PIM_IFASSERT_I_AM_LOSER
)
1442 /* Dead neighbor was winner ? */
1443 if (ch
->ifassert_winner
.s_addr
!= neigh_addr
.s_addr
)
1446 assert_action_a5(ch
);
1450 void pim_if_update_join_desired(struct pim_interface
*pim_ifp
)
1452 struct pim_ifchannel
*ch
;
1454 /* clear off flag from interface's upstreams */
1455 RB_FOREACH (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
) {
1456 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(
1457 ch
->upstream
->flags
);
1460 /* scan per-interface (S,G,I) state on this I interface */
1461 RB_FOREACH (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
) {
1462 struct pim_upstream
*up
= ch
->upstream
;
1464 if (PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(up
->flags
))
1467 /* update join_desired for the global (S,G) state */
1468 pim_upstream_update_join_desired(pim_ifp
->pim
, up
);
1469 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(up
->flags
);
1473 void pim_if_update_assert_tracking_desired(struct interface
*ifp
)
1475 struct pim_interface
*pim_ifp
;
1476 struct pim_ifchannel
*ch
;
1478 pim_ifp
= ifp
->info
;
1482 RB_FOREACH (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
) {
1483 pim_ifchannel_update_assert_tracking_desired(ch
);
1488 * PIM wants to have an interface pointer for everything it does.
1489 * The pimreg is a special interface that we have that is not
1490 * quite an inteface but a VIF is created for it.
1492 void pim_if_create_pimreg(struct pim_instance
*pim
)
1494 char pimreg_name
[INTERFACE_NAMSIZ
];
1496 if (!pim
->regiface
) {
1497 if (pim
->vrf_id
== VRF_DEFAULT
)
1498 strlcpy(pimreg_name
, "pimreg", sizeof(pimreg_name
));
1500 snprintf(pimreg_name
, sizeof(pimreg_name
), "pimreg%u",
1501 pim
->vrf
->data
.l
.table_id
);
1503 pim
->regiface
= if_create(pimreg_name
, pim
->vrf_id
);
1504 pim
->regiface
->ifindex
= PIM_OIF_PIM_REGISTER_VIF
;
1506 pim_if_new(pim
->regiface
, 0, 0);
1510 int pim_if_connected_to_source(struct interface
*ifp
, struct in_addr src
)
1512 struct listnode
*cnode
;
1513 struct connected
*c
;
1521 p
.prefixlen
= IPV4_MAX_BITLEN
;
1523 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, cnode
, c
)) {
1524 if ((c
->address
->family
== AF_INET
)
1525 && prefix_match(CONNECTED_PREFIX(c
), &p
)) {
1533 int pim_if_is_loopback(struct pim_instance
*pim
, struct interface
*ifp
)
1535 if (if_is_loopback(ifp
))
1538 if (strcmp(ifp
->name
, pim
->vrf
->name
) == 0)
1544 int pim_if_is_vrf_device(struct interface
*ifp
)
1548 RB_FOREACH (vrf
, vrf_name_head
, &vrfs_by_name
) {
1549 if (strncmp(ifp
->name
, vrf
->name
, strlen(ifp
->name
)) == 0)
1556 int pim_if_ifchannel_count(struct pim_interface
*pim_ifp
)
1558 struct pim_ifchannel
*ch
;
1561 RB_FOREACH (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
) {