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
, sec_addr
)) {
431 sec_addr
->flags
|= PIM_SEC_ADDRF_STALE
;
434 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, ifc
)) {
435 struct prefix
*p
= ifc
->address
;
437 if (PIM_INADDR_IS_ANY(p
->u
.prefix4
)) {
441 if (pim_ifp
->primary_address
.s_addr
== p
->u
.prefix4
.s_addr
) {
442 /* don't add the primary address into the secondary
447 if (pim_sec_addr_add(pim_ifp
, p
)) {
452 /* Drop stale entries */
453 for (ALL_LIST_ELEMENTS(pim_ifp
->sec_addr_list
, node
, nextnode
,
455 if (sec_addr
->flags
& PIM_SEC_ADDRF_STALE
) {
456 pim_sec_addr_del(pim_ifp
, sec_addr
);
464 static int detect_secondary_address_change(struct interface
*ifp
,
465 int force_prim_as_any
,
468 struct pim_interface
*pim_ifp
= ifp
->info
;
471 if (force_prim_as_any
) {
472 /* if primary address is being forced to zero just flush the
473 * secondary address list */
474 changed
= pim_sec_addr_del_all(pim_ifp
);
476 /* re-evaluate the secondary address list */
477 changed
= pim_sec_addr_update(ifp
);
483 static void detect_address_change(struct interface
*ifp
, int force_prim_as_any
,
487 struct pim_interface
*pim_ifp
;
493 if (detect_primary_address_change(ifp
, force_prim_as_any
, caller
)) {
497 if (detect_secondary_address_change(ifp
, force_prim_as_any
, caller
)) {
503 if (!PIM_IF_TEST_PIM(pim_ifp
->options
)) {
507 pim_addr_change(ifp
);
510 /* XXX: if we have unnumbered interfaces we need to run detect address
511 * address change on all of them when the lo address changes */
514 int pim_update_source_set(struct interface
*ifp
, struct in_addr source
)
516 struct pim_interface
*pim_ifp
= ifp
->info
;
519 return PIM_IFACE_NOT_FOUND
;
522 if (pim_ifp
->update_source
.s_addr
== source
.s_addr
) {
523 return PIM_UPDATE_SOURCE_DUP
;
526 pim_ifp
->update_source
= source
;
527 detect_address_change(ifp
, 0 /* force_prim_as_any */,
528 __PRETTY_FUNCTION__
);
533 void pim_if_addr_add(struct connected
*ifc
)
535 struct pim_interface
*pim_ifp
;
536 struct interface
*ifp
;
537 struct in_addr ifaddr
;
547 if (!if_is_operative(ifp
))
550 if (PIM_DEBUG_ZEBRA
) {
552 prefix2str(ifc
->address
, buf
, BUFSIZ
);
553 zlog_debug("%s: %s ifindex=%d connected IP address %s %s",
554 __PRETTY_FUNCTION__
, ifp
->name
, ifp
->ifindex
, buf
,
555 CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
)
560 ifaddr
= ifc
->address
->u
.prefix4
;
562 detect_address_change(ifp
, 0, __PRETTY_FUNCTION__
);
564 // if (ifc->address->family != AF_INET)
567 if (PIM_IF_TEST_IGMP(pim_ifp
->options
)) {
568 struct igmp_sock
*igmp
;
570 /* lookup IGMP socket */
571 igmp
= pim_igmp_sock_lookup_ifaddr(pim_ifp
->igmp_socket_list
,
574 /* if addr new, add IGMP socket */
575 if (ifc
->address
->family
== AF_INET
)
576 pim_igmp_sock_add(pim_ifp
->igmp_socket_list
,
578 } else if (igmp
->mtrace_only
) {
579 igmp_sock_delete(igmp
);
580 pim_igmp_sock_add(pim_ifp
->igmp_socket_list
, ifaddr
,
584 /* Replay Static IGMP groups */
585 if (pim_ifp
->igmp_join_list
) {
586 struct listnode
*node
;
587 struct listnode
*nextnode
;
588 struct igmp_join
*ij
;
591 for (ALL_LIST_ELEMENTS(pim_ifp
->igmp_join_list
, node
,
593 /* Close socket and reopen with Source and Group
596 join_fd
= igmp_join_sock(
597 ifp
->name
, ifp
->ifindex
, ij
->group_addr
,
600 char group_str
[INET_ADDRSTRLEN
];
601 char source_str
[INET_ADDRSTRLEN
];
602 pim_inet4_dump("<grp?>", ij
->group_addr
,
606 "<src?>", ij
->source_addr
,
607 source_str
, sizeof(source_str
));
609 "%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s",
610 __PRETTY_FUNCTION__
, group_str
,
611 source_str
, ifp
->name
);
614 ij
->sock_fd
= join_fd
;
619 struct igmp_sock
*igmp
;
621 /* lookup IGMP socket */
622 igmp
= pim_igmp_sock_lookup_ifaddr(pim_ifp
->igmp_socket_list
,
624 if (ifc
->address
->family
== AF_INET
) {
626 igmp_sock_delete(igmp
);
627 /* if addr new, add IGMP socket */
628 pim_igmp_sock_add(pim_ifp
->igmp_socket_list
, ifaddr
,
631 } /* igmp mtrace only */
633 if (PIM_IF_TEST_PIM(pim_ifp
->options
)) {
635 if (PIM_INADDR_ISNOT_ANY(pim_ifp
->primary_address
)) {
637 /* Interface has a valid socket ? */
638 if (pim_ifp
->pim_sock_fd
< 0) {
639 if (pim_sock_add(ifp
)) {
641 "Failure creating PIM socket for interface %s",
645 struct pim_nexthop_cache
*pnc
= NULL
;
647 struct zclient
*zclient
= NULL
;
649 zclient
= pim_zebra_zclient_get();
650 /* RP config might come prior to (local RP's interface)
652 In this case, pnc would not have pim enabled
654 Once Interface is UP and pim info is available,
656 with RNH address to receive update and add the
657 interface as nexthop. */
658 memset(&rpf
, 0, sizeof(struct pim_rpf
));
659 rpf
.rpf_addr
.family
= AF_INET
;
660 rpf
.rpf_addr
.prefixlen
= IPV4_MAX_BITLEN
;
661 rpf
.rpf_addr
.u
.prefix4
= ifc
->address
->u
.prefix4
;
662 pnc
= pim_nexthop_cache_find(pim_ifp
->pim
, &rpf
);
664 pim_sendmsg_zebra_rnh(pim_ifp
->pim
, zclient
,
666 ZEBRA_NEXTHOP_REGISTER
);
671 PIM or IGMP is enabled on interface, and there is at least one
672 address assigned, then try to create a vif_index.
674 if (pim_ifp
->mroute_vif_index
< 0) {
677 pim_ifchannel_scan_forward_start(ifp
);
680 static void pim_if_addr_del_igmp(struct connected
*ifc
)
682 struct pim_interface
*pim_ifp
= ifc
->ifp
->info
;
683 struct igmp_sock
*igmp
;
684 struct in_addr ifaddr
;
686 if (ifc
->address
->family
!= AF_INET
) {
687 /* non-IPv4 address */
692 /* IGMP not enabled on interface */
696 ifaddr
= ifc
->address
->u
.prefix4
;
698 /* lookup IGMP socket */
699 igmp
= pim_igmp_sock_lookup_ifaddr(pim_ifp
->igmp_socket_list
, ifaddr
);
701 /* if addr found, del IGMP socket */
702 igmp_sock_delete(igmp
);
706 static void pim_if_addr_del_pim(struct connected
*ifc
)
708 struct pim_interface
*pim_ifp
= ifc
->ifp
->info
;
710 if (ifc
->address
->family
!= AF_INET
) {
711 /* non-IPv4 address */
716 /* PIM not enabled on interface */
720 if (PIM_INADDR_ISNOT_ANY(pim_ifp
->primary_address
)) {
721 /* Interface keeps a valid primary address */
725 if (pim_ifp
->pim_sock_fd
< 0) {
726 /* Interface does not hold a valid socket any longer */
731 pim_sock_delete() closes the socket, stops read and timer threads,
732 and kills all neighbors.
734 pim_sock_delete(ifc
->ifp
,
735 "last address has been removed from interface");
738 void pim_if_addr_del(struct connected
*ifc
, int force_prim_as_any
)
740 struct interface
*ifp
;
746 if (PIM_DEBUG_ZEBRA
) {
748 prefix2str(ifc
->address
, buf
, BUFSIZ
);
749 zlog_debug("%s: %s ifindex=%d disconnected IP address %s %s",
750 __PRETTY_FUNCTION__
, ifp
->name
, ifp
->ifindex
, buf
,
751 CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
)
756 detect_address_change(ifp
, force_prim_as_any
, __PRETTY_FUNCTION__
);
758 pim_if_addr_del_igmp(ifc
);
759 pim_if_addr_del_pim(ifc
);
762 void pim_if_addr_add_all(struct interface
*ifp
)
764 struct connected
*ifc
;
765 struct listnode
*node
;
766 struct listnode
*nextnode
;
769 struct pim_interface
*pim_ifp
= ifp
->info
;
772 /* PIM/IGMP enabled ? */
776 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
777 struct prefix
*p
= ifc
->address
;
779 if (p
->family
!= AF_INET
)
783 pim_if_addr_add(ifc
);
786 if (!v4_addrs
&& v6_addrs
&& !if_is_loopback(ifp
)) {
787 if (PIM_IF_TEST_PIM(pim_ifp
->options
)) {
789 /* Interface has a valid primary address ? */
790 if (PIM_INADDR_ISNOT_ANY(pim_ifp
->primary_address
)) {
792 /* Interface has a valid socket ? */
793 if (pim_ifp
->pim_sock_fd
< 0) {
794 if (pim_sock_add(ifp
)) {
796 "Failure creating PIM socket for interface %s",
804 * PIM or IGMP is enabled on interface, and there is at least one
805 * address assigned, then try to create a vif_index.
807 if (pim_ifp
->mroute_vif_index
< 0) {
810 pim_ifchannel_scan_forward_start(ifp
);
812 pim_rp_setup(pim_ifp
->pim
);
813 pim_rp_check_on_if_add(pim_ifp
);
816 void pim_if_addr_del_all(struct interface
*ifp
)
818 struct connected
*ifc
;
819 struct listnode
*node
;
820 struct listnode
*nextnode
;
821 struct vrf
*vrf
= vrf_lookup_by_id(ifp
->vrf_id
);
822 struct pim_instance
*pim
;
828 /* PIM/IGMP enabled ? */
832 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
833 struct prefix
*p
= ifc
->address
;
835 if (p
->family
!= AF_INET
)
838 pim_if_addr_del(ifc
, 1 /* force_prim_as_any=true */);
842 pim_i_am_rp_re_evaluate(pim
);
845 void pim_if_addr_del_all_igmp(struct interface
*ifp
)
847 struct connected
*ifc
;
848 struct listnode
*node
;
849 struct listnode
*nextnode
;
851 /* PIM/IGMP enabled ? */
855 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
856 struct prefix
*p
= ifc
->address
;
858 if (p
->family
!= AF_INET
)
861 pim_if_addr_del_igmp(ifc
);
865 void pim_if_addr_del_all_pim(struct interface
*ifp
)
867 struct connected
*ifc
;
868 struct listnode
*node
;
869 struct listnode
*nextnode
;
871 /* PIM/IGMP enabled ? */
875 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
876 struct prefix
*p
= ifc
->address
;
878 if (p
->family
!= AF_INET
)
881 pim_if_addr_del_pim(ifc
);
885 struct in_addr
pim_find_primary_addr(struct interface
*ifp
)
887 struct connected
*ifc
;
888 struct listnode
*node
;
889 struct in_addr addr
= {0};
892 struct pim_interface
*pim_ifp
= ifp
->info
;
893 struct vrf
*vrf
= vrf_lookup_by_id(ifp
->vrf_id
);
898 if (pim_ifp
&& PIM_INADDR_ISNOT_ANY(pim_ifp
->update_source
)) {
899 return pim_ifp
->update_source
;
902 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, ifc
)) {
903 struct prefix
*p
= ifc
->address
;
905 if (p
->family
!= AF_INET
) {
910 if (PIM_INADDR_IS_ANY(p
->u
.prefix4
)) {
912 "%s: null IPv4 address connected to interface %s",
913 __PRETTY_FUNCTION__
, ifp
->name
);
919 if (CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
))
926 * If we have no v4_addrs and v6 is configured
927 * We probably are using unnumbered
928 * So let's grab the loopbacks v4 address
929 * and use that as the primary address
931 if (!v4_addrs
&& v6_addrs
&& !if_is_loopback(ifp
)) {
932 struct interface
*lo_ifp
;
933 // DBS - Come back and check here
934 if (ifp
->vrf_id
== VRF_DEFAULT
)
935 lo_ifp
= if_lookup_by_name("lo", vrf
->vrf_id
);
937 lo_ifp
= if_lookup_by_name(vrf
->name
, vrf
->vrf_id
);
940 return pim_find_primary_addr(lo_ifp
);
943 addr
.s_addr
= PIM_NET_INADDR_ANY
;
948 static int pim_iface_next_vif_index(struct interface
*ifp
)
950 struct pim_interface
*pim_ifp
= ifp
->info
;
951 struct pim_instance
*pim
= pim_ifp
->pim
;
955 * The pimreg vif is always going to be in index 0
958 if (ifp
->ifindex
== PIM_OIF_PIM_REGISTER_VIF
)
961 for (i
= 1; i
< MAXVIFS
; i
++) {
962 if (pim
->iface_vif_index
[i
] == 0)
969 pim_if_add_vif() uses ifindex as vif_index
971 see also pim_if_find_vifindex_by_ifindex()
973 int pim_if_add_vif(struct interface
*ifp
)
975 struct pim_interface
*pim_ifp
= ifp
->info
;
976 struct in_addr ifaddr
;
977 unsigned char flags
= 0;
981 if (pim_ifp
->mroute_vif_index
> 0) {
982 zlog_warn("%s: vif_index=%d > 0 on interface %s ifindex=%d",
983 __PRETTY_FUNCTION__
, pim_ifp
->mroute_vif_index
,
984 ifp
->name
, ifp
->ifindex
);
988 if (ifp
->ifindex
< 0) {
989 zlog_warn("%s: ifindex=%d < 1 on interface %s",
990 __PRETTY_FUNCTION__
, ifp
->ifindex
, ifp
->name
);
994 ifaddr
= pim_ifp
->primary_address
;
995 if (ifp
->ifindex
!= PIM_OIF_PIM_REGISTER_VIF
996 && PIM_INADDR_IS_ANY(ifaddr
)) {
998 "%s: could not get address for interface %s ifindex=%d",
999 __PRETTY_FUNCTION__
, ifp
->name
, ifp
->ifindex
);
1003 pim_ifp
->mroute_vif_index
= pim_iface_next_vif_index(ifp
);
1005 if (pim_ifp
->mroute_vif_index
>= MAXVIFS
) {
1007 "%s: Attempting to configure more than MAXVIFS=%d on pim enabled interface %s",
1008 __PRETTY_FUNCTION__
, MAXVIFS
, ifp
->name
);
1012 if (ifp
->ifindex
== PIM_OIF_PIM_REGISTER_VIF
)
1013 flags
= VIFF_REGISTER
;
1014 #ifdef VIFF_USE_IFINDEX
1016 flags
= VIFF_USE_IFINDEX
;
1019 if (pim_mroute_add_vif(ifp
, ifaddr
, flags
)) {
1020 /* pim_mroute_add_vif reported error */
1024 pim_ifp
->pim
->iface_vif_index
[pim_ifp
->mroute_vif_index
] = 1;
1028 int pim_if_del_vif(struct interface
*ifp
)
1030 struct pim_interface
*pim_ifp
= ifp
->info
;
1032 if (pim_ifp
->mroute_vif_index
< 1) {
1033 zlog_warn("%s: vif_index=%d < 1 on interface %s ifindex=%d",
1034 __PRETTY_FUNCTION__
, pim_ifp
->mroute_vif_index
,
1035 ifp
->name
, ifp
->ifindex
);
1039 pim_mroute_del_vif(ifp
);
1044 pim_ifp
->pim
->iface_vif_index
[pim_ifp
->mroute_vif_index
] = 0;
1046 pim_ifp
->mroute_vif_index
= -1;
1052 struct interface
*pim_if_find_by_vif_index(struct pim_instance
*pim
,
1053 ifindex_t vif_index
)
1055 struct interface
*ifp
;
1057 FOR_ALL_INTERFACES (pim
->vrf
, ifp
) {
1059 struct pim_interface
*pim_ifp
;
1060 pim_ifp
= ifp
->info
;
1062 if (vif_index
== pim_ifp
->mroute_vif_index
)
1071 pim_if_add_vif() uses ifindex as vif_index
1073 int pim_if_find_vifindex_by_ifindex(struct pim_instance
*pim
, ifindex_t ifindex
)
1075 struct pim_interface
*pim_ifp
;
1076 struct interface
*ifp
;
1078 ifp
= if_lookup_by_index(ifindex
, pim
->vrf_id
);
1079 if (!ifp
|| !ifp
->info
)
1081 pim_ifp
= ifp
->info
;
1083 return pim_ifp
->mroute_vif_index
;
1086 int pim_if_lan_delay_enabled(struct interface
*ifp
)
1088 struct pim_interface
*pim_ifp
;
1090 pim_ifp
= ifp
->info
;
1092 zassert(pim_ifp
->pim_number_of_nonlandelay_neighbors
>= 0);
1094 return pim_ifp
->pim_number_of_nonlandelay_neighbors
== 0;
1097 uint16_t pim_if_effective_propagation_delay_msec(struct interface
*ifp
)
1099 if (pim_if_lan_delay_enabled(ifp
)) {
1100 struct pim_interface
*pim_ifp
;
1101 pim_ifp
= ifp
->info
;
1102 return pim_ifp
->pim_neighbors_highest_propagation_delay_msec
;
1104 return PIM_DEFAULT_PROPAGATION_DELAY_MSEC
;
1108 uint16_t pim_if_effective_override_interval_msec(struct interface
*ifp
)
1110 if (pim_if_lan_delay_enabled(ifp
)) {
1111 struct pim_interface
*pim_ifp
;
1112 pim_ifp
= ifp
->info
;
1113 return pim_ifp
->pim_neighbors_highest_override_interval_msec
;
1115 return PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC
;
1119 int pim_if_t_override_msec(struct interface
*ifp
)
1121 int effective_override_interval_msec
;
1122 int t_override_msec
;
1124 effective_override_interval_msec
=
1125 pim_if_effective_override_interval_msec(ifp
);
1127 t_override_msec
= random() % (effective_override_interval_msec
+ 1);
1129 return t_override_msec
;
1132 uint16_t pim_if_jp_override_interval_msec(struct interface
*ifp
)
1134 return pim_if_effective_propagation_delay_msec(ifp
)
1135 + pim_if_effective_override_interval_msec(ifp
);
1139 RFC 4601: 4.1.6. State Summarization Macros
1141 The function NBR( I, A ) uses information gathered through PIM Hello
1142 messages to map the IP address A of a directly connected PIM
1143 neighbor router on interface I to the primary IP address of the same
1144 router (Section 4.3.4). The primary IP address of a neighbor is the
1145 address that it uses as the source of its PIM Hello messages.
1147 struct pim_neighbor
*pim_if_find_neighbor(struct interface
*ifp
,
1148 struct in_addr addr
)
1150 struct listnode
*neighnode
;
1151 struct pim_neighbor
*neigh
;
1152 struct pim_interface
*pim_ifp
;
1157 pim_ifp
= ifp
->info
;
1159 zlog_warn("%s: multicast not enabled on interface %s",
1160 __PRETTY_FUNCTION__
, ifp
->name
);
1166 p
.prefixlen
= IPV4_MAX_PREFIXLEN
;
1168 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
, neighnode
,
1171 /* primary address ? */
1172 if (neigh
->source_addr
.s_addr
== addr
.s_addr
)
1175 /* secondary address ? */
1176 if (pim_neighbor_find_secondary(neigh
, &p
))
1180 if (PIM_DEBUG_PIM_TRACE
) {
1181 char addr_str
[INET_ADDRSTRLEN
];
1182 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
1184 "%s: neighbor not found for address %s on interface %s",
1185 __PRETTY_FUNCTION__
, addr_str
, ifp
->name
);
1191 long pim_if_t_suppressed_msec(struct interface
*ifp
)
1193 struct pim_interface
*pim_ifp
;
1194 long t_suppressed_msec
;
1195 uint32_t ramount
= 0;
1197 pim_ifp
= ifp
->info
;
1200 /* join suppression disabled ? */
1201 if (PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp
->options
))
1204 /* t_suppressed = t_periodic * rand(1.1, 1.4) */
1205 ramount
= 1100 + (random() % (1400 - 1100 + 1));
1206 t_suppressed_msec
= qpim_t_periodic
* ramount
;
1208 return t_suppressed_msec
;
1211 static void igmp_join_free(struct igmp_join
*ij
)
1213 XFREE(MTYPE_PIM_IGMP_JOIN
, ij
);
1216 static struct igmp_join
*igmp_join_find(struct list
*join_list
,
1217 struct in_addr group_addr
,
1218 struct in_addr source_addr
)
1220 struct listnode
*node
;
1221 struct igmp_join
*ij
;
1225 for (ALL_LIST_ELEMENTS_RO(join_list
, node
, ij
)) {
1226 if ((group_addr
.s_addr
== ij
->group_addr
.s_addr
)
1227 && (source_addr
.s_addr
== ij
->source_addr
.s_addr
))
1234 static int igmp_join_sock(const char *ifname
, ifindex_t ifindex
,
1235 struct in_addr group_addr
, struct in_addr source_addr
)
1239 join_fd
= pim_socket_raw(IPPROTO_IGMP
);
1244 if (pim_socket_join_source(join_fd
, ifindex
, group_addr
, source_addr
,
1253 static struct igmp_join
*igmp_join_new(struct interface
*ifp
,
1254 struct in_addr group_addr
,
1255 struct in_addr source_addr
)
1257 struct pim_interface
*pim_ifp
;
1258 struct igmp_join
*ij
;
1261 pim_ifp
= ifp
->info
;
1264 join_fd
= igmp_join_sock(ifp
->name
, ifp
->ifindex
, group_addr
,
1267 char group_str
[INET_ADDRSTRLEN
];
1268 char source_str
[INET_ADDRSTRLEN
];
1269 pim_inet4_dump("<grp?>", group_addr
, group_str
,
1271 pim_inet4_dump("<src?>", source_addr
, source_str
,
1272 sizeof(source_str
));
1274 "%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s",
1275 __PRETTY_FUNCTION__
, group_str
, source_str
, ifp
->name
);
1279 ij
= XCALLOC(MTYPE_PIM_IGMP_JOIN
, sizeof(*ij
));
1281 char group_str
[INET_ADDRSTRLEN
];
1282 char source_str
[INET_ADDRSTRLEN
];
1283 pim_inet4_dump("<grp?>", group_addr
, group_str
,
1285 pim_inet4_dump("<src?>", source_addr
, source_str
,
1286 sizeof(source_str
));
1288 "%s: XCALLOC(%zu) failure for IGMP group %s source %s on interface %s",
1289 __PRETTY_FUNCTION__
, sizeof(*ij
), group_str
, source_str
,
1295 ij
->sock_fd
= join_fd
;
1296 ij
->group_addr
= group_addr
;
1297 ij
->source_addr
= source_addr
;
1298 ij
->sock_creation
= pim_time_monotonic_sec();
1300 listnode_add(pim_ifp
->igmp_join_list
, ij
);
1305 ferr_r
pim_if_igmp_join_add(struct interface
*ifp
, struct in_addr group_addr
,
1306 struct in_addr source_addr
)
1308 struct pim_interface
*pim_ifp
;
1309 struct igmp_join
*ij
;
1311 pim_ifp
= ifp
->info
;
1313 return ferr_cfg_invalid("multicast not enabled on interface %s",
1317 if (!pim_ifp
->igmp_join_list
) {
1318 pim_ifp
->igmp_join_list
= list_new();
1319 if (!pim_ifp
->igmp_join_list
) {
1320 return ferr_cfg_invalid("Insufficient memory");
1322 pim_ifp
->igmp_join_list
->del
= (void (*)(void *))igmp_join_free
;
1325 ij
= igmp_join_find(pim_ifp
->igmp_join_list
, group_addr
, source_addr
);
1327 /* This interface has already been configured to join this IGMP group
1333 ij
= igmp_join_new(ifp
, group_addr
, source_addr
);
1335 return ferr_cfg_invalid(
1336 "Failure to create new join data structure, see log file for more information");
1339 if (PIM_DEBUG_IGMP_EVENTS
) {
1340 char group_str
[INET_ADDRSTRLEN
];
1341 char source_str
[INET_ADDRSTRLEN
];
1342 pim_inet4_dump("<grp?>", group_addr
, group_str
,
1344 pim_inet4_dump("<src?>", source_addr
, source_str
,
1345 sizeof(source_str
));
1347 "%s: issued static igmp join for channel (S,G)=(%s,%s) on interface %s",
1348 __PRETTY_FUNCTION__
, source_str
, group_str
, ifp
->name
);
1355 int pim_if_igmp_join_del(struct interface
*ifp
, struct in_addr group_addr
,
1356 struct in_addr source_addr
)
1358 struct pim_interface
*pim_ifp
;
1359 struct igmp_join
*ij
;
1361 pim_ifp
= ifp
->info
;
1363 zlog_warn("%s: multicast not enabled on interface %s",
1364 __PRETTY_FUNCTION__
, ifp
->name
);
1368 if (!pim_ifp
->igmp_join_list
) {
1369 zlog_warn("%s: no IGMP join on interface %s",
1370 __PRETTY_FUNCTION__
, ifp
->name
);
1374 ij
= igmp_join_find(pim_ifp
->igmp_join_list
, group_addr
, source_addr
);
1376 char group_str
[INET_ADDRSTRLEN
];
1377 char source_str
[INET_ADDRSTRLEN
];
1378 pim_inet4_dump("<grp?>", group_addr
, group_str
,
1380 pim_inet4_dump("<src?>", source_addr
, source_str
,
1381 sizeof(source_str
));
1383 "%s: could not find IGMP group %s source %s on interface %s",
1384 __PRETTY_FUNCTION__
, group_str
, source_str
, ifp
->name
);
1388 if (close(ij
->sock_fd
)) {
1389 char group_str
[INET_ADDRSTRLEN
];
1390 char source_str
[INET_ADDRSTRLEN
];
1391 pim_inet4_dump("<grp?>", group_addr
, group_str
,
1393 pim_inet4_dump("<src?>", source_addr
, source_str
,
1394 sizeof(source_str
));
1396 "%s: failure closing sock_fd=%d for IGMP group %s source %s on interface %s: errno=%d: %s",
1397 __PRETTY_FUNCTION__
, ij
->sock_fd
, group_str
, source_str
,
1398 ifp
->name
, errno
, safe_strerror(errno
));
1401 listnode_delete(pim_ifp
->igmp_join_list
, ij
);
1403 if (listcount(pim_ifp
->igmp_join_list
) < 1) {
1404 list_delete_and_null(&pim_ifp
->igmp_join_list
);
1405 pim_ifp
->igmp_join_list
= 0;
1411 static void pim_if_igmp_join_del_all(struct interface
*ifp
)
1413 struct pim_interface
*pim_ifp
;
1414 struct listnode
*node
;
1415 struct listnode
*nextnode
;
1416 struct igmp_join
*ij
;
1418 pim_ifp
= ifp
->info
;
1420 zlog_warn("%s: multicast not enabled on interface %s",
1421 __PRETTY_FUNCTION__
, ifp
->name
);
1425 if (!pim_ifp
->igmp_join_list
)
1428 for (ALL_LIST_ELEMENTS(pim_ifp
->igmp_join_list
, node
, nextnode
, ij
))
1429 pim_if_igmp_join_del(ifp
, ij
->group_addr
, ij
->source_addr
);
1435 Transitions from "I am Assert Loser" State
1437 Current Winner's GenID Changes or NLT Expires
1439 The Neighbor Liveness Timer associated with the current winner
1440 expires or we receive a Hello message from the current winner
1441 reporting a different GenID from the one it previously reported.
1442 This indicates that the current winner's interface or router has
1443 gone down (and may have come back up), and so we must assume it no
1444 longer knows it was the winner.
1446 void pim_if_assert_on_neighbor_down(struct interface
*ifp
,
1447 struct in_addr neigh_addr
)
1449 struct pim_interface
*pim_ifp
;
1450 struct pim_ifchannel
*ch
;
1452 pim_ifp
= ifp
->info
;
1455 RB_FOREACH (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
) {
1456 /* Is (S,G,I) assert loser ? */
1457 if (ch
->ifassert_state
!= PIM_IFASSERT_I_AM_LOSER
)
1459 /* Dead neighbor was winner ? */
1460 if (ch
->ifassert_winner
.s_addr
!= neigh_addr
.s_addr
)
1463 assert_action_a5(ch
);
1467 void pim_if_update_join_desired(struct pim_interface
*pim_ifp
)
1469 struct pim_ifchannel
*ch
;
1471 /* clear off flag from interface's upstreams */
1472 RB_FOREACH (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
) {
1473 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(
1474 ch
->upstream
->flags
);
1477 /* scan per-interface (S,G,I) state on this I interface */
1478 RB_FOREACH (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
) {
1479 struct pim_upstream
*up
= ch
->upstream
;
1481 if (PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(up
->flags
))
1484 /* update join_desired for the global (S,G) state */
1485 pim_upstream_update_join_desired(pim_ifp
->pim
, up
);
1486 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(up
->flags
);
1490 void pim_if_update_assert_tracking_desired(struct interface
*ifp
)
1492 struct pim_interface
*pim_ifp
;
1493 struct pim_ifchannel
*ch
;
1495 pim_ifp
= ifp
->info
;
1499 RB_FOREACH (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
) {
1500 pim_ifchannel_update_assert_tracking_desired(ch
);
1505 * PIM wants to have an interface pointer for everything it does.
1506 * The pimreg is a special interface that we have that is not
1507 * quite an inteface but a VIF is created for it.
1509 void pim_if_create_pimreg(struct pim_instance
*pim
)
1511 char pimreg_name
[INTERFACE_NAMSIZ
];
1513 if (!pim
->regiface
) {
1514 if (pim
->vrf_id
== VRF_DEFAULT
)
1515 strlcpy(pimreg_name
, "pimreg", sizeof(pimreg_name
));
1517 snprintf(pimreg_name
, sizeof(pimreg_name
), "pimreg%u",
1518 pim
->vrf
->data
.l
.table_id
);
1520 pim
->regiface
= if_create(pimreg_name
, pim
->vrf_id
);
1521 pim
->regiface
->ifindex
= PIM_OIF_PIM_REGISTER_VIF
;
1523 pim_if_new(pim
->regiface
, 0, 0);
1527 int pim_if_connected_to_source(struct interface
*ifp
, struct in_addr src
)
1529 struct listnode
*cnode
;
1530 struct connected
*c
;
1538 p
.prefixlen
= IPV4_MAX_BITLEN
;
1540 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, cnode
, c
)) {
1541 if ((c
->address
->family
== AF_INET
)
1542 && prefix_match(CONNECTED_PREFIX(c
), &p
)) {
1550 int pim_if_is_loopback(struct pim_instance
*pim
, struct interface
*ifp
)
1552 if (if_is_loopback(ifp
))
1555 if (strcmp(ifp
->name
, pim
->vrf
->name
) == 0)
1561 int pim_if_is_vrf_device(struct interface
*ifp
)
1565 RB_FOREACH (vrf
, vrf_name_head
, &vrfs_by_name
) {
1566 if (strncmp(ifp
->name
, vrf
->name
, strlen(ifp
->name
)) == 0)
1573 int pim_if_ifchannel_count(struct pim_interface
*pim_ifp
)
1575 struct pim_ifchannel
*ch
;
1578 RB_FOREACH (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
) {