summaryrefslogtreecommitdiff
path: root/pimd/pim_iface.c
diff options
context:
space:
mode:
Diffstat (limited to 'pimd/pim_iface.c')
-rw-r--r--pimd/pim_iface.c443
1 files changed, 361 insertions, 82 deletions
diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c
index bac9692caa..cc4f4f3dce 100644
--- a/pimd/pim_iface.c
+++ b/pimd/pim_iface.c
@@ -25,6 +25,8 @@
#include "memory.h"
#include "prefix.h"
#include "vrf.h"
+#include "linklist.h"
+#include "plist.h"
#include "pimd.h"
#include "pim_iface.h"
@@ -38,14 +40,26 @@
#include "pim_sock.h"
#include "pim_time.h"
#include "pim_ssmpingd.h"
+#include "pim_rp.h"
struct interface *pim_regiface = NULL;
+struct list *pim_ifchannel_list = NULL;
static void pim_if_igmp_join_del_all(struct interface *ifp);
-void pim_if_init()
+void
+pim_if_init (void)
{
vrf_iflist_create(VRF_DEFAULT);
+ pim_ifchannel_list = list_new();
+ pim_ifchannel_list->cmp = (int (*)(void *, void *))pim_ifchannel_compare;
+}
+
+void
+pim_if_terminate (void)
+{
+ if (pim_ifchannel_list)
+ list_free (pim_ifchannel_list);
}
static void *if_list_clean(struct pim_interface *pim_ifp)
@@ -78,15 +92,16 @@ struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim)
zassert(ifp);
zassert(!ifp->info);
- pim_ifp = XMALLOC(MTYPE_PIM_INTERFACE, sizeof(*pim_ifp));
+ pim_ifp = XCALLOC(MTYPE_PIM_INTERFACE, sizeof(*pim_ifp));
if (!pim_ifp) {
- zlog_err("PIM XMALLOC(%zu) failure", sizeof(*pim_ifp));
+ zlog_err("PIM XCALLOC(%zu) failure", sizeof(*pim_ifp));
return 0;
}
pim_ifp->options = 0;
pim_ifp->mroute_vif_index = -1;
+ pim_ifp->igmp_version = IGMP_DEFAULT_VERSION;
pim_ifp->igmp_default_robustness_variable = IGMP_DEFAULT_ROBUSTNESS_VARIABLE;
pim_ifp->igmp_default_query_interval = IGMP_GENERAL_QUERY_INTERVAL;
pim_ifp->igmp_query_max_response_time_dsec = IGMP_QUERY_MAX_RESPONSE_TIME_DSEC;
@@ -104,15 +119,12 @@ struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim)
if (igmp)
PIM_IF_DO_IGMP(pim_ifp->options);
-#if 0
- /* FIXME: Should join? */
PIM_IF_DO_IGMP_LISTEN_ALLROUTERS(pim_ifp->options);
-#endif
- pim_ifp->igmp_join_list = 0;
- pim_ifp->igmp_socket_list = 0;
- pim_ifp->pim_neighbor_list = 0;
- pim_ifp->pim_ifchannel_list = 0;
+ pim_ifp->igmp_join_list = NULL;
+ pim_ifp->igmp_socket_list = NULL;
+ pim_ifp->pim_neighbor_list = NULL;
+ pim_ifp->pim_ifchannel_list = NULL;
pim_ifp->pim_generation_id = 0;
/* list of struct igmp_sock */
@@ -141,6 +153,7 @@ struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim)
return if_list_clean(pim_ifp);
}
pim_ifp->pim_ifchannel_list->del = (void (*)(void *)) pim_ifchannel_free;
+ pim_ifp->pim_ifchannel_list->cmp = (int (*)(void *, void *)) pim_ifchannel_compare;
ifp->info = pim_ifp;
@@ -164,16 +177,11 @@ void pim_if_delete(struct interface *ifp)
if (pim_ifp->igmp_join_list) {
pim_if_igmp_join_del_all(ifp);
}
- zassert(!pim_ifp->igmp_join_list);
-
- zassert(pim_ifp->igmp_socket_list);
- zassert(!listcount(pim_ifp->igmp_socket_list));
- zassert(pim_ifp->pim_neighbor_list);
- zassert(!listcount(pim_ifp->pim_neighbor_list));
+ pim_ifchannel_delete_all (ifp);
+ igmp_sock_delete_all (ifp);
- zassert(pim_ifp->pim_ifchannel_list);
- zassert(!listcount(pim_ifp->pim_ifchannel_list));
+ pim_neighbor_delete_all (ifp, "Interface removed from configuration");
if (PIM_MROUTE_IS_ENABLED) {
pim_if_del_vif(ifp);
@@ -185,7 +193,7 @@ void pim_if_delete(struct interface *ifp)
XFREE(MTYPE_PIM_INTERFACE, pim_ifp);
- ifp->info = 0;
+ ifp->info = NULL;
}
void pim_if_update_could_assert(struct interface *ifp)
@@ -258,14 +266,10 @@ static int detect_primary_address_change(struct interface *ifp,
int force_prim_as_any,
const char *caller)
{
- struct pim_interface *pim_ifp;
+ struct pim_interface *pim_ifp = ifp->info;
struct in_addr new_prim_addr;
int changed;
- pim_ifp = ifp->info;
- if (!pim_ifp)
- return 0;
-
if (force_prim_as_any)
new_prim_addr = qpim_inaddr_any;
else
@@ -274,8 +278,8 @@ static int detect_primary_address_change(struct interface *ifp,
changed = new_prim_addr.s_addr != pim_ifp->primary_address.s_addr;
if (PIM_DEBUG_ZEBRA) {
- char new_prim_str[100];
- char old_prim_str[100];
+ char new_prim_str[INET_ADDRSTRLEN];
+ char old_prim_str[INET_ADDRSTRLEN];
pim_inet4_dump("<new?>", new_prim_addr, new_prim_str, sizeof(new_prim_str));
pim_inet4_dump("<old?>", pim_ifp->primary_address, old_prim_str, sizeof(old_prim_str));
zlog_debug("%s: old=%s new=%s on interface %s: %s",
@@ -286,57 +290,230 @@ static int detect_primary_address_change(struct interface *ifp,
if (changed) {
pim_ifp->primary_address = new_prim_addr;
+ }
- if (!PIM_IF_TEST_PIM(pim_ifp->options)) {
- return changed;
+ return changed;
+}
+
+static int pim_sec_addr_comp(const void *p1, const void *p2)
+{
+ const struct pim_secondary_addr *sec1 = p1;
+ const struct pim_secondary_addr *sec2 = p2;
+
+ if (ntohl(sec1->addr.s_addr) < ntohl(sec2->addr.s_addr))
+ return -1;
+
+ if (ntohl(sec1->addr.s_addr) > ntohl(sec2->addr.s_addr))
+ return 1;
+
+ return 0;
+}
+
+static void pim_sec_addr_free(struct pim_secondary_addr *sec_addr)
+{
+ XFREE(MTYPE_PIM_SEC_ADDR, sec_addr);
+}
+
+static struct pim_secondary_addr *
+pim_sec_addr_find(struct pim_interface *pim_ifp, struct in_addr addr)
+{
+ struct pim_secondary_addr *sec_addr;
+ struct listnode *node;
+
+ if (!pim_ifp->sec_addr_list) {
+ return NULL;
+ }
+
+ for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, node, sec_addr)) {
+ if (sec_addr->addr.s_addr == addr.s_addr) {
+ return sec_addr;
}
+ }
- pim_addr_change(ifp);
+ return NULL;
+}
+
+static void pim_sec_addr_del(struct pim_interface *pim_ifp,
+ struct pim_secondary_addr *sec_addr)
+{
+ listnode_delete(pim_ifp->sec_addr_list, sec_addr);
+ pim_sec_addr_free(sec_addr);
+}
+
+static int pim_sec_addr_add(struct pim_interface *pim_ifp, struct in_addr addr)
+{
+ int changed = 0;
+ struct pim_secondary_addr *sec_addr;
+
+ sec_addr = pim_sec_addr_find(pim_ifp, addr);
+ if (sec_addr) {
+ sec_addr->flags &= ~PIM_SEC_ADDRF_STALE;
+ return changed;
+ }
+
+ if (!pim_ifp->sec_addr_list) {
+ pim_ifp->sec_addr_list = list_new();
+ pim_ifp->sec_addr_list->del = (void (*)(void *))pim_sec_addr_free;
+ pim_ifp->sec_addr_list->cmp = (int (*)(void *, void *))pim_sec_addr_comp;
+ }
+
+ sec_addr = XCALLOC(MTYPE_PIM_SEC_ADDR, sizeof(*sec_addr));
+ if (!sec_addr) {
+ if (list_isempty(pim_ifp->sec_addr_list)) {
+ list_free(pim_ifp->sec_addr_list);
+ pim_ifp->sec_addr_list = NULL;
+ }
+ return changed;
+ }
+
+ changed = 1;
+ sec_addr->addr = addr;
+ listnode_add_sort(pim_ifp->sec_addr_list, sec_addr);
+
+ return changed;
+}
+
+static int pim_sec_addr_del_all(struct pim_interface *pim_ifp)
+{
+ int changed = 0;
+
+ if (!pim_ifp->sec_addr_list) {
+ return changed;
+ }
+ if (!list_isempty(pim_ifp->sec_addr_list)) {
+ changed = 1;
+ /* remove all nodes and free up the list itself */
+ list_delete_all_node(pim_ifp->sec_addr_list);
+ list_free(pim_ifp->sec_addr_list);
+ pim_ifp->sec_addr_list = NULL;
+ }
+
+ return changed;
+}
+
+static int pim_sec_addr_update(struct interface *ifp)
+{
+ struct pim_interface *pim_ifp = ifp->info;
+ struct connected *ifc;
+ struct listnode *node;
+ struct listnode *nextnode;
+ struct pim_secondary_addr *sec_addr;
+ int changed = 0;
+
+ if (pim_ifp->sec_addr_list) {
+ for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, node, sec_addr)) {
+ sec_addr->flags |= PIM_SEC_ADDRF_STALE;
+ }
+ }
+
+ for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
+ struct prefix *p = ifc->address;
+
+ if (p->family != AF_INET) {
+ continue;
+ }
+
+ if (PIM_INADDR_IS_ANY(p->u.prefix4)) {
+ continue;
+ }
+
+ if (pim_ifp->primary_address.s_addr == p->u.prefix4.s_addr) {
+ /* don't add the primary address into the secondary address list */
+ continue;
+ }
+
+ if (pim_sec_addr_add(pim_ifp, p->u.prefix4)) {
+ changed = 1;
+ }
+ }
+
+ if (pim_ifp->sec_addr_list) {
+ /* Drop stale entries */
+ for (ALL_LIST_ELEMENTS(pim_ifp->sec_addr_list, node, nextnode, sec_addr)) {
+ if (sec_addr->flags & PIM_SEC_ADDRF_STALE) {
+ pim_sec_addr_del(pim_ifp, sec_addr);
+ changed = 1;
+ }
+ }
+
+ /* If the list went empty free it up */
+ if (list_isempty(pim_ifp->sec_addr_list)) {
+ list_free(pim_ifp->sec_addr_list);
+ pim_ifp->sec_addr_list = NULL;
+ }
}
return changed;
}
-static void detect_secondary_address_change(struct interface *ifp,
+static int detect_secondary_address_change(struct interface *ifp,
+ int force_prim_as_any,
const char *caller)
{
+ struct pim_interface *pim_ifp = ifp->info;
+ int changed = 0;
+
+ if (force_prim_as_any) {
+ /* if primary address is being forced to zero just flush the
+ * secondary address list */
+ changed = pim_sec_addr_del_all(pim_ifp);
+ } else {
+ /* re-evaluate the secondary address list */
+ changed = pim_sec_addr_update(ifp);
+ }
+
+ return changed;
+}
+
+static void detect_address_change(struct interface *ifp,
+ int force_prim_as_any,
+ const char *caller)
+{
+ int changed = 0;
struct pim_interface *pim_ifp;
- int changed;
pim_ifp = ifp->info;
if (!pim_ifp)
return;
- changed = 1; /* true */
- if (PIM_DEBUG_ZEBRA)
- zlog_debug("FIXME T31 C15 %s: on interface %s: acting on any addr change",
- __PRETTY_FUNCTION__, ifp->name);
+ if (detect_primary_address_change(ifp, force_prim_as_any, caller)) {
+ changed = 1;
+ }
- if (!changed) {
- return;
+ if (detect_secondary_address_change(ifp, force_prim_as_any, caller)) {
+ changed = 1;
}
- if (!PIM_IF_TEST_PIM(pim_ifp->options)) {
- return;
+
+ if (changed) {
+ if (!PIM_IF_TEST_PIM(pim_ifp->options)) {
+ return;
+ }
+
+ pim_addr_change(ifp);
}
- pim_addr_change(ifp);
+ /* XXX: if we have unnumbered interfaces we need to run detect address
+ * address change on all of them when the lo address changes */
}
-static void detect_address_change(struct interface *ifp,
- int force_prim_as_any,
- const char *caller)
+int pim_update_source_set(struct interface *ifp, struct in_addr source)
{
- int prim_changed;
+ struct pim_interface *pim_ifp = ifp->info;
- prim_changed = detect_primary_address_change(ifp, force_prim_as_any, caller);
- if (prim_changed) {
- /* no need to detect secondary change because
- the reaction would be the same */
- return;
+ if (!pim_ifp) {
+ return PIM_IFACE_NOT_FOUND;
}
- detect_secondary_address_change(ifp, caller);
+ if (pim_ifp->update_source.s_addr == source.s_addr) {
+ return PIM_UPDATE_SOURCE_DUP;
+ }
+
+ pim_ifp->update_source = source;
+ detect_address_change(ifp, 0 /* force_prim_as_any */,
+ __PRETTY_FUNCTION__);
+
+ return PIM_SUCCESS;
}
void pim_if_addr_add(struct connected *ifc)
@@ -406,6 +583,7 @@ void pim_if_addr_add(struct connected *ifc)
if (pim_ifp->mroute_vif_index < 0) {
pim_if_add_vif(ifp);
}
+ pim_ifchannel_scan_forward_start (ifp);
}
}
@@ -496,19 +674,59 @@ void pim_if_addr_add_all(struct interface *ifp)
struct connected *ifc;
struct listnode *node;
struct listnode *nextnode;
+ int v4_addrs = 0;
+ int v6_addrs = 0;
+ struct pim_interface *pim_ifp = ifp->info;
+
/* PIM/IGMP enabled ? */
- if (!ifp->info)
+ if (!pim_ifp)
return;
for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
struct prefix *p = ifc->address;
if (p->family != AF_INET)
- continue;
+ {
+ v6_addrs++;
+ continue;
+ }
+ v4_addrs++;
pim_if_addr_add(ifc);
}
+
+ if (!v4_addrs && v6_addrs && !if_is_loopback (ifp))
+ {
+ if (PIM_IF_TEST_PIM(pim_ifp->options)) {
+
+ /* Interface has a valid primary address ? */
+ if (PIM_INADDR_ISNOT_ANY(pim_ifp->primary_address)) {
+
+ /* Interface has a valid socket ? */
+ if (pim_ifp->pim_sock_fd < 0) {
+ if (pim_sock_add(ifp)) {
+ zlog_warn("Failure creating PIM socket for interface %s",
+ ifp->name);
+ }
+ }
+
+ }
+ } /* pim */
+ }
+ if (PIM_MROUTE_IS_ENABLED) {
+ /*
+ * PIM or IGMP is enabled on interface, and there is at least one
+ * address assigned, then try to create a vif_index.
+ */
+ if (pim_ifp->mroute_vif_index < 0) {
+ pim_if_add_vif(ifp);
+ }
+ pim_ifchannel_scan_forward_start (ifp);
+ }
+
+ pim_rp_setup();
+ pim_rp_check_on_if_add(pim_ifp);
}
void pim_if_addr_del_all(struct interface *ifp)
@@ -529,6 +747,9 @@ void pim_if_addr_del_all(struct interface *ifp)
pim_if_addr_del(ifc, 1 /* force_prim_as_any=true */);
}
+
+ pim_rp_setup();
+ pim_i_am_rp_re_evaluate();
}
void pim_if_addr_del_all_igmp(struct interface *ifp)
@@ -571,17 +792,28 @@ void pim_if_addr_del_all_pim(struct interface *ifp)
}
}
-static struct in_addr find_first_nonsec_addr(struct interface *ifp)
+struct in_addr
+pim_find_primary_addr (struct interface *ifp)
{
struct connected *ifc;
struct listnode *node;
struct in_addr addr;
+ int v4_addrs = 0;
+ int v6_addrs = 0;
+ struct pim_interface *pim_ifp = ifp->info;
+
+ if (pim_ifp && PIM_INADDR_ISNOT_ANY(pim_ifp->update_source)) {
+ return pim_ifp->update_source;
+ }
for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
struct prefix *p = ifc->address;
-
+
if (p->family != AF_INET)
- continue;
+ {
+ v6_addrs++;
+ continue;
+ }
if (PIM_INADDR_IS_ANY(p->u.prefix4)) {
zlog_warn("%s: null IPv4 address connected to interface %s",
@@ -589,22 +821,33 @@ static struct in_addr find_first_nonsec_addr(struct interface *ifp)
continue;
}
+ v4_addrs++;
+
if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY))
continue;
return p->u.prefix4;
}
+ /*
+ * If we have no v4_addrs and v6 is configured
+ * We probably are using unnumbered
+ * So let's grab the loopbacks v4 address
+ * and use that as the primary address
+ */
+ if (!v4_addrs && v6_addrs && !if_is_loopback (ifp))
+ {
+ struct interface *lo_ifp;
+ lo_ifp = if_lookup_by_name_vrf ("lo", VRF_DEFAULT);
+ if (lo_ifp)
+ return pim_find_primary_addr (lo_ifp);
+ }
+
addr.s_addr = PIM_NET_INADDR_ANY;
return addr;
}
-struct in_addr pim_find_primary_addr(struct interface *ifp)
-{
- return find_first_nonsec_addr(ifp);
-}
-
static int pim_iface_vif_index = 0;
static int
@@ -800,9 +1043,9 @@ int pim_if_find_vifindex_by_ifindex(ifindex_t ifindex)
struct interface *ifp;
ifp = if_lookup_by_index_vrf (ifindex, VRF_DEFAULT);
- pim_ifp = ifp->info;
- if (!pim_ifp)
+ if (!ifp || !ifp->info)
return -1;
+ pim_ifp = ifp->info;
return pim_ifp->mroute_vif_index;
}
@@ -899,14 +1142,14 @@ struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp,
}
if (PIM_DEBUG_PIM_TRACE) {
- char addr_str[100];
+ char addr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
zlog_debug("%s: neighbor not found for address %s on interface %s",
__PRETTY_FUNCTION__,
addr_str, ifp->name);
}
- return 0;
+ return NULL;
}
long pim_if_t_suppressed_msec(struct interface *ifp)
@@ -985,8 +1228,8 @@ static struct igmp_join *igmp_join_new(struct interface *ifp,
join_fd = igmp_join_sock(ifp->name, ifp->ifindex, group_addr, source_addr);
if (join_fd < 0) {
- char group_str[100];
- char source_str[100];
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
zlog_warn("%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s",
@@ -995,13 +1238,13 @@ static struct igmp_join *igmp_join_new(struct interface *ifp,
return 0;
}
- ij = XMALLOC(MTYPE_PIM_IGMP_JOIN, sizeof(*ij));
+ ij = XCALLOC(MTYPE_PIM_IGMP_JOIN, sizeof(*ij));
if (!ij) {
- char group_str[100];
- char source_str[100];
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
- zlog_err("%s: XMALLOC(%zu) failure for IGMP group %s source %s on interface %s",
+ zlog_err("%s: XCALLOC(%zu) failure for IGMP group %s source %s on interface %s",
__PRETTY_FUNCTION__,
sizeof(*ij), group_str, source_str, ifp->name);
close(join_fd);
@@ -1045,8 +1288,8 @@ int pim_if_igmp_join_add(struct interface *ifp,
ij = igmp_join_find(pim_ifp->igmp_join_list, group_addr, source_addr);
if (ij) {
- char group_str[100];
- char source_str[100];
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
zlog_warn("%s: can't re-join existing IGMP group %s source %s on interface %s",
@@ -1057,8 +1300,8 @@ int pim_if_igmp_join_add(struct interface *ifp,
ij = igmp_join_new(ifp, group_addr, source_addr);
if (!ij) {
- char group_str[100];
- char source_str[100];
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
zlog_warn("%s: igmp_join_new() failure for IGMP group %s source %s on interface %s",
@@ -1068,8 +1311,8 @@ int pim_if_igmp_join_add(struct interface *ifp,
}
if (PIM_DEBUG_IGMP_EVENTS) {
- char group_str[100];
- char source_str[100];
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
zlog_debug("%s: issued static igmp join for channel (S,G)=(%s,%s) on interface %s",
@@ -1106,8 +1349,8 @@ int pim_if_igmp_join_del(struct interface *ifp,
ij = igmp_join_find(pim_ifp->igmp_join_list, group_addr, source_addr);
if (!ij) {
- char group_str[100];
- char source_str[100];
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
zlog_warn("%s: could not find IGMP group %s source %s on interface %s",
@@ -1117,14 +1360,13 @@ int pim_if_igmp_join_del(struct interface *ifp,
}
if (close(ij->sock_fd)) {
- int e = errno;
- char group_str[100];
- char source_str[100];
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
zlog_warn("%s: failure closing sock_fd=%d for IGMP group %s source %s on interface %s: errno=%d: %s",
__PRETTY_FUNCTION__,
- ij->sock_fd, group_str, source_str, ifp->name, e, safe_strerror(e));
+ ij->sock_fd, group_str, source_str, ifp->name, errno, safe_strerror(errno));
/* warning only */
}
listnode_delete(pim_ifp->igmp_join_list, ij);
@@ -1249,3 +1491,40 @@ void pim_if_create_pimreg (void)
pim_if_new(pim_regiface, 0, 0);
}
}
+
+int
+pim_if_connected_to_source (struct interface *ifp, struct in_addr src)
+{
+ struct listnode *cnode;
+ struct connected *c;
+ struct prefix p;
+
+ p.family = AF_INET;
+ p.u.prefix4 = src;
+ p.prefixlen = IPV4_MAX_BITLEN;
+
+ for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, c))
+ {
+ if ((c->address->family == AF_INET) &&
+ prefix_match (CONNECTED_PREFIX (c), &p))
+ {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+struct interface *
+pim_if_lookup_address_vrf (struct in_addr src, vrf_id_t vrf_id)
+{
+ struct listnode *ifnode;
+ struct interface *ifp;
+
+ for (ALL_LIST_ELEMENTS_RO (vrf_iflist(vrf_id), ifnode, ifp))
+ {
+ if (pim_if_connected_to_source (ifp, src) && ifp->info)
+ return ifp;
+ }
+ return NULL;
+}