From 5bdd3992309ef8cf138fff1b5af8332849a7959f Mon Sep 17 00:00:00 2001 From: Divakar D Date: Sat, 8 Oct 2016 19:25:38 +0530 Subject: [PATCH] Transmit V6 Neighbour advertisement on the receiving interface 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 Disable the flow processing for Neighbour Advertisements The neighbour request packets are typically Multicast packets and there is no flow processing for these. When a neighbour request is converted to neighbour advertisement, we continue to use the same packet buffer and same packet flags for this advertisement too. This ends up in not creating a flow for neighbour advertisement too as the original packet is marked as multicast packet. But the fix we gave https://review.opencontrail.org/#/c/24973/ for bug: #1461882 for V6 resulted in creating new packet flags for advertisement and this is resulting in flow being created. The flow processing is dropping the response as the neighbour advertisement should have ideally come from different interface. We can fix this issue either by manipulating the source interface to match the interface on which neighbour is falling so that flow processing succeeds or by disabling the flow processing for advertisements. The fix now disables the flow processing for advertisements Change-Id: Ic91f0fb794c13912e43d8c96c726bd80e559b7fb closes-bug: #1635931 --- dp-core/vr_datapath.c | 99 ++++++++++++++++++++++++------------------ dp-core/vr_proto_ip6.c | 7 +-- include/vr_datapath.h | 1 + 3 files changed, 59 insertions(+), 48 deletions(-) diff --git a/dp-core/vr_datapath.c b/dp-core/vr_datapath.c index 06192c34f..2579be107 100644 --- a/dp-core/vr_datapath.c +++ b/dp-core/vr_datapath.c @@ -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) { @@ -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; } @@ -462,6 +421,62 @@ 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); + + /* Disable the flow processing for response packets */ + pkt->vp_flags |= VP_FLAG_FLOW_SET; + + /* + * 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 diff --git a/dp-core/vr_proto_ip6.c b/dp-core/vr_proto_ip6.c index e8cf2e58f..f07e689e0 100644 --- a/dp-core/vr_proto_ip6.c +++ b/dp-core/vr_proto_ip6.c @@ -323,7 +323,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); @@ -360,11 +359,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; } diff --git a/include/vr_datapath.h b/include/vr_datapath.h index 686cf91fc..520f233c4 100644 --- a/include/vr_datapath.h +++ b/include/vr_datapath.h @@ -60,6 +60,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 *);