Skip to content

Commit

Permalink
Respond with stitched MAC for unicast ARP request
Browse files Browse the repository at this point in the history
When an unicast ARP request is received on fabric interface of a compute
node, from BMS behind QFX, if MX is in ecmp, the source IP lookup might
point to subnet route pointing to Ecmp nexthop. This is because there
would not be any host route for BMS in inet table. This results in Vrouter
responding with Vhost mac address though the destination IP address is
stitched. As such this behaviour is to ensure that Routing is forced if
the packet is from Ecmp source, though destination is in same subnet.
But this behaviour creates issues to BMS behind QFX, if BMS refreshes
ARP with unicast ARP request.

As a fix, the multicast ARP requests from Ecmp source on fabric
interface are dropped. If unicast ARP requests and if the destination
mac address of the ethernet packet is stitched mac, the ARP reply is
sent with stitched mac. If destination mac address does not match with
stitched mac, that ARP request is not processed by Vrouter.

Change-Id: I58b91e410ecee809264d8914f75816cfb584ce17
closes-bug: #1594165
  • Loading branch information
divakardhar committed Sep 2, 2016
1 parent 7aaadbd commit fa7c681
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 31 deletions.
73 changes: 58 additions & 15 deletions dp-core/vr_datapath.c
Expand Up @@ -20,14 +20,15 @@ vr_get_proxy_mac(struct vr_packet *pkt, struct vr_forwarding_md *fmd,
struct vr_route_req *rt, unsigned char *dmac)
{
bool from_fabric, stitched, flood;
bool to_gateway, no_proxy, to_vcp;
bool to_gateway, no_proxy, to_vcp, ecmp_src;

unsigned char *resp_mac;
struct vr_nexthop *nh = NULL;
struct vr_interface *vif = pkt->vp_if;
struct vr_vrf_stats *stats;

from_fabric = stitched = flood = to_gateway = to_vcp = no_proxy = false;
from_fabric = stitched = flood = false;
to_gateway = to_vcp = no_proxy = ecmp_src = false;

stats = vr_inet_vrf_stats(fmd->fmd_dvrf, pkt->vp_cpu);
/* here we will not check for stats, but will check before use */
Expand Down Expand Up @@ -65,11 +66,12 @@ vr_get_proxy_mac(struct vr_packet *pkt, struct vr_forwarding_md *fmd,
}
}

/* If ECMP source, we force routing */
if (fmd->fmd_ecmp_src_nh_index != -1) {
resp_mac = vif->vif_mac;
fmd->fmd_ecmp_src_nh_index = -1;
}
/* If ECMP source, we force routing */
if (fmd->fmd_ecmp_src_nh_index != -1) {
resp_mac = vif->vif_mac;
fmd->fmd_ecmp_src_nh_index = -1;
ecmp_src = true;
}


