mac_response_t 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; 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; stats = vr_inet_vrf_stats(fmd->fmd_dvrf, pkt->vp_cpu); /* here we will not check for stats, but will check before use */ if (vif->vif_type == VIF_TYPE_PHYSICAL) from_fabric = true; if (vif->vif_flags & VIF_FLAG_NO_ARP_PROXY) no_proxy = true; if (rt->rtr_req.rtr_label_flags & VR_RT_ARP_FLOOD_FLAG) flood = true; if (vr_gateway_nexthop(rt->rtr_nh)) to_gateway = true; /* * the no_proxy flag is set for the vcp ports. From such ports * vrouter should proxy only for the gateway ip. */ if (no_proxy && !to_gateway) return MR_DROP; if (from_fabric) { if (vr_nexthop_is_vcp(rt->rtr_nh)) { to_vcp = true; } } resp_mac = vif->vif_mac; if (rt->rtr_req.rtr_index != VR_BE_INVALID_INDEX) { if ((nh = vr_bridge_lookup(fmd->fmd_dvrf, rt))) { resp_mac = rt->rtr_req.rtr_mac; stitched = true; } } /* 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; } /* * situations that are handled here (from_fabric) * * . arp request from vm, but not proxied at the source because of lack * of information at the source. only the compute that hosts the * destination should respond, and that too only if the mac information * is present (and hence the ENCAP check). * * . arp request from a baremetal arriving at a TSN, which if posesses the * mac information for the destination vm, should proxy. If it does not * hold the mac information, the request should be flooded * * . arp request from the uplink port of a vcp */ if (from_fabric) { if (flood && !stitched) { if (stats) stats->vrf_arp_physical_flood++; return MR_FLOOD; } /* * arp requests to gateway coming from the fabric should be dropped * unless the request was for the TSN DNS service (which appears as * the gateway, with the current set of checks). We should not respond * for gateway ip if we are TSN and the request came from baremetal. * TSN does not have gateway route and hence the to_gateway will be * true only for the DNS ip. */ if (to_gateway) { if (fmd->fmd_src != TOR_SOURCE) { return MR_DROP; } } /* * we should proxy if the vm is hosted by us, in which case nh will be * of ENCAP type. we should also proxy for a host in vcp port. In all * other cases, we should proxy only if * * i am a TSN(fmd->fmd_src), * i amd the dns IP or * i have the mac information (nh - (mostly tunnel)) and * the originator is a bare metal (fmd->fmd_src) */ if (to_vcp || to_gateway || (nh && ((nh->nh_type == NH_ENCAP) || (fmd->fmd_src == TOR_SOURCE)))) { if (stats) stats->vrf_arp_physical_stitch++; } else { if (stats) stats->vrf_arp_physical_flood++; return MR_FLOOD; } } else { if (!stitched && flood) { /* * if there is no stitching information, but flood flag is set * we should flood */ if (stats) stats->vrf_arp_virtual_flood++; return MR_FLOOD; } if (stats) { if (stitched) { stats->vrf_arp_virtual_stitch++; } else { stats->vrf_arp_virtual_proxy++; } } } VR_MAC_COPY(dmac, resp_mac); return MR_PROXY; }
unsigned int vr_bridge_input(struct vrouter *router, struct vr_packet *pkt, struct vr_forwarding_md *fmd) { int reason, handled; l4_pkt_type_t l4_type = L4_TYPE_UNKNOWN; unsigned short pull_len, overlay_len = VROUTER_OVERLAY_LEN; int8_t *dmac; struct vr_bridge_entry *be; struct vr_nexthop *nh = NULL; struct vr_vrf_stats *stats; dmac = (int8_t *) pkt_data(pkt); if (pkt->vp_if->vif_flags & VIF_FLAG_MAC_LEARN) { if (vr_bridge_learn(router, pkt, fmd)) { return 0; } } pull_len = 0; if ((pkt->vp_type == VP_TYPE_IP) || (pkt->vp_type == VP_TYPE_IP6) || (pkt->vp_type == VP_TYPE_ARP)) { pull_len = pkt_get_network_header_off(pkt) - pkt_head_space(pkt); if (pull_len && !pkt_pull(pkt, pull_len)) { vr_pfree(pkt, VP_DROP_PULL); return 0; } } if ((pkt->vp_type == VP_TYPE_IP) || (pkt->vp_type == VP_TYPE_IP6)) { if (fmd->fmd_dscp < 0) { if (pkt->vp_type == VP_TYPE_IP) { fmd->fmd_dscp = vr_inet_get_tos((struct vr_ip *)pkt_network_header(pkt)); } else if (pkt->vp_type == VP_TYPE_IP6) { fmd->fmd_dscp = vr_inet6_get_tos((struct vr_ip6 *)pkt_network_header(pkt)); } } } else { if (fmd->fmd_dotonep < 0) { fmd->fmd_dotonep = vr_vlan_get_tos(pkt_data(pkt)); } } /* Do the bridge lookup for the packets not meant for "me" */ if (!fmd->fmd_to_me) { /* * If DHCP packet coming from VM, Trap it to Agent before doing the bridge * lookup itself */ if (vif_is_virtual(pkt->vp_if)) { if (pkt->vp_type == VP_TYPE_IP) l4_type = vr_ip_well_known_packet(pkt); else if (pkt->vp_type == VP_TYPE_IP6) l4_type = vr_ip6_well_known_packet(pkt); if (l4_type == L4_TYPE_DHCP_REQUEST) { if (pkt->vp_if->vif_flags & VIF_FLAG_DHCP_ENABLED) { vr_trap(pkt, fmd->fmd_dvrf, AGENT_TRAP_L3_PROTOCOLS, NULL); return 0; } } /* * Handle the unicast ARP, coming from VM, not * destined to us. Broadcast ARP requests would be handled * in L2 multicast nexthop. Multicast ARP on fabric * interface also would be handled in L2 multicast nexthop. * Unicast ARP packets on fabric interface would be handled * in plug routines of interface. */ if (!IS_MAC_BMCAST(dmac)) { handled = 0; if (pkt->vp_type == VP_TYPE_ARP) { handled = vr_arp_input(pkt, fmd, dmac); } else if (l4_type == L4_TYPE_NEIGHBOUR_SOLICITATION) { handled = vr_neighbor_input(pkt, fmd, dmac); } if (handled) return 0; } } be = bridge_lookup(dmac, fmd); if (be) nh = be->be_nh; if (!nh || nh->nh_type == NH_DISCARD) { /* If Flooding of unknown unicast not allowed, drop the packet */ if (!vr_unknown_uc_flood(pkt->vp_if, pkt->vp_nh) || IS_MAC_BMCAST(dmac)) { vr_pfree(pkt, VP_DROP_L2_NO_ROUTE); return 0; } be = bridge_lookup(vr_bcast_mac, fmd); nh = be->be_nh; if (!nh) { vr_pfree(pkt, VP_DROP_L2_NO_ROUTE); return 0; } stats = vr_inet_vrf_stats(fmd->fmd_dvrf, pkt->vp_cpu); if (stats) stats->vrf_uuc_floods++; /* Treat this unknown unicast packet as multicast */ pkt->vp_flags |= VP_FLAG_MULTICAST; } if (be) __sync_fetch_and_add(&be->be_packets, 1); if (nh->nh_type != NH_L2_RCV) overlay_len = VROUTER_L2_OVERLAY_LEN; } /* Adjust MSS for V4 and V6 packets */ if ((pkt->vp_type == VP_TYPE_IP) || (pkt->vp_type == VP_TYPE_IP6)) { if (vif_is_virtual(pkt->vp_if) && vr_from_vm_mss_adj && vr_pkt_from_vm_tcp_mss_adj) { if ((reason = vr_pkt_from_vm_tcp_mss_adj(pkt, overlay_len))) { vr_pfree(pkt, reason); return 0; } } if (fmd->fmd_to_me) { handled = vr_l3_input(pkt, fmd); if (!handled) { vr_pfree(pkt, VP_DROP_NOWHERE_TO_GO); } return 0; } } if (pull_len && !pkt_push(pkt, pull_len)) { vr_pfree(pkt, VP_DROP_PUSH); return 0; } nh_output(pkt, nh, fmd); return 0; }