unsigned int
vr_fabric_input(struct vr_interface *vif, struct vr_packet *pkt,
                unsigned short vlan_id)
{
    int handled = 0;
    unsigned short pull_len;
    struct vr_forwarding_md fmd;

    vr_init_forwarding_md(&fmd);
    fmd.fmd_vlan = vlan_id;
    fmd.fmd_dvrf = vif->vif_vrf;

    if (vr_pkt_type(pkt, 0, &fmd) < 0) {
        vif_drop_pkt(vif, pkt, 1);
        return 0;
    }

    if (pkt->vp_type == VP_TYPE_IP6)
        return vif_xconnect(vif, pkt, &fmd);

    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)
        handled = vr_l3_input(pkt, &fmd);
    else if (pkt->vp_type == VP_TYPE_ARP)
        handled = vr_arp_input(pkt, &fmd);

    if (!handled) {
        pkt_push(pkt, pull_len);
        return vif_xconnect(vif, pkt, &fmd);
    }

    return 0;
}
/*
 * arp responses from vhostX need to be cross connected. nothing
 * needs to be done for arp responses from VMs, while responses
 * from fabric needs to be Xconnected and sent to agent
 */
static int
vr_handle_arp_reply(struct vr_arp *sarp, struct vr_packet *pkt,
                    struct vr_forwarding_md *fmd)
{
    struct vr_interface *vif = pkt->vp_if;
    struct vr_packet *cloned_pkt;

    if (vif_mode_xconnect(vif) || vif->vif_type == VIF_TYPE_HOST)
        return vif_xconnect(vif, pkt, fmd);

    if (vif->vif_type != VIF_TYPE_PHYSICAL) {
        if (vif_is_virtual(vif)) {
            vr_preset(pkt);
            return vr_trap(pkt, fmd->fmd_dvrf, AGENT_TRAP_ARP, NULL);
        }
        vr_pfree(pkt, VP_DROP_INVALID_IF);
        return 0;
    }


    cloned_pkt = vr_pclone(pkt);
    if (cloned_pkt) {
        vr_preset(cloned_pkt);
        vif_xconnect(vif, cloned_pkt, fmd);
    }

    return vr_trap(pkt, fmd->fmd_dvrf, AGENT_TRAP_ARP, NULL);
}
static int
vr_handle_arp_request(struct vr_arp *sarp, struct vr_packet *pkt,
                      struct vr_forwarding_md *fmd)
{
    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;

    arp_result = vif->vif_mac_request(vif, pkt, fmd, dmac);
    switch (arp_result) {
    case MR_PROXY:
        vr_arp_proxy(sarp, pkt, fmd, dmac);
        break;

    case MR_XCONNECT:
        vif_xconnect(pkt->vp_if, pkt, fmd);
        break;

    case MR_TRAP_X:
        pkt_c = vr_pclone(pkt);
        if (pkt_c)
            vif_xconnect(pkt->vp_if, pkt_c, fmd);

        vr_trap(pkt, fmd->fmd_dvrf, AGENT_TRAP_ARP, NULL);
        break;

    case MR_TRAP:
        vr_trap(pkt, fmd->fmd_dvrf, AGENT_TRAP_ARP, NULL);
        break;

    case MR_DROP:
        vr_pfree(pkt, VP_DROP_INVALID_ARP);
        break;

    case MR_FLOOD:
    default:
        handled = false;
        break;
    }

    return handled;
}
/*
 * arp responses from vhostX need to be cross connected. nothing
 * needs to be done for arp responses from VMs, while responses
 * from fabric needs to be Xconnected and sent to agent
 */
static int
vr_handle_arp_reply(struct vrouter *router, unsigned short vrf,
        struct vr_arp *sarp, struct vr_packet *pkt)
{
    struct vr_interface *vif = pkt->vp_if;
    struct vr_packet *cloned_pkt;

    if (vif_mode_xconnect(vif) || vif->vif_type == VIF_TYPE_HOST)
        return vif_xconnect(vif, pkt);

