From 1bf1644338146f843194e44c0abc7c4cdff29056 Mon Sep 17 00:00:00 2001 From: anuradhak Date: Tue, 15 Nov 2016 15:39:11 -0800 Subject: [PATCH] pim-kat: changed kat handling to match rfc-4601 more closely. 1. This is needed to layout the MSDP macros for determining what SAs are originated by a MSDP speaker. 2. We no longer let the kat timer expire on an active flow. Activity counters/lastuse is polled via a wheel for every SG entry. If new activity is detected the keepalive timer is started and SPT bit set. A SRC_STREAM reference is also created for the entry if one doesn't already exist. 3. If KAT actually expires it means the flow is no longer active. At this point we stop advertising the SA to MSDP peers. We also pull the SRC_STREAM reference (deleting the entry if there are no other references). PS: Checking counters on KAT expiry will come in the next change. Signed-off-by: Anuradha Karuppiah Acked-by: Donald Sharp --- pimd/pim_cmd.c | 63 ++++++++---- pimd/pim_mroute.c | 4 - pimd/pim_msdp.c | 118 ++++++++++++++-------- pimd/pim_msdp.h | 2 +- pimd/pim_register.c | 5 +- pimd/pim_upstream.c | 231 ++++++++++++++++++++++++++++++-------------- pimd/pim_upstream.h | 14 +-- 7 files changed, 290 insertions(+), 147 deletions(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index ebe8b362ba..0690130edf 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -1632,6 +1632,7 @@ static void pim_show_upstream(struct vty *vty, u_char uj) char join_timer[10]; char rs_timer[10]; char ka_timer[10]; + char msdp_reg_timer[10]; pim_inet4_dump("", up->sg.src, src_str, sizeof(src_str)); pim_inet4_dump("", up->sg.grp, grp_str, sizeof(grp_str)); @@ -1639,6 +1640,7 @@ static void pim_show_upstream(struct vty *vty, u_char uj) pim_time_timer_to_hhmmss (join_timer, sizeof(join_timer), up->t_join_timer); pim_time_timer_to_hhmmss (rs_timer, sizeof (rs_timer), up->t_rs_timer); pim_time_timer_to_hhmmss (ka_timer, sizeof (ka_timer), up->t_ka_timer); + pim_time_timer_to_hhmmss (msdp_reg_timer, sizeof (msdp_reg_timer), up->t_msdp_reg_timer); if (uj) { json_object_object_get_ex(json, grp_str, &json_group); @@ -1658,6 +1660,7 @@ static void pim_show_upstream(struct vty *vty, u_char uj) json_object_string_add(json_row, "joinTimer", join_timer); json_object_string_add(json_row, "resetTimer", rs_timer); json_object_string_add(json_row, "keepaliveTimer", ka_timer); + json_object_string_add(json_row, "msdpRegTimer", msdp_reg_timer); json_object_int_add(json_row, "refCount", up->ref_count); json_object_int_add(json_row, "sptBit", up->sptbit); json_object_object_add(json_group, src_str, json_row); @@ -5431,6 +5434,15 @@ DEFUN (no_ip_msdp_mesh_group, return ip_no_msdp_mesh_group_cmd_worker(vty, argv[4]->arg); } +static void +print_empty_json_obj(struct vty *vty) +{ + json_object *json; + json = json_object_new_object(); + vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE); + json_object_free(json); +} + static void ip_msdp_show_mesh_group(struct vty *vty, u_char uj) { @@ -5446,6 +5458,8 @@ ip_msdp_show_mesh_group(struct vty *vty, u_char uj) json_object *json_row = NULL; if (!mg) { + if (uj) + print_empty_json_obj(vty); return; } @@ -5670,6 +5684,7 @@ ip_msdp_show_sa(struct vty *vty, u_char uj) char rp_str[INET_ADDRSTRLEN]; char timebuf[PIM_MSDP_UPTIME_STRLEN]; char spt_str[8]; + char local_str[8]; int64_t now; json_object *json = NULL; json_object *json_group = NULL; @@ -5678,7 +5693,7 @@ ip_msdp_show_sa(struct vty *vty, u_char uj) if (uj) { json = json_object_new_object(); } else { - vty_out(vty, "Source Group RP SPT Uptime%s", VTY_NEWLINE); + vty_out(vty, "Source Group RP Local SPT Uptime%s", VTY_NEWLINE); } for (ALL_LIST_ELEMENTS_RO(msdp->sa_list, sanode, sa)) { @@ -5686,19 +5701,23 @@ ip_msdp_show_sa(struct vty *vty, u_char uj) pim_time_uptime(timebuf, sizeof(timebuf), now - sa->uptime); pim_inet4_dump("", sa->sg.src, src_str, sizeof(src_str)); pim_inet4_dump("", sa->sg.grp, grp_str, sizeof(grp_str)); - if (sa->flags & PIM_MSDP_SAF_LOCAL) { - strcpy(rp_str, "local"); - strcpy(spt_str, "-"); - } else { + if (sa->flags & PIM_MSDP_SAF_PEER) { pim_inet4_dump("", sa->rp, rp_str, sizeof(rp_str)); - } - - if (uj) { if (sa->up) { strcpy(spt_str, "yes"); } else { strcpy(spt_str, "no"); } + } else { + strcpy(rp_str, "-"); + strcpy(spt_str, "-"); + } + if (sa->flags & PIM_MSDP_SAF_LOCAL) { + strcpy(local_str, "yes"); + } else { + strcpy(local_str, "no"); + } + if (uj) { json_object_object_get_ex(json, grp_str, &json_group); if (!json_group) { @@ -5710,17 +5729,13 @@ ip_msdp_show_sa(struct vty *vty, u_char uj) json_object_string_add(json_row, "source", src_str); json_object_string_add(json_row, "group", grp_str); json_object_string_add(json_row, "rp", rp_str); + json_object_string_add(json_row, "local", local_str); json_object_string_add(json_row, "sptSetup", spt_str); json_object_string_add(json_row, "upTime", timebuf); json_object_object_add(json_group, src_str, json_row); } else { - if (sa->up) { - strcpy(spt_str, "y"); - } else { - strcpy(spt_str, "n"); - } - vty_out(vty, "%-15s %15s %15s %3s %8s%s", - src_str, grp_str, rp_str, spt_str, timebuf, VTY_NEWLINE); + vty_out(vty, "%-15s %15s %15s %5c %3c %8s%s", + src_str, grp_str, rp_str, local_str[0], spt_str[0], timebuf, VTY_NEWLINE); } } @@ -5740,6 +5755,7 @@ ip_msdp_show_sa_entry_detail(struct pim_msdp_sa *sa, const char *src_str, char peer_str[INET_ADDRSTRLEN]; char timebuf[PIM_MSDP_UPTIME_STRLEN]; char spt_str[8]; + char local_str[8]; char statetimer[PIM_MSDP_TIMER_STRLEN]; int64_t now; json_object *json_group = NULL; @@ -5747,11 +5763,7 @@ ip_msdp_show_sa_entry_detail(struct pim_msdp_sa *sa, const char *src_str, now = pim_time_monotonic_sec(); pim_time_uptime(timebuf, sizeof(timebuf), now - sa->uptime); - if (sa->flags & PIM_MSDP_SAF_LOCAL) { - strcpy(rp_str, "local"); - strcpy(peer_str, "-"); - strcpy(spt_str, "-"); - } else { + if (sa->flags & PIM_MSDP_SAF_PEER) { pim_inet4_dump("", sa->rp, rp_str, sizeof(rp_str)); pim_inet4_dump("", sa->peer, peer_str, sizeof(peer_str)); if (sa->up) { @@ -5759,6 +5771,15 @@ ip_msdp_show_sa_entry_detail(struct pim_msdp_sa *sa, const char *src_str, } else { strcpy(spt_str, "no"); } + } else { + strcpy(rp_str, "-"); + strcpy(peer_str, "-"); + strcpy(spt_str, "-"); + } + if (sa->flags & PIM_MSDP_SAF_LOCAL) { + strcpy(local_str, "yes"); + } else { + strcpy(local_str, "no"); } pim_time_timer_to_hhmmss(statetimer, sizeof(statetimer), sa->sa_state_timer); if (uj) { @@ -5773,6 +5794,7 @@ ip_msdp_show_sa_entry_detail(struct pim_msdp_sa *sa, const char *src_str, json_object_string_add(json_row, "source", src_str); json_object_string_add(json_row, "group", grp_str); json_object_string_add(json_row, "rp", rp_str); + json_object_string_add(json_row, "local", local_str); json_object_string_add(json_row, "sptSetup", spt_str); json_object_string_add(json_row, "upTime", timebuf); json_object_string_add(json_row, "stateTime", statetimer); @@ -5781,6 +5803,7 @@ ip_msdp_show_sa_entry_detail(struct pim_msdp_sa *sa, const char *src_str, vty_out(vty, "SA : %s%s", pim_str_sg_dump(&sa->sg), VTY_NEWLINE); vty_out(vty, " RP : %s%s", rp_str, VTY_NEWLINE); vty_out(vty, " Peer : %s%s", peer_str, VTY_NEWLINE); + vty_out(vty, " Local : %s%s", local_str, VTY_NEWLINE); vty_out(vty, " SPT Setup : %s%s", spt_str, VTY_NEWLINE); vty_out(vty, " Uptime : %s%s", timebuf, VTY_NEWLINE); vty_out(vty, " State Time : %s%s", statetimer, VTY_NEWLINE); diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c index 5fba681a73..3f8ec35587 100644 --- a/pimd/pim_mroute.c +++ b/pimd/pim_mroute.c @@ -160,8 +160,6 @@ pim_mroute_msg_nocache (int fd, struct interface *ifp, const struct igmpmsg *msg return 0; } PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags); - pim_upstream_set_created_by_upstream(up); - pim_upstream_keep_alive_timer_start (up, qpim_keep_alive_time); up->channel_oil = oil; @@ -422,8 +420,6 @@ pim_mroute_msg_wrvifwhole (int fd, struct interface *ifp, const char *buf) return -2; } PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags); - pim_upstream_set_created_by_upstream(up); - pim_upstream_keep_alive_timer_start (up, qpim_keep_alive_time); up->channel_oil = oil; up->channel_oil->cc.pktcnt++; diff --git a/pimd/pim_msdp.c b/pimd/pim_msdp.c index 76127245ce..12f363e6fe 100644 --- a/pimd/pim_msdp.c +++ b/pimd/pim_msdp.c @@ -36,6 +36,7 @@ #include "pim_rp.h" #include "pim_str.h" #include "pim_time.h" +#include "pim_upstream.h" #include "pim_msdp.h" #include "pim_msdp_packet.h" @@ -139,10 +140,6 @@ pim_msdp_sa_upstream_del(struct pim_msdp_sa *sa) } sa->up = NULL; - /* XXX: we can't pull the plug on an active flow even if the SA entry is - * removed. so ideally we want to start the kat in parallel and let the - * entry age out; but running the kat has fatal consequences. need to - * check with Donald on the best way to go abt this */ if (PIM_UPSTREAM_FLAG_TEST_SRC_MSDP(up->flags)) { PIM_UPSTREAM_FLAG_UNSET_SRC_MSDP(up->flags); pim_upstream_del(up, __PRETTY_FUNCTION__); @@ -158,12 +155,6 @@ pim_msdp_sa_upstream_del(struct pim_msdp_sa *sa) static bool pim_msdp_sa_upstream_add_ok(struct pim_msdp_sa *sa, struct pim_upstream *xg_up) { - if (sa->flags & PIM_MSDP_SAF_LOCAL) { - /* if there is a local reference we should NEVER use it for setting up - * SPTs otherwise we will get stuck in a simple circular deadlock */ - return false; - } - if (!(sa->flags & PIM_MSDP_SAF_PEER)) { /* SA should have been rxed from a peer */ return false; @@ -194,10 +185,9 @@ pim_msdp_sa_upstream_add_ok(struct pim_msdp_sa *sa, struct pim_upstream *xg_up) /* Upstream add evaluation needs to happen everytime - * 1. Peer reference is added or removed. - * 2. Local reference is added or removed. - * 3. The RP for a group changes. - * 4. joinDesired for the associated (*, G) changes - * 5. associated (*, G) is removed - this seems like a bit redundant + * 2. The RP for a group changes. + * 3. joinDesired for the associated (*, G) changes + * 4. associated (*, G) is removed - this seems like a bit redundant * (considering #4); but just in case an entry gets nuked without * upstream state transition * */ @@ -359,12 +349,17 @@ static void pim_msdp_sa_deref(struct pim_msdp_sa *sa, enum pim_msdp_sa_flags flags) { char key_str[PIM_MSDP_SA_KEY_STRLEN]; + bool update_up = false; - pim_msdp_sa_key_dump(sa, key_str, sizeof(key_str), true); + if (PIM_DEBUG_MSDP_EVENTS) { + pim_msdp_sa_key_dump(sa, key_str, sizeof(key_str), true); + } if ((sa->flags &PIM_MSDP_SAF_LOCAL)) { if (flags & PIM_MSDP_SAF_LOCAL) { - zlog_debug("%s local reference removed", key_str); + if (PIM_DEBUG_MSDP_EVENTS) { + zlog_debug("%s local reference removed", key_str); + } if (msdp->local_cnt) --msdp->local_cnt; } @@ -372,13 +367,21 @@ pim_msdp_sa_deref(struct pim_msdp_sa *sa, enum pim_msdp_sa_flags flags) if ((sa->flags &PIM_MSDP_SAF_PEER)) { if (flags & PIM_MSDP_SAF_PEER) { - zlog_debug("%s peer reference removed", key_str); + if (PIM_DEBUG_MSDP_EVENTS) { + zlog_debug("%s peer reference removed", key_str); + } pim_msdp_sa_state_timer_setup(sa, false /* start */); + /* if peer ref was removed we need to remove the msdp reference on the + * msdp entry */ + update_up = true; } } sa->flags &= ~flags; - pim_msdp_sa_upstream_update(sa, NULL /* xg_up */, "sa-deref"); + if (update_up) { + pim_msdp_sa_upstream_update(sa, NULL /* xg_up */, "sa-deref"); + } + if (!(sa->flags & PIM_MSDP_SAF_REF)) { pim_msdp_sa_del(sa); } @@ -424,27 +427,53 @@ pim_msdp_sa_ref(struct pim_msdp_peer *mp, struct prefix_sg *sg, } /* send an immediate SA update to peers */ pim_msdp_pkt_sa_tx_one(sa); - pim_msdp_sa_upstream_update(sa, NULL /* xg_up */, "local-ref"); } sa->flags &= ~PIM_MSDP_SAF_STALE; } } -void -pim_msdp_sa_local_add(struct prefix_sg *sg) +/* The following criteria must be met to originate an SA from the MSDP + * speaker - + * 1. KAT must be running i.e. source is active. + * 2. We must be RP for the group. + * 3. Source must be registrable to the RP (this is where the RFC is vague + * and especially ambiguous in CLOS networks; with anycast RP all sources + * are potentially registrable to all RPs in the domain). We assume #3 is + * satisfied if - + * a. We are also the FHR-DR for the source (OR) + * b. We rxed a pim register (null or data encapsulated) within the last + * (3 * (1.5 * register_suppression_timer))). + */ +static bool +pim_msdp_sa_local_add_ok(struct pim_upstream *up) { - struct in_addr rp; - if (!(msdp->flags & PIM_MSDPF_ENABLE)) { - /* if the feature is not enabled do nothing; we will collect all local - * sources whenever it is */ - return; + return false; } - /* check if I am RP for this group. XXX: is this check really needed? */ - if (!I_am_RP(sg->grp)) { - return; + if (!up->t_ka_timer) { + /* stream is not active */ + return false; + } + + if (!I_am_RP(up->sg.grp)) { + /* we are not RP for the group */ + return false; + } + + /* we are the FHR-DR for this stream or we are RP and have seen registers + * from a FHR for this source */ + if (PIM_UPSTREAM_FLAG_TEST_FHR(up->flags) || up->t_msdp_reg_timer) { + return true; } + + return false; +} + +static void +pim_msdp_sa_local_add(struct prefix_sg *sg) +{ + struct in_addr rp; rp.s_addr = 0; pim_msdp_sa_ref(NULL /* mp */, sg, rp); } @@ -454,18 +483,31 @@ pim_msdp_sa_local_del(struct prefix_sg *sg) { struct pim_msdp_sa *sa; - if (!(msdp->flags & PIM_MSDPF_ENABLE)) { - /* if the feature is not enabled do nothing; we will collect all local - * sources whenever it is */ - return; - } - sa = pim_msdp_sa_find(sg); if (sa) { pim_msdp_sa_deref(sa, PIM_MSDP_SAF_LOCAL); } } +/* Local SA qualification needs to be re-evaluated when - + * 1. KAT is started or stopped + * 2. on RP changes + * 3. Whenever FHR status changes for a (S,G) - XXX - currently there + * is no clear path to transition an entry out of "MASK_FHR" need + * to discuss this with Donald. May result in some strangeness if the + * FHR is also the RP. + * 4. When msdp_reg timer is started or stopped + */ +void +pim_msdp_sa_local_update(struct pim_upstream *up) +{ + if (pim_msdp_sa_local_add_ok(up)) { + pim_msdp_sa_local_add(&up->sg); + } else { + pim_msdp_sa_local_del(&up->sg); + } +} + static void pim_msdp_sa_local_setup(void) { @@ -473,9 +515,7 @@ pim_msdp_sa_local_setup(void) struct listnode *up_node; for (ALL_LIST_ELEMENTS_RO(pim_upstream_list, up_node, up)) { - if (PIM_UPSTREAM_FLAG_TEST_CREATED_BY_UPSTREAM(up->flags)) { - pim_msdp_sa_local_add(&up->sg); - } + pim_msdp_sa_local_update(up); } } @@ -548,8 +588,6 @@ pim_msdp_up_join_state_changed(struct pim_upstream *xg_up) } } -/* XXX: Need to maintain SAs per-group to avoid all this unnecessary - * walking */ void pim_msdp_up_xg_del(struct prefix_sg *sg) { diff --git a/pimd/pim_msdp.h b/pimd/pim_msdp.h index 4809749b94..38ac4aa337 100644 --- a/pimd/pim_msdp.h +++ b/pimd/pim_msdp.h @@ -218,7 +218,7 @@ int pim_msdp_config_write(struct vty *vty); void pim_msdp_peer_pkt_txed(struct pim_msdp_peer *mp); char *pim_msdp_sa_key_dump(struct pim_msdp_sa *sa, char *buf, int buf_size, bool long_format); void pim_msdp_sa_ref(struct pim_msdp_peer *mp, struct prefix_sg *sg, struct in_addr rp); -void pim_msdp_sa_local_add(struct prefix_sg *sg); +void pim_msdp_sa_local_update(struct pim_upstream *up); void pim_msdp_sa_local_del(struct prefix_sg *sg); void pim_msdp_i_am_rp_changed(void); bool pim_msdp_peer_rpf_check(struct pim_msdp_peer *mp, struct in_addr rp); diff --git a/pimd/pim_register.c b/pimd/pim_register.c index 914d196339..8f3edc7580 100644 --- a/pimd/pim_register.c +++ b/pimd/pim_register.c @@ -342,7 +342,7 @@ pim_register_recv (struct interface *ifp, zlog_warn ("Failure to create upstream state"); return 1; } - pim_upstream_set_created_by_upstream(upstream); + PIM_UPSTREAM_FLAG_SET_SRC_STREAM(upstream->flags); upstream->upstream_register = src_addr; pim_rp_set_upstream_addr (&upstream->upstream_addr, sg.src, sg.grp); @@ -353,7 +353,7 @@ pim_register_recv (struct interface *ifp, { zlog_debug ("Received Register(%s), for which I have no path back", pim_str_sg_dump (&upstream->sg)); } - pim_upstream_unset_created_by_upstream(upstream); + PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(upstream->flags); pim_upstream_del (upstream, __PRETTY_FUNCTION__); return 1; } @@ -390,6 +390,7 @@ pim_register_recv (struct interface *ifp, //inherited_olist(S,G,rpt) // This is taken care of by the kernel for us } + pim_upstream_msdp_reg_timer_start(upstream); } else { if (PIM_DEBUG_PIM_REG) { diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index a6d7f6e749..01b0b3ac69 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -112,20 +112,6 @@ pim_upstream_find_new_children (struct pim_upstream *up) } } -void -pim_upstream_set_created_by_upstream(struct pim_upstream *up) -{ - PIM_UPSTREAM_FLAG_SET_CREATED_BY_UPSTREAM(up->flags); - pim_msdp_sa_local_add(&up->sg); -} - -void -pim_upstream_unset_created_by_upstream(struct pim_upstream *up) -{ - PIM_UPSTREAM_FLAG_UNSET_CREATED_BY_UPSTREAM(up->flags); - pim_msdp_sa_local_del(&up->sg); -} - /* * If we have a (*,*) || (S,*) there is no parent * If we have a (S,G), find the (*,G) @@ -188,6 +174,7 @@ pim_upstream_del(struct pim_upstream *up, const char *name) THREAD_OFF(up->t_join_timer); THREAD_OFF(up->t_ka_timer); THREAD_OFF(up->t_rs_timer); + THREAD_OFF(up->t_msdp_reg_timer); if (up->join_state == PIM_UPSTREAM_JOINED) { pim_joinprune_send (up->rpf.source_nexthop.interface, @@ -576,6 +563,7 @@ static struct pim_upstream *pim_upstream_new(struct prefix_sg *sg, up->t_join_timer = NULL; up->t_ka_timer = NULL; up->t_rs_timer = NULL; + up->t_msdp_reg_timer = NULL; up->join_state = 0; up->state_transition = pim_time_monotonic_sec(); up->channel_oil = NULL; @@ -634,6 +622,12 @@ struct pim_upstream *pim_upstream_find(struct prefix_sg *sg) return up; } +static void pim_upstream_ref(struct pim_upstream *up, int flags) +{ + up->flags |= flags; + ++up->ref_count; +} + struct pim_upstream *pim_upstream_add(struct prefix_sg *sg, struct interface *incoming, int flags, const char *name) @@ -642,8 +636,7 @@ struct pim_upstream *pim_upstream_add(struct prefix_sg *sg, int found = 0; up = pim_upstream_find(sg); if (up) { - ++up->ref_count; - up->flags |= flags; + pim_upstream_ref(up, flags); found = 1; } else { @@ -908,9 +901,48 @@ static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up) } /* scan iface channel list */ } +/* When kat is stopped CouldRegister goes to false so we need to + * transition the (S, G) on FHR to NI state and remove reg tunnel + * from the OIL */ +static void pim_upstream_fhr_kat_expiry(struct pim_upstream *up) +{ + if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags)) + return; + + if (PIM_DEBUG_TRACE) + zlog_debug ("kat expired on %s; clear fhr reg state", + pim_str_sg_dump (&up->sg)); + /* stop reg-stop timer */ + THREAD_OFF(up->t_rs_timer); + /* remove regiface from the OIL if it is there*/ + pim_channel_del_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM); + /* move to "not-joined" */ + up->join_state = PIM_UPSTREAM_NOTJOINED; + PIM_UPSTREAM_FLAG_UNSET_FHR(up->flags); +} + +/* When kat is started CouldRegister can go to true. And if it does we + * need to transition the (S, G) on FHR to JOINED state and add reg tunnel + * to the OIL */ +static void pim_upstream_fhr_kat_start(struct pim_upstream *up) +{ + if (pim_upstream_could_register(up)) { + if (PIM_DEBUG_TRACE) + zlog_debug ("kat started on %s; set fhr reg state to joined", + pim_str_sg_dump (&up->sg)); + PIM_UPSTREAM_FLAG_SET_FHR(up->flags); + if (up->join_state == PIM_UPSTREAM_NOTJOINED) { + pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM); + up->join_state = PIM_UPSTREAM_JOINED; + } + } +} + /* * On an RP, the PMBR value must be cleared when the * Keepalive Timer expires + * KAT expiry indicates that flow is inactive. If the flow was created or + * maintained by activity now is the time to deref it. */ static int pim_upstream_keep_alive_timer (struct thread *t) @@ -918,56 +950,75 @@ pim_upstream_keep_alive_timer (struct thread *t) struct pim_upstream *up; up = THREAD_ARG(t); + up->t_ka_timer = NULL; if (I_am_RP (up->sg.grp)) - { - pim_br_clear_pmbr (&up->sg); - /* - * We need to do more here :) - * But this is the start. - */ - } + { + pim_br_clear_pmbr (&up->sg); + /* + * We need to do more here :) + * But this is the start. + */ + } - pim_mroute_update_counters (up->channel_oil); + /* source is no longer active - pull the SA from MSDP's cache */ + pim_msdp_sa_local_del(&up->sg); - if (PIM_DEBUG_MROUTE) - { - zlog_debug ("New: %llu %lu %lu %lu", up->channel_oil->cc.lastused, up->channel_oil->cc.pktcnt, - up->channel_oil->cc.bytecnt, up->channel_oil->cc.wrong_if); - zlog_debug ("old: %llu %lu %lu %lu", up->channel_oil->cc.lastused, up->channel_oil->cc.oldpktcnt, - up->channel_oil->cc.oldbytecnt, up->channel_oil->cc.oldwrong_if); - } - if ((up->channel_oil->cc.oldpktcnt >= up->channel_oil->cc.pktcnt) && - (up->channel_oil->cc.lastused/100 >= qpim_keep_alive_time)) - { - pim_mroute_del (up->channel_oil); - THREAD_OFF (up->t_ka_timer); - THREAD_OFF (up->t_rs_timer); - PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM (up->flags); - if (PIM_UPSTREAM_FLAG_TEST_CREATED_BY_UPSTREAM(up->flags)) - { - pim_upstream_unset_created_by_upstream(up); - pim_upstream_del (up, __PRETTY_FUNCTION__); - } - } - else - { - up->t_ka_timer = NULL; - pim_upstream_keep_alive_timer_start (up, qpim_keep_alive_time); - } + /* if entry was created because of activity we need to deref it */ + if (PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) + { + pim_upstream_fhr_kat_expiry(up); + if (PIM_DEBUG_TRACE) + zlog_debug ("kat expired on %s; remove stream reference", + pim_str_sg_dump (&up->sg)); + PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(up->flags); + pim_upstream_del(up, __PRETTY_FUNCTION__); + } - return 1; + return 0; } void pim_upstream_keep_alive_timer_start (struct pim_upstream *up, uint32_t time) { + if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) { + if (PIM_DEBUG_TRACE) + zlog_debug ("kat start on %s with no stream reference", + pim_str_sg_dump (&up->sg)); + } THREAD_OFF (up->t_ka_timer); THREAD_TIMER_ON (master, up->t_ka_timer, pim_upstream_keep_alive_timer, up, time); + + /* any time keepalive is started against a SG we will have to + * re-evaluate our active source database */ + pim_msdp_sa_local_update(up); +} + +/* MSDP on RP needs to know if a source is registerable to this RP */ +static int +pim_upstream_msdp_reg_timer(struct thread *t) +{ + struct pim_upstream *up; + + up = THREAD_ARG(t); + up->t_msdp_reg_timer = NULL; + + /* source is no longer active - pull the SA from MSDP's cache */ + pim_msdp_sa_local_del(&up->sg); + return 1; +} +void +pim_upstream_msdp_reg_timer_start(struct pim_upstream *up) +{ + THREAD_OFF(up->t_msdp_reg_timer); + THREAD_TIMER_ON(master, up->t_msdp_reg_timer, + pim_upstream_msdp_reg_timer, up, PIM_MSDP_REG_RXED_PERIOD); + + pim_msdp_sa_local_update(up); } /* @@ -1130,7 +1181,6 @@ pim_upstream_register_stop_timer (struct thread *t) struct ip ip_hdr; up = THREAD_ARG (t); - THREAD_TIMER_OFF (up->t_rs_timer); up->t_rs_timer = NULL; if (PIM_DEBUG_TRACE) @@ -1330,6 +1380,43 @@ pim_upstream_equal (const void *arg1, const void *arg2) return 0; } +/* rfc4601:section-4.2:"Data Packet Forwarding Rules" defines + * the cases where kat has to be restarted on rxing traffic - + * + * if( DirectlyConnected(S) == TRUE AND iif == RPF_interface(S) ) { + * set KeepaliveTimer(S,G) to Keepalive_Period + * # Note: a register state transition or UpstreamJPState(S,G) + * # transition may happen as a result of restarting + * # KeepaliveTimer, and must be dealt with here. + * } + * if( iif == RPF_interface(S) AND UpstreamJPState(S,G) == Joined AND + * inherited_olist(S,G) != NULL ) { + * set KeepaliveTimer(S,G) to Keepalive_Period + * } + */ +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, + up->sg.src)) { + return true; + } + + if ((up->join_state == PIM_UPSTREAM_JOINED) && + !pim_upstream_empty_inherited_olist(up)) { + /* XXX: I have added this RP check just for 3.2 and it's a digression from + * what rfc-4601 says. Till now we were only running KAT on FHR and RP and + * there is some angst around making the change to run it all routers that + * maintain the (S, G) state. This is tracked via CM-13601 and MUST be + * removed to handle spt turn-arounds correctly in a 3-tier clos */ + if (I_am_RP (up->sg.grp)) + return true; + } + + return false; +} + /* * Code to check and see if we've received packets on a S,G mroute * and if so to set the SPT bit appropriately @@ -1338,16 +1425,6 @@ static void pim_upstream_sg_running (void *arg) { struct pim_upstream *up = (struct pim_upstream *)arg; - long long now; - - // If we are TRUE already no need to do more work - if (up->sptbit == PIM_UPSTREAM_SPTBIT_TRUE) - { - if (PIM_DEBUG_TRACE) - zlog_debug ("%s: %s sptbit is true", __PRETTY_FUNCTION__, - pim_str_sg_dump(&up->sg)); - return; - } // No packet can have arrived here if this is the case if (!up->channel_oil || !up->channel_oil->installed) @@ -1358,21 +1435,11 @@ pim_upstream_sg_running (void *arg) return; } - // We need at least 30 seconds to see if we are getting packets - now = pim_time_monotonic_sec(); - if (now - up->state_transition <= 30) - { - if (PIM_DEBUG_TRACE) - zlog_debug ("%s: %s uptime is %lld", - __PRETTY_FUNCTION__, pim_str_sg_dump (&up->sg), - now - up->state_transition); - return; - } pim_mroute_update_counters (up->channel_oil); // Have we seen packets? - if ((up->channel_oil->cc.oldpktcnt <= up->channel_oil->cc.pktcnt) && + if ((up->channel_oil->cc.oldpktcnt >= up->channel_oil->cc.pktcnt) && (up->channel_oil->cc.lastused/100 > 30)) { if (PIM_DEBUG_TRACE) @@ -1384,7 +1451,25 @@ pim_upstream_sg_running (void *arg) return; } - pim_upstream_set_sptbit (up, up->rpf.source_nexthop.interface); + if (pim_upstream_kat_start_ok(up)) { + /* Add a source reference to the stream if + * one doesn't already exist */ + if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) + { + if (PIM_DEBUG_TRACE) + zlog_debug ("source reference created on kat restart %s", + pim_str_sg_dump (&up->sg)); + pim_upstream_ref(up, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM); + PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags); + pim_upstream_fhr_kat_start(up); + } + pim_upstream_keep_alive_timer_start(up, qpim_keep_alive_time); + } + + if (up->sptbit != PIM_UPSTREAM_SPTBIT_TRUE) + { + pim_upstream_set_sptbit(up, up->rpf.source_nexthop.interface); + } return; } diff --git a/pimd/pim_upstream.h b/pimd/pim_upstream.h index a073125021..b3823604c1 100644 --- a/pimd/pim_upstream.h +++ b/pimd/pim_upstream.h @@ -33,8 +33,7 @@ #define PIM_UPSTREAM_FLAG_MASK_SRC_IGMP (1 << 3) #define PIM_UPSTREAM_FLAG_MASK_SRC_PIM (1 << 4) #define PIM_UPSTREAM_FLAG_MASK_SRC_STREAM (1 << 5) -#define PIM_UPSTREAM_FLAG_MASK_CREATED_BY_UPSTREAM (1 << 6) -#define PIM_UPSTREAM_FLAG_MASK_SRC_MSDP (1 << 7) +#define PIM_UPSTREAM_FLAG_MASK_SRC_MSDP (1 << 6) #define PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED) #define PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED) @@ -42,7 +41,6 @@ #define PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_SRC_IGMP) #define PIM_UPSTREAM_FLAG_TEST_SRC_PIM(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_SRC_PIM) #define PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_SRC_STREAM) -#define PIM_UPSTREAM_FLAG_TEST_CREATED_BY_UPSTREAM(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_CREATED_BY_UPSTREAM) #define PIM_UPSTREAM_FLAG_TEST_SRC_MSDP(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_SRC_MSDP) #define PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED) @@ -51,7 +49,6 @@ #define PIM_UPSTREAM_FLAG_SET_SRC_IGMP(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SRC_IGMP) #define PIM_UPSTREAM_FLAG_SET_SRC_PIM(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SRC_PIM) #define PIM_UPSTREAM_FLAG_SET_SRC_STREAM(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SRC_STREAM) -#define PIM_UPSTREAM_FLAG_SET_CREATED_BY_UPSTREAM(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_CREATED_BY_UPSTREAM) #define PIM_UPSTREAM_FLAG_SET_SRC_MSDP(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SRC_MSDP) #define PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED) @@ -60,7 +57,6 @@ #define PIM_UPSTREAM_FLAG_UNSET_SRC_IGMP(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_IGMP) #define PIM_UPSTREAM_FLAG_UNSET_SRC_PIM(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_PIM) #define PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_STREAM) -#define PIM_UPSTREAM_FLAG_UNSET_CREATED_BY_UPSTREAM(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_CREATED_BY_UPSTREAM) #define PIM_UPSTREAM_FLAG_UNSET_SRC_MSDP(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_MSDP) enum pim_upstream_state { @@ -114,6 +110,11 @@ struct pim_upstream { #define PIM_KEEPALIVE_PERIOD (210) #define PIM_RP_KEEPALIVE_PERIOD ( 3 * qpim_register_suppress_time + qpim_register_probe_time ) + /* on the RP we restart a timer to indicate if registers are being rxed for + * SG. This is needed by MSDP to determine its local SA cache */ + struct thread *t_msdp_reg_timer; +#define PIM_MSDP_REG_RXED_PERIOD (3 * (1.5 * qpim_register_suppress_time)) + int64_t state_transition; /* Record current state uptime */ }; @@ -164,9 +165,8 @@ int pim_upstream_inherited_olist (struct pim_upstream *up); int pim_upstream_empty_inherited_olist (struct pim_upstream *up); void pim_upstream_find_new_rpf (void); +void pim_upstream_msdp_reg_timer_start(struct pim_upstream *up); void pim_upstream_init (void); void pim_upstream_terminate (void); -void pim_upstream_set_created_by_upstream(struct pim_upstream *up); -void pim_upstream_unset_created_by_upstream(struct pim_upstream *up); #endif /* PIM_UPSTREAM_H */ -- 2.39.5