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
);
192 void pim_if_delete(struct interface
*ifp
)
194 struct pim_interface
*pim_ifp
;
200 if (pim_ifp
->igmp_join_list
) {
201 pim_if_igmp_join_del_all(ifp
);
204 pim_ifchannel_delete_all (ifp
);
205 igmp_sock_delete_all (ifp
);
207 pim_neighbor_delete_all (ifp
, "Interface removed from configuration");
211 list_delete(pim_ifp
->igmp_socket_list
);
212 list_delete(pim_ifp
->pim_neighbor_list
);
213 list_delete(pim_ifp
->upstream_switch_list
);
214 list_delete(pim_ifp
->pim_ifchannel_list
);
216 hash_free (pim_ifp
->pim_ifchannel_hash
);
218 XFREE(MTYPE_PIM_INTERFACE
, pim_ifp
);
223 void pim_if_update_could_assert(struct interface
*ifp
)
225 struct pim_interface
*pim_ifp
;
226 struct listnode
*node
;
227 struct listnode
*next_node
;
228 struct pim_ifchannel
*ch
;
233 for (ALL_LIST_ELEMENTS(pim_ifp
->pim_ifchannel_list
, node
, next_node
, ch
)) {
234 pim_ifchannel_update_could_assert(ch
);
238 static void pim_if_update_my_assert_metric(struct interface
*ifp
)
240 struct pim_interface
*pim_ifp
;
241 struct listnode
*node
;
242 struct listnode
*next_node
;
243 struct pim_ifchannel
*ch
;
248 for (ALL_LIST_ELEMENTS(pim_ifp
->pim_ifchannel_list
, node
, next_node
, ch
)) {
249 pim_ifchannel_update_my_assert_metric(ch
);
253 static void pim_addr_change(struct interface
*ifp
)
255 struct pim_interface
*pim_ifp
;
260 pim_if_dr_election(ifp
); /* router's own DR Priority (addr) changes -- Done TODO T30 */
261 pim_if_update_join_desired(pim_ifp
); /* depends on DR */
262 pim_if_update_could_assert(ifp
); /* depends on DR */
263 pim_if_update_my_assert_metric(ifp
); /* depends on could_assert */
264 pim_if_update_assert_tracking_desired(ifp
); /* depends on DR, join_desired */
267 RFC 4601: 4.3.1. Sending Hello Messages
269 1) Before an interface goes down or changes primary IP address, a
270 Hello message with a zero HoldTime should be sent immediately
271 (with the old IP address if the IP address changed).
272 -- FIXME See CAVEAT C13
274 2) After an interface has changed its IP address, it MUST send a
275 Hello message with its new IP address.
278 3) If an interface changes one of its secondary IP addresses, a
279 Hello message with an updated Address_List option and a non-zero
280 HoldTime should be sent immediately.
281 -- FIXME See TODO T31
283 pim_ifp
->pim_ifstat_hello_sent
= 0; /* reset hello counter */
284 if (pim_ifp
->pim_sock_fd
< 0)
286 pim_hello_restart_now(ifp
); /* send hello and restart timer */
289 static int detect_primary_address_change(struct interface
*ifp
,
290 int force_prim_as_any
,
293 struct pim_interface
*pim_ifp
= ifp
->info
;
294 struct in_addr new_prim_addr
;
297 if (force_prim_as_any
)
298 new_prim_addr
= qpim_inaddr_any
;
300 new_prim_addr
= pim_find_primary_addr(ifp
);
302 changed
= new_prim_addr
.s_addr
!= pim_ifp
->primary_address
.s_addr
;
304 if (PIM_DEBUG_ZEBRA
) {
305 char new_prim_str
[INET_ADDRSTRLEN
];
306 char old_prim_str
[INET_ADDRSTRLEN
];
307 pim_inet4_dump("<new?>", new_prim_addr
, new_prim_str
, sizeof(new_prim_str
));
308 pim_inet4_dump("<old?>", pim_ifp
->primary_address
, old_prim_str
, sizeof(old_prim_str
));
309 zlog_debug("%s: old=%s new=%s on interface %s: %s",
311 old_prim_str
, new_prim_str
, ifp
->name
,
312 changed
? "changed" : "unchanged");
316 pim_ifp
->primary_address
= new_prim_addr
;
322 static int pim_sec_addr_comp(const void *p1
, const void *p2
)
324 const struct pim_secondary_addr
*sec1
= p1
;
325 const struct pim_secondary_addr
*sec2
= p2
;
327 if (ntohl(sec1
->addr
.s_addr
) < ntohl(sec2
->addr
.s_addr
))
330 if (ntohl(sec1
->addr
.s_addr
) > ntohl(sec2
->addr
.s_addr
))
336 static void pim_sec_addr_free(struct pim_secondary_addr
*sec_addr
)
338 XFREE(MTYPE_PIM_SEC_ADDR
, sec_addr
);
341 static struct pim_secondary_addr
*
342 pim_sec_addr_find(struct pim_interface
*pim_ifp
, struct in_addr addr
)
344 struct pim_secondary_addr
*sec_addr
;
345 struct listnode
*node
;
347 if (!pim_ifp
->sec_addr_list
) {
351 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->sec_addr_list
, node
, sec_addr
)) {
352 if (sec_addr
->addr
.s_addr
== addr
.s_addr
) {
360 static void pim_sec_addr_del(struct pim_interface
*pim_ifp
,
361 struct pim_secondary_addr
*sec_addr
)
363 listnode_delete(pim_ifp
->sec_addr_list
, sec_addr
);
364 pim_sec_addr_free(sec_addr
);
367 static int pim_sec_addr_add(struct pim_interface
*pim_ifp
, struct in_addr addr
)
370 struct pim_secondary_addr
*sec_addr
;
372 sec_addr
= pim_sec_addr_find(pim_ifp
, addr
);
374 sec_addr
->flags
&= ~PIM_SEC_ADDRF_STALE
;
378 if (!pim_ifp
->sec_addr_list
) {
379 pim_ifp
->sec_addr_list
= list_new();
380 pim_ifp
->sec_addr_list
->del
= (void (*)(void *))pim_sec_addr_free
;
381 pim_ifp
->sec_addr_list
->cmp
= (int (*)(void *, void *))pim_sec_addr_comp
;
384 sec_addr
= XCALLOC(MTYPE_PIM_SEC_ADDR
, sizeof(*sec_addr
));
386 if (list_isempty(pim_ifp
->sec_addr_list
)) {
387 list_free(pim_ifp
->sec_addr_list
);
388 pim_ifp
->sec_addr_list
= NULL
;
394 sec_addr
->addr
= addr
;
395 listnode_add_sort(pim_ifp
->sec_addr_list
, sec_addr
);
400 static int pim_sec_addr_del_all(struct pim_interface
*pim_ifp
)
404 if (!pim_ifp
->sec_addr_list
) {
407 if (!list_isempty(pim_ifp
->sec_addr_list
)) {
409 /* remove all nodes and free up the list itself */
410 list_delete_all_node(pim_ifp
->sec_addr_list
);
411 list_free(pim_ifp
->sec_addr_list
);
412 pim_ifp
->sec_addr_list
= NULL
;
418 static int pim_sec_addr_update(struct interface
*ifp
)
420 struct pim_interface
*pim_ifp
= ifp
->info
;
421 struct connected
*ifc
;
422 struct listnode
*node
;
423 struct listnode
*nextnode
;
424 struct pim_secondary_addr
*sec_addr
;
427 if (pim_ifp
->sec_addr_list
) {
428 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->sec_addr_list
, node
, sec_addr
)) {
429 sec_addr
->flags
|= PIM_SEC_ADDRF_STALE
;
433 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, ifc
)) {
434 struct prefix
*p
= ifc
->address
;
436 if (p
->family
!= AF_INET
) {
440 if (PIM_INADDR_IS_ANY(p
->u
.prefix4
)) {
444 if (pim_ifp
->primary_address
.s_addr
== p
->u
.prefix4
.s_addr
) {
445 /* don't add the primary address into the secondary address list */
449 if (pim_sec_addr_add(pim_ifp
, p
->u
.prefix4
)) {
454 if (pim_ifp
->sec_addr_list
) {
455 /* Drop stale entries */
456 for (ALL_LIST_ELEMENTS(pim_ifp
->sec_addr_list
, node
, nextnode
, sec_addr
)) {
457 if (sec_addr
->flags
& PIM_SEC_ADDRF_STALE
) {
458 pim_sec_addr_del(pim_ifp
, sec_addr
);
463 /* If the list went empty free it up */
464 if (list_isempty(pim_ifp
->sec_addr_list
)) {
465 list_free(pim_ifp
->sec_addr_list
);
466 pim_ifp
->sec_addr_list
= NULL
;
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
,
493 int force_prim_as_any
,
497 struct pim_interface
*pim_ifp
;
503 if (detect_primary_address_change(ifp
, force_prim_as_any
, caller
)) {
507 if (detect_secondary_address_change(ifp
, force_prim_as_any
, caller
)) {
513 if (!PIM_IF_TEST_PIM(pim_ifp
->options
)) {
517 pim_addr_change(ifp
);
520 /* XXX: if we have unnumbered interfaces we need to run detect address
521 * address change on all of them when the lo address changes */
524 int pim_update_source_set(struct interface
*ifp
, struct in_addr source
)
526 struct pim_interface
*pim_ifp
= ifp
->info
;
529 return PIM_IFACE_NOT_FOUND
;
532 if (pim_ifp
->update_source
.s_addr
== source
.s_addr
) {
533 return PIM_UPDATE_SOURCE_DUP
;
536 pim_ifp
->update_source
= source
;
537 detect_address_change(ifp
, 0 /* force_prim_as_any */,
538 __PRETTY_FUNCTION__
);
543 void pim_if_addr_add(struct connected
*ifc
)
545 struct pim_interface
*pim_ifp
;
546 struct interface
*ifp
;
547 struct in_addr ifaddr
;
557 if (!if_is_operative(ifp
))
560 if (PIM_DEBUG_ZEBRA
) {
562 prefix2str(ifc
->address
, buf
, BUFSIZ
);
563 zlog_debug("%s: %s ifindex=%d connected IP address %s %s",
565 ifp
->name
, ifp
->ifindex
, buf
,
566 CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
) ?
567 "secondary" : "primary");
570 ifaddr
= ifc
->address
->u
.prefix4
;
572 detect_address_change(ifp
, 0, __PRETTY_FUNCTION__
);
574 if (PIM_IF_TEST_IGMP(pim_ifp
->options
)) {
575 struct igmp_sock
*igmp
;
577 /* lookup IGMP socket */
578 igmp
= pim_igmp_sock_lookup_ifaddr(pim_ifp
->igmp_socket_list
,
581 /* if addr new, add IGMP socket */
582 pim_igmp_sock_add(pim_ifp
->igmp_socket_list
, ifaddr
, ifp
);
586 if (PIM_IF_TEST_PIM(pim_ifp
->options
)) {
588 /* Interface has a valid primary address ? */
589 if (PIM_INADDR_ISNOT_ANY(pim_ifp
->primary_address
)) {
591 /* Interface has a valid socket ? */
592 if (pim_ifp
->pim_sock_fd
< 0) {
593 if (pim_sock_add(ifp
)) {
594 zlog_warn("Failure creating PIM socket for interface %s",
603 PIM or IGMP is enabled on interface, and there is at least one
604 address assigned, then try to create a vif_index.
606 if (pim_ifp
->mroute_vif_index
< 0) {
609 pim_ifchannel_scan_forward_start (ifp
);
612 static void pim_if_addr_del_igmp(struct connected
*ifc
)
614 struct pim_interface
*pim_ifp
= ifc
->ifp
->info
;
615 struct igmp_sock
*igmp
;
616 struct in_addr ifaddr
;
618 if (ifc
->address
->family
!= AF_INET
) {
619 /* non-IPv4 address */
624 /* IGMP not enabled on interface */
628 ifaddr
= ifc
->address
->u
.prefix4
;
630 /* lookup IGMP socket */
631 igmp
= pim_igmp_sock_lookup_ifaddr(pim_ifp
->igmp_socket_list
,
634 /* if addr found, del IGMP socket */
635 igmp_sock_delete(igmp
);
639 static void pim_if_addr_del_pim(struct connected
*ifc
)
641 struct pim_interface
*pim_ifp
= ifc
->ifp
->info
;
643 if (ifc
->address
->family
!= AF_INET
) {
644 /* non-IPv4 address */
649 /* PIM not enabled on interface */
653 if (PIM_INADDR_ISNOT_ANY(pim_ifp
->primary_address
)) {
654 /* Interface keeps a valid primary address */
658 if (pim_ifp
->pim_sock_fd
< 0) {
659 /* Interface does not hold a valid socket any longer */
664 pim_sock_delete() closes the socket, stops read and timer threads,
665 and kills all neighbors.
667 pim_sock_delete(ifc
->ifp
, "last address has been removed from interface");
670 void pim_if_addr_del(struct connected
*ifc
, int force_prim_as_any
)
672 struct interface
*ifp
;
678 if (PIM_DEBUG_ZEBRA
) {
680 prefix2str(ifc
->address
, buf
, BUFSIZ
);
681 zlog_debug("%s: %s ifindex=%d disconnected IP address %s %s",
683 ifp
->name
, ifp
->ifindex
, buf
,
684 CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
) ?
685 "secondary" : "primary");
688 detect_address_change(ifp
, force_prim_as_any
, __PRETTY_FUNCTION__
);
690 pim_if_addr_del_igmp(ifc
);
691 pim_if_addr_del_pim(ifc
);
694 void pim_if_addr_add_all(struct interface
*ifp
)
696 struct connected
*ifc
;
697 struct listnode
*node
;
698 struct listnode
*nextnode
;
701 struct pim_interface
*pim_ifp
= ifp
->info
;
704 /* PIM/IGMP enabled ? */
708 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
709 struct prefix
*p
= ifc
->address
;
711 if (p
->family
!= AF_INET
)
718 pim_if_addr_add(ifc
);
721 if (!v4_addrs
&& v6_addrs
&& !if_is_loopback (ifp
))
723 if (PIM_IF_TEST_PIM(pim_ifp
->options
)) {
725 /* Interface has a valid primary address ? */
726 if (PIM_INADDR_ISNOT_ANY(pim_ifp
->primary_address
)) {
728 /* Interface has a valid socket ? */
729 if (pim_ifp
->pim_sock_fd
< 0) {
730 if (pim_sock_add(ifp
)) {
731 zlog_warn("Failure creating PIM socket for interface %s",
740 * PIM or IGMP is enabled on interface, and there is at least one
741 * address assigned, then try to create a vif_index.
743 if (pim_ifp
->mroute_vif_index
< 0) {
746 pim_ifchannel_scan_forward_start (ifp
);
749 pim_rp_check_on_if_add(pim_ifp
);
752 void pim_if_addr_del_all(struct interface
*ifp
)
754 struct connected
*ifc
;
755 struct listnode
*node
;
756 struct listnode
*nextnode
;
758 /* PIM/IGMP enabled ? */
762 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
763 struct prefix
*p
= ifc
->address
;
765 if (p
->family
!= AF_INET
)
768 pim_if_addr_del(ifc
, 1 /* force_prim_as_any=true */);
772 pim_i_am_rp_re_evaluate();
775 void pim_if_addr_del_all_igmp(struct interface
*ifp
)
777 struct connected
*ifc
;
778 struct listnode
*node
;
779 struct listnode
*nextnode
;
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
)
791 pim_if_addr_del_igmp(ifc
);
795 void pim_if_addr_del_all_pim(struct interface
*ifp
)
797 struct connected
*ifc
;
798 struct listnode
*node
;
799 struct listnode
*nextnode
;
801 /* PIM/IGMP enabled ? */
805 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
806 struct prefix
*p
= ifc
->address
;
808 if (p
->family
!= AF_INET
)
811 pim_if_addr_del_pim(ifc
);
816 pim_find_primary_addr (struct interface
*ifp
)
818 struct connected
*ifc
;
819 struct listnode
*node
;
823 struct pim_interface
*pim_ifp
= ifp
->info
;
825 if (pim_ifp
&& PIM_INADDR_ISNOT_ANY(pim_ifp
->update_source
)) {
826 return pim_ifp
->update_source
;
829 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, ifc
)) {
830 struct prefix
*p
= ifc
->address
;
832 if (p
->family
!= AF_INET
)
838 if (PIM_INADDR_IS_ANY(p
->u
.prefix4
)) {
839 zlog_warn("%s: null IPv4 address connected to interface %s",
840 __PRETTY_FUNCTION__
, ifp
->name
);
846 if (CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
))
853 * If we have no v4_addrs and v6 is configured
854 * We probably are using unnumbered
855 * So let's grab the loopbacks v4 address
856 * and use that as the primary address
858 if (!v4_addrs
&& v6_addrs
&& !if_is_loopback (ifp
))
860 struct interface
*lo_ifp
;
861 lo_ifp
= if_lookup_by_name ("lo", VRF_DEFAULT
);
863 return pim_find_primary_addr (lo_ifp
);
866 addr
.s_addr
= PIM_NET_INADDR_ANY
;
872 pim_iface_next_vif_index (struct interface
*ifp
)
876 * The pimreg vif is always going to be in index 0
879 if (ifp
->ifindex
== PIM_OIF_PIM_REGISTER_VIF
)
882 for (i
= 1 ; i
< MAXVIFS
; i
++)
884 if (pim_iface_vif_index
[i
] == 0)
891 pim_if_add_vif() uses ifindex as vif_index
893 see also pim_if_find_vifindex_by_ifindex()
895 int pim_if_add_vif(struct interface
*ifp
)
897 struct pim_interface
*pim_ifp
= ifp
->info
;
898 struct in_addr ifaddr
;
899 unsigned char flags
= 0;
903 if (pim_ifp
->mroute_vif_index
> 0) {
904 zlog_warn("%s: vif_index=%d > 0 on interface %s ifindex=%d",
906 pim_ifp
->mroute_vif_index
, ifp
->name
, ifp
->ifindex
);
910 if (ifp
->ifindex
< 0) {
911 zlog_warn("%s: ifindex=%d < 1 on interface %s",
913 ifp
->ifindex
, ifp
->name
);
917 ifaddr
= pim_ifp
->primary_address
;
918 if (ifp
->ifindex
!= PIM_OIF_PIM_REGISTER_VIF
&& PIM_INADDR_IS_ANY(ifaddr
)) {
919 zlog_warn("%s: could not get address for interface %s ifindex=%d",
921 ifp
->name
, ifp
->ifindex
);
925 pim_ifp
->mroute_vif_index
= pim_iface_next_vif_index (ifp
);
927 if (pim_ifp
->mroute_vif_index
>= MAXVIFS
)
929 zlog_warn("%s: Attempting to configure more than MAXVIFS=%d on pim enabled interface %s",
935 if (ifp
->ifindex
== PIM_OIF_PIM_REGISTER_VIF
)
936 flags
= VIFF_REGISTER
;
937 #ifdef VIFF_USE_IFINDEX
939 flags
= VIFF_USE_IFINDEX
;
942 if (pim_mroute_add_vif(ifp
, ifaddr
, flags
)) {
943 /* pim_mroute_add_vif reported error */
947 pim_iface_vif_index
[pim_ifp
->mroute_vif_index
] = 1;
951 int pim_if_del_vif(struct interface
*ifp
)
953 struct pim_interface
*pim_ifp
= ifp
->info
;
955 if (pim_ifp
->mroute_vif_index
< 1) {
956 zlog_warn("%s: vif_index=%d < 1 on interface %s ifindex=%d",
958 pim_ifp
->mroute_vif_index
, ifp
->name
, ifp
->ifindex
);
962 pim_mroute_del_vif(pim_ifp
->mroute_vif_index
);
967 pim_iface_vif_index
[pim_ifp
->mroute_vif_index
] = 0;
969 pim_ifp
->mroute_vif_index
= -1;
974 void pim_if_add_vif_all()
976 struct listnode
*ifnode
;
977 struct listnode
*ifnextnode
;
978 struct interface
*ifp
;
980 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT
), ifnode
, ifnextnode
, ifp
)) {
988 void pim_if_del_vif_all()
990 struct listnode
*ifnode
;
991 struct listnode
*ifnextnode
;
992 struct interface
*ifp
;
994 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT
), ifnode
, ifnextnode
, ifp
)) {
1002 struct interface
*pim_if_find_by_vif_index(ifindex_t vif_index
)
1004 struct listnode
*ifnode
;
1005 struct interface
*ifp
;
1008 return if_lookup_by_name ("pimreg", VRF_DEFAULT
);
1010 for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT
), ifnode
, ifp
)) {
1012 struct pim_interface
*pim_ifp
;
1013 pim_ifp
= ifp
->info
;
1015 if (vif_index
== pim_ifp
->mroute_vif_index
)
1024 pim_if_add_vif() uses ifindex as vif_index
1026 int pim_if_find_vifindex_by_ifindex(ifindex_t ifindex
)
1028 struct pim_interface
*pim_ifp
;
1029 struct interface
*ifp
;
1031 ifp
= if_lookup_by_index (ifindex
, VRF_DEFAULT
);
1032 if (!ifp
|| !ifp
->info
)
1034 pim_ifp
= ifp
->info
;
1036 return pim_ifp
->mroute_vif_index
;
1039 int pim_if_lan_delay_enabled(struct interface
*ifp
)
1041 struct pim_interface
*pim_ifp
;
1043 pim_ifp
= ifp
->info
;
1045 zassert(pim_ifp
->pim_number_of_nonlandelay_neighbors
>= 0);
1047 return pim_ifp
->pim_number_of_nonlandelay_neighbors
== 0;
1050 uint16_t pim_if_effective_propagation_delay_msec(struct interface
*ifp
)
1052 if (pim_if_lan_delay_enabled(ifp
)) {
1053 struct pim_interface
*pim_ifp
;
1054 pim_ifp
= ifp
->info
;
1055 return pim_ifp
->pim_neighbors_highest_propagation_delay_msec
;
1058 return PIM_DEFAULT_PROPAGATION_DELAY_MSEC
;
1062 uint16_t pim_if_effective_override_interval_msec(struct interface
*ifp
)
1064 if (pim_if_lan_delay_enabled(ifp
)) {
1065 struct pim_interface
*pim_ifp
;
1066 pim_ifp
= ifp
->info
;
1067 return pim_ifp
->pim_neighbors_highest_override_interval_msec
;
1070 return PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC
;
1074 int pim_if_t_override_msec(struct interface
*ifp
)
1076 int effective_override_interval_msec
;
1077 int t_override_msec
;
1079 effective_override_interval_msec
=
1080 pim_if_effective_override_interval_msec(ifp
);
1082 t_override_msec
= random() % (effective_override_interval_msec
+ 1);
1084 return t_override_msec
;
1087 uint16_t pim_if_jp_override_interval_msec(struct interface
*ifp
)
1089 return pim_if_effective_propagation_delay_msec(ifp
) +
1090 pim_if_effective_override_interval_msec(ifp
);
1094 RFC 4601: 4.1.6. State Summarization Macros
1096 The function NBR( I, A ) uses information gathered through PIM Hello
1097 messages to map the IP address A of a directly connected PIM
1098 neighbor router on interface I to the primary IP address of the same
1099 router (Section 4.3.4). The primary IP address of a neighbor is the
1100 address that it uses as the source of its PIM Hello messages.
1102 struct pim_neighbor
*pim_if_find_neighbor(struct interface
*ifp
,
1103 struct in_addr addr
)
1105 struct listnode
*neighnode
;
1106 struct pim_neighbor
*neigh
;
1107 struct pim_interface
*pim_ifp
;
1111 pim_ifp
= ifp
->info
;
1113 zlog_warn("%s: multicast not enabled on interface %s",
1114 __PRETTY_FUNCTION__
,
1119 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
, neighnode
, neigh
)) {
1121 /* primary address ? */
1122 if (neigh
->source_addr
.s_addr
== addr
.s_addr
)
1125 /* secondary address ? */
1126 if (pim_neighbor_find_secondary(neigh
, addr
))
1130 if (PIM_DEBUG_PIM_TRACE
) {
1131 char addr_str
[INET_ADDRSTRLEN
];
1132 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
1133 zlog_debug("%s: neighbor not found for address %s on interface %s",
1134 __PRETTY_FUNCTION__
,
1135 addr_str
, ifp
->name
);
1141 long pim_if_t_suppressed_msec(struct interface
*ifp
)
1143 struct pim_interface
*pim_ifp
;
1144 long t_suppressed_msec
;
1145 uint32_t ramount
= 0;
1147 pim_ifp
= ifp
->info
;
1150 /* join suppression disabled ? */
1151 if (PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp
->options
))
1154 /* t_suppressed = t_periodic * rand(1.1, 1.4) */
1155 ramount
= 1100 + (random() % (1400 - 1100 + 1));
1156 t_suppressed_msec
= qpim_t_periodic
* ramount
;
1158 return t_suppressed_msec
;
1161 static void igmp_join_free(struct igmp_join
*ij
)
1163 XFREE(MTYPE_PIM_IGMP_JOIN
, ij
);
1166 static struct igmp_join
*igmp_join_find(struct list
*join_list
,
1167 struct in_addr group_addr
,
1168 struct in_addr source_addr
)
1170 struct listnode
*node
;
1171 struct igmp_join
*ij
;
1175 for (ALL_LIST_ELEMENTS_RO(join_list
, node
, ij
)) {
1176 if ((group_addr
.s_addr
== ij
->group_addr
.s_addr
) &&
1177 (source_addr
.s_addr
== ij
->source_addr
.s_addr
))
1184 static int igmp_join_sock(const char *ifname
,
1186 struct in_addr group_addr
,
1187 struct in_addr source_addr
)
1191 join_fd
= pim_socket_raw(IPPROTO_IGMP
);
1196 if (pim_socket_join_source(join_fd
, ifindex
, group_addr
, source_addr
, ifname
)) {
1204 static struct igmp_join
*igmp_join_new(struct interface
*ifp
,
1205 struct in_addr group_addr
,
1206 struct in_addr source_addr
)
1208 struct pim_interface
*pim_ifp
;
1209 struct igmp_join
*ij
;
1212 pim_ifp
= ifp
->info
;
1215 join_fd
= igmp_join_sock(ifp
->name
, ifp
->ifindex
, group_addr
, source_addr
);
1217 char group_str
[INET_ADDRSTRLEN
];
1218 char source_str
[INET_ADDRSTRLEN
];
1219 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
1220 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
1221 zlog_warn("%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s",
1222 __PRETTY_FUNCTION__
,
1223 group_str
, source_str
, ifp
->name
);
1227 ij
= XCALLOC(MTYPE_PIM_IGMP_JOIN
, sizeof(*ij
));
1229 char group_str
[INET_ADDRSTRLEN
];
1230 char source_str
[INET_ADDRSTRLEN
];
1231 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
1232 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
1233 zlog_err("%s: XCALLOC(%zu) failure for IGMP group %s source %s on interface %s",
1234 __PRETTY_FUNCTION__
,
1235 sizeof(*ij
), group_str
, source_str
, ifp
->name
);
1240 ij
->sock_fd
= join_fd
;
1241 ij
->group_addr
= group_addr
;
1242 ij
->source_addr
= source_addr
;
1243 ij
->sock_creation
= pim_time_monotonic_sec();
1245 listnode_add(pim_ifp
->igmp_join_list
, ij
);
1250 int pim_if_igmp_join_add(struct interface
*ifp
,
1251 struct in_addr group_addr
,
1252 struct in_addr source_addr
)
1254 struct pim_interface
*pim_ifp
;
1255 struct igmp_join
*ij
;
1257 pim_ifp
= ifp
->info
;
1259 zlog_warn("%s: multicast not enabled on interface %s",
1260 __PRETTY_FUNCTION__
,
1265 if (!pim_ifp
->igmp_join_list
) {
1266 pim_ifp
->igmp_join_list
= list_new();
1267 if (!pim_ifp
->igmp_join_list
) {
1268 zlog_err("%s %s: failure: igmp_join_list=list_new()",
1269 __FILE__
, __PRETTY_FUNCTION__
);
1272 pim_ifp
->igmp_join_list
->del
= (void (*)(void *)) igmp_join_free
;
1275 ij
= igmp_join_find(pim_ifp
->igmp_join_list
, group_addr
, source_addr
);
1277 char group_str
[INET_ADDRSTRLEN
];
1278 char source_str
[INET_ADDRSTRLEN
];
1279 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
1280 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
1281 zlog_warn("%s: can't re-join existing IGMP group %s source %s on interface %s",
1282 __PRETTY_FUNCTION__
,
1283 group_str
, source_str
, ifp
->name
);
1287 ij
= igmp_join_new(ifp
, group_addr
, source_addr
);
1289 char group_str
[INET_ADDRSTRLEN
];
1290 char source_str
[INET_ADDRSTRLEN
];
1291 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
1292 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
1293 zlog_warn("%s: igmp_join_new() failure for IGMP group %s source %s on interface %s",
1294 __PRETTY_FUNCTION__
,
1295 group_str
, source_str
, ifp
->name
);
1299 if (PIM_DEBUG_IGMP_EVENTS
) {
1300 char group_str
[INET_ADDRSTRLEN
];
1301 char source_str
[INET_ADDRSTRLEN
];
1302 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
1303 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
1304 zlog_debug("%s: issued static igmp join for channel (S,G)=(%s,%s) on interface %s",
1305 __PRETTY_FUNCTION__
,
1306 source_str
, group_str
, ifp
->name
);
1314 int pim_if_igmp_join_del(struct interface
*ifp
,
1315 struct in_addr group_addr
,
1316 struct in_addr source_addr
)
1318 struct pim_interface
*pim_ifp
;
1319 struct igmp_join
*ij
;
1321 pim_ifp
= ifp
->info
;
1323 zlog_warn("%s: multicast not enabled on interface %s",
1324 __PRETTY_FUNCTION__
,
1329 if (!pim_ifp
->igmp_join_list
) {
1330 zlog_warn("%s: no IGMP join on interface %s",
1331 __PRETTY_FUNCTION__
,
1336 ij
= igmp_join_find(pim_ifp
->igmp_join_list
, group_addr
, source_addr
);
1338 char group_str
[INET_ADDRSTRLEN
];
1339 char source_str
[INET_ADDRSTRLEN
];
1340 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
1341 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
1342 zlog_warn("%s: could not find IGMP group %s source %s on interface %s",
1343 __PRETTY_FUNCTION__
,
1344 group_str
, source_str
, ifp
->name
);
1348 if (close(ij
->sock_fd
)) {
1349 char group_str
[INET_ADDRSTRLEN
];
1350 char source_str
[INET_ADDRSTRLEN
];
1351 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
1352 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
1353 zlog_warn("%s: failure closing sock_fd=%d for IGMP group %s source %s on interface %s: errno=%d: %s",
1354 __PRETTY_FUNCTION__
,
1355 ij
->sock_fd
, group_str
, source_str
, ifp
->name
, errno
, safe_strerror(errno
));
1358 listnode_delete(pim_ifp
->igmp_join_list
, ij
);
1360 if (listcount(pim_ifp
->igmp_join_list
) < 1) {
1361 list_delete(pim_ifp
->igmp_join_list
);
1362 pim_ifp
->igmp_join_list
= 0;
1368 static void pim_if_igmp_join_del_all(struct interface
*ifp
)
1370 struct pim_interface
*pim_ifp
;
1371 struct listnode
*node
;
1372 struct listnode
*nextnode
;
1373 struct igmp_join
*ij
;
1375 pim_ifp
= ifp
->info
;
1377 zlog_warn("%s: multicast not enabled on interface %s",
1378 __PRETTY_FUNCTION__
,
1383 if (!pim_ifp
->igmp_join_list
)
1386 for (ALL_LIST_ELEMENTS(pim_ifp
->igmp_join_list
, node
, nextnode
, ij
))
1387 pim_if_igmp_join_del(ifp
, ij
->group_addr
, ij
->source_addr
);
1393 Transitions from "I am Assert Loser" State
1395 Current Winner's GenID Changes or NLT Expires
1397 The Neighbor Liveness Timer associated with the current winner
1398 expires or we receive a Hello message from the current winner
1399 reporting a different GenID from the one it previously reported.
1400 This indicates that the current winner's interface or router has
1401 gone down (and may have come back up), and so we must assume it no
1402 longer knows it was the winner.
1404 void pim_if_assert_on_neighbor_down(struct interface
*ifp
,
1405 struct in_addr neigh_addr
)
1407 struct pim_interface
*pim_ifp
;
1408 struct listnode
*node
;
1409 struct listnode
*next_node
;
1410 struct pim_ifchannel
*ch
;
1412 pim_ifp
= ifp
->info
;
1415 for (ALL_LIST_ELEMENTS(pim_ifp
->pim_ifchannel_list
, node
, next_node
, ch
)) {
1416 /* Is (S,G,I) assert loser ? */
1417 if (ch
->ifassert_state
!= PIM_IFASSERT_I_AM_LOSER
)
1419 /* Dead neighbor was winner ? */
1420 if (ch
->ifassert_winner
.s_addr
!= neigh_addr
.s_addr
)
1423 assert_action_a5(ch
);
1427 void pim_if_update_join_desired(struct pim_interface
*pim_ifp
)
1429 struct listnode
*ch_node
;
1430 struct pim_ifchannel
*ch
;
1432 /* clear off flag from interface's upstreams */
1433 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_ifchannel_list
, ch_node
, ch
)) {
1434 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(ch
->upstream
->flags
);
1437 /* scan per-interface (S,G,I) state on this I interface */
1438 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_ifchannel_list
, ch_node
, ch
)) {
1439 struct pim_upstream
*up
= ch
->upstream
;
1441 if (PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(up
->flags
))
1444 /* update join_desired for the global (S,G) state */
1445 pim_upstream_update_join_desired(up
);
1446 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(up
->flags
);
1450 void pim_if_update_assert_tracking_desired(struct interface
*ifp
)
1452 struct pim_interface
*pim_ifp
;
1453 struct listnode
*node
;
1454 struct listnode
*next_node
;
1455 struct pim_ifchannel
*ch
;
1457 pim_ifp
= ifp
->info
;
1461 for (ALL_LIST_ELEMENTS(pim_ifp
->pim_ifchannel_list
, node
, next_node
, ch
)) {
1462 pim_ifchannel_update_assert_tracking_desired(ch
);
1467 * PIM wants to have an interface pointer for everything it does.
1468 * The pimreg is a special interface that we have that is not
1469 * quite an inteface but a VIF is created for it.
1471 void pim_if_create_pimreg (void)
1473 if (!pim_regiface
) {
1474 pim_regiface
= if_create("pimreg", strlen("pimreg"), VRF_DEFAULT
);
1475 pim_regiface
->ifindex
= PIM_OIF_PIM_REGISTER_VIF
;
1477 pim_if_new(pim_regiface
, 0, 0);
1482 pim_if_connected_to_source (struct interface
*ifp
, struct in_addr src
)
1484 struct listnode
*cnode
;
1485 struct connected
*c
;
1490 p
.prefixlen
= IPV4_MAX_BITLEN
;
1492 for (ALL_LIST_ELEMENTS_RO (ifp
->connected
, cnode
, c
))
1494 if ((c
->address
->family
== AF_INET
) &&
1495 prefix_match (CONNECTED_PREFIX (c
), &p
))
1505 pim_if_lookup_address_vrf (struct in_addr src
, vrf_id_t vrf_id
)
1507 struct listnode
*ifnode
;
1508 struct interface
*ifp
;
1510 for (ALL_LIST_ELEMENTS_RO (vrf_iflist(vrf_id
), ifnode
, ifp
))
1512 if (pim_if_connected_to_source (ifp
, src
) && ifp
->info
)