    if (vif->vif_type != VIF_TYPE_PHYSICAL) {
        vr_pfree(pkt, VP_DROP_INVALID_IF);
        return 0;
    }

    cloned_pkt = vr_pclone(pkt);
    if (cloned_pkt) {
        vr_preset(cloned_pkt);
        vif_xconnect(vif, cloned_pkt);
    }

    return vr_trap(pkt, vrf, AGENT_TRAP_ARP, NULL);
}
Beispiel #5
0
/* vhost driver */
static int
vhost_rx(struct vr_interface *vif, struct vr_packet *pkt,
        unsigned short vlan_id __attribute__((unused)))
{
    struct vr_interface_stats *stats = vif_get_stats(vif, pkt->vp_cpu);

    stats->vis_ibytes += pkt_len(pkt);
    stats->vis_ipackets++;

    /* please see the text on xconnect mode */
    if (vif_mode_xconnect(vif))
        return vif_xconnect(vif, pkt);

    return vr_input(vif->vif_vrf, vif, pkt);
}
static int
vr_handle_arp_request(struct vrouter *router, unsigned short vrf,
        struct vr_arp *sarp, struct vr_packet *pkt)
{
    struct vr_packet *cloned_pkt;
    struct vr_interface *vif = pkt->vp_if;
    unsigned short proto = htons(VR_ETH_PROTO_ARP);
    struct vr_eth *eth;
    struct vr_arp *arp;
    unsigned int dpa;
    bool should_proxy = false;

    /* 
     * still @ l2 level, and hence we can use the mode of the interface
     * to figure out whether we need to xconnect or not. in the xconnect
     * mode, just pass it to the peer so that he can handle the arp requests
     */
    if (vif_mode_xconnect(vif))
        return vif_xconnect(vif, pkt);

    should_proxy = vr_should_proxy(vif, sarp->arp_dpa, sarp->arp_spa);

    /*
     * if vr should not proxy, all the other arp requests should go out on
     * the physical interface
     */
    if (vif->vif_type == VIF_TYPE_HOST && !should_proxy)
       return vif_xconnect(vif, pkt);

    /*
     * grat arp from
     *
     * VMs - need to be dropped
     * Fabric - need to be xconnected and also sent to agent
     * Vhost - xconnected above
     */
    if (vr_grat_arp(sarp)) {
        if (vif->vif_type == VIF_TYPE_VIRTUAL) {
            vr_pfree(pkt, VP_DROP_GARP_FROM_VM);
            return 0;
        }

        cloned_pkt = vr_pclone(pkt);
        if (cloned_pkt) {
            vr_preset(cloned_pkt);
            vif_xconnect(vif, cloned_pkt);
        }

        return vr_trap(pkt, vrf, AGENT_TRAP_ARP, NULL);
    }

    if (should_proxy) {
        pkt_reset(pkt);

        eth = (struct vr_eth *)pkt_data(pkt);
        memcpy(eth->eth_dmac, sarp->arp_sha, VR_ETHER_ALEN);
        memcpy(eth->eth_smac, vif->vif_mac, VR_ETHER_ALEN);
        memcpy(&eth->eth_proto, &proto, sizeof(proto));

        arp = (struct vr_arp *)pkt_pull_tail(pkt, VR_ETHER_HLEN);

        sarp->arp_op = htons(VR_ARP_OP_REPLY);
        memcpy(sarp->arp_sha, vif->vif_mac, VR_ETHER_ALEN);
        memcpy(sarp->arp_dha, eth->eth_dmac, VR_ETHER_ALEN);
        dpa = sarp->arp_dpa;
        memcpy(&sarp->arp_dpa, &sarp->arp_spa, sizeof(sarp->arp_dpa));
        memcpy(&sarp->arp_spa, &dpa, sizeof(sarp->arp_spa));

        memcpy(arp, sarp, sizeof(*sarp));
        pkt_pull_tail(pkt, sizeof(*arp));

        vif->vif_tx(vif, pkt);
    } else {
        /* requests for which vr doesn't have to do anything */
        vr_pfree(pkt, VP_DROP_INVALID_ARP);
    }

    return 0;
}