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
15 along with this program; see the file COPYING; if not, write to the
16 Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
33 #include "pim_iface.h"
35 #include "pim_mroute.h"
39 #include "pim_neighbor.h"
40 #include "pim_ifchannel.h"
43 #include "pim_ssmpingd.h"
46 struct interface
*pim_regiface
= NULL
;
47 struct list
*pim_ifchannel_list
= NULL
;
48 static int pim_iface_vif_index
[MAXVIFS
];
50 static void pim_if_igmp_join_del_all(struct interface
*ifp
);
57 for (i
= 0; i
< MAXVIFS
; i
++)
58 pim_iface_vif_index
[i
] = 0;
60 vrf_iflist_create(VRF_DEFAULT
);
61 pim_ifchannel_list
= list_new();
62 pim_ifchannel_list
->cmp
= (int (*)(void *, void *))pim_ifchannel_compare
;
66 pim_if_terminate (void)
68 if (pim_ifchannel_list
)
69 list_free (pim_ifchannel_list
);
72 static void *if_list_clean(struct pim_interface
*pim_ifp
)
74 if (pim_ifp
->igmp_join_list
) {
75 list_delete(pim_ifp
->igmp_join_list
);
78 if (pim_ifp
->igmp_socket_list
) {
79 list_delete(pim_ifp
->igmp_socket_list
);
82 if (pim_ifp
->pim_neighbor_list
) {
83 list_delete(pim_ifp
->pim_neighbor_list
);
86 if (pim_ifp
->upstream_switch_list
)
87 list_delete(pim_ifp
->upstream_switch_list
);
89 if (pim_ifp
->pim_ifchannel_list
) {
90 list_delete(pim_ifp
->pim_ifchannel_list
);
93 if (pim_ifp
->pim_ifchannel_hash
)
94 hash_free(pim_ifp
->pim_ifchannel_hash
);
96 XFREE(MTYPE_PIM_INTERFACE
, pim_ifp
);
101 struct pim_interface
*pim_if_new(struct interface
*ifp
, int igmp
, int pim
)
103 struct pim_interface
*pim_ifp
;
108 pim_ifp
= XCALLOC(MTYPE_PIM_INTERFACE
, sizeof(*pim_ifp
));
110 zlog_err("PIM XCALLOC(%zu) failure", sizeof(*pim_ifp
));
114 pim_ifp
->options
= 0;
115 pim_ifp
->mroute_vif_index
= -1;
117 pim_ifp
->igmp_version
= IGMP_DEFAULT_VERSION
;
118 pim_ifp
->igmp_default_robustness_variable
= IGMP_DEFAULT_ROBUSTNESS_VARIABLE
;
119 pim_ifp
->igmp_default_query_interval
= IGMP_GENERAL_QUERY_INTERVAL
;
120 pim_ifp
->igmp_query_max_response_time_dsec
= IGMP_QUERY_MAX_RESPONSE_TIME_DSEC
;
121 pim_ifp
->igmp_specific_query_max_response_time_dsec
= IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC
;
124 RFC 3376: 8.3. Query Response Interval
125 The number of seconds represented by the [Query Response Interval]
126 must be less than the [Query Interval].
128 zassert(pim_ifp
->igmp_query_max_response_time_dsec
< pim_ifp
->igmp_default_query_interval
);
131 PIM_IF_DO_PIM(pim_ifp
->options
);
133 PIM_IF_DO_IGMP(pim_ifp
->options
);
135 PIM_IF_DO_IGMP_LISTEN_ALLROUTERS(pim_ifp
->options
);
137 pim_ifp
->igmp_join_list
= NULL
;
138 pim_ifp
->igmp_socket_list
= NULL
;
139 pim_ifp
->pim_neighbor_list
= NULL
;
140 pim_ifp
->upstream_switch_list
= NULL
;
141 pim_ifp
->pim_ifchannel_list
= NULL
;
142 pim_ifp
->pim_ifchannel_hash
= NULL
;
143 pim_ifp
->pim_generation_id
= 0;
145 /* list of struct igmp_sock */
146 pim_ifp
->igmp_socket_list
= list_new();
147 if (!pim_ifp
->igmp_socket_list
) {
148 zlog_err("%s %s: failure: igmp_socket_list=list_new()",
149 __FILE__
, __PRETTY_FUNCTION__
);
150 return if_list_clean(pim_ifp
);
152 pim_ifp
->igmp_socket_list
->del
= (void (*)(void *)) igmp_sock_free
;
154 /* list of struct pim_neighbor */
155 pim_ifp
->pim_neighbor_list
= list_new();
156 if (!pim_ifp
->pim_neighbor_list
) {
157 zlog_err("%s %s: failure: pim_neighbor_list=list_new()",
158 __FILE__
, __PRETTY_FUNCTION__
);
159 return if_list_clean(pim_ifp
);
161 pim_ifp
->pim_neighbor_list
->del
= (void (*)(void *)) pim_neighbor_free
;
163 pim_ifp
->upstream_switch_list
= list_new();
164 if (!pim_ifp
->upstream_switch_list
) {
165 zlog_err("%s %s: failure: upstream_switch_list=list_new()",
166 __FILE__
, __PRETTY_FUNCTION__
);
167 return if_list_clean(pim_ifp
);
170 /* list of struct pim_ifchannel */
171 pim_ifp
->pim_ifchannel_list
= list_new();
172 if (!pim_ifp
->pim_ifchannel_list
) {
173 zlog_err("%s %s: failure: pim_ifchannel_list=list_new()",
174 __FILE__
, __PRETTY_FUNCTION__
);
175 return if_list_clean(pim_ifp
);
177 pim_ifp
->pim_ifchannel_list
->del
= (void (*)(void *)) pim_ifchannel_free
;
178 pim_ifp
->pim_ifchannel_list
->cmp
= (int (*)(void *, void *)) pim_ifchannel_compare
;
180 pim_ifp
->pim_ifchannel_hash
= hash_create (pim_ifchannel_hash_key
,
181 pim_ifchannel_equal
);
187 if (PIM_MROUTE_IS_ENABLED
) {
194 void pim_if_delete(struct interface
*ifp
)
196 struct pim_interface
*pim_ifp
;
202 if (pim_ifp
->igmp_join_list
) {
203 pim_if_igmp_join_del_all(ifp
);
206 pim_ifchannel_delete_all (ifp
);
207 igmp_sock_delete_all (ifp
);
209 pim_neighbor_delete_all (ifp
, "Interface removed from configuration");
211 if (PIM_MROUTE_IS_ENABLED
) {
215 list_delete(pim_ifp
->igmp_socket_list
);
216 list_delete(pim_ifp
->pim_neighbor_list
);
217 list_delete(pim_ifp
->upstream_switch_list
);
218 list_delete(pim_ifp
->pim_ifchannel_list
);
220 hash_free (pim_ifp
->pim_ifchannel_hash
);
222 XFREE(MTYPE_PIM_INTERFACE
, pim_ifp
);
227 void pim_if_update_could_assert(struct interface
*ifp
)
229 struct pim_interface
*pim_ifp
;
230 struct listnode
*node
;
231 struct listnode
*next_node
;
232 struct pim_ifchannel
*ch
;
237 for (ALL_LIST_ELEMENTS(pim_ifp
->pim_ifchannel_list
, node
, next_node
, ch
)) {
238 pim_ifchannel_update_could_assert(ch
);
242 static void pim_if_update_my_assert_metric(struct interface
*ifp
)
244 struct pim_interface
*pim_ifp
;
245 struct listnode
*node
;
246 struct listnode
*next_node
;
247 struct pim_ifchannel
*ch
;
252 for (ALL_LIST_ELEMENTS(pim_ifp
->pim_ifchannel_list
, node
, next_node
, ch
)) {
253 pim_ifchannel_update_my_assert_metric(ch
);
257 static void pim_addr_change(struct interface
*ifp
)
259 struct pim_interface
*pim_ifp
;
264 pim_if_dr_election(ifp
); /* router's own DR Priority (addr) changes -- Done TODO T30 */
265 pim_if_update_join_desired(pim_ifp
); /* depends on DR */
266 pim_if_update_could_assert(ifp
); /* depends on DR */
267 pim_if_update_my_assert_metric(ifp
); /* depends on could_assert */
268 pim_if_update_assert_tracking_desired(ifp
); /* depends on DR, join_desired */
271 RFC 4601: 4.3.1. Sending Hello Messages
273 1) Before an interface goes down or changes primary IP address, a
274 Hello message with a zero HoldTime should be sent immediately
275 (with the old IP address if the IP address changed).
276 -- FIXME See CAVEAT C13
278 2) After an interface has changed its IP address, it MUST send a
279 Hello message with its new IP address.
282 3) If an interface changes one of its secondary IP addresses, a
283 Hello message with an updated Address_List option and a non-zero
284 HoldTime should be sent immediately.
285 -- FIXME See TODO T31
287 pim_ifp
->pim_ifstat_hello_sent
= 0; /* reset hello counter */
288 if (pim_ifp
->pim_sock_fd
< 0)
290 pim_hello_restart_now(ifp
); /* send hello and restart timer */
293 static int detect_primary_address_change(struct interface
*ifp
,
294 int force_prim_as_any
,
297 struct pim_interface
*pim_ifp
= ifp
->info
;
298 struct in_addr new_prim_addr
;
301 if (force_prim_as_any
)
302 new_prim_addr
= qpim_inaddr_any
;
304 new_prim_addr
= pim_find_primary_addr(ifp
);
306 changed
= new_prim_addr
.s_addr
!= pim_ifp
->primary_address
.s_addr
;
308 if (PIM_DEBUG_ZEBRA
) {
309 char new_prim_str
[INET_ADDRSTRLEN
];
310 char old_prim_str
[INET_ADDRSTRLEN
];
311 pim_inet4_dump("<new?>", new_prim_addr
, new_prim_str
, sizeof(new_prim_str
));
312 pim_inet4_dump("<old?>", pim_ifp
->primary_address
, old_prim_str
, sizeof(old_prim_str
));
313 zlog_debug("%s: old=%s new=%s on interface %s: %s",
315 old_prim_str
, new_prim_str
, ifp
->name
,
316 changed
? "changed" : "unchanged");
320 pim_ifp
->primary_address
= new_prim_addr
;
326 static int pim_sec_addr_comp(const void *p1
, const void *p2
)
328 const struct pim_secondary_addr
*sec1
= p1
;
329 const struct pim_secondary_addr
*sec2
= p2
;
331 if (ntohl(sec1
->addr
.s_addr
) < ntohl(sec2
->addr
.s_addr
))
334 if (ntohl(sec1
->addr
.s_addr
) > ntohl(sec2
->addr
.s_addr
))
340 static void pim_sec_addr_free(struct pim_secondary_addr
*sec_addr
)
342 XFREE(MTYPE_PIM_SEC_ADDR
, sec_addr
);
345 static struct pim_secondary_addr
*
346 pim_sec_addr_find(struct pim_interface
*pim_ifp
, struct in_addr addr
)
348 struct pim_secondary_addr
*sec_addr
;
349 struct listnode
*node
;
351 if (!pim_ifp
->sec_addr_list
) {
355 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->sec_addr_list
, node
, sec_addr
)) {
356 if (sec_addr
->addr
.s_addr
== addr
.s_addr
) {
364 static void pim_sec_addr_del(struct pim_interface
*pim_ifp
,
365 struct pim_secondary_addr
*sec_addr
)
367 listnode_delete(pim_ifp
->sec_addr_list
, sec_addr
);
368 pim_sec_addr_free(sec_addr
);
371 static int pim_sec_addr_add(struct pim_interface
*pim_ifp
, struct in_addr addr
)
374 struct pim_secondary_addr
*sec_addr
;
376 sec_addr
= pim_sec_addr_find(pim_ifp
, addr
);
378 sec_addr
->flags
&= ~PIM_SEC_ADDRF_STALE
;
382 if (!pim_ifp
->sec_addr_list
) {
383 pim_ifp
->sec_addr_list
= list_new();
384 pim_ifp
->sec_addr_list
->del
= (void (*)(void *))pim_sec_addr_free
;
385 pim_ifp
->sec_addr_list
->cmp
= (int (*)(void *, void *))pim_sec_addr_comp
;
388 sec_addr
= XCALLOC(MTYPE_PIM_SEC_ADDR
, sizeof(*sec_addr
));
390 if (list_isempty(pim_ifp
->sec_addr_list
)) {
391 list_free(pim_ifp
->sec_addr_list
);
392 pim_ifp
->sec_addr_list
= NULL
;
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 (!pim_ifp
->sec_addr_list
) {
411 if (!list_isempty(pim_ifp
->sec_addr_list
)) {
413 /* remove all nodes and free up the list itself */
414 list_delete_all_node(pim_ifp
->sec_addr_list
);
415 list_free(pim_ifp
->sec_addr_list
);
416 pim_ifp
->sec_addr_list
= NULL
;
422 static int pim_sec_addr_update(struct interface
*ifp
)
424 struct pim_interface
*pim_ifp
= ifp
->info
;
425 struct connected
*ifc
;
426 struct listnode
*node
;
427 struct listnode
*nextnode
;
428 struct pim_secondary_addr
*sec_addr
;
431 if (pim_ifp
->sec_addr_list
) {
432 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->sec_addr_list
, node
, sec_addr
)) {
433 sec_addr
->flags
|= PIM_SEC_ADDRF_STALE
;
437 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, ifc
)) {
438 struct prefix
*p
= ifc
->address
;
440 if (p
->family
!= AF_INET
) {
444 if (PIM_INADDR_IS_ANY(p
->u
.prefix4
)) {
448 if (pim_ifp
->primary_address
.s_addr
== p
->u
.prefix4
.s_addr
) {
449 /* don't add the primary address into the secondary address list */
453 if (pim_sec_addr_add(pim_ifp
, p
->u
.prefix4
)) {
458 if (pim_ifp
->sec_addr_list
) {
459 /* Drop stale entries */
460 for (ALL_LIST_ELEMENTS(pim_ifp
->sec_addr_list
, node
, nextnode
, sec_addr
)) {
461 if (sec_addr
->flags
& PIM_SEC_ADDRF_STALE
) {
462 pim_sec_addr_del(pim_ifp
, sec_addr
);
467 /* If the list went empty free it up */
468 if (list_isempty(pim_ifp
->sec_addr_list
)) {
469 list_free(pim_ifp
->sec_addr_list
);
470 pim_ifp
->sec_addr_list
= NULL
;
477 static int detect_secondary_address_change(struct interface
*ifp
,
478 int force_prim_as_any
,
481 struct pim_interface
*pim_ifp
= ifp
->info
;
484 if (force_prim_as_any
) {
485 /* if primary address is being forced to zero just flush the
486 * secondary address list */
487 changed
= pim_sec_addr_del_all(pim_ifp
);
489 /* re-evaluate the secondary address list */
490 changed
= pim_sec_addr_update(ifp
);
496 static void detect_address_change(struct interface
*ifp
,
497 int force_prim_as_any
,
501 struct pim_interface
*pim_ifp
;
507 if (detect_primary_address_change(ifp
, force_prim_as_any
, caller
)) {
511 if (detect_secondary_address_change(ifp
, force_prim_as_any
, caller
)) {
517 if (!PIM_IF_TEST_PIM(pim_ifp
->options
)) {
521 pim_addr_change(ifp
);
524 /* XXX: if we have unnumbered interfaces we need to run detect address
525 * address change on all of them when the lo address changes */
528 int pim_update_source_set(struct interface
*ifp
, struct in_addr source
)
530 struct pim_interface
*pim_ifp
= ifp
->info
;
533 return PIM_IFACE_NOT_FOUND
;
536 if (pim_ifp
->update_source
.s_addr
== source
.s_addr
) {
537 return PIM_UPDATE_SOURCE_DUP
;
540 pim_ifp
->update_source
= source
;
541 detect_address_change(ifp
, 0 /* force_prim_as_any */,
542 __PRETTY_FUNCTION__
);
547 void pim_if_addr_add(struct connected
*ifc
)
549 struct pim_interface
*pim_ifp
;
550 struct interface
*ifp
;
551 struct in_addr ifaddr
;
561 if (!if_is_operative(ifp
))
564 if (PIM_DEBUG_ZEBRA
) {
566 prefix2str(ifc
->address
, buf
, BUFSIZ
);
567 zlog_debug("%s: %s ifindex=%d connected IP address %s %s",
569 ifp
->name
, ifp
->ifindex
, buf
,
570 CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
) ?
571 "secondary" : "primary");
574 ifaddr
= ifc
->address
->u
.prefix4
;
576 detect_address_change(ifp
, 0, __PRETTY_FUNCTION__
);
578 if (PIM_IF_TEST_IGMP(pim_ifp
->options
)) {
579 struct igmp_sock
*igmp
;
581 /* lookup IGMP socket */
582 igmp
= pim_igmp_sock_lookup_ifaddr(pim_ifp
->igmp_socket_list
,
585 /* if addr new, add IGMP socket */
586 pim_igmp_sock_add(pim_ifp
->igmp_socket_list
, ifaddr
, ifp
);
590 if (PIM_IF_TEST_PIM(pim_ifp
->options
)) {
592 /* Interface has a valid primary address ? */
593 if (PIM_INADDR_ISNOT_ANY(pim_ifp
->primary_address
)) {
595 /* Interface has a valid socket ? */
596 if (pim_ifp
->pim_sock_fd
< 0) {
597 if (pim_sock_add(ifp
)) {
598 zlog_warn("Failure creating PIM socket for interface %s",
606 if (PIM_MROUTE_IS_ENABLED
) {
608 PIM or IGMP is enabled on interface, and there is at least one
609 address assigned, then try to create a vif_index.
611 if (pim_ifp
->mroute_vif_index
< 0) {
614 pim_ifchannel_scan_forward_start (ifp
);
618 static void pim_if_addr_del_igmp(struct connected
*ifc
)
620 struct pim_interface
*pim_ifp
= ifc
->ifp
->info
;
621 struct igmp_sock
*igmp
;
622 struct in_addr ifaddr
;
624 if (ifc
->address
->family
!= AF_INET
) {
625 /* non-IPv4 address */
630 /* IGMP not enabled on interface */
634 ifaddr
= ifc
->address
->u
.prefix4
;
636 /* lookup IGMP socket */
637 igmp
= pim_igmp_sock_lookup_ifaddr(pim_ifp
->igmp_socket_list
,
640 /* if addr found, del IGMP socket */
641 igmp_sock_delete(igmp
);
645 static void pim_if_addr_del_pim(struct connected
*ifc
)
647 struct pim_interface
*pim_ifp
= ifc
->ifp
->info
;
649 if (ifc
->address
->family
!= AF_INET
) {
650 /* non-IPv4 address */
655 /* PIM not enabled on interface */
659 if (PIM_INADDR_ISNOT_ANY(pim_ifp
->primary_address
)) {
660 /* Interface keeps a valid primary address */
664 if (pim_ifp
->pim_sock_fd
< 0) {
665 /* Interface does not hold a valid socket any longer */
670 pim_sock_delete() closes the socket, stops read and timer threads,
671 and kills all neighbors.
673 pim_sock_delete(ifc
->ifp
, "last address has been removed from interface");
676 void pim_if_addr_del(struct connected
*ifc
, int force_prim_as_any
)
678 struct interface
*ifp
;
684 if (PIM_DEBUG_ZEBRA
) {
686 prefix2str(ifc
->address
, buf
, BUFSIZ
);
687 zlog_debug("%s: %s ifindex=%d disconnected IP address %s %s",
689 ifp
->name
, ifp
->ifindex
, buf
,
690 CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
) ?
691 "secondary" : "primary");
694 detect_address_change(ifp
, force_prim_as_any
, __PRETTY_FUNCTION__
);
696 pim_if_addr_del_igmp(ifc
);
697 pim_if_addr_del_pim(ifc
);
700 void pim_if_addr_add_all(struct interface
*ifp
)
702 struct connected
*ifc
;
703 struct listnode
*node
;
704 struct listnode
*nextnode
;
707 struct pim_interface
*pim_ifp
= ifp
->info
;
710 /* PIM/IGMP enabled ? */
714 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
715 struct prefix
*p
= ifc
->address
;
717 if (p
->family
!= AF_INET
)
724 pim_if_addr_add(ifc
);
727 if (!v4_addrs
&& v6_addrs
&& !if_is_loopback (ifp
))
729 if (PIM_IF_TEST_PIM(pim_ifp
->options
)) {
731 /* Interface has a valid primary address ? */
732 if (PIM_INADDR_ISNOT_ANY(pim_ifp
->primary_address
)) {
734 /* Interface has a valid socket ? */
735 if (pim_ifp
->pim_sock_fd
< 0) {
736 if (pim_sock_add(ifp
)) {
737 zlog_warn("Failure creating PIM socket for interface %s",
745 if (PIM_MROUTE_IS_ENABLED
) {
747 * PIM or IGMP is enabled on interface, and there is at least one
748 * address assigned, then try to create a vif_index.
750 if (pim_ifp
->mroute_vif_index
< 0) {
753 pim_ifchannel_scan_forward_start (ifp
);
757 pim_rp_check_on_if_add(pim_ifp
);
760 void pim_if_addr_del_all(struct interface
*ifp
)
762 struct connected
*ifc
;
763 struct listnode
*node
;
764 struct listnode
*nextnode
;
766 /* PIM/IGMP enabled ? */
770 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
771 struct prefix
*p
= ifc
->address
;
773 if (p
->family
!= AF_INET
)
776 pim_if_addr_del(ifc
, 1 /* force_prim_as_any=true */);
780 pim_i_am_rp_re_evaluate();
783 void pim_if_addr_del_all_igmp(struct interface
*ifp
)
785 struct connected
*ifc
;
786 struct listnode
*node
;
787 struct listnode
*nextnode
;
789 /* PIM/IGMP enabled ? */
793 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
794 struct prefix
*p
= ifc
->address
;
796 if (p
->family
!= AF_INET
)
799 pim_if_addr_del_igmp(ifc
);
803 void pim_if_addr_del_all_pim(struct interface
*ifp
)
805 struct connected
*ifc
;
806 struct listnode
*node
;
807 struct listnode
*nextnode
;
809 /* PIM/IGMP enabled ? */
813 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
814 struct prefix
*p
= ifc
->address
;
816 if (p
->family
!= AF_INET
)
819 pim_if_addr_del_pim(ifc
);
824 pim_find_primary_addr (struct interface
*ifp
)
826 struct connected
*ifc
;
827 struct listnode
*node
;
831 struct pim_interface
*pim_ifp
= ifp
->info
;
833 if (pim_ifp
&& PIM_INADDR_ISNOT_ANY(pim_ifp
->update_source
)) {
834 return pim_ifp
->update_source
;
837 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, ifc
)) {
838 struct prefix
*p
= ifc
->address
;
840 if (p
->family
!= AF_INET
)
846 if (PIM_INADDR_IS_ANY(p
->u
.prefix4
)) {
847 zlog_warn("%s: null IPv4 address connected to interface %s",
848 __PRETTY_FUNCTION__
, ifp
->name
);
854 if (CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
))
861 * If we have no v4_addrs and v6 is configured
862 * We probably are using unnumbered
863 * So let's grab the loopbacks v4 address
864 * and use that as the primary address
866 if (!v4_addrs
&& v6_addrs
&& !if_is_loopback (ifp
))
868 struct interface
*lo_ifp
;
869 lo_ifp
= if_lookup_by_name_vrf ("lo", VRF_DEFAULT
);
871 return pim_find_primary_addr (lo_ifp
);
874 addr
.s_addr
= PIM_NET_INADDR_ANY
;
880 pim_iface_next_vif_index (struct interface
*ifp
)
884 * The pimreg vif is always going to be in index 0
887 if (ifp
->ifindex
== PIM_OIF_PIM_REGISTER_VIF
)
890 for (i
= 1 ; i
< MAXVIFS
; i
++)
892 if (pim_iface_vif_index
[i
] == 0)
899 pim_if_add_vif() uses ifindex as vif_index
901 see also pim_if_find_vifindex_by_ifindex()
903 int pim_if_add_vif(struct interface
*ifp
)
905 struct pim_interface
*pim_ifp
= ifp
->info
;
906 struct in_addr ifaddr
;
907 unsigned char flags
= 0;
911 if (pim_ifp
->mroute_vif_index
> 0) {
912 zlog_warn("%s: vif_index=%d > 0 on interface %s ifindex=%d",
914 pim_ifp
->mroute_vif_index
, ifp
->name
, ifp
->ifindex
);
918 if (ifp
->ifindex
< 0) {
919 zlog_warn("%s: ifindex=%d < 1 on interface %s",
921 ifp
->ifindex
, ifp
->name
);
925 ifaddr
= pim_ifp
->primary_address
;
926 if (ifp
->ifindex
!= PIM_OIF_PIM_REGISTER_VIF
&& PIM_INADDR_IS_ANY(ifaddr
)) {
927 zlog_warn("%s: could not get address for interface %s ifindex=%d",
929 ifp
->name
, ifp
->ifindex
);
933 pim_ifp
->mroute_vif_index
= pim_iface_next_vif_index (ifp
);
935 if (pim_ifp
->mroute_vif_index
>= MAXVIFS
)
937 zlog_warn("%s: Attempting to configure more than MAXVIFS=%d on pim enabled interface %s",
943 if (ifp
->ifindex
== PIM_OIF_PIM_REGISTER_VIF
)
944 flags
= VIFF_REGISTER
;
945 #ifdef VIFF_USE_IFINDEX
947 flags
= VIFF_USE_IFINDEX
;
950 if (pim_mroute_add_vif(ifp
, ifaddr
, flags
)) {
951 /* pim_mroute_add_vif reported error */
955 pim_iface_vif_index
[pim_ifp
->mroute_vif_index
] = 1;
959 int pim_if_del_vif(struct interface
*ifp
)
961 struct pim_interface
*pim_ifp
= ifp
->info
;
963 if (pim_ifp
->mroute_vif_index
< 1) {
964 zlog_warn("%s: vif_index=%d < 1 on interface %s ifindex=%d",
966 pim_ifp
->mroute_vif_index
, ifp
->name
, ifp
->ifindex
);
970 pim_mroute_del_vif(pim_ifp
->mroute_vif_index
);
975 pim_iface_vif_index
[pim_ifp
->mroute_vif_index
] = 0;
977 pim_ifp
->mroute_vif_index
= -1;
982 void pim_if_add_vif_all()
984 struct listnode
*ifnode
;
985 struct listnode
*ifnextnode
;
986 struct interface
*ifp
;
988 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT
), ifnode
, ifnextnode
, ifp
)) {
996 void pim_if_del_vif_all()
998 struct listnode
*ifnode
;
999 struct listnode
*ifnextnode
;
1000 struct interface
*ifp
;
1002 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT
), ifnode
, ifnextnode
, ifp
)) {
1006 pim_if_del_vif(ifp
);
1010 struct interface
*pim_if_find_by_vif_index(ifindex_t vif_index
)
1012 struct listnode
*ifnode
;
1013 struct interface
*ifp
;
1016 return if_lookup_by_name_vrf ("pimreg", VRF_DEFAULT
);
1018 for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT
), ifnode
, ifp
)) {
1020 struct pim_interface
*pim_ifp
;
1021 pim_ifp
= ifp
->info
;
1023 if (vif_index
== pim_ifp
->mroute_vif_index
)
1032 pim_if_add_vif() uses ifindex as vif_index
1034 int pim_if_find_vifindex_by_ifindex(ifindex_t ifindex
)
1036 struct pim_interface
*pim_ifp
;
1037 struct interface
*ifp
;
1039 ifp
= if_lookup_by_index_vrf (ifindex
, VRF_DEFAULT
);
1040 if (!ifp
|| !ifp
->info
)
1042 pim_ifp
= ifp
->info
;
1044 return pim_ifp
->mroute_vif_index
;
1047 int pim_if_lan_delay_enabled(struct interface
*ifp
)
1049 struct pim_interface
*pim_ifp
;
1051 pim_ifp
= ifp
->info
;
1053 zassert(pim_ifp
->pim_number_of_nonlandelay_neighbors
>= 0);
1055 return pim_ifp
->pim_number_of_nonlandelay_neighbors
== 0;
1058 uint16_t pim_if_effective_propagation_delay_msec(struct interface
*ifp
)
1060 if (pim_if_lan_delay_enabled(ifp
)) {
1061 struct pim_interface
*pim_ifp
;
1062 pim_ifp
= ifp
->info
;
1063 return pim_ifp
->pim_neighbors_highest_propagation_delay_msec
;
1066 return PIM_DEFAULT_PROPAGATION_DELAY_MSEC
;
1070 uint16_t pim_if_effective_override_interval_msec(struct interface
*ifp
)
1072 if (pim_if_lan_delay_enabled(ifp
)) {
1073 struct pim_interface
*pim_ifp
;
1074 pim_ifp
= ifp
->info
;
1075 return pim_ifp
->pim_neighbors_highest_override_interval_msec
;
1078 return PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC
;
1082 int pim_if_t_override_msec(struct interface
*ifp
)
1084 int effective_override_interval_msec
;
1085 int t_override_msec
;
1087 effective_override_interval_msec
=
1088 pim_if_effective_override_interval_msec(ifp
);
1090 t_override_msec
= random() % (effective_override_interval_msec
+ 1);
1092 return t_override_msec
;
1095 uint16_t pim_if_jp_override_interval_msec(struct interface
*ifp
)
1097 return pim_if_effective_propagation_delay_msec(ifp
) +
1098 pim_if_effective_override_interval_msec(ifp
);
1102 RFC 4601: 4.1.6. State Summarization Macros
1104 The function NBR( I, A ) uses information gathered through PIM Hello
1105 messages to map the IP address A of a directly connected PIM
1106 neighbor router on interface I to the primary IP address of the same
1107 router (Section 4.3.4). The primary IP address of a neighbor is the
1108 address that it uses as the source of its PIM Hello messages.
1110 struct pim_neighbor
*pim_if_find_neighbor(struct interface
*ifp
,
1111 struct in_addr addr
)
1113 struct listnode
*neighnode
;
1114 struct pim_neighbor
*neigh
;
1115 struct pim_interface
*pim_ifp
;
1119 pim_ifp
= ifp
->info
;
1121 zlog_warn("%s: multicast not enabled on interface %s",
1122 __PRETTY_FUNCTION__
,
1127 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
, neighnode
, neigh
)) {
1129 /* primary address ? */
1130 if (neigh
->source_addr
.s_addr
== addr
.s_addr
)
1133 /* secondary address ? */
1134 if (pim_neighbor_find_secondary(neigh
, addr
))
1138 if (PIM_DEBUG_PIM_TRACE
) {
1139 char addr_str
[INET_ADDRSTRLEN
];
1140 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
1141 zlog_debug("%s: neighbor not found for address %s on interface %s",
1142 __PRETTY_FUNCTION__
,
1143 addr_str
, ifp
->name
);
1149 long pim_if_t_suppressed_msec(struct interface
*ifp
)
1151 struct pim_interface
*pim_ifp
;
1152 long t_suppressed_msec
;
1153 uint32_t ramount
= 0;
1155 pim_ifp
= ifp
->info
;
1158 /* join suppression disabled ? */
1159 if (PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp
->options
))
1162 /* t_suppressed = t_periodic * rand(1.1, 1.4) */
1163 ramount
= 1100 + (random() % (1400 - 1100 + 1));
1164 t_suppressed_msec
= qpim_t_periodic
* ramount
;
1166 return t_suppressed_msec
;
1169 static void igmp_join_free(struct igmp_join
*ij
)
1171 XFREE(MTYPE_PIM_IGMP_JOIN
, ij
);
1174 static struct igmp_join
*igmp_join_find(struct list
*join_list
,
1175 struct in_addr group_addr
,
1176 struct in_addr source_addr
)
1178 struct listnode
*node
;
1179 struct igmp_join
*ij
;
1183 for (ALL_LIST_ELEMENTS_RO(join_list
, node
, ij
)) {
1184 if ((group_addr
.s_addr
== ij
->group_addr
.s_addr
) &&
1185 (source_addr
.s_addr
== ij
->source_addr
.s_addr
))
1192 static int igmp_join_sock(const char *ifname
,
1194 struct in_addr group_addr
,
1195 struct in_addr source_addr
)
1199 join_fd
= pim_socket_raw(IPPROTO_IGMP
);
1204 if (pim_socket_join_source(join_fd
, ifindex
, group_addr
, source_addr
, ifname
)) {
1212 static struct igmp_join
*igmp_join_new(struct interface
*ifp
,
1213 struct in_addr group_addr
,
1214 struct in_addr source_addr
)
1216 struct pim_interface
*pim_ifp
;
1217 struct igmp_join
*ij
;
1220 pim_ifp
= ifp
->info
;
1223 join_fd
= igmp_join_sock(ifp
->name
, ifp
->ifindex
, group_addr
, source_addr
);
1225 char group_str
[INET_ADDRSTRLEN
];
1226 char source_str
[INET_ADDRSTRLEN
];
1227 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
1228 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
1229 zlog_warn("%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s",
1230 __PRETTY_FUNCTION__
,
1231 group_str
, source_str
, ifp
->name
);
1235 ij
= XCALLOC(MTYPE_PIM_IGMP_JOIN
, sizeof(*ij
));
1237 char group_str
[INET_ADDRSTRLEN
];
1238 char source_str
[INET_ADDRSTRLEN
];
1239 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
1240 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
1241 zlog_err("%s: XCALLOC(%zu) failure for IGMP group %s source %s on interface %s",
1242 __PRETTY_FUNCTION__
,
1243 sizeof(*ij
), group_str
, source_str
, ifp
->name
);
1248 ij
->sock_fd
= join_fd
;
1249 ij
->group_addr
= group_addr
;
1250 ij
->source_addr
= source_addr
;
1251 ij
->sock_creation
= pim_time_monotonic_sec();
1253 listnode_add(pim_ifp
->igmp_join_list
, ij
);
1258 int pim_if_igmp_join_add(struct interface
*ifp
,
1259 struct in_addr group_addr
,
1260 struct in_addr source_addr
)
1262 struct pim_interface
*pim_ifp
;
1263 struct igmp_join
*ij
;
1265 pim_ifp
= ifp
->info
;
1267 zlog_warn("%s: multicast not enabled on interface %s",
1268 __PRETTY_FUNCTION__
,
1273 if (!pim_ifp
->igmp_join_list
) {
1274 pim_ifp
->igmp_join_list
= list_new();
1275 if (!pim_ifp
->igmp_join_list
) {
1276 zlog_err("%s %s: failure: igmp_join_list=list_new()",
1277 __FILE__
, __PRETTY_FUNCTION__
);
1280 pim_ifp
->igmp_join_list
->del
= (void (*)(void *)) igmp_join_free
;
1283 ij
= igmp_join_find(pim_ifp
->igmp_join_list
, group_addr
, source_addr
);
1285 char group_str
[INET_ADDRSTRLEN
];
1286 char source_str
[INET_ADDRSTRLEN
];
1287 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
1288 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
1289 zlog_warn("%s: can't re-join existing IGMP group %s source %s on interface %s",
1290 __PRETTY_FUNCTION__
,
1291 group_str
, source_str
, ifp
->name
);
1295 ij
= igmp_join_new(ifp
, group_addr
, source_addr
);
1297 char group_str
[INET_ADDRSTRLEN
];
1298 char source_str
[INET_ADDRSTRLEN
];
1299 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
1300 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
1301 zlog_warn("%s: igmp_join_new() failure for IGMP group %s source %s on interface %s",
1302 __PRETTY_FUNCTION__
,
1303 group_str
, source_str
, ifp
->name
);
1307 if (PIM_DEBUG_IGMP_EVENTS
) {
1308 char group_str
[INET_ADDRSTRLEN
];
1309 char source_str
[INET_ADDRSTRLEN
];
1310 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
1311 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
1312 zlog_debug("%s: issued static igmp join for channel (S,G)=(%s,%s) on interface %s",
1313 __PRETTY_FUNCTION__
,
1314 source_str
, group_str
, ifp
->name
);
1322 int pim_if_igmp_join_del(struct interface
*ifp
,
1323 struct in_addr group_addr
,
1324 struct in_addr source_addr
)
1326 struct pim_interface
*pim_ifp
;
1327 struct igmp_join
*ij
;
1329 pim_ifp
= ifp
->info
;
1331 zlog_warn("%s: multicast not enabled on interface %s",
1332 __PRETTY_FUNCTION__
,
1337 if (!pim_ifp
->igmp_join_list
) {
1338 zlog_warn("%s: no IGMP join on interface %s",
1339 __PRETTY_FUNCTION__
,
1344 ij
= igmp_join_find(pim_ifp
->igmp_join_list
, group_addr
, source_addr
);
1346 char group_str
[INET_ADDRSTRLEN
];
1347 char source_str
[INET_ADDRSTRLEN
];
1348 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
1349 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
1350 zlog_warn("%s: could not find IGMP group %s source %s on interface %s",
1351 __PRETTY_FUNCTION__
,
1352 group_str
, source_str
, ifp
->name
);
1356 if (close(ij
->sock_fd
)) {
1357 char group_str
[INET_ADDRSTRLEN
];
1358 char source_str
[INET_ADDRSTRLEN
];
1359 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
1360 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
1361 zlog_warn("%s: failure closing sock_fd=%d for IGMP group %s source %s on interface %s: errno=%d: %s",
1362 __PRETTY_FUNCTION__
,
1363 ij
->sock_fd
, group_str
, source_str
, ifp
->name
, errno
, safe_strerror(errno
));
1366 listnode_delete(pim_ifp
->igmp_join_list
, ij
);
1368 if (listcount(pim_ifp
->igmp_join_list
) < 1) {
1369 list_delete(pim_ifp
->igmp_join_list
);
1370 pim_ifp
->igmp_join_list
= 0;
1376 static void pim_if_igmp_join_del_all(struct interface
*ifp
)
1378 struct pim_interface
*pim_ifp
;
1379 struct listnode
*node
;
1380 struct listnode
*nextnode
;
1381 struct igmp_join
*ij
;
1383 pim_ifp
= ifp
->info
;
1385 zlog_warn("%s: multicast not enabled on interface %s",
1386 __PRETTY_FUNCTION__
,
1391 if (!pim_ifp
->igmp_join_list
)
1394 for (ALL_LIST_ELEMENTS(pim_ifp
->igmp_join_list
, node
, nextnode
, ij
))
1395 pim_if_igmp_join_del(ifp
, ij
->group_addr
, ij
->source_addr
);
1401 Transitions from "I am Assert Loser" State
1403 Current Winner's GenID Changes or NLT Expires
1405 The Neighbor Liveness Timer associated with the current winner
1406 expires or we receive a Hello message from the current winner
1407 reporting a different GenID from the one it previously reported.
1408 This indicates that the current winner's interface or router has
1409 gone down (and may have come back up), and so we must assume it no
1410 longer knows it was the winner.
1412 void pim_if_assert_on_neighbor_down(struct interface
*ifp
,
1413 struct in_addr neigh_addr
)
1415 struct pim_interface
*pim_ifp
;
1416 struct listnode
*node
;
1417 struct listnode
*next_node
;
1418 struct pim_ifchannel
*ch
;
1420 pim_ifp
= ifp
->info
;
1423 for (ALL_LIST_ELEMENTS(pim_ifp
->pim_ifchannel_list
, node
, next_node
, ch
)) {
1424 /* Is (S,G,I) assert loser ? */
1425 if (ch
->ifassert_state
!= PIM_IFASSERT_I_AM_LOSER
)
1427 /* Dead neighbor was winner ? */
1428 if (ch
->ifassert_winner
.s_addr
!= neigh_addr
.s_addr
)
1431 assert_action_a5(ch
);
1435 void pim_if_update_join_desired(struct pim_interface
*pim_ifp
)
1437 struct listnode
*ch_node
;
1438 struct pim_ifchannel
*ch
;
1440 /* clear off flag from interface's upstreams */
1441 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_ifchannel_list
, ch_node
, ch
)) {
1442 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(ch
->upstream
->flags
);
1445 /* scan per-interface (S,G,I) state on this I interface */
1446 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_ifchannel_list
, ch_node
, ch
)) {
1447 struct pim_upstream
*up
= ch
->upstream
;
1449 if (PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(up
->flags
))
1452 /* update join_desired for the global (S,G) state */
1453 pim_upstream_update_join_desired(up
);
1454 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(up
->flags
);
1458 void pim_if_update_assert_tracking_desired(struct interface
*ifp
)
1460 struct pim_interface
*pim_ifp
;
1461 struct listnode
*node
;
1462 struct listnode
*next_node
;
1463 struct pim_ifchannel
*ch
;
1465 pim_ifp
= ifp
->info
;
1469 for (ALL_LIST_ELEMENTS(pim_ifp
->pim_ifchannel_list
, node
, next_node
, ch
)) {
1470 pim_ifchannel_update_assert_tracking_desired(ch
);
1475 * PIM wants to have an interface pointer for everything it does.
1476 * The pimreg is a special interface that we have that is not
1477 * quite an inteface but a VIF is created for it.
1479 void pim_if_create_pimreg (void)
1481 if (!pim_regiface
) {
1482 pim_regiface
= if_create("pimreg", strlen("pimreg"));
1483 pim_regiface
->ifindex
= PIM_OIF_PIM_REGISTER_VIF
;
1485 pim_if_new(pim_regiface
, 0, 0);
1490 pim_if_connected_to_source (struct interface
*ifp
, struct in_addr src
)
1492 struct listnode
*cnode
;
1493 struct connected
*c
;
1498 p
.prefixlen
= IPV4_MAX_BITLEN
;
1500 for (ALL_LIST_ELEMENTS_RO (ifp
->connected
, cnode
, c
))
1502 if ((c
->address
->family
== AF_INET
) &&
1503 prefix_match (CONNECTED_PREFIX (c
), &p
))
1513 pim_if_lookup_address_vrf (struct in_addr src
, vrf_id_t vrf_id
)
1515 struct listnode
*ifnode
;
1516 struct interface
*ifp
;
1518 for (ALL_LIST_ELEMENTS_RO (vrf_iflist(vrf_id
), ifnode
, ifp
))
1520 if (pim_if_connected_to_source (ifp
, src
) && ifp
->info
)