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"
49 #include "pim_igmp_join.h"
51 static void pim_if_igmp_join_del_all(struct interface
*ifp
);
52 static int igmp_join_sock(const char *ifname
, ifindex_t ifindex
,
53 struct in_addr group_addr
,
54 struct in_addr source_addr
);
56 void pim_if_init(struct pim_instance
*pim
)
60 for (i
= 0; i
< MAXVIFS
; i
++)
61 pim
->iface_vif_index
[i
] = 0;
64 void pim_if_terminate(struct pim_instance
*pim
)
66 struct interface
*ifp
;
68 FOR_ALL_INTERFACES (pim
->vrf
, ifp
) {
69 struct pim_interface
*pim_ifp
= ifp
->info
;
79 static void pim_sec_addr_free(struct pim_secondary_addr
*sec_addr
)
81 XFREE(MTYPE_PIM_SEC_ADDR
, sec_addr
);
84 static int pim_sec_addr_comp(const void *p1
, const void *p2
)
86 const struct pim_secondary_addr
*sec1
= p1
;
87 const struct pim_secondary_addr
*sec2
= p2
;
89 if (sec1
->addr
.family
== AF_INET
&& sec2
->addr
.family
== AF_INET6
)
92 if (sec1
->addr
.family
== AF_INET6
&& sec2
->addr
.family
== AF_INET
)
95 if (sec1
->addr
.family
== AF_INET
) {
96 if (ntohl(sec1
->addr
.u
.prefix4
.s_addr
)
97 < ntohl(sec2
->addr
.u
.prefix4
.s_addr
))
100 if (ntohl(sec1
->addr
.u
.prefix4
.s_addr
)
101 > ntohl(sec2
->addr
.u
.prefix4
.s_addr
))
104 return memcmp(&sec1
->addr
.u
.prefix6
, &sec2
->addr
.u
.prefix6
,
105 sizeof(struct in6_addr
));
111 struct pim_interface
*pim_if_new(struct interface
*ifp
, bool igmp
, bool pim
,
114 struct pim_interface
*pim_ifp
;
119 pim_ifp
= XCALLOC(MTYPE_PIM_INTERFACE
, sizeof(*pim_ifp
));
121 pim_ifp
->options
= 0;
122 pim_ifp
->pim
= pim_get_pim_instance(ifp
->vrf_id
);
123 pim_ifp
->mroute_vif_index
= -1;
125 pim_ifp
->igmp_version
= IGMP_DEFAULT_VERSION
;
126 pim_ifp
->igmp_default_robustness_variable
=
127 IGMP_DEFAULT_ROBUSTNESS_VARIABLE
;
128 pim_ifp
->igmp_default_query_interval
= IGMP_GENERAL_QUERY_INTERVAL
;
129 pim_ifp
->igmp_query_max_response_time_dsec
=
130 IGMP_QUERY_MAX_RESPONSE_TIME_DSEC
;
131 pim_ifp
->igmp_specific_query_max_response_time_dsec
=
132 IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC
;
135 RFC 3376: 8.3. Query Response Interval
136 The number of seconds represented by the [Query Response Interval]
137 must be less than the [Query Interval].
139 zassert(pim_ifp
->igmp_query_max_response_time_dsec
140 < pim_ifp
->igmp_default_query_interval
);
143 PIM_IF_DO_PIM(pim_ifp
->options
);
145 PIM_IF_DO_IGMP(pim_ifp
->options
);
147 PIM_IF_DO_IGMP_LISTEN_ALLROUTERS(pim_ifp
->options
);
149 pim_ifp
->igmp_join_list
= NULL
;
150 pim_ifp
->igmp_socket_list
= NULL
;
151 pim_ifp
->pim_neighbor_list
= NULL
;
152 pim_ifp
->upstream_switch_list
= NULL
;
153 pim_ifp
->pim_generation_id
= 0;
155 /* list of struct igmp_sock */
156 pim_ifp
->igmp_socket_list
= list_new();
157 pim_ifp
->igmp_socket_list
->del
= (void (*)(void *))igmp_sock_free
;
159 /* list of struct pim_neighbor */
160 pim_ifp
->pim_neighbor_list
= list_new();
161 pim_ifp
->pim_neighbor_list
->del
= (void (*)(void *))pim_neighbor_free
;
163 pim_ifp
->upstream_switch_list
= list_new();
164 pim_ifp
->upstream_switch_list
->del
=
165 (void (*)(void *))pim_jp_agg_group_list_free
;
166 pim_ifp
->upstream_switch_list
->cmp
= pim_jp_agg_group_list_cmp
;
168 pim_ifp
->sec_addr_list
= list_new();
169 pim_ifp
->sec_addr_list
->del
= (void (*)(void *))pim_sec_addr_free
;
170 pim_ifp
->sec_addr_list
->cmp
=
171 (int (*)(void *, void *))pim_sec_addr_comp
;
173 RB_INIT(pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
);
179 pim_if_add_vif(ifp
, ispimreg
);
184 void pim_if_delete(struct interface
*ifp
)
186 struct pim_interface
*pim_ifp
;
187 struct pim_ifchannel
*ch
;
193 if (pim_ifp
->igmp_join_list
) {
194 pim_if_igmp_join_del_all(ifp
);
197 pim_ifchannel_delete_all(ifp
);
198 igmp_sock_delete_all(ifp
);
200 pim_neighbor_delete_all(ifp
, "Interface removed from configuration");
204 list_delete_and_null(&pim_ifp
->igmp_socket_list
);
205 list_delete_and_null(&pim_ifp
->pim_neighbor_list
);
206 list_delete_and_null(&pim_ifp
->upstream_switch_list
);
207 list_delete_and_null(&pim_ifp
->sec_addr_list
);
209 if (pim_ifp
->boundary_oil_plist
)
210 XFREE(MTYPE_PIM_INTERFACE
, pim_ifp
->boundary_oil_plist
);
212 while (!RB_EMPTY(pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
)) {
213 ch
= RB_ROOT(pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
);
215 pim_ifchannel_delete(ch
);
218 XFREE(MTYPE_PIM_INTERFACE
, pim_ifp
);
223 void pim_if_update_could_assert(struct interface
*ifp
)
225 struct pim_interface
*pim_ifp
;
226 struct pim_ifchannel
*ch
;
231 RB_FOREACH (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
) {
232 pim_ifchannel_update_could_assert(ch
);
236 static void pim_if_update_my_assert_metric(struct interface
*ifp
)
238 struct pim_interface
*pim_ifp
;
239 struct pim_ifchannel
*ch
;
244 RB_FOREACH (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
) {
245 pim_ifchannel_update_my_assert_metric(ch
);
249 static void pim_addr_change(struct interface
*ifp
)
251 struct pim_interface
*pim_ifp
;
256 pim_if_dr_election(ifp
); /* router's own DR Priority (addr) changes --
258 pim_if_update_join_desired(pim_ifp
); /* depends on DR */
259 pim_if_update_could_assert(ifp
); /* depends on DR */
260 pim_if_update_my_assert_metric(ifp
); /* depends on could_assert */
261 pim_if_update_assert_tracking_desired(
262 ifp
); /* depends on DR, join_desired */
265 RFC 4601: 4.3.1. Sending Hello Messages
267 1) Before an interface goes down or changes primary IP address, a
268 Hello message with a zero HoldTime should be sent immediately
269 (with the old IP address if the IP address changed).
270 -- FIXME See CAVEAT C13
272 2) After an interface has changed its IP address, it MUST send a
273 Hello message with its new IP address.
276 3) If an interface changes one of its secondary IP addresses, a
277 Hello message with an updated Address_List option and a non-zero
278 HoldTime should be sent immediately.
279 -- FIXME See TODO T31
281 pim_ifp
->pim_ifstat_hello_sent
= 0; /* reset hello counter */
282 if (pim_ifp
->pim_sock_fd
< 0)
284 pim_hello_restart_now(ifp
); /* send hello and restart timer */
287 static int detect_primary_address_change(struct interface
*ifp
,
288 int force_prim_as_any
,
291 struct pim_interface
*pim_ifp
= ifp
->info
;
292 struct in_addr new_prim_addr
;
295 if (force_prim_as_any
)
296 new_prim_addr
.s_addr
= INADDR_ANY
;
298 new_prim_addr
= pim_find_primary_addr(ifp
);
300 changed
= new_prim_addr
.s_addr
!= pim_ifp
->primary_address
.s_addr
;
302 if (PIM_DEBUG_ZEBRA
) {
303 char new_prim_str
[INET_ADDRSTRLEN
];
304 char old_prim_str
[INET_ADDRSTRLEN
];
305 pim_inet4_dump("<new?>", new_prim_addr
, new_prim_str
,
306 sizeof(new_prim_str
));
307 pim_inet4_dump("<old?>", pim_ifp
->primary_address
, old_prim_str
,
308 sizeof(old_prim_str
));
309 zlog_debug("%s: old=%s new=%s on interface %s: %s",
310 __PRETTY_FUNCTION__
, old_prim_str
, new_prim_str
,
311 ifp
->name
, changed
? "changed" : "unchanged");
315 pim_ifp
->primary_address
= new_prim_addr
;
321 static struct pim_secondary_addr
*
322 pim_sec_addr_find(struct pim_interface
*pim_ifp
, struct prefix
*addr
)
324 struct pim_secondary_addr
*sec_addr
;
325 struct listnode
*node
;
327 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->sec_addr_list
, node
, sec_addr
)) {
328 if (prefix_cmp(&sec_addr
->addr
, addr
)) {
336 static void pim_sec_addr_del(struct pim_interface
*pim_ifp
,
337 struct pim_secondary_addr
*sec_addr
)
339 listnode_delete(pim_ifp
->sec_addr_list
, sec_addr
);
340 pim_sec_addr_free(sec_addr
);
343 static int pim_sec_addr_add(struct pim_interface
*pim_ifp
, struct prefix
*addr
)
346 struct pim_secondary_addr
*sec_addr
;
348 sec_addr
= pim_sec_addr_find(pim_ifp
, addr
);
350 sec_addr
->flags
&= ~PIM_SEC_ADDRF_STALE
;
354 sec_addr
= XCALLOC(MTYPE_PIM_SEC_ADDR
, sizeof(*sec_addr
));
357 sec_addr
->addr
= *addr
;
358 listnode_add_sort(pim_ifp
->sec_addr_list
, sec_addr
);
363 static int pim_sec_addr_del_all(struct pim_interface
*pim_ifp
)
367 if (!list_isempty(pim_ifp
->sec_addr_list
)) {
369 /* remove all nodes and free up the list itself */
370 list_delete_all_node(pim_ifp
->sec_addr_list
);
376 static int pim_sec_addr_update(struct interface
*ifp
)
378 struct pim_interface
*pim_ifp
= ifp
->info
;
379 struct connected
*ifc
;
380 struct listnode
*node
;
381 struct listnode
*nextnode
;
382 struct pim_secondary_addr
*sec_addr
;
385 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->sec_addr_list
, node
, sec_addr
)) {
386 sec_addr
->flags
|= PIM_SEC_ADDRF_STALE
;
389 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, ifc
)) {
390 struct prefix
*p
= ifc
->address
;
392 if (PIM_INADDR_IS_ANY(p
->u
.prefix4
)) {
396 if (pim_ifp
->primary_address
.s_addr
== p
->u
.prefix4
.s_addr
) {
397 /* don't add the primary address into the secondary
402 if (pim_sec_addr_add(pim_ifp
, p
)) {
407 /* Drop stale entries */
408 for (ALL_LIST_ELEMENTS(pim_ifp
->sec_addr_list
, node
, nextnode
,
410 if (sec_addr
->flags
& PIM_SEC_ADDRF_STALE
) {
411 pim_sec_addr_del(pim_ifp
, sec_addr
);
419 static int detect_secondary_address_change(struct interface
*ifp
,
420 int force_prim_as_any
,
423 struct pim_interface
*pim_ifp
= ifp
->info
;
426 if (force_prim_as_any
) {
427 /* if primary address is being forced to zero just flush the
428 * secondary address list */
429 changed
= pim_sec_addr_del_all(pim_ifp
);
431 /* re-evaluate the secondary address list */
432 changed
= pim_sec_addr_update(ifp
);
438 static void detect_address_change(struct interface
*ifp
, int force_prim_as_any
,
442 struct pim_interface
*pim_ifp
;
448 if (detect_primary_address_change(ifp
, force_prim_as_any
, caller
)) {
452 if (detect_secondary_address_change(ifp
, force_prim_as_any
, caller
)) {
458 if (!PIM_IF_TEST_PIM(pim_ifp
->options
)) {
462 pim_addr_change(ifp
);
465 /* XXX: if we have unnumbered interfaces we need to run detect address
466 * address change on all of them when the lo address changes */
469 int pim_update_source_set(struct interface
*ifp
, struct in_addr source
)
471 struct pim_interface
*pim_ifp
= ifp
->info
;
474 return PIM_IFACE_NOT_FOUND
;
477 if (pim_ifp
->update_source
.s_addr
== source
.s_addr
) {
478 return PIM_UPDATE_SOURCE_DUP
;
481 pim_ifp
->update_source
= source
;
482 detect_address_change(ifp
, 0 /* force_prim_as_any */,
483 __PRETTY_FUNCTION__
);
488 void pim_if_addr_add(struct connected
*ifc
)
490 struct pim_interface
*pim_ifp
;
491 struct interface
*ifp
;
492 struct in_addr ifaddr
;
502 if (!if_is_operative(ifp
))
505 if (PIM_DEBUG_ZEBRA
) {
507 prefix2str(ifc
->address
, buf
, BUFSIZ
);
508 zlog_debug("%s: %s ifindex=%d connected IP address %s %s",
509 __PRETTY_FUNCTION__
, ifp
->name
, ifp
->ifindex
, buf
,
510 CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
)
515 ifaddr
= ifc
->address
->u
.prefix4
;
517 detect_address_change(ifp
, 0, __PRETTY_FUNCTION__
);
519 // if (ifc->address->family != AF_INET)
522 if (PIM_IF_TEST_IGMP(pim_ifp
->options
)) {
523 struct igmp_sock
*igmp
;
525 /* lookup IGMP socket */
526 igmp
= pim_igmp_sock_lookup_ifaddr(pim_ifp
->igmp_socket_list
,
529 /* if addr new, add IGMP socket */
530 if (ifc
->address
->family
== AF_INET
)
531 pim_igmp_sock_add(pim_ifp
->igmp_socket_list
,
533 } else if (igmp
->mtrace_only
) {
534 igmp_sock_delete(igmp
);
535 pim_igmp_sock_add(pim_ifp
->igmp_socket_list
, ifaddr
,
539 /* Replay Static IGMP groups */
540 if (pim_ifp
->igmp_join_list
) {
541 struct listnode
*node
;
542 struct listnode
*nextnode
;
543 struct igmp_join
*ij
;
546 for (ALL_LIST_ELEMENTS(pim_ifp
->igmp_join_list
, node
,
548 /* Close socket and reopen with Source and Group
551 join_fd
= igmp_join_sock(
552 ifp
->name
, ifp
->ifindex
, ij
->group_addr
,
555 char group_str
[INET_ADDRSTRLEN
];
556 char source_str
[INET_ADDRSTRLEN
];
557 pim_inet4_dump("<grp?>", ij
->group_addr
,
561 "<src?>", ij
->source_addr
,
562 source_str
, sizeof(source_str
));
564 "%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s",
565 __PRETTY_FUNCTION__
, group_str
,
566 source_str
, ifp
->name
);
569 ij
->sock_fd
= join_fd
;
574 struct igmp_sock
*igmp
;
576 /* lookup IGMP socket */
577 igmp
= pim_igmp_sock_lookup_ifaddr(pim_ifp
->igmp_socket_list
,
579 if (ifc
->address
->family
== AF_INET
) {
581 igmp_sock_delete(igmp
);
582 /* if addr new, add IGMP socket */
583 pim_igmp_sock_add(pim_ifp
->igmp_socket_list
, ifaddr
,
586 } /* igmp mtrace only */
588 if (PIM_IF_TEST_PIM(pim_ifp
->options
)) {
590 if (PIM_INADDR_ISNOT_ANY(pim_ifp
->primary_address
)) {
592 /* Interface has a valid socket ? */
593 if (pim_ifp
->pim_sock_fd
< 0) {
594 if (pim_sock_add(ifp
)) {
596 "Failure creating PIM socket for interface %s",
600 struct pim_nexthop_cache
*pnc
= NULL
;
602 struct zclient
*zclient
= NULL
;
604 zclient
= pim_zebra_zclient_get();
605 /* RP config might come prior to (local RP's interface)
607 In this case, pnc would not have pim enabled
609 Once Interface is UP and pim info is available,
611 with RNH address to receive update and add the
612 interface as nexthop. */
613 memset(&rpf
, 0, sizeof(struct pim_rpf
));
614 rpf
.rpf_addr
.family
= AF_INET
;
615 rpf
.rpf_addr
.prefixlen
= IPV4_MAX_BITLEN
;
616 rpf
.rpf_addr
.u
.prefix4
= ifc
->address
->u
.prefix4
;
617 pnc
= pim_nexthop_cache_find(pim_ifp
->pim
, &rpf
);
619 pim_sendmsg_zebra_rnh(pim_ifp
->pim
, zclient
,
621 ZEBRA_NEXTHOP_REGISTER
);
626 PIM or IGMP is enabled on interface, and there is at least one
627 address assigned, then try to create a vif_index.
629 if (pim_ifp
->mroute_vif_index
< 0) {
630 pim_if_add_vif(ifp
, false);
632 pim_ifchannel_scan_forward_start(ifp
);
635 static void pim_if_addr_del_igmp(struct connected
*ifc
)
637 struct pim_interface
*pim_ifp
= ifc
->ifp
->info
;
638 struct igmp_sock
*igmp
;
639 struct in_addr ifaddr
;
641 if (ifc
->address
->family
!= AF_INET
) {
642 /* non-IPv4 address */
647 /* IGMP not enabled on interface */
651 ifaddr
= ifc
->address
->u
.prefix4
;
653 /* lookup IGMP socket */
654 igmp
= pim_igmp_sock_lookup_ifaddr(pim_ifp
->igmp_socket_list
, ifaddr
);
656 /* if addr found, del IGMP socket */
657 igmp_sock_delete(igmp
);
661 static void pim_if_addr_del_pim(struct connected
*ifc
)
663 struct pim_interface
*pim_ifp
= ifc
->ifp
->info
;
665 if (ifc
->address
->family
!= AF_INET
) {
666 /* non-IPv4 address */
671 /* PIM not enabled on interface */
675 if (PIM_INADDR_ISNOT_ANY(pim_ifp
->primary_address
)) {
676 /* Interface keeps a valid primary address */
680 if (pim_ifp
->pim_sock_fd
< 0) {
681 /* Interface does not hold a valid socket any longer */
686 pim_sock_delete() closes the socket, stops read and timer threads,
687 and kills all neighbors.
689 pim_sock_delete(ifc
->ifp
,
690 "last address has been removed from interface");
693 void pim_if_addr_del(struct connected
*ifc
, int force_prim_as_any
)
695 struct interface
*ifp
;
701 if (PIM_DEBUG_ZEBRA
) {
703 prefix2str(ifc
->address
, buf
, BUFSIZ
);
704 zlog_debug("%s: %s ifindex=%d disconnected IP address %s %s",
705 __PRETTY_FUNCTION__
, ifp
->name
, ifp
->ifindex
, buf
,
706 CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
)
711 detect_address_change(ifp
, force_prim_as_any
, __PRETTY_FUNCTION__
);
713 pim_if_addr_del_igmp(ifc
);
714 pim_if_addr_del_pim(ifc
);
717 void pim_if_addr_add_all(struct interface
*ifp
)
719 struct connected
*ifc
;
720 struct listnode
*node
;
721 struct listnode
*nextnode
;
724 struct pim_interface
*pim_ifp
= ifp
->info
;
727 /* PIM/IGMP enabled ? */
731 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
732 struct prefix
*p
= ifc
->address
;
734 if (p
->family
!= AF_INET
)
738 pim_if_addr_add(ifc
);
741 if (!v4_addrs
&& v6_addrs
&& !if_is_loopback(ifp
)) {
742 if (PIM_IF_TEST_PIM(pim_ifp
->options
)) {
744 /* Interface has a valid primary address ? */
745 if (PIM_INADDR_ISNOT_ANY(pim_ifp
->primary_address
)) {
747 /* Interface has a valid socket ? */
748 if (pim_ifp
->pim_sock_fd
< 0) {
749 if (pim_sock_add(ifp
)) {
751 "Failure creating PIM socket for interface %s",
759 * PIM or IGMP is enabled on interface, and there is at least one
760 * address assigned, then try to create a vif_index.
762 if (pim_ifp
->mroute_vif_index
< 0) {
763 pim_if_add_vif(ifp
, false);
765 pim_ifchannel_scan_forward_start(ifp
);
767 pim_rp_setup(pim_ifp
->pim
);
768 pim_rp_check_on_if_add(pim_ifp
);
771 void pim_if_addr_del_all(struct interface
*ifp
)
773 struct connected
*ifc
;
774 struct listnode
*node
;
775 struct listnode
*nextnode
;
776 struct vrf
*vrf
= vrf_lookup_by_id(ifp
->vrf_id
);
777 struct pim_instance
*pim
;
783 /* PIM/IGMP enabled ? */
787 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
788 struct prefix
*p
= ifc
->address
;
790 if (p
->family
!= AF_INET
)
793 pim_if_addr_del(ifc
, 1 /* force_prim_as_any=true */);
797 pim_i_am_rp_re_evaluate(pim
);
800 void pim_if_addr_del_all_igmp(struct interface
*ifp
)
802 struct connected
*ifc
;
803 struct listnode
*node
;
804 struct listnode
*nextnode
;
806 /* PIM/IGMP enabled ? */
810 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
811 struct prefix
*p
= ifc
->address
;
813 if (p
->family
!= AF_INET
)
816 pim_if_addr_del_igmp(ifc
);
820 void pim_if_addr_del_all_pim(struct interface
*ifp
)
822 struct connected
*ifc
;
823 struct listnode
*node
;
824 struct listnode
*nextnode
;
826 /* PIM/IGMP enabled ? */
830 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
831 struct prefix
*p
= ifc
->address
;
833 if (p
->family
!= AF_INET
)
836 pim_if_addr_del_pim(ifc
);
840 struct in_addr
pim_find_primary_addr(struct interface
*ifp
)
842 struct connected
*ifc
;
843 struct listnode
*node
;
844 struct in_addr addr
= {0};
847 struct pim_interface
*pim_ifp
= ifp
->info
;
848 struct vrf
*vrf
= vrf_lookup_by_id(ifp
->vrf_id
);
853 if (pim_ifp
&& PIM_INADDR_ISNOT_ANY(pim_ifp
->update_source
)) {
854 return pim_ifp
->update_source
;
857 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, ifc
)) {
858 struct prefix
*p
= ifc
->address
;
860 if (p
->family
!= AF_INET
) {
865 if (PIM_INADDR_IS_ANY(p
->u
.prefix4
)) {
867 "%s: null IPv4 address connected to interface %s",
868 __PRETTY_FUNCTION__
, ifp
->name
);
874 if (CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
))
881 * If we have no v4_addrs and v6 is configured
882 * We probably are using unnumbered
883 * So let's grab the loopbacks v4 address
884 * and use that as the primary address
886 if (!v4_addrs
&& v6_addrs
&& !if_is_loopback(ifp
)) {
887 struct interface
*lo_ifp
;
888 // DBS - Come back and check here
889 if (ifp
->vrf_id
== VRF_DEFAULT
)
890 lo_ifp
= if_lookup_by_name("lo", vrf
->vrf_id
);
892 lo_ifp
= if_lookup_by_name(vrf
->name
, vrf
->vrf_id
);
895 return pim_find_primary_addr(lo_ifp
);
898 addr
.s_addr
= PIM_NET_INADDR_ANY
;
903 static int pim_iface_next_vif_index(struct interface
*ifp
)
905 struct pim_interface
*pim_ifp
= ifp
->info
;
906 struct pim_instance
*pim
= pim_ifp
->pim
;
910 * The pimreg vif is always going to be in index 0
913 if (ifp
->ifindex
== PIM_OIF_PIM_REGISTER_VIF
)
916 for (i
= 1; i
< MAXVIFS
; i
++) {
917 if (pim
->iface_vif_index
[i
] == 0)
924 pim_if_add_vif() uses ifindex as vif_index
926 see also pim_if_find_vifindex_by_ifindex()
928 int pim_if_add_vif(struct interface
*ifp
, bool ispimreg
)
930 struct pim_interface
*pim_ifp
= ifp
->info
;
931 struct in_addr ifaddr
;
932 unsigned char flags
= 0;
936 if (pim_ifp
->mroute_vif_index
> 0) {
937 zlog_warn("%s: vif_index=%d > 0 on interface %s ifindex=%d",
938 __PRETTY_FUNCTION__
, pim_ifp
->mroute_vif_index
,
939 ifp
->name
, ifp
->ifindex
);
943 if (ifp
->ifindex
< 0) {
944 zlog_warn("%s: ifindex=%d < 1 on interface %s",
945 __PRETTY_FUNCTION__
, ifp
->ifindex
, ifp
->name
);
949 ifaddr
= pim_ifp
->primary_address
;
950 if (!ispimreg
&& PIM_INADDR_IS_ANY(ifaddr
)) {
952 "%s: could not get address for interface %s ifindex=%d",
953 __PRETTY_FUNCTION__
, ifp
->name
, ifp
->ifindex
);
957 pim_ifp
->mroute_vif_index
= pim_iface_next_vif_index(ifp
);
959 if (pim_ifp
->mroute_vif_index
>= MAXVIFS
) {
961 "%s: Attempting to configure more than MAXVIFS=%d on pim enabled interface %s",
962 __PRETTY_FUNCTION__
, MAXVIFS
, ifp
->name
);
966 if (ifp
->ifindex
== PIM_OIF_PIM_REGISTER_VIF
)
967 flags
= VIFF_REGISTER
;
968 #ifdef VIFF_USE_IFINDEX
970 flags
= VIFF_USE_IFINDEX
;
973 if (pim_mroute_add_vif(ifp
, ifaddr
, flags
)) {
974 /* pim_mroute_add_vif reported error */
978 pim_ifp
->pim
->iface_vif_index
[pim_ifp
->mroute_vif_index
] = 1;
982 int pim_if_del_vif(struct interface
*ifp
)
984 struct pim_interface
*pim_ifp
= ifp
->info
;
986 if (pim_ifp
->mroute_vif_index
< 1) {
987 zlog_warn("%s: vif_index=%d < 1 on interface %s ifindex=%d",
988 __PRETTY_FUNCTION__
, pim_ifp
->mroute_vif_index
,
989 ifp
->name
, ifp
->ifindex
);
993 pim_mroute_del_vif(ifp
);
998 pim_ifp
->pim
->iface_vif_index
[pim_ifp
->mroute_vif_index
] = 0;
1000 pim_ifp
->mroute_vif_index
= -1;
1006 struct interface
*pim_if_find_by_vif_index(struct pim_instance
*pim
,
1007 ifindex_t vif_index
)
1009 struct interface
*ifp
;
1011 FOR_ALL_INTERFACES (pim
->vrf
, ifp
) {
1013 struct pim_interface
*pim_ifp
;
1014 pim_ifp
= ifp
->info
;
1016 if (vif_index
== pim_ifp
->mroute_vif_index
)
1025 pim_if_add_vif() uses ifindex as vif_index
1027 int pim_if_find_vifindex_by_ifindex(struct pim_instance
*pim
, ifindex_t ifindex
)
1029 struct pim_interface
*pim_ifp
;
1030 struct interface
*ifp
;
1032 ifp
= if_lookup_by_index(ifindex
, pim
->vrf_id
);
1033 if (!ifp
|| !ifp
->info
)
1035 pim_ifp
= ifp
->info
;
1037 return pim_ifp
->mroute_vif_index
;
1040 int pim_if_lan_delay_enabled(struct interface
*ifp
)
1042 struct pim_interface
*pim_ifp
;
1044 pim_ifp
= ifp
->info
;
1046 zassert(pim_ifp
->pim_number_of_nonlandelay_neighbors
>= 0);
1048 return pim_ifp
->pim_number_of_nonlandelay_neighbors
== 0;
1051 uint16_t pim_if_effective_propagation_delay_msec(struct interface
*ifp
)
1053 if (pim_if_lan_delay_enabled(ifp
)) {
1054 struct pim_interface
*pim_ifp
;
1055 pim_ifp
= ifp
->info
;
1056 return pim_ifp
->pim_neighbors_highest_propagation_delay_msec
;
1058 return PIM_DEFAULT_PROPAGATION_DELAY_MSEC
;
1062 uint16_t pim_if_effective_override_interval_msec(struct interface
*ifp
)
1064 if (pim_if_lan_delay_enabled(ifp
)) {
1065 struct pim_interface
*pim_ifp
;
1066 pim_ifp
= ifp
->info
;
1067 return pim_ifp
->pim_neighbors_highest_override_interval_msec
;
1069 return PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC
;
1073 int pim_if_t_override_msec(struct interface
*ifp
)
1075 int effective_override_interval_msec
;
1076 int t_override_msec
;
1078 effective_override_interval_msec
=
1079 pim_if_effective_override_interval_msec(ifp
);
1081 t_override_msec
= random() % (effective_override_interval_msec
+ 1);
1083 return t_override_msec
;
1086 uint16_t pim_if_jp_override_interval_msec(struct interface
*ifp
)
1088 return pim_if_effective_propagation_delay_msec(ifp
)
1089 + pim_if_effective_override_interval_msec(ifp
);
1093 RFC 4601: 4.1.6. State Summarization Macros
1095 The function NBR( I, A ) uses information gathered through PIM Hello
1096 messages to map the IP address A of a directly connected PIM
1097 neighbor router on interface I to the primary IP address of the same
1098 router (Section 4.3.4). The primary IP address of a neighbor is the
1099 address that it uses as the source of its PIM Hello messages.
1101 struct pim_neighbor
*pim_if_find_neighbor(struct interface
*ifp
,
1102 struct in_addr addr
)
1104 struct listnode
*neighnode
;
1105 struct pim_neighbor
*neigh
;
1106 struct pim_interface
*pim_ifp
;
1111 pim_ifp
= ifp
->info
;
1113 zlog_warn("%s: multicast not enabled on interface %s",
1114 __PRETTY_FUNCTION__
, ifp
->name
);
1120 p
.prefixlen
= IPV4_MAX_PREFIXLEN
;
1122 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
, neighnode
,
1125 /* primary address ? */
1126 if (neigh
->source_addr
.s_addr
== addr
.s_addr
)
1129 /* secondary address ? */
1130 if (pim_neighbor_find_secondary(neigh
, &p
))
1134 if (PIM_DEBUG_PIM_TRACE
) {
1135 char addr_str
[INET_ADDRSTRLEN
];
1136 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
1138 "%s: neighbor not found for address %s on interface %s",
1139 __PRETTY_FUNCTION__
, addr_str
, ifp
->name
);
1145 long pim_if_t_suppressed_msec(struct interface
*ifp
)
1147 struct pim_interface
*pim_ifp
;
1148 long t_suppressed_msec
;
1149 uint32_t ramount
= 0;
1151 pim_ifp
= ifp
->info
;
1154 /* join suppression disabled ? */
1155 if (PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp
->options
))
1158 /* t_suppressed = t_periodic * rand(1.1, 1.4) */
1159 ramount
= 1100 + (random() % (1400 - 1100 + 1));
1160 t_suppressed_msec
= qpim_t_periodic
* ramount
;
1162 return t_suppressed_msec
;
1165 static void igmp_join_free(struct igmp_join
*ij
)
1167 XFREE(MTYPE_PIM_IGMP_JOIN
, ij
);
1170 static struct igmp_join
*igmp_join_find(struct list
*join_list
,
1171 struct in_addr group_addr
,
1172 struct in_addr source_addr
)
1174 struct listnode
*node
;
1175 struct igmp_join
*ij
;
1179 for (ALL_LIST_ELEMENTS_RO(join_list
, node
, ij
)) {
1180 if ((group_addr
.s_addr
== ij
->group_addr
.s_addr
)
1181 && (source_addr
.s_addr
== ij
->source_addr
.s_addr
))
1188 static int igmp_join_sock(const char *ifname
, ifindex_t ifindex
,
1189 struct in_addr group_addr
, struct in_addr source_addr
)
1193 join_fd
= pim_socket_raw(IPPROTO_IGMP
);
1198 if (pim_igmp_join_source(join_fd
, ifindex
, group_addr
, source_addr
)) {
1199 char group_str
[INET_ADDRSTRLEN
];
1200 char source_str
[INET_ADDRSTRLEN
];
1201 pim_inet4_dump("<grp?>", group_addr
, group_str
,
1203 pim_inet4_dump("<src?>", source_addr
, source_str
,
1204 sizeof(source_str
));
1206 "%s: setsockopt(fd=%d) failure for IGMP group %s source %s ifindex %d on interface %s: errno=%d: %s",
1207 __PRETTY_FUNCTION__
, join_fd
, group_str
, source_str
,
1208 ifindex
, ifname
, errno
, safe_strerror(errno
));
1217 static struct igmp_join
*igmp_join_new(struct interface
*ifp
,
1218 struct in_addr group_addr
,
1219 struct in_addr source_addr
)
1221 struct pim_interface
*pim_ifp
;
1222 struct igmp_join
*ij
;
1225 pim_ifp
= ifp
->info
;
1228 join_fd
= igmp_join_sock(ifp
->name
, ifp
->ifindex
, group_addr
,
1231 char group_str
[INET_ADDRSTRLEN
];
1232 char source_str
[INET_ADDRSTRLEN
];
1234 pim_inet4_dump("<grp?>", group_addr
, group_str
,
1236 pim_inet4_dump("<src?>", source_addr
, source_str
,
1237 sizeof(source_str
));
1239 "%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s",
1240 __PRETTY_FUNCTION__
, group_str
, source_str
, ifp
->name
);
1244 ij
= XCALLOC(MTYPE_PIM_IGMP_JOIN
, sizeof(*ij
));
1246 ij
->sock_fd
= join_fd
;
1247 ij
->group_addr
= group_addr
;
1248 ij
->source_addr
= source_addr
;
1249 ij
->sock_creation
= pim_time_monotonic_sec();
1251 listnode_add(pim_ifp
->igmp_join_list
, ij
);
1256 ferr_r
pim_if_igmp_join_add(struct interface
*ifp
, struct in_addr group_addr
,
1257 struct in_addr source_addr
)
1259 struct pim_interface
*pim_ifp
;
1260 struct igmp_join
*ij
;
1262 pim_ifp
= ifp
->info
;
1264 return ferr_cfg_invalid("multicast not enabled on interface %s",
1268 if (!pim_ifp
->igmp_join_list
) {
1269 pim_ifp
->igmp_join_list
= list_new();
1270 pim_ifp
->igmp_join_list
->del
= (void (*)(void *))igmp_join_free
;
1273 ij
= igmp_join_find(pim_ifp
->igmp_join_list
, group_addr
, source_addr
);
1275 /* This interface has already been configured to join this IGMP group
1281 ij
= igmp_join_new(ifp
, group_addr
, source_addr
);
1283 return ferr_cfg_invalid(
1284 "Failure to create new join data structure, see log file for more information");
1287 if (PIM_DEBUG_IGMP_EVENTS
) {
1288 char group_str
[INET_ADDRSTRLEN
];
1289 char source_str
[INET_ADDRSTRLEN
];
1290 pim_inet4_dump("<grp?>", group_addr
, group_str
,
1292 pim_inet4_dump("<src?>", source_addr
, source_str
,
1293 sizeof(source_str
));
1295 "%s: issued static igmp join for channel (S,G)=(%s,%s) on interface %s",
1296 __PRETTY_FUNCTION__
, source_str
, group_str
, ifp
->name
);
1303 int pim_if_igmp_join_del(struct interface
*ifp
, struct in_addr group_addr
,
1304 struct in_addr source_addr
)
1306 struct pim_interface
*pim_ifp
;
1307 struct igmp_join
*ij
;
1309 pim_ifp
= ifp
->info
;
1311 zlog_warn("%s: multicast not enabled on interface %s",
1312 __PRETTY_FUNCTION__
, ifp
->name
);
1316 if (!pim_ifp
->igmp_join_list
) {
1317 zlog_warn("%s: no IGMP join on interface %s",
1318 __PRETTY_FUNCTION__
, ifp
->name
);
1322 ij
= igmp_join_find(pim_ifp
->igmp_join_list
, group_addr
, source_addr
);
1324 char group_str
[INET_ADDRSTRLEN
];
1325 char source_str
[INET_ADDRSTRLEN
];
1326 pim_inet4_dump("<grp?>", group_addr
, group_str
,
1328 pim_inet4_dump("<src?>", source_addr
, source_str
,
1329 sizeof(source_str
));
1331 "%s: could not find IGMP group %s source %s on interface %s",
1332 __PRETTY_FUNCTION__
, group_str
, source_str
, ifp
->name
);
1336 if (close(ij
->sock_fd
)) {
1337 char group_str
[INET_ADDRSTRLEN
];
1338 char source_str
[INET_ADDRSTRLEN
];
1339 pim_inet4_dump("<grp?>", group_addr
, group_str
,
1341 pim_inet4_dump("<src?>", source_addr
, source_str
,
1342 sizeof(source_str
));
1344 "%s: failure closing sock_fd=%d for IGMP group %s source %s on interface %s: errno=%d: %s",
1345 __PRETTY_FUNCTION__
, ij
->sock_fd
, group_str
, source_str
,
1346 ifp
->name
, errno
, safe_strerror(errno
));
1349 listnode_delete(pim_ifp
->igmp_join_list
, ij
);
1351 if (listcount(pim_ifp
->igmp_join_list
) < 1) {
1352 list_delete_and_null(&pim_ifp
->igmp_join_list
);
1353 pim_ifp
->igmp_join_list
= 0;
1359 static void pim_if_igmp_join_del_all(struct interface
*ifp
)
1361 struct pim_interface
*pim_ifp
;
1362 struct listnode
*node
;
1363 struct listnode
*nextnode
;
1364 struct igmp_join
*ij
;
1366 pim_ifp
= ifp
->info
;
1368 zlog_warn("%s: multicast not enabled on interface %s",
1369 __PRETTY_FUNCTION__
, ifp
->name
);
1373 if (!pim_ifp
->igmp_join_list
)
1376 for (ALL_LIST_ELEMENTS(pim_ifp
->igmp_join_list
, node
, nextnode
, ij
))
1377 pim_if_igmp_join_del(ifp
, ij
->group_addr
, ij
->source_addr
);
1383 Transitions from "I am Assert Loser" State
1385 Current Winner's GenID Changes or NLT Expires
1387 The Neighbor Liveness Timer associated with the current winner
1388 expires or we receive a Hello message from the current winner
1389 reporting a different GenID from the one it previously reported.
1390 This indicates that the current winner's interface or router has
1391 gone down (and may have come back up), and so we must assume it no
1392 longer knows it was the winner.
1394 void pim_if_assert_on_neighbor_down(struct interface
*ifp
,
1395 struct in_addr neigh_addr
)
1397 struct pim_interface
*pim_ifp
;
1398 struct pim_ifchannel
*ch
;
1400 pim_ifp
= ifp
->info
;
1403 RB_FOREACH (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
) {
1404 /* Is (S,G,I) assert loser ? */
1405 if (ch
->ifassert_state
!= PIM_IFASSERT_I_AM_LOSER
)
1407 /* Dead neighbor was winner ? */
1408 if (ch
->ifassert_winner
.s_addr
!= neigh_addr
.s_addr
)
1411 assert_action_a5(ch
);
1415 void pim_if_update_join_desired(struct pim_interface
*pim_ifp
)
1417 struct pim_ifchannel
*ch
;
1419 /* clear off flag from interface's upstreams */
1420 RB_FOREACH (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
) {
1421 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(
1422 ch
->upstream
->flags
);
1425 /* scan per-interface (S,G,I) state on this I interface */
1426 RB_FOREACH (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
) {
1427 struct pim_upstream
*up
= ch
->upstream
;
1429 if (PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(up
->flags
))
1432 /* update join_desired for the global (S,G) state */
1433 pim_upstream_update_join_desired(pim_ifp
->pim
, up
);
1434 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(up
->flags
);
1438 void pim_if_update_assert_tracking_desired(struct interface
*ifp
)
1440 struct pim_interface
*pim_ifp
;
1441 struct pim_ifchannel
*ch
;
1443 pim_ifp
= ifp
->info
;
1447 RB_FOREACH (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
) {
1448 pim_ifchannel_update_assert_tracking_desired(ch
);
1453 * PIM wants to have an interface pointer for everything it does.
1454 * The pimreg is a special interface that we have that is not
1455 * quite an inteface but a VIF is created for it.
1457 void pim_if_create_pimreg(struct pim_instance
*pim
)
1459 char pimreg_name
[INTERFACE_NAMSIZ
];
1461 if (!pim
->regiface
) {
1462 if (pim
->vrf_id
== VRF_DEFAULT
)
1463 strlcpy(pimreg_name
, "pimreg", sizeof(pimreg_name
));
1465 snprintf(pimreg_name
, sizeof(pimreg_name
), "pimreg%u",
1466 pim
->vrf
->data
.l
.table_id
);
1468 pim
->regiface
= if_create(pimreg_name
, pim
->vrf_id
);
1469 pim
->regiface
->ifindex
= PIM_OIF_PIM_REGISTER_VIF
;
1471 pim_if_new(pim
->regiface
, false, false, true);
1475 int pim_if_connected_to_source(struct interface
*ifp
, struct in_addr src
)
1477 struct listnode
*cnode
;
1478 struct connected
*c
;
1486 p
.prefixlen
= IPV4_MAX_BITLEN
;
1488 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, cnode
, c
)) {
1489 if ((c
->address
->family
== AF_INET
)
1490 && prefix_match(CONNECTED_PREFIX(c
), &p
)) {
1498 bool pim_if_is_vrf_device(struct interface
*ifp
)
1506 int pim_if_ifchannel_count(struct pim_interface
*pim_ifp
)
1508 struct pim_ifchannel
*ch
;
1511 RB_FOREACH (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
) {