Example #1
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);
}
Example #2
0
static void
vr_flow_init_close(struct vrouter *router, struct vr_flow_entry *flow_e,
        struct vr_packet *pkt, struct vr_forwarding_md *fmd)
{
    unsigned int flow_index;
    unsigned int head_room = sizeof(struct agent_hdr) + sizeof(struct vr_eth);

    struct vr_packet *pkt_c;

    pkt_c = vr_pclone(pkt);
    if (!pkt_c)
        return;

    vr_preset(pkt_c);
    if (vr_pcow(pkt_c, head_room)) {
        vr_pfree(pkt_c, VP_DROP_PCOW_FAIL);
        return;
    }

    flow_index = fmd->fmd_flow_index;
    vr_trap(pkt_c, fmd->fmd_dvrf, AGENT_TRAP_SESSION_CLOSE,
            (void *)&flow_index);

    return;
}
Example #3
0
static unsigned char *
agent_set_rewrite(struct vr_interface *vif, struct vr_packet *pkt,
        unsigned char *rewrite, unsigned short len)
{
    unsigned char *head;
    unsigned int hdr_len;
    struct agent_hdr *hdr;

    vr_preset(pkt);

    hdr_len = sizeof(struct agent_hdr) + len;
    if (pkt_head_space(pkt) < hdr_len) {
        pkt = vr_pexpand_head(pkt, hdr_len - pkt_head_space(pkt));
        if (!pkt)
            return NULL;
    }

    head = pkt_push(pkt, hdr_len);
    if (!head)
        return NULL;

    /* copy the rewrite first */
    memcpy(head, rewrite, len);

    hdr = (struct agent_hdr *)(head + len);
    hdr->hdr_ifindex = htons(pkt->vp_if->vif_idx);
    hdr->hdr_vrf = htons(pkt->vp_if->vif_vrf);
    /* this needs some thought */
    hdr->hdr_cmd = htons(AGENT_TRAP_NEXTHOP);
    hdr->hdr_cmd_param = 0;

    return head;
}
Example #4
0
unsigned int
vr_trap_flow(struct vrouter *router, struct vr_flow_entry *fe,
        struct vr_packet *pkt, unsigned int index)
{
    unsigned int trap_reason;
    struct vr_packet *npkt;
    struct vr_flow_trap_arg ta;

    npkt = vr_pclone(pkt);
    if (!npkt)
        return -ENOMEM;

    vr_preset(npkt);

    switch (fe->fe_flags & VR_FLOW_FLAG_TRAP_MASK) {
    default:
        trap_reason = AGENT_TRAP_FLOW_MISS;
        ta.vfta_index = index;
        if ((fe->fe_type == VP_TYPE_IP) || (fe->fe_type == VP_TYPE_IP6))
            ta.vfta_nh_index = fe->fe_key.flow_nh_id;
        break;
    }


    return vr_trap(npkt, fe->fe_vrf, trap_reason, &ta);
}
static int
vr_default_input(struct vr_packet *pkt)
{
    struct vr_interface *vif = pkt->vp_if;
    struct vrouter *router = vif->vif_router;

    if (router->vr_host_if && (vif != router->vr_host_if)) {
        vr_preset(pkt);
        return router->vr_host_if->vif_tx(router->vr_host_if, pkt);
    }
    
    vr_pfree(pkt, VP_DROP_NOWHERE_TO_GO);
    return 0;
}
Example #6
0
int
vif_xconnect(struct vr_interface *vif, struct vr_packet *pkt)
{
    struct vr_interface *bridge;
    
    if (!vif)
        goto free_pkt;

    bridge = vif->vif_bridge;
    if (bridge) {
        vr_preset(pkt);
        return bridge->vif_tx(bridge, pkt);
    }

free_pkt:
    if (vif)
        vif_drop_pkt(vif, pkt, 1);
    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 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);
}
Example #8
0
static int
agent_send(struct vr_interface *vif, struct vr_packet *pkt,
                void *ifspecific)
{
    int len;
    struct agent_hdr *hdr;
    unsigned char *rewrite;
    struct vr_interface_stats *stats = vif_get_stats(vif, pkt->vp_cpu);
    struct vr_packet *pkt_c;
    struct agent_send_params *params =
        (struct agent_send_params *)ifspecific;

    vr_preset(pkt);

    if (pkt_head_space(pkt) < AGENT_PKT_HEAD_SPACE) {
        len = pkt_len(pkt);

        if (agent_trap_may_truncate(params->trap_reason)) {
            len = MINIMUM(len, VR_AGENT_MIN_PACKET_LEN);
        }

        pkt_c = pkt_copy(pkt, 0, len);
        if (pkt_c) {
            vr_pfree(pkt, VP_DROP_DUPLICATED);
            pkt = pkt_c;
        }
    }

    hdr = (struct agent_hdr *)pkt_push(pkt, sizeof(struct agent_hdr));
    if (!hdr)
        goto drop;

    hdr->hdr_ifindex = htons(pkt->vp_if->vif_idx);
    hdr->hdr_vrf = htons(params->trap_vrf);
    hdr->hdr_cmd = htons(params->trap_reason);

    switch (params->trap_reason) {
    case AGENT_TRAP_FLOW_MISS:
    case AGENT_TRAP_ECMP_RESOLVE:
    case AGENT_TRAP_SOURCE_MISMATCH:
        if (params->trap_param)
            hdr->hdr_cmd_param = htonl(*(unsigned int *)(params->trap_param));
        break;

    case AGENT_TRAP_DIAG:
        if (params->trap_param)
            hdr->hdr_cmd_param = htonl(*(unsigned int *)(params->trap_param));
        break;

    default:
        hdr->hdr_cmd_param = 0;
        break;
    }

    rewrite = pkt_push(pkt, VR_ETHER_HLEN);
    if (!rewrite)
        goto drop;

    memcpy(rewrite, vif->vif_rewrite, VR_ETHER_HLEN);
    return vif->vif_tx(vif, pkt);

drop:
    stats->vis_oerrors++;
    vr_pfree(pkt, VP_DROP_PUSH);
    return 0;
}
Example #9
0
int
vr_mirror(struct vrouter *router, uint8_t mirror_id, struct vr_packet *pkt,
            struct vr_forwarding_md *fmd, mirror_type_t mtype)
{
    bool reset = true;
    void *mirror_md;
    unsigned char *buf, default_mme[2] = {0xff, 0x0};
    unsigned int captured_len, clone_len = 0;
    unsigned int mirror_md_len = 0, drop_reason;
    struct vr_nexthop *nh, *pkt_nh;
    struct vr_mirror_entry *mirror;
    struct vr_mirror_meta_entry *mme;
    struct vr_forwarding_md new_fmd;

