【OVS2.5.0源码分析】vlan&trunk实现原理分析(1)

来源:互联网 发布:nodejs nginx静态文件 编辑:程序博客网 时间:2024/06/05 19:32

传统交换机的端口可以按照vlan可以划分为access、trunk和hybrid三类接口。 首先,我们先看OVS的VLAN实现原理,最后对比OVS与传统交换机的差异。

OVS中,数据面的转发流表都是从用户态下发的,所以流表生成的入口是upcall_actions函数(该函数不是upcall的总入口,由于层次比较多,以该函数作为分析的入口是合适的)。

1、xlate_actions函数

            mirror_ingress_packet(&ctx);            do_xlate_actions(ofpacts, ofpacts_len, &ctx);   //openflow流表转化为精确流表            if (ctx.error) {                goto exit;            }

2、do_xlate_actons函数

        case OFPACT_OUTPUT:            xlate_output_action(ctx, ofpact_get_OUTPUT(a)->port,       //normal规则也是output的一种                                ofpact_get_OUTPUT(a)->max_len, true);            break;

3、xlate_output_action函数

static voidxlate_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);     //normal规则流表转化为精确流表        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、xlate_normal函数

<pre name="code" class="cpp">xlate_normal(struct xlate_ctx *ctx){    .......    /* Check VLAN. */    vid = vlan_tci_to_vid(flow->vlan_tci);   //计算报文的vlan值    if (!input_vid_is_valid(vid, in_xbundle, ctx->xin->packet != NULL)) {     //判断报文是否满足vlan要求,如果不满足则丢球        xlate_report(ctx, "disallowed VLAN VID for this input port, dropping");        return;    }    vlan = input_vid_to_vlan(in_xbundle, vid);    //计算报文进入OVS桥之后的VLAN值,该VLAN会贯穿报文在OVS内处理的全流程    ......
    /* Determine output bundle. */    if (mcast_snooping_enabled(ctx->xbridge->ms)        ......    } else {        ovs_rwlock_rdlock(&ctx->xbridge->ml->rwlock);        mac = mac_learning_lookup(ctx->xbridge->ml, flow->dl_dst, vlan);     //根据目标mac和vlan值寻找目的端口        mac_port = mac ? mac_entry_get_port(ctx->xbridge->ml, mac) : NULL;        ovs_rwlock_unlock(&ctx->xbridge->ml->rwlock);        if (mac_port) {            struct xlate_cfg *xcfg = ovsrcu_get(struct xlate_cfg *, &xcfgp);            struct xbundle *mac_xbundle = xbundle_lookup(xcfg, mac_port);            if (mac_xbundle && mac_xbundle != in_xbundle) {                xlate_report(ctx, "forwarding to learned port");                output_normal(ctx, mac_xbundle, vlan);                 //找到目的端口,从该端口发送报文            } else if (!mac_xbundle) {                xlate_report(ctx, "learned port is unknown, dropping");            } else {                xlate_report(ctx, "learned port is input port, dropping");            }        } else {            xlate_report(ctx, "no learned MAC for destination, flooding");            xlate_normal_flood(ctx, in_xbundle, vlan);     //没找到目的端口,flood报文        }    }}


static boolinput_vid_is_valid(uint16_t vid, struct xbundle *in_xbundle, bool warn){    /* Allow any VID on the OFPP_NONE port. */    if (in_xbundle == &ofpp_none_bundle) {        return true;    }    switch (in_xbundle->vlan_mode) {    case PORT_VLAN_ACCESS:        if (vid) {          //如果入端口为ACCESS口,且报文包含VLAN,那么丢弃该报文            if (warn) {                static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);                VLOG_WARN_RL(&rl, "dropping VLAN %"PRIu16" tagged "                             "packet received on port %s configured as VLAN "                             "%"PRIu16" access port", vid, in_xbundle->name,                             in_xbundle->vlan);            }            return false;        }        return true;    case PORT_VLAN_NATIVE_UNTAGGED:    case PORT_VLAN_NATIVE_TAGGED:        if (!vid) {      //如果端口类型为native-untagged和native-tagged,如果报文不包含VLAN,则接受该报文;如果包含VLAN,那么VLAN必须包含在端口的VLAN中。            /* Port must always carry its native VLAN. */            return true;        }        /* Fall through. */    case PORT_VLAN_TRUNK:        if (!xbundle_includes_vlan(in_xbundle, vid)) {    //如果端口类型为trunk,<span style="font-family: Arial, Helvetica, sans-serif;">如果报文不包含VLAN,则接受该报文;如果包含VLAN,那么VLAN必须包含在端口的VLAN中。</span>            if (warn) {                static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);                VLOG_WARN_RL(&rl, "dropping VLAN %"PRIu16" packet "                             "received on port %s not configured for trunking "                             "VLAN %"PRIu16, vid, in_xbundle->name, vid);            }            return false;        }        return true;    default:        OVS_NOT_REACHED();    }}

static uint16_tinput_vid_to_vlan(const struct xbundle *in_xbundle, uint16_t vid)  //计算报文进入OVS交换机之后,报文的VLAN值{    switch (in_xbundle->vlan_mode) {    case PORT_VLAN_ACCESS:        return in_xbundle->vlan;   //如果端口是ACCESS口,则报文进入OVS交换机后,VLAN值=端口的VLAN值;        break;    case PORT_VLAN_TRUNK:  //如果端口是trunk口,则报文的VLAN值不变;        return vid;    case PORT_VLAN_NATIVE_UNTAGGED:    case PORT_VLAN_NATIVE_TAGGED:        return vid ? vid : in_xbundle->vlan;  //如果端口是native-tagged和native-untagged,当报文没有vlan时,报文的VLAN等于端口vlan,否则不变;    default:        OVS_NOT_REACHED();    }}

5、output_normal函数

    ......    vid = output_vlan_to_vid(out_xbundle, vlan);  //计算报文发出OVS交换机之后的VLAN值     ......    old_tci = *flow_tci;    tci = htons(vid);    if (tci || out_xbundle->use_priority_tags) {        tci |= *flow_tci & htons(VLAN_PCP_MASK);        if (tci) {            tci |= htons(VLAN_CFI);        }    }    *flow_tci = tci;    compose_output_action(ctx, xport->ofp_port, use_recirc ? &xr : NULL);    //生成流表

static uint16_toutput_vlan_to_vid(const struct xbundle *out_xbundle, uint16_t vlan){    switch (out_xbundle->vlan_mode) {    case PORT_VLAN_ACCESS:   //access端口,报文没有vlan        return 0;    case PORT_VLAN_TRUNK:    case PORT_VLAN_NATIVE_TAGGED:        return vlan;         //trunk和native-tagged端口,出口报文的VLAN等于过程中的VLAN值    case PORT_VLAN_NATIVE_UNTAGGED:   //native-untagged端口,如果vlan值等于端口的vlan值,那么剥掉vlan值,否则保留vlan值        return vlan == out_xbundle->vlan ? 0 : vlan;    default:        OVS_NOT_REACHED();    }}

6、xlate_normal_flood函数

static voidxlate_normal_flood(struct xlate_ctx *ctx, struct xbundle *in_xbundle,                   uint16_t vlan){    struct xbundle *xbundle;    LIST_FOR_EACH (xbundle, list_node, &ctx->xbridge->xbundles) {        if (xbundle != in_xbundle            && xbundle_includes_vlan(xbundle, vlan)    //端口包含该vlan值            && xbundle->floodable            && !xbundle_mirror_out(ctx->xbridge, xbundle)) {            output_normal(ctx, xbundle, vlan);        }    }    ctx->nf_output_iface = NF_OUT_FLOOD;}

下一篇将系统总结下,OVS交换机的总体行为,并和标准交换机进行对比。

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 老打孩子骂孩子怎么办 站久了脚肿了怎么办 孩子初中了书写越来越潦草怎么办 给孩子自由孩子无法无天怎么办 孩子挑食幼儿园老师该怎么办 老师说孩子挑食家长怎么办 工作中老是粗心不细心怎么办 小孩数学总是特别粗心该怎么办 孩子起范疙瘩的怎么办 做题马虎不认真怎么办 孩子考差了家长怎么办 小孩写作业不认真怎么办 小孩不认真检查作业怎么办 一年级的小孩作业不认真怎么办 一年级学生做题粗心怎么办 一年级的学生做题粗心怎么办 孩子做作业注意力不集中怎么办 小学三年孩子抄答案怎么办 孩子写作业不认真审题怎么办 一年级小孩审题不认真怎么办 孩子审题不认真马虎怎么办 孩子做作业不认真审题怎么办? 考老师考砸了怎么办 重要考试考砸了怎么办 二年级孩子做数学题粗心怎么办 二年级孩子考试粗心怎么办 二年级孩子考试总是粗心怎么办 二年级孩子总是粗心怎么办 小学一年级孩子抄别人作业怎么办 被老师发现抄答案怎么办 考试抄答案被老师发现怎么办 孩子撒谎不写作业怎么办 小学生做题容易马虎出错怎么办 小学生做题老是马虎怎么办 小学生做题马虎不认真怎么办 会做的题总做错怎么办 孩子数学做题粗心怎么办 孩子成绩考差了怎么办 孩子静不下心学习怎么办 孩子考试时总是粗心马虎怎么办 小学二年级学生厌学怎么办