/*
Expand All @@ -87,6 +89,38 @@ vr_get_proxy_mac(struct vr_packet *pkt, struct vr_forwarding_md *fmd,
* . arp request from the uplink port of a vcp
*/
if (from_fabric) {
if (ecmp_src) {

/*
* If a Multicast ARP request, it is not answered on Fabric
* side
*/
if (IS_MAC_BMCAST(dmac))
return MR_DROP;

/*
* If unicast and not stiched, we do not have enough
* information what to respond. We can not even flood,
* probably because this need to be answered with Vrouter
* Mac in source Vrouter itself. So we drop this
*/
if (!stitched)
return MR_DROP;

/*
* If our stiched mac does not match, we will let the VM
* decide what to do with request
*/
if (!VR_MAC_CMP(dmac, rt->rtr_req.rtr_mac))
return MR_FLOOD;

/*
* Very likely response need to go with stiched mac. But
* below conditions might override
*/
resp_mac = rt->rtr_req.rtr_mac;
}

if (flood && !stitched) {
if (stats)
stats->vrf_arp_physical_flood++;
Expand Down Expand Up @@ -229,14 +263,15 @@ vr_arp_proxy(struct vr_arp *sarp, struct vr_packet *pkt,

static int
vr_handle_arp_request(struct vr_arp *sarp, struct vr_packet *pkt,
struct vr_forwarding_md *fmd)
struct vr_forwarding_md *fmd, unsigned char *eth_dmac)
{
bool handled = true;
unsigned char dmac[VR_ETHER_ALEN];
mac_response_t arp_result;

struct vr_packet *pkt_c;
struct vr_interface *vif = pkt->vp_if;
VR_MAC_COPY(dmac, eth_dmac);

arp_result = vif->vif_mac_request(vif, pkt, fmd, dmac);
switch (arp_result) {
Expand Down Expand Up @@ -386,6 +421,7 @@ vif_plug_mac_request(struct vr_interface *vif, struct vr_packet *pkt,
struct vr_forwarding_md *fmd)
{
int nheader, handled = 1;
unsigned char eth_dmac[VR_ETHER_ALEN];

if (pkt->vp_flags & VP_FLAG_MULTICAST)
goto unhandled;
Expand All @@ -394,13 +430,15 @@ vif_plug_mac_request(struct vr_interface *vif, struct vr_packet *pkt,
if (nheader < 0 || (pkt->vp_data + nheader > pkt->vp_end))
goto unhandled;

VR_MAC_COPY(eth_dmac, pkt_data(pkt));

if (pkt->vp_type == VP_TYPE_ARP) {
if (pkt->vp_len < (nheader + sizeof(struct vr_arp)))
goto unhandled;

pkt_pull(pkt, nheader);

handled = vr_arp_input(pkt, fmd);
handled = vr_arp_input(pkt, fmd, eth_dmac);
if (!handled) {
pkt_push(pkt, nheader);
}
Expand All @@ -413,7 +451,7 @@ vif_plug_mac_request(struct vr_interface *vif, struct vr_packet *pkt,

pkt_pull(pkt, nheader);

handled = vr_neighbor_input(pkt, fmd);
handled = vr_neighbor_input(pkt, fmd, eth_dmac);
if (!handled) {
pkt_push(pkt, nheader);
}
Expand Down Expand Up @@ -468,7 +506,8 @@ vr_pkt_type(struct vr_packet *pkt, unsigned short offset,
}

int
vr_arp_input(struct vr_packet *pkt, struct vr_forwarding_md *fmd)
vr_arp_input(struct vr_packet *pkt, struct vr_forwarding_md *fmd,
unsigned char *eth_dmac)
{
int handled = 1;
struct vr_arp sarp;
Expand All @@ -486,7 +525,7 @@ vr_arp_input(struct vr_packet *pkt, struct vr_forwarding_md *fmd)

switch (ntohs(sarp.arp_op)) {
case VR_ARP_OP_REQUEST:
return vr_handle_arp_request(&sarp, pkt, fmd);
return vr_handle_arp_request(&sarp, pkt, fmd, eth_dmac);

case VR_ARP_OP_REPLY:
return vr_handle_arp_reply(&sarp, pkt, fmd);
Expand Down Expand Up @@ -606,6 +645,7 @@ vr_fabric_input(struct vr_interface *vif, struct vr_packet *pkt,
int handled = 0;
unsigned short pull_len;
struct vr_forwarding_md fmd;
unsigned char *data, eth_dmac[VR_ETHER_ALEN];

vr_init_forwarding_md(&fmd);
fmd.fmd_vlan = vlan_id;
Expand All @@ -628,13 +668,16 @@ vr_fabric_input(struct vr_interface *vif, struct vr_packet *pkt,
return vif_xconnect(vif, pkt, &fmd);
}

data = pkt_data(pkt);
pull_len = pkt_get_network_header_off(pkt) - pkt_head_space(pkt);
pkt_pull(pkt, pull_len);

if (pkt->vp_type == VP_TYPE_IP || pkt->vp_type == VP_TYPE_IP6)
if (pkt->vp_type == VP_TYPE_IP || pkt->vp_type == VP_TYPE_IP6) {
handled = vr_l3_input(pkt, &fmd);
else if (pkt->vp_type == VP_TYPE_ARP)
handled = vr_arp_input(pkt, &fmd);
} else if (pkt->vp_type == VP_TYPE_ARP) {
VR_MAC_COPY(eth_dmac, data);
handled = vr_arp_input(pkt, &fmd, eth_dmac);
}

if (!handled) {
pkt_push(pkt, pull_len);
Expand Down
28 changes: 15 additions & 13 deletions dp-core/vr_nexthop.c
Expand Up @@ -281,13 +281,15 @@ static int
nh_l2_rcv(struct vr_packet *pkt, struct vr_nexthop *nh,
struct vr_forwarding_md *fmd)
{
struct vr_vrf_stats *stats;
unsigned char eth_dmac[VR_ETHER_ALEN], *data;
int pull_len, handled = 0;
struct vr_vrf_stats *stats;

stats = vr_inet_vrf_stats(fmd->fmd_dvrf, pkt->vp_cpu);
if (stats)
stats->vrf_l2_receives++;

data = pkt_data(pkt);
fmd->fmd_to_me = 1;
pull_len = pkt_get_network_header_off(pkt) - pkt_head_space(pkt);
if (pkt_pull(pkt, pull_len) < 0) {
Expand All @@ -301,13 +303,15 @@ nh_l2_rcv(struct vr_packet *pkt, struct vr_nexthop *nh,
* generated by Agent for some features
*/
if (pkt->vp_type == VP_TYPE_IP6) {
handled = vr_neighbor_input(pkt, fmd);
VR_MAC_COPY(eth_dmac, data);
handled = vr_neighbor_input(pkt, fmd, eth_dmac);
if (!handled)
handled = vr_l3_input(pkt, fmd);
} else if (pkt->vp_type == VP_TYPE_IP) {
handled = vr_l3_input(pkt, fmd);
} else if (pkt->vp_type == VP_TYPE_ARP) {
handled = vr_arp_input(pkt, fmd);
VR_MAC_COPY(eth_dmac, data);
handled = vr_arp_input(pkt, fmd, eth_dmac);
}

if (!handled)
Expand Down Expand Up @@ -769,16 +773,14 @@ nh_composite_mcast_validate_src(struct vr_packet *pkt, struct vr_nexthop *nh,
}

static int
nh_handle_mcast_control_pkt(struct vr_packet *pkt, struct vr_forwarding_md *fmd,
unsigned int pkt_src, bool *flood_to_vms)
nh_handle_mcast_control_pkt(struct vr_packet *pkt, struct vr_eth *eth,
struct vr_forwarding_md *fmd, unsigned int pkt_src, bool *flood_to_vms)
{
int handled = 1;
bool flood = false;
unsigned char eth_dmac[VR_ETHER_ALEN];
unsigned short trap, rt_flags, drop_reason, pull_len = 0;

l4_pkt_type_t l4_type = L4_TYPE_UNKNOWN;

struct vr_eth *eth;
struct vr_arp *sarp;
struct vr_nexthop *src_nh;
struct vr_ip6 *ip6;
Expand All @@ -791,16 +793,15 @@ nh_handle_mcast_control_pkt(struct vr_packet *pkt, struct vr_forwarding_md *fmd,
if (fmd->fmd_vlan != VLAN_ID_INVALID)
return !handled;

eth = (struct vr_eth *)pkt_data(pkt);

pull_len = pkt_get_network_header_off(pkt) - pkt_head_space(pkt);
if (pkt_pull(pkt, pull_len) < 0) {
drop_reason = VP_DROP_PULL;
goto drop;
}

if (pkt->vp_type == VP_TYPE_ARP) {
handled = vr_arp_input(pkt, fmd);
VR_MAC_COPY(eth_dmac, eth->eth_dmac);
handled = vr_arp_input(pkt, fmd, eth_dmac);
if (handled)
return handled;

Expand Down Expand Up @@ -880,7 +881,8 @@ nh_handle_mcast_control_pkt(struct vr_packet *pkt, struct vr_forwarding_md *fmd,
}

if (l4_type == L4_TYPE_NEIGHBOUR_SOLICITATION) {
handled = vr_neighbor_input(pkt, fmd);
VR_MAC_COPY(eth_dmac, eth->eth_dmac);
handled = vr_neighbor_input(pkt, fmd, eth_dmac);
if (handled)
return handled;

Expand Down Expand Up @@ -966,7 +968,7 @@ nh_composite_mcast_l2(struct vr_packet *pkt, struct vr_nexthop *nh,
goto drop;
}

handled = nh_handle_mcast_control_pkt(pkt, fmd, pkt_src, &flood_to_vms);
handled = nh_handle_mcast_control_pkt(pkt, eth, fmd, pkt_src, &flood_to_vms);
if (handled)
return 0;

Expand Down
5 changes: 4 additions & 1 deletion dp-core/vr_proto_ip6.c
Expand Up @@ -416,7 +416,8 @@ vm_neighbor_request(struct vr_interface *vif, struct vr_packet *pkt,
}

int
vr_neighbor_input(struct vr_packet *pkt, struct vr_forwarding_md *fmd)
vr_neighbor_input(struct vr_packet *pkt, struct vr_forwarding_md *fmd,
unsigned char *eth_dmac)
{
int handled = 1;
uint32_t pull_len, len;
Expand Down Expand Up @@ -465,6 +466,8 @@ vr_neighbor_input(struct vr_packet *pkt, struct vr_forwarding_md *fmd)
if (nopt->vno_type != SOURCE_LINK_LAYER_ADDRESS_OPTION)
goto drop;

VR_MAC_COPY(dmac, eth_dmac);

ndisc_result = vif->vif_mac_request(vif, pkt, fmd, dmac);
switch (ndisc_result) {
case MR_PROXY:
Expand Down
5 changes: 3 additions & 2 deletions include/vr_datapath.h
Expand Up @@ -27,10 +27,11 @@ unsigned int vr_fabric_input(struct vr_interface *, struct vr_packet *,

int vr_l3_input(struct vr_packet *, struct vr_forwarding_md *);
int vr_l2_input(struct vr_packet *, struct vr_forwarding_md *);
int vr_arp_input(struct vr_packet *, struct vr_forwarding_md *);
int vr_arp_input(struct vr_packet *, struct vr_forwarding_md *, unsigned char *);
int vr_ip_input(struct vrouter *, struct vr_packet *,
struct vr_forwarding_md *);
int vr_neighbor_input(struct vr_packet *, struct vr_forwarding_md *);
int vr_neighbor_input(struct vr_packet *, struct vr_forwarding_md *,
unsigned char *);
int vr_ip6_input(struct vrouter *, struct vr_packet *,
struct vr_forwarding_md *);
extern void vr_ip_update_csum(struct vr_packet *, unsigned int, unsigned int);
Expand Down

0 comments on commit fa7c681

Please sign in to comment.