我是靠谱客的博主 冷酷奇异果,最近开发中收集的这篇文章主要介绍【OVS2.5.0源码分析】mirror实现原理(1),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

端口镜像是交换机的标准功能之一,针对某个端口的报文拷贝到除真实目的之外的另外一个目的地(output),这一篇我们先分析配置mirror之后,如何生成流表,在什么阶段生成流表。

1、xlate_actions函数

            mirror_ingress_packet(&ctx);   //生成满足入端口的流表生成,即进入该端口的报文会被镜像到其他目的地。
            do_xlate_actions(ofpacts, ofpacts_len, &ctx);   //解析成精确流表。 针对源端口的mirror,先执行mirror动作,再执行其他操作。
            if (ctx.error) {
                goto exit;
            }

mirror_ingress_packet函数

static void
mirror_ingress_packet(struct xlate_ctx *ctx)
{
    if (mbridge_has_mirrors(ctx->xbridge->mbridge)) {
        bool warn = ctx->xin->packet != NULL;
        struct xbundle *xbundle = lookup_input_bundle(
            ctx->xbridge, ctx->xin->flow.in_port.ofp_port, warn, NULL);
        if (xbundle) {
            mirror_packet(ctx, xbundle,    //生成mirror的精确流表
                          xbundle_mirror_src(ctx->xbridge, xbundle));
        }
    }
}
mirror_packet函数

static void
mirror_packet(struct xlate_ctx *ctx, struct xbundle *xbundle,
              mirror_mask_t mirrors)
{
    /* Figure out what VLAN the packet is in (because mirrors can select
     * packets on basis of VLAN). */
    bool warn = ctx->xin->packet != NULL;
    uint16_t vid = vlan_tci_to_vid(ctx->xin->flow.vlan_tci);
    if (!input_vid_is_valid(vid, xbundle, warn)) {
        return;
    }
    uint16_t vlan = input_vid_to_vlan(xbundle, vid);

    const struct xbridge *xbridge = ctx->xbridge;

    /* Don't mirror to destinations that we've already mirrored to. */
    mirrors &= ~ctx->mirrors;    //避免出现循环地生成mirror actions
    if (!mirrors) {
        return;
    }

    if (ctx->xin->resubmit_stats) {
        mirror_update_stats(xbridge->mbridge, mirrors,
                            ctx->xin->resubmit_stats->n_packets,
                            ctx->xin->resubmit_stats->n_bytes);
    }
    if (ctx->xin->xcache) {
        struct xc_entry *entry;

        entry = xlate_cache_add_entry(ctx->xin->xcache, XC_MIRROR);
        entry->u.mirror.mbridge = mbridge_ref(xbridge->mbridge);
        entry->u.mirror.mirrors = mirrors;
    }

    /* 'mirrors' is a bit-mask of candidates for mirroring.  Iterate as long as
     * some candidates remain.  */
    while (mirrors) {
        const unsigned long *vlans;
        mirror_mask_t dup_mirrors;
        struct ofbundle *out;
        int out_vlan;

        /* Get the details of the mirror represented by the rightmost 1-bit. */
        bool has_mirror = mirror_get(xbridge->mbridge, raw_ctz(mirrors),     //针对该mirror的out端口或者out vlan,两者选其一。
                                     &vlans, &dup_mirrors, &out, &out_vlan);
        ovs_assert(has_mirror);

        /* If this mirror selects on the basis of VLAN, and it does not select
         * 'vlan', then discard this mirror and go on to the next one. */
        if (vlans) {
            ctx->wc->masks.vlan_tci |= htons(VLAN_CFI | VLAN_VID_MASK);
        }
        if (vlans && !bitmap_is_set(vlans, vlan)) {
            mirrors = zero_rightmost_1bit(mirrors);
            continue;
        }

        /* Record the mirror, and the mirrors that output to the same
         * destination, so that we don't mirror to them again.  This must be
         * done now to ensure that output_normal(), below, doesn't recursively
         * output to the same mirrors. */
        ctx->mirrors |= dup_mirrors;

        /* Send the packet to the mirror. */
        if (out) {
            struct xlate_cfg *xcfg = ovsrcu_get(struct xlate_cfg *, &xcfgp);
            struct xbundle *out_xbundle = xbundle_lookup(xcfg, out);
            if (out_xbundle) {
                output_normal(ctx, out_xbundle, vlan);     //如果是端口,则生成一个output action。
            }
        } else if (vlan != out_vlan
                   && !eth_addr_is_reserved(ctx->xin->flow.dl_dst)) {
            struct xbundle *xbundle;

            LIST_FOR_EACH (xbundle, list_node, &xbridge->xbundles) {
                if (xbundle_includes_vlan(xbundle, out_vlan)    //端口必须包含out vlan
                    && !xbundle_mirror_out(xbridge, xbundle)) { //端口不允许同时作为mirror的output端口
                    output_normal(ctx, xbundle, out_vlan);      //生成一个output action
                }
            }
        }

        /* output_normal() could have recursively output (to different
         * mirrors), so make sure that we don't send duplicates. */
        mirrors &= ~ctx->mirrors;
    }
}

