概述
端口镜像是交换机的标准功能之一,针对某个端口的报文拷贝到除真实目的之外的另外一个目的地(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);
}
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)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复