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
->pim_ifchannel_list
) {
87 list_delete(pim_ifp
->pim_ifchannel_list
);
90 if (pim_ifp
->pim_ifchannel_hash
)
91 hash_free (pim_ifp
->pim_ifchannel_hash
);
93 XFREE(MTYPE_PIM_INTERFACE
, pim_ifp
);
98 struct pim_interface
*pim_if_new(struct interface
*ifp
, int igmp
, int pim
)
100 struct pim_interface
*pim_ifp
;
105 pim_ifp
= XCALLOC(MTYPE_PIM_INTERFACE
, sizeof(*pim_ifp
));
107 zlog_err("PIM XCALLOC(%zu) failure", sizeof(*pim_ifp
));
111 pim_ifp
->options
= 0;
112 pim_ifp
->mroute_vif_index
= -1;
114 pim_ifp
->igmp_version
= IGMP_DEFAULT_VERSION
;
115 pim_ifp
->igmp_default_robustness_variable
= IGMP_DEFAULT_ROBUSTNESS_VARIABLE
;
116 pim_ifp
->igmp_default_query_interval
= IGMP_GENERAL_QUERY_INTERVAL
;
117 pim_ifp
->igmp_query_max_response_time_dsec
= IGMP_QUERY_MAX_RESPONSE_TIME_DSEC
;
118 pim_ifp
->igmp_specific_query_max_response_time_dsec
= IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC
;
121 RFC 3376: 8.3. Query Response Interval
122 The number of seconds represented by the [Query Response Interval]
123 must be less than the [Query Interval].
125 zassert(pim_ifp
->igmp_query_max_response_time_dsec
< pim_ifp
->igmp_default_query_interval
);
128 PIM_IF_DO_PIM(pim_ifp
->options
);
130 PIM_IF_DO_IGMP(pim_ifp
->options
);
132 PIM_IF_DO_IGMP_LISTEN_ALLROUTERS(pim_ifp
->options
);
134 pim_ifp
->igmp_join_list
= NULL
;
135 pim_ifp
->igmp_socket_list
= NULL
;
136 pim_ifp
->pim_neighbor_list
= NULL
;
137 pim_ifp
->pim_ifchannel_list
= NULL
;
138 pim_ifp
->pim_ifchannel_hash
= NULL
;
139 pim_ifp
->pim_generation_id
= 0;
141 /* list of struct igmp_sock */
142 pim_ifp
->igmp_socket_list
= list_new();
143 if (!pim_ifp
->igmp_socket_list
) {
144 zlog_err("%s %s: failure: igmp_socket_list=list_new()",
145 __FILE__
, __PRETTY_FUNCTION__
);
146 return if_list_clean(pim_ifp
);
148 pim_ifp
->igmp_socket_list
->del
= (void (*)(void *)) igmp_sock_free
;
150 /* list of struct pim_neighbor */
151 pim_ifp
->pim_neighbor_list
= list_new();
152 if (!pim_ifp
->pim_neighbor_list
) {
153 zlog_err("%s %s: failure: pim_neighbor_list=list_new()",
154 __FILE__
, __PRETTY_FUNCTION__
);
155 return if_list_clean(pim_ifp
);
157 pim_ifp
->pim_neighbor_list
->del
= (void (*)(void *)) pim_neighbor_free
;
159 /* list of struct pim_ifchannel */
160 pim_ifp
->pim_ifchannel_list
= list_new();
161 if (!pim_ifp
->pim_ifchannel_list
) {
162 zlog_err("%s %s: failure: pim_ifchannel_list=list_new()",
163 __FILE__
, __PRETTY_FUNCTION__
);
164 return if_list_clean(pim_ifp
);
166 pim_ifp
->pim_ifchannel_list
->del
= (void (*)(void *)) pim_ifchannel_free
;
167 pim_ifp
->pim_ifchannel_list
->cmp
= (int (*)(void *, void *)) pim_ifchannel_compare
;
169 pim_ifp
->pim_ifchannel_hash
= hash_create (pim_ifchannel_hash_key
,
170 pim_ifchannel_equal
);
176 if (PIM_MROUTE_IS_ENABLED
) {
183 void pim_if_delete(struct interface
*ifp
)
185 struct pim_interface
*pim_ifp
;
191 if (pim_ifp
->igmp_join_list
) {
192 pim_if_igmp_join_del_all(ifp
);
195 pim_ifchannel_delete_all (ifp
);
196 igmp_sock_delete_all (ifp
);
198 pim_neighbor_delete_all (ifp
, "Interface removed from configuration");
200 if (PIM_MROUTE_IS_ENABLED
) {
204 list_delete(pim_ifp
->igmp_socket_list
);
205 list_delete(pim_ifp
->pim_neighbor_list
);
206 list_delete(pim_ifp
->pim_ifchannel_list
);
208 hash_free (pim_ifp
->pim_ifchannel_hash
);
210 XFREE(MTYPE_PIM_INTERFACE
, pim_ifp
);
215 void pim_if_update_could_assert(struct interface
*ifp
)
217 struct pim_interface
*pim_ifp
;
218 struct listnode
*node
;
219 struct listnode
*next_node
;
220 struct pim_ifchannel
*ch
;
225 for (ALL_LIST_ELEMENTS(pim_ifp
->pim_ifchannel_list
, node
, next_node
, ch
)) {
226 pim_ifchannel_update_could_assert(ch
);
230 static void pim_if_update_my_assert_metric(struct interface
*ifp
)
232 struct pim_interface
*pim_ifp
;
233 struct listnode
*node
;
234 struct listnode
*next_node
;
235 struct pim_ifchannel
*ch
;
240 for (ALL_LIST_ELEMENTS(pim_ifp
->pim_ifchannel_list
, node
, next_node
, ch
)) {
241 pim_ifchannel_update_my_assert_metric(ch
);
245 static void pim_addr_change(struct interface
*ifp
)
247 struct pim_interface
*pim_ifp
;
252 pim_if_dr_election(ifp
); /* router's own DR Priority (addr) changes -- Done TODO T30 */
253 pim_if_update_join_desired(pim_ifp
); /* depends on DR */
254 pim_if_update_could_assert(ifp
); /* depends on DR */
255 pim_if_update_my_assert_metric(ifp
); /* depends on could_assert */
256 pim_if_update_assert_tracking_desired(ifp
); /* depends on DR, join_desired */
259 RFC 4601: 4.3.1. Sending Hello Messages
261 1) Before an interface goes down or changes primary IP address, a
262 Hello message with a zero HoldTime should be sent immediately
263 (with the old IP address if the IP address changed).
264 -- FIXME See CAVEAT C13
266 2) After an interface has changed its IP address, it MUST send a
267 Hello message with its new IP address.
270 3) If an interface changes one of its secondary IP addresses, a
271 Hello message with an updated Address_List option and a non-zero
272 HoldTime should be sent immediately.
273 -- FIXME See TODO T31
275 pim_ifp
->pim_ifstat_hello_sent
= 0; /* reset hello counter */
276 if (pim_ifp
->pim_sock_fd
< 0)
278 pim_hello_restart_now(ifp
); /* send hello and restart timer */
281 static int detect_primary_address_change(struct interface
*ifp
,
282 int force_prim_as_any
,
285 struct pim_interface
*pim_ifp
= ifp
->info
;
286 struct in_addr new_prim_addr
;
289 if (force_prim_as_any
)
290 new_prim_addr
= qpim_inaddr_any
;
292 new_prim_addr
= pim_find_primary_addr(ifp
);
294 changed
= new_prim_addr
.s_addr
!= pim_ifp
->primary_address
.s_addr
;
296 if (PIM_DEBUG_ZEBRA
) {
297 char new_prim_str
[INET_ADDRSTRLEN
];
298 char old_prim_str
[INET_ADDRSTRLEN
];
299 pim_inet4_dump("<new?>", new_prim_addr
, new_prim_str
, sizeof(new_prim_str
));
300 pim_inet4_dump("<old?>", pim_ifp
->primary_address
, old_prim_str
, sizeof(old_prim_str
));
301 zlog_debug("%s: old=%s new=%s on interface %s: %s",
303 old_prim_str
, new_prim_str
, ifp
->name
,
304 changed
? "changed" : "unchanged");
308 pim_ifp
->primary_address
= new_prim_addr
;
314 static int pim_sec_addr_comp(const void *p1
, const void *p2
)
316 const struct pim_secondary_addr
*sec1
= p1
;
317 const struct pim_secondary_addr
*sec2
= p2
;
319 if (ntohl(sec1
->addr
.s_addr
) < ntohl(sec2
->addr
.s_addr
))
322 if (ntohl(sec1
->addr
.s_addr
) > ntohl(sec2
->addr
.s_addr
))
328 static void pim_sec_addr_free(struct pim_secondary_addr
*sec_addr
)
330 XFREE(MTYPE_PIM_SEC_ADDR
, sec_addr
);
333 static struct pim_secondary_addr
*
334 pim_sec_addr_find(struct pim_interface
*pim_ifp
, struct in_addr addr
)
336 struct pim_secondary_addr
*sec_addr
;
337 struct listnode
*node
;
339 if (!pim_ifp
->sec_addr_list
) {
343 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->sec_addr_list
, node
, sec_addr
)) {
344 if (sec_addr
->addr
.s_addr
== addr
.s_addr
) {
352 static void pim_sec_addr_del(struct pim_interface
*pim_ifp
,
353 struct pim_secondary_addr
*sec_addr
)
355 listnode_delete(pim_ifp
->sec_addr_list
, sec_addr
);
356 pim_sec_addr_free(sec_addr
);
359 static int pim_sec_addr_add(struct pim_interface
*pim_ifp
, struct in_addr addr
)
362 struct pim_secondary_addr
*sec_addr
;
364 sec_addr
= pim_sec_addr_find(pim_ifp
, addr
);
366 sec_addr
->flags
&= ~PIM_SEC_ADDRF_STALE
;
370 if (!pim_ifp
->sec_addr_list
) {
371 pim_ifp
->sec_addr_list
= list_new();
372 pim_ifp
->sec_addr_list
->del
= (void (*)(void *))pim_sec_addr_free
;
373 pim_ifp
->sec_addr_list
->cmp
= (int (*)(void *, void *))pim_sec_addr_comp
;
376 sec_addr
= XCALLOC(MTYPE_PIM_SEC_ADDR
, sizeof(*sec_addr
));
378 if (list_isempty(pim_ifp
->sec_addr_list
)) {
379 list_free(pim_ifp
->sec_addr_list
);
380 pim_ifp
->sec_addr_list
= NULL
;
386 sec_addr
->addr
= addr
;
387 listnode_add_sort(pim_ifp
->sec_addr_list
, sec_addr
);
392 static int pim_sec_addr_del_all(struct pim_interface
*pim_ifp
)
396 if (!pim_ifp
->sec_addr_list
) {
399 if (!list_isempty(pim_ifp
->sec_addr_list
)) {
401 /* remove all nodes and free up the list itself */
402 list_delete_all_node(pim_ifp
->sec_addr_list
);
403 list_free(pim_ifp
->sec_addr_list
);
404 pim_ifp
->sec_addr_list
= NULL
;
410 static int pim_sec_addr_update(struct interface
*ifp
)
412 struct pim_interface
*pim_ifp
= ifp
->info
;
413 struct connected
*ifc
;
414 struct listnode
*node
;
415 struct listnode
*nextnode
;
416 struct pim_secondary_addr
*sec_addr
;
419 if (pim_ifp
->sec_addr_list
) {
420 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->sec_addr_list
, node
, sec_addr
)) {
421 sec_addr
->flags
|= PIM_SEC_ADDRF_STALE
;
425 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, ifc
)) {
426 struct prefix
*p
= ifc
->address
;
428 if (p
->family
!= AF_INET
) {
432 if (PIM_INADDR_IS_ANY(p
->u
.prefix4
)) {
436 if (pim_ifp
->primary_address
.s_addr
== p
->u
.prefix4
.s_addr
) {
437 /* don't add the primary address into the secondary address list */
441 if (pim_sec_addr_add(pim_ifp
, p
->u
.prefix4
)) {
446 if (pim_ifp
->sec_addr_list
) {
447 /* Drop stale entries */
448 for (ALL_LIST_ELEMENTS(pim_ifp
->sec_addr_list
, node
, nextnode
, sec_addr
)) {
449 if (sec_addr
->flags
& PIM_SEC_ADDRF_STALE
) {
450 pim_sec_addr_del(pim_ifp
, sec_addr
);
455 /* If the list went empty free it up */
456 if (list_isempty(pim_ifp
->sec_addr_list
)) {
457 list_free(pim_ifp
->sec_addr_list
);
458 pim_ifp
->sec_addr_list
= NULL
;
465 static int detect_secondary_address_change(struct interface
*ifp
,
466 int force_prim_as_any
,
469 struct pim_interface
*pim_ifp
= ifp
->info
;
472 if (force_prim_as_any
) {
473 /* if primary address is being forced to zero just flush the
474 * secondary address list */
475 changed
= pim_sec_addr_del_all(pim_ifp
);
477 /* re-evaluate the secondary address list */
478 changed
= pim_sec_addr_update(ifp
);
484 static void detect_address_change(struct interface
*ifp
,
485 int force_prim_as_any
,
489 struct pim_interface
*pim_ifp
;
495 if (detect_primary_address_change(ifp
, force_prim_as_any
, caller
)) {
499 if (detect_secondary_address_change(ifp
, force_prim_as_any
, caller
)) {
505 if (!PIM_IF_TEST_PIM(pim_ifp
->options
)) {
509 pim_addr_change(ifp
);
512 /* XXX: if we have unnumbered interfaces we need to run detect address
513 * address change on all of them when the lo address changes */
516 int pim_update_source_set(struct interface
*ifp
, struct in_addr source
)
518 struct pim_interface
*pim_ifp
= ifp
->info
;
521 return PIM_IFACE_NOT_FOUND
;
524 if (pim_ifp
->update_source
.s_addr
== source
.s_addr
) {
525 return PIM_UPDATE_SOURCE_DUP
;
528 pim_ifp
->update_source
= source
;
529 detect_address_change(ifp
, 0 /* force_prim_as_any */,
530 __PRETTY_FUNCTION__
);
535 void pim_if_addr_add(struct connected
*ifc
)
537 struct pim_interface
*pim_ifp
;
538 struct interface
*ifp
;
539 struct in_addr ifaddr
;
549 if (!if_is_operative(ifp
))
552 if (PIM_DEBUG_ZEBRA
) {
554 prefix2str(ifc
->address
, buf
, BUFSIZ
);
555 zlog_debug("%s: %s ifindex=%d connected IP address %s %s",
557 ifp
->name
, ifp
->ifindex
, buf
,
558 CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
) ?
559 "secondary" : "primary");
562 ifaddr
= ifc
->address
->u
.prefix4
;
564 detect_address_change(ifp
, 0, __PRETTY_FUNCTION__
);
566 if (PIM_IF_TEST_IGMP(pim_ifp
->options
)) {
567 struct igmp_sock
*igmp
;
569 /* lookup IGMP socket */
570 igmp
= pim_igmp_sock_lookup_ifaddr(pim_ifp
->igmp_socket_list
,
573 /* if addr new, add IGMP socket */
574 pim_igmp_sock_add(pim_ifp
->igmp_socket_list
, ifaddr
, ifp
);
578 if (PIM_IF_TEST_PIM(pim_ifp
->options
)) {
580 /* Interface has a valid primary address ? */
581 if (PIM_INADDR_ISNOT_ANY(pim_ifp
->primary_address
)) {
583 /* Interface has a valid socket ? */
584 if (pim_ifp
->pim_sock_fd
< 0) {
585 if (pim_sock_add(ifp
)) {
586 zlog_warn("Failure creating PIM socket for interface %s",
594 if (PIM_MROUTE_IS_ENABLED
) {
596 PIM or IGMP is enabled on interface, and there is at least one
597 address assigned, then try to create a vif_index.
599 if (pim_ifp
->mroute_vif_index
< 0) {
602 pim_ifchannel_scan_forward_start (ifp
);
606 static void pim_if_addr_del_igmp(struct connected
*ifc
)
608 struct pim_interface
*pim_ifp
= ifc
->ifp
->info
;
609 struct igmp_sock
*igmp
;
610 struct in_addr ifaddr
;
612 if (ifc
->address
->family
!= AF_INET
) {
613 /* non-IPv4 address */
618 /* IGMP not enabled on interface */
622 ifaddr
= ifc
->address
->u
.prefix4
;
624 /* lookup IGMP socket */
625 igmp
= pim_igmp_sock_lookup_ifaddr(pim_ifp
->igmp_socket_list
,
628 /* if addr found, del IGMP socket */
629 igmp_sock_delete(igmp
);
633 static void pim_if_addr_del_pim(struct connected
*ifc
)
635 struct pim_interface
*pim_ifp
= ifc
->ifp
->info
;
637 if (ifc
->address
->family
!= AF_INET
) {
638 /* non-IPv4 address */
643 /* PIM not enabled on interface */
647 if (PIM_INADDR_ISNOT_ANY(pim_ifp
->primary_address
)) {
648 /* Interface keeps a valid primary address */
652 if (pim_ifp
->pim_sock_fd
< 0) {
653 /* Interface does not hold a valid socket any longer */
658 pim_sock_delete() closes the socket, stops read and timer threads,
659 and kills all neighbors.
661 pim_sock_delete(ifc
->ifp
, "last address has been removed from interface");
664 void pim_if_addr_del(struct connected
*ifc
, int force_prim_as_any
)
666 struct interface
*ifp
;
672 if (PIM_DEBUG_ZEBRA
) {
674 prefix2str(ifc
->address
, buf
, BUFSIZ
);
675 zlog_debug("%s: %s ifindex=%d disconnected IP address %s %s",
677 ifp
->name
, ifp
->ifindex
, buf
,
678 CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
) ?
679 "secondary" : "primary");
682 detect_address_change(ifp
, force_prim_as_any
, __PRETTY_FUNCTION__
);
684 pim_if_addr_del_igmp(ifc
);
685 pim_if_addr_del_pim(ifc
);
688 void pim_if_addr_add_all(struct interface
*ifp
)
690 struct connected
*ifc
;
691 struct listnode
*node
;
692 struct listnode
*nextnode
;
695 struct pim_interface
*pim_ifp
= ifp
->info
;
698 /* PIM/IGMP enabled ? */
702 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
703 struct prefix
*p
= ifc
->address
;
705 if (p
->family
!= AF_INET
)
712 pim_if_addr_add(ifc
);
715 if (!v4_addrs
&& v6_addrs
&& !if_is_loopback (ifp
))
717 if (PIM_IF_TEST_PIM(pim_ifp
->options
)) {
719 /* Interface has a valid primary address ? */
720 if (PIM_INADDR_ISNOT_ANY(pim_ifp
->primary_address
)) {
722 /* Interface has a valid socket ? */
723 if (pim_ifp
->pim_sock_fd
< 0) {
724 if (pim_sock_add(ifp
)) {
725 zlog_warn("Failure creating PIM socket for interface %s",
733 if (PIM_MROUTE_IS_ENABLED
) {
735 * PIM or IGMP is enabled on interface, and there is at least one
736 * address assigned, then try to create a vif_index.
738 if (pim_ifp
->mroute_vif_index
< 0) {
741 pim_ifchannel_scan_forward_start (ifp
);
745 pim_rp_check_on_if_add(pim_ifp
);
748 void pim_if_addr_del_all(struct interface
*ifp
)
750 struct connected
*ifc
;
751 struct listnode
*node
;
752 struct listnode
*nextnode
;
754 /* PIM/IGMP enabled ? */
758 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
759 struct prefix
*p
= ifc
->address
;
761 if (p
->family
!= AF_INET
)
764 pim_if_addr_del(ifc
, 1 /* force_prim_as_any=true */);
768 pim_i_am_rp_re_evaluate();
771 void pim_if_addr_del_all_igmp(struct interface
*ifp
)
773 struct connected
*ifc
;
774 struct listnode
*node
;
775 struct listnode
*nextnode
;
777 /* PIM/IGMP enabled ? */
781 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
782 struct prefix
*p
= ifc
->address
;
784 if (p
->family
!= AF_INET
)
787 pim_if_addr_del_igmp(ifc
);
791 void pim_if_addr_del_all_pim(struct interface
*ifp
)
793 struct connected
*ifc
;
794 struct listnode
*node
;
795 struct listnode
*nextnode
;
797 /* PIM/IGMP enabled ? */
801 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
802 struct prefix
*p
= ifc
->address
;
804 if (p
->family
!= AF_INET
)
807 pim_if_addr_del_pim(ifc
);
812 pim_find_primary_addr (struct interface
*ifp
)
814 struct connected
*ifc
;
815 struct listnode
*node
;
819 struct pim_interface
*pim_ifp
= ifp
->info
;
821 if (pim_ifp
&& PIM_INADDR_ISNOT_ANY(pim_ifp
->update_source
)) {
822 return pim_ifp
->update_source
;
825 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, ifc
)) {
826 struct prefix
*p
= ifc
->address
;
828 if (p
->family
!= AF_INET
)
834 if (PIM_INADDR_IS_ANY(p
->u
.prefix4
)) {
835 zlog_warn("%s: null IPv4 address connected to interface %s",
836 __PRETTY_FUNCTION__
, ifp
->name
);
842 if (CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
))
849 * If we have no v4_addrs and v6 is configured
850 * We probably are using unnumbered
851 * So let's grab the loopbacks v4 address
852 * and use that as the primary address
854 if (!v4_addrs
&& v6_addrs
&& !if_is_loopback (ifp
))
856 struct interface
*lo_ifp
;
857 lo_ifp
= if_lookup_by_name_vrf ("lo", VRF_DEFAULT
);
859 return pim_find_primary_addr (lo_ifp
);
862 addr
.s_addr
= PIM_NET_INADDR_ANY
;
868 pim_iface_next_vif_index (struct interface
*ifp
)
872 * The pimreg vif is always going to be in index 0
875 if (ifp
->ifindex
== PIM_OIF_PIM_REGISTER_VIF
)
878 for (i
= 1 ; i
< MAXVIFS
; i
++)
880 if (pim_iface_vif_index
[i
] == 0)
887 pim_if_add_vif() uses ifindex as vif_index
889 see also pim_if_find_vifindex_by_ifindex()
891 int pim_if_add_vif(struct interface
*ifp
)
893 struct pim_interface
*pim_ifp
= ifp
->info
;
894 struct in_addr ifaddr
;
895 unsigned char flags
= 0;
899 if (pim_ifp
->mroute_vif_index
> 0) {
900 zlog_warn("%s: vif_index=%d > 0 on interface %s ifindex=%d",
902 pim_ifp
->mroute_vif_index
, ifp
->name
, ifp
->ifindex
);
906 if (ifp
->ifindex
< 0) {
907 zlog_warn("%s: ifindex=%d < 1 on interface %s",
909 ifp
->ifindex
, ifp
->name
);
913 ifaddr
= pim_ifp
->primary_address
;
914 if (ifp
->ifindex
!= PIM_OIF_PIM_REGISTER_VIF
&& PIM_INADDR_IS_ANY(ifaddr
)) {
915 zlog_warn("%s: could not get address for interface %s ifindex=%d",
917 ifp
->name
, ifp
->ifindex
);
921 pim_ifp
->mroute_vif_index
= pim_iface_next_vif_index (ifp
);
923 if (pim_ifp
->mroute_vif_index
>= MAXVIFS
)
925 zlog_warn("%s: Attempting to configure more than MAXVIFS=%d on pim enabled interface %s",
931 if (ifp
->ifindex
== PIM_OIF_PIM_REGISTER_VIF
)
932 flags
= VIFF_REGISTER
;
933 #ifdef VIFF_USE_IFINDEX
935 flags
= VIFF_USE_IFINDEX
;
938 if (pim_mroute_add_vif(ifp
, ifaddr
, flags
)) {
939 /* pim_mroute_add_vif reported error */
943 pim_iface_vif_index
[pim_ifp
->mroute_vif_index
] = 1;
947 int pim_if_del_vif(struct interface
*ifp
)
949 struct pim_interface
*pim_ifp
= ifp
->info
;
951 if (pim_ifp
->mroute_vif_index
< 1) {
952 zlog_warn("%s: vif_index=%d < 1 on interface %s ifindex=%d",
954 pim_ifp
->mroute_vif_index
, ifp
->name
, ifp
->ifindex
);
958 pim_mroute_del_vif(pim_ifp
->mroute_vif_index
);
963 pim_iface_vif_index
[pim_ifp
->mroute_vif_index
] = 0;
965 pim_ifp
->mroute_vif_index
= -1;
970 void pim_if_add_vif_all()
972 struct listnode
*ifnode
;
973 struct listnode
*ifnextnode
;
974 struct interface
*ifp
;
976 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT
), ifnode
, ifnextnode
, ifp
)) {
984 void pim_if_del_vif_all()
986 struct listnode
*ifnode
;
987 struct listnode
*ifnextnode
;
988 struct interface
*ifp
;
990 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT
), ifnode
, ifnextnode
, ifp
)) {
998 struct interface
*pim_if_find_by_vif_index(ifindex_t vif_index
)
1000 struct listnode
*ifnode
;
1001 struct interface
*ifp
;
1004 return if_lookup_by_name_vrf ("pimreg", VRF_DEFAULT
);
1006 for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT
), ifnode
, ifp
)) {
1008 struct pim_interface
*pim_ifp
;
1009 pim_ifp
= ifp
->info
;
1011 if (vif_index
== pim_ifp
->mroute_vif_index
)
1020 pim_if_add_vif() uses ifindex as vif_index
1022 int pim_if_find_vifindex_by_ifindex(ifindex_t ifindex
)
1024 struct pim_interface
*pim_ifp
;
1025 struct interface
*ifp
;
1027 ifp
= if_lookup_by_index_vrf (ifindex
, VRF_DEFAULT
);
1028 if (!ifp
|| !ifp
->info
)
1030 pim_ifp
= ifp
->info
;
1032 return pim_ifp
->mroute_vif_index
;
1035 int pim_if_lan_delay_enabled(struct interface
*ifp
)
1037 struct pim_interface
*pim_ifp
;
1039 pim_ifp
= ifp
->info
;
1041 zassert(pim_ifp
->pim_number_of_nonlandelay_neighbors
>= 0);
1043 return pim_ifp
->pim_number_of_nonlandelay_neighbors
== 0;
1046 uint16_t pim_if_effective_propagation_delay_msec(struct interface
*ifp
)
1048 if (pim_if_lan_delay_enabled(ifp
)) {
1049 struct pim_interface
*pim_ifp
;
1050 pim_ifp
= ifp
->info
;
1051 return pim_ifp
->pim_neighbors_highest_propagation_delay_msec
;
1054 return PIM_DEFAULT_PROPAGATION_DELAY_MSEC
;
1058 uint16_t pim_if_effective_override_interval_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_override_interval_msec
;
1066 return PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC
;
1070 int pim_if_t_override_msec(struct interface
*ifp
)
1072 int effective_override_interval_msec
;
1073 int t_override_msec
;
1075 effective_override_interval_msec
=
1076 pim_if_effective_override_interval_msec(ifp
);
1078 t_override_msec
= random() % (effective_override_interval_msec
+ 1);
1080 return t_override_msec
;
1083 uint16_t pim_if_jp_override_interval_msec(struct interface
*ifp
)
1085 return pim_if_effective_propagation_delay_msec(ifp
) +
1086 pim_if_effective_override_interval_msec(ifp
);
1090 RFC 4601: 4.1.6. State Summarization Macros
1092 The function NBR( I, A ) uses information gathered through PIM Hello
1093 messages to map the IP address A of a directly connected PIM
1094 neighbor router on interface I to the primary IP address of the same
1095 router (Section 4.3.4). The primary IP address of a neighbor is the
1096 address that it uses as the source of its PIM Hello messages.
1098 struct pim_neighbor
*pim_if_find_neighbor(struct interface
*ifp
,
1099 struct in_addr addr
)
1101 struct listnode
*neighnode
;
1102 struct pim_neighbor
*neigh
;
1103 struct pim_interface
*pim_ifp
;
1107 pim_ifp
= ifp
->info
;
1109 zlog_warn("%s: multicast not enabled on interface %s",
1110 __PRETTY_FUNCTION__
,
1115 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
, neighnode
, neigh
)) {
1117 /* primary address ? */
1118 if (neigh
->source_addr
.s_addr
== addr
.s_addr
)
1121 /* secondary address ? */
1122 if (pim_neighbor_find_secondary(neigh
, addr
))
1126 if (PIM_DEBUG_PIM_TRACE
) {
1127 char addr_str
[INET_ADDRSTRLEN
];
1128 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
1129 zlog_debug("%s: neighbor not found for address %s on interface %s",
1130 __PRETTY_FUNCTION__
,
1131 addr_str
, ifp
->name
);
1137 long pim_if_t_suppressed_msec(struct interface
*ifp
)
1139 struct pim_interface
*pim_ifp
;
1140 long t_suppressed_msec
;
1141 uint32_t ramount
= 0;
1143 pim_ifp
= ifp
->info
;
1146 /* join suppression disabled ? */
1147 if (PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp
->options
))
1150 /* t_suppressed = t_periodic * rand(1.1, 1.4) */
1151 ramount
= 1100 + (random() % (1400 - 1100 + 1));
1152 t_suppressed_msec
= qpim_t_periodic
* ramount
;
1154 return t_suppressed_msec
;
1157 static void igmp_join_free(struct igmp_join
*ij
)
1159 XFREE(MTYPE_PIM_IGMP_JOIN
, ij
);
1162 static struct igmp_join
*igmp_join_find(struct list
*join_list
,
1163 struct in_addr group_addr
,
1164 struct in_addr source_addr
)
1166 struct listnode
*node
;
1167 struct igmp_join
*ij
;
1171 for (ALL_LIST_ELEMENTS_RO(join_list
, node
, ij
)) {
1172 if ((group_addr
.s_addr
== ij
->group_addr
.s_addr
) &&
1173 (source_addr
.s_addr
== ij
->source_addr
.s_addr
))
1180 static int igmp_join_sock(const char *ifname
,
1182 struct in_addr group_addr
,
1183 struct in_addr source_addr
)
1187 join_fd
= pim_socket_raw(IPPROTO_IGMP
);
1192 if (pim_socket_join_source(join_fd
, ifindex
, group_addr
, source_addr
, ifname
)) {
1200 static struct igmp_join
*igmp_join_new(struct interface
*ifp
,
1201 struct in_addr group_addr
,
1202 struct in_addr source_addr
)
1204 struct pim_interface
*pim_ifp
;
1205 struct igmp_join
*ij
;
1208 pim_ifp
= ifp
->info
;
1211 join_fd
= igmp_join_sock(ifp
->name
, ifp
->ifindex
, group_addr
, source_addr
);
1213 char group_str
[INET_ADDRSTRLEN
];
1214 char source_str
[INET_ADDRSTRLEN
];
1215 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
1216 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
1217 zlog_warn("%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s",
1218 __PRETTY_FUNCTION__
,
1219 group_str
, source_str
, ifp
->name
);
1223 ij
= XCALLOC(MTYPE_PIM_IGMP_JOIN
, sizeof(*ij
));
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_err("%s: XCALLOC(%zu) failure for IGMP group %s source %s on interface %s",
1230 __PRETTY_FUNCTION__
,
1231 sizeof(*ij
), group_str
, source_str
, ifp
->name
);
1236 ij
->sock_fd
= join_fd
;
1237 ij
->group_addr
= group_addr
;
1238 ij
->source_addr
= source_addr
;
1239 ij
->sock_creation
= pim_time_monotonic_sec();
1241 listnode_add(pim_ifp
->igmp_join_list
, ij
);
1246 int pim_if_igmp_join_add(struct interface
*ifp
,
1247 struct in_addr group_addr
,
1248 struct in_addr source_addr
)
1250 struct pim_interface
*pim_ifp
;
1251 struct igmp_join
*ij
;
1253 pim_ifp
= ifp
->info
;
1255 zlog_warn("%s: multicast not enabled on interface %s",
1256 __PRETTY_FUNCTION__
,
1261 if (!pim_ifp
->igmp_join_list
) {
1262 pim_ifp
->igmp_join_list
= list_new();
1263 if (!pim_ifp
->igmp_join_list
) {
1264 zlog_err("%s %s: failure: igmp_join_list=list_new()",
1265 __FILE__
, __PRETTY_FUNCTION__
);
1268 pim_ifp
->igmp_join_list
->del
= (void (*)(void *)) igmp_join_free
;
1271 ij
= igmp_join_find(pim_ifp
->igmp_join_list
, group_addr
, source_addr
);
1273 char group_str
[INET_ADDRSTRLEN
];
1274 char source_str
[INET_ADDRSTRLEN
];
1275 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
1276 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
1277 zlog_warn("%s: can't re-join existing IGMP group %s source %s on interface %s",
1278 __PRETTY_FUNCTION__
,
1279 group_str
, source_str
, ifp
->name
);
1283 ij
= igmp_join_new(ifp
, 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: igmp_join_new() failure for IGMP group %s source %s on interface %s",
1290 __PRETTY_FUNCTION__
,
1291 group_str
, source_str
, ifp
->name
);
1295 if (PIM_DEBUG_IGMP_EVENTS
) {
1296 char group_str
[INET_ADDRSTRLEN
];
1297 char source_str
[INET_ADDRSTRLEN
];
1298 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
1299 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
1300 zlog_debug("%s: issued static igmp join for channel (S,G)=(%s,%s) on interface %s",
1301 __PRETTY_FUNCTION__
,
1302 source_str
, group_str
, ifp
->name
);
1310 int pim_if_igmp_join_del(struct interface
*ifp
,
1311 struct in_addr group_addr
,
1312 struct in_addr source_addr
)
1314 struct pim_interface
*pim_ifp
;
1315 struct igmp_join
*ij
;
1317 pim_ifp
= ifp
->info
;
1319 zlog_warn("%s: multicast not enabled on interface %s",
1320 __PRETTY_FUNCTION__
,
1325 if (!pim_ifp
->igmp_join_list
) {
1326 zlog_warn("%s: no IGMP join on interface %s",
1327 __PRETTY_FUNCTION__
,
1332 ij
= igmp_join_find(pim_ifp
->igmp_join_list
, group_addr
, source_addr
);
1334 char group_str
[INET_ADDRSTRLEN
];
1335 char source_str
[INET_ADDRSTRLEN
];
1336 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
1337 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
1338 zlog_warn("%s: could not find IGMP group %s source %s on interface %s",
1339 __PRETTY_FUNCTION__
,
1340 group_str
, source_str
, ifp
->name
);
1344 if (close(ij
->sock_fd
)) {
1345 char group_str
[INET_ADDRSTRLEN
];
1346 char source_str
[INET_ADDRSTRLEN
];
1347 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
1348 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
1349 zlog_warn("%s: failure closing sock_fd=%d for IGMP group %s source %s on interface %s: errno=%d: %s",
1350 __PRETTY_FUNCTION__
,
1351 ij
->sock_fd
, group_str
, source_str
, ifp
->name
, errno
, safe_strerror(errno
));
1354 listnode_delete(pim_ifp
->igmp_join_list
, ij
);
1356 if (listcount(pim_ifp
->igmp_join_list
) < 1) {
1357 list_delete(pim_ifp
->igmp_join_list
);
1358 pim_ifp
->igmp_join_list
= 0;
1364 static void pim_if_igmp_join_del_all(struct interface
*ifp
)
1366 struct pim_interface
*pim_ifp
;
1367 struct listnode
*node
;
1368 struct listnode
*nextnode
;
1369 struct igmp_join
*ij
;
1371 pim_ifp
= ifp
->info
;
1373 zlog_warn("%s: multicast not enabled on interface %s",
1374 __PRETTY_FUNCTION__
,
1379 if (!pim_ifp
->igmp_join_list
)
1382 for (ALL_LIST_ELEMENTS(pim_ifp
->igmp_join_list
, node
, nextnode
, ij
))
1383 pim_if_igmp_join_del(ifp
, ij
->group_addr
, ij
->source_addr
);
1389 Transitions from "I am Assert Loser" State
1391 Current Winner's GenID Changes or NLT Expires
1393 The Neighbor Liveness Timer associated with the current winner
1394 expires or we receive a Hello message from the current winner
1395 reporting a different GenID from the one it previously reported.
1396 This indicates that the current winner's interface or router has
1397 gone down (and may have come back up), and so we must assume it no
1398 longer knows it was the winner.
1400 void pim_if_assert_on_neighbor_down(struct interface
*ifp
,
1401 struct in_addr neigh_addr
)
1403 struct pim_interface
*pim_ifp
;
1404 struct listnode
*node
;
1405 struct listnode
*next_node
;
1406 struct pim_ifchannel
*ch
;
1408 pim_ifp
= ifp
->info
;
1411 for (ALL_LIST_ELEMENTS(pim_ifp
->pim_ifchannel_list
, node
, next_node
, ch
)) {
1412 /* Is (S,G,I) assert loser ? */
1413 if (ch
->ifassert_state
!= PIM_IFASSERT_I_AM_LOSER
)
1415 /* Dead neighbor was winner ? */
1416 if (ch
->ifassert_winner
.s_addr
!= neigh_addr
.s_addr
)
1419 assert_action_a5(ch
);
1423 void pim_if_update_join_desired(struct pim_interface
*pim_ifp
)
1425 struct listnode
*ch_node
;
1426 struct pim_ifchannel
*ch
;
1428 /* clear off flag from interface's upstreams */
1429 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_ifchannel_list
, ch_node
, ch
)) {
1430 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(ch
->upstream
->flags
);
1433 /* scan per-interface (S,G,I) state on this I interface */
1434 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_ifchannel_list
, ch_node
, ch
)) {
1435 struct pim_upstream
*up
= ch
->upstream
;
1437 if (PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(up
->flags
))
1440 /* update join_desired for the global (S,G) state */
1441 pim_upstream_update_join_desired(up
);
1442 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(up
->flags
);
1446 void pim_if_update_assert_tracking_desired(struct interface
*ifp
)
1448 struct pim_interface
*pim_ifp
;
1449 struct listnode
*node
;
1450 struct listnode
*next_node
;
1451 struct pim_ifchannel
*ch
;
1453 pim_ifp
= ifp
->info
;
1457 for (ALL_LIST_ELEMENTS(pim_ifp
->pim_ifchannel_list
, node
, next_node
, ch
)) {
1458 pim_ifchannel_update_assert_tracking_desired(ch
);
1463 * PIM wants to have an interface pointer for everything it does.
1464 * The pimreg is a special interface that we have that is not
1465 * quite an inteface but a VIF is created for it.
1467 void pim_if_create_pimreg (void)
1469 if (!pim_regiface
) {
1470 pim_regiface
= if_create("pimreg", strlen("pimreg"));
1471 pim_regiface
->ifindex
= PIM_OIF_PIM_REGISTER_VIF
;
1473 pim_if_new(pim_regiface
, 0, 0);
1478 pim_if_connected_to_source (struct interface
*ifp
, struct in_addr src
)
1480 struct listnode
*cnode
;
1481 struct connected
*c
;
1486 p
.prefixlen
= IPV4_MAX_BITLEN
;
1488 for (ALL_LIST_ELEMENTS_RO (ifp
->connected
, cnode
, c
))
1490 if ((c
->address
->family
== AF_INET
) &&
1491 prefix_match (CONNECTED_PREFIX (c
), &p
))
1501 pim_if_lookup_address_vrf (struct in_addr src
, vrf_id_t vrf_id
)
1503 struct listnode
*ifnode
;
1504 struct interface
*ifp
;
1506 for (ALL_LIST_ELEMENTS_RO (vrf_iflist(vrf_id
), ifnode
, ifp
))
1508 if (pim_if_connected_to_source (ifp
, src
) && ifp
->info
)