2、do_xlate_actions函数

        switch (a->type) {
        case OFPACT_OUTPUT:
            xlate_output_action(ctx, ofpact_get_OUTPUT(a)->port,    //生成output actions
                                ofpact_get_OUTPUT(a)->max_len, true);
            break;

3、xlate_ouput_action函数

static void
xlate_output_action(struct xlate_ctx *ctx,
                    ofp_port_t port, uint16_t max_len, bool may_packet_in)
{
    ofp_port_t prev_nf_output_iface = ctx->nf_output_iface;

    ctx->nf_output_iface = NF_OUT_DROP;

    switch (port) {
    case OFPP_IN_PORT:
        compose_output_action(ctx, ctx->xin->flow.in_port.ofp_port, NULL);
        break;
    case OFPP_TABLE:
        xlate_table_action(ctx, ctx->xin->flow.in_port.ofp_port,
                           0, may_packet_in, true);
        break;
    case OFPP_NORMAL:
        xlate_normal(ctx);
        break;
    case OFPP_FLOOD:
        flood_packets(ctx,  false);
        break;
    case OFPP_ALL:
        flood_packets(ctx, true);
        break;
    case OFPP_CONTROLLER:
        execute_controller_action(ctx, max_len,
                                  (ctx->in_group ? OFPR_GROUP
                                   : ctx->in_action_set ? OFPR_ACTION_SET
                                   : OFPR_ACTION),
                                  0);
        break;
    case OFPP_NONE:
        break;
    case OFPP_LOCAL:
    default:
        if (port != ctx->xin->flow.in_port.ofp_port) {
            compose_output_action(ctx, port, NULL);
        } else {
            xlate_report(ctx, "skipping output to input port");
        }
        break;
    }

    if (prev_nf_output_iface == NF_OUT_FLOOD) {
        ctx->nf_output_iface = NF_OUT_FLOOD;
    } else if (ctx->nf_output_iface == NF_OUT_DROP) {
        ctx->nf_output_iface = prev_nf_output_iface;
    } else if (prev_nf_output_iface != NF_OUT_DROP &&
               ctx->nf_output_iface != NF_OUT_FLOOD) {
        ctx->nf_output_iface = NF_OUT_MULTI;
    }
}

4、compose_outpu_action函数

static void
compose_output_action(struct xlate_ctx *ctx, ofp_port_t ofp_port,
                      const struct xlate_bond_recirc *xr)
{
    compose_output_action__(ctx, ofp_port, xr, true);
}


compose_output_action__函数

    if (mbridge_has_mirrors(ctx->xbridge->mbridge) && xport->xbundle) {    //判断output端口是否有mirror,对于patch port,会针对peer重现遍历流表和mirror
        mirror_packet(ctx, xport->xbundle,                                 //针对output的mirror,类似深度优先原则,嵌套越深的mirror越先执行
                      xbundle_mirror_dst(xport->xbundle->xbridge,          //在output阶段,基于input的mirror规则不被生效
                                         xport->xbundle));
    }

 out:
    /* Restore flow */
    flow->vlan_tci = flow_vlan_tci;
    flow->pkt_mark = flow_pkt_mark;
    flow->nw_tos = flow_nw_tos;
}







最后

以上就是冷酷奇异果为你收集整理的【OVS2.5.0源码分析】mirror实现原理(1)的全部内容,希望文章能够帮你解决【OVS2.5.0源码分析】mirror实现原理(1)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(52)

评论列表共有 0 条评论

立即
投稿
返回
顶部