From 7e9c21bb7127f12bea8ab26229fee106b0dbecd5 Mon Sep 17 00:00:00 2001 From: Praveen K V Date: Wed, 7 Dec 2016 13:25:11 +0530 Subject: [PATCH] Ensure flow-stickiness with bridged forward flow and routed reverse flow Support for following scenario, - An ECMP source sends a bridged packet to destination - On the destination compute node, l2-flow is created - Destination VM responds to flow with l3-flow - In VRouter packet processing, - Packet hits flow without any ECMP-Index - Packet go thru route processing (since dest mac is VRRP-MAC) - L3-Processing results in ECMP-NH - Packet trapped for ECMP resolution since ECMP-Index is not known In this scenario, we need to pick ECMP-Index such that packet reaches the reaches original source of packet from (1) after routing. Agent changes in ECMP Resolve processing: - Original source is found from the tunnel-info field of original forward flow - ECMP index computation logic is changed to choose the NH with tunnel-source got above Closes-Bug: #1645978 (cherry picked from commit 14333196c7fe7f2351a9552521719f979373c102) Conflicts: src/vnsw/agent/pkt/pkt_flow_info.h Change-Id: I1f7ac4bc46de49bc68f93a9248d40db325eb51bb --- src/vnsw/agent/oper/nexthop.h | 25 ++-- src/vnsw/agent/pkt/flow_entry.h | 2 + src/vnsw/agent/pkt/pkt_flow_info.cc | 119 +++++++++++++++--- src/vnsw/agent/pkt/pkt_flow_info.h | 14 ++- src/vnsw/agent/pkt/test/test_ecmp.cc | 150 ++++++++++++++++++++++- src/vnsw/agent/pkt/test/test_pkt_util.cc | 31 ++++- src/vnsw/agent/pkt/test/test_pkt_util.h | 16 ++- src/vnsw/agent/test/pkt_gen.h | 13 ++ 8 files changed, 326 insertions(+), 44 deletions(-) diff --git a/src/vnsw/agent/oper/nexthop.h b/src/vnsw/agent/oper/nexthop.h index 195cf7d238d..001357b0522 100644 --- a/src/vnsw/agent/oper/nexthop.h +++ b/src/vnsw/agent/oper/nexthop.h @@ -201,16 +201,6 @@ class MemberList { return mbr_list_.size(); } - uint32_t hash(size_t hash) const { - for (uint32_t i = 0; i < mbr_list_.size(); i++) { - if (hash_table_[hash % hash_table_.size()] != 0xffff) { - return hash_table_[hash % hash_table_.size()]; - } - hash++; - } - return 0; - } - uint32_t count() const { int cnt = 0; for (uint32_t i = 0; i < mbr_list_.size(); i++) { @@ -1431,12 +1421,21 @@ class CompositeNH : public NextHop { const VrfEntry* vrf() const { return vrf_.get(); } - uint32_t hash(uint32_t seed) const { + uint32_t PickMember(uint32_t seed, const NextHop *affinity_nh) const { + uint32_t idx = kInvalidComponentNHIdx; size_t size = component_nh_list_.size(); if (size == 0) { - return kInvalidComponentNHIdx; + return idx; } - uint32_t idx = seed % size; + + if (affinity_nh != NULL) { + ComponentNH comp_nh(0, affinity_nh); + if (GetIndex(comp_nh, idx)) { + return idx; + } + } + + idx = seed % size; while (component_nh_list_[idx].get() == NULL || component_nh_list_[idx]->nh() == NULL || component_nh_list_[idx]->nh()->IsActive() == false) { diff --git a/src/vnsw/agent/pkt/flow_entry.h b/src/vnsw/agent/pkt/flow_entry.h index 493203d46e7..e8a24b79635 100644 --- a/src/vnsw/agent/pkt/flow_entry.h +++ b/src/vnsw/agent/pkt/flow_entry.h @@ -656,6 +656,8 @@ class FlowEntry { void set_flow_mgmt_info(FlowEntryInfo *info) { flow_mgmt_info_.reset(info); } + bool IsReverseFlow() const { return is_flags_set(FlowEntry::ReverseFlow); } + bool IsForwardFlow() const { return !is_flags_set(FlowEntry::ReverseFlow); } private: friend class FlowTable; friend class FlowEntryFreeList; diff --git a/src/vnsw/agent/pkt/pkt_flow_info.cc b/src/vnsw/agent/pkt/pkt_flow_info.cc index da240f2a376..2318aff8eca 100644 --- a/src/vnsw/agent/pkt/pkt_flow_info.cc +++ b/src/vnsw/agent/pkt/pkt_flow_info.cc @@ -216,8 +216,9 @@ static bool NhDecode(const NextHop *nh, const PktInfo *pkt, PktFlowInfo *info, if (info->out_component_nh_idx == CompositeNH::kInvalidComponentNHIdx || (comp_nh->GetNH(info->out_component_nh_idx) == NULL)) { - info->out_component_nh_idx = comp_nh->hash(pkt-> - hash(ecmp_load_balance)); + info->out_component_nh_idx = comp_nh->PickMember + (pkt->hash(ecmp_load_balance), + info->ecmp_component_affinity_nh); } nh = comp_nh->GetNH(info->out_component_nh_idx); // TODO: Should we re-hash here? @@ -1357,9 +1358,9 @@ void PktFlowInfo::EgressProcess(const PktInfo *pkt, PktControlInfo *in, if (out->rt_) { if (ecmp && out->rt_->GetActivePath()) { const CompositeNH *comp_nh = static_cast(nh); - out_component_nh_idx = comp_nh->hash(pkt-> - hash(out->rt_->GetActivePath()-> - ecmp_load_balance())); + out_component_nh_idx = comp_nh->PickMember + (pkt->hash(out->rt_->GetActivePath()->ecmp_load_balance()), + ecmp_component_affinity_nh); } if (out->rt_->GetActiveNextHop()->GetType() == NextHop::ARP || out->rt_->GetActiveNextHop()->GetType() == NextHop::RESOLVE) { @@ -1672,6 +1673,32 @@ void PktFlowInfo::UpdateEvictedFlowStats(const PktInfo *pkt) { } } +// We want to retain forward and reverse flow semantics when flows are +// being processed due to revaluation or ECMP resolution +// +// If the flow corresponding to the request is already present as reverse flow, +// swap the flows being processed +static bool ShouldSwapFlows(const PktFlowInfo *info, const PktInfo *pkt, + const FlowEntry *flow) { + if (flow == NULL) + return false; + + if (info->short_flow) { + return false; + } + + // If this is message processing, then retain forward and reverse flows + if (pkt->type == PktType::MESSAGE) { + return flow->IsReverseFlow(); + } + + if (pkt->agent_hdr.cmd == AgentHdr::TRAP_ECMP_RESOLVE) { + return flow->IsReverseFlow(); + } + + return false; +} + void PktFlowInfo::Add(const PktInfo *pkt, PktControlInfo *in, PktControlInfo *out) { bool update = false; @@ -1730,9 +1757,9 @@ void PktFlowInfo::Add(const PktInfo *pkt, PktControlInfo *in, } bool swap_flows = false; - // If this is message processing, then retain forward and reverse flows - if (pkt->type == PktType::MESSAGE && !short_flow && - flow_entry->is_flags_set(FlowEntry::ReverseFlow)) { + // If this is message processing or ECMP resolution, then retain forward + // and reverse flows + if (ShouldSwapFlows(this, pkt, flow_entry)) { // for cases where we need to swap flows rflow should always // be Non-NULL assert(rflow != NULL); @@ -1826,6 +1853,62 @@ void PktFlowInfo::UpdateFipStatsInfo } } +// Flow changing from Non-ECMP to ECMP. +// If flow-trapped is forward flow, +// - If this was originally a L2-Flow +// The source transitioned from L2 to L3 Flow. This is unexpected. +// Set ECMP-Index to 0 +// - If this was originally a L3-Flow +// Route transitioned from Non-ECMP to ECMP. The NH used in Non-ECMP +// state is added as first member of ECMP-NH. +// Set the ECMP-Index to 0 +// If flow-trapped is reverse flow, +// - If this was originally a L2-Flow +// We must send packet to originator of the old flow. The forward flow +// will contain originator info. +// - If old flow received from fabric, tunnel-info in forward flow +// will have source-ip of originator +// - If old flow received from VM, NH in flow-key is the originator VM +// - If this was originally a L3-Flow +// Route transitioned from Non-ECMP to ECMP. The NH used in Non-ECMP +// state is added as first member of ECMP-NH. +// Set the ECMP-Index to 0 +void PktFlowInfo::GetEcmpCompositeAffinityNh() { + // Pick the first member in ECMP by default + out_component_nh_idx = 0; + if (flow_entry->IsForwardFlow()) + return; + + // Get reverse-flow. We will try to setup ECMP member such that packet is + // forwarded to origin of reverse flow + FlowEntry *fwd_flow = flow_entry->reverse_flow_entry(); + if (fwd_flow == NULL) + return; + + // Affinity-nh is needed only trapped flow is l2-flow + if (flow_entry->l3_flow()) + return; + + NextHopTable *nh_table = flow_table->agent()->nexthop_table(); + if (fwd_flow->is_flags_set(FlowEntry::IngressDir)) { + // Original packet from VM. Get affnity-nh from flow-key + ecmp_component_affinity_nh = + dynamic_cast(nh_table->FindNextHop(fwd_flow->key().nh)); + } else { + // Original packet from fabric. Get affinity-nh from tunnel-info + Ip4Address tunnel_dest(fwd_flow->data().tunnel_info.ip_saddr); + TunnelNHKey key(flow_table->agent()->fabric_vrf_name(), + flow_table->agent()->router_id(), tunnel_dest, + false, fwd_flow->data().tunnel_info.type); + ecmp_component_affinity_nh = + dynamic_cast(nh_table->Find(&key, false)); + } + + if (ecmp_component_affinity_nh != NULL) { + out_component_nh_idx = CompositeNH::kInvalidComponentNHIdx; + } +} + //If a packet is trapped for ecmp resolve, dp might have already //overwritten original packet(NAT case), hence get actual packet by //overwritting packet with data in flow entry. @@ -1845,8 +1928,8 @@ void PktFlowInfo::RewritePktInfo(uint32_t flow_index) { return; } - FlowEntry *flow = flow_table->Find(key); - if (!flow) { + flow_entry = flow_table->Find(key); + if (!flow_entry) { std::ostringstream ostr; ostr << "ECMP Resolve: unable to find flow index " << flow_index; PKTFLOW_TRACE(Err,ostr.str()); @@ -1858,16 +1941,18 @@ void PktFlowInfo::RewritePktInfo(uint32_t flow_index) { pkt->ip_proto = key.protocol; pkt->sport = key.src_port; pkt->dport = key.dst_port; - pkt->agent_hdr.vrf = flow->data().vrf; - pkt->vrf = flow->data().vrf; + pkt->agent_hdr.vrf = flow_entry->data().vrf; + pkt->vrf = flow_entry->data().vrf; pkt->agent_hdr.nh = key.nh; // If component_nh_idx is not set, assume that NH transitioned from - // Non ECMP to ECMP. The old Non-ECMP NH would always be placed at index 0 - // in this case. So, set ECMP index 0 in this case - if (flow->data().component_nh_idx == CompositeNH::kInvalidComponentNHIdx) { - out_component_nh_idx = 0; + // Non ECMP to ECMP. Set the ecmp_component_affinity_nh so that ECMP member + // computation is set to it + ecmp_component_affinity_nh = NULL; + if (flow_entry->data().component_nh_idx == + CompositeNH::kInvalidComponentNHIdx) { + GetEcmpCompositeAffinityNh(); } else { - out_component_nh_idx = flow->data().component_nh_idx; + out_component_nh_idx = flow_entry->data().component_nh_idx; } return; } diff --git a/src/vnsw/agent/pkt/pkt_flow_info.h b/src/vnsw/agent/pkt/pkt_flow_info.h index 4f5db8a68a6..c9455e56c43 100644 --- a/src/vnsw/agent/pkt/pkt_flow_info.h +++ b/src/vnsw/agent/pkt/pkt_flow_info.h @@ -20,7 +20,7 @@ typedef map FlowRouteRefMap; struct PktControlInfo { PktControlInfo() : vrf_(NULL), intf_(NULL), rt_(NULL), vn_(NULL), vm_(NULL), - vlan_nh_(false), vlan_tag_(0) { } + vlan_nh_(false), vlan_tag_(0), nh_(0) { } virtual ~PktControlInfo() { } const VrfEntry *vrf_; @@ -54,7 +54,7 @@ class PktFlowInfo { trap_rev_flow(false), fip_snat(false), fip_dnat(false), snat_fip(), short_flow_reason(0), peer_vrouter(), tunnel_type(TunnelType::INVALID), flood_unknown_unicast(false), bgp_router_service_flow(false), - alias_ip_flow(false), ttl(0) { + alias_ip_flow(false), ttl(0), ecmp_component_affinity_nh(NULL) { } static bool ComputeDirection(const Interface *intf); @@ -84,6 +84,7 @@ class PktFlowInfo { const VnEntry *vn, MatchPolicy *m_policy); void RewritePktInfo(uint32_t index); + void GetEcmpCompositeAffinityNh(); bool VrfTranslate(const PktInfo *pkt, PktControlInfo *ctrl, PktControlInfo *rev_flow, const IpAddress &src_ip, bool nat_flow); @@ -181,7 +182,7 @@ class PktFlowInfo { std::string peer_vrouter; TunnelType tunnel_type; - // flow entry obtained from flow IPC, which requires recomputation. + // flow entry being revaluated or trapped for ECMP resolution FlowEntry *flow_entry; bool flood_unknown_unicast; @@ -192,6 +193,13 @@ class PktFlowInfo { bool alias_ip_flow; //TTL of nat'd flow especially bgp-service flows uint8_t ttl; + + // Affinity to Ecmp component NH. + // When a packet is trapped for ECMP Resolution its possible that flow is + // transition from Non-ECMP to ECMP. In that case, the ECMP index must be + // be set to unicast-nh used when flow is non-ECMP. The affinity-nh + // is set in this case. + const NextHop *ecmp_component_affinity_nh; }; #endif // __agent_pkt_flow_info_h_ diff --git a/src/vnsw/agent/pkt/test/test_ecmp.cc b/src/vnsw/agent/pkt/test/test_ecmp.cc index 6870f358eed..d0cc8b40fb2 100644 --- a/src/vnsw/agent/pkt/test/test_ecmp.cc +++ b/src/vnsw/agent/pkt/test/test_ecmp.cc @@ -226,12 +226,30 @@ class EcmpTest : public ::testing::Test { ControllerVmRoute::MakeControllerVmRoute(bgp_peer, agent_->fabric_vrf_name(), agent_->router_id(), vrf_name, addr, TunnelType::GREType(), 16, - vn_list, SecurityGroupList(), - PathPreference(), false, EcmpLoadBalance()); + vn_list, SecurityGroupList(), PathPreference(), + false, EcmpLoadBalance()); InetUnicastAgentRouteTable::AddRemoteVmRouteReq(bgp_peer, vrf_name, addr, plen, data); } + void AddRemoteEvpnVmRoute(const string &vrf_name, const string &mac, + uint32_t label, const string &vn, + const char *nh_ip) { + const Ip4Address nh_addr = Ip4Address::from_string(nh_ip); + VnListType vn_list; + vn_list.insert(vn); + ControllerVmRoute *data = ControllerVmRoute::MakeControllerVmRoute + (bgp_peer, agent_->fabric_vrf_name(), agent_->router_id(), + vrf_name, nh_addr, TunnelType::GREType(), label, vn_list, + SecurityGroupList(), PathPreference(), false, EcmpLoadBalance()); + + EvpnAgentRouteTable *rt_table = static_cast + (agent_->vrf_table()->GetEvpnRouteTable(vrf_name)); + rt_table->AddRemoteVmRouteReq(bgp_peer, vrf_name, + MacAddress::FromString(mac), Ip4Address(), + 0, data); + } + void DeleteRemoteRoute(const string vrf_name, const string ip, uint32_t plen) { Ip4Address server_ip = Ip4Address::from_string(ip); @@ -239,6 +257,13 @@ class EcmpTest : public ::testing::Test { vrf_name, server_ip, plen, new ControllerVmRoute(bgp_peer)); } + void DeleteRemoteEvpnRoute(const string &vrf_name, const string &mac) { + agent_->fabric_evpn_table()->DeleteReq(bgp_peer, vrf_name, + MacAddress::FromString(mac), + Ip4Address(), 0, + new ControllerVmRoute(bgp_peer)); + } + uint32_t eth_intf_id_; Ip4Address remote_vm_ip1_; Ip4Address remote_vm_ip2_; @@ -2374,6 +2399,127 @@ TEST_F(EcmpTest, VgwFlag) { WAIT_FOR(1000, 1000, (get_flow_proto()->FlowCount() == 0)); } +// Test that flow direction is not changed based on packet trapped for +// ECMP resolution +TEST_F(EcmpTest, FlowDir_Fwd_Rev_1) { + // Create ECMP route for address reachable on fabric + ComponentNHKeyList local_comp_nh; + AddRemoteEcmpRoute("vrf2", "20.1.1.0", 24, "vn2", 2, local_comp_nh); + client->WaitForIdle(); + AddRemoteEvpnVmRoute("vrf2", "00:00:00:10:00:01", 100, "vn2", "10.10.10.2"); + client->WaitForIdle(); + + VmInterface *vmi = static_cast(VmPortGet(1)); + TxIpMplsPacket(eth_intf_id_, "10.10.10.10", + agent_->router_id().to_string().c_str(), + vmi->label(), "20.1.1.1", "1.1.1.1", 1); + client->WaitForIdle(); + + // Validate forward flow is not ECMP + FlowEntry *entry = FlowGet(VrfGet("vrf2")->vrf_id(), + "20.1.1.1", "1.1.1.1", 1, 0, 0, + GetFlowKeyNH(1)); + EXPECT_TRUE(entry != NULL); + EXPECT_TRUE(entry->data().component_nh_idx = + CompositeNH::kInvalidComponentNHIdx); + EXPECT_TRUE(entry->IsForwardFlow()); + + // Validate reverse flow is ECMP + FlowEntry *rev_entry = entry->reverse_flow_entry(); + EXPECT_TRUE(rev_entry->data().component_nh_idx != + CompositeNH::kInvalidComponentNHIdx); + EXPECT_TRUE(rev_entry->IsReverseFlow()); + + // Trap reverse flow for ECMP resolution + TxIpPacketEcmp(VmPortGetId(1), "1.1.1.1", "20.1.1.1", 1); + client->WaitForIdle(); + + // Ensure no new flows are added because of ECMP resolution + WAIT_FOR(1000, 1000, (get_flow_proto()->FlowCount() == 2)); + + // Validate forward/reverse flow flags are not modified + EXPECT_TRUE(entry->IsForwardFlow()); + EXPECT_TRUE(rev_entry->IsReverseFlow()); + + DeleteRemoteRoute("vrf2", "20.1.1.0", 24); +} + +// Source IP is in ECMP +// Destination IP is non-ECMP +// Destination receives a L2 Flow +// Destination replies with L3 Flow +// The old-reverse flow must be stitched to use right ECMP index so that it +// reaches right compute-node +// +// FIXME : The test is not complete. For packet trapped with ECMP_RESOLVE, +// flow code tried to get flow-key from mapped flow-memory. +// This API failsin UT. So, the test is not really complete +TEST_F(EcmpTest, L2ToL3_1) { + uint8_t nh_count = 4; + // Create an ECMP flow from fabric + ComponentNHKeyList local_comp_nh; + AddRemoteEcmpRoute("vrf2", "20.1.1.0", 24, "vn2", nh_count, local_comp_nh); + client->WaitForIdle(); + + int remote_server_ip = 0x0A0A0A0A; + Ip4Address ip_list[nh_count]; + MacAddress mac_list[nh_count]; + + for (uint32_t i = 0; i < nh_count; i++) { + ip_list[i] = Ip4Address(remote_server_ip + i); + mac_list[i] = MacAddress(0x0, 0x0, 0x0, 0x10, 0x0, i); + AddRemoteEvpnVmRoute("vrf2", mac_list[i].ToString().c_str(), 100+i, + "vn2", ip_list[0].to_string().c_str()); + } + client->WaitForIdle(); + + uint32_t flow_nh_count[nh_count]; + for (uint32_t i = 0; i < nh_count; i++) { + flow_nh_count[i] = 0; + } + + // Add flows from each of the tunnel source and validate that flow + // stickiness is maintained even in case of ECMP revaluation + for (uint32_t i = 0; i < nh_count; i++) { + VmInterface *vmi = static_cast(VmPortGet(1)); + Ip4Address dest = Ip4Address(0x14010101 + i); + TxL2IpMplsPacket(eth_intf_id_, ip_list[i].to_string().c_str(), + agent_->router_id().to_string().c_str(), + vmi->l2_label(), mac_list[i].ToString().c_str(), + vmi->vm_mac().ToString().c_str(), + dest.to_string().c_str(), "1.1.1.1", 1); + client->WaitForIdle(); + + FlowEntry *entry = FlowGet(VrfGet("vrf2")->vrf_id(), + dest.to_string().c_str(), "1.1.1.1", 1, 0, 0, + GetFlowKeyNH(1)); + EXPECT_TRUE(entry != NULL); + EXPECT_TRUE(entry->data().component_nh_idx = + CompositeNH::kInvalidComponentNHIdx); + + // Reverse flow is no ECMP + FlowEntry *rev_entry = entry->reverse_flow_entry(); + EXPECT_TRUE(rev_entry->data().component_nh_idx == + CompositeNH::kInvalidComponentNHIdx); + + TxIpPacketEcmp(VmPortGetId(1), "1.1.1.1", dest.to_string().c_str(), 1); + client->WaitForIdle(); + + EXPECT_TRUE(rev_entry->data().component_nh_idx != + CompositeNH::kInvalidComponentNHIdx); + flow_nh_count[rev_entry->data().component_nh_idx]++; + } + + for (uint32_t i = 0; i < nh_count; i++) { + EXPECT_EQ(1, flow_nh_count[i]); + } + // Cleanup + DeleteRemoteRoute("vrf2", "20.1.1.0", 24); + for (uint32_t i = 0; i < nh_count; i++) { + DeleteRemoteEvpnRoute("vrf2", mac_list[i].ToString().c_str()); + } +} + int main(int argc, char *argv[]) { GETUSERARGS(); client = TestInit(init_file, ksync_init, true, true, true, 100*1000); diff --git a/src/vnsw/agent/pkt/test/test_pkt_util.cc b/src/vnsw/agent/pkt/test/test_pkt_util.cc index 0410496f95c..cf21b439b70 100644 --- a/src/vnsw/agent/pkt/test/test_pkt_util.cc +++ b/src/vnsw/agent/pkt/test/test_pkt_util.cc @@ -126,14 +126,21 @@ void TxTcpPacket(int ifindex, const char *sip, const char *dip, void MakeIpMplsPacket(PktGen *pkt, int ifindex, const char *out_sip, const char *out_dip, uint32_t label, const char *sip, const char *dip, uint8_t proto, - int hash_id) { + int hash_id, const char *smac, const char *dmac, + bool ecmp_resolve) { pkt->AddEthHdr("00:00:00:00:00:01", "00:00:00:00:00:02", 0x800); - pkt->AddAgentHdr(ifindex, AgentHdr::TRAP_FLOW_MISS, hash_id, MplsToVrfId(label), - label); + int cmd = AgentHdr::TRAP_FLOW_MISS; + if (ecmp_resolve) + cmd = AgentHdr::TRAP_ECMP_RESOLVE; + + pkt->AddAgentHdr(ifindex, cmd, hash_id, MplsToVrfId(label), label); pkt->AddEthHdr("00:00:5E:00:01:00", "00:00:00:00:00:01", 0x800); pkt->AddIpHdr(out_sip, out_dip, IPPROTO_GRE); pkt->AddGreHdr(); pkt->AddMplsHdr(label, true); + if (smac != NULL && dmac != NULL) { + pkt->AddEthHdr(dmac, smac, 0x800); + } pkt->AddIpHdr(sip, dip, proto); if (proto == 1) { pkt->AddIcmpHdr(); @@ -143,10 +150,24 @@ void MakeIpMplsPacket(PktGen *pkt, int ifindex, const char *out_sip, void TxIpMplsPacket(int ifindex, const char *out_sip, const char *out_dip, uint32_t label, const char *sip, const char *dip, uint8_t proto, - int hash_id) { + int hash_id, bool ecmp_resolve) { + PktGen *pkt = new PktGen(); + MakeIpMplsPacket(pkt, ifindex, out_sip, out_dip, label, sip, dip, proto, + hash_id, NULL, NULL, ecmp_resolve); + uint8_t *ptr(new uint8_t[pkt->GetBuffLen()]); + memcpy(ptr, pkt->GetBuff(), pkt->GetBuffLen()); + client->agent_init()->pkt0()->ProcessFlowPacket(ptr, pkt->GetBuffLen(), + pkt->GetBuffLen()); + delete pkt; +} + +void TxL2IpMplsPacket(int ifindex, const char *out_sip, const char *out_dip, + uint32_t label, const char *smac, const char *dmac, + const char *sip, const char *dip, uint8_t proto, + bool ecmp_resolve) { PktGen *pkt = new PktGen(); MakeIpMplsPacket(pkt, ifindex, out_sip, out_dip, label, sip, dip, proto, - hash_id); + 0, smac, dmac, ecmp_resolve); uint8_t *ptr(new uint8_t[pkt->GetBuffLen()]); memcpy(ptr, pkt->GetBuff(), pkt->GetBuffLen()); client->agent_init()->pkt0()->ProcessFlowPacket(ptr, pkt->GetBuffLen(), diff --git a/src/vnsw/agent/pkt/test/test_pkt_util.h b/src/vnsw/agent/pkt/test/test_pkt_util.h index bbeec57fba6..c67d60471b3 100644 --- a/src/vnsw/agent/pkt/test/test_pkt_util.h +++ b/src/vnsw/agent/pkt/test/test_pkt_util.h @@ -42,13 +42,21 @@ extern void TxTcpPacket(int ifindex, const char *sip, const char *dip, uint32_t vrf_id = -1, int ttl = 0); extern void MakeIpMplsPacket(PktGen *pkt, int ifindex, const char *out_sip, - const char *out_dip, uint32_t label, - const char *sip, const char *dip, uint8_t proto, - int hash_id); + const char *out_dip, uint32_t label, + const char *sip, const char *dip, uint8_t proto, + int hash_id, + const char *smac = "00:00:00:00:00:01", + const char *dmac = "00:00:5E:00:01:00", + bool ecmp_resolve = false); extern void TxIpMplsPacket(int ifindex, const char *out_sip, const char *out_dip, uint32_t label, const char *sip, const char *dip, uint8_t proto, - int hash_id = 1); + int hash_id = 1, bool ecmp_resolve = false); +extern void TxL2IpMplsPacket(int ifindex, const char *out_sip, + const char *out_dip, uint32_t label, + const char *smac, const char *dmac, + const char *sip, const char *dip, uint8_t proto, + bool ecmp_resolve = false); extern void MakeUdpMplsPacket(PktGen *pkt, int ifindex, const char *out_sip, const char *out_dip, uint32_t label, const char *sip, const char *dip, uint16_t sport, diff --git a/src/vnsw/agent/test/pkt_gen.h b/src/vnsw/agent/test/pkt_gen.h index a0eb902f791..1c5f25cb27a 100644 --- a/src/vnsw/agent/test/pkt_gen.h +++ b/src/vnsw/agent/test/pkt_gen.h @@ -410,6 +410,19 @@ class PktGen { Agent::GetInstance()->mpls_table()->FindMplsLabel(label); if (mpls_label) { nh = mpls_label->nexthop()->id(); +#if 0 + const InterfaceNH *intf_nh = dynamic_cast + (mpls_label->nexthop()); + if (intf_nh) { + const VmInterface *vmi = dynamic_cast + (intf_nh->GetInterface()); + if (vmi != NULL) { + if (vmi->flow_key_nh()) { + nh = vmi->flow_key_nh()->id(); + } + } + } +#endif } } else if (vxlan_id > 0) { VxLanId *vxlan =