From 7ff3bced6d2f9bc58978781961d2681fea74d62b Mon Sep 17 00:00:00 2001 From: Divakar Date: Sun, 26 Apr 2015 22:21:20 -0700 Subject: [PATCH] Flooding of Unknown unicast Frames The L2 bridge miss packets are dropped as of now. This leads to network disconnectivity if BM ARP timeout is longer than Bridge timeout. To avoid this, unknow unicast packets are flooded into multicast tree. This flooding is limited by per VN flag for user. For Vrouter, the per VN flag is trnanslated to VIF and VrfTranslate NH. If unicast lookup fails, and if the above flag is set, packet if forwarded to broadcast tree. A counter is also added when unknown unicast is flooded. Change-Id: Ia618f6fa981e13b0163e0cd5cb3bdb0919fad901 partial-bug:#1424523 --- dp-core/vr_bridge.c | 41 +++++++++++++++++++++++++++++++++++++++-- dp-core/vr_ip_mtrie.c | 1 + include/vr_interface.h | 1 + include/vr_nexthop.h | 1 + include/vr_route.h | 1 + sandesh/vr.sandesh | 1 + utils/nh.c | 10 +++++++++- utils/vif.c | 1 + utils/vrfstats.c | 6 ++++-- 9 files changed, 58 insertions(+), 5 deletions(-) diff --git a/dp-core/vr_bridge.c b/dp-core/vr_bridge.c index 0622e910e..5ffbe6d26 100644 --- a/dp-core/vr_bridge.c +++ b/dp-core/vr_bridge.c @@ -49,6 +49,7 @@ int bridge_table_init(struct vr_rtable *, struct rtable_fspec *); void bridge_table_deinit(struct vr_rtable *, struct rtable_fspec *, bool); struct vr_bridge_entry *vr_find_bridge_entry(struct vr_bridge_entry_key *); struct vr_bridge_entry *vr_find_free_bridge_entry(unsigned int, char *); +extern struct vr_vrf_stats *(*vr_inet_vrf_stats)(unsigned short, unsigned int); static bool @@ -65,6 +66,23 @@ bridge_entry_valid(vr_htable_t htable, vr_hentry_t hentry, return false; } + +bool +vr_unknown_uc_flood(struct vr_interface *ingress_vif, + struct vr_nexthop *ingress_nh) +{ + if (!ingress_vif) + return false; + + if (vif_is_virtual(ingress_vif)) { + return ((ingress_vif->vif_flags & VIF_FLAG_UNKNOWN_UC_FLOOD) != 0); + } else if (vif_is_fabric(ingress_vif) && ingress_nh) { + return ((ingress_nh->nh_flags & NH_FLAG_UNKNOWN_UC_FLOOD) != 0); + } + + return false; +} + struct vr_bridge_entry * vr_find_bridge_entry(struct vr_bridge_entry_key *key) { @@ -420,6 +438,7 @@ vr_bridge_input(struct vrouter *router, struct vr_packet *pkt, struct vr_nexthop *nh = NULL; unsigned short pull_len, overlay_len = VROUTER_OVERLAY_LEN; int reason, handled; + struct vr_vrf_stats *stats; /* Do the bridge lookup for the packets not meant for "me" */ if (!fmd->fmd_to_me) { @@ -434,8 +453,26 @@ vr_bridge_input(struct vrouter *router, struct vr_packet *pkt, nh = vr_bridge_lookup(fmd->fmd_dvrf, &rt); if (!nh) { - vr_pfree(pkt, VP_DROP_L2_NO_ROUTE); - return 0; + + /* If Flooding of unknown unicast not allowed, drop the packet */ + if (!vr_unknown_uc_flood(pkt->vp_if, pkt->vp_nh) || + IS_MAC_BMCAST(rt.rtr_req.rtr_mac)) { + vr_pfree(pkt, VP_DROP_L2_NO_ROUTE); + return 0; + } + + rt.rtr_req.rtr_mac = (int8_t *)vr_bcast_mac; + nh = vr_bridge_lookup(fmd->fmd_dvrf, &rt); + if (!nh) { + vr_pfree(pkt, VP_DROP_L2_NO_ROUTE); + return 0; + } + stats = vr_inet_vrf_stats(fmd->fmd_dvrf, pkt->vp_cpu); + if (stats) + stats->vrf_uuc_floods++; + + /* Treat this unknown unicast packet as multicast */ + pkt->vp_flags |= VP_FLAG_MULTICAST; } if (nh->nh_type != NH_L2_RCV) diff --git a/dp-core/vr_ip_mtrie.c b/dp-core/vr_ip_mtrie.c index fbba5dae9..dc243cd19 100644 --- a/dp-core/vr_ip_mtrie.c +++ b/dp-core/vr_ip_mtrie.c @@ -762,6 +762,7 @@ mtrie_stats_get(vr_vrf_stats_req *req, vr_vrf_stats_req *response) response->vsr_arp_tor_proxy += stats->vrf_arp_tor_proxy; response->vsr_arp_physical_flood += stats->vrf_arp_physical_flood; response->vsr_vrf_translates += stats->vrf_vrf_translates; + response->vsr_uuc_floods += stats->vrf_uuc_floods; } } diff --git a/include/vr_interface.h b/include/vr_interface.h index af8efae5c..7fd07a2ca 100644 --- a/include/vr_interface.h +++ b/include/vr_interface.h @@ -76,6 +76,7 @@ * so we copy all the packets to another interface */ #define VIF_FLAG_MONITORED 0x8000 +#define VIF_FLAG_UNKNOWN_UC_FLOOD 0x10000 #define vif_mode_xconnect(vif) (vif->vif_flags & VIF_FLAG_XCONNECT) #define vif_dhcp_enabled(vif) (vif->vif_flags & VIF_FLAG_DHCP_ENABLED) diff --git a/include/vr_nexthop.h b/include/vr_nexthop.h index d02e15ab3..d2bec33a5 100644 --- a/include/vr_nexthop.h +++ b/include/vr_nexthop.h @@ -54,6 +54,7 @@ enum nexthop_type { #define NH_FLAG_COMPOSITE_TOR 0x04000 #define NH_FLAG_VNID 0x08000 #define NH_FLAG_ROUTE_LOOKUP 0x10000 +#define NH_FLAG_UNKNOWN_UC_FLOOD 0x20000 #define NH_SOURCE_INVALID 0 #define NH_SOURCE_VALID 1 diff --git a/include/vr_route.h b/include/vr_route.h index 2f1de6f5b..4030ef5bd 100644 --- a/include/vr_route.h +++ b/include/vr_route.h @@ -57,6 +57,7 @@ struct vr_vrf_stats { uint64_t vrf_arp_physical_stitch; uint64_t vrf_arp_tor_proxy; uint64_t vrf_arp_physical_flood; + uint64_t vrf_uuc_floods; }; struct vr_route { diff --git a/sandesh/vr.sandesh b/sandesh/vr.sandesh index b6863bf56..be76e4618 100644 --- a/sandesh/vr.sandesh +++ b/sandesh/vr.sandesh @@ -199,6 +199,7 @@ buffer sandesh vr_vrf_stats_req { 28: i64 vsr_arp_tor_proxy; 29: i64 vsr_arp_physical_flood; 30: i64 vsr_l2_receives; + 31: i64 vsr_uuc_floods; } buffer sandesh vr_response { diff --git a/utils/nh.c b/utils/nh.c index 10ddbade4..55b5790ff 100644 --- a/utils/nh.c +++ b/utils/nh.c @@ -163,6 +163,9 @@ nh_flags(uint32_t flags, uint8_t type, char *ptr) case NH_FLAG_VNID: strcat(ptr, "Vxlan, "); break; + case NH_FLAG_UNKNOWN_UC_FLOOD: + strcat(ptr, "Unicast Flood, "); + break; } } return ptr; @@ -445,7 +448,8 @@ cmd_usage() " [--tor composit tor ]\n" " [--lbl label for composit fabric ]\n" " [VRF Translate options]\n" - " [--vxlan Vxlan VRF Translation]\n"); + " [--vxlan Vxlan VRF Translation]\n" + " [--uucf Unknown Unicast Flood]\n"); exit(-EINVAL); } @@ -486,6 +490,7 @@ enum opt_index { TOR_OPT_IND, RLKUP_OPT_IND, LBL_OPT_IND, + UUCF_OPT_IND, LST_OPT_IND, GET_OPT_IND, CRT_OPT_IND, @@ -531,6 +536,7 @@ static struct option long_options[] = { [TOR_OPT_IND] = {"tor", no_argument, &opt[TOR_OPT_IND], 1}, [RLKUP_OPT_IND] = {"rlkup", no_argument, &opt[RLKUP_OPT_IND], 1}, [LBL_OPT_IND] = {"lbl", required_argument, &opt[LBL_OPT_IND], 1}, + [UUCF_OPT_IND] = {"uucf", no_argument, &opt[UUCF_OPT_IND], 1}, [LST_OPT_IND] = {"list", no_argument, &opt[LST_OPT_IND], 1}, [GET_OPT_IND] = {"get", required_argument, &opt[GET_OPT_IND], 1}, [CRT_OPT_IND] = {"create", required_argument, &opt[CRT_OPT_IND], 1}, @@ -721,6 +727,8 @@ validate_options() } else if (type == NH_VRF_TRANSLATE) { if (opt_set(VXLAN_OPT_IND)) flags |= NH_FLAG_VNID; + if (opt_set(UUCF_OPT_IND)) + flags |= NH_FLAG_UNKNOWN_UC_FLOOD; } else { cmd_usage(); } diff --git a/utils/vif.c b/utils/vif.c index a20c68384..9442c193c 100644 --- a/utils/vif.c +++ b/utils/vif.c @@ -96,6 +96,7 @@ static struct vr_util_flags flag_metadata[] = { {VIF_FLAG_PMD, "Dpdk", "DPDK PMD Interface"}, {VIF_FLAG_FILTERING_OFFLOAD,"Rfl", "Receive Filtering Offload"}, {VIF_FLAG_MONITORED, "Mon", "Interface is Monitored"}, + {VIF_FLAG_UNKNOWN_UC_FLOOD, "Uuf", "Unknown Unicast Flood"}, }; static char * diff --git a/utils/vrfstats.c b/utils/vrfstats.c index 84b7969c6..e9685ae12 100644 --- a/utils/vrfstats.c +++ b/utils/vrfstats.c @@ -58,9 +58,11 @@ vr_vrf_stats_req_process(void *s_req) stats_req.vsr_marker = stats->vsr_vrf; printf("Vrf: %d\n", stats->vsr_vrf); printf("Discards %" PRIu64 ", Resolves %" PRIu64 ", Receives %" - PRIu64 ", L2 Receives %" PRIu64 ", Vrf Translates %" PRIu64 "\n", + PRIu64 ", L2 Receives %" PRIu64 ", Vrf Translates %" PRIu64 + ", Unknown Unicast Floods %" PRIu64 "\n", stats->vsr_discards, stats->vsr_resolves, stats->vsr_receives, - stats->vsr_l2_receives, stats->vsr_vrf_translates); + stats->vsr_l2_receives, stats->vsr_vrf_translates, + stats->vsr_uuc_floods); printf("Ecmp Composites %" PRIu64 ", L2 Mcast Composites %" PRIu64 ", Fabric Composites %" PRIu64 ", Encap Composites %" PRIu64 ", Evpn Composites %" PRIu64 "\n", stats->vsr_ecmp_composites,