1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | static enum ofperr handle_flow_mod(struct ofconn *ofconn, const struct ofp_header *oh) OVS_EXCLUDED(ofproto_mutex) { /* 每一个ofproto代表一个交换机,并且挂在ofconn连接中, * 如果有谁不知道其中关联关系,请参考我的第三篇文章。 * 因此第一步就需要获取openflow交换机对象,即ofproto */ struct ofproto *ofproto = ofconn_get_ofproto(ofconn); struct ofputil_flow_mod fm; /* flow mod 消息 */ uint64_t ofpacts_stub[1024 / 8]; struct ofpbuf ofpacts; enum ofperr error; error = reject_slave_controller(ofconn); /* 角色权限验证我们可以忽略。 */ if (error) { goto exit; } /* 将stub挂在ofpbuf中这个地方经常见到不再详细分析有不明白的可参考前面几篇*/ ofpbuf_use_stub(&ofpacts, ofpacts_stub, sizeof ofpacts_stub); /* flow_mod解码解码过程其实很简单,只要按照标准协议格式一个字段一个字段 * 解析就可以啦!!这里我们按照某一种报文进行讲解,这样对于代码理解帮助非常有 * 意义,也不至于会有这样的疑问,为什么这样写??哈哈哈 */ error = ofputil_decode_flow_mod(&fm, oh, ofconn_get_protocol(ofconn), &ofpacts, u16_to_ofp(ofproto->max_ports), ofproto->n_tables); /* 校验action内容 */ if (!error) { error = ofproto_check_ofpacts(ofproto, fm.ofpacts, fm.ofpacts_len); } if (!error) { error = handle_flow_mod__(ofproto, ofconn, &fm, oh); /* 真正处理flow_mod函数 */ } if (error) { goto exit_free_ofpacts; } /* * 修改统计值大概是为了控制器下发统计请求用的吧!! */ ofconn_report_flow_mod(ofconn, fm.command); /* 释放内存,这里不会真正调用free函数的 */ exit_free_ofpacts: ofpbuf_uninit(&ofpacts); exit: return error; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | /* Converts an OFPT_FLOW_MOD or NXT_FLOW_MOD message 'oh' into an abstract * flow_mod in 'fm'. Returns 0 if successful, otherwise an OpenFlow error * code. * * Uses 'ofpacts' to store the abstract OFPACT_* version of 'oh''s actions. * The caller must initialize 'ofpacts' and retains ownership of it. * 'fm->ofpacts' will point into the 'ofpacts' buffer. * * Does not validate the flow_mod actions. The caller should do that, with * ofpacts_check. * OpenvSwitch支持两种flow格式,一种标准flow_mod,一种NXT flow_mod. * 对于OpenvSwitch来说无论是哪种flow_mod,经过ovs抽象之后都会转成 * struct ofputil_flow_mod进行存储。 */ enum ofperr ofputil_decode_flow_mod(struct ofputil_flow_mod *fm, const struct ofp_header *oh, enum ofputil_protocol protocol, struct ofpbuf *ofpacts, ofp_port_t max_port, uint8_t max_table) { ovs_be16 raw_flags; enum ofperr error; struct ofpbuf b; enum ofpraw raw; /* 将flow_mod消息挂载在ofpbuf的b中 */ ofpbuf_use_const(&b, oh, ntohs(oh->length)); /* 解析消息头前面有一篇介绍OpenvSwitch是如何进行版本兼容。*/ raw = ofpraw_pull_assert(&b); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | if (raw == OFPRAW_OFPT11_FLOW_MOD) { /* Standard OpenFlow 1.1+ flow_mod. Openflow1.1之后版本flow_mod无变化*/ const struct ofp11_flow_mod *ofm; /* 获取flow_mod固定长度字段头其实是通过指针偏移指向buf,并非申请内存 * 主要是标准flow_mod, 在下面会把ofm相关值赋值到fm中。 */ ofm = ofpbuf_pull(&b, sizeof *ofm); /* 从b中移出大小为sizeof(*ofm) */ /* 获取flow_mod中的match数据赋值到fm->match中 * 如果存在多个oxm的话,也会同时解析出来的,而且所有的 * oxm做为一个flow流结构 */ error = ofputil_pull_ofp11_match(&b, &fm->match, NULL); if (error) { return error; } /* 解析instruction数据主要是解析action,将报文中action保存在ofpacts中*/ error = ofpacts_pull_openflow_instructions(&b, ofpbuf_size(&b), oh->version, ofpacts); if (error) { return error; } /* Translate the message. Flow_mod固定字段解析。这个地方其实没有什么需要讲解,纯粹赋值。*/ fm->priority = ntohs(ofm->priority); if (ofm->command == OFPFC_ADD || (oh->version == OFP11_VERSION && (ofm->command == OFPFC_MODIFY || ofm->command == OFPFC_MODIFY_STRICT) && ofm->cookie_mask == htonll(0))) { /* In OpenFlow 1.1 only, a "modify" or "modify-strict" that does * not match on the cookie is treated as an "add" if there is no * match. */ fm->cookie = htonll(0); fm->cookie_mask = htonll(0); fm->new_cookie = ofm->cookie; } else { fm->cookie = ofm->cookie; fm->cookie_mask = ofm->cookie_mask; fm->new_cookie = OVS_BE64_MAX; } fm->modify_cookie = false; fm->command = ofm->command; /* Get table ID. * * OF1.1 entirely forbids table_id == OFPTT_ALL. * OF1.2+ allows table_id == OFPTT_ALL only for deletes. */ fm->table_id = ofm->table_id; if (fm->table_id == OFPTT_ALL && (oh->version == OFP11_VERSION || (ofm->command != OFPFC_DELETE && ofm->command != OFPFC_DELETE_STRICT))) { return OFPERR_OFPFMFC_BAD_TABLE_ID; } fm->idle_timeout = ntohs(ofm->idle_timeout); fm->hard_timeout = ntohs(ofm->hard_timeout); fm->buffer_id = ntohl(ofm->buffer_id); error = ofputil_port_from_ofp11(ofm->out_port, &fm->out_port); if (error) { return error; } fm->out_group = (ofm->command == OFPFC_DELETE || ofm->command == OFPFC_DELETE_STRICT ? ntohl(ofm->out_group) : OFPG11_ANY); raw_flags = ofm->flags; } else { /* 这个else是针对openflow1.0的flow_mod消息进行解析的,我们可以忽略掉 */ } 最后一部分代码,主要内容就是常规校验,我也没有太深入阅读,这里为了保证一致性还是顺便提一下。 /* * 保存actions。因为fm是抽象层flow_mod,在最后生成流表项的时候需要这个。 */ fm->ofpacts = ofpbuf_data(ofpacts); fm->ofpacts_len = ofpbuf_size(ofpacts); error=ofputil_decode_flow_mod_flags(raw_flags,fm->command,oh->version, &fm->flags); if (error) { return error; } if (fm->flags & OFPUTIL_FF_EMERG) { /* We do not support the OpenFlow 1.0 emergency flow cache, which * is not required in OpenFlow 1.0.1 and removed from OpenFlow 1.1. * * OpenFlow 1.0 specifies the error code to use when idle_timeout * or hard_timeout is nonzero. Otherwise, there is no good error * code, so just state that the flow table is full. */ return (fm->hard_timeout || fm->idle_timeout ? OFPERR_OFPFMFC_BAD_EMERG_TIMEOUT : OFPERR_OFPFMFC_TABLE_FULL); } /* 校验action */ return ofpacts_check_consistency(fm->ofpacts, fm->ofpacts_len, &fm->match.flow, max_port, fm->table_id, max_table, protocol); } /* 整个函数结束 */ |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | /* * strict – 是否需要严格检查 * b – 保存match的原始报文buf * match – 保存解析后的match 输出参数 */ static enum ofperr oxm_pull_match__(struct ofpbuf *b, bool strict, struct match *match) { struct ofp11_match_header *omh = ofpbuf_data(b); /* 获取match head指针 */ uint8_t *p; uint16_t match_len; if (ofpbuf_size(b) < sizeof *omh) { return OFPERR_OFPBMC_BAD_LEN; } match_len = ntohs(omh->length); if (match_len < sizeof *omh) { return OFPERR_OFPBMC_BAD_LEN; } if (omh->type != htons(OFPMT_OXM)) { return OFPERR_OFPBMC_BAD_TYPE; } /* 尝试将缓冲区b中移除大小为match_len数据 * 经过下面这个函数处理之后,缓冲区b里面已经没有match相关数据, * 剩下就是instruction域 */ p = ofpbuf_try_pull(b, ROUND_UP(match_len, 8)); if (!p) { VLOG_DBG_RL(&rl, "oxm length %u, rounded up to a " "multiple of 8, is longer than space in message (max " "length %"PRIu32")", match_len, ofpbuf_size(b)); return OFPERR_OFPBMC_BAD_LEN; } /* * 解析一下这个函数实参: * p + sizeof *omh == 跳过match头部 * match_len - sizeof *omh == 总长度减去match头部长度,即实际报文内容长度。 */ return nx_pull_raw(p + sizeof *omh, match_len - sizeof *omh, strict, match, NULL, NULL); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | const struct mf_field mf_fields[MFF_N_IDS] = { /* ## -------- ## */ /* ## metadata ## */ /* ## -------- ## */ { MFF_DP_HASH, "dp_hash", NULL, MF_FIELD_SIZES(be32), MFM_FULLY, MFS_HEXADECIMAL, MFP_NONE, false, NXM_NX_DP_HASH, "NXM_NX_DP_HASH", NXM_NX_DP_HASH, "NXM_NX_DP_HASH", 0, OFPUTIL_P_NXM_OXM_ANY, OFPUTIL_P_NXM_OXM_ANY, -1, }, {… } /* ## -- ## */ /* ## L2层以太网层 ## */ /* ## -- ## */ {/*源mac地址 */ MFF_ETH_SRC, "eth_src", "dl_src", MF_FIELD_SIZES(mac), MFM_FULLY, MFS_ETHERNET, MFP_NONE, true, NXM_OF_ETH_SRC, "NXM_OF_ETH_SRC", OXM_OF_ETH_SRC, "OXM_OF_ETH_SRC", OFP12_VERSION, OFPUTIL_P_ANY, OFPUTIL_P_NXM_OF11_UP, /* Bitwise masking only with NXM and OF11+! */ -1, }, {/* 目的mac地址 */ MFF_ETH_DST, "eth_dst", "dl_dst", MF_FIELD_SIZES(mac), MFM_FULLY, MFS_ETHERNET, MFP_NONE, true, NXM_OF_ETH_DST, "NXM_OF_ETH_DST", OXM_OF_ETH_DST, "OXM_OF_ETH_DST", OFP12_VERSION, OFPUTIL_P_ANY, OFPUTIL_P_NXM_OF11_UP, /* Bitwise masking only with NXM and OF11+! */ -1, }, {/*以太网类型*/ MFF_ETH_TYPE, "eth_type", "dl_type", MF_FIELD_SIZES(be16), MFM_NONE, MFS_HEXADECIMAL, MFP_NONE, false, NXM_OF_ETH_TYPE, "NXM_OF_ETH_TYPE", OXM_OF_ETH_TYPE, "OXM_OF_ETH_TYPE", OFP12_VERSION, OFPUTIL_P_ANY, OFPUTIL_P_NONE, -1, },{…} /* ## ---- ## */ /* ## L2.5层 ## */ /* ## ---- ## */ {…} /* ## ---- ## */ /* ## L3层 ## */ /* ## ---- ## */ {…} } /* 数组结束 */ |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | /* * p -- 指向第一个oxm字段起始内存位置 * match_len = 整个match字段-match头部长度即所有oxm字段长度,不包括padding * strict 是否需要严格检查 * match 存储match数据(出参) */ static enum ofperr nx_pull_raw(const uint8_t *p, unsigned int match_len, bool strict, struct match *match, ovs_be64 *cookie, ovs_be64 *cookie_mask) { uint32_t header; ovs_assert((cookie != NULL) == (cookie_mask != NULL)); match_init_catchall(match); /* init match. */ if (cookie) { *cookie = *cookie_mask = htonll(0); } if (!match_len) { return 0; } /* 我们分析一下for的条件 * 1、可能有多个oxm字段因此需要一个一个遍历 * 标准里面oxm头部只能说类tlv格式,为什么说是类tlv呢? * 标准tlv格式 t和l是两个字节(有的是4个字节),而oxm中tlv * t = 3个字节,l = 1个字节其中t中前两个字节是表示类型, * 最后一个字节是又被分成两部分,高7位表示子类型,最后一位代表是否存在mask (根据上面报文可以知道) * * 2、for循环中魔鬼数字4表示tlv中header字段长度,也就是说header是固长度 * 3、函数nx_entry_ok 其实是拷贝oxm header部分(4个字节)到变量uint32 header中,对于上面报文中第一个oxm,这个header=0x80000606。 * 4、宏NXM_LENGTH是用于获取tlv中length值。就是header&0xff。针对上面header是0x80000606,与oxff与操作后正好是6。通过报文查看length的确是6。 * 5、每解析一次oxm,p就要指向下一个oxm起始位置,match_len就要减去对应长度。 */ for (; (header = nx_entry_ok(p, match_len)) != 0; p += 4 + NXM_LENGTH(header), match_len -= 4 + NXM_LENGTH(header)) { const struct mf_field *mf; enum ofperr error; mf = mf_from_nxm_header(header); /* 从hmap中获取mf,mf这个数组在上面已经介绍过!!这里就不详细介绍了*/ if (!mf) { if (strict) { error = OFPERR_OFPBMC_BAD_FIELD; } else { continue; } } else if (!mf_are_prereqs_ok(mf, &match->flow)) { error = OFPERR_OFPBMC_BAD_PREREQ; } else if (!mf_is_all_wild(mf, &match->wc)) { error = OFPERR_OFPBMC_DUP_FIELD; } else { unsigned int width = mf->n_bytes; union mf_value value; /* 这个地方的value是一个联合,设计非常巧妙,可以同时满足各种类型。 */ memcpy(&value, p + 4, width); /* 将tlv(match)中的value字段赋值到value变量*/ if (!mf_is_value_valid(mf, &value)) { error = OFPERR_OFPBMC_BAD_VALUE; } else if (!NXM_HASMASK(header)) {/* 没有设置mask标志会进入此分支针对上面报文,会进入这个分支的!!*/ error = 0; mf_set_value(mf, &value, match); /* 上面已经说过了value是一个联合类型,因此在mf赋值的时候需要进行类型判断,才能正确赋值。 */ } else {/* 设置了mask标志才会进入else分支 */ union mf_value mask; memcpy(&mask, p + 4 + width, width); if (!mf_is_mask_valid(mf, &mask)) { error = OFPERR_OFPBMC_BAD_MASK; } else { error = 0; check_mask_consistency(p, mf); mf_set(mf, &value, &mask, match); } } } /* 下面都一些基本校验,对于业务逻辑没有影响我们不进行深入分析 */ /* Check if the match is for a cookie rather than a classifier rule. */ if ((header == NXM_NX_COOKIE || header == NXM_NX_COOKIE_W) && cookie) { if (*cookie_mask) { error = OFPERR_OFPBMC_DUP_FIELD; } else { unsigned int width = sizeof *cookie; memcpy(cookie, p + 4, width); if (NXM_HASMASK(header)) { memcpy(cookie_mask, p + 4 + width, width); } else { *cookie_mask = OVS_BE64_MAX; } error = 0; } } if (error) { VLOG_DBG_RL(&rl, "bad nxm_entry %#08"PRIx32" (vendor=%"PRIu32", " "field=%"PRIu32", hasmask=%"PRIu32", len=%"PRIu32"), " "(%s)", header, NXM_VENDOR(header), NXM_FIELD(header), NXM_HASMASK(header), NXM_LENGTH(header), ofperr_to_string(error)); return error; } } return match_len ? OFPERR_OFPBMC_BAD_LEN : 0; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | enum ofperr ofpacts_pull_openflow_instructions(struct ofpbuf *openflow, unsigned int instructions_len, enum ofp_version version, struct ofpbuf *ofpacts) { const struct ofp11_instruction *instructions; /* 通过查看宏定义可知, N_OVS_INSTRUCTIONS=6 */ const struct ofp11_instruction *insts[N_OVS_INSTRUCTIONS]; enum ofperr error; ofpbuf_clear(ofpacts); /* 清空缓冲区输出参数保留action */ if (instructions_len % OFP11_INSTRUCTION_ALIGN != 0) { VLOG_WARN_RL(&rl, "OpenFlow message instructions length %u is not a " "multiple of %d", instructions_len, OFP11_INSTRUCTION_ALIGN); error = OFPERR_OFPBIC_BAD_LEN; goto exit; } /* 移除instructions_len大小内存数据instructions 保存数据起始位置*/ instructions = ofpbuf_try_pull(openflow, instructions_len); if (instructions == NULL) { VLOG_WARN_RL(&rl, "OpenFlow message instructions length %u exceeds " "remaining message length (%"PRIu32")", instructions_len, ofpbuf_size(openflow)); error = OFPERR_OFPBIC_BAD_LEN; goto exit; } /* * 解析openflow中instructions,并保存在指针数组out中 * 这个函数介绍重点。我们放到后面进行详细解说!! * 这里说一下insts这个指针数组,即每个数组元素都是一个指针,指针类型就是 * 标准instruction头部,其大小固定是6。这里insts就是上面表格,经过这个函数 * 处理之后就会把某一个数组单元设置成有效地址。 */ error = decode_openflow11_instructions( instructions, instructions_len / OFP11_INSTRUCTION_ALIGN, insts); if (error) { goto exit; } /* * 针对上面的解析结构即对out指针数组进行action解析 * 解析meter表 */ if (insts[OVSINST_OFPIT13_METER]) {… } /* * 应用action--解析,当前flowmod就这个!着重说一下这个, *其他无关代码已经删除 */ if (insts[OVSINST_OFPIT11_APPLY_ACTIONS]) { const union ofp_action *actions; size_t max_actions; /* * 可以有多个action * actions变量保存报文actions指针,这是一个联合结构。 * max_actions变量保存action个数 */ get_actions_from_instruction(insts[OVSINST_OFPIT11_APPLY_ACTIONS], &actions, &max_actions); /* * 解析action 保存在ofpacts * 通过不同类型判断,是openflow1.0还是openflow1.1。对于上面报文来说, * 最终调用解析函数是openflow1.1的函数即ofpact_from_openflow11。 * 注:actions这个变量时一个联合,这个地方涉及非常巧妙。 */ error = ofpacts_from_openflow(actions, max_actions, version, ofpacts); if (error) { goto exit; } } /* * 清空action--解析 */ if (insts[OVSINST_OFPIT11_CLEAR_ACTIONS]) {… } /* * 重写action--解析 */ if (insts[OVSINST_OFPIT11_WRITE_ACTIONS]) {… } /* * 重写元数据--解析 */ if (insts[OVSINST_OFPIT11_WRITE_METADATA]) {… } /* * 跳转流表--解析 */ if (insts[OVSINST_OFPIT11_GOTO_TABLE]) {… } error = ofpacts_verify(ofpbuf_data(ofpacts), ofpbuf_size(ofpacts)); exit: if (error) { ofpbuf_clear(ofpacts); } return error; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | static enum ofperr decode_openflow11_instruction(const struct ofp11_instruction *inst, enum ovs_instruction_type *type) { uint16_t len = ntohs(inst->len); switch (inst->type) { case CONSTANT_HTONS(OFPIT11_EXPERIMENTER): return OFPERR_OFPBIC_BAD_EXPERIMENTER; /* 该报文相关的case子句—apply_actions */ case CONSTANT_HTONS( OFPIT11_APPLY_ACTIONS ): if ( true ? len >= sizeof(struct ofp11_instruction_actions) : len == sizeof(struct ofp11_instruction_actions) ) { *type = OVSINST_OFPIT11_APPLY_ACTIONS;/* 返回枚举定义*/ return(0); } else { return(OFPERR_OFPBIC_BAD_LEN); } default: return OFPERR_OFPBIC_UNKNOWN_INST; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | static enum ofperr ofpact_from_openflow11(const union ofp_action *a, enum ofp_version version, struct ofpbuf *out) { enum ofputil_action_code code; enum ofperr error; struct ofpact_vlan_vid *vlan_vid; struct ofpact_vlan_pcp *vlan_pcp; error = decode_openflow11_action(a, &code); /* 这个函数和上面那个函数类似,也是通过宏定义构建的,也可以通过同样方式获取宏展开后代码。 */ if (error) { return error; } /* * openflow1.2+ 中部分消息将废弃掉 */ if (version >= OFP12_VERSION) { … } } switch (code) { case OFPUTIL_ACTION_INVALID: #define OFPAT10_ACTION(ENUM, STRUCT, NAME) case OFPUTIL_##ENUM: #define OFPAT13_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) case OFPUTIL_##ENUM: #include "ofp-util.def" OVS_NOT_REACHED; case OFPUTIL_OFPAT11_OUTPUT: /* 针对上面报来说,最终会进入这个case子句 */ return output_from_openflow11(&a->ofp11_output, out); /* 将ofp11_output中端口信息在保存out中。 */ … }//end switch 函数结束 } static enum ofperr output_from_openflow11(const struct ofp11_action_output *oao, struct ofpbuf *out) { struct ofpact_output *output; enum ofperr error; /* 这个函数是宏定义函数,最终调用是调用ofpact_put。宏定义位置:ofp_actions.h,689行 */ output = ofpact_put_OUTPUT(out); output->max_len = ntohs(oao->max_len); error = ofputil_port_from_ofp11(oao->port, &output->port); /* 将端口保存在output->port中。 */ if (error) { return error; } return ofpact_check_output_port(output->port, OFPP_MAX); /* 验证端口 */ } |
欢迎光临 51学通信论坛2017新版 (http://bbs.51xuetongxin.com/) | Powered by Discuz! X3 |