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 struct interface
*ifp
;
67 FOR_ALL_INTERFACES (pim
->vrf
, ifp
) {
68 struct pim_interface
*pim_ifp
= ifp
->info
;
78 static void *if_list_clean(struct pim_interface
*pim_ifp
)
80 struct pim_ifchannel
*ch
;
82 if (pim_ifp
->igmp_join_list
)
83 list_delete_and_null(&pim_ifp
->igmp_join_list
);
85 if (pim_ifp
->igmp_socket_list
)
86 list_delete_and_null(&pim_ifp
->igmp_socket_list
);
88 if (pim_ifp
->pim_neighbor_list
)
89 list_delete_and_null(&pim_ifp
->pim_neighbor_list
);
91 if (pim_ifp
->upstream_switch_list
)
92 list_delete_and_null(&pim_ifp
->upstream_switch_list
);
94 if (pim_ifp
->sec_addr_list
)
95 list_delete_and_null(&pim_ifp
->sec_addr_list
);
97 while (!RB_EMPTY(pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
)) {
98 ch
= RB_ROOT(pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
);
100 pim_ifchannel_delete(ch
);
103 XFREE(MTYPE_PIM_INTERFACE
, pim_ifp
);
108 static void pim_sec_addr_free(struct pim_secondary_addr
*sec_addr
)
110 XFREE(MTYPE_PIM_SEC_ADDR
, sec_addr
);
113 static int pim_sec_addr_comp(const void *p1
, const void *p2
)
115 const struct pim_secondary_addr
*sec1
= p1
;
116 const struct pim_secondary_addr
*sec2
= p2
;
118 if (sec1
->addr
.family
== AF_INET
&& sec2
->addr
.family
== AF_INET6
)
121 if (sec1
->addr
.family
== AF_INET6
&& sec2
->addr
.family
== AF_INET
)
124 if (sec1
->addr
.family
== AF_INET
) {
125 if (ntohl(sec1
->addr
.u
.prefix4
.s_addr
)
126 < ntohl(sec2
->addr
.u
.prefix4
.s_addr
))
129 if (ntohl(sec1
->addr
.u
.prefix4
.s_addr
)
130 > ntohl(sec2
->addr
.u
.prefix4
.s_addr
))
133 return memcmp(&sec1
->addr
.u
.prefix6
, &sec2
->addr
.u
.prefix6
,
134 sizeof(struct in6_addr
));
140 struct pim_interface
*pim_if_new(struct interface
*ifp
, int igmp
, int pim
)
142 struct pim_interface
*pim_ifp
;
147 pim_ifp
= XCALLOC(MTYPE_PIM_INTERFACE
, sizeof(*pim_ifp
));
149 zlog_err("PIM XCALLOC(%zu) failure", sizeof(*pim_ifp
));
153 pim_ifp
->options
= 0;
154 pim_ifp
->pim
= pim_get_pim_instance(ifp
->vrf_id
);
155 pim_ifp
->mroute_vif_index
= -1;
157 pim_ifp
->igmp_version
= IGMP_DEFAULT_VERSION
;
158 pim_ifp
->igmp_default_robustness_variable
=
159 IGMP_DEFAULT_ROBUSTNESS_VARIABLE
;
160 pim_ifp
->igmp_default_query_interval
= IGMP_GENERAL_QUERY_INTERVAL
;
161 pim_ifp
->igmp_query_max_response_time_dsec
=
162 IGMP_QUERY_MAX_RESPONSE_TIME_DSEC
;
163 pim_ifp
->igmp_specific_query_max_response_time_dsec
=
164 IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC
;
167 RFC 3376: 8.3. Query Response Interval
168 The number of seconds represented by the [Query Response Interval]
169 must be less than the [Query Interval].
171 zassert(pim_ifp
->igmp_query_max_response_time_dsec
172 < pim_ifp
->igmp_default_query_interval
);
175 PIM_IF_DO_PIM(pim_ifp
->options
);
177 PIM_IF_DO_IGMP(pim_ifp
->options
);
179 PIM_IF_DO_IGMP_LISTEN_ALLROUTERS(pim_ifp
->options
);
181 pim_ifp
->igmp_join_list
= NULL
;
182 pim_ifp
->igmp_socket_list
= NULL
;
183 pim_ifp
->pim_neighbor_list
= NULL
;
184 pim_ifp
->upstream_switch_list
= NULL
;
185 pim_ifp
->pim_generation_id
= 0;
187 /* list of struct igmp_sock */
188 pim_ifp
->igmp_socket_list
= list_new();
189 if (!pim_ifp
->igmp_socket_list
) {
190 zlog_err("%s: failure: igmp_socket_list=list_new()",
191 __PRETTY_FUNCTION__
);
192 return if_list_clean(pim_ifp
);
194 pim_ifp
->igmp_socket_list
->del
= (void (*)(void *))igmp_sock_free
;
196 /* list of struct pim_neighbor */
197 pim_ifp
->pim_neighbor_list
= list_new();
198 if (!pim_ifp
->pim_neighbor_list
) {
199 zlog_err("%s: failure: pim_neighbor_list=list_new()",
200 __PRETTY_FUNCTION__
);
201 return if_list_clean(pim_ifp
);
203 pim_ifp
->pim_neighbor_list
->del
= (void (*)(void *))pim_neighbor_free
;
205 pim_ifp
->upstream_switch_list
= list_new();
206 if (!pim_ifp
->upstream_switch_list
) {
207 zlog_err("%s: failure: upstream_switch_list=list_new()",
208 __PRETTY_FUNCTION__
);
209 return if_list_clean(pim_ifp
);
211 pim_ifp
->upstream_switch_list
->del
=
212 (void (*)(void *))pim_jp_agg_group_list_free
;
213 pim_ifp
->upstream_switch_list
->cmp
= pim_jp_agg_group_list_cmp
;
215 pim_ifp
->sec_addr_list
= list_new();
216 if (!pim_ifp
->sec_addr_list
) {
217 zlog_err("%s: failure: secondary addresslist",
218 __PRETTY_FUNCTION__
);
219 return if_list_clean(pim_ifp
);
221 pim_ifp
->sec_addr_list
->del
= (void (*)(void *))pim_sec_addr_free
;
222 pim_ifp
->sec_addr_list
->cmp
=
223 (int (*)(void *, void *))pim_sec_addr_comp
;
225 RB_INIT(pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
);
236 void pim_if_delete(struct interface
*ifp
)
238 struct pim_interface
*pim_ifp
;
239 struct pim_ifchannel
*ch
;
245 if (pim_ifp
->igmp_join_list
) {
246 pim_if_igmp_join_del_all(ifp
);
249 pim_ifchannel_delete_all(ifp
);
250 igmp_sock_delete_all(ifp
);
252 pim_neighbor_delete_all(ifp
, "Interface removed from configuration");
256 list_delete_and_null(&pim_ifp
->igmp_socket_list
);
257 list_delete_and_null(&pim_ifp
->pim_neighbor_list
);
258 list_delete_and_null(&pim_ifp
->upstream_switch_list
);
259 list_delete_and_null(&pim_ifp
->sec_addr_list
);
261 if (pim_ifp
->boundary_oil_plist
)
262 XFREE(MTYPE_PIM_INTERFACE
, pim_ifp
->boundary_oil_plist
);
264 while (!RB_EMPTY(pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
)) {
265 ch
= RB_ROOT(pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
);
267 pim_ifchannel_delete(ch
);
270 XFREE(MTYPE_PIM_INTERFACE
, pim_ifp
);
275 void pim_if_update_could_assert(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_could_assert(ch
);
288 static void pim_if_update_my_assert_metric(struct interface
*ifp
)
290 struct pim_interface
*pim_ifp
;
291 struct pim_ifchannel
*ch
;
296 RB_FOREACH (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
) {
297 pim_ifchannel_update_my_assert_metric(ch
);
301 static void pim_addr_change(struct interface
*ifp
)
303 struct pim_interface
*pim_ifp
;
308 pim_if_dr_election(ifp
); /* router's own DR Priority (addr) changes --
310 pim_if_update_join_desired(pim_ifp
); /* depends on DR */
311 pim_if_update_could_assert(ifp
); /* depends on DR */
312 pim_if_update_my_assert_metric(ifp
); /* depends on could_assert */
313 pim_if_update_assert_tracking_desired(
314 ifp
); /* depends on DR, join_desired */
317 RFC 4601: 4.3.1. Sending Hello Messages
319 1) Before an interface goes down or changes primary IP address, a
320 Hello message with a zero HoldTime should be sent immediately
321 (with the old IP address if the IP address changed).
322 -- FIXME See CAVEAT C13
324 2) After an interface has changed its IP address, it MUST send a
325 Hello message with its new IP address.
328 3) If an interface changes one of its secondary IP addresses, a
329 Hello message with an updated Address_List option and a non-zero
330 HoldTime should be sent immediately.
331 -- FIXME See TODO T31
333 pim_ifp
->pim_ifstat_hello_sent
= 0; /* reset hello counter */
334 if (pim_ifp
->pim_sock_fd
< 0)
336 pim_hello_restart_now(ifp
); /* send hello and restart timer */
339 static int detect_primary_address_change(struct interface
*ifp
,
340 int force_prim_as_any
,
343 struct pim_interface
*pim_ifp
= ifp
->info
;
344 struct in_addr new_prim_addr
;
347 if (force_prim_as_any
)
348 new_prim_addr
.s_addr
= INADDR_ANY
;
350 new_prim_addr
= pim_find_primary_addr(ifp
);
352 changed
= new_prim_addr
.s_addr
!= pim_ifp
->primary_address
.s_addr
;
354 if (PIM_DEBUG_ZEBRA
) {
355 char new_prim_str
[INET_ADDRSTRLEN
];
356 char old_prim_str
[INET_ADDRSTRLEN
];
357 pim_inet4_dump("<new?>", new_prim_addr
, new_prim_str
,
358 sizeof(new_prim_str
));
359 pim_inet4_dump("<old?>", pim_ifp
->primary_address
, old_prim_str
,
360 sizeof(old_prim_str
));
361 zlog_debug("%s: old=%s new=%s on interface %s: %s",
362 __PRETTY_FUNCTION__
, old_prim_str
, new_prim_str
,
363 ifp
->name
, changed
? "changed" : "unchanged");
367 pim_ifp
->primary_address
= new_prim_addr
;
373 static struct pim_secondary_addr
*
374 pim_sec_addr_find(struct pim_interface
*pim_ifp
, struct prefix
*addr
)
376 struct pim_secondary_addr
*sec_addr
;
377 struct listnode
*node
;
379 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->sec_addr_list
, node
, sec_addr
)) {
380 if (prefix_cmp(&sec_addr
->addr
, addr
)) {
388 static void pim_sec_addr_del(struct pim_interface
*pim_ifp
,
389 struct pim_secondary_addr
*sec_addr
)
391 listnode_delete(pim_ifp
->sec_addr_list
, sec_addr
);
392 pim_sec_addr_free(sec_addr
);
395 static int pim_sec_addr_add(struct pim_interface
*pim_ifp
, struct prefix
*addr
)
398 struct pim_secondary_addr
*sec_addr
;
400 sec_addr
= pim_sec_addr_find(pim_ifp
, addr
);
402 sec_addr
->flags
&= ~PIM_SEC_ADDRF_STALE
;
406 sec_addr
= XCALLOC(MTYPE_PIM_SEC_ADDR
, sizeof(*sec_addr
));
411 sec_addr
->addr
= *addr
;
412 listnode_add_sort(pim_ifp
->sec_addr_list
, sec_addr
);
417 static int pim_sec_addr_del_all(struct pim_interface
*pim_ifp
)
421 if (!list_isempty(pim_ifp
->sec_addr_list
)) {
423 /* remove all nodes and free up the list itself */
424 list_delete_all_node(pim_ifp
->sec_addr_list
);
430 static int pim_sec_addr_update(struct interface
*ifp
)
432 struct pim_interface
*pim_ifp
= ifp
->info
;
433 struct connected
*ifc
;
434 struct listnode
*node
;
435 struct listnode
*nextnode
;
436 struct pim_secondary_addr
*sec_addr
;
439 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->sec_addr_list
, node
, sec_addr
)) {
440 sec_addr
->flags
|= PIM_SEC_ADDRF_STALE
;
443 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, ifc
)) {
444 struct prefix
*p
= ifc
->address
;
446 if (PIM_INADDR_IS_ANY(p
->u
.prefix4
)) {
450 if (pim_ifp
->primary_address
.s_addr
== p
->u
.prefix4
.s_addr
) {
451 /* don't add the primary address into the secondary
456 if (pim_sec_addr_add(pim_ifp
, p
)) {
461 /* Drop stale entries */
462 for (ALL_LIST_ELEMENTS(pim_ifp
->sec_addr_list
, node
, nextnode
,
464 if (sec_addr
->flags
& PIM_SEC_ADDRF_STALE
) {
465 pim_sec_addr_del(pim_ifp
, sec_addr
);
473 static int detect_secondary_address_change(struct interface
*ifp
,
474 int force_prim_as_any
,
477 struct pim_interface
*pim_ifp
= ifp
->info
;
480 if (force_prim_as_any
) {
481 /* if primary address is being forced to zero just flush the
482 * secondary address list */
483 changed
= pim_sec_addr_del_all(pim_ifp
);
485 /* re-evaluate the secondary address list */
486 changed
= pim_sec_addr_update(ifp
);
492 static void detect_address_change(struct interface
*ifp
, int force_prim_as_any
,
496 struct pim_interface
*pim_ifp
;
502 if (detect_primary_address_change(ifp
, force_prim_as_any
, caller
)) {
506 if (detect_secondary_address_change(ifp
, force_prim_as_any
, caller
)) {
512 if (!PIM_IF_TEST_PIM(pim_ifp
->options
)) {
516 pim_addr_change(ifp
);
519 /* XXX: if we have unnumbered interfaces we need to run detect address
520 * address change on all of them when the lo address changes */
523 int pim_update_source_set(struct interface
*ifp
, struct in_addr source
)
525 struct pim_interface
*pim_ifp
= ifp
->info
;
528 return PIM_IFACE_NOT_FOUND
;
531 if (pim_ifp
->update_source
.s_addr
== source
.s_addr
) {
532 return PIM_UPDATE_SOURCE_DUP
;
535 pim_ifp
->update_source
= source
;
536 detect_address_change(ifp
, 0 /* force_prim_as_any */,
537 __PRETTY_FUNCTION__
);
542 void pim_if_addr_add(struct connected
*ifc
)
544 struct pim_interface
*pim_ifp
;
545 struct interface
*ifp
;
546 struct in_addr ifaddr
;
556 if (!if_is_operative(ifp
))
559 if (PIM_DEBUG_ZEBRA
) {
561 prefix2str(ifc
->address
, buf
, BUFSIZ
);
562 zlog_debug("%s: %s ifindex=%d connected IP address %s %s",
563 __PRETTY_FUNCTION__
, ifp
->name
, ifp
->ifindex
, buf
,
564 CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
)
569 ifaddr
= ifc
->address
->u
.prefix4
;
571 detect_address_change(ifp
, 0, __PRETTY_FUNCTION__
);
573 // if (ifc->address->family != AF_INET)
576 if (PIM_IF_TEST_IGMP(pim_ifp
->options
)) {
577 struct igmp_sock
*igmp
;
579 /* lookup IGMP socket */
580 igmp
= pim_igmp_sock_lookup_ifaddr(pim_ifp
->igmp_socket_list
,
583 /* if addr new, add IGMP socket */
584 if (ifc
->address
->family
== AF_INET
)
585 pim_igmp_sock_add(pim_ifp
->igmp_socket_list
,
587 } else if (igmp
->mtrace_only
) {
588 igmp_sock_delete(igmp
);
589 pim_igmp_sock_add(pim_ifp
->igmp_socket_list
, ifaddr
,
593 /* Replay Static IGMP groups */
594 if (pim_ifp
->igmp_join_list
) {
595 struct listnode
*node
;
596 struct listnode
*nextnode
;
597 struct igmp_join
*ij
;
600 for (ALL_LIST_ELEMENTS(pim_ifp
->igmp_join_list
, node
,
602 /* Close socket and reopen with Source and Group
605 join_fd
= igmp_join_sock(
606 ifp
->name
, ifp
->ifindex
, ij
->group_addr
,
609 char group_str
[INET_ADDRSTRLEN
];
610 char source_str
[INET_ADDRSTRLEN
];
611 pim_inet4_dump("<grp?>", ij
->group_addr
,
615 "<src?>", ij
->source_addr
,
616 source_str
, sizeof(source_str
));
618 "%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s",
619 __PRETTY_FUNCTION__
, group_str
,
620 source_str
, ifp
->name
);
623 ij
->sock_fd
= join_fd
;
628 struct igmp_sock
*igmp
;
630 /* lookup IGMP socket */
631 igmp
= pim_igmp_sock_lookup_ifaddr(pim_ifp
->igmp_socket_list
,
633 if (ifc
->address
->family
== AF_INET
) {
635 igmp_sock_delete(igmp
);
636 /* if addr new, add IGMP socket */
637 pim_igmp_sock_add(pim_ifp
->igmp_socket_list
, ifaddr
,
640 } /* igmp mtrace only */
642 if (PIM_IF_TEST_PIM(pim_ifp
->options
)) {
644 if (PIM_INADDR_ISNOT_ANY(pim_ifp
->primary_address
)) {
646 /* Interface has a valid socket ? */
647 if (pim_ifp
->pim_sock_fd
< 0) {
648 if (pim_sock_add(ifp
)) {
650 "Failure creating PIM socket for interface %s",
654 struct pim_nexthop_cache
*pnc
= NULL
;
656 struct zclient
*zclient
= NULL
;
658 zclient
= pim_zebra_zclient_get();
659 /* RP config might come prior to (local RP's interface)
661 In this case, pnc would not have pim enabled
663 Once Interface is UP and pim info is available,
665 with RNH address to receive update and add the
666 interface as nexthop. */
667 memset(&rpf
, 0, sizeof(struct pim_rpf
));
668 rpf
.rpf_addr
.family
= AF_INET
;
669 rpf
.rpf_addr
.prefixlen
= IPV4_MAX_BITLEN
;
670 rpf
.rpf_addr
.u
.prefix4
= ifc
->address
->u
.prefix4
;
671 pnc
= pim_nexthop_cache_find(pim_ifp
->pim
, &rpf
);
673 pim_sendmsg_zebra_rnh(pim_ifp
->pim
, zclient
,
675 ZEBRA_NEXTHOP_REGISTER
);
680 PIM or IGMP is enabled on interface, and there is at least one
681 address assigned, then try to create a vif_index.
683 if (pim_ifp
->mroute_vif_index
< 0) {
686 pim_ifchannel_scan_forward_start(ifp
);
689 static void pim_if_addr_del_igmp(struct connected
*ifc
)
691 struct pim_interface
*pim_ifp
= ifc
->ifp
->info
;
692 struct igmp_sock
*igmp
;
693 struct in_addr ifaddr
;
695 if (ifc
->address
->family
!= AF_INET
) {
696 /* non-IPv4 address */
701 /* IGMP not enabled on interface */
705 ifaddr
= ifc
->address
->u
.prefix4
;
707 /* lookup IGMP socket */
708 igmp
= pim_igmp_sock_lookup_ifaddr(pim_ifp
->igmp_socket_list
, ifaddr
);
710 /* if addr found, del IGMP socket */
711 igmp_sock_delete(igmp
);
715 static void pim_if_addr_del_pim(struct connected
*ifc
)
717 struct pim_interface
*pim_ifp
= ifc
->ifp
->info
;
719 if (ifc
->address
->family
!= AF_INET
) {
720 /* non-IPv4 address */
725 /* PIM not enabled on interface */
729 if (PIM_INADDR_ISNOT_ANY(pim_ifp
->primary_address
)) {
730 /* Interface keeps a valid primary address */
734 if (pim_ifp
->pim_sock_fd
< 0) {
735 /* Interface does not hold a valid socket any longer */
740 pim_sock_delete() closes the socket, stops read and timer threads,
741 and kills all neighbors.
743 pim_sock_delete(ifc
->ifp
,
744 "last address has been removed from interface");
747 void pim_if_addr_del(struct connected
*ifc
, int force_prim_as_any
)
749 struct interface
*ifp
;
755 if (PIM_DEBUG_ZEBRA
) {
757 prefix2str(ifc
->address
, buf
, BUFSIZ
);
758 zlog_debug("%s: %s ifindex=%d disconnected IP address %s %s",
759 __PRETTY_FUNCTION__
, ifp
->name
, ifp
->ifindex
, buf
,
760 CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
)
765 detect_address_change(ifp
, force_prim_as_any
, __PRETTY_FUNCTION__
);
767 pim_if_addr_del_igmp(ifc
);
768 pim_if_addr_del_pim(ifc
);
771 void pim_if_addr_add_all(struct interface
*ifp
)
773 struct connected
*ifc
;
774 struct listnode
*node
;
775 struct listnode
*nextnode
;
778 struct pim_interface
*pim_ifp
= ifp
->info
;
781 /* PIM/IGMP enabled ? */
785 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
786 struct prefix
*p
= ifc
->address
;
788 if (p
->family
!= AF_INET
)
792 pim_if_addr_add(ifc
);
795 if (!v4_addrs
&& v6_addrs
&& !if_is_loopback(ifp
)) {
796 if (PIM_IF_TEST_PIM(pim_ifp
->options
)) {
798 /* Interface has a valid primary address ? */
799 if (PIM_INADDR_ISNOT_ANY(pim_ifp
->primary_address
)) {
801 /* Interface has a valid socket ? */
802 if (pim_ifp
->pim_sock_fd
< 0) {
803 if (pim_sock_add(ifp
)) {
805 "Failure creating PIM socket for interface %s",
813 * PIM or IGMP is enabled on interface, and there is at least one
814 * address assigned, then try to create a vif_index.
816 if (pim_ifp
->mroute_vif_index
< 0) {
819 pim_ifchannel_scan_forward_start(ifp
);
821 pim_rp_setup(pim_ifp
->pim
);
822 pim_rp_check_on_if_add(pim_ifp
);
825 void pim_if_addr_del_all(struct interface
*ifp
)
827 struct connected
*ifc
;
828 struct listnode
*node
;
829 struct listnode
*nextnode
;
830 struct vrf
*vrf
= vrf_lookup_by_id(ifp
->vrf_id
);
831 struct pim_instance
*pim
;
837 /* PIM/IGMP enabled ? */
841 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
842 struct prefix
*p
= ifc
->address
;
844 if (p
->family
!= AF_INET
)
847 pim_if_addr_del(ifc
, 1 /* force_prim_as_any=true */);
851 pim_i_am_rp_re_evaluate(pim
);
854 void pim_if_addr_del_all_igmp(struct interface
*ifp
)
856 struct connected
*ifc
;
857 struct listnode
*node
;
858 struct listnode
*nextnode
;
860 /* PIM/IGMP enabled ? */
864 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
865 struct prefix
*p
= ifc
->address
;
867 if (p
->family
!= AF_INET
)
870 pim_if_addr_del_igmp(ifc
);
874 void pim_if_addr_del_all_pim(struct interface
*ifp
)
876 struct connected
*ifc
;
877 struct listnode
*node
;
878 struct listnode
*nextnode
;
880 /* PIM/IGMP enabled ? */
884 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
885 struct prefix
*p
= ifc
->address
;
887 if (p
->family
!= AF_INET
)
890 pim_if_addr_del_pim(ifc
);
894 struct in_addr
pim_find_primary_addr(struct interface
*ifp
)
896 struct connected
*ifc
;
897 struct listnode
*node
;
898 struct in_addr addr
= {0};
901 struct pim_interface
*pim_ifp
= ifp
->info
;
902 struct vrf
*vrf
= vrf_lookup_by_id(ifp
->vrf_id
);
907 if (pim_ifp
&& PIM_INADDR_ISNOT_ANY(pim_ifp
->update_source
)) {
908 return pim_ifp
->update_source
;
911 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, ifc
)) {
912 struct prefix
*p
= ifc
->address
;
914 if (p
->family
!= AF_INET
) {
919 if (PIM_INADDR_IS_ANY(p
->u
.prefix4
)) {
921 "%s: null IPv4 address connected to interface %s",
922 __PRETTY_FUNCTION__
, ifp
->name
);
928 if (CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
))
935 * If we have no v4_addrs and v6 is configured
936 * We probably are using unnumbered
937 * So let's grab the loopbacks v4 address
938 * and use that as the primary address
940 if (!v4_addrs
&& v6_addrs
&& !if_is_loopback(ifp
)) {
941 struct interface
*lo_ifp
;
942 // DBS - Come back and check here
943 if (ifp
->vrf_id
== VRF_DEFAULT
)
944 lo_ifp
= if_lookup_by_name("lo", vrf
->vrf_id
);
946 lo_ifp
= if_lookup_by_name(vrf
->name
, vrf
->vrf_id
);
949 return pim_find_primary_addr(lo_ifp
);
952 addr
.s_addr
= PIM_NET_INADDR_ANY
;
957 static int pim_iface_next_vif_index(struct interface
*ifp
)
959 struct pim_interface
*pim_ifp
= ifp
->info
;
960 struct pim_instance
*pim
= pim_ifp
->pim
;
964 * The pimreg vif is always going to be in index 0
967 if (ifp
->ifindex
== PIM_OIF_PIM_REGISTER_VIF
)
970 for (i
= 1; i
< MAXVIFS
; i
++) {
971 if (pim
->iface_vif_index
[i
] == 0)
978 pim_if_add_vif() uses ifindex as vif_index
980 see also pim_if_find_vifindex_by_ifindex()
982 int pim_if_add_vif(struct interface
*ifp
)
984 struct pim_interface
*pim_ifp
= ifp
->info
;
985 struct in_addr ifaddr
;
986 unsigned char flags
= 0;
990 if (pim_ifp
->mroute_vif_index
> 0) {
991 zlog_warn("%s: vif_index=%d > 0 on interface %s ifindex=%d",
992 __PRETTY_FUNCTION__
, pim_ifp
->mroute_vif_index
,
993 ifp
->name
, ifp
->ifindex
);
997 if (ifp
->ifindex
< 0) {
998 zlog_warn("%s: ifindex=%d < 1 on interface %s",
999 __PRETTY_FUNCTION__
, ifp
->ifindex
, ifp
->name
);
1003 ifaddr
= pim_ifp
->primary_address
;
1004 if (ifp
->ifindex
!= PIM_OIF_PIM_REGISTER_VIF
1005 && PIM_INADDR_IS_ANY(ifaddr
)) {
1007 "%s: could not get address for interface %s ifindex=%d",
1008 __PRETTY_FUNCTION__
, ifp
->name
, ifp
->ifindex
);
1012 pim_ifp
->mroute_vif_index
= pim_iface_next_vif_index(ifp
);
1014 if (pim_ifp
->mroute_vif_index
>= MAXVIFS
) {
1016 "%s: Attempting to configure more than MAXVIFS=%d on pim enabled interface %s",
1017 __PRETTY_FUNCTION__
, MAXVIFS
, ifp
->name
);
1021 if (ifp
->ifindex
== PIM_OIF_PIM_REGISTER_VIF
)
1022 flags
= VIFF_REGISTER
;
1023 #ifdef VIFF_USE_IFINDEX
1025 flags
= VIFF_USE_IFINDEX
;
1028 if (pim_mroute_add_vif(ifp
, ifaddr
, flags
)) {
1029 /* pim_mroute_add_vif reported error */
1033 pim_ifp
->pim
->iface_vif_index
[pim_ifp
->mroute_vif_index
] = 1;
1037 int pim_if_del_vif(struct interface
*ifp
)
1039 struct pim_interface
*pim_ifp
= ifp
->info
;
1041 if (pim_ifp
->mroute_vif_index
< 1) {
1042 zlog_warn("%s: vif_index=%d < 1 on interface %s ifindex=%d",
1043 __PRETTY_FUNCTION__
, pim_ifp
->mroute_vif_index
,
1044 ifp
->name
, ifp
->ifindex
);
1048 pim_mroute_del_vif(ifp
);
1053 pim_ifp
->pim
->iface_vif_index
[pim_ifp
->mroute_vif_index
] = 0;
1055 pim_ifp
->mroute_vif_index
= -1;
1061 struct interface
*pim_if_find_by_vif_index(struct pim_instance
*pim
,
1062 ifindex_t vif_index
)
1064 struct interface
*ifp
;
1066 FOR_ALL_INTERFACES (pim
->vrf
, ifp
) {
1068 struct pim_interface
*pim_ifp
;
1069 pim_ifp
= ifp
->info
;
1071 if (vif_index
== pim_ifp
->mroute_vif_index
)
1080 pim_if_add_vif() uses ifindex as vif_index
1082 int pim_if_find_vifindex_by_ifindex(struct pim_instance
*pim
, ifindex_t ifindex
)
1084 struct pim_interface
*pim_ifp
;
1085 struct interface
*ifp
;
1087 ifp
= if_lookup_by_index(ifindex
, pim
->vrf_id
);
1088 if (!ifp
|| !ifp
->info
)
1090 pim_ifp
= ifp
->info
;
1092 return pim_ifp
->mroute_vif_index
;
1095 int pim_if_lan_delay_enabled(struct interface
*ifp
)
1097 struct pim_interface
*pim_ifp
;
1099 pim_ifp
= ifp
->info
;
1101 zassert(pim_ifp
->pim_number_of_nonlandelay_neighbors
>= 0);
1103 return pim_ifp
->pim_number_of_nonlandelay_neighbors
== 0;
1106 uint16_t pim_if_effective_propagation_delay_msec(struct interface
*ifp
)
1108 if (pim_if_lan_delay_enabled(ifp
)) {
1109 struct pim_interface
*pim_ifp
;
1110 pim_ifp
= ifp
->info
;
1111 return pim_ifp
->pim_neighbors_highest_propagation_delay_msec
;
1113 return PIM_DEFAULT_PROPAGATION_DELAY_MSEC
;
1117 uint16_t pim_if_effective_override_interval_msec(struct interface
*ifp
)
1119 if (pim_if_lan_delay_enabled(ifp
)) {
1120 struct pim_interface
*pim_ifp
;
1121 pim_ifp
= ifp
->info
;
1122 return pim_ifp
->pim_neighbors_highest_override_interval_msec
;
1124 return PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC
;
1128 int pim_if_t_override_msec(struct interface
*ifp
)
1130 int effective_override_interval_msec
;
1131 int t_override_msec
;
1133 effective_override_interval_msec
=
1134 pim_if_effective_override_interval_msec(ifp
);
1136 t_override_msec
= random() % (effective_override_interval_msec
+ 1);
1138 return t_override_msec
;
1141 uint16_t pim_if_jp_override_interval_msec(struct interface
*ifp
)
1143 return pim_if_effective_propagation_delay_msec(ifp
)
1144 + pim_if_effective_override_interval_msec(ifp
);
1148 RFC 4601: 4.1.6. State Summarization Macros
1150 The function NBR( I, A ) uses information gathered through PIM Hello
1151 messages to map the IP address A of a directly connected PIM
1152 neighbor router on interface I to the primary IP address of the same
1153 router (Section 4.3.4). The primary IP address of a neighbor is the
1154 address that it uses as the source of its PIM Hello messages.
1156 struct pim_neighbor
*pim_if_find_neighbor(struct interface
*ifp
,
1157 struct in_addr addr
)
1159 struct listnode
*neighnode
;
1160 struct pim_neighbor
*neigh
;
1161 struct pim_interface
*pim_ifp
;
1166 pim_ifp
= ifp
->info
;
1168 zlog_warn("%s: multicast not enabled on interface %s",
1169 __PRETTY_FUNCTION__
, ifp
->name
);
1175 p
.prefixlen
= IPV4_MAX_PREFIXLEN
;
1177 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
, neighnode
,
1180 /* primary address ? */
1181 if (neigh
->source_addr
.s_addr
== addr
.s_addr
)
1184 /* secondary address ? */
1185 if (pim_neighbor_find_secondary(neigh
, &p
))
1189 if (PIM_DEBUG_PIM_TRACE
) {
1190 char addr_str
[INET_ADDRSTRLEN
];
1191 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
1193 "%s: neighbor not found for address %s on interface %s",
1194 __PRETTY_FUNCTION__
, addr_str
, ifp
->name
);
1200 long pim_if_t_suppressed_msec(struct interface
*ifp
)
1202 struct pim_interface
*pim_ifp
;
1203 long t_suppressed_msec
;
1204 uint32_t ramount
= 0;
1206 pim_ifp
= ifp
->info
;
1209 /* join suppression disabled ? */
1210 if (PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp
->options
))
1213 /* t_suppressed = t_periodic * rand(1.1, 1.4) */
1214 ramount
= 1100 + (random() % (1400 - 1100 + 1));
1215 t_suppressed_msec
= qpim_t_periodic
* ramount
;
1217 return t_suppressed_msec
;
1220 static void igmp_join_free(struct igmp_join
*ij
)
1222 XFREE(MTYPE_PIM_IGMP_JOIN
, ij
);
1225 static struct igmp_join
*igmp_join_find(struct list
*join_list
,
1226 struct in_addr group_addr
,
1227 struct in_addr source_addr
)
1229 struct listnode
*node
;
1230 struct igmp_join
*ij
;
1234 for (ALL_LIST_ELEMENTS_RO(join_list
, node
, ij
)) {
1235 if ((group_addr
.s_addr
== ij
->group_addr
.s_addr
)
1236 && (source_addr
.s_addr
== ij
->source_addr
.s_addr
))
1243 static int igmp_join_sock(const char *ifname
, ifindex_t ifindex
,
1244 struct in_addr group_addr
, struct in_addr source_addr
)
1248 join_fd
= pim_socket_raw(IPPROTO_IGMP
);
1253 if (pim_socket_join_source(join_fd
, ifindex
, group_addr
, source_addr
,
1262 static struct igmp_join
*igmp_join_new(struct interface
*ifp
,
1263 struct in_addr group_addr
,
1264 struct in_addr source_addr
)
1266 struct pim_interface
*pim_ifp
;
1267 struct igmp_join
*ij
;
1270 pim_ifp
= ifp
->info
;
1273 join_fd
= igmp_join_sock(ifp
->name
, ifp
->ifindex
, group_addr
,
1276 char group_str
[INET_ADDRSTRLEN
];
1277 char source_str
[INET_ADDRSTRLEN
];
1278 pim_inet4_dump("<grp?>", group_addr
, group_str
,
1280 pim_inet4_dump("<src?>", source_addr
, source_str
,
1281 sizeof(source_str
));
1283 "%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s",
1284 __PRETTY_FUNCTION__
, group_str
, source_str
, ifp
->name
);
1288 ij
= XCALLOC(MTYPE_PIM_IGMP_JOIN
, sizeof(*ij
));
1290 char group_str
[INET_ADDRSTRLEN
];
1291 char source_str
[INET_ADDRSTRLEN
];
1292 pim_inet4_dump("<grp?>", group_addr
, group_str
,
1294 pim_inet4_dump("<src?>", source_addr
, source_str
,
1295 sizeof(source_str
));
1297 "%s: XCALLOC(%zu) failure for IGMP group %s source %s on interface %s",
1298 __PRETTY_FUNCTION__
, sizeof(*ij
), group_str
, source_str
,
1304 ij
->sock_fd
= join_fd
;
1305 ij
->group_addr
= group_addr
;
1306 ij
->source_addr
= source_addr
;
1307 ij
->sock_creation
= pim_time_monotonic_sec();
1309 listnode_add(pim_ifp
->igmp_join_list
, ij
);
1314 ferr_r
pim_if_igmp_join_add(struct interface
*ifp
, struct in_addr group_addr
,
1315 struct in_addr source_addr
)
1317 struct pim_interface
*pim_ifp
;
1318 struct igmp_join
*ij
;
1320 pim_ifp
= ifp
->info
;
1322 return ferr_cfg_invalid("multicast not enabled on interface %s",
1326 if (!pim_ifp
->igmp_join_list
) {
1327 pim_ifp
->igmp_join_list
= list_new();
1328 if (!pim_ifp
->igmp_join_list
) {
1329 return ferr_cfg_invalid("Insufficient memory");
1331 pim_ifp
->igmp_join_list
->del
= (void (*)(void *))igmp_join_free
;
1334 ij
= igmp_join_find(pim_ifp
->igmp_join_list
, group_addr
, source_addr
);
1336 /* This interface has already been configured to join this IGMP group
1342 ij
= igmp_join_new(ifp
, group_addr
, source_addr
);
1344 return ferr_cfg_invalid(
1345 "Failure to create new join data structure, see log file for more information");
1348 if (PIM_DEBUG_IGMP_EVENTS
) {
1349 char group_str
[INET_ADDRSTRLEN
];
1350 char source_str
[INET_ADDRSTRLEN
];
1351 pim_inet4_dump("<grp?>", group_addr
, group_str
,
1353 pim_inet4_dump("<src?>", source_addr
, source_str
,
1354 sizeof(source_str
));
1356 "%s: issued static igmp join for channel (S,G)=(%s,%s) on interface %s",
1357 __PRETTY_FUNCTION__
, source_str
, group_str
, ifp
->name
);
1364 int pim_if_igmp_join_del(struct interface
*ifp
, struct in_addr group_addr
,
1365 struct in_addr source_addr
)
1367 struct pim_interface
*pim_ifp
;
1368 struct igmp_join
*ij
;
1370 pim_ifp
= ifp
->info
;
1372 zlog_warn("%s: multicast not enabled on interface %s",
1373 __PRETTY_FUNCTION__
, ifp
->name
);
1377 if (!pim_ifp
->igmp_join_list
) {
1378 zlog_warn("%s: no IGMP join on interface %s",
1379 __PRETTY_FUNCTION__
, ifp
->name
);
1383 ij
= igmp_join_find(pim_ifp
->igmp_join_list
, group_addr
, source_addr
);
1385 char group_str
[INET_ADDRSTRLEN
];
1386 char source_str
[INET_ADDRSTRLEN
];
1387 pim_inet4_dump("<grp?>", group_addr
, group_str
,
1389 pim_inet4_dump("<src?>", source_addr
, source_str
,
1390 sizeof(source_str
));
1392 "%s: could not find IGMP group %s source %s on interface %s",
1393 __PRETTY_FUNCTION__
, group_str
, source_str
, ifp
->name
);
1397 if (close(ij
->sock_fd
)) {
1398 char group_str
[INET_ADDRSTRLEN
];
1399 char source_str
[INET_ADDRSTRLEN
];
1400 pim_inet4_dump("<grp?>", group_addr
, group_str
,
1402 pim_inet4_dump("<src?>", source_addr
, source_str
,
1403 sizeof(source_str
));
1405 "%s: failure closing sock_fd=%d for IGMP group %s source %s on interface %s: errno=%d: %s",
1406 __PRETTY_FUNCTION__
, ij
->sock_fd
, group_str
, source_str
,
1407 ifp
->name
, errno
, safe_strerror(errno
));
1410 listnode_delete(pim_ifp
->igmp_join_list
, ij
);
1412 if (listcount(pim_ifp
->igmp_join_list
) < 1) {
1413 list_delete_and_null(&pim_ifp
->igmp_join_list
);
1414 pim_ifp
->igmp_join_list
= 0;
1420 static void pim_if_igmp_join_del_all(struct interface
*ifp
)
1422 struct pim_interface
*pim_ifp
;
1423 struct listnode
*node
;
1424 struct listnode
*nextnode
;
1425 struct igmp_join
*ij
;
1427 pim_ifp
= ifp
->info
;
1429 zlog_warn("%s: multicast not enabled on interface %s",
1430 __PRETTY_FUNCTION__
, ifp
->name
);
1434 if (!pim_ifp
->igmp_join_list
)
1437 for (ALL_LIST_ELEMENTS(pim_ifp
->igmp_join_list
, node
, nextnode
, ij
))
1438 pim_if_igmp_join_del(ifp
, ij
->group_addr
, ij
->source_addr
);
1444 Transitions from "I am Assert Loser" State
1446 Current Winner's GenID Changes or NLT Expires
1448 The Neighbor Liveness Timer associated with the current winner
1449 expires or we receive a Hello message from the current winner
1450 reporting a different GenID from the one it previously reported.
1451 This indicates that the current winner's interface or router has
1452 gone down (and may have come back up), and so we must assume it no
1453 longer knows it was the winner.
1455 void pim_if_assert_on_neighbor_down(struct interface
*ifp
,
1456 struct in_addr neigh_addr
)
1458 struct pim_interface
*pim_ifp
;
1459 struct pim_ifchannel
*ch
;
1461 pim_ifp
= ifp
->info
;
1464 RB_FOREACH (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
) {
1465 /* Is (S,G,I) assert loser ? */
1466 if (ch
->ifassert_state
!= PIM_IFASSERT_I_AM_LOSER
)
1468 /* Dead neighbor was winner ? */
1469 if (ch
->ifassert_winner
.s_addr
!= neigh_addr
.s_addr
)
1472 assert_action_a5(ch
);
1476 void pim_if_update_join_desired(struct pim_interface
*pim_ifp
)
1478 struct pim_ifchannel
*ch
;
1480 /* clear off flag from interface's upstreams */
1481 RB_FOREACH (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
) {
1482 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(
1483 ch
->upstream
->flags
);
1486 /* scan per-interface (S,G,I) state on this I interface */
1487 RB_FOREACH (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
) {
1488 struct pim_upstream
*up
= ch
->upstream
;
1490 if (PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(up
->flags
))
1493 /* update join_desired for the global (S,G) state */
1494 pim_upstream_update_join_desired(pim_ifp
->pim
, up
);
1495 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(up
->flags
);
1499 void pim_if_update_assert_tracking_desired(struct interface
*ifp
)
1501 struct pim_interface
*pim_ifp
;
1502 struct pim_ifchannel
*ch
;
1504 pim_ifp
= ifp
->info
;
1508 RB_FOREACH (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
) {
1509 pim_ifchannel_update_assert_tracking_desired(ch
);
1514 * PIM wants to have an interface pointer for everything it does.
1515 * The pimreg is a special interface that we have that is not
1516 * quite an inteface but a VIF is created for it.
1518 void pim_if_create_pimreg(struct pim_instance
*pim
)
1520 char pimreg_name
[INTERFACE_NAMSIZ
];
1522 if (!pim
->regiface
) {
1523 if (pim
->vrf_id
== VRF_DEFAULT
)
1524 strlcpy(pimreg_name
, "pimreg", sizeof(pimreg_name
));
1526 snprintf(pimreg_name
, sizeof(pimreg_name
), "pimreg%u",
1527 pim
->vrf
->data
.l
.table_id
);
1529 pim
->regiface
= if_create(pimreg_name
, pim
->vrf_id
);
1530 pim
->regiface
->ifindex
= PIM_OIF_PIM_REGISTER_VIF
;
1532 pim_if_new(pim
->regiface
, 0, 0);
1536 int pim_if_connected_to_source(struct interface
*ifp
, struct in_addr src
)
1538 struct listnode
*cnode
;
1539 struct connected
*c
;
1547 p
.prefixlen
= IPV4_MAX_BITLEN
;
1549 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, cnode
, c
)) {
1550 if ((c
->address
->family
== AF_INET
)
1551 && prefix_match(CONNECTED_PREFIX(c
), &p
)) {
1559 bool pim_if_is_loopback(struct interface
*ifp
)
1561 if (if_is_loopback(ifp
) || if_is_vrf(ifp
))
1567 bool pim_if_is_vrf_device(struct interface
*ifp
)
1575 int pim_if_ifchannel_count(struct pim_interface
*pim_ifp
)
1577 struct pim_ifchannel
*ch
;
1580 RB_FOREACH (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
) {