3 * Copyright (C) 2008 Everton da Silva Marques
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; see the file COPYING; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
32 #include "pim_zebra.h"
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"
47 struct interface
*pim_regiface
= NULL
;
48 struct list
*pim_ifchannel_list
= NULL
;
49 static int pim_iface_vif_index
[MAXVIFS
];
51 static void pim_if_igmp_join_del_all(struct interface
*ifp
);
52 static int igmp_join_sock(const char *ifname
, ifindex_t ifindex
,
53 struct in_addr group_addr
, struct in_addr source_addr
);
60 for (i
= 0; i
< MAXVIFS
; i
++)
61 pim_iface_vif_index
[i
] = 0;
63 pim_ifchannel_list
= list_new();
64 pim_ifchannel_list
->cmp
= (int (*)(void *, void *))pim_ifchannel_compare
;
68 pim_if_terminate (void)
70 if (pim_ifchannel_list
)
71 list_free (pim_ifchannel_list
);
74 static void *if_list_clean(struct pim_interface
*pim_ifp
)
76 if (pim_ifp
->igmp_join_list
) {
77 list_delete(pim_ifp
->igmp_join_list
);
80 if (pim_ifp
->igmp_socket_list
) {
81 list_delete(pim_ifp
->igmp_socket_list
);
84 if (pim_ifp
->pim_neighbor_list
) {
85 list_delete(pim_ifp
->pim_neighbor_list
);
88 if (pim_ifp
->upstream_switch_list
)
89 list_delete(pim_ifp
->upstream_switch_list
);
91 if (pim_ifp
->pim_ifchannel_list
) {
92 list_delete(pim_ifp
->pim_ifchannel_list
);
95 if (pim_ifp
->pim_ifchannel_hash
)
96 hash_free(pim_ifp
->pim_ifchannel_hash
);
98 XFREE(MTYPE_PIM_INTERFACE
, pim_ifp
);
103 struct pim_interface
*pim_if_new(struct interface
*ifp
, int igmp
, int pim
)
105 struct pim_interface
*pim_ifp
;
110 pim_ifp
= XCALLOC(MTYPE_PIM_INTERFACE
, sizeof(*pim_ifp
));
112 zlog_err("PIM XCALLOC(%zu) failure", sizeof(*pim_ifp
));
116 pim_ifp
->options
= 0;
117 pim_ifp
->mroute_vif_index
= -1;
119 pim_ifp
->igmp_version
= IGMP_DEFAULT_VERSION
;
120 pim_ifp
->igmp_default_robustness_variable
= IGMP_DEFAULT_ROBUSTNESS_VARIABLE
;
121 pim_ifp
->igmp_default_query_interval
= IGMP_GENERAL_QUERY_INTERVAL
;
122 pim_ifp
->igmp_query_max_response_time_dsec
= IGMP_QUERY_MAX_RESPONSE_TIME_DSEC
;
123 pim_ifp
->igmp_specific_query_max_response_time_dsec
= IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC
;
126 RFC 3376: 8.3. Query Response Interval
127 The number of seconds represented by the [Query Response Interval]
128 must be less than the [Query Interval].
130 zassert(pim_ifp
->igmp_query_max_response_time_dsec
< pim_ifp
->igmp_default_query_interval
);
133 PIM_IF_DO_PIM(pim_ifp
->options
);
135 PIM_IF_DO_IGMP(pim_ifp
->options
);
137 PIM_IF_DO_IGMP_LISTEN_ALLROUTERS(pim_ifp
->options
);
139 pim_ifp
->igmp_join_list
= NULL
;
140 pim_ifp
->igmp_socket_list
= NULL
;
141 pim_ifp
->pim_neighbor_list
= NULL
;
142 pim_ifp
->upstream_switch_list
= NULL
;
143 pim_ifp
->pim_ifchannel_list
= NULL
;
144 pim_ifp
->pim_ifchannel_hash
= NULL
;
145 pim_ifp
->pim_generation_id
= 0;
147 /* list of struct igmp_sock */
148 pim_ifp
->igmp_socket_list
= list_new();
149 if (!pim_ifp
->igmp_socket_list
) {
150 zlog_err("%s %s: failure: igmp_socket_list=list_new()",
151 __FILE__
, __PRETTY_FUNCTION__
);
152 return if_list_clean(pim_ifp
);
154 pim_ifp
->igmp_socket_list
->del
= (void (*)(void *)) igmp_sock_free
;
156 /* list of struct pim_neighbor */
157 pim_ifp
->pim_neighbor_list
= list_new();
158 if (!pim_ifp
->pim_neighbor_list
) {
159 zlog_err("%s %s: failure: pim_neighbor_list=list_new()",
160 __FILE__
, __PRETTY_FUNCTION__
);
161 return if_list_clean(pim_ifp
);
163 pim_ifp
->pim_neighbor_list
->del
= (void (*)(void *)) pim_neighbor_free
;
165 pim_ifp
->upstream_switch_list
= list_new();
166 if (!pim_ifp
->upstream_switch_list
) {
167 zlog_err("%s %s: failure: upstream_switch_list=list_new()",
168 __FILE__
, __PRETTY_FUNCTION__
);
169 return if_list_clean(pim_ifp
);
172 /* list of struct pim_ifchannel */
173 pim_ifp
->pim_ifchannel_list
= list_new();
174 if (!pim_ifp
->pim_ifchannel_list
) {
175 zlog_err("%s %s: failure: pim_ifchannel_list=list_new()",
176 __FILE__
, __PRETTY_FUNCTION__
);
177 return if_list_clean(pim_ifp
);
179 pim_ifp
->pim_ifchannel_list
->del
= (void (*)(void *)) pim_ifchannel_free
;
180 pim_ifp
->pim_ifchannel_list
->cmp
= (int (*)(void *, void *)) pim_ifchannel_compare
;
182 pim_ifp
->pim_ifchannel_hash
= hash_create (pim_ifchannel_hash_key
,
183 pim_ifchannel_equal
, NULL
);
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");
213 list_delete(pim_ifp
->igmp_socket_list
);
214 list_delete(pim_ifp
->pim_neighbor_list
);
215 list_delete(pim_ifp
->upstream_switch_list
);
216 list_delete(pim_ifp
->pim_ifchannel_list
);
218 hash_free (pim_ifp
->pim_ifchannel_hash
);
220 XFREE(MTYPE_PIM_INTERFACE
, pim_ifp
);
225 void pim_if_update_could_assert(struct interface
*ifp
)
227 struct pim_interface
*pim_ifp
;
228 struct listnode
*node
;
229 struct listnode
*next_node
;
230 struct pim_ifchannel
*ch
;
235 for (ALL_LIST_ELEMENTS(pim_ifp
->pim_ifchannel_list
, node
, next_node
, ch
)) {
236 pim_ifchannel_update_could_assert(ch
);
240 static void pim_if_update_my_assert_metric(struct interface
*ifp
)
242 struct pim_interface
*pim_ifp
;
243 struct listnode
*node
;
244 struct listnode
*next_node
;
245 struct pim_ifchannel
*ch
;
250 for (ALL_LIST_ELEMENTS(pim_ifp
->pim_ifchannel_list
, node
, next_node
, ch
)) {
251 pim_ifchannel_update_my_assert_metric(ch
);
255 static void pim_addr_change(struct interface
*ifp
)
257 struct pim_interface
*pim_ifp
;
262 pim_if_dr_election(ifp
); /* router's own DR Priority (addr) changes -- Done TODO T30 */
263 pim_if_update_join_desired(pim_ifp
); /* depends on DR */
264 pim_if_update_could_assert(ifp
); /* depends on DR */
265 pim_if_update_my_assert_metric(ifp
); /* depends on could_assert */
266 pim_if_update_assert_tracking_desired(ifp
); /* depends on DR, join_desired */
269 RFC 4601: 4.3.1. Sending Hello Messages
271 1) Before an interface goes down or changes primary IP address, a
272 Hello message with a zero HoldTime should be sent immediately
273 (with the old IP address if the IP address changed).
274 -- FIXME See CAVEAT C13
276 2) After an interface has changed its IP address, it MUST send a
277 Hello message with its new IP address.
280 3) If an interface changes one of its secondary IP addresses, a
281 Hello message with an updated Address_List option and a non-zero
282 HoldTime should be sent immediately.
283 -- FIXME See TODO T31
285 pim_ifp
->pim_ifstat_hello_sent
= 0; /* reset hello counter */
286 if (pim_ifp
->pim_sock_fd
< 0)
288 pim_hello_restart_now(ifp
); /* send hello and restart timer */
291 static int detect_primary_address_change(struct interface
*ifp
,
292 int force_prim_as_any
,
295 struct pim_interface
*pim_ifp
= ifp
->info
;
296 struct in_addr new_prim_addr
;
299 if (force_prim_as_any
)
300 new_prim_addr
.s_addr
= INADDR_ANY
;
302 new_prim_addr
= pim_find_primary_addr(ifp
);
304 changed
= new_prim_addr
.s_addr
!= pim_ifp
->primary_address
.s_addr
;
306 if (PIM_DEBUG_ZEBRA
) {
307 char new_prim_str
[INET_ADDRSTRLEN
];
308 char old_prim_str
[INET_ADDRSTRLEN
];
309 pim_inet4_dump("<new?>", new_prim_addr
, new_prim_str
, sizeof(new_prim_str
));
310 pim_inet4_dump("<old?>", pim_ifp
->primary_address
, old_prim_str
, sizeof(old_prim_str
));
311 zlog_debug("%s: old=%s new=%s on interface %s: %s",
313 old_prim_str
, new_prim_str
, ifp
->name
,
314 changed
? "changed" : "unchanged");
318 pim_ifp
->primary_address
= new_prim_addr
;
324 static int pim_sec_addr_comp(const void *p1
, const void *p2
)
326 const struct pim_secondary_addr
*sec1
= p1
;
327 const struct pim_secondary_addr
*sec2
= p2
;
329 if (sec1
->addr
.family
== AF_INET
&&
330 sec2
->addr
.family
== AF_INET6
)
333 if (sec1
->addr
.family
== AF_INET6
&&
334 sec2
->addr
.family
== AF_INET
)
337 if (sec1
->addr
.family
== AF_INET
)
339 if (ntohl(sec1
->addr
.u
.prefix4
.s_addr
) < ntohl(sec2
->addr
.u
.prefix4
.s_addr
))
342 if (ntohl(sec1
->addr
.u
.prefix4
.s_addr
) > ntohl(sec2
->addr
.u
.prefix4
.s_addr
))
347 return memcmp (&sec1
->addr
.u
.prefix6
,
348 &sec2
->addr
.u
.prefix6
,
349 sizeof (struct in6_addr
));
355 static void pim_sec_addr_free(struct pim_secondary_addr
*sec_addr
)
357 XFREE(MTYPE_PIM_SEC_ADDR
, sec_addr
);
360 static struct pim_secondary_addr
*
361 pim_sec_addr_find(struct pim_interface
*pim_ifp
, struct prefix
*addr
)
363 struct pim_secondary_addr
*sec_addr
;
364 struct listnode
*node
;
366 if (!pim_ifp
->sec_addr_list
) {
370 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->sec_addr_list
, node
, sec_addr
)) {
371 if (prefix_cmp(&sec_addr
->addr
, addr
)) {
379 static void pim_sec_addr_del(struct pim_interface
*pim_ifp
,
380 struct pim_secondary_addr
*sec_addr
)
382 listnode_delete(pim_ifp
->sec_addr_list
, sec_addr
);
383 pim_sec_addr_free(sec_addr
);
386 static int pim_sec_addr_add(struct pim_interface
*pim_ifp
, struct prefix
*addr
)
389 struct pim_secondary_addr
*sec_addr
;
391 sec_addr
= pim_sec_addr_find(pim_ifp
, addr
);
393 sec_addr
->flags
&= ~PIM_SEC_ADDRF_STALE
;
397 if (!pim_ifp
->sec_addr_list
) {
398 pim_ifp
->sec_addr_list
= list_new();
399 pim_ifp
->sec_addr_list
->del
= (void (*)(void *))pim_sec_addr_free
;
400 pim_ifp
->sec_addr_list
->cmp
= (int (*)(void *, void *))pim_sec_addr_comp
;
403 sec_addr
= XCALLOC(MTYPE_PIM_SEC_ADDR
, sizeof(*sec_addr
));
405 if (list_isempty(pim_ifp
->sec_addr_list
)) {
406 list_free(pim_ifp
->sec_addr_list
);
407 pim_ifp
->sec_addr_list
= NULL
;
413 sec_addr
->addr
= *addr
;
414 listnode_add_sort(pim_ifp
->sec_addr_list
, sec_addr
);
419 static int pim_sec_addr_del_all(struct pim_interface
*pim_ifp
)
423 if (!pim_ifp
->sec_addr_list
) {
426 if (!list_isempty(pim_ifp
->sec_addr_list
)) {
428 /* remove all nodes and free up the list itself */
429 list_delete_all_node(pim_ifp
->sec_addr_list
);
430 list_free(pim_ifp
->sec_addr_list
);
431 pim_ifp
->sec_addr_list
= NULL
;
437 static int pim_sec_addr_update(struct interface
*ifp
)
439 struct pim_interface
*pim_ifp
= ifp
->info
;
440 struct connected
*ifc
;
441 struct listnode
*node
;
442 struct listnode
*nextnode
;
443 struct pim_secondary_addr
*sec_addr
;
446 if (pim_ifp
->sec_addr_list
) {
447 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->sec_addr_list
, node
, sec_addr
)) {
448 sec_addr
->flags
|= PIM_SEC_ADDRF_STALE
;
452 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, ifc
)) {
453 struct prefix
*p
= ifc
->address
;
455 if (PIM_INADDR_IS_ANY(p
->u
.prefix4
)) {
459 if (pim_ifp
->primary_address
.s_addr
== p
->u
.prefix4
.s_addr
) {
460 /* don't add the primary address into the secondary address list */
464 if (pim_sec_addr_add(pim_ifp
, p
)) {
469 if (pim_ifp
->sec_addr_list
) {
470 /* Drop stale entries */
471 for (ALL_LIST_ELEMENTS(pim_ifp
->sec_addr_list
, node
, nextnode
, sec_addr
)) {
472 if (sec_addr
->flags
& PIM_SEC_ADDRF_STALE
) {
473 pim_sec_addr_del(pim_ifp
, sec_addr
);
478 /* If the list went empty free it up */
479 if (list_isempty(pim_ifp
->sec_addr_list
)) {
480 list_free(pim_ifp
->sec_addr_list
);
481 pim_ifp
->sec_addr_list
= NULL
;
488 static int detect_secondary_address_change(struct interface
*ifp
,
489 int force_prim_as_any
,
492 struct pim_interface
*pim_ifp
= ifp
->info
;
495 if (force_prim_as_any
) {
496 /* if primary address is being forced to zero just flush the
497 * secondary address list */
498 changed
= pim_sec_addr_del_all(pim_ifp
);
500 /* re-evaluate the secondary address list */
501 changed
= pim_sec_addr_update(ifp
);
507 static void detect_address_change(struct interface
*ifp
,
508 int force_prim_as_any
,
512 struct pim_interface
*pim_ifp
;
518 if (detect_primary_address_change(ifp
, force_prim_as_any
, caller
)) {
522 if (detect_secondary_address_change(ifp
, force_prim_as_any
, caller
)) {
528 if (!PIM_IF_TEST_PIM(pim_ifp
->options
)) {
532 pim_addr_change(ifp
);
535 /* XXX: if we have unnumbered interfaces we need to run detect address
536 * address change on all of them when the lo address changes */
539 int pim_update_source_set(struct interface
*ifp
, struct in_addr source
)
541 struct pim_interface
*pim_ifp
= ifp
->info
;
544 return PIM_IFACE_NOT_FOUND
;
547 if (pim_ifp
->update_source
.s_addr
== source
.s_addr
) {
548 return PIM_UPDATE_SOURCE_DUP
;
551 pim_ifp
->update_source
= source
;
552 detect_address_change(ifp
, 0 /* force_prim_as_any */,
553 __PRETTY_FUNCTION__
);
558 void pim_if_addr_add(struct connected
*ifc
)
560 struct pim_interface
*pim_ifp
;
561 struct interface
*ifp
;
562 struct in_addr ifaddr
;
572 if (!if_is_operative(ifp
))
575 if (PIM_DEBUG_ZEBRA
) {
577 prefix2str(ifc
->address
, buf
, BUFSIZ
);
578 zlog_debug("%s: %s ifindex=%d connected IP address %s %s",
580 ifp
->name
, ifp
->ifindex
, buf
,
581 CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
) ?
582 "secondary" : "primary");
585 ifaddr
= ifc
->address
->u
.prefix4
;
587 detect_address_change(ifp
, 0, __PRETTY_FUNCTION__
);
589 if (ifc
->address
->family
!= AF_INET
)
592 if (PIM_IF_TEST_IGMP(pim_ifp
->options
)) {
593 struct igmp_sock
*igmp
;
595 /* lookup IGMP socket */
596 igmp
= pim_igmp_sock_lookup_ifaddr(pim_ifp
->igmp_socket_list
,
599 /* if addr new, add IGMP socket */
600 pim_igmp_sock_add(pim_ifp
->igmp_socket_list
, ifaddr
, ifp
);
603 /* Replay Static IGMP groups */
604 if (pim_ifp
->igmp_join_list
)
606 struct listnode
*node
;
607 struct listnode
*nextnode
;
608 struct igmp_join
*ij
;
611 for (ALL_LIST_ELEMENTS (pim_ifp
->igmp_join_list
, node
, nextnode
, ij
))
613 /* Close socket and reopen with Source and Group */
615 join_fd
= igmp_join_sock(ifp
->name
, ifp
->ifindex
, ij
->group_addr
, ij
->source_addr
);
618 char group_str
[INET_ADDRSTRLEN
];
619 char source_str
[INET_ADDRSTRLEN
];
620 pim_inet4_dump("<grp?>", ij
->group_addr
, group_str
, sizeof(group_str
));
621 pim_inet4_dump("<src?>", ij
->source_addr
, source_str
, sizeof(source_str
));
622 zlog_warn("%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s",
624 group_str
, source_str
, ifp
->name
);
628 ij
->sock_fd
= join_fd
;
633 if (PIM_IF_TEST_PIM(pim_ifp
->options
))
636 if (PIM_INADDR_ISNOT_ANY (pim_ifp
->primary_address
))
639 /* Interface has a valid socket ? */
640 if (pim_ifp
->pim_sock_fd
< 0)
642 if (pim_sock_add (ifp
))
644 zlog_warn ("Failure creating PIM socket for interface %s",
648 struct pim_nexthop_cache
*pnc
= NULL
;
650 struct zclient
*zclient
= NULL
;
652 zclient
= pim_zebra_zclient_get ();
653 /* RP config might come prior to (local RP's interface) IF UP event.
654 In this case, pnc would not have pim enabled nexthops.
655 Once Interface is UP and pim info is available, reregister
656 with RNH address to receive update and add the interface as nexthop. */
657 memset (&rpf
, 0, sizeof (struct pim_rpf
));
658 rpf
.rpf_addr
.family
= AF_INET
;
659 rpf
.rpf_addr
.prefixlen
= IPV4_MAX_BITLEN
;
660 rpf
.rpf_addr
.u
.prefix4
= ifc
->address
->u
.prefix4
;
661 pnc
= pim_nexthop_cache_find (&rpf
);
663 pim_sendmsg_zebra_rnh (zclient
, pnc
,
664 ZEBRA_NEXTHOP_REGISTER
);
669 PIM or IGMP is enabled on interface, and there is at least one
670 address assigned, then try to create a vif_index.
672 if (pim_ifp
->mroute_vif_index
< 0) {
675 pim_ifchannel_scan_forward_start (ifp
);
678 static void pim_if_addr_del_igmp(struct connected
*ifc
)
680 struct pim_interface
*pim_ifp
= ifc
->ifp
->info
;
681 struct igmp_sock
*igmp
;
682 struct in_addr ifaddr
;
684 if (ifc
->address
->family
!= AF_INET
) {
685 /* non-IPv4 address */
690 /* IGMP not enabled on interface */
694 ifaddr
= ifc
->address
->u
.prefix4
;
696 /* lookup IGMP socket */
697 igmp
= pim_igmp_sock_lookup_ifaddr(pim_ifp
->igmp_socket_list
,
700 /* if addr found, del IGMP socket */
701 igmp_sock_delete(igmp
);
705 static void pim_if_addr_del_pim(struct connected
*ifc
)
707 struct pim_interface
*pim_ifp
= ifc
->ifp
->info
;
709 if (ifc
->address
->family
!= AF_INET
) {
710 /* non-IPv4 address */
715 /* PIM not enabled on interface */
719 if (PIM_INADDR_ISNOT_ANY(pim_ifp
->primary_address
)) {
720 /* Interface keeps a valid primary address */
724 if (pim_ifp
->pim_sock_fd
< 0) {
725 /* Interface does not hold a valid socket any longer */
730 pim_sock_delete() closes the socket, stops read and timer threads,
731 and kills all neighbors.
733 pim_sock_delete(ifc
->ifp
, "last address has been removed from interface");
736 void pim_if_addr_del(struct connected
*ifc
, int force_prim_as_any
)
738 struct interface
*ifp
;
744 if (ifc
->address
->family
!= AF_INET
)
747 if (PIM_DEBUG_ZEBRA
) {
749 prefix2str(ifc
->address
, buf
, BUFSIZ
);
750 zlog_debug("%s: %s ifindex=%d disconnected IP address %s %s",
752 ifp
->name
, ifp
->ifindex
, buf
,
753 CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
) ?
754 "secondary" : "primary");
757 detect_address_change(ifp
, force_prim_as_any
, __PRETTY_FUNCTION__
);
759 pim_if_addr_del_igmp(ifc
);
760 pim_if_addr_del_pim(ifc
);
763 void pim_if_addr_add_all(struct interface
*ifp
)
765 struct connected
*ifc
;
766 struct listnode
*node
;
767 struct listnode
*nextnode
;
770 struct pim_interface
*pim_ifp
= ifp
->info
;
773 /* PIM/IGMP enabled ? */
777 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
778 struct prefix
*p
= ifc
->address
;
780 if (p
->family
!= AF_INET
)
784 pim_if_addr_add(ifc
);
787 if (!v4_addrs
&& v6_addrs
&& !if_is_loopback (ifp
))
789 if (PIM_IF_TEST_PIM(pim_ifp
->options
)) {
791 /* Interface has a valid primary address ? */
792 if (PIM_INADDR_ISNOT_ANY(pim_ifp
->primary_address
)) {
794 /* Interface has a valid socket ? */
795 if (pim_ifp
->pim_sock_fd
< 0) {
796 if (pim_sock_add(ifp
)) {
797 zlog_warn("Failure creating PIM socket for interface %s",
806 * PIM or IGMP is enabled on interface, and there is at least one
807 * address assigned, then try to create a vif_index.
809 if (pim_ifp
->mroute_vif_index
< 0) {
812 pim_ifchannel_scan_forward_start (ifp
);
815 pim_rp_check_on_if_add(pim_ifp
);
818 void pim_if_addr_del_all(struct interface
*ifp
)
820 struct connected
*ifc
;
821 struct listnode
*node
;
822 struct listnode
*nextnode
;
824 /* PIM/IGMP enabled ? */
828 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
829 struct prefix
*p
= ifc
->address
;
831 if (p
->family
!= AF_INET
)
834 pim_if_addr_del(ifc
, 1 /* force_prim_as_any=true */);
838 pim_i_am_rp_re_evaluate();
841 void pim_if_addr_del_all_igmp(struct interface
*ifp
)
843 struct connected
*ifc
;
844 struct listnode
*node
;
845 struct listnode
*nextnode
;
847 /* PIM/IGMP enabled ? */
851 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
852 struct prefix
*p
= ifc
->address
;
854 if (p
->family
!= AF_INET
)
857 pim_if_addr_del_igmp(ifc
);
861 void pim_if_addr_del_all_pim(struct interface
*ifp
)
863 struct connected
*ifc
;
864 struct listnode
*node
;
865 struct listnode
*nextnode
;
867 /* PIM/IGMP enabled ? */
871 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
872 struct prefix
*p
= ifc
->address
;
874 if (p
->family
!= AF_INET
)
877 pim_if_addr_del_pim(ifc
);
882 pim_find_primary_addr (struct interface
*ifp
)
884 struct connected
*ifc
;
885 struct listnode
*node
;
889 struct pim_interface
*pim_ifp
= ifp
->info
;
891 if (pim_ifp
&& PIM_INADDR_ISNOT_ANY(pim_ifp
->update_source
)) {
892 return pim_ifp
->update_source
;
895 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, ifc
)) {
896 struct prefix
*p
= ifc
->address
;
898 if (p
->family
!= AF_INET
)
904 if (PIM_INADDR_IS_ANY(p
->u
.prefix4
)) {
905 zlog_warn("%s: null IPv4 address connected to interface %s",
906 __PRETTY_FUNCTION__
, ifp
->name
);
912 if (CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
))
919 * If we have no v4_addrs and v6 is configured
920 * We probably are using unnumbered
921 * So let's grab the loopbacks v4 address
922 * and use that as the primary address
924 if (!v4_addrs
&& v6_addrs
&& !if_is_loopback (ifp
))
926 struct interface
*lo_ifp
;
927 lo_ifp
= if_lookup_by_name ("lo", VRF_DEFAULT
);
929 return pim_find_primary_addr (lo_ifp
);
932 addr
.s_addr
= PIM_NET_INADDR_ANY
;
938 pim_iface_next_vif_index (struct interface
*ifp
)
942 * The pimreg vif is always going to be in index 0
945 if (ifp
->ifindex
== PIM_OIF_PIM_REGISTER_VIF
)
948 for (i
= 1 ; i
< MAXVIFS
; i
++)
950 if (pim_iface_vif_index
[i
] == 0)
957 pim_if_add_vif() uses ifindex as vif_index
959 see also pim_if_find_vifindex_by_ifindex()
961 int pim_if_add_vif(struct interface
*ifp
)
963 struct pim_interface
*pim_ifp
= ifp
->info
;
964 struct in_addr ifaddr
;
965 unsigned char flags
= 0;
969 if (pim_ifp
->mroute_vif_index
> 0) {
970 zlog_warn("%s: vif_index=%d > 0 on interface %s ifindex=%d",
972 pim_ifp
->mroute_vif_index
, ifp
->name
, ifp
->ifindex
);
976 if (ifp
->ifindex
< 0) {
977 zlog_warn("%s: ifindex=%d < 1 on interface %s",
979 ifp
->ifindex
, ifp
->name
);
983 ifaddr
= pim_ifp
->primary_address
;
984 if (ifp
->ifindex
!= PIM_OIF_PIM_REGISTER_VIF
&& PIM_INADDR_IS_ANY(ifaddr
)) {
985 zlog_warn("%s: could not get address for interface %s ifindex=%d",
987 ifp
->name
, ifp
->ifindex
);
991 pim_ifp
->mroute_vif_index
= pim_iface_next_vif_index (ifp
);
993 if (pim_ifp
->mroute_vif_index
>= MAXVIFS
)
995 zlog_warn("%s: Attempting to configure more than MAXVIFS=%d on pim enabled interface %s",
1001 if (ifp
->ifindex
== PIM_OIF_PIM_REGISTER_VIF
)
1002 flags
= VIFF_REGISTER
;
1003 #ifdef VIFF_USE_IFINDEX
1005 flags
= VIFF_USE_IFINDEX
;
1008 if (pim_mroute_add_vif(ifp
, ifaddr
, flags
)) {
1009 /* pim_mroute_add_vif reported error */
1013 pim_iface_vif_index
[pim_ifp
->mroute_vif_index
] = 1;
1017 int pim_if_del_vif(struct interface
*ifp
)
1019 struct pim_interface
*pim_ifp
= ifp
->info
;
1021 if (pim_ifp
->mroute_vif_index
< 1) {
1022 zlog_warn("%s: vif_index=%d < 1 on interface %s ifindex=%d",
1023 __PRETTY_FUNCTION__
,
1024 pim_ifp
->mroute_vif_index
, ifp
->name
, ifp
->ifindex
);
1028 pim_mroute_del_vif(pim_ifp
->mroute_vif_index
);
1033 pim_iface_vif_index
[pim_ifp
->mroute_vif_index
] = 0;
1035 pim_ifp
->mroute_vif_index
= -1;
1040 void pim_if_add_vif_all()
1042 struct listnode
*ifnode
;
1043 struct listnode
*ifnextnode
;
1044 struct interface
*ifp
;
1046 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT
), ifnode
, ifnextnode
, ifp
)) {
1050 pim_if_add_vif(ifp
);
1054 void pim_if_del_vif_all()
1056 struct listnode
*ifnode
;
1057 struct listnode
*ifnextnode
;
1058 struct interface
*ifp
;
1060 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT
), ifnode
, ifnextnode
, ifp
)) {
1064 pim_if_del_vif(ifp
);
1068 struct interface
*pim_if_find_by_vif_index(ifindex_t vif_index
)
1070 struct listnode
*ifnode
;
1071 struct interface
*ifp
;
1074 return if_lookup_by_name ("pimreg", VRF_DEFAULT
);
1076 for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT
), ifnode
, ifp
)) {
1078 struct pim_interface
*pim_ifp
;
1079 pim_ifp
= ifp
->info
;
1081 if (vif_index
== pim_ifp
->mroute_vif_index
)
1090 pim_if_add_vif() uses ifindex as vif_index
1092 int pim_if_find_vifindex_by_ifindex(ifindex_t ifindex
)
1094 struct pim_interface
*pim_ifp
;
1095 struct interface
*ifp
;
1097 ifp
= if_lookup_by_index (ifindex
, VRF_DEFAULT
);
1098 if (!ifp
|| !ifp
->info
)
1100 pim_ifp
= ifp
->info
;
1102 return pim_ifp
->mroute_vif_index
;
1105 int pim_if_lan_delay_enabled(struct interface
*ifp
)
1107 struct pim_interface
*pim_ifp
;
1109 pim_ifp
= ifp
->info
;
1111 zassert(pim_ifp
->pim_number_of_nonlandelay_neighbors
>= 0);
1113 return pim_ifp
->pim_number_of_nonlandelay_neighbors
== 0;
1116 uint16_t pim_if_effective_propagation_delay_msec(struct interface
*ifp
)
1118 if (pim_if_lan_delay_enabled(ifp
)) {
1119 struct pim_interface
*pim_ifp
;
1120 pim_ifp
= ifp
->info
;
1121 return pim_ifp
->pim_neighbors_highest_propagation_delay_msec
;
1124 return PIM_DEFAULT_PROPAGATION_DELAY_MSEC
;
1128 uint16_t pim_if_effective_override_interval_msec(struct interface
*ifp
)
1130 if (pim_if_lan_delay_enabled(ifp
)) {
1131 struct pim_interface
*pim_ifp
;
1132 pim_ifp
= ifp
->info
;
1133 return pim_ifp
->pim_neighbors_highest_override_interval_msec
;
1136 return PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC
;
1140 int pim_if_t_override_msec(struct interface
*ifp
)
1142 int effective_override_interval_msec
;
1143 int t_override_msec
;
1145 effective_override_interval_msec
=
1146 pim_if_effective_override_interval_msec(ifp
);
1148 t_override_msec
= random() % (effective_override_interval_msec
+ 1);
1150 return t_override_msec
;
1153 uint16_t pim_if_jp_override_interval_msec(struct interface
*ifp
)
1155 return pim_if_effective_propagation_delay_msec(ifp
) +
1156 pim_if_effective_override_interval_msec(ifp
);
1160 RFC 4601: 4.1.6. State Summarization Macros
1162 The function NBR( I, A ) uses information gathered through PIM Hello
1163 messages to map the IP address A of a directly connected PIM
1164 neighbor router on interface I to the primary IP address of the same
1165 router (Section 4.3.4). The primary IP address of a neighbor is the
1166 address that it uses as the source of its PIM Hello messages.
1168 struct pim_neighbor
*pim_if_find_neighbor(struct interface
*ifp
,
1169 struct in_addr addr
)
1171 struct listnode
*neighnode
;
1172 struct pim_neighbor
*neigh
;
1173 struct pim_interface
*pim_ifp
;
1178 pim_ifp
= ifp
->info
;
1180 zlog_warn("%s: multicast not enabled on interface %s",
1181 __PRETTY_FUNCTION__
,
1188 p
.prefixlen
= IPV4_MAX_PREFIXLEN
;
1190 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
, neighnode
, neigh
)) {
1192 /* primary address ? */
1193 if (neigh
->source_addr
.s_addr
== addr
.s_addr
)
1196 /* secondary address ? */
1197 if (pim_neighbor_find_secondary(neigh
, &p
))
1201 if (PIM_DEBUG_PIM_TRACE
) {
1202 char addr_str
[INET_ADDRSTRLEN
];
1203 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
1204 zlog_debug("%s: neighbor not found for address %s on interface %s",
1205 __PRETTY_FUNCTION__
,
1206 addr_str
, ifp
->name
);
1212 long pim_if_t_suppressed_msec(struct interface
*ifp
)
1214 struct pim_interface
*pim_ifp
;
1215 long t_suppressed_msec
;
1216 uint32_t ramount
= 0;
1218 pim_ifp
= ifp
->info
;
1221 /* join suppression disabled ? */
1222 if (PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp
->options
))
1225 /* t_suppressed = t_periodic * rand(1.1, 1.4) */
1226 ramount
= 1100 + (random() % (1400 - 1100 + 1));
1227 t_suppressed_msec
= qpim_t_periodic
* ramount
;
1229 return t_suppressed_msec
;
1232 static void igmp_join_free(struct igmp_join
*ij
)
1234 XFREE(MTYPE_PIM_IGMP_JOIN
, ij
);
1237 static struct igmp_join
*igmp_join_find(struct list
*join_list
,
1238 struct in_addr group_addr
,
1239 struct in_addr source_addr
)
1241 struct listnode
*node
;
1242 struct igmp_join
*ij
;
1246 for (ALL_LIST_ELEMENTS_RO(join_list
, node
, ij
)) {
1247 if ((group_addr
.s_addr
== ij
->group_addr
.s_addr
) &&
1248 (source_addr
.s_addr
== ij
->source_addr
.s_addr
))
1255 static int igmp_join_sock(const char *ifname
,
1257 struct in_addr group_addr
,
1258 struct in_addr source_addr
)
1262 join_fd
= pim_socket_raw(IPPROTO_IGMP
);
1267 if (pim_socket_join_source(join_fd
, ifindex
, group_addr
, source_addr
, ifname
)) {
1275 static struct igmp_join
*igmp_join_new(struct interface
*ifp
,
1276 struct in_addr group_addr
,
1277 struct in_addr source_addr
)
1279 struct pim_interface
*pim_ifp
;
1280 struct igmp_join
*ij
;
1283 pim_ifp
= ifp
->info
;
1286 join_fd
= igmp_join_sock(ifp
->name
, ifp
->ifindex
, group_addr
, source_addr
);
1288 char group_str
[INET_ADDRSTRLEN
];
1289 char source_str
[INET_ADDRSTRLEN
];
1290 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
1291 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
1292 zlog_warn("%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s",
1293 __PRETTY_FUNCTION__
,
1294 group_str
, source_str
, ifp
->name
);
1298 ij
= XCALLOC(MTYPE_PIM_IGMP_JOIN
, sizeof(*ij
));
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_err("%s: XCALLOC(%zu) failure for IGMP group %s source %s on interface %s",
1305 __PRETTY_FUNCTION__
,
1306 sizeof(*ij
), group_str
, source_str
, ifp
->name
);
1311 ij
->sock_fd
= join_fd
;
1312 ij
->group_addr
= group_addr
;
1313 ij
->source_addr
= source_addr
;
1314 ij
->sock_creation
= pim_time_monotonic_sec();
1316 listnode_add(pim_ifp
->igmp_join_list
, ij
);
1321 int pim_if_igmp_join_add(struct interface
*ifp
,
1322 struct in_addr group_addr
,
1323 struct in_addr source_addr
)
1325 struct pim_interface
*pim_ifp
;
1326 struct igmp_join
*ij
;
1328 pim_ifp
= ifp
->info
;
1330 zlog_warn("%s: multicast not enabled on interface %s",
1331 __PRETTY_FUNCTION__
,
1336 if (!pim_ifp
->igmp_join_list
) {
1337 pim_ifp
->igmp_join_list
= list_new();
1338 if (!pim_ifp
->igmp_join_list
) {
1339 zlog_err("%s %s: failure: igmp_join_list=list_new()",
1340 __FILE__
, __PRETTY_FUNCTION__
);
1343 pim_ifp
->igmp_join_list
->del
= (void (*)(void *)) igmp_join_free
;
1346 ij
= igmp_join_find(pim_ifp
->igmp_join_list
, group_addr
, source_addr
);
1348 char group_str
[INET_ADDRSTRLEN
];
1349 char source_str
[INET_ADDRSTRLEN
];
1350 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
1351 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
1352 zlog_warn("%s: can't re-join existing IGMP group %s source %s on interface %s",
1353 __PRETTY_FUNCTION__
,
1354 group_str
, source_str
, ifp
->name
);
1358 ij
= igmp_join_new(ifp
, group_addr
, source_addr
);
1360 char group_str
[INET_ADDRSTRLEN
];
1361 char source_str
[INET_ADDRSTRLEN
];
1362 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
1363 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
1364 zlog_warn("%s: igmp_join_new() failure for IGMP group %s source %s on interface %s",
1365 __PRETTY_FUNCTION__
,
1366 group_str
, source_str
, ifp
->name
);
1370 if (PIM_DEBUG_IGMP_EVENTS
) {
1371 char group_str
[INET_ADDRSTRLEN
];
1372 char source_str
[INET_ADDRSTRLEN
];
1373 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
1374 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
1375 zlog_debug("%s: issued static igmp join for channel (S,G)=(%s,%s) on interface %s",
1376 __PRETTY_FUNCTION__
,
1377 source_str
, group_str
, ifp
->name
);
1385 int pim_if_igmp_join_del(struct interface
*ifp
,
1386 struct in_addr group_addr
,
1387 struct in_addr source_addr
)
1389 struct pim_interface
*pim_ifp
;
1390 struct igmp_join
*ij
;
1392 pim_ifp
= ifp
->info
;
1394 zlog_warn("%s: multicast not enabled on interface %s",
1395 __PRETTY_FUNCTION__
,
1400 if (!pim_ifp
->igmp_join_list
) {
1401 zlog_warn("%s: no IGMP join on interface %s",
1402 __PRETTY_FUNCTION__
,
1407 ij
= igmp_join_find(pim_ifp
->igmp_join_list
, group_addr
, source_addr
);
1409 char group_str
[INET_ADDRSTRLEN
];
1410 char source_str
[INET_ADDRSTRLEN
];
1411 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
1412 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
1413 zlog_warn("%s: could not find IGMP group %s source %s on interface %s",
1414 __PRETTY_FUNCTION__
,
1415 group_str
, source_str
, ifp
->name
);
1419 if (close(ij
->sock_fd
)) {
1420 char group_str
[INET_ADDRSTRLEN
];
1421 char source_str
[INET_ADDRSTRLEN
];
1422 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
1423 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
1424 zlog_warn("%s: failure closing sock_fd=%d for IGMP group %s source %s on interface %s: errno=%d: %s",
1425 __PRETTY_FUNCTION__
,
1426 ij
->sock_fd
, group_str
, source_str
, ifp
->name
, errno
, safe_strerror(errno
));
1429 listnode_delete(pim_ifp
->igmp_join_list
, ij
);
1431 if (listcount(pim_ifp
->igmp_join_list
) < 1) {
1432 list_delete(pim_ifp
->igmp_join_list
);
1433 pim_ifp
->igmp_join_list
= 0;
1439 static void pim_if_igmp_join_del_all(struct interface
*ifp
)
1441 struct pim_interface
*pim_ifp
;
1442 struct listnode
*node
;
1443 struct listnode
*nextnode
;
1444 struct igmp_join
*ij
;
1446 pim_ifp
= ifp
->info
;
1448 zlog_warn("%s: multicast not enabled on interface %s",
1449 __PRETTY_FUNCTION__
,
1454 if (!pim_ifp
->igmp_join_list
)
1457 for (ALL_LIST_ELEMENTS(pim_ifp
->igmp_join_list
, node
, nextnode
, ij
))
1458 pim_if_igmp_join_del(ifp
, ij
->group_addr
, ij
->source_addr
);
1464 Transitions from "I am Assert Loser" State
1466 Current Winner's GenID Changes or NLT Expires
1468 The Neighbor Liveness Timer associated with the current winner
1469 expires or we receive a Hello message from the current winner
1470 reporting a different GenID from the one it previously reported.
1471 This indicates that the current winner's interface or router has
1472 gone down (and may have come back up), and so we must assume it no
1473 longer knows it was the winner.
1475 void pim_if_assert_on_neighbor_down(struct interface
*ifp
,
1476 struct in_addr neigh_addr
)
1478 struct pim_interface
*pim_ifp
;
1479 struct listnode
*node
;
1480 struct listnode
*next_node
;
1481 struct pim_ifchannel
*ch
;
1483 pim_ifp
= ifp
->info
;
1486 for (ALL_LIST_ELEMENTS(pim_ifp
->pim_ifchannel_list
, node
, next_node
, ch
)) {
1487 /* Is (S,G,I) assert loser ? */
1488 if (ch
->ifassert_state
!= PIM_IFASSERT_I_AM_LOSER
)
1490 /* Dead neighbor was winner ? */
1491 if (ch
->ifassert_winner
.s_addr
!= neigh_addr
.s_addr
)
1494 assert_action_a5(ch
);
1498 void pim_if_update_join_desired(struct pim_interface
*pim_ifp
)
1500 struct listnode
*ch_node
;
1501 struct pim_ifchannel
*ch
;
1503 /* clear off flag from interface's upstreams */
1504 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_ifchannel_list
, ch_node
, ch
)) {
1505 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(ch
->upstream
->flags
);
1508 /* scan per-interface (S,G,I) state on this I interface */
1509 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_ifchannel_list
, ch_node
, ch
)) {
1510 struct pim_upstream
*up
= ch
->upstream
;
1512 if (PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(up
->flags
))
1515 /* update join_desired for the global (S,G) state */
1516 pim_upstream_update_join_desired(up
);
1517 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(up
->flags
);
1521 void pim_if_update_assert_tracking_desired(struct interface
*ifp
)
1523 struct pim_interface
*pim_ifp
;
1524 struct listnode
*node
;
1525 struct listnode
*next_node
;
1526 struct pim_ifchannel
*ch
;
1528 pim_ifp
= ifp
->info
;
1532 for (ALL_LIST_ELEMENTS(pim_ifp
->pim_ifchannel_list
, node
, next_node
, ch
)) {
1533 pim_ifchannel_update_assert_tracking_desired(ch
);
1538 * PIM wants to have an interface pointer for everything it does.
1539 * The pimreg is a special interface that we have that is not
1540 * quite an inteface but a VIF is created for it.
1542 void pim_if_create_pimreg (void)
1544 if (!pim_regiface
) {
1545 pim_regiface
= if_create("pimreg", strlen("pimreg"), VRF_DEFAULT
);
1546 pim_regiface
->ifindex
= PIM_OIF_PIM_REGISTER_VIF
;
1548 pim_if_new(pim_regiface
, 0, 0);
1553 pim_if_connected_to_source (struct interface
*ifp
, struct in_addr src
)
1555 struct listnode
*cnode
;
1556 struct connected
*c
;
1564 p
.prefixlen
= IPV4_MAX_BITLEN
;
1566 for (ALL_LIST_ELEMENTS_RO (ifp
->connected
, cnode
, c
))
1568 if ((c
->address
->family
== AF_INET
) &&
1569 prefix_match (CONNECTED_PREFIX (c
), &p
))
1579 pim_if_lookup_address_vrf (struct in_addr src
, vrf_id_t vrf_id
)
1581 struct listnode
*ifnode
;
1582 struct interface
*ifp
;
1584 for (ALL_LIST_ELEMENTS_RO (vrf_iflist(vrf_id
), ifnode
, ifp
))
1586 if (pim_if_connected_to_source (ifp
, src
) && ifp
->info
)