    /* If the packet is already mirrored, dont mirror again */
    if (pkt->vp_flags & VP_FLAG_FROM_DP)
        return 0;

    if (mtype <= MIRROR_TYPE_UNKNOWN || mtype >= MIRROR_TYPE_MAX)
        return 0;

    mirror = router->vr_mirrors[mirror_id];
    if (!mirror)
        return 0;

    if (mirror->mir_flags & VR_MIRROR_FLAG_HW_ASSISTED) {
        vr_fmd_put_mirror_vlan(fmd, mirror->mir_vlan_id);
        return 0;
    }

    memcpy(&new_fmd, fmd, sizeof(*fmd));
    new_fmd.fmd_ecmp_nh_index = -1;
    fmd = &new_fmd;

    vr_fmd_put_mirror_type(fmd, mtype);

    nh = mirror->mir_nh;
    if (!nh || !(nh->nh_flags & NH_FLAG_VALID))
        return 0;

    pkt = vr_pclone(pkt);
    if (!pkt)
        return 0;

    /* Mark as mirrored */
    pkt->vp_flags |= VP_FLAG_FROM_DP;

    /* Set the GSO and partial checksum flag */
    pkt->vp_flags |= (VP_FLAG_FLOW_SET | VP_FLAG_GSO);
    vr_pkt_unset_gro(pkt);

    if (mirror->mir_flags & VR_MIRROR_FLAG_DYNAMIC) {

        if (mtype == MIRROR_TYPE_ACL) {
            if (fmd->fmd_flow_index >= 0) {
                mme = (struct vr_mirror_meta_entry *)
                    vr_itable_get(router->vr_mirror_md, fmd->fmd_flow_index);
                if (mme) {
                    mirror_md_len = mme->mirror_md_len;
                    mirror_md = mme->mirror_md;
                }
            }
        } else if (mtype == MIRROR_TYPE_PORT_RX) {
            if (!pkt->vp_if) {
                drop_reason = VP_DROP_INVALID_IF;
                goto fail;
            }

            mirror_md_len = pkt->vp_if->vif_in_mirror_md_len;
            mirror_md = pkt->vp_if->vif_in_mirror_md;
        } else {
            if (!pkt->vp_nh || !pkt->vp_nh->nh_dev) {
                drop_reason = VP_DROP_INVALID_NH;
                goto fail;
            }

            mirror_md_len = pkt->vp_nh->nh_dev->vif_out_mirror_md_len;
            mirror_md = pkt->vp_nh->nh_dev->vif_out_mirror_md;
        }

        if (!mirror_md_len) {
            mirror_md = default_mme;
            mirror_md_len = sizeof(default_mme);
        }

        clone_len += mirror_md_len;
        clone_len += VR_MIRROR_PKT_HEAD_SPACE;
    } else {
        clone_len += VR_VXLAN_HDR_LEN;
        fmd->fmd_label = mirror->mir_vni;
    }

