summaryrefslogtreecommitdiff
path: root/pimd/pim_zebra.c
diff options
context:
space:
mode:
authorChirag Shah <chirag@cumulusnetworks.com>2017-04-05 13:14:12 -0700
committerChirag Shah <chirag@cumulusnetworks.com>2017-04-06 11:18:07 -0700
commitcba444817883b8b3b22a7ed9958dc9ed77f76230 (patch)
tree9167aeb0623fe581a831324b8ba90de14432397d /pimd/pim_zebra.c
parentbc7268d524eaac8d4a29ed843f01ac1bc5e8d4f2 (diff)
pimd: Pim Nexthop Tracking support with ECMP
In this patch, PIM nexthop tracking uses locally populated nexthop cached list to determine ECMP based nexthop (w/ ECMP knob enabled), otherwise picks the first nexthop as RPF. Introduced '[no] ip pim ecmp' command to enable/disable PIM ECMP knob. By default, PIM ECMP is disabled. Intorudced '[no] ip pim ecmp rebalance' command to provide existing mcache entry to switch new path based on hash chosen path. Introduced, show command to display pim registered addresses and respective nexthops. Introuduce, show command to find nexthop and out interface for (S,G) or (RP,G). Re-Register an address with nexthop when Interface UP event received, to ensure the PIM nexthop cache is updated (being PIM enabled). During PIM neighbor UP, traverse all RPs and Upstreams nexthop and determine, if any of nexthop's IPv4 address changes/resolves due to neigbor UP event. Testing Done: Run various LHR, RP and FHR related cases to resolve RPF using nexthop cache with ECMP knob disabled, performed interface/PIM neighbor flap events. Executed pim-smoke with knob disabled. Signed-off-by: Chirag Shah <chirag@cumulusnetworks.com>
Diffstat (limited to 'pimd/pim_zebra.c')
-rw-r--r--pimd/pim_zebra.c168
1 files changed, 141 insertions, 27 deletions
diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c
index 4e18c478d6..80e7d77642 100644
--- a/pimd/pim_zebra.c
+++ b/pimd/pim_zebra.c
@@ -372,6 +372,12 @@ static void scan_upstream_rpf_cache()
for (ALL_LIST_ELEMENTS(pim_upstream_list, up_node, up_nextnode, up)) {
enum pim_rpf_result rpf_result;
struct pim_rpf old;
+ struct prefix nht_p;
+
+ nht_p.family = AF_INET;
+ nht_p.prefixlen = IPV4_MAX_BITLEN;
+ nht_p.u.prefix4.s_addr = up->upstream_addr.s_addr;
+ pim_resolve_upstream_nh (&nht_p);
old.source_nexthop.interface = up->rpf.source_nexthop.interface;
old.source_nexthop.nbr = up->rpf.source_nexthop.nbr;
@@ -574,7 +580,8 @@ static int on_rpf_cache_refresh(struct thread *t)
qpim_rpf_cache_refresh_last = pim_time_monotonic_sec();
++qpim_rpf_cache_refresh_events;
- pim_rp_setup ();
+ //It is called as part of pim_neighbor_add
+ //pim_rp_setup ();
return 0;
}
@@ -836,6 +843,7 @@ void igmp_source_forward_start(struct igmp_source *source)
struct igmp_group *group;
struct prefix_sg sg;
int result;
+ int input_iface_vif_index = 0;
memset (&sg, 0, sizeof (struct prefix_sg));
sg.src = source->source_addr;
@@ -861,11 +869,61 @@ void igmp_source_forward_start(struct igmp_source *source)
if (!source->source_channel_oil) {
struct in_addr vif_source;
struct pim_interface *pim_oif;
+ struct prefix nht_p, src, grp;
+ int ret = 0;
+ struct pim_nexthop_cache out_pnc;
+ struct pim_nexthop nexthop;
if (!pim_rp_set_upstream_addr (&vif_source, source->source_addr, sg.grp))
return;
- int input_iface_vif_index = fib_lookup_if_vif_index(vif_source);
+ /* 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));
+
+ if ((ret = pim_find_or_track_nexthop (&nht_p, NULL, NULL, &out_pnc)) == 1)
+ {
+ if (out_pnc.nexthop_num)
+ {
+ 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;
+ memset (&nexthop, 0, sizeof (nexthop));
+ //Compute PIM RPF using Cached nexthop
+ pim_ecmp_nexthop_search (&out_pnc, &nexthop,
+ &src, &grp, 0);
+ if (nexthop.interface)
+ input_iface_vif_index = pim_if_find_vifindex_by_ifindex (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?>", grp.u.prefix4, buf2, sizeof(buf2));
+ zlog_debug ("%s: NHT Nexthop not found for addr %s grp %s" ,
+ __PRETTY_FUNCTION__, buf1, buf2);
+ }
+ }
+ }
+ else
+ input_iface_vif_index = fib_lookup_if_vif_index(vif_source);
+
+ 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)
{
@@ -1013,49 +1071,105 @@ void pim_forward_start(struct pim_ifchannel *ch)
{
struct pim_upstream *up = ch->upstream;
uint32_t mask = PIM_OIF_FLAG_PROTO_PIM;
+ int input_iface_vif_index = 0;
if (PIM_DEBUG_PIM_TRACE) {
char source_str[INET_ADDRSTRLEN];
- char group_str[INET_ADDRSTRLEN];
+ char group_str[INET_ADDRSTRLEN];
char upstream_str[INET_ADDRSTRLEN];
pim_inet4_dump("<source?>", ch->sg.src, source_str, sizeof(source_str));
pim_inet4_dump("<group?>", ch->sg.grp, group_str, sizeof(group_str));
pim_inet4_dump("<upstream?>", up->upstream_addr, upstream_str, sizeof(upstream_str));
- zlog_debug("%s: (S,G)=(%s,%s) oif=%s(%s)",
+ zlog_debug("%s: (S,G)=(%s,%s) oif=%s (%s)",
__PRETTY_FUNCTION__,
source_str, group_str, ch->interface->name, upstream_str);
}
- if (!up->channel_oil) {
- int input_iface_vif_index = fib_lookup_if_vif_index(up->upstream_addr);
- if (input_iface_vif_index < 1) {
- if (PIM_DEBUG_PIM_TRACE)
- {
- char source_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<source?>", up->sg.src, source_str, sizeof(source_str));
- zlog_debug("%s %s: could not find input interface for source %s",
- __FILE__, __PRETTY_FUNCTION__,
- source_str);
- }
- return;
- }
+ /* 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))
+ {
+ struct prefix nht_p, src, grp;
+ int ret = 0;
+ struct pim_nexthop_cache out_pnc;
+ struct pim_nexthop nexthop;
+
+ /* Register addr with Zebra NHT */
+ nht_p.family = AF_INET;
+ nht_p.prefixlen = IPV4_MAX_BITLEN;
+ nht_p.u.prefix4.s_addr = up->upstream_addr.s_addr;
+ grp.family = AF_INET;
+ grp.prefixlen = IPV4_MAX_BITLEN;
+ grp.u.prefix4 = up->sg.grp;
+ memset (&out_pnc, 0, sizeof (struct pim_nexthop_cache));
+
+ if ((ret =
+ pim_find_or_track_nexthop (&nht_p, NULL, NULL, &out_pnc)) == 1)
+ {
+ if (out_pnc.nexthop_num)
+ {
+ src.family = AF_INET;
+ src.prefixlen = IPV4_MAX_BITLEN;
+ src.u.prefix4 = up->upstream_addr; //RP or Src address
+ grp.family = AF_INET;
+ grp.prefixlen = IPV4_MAX_BITLEN;
+ grp.u.prefix4 = up->sg.grp;
+ memset (&nexthop, 0, sizeof (nexthop));
+ //Compute PIM RPF using Cached nexthop
+ pim_ecmp_nexthop_search (&out_pnc, &nexthop, &src, &grp, 0);
+ input_iface_vif_index =
+ pim_if_find_vifindex_by_ifindex (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?>", grp.u.prefix4, buf2, sizeof(buf2));
+ zlog_debug ("%s: NHT pnc is NULL for addr %s grp %s" ,
+ __PRETTY_FUNCTION__, buf1, buf2);
+ }
+ }
+ }
+ else
+ input_iface_vif_index = fib_lookup_if_vif_index (up->upstream_addr);
- up->channel_oil = pim_channel_oil_add(&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 (input_iface_vif_index < 1)
+ {
+ if (PIM_DEBUG_PIM_TRACE)
+ {
+ char source_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<source?>", up->sg.src, 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_TRACE)
+ {
+ zlog_debug ("%s: NHT entry %s update channel_oil vif_index %d ",
+ __PRETTY_FUNCTION__, up->sg_str, input_iface_vif_index);
+ }
+ up->channel_oil = pim_channel_oil_add (&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 (up->flags & PIM_UPSTREAM_FLAG_MASK_SRC_IGMP)
mask = PIM_OIF_FLAG_PROTO_IGMP;
- pim_channel_add_oif(up->channel_oil, ch->interface, mask);
+ pim_channel_add_oif (up->channel_oil, ch->interface, mask);
}
void pim_forward_stop(struct pim_ifchannel *ch)