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
34 #include "pim_instance.h"
35 #include "pim_zebra.h"
36 #include "pim_iface.h"
38 #include "pim_mroute.h"
42 #include "pim_neighbor.h"
43 #include "pim_ifchannel.h"
46 #include "pim_ssmpingd.h"
49 #include "pim_jp_agg.h"
50 #include "pim_igmp_join.h"
51 #include "pim_vxlan.h"
53 static void pim_if_igmp_join_del_all(struct interface
*ifp
);
54 static int igmp_join_sock(const char *ifname
, ifindex_t ifindex
,
55 struct in_addr group_addr
,
56 struct in_addr source_addr
);
58 void pim_if_init(struct pim_instance
*pim
)
62 for (i
= 0; i
< MAXVIFS
; i
++)
63 pim
->iface_vif_index
[i
] = 0;
66 void pim_if_terminate(struct pim_instance
*pim
)
68 struct interface
*ifp
;
70 FOR_ALL_INTERFACES (pim
->vrf
, ifp
) {
71 struct pim_interface
*pim_ifp
= ifp
->info
;
81 static void pim_sec_addr_free(struct pim_secondary_addr
*sec_addr
)
83 XFREE(MTYPE_PIM_SEC_ADDR
, sec_addr
);
86 static int pim_sec_addr_comp(const void *p1
, const void *p2
)
88 const struct pim_secondary_addr
*sec1
= p1
;
89 const struct pim_secondary_addr
*sec2
= p2
;
91 if (sec1
->addr
.family
== AF_INET
&& sec2
->addr
.family
== AF_INET6
)
94 if (sec1
->addr
.family
== AF_INET6
&& sec2
->addr
.family
== AF_INET
)
97 if (sec1
->addr
.family
== AF_INET
) {
98 if (ntohl(sec1
->addr
.u
.prefix4
.s_addr
)
99 < ntohl(sec2
->addr
.u
.prefix4
.s_addr
))
102 if (ntohl(sec1
->addr
.u
.prefix4
.s_addr
)
103 > ntohl(sec2
->addr
.u
.prefix4
.s_addr
))
106 return memcmp(&sec1
->addr
.u
.prefix6
, &sec2
->addr
.u
.prefix6
,
107 sizeof(struct in6_addr
));
113 struct pim_interface
*pim_if_new(struct interface
*ifp
, bool igmp
, bool pim
,
114 bool ispimreg
, bool is_vxlan_term
)
116 struct pim_interface
*pim_ifp
;
121 pim_ifp
= XCALLOC(MTYPE_PIM_INTERFACE
, sizeof(*pim_ifp
));
123 pim_ifp
->options
= 0;
124 pim_ifp
->pim
= ifp
->vrf
->info
;
125 pim_ifp
->mroute_vif_index
= -1;
127 pim_ifp
->igmp_version
= IGMP_DEFAULT_VERSION
;
128 pim_ifp
->gm_default_robustness_variable
=
129 IGMP_DEFAULT_ROBUSTNESS_VARIABLE
;
130 pim_ifp
->gm_default_query_interval
= IGMP_GENERAL_QUERY_INTERVAL
;
131 pim_ifp
->gm_query_max_response_time_dsec
=
132 IGMP_QUERY_MAX_RESPONSE_TIME_DSEC
;
133 pim_ifp
->gm_specific_query_max_response_time_dsec
=
134 IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC
;
135 pim_ifp
->gm_last_member_query_count
= IGMP_DEFAULT_ROBUSTNESS_VARIABLE
;
137 /* BSM config on interface: true by default */
138 pim_ifp
->bsm_enable
= true;
139 pim_ifp
->ucast_bsm_accept
= true;
140 pim_ifp
->am_i_dr
= false;
143 RFC 3376: 8.3. Query Response Interval
144 The number of seconds represented by the [Query Response Interval]
145 must be less than the [Query Interval].
147 assert(pim_ifp
->gm_query_max_response_time_dsec
<
148 pim_ifp
->gm_default_query_interval
);
151 PIM_IF_DO_PIM(pim_ifp
->options
);
153 PIM_IF_DO_IGMP(pim_ifp
->options
);
155 PIM_IF_DO_IGMP_LISTEN_ALLROUTERS(pim_ifp
->options
);
157 pim_ifp
->gm_join_list
= NULL
;
158 pim_ifp
->pim_neighbor_list
= NULL
;
159 pim_ifp
->upstream_switch_list
= NULL
;
160 pim_ifp
->pim_generation_id
= 0;
162 /* list of struct gm_sock */
163 pim_igmp_if_init(pim_ifp
, ifp
);
165 /* list of struct pim_neighbor */
166 pim_ifp
->pim_neighbor_list
= list_new();
167 pim_ifp
->pim_neighbor_list
->del
= (void (*)(void *))pim_neighbor_free
;
169 pim_ifp
->upstream_switch_list
= list_new();
170 pim_ifp
->upstream_switch_list
->del
=
171 (void (*)(void *))pim_jp_agg_group_list_free
;
172 pim_ifp
->upstream_switch_list
->cmp
= pim_jp_agg_group_list_cmp
;
174 pim_ifp
->sec_addr_list
= list_new();
175 pim_ifp
->sec_addr_list
->del
= (void (*)(void *))pim_sec_addr_free
;
176 pim_ifp
->sec_addr_list
->cmp
=
177 (int (*)(void *, void *))pim_sec_addr_comp
;
179 pim_ifp
->activeactive
= false;
181 RB_INIT(pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
);
187 pim_if_add_vif(ifp
, ispimreg
, is_vxlan_term
);
188 pim_ifp
->pim
->mcast_if_count
++;
193 void pim_if_delete(struct interface
*ifp
)
195 struct pim_interface
*pim_ifp
;
201 if (pim_ifp
->gm_join_list
) {
202 pim_if_igmp_join_del_all(ifp
);
205 pim_ifchannel_delete_all(ifp
);
206 igmp_sock_delete_all(ifp
);
208 pim_neighbor_delete_all(ifp
, "Interface removed from configuration");
211 pim_ifp
->pim
->mcast_if_count
--;
213 pim_igmp_if_fini(pim_ifp
);
215 list_delete(&pim_ifp
->pim_neighbor_list
);
216 list_delete(&pim_ifp
->upstream_switch_list
);
217 list_delete(&pim_ifp
->sec_addr_list
);
219 XFREE(MTYPE_PIM_INTERFACE
, pim_ifp
->boundary_oil_plist
);
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 pim_ifchannel
*ch
;
233 RB_FOREACH (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
) {
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 pim_ifchannel
*ch
;
246 RB_FOREACH (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
) {
247 pim_ifchannel_update_my_assert_metric(ch
);
251 static void pim_addr_change(struct interface
*ifp
)
253 struct pim_interface
*pim_ifp
;
258 pim_if_dr_election(ifp
); /* router's own DR Priority (addr) changes --
260 pim_if_update_join_desired(pim_ifp
); /* depends on DR */
261 pim_if_update_could_assert(ifp
); /* depends on DR */
262 pim_if_update_my_assert_metric(ifp
); /* depends on could_assert */
263 pim_if_update_assert_tracking_desired(
264 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 -- Done at the caller of the function as new ip already updated here
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_IF_FLAG_UNSET_HELLO_SENT(pim_ifp
->flags
);
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 pim_addr new_prim_addr
;
297 if (force_prim_as_any
)
298 new_prim_addr
= PIMADDR_ANY
;
300 new_prim_addr
= pim_find_primary_addr(ifp
);
302 changed
= pim_addr_cmp(new_prim_addr
, pim_ifp
->primary_address
);
305 zlog_debug("%s: old=%pPA new=%pPA on interface %s: %s",
306 __func__
, &pim_ifp
->primary_address
, &new_prim_addr
,
307 ifp
->name
, changed
? "changed" : "unchanged");
310 /* Before updating pim_ifp send Hello time with 0 hold time */
311 if (PIM_IF_TEST_PIM(pim_ifp
->options
)) {
312 pim_hello_send(ifp
, 0 /* zero-sec holdtime */);
314 pim_ifp
->primary_address
= new_prim_addr
;
320 static struct pim_secondary_addr
*
321 pim_sec_addr_find(struct pim_interface
*pim_ifp
, struct prefix
*addr
)
323 struct pim_secondary_addr
*sec_addr
;
324 struct listnode
*node
;
326 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->sec_addr_list
, node
, sec_addr
)) {
327 if (prefix_cmp(&sec_addr
->addr
, addr
) == 0) {
335 static void pim_sec_addr_del(struct pim_interface
*pim_ifp
,
336 struct pim_secondary_addr
*sec_addr
)
338 listnode_delete(pim_ifp
->sec_addr_list
, sec_addr
);
339 pim_sec_addr_free(sec_addr
);
342 static int pim_sec_addr_add(struct pim_interface
*pim_ifp
, struct prefix
*addr
)
345 struct pim_secondary_addr
*sec_addr
;
347 sec_addr
= pim_sec_addr_find(pim_ifp
, addr
);
349 sec_addr
->flags
&= ~PIM_SEC_ADDRF_STALE
;
353 sec_addr
= XCALLOC(MTYPE_PIM_SEC_ADDR
, sizeof(*sec_addr
));
356 sec_addr
->addr
= *addr
;
357 listnode_add_sort(pim_ifp
->sec_addr_list
, sec_addr
);
362 static int pim_sec_addr_del_all(struct pim_interface
*pim_ifp
)
366 if (!list_isempty(pim_ifp
->sec_addr_list
)) {
368 /* remove all nodes and free up the list itself */
369 list_delete_all_node(pim_ifp
->sec_addr_list
);
375 static int pim_sec_addr_update(struct interface
*ifp
)
377 struct pim_interface
*pim_ifp
= ifp
->info
;
378 struct connected
*ifc
;
379 struct listnode
*node
;
380 struct listnode
*nextnode
;
381 struct pim_secondary_addr
*sec_addr
;
384 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->sec_addr_list
, node
, sec_addr
)) {
385 sec_addr
->flags
|= PIM_SEC_ADDRF_STALE
;
388 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, ifc
)) {
389 pim_addr addr
= pim_addr_from_prefix(ifc
->address
);
391 if (pim_addr_is_any(addr
))
394 if (!pim_addr_cmp(addr
, pim_ifp
->primary_address
)) {
395 /* don't add the primary address into the secondary
400 if (pim_sec_addr_add(pim_ifp
, ifc
->address
)) {
405 /* Drop stale entries */
406 for (ALL_LIST_ELEMENTS(pim_ifp
->sec_addr_list
, node
, nextnode
,
408 if (sec_addr
->flags
& PIM_SEC_ADDRF_STALE
) {
409 pim_sec_addr_del(pim_ifp
, sec_addr
);
417 static int detect_secondary_address_change(struct interface
*ifp
,
418 int force_prim_as_any
,
421 struct pim_interface
*pim_ifp
= ifp
->info
;
424 if (force_prim_as_any
) {
425 /* if primary address is being forced to zero just flush the
426 * secondary address list */
427 changed
= pim_sec_addr_del_all(pim_ifp
);
429 /* re-evaluate the secondary address list */
430 changed
= pim_sec_addr_update(ifp
);
436 static void detect_address_change(struct interface
*ifp
, int force_prim_as_any
,
440 struct pim_interface
*pim_ifp
;
446 if (detect_primary_address_change(ifp
, force_prim_as_any
, caller
)) {
450 if (detect_secondary_address_change(ifp
, force_prim_as_any
, caller
)) {
456 if (!PIM_IF_TEST_PIM(pim_ifp
->options
)) {
460 pim_addr_change(ifp
);
463 /* XXX: if we have unnumbered interfaces we need to run detect address
464 * address change on all of them when the lo address changes */
467 int pim_update_source_set(struct interface
*ifp
, pim_addr source
)
469 struct pim_interface
*pim_ifp
= ifp
->info
;
472 return PIM_IFACE_NOT_FOUND
;
475 if (!pim_addr_cmp(pim_ifp
->update_source
, source
)) {
476 return PIM_UPDATE_SOURCE_DUP
;
479 pim_ifp
->update_source
= source
;
480 detect_address_change(ifp
, 0 /* force_prim_as_any */, __func__
);
485 void pim_if_addr_add(struct connected
*ifc
)
487 struct pim_interface
*pim_ifp
;
488 struct interface
*ifp
;
489 struct in_addr ifaddr
;
500 if (!if_is_operative(ifp
))
504 zlog_debug("%s: %s ifindex=%d connected IP address %pFX %s",
505 __func__
, ifp
->name
, ifp
->ifindex
, ifc
->address
,
506 CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
)
510 ifaddr
= ifc
->address
->u
.prefix4
;
512 detect_address_change(ifp
, 0, __func__
);
514 // if (ifc->address->family != AF_INET)
517 if (PIM_IF_TEST_IGMP(pim_ifp
->options
)) {
518 struct gm_sock
*igmp
;
520 /* lookup IGMP socket */
521 igmp
= pim_igmp_sock_lookup_ifaddr(pim_ifp
->gm_socket_list
,
524 /* if addr new, add IGMP socket */
525 if (ifc
->address
->family
== AF_INET
)
526 pim_igmp_sock_add(pim_ifp
->gm_socket_list
,
528 } else if (igmp
->mtrace_only
) {
529 igmp_sock_delete(igmp
);
530 pim_igmp_sock_add(pim_ifp
->gm_socket_list
, ifaddr
, ifp
,
534 /* Replay Static IGMP groups */
535 if (pim_ifp
->gm_join_list
) {
536 struct listnode
*node
;
537 struct listnode
*nextnode
;
541 for (ALL_LIST_ELEMENTS(pim_ifp
->gm_join_list
, node
,
543 /* Close socket and reopen with Source and Group
546 join_fd
= igmp_join_sock(
547 ifp
->name
, ifp
->ifindex
, ij
->group_addr
,
550 char group_str
[INET_ADDRSTRLEN
];
551 char source_str
[INET_ADDRSTRLEN
];
552 pim_inet4_dump("<grp?>", ij
->group_addr
,
556 "<src?>", ij
->source_addr
,
557 source_str
, sizeof(source_str
));
559 "%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s",
560 __func__
, group_str
, source_str
,
564 ij
->sock_fd
= join_fd
;
569 struct gm_sock
*igmp
;
571 /* lookup IGMP socket */
572 igmp
= pim_igmp_sock_lookup_ifaddr(pim_ifp
->gm_socket_list
,
574 if (ifc
->address
->family
== AF_INET
) {
576 igmp_sock_delete(igmp
);
577 /* if addr new, add IGMP socket */
578 pim_igmp_sock_add(pim_ifp
->gm_socket_list
, ifaddr
, ifp
,
581 } /* igmp mtrace only */
583 if (PIM_IF_TEST_PIM(pim_ifp
->options
)) {
585 if (!pim_addr_is_any(pim_ifp
->primary_address
)) {
587 /* Interface has a valid socket ? */
588 if (pim_ifp
->pim_sock_fd
< 0) {
589 if (pim_sock_add(ifp
)) {
591 "Failure creating PIM socket for interface %s",
595 struct pim_nexthop_cache
*pnc
= NULL
;
597 struct zclient
*zclient
= NULL
;
599 zclient
= pim_zebra_zclient_get();
600 /* RP config might come prior to (local RP's interface)
602 In this case, pnc would not have pim enabled
604 Once Interface is UP and pim info is available,
606 with RNH address to receive update and add the
607 interface as nexthop. */
608 memset(&rpf
, 0, sizeof(struct pim_rpf
));
609 rpf
.rpf_addr
.family
= AF_INET
;
610 rpf
.rpf_addr
.prefixlen
= IPV4_MAX_BITLEN
;
611 rpf
.rpf_addr
.u
.prefix4
= ifc
->address
->u
.prefix4
;
612 pnc
= pim_nexthop_cache_find(pim_ifp
->pim
, &rpf
);
614 pim_sendmsg_zebra_rnh(pim_ifp
->pim
, zclient
,
616 ZEBRA_NEXTHOP_REGISTER
);
621 PIM or IGMP is enabled on interface, and there is at least one
622 address assigned, then try to create a vif_index.
624 if (pim_ifp
->mroute_vif_index
< 0) {
625 vxlan_term
= pim_vxlan_is_term_dev_cfg(pim_ifp
->pim
, ifp
);
626 pim_if_add_vif(ifp
, false, vxlan_term
);
628 pim_ifchannel_scan_forward_start(ifp
);
631 static void pim_if_addr_del_igmp(struct connected
*ifc
)
633 struct pim_interface
*pim_ifp
= ifc
->ifp
->info
;
634 struct gm_sock
*igmp
;
635 struct in_addr ifaddr
;
637 if (ifc
->address
->family
!= AF_INET
) {
638 /* non-IPv4 address */
643 /* IGMP not enabled on interface */
647 ifaddr
= ifc
->address
->u
.prefix4
;
649 /* lookup IGMP socket */
650 igmp
= pim_igmp_sock_lookup_ifaddr(pim_ifp
->gm_socket_list
, ifaddr
);
652 /* if addr found, del IGMP socket */
653 igmp_sock_delete(igmp
);
657 static void pim_if_addr_del_pim(struct connected
*ifc
)
659 struct pim_interface
*pim_ifp
= ifc
->ifp
->info
;
661 if (ifc
->address
->family
!= AF_INET
) {
662 /* non-IPv4 address */
667 /* PIM not enabled on interface */
671 if (!pim_addr_is_any(pim_ifp
->primary_address
)) {
672 /* Interface keeps a valid primary address */
676 if (pim_ifp
->pim_sock_fd
< 0) {
677 /* Interface does not hold a valid socket any longer */
682 pim_sock_delete() closes the socket, stops read and timer threads,
683 and kills all neighbors.
685 pim_sock_delete(ifc
->ifp
,
686 "last address has been removed from interface");
689 void pim_if_addr_del(struct connected
*ifc
, int force_prim_as_any
)
691 struct interface
*ifp
;
698 zlog_debug("%s: %s ifindex=%d disconnected IP address %pFX %s",
699 __func__
, ifp
->name
, ifp
->ifindex
, ifc
->address
,
700 CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
)
704 detect_address_change(ifp
, force_prim_as_any
, __func__
);
706 pim_if_addr_del_igmp(ifc
);
707 pim_if_addr_del_pim(ifc
);
710 void pim_if_addr_add_all(struct interface
*ifp
)
712 struct connected
*ifc
;
713 struct listnode
*node
;
714 struct listnode
*nextnode
;
717 struct pim_interface
*pim_ifp
= ifp
->info
;
721 /* PIM/IGMP enabled ? */
725 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
726 struct prefix
*p
= ifc
->address
;
728 if (p
->family
!= AF_INET
)
732 pim_if_addr_add(ifc
);
735 if (!v4_addrs
&& v6_addrs
&& !if_is_loopback(ifp
)) {
736 if (PIM_IF_TEST_PIM(pim_ifp
->options
)) {
738 /* Interface has a valid primary address ? */
739 if (!pim_addr_is_any(pim_ifp
->primary_address
)) {
741 /* Interface has a valid socket ? */
742 if (pim_ifp
->pim_sock_fd
< 0) {
743 if (pim_sock_add(ifp
)) {
745 "Failure creating PIM socket for interface %s",
753 * PIM or IGMP is enabled on interface, and there is at least one
754 * address assigned, then try to create a vif_index.
756 if (pim_ifp
->mroute_vif_index
< 0) {
757 vxlan_term
= pim_vxlan_is_term_dev_cfg(pim_ifp
->pim
, ifp
);
758 pim_if_add_vif(ifp
, false, vxlan_term
);
760 pim_ifchannel_scan_forward_start(ifp
);
762 pim_rp_setup(pim_ifp
->pim
);
763 pim_rp_check_on_if_add(pim_ifp
);
766 void pim_if_addr_del_all(struct interface
*ifp
)
768 struct connected
*ifc
;
769 struct listnode
*node
;
770 struct listnode
*nextnode
;
771 struct pim_instance
*pim
;
773 pim
= ifp
->vrf
->info
;
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(ifc
, 1 /* force_prim_as_any=true */);
791 pim_i_am_rp_re_evaluate(pim
);
794 void pim_if_addr_del_all_igmp(struct interface
*ifp
)
796 struct connected
*ifc
;
797 struct listnode
*node
;
798 struct listnode
*nextnode
;
800 /* PIM/IGMP enabled ? */
804 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
805 struct prefix
*p
= ifc
->address
;
807 if (p
->family
!= AF_INET
)
810 pim_if_addr_del_igmp(ifc
);
814 pim_addr
pim_find_primary_addr(struct interface
*ifp
)
816 struct connected
*ifc
;
817 struct listnode
*node
;
820 struct pim_interface
*pim_ifp
= ifp
->info
;
822 if (pim_ifp
&& !pim_addr_is_any(pim_ifp
->update_source
)) {
823 return pim_ifp
->update_source
;
826 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, ifc
)) {
829 switch (ifc
->address
->family
) {
840 if (CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
))
843 if (ifc
->address
->family
!= PIM_AF
)
846 addr
= pim_addr_from_prefix(ifc
->address
);
849 if (!IN6_IS_ADDR_LINKLOCAL(&addr
))
857 * If we have no v4_addrs and v6 is configured
858 * We probably are using unnumbered
859 * So let's grab the loopbacks v4 address
860 * and use that as the primary address
862 if (!v4_addrs
&& v6_addrs
) {
863 struct interface
*lo_ifp
;
865 // DBS - Come back and check here
866 if (ifp
->vrf
->vrf_id
== VRF_DEFAULT
)
867 lo_ifp
= if_lookup_by_name("lo", ifp
->vrf
->vrf_id
);
869 lo_ifp
= if_lookup_by_name(ifp
->vrf
->name
,
872 if (lo_ifp
&& (lo_ifp
!= ifp
))
873 return pim_find_primary_addr(lo_ifp
);
879 static int pim_iface_next_vif_index(struct interface
*ifp
)
881 struct pim_interface
*pim_ifp
= ifp
->info
;
882 struct pim_instance
*pim
= pim_ifp
->pim
;
886 * The pimreg vif is always going to be in index 0
889 if (ifp
->ifindex
== PIM_OIF_PIM_REGISTER_VIF
)
892 for (i
= 1; i
< MAXVIFS
; i
++) {
893 if (pim
->iface_vif_index
[i
] == 0)
900 pim_if_add_vif() uses ifindex as vif_index
902 see also pim_if_find_vifindex_by_ifindex()
904 int pim_if_add_vif(struct interface
*ifp
, bool ispimreg
, bool is_vxlan_term
)
906 struct pim_interface
*pim_ifp
= ifp
->info
;
908 unsigned char flags
= 0;
912 if (pim_ifp
->mroute_vif_index
> 0) {
913 zlog_warn("%s: vif_index=%d > 0 on interface %s ifindex=%d",
914 __func__
, pim_ifp
->mroute_vif_index
, ifp
->name
,
919 if (ifp
->ifindex
< 0) {
920 zlog_warn("%s: ifindex=%d < 1 on interface %s", __func__
,
921 ifp
->ifindex
, ifp
->name
);
925 ifaddr
= pim_ifp
->primary_address
;
926 if (!ispimreg
&& !is_vxlan_term
&& pim_addr_is_any(ifaddr
)) {
928 "%s: could not get address for interface %s ifindex=%d",
929 __func__
, ifp
->name
, ifp
->ifindex
);
933 pim_ifp
->mroute_vif_index
= pim_iface_next_vif_index(ifp
);
935 if (pim_ifp
->mroute_vif_index
>= MAXVIFS
) {
937 "%s: Attempting to configure more than MAXVIFS=%d on pim enabled interface %s",
938 __func__
, MAXVIFS
, ifp
->name
);
942 if (ifp
->ifindex
== PIM_OIF_PIM_REGISTER_VIF
)
943 flags
= VIFF_REGISTER
;
944 #ifdef VIFF_USE_IFINDEX
946 flags
= VIFF_USE_IFINDEX
;
949 if (pim_mroute_add_vif(ifp
, ifaddr
, flags
)) {
950 /* pim_mroute_add_vif reported error */
954 pim_ifp
->pim
->iface_vif_index
[pim_ifp
->mroute_vif_index
] = 1;
956 /* if the device qualifies as pim_vxlan iif/oif update vxlan entries */
957 pim_vxlan_add_vif(ifp
);
962 int pim_if_del_vif(struct interface
*ifp
)
964 struct pim_interface
*pim_ifp
= ifp
->info
;
966 if (pim_ifp
->mroute_vif_index
< 1) {
967 zlog_warn("%s: vif_index=%d < 1 on interface %s ifindex=%d",
968 __func__
, pim_ifp
->mroute_vif_index
, ifp
->name
,
973 /* if the device was a pim_vxlan iif/oif update vxlan mroute entries */
974 pim_vxlan_del_vif(ifp
);
976 pim_mroute_del_vif(ifp
);
981 pim_ifp
->pim
->iface_vif_index
[pim_ifp
->mroute_vif_index
] = 0;
983 pim_ifp
->mroute_vif_index
= -1;
989 struct interface
*pim_if_find_by_vif_index(struct pim_instance
*pim
,
992 struct interface
*ifp
;
994 FOR_ALL_INTERFACES (pim
->vrf
, ifp
) {
996 struct pim_interface
*pim_ifp
;
999 if (vif_index
== pim_ifp
->mroute_vif_index
)
1008 pim_if_add_vif() uses ifindex as vif_index
1010 int pim_if_find_vifindex_by_ifindex(struct pim_instance
*pim
, ifindex_t ifindex
)
1012 struct pim_interface
*pim_ifp
;
1013 struct interface
*ifp
;
1015 ifp
= if_lookup_by_index(ifindex
, pim
->vrf
->vrf_id
);
1016 if (!ifp
|| !ifp
->info
)
1018 pim_ifp
= ifp
->info
;
1020 return pim_ifp
->mroute_vif_index
;
1023 int pim_if_lan_delay_enabled(struct interface
*ifp
)
1025 struct pim_interface
*pim_ifp
;
1027 pim_ifp
= ifp
->info
;
1029 assert(pim_ifp
->pim_number_of_nonlandelay_neighbors
>= 0);
1031 return pim_ifp
->pim_number_of_nonlandelay_neighbors
== 0;
1034 uint16_t pim_if_effective_propagation_delay_msec(struct interface
*ifp
)
1036 if (pim_if_lan_delay_enabled(ifp
)) {
1037 struct pim_interface
*pim_ifp
;
1038 pim_ifp
= ifp
->info
;
1039 return pim_ifp
->pim_neighbors_highest_propagation_delay_msec
;
1041 return PIM_DEFAULT_PROPAGATION_DELAY_MSEC
;
1045 uint16_t pim_if_effective_override_interval_msec(struct interface
*ifp
)
1047 if (pim_if_lan_delay_enabled(ifp
)) {
1048 struct pim_interface
*pim_ifp
;
1049 pim_ifp
= ifp
->info
;
1050 return pim_ifp
->pim_neighbors_highest_override_interval_msec
;
1052 return PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC
;
1056 int pim_if_t_override_msec(struct interface
*ifp
)
1058 int effective_override_interval_msec
;
1059 int t_override_msec
;
1061 effective_override_interval_msec
=
1062 pim_if_effective_override_interval_msec(ifp
);
1065 frr_weak_random() % (effective_override_interval_msec
+ 1);
1067 return t_override_msec
;
1070 uint16_t pim_if_jp_override_interval_msec(struct interface
*ifp
)
1072 return pim_if_effective_propagation_delay_msec(ifp
)
1073 + pim_if_effective_override_interval_msec(ifp
);
1077 RFC 4601: 4.1.6. State Summarization Macros
1079 The function NBR( I, A ) uses information gathered through PIM Hello
1080 messages to map the IP address A of a directly connected PIM
1081 neighbor router on interface I to the primary IP address of the same
1082 router (Section 4.3.4). The primary IP address of a neighbor is the
1083 address that it uses as the source of its PIM Hello messages.
1085 struct pim_neighbor
*pim_if_find_neighbor(struct interface
*ifp
, pim_addr addr
)
1087 struct listnode
*neighnode
;
1088 struct pim_neighbor
*neigh
;
1089 struct pim_interface
*pim_ifp
;
1094 pim_ifp
= ifp
->info
;
1096 zlog_warn("%s: multicast not enabled on interface %s", __func__
,
1101 pim_addr_to_prefix(&p
, addr
);
1103 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
, neighnode
,
1106 /* primary address ? */
1107 if (!pim_addr_cmp(neigh
->source_addr
, addr
))
1110 /* secondary address ? */
1111 if (pim_neighbor_find_secondary(neigh
, &p
))
1115 if (PIM_DEBUG_PIM_TRACE
)
1117 "%s: neighbor not found for address %pPA on interface %s",
1118 __func__
, &addr
, ifp
->name
);
1123 long pim_if_t_suppressed_msec(struct interface
*ifp
)
1125 struct pim_interface
*pim_ifp
;
1126 long t_suppressed_msec
;
1127 uint32_t ramount
= 0;
1129 pim_ifp
= ifp
->info
;
1132 /* join suppression disabled ? */
1133 if (PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPPRESSION(pim_ifp
->options
))
1136 /* t_suppressed = t_periodic * rand(1.1, 1.4) */
1137 ramount
= 1100 + (frr_weak_random() % (1400 - 1100 + 1));
1138 t_suppressed_msec
= router
->t_periodic
* ramount
;
1140 return t_suppressed_msec
;
1143 static void igmp_join_free(struct gm_join
*ij
)
1145 XFREE(MTYPE_PIM_IGMP_JOIN
, ij
);
1148 static struct gm_join
*igmp_join_find(struct list
*join_list
,
1149 struct in_addr group_addr
,
1150 struct in_addr source_addr
)
1152 struct listnode
*node
;
1157 for (ALL_LIST_ELEMENTS_RO(join_list
, node
, ij
)) {
1158 if ((group_addr
.s_addr
== ij
->group_addr
.s_addr
)
1159 && (source_addr
.s_addr
== ij
->source_addr
.s_addr
))
1166 static int igmp_join_sock(const char *ifname
, ifindex_t ifindex
,
1167 struct in_addr group_addr
, struct in_addr source_addr
)
1171 join_fd
= pim_socket_raw(IPPROTO_IGMP
);
1176 if (pim_igmp_join_source(join_fd
, ifindex
, group_addr
, source_addr
)) {
1177 char group_str
[INET_ADDRSTRLEN
];
1178 char source_str
[INET_ADDRSTRLEN
];
1179 pim_inet4_dump("<grp?>", group_addr
, group_str
,
1181 pim_inet4_dump("<src?>", source_addr
, source_str
,
1182 sizeof(source_str
));
1184 "%s: setsockopt(fd=%d) failure for IGMP group %s source %s ifindex %d on interface %s: errno=%d: %s",
1185 __func__
, join_fd
, group_str
, source_str
, ifindex
,
1186 ifname
, errno
, safe_strerror(errno
));
1195 static struct gm_join
*igmp_join_new(struct interface
*ifp
,
1196 struct in_addr group_addr
,
1197 struct in_addr source_addr
)
1199 struct pim_interface
*pim_ifp
;
1203 pim_ifp
= ifp
->info
;
1206 join_fd
= igmp_join_sock(ifp
->name
, ifp
->ifindex
, group_addr
,
1209 char group_str
[INET_ADDRSTRLEN
];
1210 char source_str
[INET_ADDRSTRLEN
];
1212 pim_inet4_dump("<grp?>", group_addr
, group_str
,
1214 pim_inet4_dump("<src?>", source_addr
, source_str
,
1215 sizeof(source_str
));
1217 "%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s",
1218 __func__
, group_str
, source_str
, ifp
->name
);
1222 ij
= XCALLOC(MTYPE_PIM_IGMP_JOIN
, sizeof(*ij
));
1224 ij
->sock_fd
= join_fd
;
1225 ij
->group_addr
= group_addr
;
1226 ij
->source_addr
= source_addr
;
1227 ij
->sock_creation
= pim_time_monotonic_sec();
1229 listnode_add(pim_ifp
->gm_join_list
, ij
);
1234 ferr_r
pim_if_igmp_join_add(struct interface
*ifp
, struct in_addr group_addr
,
1235 struct in_addr source_addr
)
1237 struct pim_interface
*pim_ifp
;
1240 pim_ifp
= ifp
->info
;
1242 return ferr_cfg_invalid("multicast not enabled on interface %s",
1246 if (!pim_ifp
->gm_join_list
) {
1247 pim_ifp
->gm_join_list
= list_new();
1248 pim_ifp
->gm_join_list
->del
= (void (*)(void *))igmp_join_free
;
1251 ij
= igmp_join_find(pim_ifp
->gm_join_list
, group_addr
, source_addr
);
1253 /* This interface has already been configured to join this IGMP group
1259 (void)igmp_join_new(ifp
, group_addr
, source_addr
);
1261 if (PIM_DEBUG_IGMP_EVENTS
) {
1262 char group_str
[INET_ADDRSTRLEN
];
1263 char source_str
[INET_ADDRSTRLEN
];
1264 pim_inet4_dump("<grp?>", group_addr
, group_str
,
1266 pim_inet4_dump("<src?>", source_addr
, source_str
,
1267 sizeof(source_str
));
1269 "%s: issued static igmp join for channel (S,G)=(%s,%s) on interface %s",
1270 __func__
, source_str
, group_str
, ifp
->name
);
1277 int pim_if_igmp_join_del(struct interface
*ifp
, struct in_addr group_addr
,
1278 struct in_addr source_addr
)
1280 struct pim_interface
*pim_ifp
;
1283 pim_ifp
= ifp
->info
;
1285 zlog_warn("%s: multicast not enabled on interface %s", __func__
,
1290 if (!pim_ifp
->gm_join_list
) {
1291 zlog_warn("%s: no IGMP join on interface %s", __func__
,
1296 ij
= igmp_join_find(pim_ifp
->gm_join_list
, group_addr
, source_addr
);
1298 char group_str
[INET_ADDRSTRLEN
];
1299 char source_str
[INET_ADDRSTRLEN
];
1300 pim_inet4_dump("<grp?>", group_addr
, group_str
,
1302 pim_inet4_dump("<src?>", source_addr
, source_str
,
1303 sizeof(source_str
));
1305 "%s: could not find IGMP group %s source %s on interface %s",
1306 __func__
, group_str
, source_str
, ifp
->name
);
1310 if (close(ij
->sock_fd
)) {
1311 char group_str
[INET_ADDRSTRLEN
];
1312 char source_str
[INET_ADDRSTRLEN
];
1313 pim_inet4_dump("<grp?>", group_addr
, group_str
,
1315 pim_inet4_dump("<src?>", source_addr
, source_str
,
1316 sizeof(source_str
));
1318 "%s: failure closing sock_fd=%d for IGMP group %s source %s on interface %s: errno=%d: %s",
1319 __func__
, ij
->sock_fd
, group_str
, source_str
, ifp
->name
,
1320 errno
, safe_strerror(errno
));
1323 listnode_delete(pim_ifp
->gm_join_list
, ij
);
1325 if (listcount(pim_ifp
->gm_join_list
) < 1) {
1326 list_delete(&pim_ifp
->gm_join_list
);
1327 pim_ifp
->gm_join_list
= 0;
1333 static void pim_if_igmp_join_del_all(struct interface
*ifp
)
1335 struct pim_interface
*pim_ifp
;
1336 struct listnode
*node
;
1337 struct listnode
*nextnode
;
1340 pim_ifp
= ifp
->info
;
1342 zlog_warn("%s: multicast not enabled on interface %s", __func__
,
1347 if (!pim_ifp
->gm_join_list
)
1350 for (ALL_LIST_ELEMENTS(pim_ifp
->gm_join_list
, node
, nextnode
, ij
))
1351 pim_if_igmp_join_del(ifp
, ij
->group_addr
, ij
->source_addr
);
1357 Transitions from "I am Assert Loser" State
1359 Current Winner's GenID Changes or NLT Expires
1361 The Neighbor Liveness Timer associated with the current winner
1362 expires or we receive a Hello message from the current winner
1363 reporting a different GenID from the one it previously reported.
1364 This indicates that the current winner's interface or router has
1365 gone down (and may have come back up), and so we must assume it no
1366 longer knows it was the winner.
1368 void pim_if_assert_on_neighbor_down(struct interface
*ifp
, pim_addr neigh_addr
)
1370 struct pim_interface
*pim_ifp
;
1371 struct pim_ifchannel
*ch
;
1373 pim_ifp
= ifp
->info
;
1376 RB_FOREACH (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
) {
1377 /* Is (S,G,I) assert loser ? */
1378 if (ch
->ifassert_state
!= PIM_IFASSERT_I_AM_LOSER
)
1380 /* Dead neighbor was winner ? */
1381 if (pim_addr_cmp(ch
->ifassert_winner
, neigh_addr
))
1384 assert_action_a5(ch
);
1388 void pim_if_update_join_desired(struct pim_interface
*pim_ifp
)
1390 struct pim_ifchannel
*ch
;
1392 /* clear off flag from interface's upstreams */
1393 RB_FOREACH (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
) {
1394 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(
1395 ch
->upstream
->flags
);
1398 /* scan per-interface (S,G,I) state on this I interface */
1399 RB_FOREACH (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
) {
1400 struct pim_upstream
*up
= ch
->upstream
;
1402 if (PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(up
->flags
))
1405 /* update join_desired for the global (S,G) state */
1406 pim_upstream_update_join_desired(pim_ifp
->pim
, up
);
1407 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(up
->flags
);
1411 void pim_if_update_assert_tracking_desired(struct interface
*ifp
)
1413 struct pim_interface
*pim_ifp
;
1414 struct pim_ifchannel
*ch
;
1416 pim_ifp
= ifp
->info
;
1420 RB_FOREACH (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
) {
1421 pim_ifchannel_update_assert_tracking_desired(ch
);
1426 * PIM wants to have an interface pointer for everything it does.
1427 * The pimreg is a special interface that we have that is not
1428 * quite an inteface but a VIF is created for it.
1430 void pim_if_create_pimreg(struct pim_instance
*pim
)
1432 char pimreg_name
[INTERFACE_NAMSIZ
];
1434 if (!pim
->regiface
) {
1435 if (pim
->vrf
->vrf_id
== VRF_DEFAULT
)
1436 strlcpy(pimreg_name
, "pimreg", sizeof(pimreg_name
));
1438 snprintf(pimreg_name
, sizeof(pimreg_name
), "pimreg%u",
1439 pim
->vrf
->data
.l
.table_id
);
1441 pim
->regiface
= if_get_by_name(pimreg_name
, pim
->vrf
->vrf_id
,
1443 pim
->regiface
->ifindex
= PIM_OIF_PIM_REGISTER_VIF
;
1445 pim_if_new(pim
->regiface
, false, false, true,
1446 false /*vxlan_term*/);
1448 * On vrf moves we delete the interface if there
1449 * is nothing going on with it. We cannot have
1450 * the pimregiface deleted.
1452 pim
->regiface
->configured
= true;
1457 struct prefix
*pim_if_connected_to_source(struct interface
*ifp
, pim_addr src
)
1459 struct listnode
*cnode
;
1460 struct connected
*c
;
1466 pim_addr_to_prefix(&p
, src
);
1468 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, cnode
, c
)) {
1469 if (c
->address
->family
!= PIM_AF
)
1471 if (prefix_match(c
->address
, &p
))
1473 if (CONNECTED_PEER(c
) && prefix_match(c
->destination
, &p
))
1474 /* this is not a typo, on PtP we need to return the
1475 * *local* address that lines up with src.
1483 bool pim_if_is_vrf_device(struct interface
*ifp
)
1491 int pim_if_ifchannel_count(struct pim_interface
*pim_ifp
)
1493 struct pim_ifchannel
*ch
;
1496 RB_FOREACH (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
) {
1503 static int pim_ifp_create(struct interface
*ifp
)
1505 struct pim_instance
*pim
;
1507 pim
= ifp
->vrf
->info
;
1508 if (PIM_DEBUG_ZEBRA
) {
1510 "%s: %s index %d vrf %s(%u) flags %ld metric %d mtu %d operative %d",
1511 __func__
, ifp
->name
, ifp
->ifindex
, ifp
->vrf
->name
,
1512 ifp
->vrf
->vrf_id
, (long)ifp
->flags
, ifp
->metric
,
1513 ifp
->mtu
, if_is_operative(ifp
));
1516 if (if_is_operative(ifp
)) {
1517 struct pim_interface
*pim_ifp
;
1519 pim_ifp
= ifp
->info
;
1521 * If we have a pim_ifp already and this is an if_add
1522 * that means that we probably have a vrf move event
1523 * If that is the case, set the proper vrfness.
1527 pim_if_addr_add_all(ifp
);
1530 * Due to ordering issues based upon when
1531 * a command is entered we should ensure that
1532 * the pim reg is created for this vrf if we
1533 * have configuration for it already.
1535 * this is a no-op if it's already been done.
1537 pim_if_create_pimreg(pim
);
1541 * If we are a vrf device that is up, open up the pim_socket for
1543 * to incoming pim messages irrelevant if the user has configured us
1546 if (pim_if_is_vrf_device(ifp
)) {
1547 struct pim_interface
*pim_ifp
;
1550 pim_ifp
= pim_if_new(ifp
, false, false, false,
1551 false /*vxlan_term*/);
1552 ifp
->info
= pim_ifp
;
1558 if (!strncmp(ifp
->name
, PIM_VXLAN_TERM_DEV_NAME
,
1559 sizeof(PIM_VXLAN_TERM_DEV_NAME
))) {
1560 if (pim
->mcast_if_count
< MAXVIFS
)
1561 pim_vxlan_add_term_dev(pim
, ifp
);
1564 "%s: Cannot enable pim on %s. MAXVIFS(%d) reached. Deleting and readding the vxlan termimation device after unconfiguring pim from other interfaces may succeed.",
1565 __func__
, ifp
->name
, MAXVIFS
);
1571 static int pim_ifp_up(struct interface
*ifp
)
1573 struct pim_interface
*pim_ifp
;
1574 struct pim_instance
*pim
;
1577 if (PIM_DEBUG_ZEBRA
) {
1579 "%s: %s index %d vrf %s(%u) flags %ld metric %d mtu %d operative %d",
1580 __func__
, ifp
->name
, ifp
->ifindex
, ifp
->vrf
->name
,
1581 ifp
->vrf
->vrf_id
, (long)ifp
->flags
, ifp
->metric
,
1582 ifp
->mtu
, if_is_operative(ifp
));
1585 pim
= ifp
->vrf
->info
;
1587 pim_ifp
= ifp
->info
;
1589 * If we have a pim_ifp already and this is an if_add
1590 * that means that we probably have a vrf move event
1591 * If that is the case, set the proper vrfness.
1597 pim_if_addr_add_all() suffices for bringing up both IGMP and
1600 pim_if_addr_add_all(ifp
);
1603 * If we have a pimreg device callback and it's for a specific
1604 * table set the master appropriately
1606 if (sscanf(ifp
->name
, "pimreg%" SCNu32
, &table_id
) == 1) {
1608 RB_FOREACH (vrf
, vrf_name_head
, &vrfs_by_name
) {
1609 if ((table_id
== vrf
->data
.l
.table_id
)
1610 && (ifp
->vrf
->vrf_id
!= vrf
->vrf_id
)) {
1611 struct interface
*master
= if_lookup_by_name(
1612 vrf
->name
, vrf
->vrf_id
);
1616 "%s: Unable to find Master interface for %s",
1617 __func__
, vrf
->name
);
1620 pim_zebra_interface_set_master(master
, ifp
);
1627 static int pim_ifp_down(struct interface
*ifp
)
1629 if (PIM_DEBUG_ZEBRA
) {
1631 "%s: %s index %d vrf %s(%u) flags %ld metric %d mtu %d operative %d",
1632 __func__
, ifp
->name
, ifp
->ifindex
, ifp
->vrf
->name
,
1633 ifp
->vrf
->vrf_id
, (long)ifp
->flags
, ifp
->metric
,
1634 ifp
->mtu
, if_is_operative(ifp
));
1637 if (!if_is_operative(ifp
)) {
1638 pim_ifchannel_delete_all(ifp
);
1640 pim_if_addr_del_all() suffices for shutting down IGMP,
1641 but not for shutting down PIM
1643 pim_if_addr_del_all(ifp
);
1646 pim_sock_delete() closes the socket, stops read and timer
1648 and kills all neighbors.
1651 pim_sock_delete(ifp
, "link down");
1656 pim_if_del_vif(ifp
);
1657 pim_ifstat_reset(ifp
);
1663 static int pim_ifp_destroy(struct interface
*ifp
)
1665 struct pim_instance
*pim
;
1667 if (PIM_DEBUG_ZEBRA
) {
1669 "%s: %s index %d vrf %s(%u) flags %ld metric %d mtu %d operative %d",
1670 __func__
, ifp
->name
, ifp
->ifindex
, ifp
->vrf
->name
,
1671 ifp
->vrf
->vrf_id
, (long)ifp
->flags
, ifp
->metric
,
1672 ifp
->mtu
, if_is_operative(ifp
));
1675 if (!if_is_operative(ifp
))
1676 pim_if_addr_del_all(ifp
);
1678 pim
= ifp
->vrf
->info
;
1679 if (pim
&& pim
->vxlan
.term_if
== ifp
)
1680 pim_vxlan_del_term_dev(pim
);
1685 static int pim_if_new_hook(struct interface
*ifp
)
1690 static int pim_if_delete_hook(struct interface
*ifp
)
1698 void pim_iface_init(void)
1700 hook_register_prio(if_add
, 0, pim_if_new_hook
);
1701 hook_register_prio(if_del
, 0, pim_if_delete_hook
);
1703 if_zapi_callbacks(pim_ifp_create
, pim_ifp_up
, pim_ifp_down
,