diff -Nru openvswitch-2.4.1/debian/changelog openvswitch-2.4.1/debian/changelog --- openvswitch-2.4.1/debian/changelog 2016-05-26 20:33:41.000000000 +0800 +++ openvswitch-2.4.1/debian/changelog 2016-11-15 14:11:50.000000000 +0800 @@ -1,3 +1,9 @@ +openvswitch (2.4.1-0ubuntu0.15.10.1~cloud0ubuntu1) trusty-liberty; urgency=medium + + * Fix Open vSwitch port mirroring only mirrors egress traffic. (LP: #1639273) + + -- Hui Xiang Sun, 13 Nov 2016 09:52:51 +0800 + openvswitch (2.4.1-0ubuntu0.15.10.1~cloud0) trusty-liberty; urgency=medium * New upstream release for the Ubuntu Cloud Archive. diff -Nru openvswitch-2.4.1/debian/patches/ovs-mirror-no-ingress-traffic.patch openvswitch-2.4.1/debian/patches/ovs-mirror-no-ingress-traffic.patch --- openvswitch-2.4.1/debian/patches/ovs-mirror-no-ingress-traffic.patch 1970-01-01 08:00:00.000000000 +0800 +++ openvswitch-2.4.1/debian/patches/ovs-mirror-no-ingress-traffic.patch 2016-11-15 14:14:14.000000000 +0800 @@ -0,0 +1,309 @@ +Description: Open vSwitch port mirroring only mirrors egress traffic + With a OpenStack(trusty-liberty) and Open vSwitch( 2.4.1-0ubuntu0.15.10.1~cloud0) +installation, spawned two VMs, when vm1's interface targeted as src and dst mirroring +to vm2's interface , only egress traffic of vm1's interface is mirrored, ingress traffic + does not appear on vm2's interface. +Author: Hui Xiang +Origin: backport + https://github.com/openvswitch/ovs/commit/7efbc3b7c4006caed79cc9afa799cd0f9b8f5d38 + https://github.com/openvswitch/ovs/commit/faa624b4f65311d7492d68858c4f81a56e3f8650 +Bug: https://bugs.launchpad.net/cloud-archive/+bug/1639273 +--- +This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ +Index: openvswitch-2.4.1/ofproto/ofproto-dpif-xlate.c +=================================================================== +--- openvswitch-2.4.1.orig/ofproto/ofproto-dpif-xlate.c 2016-03-22 21:09:54.454616648 +0800 ++++ openvswitch-2.4.1/ofproto/ofproto-dpif-xlate.c 2016-11-10 21:13:03.182905980 +0800 +@@ -1511,75 +1511,73 @@ + return NULL; + } + ++/* Mirrors the packet represented by 'ctx' to appropriate mirror destinations, ++ * given the packet is ingressing or egressing on 'xbundle', which has ingress ++ * or egress (as appropriate) mirrors 'mirrors'. */ + static void +-add_mirror_actions(struct xlate_ctx *ctx, const struct flow *orig_flow) ++mirror_packet(struct xlate_ctx *ctx, struct xbundle *xbundle, ++ mirror_mask_t mirrors) + { +- const struct xbridge *xbridge = ctx->xbridge; +- mirror_mask_t mirrors; +- struct xbundle *in_xbundle; +- uint16_t vlan; +- uint16_t vid; +- +- mirrors = ctx->xout->mirrors; +- ctx->xout->mirrors = 0; +- +- in_xbundle = lookup_input_bundle(xbridge, orig_flow->in_port.ofp_port, +- ctx->xin->packet != NULL, NULL); +- if (!in_xbundle) { ++ /* 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; + } +- mirrors |= xbundle_mirror_src(xbridge, in_xbundle); ++ uint16_t vlan = input_vid_to_vlan(xbundle, vid); + +- /* Drop frames on bundles reserved for mirroring. */ +- if (xbundle_mirror_out(xbridge, in_xbundle)) { +- if (ctx->xin->packet != NULL) { +- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); +- VLOG_WARN_RL(&rl, "bridge %s: dropping packet received on port " +- "%s, which is reserved exclusively for mirroring", +- ctx->xbridge->name, in_xbundle->name); +- } +- ofpbuf_clear(ctx->xout->odp_actions); +- return; +- } ++ const struct xbridge *xbridge = ctx->xbridge; + +- /* Check VLAN. */ +- vid = vlan_tci_to_vid(orig_flow->vlan_tci); +- if (!input_vid_is_valid(vid, in_xbundle, ctx->xin->packet != NULL)) { ++ /* Don't mirror to destinations that we've already mirrored to. */ ++ mirrors &= ~ctx->xout->mirrors; ++ if (!mirrors) { + return; + } +- vlan = input_vid_to_vlan(in_xbundle, vid); + +- 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; + +- /* Restore the original packet before adding the mirror actions. */ +- ctx->xin->flow = *orig_flow; ++ 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; +- const unsigned long *vlans; +- bool vlan_mirrored; +- bool has_mirror; + int out_vlan; + +- has_mirror = mirror_get(xbridge->mbridge, raw_ctz(mirrors), +- &vlans, &dup_mirrors, &out, &out_vlan); ++ /* Get the details of the mirror represented by the rightmost 1-bit. */ ++ bool has_mirror = mirror_get(xbridge->mbridge, raw_ctz(mirrors), ++ &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->xout->wc.masks.vlan_tci |= htons(VLAN_CFI | VLAN_VID_MASK); + } +- vlan_mirrored = !vlans || bitmap_is_set(vlans, vlan); +- +- if (!vlan_mirrored) { ++ if (vlans && !bitmap_is_set(vlans, vlan)) { + mirrors = zero_rightmost_1bit(mirrors); + continue; + } + +- mirrors &= ~dup_mirrors; ++ /* 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->xout->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); +@@ -1587,7 +1585,7 @@ + output_normal(ctx, out_xbundle, vlan); + } + } else if (vlan != out_vlan +- && !eth_addr_is_reserved(orig_flow->dl_dst)) { ++ && !eth_addr_is_reserved(ctx->xin->flow.dl_dst)) { + struct xbundle *xbundle; + + LIST_FOR_EACH (xbundle, list_node, &xbridge->xbundles) { +@@ -1597,6 +1595,24 @@ + } + } + } ++ ++ /* output_normal() could have recursively output (to different ++ * mirrors), so make sure that we don't send duplicates. */ ++ mirrors &= ~ctx->xout->mirrors; ++ } ++} ++ ++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, ++ xbundle_mirror_src(ctx->xbridge, xbundle)); ++ } + } + } + +@@ -2784,11 +2800,6 @@ + } + } + +- if (mbridge_has_mirrors(ctx->xbridge->mbridge) && xport->xbundle) { +- ctx->xout->mirrors |= xbundle_mirror_dst(xport->xbundle->xbridge, +- xport->xbundle); +- } +- + if (xport->peer) { + const struct xport *peer = xport->peer; + struct flow old_flow = ctx->xin->flow; +@@ -3008,6 +3019,12 @@ + ctx->xout->nf_output_iface = ofp_port; + } + ++ if (mbridge_has_mirrors(ctx->xbridge->mbridge) && xport->xbundle) { ++ mirror_packet(ctx, xport->xbundle, ++ xbundle_mirror_dst(xport->xbundle->xbridge, ++ xport->xbundle)); ++ } ++ + out: + /* Restore flow */ + flow->vlan_tci = flow_vlan_tci; +@@ -4688,7 +4705,6 @@ + const struct ofpact *ofpacts; + struct xbridge *xbridge; + struct xport *in_port; +- struct flow orig_flow; + struct xlate_ctx ctx; + size_t ofpacts_len; + bool tnl_may_send; +@@ -4902,12 +4918,6 @@ + OVS_NOT_REACHED(); + } + +- if (mbridge_has_mirrors(xbridge->mbridge)) { +- /* Do this conditionally because the copy is expensive enough that it +- * shows up in profiles. */ +- orig_flow = *flow; +- } +- + /* Tunnel stats only for non-recirculated packets. */ + if (!xin->recirc && in_port && in_port->is_tunnel) { + if (ctx.xin->resubmit_stats) { +@@ -4950,6 +4960,7 @@ + } + + if (tnl_may_send && (!in_port || may_receive(in_port, &ctx))) { ++ mirror_ingress_packet(&ctx); + do_xlate_actions(ofpacts, ofpacts_len, &ctx); + + /* We've let OFPP_NORMAL and the learning action look at the +@@ -4989,11 +5000,6 @@ + if (!xin->recirc) { + fix_sflow_action(&ctx); + } +- /* Only mirror fully processed packets. */ +- if (!exit_recirculates(&ctx) +- && mbridge_has_mirrors(xbridge->mbridge)) { +- add_mirror_actions(&ctx, &orig_flow); +- } + } + + if (nl_attr_oversized(ctx.xout->odp_actions->size)) { +@@ -5008,22 +5014,6 @@ + ctx.xout->slow |= SLOW_ACTION; + } + +- /* Update mirror stats only for packets really received by the bridge. */ +- if (!xin->recirc && mbridge_has_mirrors(xbridge->mbridge)) { +- if (ctx.xin->resubmit_stats) { +- mirror_update_stats(xbridge->mbridge, xout->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 = xout->mirrors; +- } +- } +- + /* Do netflow only for packets really received by the bridge. */ + if (!xin->recirc && xbridge->netflow) { + /* Only update netflow if we don't have controller flow. We don't +Index: openvswitch-2.4.1/tests/ofproto-dpif.at +=================================================================== +--- openvswitch-2.4.1.orig/tests/ofproto-dpif.at 2016-11-13 09:31:57.596828378 +0800 ++++ openvswitch-2.4.1/tests/ofproto-dpif.at 2016-11-13 09:34:01.496832999 +0800 +@@ -3951,13 +3951,13 @@ + flow="in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no),icmp(type=8,code=0)" + AT_CHECK([ovs-appctl ofproto/trace ovs-dummy "$flow"], [0], [stdout]) + AT_CHECK_UNQUOTED([tail -1 stdout], [0], +- [Datapath actions: 2,3 ++ [Datapath actions: 3,2 + ]) + + flow="in_port(2),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no),icmp(type=8,code=0)" + AT_CHECK([ovs-appctl ofproto/trace ovs-dummy "$flow"], [0], [stdout]) + AT_CHECK_UNQUOTED([tail -1 stdout], [0], +- [Datapath actions: 1,3 ++ [Datapath actions: 3,1 + ]) + + OVS_VSWITCHD_STOP +@@ -3981,7 +3981,7 @@ + flow="in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no),icmp(type=8,code=0)" + AT_CHECK([ovs-appctl ofproto/trace ovs-dummy "$flow"], [0], [stdout]) + AT_CHECK_UNQUOTED([tail -1 stdout], [0], +- [Datapath actions: 2,3 ++ [Datapath actions: 3,2 + ]) + + flow="in_port(2),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no),icmp(type=8,code=0)" +@@ -4071,7 +4071,7 @@ + flow="in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x8100),vlan(vid=11,pcp=0),encap(eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no),icmp(type=8,code=0))" + AT_CHECK([ovs-appctl ofproto/trace ovs-dummy "$flow"], [0], [stdout]) + AT_CHECK_UNQUOTED([tail -1 stdout], [0], +- [Datapath actions: 2,3 ++ [Datapath actions: 3,2 + ]) + + OVS_VSWITCHD_STOP +@@ -4095,13 +4095,13 @@ + flow="in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no),icmp(type=8,code=0)" + AT_CHECK([ovs-appctl ofproto/trace ovs-dummy "$flow"], [0], [stdout]) + AT_CHECK_UNQUOTED([tail -1 stdout], [0], +- [Datapath actions: push_vlan(vid=17,pcp=0),2,pop_vlan,3 ++ [Datapath actions: 3,push_vlan(vid=17,pcp=0),2 + ]) + + flow="in_port(2),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no),icmp(type=8,code=0)" + AT_CHECK([ovs-appctl ofproto/trace ovs-dummy "$flow"], [0], [stdout]) + AT_CHECK_UNQUOTED([tail -1 stdout], [0], +- [Datapath actions: 1,3 ++ [Datapath actions: 3,1 + ]) + + OVS_VSWITCHD_STOP diff -Nru openvswitch-2.4.1/debian/patches/series openvswitch-2.4.1/debian/patches/series --- openvswitch-2.4.1/debian/patches/series 2015-09-28 22:30:37.000000000 +0800 +++ openvswitch-2.4.1/debian/patches/series 2016-11-13 09:50:27.000000000 +0800 @@ -1 +1,2 @@ ovs-ctl-dpdk.patch +ovs-mirror-no-ingress-traffic.patch