Skip to content

Commit

Permalink
* Try ARP request even when EVPN route is in wait for traffic mode
Browse files Browse the repository at this point in the history
Currently if only EVPN route is in backup mode, GARP packets are
not trapped to agent, hence upon mastership switch agent would
not be able to identify and update EVPN route preference.
Its easily reproducible by changing the group id of VRRP.

Consider VM 1 was configured with group ID 100, but AAP was configured
with AAP vmac of group ID 10, now prefernece of IP route would be
bumped but not EVPN route since mac of GARP packets doesnt match with
AAP configured mac. Now if group ID is changed to 10, VRRP would still
send a GARP but it would not be trapped to agent, since l3 route is
already in high prefernece. Fixing the same by having TRAP flag set even
if EVPN route is in backup mode, also from flow if EVPN route is in low
preference.
Closes-bug:#1644170

Change-Id: I7e9e87f32c453159a56d828bfb16a1dca8627623
  • Loading branch information
naveen-n committed Dec 6, 2016
1 parent f73268a commit 795fde8
Show file tree
Hide file tree
Showing 12 changed files with 684 additions and 83 deletions.
10 changes: 10 additions & 0 deletions src/vnsw/agent/pkt/flow_table.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3369,6 +3369,16 @@ AgentRoute *FlowTable::GetL2Route(const VrfEntry *vrf,
return table->FindRoute(mac);
}

//Find EVPN route
AgentRoute* FlowTable::GetEvpnRoute(const VrfEntry *vrf,
const MacAddress &mac,
const IpAddress &ip,
uint32_t ethernet_tag) {
EvpnAgentRouteTable *table = static_cast<EvpnAgentRouteTable *>(
vrf->GetEvpnRouteTable());
return table->FindRoute(mac, ip, ethernet_tag);
}

AgentRoute *FlowTable::GetUcRoute(const VrfEntry *entry,
const IpAddress &addr) {
AgentRoute *rt = NULL;
Expand Down
2 changes: 2 additions & 0 deletions src/vnsw/agent/pkt/flow_table.h
Original file line number Diff line number Diff line change
Expand Up @@ -720,6 +720,8 @@ class FlowTable {

DBTableBase::ListenerId nh_listener_id();
AgentRoute *GetL2Route(const VrfEntry *entry, const MacAddress &mac);
AgentRoute *GetEvpnRoute(const VrfEntry *entry, const MacAddress &mac,
const IpAddress &addr, uint32_t ethernet_tag);
AgentRoute *GetUcRoute(const VrfEntry *entry, const IpAddress &addr);
static const SecurityGroupList &default_sg_list() {return default_sg_list_;}
bool ValidFlowMove(const FlowEntry *new_flow,
Expand Down
61 changes: 43 additions & 18 deletions src/vnsw/agent/pkt/pkt_flow_info.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1353,6 +1353,48 @@ bool PktFlowInfo::Process(const PktInfo *pkt, PktControlInfo *in,
return true;
}

void PktFlowInfo::EnqueueTrafficSeen(const PktInfo *pkt,
PktControlInfo *in,
PktControlInfo *out) {
if (pkt->family != Address::INET) {
return;
}

Ip4Address v4_src = pkt->ip_saddr.to_v4();
if (short_flow || linklocal_flow || !ingress) {
return;
}

const AgentRoute *rt = NULL;
bool enqueue_traffic_seen = false;
const VmInterface *vm_intf = dynamic_cast<const VmInterface *>(in->intf_);

if (l3_flow) {
rt = in->rt_;
} else if (in->vrf_) {
rt = flow_table->GetUcRoute(in->vrf_, v4_src);
}

if (rt && rt->WaitForTraffic()) {
enqueue_traffic_seen = true;
} else if (vm_intf) {
//L3 route is not in wait for traffic state
//EVPN route could be in wait for traffic, if yes
//enqueue traffic seen
rt = flow_table->GetEvpnRoute(in->vrf_, pkt->smac, v4_src,
vm_intf->ethernet_tag());
if (rt && rt->WaitForTraffic()) {
enqueue_traffic_seen = true;
}
}

if (enqueue_traffic_seen) {
flow_table->agent()->oper_db()->route_preference_module()->
EnqueueTrafficSeen(v4_src, 32, in->intf_->id(),
pkt->vrf, pkt->smac);
}
}

void PktFlowInfo::Add(const PktInfo *pkt, PktControlInfo *in,
PktControlInfo *out) {
FlowKey key(in->nh_, pkt->ip_saddr, pkt->ip_daddr, pkt->ip_proto,
Expand All @@ -1365,24 +1407,7 @@ void PktFlowInfo::Add(const PktInfo *pkt, PktControlInfo *in,
Agent::GetInstance()->pkt()->flow_table()->DeleteFlowInfo(flow.get());
}

if (pkt->family == Address::INET) {
Ip4Address v4_src = pkt->ip_saddr.to_v4();
if (ingress && !short_flow && !linklocal_flow) {
const AgentRoute *rt = NULL;
if (l3_flow) {
rt = in->rt_;
} else if (in->vrf_) {
rt = flow_table->GetUcRoute(in->vrf_, v4_src);
}
if (rt && rt->WaitForTraffic()) {
flow_table->agent()->oper_db()->route_preference_module()->
EnqueueTrafficSeen(v4_src, 32, in->intf_->id(),
pkt->vrf, pkt->smac);
}
}
} else if (pkt->family == Address::INET6) {
//TODO:: Handle Ipv6 changes
}
EnqueueTrafficSeen(pkt, in, out);

// Do not allow more than max flows
if ((in->vm_ &&
Expand Down
3 changes: 3 additions & 0 deletions src/vnsw/agent/pkt/pkt_flow_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ class PktFlowInfo {
const IpAddress &addr, const MacAddress &mac,
FlowRouteRefMap &ref_map);
uint8_t RouteToPrefixLen(const AgentRoute *route);
void EnqueueTrafficSeen(const PktInfo *pkt,
PktControlInfo *in,
PktControlInfo *out);

bool l3_flow;
Address::Family family;
Expand Down
30 changes: 30 additions & 0 deletions src/vnsw/agent/pkt/test/test_pkt_flow.cc
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,7 @@ class FlowTest : public ::testing::Test {
};

bool FlowTest::ksync_init_;

//Ingress flow test (VMport to VMport - Same VN)
//Flow creation using IP and TCP packets
TEST_F(FlowTest, FlowAdd_1) {
Expand Down Expand Up @@ -3853,6 +3854,35 @@ TEST_F(FlowTest, AclRuleUpdate) {
client->WaitForIdle(5);
}

//Create a layer2 flow and verify that we dont add layer2 route
//in prefix length manipulation
TEST_F(FlowTest, WaitForTraffic) {
Ip4Address ip = Ip4Address::from_string(vm1_ip);
MacAddress mac(0, 0, 0, 1, 1, 1);

AgentRoute *ip_rt = RouteGet("vrf5", Ip4Address::from_string(vm1_ip), 32);
AgentRoute *evpn_Rt = EvpnRouteGet("vrf5", mac, ip, 0);

EXPECT_TRUE(ip_rt->WaitForTraffic() == true);
EXPECT_TRUE(evpn_Rt->WaitForTraffic() == true);

//Enqueue a flow with wrong mac address
TxL2Packet(flow0->id(),input[2].mac, input[1].mac,
input[0].addr, input[1].addr, 1);
client->WaitForIdle();
//Only IP route should goto wait for traffic
EXPECT_TRUE(ip_rt->WaitForTraffic() == false);
EXPECT_TRUE(evpn_Rt->WaitForTraffic() == true);

//Enqueue flow with right mac address
//EVPN route should also goto traffic seen state
TxL2Packet(flow0->id(),input[0].mac, input[1].mac,
input[0].addr, input[1].addr, 1);
client->WaitForIdle();
EXPECT_TRUE(ip_rt->WaitForTraffic() == false);
EXPECT_TRUE(evpn_Rt->WaitForTraffic() == false);
}

int main(int argc, char *argv[]) {
GETUSERARGS();

Expand Down

0 comments on commit 795fde8

Please sign in to comment.