Skip to content

Commit

Permalink
Transmit V6 Neighbour advertisement on the receiving interface
Browse files Browse the repository at this point in the history
This fix is IPV6 equivalent of
https://review.opencontrail.org/#/c/11506/.

In in-network service instance case, when service scaling
is more than one, all the instances are going to have the
same mac address and IP address. Inet route points to
ECMP composite nexthop but FDB route does not point to ECMP
nexthop. So when neighbour request is received from service VM
Vrouter needs to send response on the incoming interface
rather bridging the reply packet, as FDB route points
to arbitrarly any of the service VM encap L2 nexthop.

After preparing the reply packet,bridge lookup is done
and outgoing interface is compared against ingress interface.
If they are not same, reply packet is transmitted on
ingress interface.

Change-Id: Ib0113227019d7a452541129843813a647d388b36
closes-bug: #1461882
  • Loading branch information
divakardhar committed Oct 18, 2016
1 parent 85ca42b commit d64b773
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 48 deletions.
96 changes: 54 additions & 42 deletions dp-core/vr_datapath.c
Expand Up @@ -193,11 +193,6 @@ vr_arp_proxy(struct vr_arp *sarp, struct vr_packet *pkt,
{
struct vr_eth *eth;
struct vr_arp *arp;
struct vr_forwarding_md fmd_new;
struct vr_interface *vif = pkt->vp_if;
struct vr_route_req rt;
bool vif_tx = false;
struct vr_nexthop *nh;

eth = (struct vr_eth *)pkt_push(pkt, sizeof(*eth));
if (!eth) {
Expand All @@ -220,44 +215,8 @@ vr_arp_proxy(struct vr_arp *sarp, struct vr_packet *pkt,
memcpy(&arp->arp_dpa, &sarp->arp_spa, sizeof(sarp->arp_spa));
memcpy(&arp->arp_spa, &sarp->arp_dpa, sizeof(sarp->arp_dpa));

vr_init_forwarding_md(&fmd_new);
fmd_new.fmd_dvrf = fmd->fmd_dvrf;
vr_pkt_type(pkt, 0, &fmd_new);

/*
* XXX: for vcp ports, there won't be bridge table entries. to avoid
* doing vr_bridge_input, we check for the flag NO_ARP_PROXY and
* and if set, directly send out on that interface
*/


if (vif_is_vhost(vif) ||
(vif->vif_flags & VIF_FLAG_NO_ARP_PROXY)) {
vif_tx = true;
} else {

rt.rtr_req.rtr_label_flags = 0;
rt.rtr_req.rtr_index = VR_BE_INVALID_INDEX;
rt.rtr_req.rtr_mac_size = VR_ETHER_ALEN;
rt.rtr_req.rtr_mac =(int8_t *) arp->arp_dha;
rt.rtr_req.rtr_vrf_id = fmd_new.fmd_dvrf;
nh = vr_bridge_lookup(fmd->fmd_dvrf, &rt);
if (!nh || !(nh->nh_flags & NH_FLAG_VALID)) {
vr_pfree(pkt, VP_DROP_INVALID_NH);
return;
}
if (rt.rtr_req.rtr_label_flags & VR_BE_LABEL_VALID_FLAG)
fmd_new.fmd_label = rt.rtr_req.rtr_label;

if (vif_is_virtual(vif) && (nh->nh_dev != vif)) {
vif_tx = true;
}
}
vr_mac_reply_send(pkt, fmd);

if (vif_tx)
vif->vif_tx(vif, pkt, &fmd_new);
else
nh_output(pkt, nh, &fmd_new);
return;
}

Expand Down Expand Up @@ -462,6 +421,59 @@ vif_plug_mac_request(struct vr_interface *vif, struct vr_packet *pkt,
return !handled;
}

void
vr_mac_reply_send(struct vr_packet *pkt, struct vr_forwarding_md *fmd)
{
bool vif_tx = false;
struct vr_forwarding_md fmd_new;
struct vr_route_req rt;
struct vr_nexthop *nh;
struct vr_interface *vif = pkt->vp_if;

vr_init_forwarding_md(&fmd_new);
fmd_new.fmd_dvrf = fmd->fmd_dvrf;
vr_pkt_type(pkt, 0, &fmd_new);

/*
* XXX: for vcp ports, there won't be bridge table entries. to avoid
* doing vr_bridge_input, we check for the flag NO_ARP_PROXY and
* and if set, directly send out on that interface
* Incase of service instance with scaling of more than one, reply
* can not be bridged as the destination mac address might point to
* any of the primary/secondary. In this case, reply is forced
* to go on the receiving VIF
*/
if (vif_is_vhost(vif) ||
(vif->vif_flags & VIF_FLAG_NO_ARP_PROXY)) {
vif_tx = true;
} else {
rt.rtr_req.rtr_label_flags = 0;
rt.rtr_req.rtr_index = VR_BE_INVALID_INDEX;
rt.rtr_req.rtr_mac_size = VR_ETHER_ALEN;
rt.rtr_req.rtr_mac = pkt_data(pkt);
rt.rtr_req.rtr_vrf_id = fmd_new.fmd_dvrf;
nh = vr_bridge_lookup(fmd->fmd_dvrf, &rt);
if (!nh || !(nh->nh_flags & NH_FLAG_VALID)) {
vr_pfree(pkt, VP_DROP_INVALID_NH);
return;
}
if (rt.rtr_req.rtr_label_flags & VR_BE_LABEL_VALID_FLAG)
fmd_new.fmd_label = rt.rtr_req.rtr_label;

if (vif_is_virtual(vif) && (nh->nh_dev != vif)) {
vif_tx = true;
}
}

if (vif_tx)
vif->vif_tx(vif, pkt, &fmd_new);
else
nh_output(pkt, nh, &fmd_new);

return;
}


/*
* This funciton parses the ethernet packet and assigns the
* pkt->vp_type, network protocol of the packet. The ethernet header can
Expand Down
7 changes: 1 addition & 6 deletions dp-core/vr_proto_ip6.c
Expand Up @@ -335,7 +335,6 @@ vr_neighbor_proxy(struct vr_packet *pkt, struct vr_forwarding_md *fmd,
struct vr_ip6 *ip6;
struct vr_icmp *icmph;
struct vr_neighbor_option *nopt;
struct vr_interface *vif = pkt->vp_if;


icmph = (struct vr_icmp *)pkt_data(pkt);
Expand Down Expand Up @@ -370,11 +369,7 @@ vr_neighbor_proxy(struct vr_packet *pkt, struct vr_forwarding_md *fmd,
icmph->icmp_csum =
~(vr_icmp6_checksum(ip6, icmph));

if (vif->vif_flags & VIF_FLAG_NO_ARP_PROXY) {
vif->vif_tx(vif, pkt, fmd);
} else {
vr_bridge_input(vif->vif_router, pkt, fmd);
}
vr_mac_reply_send(pkt, fmd);

return;
}
Expand Down
1 change: 1 addition & 0 deletions include/vr_datapath.h
Expand Up @@ -61,6 +61,7 @@ mac_response_t vm_neighbor_request(struct vr_interface *, struct vr_packet *,
extern int vif_plug_mac_request(struct vr_interface *, struct vr_packet *,
struct vr_forwarding_md *);
int vr_gro_input(struct vr_packet *, struct vr_nexthop *);
void vr_mac_reply_send(struct vr_packet *, struct vr_forwarding_md *);



Expand Down

0 comments on commit d64b773

Please sign in to comment.