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__
);
208 return if_list_clean(pim_ifp
);
210 pim_ifp
->sec_addr_list
->del
= (void (*)(void *))pim_sec_addr_free
;
211 pim_ifp
->sec_addr_list
->cmp
=
212 (int (*)(void *, void *))pim_sec_addr_comp
;
214 RB_INIT(pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
);
225 void pim_if_delete(struct interface
*ifp
)
227 struct pim_interface
*pim_ifp
;
228 struct pim_ifchannel
*ch
;
234 if (pim_ifp
->igmp_join_list
) {
235 pim_if_igmp_join_del_all(ifp
);
238 pim_ifchannel_delete_all(ifp
);
239 igmp_sock_delete_all(ifp
);
241 pim_neighbor_delete_all(ifp
, "Interface removed from configuration");
245 list_delete_and_null(&pim_ifp
->igmp_socket_list
);
246 list_delete_and_null(&pim_ifp
->pim_neighbor_list
);
247 list_delete_and_null(&pim_ifp
->upstream_switch_list
);
248 list_delete_and_null(&pim_ifp
->sec_addr_list
);
250 if (pim_ifp
->boundary_oil_plist
)
251 XFREE(MTYPE_PIM_INTERFACE
, pim_ifp
->boundary_oil_plist
);
253 while ((ch
= RB_ROOT(pim_ifchannel_rb
,
254 &pim_ifp
->ifchannel_rb
)) != NULL
)
255 pim_ifchannel_delete(ch
);
257 XFREE(MTYPE_PIM_INTERFACE
, pim_ifp
);
262 void pim_if_update_could_assert(struct interface
*ifp
)
264 struct pim_interface
*pim_ifp
;
265 struct pim_ifchannel
*ch
;
270 RB_FOREACH (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
) {
271 pim_ifchannel_update_could_assert(ch
);
275 static void pim_if_update_my_assert_metric(struct interface
*ifp
)
277 struct pim_interface
*pim_ifp
;
278 struct pim_ifchannel
*ch
;
283 RB_FOREACH (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
) {
284 pim_ifchannel_update_my_assert_metric(ch
);
288 static void pim_addr_change(struct interface
*ifp
)
290 struct pim_interface
*pim_ifp
;
295 pim_if_dr_election(ifp
); /* router's own DR Priority (addr) changes --
297 pim_if_update_join_desired(pim_ifp
); /* depends on DR */
298 pim_if_update_could_assert(ifp
); /* depends on DR */
299 pim_if_update_my_assert_metric(ifp
); /* depends on could_assert */
300 pim_if_update_assert_tracking_desired(
301 ifp
); /* depends on DR, join_desired */
304 RFC 4601: 4.3.1. Sending Hello Messages
306 1) Before an interface goes down or changes primary IP address, a
307 Hello message with a zero HoldTime should be sent immediately
308 (with the old IP address if the IP address changed).
309 -- FIXME See CAVEAT C13
311 2) After an interface has changed its IP address, it MUST send a
312 Hello message with its new IP address.
315 3) If an interface changes one of its secondary IP addresses, a
316 Hello message with an updated Address_List option and a non-zero
317 HoldTime should be sent immediately.
318 -- FIXME See TODO T31
320 pim_ifp
->pim_ifstat_hello_sent
= 0; /* reset hello counter */
321 if (pim_ifp
->pim_sock_fd
< 0)
323 pim_hello_restart_now(ifp
); /* send hello and restart timer */
326 static int detect_primary_address_change(struct interface
*ifp
,
327 int force_prim_as_any
,
330 struct pim_interface
*pim_ifp
= ifp
->info
;
331 struct in_addr new_prim_addr
;
334 if (force_prim_as_any
)
335 new_prim_addr
.s_addr
= INADDR_ANY
;
337 new_prim_addr
= pim_find_primary_addr(ifp
);
339 changed
= new_prim_addr
.s_addr
!= pim_ifp
->primary_address
.s_addr
;
341 if (PIM_DEBUG_ZEBRA
) {
342 char new_prim_str
[INET_ADDRSTRLEN
];
343 char old_prim_str
[INET_ADDRSTRLEN
];
344 pim_inet4_dump("<new?>", new_prim_addr
, new_prim_str
,
345 sizeof(new_prim_str
));
346 pim_inet4_dump("<old?>", pim_ifp
->primary_address
, old_prim_str
,
347 sizeof(old_prim_str
));
348 zlog_debug("%s: old=%s new=%s on interface %s: %s",
349 __PRETTY_FUNCTION__
, old_prim_str
, new_prim_str
,
350 ifp
->name
, changed
? "changed" : "unchanged");
354 pim_ifp
->primary_address
= new_prim_addr
;
360 static struct pim_secondary_addr
*
361 pim_sec_addr_find(struct pim_interface
*pim_ifp
, struct prefix
*addr
)
363 struct pim_secondary_addr
*sec_addr
;
364 struct listnode
*node
;
366 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->sec_addr_list
, node
, sec_addr
)) {
367 if (prefix_cmp(&sec_addr
->addr
, addr
)) {
375 static void pim_sec_addr_del(struct pim_interface
*pim_ifp
,
376 struct pim_secondary_addr
*sec_addr
)
378 listnode_delete(pim_ifp
->sec_addr_list
, sec_addr
);
379 pim_sec_addr_free(sec_addr
);
382 static int pim_sec_addr_add(struct pim_interface
*pim_ifp
, struct prefix
*addr
)
385 struct pim_secondary_addr
*sec_addr
;
387 sec_addr
= pim_sec_addr_find(pim_ifp
, addr
);
389 sec_addr
->flags
&= ~PIM_SEC_ADDRF_STALE
;
393 sec_addr
= XCALLOC(MTYPE_PIM_SEC_ADDR
, sizeof(*sec_addr
));
398 sec_addr
->addr
= *addr
;
399 listnode_add_sort(pim_ifp
->sec_addr_list
, sec_addr
);
404 static int pim_sec_addr_del_all(struct pim_interface
*pim_ifp
)
408 if (!list_isempty(pim_ifp
->sec_addr_list
)) {
410 /* remove all nodes and free up the list itself */
411 list_delete_all_node(pim_ifp
->sec_addr_list
);
417 static int pim_sec_addr_update(struct interface
*ifp
)
419 struct pim_interface
*pim_ifp
= ifp
->info
;
420 struct connected
*ifc
;
421 struct listnode
*node
;
422 struct listnode
*nextnode
;
423 struct pim_secondary_addr
*sec_addr
;
426 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->sec_addr_list
, node
,
428 sec_addr
->flags
|= PIM_SEC_ADDRF_STALE
;
431 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, ifc
)) {
432 struct prefix
*p
= ifc
->address
;
434 if (PIM_INADDR_IS_ANY(p
->u
.prefix4
)) {
438 if (pim_ifp
->primary_address
.s_addr
== p
->u
.prefix4
.s_addr
) {
439 /* don't add the primary address into the secondary
444 if (pim_sec_addr_add(pim_ifp
, p
)) {
449 /* Drop stale entries */
450 for (ALL_LIST_ELEMENTS(pim_ifp
->sec_addr_list
, node
, nextnode
,
452 if (sec_addr
->flags
& PIM_SEC_ADDRF_STALE
) {
453 pim_sec_addr_del(pim_ifp
, sec_addr
);
461 static int detect_secondary_address_change(struct interface
*ifp
,
462 int force_prim_as_any
,
465 struct pim_interface
*pim_ifp
= ifp
->info
;
468 if (force_prim_as_any
) {
469 /* if primary address is being forced to zero just flush the
470 * secondary address list */
471 changed
= pim_sec_addr_del_all(pim_ifp
);
473 /* re-evaluate the secondary address list */
474 changed
= pim_sec_addr_update(ifp
);
480 static void detect_address_change(struct interface
*ifp
, int force_prim_as_any
,
484 struct pim_interface
*pim_ifp
;
490 if (detect_primary_address_change(ifp
, force_prim_as_any
, caller
)) {
494 if (detect_secondary_address_change(ifp
, force_prim_as_any
, caller
)) {
500 if (!PIM_IF_TEST_PIM(pim_ifp
->options
)) {
504 pim_addr_change(ifp
);
507 /* XXX: if we have unnumbered interfaces we need to run detect address
508 * address change on all of them when the lo address changes */
511 int pim_update_source_set(struct interface
*ifp
, struct in_addr source
)
513 struct pim_interface
*pim_ifp
= ifp
->info
;
516 return PIM_IFACE_NOT_FOUND
;
519 if (pim_ifp
->update_source
.s_addr
== source
.s_addr
) {
520 return PIM_UPDATE_SOURCE_DUP
;
523 pim_ifp
->update_source
= source
;
524 detect_address_change(ifp
, 0 /* force_prim_as_any */,
525 __PRETTY_FUNCTION__
);
530 void pim_if_addr_add(struct connected
*ifc
)
532 struct pim_interface
*pim_ifp
;
533 struct interface
*ifp
;
534 struct in_addr ifaddr
;
544 if (!if_is_operative(ifp
))
547 if (PIM_DEBUG_ZEBRA
) {
549 prefix2str(ifc
->address
, buf
, BUFSIZ
);
550 zlog_debug("%s: %s ifindex=%d connected IP address %s %s",
551 __PRETTY_FUNCTION__
, ifp
->name
, ifp
->ifindex
, buf
,
552 CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
)
557 ifaddr
= ifc
->address
->u
.prefix4
;
559 detect_address_change(ifp
, 0, __PRETTY_FUNCTION__
);
561 // if (ifc->address->family != AF_INET)
564 if (PIM_IF_TEST_IGMP(pim_ifp
->options
)) {
565 struct igmp_sock
*igmp
;
567 /* lookup IGMP socket */
568 igmp
= pim_igmp_sock_lookup_ifaddr(pim_ifp
->igmp_socket_list
,
571 /* if addr new, add IGMP socket */
572 if (ifc
->address
->family
== AF_INET
)
573 pim_igmp_sock_add(pim_ifp
->igmp_socket_list
,
577 /* Replay Static IGMP groups */
578 if (pim_ifp
->igmp_join_list
) {
579 struct listnode
*node
;
580 struct listnode
*nextnode
;
581 struct igmp_join
*ij
;
584 for (ALL_LIST_ELEMENTS(pim_ifp
->igmp_join_list
, node
,
586 /* Close socket and reopen with Source and Group
589 join_fd
= igmp_join_sock(
590 ifp
->name
, ifp
->ifindex
, ij
->group_addr
,
593 char group_str
[INET_ADDRSTRLEN
];
594 char source_str
[INET_ADDRSTRLEN
];
595 pim_inet4_dump("<grp?>", ij
->group_addr
,
599 "<src?>", ij
->source_addr
,
600 source_str
, sizeof(source_str
));
602 "%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s",
603 __PRETTY_FUNCTION__
, group_str
,
604 source_str
, ifp
->name
);
607 ij
->sock_fd
= join_fd
;
612 if (PIM_IF_TEST_PIM(pim_ifp
->options
)) {
614 if (PIM_INADDR_ISNOT_ANY(pim_ifp
->primary_address
)) {
616 /* Interface has a valid socket ? */
617 if (pim_ifp
->pim_sock_fd
< 0) {
618 if (pim_sock_add(ifp
)) {
620 "Failure creating PIM socket for interface %s",
624 struct pim_nexthop_cache
*pnc
= NULL
;
626 struct zclient
*zclient
= NULL
;
628 zclient
= pim_zebra_zclient_get();
629 /* RP config might come prior to (local RP's interface)
631 In this case, pnc would not have pim enabled
633 Once Interface is UP and pim info is available,
635 with RNH address to receive update and add the
636 interface as nexthop. */
637 memset(&rpf
, 0, sizeof(struct pim_rpf
));
638 rpf
.rpf_addr
.family
= AF_INET
;
639 rpf
.rpf_addr
.prefixlen
= IPV4_MAX_BITLEN
;
640 rpf
.rpf_addr
.u
.prefix4
= ifc
->address
->u
.prefix4
;
641 pnc
= pim_nexthop_cache_find(pim_ifp
->pim
, &rpf
);
643 pim_sendmsg_zebra_rnh(pim_ifp
->pim
, zclient
,
645 ZEBRA_NEXTHOP_REGISTER
);
650 PIM or IGMP is enabled on interface, and there is at least one
651 address assigned, then try to create a vif_index.
653 if (pim_ifp
->mroute_vif_index
< 0) {
656 pim_ifchannel_scan_forward_start(ifp
);
659 static void pim_if_addr_del_igmp(struct connected
*ifc
)
661 struct pim_interface
*pim_ifp
= ifc
->ifp
->info
;
662 struct igmp_sock
*igmp
;
663 struct in_addr ifaddr
;
665 if (ifc
->address
->family
!= AF_INET
) {
666 /* non-IPv4 address */
671 /* IGMP not enabled on interface */
675 ifaddr
= ifc
->address
->u
.prefix4
;
677 /* lookup IGMP socket */
678 igmp
= pim_igmp_sock_lookup_ifaddr(pim_ifp
->igmp_socket_list
, ifaddr
);
680 /* if addr found, del IGMP socket */
681 igmp_sock_delete(igmp
);
685 static void pim_if_addr_del_pim(struct connected
*ifc
)
687 struct pim_interface
*pim_ifp
= ifc
->ifp
->info
;
689 if (ifc
->address
->family
!= AF_INET
) {
690 /* non-IPv4 address */
695 /* PIM not enabled on interface */
699 if (PIM_INADDR_ISNOT_ANY(pim_ifp
->primary_address
)) {
700 /* Interface keeps a valid primary address */
704 if (pim_ifp
->pim_sock_fd
< 0) {
705 /* Interface does not hold a valid socket any longer */
710 pim_sock_delete() closes the socket, stops read and timer threads,
711 and kills all neighbors.
713 pim_sock_delete(ifc
->ifp
,
714 "last address has been removed from interface");
717 void pim_if_addr_del(struct connected
*ifc
, int force_prim_as_any
)
719 struct interface
*ifp
;
725 if (PIM_DEBUG_ZEBRA
) {
727 prefix2str(ifc
->address
, buf
, BUFSIZ
);
728 zlog_debug("%s: %s ifindex=%d disconnected IP address %s %s",
729 __PRETTY_FUNCTION__
, ifp
->name
, ifp
->ifindex
, buf
,
730 CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
)
735 detect_address_change(ifp
, force_prim_as_any
, __PRETTY_FUNCTION__
);
737 pim_if_addr_del_igmp(ifc
);
738 pim_if_addr_del_pim(ifc
);
741 void pim_if_addr_add_all(struct interface
*ifp
)
743 struct connected
*ifc
;
744 struct listnode
*node
;
745 struct listnode
*nextnode
;
748 struct pim_interface
*pim_ifp
= ifp
->info
;
751 /* PIM/IGMP enabled ? */
755 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
756 struct prefix
*p
= ifc
->address
;
758 if (p
->family
!= AF_INET
)
762 pim_if_addr_add(ifc
);
765 if (!v4_addrs
&& v6_addrs
&& !if_is_loopback(ifp
)) {
766 if (PIM_IF_TEST_PIM(pim_ifp
->options
)) {
768 /* Interface has a valid primary address ? */
769 if (PIM_INADDR_ISNOT_ANY(pim_ifp
->primary_address
)) {
771 /* Interface has a valid socket ? */
772 if (pim_ifp
->pim_sock_fd
< 0) {
773 if (pim_sock_add(ifp
)) {
775 "Failure creating PIM socket for interface %s",
783 * PIM or IGMP is enabled on interface, and there is at least one
784 * address assigned, then try to create a vif_index.
786 if (pim_ifp
->mroute_vif_index
< 0) {
789 pim_ifchannel_scan_forward_start(ifp
);
791 pim_rp_setup(pim_ifp
->pim
);
792 pim_rp_check_on_if_add(pim_ifp
);
795 void pim_if_addr_del_all(struct interface
*ifp
)
797 struct connected
*ifc
;
798 struct listnode
*node
;
799 struct listnode
*nextnode
;
800 struct vrf
*vrf
= vrf_lookup_by_id(ifp
->vrf_id
);
801 struct pim_instance
*pim
;
807 /* PIM/IGMP enabled ? */
811 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
812 struct prefix
*p
= ifc
->address
;
814 if (p
->family
!= AF_INET
)
817 pim_if_addr_del(ifc
, 1 /* force_prim_as_any=true */);
821 pim_i_am_rp_re_evaluate(pim
);
824 void pim_if_addr_del_all_igmp(struct interface
*ifp
)
826 struct connected
*ifc
;
827 struct listnode
*node
;
828 struct listnode
*nextnode
;
830 /* PIM/IGMP enabled ? */
834 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
835 struct prefix
*p
= ifc
->address
;
837 if (p
->family
!= AF_INET
)
840 pim_if_addr_del_igmp(ifc
);
844 void pim_if_addr_del_all_pim(struct interface
*ifp
)
846 struct connected
*ifc
;
847 struct listnode
*node
;
848 struct listnode
*nextnode
;
850 /* PIM/IGMP enabled ? */
854 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
855 struct prefix
*p
= ifc
->address
;
857 if (p
->family
!= AF_INET
)
860 pim_if_addr_del_pim(ifc
);
864 struct in_addr
pim_find_primary_addr(struct interface
*ifp
)
866 struct connected
*ifc
;
867 struct listnode
*node
;
868 struct in_addr addr
= {0};
871 struct pim_interface
*pim_ifp
= ifp
->info
;
872 struct vrf
*vrf
= vrf_lookup_by_id(ifp
->vrf_id
);
877 if (pim_ifp
&& PIM_INADDR_ISNOT_ANY(pim_ifp
->update_source
)) {
878 return pim_ifp
->update_source
;
881 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, ifc
)) {
882 struct prefix
*p
= ifc
->address
;
884 if (p
->family
!= AF_INET
) {
889 if (PIM_INADDR_IS_ANY(p
->u
.prefix4
)) {
891 "%s: null IPv4 address connected to interface %s",
892 __PRETTY_FUNCTION__
, ifp
->name
);
898 if (CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
))
905 * If we have no v4_addrs and v6 is configured
906 * We probably are using unnumbered
907 * So let's grab the loopbacks v4 address
908 * and use that as the primary address
910 if (!v4_addrs
&& v6_addrs
&& !if_is_loopback(ifp
)) {
911 struct interface
*lo_ifp
;
912 // DBS - Come back and check here
913 if (ifp
->vrf_id
== VRF_DEFAULT
)
914 lo_ifp
= if_lookup_by_name("lo", vrf
->vrf_id
);
916 lo_ifp
= if_lookup_by_name(vrf
->name
, vrf
->vrf_id
);
919 return pim_find_primary_addr(lo_ifp
);
922 addr
.s_addr
= PIM_NET_INADDR_ANY
;
927 static int pim_iface_next_vif_index(struct interface
*ifp
)
929 struct pim_interface
*pim_ifp
= ifp
->info
;
930 struct pim_instance
*pim
= pim_ifp
->pim
;
934 * The pimreg vif is always going to be in index 0
937 if (ifp
->ifindex
== PIM_OIF_PIM_REGISTER_VIF
)
940 for (i
= 1; i
< MAXVIFS
; i
++) {
941 if (pim
->iface_vif_index
[i
] == 0)
948 pim_if_add_vif() uses ifindex as vif_index
950 see also pim_if_find_vifindex_by_ifindex()
952 int pim_if_add_vif(struct interface
*ifp
)
954 struct pim_interface
*pim_ifp
= ifp
->info
;
955 struct in_addr ifaddr
;
956 unsigned char flags
= 0;
960 if (pim_ifp
->mroute_vif_index
> 0) {
961 zlog_warn("%s: vif_index=%d > 0 on interface %s ifindex=%d",
962 __PRETTY_FUNCTION__
, pim_ifp
->mroute_vif_index
,
963 ifp
->name
, ifp
->ifindex
);
967 if (ifp
->ifindex
< 0) {
968 zlog_warn("%s: ifindex=%d < 1 on interface %s",
969 __PRETTY_FUNCTION__
, ifp
->ifindex
, ifp
->name
);
973 ifaddr
= pim_ifp
->primary_address
;
974 if (ifp
->ifindex
!= PIM_OIF_PIM_REGISTER_VIF
975 && PIM_INADDR_IS_ANY(ifaddr
)) {
977 "%s: could not get address for interface %s ifindex=%d",
978 __PRETTY_FUNCTION__
, ifp
->name
, ifp
->ifindex
);
982 pim_ifp
->mroute_vif_index
= pim_iface_next_vif_index(ifp
);
984 if (pim_ifp
->mroute_vif_index
>= MAXVIFS
) {
986 "%s: Attempting to configure more than MAXVIFS=%d on pim enabled interface %s",
987 __PRETTY_FUNCTION__
, MAXVIFS
, ifp
->name
);
991 if (ifp
->ifindex
== PIM_OIF_PIM_REGISTER_VIF
)
992 flags
= VIFF_REGISTER
;
993 #ifdef VIFF_USE_IFINDEX
995 flags
= VIFF_USE_IFINDEX
;
998 if (pim_mroute_add_vif(ifp
, ifaddr
, flags
)) {
999 /* pim_mroute_add_vif reported error */
1003 pim_ifp
->pim
->iface_vif_index
[pim_ifp
->mroute_vif_index
] = 1;
1007 int pim_if_del_vif(struct interface
*ifp
)
1009 struct pim_interface
*pim_ifp
= ifp
->info
;
1011 if (pim_ifp
->mroute_vif_index
< 1) {
1012 zlog_warn("%s: vif_index=%d < 1 on interface %s ifindex=%d",
1013 __PRETTY_FUNCTION__
, pim_ifp
->mroute_vif_index
,
1014 ifp
->name
, ifp
->ifindex
);
1018 pim_mroute_del_vif(ifp
);
1023 pim_ifp
->pim
->iface_vif_index
[pim_ifp
->mroute_vif_index
] = 0;
1025 pim_ifp
->mroute_vif_index
= -1;
1031 struct interface
*pim_if_find_by_vif_index(struct pim_instance
*pim
,
1032 ifindex_t vif_index
)
1034 struct interface
*ifp
;
1036 FOR_ALL_INTERFACES (pim
->vrf
, ifp
) {
1038 struct pim_interface
*pim_ifp
;
1039 pim_ifp
= ifp
->info
;
1041 if (vif_index
== pim_ifp
->mroute_vif_index
)
1050 pim_if_add_vif() uses ifindex as vif_index
1052 int pim_if_find_vifindex_by_ifindex(struct pim_instance
*pim
, ifindex_t ifindex
)
1054 struct pim_interface
*pim_ifp
;
1055 struct interface
*ifp
;
1057 ifp
= if_lookup_by_index(ifindex
, pim
->vrf_id
);
1058 if (!ifp
|| !ifp
->info
)
1060 pim_ifp
= ifp
->info
;
1062 return pim_ifp
->mroute_vif_index
;
1065 int pim_if_lan_delay_enabled(struct interface
*ifp
)
1067 struct pim_interface
*pim_ifp
;
1069 pim_ifp
= ifp
->info
;
1071 zassert(pim_ifp
->pim_number_of_nonlandelay_neighbors
>= 0);
1073 return pim_ifp
->pim_number_of_nonlandelay_neighbors
== 0;
1076 uint16_t pim_if_effective_propagation_delay_msec(struct interface
*ifp
)
1078 if (pim_if_lan_delay_enabled(ifp
)) {
1079 struct pim_interface
*pim_ifp
;
1080 pim_ifp
= ifp
->info
;
1081 return pim_ifp
->pim_neighbors_highest_propagation_delay_msec
;
1083 return PIM_DEFAULT_PROPAGATION_DELAY_MSEC
;
1087 uint16_t pim_if_effective_override_interval_msec(struct interface
*ifp
)
1089 if (pim_if_lan_delay_enabled(ifp
)) {
1090 struct pim_interface
*pim_ifp
;
1091 pim_ifp
= ifp
->info
;
1092 return pim_ifp
->pim_neighbors_highest_override_interval_msec
;
1094 return PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC
;
1098 int pim_if_t_override_msec(struct interface
*ifp
)
1100 int effective_override_interval_msec
;
1101 int t_override_msec
;
1103 effective_override_interval_msec
=
1104 pim_if_effective_override_interval_msec(ifp
);
1106 t_override_msec
= random() % (effective_override_interval_msec
+ 1);
1108 return t_override_msec
;
1111 uint16_t pim_if_jp_override_interval_msec(struct interface
*ifp
)
1113 return pim_if_effective_propagation_delay_msec(ifp
)
1114 + pim_if_effective_override_interval_msec(ifp
);
1118 RFC 4601: 4.1.6. State Summarization Macros
1120 The function NBR( I, A ) uses information gathered through PIM Hello
1121 messages to map the IP address A of a directly connected PIM
1122 neighbor router on interface I to the primary IP address of the same
1123 router (Section 4.3.4). The primary IP address of a neighbor is the
1124 address that it uses as the source of its PIM Hello messages.
1126 struct pim_neighbor
*pim_if_find_neighbor(struct interface
*ifp
,
1127 struct in_addr addr
)
1129 struct listnode
*neighnode
;
1130 struct pim_neighbor
*neigh
;
1131 struct pim_interface
*pim_ifp
;
1136 pim_ifp
= ifp
->info
;
1138 zlog_warn("%s: multicast not enabled on interface %s",
1139 __PRETTY_FUNCTION__
, ifp
->name
);
1145 p
.prefixlen
= IPV4_MAX_PREFIXLEN
;
1147 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
, neighnode
,
1150 /* primary address ? */
1151 if (neigh
->source_addr
.s_addr
== addr
.s_addr
)
1154 /* secondary address ? */
1155 if (pim_neighbor_find_secondary(neigh
, &p
))
1159 if (PIM_DEBUG_PIM_TRACE
) {
1160 char addr_str
[INET_ADDRSTRLEN
];
1161 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
1163 "%s: neighbor not found for address %s on interface %s",
1164 __PRETTY_FUNCTION__
, addr_str
, ifp
->name
);
1170 long pim_if_t_suppressed_msec(struct interface
*ifp
)
1172 struct pim_interface
*pim_ifp
;
1173 long t_suppressed_msec
;
1174 uint32_t ramount
= 0;
1176 pim_ifp
= ifp
->info
;
1179 /* join suppression disabled ? */
1180 if (PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp
->options
))
1183 /* t_suppressed = t_periodic * rand(1.1, 1.4) */
1184 ramount
= 1100 + (random() % (1400 - 1100 + 1));
1185 t_suppressed_msec
= qpim_t_periodic
* ramount
;
1187 return t_suppressed_msec
;
1190 static void igmp_join_free(struct igmp_join
*ij
)
1192 XFREE(MTYPE_PIM_IGMP_JOIN
, ij
);
1195 static struct igmp_join
*igmp_join_find(struct list
*join_list
,
1196 struct in_addr group_addr
,
1197 struct in_addr source_addr
)
1199 struct listnode
*node
;
1200 struct igmp_join
*ij
;
1204 for (ALL_LIST_ELEMENTS_RO(join_list
, node
, ij
)) {
1205 if ((group_addr
.s_addr
== ij
->group_addr
.s_addr
)
1206 && (source_addr
.s_addr
== ij
->source_addr
.s_addr
))
1213 static int igmp_join_sock(const char *ifname
, ifindex_t ifindex
,
1214 struct in_addr group_addr
, struct in_addr source_addr
)
1218 join_fd
= pim_socket_raw(IPPROTO_IGMP
);
1223 if (pim_socket_join_source(join_fd
, ifindex
, group_addr
, source_addr
,
1232 static struct igmp_join
*igmp_join_new(struct interface
*ifp
,
1233 struct in_addr group_addr
,
1234 struct in_addr source_addr
)
1236 struct pim_interface
*pim_ifp
;
1237 struct igmp_join
*ij
;
1240 pim_ifp
= ifp
->info
;
1243 join_fd
= igmp_join_sock(ifp
->name
, ifp
->ifindex
, group_addr
,
1246 char group_str
[INET_ADDRSTRLEN
];
1247 char source_str
[INET_ADDRSTRLEN
];
1248 pim_inet4_dump("<grp?>", group_addr
, group_str
,
1250 pim_inet4_dump("<src?>", source_addr
, source_str
,
1251 sizeof(source_str
));
1253 "%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s",
1254 __PRETTY_FUNCTION__
, group_str
, source_str
, ifp
->name
);
1258 ij
= XCALLOC(MTYPE_PIM_IGMP_JOIN
, sizeof(*ij
));
1260 char group_str
[INET_ADDRSTRLEN
];
1261 char source_str
[INET_ADDRSTRLEN
];
1262 pim_inet4_dump("<grp?>", group_addr
, group_str
,
1264 pim_inet4_dump("<src?>", source_addr
, source_str
,
1265 sizeof(source_str
));
1267 "%s: XCALLOC(%zu) failure for IGMP group %s source %s on interface %s",
1268 __PRETTY_FUNCTION__
, sizeof(*ij
), group_str
, source_str
,
1274 ij
->sock_fd
= join_fd
;
1275 ij
->group_addr
= group_addr
;
1276 ij
->source_addr
= source_addr
;
1277 ij
->sock_creation
= pim_time_monotonic_sec();
1279 listnode_add(pim_ifp
->igmp_join_list
, ij
);
1284 ferr_r
pim_if_igmp_join_add(struct interface
*ifp
, struct in_addr group_addr
,
1285 struct in_addr source_addr
)
1287 struct pim_interface
*pim_ifp
;
1288 struct igmp_join
*ij
;
1290 pim_ifp
= ifp
->info
;
1292 return ferr_cfg_invalid("multicast not enabled on interface %s",
1296 if (!pim_ifp
->igmp_join_list
) {
1297 pim_ifp
->igmp_join_list
= list_new();
1298 if (!pim_ifp
->igmp_join_list
) {
1299 return ferr_cfg_invalid("Insufficient memory");
1301 pim_ifp
->igmp_join_list
->del
= (void (*)(void *))igmp_join_free
;
1304 ij
= igmp_join_find(pim_ifp
->igmp_join_list
, group_addr
, source_addr
);
1306 /* This interface has already been configured to join this IGMP group
1312 ij
= igmp_join_new(ifp
, group_addr
, source_addr
);
1314 return ferr_cfg_invalid(
1315 "Failure to create new join data structure, see log file for more information");
1318 if (PIM_DEBUG_IGMP_EVENTS
) {
1319 char group_str
[INET_ADDRSTRLEN
];
1320 char source_str
[INET_ADDRSTRLEN
];
1321 pim_inet4_dump("<grp?>", group_addr
, group_str
,
1323 pim_inet4_dump("<src?>", source_addr
, source_str
,
1324 sizeof(source_str
));
1326 "%s: issued static igmp join for channel (S,G)=(%s,%s) on interface %s",
1327 __PRETTY_FUNCTION__
, source_str
, group_str
, ifp
->name
);
1334 int pim_if_igmp_join_del(struct interface
*ifp
, struct in_addr group_addr
,
1335 struct in_addr source_addr
)
1337 struct pim_interface
*pim_ifp
;
1338 struct igmp_join
*ij
;
1340 pim_ifp
= ifp
->info
;
1342 zlog_warn("%s: multicast not enabled on interface %s",
1343 __PRETTY_FUNCTION__
, ifp
->name
);
1347 if (!pim_ifp
->igmp_join_list
) {
1348 zlog_warn("%s: no IGMP join on interface %s",
1349 __PRETTY_FUNCTION__
, ifp
->name
);
1353 ij
= igmp_join_find(pim_ifp
->igmp_join_list
, group_addr
, source_addr
);
1355 char group_str
[INET_ADDRSTRLEN
];
1356 char source_str
[INET_ADDRSTRLEN
];
1357 pim_inet4_dump("<grp?>", group_addr
, group_str
,
1359 pim_inet4_dump("<src?>", source_addr
, source_str
,
1360 sizeof(source_str
));
1362 "%s: could not find IGMP group %s source %s on interface %s",
1363 __PRETTY_FUNCTION__
, group_str
, source_str
, ifp
->name
);
1367 if (close(ij
->sock_fd
)) {
1368 char group_str
[INET_ADDRSTRLEN
];
1369 char source_str
[INET_ADDRSTRLEN
];
1370 pim_inet4_dump("<grp?>", group_addr
, group_str
,
1372 pim_inet4_dump("<src?>", source_addr
, source_str
,
1373 sizeof(source_str
));
1375 "%s: failure closing sock_fd=%d for IGMP group %s source %s on interface %s: errno=%d: %s",
1376 __PRETTY_FUNCTION__
, ij
->sock_fd
, group_str
, source_str
,
1377 ifp
->name
, errno
, safe_strerror(errno
));
1380 listnode_delete(pim_ifp
->igmp_join_list
, ij
);
1382 if (listcount(pim_ifp
->igmp_join_list
) < 1) {
1383 list_delete_and_null(&pim_ifp
->igmp_join_list
);
1384 pim_ifp
->igmp_join_list
= 0;
1390 static void pim_if_igmp_join_del_all(struct interface
*ifp
)
1392 struct pim_interface
*pim_ifp
;
1393 struct listnode
*node
;
1394 struct listnode
*nextnode
;
1395 struct igmp_join
*ij
;
1397 pim_ifp
= ifp
->info
;
1399 zlog_warn("%s: multicast not enabled on interface %s",
1400 __PRETTY_FUNCTION__
, ifp
->name
);
1404 if (!pim_ifp
->igmp_join_list
)
1407 for (ALL_LIST_ELEMENTS(pim_ifp
->igmp_join_list
, node
, nextnode
, ij
))
1408 pim_if_igmp_join_del(ifp
, ij
->group_addr
, ij
->source_addr
);
1414 Transitions from "I am Assert Loser" State
1416 Current Winner's GenID Changes or NLT Expires
1418 The Neighbor Liveness Timer associated with the current winner
1419 expires or we receive a Hello message from the current winner
1420 reporting a different GenID from the one it previously reported.
1421 This indicates that the current winner's interface or router has
1422 gone down (and may have come back up), and so we must assume it no
1423 longer knows it was the winner.
1425 void pim_if_assert_on_neighbor_down(struct interface
*ifp
,
1426 struct in_addr neigh_addr
)
1428 struct pim_interface
*pim_ifp
;
1429 struct pim_ifchannel
*ch
;
1431 pim_ifp
= ifp
->info
;
1434 RB_FOREACH (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
) {
1435 /* Is (S,G,I) assert loser ? */
1436 if (ch
->ifassert_state
!= PIM_IFASSERT_I_AM_LOSER
)
1438 /* Dead neighbor was winner ? */
1439 if (ch
->ifassert_winner
.s_addr
!= neigh_addr
.s_addr
)
1442 assert_action_a5(ch
);
1446 void pim_if_update_join_desired(struct pim_interface
*pim_ifp
)
1448 struct pim_ifchannel
*ch
;
1450 /* clear off flag from interface's upstreams */
1451 RB_FOREACH (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
) {
1452 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(
1453 ch
->upstream
->flags
);
1456 /* scan per-interface (S,G,I) state on this I interface */
1457 RB_FOREACH (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
) {
1458 struct pim_upstream
*up
= ch
->upstream
;
1460 if (PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(up
->flags
))
1463 /* update join_desired for the global (S,G) state */
1464 pim_upstream_update_join_desired(pim_ifp
->pim
, up
);
1465 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(up
->flags
);
1469 void pim_if_update_assert_tracking_desired(struct interface
*ifp
)
1471 struct pim_interface
*pim_ifp
;
1472 struct pim_ifchannel
*ch
;
1474 pim_ifp
= ifp
->info
;
1478 RB_FOREACH (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
) {
1479 pim_ifchannel_update_assert_tracking_desired(ch
);
1484 * PIM wants to have an interface pointer for everything it does.
1485 * The pimreg is a special interface that we have that is not
1486 * quite an inteface but a VIF is created for it.
1488 void pim_if_create_pimreg(struct pim_instance
*pim
)
1490 char pimreg_name
[INTERFACE_NAMSIZ
];
1492 if (!pim
->regiface
) {
1493 if (pim
->vrf_id
== VRF_DEFAULT
)
1494 strlcpy(pimreg_name
, "pimreg", sizeof(pimreg_name
));
1496 snprintf(pimreg_name
, sizeof(pimreg_name
), "pimreg%u",
1497 pim
->vrf
->data
.l
.table_id
);
1499 pim
->regiface
= if_create(pimreg_name
, pim
->vrf_id
);
1500 pim
->regiface
->ifindex
= PIM_OIF_PIM_REGISTER_VIF
;
1502 pim_if_new(pim
->regiface
, 0, 0);
1506 int pim_if_connected_to_source(struct interface
*ifp
, struct in_addr src
)
1508 struct listnode
*cnode
;
1509 struct connected
*c
;
1517 p
.prefixlen
= IPV4_MAX_BITLEN
;
1519 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, cnode
, c
)) {
1520 if ((c
->address
->family
== AF_INET
)
1521 && prefix_match(CONNECTED_PREFIX(c
), &p
)) {
1529 int pim_if_is_loopback(struct pim_instance
*pim
, struct interface
*ifp
)
1531 if (if_is_loopback(ifp
))
1534 if (strcmp(ifp
->name
, pim
->vrf
->name
) == 0)
1540 int pim_if_is_vrf_device(struct interface
*ifp
)
1544 RB_FOREACH (vrf
, vrf_name_head
, &vrfs_by_name
) {
1545 if (strncmp(ifp
->name
, vrf
->name
, strlen(ifp
->name
)) == 0)
1552 int pim_if_ifchannel_count(struct pim_interface
*pim_ifp
)
1554 struct pim_ifchannel
*ch
;
1557 RB_FOREACH (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
) {