    if (pkt->vp_if && (pkt->vp_if->vif_type == VIF_TYPE_PHYSICAL)) {
        /* No need to mirror the Tunnel headers. So packet cant be reset */
        reset = false;

        /* Identify whether the packet currently has L2 header. If not a
         * port mirroring, we need to add the extra L2 header
         */
        if (mtype == MIRROR_TYPE_ACL) {

            pkt_nh = pkt->vp_nh;
            if (pkt_nh && (pkt_nh->nh_flags & NH_FLAG_VALID) &&
                        (pkt_nh->nh_type == NH_ENCAP) &&
                        (pkt_nh->nh_family == AF_INET)) {

                clone_len += pkt_nh->nh_encap_len;

                if (vr_pcow(&pkt, clone_len)) {
                    drop_reason = VP_DROP_PCOW_FAIL;
                    goto fail;
                }

                clone_len = 0;

                if (pkt_nh->nh_dev->vif_set_rewrite(pkt_nh->nh_dev, pkt, fmd,
                                    pkt_nh->nh_data, pkt_nh->nh_encap_len) < 0) {
                    drop_reason = VP_DROP_REWRITE_FAIL;
                    goto fail;
                }
            }
        }
    }

    if (reset)
        vr_preset(pkt);

    if (clone_len) {
        if (vr_pcow(&pkt, clone_len)) {
            drop_reason = VP_DROP_PCOW_FAIL;
            goto fail;
        }
    }

    captured_len = htonl(pkt_len(pkt));
    if (mirror_md_len) {
        buf = pkt_push(pkt, mirror_md_len);
        if (!buf) {
            drop_reason = VP_DROP_PUSH;
            goto fail;
        }
        memcpy(buf, mirror_md, mirror_md_len);
    }

    if (nh->nh_vrf >= 0)
        fmd->fmd_dvrf = nh->nh_vrf;

    /*
     * we are now in the mirroring context and there isn't a flow for this
     * mirror packet. hence, set the flow index to -1.
     */
    fmd->fmd_flow_index = -1;

    fmd->fmd_outer_src_ip = 0;

    nh_output(pkt, nh, fmd);
    return 0;

fail:
    vr_pfree(pkt, drop_reason);
    return 0;
}
Example #10
0
static flow_result_t
vr_flow_action(struct vrouter *router, struct vr_flow_entry *fe,
        unsigned int index, struct vr_packet *pkt,
        struct vr_forwarding_md *fmd)
{
    int valid_src;

    flow_result_t result;

    struct vr_forwarding_md mirror_fmd;
    struct vr_nexthop *src_nh;
    struct vr_packet *pkt_clone;

    fmd->fmd_dvrf = fe->fe_vrf;
    /*
     * for now, we will not use dvrf if VRFT is set, because the RPF
     * check needs to happen in the source vrf
     */
    src_nh = __vrouter_get_nexthop(router, fe->fe_src_nh_index);
    if (!src_nh) {
        vr_pfree(pkt, VP_DROP_INVALID_NH);
        return FLOW_CONSUMED;
    }

    if (src_nh->nh_validate_src) {
        valid_src = src_nh->nh_validate_src(pkt, src_nh, fmd, NULL);
        if (valid_src == NH_SOURCE_INVALID) {
            vr_pfree(pkt, VP_DROP_INVALID_SOURCE);
            return FLOW_CONSUMED;
        }

        if (valid_src == NH_SOURCE_MISMATCH) {
            pkt_clone = vr_pclone(pkt);
            if (pkt_clone) {
                vr_preset(pkt_clone);
                if (vr_pcow(pkt_clone, sizeof(struct vr_eth) +
                            sizeof(struct agent_hdr))) {
                    vr_pfree(pkt_clone, VP_DROP_PCOW_FAIL);
                } else {
                    vr_trap(pkt_clone, fmd->fmd_dvrf,
                            AGENT_TRAP_ECMP_RESOLVE, &fmd->fmd_flow_index);
                }
            }
        }
    }


    if (fe->fe_flags & VR_FLOW_FLAG_VRFT) {
        if (fmd->fmd_dvrf != fe->fe_dvrf) {
            fmd->fmd_dvrf = fe->fe_dvrf;
            fmd->fmd_to_me = 1;
        }
    }

    if (fe->fe_flags & VR_FLOW_FLAG_MIRROR) {
        if (fe->fe_mirror_id < VR_MAX_MIRROR_INDICES) {
            mirror_fmd = *fmd;
            mirror_fmd.fmd_ecmp_nh_index = -1;
            vr_mirror(router, fe->fe_mirror_id, pkt, &mirror_fmd);
        }
        if (fe->fe_sec_mirror_id < VR_MAX_MIRROR_INDICES) {
            mirror_fmd = *fmd;
            mirror_fmd.fmd_ecmp_nh_index = -1;
            vr_mirror(router, fe->fe_sec_mirror_id, pkt, &mirror_fmd);
        }
    }

    switch (fe->fe_action) {
    case VR_FLOW_ACTION_DROP:
        vr_pfree(pkt, VP_DROP_FLOW_ACTION_DROP);
        result = FLOW_CONSUMED;
        break;

    case VR_FLOW_ACTION_FORWARD:
        result = FLOW_FORWARD;
        break;

    case VR_FLOW_ACTION_NAT:
        result = vr_flow_nat(fe, pkt, fmd);
        break;

    default:
        vr_pfree(pkt, VP_DROP_FLOW_ACTION_INVALID);
        result = FLOW_CONSUMED;
        break;
    }

    return result;
}
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;
}