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 ((ch
= RB_ROOT(pim_ifchannel_rb
,
89 &pim_ifp
->ifchannel_rb
)) != NULL
)
90 pim_ifchannel_delete(ch
);
92 XFREE(MTYPE_PIM_INTERFACE
, pim_ifp
);
97 static void pim_sec_addr_free(struct pim_secondary_addr
*sec_addr
)
99 XFREE(MTYPE_PIM_SEC_ADDR
, sec_addr
);
102 static int pim_sec_addr_comp(const void *p1
, const void *p2
)
104 const struct pim_secondary_addr
*sec1
= p1
;
105 const struct pim_secondary_addr
*sec2
= p2
;
107 if (sec1
->addr
.family
== AF_INET
&& sec2
->addr
.family
== AF_INET6
)
110 if (sec1
->addr
.family
== AF_INET6
&& sec2
->addr
.family
== AF_INET
)
113 if (sec1
->addr
.family
== AF_INET
) {
114 if (ntohl(sec1
->addr
.u
.prefix4
.s_addr
)
115 < ntohl(sec2
->addr
.u
.prefix4
.s_addr
))
118 if (ntohl(sec1
->addr
.u
.prefix4
.s_addr
)
119 > ntohl(sec2
->addr
.u
.prefix4
.s_addr
))
122 return memcmp(&sec1
->addr
.u
.prefix6
, &sec2
->addr
.u
.prefix6
,
123 sizeof(struct in6_addr
));
129 struct pim_interface
*pim_if_new(struct interface
*ifp
, int igmp
, int pim
)
131 struct pim_interface
*pim_ifp
;
136 pim_ifp
= XCALLOC(MTYPE_PIM_INTERFACE
, sizeof(*pim_ifp
));
138 zlog_err("PIM XCALLOC(%zu) failure", sizeof(*pim_ifp
));
142 pim_ifp
->options
= 0;
143 pim_ifp
->pim
= pim_get_pim_instance(ifp
->vrf_id
);
144 pim_ifp
->mroute_vif_index
= -1;
146 pim_ifp
->igmp_version
= IGMP_DEFAULT_VERSION
;
147 pim_ifp
->igmp_default_robustness_variable
=
148 IGMP_DEFAULT_ROBUSTNESS_VARIABLE
;
149 pim_ifp
->igmp_default_query_interval
= IGMP_GENERAL_QUERY_INTERVAL
;
150 pim_ifp
->igmp_query_max_response_time_dsec
=
151 IGMP_QUERY_MAX_RESPONSE_TIME_DSEC
;
152 pim_ifp
->igmp_specific_query_max_response_time_dsec
=
153 IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC
;
156 RFC 3376: 8.3. Query Response Interval
157 The number of seconds represented by the [Query Response Interval]
158 must be less than the [Query Interval].
160 zassert(pim_ifp
->igmp_query_max_response_time_dsec
161 < pim_ifp
->igmp_default_query_interval
);
164 PIM_IF_DO_PIM(pim_ifp
->options
);
166 PIM_IF_DO_IGMP(pim_ifp
->options
);
168 PIM_IF_DO_IGMP_LISTEN_ALLROUTERS(pim_ifp
->options
);
170 pim_ifp
->igmp_join_list
= NULL
;
171 pim_ifp
->igmp_socket_list
= NULL
;
172 pim_ifp
->pim_neighbor_list
= NULL
;
173 pim_ifp
->upstream_switch_list
= NULL
;
174 pim_ifp
->pim_generation_id
= 0;
176 /* list of struct igmp_sock */
177 pim_ifp
->igmp_socket_list
= list_new();
178 if (!pim_ifp
->igmp_socket_list
) {
179 zlog_err("%s: failure: igmp_socket_list=list_new()",
180 __PRETTY_FUNCTION__
);
181 return if_list_clean(pim_ifp
);
183 pim_ifp
->igmp_socket_list
->del
= (void (*)(void *))igmp_sock_free
;
185 /* list of struct pim_neighbor */
186 pim_ifp
->pim_neighbor_list
= list_new();
187 if (!pim_ifp
->pim_neighbor_list
) {
188 zlog_err("%s: failure: pim_neighbor_list=list_new()",
189 __PRETTY_FUNCTION__
);
190 return if_list_clean(pim_ifp
);
192 pim_ifp
->pim_neighbor_list
->del
= (void (*)(void *))pim_neighbor_free
;
194 pim_ifp
->upstream_switch_list
= list_new();
195 if (!pim_ifp
->upstream_switch_list
) {
196 zlog_err("%s: failure: upstream_switch_list=list_new()",
197 __PRETTY_FUNCTION__
);
198 return if_list_clean(pim_ifp
);
200 pim_ifp
->upstream_switch_list
->del
=
201 (void (*)(void *))pim_jp_agg_group_list_free
;
202 pim_ifp
->upstream_switch_list
->cmp
= pim_jp_agg_group_list_cmp
;
204 pim_ifp
->sec_addr_list
= list_new();
205 if (!pim_ifp
->sec_addr_list
) {
206 zlog_err("%s: failure: secondary addresslist",
207 __PRETTY_FUNCTION__
);
209 pim_ifp
->sec_addr_list
->del
= (void (*)(void *))pim_sec_addr_free
;
210 pim_ifp
->sec_addr_list
->cmp
=
211 (int (*)(void *, void *))pim_sec_addr_comp
;
213 RB_INIT(pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
);
224 void pim_if_delete(struct interface
*ifp
)
226 struct pim_interface
*pim_ifp
;
227 struct pim_ifchannel
*ch
;
233 if (pim_ifp
->igmp_join_list
) {
234 pim_if_igmp_join_del_all(ifp
);
237 pim_ifchannel_delete_all(ifp
);
238 igmp_sock_delete_all(ifp
);
240 pim_neighbor_delete_all(ifp
, "Interface removed from configuration");
244 list_delete_and_null(&pim_ifp
->igmp_socket_list
);
245 list_delete_and_null(&pim_ifp
->pim_neighbor_list
);
246 list_delete_and_null(&pim_ifp
->upstream_switch_list
);
247 list_delete_and_null(&pim_ifp
->sec_addr_list
);
249 if (pim_ifp
->boundary_oil_plist
)
250 XFREE(MTYPE_PIM_INTERFACE
, pim_ifp
->boundary_oil_plist
);
252 while ((ch
= RB_ROOT(pim_ifchannel_rb
,
253 &pim_ifp
->ifchannel_rb
)) != NULL
)
254 pim_ifchannel_delete(ch
);
256 XFREE(MTYPE_PIM_INTERFACE
, pim_ifp
);
261 void pim_if_update_could_assert(struct interface
*ifp
)
263 struct pim_interface
*pim_ifp
;
264 struct pim_ifchannel
*ch
;
269 RB_FOREACH (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
) {
270 pim_ifchannel_update_could_assert(ch
);
274 static void pim_if_update_my_assert_metric(struct interface
*ifp
)
276 struct pim_interface
*pim_ifp
;
277 struct pim_ifchannel
*ch
;
282 RB_FOREACH (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
) {
283 pim_ifchannel_update_my_assert_metric(ch
);
287 static void pim_addr_change(struct interface
*ifp
)
289 struct pim_interface
*pim_ifp
;
294 pim_if_dr_election(ifp
); /* router's own DR Priority (addr) changes --
296 pim_if_update_join_desired(pim_ifp
); /* depends on DR */
297 pim_if_update_could_assert(ifp
); /* depends on DR */
298 pim_if_update_my_assert_metric(ifp
); /* depends on could_assert */
299 pim_if_update_assert_tracking_desired(
300 ifp
); /* depends on DR, join_desired */
303 RFC 4601: 4.3.1. Sending Hello Messages
305 1) Before an interface goes down or changes primary IP address, a
306 Hello message with a zero HoldTime should be sent immediately
307 (with the old IP address if the IP address changed).
308 -- FIXME See CAVEAT C13
310 2) After an interface has changed its IP address, it MUST send a
311 Hello message with its new IP address.
314 3) If an interface changes one of its secondary IP addresses, a
315 Hello message with an updated Address_List option and a non-zero
316 HoldTime should be sent immediately.
317 -- FIXME See TODO T31
319 pim_ifp
->pim_ifstat_hello_sent
= 0; /* reset hello counter */
320 if (pim_ifp
->pim_sock_fd
< 0)
322 pim_hello_restart_now(ifp
); /* send hello and restart timer */
325 static int detect_primary_address_change(struct interface
*ifp
,
326 int force_prim_as_any
,
329 struct pim_interface
*pim_ifp
= ifp
->info
;
330 struct in_addr new_prim_addr
;
333 if (force_prim_as_any
)
334 new_prim_addr
.s_addr
= INADDR_ANY
;
336 new_prim_addr
= pim_find_primary_addr(ifp
);
338 changed
= new_prim_addr
.s_addr
!= pim_ifp
->primary_address
.s_addr
;
340 if (PIM_DEBUG_ZEBRA
) {
341 char new_prim_str
[INET_ADDRSTRLEN
];
342 char old_prim_str
[INET_ADDRSTRLEN
];
343 pim_inet4_dump("<new?>", new_prim_addr
, new_prim_str
,
344 sizeof(new_prim_str
));
345 pim_inet4_dump("<old?>", pim_ifp
->primary_address
, old_prim_str
,
346 sizeof(old_prim_str
));
347 zlog_debug("%s: old=%s new=%s on interface %s: %s",
348 __PRETTY_FUNCTION__
, old_prim_str
, new_prim_str
,
349 ifp
->name
, changed
? "changed" : "unchanged");
353 pim_ifp
->primary_address
= new_prim_addr
;
359 static struct pim_secondary_addr
*
360 pim_sec_addr_find(struct pim_interface
*pim_ifp
, struct prefix
*addr
)
362 struct pim_secondary_addr
*sec_addr
;
363 struct listnode
*node
;
365 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->sec_addr_list
, node
, sec_addr
)) {
366 if (prefix_cmp(&sec_addr
->addr
, addr
)) {
374 static void pim_sec_addr_del(struct pim_interface
*pim_ifp
,
375 struct pim_secondary_addr
*sec_addr
)
377 listnode_delete(pim_ifp
->sec_addr_list
, sec_addr
);
378 pim_sec_addr_free(sec_addr
);
381 static int pim_sec_addr_add(struct pim_interface
*pim_ifp
, struct prefix
*addr
)
384 struct pim_secondary_addr
*sec_addr
;
386 sec_addr
= pim_sec_addr_find(pim_ifp
, addr
);
388 sec_addr
->flags
&= ~PIM_SEC_ADDRF_STALE
;
392 sec_addr
= XCALLOC(MTYPE_PIM_SEC_ADDR
, sizeof(*sec_addr
));
397 sec_addr
->addr
= *addr
;
398 listnode_add_sort(pim_ifp
->sec_addr_list
, sec_addr
);
403 static int pim_sec_addr_del_all(struct pim_interface
*pim_ifp
)
407 if (!list_isempty(pim_ifp
->sec_addr_list
)) {
409 /* remove all nodes and free up the list itself */
410 list_delete_all_node(pim_ifp
->sec_addr_list
);
416 static int pim_sec_addr_update(struct interface
*ifp
)
418 struct pim_interface
*pim_ifp
= ifp
->info
;
419 struct connected
*ifc
;
420 struct listnode
*node
;
421 struct listnode
*nextnode
;
422 struct pim_secondary_addr
*sec_addr
;
425 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->sec_addr_list
, node
,
427 sec_addr
->flags
|= PIM_SEC_ADDRF_STALE
;
430 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, ifc
)) {
431 struct prefix
*p
= ifc
->address
;
433 if (PIM_INADDR_IS_ANY(p
->u
.prefix4
)) {
437 if (pim_ifp
->primary_address
.s_addr
== p
->u
.prefix4
.s_addr
) {
438 /* don't add the primary address into the secondary
443 if (pim_sec_addr_add(pim_ifp
, p
)) {
448 /* Drop stale entries */
449 for (ALL_LIST_ELEMENTS(pim_ifp
->sec_addr_list
, node
, nextnode
,
451 if (sec_addr
->flags
& PIM_SEC_ADDRF_STALE
) {
452 pim_sec_addr_del(pim_ifp
, sec_addr
);
460 static int detect_secondary_address_change(struct interface
*ifp
,
461 int force_prim_as_any
,
464 struct pim_interface
*pim_ifp
= ifp
->info
;
467 if (force_prim_as_any
) {
468 /* if primary address is being forced to zero just flush the
469 * secondary address list */
470 changed
= pim_sec_addr_del_all(pim_ifp
);
472 /* re-evaluate the secondary address list */
473 changed
= pim_sec_addr_update(ifp
);
479 static void detect_address_change(struct interface
*ifp
, int force_prim_as_any
,
483 struct pim_interface
*pim_ifp
;
489 if (detect_primary_address_change(ifp
, force_prim_as_any
, caller
)) {
493 if (detect_secondary_address_change(ifp
, force_prim_as_any
, caller
)) {
499 if (!PIM_IF_TEST_PIM(pim_ifp
->options
)) {
503 pim_addr_change(ifp
);
506 /* XXX: if we have unnumbered interfaces we need to run detect address
507 * address change on all of them when the lo address changes */
510 int pim_update_source_set(struct interface
*ifp
, struct in_addr source
)
512 struct pim_interface
*pim_ifp
= ifp
->info
;
515 return PIM_IFACE_NOT_FOUND
;
518 if (pim_ifp
->update_source
.s_addr
== source
.s_addr
) {
519 return PIM_UPDATE_SOURCE_DUP
;
522 pim_ifp
->update_source
= source
;
523 detect_address_change(ifp
, 0 /* force_prim_as_any */,
524 __PRETTY_FUNCTION__
);
529 void pim_if_addr_add(struct connected
*ifc
)
531 struct pim_interface
*pim_ifp
;
532 struct interface
*ifp
;
533 struct in_addr ifaddr
;
543 if (!if_is_operative(ifp
))
546 if (PIM_DEBUG_ZEBRA
) {
548 prefix2str(ifc
->address
, buf
, BUFSIZ
);
549 zlog_debug("%s: %s ifindex=%d connected IP address %s %s",
550 __PRETTY_FUNCTION__
, ifp
->name
, ifp
->ifindex
, buf
,
551 CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
)
556 ifaddr
= ifc
->address
->u
.prefix4
;
558 detect_address_change(ifp
, 0, __PRETTY_FUNCTION__
);
560 // if (ifc->address->family != AF_INET)
563 if (PIM_IF_TEST_IGMP(pim_ifp
->options
)) {
564 struct igmp_sock
*igmp
;
566 /* lookup IGMP socket */
567 igmp
= pim_igmp_sock_lookup_ifaddr(pim_ifp
->igmp_socket_list
,
570 /* if addr new, add IGMP socket */
571 if (ifc
->address
->family
== AF_INET
)
572 pim_igmp_sock_add(pim_ifp
->igmp_socket_list
,
576 /* Replay Static IGMP groups */
577 if (pim_ifp
->igmp_join_list
) {
578 struct listnode
*node
;
579 struct listnode
*nextnode
;
580 struct igmp_join
*ij
;
583 for (ALL_LIST_ELEMENTS(pim_ifp
->igmp_join_list
, node
,
585 /* Close socket and reopen with Source and Group
588 join_fd
= igmp_join_sock(
589 ifp
->name
, ifp
->ifindex
, ij
->group_addr
,
592 char group_str
[INET_ADDRSTRLEN
];
593 char source_str
[INET_ADDRSTRLEN
];
594 pim_inet4_dump("<grp?>", ij
->group_addr
,
598 "<src?>", ij
->source_addr
,
599 source_str
, sizeof(source_str
));
601 "%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s",
602 __PRETTY_FUNCTION__
, group_str
,
603 source_str
, ifp
->name
);
606 ij
->sock_fd
= join_fd
;
611 if (PIM_IF_TEST_PIM(pim_ifp
->options
)) {
613 if (PIM_INADDR_ISNOT_ANY(pim_ifp
->primary_address
)) {
615 /* Interface has a valid socket ? */
616 if (pim_ifp
->pim_sock_fd
< 0) {
617 if (pim_sock_add(ifp
)) {
619 "Failure creating PIM socket for interface %s",
623 struct pim_nexthop_cache
*pnc
= NULL
;
625 struct zclient
*zclient
= NULL
;
627 zclient
= pim_zebra_zclient_get();
628 /* RP config might come prior to (local RP's interface)
630 In this case, pnc would not have pim enabled
632 Once Interface is UP and pim info is available,
634 with RNH address to receive update and add the
635 interface as nexthop. */
636 memset(&rpf
, 0, sizeof(struct pim_rpf
));
637 rpf
.rpf_addr
.family
= AF_INET
;
638 rpf
.rpf_addr
.prefixlen
= IPV4_MAX_BITLEN
;
639 rpf
.rpf_addr
.u
.prefix4
= ifc
->address
->u
.prefix4
;
640 pnc
= pim_nexthop_cache_find(pim_ifp
->pim
, &rpf
);
642 pim_sendmsg_zebra_rnh(pim_ifp
->pim
, zclient
,
644 ZEBRA_NEXTHOP_REGISTER
);
649 PIM or IGMP is enabled on interface, and there is at least one
650 address assigned, then try to create a vif_index.
652 if (pim_ifp
->mroute_vif_index
< 0) {
655 pim_ifchannel_scan_forward_start(ifp
);
658 static void pim_if_addr_del_igmp(struct connected
*ifc
)
660 struct pim_interface
*pim_ifp
= ifc
->ifp
->info
;
661 struct igmp_sock
*igmp
;
662 struct in_addr ifaddr
;
664 if (ifc
->address
->family
!= AF_INET
) {
665 /* non-IPv4 address */
670 /* IGMP not enabled on interface */
674 ifaddr
= ifc
->address
->u
.prefix4
;
676 /* lookup IGMP socket */
677 igmp
= pim_igmp_sock_lookup_ifaddr(pim_ifp
->igmp_socket_list
, ifaddr
);
679 /* if addr found, del IGMP socket */
680 igmp_sock_delete(igmp
);
684 static void pim_if_addr_del_pim(struct connected
*ifc
)
686 struct pim_interface
*pim_ifp
= ifc
->ifp
->info
;
688 if (ifc
->address
->family
!= AF_INET
) {
689 /* non-IPv4 address */
694 /* PIM not enabled on interface */
698 if (PIM_INADDR_ISNOT_ANY(pim_ifp
->primary_address
)) {
699 /* Interface keeps a valid primary address */
703 if (pim_ifp
->pim_sock_fd
< 0) {
704 /* Interface does not hold a valid socket any longer */
709 pim_sock_delete() closes the socket, stops read and timer threads,
710 and kills all neighbors.
712 pim_sock_delete(ifc
->ifp
,
713 "last address has been removed from interface");
716 void pim_if_addr_del(struct connected
*ifc
, int force_prim_as_any
)
718 struct interface
*ifp
;
724 if (PIM_DEBUG_ZEBRA
) {
726 prefix2str(ifc
->address
, buf
, BUFSIZ
);
727 zlog_debug("%s: %s ifindex=%d disconnected IP address %s %s",
728 __PRETTY_FUNCTION__
, ifp
->name
, ifp
->ifindex
, buf
,
729 CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
)
734 detect_address_change(ifp
, force_prim_as_any
, __PRETTY_FUNCTION__
);
736 pim_if_addr_del_igmp(ifc
);
737 pim_if_addr_del_pim(ifc
);
740 void pim_if_addr_add_all(struct interface
*ifp
)
742 struct connected
*ifc
;
743 struct listnode
*node
;
744 struct listnode
*nextnode
;
747 struct pim_interface
*pim_ifp
= ifp
->info
;
750 /* PIM/IGMP enabled ? */
754 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
755 struct prefix
*p
= ifc
->address
;
757 if (p
->family
!= AF_INET
)
761 pim_if_addr_add(ifc
);
764 if (!v4_addrs
&& v6_addrs
&& !if_is_loopback(ifp
)) {
765 if (PIM_IF_TEST_PIM(pim_ifp
->options
)) {
767 /* Interface has a valid primary address ? */
768 if (PIM_INADDR_ISNOT_ANY(pim_ifp
->primary_address
)) {
770 /* Interface has a valid socket ? */
771 if (pim_ifp
->pim_sock_fd
< 0) {
772 if (pim_sock_add(ifp
)) {
774 "Failure creating PIM socket for interface %s",
782 * PIM or IGMP is enabled on interface, and there is at least one
783 * address assigned, then try to create a vif_index.
785 if (pim_ifp
->mroute_vif_index
< 0) {
788 pim_ifchannel_scan_forward_start(ifp
);
790 pim_rp_setup(pim_ifp
->pim
);
791 pim_rp_check_on_if_add(pim_ifp
);
794 void pim_if_addr_del_all(struct interface
*ifp
)
796 struct connected
*ifc
;
797 struct listnode
*node
;
798 struct listnode
*nextnode
;
799 struct vrf
*vrf
= vrf_lookup_by_id(ifp
->vrf_id
);
800 struct pim_instance
*pim
= vrf
->info
;
802 /* PIM/IGMP enabled ? */
806 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
807 struct prefix
*p
= ifc
->address
;
809 if (p
->family
!= AF_INET
)
812 pim_if_addr_del(ifc
, 1 /* force_prim_as_any=true */);
816 pim_i_am_rp_re_evaluate(pim
);
819 void pim_if_addr_del_all_igmp(struct interface
*ifp
)
821 struct connected
*ifc
;
822 struct listnode
*node
;
823 struct listnode
*nextnode
;
825 /* PIM/IGMP enabled ? */
829 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
830 struct prefix
*p
= ifc
->address
;
832 if (p
->family
!= AF_INET
)
835 pim_if_addr_del_igmp(ifc
);
839 void pim_if_addr_del_all_pim(struct interface
*ifp
)
841 struct connected
*ifc
;
842 struct listnode
*node
;
843 struct listnode
*nextnode
;
845 /* PIM/IGMP enabled ? */
849 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
850 struct prefix
*p
= ifc
->address
;
852 if (p
->family
!= AF_INET
)
855 pim_if_addr_del_pim(ifc
);
859 struct in_addr
pim_find_primary_addr(struct interface
*ifp
)
861 struct connected
*ifc
;
862 struct listnode
*node
;
866 struct pim_interface
*pim_ifp
= ifp
->info
;
867 struct vrf
*vrf
= vrf_lookup_by_id(ifp
->vrf_id
);
869 if (pim_ifp
&& PIM_INADDR_ISNOT_ANY(pim_ifp
->update_source
)) {
870 return pim_ifp
->update_source
;
873 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, ifc
)) {
874 struct prefix
*p
= ifc
->address
;
876 if (p
->family
!= AF_INET
) {
881 if (PIM_INADDR_IS_ANY(p
->u
.prefix4
)) {
883 "%s: null IPv4 address connected to interface %s",
884 __PRETTY_FUNCTION__
, ifp
->name
);
890 if (CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
))
897 * If we have no v4_addrs and v6 is configured
898 * We probably are using unnumbered
899 * So let's grab the loopbacks v4 address
900 * and use that as the primary address
902 if (!v4_addrs
&& v6_addrs
&& !if_is_loopback(ifp
)) {
903 struct interface
*lo_ifp
;
904 // DBS - Come back and check here
905 if (ifp
->vrf_id
== VRF_DEFAULT
)
906 lo_ifp
= if_lookup_by_name("lo", vrf
->vrf_id
);
908 lo_ifp
= if_lookup_by_name(vrf
->name
, vrf
->vrf_id
);
911 return pim_find_primary_addr(lo_ifp
);
914 addr
.s_addr
= PIM_NET_INADDR_ANY
;
919 static int pim_iface_next_vif_index(struct interface
*ifp
)
921 struct pim_interface
*pim_ifp
= ifp
->info
;
922 struct pim_instance
*pim
= pim_ifp
->pim
;
926 * The pimreg vif is always going to be in index 0
929 if (ifp
->ifindex
== PIM_OIF_PIM_REGISTER_VIF
)
932 for (i
= 1; i
< MAXVIFS
; i
++) {
933 if (pim
->iface_vif_index
[i
] == 0)
940 pim_if_add_vif() uses ifindex as vif_index
942 see also pim_if_find_vifindex_by_ifindex()
944 int pim_if_add_vif(struct interface
*ifp
)
946 struct pim_interface
*pim_ifp
= ifp
->info
;
947 struct in_addr ifaddr
;
948 unsigned char flags
= 0;
952 if (pim_ifp
->mroute_vif_index
> 0) {
953 zlog_warn("%s: vif_index=%d > 0 on interface %s ifindex=%d",
954 __PRETTY_FUNCTION__
, pim_ifp
->mroute_vif_index
,
955 ifp
->name
, ifp
->ifindex
);
959 if (ifp
->ifindex
< 0) {
960 zlog_warn("%s: ifindex=%d < 1 on interface %s",
961 __PRETTY_FUNCTION__
, ifp
->ifindex
, ifp
->name
);
965 ifaddr
= pim_ifp
->primary_address
;
966 if (ifp
->ifindex
!= PIM_OIF_PIM_REGISTER_VIF
967 && PIM_INADDR_IS_ANY(ifaddr
)) {
969 "%s: could not get address for interface %s ifindex=%d",
970 __PRETTY_FUNCTION__
, ifp
->name
, ifp
->ifindex
);
974 pim_ifp
->mroute_vif_index
= pim_iface_next_vif_index(ifp
);
976 if (pim_ifp
->mroute_vif_index
>= MAXVIFS
) {
978 "%s: Attempting to configure more than MAXVIFS=%d on pim enabled interface %s",
979 __PRETTY_FUNCTION__
, MAXVIFS
, ifp
->name
);
983 if (ifp
->ifindex
== PIM_OIF_PIM_REGISTER_VIF
)
984 flags
= VIFF_REGISTER
;
985 #ifdef VIFF_USE_IFINDEX
987 flags
= VIFF_USE_IFINDEX
;
990 if (pim_mroute_add_vif(ifp
, ifaddr
, flags
)) {
991 /* pim_mroute_add_vif reported error */
995 pim_ifp
->pim
->iface_vif_index
[pim_ifp
->mroute_vif_index
] = 1;
999 int pim_if_del_vif(struct interface
*ifp
)
1001 struct pim_interface
*pim_ifp
= ifp
->info
;
1003 if (pim_ifp
->mroute_vif_index
< 1) {
1004 zlog_warn("%s: vif_index=%d < 1 on interface %s ifindex=%d",
1005 __PRETTY_FUNCTION__
, pim_ifp
->mroute_vif_index
,
1006 ifp
->name
, ifp
->ifindex
);
1010 pim_mroute_del_vif(ifp
);
1015 pim_ifp
->pim
->iface_vif_index
[pim_ifp
->mroute_vif_index
] = 0;
1017 pim_ifp
->mroute_vif_index
= -1;
1023 struct interface
*pim_if_find_by_vif_index(struct pim_instance
*pim
,
1024 ifindex_t vif_index
)
1026 struct interface
*ifp
;
1028 RB_FOREACH (ifp
, if_name_head
, &pim
->vrf
->ifaces_by_name
) {
1030 struct pim_interface
*pim_ifp
;
1031 pim_ifp
= ifp
->info
;
1033 if (vif_index
== pim_ifp
->mroute_vif_index
)
1042 pim_if_add_vif() uses ifindex as vif_index
1044 int pim_if_find_vifindex_by_ifindex(struct pim_instance
*pim
, ifindex_t ifindex
)
1046 struct pim_interface
*pim_ifp
;
1047 struct interface
*ifp
;
1049 ifp
= if_lookup_by_index(ifindex
, pim
->vrf_id
);
1050 if (!ifp
|| !ifp
->info
)
1052 pim_ifp
= ifp
->info
;
1054 return pim_ifp
->mroute_vif_index
;
1057 int pim_if_lan_delay_enabled(struct interface
*ifp
)
1059 struct pim_interface
*pim_ifp
;
1061 pim_ifp
= ifp
->info
;
1063 zassert(pim_ifp
->pim_number_of_nonlandelay_neighbors
>= 0);
1065 return pim_ifp
->pim_number_of_nonlandelay_neighbors
== 0;
1068 uint16_t pim_if_effective_propagation_delay_msec(struct interface
*ifp
)
1070 if (pim_if_lan_delay_enabled(ifp
)) {
1071 struct pim_interface
*pim_ifp
;
1072 pim_ifp
= ifp
->info
;
1073 return pim_ifp
->pim_neighbors_highest_propagation_delay_msec
;
1075 return PIM_DEFAULT_PROPAGATION_DELAY_MSEC
;
1079 uint16_t pim_if_effective_override_interval_msec(struct interface
*ifp
)
1081 if (pim_if_lan_delay_enabled(ifp
)) {
1082 struct pim_interface
*pim_ifp
;
1083 pim_ifp
= ifp
->info
;
1084 return pim_ifp
->pim_neighbors_highest_override_interval_msec
;
1086 return PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC
;
1090 int pim_if_t_override_msec(struct interface
*ifp
)
1092 int effective_override_interval_msec
;
1093 int t_override_msec
;
1095 effective_override_interval_msec
=
1096 pim_if_effective_override_interval_msec(ifp
);
1098 t_override_msec
= random() % (effective_override_interval_msec
+ 1);
1100 return t_override_msec
;
1103 uint16_t pim_if_jp_override_interval_msec(struct interface
*ifp
)
1105 return pim_if_effective_propagation_delay_msec(ifp
)
1106 + pim_if_effective_override_interval_msec(ifp
);
1110 RFC 4601: 4.1.6. State Summarization Macros
1112 The function NBR( I, A ) uses information gathered through PIM Hello
1113 messages to map the IP address A of a directly connected PIM
1114 neighbor router on interface I to the primary IP address of the same
1115 router (Section 4.3.4). The primary IP address of a neighbor is the
1116 address that it uses as the source of its PIM Hello messages.
1118 struct pim_neighbor
*pim_if_find_neighbor(struct interface
*ifp
,
1119 struct in_addr addr
)
1121 struct listnode
*neighnode
;
1122 struct pim_neighbor
*neigh
;
1123 struct pim_interface
*pim_ifp
;
1128 pim_ifp
= ifp
->info
;
1130 zlog_warn("%s: multicast not enabled on interface %s",
1131 __PRETTY_FUNCTION__
, ifp
->name
);
1137 p
.prefixlen
= IPV4_MAX_PREFIXLEN
;
1139 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
, neighnode
,
1142 /* primary address ? */
1143 if (neigh
->source_addr
.s_addr
== addr
.s_addr
)
1146 /* secondary address ? */
1147 if (pim_neighbor_find_secondary(neigh
, &p
))
1151 if (PIM_DEBUG_PIM_TRACE
) {
1152 char addr_str
[INET_ADDRSTRLEN
];
1153 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
1155 "%s: neighbor not found for address %s on interface %s",
1156 __PRETTY_FUNCTION__
, addr_str
, ifp
->name
);
1162 long pim_if_t_suppressed_msec(struct interface
*ifp
)
1164 struct pim_interface
*pim_ifp
;
1165 long t_suppressed_msec
;
1166 uint32_t ramount
= 0;
1168 pim_ifp
= ifp
->info
;
1171 /* join suppression disabled ? */
1172 if (PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp
->options
))
1175 /* t_suppressed = t_periodic * rand(1.1, 1.4) */
1176 ramount
= 1100 + (random() % (1400 - 1100 + 1));
1177 t_suppressed_msec
= qpim_t_periodic
* ramount
;
1179 return t_suppressed_msec
;
1182 static void igmp_join_free(struct igmp_join
*ij
)
1184 XFREE(MTYPE_PIM_IGMP_JOIN
, ij
);
1187 static struct igmp_join
*igmp_join_find(struct list
*join_list
,
1188 struct in_addr group_addr
,
1189 struct in_addr source_addr
)
1191 struct listnode
*node
;
1192 struct igmp_join
*ij
;
1196 for (ALL_LIST_ELEMENTS_RO(join_list
, node
, ij
)) {
1197 if ((group_addr
.s_addr
== ij
->group_addr
.s_addr
)
1198 && (source_addr
.s_addr
== ij
->source_addr
.s_addr
))
1205 static int igmp_join_sock(const char *ifname
, ifindex_t ifindex
,
1206 struct in_addr group_addr
, struct in_addr source_addr
)
1210 join_fd
= pim_socket_raw(IPPROTO_IGMP
);
1215 if (pim_socket_join_source(join_fd
, ifindex
, group_addr
, source_addr
,
1224 static struct igmp_join
*igmp_join_new(struct interface
*ifp
,
1225 struct in_addr group_addr
,
1226 struct in_addr source_addr
)
1228 struct pim_interface
*pim_ifp
;
1229 struct igmp_join
*ij
;
1232 pim_ifp
= ifp
->info
;
1235 join_fd
= igmp_join_sock(ifp
->name
, ifp
->ifindex
, group_addr
,
1238 char group_str
[INET_ADDRSTRLEN
];
1239 char source_str
[INET_ADDRSTRLEN
];
1240 pim_inet4_dump("<grp?>", group_addr
, group_str
,
1242 pim_inet4_dump("<src?>", source_addr
, source_str
,
1243 sizeof(source_str
));
1245 "%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s",
1246 __PRETTY_FUNCTION__
, group_str
, source_str
, ifp
->name
);
1250 ij
= XCALLOC(MTYPE_PIM_IGMP_JOIN
, sizeof(*ij
));
1252 char group_str
[INET_ADDRSTRLEN
];
1253 char source_str
[INET_ADDRSTRLEN
];
1254 pim_inet4_dump("<grp?>", group_addr
, group_str
,
1256 pim_inet4_dump("<src?>", source_addr
, source_str
,
1257 sizeof(source_str
));
1259 "%s: XCALLOC(%zu) failure for IGMP group %s source %s on interface %s",
1260 __PRETTY_FUNCTION__
, sizeof(*ij
), group_str
, source_str
,
1266 ij
->sock_fd
= join_fd
;
1267 ij
->group_addr
= group_addr
;
1268 ij
->source_addr
= source_addr
;
1269 ij
->sock_creation
= pim_time_monotonic_sec();
1271 listnode_add(pim_ifp
->igmp_join_list
, ij
);
1276 ferr_r
pim_if_igmp_join_add(struct interface
*ifp
, struct in_addr group_addr
,
1277 struct in_addr source_addr
)
1279 struct pim_interface
*pim_ifp
;
1280 struct igmp_join
*ij
;
1282 pim_ifp
= ifp
->info
;
1284 return ferr_cfg_invalid("multicast not enabled on interface %s",
1288 if (!pim_ifp
->igmp_join_list
) {
1289 pim_ifp
->igmp_join_list
= list_new();
1290 if (!pim_ifp
->igmp_join_list
) {
1291 return ferr_cfg_invalid("Insufficient memory");
1293 pim_ifp
->igmp_join_list
->del
= (void (*)(void *))igmp_join_free
;
1296 ij
= igmp_join_find(pim_ifp
->igmp_join_list
, group_addr
, source_addr
);
1298 /* This interface has already been configured to join this IGMP group
1304 ij
= igmp_join_new(ifp
, group_addr
, source_addr
);
1306 return ferr_cfg_invalid(
1307 "Failure to create new join data structure, see log file for more information");
1310 if (PIM_DEBUG_IGMP_EVENTS
) {
1311 char group_str
[INET_ADDRSTRLEN
];
1312 char source_str
[INET_ADDRSTRLEN
];
1313 pim_inet4_dump("<grp?>", group_addr
, group_str
,
1315 pim_inet4_dump("<src?>", source_addr
, source_str
,
1316 sizeof(source_str
));
1318 "%s: issued static igmp join for channel (S,G)=(%s,%s) on interface %s",
1319 __PRETTY_FUNCTION__
, source_str
, group_str
, ifp
->name
);
1326 int pim_if_igmp_join_del(struct interface
*ifp
, struct in_addr group_addr
,
1327 struct in_addr source_addr
)
1329 struct pim_interface
*pim_ifp
;
1330 struct igmp_join
*ij
;
1332 pim_ifp
= ifp
->info
;
1334 zlog_warn("%s: multicast not enabled on interface %s",
1335 __PRETTY_FUNCTION__
, ifp
->name
);
1339 if (!pim_ifp
->igmp_join_list
) {
1340 zlog_warn("%s: no IGMP join on interface %s",
1341 __PRETTY_FUNCTION__
, ifp
->name
);
1345 ij
= igmp_join_find(pim_ifp
->igmp_join_list
, group_addr
, source_addr
);
1347 char group_str
[INET_ADDRSTRLEN
];
1348 char source_str
[INET_ADDRSTRLEN
];
1349 pim_inet4_dump("<grp?>", group_addr
, group_str
,
1351 pim_inet4_dump("<src?>", source_addr
, source_str
,
1352 sizeof(source_str
));
1354 "%s: could not find IGMP group %s source %s on interface %s",
1355 __PRETTY_FUNCTION__
, group_str
, source_str
, ifp
->name
);
1359 if (close(ij
->sock_fd
)) {
1360 char group_str
[INET_ADDRSTRLEN
];
1361 char source_str
[INET_ADDRSTRLEN
];
1362 pim_inet4_dump("<grp?>", group_addr
, group_str
,
1364 pim_inet4_dump("<src?>", source_addr
, source_str
,
1365 sizeof(source_str
));
1367 "%s: failure closing sock_fd=%d for IGMP group %s source %s on interface %s: errno=%d: %s",
1368 __PRETTY_FUNCTION__
, ij
->sock_fd
, group_str
, source_str
,
1369 ifp
->name
, errno
, safe_strerror(errno
));
1372 listnode_delete(pim_ifp
->igmp_join_list
, ij
);
1374 if (listcount(pim_ifp
->igmp_join_list
) < 1) {
1375 list_delete_and_null(&pim_ifp
->igmp_join_list
);
1376 pim_ifp
->igmp_join_list
= 0;
1382 static void pim_if_igmp_join_del_all(struct interface
*ifp
)
1384 struct pim_interface
*pim_ifp
;
1385 struct listnode
*node
;
1386 struct listnode
*nextnode
;
1387 struct igmp_join
*ij
;
1389 pim_ifp
= ifp
->info
;
1391 zlog_warn("%s: multicast not enabled on interface %s",
1392 __PRETTY_FUNCTION__
, ifp
->name
);
1396 if (!pim_ifp
->igmp_join_list
)
1399 for (ALL_LIST_ELEMENTS(pim_ifp
->igmp_join_list
, node
, nextnode
, ij
))
1400 pim_if_igmp_join_del(ifp
, ij
->group_addr
, ij
->source_addr
);
1406 Transitions from "I am Assert Loser" State
1408 Current Winner's GenID Changes or NLT Expires
1410 The Neighbor Liveness Timer associated with the current winner
1411 expires or we receive a Hello message from the current winner
1412 reporting a different GenID from the one it previously reported.
1413 This indicates that the current winner's interface or router has
1414 gone down (and may have come back up), and so we must assume it no
1415 longer knows it was the winner.
1417 void pim_if_assert_on_neighbor_down(struct interface
*ifp
,
1418 struct in_addr neigh_addr
)
1420 struct pim_interface
*pim_ifp
;
1421 struct pim_ifchannel
*ch
;
1423 pim_ifp
= ifp
->info
;
1426 RB_FOREACH (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
) {
1427 /* Is (S,G,I) assert loser ? */
1428 if (ch
->ifassert_state
!= PIM_IFASSERT_I_AM_LOSER
)
1430 /* Dead neighbor was winner ? */
1431 if (ch
->ifassert_winner
.s_addr
!= neigh_addr
.s_addr
)
1434 assert_action_a5(ch
);
1438 void pim_if_update_join_desired(struct pim_interface
*pim_ifp
)
1440 struct pim_ifchannel
*ch
;
1442 /* clear off flag from interface's upstreams */
1443 RB_FOREACH (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
) {
1444 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(
1445 ch
->upstream
->flags
);
1448 /* scan per-interface (S,G,I) state on this I interface */
1449 RB_FOREACH (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
) {
1450 struct pim_upstream
*up
= ch
->upstream
;
1452 if (PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(up
->flags
))
1455 /* update join_desired for the global (S,G) state */
1456 pim_upstream_update_join_desired(pim_ifp
->pim
, up
);
1457 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(up
->flags
);
1461 void pim_if_update_assert_tracking_desired(struct interface
*ifp
)
1463 struct pim_interface
*pim_ifp
;
1464 struct pim_ifchannel
*ch
;
1466 pim_ifp
= ifp
->info
;
1470 RB_FOREACH (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
) {
1471 pim_ifchannel_update_assert_tracking_desired(ch
);
1476 * PIM wants to have an interface pointer for everything it does.
1477 * The pimreg is a special interface that we have that is not
1478 * quite an inteface but a VIF is created for it.
1480 void pim_if_create_pimreg(struct pim_instance
*pim
)
1482 char pimreg_name
[INTERFACE_NAMSIZ
];
1484 if (!pim
->regiface
) {
1485 if (pim
->vrf_id
== VRF_DEFAULT
)
1486 strlcpy(pimreg_name
, "pimreg", sizeof(pimreg_name
));
1488 snprintf(pimreg_name
, sizeof(pimreg_name
), "pimreg%u",
1489 pim
->vrf
->data
.l
.table_id
);
1491 pim
->regiface
= if_create(pimreg_name
, pim
->vrf_id
);
1492 pim
->regiface
->ifindex
= PIM_OIF_PIM_REGISTER_VIF
;
1494 pim_if_new(pim
->regiface
, 0, 0);
1498 int pim_if_connected_to_source(struct interface
*ifp
, struct in_addr src
)
1500 struct listnode
*cnode
;
1501 struct connected
*c
;
1509 p
.prefixlen
= IPV4_MAX_BITLEN
;
1511 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, cnode
, c
)) {
1512 if ((c
->address
->family
== AF_INET
)
1513 && prefix_match(CONNECTED_PREFIX(c
), &p
)) {
1521 int pim_if_is_loopback(struct pim_instance
*pim
, struct interface
*ifp
)
1523 if (if_is_loopback(ifp
))
1526 if (strcmp(ifp
->name
, pim
->vrf
->name
) == 0)
1532 int pim_if_is_vrf_device(struct interface
*ifp
)
1536 RB_FOREACH (vrf
, vrf_name_head
, &vrfs_by_name
) {
1537 if (strncmp(ifp
->name
, vrf
->name
, strlen(ifp
->name
)) == 0)
1544 int pim_if_ifchannel_count(struct pim_interface
*pim_ifp
)
1546 struct pim_ifchannel
*ch
;
1549 RB_FOREACH (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
) {