From af7e38e0b6b21b3265b8d2ed0bd8a365f66909c9 Mon Sep 17 00:00:00 2001 From: Praveen K V Date: Sat, 11 Jul 2015 17:00:03 +0530 Subject: [PATCH] Handle SIMPLE_GATEWAY interface in NHDecode() NHDecode used in Egress flow processing does not handle SIMPLE_GATEWAY interfaces as of now. As a result, the out->vrf_ field is NULL even after NHDecode() resulting in crash. Modify NHDecode to handle SIMPLE_GATEWAY interface. Change-Id: I2faf73c62fe671f86af17f54dc57ce4e9596c22f Closes-Bug: #1473647 --- src/vnsw/agent/pkt/pkt_flow_info.cc | 20 ++++++- src/vnsw/agent/test/test_cmn_util.h | 6 +++ src/vnsw/agent/test/test_util.cc | 67 ++++++++++++++++++++++++ src/vnsw/agent/vgw/test/test_vgw.cc | 81 +++++++++++++++++++++++++++++ 4 files changed, 172 insertions(+), 2 deletions(-) diff --git a/src/vnsw/agent/pkt/pkt_flow_info.cc b/src/vnsw/agent/pkt/pkt_flow_info.cc index 54fd8bea9da..d427761eeb0 100644 --- a/src/vnsw/agent/pkt/pkt_flow_info.cc +++ b/src/vnsw/agent/pkt/pkt_flow_info.cc @@ -155,6 +155,18 @@ static const NextHop* GetPolicyDisabledNH(const NextHop *nh) { Agent::GetInstance()->nexthop_table()->FindActiveEntry(key.get())); } +static bool IsVgwOrVmInterface(const Interface *intf) { + if (intf->type() == Interface::VM_INTERFACE) + return true; + + if (intf->type() == Interface::INET) { + const InetInterface *inet = static_cast(intf); + if (inet->sub_type() == InetInterface::SIMPLE_GATEWAY) + return true; + } + return false; +} + // Get interface from a NH. Also, decode ECMP information from NH // Responsible to set following fields, // out->nh_ : outgoing Nexthop Index. Will also be used to set reverse flow-key @@ -343,8 +355,7 @@ static bool NhDecode(const NextHop *nh, const PktInfo *pkt, PktFlowInfo *info, if (!out->intf_->IsActive()) { out->intf_ = NULL; ret = false; - } else if (force_vmport && - out->intf_->type() != Interface::VM_INTERFACE) { + } else if (force_vmport && IsVgwOrVmInterface(out->intf_) == false) { out->intf_ = NULL; out->vrf_ = NULL; ret = true; @@ -1120,6 +1131,11 @@ void PktFlowInfo::EgressProcess(const PktInfo *pkt, PktControlInfo *in, l3_flow = true; } } + + if (out->vrf_ == NULL) { + return; + } + UpdateRoute(&out->rt_, out->vrf_, pkt->ip_daddr, pkt->dmac, flow_dest_plen_map); UpdateRoute(&in->rt_, out->vrf_, pkt->ip_saddr, pkt->smac, diff --git a/src/vnsw/agent/test/test_cmn_util.h b/src/vnsw/agent/test/test_cmn_util.h index dacf2b30e35..5ecfa1c970d 100644 --- a/src/vnsw/agent/test/test_cmn_util.h +++ b/src/vnsw/agent/test/test_cmn_util.h @@ -243,6 +243,12 @@ void DelLinkLocalConfig(); void DeleteGlobalVrouterConfig(); void send_icmp(int fd, uint8_t smac, uint8_t dmac, uint32_t sip, uint32_t dip); bool FlowStats(FlowIp *input, int id, uint32_t bytes, uint32_t pkts); +void AddVmPort(const char *vmi, int intf_id, const char *ip, const char *mac, + const char *vrf, const char *vn, int vn_uuid, const char *vm, + int vm_uuid, const char *instance_ip, int instance_uuid); +void DelVmPort(const char *vmi, int intf_id, const char *ip, const char *mac, + const char *vrf, const char *vn, int vn_uuid, const char *vm, + int vm_uuid, const char *instance_ip, int instance_uuid); void DeleteVmportEnv(struct PortInfo *input, int count, int del_vn, int acl_id = 0, const char *vn = NULL, const char *vrf = NULL, bool with_ip = false, bool with_ip6 = false); diff --git a/src/vnsw/agent/test/test_util.cc b/src/vnsw/agent/test/test_util.cc index cd5dfaadd9c..430d71b9c9d 100644 --- a/src/vnsw/agent/test/test_util.cc +++ b/src/vnsw/agent/test/test_util.cc @@ -2058,6 +2058,73 @@ bool FlowStats(FlowIp *input, int id, uint32_t bytes, uint32_t pkts) { return false; } +void AddVmPort(const char *vmi, int intf_id, const char *ip, const char *mac, + const char *vrf, const char *vn, int vn_uuid, const char *vm, + int vm_uuid, const char *instance_ip, int instance_uuid) { + struct PortInfo input[] = { + {"", 0, "", "", 0, 0 } + }; + + strcpy(input[0].name, vmi); + input[0].intf_id = intf_id; + strcpy(input[0].addr, ip); + strcpy(input[0].mac, mac); + input[0].vn_id = vn_uuid; + input[0].vm_id = vm_uuid; + + AddVn(vn, vn_uuid); + AddVrf(vrf); + AddVm(vm, vm_uuid); + AddPort(vmi, intf_id); + AddVmPortVrf(vmi, "", 0); + IntfCfgAdd(input, 0); + AddInstanceIp(instance_ip, instance_uuid, ip); + AddLink("virtual-machine-interface", vmi, "virtual-network", vn); + AddLink("virtual-network", vn, "routing-instance", vrf); + AddLink("virtual-machine", vm, "virtual-machine-interface", vmi); + AddLink("virtual-machine-interface-routing-instance", vmi, + "routing-instance", vrf); + AddLink("virtual-machine-interface-routing-instance", vmi, + "virtual-machine-interface", vmi); + AddLink("virtual-machine-interface", vmi, "instance-ip", instance_ip); + client->WaitForIdle(); +} + +void DelVmPort(const char *vmi, int intf_id, const char *ip, const char *mac, + const char *vrf, const char *vn, int vn_uuid, const char *vm, + int vm_uuid, const char *instance_ip, int instance_uuid) { + struct PortInfo input[] = { + {"", 0, "", "", 0, 0 } + }; + + strcpy(input[0].name, vmi); + input[0].intf_id = intf_id; + strcpy(input[0].addr, ip); + strcpy(input[0].mac, mac); + input[0].vn_id = vn_uuid; + input[0].vm_id = vm_uuid; + + DelLink("virtual-machine-interface", vmi, "virtual-network", vm); + DelLink("virtual-network", vn, "routing-instance", vrf); + DelLink("virtual-machine", vm, "virtual-machine-interface", vmi); + DelLink("virtual-machine-interface-routing-instance", vmi, + "routing-instance", vrf); + DelLink("virtual-machine-interface-routing-instance", vmi, + "virtual-machine-interface", vmi); + DelLink("virtual-machine-interface", vmi, + "instance-ip", instance_ip); + DelVn(vn); + DelVrf(vrf); + DelVm(vm); + DelPort(vmi); + DelVmPortVrf(vmi); + DelInstanceIp(instance_ip); + IntfCfgDel(input, 0); + DelNode("virtual-machine-interface", vmi); + DelNode("virtual-machine-interface-routing-instance", vmi); + client->WaitForIdle(); +} + void DeleteVmportFIpEnv(struct PortInfo *input, int count, int del_vn, int acl_id, const char *vn, const char *vrf) { char vn_name[80]; diff --git a/src/vnsw/agent/vgw/test/test_vgw.cc b/src/vnsw/agent/vgw/test/test_vgw.cc index 4d6cb469ce1..adfec593478 100644 --- a/src/vnsw/agent/vgw/test/test_vgw.cc +++ b/src/vnsw/agent/vgw/test/test_vgw.cc @@ -11,6 +11,7 @@ #include "vgw/cfg_vgw.h" #include "vgw/vgw.h" #include "oper/mpls.h" +#include "pkt/test/test_flow_util.h" namespace opt = boost::program_options; @@ -20,6 +21,7 @@ void RouterIdDepInit(Agent *agent) { class VgwTest : public ::testing::Test { public: virtual void SetUp() { + agent_ = Agent::GetInstance(); } virtual void TearDown() { @@ -27,6 +29,7 @@ class VgwTest : public ::testing::Test { opt::options_description desc; opt::variables_map var_map; + Agent *agent_; }; TEST_F(VgwTest, conf_file_1) { @@ -248,6 +251,84 @@ TEST_F(VgwTest, RouteResync) { ValidateVgwInterface(route, "vgw"); } +TEST_F(VgwTest, IngressFlow_1) { + AddVmPort("vnet2", 2, "2.2.2.3", "00:00:02:02:02:03", + "default-domain:admin:public:public", + "default-domain:admin:public", 2, "vm2", 2, "instance-ip-2", 2); + WAIT_FOR(1000, 100, (VmPortFind(2) == true)); + VmInterface *vmi = static_cast(VmPortGet(2)); + EXPECT_TRUE(vmi != NULL); + + const InetInterface *gw = InetInterfaceGet("vgw"); + EXPECT_TRUE(gw != NULL); + if (gw == NULL) + return; + TestFlow flow[] = { + { + TestFlowPkt(Address::INET, "2.2.2.2", "100.100.100.100", 1, 0, 0, + "default-domain:admin:public:public", vmi->id()), + }, + }; + CreateFlow(flow, 1); + client->WaitForIdle(); + + FlowEntry *fe = FlowGet(vmi->vrf_id(), "2.2.2.2", "100.100.100.100", + 1, 0, 0, vmi->flow_key_nh()->id()); + EXPECT_TRUE(fe != NULL); + + DeleteFlow(flow, 1); + client->WaitForIdle(); + WAIT_FOR(1000, 100, (agent_->pkt()->flow_table()->Size() == 0)); + + DelVmPort("vnet2", 2, "2.2.2.3", "00:00:02:02:02:03", + "default-domain:admin:public:public", + "default-domain:admin:public", 2, "vm2", 2, "instance-ip-2", 2); + client->WaitForIdle(); + + EXPECT_FALSE(VmPortFind(2)); + WAIT_FOR(1000, 100, (VmPortFind(2) == false)); +} + +TEST_F(VgwTest, EgressFlow_1) { + AddVmPort("vnet2", 2, "2.2.2.3", "00:00:02:02:02:03", + "default-domain:admin:public:public", + "default-domain:admin:public", 2, "vm2", 2, "instance-ip-2", 2); + WAIT_FOR(1000, 100, (VmPortFind(2) == true)); + VmInterface *vmi = static_cast(VmPortGet(2)); + EXPECT_TRUE(vmi != NULL); + + const InetInterface *gw = InetInterfaceGet("vgw"); + EXPECT_TRUE(gw != NULL); + if (gw == NULL) + return; + TestFlow flow[] = { + { + TestFlowPkt(Address::INET, "100.100.100.100", "2.2.2.2", 1, 0, 0, + "default-domain:admin:public:public", "20.20.20.20", + gw->label()), + }, + }; + CreateFlow(flow, 1); + client->WaitForIdle(); + + MplsLabel *label = GetActiveLabel(MplsLabel::VPORT_NH, gw->label()); + FlowEntry *fe = FlowGet(vmi->vrf_id(), "100.100.100.100", "2.2.2.2", + 1, 0, 0, label->nexthop()->id()); + EXPECT_TRUE(fe != NULL); + + DeleteFlow(flow, 1); + client->WaitForIdle(); + WAIT_FOR(1000, 100, (agent_->pkt()->flow_table()->Size() == 0)); + + DelVmPort("vnet2", 2, "2.2.2.3", "00:00:02:02:02:03", + "default-domain:admin:public:public", + "default-domain:admin:public", 2, "vm2", 2, "instance-ip-2", 2); + client->WaitForIdle(); + + EXPECT_FALSE(VmPortFind(2)); + WAIT_FOR(1000, 100, (VmPortFind(2) == false)); +} + int main(int argc, char **argv) { GETUSERARGS();