Added recirculation support for bond. A unique per datapath recirculation id is allocated whenever a bond is configured with balancing mode other than active/backup. This recirculation ID is freed back when bond configuration changes to active/backup mode or when the bond is no longer configured.
When the bond holds a valid recirculation id, any output to bond port actions will be replaced with hash and recirculation action. The post recirculation rules will also be set up soon after, when bond_run() is called. The post recirculation packet in datapath will miss again, causing the data path flows to be set up based on post recirculation rules set up in bridge's. The post recirculation rules are "hidden" rules similar to those setup to enable in-band controller communication. Signed-off-by: Andy Zhou <az...@nicira.com> --- include/linux/openvswitch.h | 1 + lib/dpif-netdev.c | 10 ++- lib/odp-execute.c | 4 +- ofproto/bond.c | 139 +++++++++++++++++++++++++++++++++++++++++- ofproto/bond.h | 6 +- ofproto/ofproto-dpif-xlate.c | 30 +++++++-- ofproto/ofproto-dpif-xlate.h | 2 + ofproto/ofproto-dpif.c | 10 ++- ofproto/ofproto-dpif.h | 2 + tests/ofproto-dpif.at | 139 ++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 330 insertions(+), 13 deletions(-) diff --git a/include/linux/openvswitch.h b/include/linux/openvswitch.h index 1dea78e..d0e74ac 100644 --- a/include/linux/openvswitch.h +++ b/include/linux/openvswitch.h @@ -533,6 +533,7 @@ struct ovs_action_push_vlan { /* * struct ovs_action_recirc - %OVS_ACTION_ATTR_RECIRC action argument. * @recirc_id: The Recirculation label, Zero is invalid. + * @dp_port: The output port label, Zero is invalid. */ struct ovs_action_recirc { uint32_t recirc_id; /* Recirculation label. */ diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index cb66c1e..374e337 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -1773,6 +1773,7 @@ dp_execute_cb(void *aux_, struct ofpbuf *packet, struct dp_netdev_execute_aux *aux = aux_; int type = nl_attr_type(a); struct dp_netdev_port *p; + const struct ovs_action_recirc *act_recirc; switch ((enum ovs_action_attr)type) { case OVS_ACTION_ATTR_OUTPUT: @@ -1798,6 +1799,14 @@ dp_execute_cb(void *aux_, struct ofpbuf *packet, } break; } + case OVS_ACTION_ATTR_RECIRC: + act_recirc = nl_attr_get(a); + p = dp_netdev_lookup_port(aux->dp, u32_to_odp(act_recirc->out_port)); + if (p) { + netdev_send(p->netdev, packet); + } + break; + case OVS_ACTION_ATTR_PUSH_VLAN: case OVS_ACTION_ATTR_POP_VLAN: case OVS_ACTION_ATTR_PUSH_MPLS: @@ -1806,7 +1815,6 @@ dp_execute_cb(void *aux_, struct ofpbuf *packet, case OVS_ACTION_ATTR_SAMPLE: case OVS_ACTION_ATTR_UNSPEC: case OVS_ACTION_ATTR_HASH: - case OVS_ACTION_ATTR_RECIRC: case __OVS_ACTION_ATTR_MAX: OVS_NOT_REACHED(); } diff --git a/lib/odp-execute.c b/lib/odp-execute.c index 20c36b8..daea700 100644 --- a/lib/odp-execute.c +++ b/lib/odp-execute.c @@ -195,6 +195,7 @@ odp_execute_actions__(void *dp, struct ofpbuf *packet, struct pkt_metadata *md, /* These only make sense in the context of a datapath. */ case OVS_ACTION_ATTR_OUTPUT: case OVS_ACTION_ATTR_USERSPACE: + case OVS_ACTION_ATTR_RECIRC: if (dp_execute_action) { /* Allow 'dp_execute_action' to steal the packet data if we do * not need it any more. */ @@ -233,7 +234,8 @@ odp_execute_actions__(void *dp, struct ofpbuf *packet, struct pkt_metadata *md, break; case OVS_ACTION_ATTR_HASH: - case OVS_ACTION_ATTR_RECIRC: + break; + case OVS_ACTION_ATTR_UNSPEC: case __OVS_ACTION_ATTR_MAX: OVS_NOT_REACHED(); diff --git a/ofproto/bond.c b/ofproto/bond.c index b4d9487..b100e19 100644 --- a/ofproto/bond.c +++ b/ofproto/bond.c @@ -23,6 +23,10 @@ #include <stdlib.h> #include <math.h> +#include "ofp-util.h" +#include "ofp-actions.h" +#include "ofpbuf.h" +#include "ofproto/ofproto-dpif.h" #include "connectivity.h" #include "coverage.h" #include "dynamic-string.h" @@ -36,6 +40,7 @@ #include "packets.h" #include "poll-loop.h" #include "seq.h" +#include "match.h" #include "shash.h" #include "timeval.h" #include "unixctl.h" @@ -46,6 +51,7 @@ VLOG_DEFINE_THIS_MODULE(bond); /* Bit-mask for hashing a flow down to a bucket. * There are (BOND_MASK + 1) buckets. */ #define BOND_MASK 0xff +#define BOND_RECIRC_RULE_PRIORITY 0xB07D0000 /* Recirc rule fixed priority. */ /* A hash bucket for mapping a flow to a slave. * "struct bond" has an array of (BOND_MASK + 1) of these. */ @@ -81,6 +87,7 @@ struct bond_slave { struct bond { struct hmap_node hmap_node; /* In 'all_bonds' hmap. */ char *name; /* Name provided by client. */ + struct ofproto *ofproto; /* The bridge this bond belongs to. */ /* Slaves. */ struct hmap slaves; @@ -98,6 +105,8 @@ struct bond { int rebalance_interval; /* Interval between rebalances, in ms. */ long long int next_rebalance; /* Next rebalancing time. */ bool send_learning_packets; + uint32_t recirc_id; /* Non zero if recirculation can be used.*/ + struct hmap recirc_rules; /* Post recirculation rules. */ /* Legacy compatibility. */ long long int next_fake_iface_update; /* LLONG_MAX if disabled. */ @@ -106,6 +115,22 @@ struct bond { struct ovs_refcount ref_cnt; }; +/* What to do with an bond_recirc_rule. */ +enum bond_op { + ADD, /* Add the rule to ofproto's flow table. */ + DELETE, /* Delete the rule from the ofproto's flow table. */ + +}; + +/* A rule to add to or delete from ofproto's flow table. */ +struct bond_recirc_rule { + struct hmap_node hmap_node; + struct match match; + ofp_port_t out_ofport; + enum bond_op op; + +}; + static struct ovs_rwlock rwlock = OVS_RWLOCK_INITIALIZER; static struct hmap all_bonds__ = HMAP_INITIALIZER(&all_bonds__); static struct hmap *const all_bonds OVS_GUARDED_BY(rwlock) = &all_bonds__; @@ -174,15 +199,19 @@ bond_mode_to_string(enum bond_mode balance) { * The caller should register each slave on the new bond by calling * bond_slave_register(). */ struct bond * -bond_create(const struct bond_settings *s) +bond_create(const struct bond_settings *s, struct ofproto *ofproto) { struct bond *bond; bond = xzalloc(sizeof *bond); hmap_init(&bond->slaves); + bond->ofproto = ofproto; bond->next_fake_iface_update = LLONG_MAX; ovs_refcount_init(&bond->ref_cnt); + bond->recirc_id = 0; + hmap_init(&bond->recirc_rules); + bond_reconfigure(bond, s); return bond; } @@ -203,6 +232,7 @@ void bond_unref(struct bond *bond) { struct bond_slave *slave, *next_slave; + struct bond_recirc_rule *rule, *next_rule; if (!bond || ovs_refcount_unref(&bond->ref_cnt) != 1) { return; @@ -222,8 +252,69 @@ bond_unref(struct bond *bond) free(bond->hash); free(bond->name); - ovs_refcount_destroy(&bond->ref_cnt); + + HMAP_FOR_EACH_SAFE(rule, next_rule, hmap_node, &bond->recirc_rules) { + hmap_remove(&bond->recirc_rules, &rule->hmap_node); + free(rule); + } + hmap_destroy(&bond->recirc_rules); + + if (bond->recirc_id) { + ofproto_dpif_free_recirc_id(bond->ofproto, bond->recirc_id); + } + free(bond); + + ovs_refcount_destroy(&bond->ref_cnt); +} + +static void +add_recirc_rule(struct bond *bond, const struct match *match, ofp_port_t out_ofport) +{ + uint32_t hash = match_hash(match, 0); + struct bond_recirc_rule *rule; + + HMAP_FOR_EACH_WITH_HASH(rule, hmap_node, hash, &bond->recirc_rules) { + if (match_equal(&rule->match, match)) { + rule->op = ADD; + return; + } + } + + rule = xmalloc(sizeof *rule); + rule->match = *match; + rule->op = ADD; + rule->out_ofport = out_ofport; + hmap_insert(&bond->recirc_rules, &rule->hmap_node, hash); +} + +static void +update_recirc_rules(struct bond *bond) +{ + struct match match; + struct bond_recirc_rule *rule; + int i; + + HMAP_FOR_EACH(rule, hmap_node, &bond->recirc_rules) { + rule->op = DELETE; + } + + if ((bond->hash == NULL) || (!bond->recirc_id)) + return; + + for (i = 0; i < BOND_MASK + 1; i++) { + struct bond_slave *slave = bond->hash[i].slave; + + if (slave) { + struct ofport *ofport = slave->aux; + + match_init_catchall(&match); + match_set_recirc_id(&match, bond->recirc_id); + match_set_dp_hash_masked(&match, i, BOND_MASK); + + add_recirc_rule(bond, &match, ofport->ofp_port); + } + } } /* Updates 'bond''s overall configuration to 's'. @@ -286,6 +377,15 @@ bond_reconfigure(struct bond *bond, const struct bond_settings *s) bond->bond_revalidate = false; } + if (bond->balance != BM_AB) { + if (!bond->recirc_id) { + bond->recirc_id = ofproto_dpif_alloc_recirc_id(bond->ofproto); + } + } else if (bond -> recirc_id) { + ofproto_dpif_free_recirc_id(bond->ofproto, bond->recirc_id); + bond->recirc_id = 0; + } + if (bond->balance == BM_AB || !bond->hash || revalidate) { bond_entry_reset(bond); } @@ -425,6 +525,11 @@ bond_run(struct bond *bond, enum lacp_status lacp_status) { struct bond_slave *slave; bool revalidate; + struct bond_recirc_rule *rule, *next; + uint64_t ofpacts_stub[128 / 8]; + struct ofpbuf ofpacts; + + ofpbuf_use_stub(&ofpacts, ofpacts_stub, sizeof ofpacts_stub); ovs_rwlock_wrlock(&rwlock); if (bond->lacp_status != lacp_status) { @@ -447,6 +552,30 @@ bond_run(struct bond *bond, enum lacp_status lacp_status) bond->next_fake_iface_update = time_msec() + 1000; } + /* Update recirculation rules. */ + update_recirc_rules(bond); + + HMAP_FOR_EACH_SAFE(rule, next, hmap_node, &bond->recirc_rules) { + switch (rule->op) { + case ADD: + ofpbuf_clear(&ofpacts); + ofpact_put_OUTPUT(&ofpacts)->port = rule->out_ofport; + ofproto_add_flow(bond->ofproto, &rule->match, + BOND_RECIRC_RULE_PRIORITY, + ofpacts.data, ofpacts.size); + break; + case DELETE: + if (ofproto_delete_flow(bond->ofproto, &rule->match, + BOND_RECIRC_RULE_PRIORITY)) { + hmap_remove(&bond->recirc_rules, &rule->hmap_node); + free(rule); + } + break; + } + } + + ofpbuf_uninit(&ofpacts); + revalidate = bond->bond_revalidate; bond->bond_revalidate = false; ovs_rwlock_unlock(&rwlock); @@ -674,6 +803,12 @@ bond_choose_output_slave(struct bond *bond, const struct flow *flow, return aux; } + +uint32_t +bond_get_recirc_id(const struct bond *bond) +{ + return bond->recirc_id; +} /* Rebalancing. */ diff --git a/ofproto/bond.h b/ofproto/bond.h index 5b3814e..7a9455c 100644 --- a/ofproto/bond.h +++ b/ofproto/bond.h @@ -19,7 +19,7 @@ #include <stdbool.h> #include <stdint.h> - +#include "ofproto-provider.h" #include "packets.h" struct flow; @@ -60,7 +60,8 @@ struct bond_settings { void bond_init(void); /* Basics. */ -struct bond *bond_create(const struct bond_settings *); +struct bond *bond_create(const struct bond_settings *, + struct ofproto *ofproto); void bond_unref(struct bond *); struct bond *bond_ref(const struct bond *); @@ -95,5 +96,6 @@ void *bond_choose_output_slave(struct bond *, const struct flow *, void bond_account(struct bond *, const struct flow *, uint16_t vlan, uint64_t n_bytes); void bond_rebalance(struct bond *); +uint32_t bond_get_recirc_id(const struct bond *); #endif /* bond.h */ diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index 5b74dbb..2583d94 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -225,9 +225,9 @@ static void do_xlate_actions(const struct ofpact *, size_t ofpacts_len, struct xlate_ctx *); static void xlate_actions__(struct xlate_in *, struct xlate_out *) OVS_REQ_RDLOCK(xlate_rwlock); - static void xlate_normal(struct xlate_ctx *); - static void xlate_report(struct xlate_ctx *, const char *); - static void xlate_table_action(struct xlate_ctx *, ofp_port_t in_port, +static void xlate_normal(struct xlate_ctx *); +static void xlate_report(struct xlate_ctx *, const char *); +static void xlate_table_action(struct xlate_ctx *, ofp_port_t in_port, uint8_t table_id, bool may_packet_in); static bool input_vid_is_valid(uint16_t vid, struct xbundle *, bool warn); static uint16_t input_vid_to_vlan(const struct xbundle *, uint16_t vid); @@ -1146,6 +1146,8 @@ output_normal(struct xlate_ctx *ctx, const struct xbundle *out_xbundle, return; } + ctx->xout->recirc_id = bond_get_recirc_id(out_xbundle->bond); + if (ctx->xin->resubmit_stats) { bond_account(out_xbundle->bond, &ctx->xin->flow, vid, ctx->xin->resubmit_stats->n_bytes); @@ -1811,8 +1813,25 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, &ctx->xout->odp_actions, &ctx->xout->wc, &ctx->mpls_depth_delta); - nl_msg_put_odp_port(&ctx->xout->odp_actions, OVS_ACTION_ATTR_OUTPUT, - out_port); + if (ctx->xout->recirc_id) { + struct ovs_action_hash *act_hash; + struct ovs_action_recirc *act_recirc; + + act_hash = (struct ovs_action_hash *) + nl_msg_put_unspec_uninit(&ctx->xout->odp_actions, + OVS_ACTION_ATTR_HASH, sizeof *act_hash); + act_hash->hash_type = 0; + act_hash->bias = 0; + + act_recirc = (struct ovs_action_recirc *) + nl_msg_put_unspec_uninit(&ctx->xout->odp_actions, + OVS_ACTION_ATTR_RECIRC, sizeof *act_recirc); + act_recirc->recirc_id = ctx->xout->recirc_id; + act_recirc->out_port = odp_to_u32(out_port); + } else { + nl_msg_put_odp_port(&ctx->xout->odp_actions, OVS_ACTION_ATTR_OUTPUT, + out_port); + } ctx->sflow_odp_port = odp_port; ctx->sflow_n_outputs++; @@ -3103,6 +3122,7 @@ xlate_actions__(struct xlate_in *xin, struct xlate_out *xout) ctx.rule = rule; } xout->fail_open = ctx.rule && rule_dpif_is_fail_open(ctx.rule); + xout->recirc_id = 0; if (xin->ofpacts) { ofpacts = xin->ofpacts; diff --git a/ofproto/ofproto-dpif-xlate.h b/ofproto/ofproto-dpif-xlate.h index 982f1a4..4ffea6a 100644 --- a/ofproto/ofproto-dpif-xlate.h +++ b/ofproto/ofproto-dpif-xlate.h @@ -50,6 +50,8 @@ struct xlate_out { ofp_port_t nf_output_iface; /* Output interface index for NetFlow. */ mirror_mask_t mirrors; /* Bitmap of associated mirrors. */ + uint32_t recirc_id; /* !0 Use recirculation instead of output.*/ + uint64_t odp_actions_stub[256 / 8]; struct ofpbuf odp_actions; }; diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index b79f335..0d1cc4f 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -914,7 +914,7 @@ open_dpif_backer(const char *type, struct dpif_backer **backerp) } ovs_mutex_init(&backer->recirc_id_lock); - recirc_id_set_init(&backer->rids, 0, 0); + recirc_id_set_init(&backer->rids, 100, 0); return error; } @@ -2290,7 +2290,7 @@ bundle_set(struct ofproto *ofproto_, void *aux, ofproto->backer->need_revalidate = REV_RECONFIGURE; } } else { - bundle->bond = bond_create(s->bond); + bundle->bond = bond_create(s->bond, ofproto_); ofproto->backer->need_revalidate = REV_RECONFIGURE; } @@ -4547,6 +4547,12 @@ odp_port_to_ofp_port(const struct ofproto_dpif *ofproto, odp_port_t odp_port) } } +odp_port_t +ofpport_to_odp_port(const struct ofport_dpif *ofport) +{ + return ofport ? ofport->odp_port : ODPP_NONE; +} + const struct ofproto_class ofproto_dpif_class = { init, enumerate_types, diff --git a/ofproto/ofproto-dpif.h b/ofproto/ofproto-dpif.h index 898448a..2352b65 100644 --- a/ofproto/ofproto-dpif.h +++ b/ofproto/ofproto-dpif.h @@ -123,4 +123,6 @@ void ofproto_dpif_free_recirc_id(struct ofproto *ofproto_, uint32_t recirc_id); struct ofport_dpif *odp_port_to_ofport(const struct dpif_backer *, odp_port_t); +odp_port_t ofpport_to_odp_port(const struct ofport_dpif *ofport); + #endif /* ofproto-dpif.h */ diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at index 23a1f14..2bc2f10 100644 --- a/tests/ofproto-dpif.at +++ b/tests/ofproto-dpif.at @@ -46,6 +46,145 @@ skb_priority(0),in_port(8),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_ OVS_VSWITCHD_STOP AT_CLEANUP +AT_SETUP([ofproto-dpif, active-backup bonding]) +# Create br0 with interfaces p1, p2 and p7, creating bond0 with p1 and p2 +# and br1 with interfaces p3, p4 and p8. +# toggle p1,p2 of bond0 up and down to test bonding in active-backup mode. +OVS_VSWITCHD_START( + [add-bond br0 bond0 p1 p2 bond_mode=active-backup --\ + set interface p1 type=dummy options:pstream=punix:$OVS_RUNDIR/p1.sock ofport_request=1 -- \ + set interface p2 type=dummy options:pstream=punix:$OVS_RUNDIR/p2.sock ofport_request=2 -- \ + add-port br0 p7 -- set interface p7 ofport_request=7 type=dummy -- \ + add-br br1 -- \ + set bridge br1 other-config:hwaddr=aa:66:aa:66:00:00 -- \ + set bridge br1 datapath-type=dummy other-config:datapath-id=1234 \ + fail-mode=secure -- \ + add-port br1 p3 -- set interface p3 type=dummy options:stream=unix:$OVS_RUNDIR/p1.sock ofport_request=3 -- \ + add-port br1 p4 -- set interface p4 type=dummy options:stream=unix:$OVS_RUNDIR/p2.sock ofport_request=4 -- \ + add-port br1 p8 -- set interface p8 ofport_request=8 type=dummy --]) + +AT_CHECK([ovs-ofctl add-flow br0 action=normal]) +AT_CHECK([ovs-ofctl add-flow br1 action=normal]) +ovs-appctl netdev-dummy/set-admin-state up +ovs-appctl netdev-dummy/set-admin-state p2 down +ovs-appctl time/stop +ovs-appctl time/warp 100 +AT_CHECK([ovs-appctl netdev-dummy/receive p7 'in_port(7),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)']) +AT_CHECK([ovs-appctl netdev-dummy/receive p7 'in_port(7),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.3,dst=10.0.0.4,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)']) +ovs-appctl time/warp 100 +ovs-appctl netdev-dummy/set-admin-state p2 up +ovs-appctl netdev-dummy/set-admin-state p1 down +ovs-appctl time/warp 100 +AT_CHECK([ovs-appctl netdev-dummy/receive p7 'in_port(7),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0d),eth_type(0x0800),ipv4(src=10.0.0.5,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)']) +AT_CHECK([ovs-appctl netdev-dummy/receive p7 'in_port(7),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0e),eth_type(0x0800),ipv4(src=10.0.0.6,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)']) +ovs-appctl time/warp 100 +AT_CHECK([ovs-appctl dpif/dump-flows br1 | STRIP_XOUT], [0], [dnl +skb_priority(0),in_port(3),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:never, actions: <del> +skb_priority(0),in_port(3),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.3/0.0.0.0,dst=10.0.0.4/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:never, actions: <del> +skb_priority(0),in_port(4),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0d),eth_type(0x0800),ipv4(src=10.0.0.5/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:never, actions: <del> +skb_priority(0),in_port(4),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0e),eth_type(0x0800),ipv4(src=10.0.0.6/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:never, actions: <del> +skb_priority(0),in_port(4),eth(src=50:54:00:00:00:09,dst=ff:ff:ff:ff:ff:ff),eth_type(0x8035), packets:0, bytes:0, used:never, actions: <del> +skb_priority(0),in_port(4),eth(src=50:54:00:00:00:0b,dst=ff:ff:ff:ff:ff:ff),eth_type(0x8035), packets:0, bytes:0, used:never, actions: <del> +]) +OVS_VSWITCHD_STOP +AT_CLEANUP + +AT_SETUP([ofproto-dpif, balance-slb bonding]) +# Create br0 with interfaces bond0(p1, p2, p3) and p7, +# and br1 with interfaces p4, p5, p6 and p8. +# p1 <-> p4, p2 <-> p5, p3 <-> p6 +# Send some traffic, make sure the traffic are spread based on source mac. +OVS_VSWITCHD_START( + [add-bond br0 bond0 p1 p2 p3 bond_mode=balance-slb --\ + set interface p1 type=dummy options:pstream=punix:$OVS_RUNDIR/p1.sock ofport_request=1 -- \ + set interface p2 type=dummy options:pstream=punix:$OVS_RUNDIR/p2.sock ofport_request=2 -- \ + set interface p3 type=dummy options:pstream=punix:$OVS_RUNDIR/p3.sock ofport_request=3 -- \ + add-port br0 p7 -- set interface p7 ofport_request=7 type=dummy -- \ + add-br br1 -- \ + set bridge br1 other-config:hwaddr=aa:66:aa:66:00:00 -- \ + set bridge br1 datapath-type=dummy other-config:datapath-id=1234 \ + fail-mode=secure -- \ + add-port br1 p4 -- set interface p4 type=dummy options:stream=unix:$OVS_RUNDIR/p1.sock ofport_request=4 -- \ + add-port br1 p5 -- set interface p5 type=dummy options:stream=unix:$OVS_RUNDIR/p2.sock ofport_request=5 -- \ + add-port br1 p6 -- set interface p6 type=dummy options:stream=unix:$OVS_RUNDIR/p3.sock ofport_request=6 -- \ + add-port br1 p8 -- set interface p8 ofport_request=8 type=dummy --]) + +AT_CHECK([ovs-ofctl add-flow br0 action=normal]) +AT_CHECK([ovs-ofctl add-flow br1 action=normal]) +ovs-appctl netdev-dummy/set-admin-state up +ovs-appctl time/stop +ovs-appctl time/warp 100 +( +for i in `seq 0 100 |xargs printf '%02x\n'`; + do + pkt="in_port(7),eth(src=50:54:00:00:00:$i,dst=50:54:00:00:01:00),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)" + AT_CHECK([ovs-appctl netdev-dummy/receive p7 $pkt]) + done +) +ovs-appctl time/warp 100 +AT_CHECK([ovs-appctl dpif/dump-flows br1 > br1_flows.txt]) +# Make sure there is resonable distribution to all three ports. +# We don't want to make this check precise, in case hash function changes. +AT_CHECK([test `egrep 'in_port\(4\)' br1_flows.txt |wc -l` -gt 3]) +AT_CHECK([test `egrep 'in_port\(5\)' br1_flows.txt |wc -l` -gt 3]) +AT_CHECK([test `egrep 'in_port\(6\)' br1_flows.txt |wc -l` -gt 3]) +OVS_VSWITCHD_STOP +AT_CLEANUP + +AT_SETUP([ofproto-dpif, balance-tcp bonding]) +# Create br0 with interfaces bond0(p1, p2, p3) and p7, +# and br1 with interfaces bond1(p4, p5, p6) and p8. +# bond0 <-> bond1 +# Send some traffic, make sure the traffic are spread based on L4 headers. +OVS_VSWITCHD_START( + [add-bond br0 bond0 p1 p2 p3 bond_mode=balance-tcp lacp=active \ + other-config:lacp-time=fast other-config:bond-rebalance-interval=0 --\ + set interface p1 type=dummy options:pstream=punix:$OVS_RUNDIR/p1.sock ofport_request=1 -- \ + set interface p2 type=dummy options:pstream=punix:$OVS_RUNDIR/p2.sock ofport_request=2 -- \ + set interface p3 type=dummy options:pstream=punix:$OVS_RUNDIR/p3.sock ofport_request=3 -- \ + add-port br0 p7 -- set interface p7 ofport_request=7 type=dummy -- \ + add-br br1 -- \ + set bridge br1 other-config:hwaddr=aa:66:aa:66:00:00 -- \ + set bridge br1 datapath-type=dummy other-config:datapath-id=1234 \ + fail-mode=secure -- \ + add-bond br1 bond1 p4 p5 p6 bond_mode=balance-tcp lacp=active \ + other-config:lacp-time=fast other-config:bond-rebalance-interval=0 --\ + set interface p4 type=dummy options:stream=unix:$OVS_RUNDIR/p1.sock ofport_request=4 -- \ + set interface p5 type=dummy options:stream=unix:$OVS_RUNDIR/p2.sock ofport_request=5 -- \ + set interface p6 type=dummy options:stream=unix:$OVS_RUNDIR/p3.sock ofport_request=6 -- \ + add-port br1 p8 -- set interface p8 ofport_request=8 type=dummy --]) + +ovs-appctl netdev-dummy/set-admin-state up +AT_CHECK([ovs-ofctl add-flow br0 action=normal]) +AT_CHECK([ovs-ofctl add-flow br1 action=normal]) +AT_CHECK([ovs-appctl upcall/disable-megaflows], [0], [megaflows disabled +], []) +AT_CHECK([ovs-appctl vlog/set :dbg], [0], [], []) +ovs-appctl time/stop +ovs-appctl time/warp 100 +ovs-appctl time/warp 100 +ovs-appctl time/warp 100 +ovs-appctl lacp/show > lacp.txt +ovs-appctl bond/show > bond.txt +( +for i in `seq 10 100` ; + do + pkt="in_port(7),eth(src=50:54:00:00:00:05,dst=50:54:00:00:01:00),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=$i),tcp_flags(0x010)" + AT_CHECK([ovs-appctl netdev-dummy/receive p7 $pkt]) + done +) +ovs-appctl time/warp 100 +ovs-appctl dpif/dump-flows br1 > br1.txt +ovs-appctl dpif/dump-flows br0 > br0.txt +AT_CHECK([ovs-appctl dpif/dump-flows br1 > br1_flows.txt]) +# Make sure there is resonable distribution to all three ports. +# We don't want to make this check precise, in case hash function changes. +AT_CHECK([test `egrep 'in_port.4' br1_flows.txt |wc -l` -gt 10]) +AT_CHECK([test `egrep 'in_port.5' br1_flows.txt |wc -l` -gt 10]) +AT_CHECK([test `egrep 'in_port.6' br1_flows.txt |wc -l` -gt 10]) +OVS_VSWITCHD_STOP +AT_CLEANUP + AT_SETUP([ofproto-dpif - resubmit]) OVS_VSWITCHD_START ADD_OF_PORTS([br0], [1], [10], [11], [12], [13], [14], [15], -- 1.7.9.5 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev