summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_evpn.c40
-rw-r--r--pimd/pim_cmd.c17
-rw-r--r--pimd/pim_igmp_mtrace.c7
-rw-r--r--pimd/pim_join.c6
-rw-r--r--pimd/pim_jp_agg.c14
-rw-r--r--pimd/pim_mroute.c10
-rw-r--r--pimd/pim_nht.c57
-rw-r--r--pimd/pim_nht.h1
-rw-r--r--pimd/pim_oil.c58
-rw-r--r--pimd/pim_oil.h19
-rw-r--r--pimd/pim_rp.c167
-rw-r--r--pimd/pim_rp.h3
-rw-r--r--pimd/pim_rpf.c33
-rw-r--r--pimd/pim_rpf.h3
-rw-r--r--pimd/pim_upstream.c187
-rw-r--r--pimd/pim_upstream.h24
-rw-r--r--pimd/pim_zebra.c337
17 files changed, 733 insertions, 250 deletions
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c
index 19cda453f5..6ced286dde 100644
--- a/bgpd/bgp_evpn.c
+++ b/bgpd/bgp_evpn.c
@@ -48,6 +48,7 @@
#include "bgpd/bgp_zebra.h"
#include "bgpd/bgp_nexthop.h"
#include "bgpd/bgp_addpath.h"
+#include "bgpd/bgp_mac.h"
/*
* Definitions and external declarations.
@@ -2945,6 +2946,41 @@ static int install_uninstall_routes_for_es(struct bgp *bgp,
return 0;
}
+/* This API will scan evpn routes for checking attribute's rmac
+ * macthes with bgp instance router mac. It avoid installing
+ * route into bgp vrf table and remote rmac in bridge table.
+ */
+static int bgp_evpn_route_rmac_self_check(struct bgp *bgp_vrf,
+ struct prefix_evpn *evp,
+ struct bgp_path_info *pi)
+{
+ /* evpn route could have learnt prior to L3vni has come up,
+ * perform rmac check before installing route and
+ * remote router mac.
+ * The route will be removed from global bgp table once
+ * SVI comes up with MAC and stored in hash, triggers
+ * bgp_mac_rescan_all_evpn_tables.
+ */
+ if (pi->attr &&
+ memcmp(&bgp_vrf->rmac, &pi->attr->rmac, ETH_ALEN) == 0) {
+ if (bgp_debug_update(pi->peer, NULL, NULL, 1)) {
+ char buf1[PREFIX_STRLEN];
+ char attr_str[BUFSIZ] = {0};
+
+ bgp_dump_attr(pi->attr, attr_str, BUFSIZ);
+
+ zlog_debug("%s: bgp %u prefix %s with attr %s - DENIED due to self mac",
+ __func__, bgp_vrf->vrf_id,
+ prefix2str(evp, buf1, sizeof(buf1)),
+ attr_str);
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
/*
* Install or uninstall mac-ip routes are appropriate for this
* particular VRF.
@@ -3001,6 +3037,10 @@ static int install_uninstall_routes_for_vrf(struct bgp *bgp_vrf, int install)
continue;
if (is_route_matching_for_vrf(bgp_vrf, pi)) {
+ if (bgp_evpn_route_rmac_self_check(
+ bgp_vrf, evp, pi))
+ continue;
+
if (install)
ret = install_evpn_route_entry_in_vrf(
bgp_vrf, evp, pi);
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c
index 012c3b4f1d..f058b7adbf 100644
--- a/pimd/pim_cmd.c
+++ b/pimd/pim_cmd.c
@@ -2370,9 +2370,10 @@ static void pim_show_upstream(struct pim_instance *pim, struct vty *vty,
up->t_join_timer);
/*
- * If we have a J/P timer for the neighbor display that
+ * If the upstream is not dummy and it has a J/P timer for the
+ * neighbor display that
*/
- if (!up->t_join_timer) {
+ if (!up->t_join_timer && up->rpf.source_nexthop.interface) {
struct pim_neighbor *nbr;
nbr = pim_neighbor_find(
@@ -2412,8 +2413,10 @@ static void pim_show_upstream(struct pim_instance *pim, struct vty *vty,
json_row = json_object_new_object();
json_object_pim_upstream_add(json_row, up);
json_object_string_add(
- json_row, "inboundInterface",
- up->rpf.source_nexthop.interface->name);
+ json_row, "inboundInterface",
+ up->rpf.source_nexthop.interface
+ ? up->rpf.source_nexthop.interface->name
+ : "Unknown");
/*
* The RPF address we use is slightly different
@@ -2463,8 +2466,10 @@ static void pim_show_upstream(struct pim_instance *pim, struct vty *vty,
} else {
vty_out(vty,
"%-10s%-15s %-15s %-11s %-8s %-9s %-9s %-9s %6d\n",
- up->rpf.source_nexthop.interface->name, src_str,
- grp_str, state_str, uptime, join_timer,
+ up->rpf.source_nexthop.interface
+ ? up->rpf.source_nexthop.interface->name
+ : "Unknown",
+ src_str, grp_str, state_str, uptime, join_timer,
rs_timer, ka_timer, up->ref_count);
}
}
diff --git a/pimd/pim_igmp_mtrace.c b/pimd/pim_igmp_mtrace.c
index 1fb624a6a0..f51e0c0d2f 100644
--- a/pimd/pim_igmp_mtrace.c
+++ b/pimd/pim_igmp_mtrace.c
@@ -133,6 +133,13 @@ static bool mtrace_fwd_info(struct pim_instance *pim,
if (!up)
return false;
+ if (!up->rpf.source_nexthop.interface) {
+ if (PIM_DEBUG_TRACE)
+ zlog_debug("%s: up %s RPF is not present",
+ __PRETTY_FUNCTION__, up->sg_str);
+ return false;
+ }
+
ifp_in = up->rpf.source_nexthop.interface;
nh_addr = up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4;
total = htonl(MTRACE_UNKNOWN_COUNT);
diff --git a/pimd/pim_join.c b/pimd/pim_join.c
index ae5032be73..cbacaf3ea8 100644
--- a/pimd/pim_join.c
+++ b/pimd/pim_join.c
@@ -439,9 +439,6 @@ int pim_joinprune_send(struct pim_rpf *rpf, struct list *groups)
size_t packet_size = 0;
size_t group_size = 0;
- on_trace(__PRETTY_FUNCTION__, rpf->source_nexthop.interface,
- rpf->rpf_addr.u.prefix4);
-
if (rpf->source_nexthop.interface)
pim_ifp = rpf->source_nexthop.interface->info;
else {
@@ -450,6 +447,9 @@ int pim_joinprune_send(struct pim_rpf *rpf, struct list *groups)
return -1;
}
+ on_trace(__PRETTY_FUNCTION__, rpf->source_nexthop.interface,
+ rpf->rpf_addr.u.prefix4);
+
if (!pim_ifp) {
zlog_warn("%s: multicast not enabled on interface %s",
__PRETTY_FUNCTION__,
diff --git a/pimd/pim_jp_agg.c b/pimd/pim_jp_agg.c
index 7726ffda57..06a9e6d0d6 100644
--- a/pimd/pim_jp_agg.c
+++ b/pimd/pim_jp_agg.c
@@ -213,8 +213,18 @@ void pim_jp_agg_upstream_verification(struct pim_upstream *up, bool ignore)
{
#ifdef PIM_JP_AGG_DEBUG
struct interface *ifp;
- struct pim_interface *pim_ifp = up->rpf.source_nexthop.interface->info;
- struct pim_instance *pim = pim_ifp->pim;
+ struct pim_interface *pim_ifp;
+ struct pim_instance *pim;
+
+ if (!up->rpf.source_nexthop.interface) {
+ if (PIM_DEBUG_TRACE)
+ zlog_debug("%s: up %s RPF is not present",
+ __PRETTY_FUNCTION__, up->sg_str);
+ return;
+ }
+
+ pim_ifp = up->rpf.source_nexthop.interface->info;
+ pim = pim_ifp->pim;
FOR_ALL_INTERFACES (pim->vrf, ifp) {
pim_ifp = ifp->info;
diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c
index dd9e21cae8..67b1a95f74 100644
--- a/pimd/pim_mroute.c
+++ b/pimd/pim_mroute.c
@@ -234,7 +234,8 @@ static int pim_mroute_msg_nocache(int fd, struct interface *ifp,
up->channel_oil->cc.pktcnt++;
PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
// resolve mfcc_parent prior to mroute_add in channel_add_oif
- if (up->channel_oil->oil.mfcc_parent >= MAXVIFS) {
+ if (up->rpf.source_nexthop.interface &&
+ up->channel_oil->oil.mfcc_parent >= MAXVIFS) {
int vif_index = 0;
vif_index = pim_if_find_vifindex_by_ifindex(
pim_ifp->pim,
@@ -301,6 +302,13 @@ static int pim_mroute_msg_wholepkt(int fd, struct interface *ifp,
return 0;
}
+ if (!up->rpf.source_nexthop.interface) {
+ if (PIM_DEBUG_TRACE)
+ zlog_debug("%s: up %s RPF is not present",
+ __PRETTY_FUNCTION__, up->sg_str);
+ return 0;
+ }
+
pim_ifp = up->rpf.source_nexthop.interface->info;
rpg = pim_ifp ? RP(pim_ifp->pim, sg.grp) : NULL;
diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c
index b6cd1a7d11..9b5379384c 100644
--- a/pimd/pim_nht.c
+++ b/pimd/pim_nht.c
@@ -39,6 +39,7 @@
#include "pim_jp_agg.h"
#include "pim_zebra.h"
#include "pim_zlookup.h"
+#include "pim_rp.h"
/**
* pim_sendmsg_zebra_rnh -- Format and send a nexthop register/Unregister
@@ -170,6 +171,8 @@ void pim_delete_tracked_nexthop(struct pim_instance *pim, struct prefix *addr,
struct pim_nexthop_cache *pnc = NULL;
struct pim_nexthop_cache lookup;
struct zclient *zclient = NULL;
+ struct listnode *upnode = NULL;
+ struct pim_upstream *upstream = NULL;
zclient = pim_zebra_zclient_get();
@@ -177,8 +180,30 @@ void pim_delete_tracked_nexthop(struct pim_instance *pim, struct prefix *addr,
lookup.rpf.rpf_addr = *addr;
pnc = hash_lookup(pim->rpf_hash, &lookup);
if (pnc) {
- if (rp)
+ if (rp) {
+ /* Release the (*, G)upstream from pnc->upstream_hash,
+ * whose Group belongs to the RP getting deleted
+ */
+ for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode,
+ upstream)) {
+ struct prefix grp;
+ struct rp_info *trp_info;
+
+ if (upstream->sg.src.s_addr != INADDR_ANY)
+ continue;
+
+ grp.family = AF_INET;
+ grp.prefixlen = IPV4_MAX_BITLEN;
+ grp.u.prefix4 = upstream->sg.grp;
+
+ trp_info = pim_rp_find_match_group(pim, &grp);
+ if (trp_info == rp)
+ hash_release(pnc->upstream_hash,
+ upstream);
+ }
listnode_delete(pnc->rp_list, rp);
+ }
+
if (up)
hash_release(pnc->upstream_hash, up);
@@ -207,6 +232,17 @@ void pim_delete_tracked_nexthop(struct pim_instance *pim, struct prefix *addr,
}
}
+void pim_rp_nexthop_del(struct rp_info *rp_info)
+{
+ rp_info->rp.source_nexthop.interface = NULL;
+ rp_info->rp.source_nexthop.mrib_nexthop_addr.u.prefix4.s_addr =
+ PIM_NET_INADDR_ANY;
+ rp_info->rp.source_nexthop.mrib_metric_preference =
+ router->infinite_assert_metric.metric_preference;
+ rp_info->rp.source_nexthop.mrib_route_metric =
+ router->infinite_assert_metric.route_metric;
+}
+
/* Update RP nexthop info based on Nexthop update received from Zebra.*/
static void pim_update_rp_nh(struct pim_instance *pim,
struct pim_nexthop_cache *pnc)
@@ -220,9 +256,11 @@ static void pim_update_rp_nh(struct pim_instance *pim,
continue;
// Compute PIM RPF using cached nexthop
- pim_ecmp_nexthop_search(pim, pnc, &rp_info->rp.source_nexthop,
- &rp_info->rp.rpf_addr, &rp_info->group,
- 1);
+ if (!pim_ecmp_nexthop_search(pim, pnc,
+ &rp_info->rp.source_nexthop,
+ &rp_info->rp.rpf_addr, &rp_info->group,
+ 1))
+ pim_rp_nexthop_del(rp_info);
}
}
@@ -278,12 +316,12 @@ static int pim_update_upstream_nh_helper(struct hash_bucket *bucket, void *arg)
old.source_nexthop.interface = up->rpf.source_nexthop.interface;
rpf_result = pim_rpf_update(pim, up, &old, 0);
if (rpf_result == PIM_RPF_FAILURE) {
- pim_mroute_del(up->channel_oil, __PRETTY_FUNCTION__);
+ pim_upstream_rpf_clear(pim, up);
return HASHWALK_CONTINUE;
}
/* update kernel multicast forwarding cache (MFC) */
- if (up->channel_oil) {
+ if (up->rpf.source_nexthop.interface) {
ifindex_t ifindex = up->rpf.source_nexthop.interface->ifindex;
vif_index = pim_if_find_vifindex_by_ifindex(pim, ifindex);
@@ -306,9 +344,10 @@ static int pim_update_upstream_nh_helper(struct hash_bucket *bucket, void *arg)
if (PIM_DEBUG_PIM_NHT) {
zlog_debug("%s: NHT upstream %s(%s) old ifp %s new ifp %s",
- __PRETTY_FUNCTION__, up->sg_str, pim->vrf->name,
- old.source_nexthop.interface->name,
- up->rpf.source_nexthop.interface->name);
+ __PRETTY_FUNCTION__, up->sg_str, pim->vrf->name,
+ old.source_nexthop.interface
+ ? old.source_nexthop.interface->name : "Unknwon",
+ up->rpf.source_nexthop.interface->name);
}
return HASHWALK_CONTINUE;
diff --git a/pimd/pim_nht.h b/pimd/pim_nht.h
index 796fbf9731..6eff7bbc89 100644
--- a/pimd/pim_nht.h
+++ b/pimd/pim_nht.h
@@ -68,4 +68,5 @@ void pim_sendmsg_zebra_rnh(struct pim_instance *pim, struct zclient *zclient,
void pim_resolve_upstream_nh(struct pim_instance *pim, struct prefix *nht_p);
int pim_ecmp_fib_lookup_if_vif_index(struct pim_instance *pim,
struct prefix *src, struct prefix *grp);
+void pim_rp_nexthop_del(struct rp_info *rp_info);
#endif
diff --git a/pimd/pim_oil.c b/pimd/pim_oil.c
index 2e12d728cf..55d26113f7 100644
--- a/pimd/pim_oil.c
+++ b/pimd/pim_oil.c
@@ -168,13 +168,15 @@ struct channel_oil *pim_channel_oil_add(struct pim_instance *pim,
return c_oil;
}
- ifp = pim_if_find_by_vif_index(pim, input_vif_index);
- if (!ifp) {
- /* warning only */
- zlog_warn(
- "%s: (S,G)=%s could not find input interface for input_vif_index=%d",
- __PRETTY_FUNCTION__, pim_str_sg_dump(sg),
- input_vif_index);
+ if (input_vif_index != MAXVIFS) {
+ ifp = pim_if_find_by_vif_index(pim, input_vif_index);
+ if (!ifp) {
+ /* warning only */
+ zlog_warn(
+ "%s: (S,G)=%s could not find input interface for input_vif_index=%d",
+ __PRETTY_FUNCTION__, pim_str_sg_dump(sg),
+ input_vif_index);
+ }
}
c_oil = XCALLOC(MTYPE_PIM_CHANNEL_OIL, sizeof(*c_oil));
@@ -447,25 +449,31 @@ int pim_channel_add_oif(struct channel_oil *channel_oil, struct interface *oif,
channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] =
PIM_MROUTE_MIN_TTL;
- if (pim_mroute_add(channel_oil, __PRETTY_FUNCTION__)) {
- if (PIM_DEBUG_MROUTE) {
- char group_str[INET_ADDRSTRLEN];
- char source_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<group?>",
- channel_oil->oil.mfcc_mcastgrp,
- group_str, sizeof(group_str));
- pim_inet4_dump("<source?>",
- channel_oil->oil.mfcc_origin, source_str,
- sizeof(source_str));
- zlog_debug(
- "%s %s: could not add output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)",
- __FILE__, __PRETTY_FUNCTION__, oif->name,
- pim_ifp->mroute_vif_index, source_str,
- group_str);
- }
+ /* channel_oil->oil.mfcc_parent != MAXVIFS indicate this entry is not
+ * valid to get installed in kernel.
+ */
+ if (channel_oil->oil.mfcc_parent != MAXVIFS) {
+ if (pim_mroute_add(channel_oil, __PRETTY_FUNCTION__)) {
+ if (PIM_DEBUG_MROUTE) {
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<group?>",
+ channel_oil->oil.mfcc_mcastgrp,
+ group_str, sizeof(group_str));
+ pim_inet4_dump("<source?>",
+ channel_oil->oil.mfcc_origin, source_str,
+ sizeof(source_str));
+ zlog_debug(
+ "%s %s: could not add output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)",
+ __FILE__, __PRETTY_FUNCTION__, oif->name,
+ pim_ifp->mroute_vif_index, source_str,
+ group_str);
+ }
- channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl;
- return -5;
+ channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index]
+ = old_ttl;
+ return -5;
+ }
}
channel_oil->oif_creation[pim_ifp->mroute_vif_index] =
diff --git a/pimd/pim_oil.h b/pimd/pim_oil.h
index 94d3840e98..5dd4e8b326 100644
--- a/pimd/pim_oil.h
+++ b/pimd/pim_oil.h
@@ -64,6 +64,25 @@ struct channel_counts {
Each channel_oil.oil is used to control an (S,G) entry in the Kernel
Multicast Forwarding Cache.
+
+ There is a case when we create a channel_oil but don't install in the kernel
+
+ Case where (S, G) entry not installed in the kernel:
+ FRR receives IGMP/PIM (*, G) join and RP is not configured or
+ not-reachable, then create a channel_oil for the group G with the incoming
+ interface(channel_oil.oil.mfcc_parent) as invalid i.e "MAXVIF" and populate
+ the outgoing interface where join is received. Keep this entry in the stack,
+ but don't install in the kernel(channel_oil.installed = 0).
+
+ Case where (S, G) entry installed in the kernel:
+ When RP is configured and is reachable for the group G, and receiving a
+ join if channel_oil is already present then populate the incoming interface
+ and install the entry in the kernel, if channel_oil not present, then create
+ a new_channel oil(channel_oil.installed = 1).
+
+ is_valid: indicate if this entry is valid to get installed in kernel.
+ installed: indicate if this entry is installed in the kernel.
+
*/
struct channel_oil {
diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c
index 308d5a5e06..7094b93a45 100644
--- a/pimd/pim_rp.c
+++ b/pimd/pim_rp.c
@@ -45,7 +45,9 @@
#include "pim_iface.h"
#include "pim_msdp.h"
#include "pim_nht.h"
-
+#include "pim_mroute.h"
+#include "pim_oil.h"
+#include "pim_zebra.h"
/* Cleanup pim->rpf_hash each node data */
void pim_rp_list_hash_clean(void *data)
@@ -200,7 +202,7 @@ static struct rp_info *pim_rp_find_exact(struct pim_instance *pim,
/*
* Given a group, return the rp_info for that group
*/
-static struct rp_info *pim_rp_find_match_group(struct pim_instance *pim,
+struct rp_info *pim_rp_find_match_group(struct pim_instance *pim,
const struct prefix *group)
{
struct listnode *node;
@@ -333,6 +335,77 @@ static void pim_rp_check_interfaces(struct pim_instance *pim,
}
}
+void pim_upstream_update(struct pim_instance *pim, struct pim_upstream *up)
+{
+ struct pim_rpf old_rpf;
+ enum pim_rpf_result rpf_result;
+ struct in_addr old_upstream_addr;
+ struct in_addr new_upstream_addr;
+ struct prefix nht_p;
+
+ old_upstream_addr = up->upstream_addr;
+ pim_rp_set_upstream_addr(pim, &new_upstream_addr, up->sg.src,
+ up->sg.grp);
+
+ if (PIM_DEBUG_TRACE)
+ zlog_debug("%s: pim upstream update for old upstream %s",
+ __PRETTY_FUNCTION__,
+ inet_ntoa(old_upstream_addr));
+
+ if (old_upstream_addr.s_addr == new_upstream_addr.s_addr)
+ return;
+
+ /* Lets consider a case, where a PIM upstream has a better RP as a
+ * result of a new RP configuration with more precise group range.
+ * This upstream has to be added to the upstream hash of new RP's
+ * NHT(pnc) and has to be removed from old RP's NHT upstream hash
+ */
+ if (old_upstream_addr.s_addr != INADDR_ANY) {
+ /* Deregister addr with Zebra NHT */
+ nht_p.family = AF_INET;
+ nht_p.prefixlen = IPV4_MAX_BITLEN;
+ nht_p.u.prefix4 = old_upstream_addr;
+ if (PIM_DEBUG_TRACE) {
+ char buf[PREFIX2STR_BUFFER];
+
+ prefix2str(&nht_p, buf, sizeof(buf));
+ zlog_debug("%s: Deregister upstream %s addr %s with Zebra NHT",
+ __PRETTY_FUNCTION__, up->sg_str, buf);
+ }
+ pim_delete_tracked_nexthop(pim, &nht_p, up, NULL);
+ }
+
+ /* Update the upstream address */
+ up->upstream_addr = new_upstream_addr;
+
+ old_rpf.source_nexthop.interface = up->rpf.source_nexthop.interface;
+
+ rpf_result = pim_rpf_update(pim, up, &old_rpf, 1);
+ if (rpf_result == PIM_RPF_FAILURE)
+ pim_mroute_del(up->channel_oil, __PRETTY_FUNCTION__);
+
+ /* update kernel multicast forwarding cache (MFC) */
+ if (up->rpf.source_nexthop.interface && up->channel_oil) {
+ ifindex_t ifindex = up->rpf.source_nexthop.interface->ifindex;
+ int vif_index = pim_if_find_vifindex_by_ifindex(pim, ifindex);
+ /* Pass Current selected NH vif index to mroute download */
+ if (vif_index)
+ pim_scan_individual_oil(up->channel_oil, vif_index);
+ else {
+ if (PIM_DEBUG_PIM_NHT)
+ zlog_debug(
+ "%s: NHT upstream %s channel_oil IIF %s vif_index is not valid",
+ __PRETTY_FUNCTION__, up->sg_str,
+ up->rpf.source_nexthop.interface->name);
+ }
+ }
+
+ if (rpf_result == PIM_RPF_CHANGED)
+ pim_zebra_upstream_rpf_changed(pim, up, &old_rpf);
+
+ pim_zebra_update_all_interfaces(pim);
+}
+
int pim_rp_new(struct pim_instance *pim, const char *rp,
const char *group_range, const char *plist)
{
@@ -347,6 +420,8 @@ int pim_rp_new(struct pim_instance *pim, const char *rp,
struct prefix temp;
struct pim_nexthop_cache pnc;
struct route_node *rn;
+ struct pim_upstream *up;
+ struct listnode *upnode;
rp_info = XCALLOC(MTYPE_PIM_RP, sizeof(*rp_info));
@@ -468,6 +543,27 @@ int pim_rp_new(struct pim_instance *pim, const char *rp,
"%s: NHT Register rp_all addr %s grp %s ",
__PRETTY_FUNCTION__, buf, buf1);
}
+
+ for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode,
+ up)) {
+ /* Find (*, G) upstream whose RP is not
+ * configured yet
+ */
+ if ((up->upstream_addr.s_addr == INADDR_ANY)
+ && (up->sg.src.s_addr == INADDR_ANY)) {
+ struct prefix grp;
+ struct rp_info *trp_info;
+
+ grp.family = AF_INET;
+ grp.prefixlen = IPV4_MAX_BITLEN;
+ grp.u.prefix4 = up->sg.grp;
+ trp_info = pim_rp_find_match_group(pim,
+ &grp);
+ if (trp_info == rp_all)
+ pim_upstream_update(pim, up);
+ }
+ }
+
memset(&pnc, 0, sizeof(struct pim_nexthop_cache));
if (pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_all,
&pnc)) {
@@ -535,6 +631,21 @@ int pim_rp_new(struct pim_instance *pim, const char *rp,
rn->lock);
}
+ for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) {
+ if (up->sg.src.s_addr == INADDR_ANY) {
+ struct prefix grp;
+ struct rp_info *trp_info;
+
+ grp.family = AF_INET;
+ grp.prefixlen = IPV4_MAX_BITLEN;
+ grp.u.prefix4 = up->sg.grp;
+ trp_info = pim_rp_find_match_group(pim, &grp);
+
+ if (trp_info == rp_info)
+ pim_upstream_update(pim, up);
+ }
+ }
+
/* Register addr with Zebra NHT */
nht_p.family = AF_INET;
nht_p.prefixlen = IPV4_MAX_BITLEN;
@@ -577,6 +688,9 @@ int pim_rp_del(struct pim_instance *pim, const char *rp,
struct prefix nht_p;
struct route_node *rn;
bool was_plist = false;
+ struct rp_info *trp_info;
+ struct pim_upstream *up;
+ struct listnode *upnode;
if (group_range == NULL)
result = str2prefix("224.0.0.0/4", &group);
@@ -621,6 +735,23 @@ int pim_rp_del(struct pim_instance *pim, const char *rp,
rp_all = pim_rp_find_match_group(pim, &g_all);
if (rp_all == rp_info) {
+ for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) {
+ /* Find the upstream (*, G) whose upstream address is
+ * same as the deleted RP
+ */
+ if ((up->upstream_addr.s_addr == rp_addr.s_addr) &&
+ (up->sg.src.s_addr == INADDR_ANY)) {
+ struct prefix grp;
+ grp.family = AF_INET;
+ grp.prefixlen = IPV4_MAX_BITLEN;
+ grp.u.prefix4 = up->sg.grp;
+ trp_info = pim_rp_find_match_group(pim, &grp);
+ if (trp_info == rp_all) {
+ pim_upstream_rpf_clear(pim, up);
+ up->upstream_addr.s_addr = INADDR_ANY;
+ }
+ }
+ }
rp_all->rp.rpf_addr.family = AF_INET;
rp_all->rp.rpf_addr.u.prefix4.s_addr = INADDR_NONE;
rp_all->i_am_rp = 0;
@@ -655,6 +786,34 @@ int pim_rp_del(struct pim_instance *pim, const char *rp,
pim_rp_refresh_group_to_rp_mapping(pim);
+ for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) {
+ /* Find the upstream (*, G) whose upstream address is same as
+ * the deleted RP
+ */
+ if ((up->upstream_addr.s_addr == rp_addr.s_addr) &&
+ (up->sg.src.s_addr == INADDR_ANY)) {
+ struct prefix grp;
+
+ grp.family = AF_INET;
+ grp.prefixlen = IPV4_MAX_BITLEN;
+ grp.u.prefix4 = up->sg.grp;
+
+ trp_info = pim_rp_find_match_group(pim, &grp);
+
+ /* RP not found for the group grp */
+ if (pim_rpf_addr_is_inaddr_none(&trp_info->rp)) {
+ pim_upstream_rpf_clear(pim, up);
+ pim_rp_set_upstream_addr(pim,
+ &up->upstream_addr,
+ up->sg.src, up->sg.grp);
+ }
+
+ /* RP found for the group grp */
+ else
+ pim_upstream_update(pim, up);
+ }
+ }
+
XFREE(MTYPE_PIM_RP, rp_info);
return PIM_SUCCESS;
}
@@ -681,6 +840,7 @@ void pim_rp_setup(struct pim_instance *pim)
else {
if (PIM_DEBUG_PIM_NHT_RP) {
char buf[PREFIX2STR_BUFFER];
+
prefix2str(&nht_p, buf, sizeof(buf));
zlog_debug(
"%s: NHT Local Nexthop not found for RP %s ",
@@ -869,7 +1029,7 @@ struct pim_rpf *pim_rp_g(struct pim_instance *pim, struct in_addr group)
* the rp configured and the source address
*
* If we have don't have a RP configured and the source address is *
- * then return failure.
+ * then set the upstream addr as INADDR_ANY and return failure.
*
*/
int pim_rp_set_upstream_addr(struct pim_instance *pim, struct in_addr *up,
@@ -890,6 +1050,7 @@ int pim_rp_set_upstream_addr(struct pim_instance *pim, struct in_addr *up,
if (PIM_DEBUG_PIM_NHT_RP)
zlog_debug("%s: Received a (*,G) with no RP configured",
__PRETTY_FUNCTION__);
+ up->s_addr = INADDR_ANY;
return 0;
}
diff --git a/pimd/pim_rp.h b/pimd/pim_rp.h
index 672a696319..7769864c08 100644
--- a/pimd/pim_rp.h
+++ b/pimd/pim_rp.h
@@ -71,4 +71,7 @@ void pim_rp_show_information(struct pim_instance *pim, struct vty *vty,
bool uj);
void pim_resolve_rp_nh(struct pim_instance *pim);
int pim_rp_list_cmp(void *v1, void *v2);
+struct rp_info *pim_rp_find_match_group(struct pim_instance *pim,
+ const struct prefix *group);
+void pim_upstream_update(struct pim_instance *pim, struct pim_upstream *up);
#endif
diff --git a/pimd/pim_rpf.c b/pimd/pim_rpf.c
index 814d2e076b..ee145a5b51 100644
--- a/pimd/pim_rpf.c
+++ b/pimd/pim_rpf.c
@@ -205,6 +205,12 @@ enum pim_rpf_result pim_rpf_update(struct pim_instance *pim,
struct prefix src, grp;
bool neigh_needed = true;
+ if (up->upstream_addr.s_addr == INADDR_ANY) {
+ zlog_debug("%s: RP is not configured yet for %s",
+ __PRETTY_FUNCTION__, up->sg_str);
+ return PIM_RPF_OK;
+ }
+
saved.source_nexthop = rpf->source_nexthop;
saved.rpf_addr = rpf->rpf_addr;
@@ -308,6 +314,33 @@ enum pim_rpf_result pim_rpf_update(struct pim_instance *pim,
}
/*
+ * In the case of RP deletion and RP unreachablity,
+ * uninstall the mroute in the kernel and clear the
+ * rpf information in the pim upstream and pim channel
+ * oil data structure.
+ */
+void pim_upstream_rpf_clear(struct pim_instance *pim,
+ struct pim_upstream *up)
+{
+ if (up->rpf.source_nexthop.interface) {
+ if (up->channel_oil) {
+ up->channel_oil->oil.mfcc_parent = MAXVIFS;
+ pim_mroute_del(up->channel_oil, __PRETTY_FUNCTION__);
+
+ }
+ pim_upstream_switch(pim, up, PIM_UPSTREAM_NOTJOINED);
+ up->rpf.source_nexthop.interface = NULL;
+ up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4.s_addr =
+ PIM_NET_INADDR_ANY;
+ up->rpf.source_nexthop.mrib_metric_preference =
+ router->infinite_assert_metric.metric_preference;
+ up->rpf.source_nexthop.mrib_route_metric =
+ router->infinite_assert_metric.route_metric;
+ up->rpf.rpf_addr.u.prefix4.s_addr = PIM_NET_INADDR_ANY;
+ }
+}
+
+/*
RFC 4601: 4.1.6. State Summarization Macros
neighbor RPF'(S,G) {
diff --git a/pimd/pim_rpf.h b/pimd/pim_rpf.h
index b9fe162f21..a4793df667 100644
--- a/pimd/pim_rpf.h
+++ b/pimd/pim_rpf.h
@@ -64,7 +64,8 @@ int pim_nexthop_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop,
enum pim_rpf_result pim_rpf_update(struct pim_instance *pim,
struct pim_upstream *up, struct pim_rpf *old,
uint8_t is_new);
-
+void pim_upstream_rpf_clear(struct pim_instance *pim,
+ struct pim_upstream *up);
int pim_rpf_addr_is_inaddr_none(struct pim_rpf *rpf);
int pim_rpf_addr_is_inaddr_any(struct pim_rpf *rpf);
diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c
index c6ab8f5a2a..cb89e30a50 100644
--- a/pimd/pim_upstream.c
+++ b/pimd/pim_upstream.c
@@ -219,17 +219,25 @@ struct pim_upstream *pim_upstream_del(struct pim_instance *pim,
pim_msdp_up_del(pim, &up->sg);
}
- /* Deregister addr with Zebra NHT */
- nht_p.family = AF_INET;
- nht_p.prefixlen = IPV4_MAX_BITLEN;
- nht_p.u.prefix4 = up->upstream_addr;
- if (PIM_DEBUG_TRACE) {
- char buf[PREFIX2STR_BUFFER];
- prefix2str(&nht_p, buf, sizeof(buf));
- zlog_debug("%s: Deregister upstream %s addr %s with Zebra NHT",
- __PRETTY_FUNCTION__, up->sg_str, buf);
+ /* When RP gets deleted, pim_rp_del() deregister addr with Zebra NHT
+ * and assign up->upstream_addr as INADDR_ANY.
+ * So before de-registering the upstream address, check if is not equal
+ * to INADDR_ANY. This is done in order to avoid de-registering for
+ * 255.255.255.255 which is maintained for some reason..
+ */
+ if (up->upstream_addr.s_addr != INADDR_ANY) {
+ /* Deregister addr with Zebra NHT */
+ nht_p.family = AF_INET;
+ nht_p.prefixlen = IPV4_MAX_BITLEN;
+ nht_p.u.prefix4 = up->upstream_addr;
+ if (PIM_DEBUG_TRACE) {
+ char buf[PREFIX2STR_BUFFER];
+ prefix2str(&nht_p, buf, sizeof(buf));
+ zlog_debug("%s: Deregister upstream %s addr %s with Zebra NHT",
+ __PRETTY_FUNCTION__, up->sg_str, buf);
+ }
+ pim_delete_tracked_nexthop(pim, &nht_p, up, NULL);
}
- pim_delete_tracked_nexthop(pim, &nht_p, up, NULL);
XFREE(MTYPE_PIM_UPSTREAM, up);
@@ -238,6 +246,13 @@ struct pim_upstream *pim_upstream_del(struct pim_instance *pim,
void pim_upstream_send_join(struct pim_upstream *up)
{
+ if (!up->rpf.source_nexthop.interface) {
+ if (PIM_DEBUG_TRACE)
+ zlog_debug("%s: up %s RPF is not present",
+ __PRETTY_FUNCTION__, up->sg_str);
+ return;
+ }
+
if (PIM_DEBUG_TRACE) {
char rpf_str[PREFIX_STRLEN];
pim_addr_dump("<rpf?>", &up->rpf.rpf_addr, rpf_str,
@@ -263,6 +278,13 @@ static int on_join_timer(struct thread *t)
up = THREAD_ARG(t);
+ if (!up->rpf.source_nexthop.interface) {
+ if (PIM_DEBUG_TRACE)
+ zlog_debug("%s: up %s RPF is not present",
+ __PRETTY_FUNCTION__, up->sg_str);
+ return 0;
+ }
+
/*
* In the case of a HFR we will not ahve anyone to send this to.
*/
@@ -284,12 +306,13 @@ static int on_join_timer(struct thread *t)
static void join_timer_stop(struct pim_upstream *up)
{
- struct pim_neighbor *nbr;
+ struct pim_neighbor *nbr = NULL;
THREAD_OFF(up->t_join_timer);
- nbr = pim_neighbor_find(up->rpf.source_nexthop.interface,
- up->rpf.rpf_addr.u.prefix4);
+ if (up->rpf.source_nexthop.interface)
+ nbr = pim_neighbor_find(up->rpf.source_nexthop.interface,
+ up->rpf.rpf_addr.u.prefix4);
if (nbr)
pim_jp_agg_remove_group(nbr->upstream_jp_agg, up);
@@ -356,6 +379,13 @@ void pim_upstream_join_suppress(struct pim_upstream *up,
long t_joinsuppress_msec;
long join_timer_remain_msec;
+ if (!up->rpf.source_nexthop.interface) {
+ if (PIM_DEBUG_TRACE)
+ zlog_debug("%s: up %s RPF is not present",
+ __PRETTY_FUNCTION__, up->sg_str);
+ return;
+ }
+
t_joinsuppress_msec =
MIN(pim_if_t_suppressed_msec(up->rpf.source_nexthop.interface),
1000 * holdtime);
@@ -389,6 +419,13 @@ void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label,
long join_timer_remain_msec;
int t_override_msec;
+ if (!up->rpf.source_nexthop.interface) {
+ if (PIM_DEBUG_TRACE)
+ zlog_debug("%s: up %s RPF is not present",
+ __PRETTY_FUNCTION__, up->sg_str);
+ return;
+ }
+
join_timer_remain_msec = pim_time_timer_remain_msec(up->t_join_timer);
t_override_msec =
pim_if_t_override_msec(up->rpf.source_nexthop.interface);
@@ -511,6 +548,20 @@ void pim_upstream_switch(struct pim_instance *pim, struct pim_upstream *up,
{
enum pim_upstream_state old_state = up->join_state;
+ if (up->upstream_addr.s_addr == INADDR_ANY) {
+ if (PIM_DEBUG_PIM_EVENTS)
+ zlog_debug("%s: RPF not configured for %s",
+ __PRETTY_FUNCTION__, up->sg_str);
+ return;
+ }
+
+ if (!up->rpf.source_nexthop.interface) {
+ if (PIM_DEBUG_PIM_EVENTS)
+ zlog_debug("%s: RP not reachable for %s",
+ __PRETTY_FUNCTION__, up->sg_str);
+ return;
+ }
+
if (PIM_DEBUG_PIM_EVENTS) {
zlog_debug("%s: PIM_UPSTREAM_%s: (S,G) old: %s new: %s",
__PRETTY_FUNCTION__, up->sg_str,
@@ -558,11 +609,14 @@ void pim_upstream_switch(struct pim_instance *pim, struct pim_upstream *up,
&& !I_am_RP(pim, up->sg.grp)) {
if (PIM_DEBUG_PIM_TRACE_DETAIL)
zlog_debug(
- "%s: *,G IIF %s S,G IIF %s ",
- __PRETTY_FUNCTION__,
- up->parent->rpf.source_nexthop
- .interface->name,
- up->rpf.source_nexthop.interface->name);
+ "%s: *,G IIF %s S,G IIF %s ",
+ __PRETTY_FUNCTION__,
+ up->parent->rpf.source_nexthop.interface ?
+ up->parent->rpf.source_nexthop.interface->name
+ : "Unknown",
+ up->rpf.source_nexthop.interface ?
+ up->rpf.source_nexthop.interface->name :
+ "Unknown");
pim_jp_agg_single_upstream_send(&up->parent->rpf,
up->parent,
1 /* (W,G) Join */);
@@ -611,15 +665,14 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim,
ch->upstream = up;
up = hash_get(pim->upstream_hash, up, hash_alloc_intern);
+ /* Set up->upstream_addr as INADDR_ANY, if RP is not
+ * configured and retain the upstream data structure
+ */
if (!pim_rp_set_upstream_addr(pim, &up->upstream_addr, sg->src,
sg->grp)) {
if (PIM_DEBUG_TRACE)
zlog_debug("%s: Received a (*,G) with no RP configured",
__PRETTY_FUNCTION__);
-
- hash_release(pim->upstream_hash, up);
- XFREE(MTYPE_PIM_UPSTREAM, up);
- return NULL;
}
up->parent = pim_upstream_find_parent(pim, up);
@@ -659,45 +712,34 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim,
if (up->sg.src.s_addr != INADDR_ANY)
wheel_add_item(pim->upstream_sg_wheel, up);
- rpf_result = pim_rpf_update(pim, up, NULL, 1);
- if (rpf_result == PIM_RPF_FAILURE) {
- struct prefix nht_p;
-
- if (PIM_DEBUG_TRACE)
- zlog_debug(
- "%s: Attempting to create upstream(%s), Unable to RPF for source",
- __PRETTY_FUNCTION__, up->sg_str);
-
- nht_p.family = AF_INET;
- nht_p.prefixlen = IPV4_MAX_BITLEN;
- nht_p.u.prefix4 = up->upstream_addr;
- pim_delete_tracked_nexthop(pim, &nht_p, up, NULL);
+ if (up->upstream_addr.s_addr == INADDR_ANY)
+ /* Create a dummmy channel oil with incoming ineterface MAXVIFS,
+ * since RP is not configured
+ */
+ up->channel_oil = pim_channel_oil_add(pim, &up->sg, MAXVIFS);
- if (up->parent) {
- listnode_delete(up->parent->sources, up);
- up->parent = NULL;
+ else {
+ rpf_result = pim_rpf_update(pim, up, NULL, 1);
+ if (rpf_result == PIM_RPF_FAILURE) {
+ if (PIM_DEBUG_TRACE)
+ zlog_debug(
+ "%s: Attempting to create upstream(%s), Unable to RPF for source",
+ __PRETTY_FUNCTION__, up->sg_str);
+ /* Create a dummmy channel oil with incoming ineterface
+ * MAXVIFS, since RP is not reachable
+ */
+ up->channel_oil = pim_channel_oil_add(
+ pim, &up->sg, MAXVIFS);
}
- if (up->sg.src.s_addr != INADDR_ANY)
- wheel_remove_item(pim->upstream_sg_wheel, up);
-
- pim_upstream_remove_children(pim, up);
- if (up->sources)
- list_delete(&up->sources);
-
- list_delete(&up->ifchannels);
-
- hash_release(pim->upstream_hash, up);
- XFREE(MTYPE_PIM_UPSTREAM, up);
- return NULL;
+ if (up->rpf.source_nexthop.interface) {
+ pim_ifp = up->rpf.source_nexthop.interface->info;
+ if (pim_ifp)
+ up->channel_oil = pim_channel_oil_add(pim,
+ &up->sg, pim_ifp->mroute_vif_index);
+ }
}
- if (up->rpf.source_nexthop.interface) {
- pim_ifp = up->rpf.source_nexthop.interface->info;
- if (pim_ifp)
- up->channel_oil = pim_channel_oil_add(
- pim, &up->sg, pim_ifp->mroute_vif_index);
- }
listnode_add_sort(pim->upstream_list, up);
if (PIM_DEBUG_TRACE) {
@@ -783,7 +825,7 @@ struct pim_upstream *pim_upstream_add(struct pim_instance *pim,
zlog_debug("%s(%s): %s, iif %s (%s) found: %d: ref_count: %d",
__PRETTY_FUNCTION__, name,
up->sg_str, buf, up->rpf.source_nexthop.interface ?
- up->rpf.source_nexthop.interface->name : "NIL" ,
+ up->rpf.source_nexthop.interface->name : "Unknown" ,
found, up->ref_count);
} else
zlog_debug("%s(%s): (%s) failure to create",
@@ -896,7 +938,7 @@ void pim_upstream_update_join_desired(struct pim_instance *pim,
PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(up->flags);
/* switched from false to true */
- if (is_join_desired && !was_join_desired) {
+ if (is_join_desired && (up->join_state == PIM_UPSTREAM_NOTJOINED)) {
pim_upstream_switch(pim, up, PIM_UPSTREAM_JOINED);
return;
}
@@ -973,7 +1015,9 @@ void pim_upstream_rpf_interface_changed(struct pim_upstream *up,
(old_rpf_ifp == ch->interface) &&
/* RPF_interface(S) stopped being I */
(ch->upstream->rpf.source_nexthop
- .interface != ch->interface)) {
+ .interface) &&
+ (ch->upstream->rpf.source_nexthop
+ .interface != ch->interface)) {
assert_action_a5(ch);
}
} /* PIM_IFASSERT_I_AM_LOSER */
@@ -1339,6 +1383,13 @@ static int pim_upstream_register_stop_timer(struct thread *t)
case PIM_REG_JOIN:
break;
case PIM_REG_PRUNE:
+ if (!up->rpf.source_nexthop.interface) {
+ if (PIM_DEBUG_TRACE)
+ zlog_debug("%s: up %s RPF is not present",
+ __PRETTY_FUNCTION__, up->sg_str);
+ return 0;
+ }
+
pim_ifp = up->rpf.source_nexthop.interface->info;
if (!pim_ifp) {
if (PIM_DEBUG_TRACE)
@@ -1515,11 +1566,19 @@ void pim_upstream_find_new_rpf(struct pim_instance *pim)
* Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
*/
for (ALL_LIST_ELEMENTS(pim->upstream_list, up_node, up_nextnode, up)) {
+ if (up->upstream_addr.s_addr == INADDR_ANY) {
+ if (PIM_DEBUG_TRACE)
+ zlog_debug(
+ "%s: RP not configured for Upstream %s",
+ __PRETTY_FUNCTION__, up->sg_str);
+ continue;
+ }
+
if (pim_rpf_addr_is_inaddr_any(&up->rpf)) {
if (PIM_DEBUG_TRACE)
zlog_debug(
- "Upstream %s without a path to send join, checking",
- up->sg_str);
+ "%s: Upstream %s without a path to send join, checking",
+ __PRETTY_FUNCTION__, up->sg_str);
pim_rpf_update(pim, up, NULL, 1);
}
}
@@ -1586,7 +1645,8 @@ static bool pim_upstream_kat_start_ok(struct pim_upstream *up)
/* "iif == RPF_interface(S)" check has to be done by the kernel or hw
* so we will skip that here */
- if (pim_if_connected_to_source(up->rpf.source_nexthop.interface,
+ if (up->rpf.source_nexthop.interface &&
+ pim_if_connected_to_source(up->rpf.source_nexthop.interface,
up->sg.src)) {
return true;
}
@@ -1679,7 +1739,8 @@ static void pim_upstream_sg_running(void *arg)
} else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up->flags))
pim_upstream_keep_alive_timer_start(up, pim->keep_alive_time);
- if (up->sptbit != PIM_UPSTREAM_SPTBIT_TRUE) {
+ if ((up->sptbit != PIM_UPSTREAM_SPTBIT_TRUE) &&
+ (up->rpf.source_nexthop.interface)) {
pim_upstream_set_sptbit(up, up->rpf.source_nexthop.interface);
}
return;
diff --git a/pimd/pim_upstream.h b/pimd/pim_upstream.h
index f44b95c811..70e70140d1 100644
--- a/pimd/pim_upstream.h
+++ b/pimd/pim_upstream.h
@@ -88,10 +88,30 @@ enum pim_upstream_sptbit {
/*
Upstream (S,G) channel in Joined state
-
(S,G) in the "Not Joined" state is not represented
-
See RFC 4601: 4.5.7. Sending (S,G) Join/Prune Message
+
+ upstream_addr : Who we are talking to.
+ For (*, G), upstream_addr is RP address or INADDR_ANY(if RP not configured)
+ For (S, G), upstream_addr is source address
+
+ rpf: contains the nexthop information to whom we are talking to.
+
+ join_state: JOINED/NOTJOINED
+
+ In the case when FRR receives IGMP/PIM (*, G) join for group G and RP is not
+ configured, then create a pim_upstream with the below information.
+ pim_upstream->upstream address: INADDR_ANY
+ pim_upstream->rpf: Unknown
+ pim_upstream->state: NOTJOINED
+
+ When a new RP gets configured for G, find the corresponding pim upstream (*,G)
+ entries and update the upstream address as new RP address if it the better one
+ for the group G.
+
+ When RP becomes reachable, populate the nexthop information in
+ pim_upstream->rpf and update the state to JOINED.
+
*/
struct pim_upstream {
struct pim_upstream *parent;
diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c
index 11ca6e8a10..78cccd5877 100644
--- a/pimd/pim_zebra.c
+++ b/pimd/pim_zebra.c
@@ -472,55 +472,72 @@ void pim_zebra_upstream_rpf_changed(struct pim_instance *pim,
struct pim_upstream *up,
struct pim_rpf *old)
{
- struct pim_neighbor *nbr;
+ if (old->source_nexthop.interface) {
+ struct pim_neighbor *nbr;
- nbr = pim_neighbor_find(old->source_nexthop.interface,
- old->rpf_addr.u.prefix4);
- if (nbr)
- pim_jp_agg_remove_group(nbr->upstream_jp_agg, up);
+ nbr = pim_neighbor_find(old->source_nexthop.interface,
+ old->rpf_addr.u.prefix4);
+ if (nbr)
+ pim_jp_agg_remove_group(nbr->upstream_jp_agg, up);
- /*
- * We have detected a case where we might need
- * to rescan the inherited o_list so do it.
- */
- if (up->channel_oil->oil_inherited_rescan) {
- pim_upstream_inherited_olist_decide(pim, up);
- up->channel_oil->oil_inherited_rescan = 0;
- }
-
- if (up->join_state == PIM_UPSTREAM_JOINED) {
/*
- * If we come up real fast we can be here
- * where the mroute has not been installed
- * so install it.
+ * We have detected a case where we might need
+ * to rescan the inherited o_list so do it.
*/
- if (!up->channel_oil->installed)
- pim_mroute_add(up->channel_oil, __PRETTY_FUNCTION__);
+ if (up->channel_oil->oil_inherited_rescan) {
+ pim_upstream_inherited_olist_decide(pim, up);
+ up->channel_oil->oil_inherited_rescan = 0;
+ }
+
+ if (up->join_state == PIM_UPSTREAM_JOINED) {
+ /*
+ * If we come up real fast we can be here
+ * where the mroute has not been installed
+ * so install it.
+ */
+ if (!up->channel_oil->installed)
+ pim_mroute_add(up->channel_oil,
+ __PRETTY_FUNCTION__);
+
+ /*
+ * RFC 4601: 4.5.7. Sending (S,G)
+ * Join/Prune Messages
+ *
+ * Transitions from Joined State
+ *
+ * RPF'(S,G) changes not due to an Assert
+ *
+ * The upstream (S,G) state machine remains
+ * in Joined state. Send Join(S,G) to the new
+ * upstream neighbor, which is the new value
+ * of RPF'(S,G). Send Prune(S,G) to the old
+ * upstream neighbor, which is the old value
+ * of RPF'(S,G). Set the Join Timer (JT) to
+ * expire after t_periodic seconds.
+ */
+ pim_jp_agg_switch_interface(old, &up->rpf, up);
+
+ pim_upstream_join_timer_restart(up, old);
+ } /* up->join_state == PIM_UPSTREAM_JOINED */
+ }
+ else {
/*
- * RFC 4601: 4.5.7. Sending (S,G)
- * Join/Prune Messages
- *
- * Transitions from Joined State
- *
- * RPF'(S,G) changes not due to an Assert
- *
- * The upstream (S,G) state machine remains
- * in Joined state. Send Join(S,G) to the new
- * upstream neighbor, which is the new value
- * of RPF'(S,G). Send Prune(S,G) to the old
- * upstream neighbor, which is the old value
- * of RPF'(S,G). Set the Join Timer (JT) to
- * expire after t_periodic seconds.
+ * We have detected a case where we might need
+ * to rescan the inherited o_list so do it.
*/
- pim_jp_agg_switch_interface(old, &up->rpf, up);
+ if (up->channel_oil->oil_inherited_rescan) {
+ pim_upstream_inherited_olist_decide(pim, up);
+ up->channel_oil->oil_inherited_rescan = 0;
+ }
- pim_upstream_join_timer_restart(up, old);
- } /* up->join_state == PIM_UPSTREAM_JOINED */
+ if (!up->channel_oil->installed)
+ pim_mroute_add(up->channel_oil, __PRETTY_FUNCTION__);
+ }
- /* FIXME can join_desired actually be changed by
- pim_rpf_update()
- returning PIM_RPF_CHANGED ? */
+ /* FIXME can join_desired actually be changed by pim_rpf_update()
+ * returning PIM_RPF_CHANGED ?
+ */
pim_upstream_update_join_desired(pim, up);
}
@@ -535,6 +552,14 @@ static void scan_upstream_rpf_cache(struct pim_instance *pim)
struct pim_rpf old;
struct prefix nht_p;
+ if (up->upstream_addr.s_addr == INADDR_ANY) {
+ if (PIM_DEBUG_TRACE)
+ zlog_debug(
+ "%s: RP not configured for Upstream %s",
+ __PRETTY_FUNCTION__, up->sg_str);
+ continue;
+ }
+
nht_p.family = AF_INET;
nht_p.prefixlen = IPV4_MAX_BITLEN;
nht_p.u.prefix4.s_addr = up->upstream_addr.s_addr;
@@ -561,10 +586,9 @@ void pim_scan_individual_oil(struct channel_oil *c_oil, int in_vif_index)
int input_iface_vif_index;
int old_vif_index;
- if (!pim_rp_set_upstream_addr(c_oil->pim, &vif_source,
+ pim_rp_set_upstream_addr(c_oil->pim, &vif_source,
c_oil->oil.mfcc_origin,
- c_oil->oil.mfcc_mcastgrp))
- return;
+ c_oil->oil.mfcc_mcastgrp);
if (in_vif_index)
input_iface_vif_index = in_vif_index;
@@ -950,112 +974,141 @@ void igmp_source_forward_start(struct pim_instance *pim,
struct pim_upstream *up = NULL;
if (!pim_rp_set_upstream_addr(pim, &vif_source,
- source->source_addr, sg.grp))
- return;
-
- /* Register addr with Zebra NHT */
- nht_p.family = AF_INET;
- nht_p.prefixlen = IPV4_MAX_BITLEN;
- nht_p.u.prefix4 = vif_source;
- memset(&out_pnc, 0, sizeof(struct pim_nexthop_cache));
+ source->source_addr, sg.grp)) {
+ /*Create a dummy channel oil */
+ source->source_channel_oil =
+ pim_channel_oil_add(pim, &sg, MAXVIFS);
- src.family = AF_INET;
- src.prefixlen = IPV4_MAX_BITLEN;
- src.u.prefix4 = vif_source; // RP or Src address
- grp.family = AF_INET;
- grp.prefixlen = IPV4_MAX_BITLEN;
- grp.u.prefix4 = sg.grp;
+ if (!source->source_channel_oil) {
+ if (PIM_DEBUG_IGMP_TRACE) {
+ zlog_debug(
+ "%s %s: could not create OIL for channel (S,G)=%s",
+ __FILE__, __PRETTY_FUNCTION__,
+ pim_str_sg_dump(&sg));
+ }
+ return;
+ }
+ }
- if (pim_find_or_track_nexthop(pim, &nht_p, NULL, NULL,
+ else {
+ /* Register addr with Zebra NHT */
+ nht_p.family = AF_INET;
+ nht_p.prefixlen = IPV4_MAX_BITLEN;
+ nht_p.u.prefix4 = vif_source;
+ memset(&out_pnc, 0, sizeof(struct pim_nexthop_cache));
+
+ src.family = AF_INET;
+ src.prefixlen = IPV4_MAX_BITLEN;
+ src.u.prefix4 = vif_source; // RP or Src address
+ grp.family = AF_INET;
+ grp.prefixlen = IPV4_MAX_BITLEN;
+ grp.u.prefix4 = sg.grp;
+
+ if (pim_find_or_track_nexthop(pim, &nht_p, NULL, NULL,
&out_pnc)) {
- if (out_pnc.nexthop_num) {
- up = pim_upstream_find(pim, &sg);
- memset(&nexthop, 0, sizeof(nexthop));
- if (up)
- memcpy(&nexthop,
- &up->rpf.source_nexthop,
- sizeof(struct pim_nexthop));
- pim_ecmp_nexthop_search(pim, &out_pnc, &nexthop,
- &src, &grp, 0);
- if (nexthop.interface)
- input_iface_vif_index =
+ if (out_pnc.nexthop_num) {
+ up = pim_upstream_find(pim, &sg);
+ memset(&nexthop, 0, sizeof(nexthop));
+ if (up)
+ memcpy(&nexthop,
+ &up->rpf.source_nexthop,
+ sizeof(struct pim_nexthop));
+ pim_ecmp_nexthop_search(pim, &out_pnc,
+ &nexthop,
+ &src, &grp, 0);
+ if (nexthop.interface)
+ input_iface_vif_index =
pim_if_find_vifindex_by_ifindex(
- pim,
- nexthop.interface->ifindex);
- } else {
- if (PIM_DEBUG_ZEBRA) {
- char buf1[INET_ADDRSTRLEN];
- char buf2[INET_ADDRSTRLEN];
- pim_inet4_dump("<source?>",
+ pim,
+ nexthop.interface->ifindex);
+ } else {
+ if (PIM_DEBUG_ZEBRA) {
+ char buf1[INET_ADDRSTRLEN];
+ char buf2[INET_ADDRSTRLEN];
+
+ pim_inet4_dump("<source?>",
nht_p.u.prefix4, buf1,
sizeof(buf1));
- pim_inet4_dump("<source?>",
+ pim_inet4_dump("<source?>",
grp.u.prefix4, buf2,
sizeof(buf2));
- zlog_debug(
+ zlog_debug(
"%s: NHT Nexthop not found for addr %s grp %s",
__PRETTY_FUNCTION__, buf1,
buf2);
+ }
}
- }
- } else
- input_iface_vif_index =
- pim_ecmp_fib_lookup_if_vif_index(pim, &src,
+ } else
+ input_iface_vif_index =
+ pim_ecmp_fib_lookup_if_vif_index(pim, &src,
&grp);
- if (PIM_DEBUG_ZEBRA) {
- char buf2[INET_ADDRSTRLEN];
- pim_inet4_dump("<source?>", vif_source, buf2,
- sizeof(buf2));
- zlog_debug("%s: NHT %s vif_source %s vif_index:%d ",
- __PRETTY_FUNCTION__, pim_str_sg_dump(&sg),
- buf2, input_iface_vif_index);
- }
-
- if (input_iface_vif_index < 1) {
- if (PIM_DEBUG_IGMP_TRACE) {
- char source_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<source?>", source->source_addr,
- source_str, sizeof(source_str));
- zlog_debug(
- "%s %s: could not find input interface for source %s",
- __FILE__, __PRETTY_FUNCTION__,
- source_str);
- }
- return;
- }
+ if (PIM_DEBUG_ZEBRA) {
+ char buf2[INET_ADDRSTRLEN];
- /*
- Protect IGMP against adding looped MFC entries created by both
- source and receiver attached to the same interface. See TODO
- T22.
- */
- if (input_iface_vif_index == pim_oif->mroute_vif_index) {
- /* ignore request for looped MFC entry */
- if (PIM_DEBUG_IGMP_TRACE) {
- zlog_debug(
- "%s: ignoring request for looped MFC entry (S,G)=%s: igmp_sock=%d oif=%s vif_index=%d",
+ pim_inet4_dump("<source?>", vif_source, buf2,
+ sizeof(buf2));
+ zlog_debug("%s: NHT %s vif_source %s vif_index:%d ",
__PRETTY_FUNCTION__,
pim_str_sg_dump(&sg),
- source->source_group->group_igmp_sock
- ->fd,
- source->source_group->group_igmp_sock
- ->interface->name,
- input_iface_vif_index);
+ buf2, input_iface_vif_index);
}
- return;
- }
- source->source_channel_oil =
- pim_channel_oil_add(pim, &sg, input_iface_vif_index);
- if (!source->source_channel_oil) {
- if (PIM_DEBUG_IGMP_TRACE) {
- zlog_debug(
- "%s %s: could not create OIL for channel (S,G)=%s",
- __FILE__, __PRETTY_FUNCTION__,
- pim_str_sg_dump(&sg));
+ if (input_iface_vif_index < 1) {
+ if (PIM_DEBUG_IGMP_TRACE) {
+ char source_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<source?>",
+ source->source_addr,
+ source_str, sizeof(source_str));
+ zlog_debug(
+ "%s %s: could not find input interface for source %s",
+ __FILE__, __PRETTY_FUNCTION__,
+ source_str);
+ }
+ source->source_channel_oil =
+ pim_channel_oil_add(pim, &sg, MAXVIFS);
+ }
+
+ else {
+ /*
+ * Protect IGMP against adding looped MFC
+ * entries created by both source and receiver
+ * attached to the same interface. See TODO
+ * T22.
+ */
+ if (input_iface_vif_index ==
+ pim_oif->mroute_vif_index) {
+ /* ignore request for looped MFC entry
+ */
+ if (PIM_DEBUG_IGMP_TRACE) {
+ zlog_debug(
+ "%s: ignoring request for looped MFC entry (S,G)=%s: igmp_sock=%d oif=%s vif_index=%d",
+ __PRETTY_FUNCTION__,
+ pim_str_sg_dump(&sg),
+ source->source_group
+ ->group_igmp_sock->fd,
+ source->source_group
+ ->group_igmp_sock
+ ->interface->name,
+ input_iface_vif_index);
+ }
+ return;
+ }
+
+ source->source_channel_oil =
+ pim_channel_oil_add(pim, &sg,
+ input_iface_vif_index);
+ if (!source->source_channel_oil) {
+ if (PIM_DEBUG_IGMP_TRACE) {
+ zlog_debug(
+ "%s %s: could not create OIL for channel (S,G)=%s",
+ __FILE__,
+ __PRETTY_FUNCTION__,
+ pim_str_sg_dump(&sg));
+ }
+ return;
+ }
}
- return;
}
}
@@ -1188,15 +1241,13 @@ void pim_forward_start(struct pim_ifchannel *ch)
sizeof(upstream_str));
zlog_debug("%s: (S,G)=(%s,%s) oif=%s (%s)", __PRETTY_FUNCTION__,
source_str, group_str, ch->interface->name,
- upstream_str);
+ inet_ntoa(up->upstream_addr));
}
/* Resolve IIF for upstream as mroute_del sets mfcc_parent to MAXVIFS,
as part of mroute_del called by pim_forward_stop.
*/
- if (!up->channel_oil
- || (up->channel_oil
- && up->channel_oil->oil.mfcc_parent >= MAXVIFS)) {
+ if ((up->upstream_addr.s_addr != INADDR_ANY) && (!up->channel_oil)) {
struct prefix nht_p, src, grp;
struct pim_nexthop_cache out_pnc;
@@ -1267,17 +1318,33 @@ void pim_forward_start(struct pim_ifchannel *ch)
__FILE__, __PRETTY_FUNCTION__,
source_str);
}
- return;
+ up->channel_oil = pim_channel_oil_add(pim, &up->sg,
+ MAXVIFS);
}
+
+ else {
+ up->channel_oil = pim_channel_oil_add(pim, &up->sg,
+ input_iface_vif_index);
+ if (!up->channel_oil) {
+ if (PIM_DEBUG_PIM_TRACE)
+ zlog_debug(
+ "%s %s: could not create OIL for channel (S,G)=%s",
+ __FILE__, __PRETTY_FUNCTION__,
+ up->sg_str);
+ return;
+ }
+ }
+
if (PIM_DEBUG_TRACE) {
struct interface *in_intf = pim_if_find_by_vif_index(
pim, input_iface_vif_index);
zlog_debug(
"%s: Update channel_oil IIF %s VIFI %d entry %s ",
__PRETTY_FUNCTION__,
- in_intf ? in_intf->name : "NIL",
+ in_intf ? in_intf->name : "Unknown",
input_iface_vif_index, up->sg_str);
}
+
up->channel_oil = pim_channel_oil_add(pim, &up->sg,
input_iface_vif_index);
if (!up->channel_oil) {