Consider following setup: br0: phy-port random-port patch-to-br-int
br-int: port-1 port-2 patch-to-br0 And the expected traffic pattern: phy-port ---> port-1 ---> port-2 ---> phy-port For example, this could be done if 'port-1' and 'port-2' are ports of two VMs and we have some service chain PHY --> VM1 --> VM2 --> PHY. In case we have a unidirectional packet stream (UDP), VM1 will never send packets outside the integration bridge (br-int). This will lead to situation where the physical bridge (br0) will expire the mac of 'port-1' from the mac learning table after some time and will never know it again, causing constant flooding inside the physical bridge (br0): # ovs-appctl ofproto/trace \ br0 "in_port=phy-port,ip,eth_src=<SRC>,eth_dst=<DST>" Flow: ip,in_port=1,dl_src=<SRC>,dl_dst=<DST> bridge("br0") ----------------- 0. priority 0 NORMAL -> no learned MAC for destination, flooding bridge("br-int") ---------------- 0. in_port=patch-to-br0, priority 0 NORMAL -> forwarding to learned port Final flow: unchanged Megaflow: recirc_id=0,eth,ip,in_port=phy-port,dl_src=<SRC>,dl_dst=<DST> Datapath actions: br0,random-port,port-1 This is unwanted because 'br-int' knows that the desired mac is behind the 'port-1' and sends packets directly, while 'br0' keeps flooding the packets to all the ports significantly reducing performance. Since bridges connected via patch ports are almost the same L2 bridge, they should share L2 learning information in order to avoid such conditions. This could be implemented by flooding of the mac learning information over the patch ports while updating the learning tables. Signed-off-by: Ilya Maximets <i.maxim...@samsung.com> --- Not fully tested. ofproto/ofproto-dpif-xlate.c | 66 ++++++++++++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 7 deletions(-) diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index 73966a4e8..11d04e049 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -34,6 +34,7 @@ #include "csum.h" #include "dp-packet.h" #include "dpif.h" +#include "hmapx.h" #include "in-band.h" #include "lacp.h" #include "learn.h" @@ -544,7 +545,7 @@ static void xlate_table_action(struct xlate_ctx *, ofp_port_t in_port, bool is_last_action, xlate_actions_handler *); static bool input_vid_is_valid(const struct xlate_ctx *, - uint16_t vid, struct xbundle *); + uint16_t vid, const struct xbundle *); static void xvlan_copy(struct xvlan *dst, const struct xvlan *src); static void xvlan_pop(struct xvlan *src); static void xvlan_push_uninit(struct xvlan *src); @@ -2181,7 +2182,7 @@ mirror_ingress_packet(struct xlate_ctx *ctx) * 0...4095. */ static bool input_vid_is_valid(const struct xlate_ctx *ctx, - uint16_t vid, struct xbundle *in_xbundle) + uint16_t vid, const struct xbundle *in_xbundle) { /* Allow any VID on the OFPP_NONE port. */ if (in_xbundle == &ofpp_none_bundle) { @@ -2554,7 +2555,8 @@ is_admissible(struct xlate_ctx *ctx, struct xport *in_port, static bool update_learning_table__(const struct xbridge *xbridge, - struct xbundle *in_xbundle, struct eth_addr dl_src, + const struct xbundle *in_xbundle, + struct eth_addr dl_src, int vlan, bool is_grat_arp) { return (in_xbundle == &ofpp_none_bundle @@ -2565,10 +2567,48 @@ update_learning_table__(const struct xbridge *xbridge, } static void -update_learning_table(const struct xlate_ctx *ctx, - struct xbundle *in_xbundle, struct eth_addr dl_src, - int vlan, bool is_grat_arp) +update_learning_table_with_flood(struct xlate_ctx *ctx, + const struct xbundle *in_xbundle, + struct eth_addr dl_src, + const struct xvlan *xvlan, bool is_grat_arp, + struct hmapx *updated_bridges) { + struct xport *xport; + int vlan = xvlan->v[0].vid; + + /* Prevent updating the same bridge twice. */ + hmapx_add(updated_bridges, CONST_CAST(void *, ctx->xbridge)); + + /* Flooding the mac updates through the peers. */ + HMAP_FOR_EACH (xport, ofp_node, &ctx->xbridge->xports) { + if (xport->peer + && !hmapx_contains(updated_bridges, xport->peer->xbridge) + && xport->xbundle + && xport->xbundle != in_xbundle + && xport->xbundle->ofbundle != in_xbundle->ofbundle + && xbundle_includes_vlan(xport->xbundle, xvlan) + && xport->xbundle->floodable + && !xbundle_mirror_out(ctx->xbridge, xport->xbundle)) { + + const struct xbridge *xbridge_orig = ctx->xbridge; + const struct xbundle *peer_xbundle = xport->peer->xbundle; + struct xvlan out_xvlan, peer_xvlan; + + xvlan_output_translate(xport->xbundle, xvlan, &out_xvlan); + if (!input_vid_is_valid(ctx, out_xvlan.v[0].vid, peer_xbundle)) { + continue; + } + xvlan_input_translate(peer_xbundle, &out_xvlan, &peer_xvlan); + + ctx->xbridge = xport->peer->xbridge; + update_learning_table_with_flood(ctx, peer_xbundle, dl_src, + &peer_xvlan, is_grat_arp, + updated_bridges); + ctx->xbridge = xbridge_orig; + } + } + + /* Update the current bridge. */ if (!update_learning_table__(ctx->xbridge, in_xbundle, dl_src, vlan, is_grat_arp)) { xlate_report_debug(ctx, OFT_DETAIL, "learned that "ETH_ADDR_FMT" is " @@ -2577,6 +2617,18 @@ update_learning_table(const struct xlate_ctx *ctx, } } +static void +update_learning_table(struct xlate_ctx *ctx, + const struct xbundle *in_xbundle, struct eth_addr dl_src, + const struct xvlan *xvlan, bool is_grat_arp) +{ + struct hmapx updated_bridges = HMAPX_INITIALIZER(&updated_bridges); + + update_learning_table_with_flood(ctx, in_xbundle, dl_src, xvlan, + is_grat_arp, &updated_bridges); + hmapx_destroy(&updated_bridges); +} + /* Updates multicast snooping table 'ms' given that a packet matching 'flow' * was received on 'in_xbundle' in 'vlan' and is either Report or Query. */ static void @@ -2984,7 +3036,7 @@ xlate_normal(struct xlate_ctx *ctx) && flow->packet_type == htonl(PT_ETH) && in_port->pt_mode != NETDEV_PT_LEGACY_L3 ) { - update_learning_table(ctx, in_xbundle, flow->dl_src, vlan, + update_learning_table(ctx, in_xbundle, flow->dl_src, &xvlan, is_grat_arp); } if (ctx->xin->xcache && in_xbundle != &ofpp_none_bundle) { -- 2.17.1 _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev