Signed-off-by: Jarno Rajahalme <jrajaha...@nicira.com> --- v3: Fix byte order errors.
include/openflow/nicira-ext.h | 24 ++++++++++++ lib/ofp-actions.c | 82 +++++++++++++++++++++++++++++++++++++++-- lib/ofp-actions.h | 22 ++++++++++- lib/ofp-parse.c | 46 +++++++++++++++++++++++ lib/ofp-util.c | 24 ++++++++---- lib/ofp-util.def | 4 ++ ofproto/ofproto-dpif-xlate.c | 62 +++++++++++++++++++++++++++++++ tests/ovs-ofctl.at | 9 +++-- 8 files changed, 256 insertions(+), 17 deletions(-) diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h index 3362a49..0cd62ea 100644 --- a/include/openflow/nicira-ext.h +++ b/include/openflow/nicira-ext.h @@ -312,6 +312,8 @@ enum nx_action_subtype { NXAST_STACK_PUSH, /* struct nx_action_stack */ NXAST_STACK_POP, /* struct nx_action_stack */ NXAST_SAMPLE, /* struct nx_action_sample */ + NXAST_SET_MPLS_LABEL, /* struct nx_action_ttl */ + NXAST_SET_MPLS_TC, /* struct nx_action_ttl */ }; /* Header for Nicira-defined actions. */ @@ -2261,6 +2263,28 @@ struct nx_action_pop_mpls { }; OFP_ASSERT(sizeof(struct nx_action_pop_mpls) == 16); +/* Action structure for NXAST_SET_MPLS_LABEL. */ +struct nx_action_mpls_label { + ovs_be16 type; /* OFPAT_VENDOR. */ + ovs_be16 len; /* Length is 8. */ + ovs_be32 vendor; /* NX_VENDOR_ID. */ + ovs_be16 subtype; /* NXAST_SET_MPLS_LABEL. */ + uint8_t zeros[2]; /* Must be zero. */ + ovs_be32 label; /* LABEL */ +}; +OFP_ASSERT(sizeof(struct nx_action_mpls_label) == 16); + +/* Action structure for NXAST_SET_MPLS_TC. */ +struct nx_action_mpls_tc { + ovs_be16 type; /* OFPAT_VENDOR. */ + ovs_be16 len; /* Length is 8. */ + ovs_be32 vendor; /* NX_VENDOR_ID. */ + ovs_be16 subtype; /* NXAST_SET_MPLS_TC. */ + uint8_t tc; /* TC */ + uint8_t pad[5]; +}; +OFP_ASSERT(sizeof(struct nx_action_mpls_tc) == 16); + /* Action structure for NXAST_SET_MPLS_TTL. */ struct nx_action_mpls_ttl { ovs_be16 type; /* OFPAT_VENDOR. */ diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c index 4713371..9ef1c12 100644 --- a/lib/ofp-actions.c +++ b/lib/ofp-actions.c @@ -53,6 +53,8 @@ union ofp_action { struct ofp11_action_push push; struct ofp11_action_pop_mpls ofp11_pop_mpls; struct ofp11_action_set_queue ofp11_set_queue; + struct ofp11_action_mpls_label ofp11_mpls_label; + struct ofp11_action_mpls_tc ofp11_mpls_tc; struct ofp11_action_mpls_ttl ofp11_mpls_ttl; struct ofp11_action_group group; struct ofp12_action_set_field set_field; @@ -77,6 +79,8 @@ union ofp_action { struct nx_action_pop_mpls pop_mpls; struct nx_action_sample sample; struct nx_action_learn learn; + struct nx_action_mpls_label mpls_label; + struct nx_action_mpls_tc mpls_tc; }; static enum ofperr @@ -473,6 +477,14 @@ ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code, OFPACT_MPLS_AFTER_VLAN, out); break; + case OFPUTIL_NXAST_SET_MPLS_LABEL: + ofpact_put_SET_MPLS_LABEL(out)->label = a->mpls_label.label; + break; + + case OFPUTIL_NXAST_SET_MPLS_TC: + ofpact_put_SET_MPLS_TC(out)->tc = a->mpls_tc.tc; + break; + case OFPUTIL_NXAST_SET_MPLS_TTL: ofpact_put_SET_MPLS_TTL(out)->ttl = a->mpls_ttl.ttl; break; @@ -993,13 +1005,13 @@ set_field_to_openflow(const struct ofpact_set_field *sf, return; case MFF_MPLS_LABEL: - /* ofputil_put_OFPAT11_SET_MPLS_LABEL(openflow)->label = - sf->value.be32; */ + ofputil_put_OFPAT11_SET_MPLS_LABEL(openflow)->mpls_label = + sf->value.be32; break; case MFF_MPLS_TC: - /* ofputil_put_OFPAT11_SET_MPLS_TC(openflow)->tc = - sf->value.u8; */ + ofputil_put_OFPAT11_SET_MPLS_TC(openflow)->mpls_tc = + sf->value.u8; break; case MFF_IPV4_SRC: @@ -1220,6 +1232,14 @@ ofpact_from_openflow11(const union ofp_action *a, enum ofp_version version, case OFPUTIL_OFPAT12_SET_FIELD: return set_field_from_openflow(&a->set_field, out); + case OFPUTIL_OFPAT11_SET_MPLS_LABEL: + ofpact_put_SET_MPLS_LABEL(out)->label = a->ofp11_mpls_label.mpls_label; + break; + + case OFPUTIL_OFPAT11_SET_MPLS_TC: + ofpact_put_SET_MPLS_TC(out)->tc = a->ofp11_mpls_tc.mpls_tc; + break; + case OFPUTIL_OFPAT11_SET_MPLS_TTL: ofpact_put_SET_MPLS_TTL(out)->ttl = a->ofp11_mpls_ttl.mpls_ttl; break; @@ -1273,6 +1293,8 @@ ofpact_is_set_action(const struct ofpact *a) case OFPACT_SET_IPV4_SRC: case OFPACT_SET_L4_DST_PORT: case OFPACT_SET_L4_SRC_PORT: + case OFPACT_SET_MPLS_LABEL: + case OFPACT_SET_MPLS_TC: case OFPACT_SET_MPLS_TTL: case OFPACT_SET_QUEUE: case OFPACT_SET_TUNNEL: @@ -1337,6 +1359,8 @@ ofpact_is_allowed_in_actions_set(const struct ofpact *a) case OFPACT_SET_IPV4_SRC: case OFPACT_SET_L4_DST_PORT: case OFPACT_SET_L4_SRC_PORT: + case OFPACT_SET_MPLS_LABEL: + case OFPACT_SET_MPLS_TC: case OFPACT_SET_MPLS_TTL: case OFPACT_SET_QUEUE: case OFPACT_SET_TUNNEL: @@ -1586,6 +1610,8 @@ ovs_instruction_type_from_ofpact_type(enum ofpact_type type) case OFPACT_STACK_PUSH: case OFPACT_STACK_POP: case OFPACT_DEC_TTL: + case OFPACT_SET_MPLS_LABEL: + case OFPACT_SET_MPLS_TC: case OFPACT_SET_MPLS_TTL: case OFPACT_DEC_MPLS_TTL: case OFPACT_PUSH_MPLS: @@ -1961,6 +1987,8 @@ ofpact_check__(struct ofpact *a, struct flow *flow, ofp_port_t max_ports, case OFPACT_STACK_POP: return nxm_stack_pop_check(ofpact_get_STACK_POP(a), flow); + case OFPACT_SET_MPLS_LABEL: + case OFPACT_SET_MPLS_TC: case OFPACT_SET_MPLS_TTL: case OFPACT_DEC_MPLS_TTL: if (!eth_type_mpls(flow->dl_type)) { @@ -2280,6 +2308,16 @@ ofpact_to_nxast(const struct ofpact *a, struct ofpbuf *out) ofpact_dec_ttl_to_nxast(ofpact_get_DEC_TTL(a), out); break; + case OFPACT_SET_MPLS_LABEL: + ofputil_put_NXAST_SET_MPLS_LABEL(out)->label + = ofpact_get_SET_MPLS_LABEL(a)->label; + break; + + case OFPACT_SET_MPLS_TC: + ofputil_put_NXAST_SET_MPLS_TC(out)->tc + = ofpact_get_SET_MPLS_TC(a)->tc; + break; + case OFPACT_SET_MPLS_TTL: ofputil_put_NXAST_SET_MPLS_TTL(out)->ttl = ofpact_get_SET_MPLS_TTL(a)->ttl; @@ -2483,6 +2521,8 @@ ofpact_to_openflow10(const struct ofpact *a, struct ofpbuf *out) case OFPACT_DEC_TTL: case OFPACT_SET_IP_ECN: case OFPACT_SET_IP_TTL: + case OFPACT_SET_MPLS_LABEL: + case OFPACT_SET_MPLS_TC: case OFPACT_SET_MPLS_TTL: case OFPACT_DEC_MPLS_TTL: case OFPACT_SET_TUNNEL: @@ -2626,6 +2666,16 @@ ofpact_to_openflow11(const struct ofpact *a, struct ofpbuf *out) ofpact_dec_ttl_to_openflow11(ofpact_get_DEC_TTL(a), out); break; + case OFPACT_SET_MPLS_LABEL: + ofputil_put_OFPAT11_SET_MPLS_LABEL(out)->mpls_label + = ofpact_get_SET_MPLS_LABEL(a)->label; + break; + + case OFPACT_SET_MPLS_TC: + ofputil_put_OFPAT11_SET_MPLS_TC(out)->mpls_tc + = ofpact_get_SET_MPLS_TC(a)->tc; + break; + case OFPACT_SET_MPLS_TTL: ofputil_put_OFPAT11_SET_MPLS_TTL(out)->mpls_ttl = ofpact_get_SET_MPLS_TTL(a)->ttl; @@ -2710,6 +2760,8 @@ ofpact_to_openflow12(const struct ofpact *a, struct ofpbuf *out) case OFPACT_SET_IP_ECN: case OFPACT_SET_L4_SRC_PORT: case OFPACT_SET_L4_DST_PORT: + case OFPACT_SET_MPLS_LABEL: + case OFPACT_SET_MPLS_TC: case OFPACT_SET_TUNNEL: /* Convert to a set_field, too. */ switch ((int)a->type) { @@ -2791,6 +2843,16 @@ ofpact_to_openflow12(const struct ofpact *a, struct ofpbuf *out) value.be16 = htons(l4port->port); break; + case OFPACT_SET_MPLS_LABEL: + field = MFF_MPLS_LABEL; + value.be32 = ofpact_get_SET_MPLS_LABEL(a)->label; + break; + + case OFPACT_SET_MPLS_TC: + field = MFF_MPLS_TC; + value.u8 = ofpact_get_SET_MPLS_TC(a)->tc; + break; + case OFPACT_SET_TUNNEL: field = MFF_TUN_ID; value.be64 = htonll(ofpact_get_SET_TUNNEL(a)->tun_id); @@ -2975,6 +3037,8 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, ofp_port_t port) case OFPACT_STACK_PUSH: case OFPACT_STACK_POP: case OFPACT_DEC_TTL: + case OFPACT_SET_MPLS_LABEL: + case OFPACT_SET_MPLS_TC: case OFPACT_SET_MPLS_TTL: case OFPACT_DEC_MPLS_TTL: case OFPACT_SET_TUNNEL: @@ -3291,6 +3355,16 @@ ofpact_format(const struct ofpact *a, struct ds *s) print_dec_ttl(ofpact_get_DEC_TTL(a), s); break; + case OFPACT_SET_MPLS_LABEL: + ds_put_format(s, "set_mpls_label(%"PRIu32")", + ntohl(ofpact_get_SET_MPLS_LABEL(a)->label)); + break; + + case OFPACT_SET_MPLS_TC: + ds_put_format(s, "set_mpls_ttl(%"PRIu8")", + ofpact_get_SET_MPLS_TC(a)->tc); + break; + case OFPACT_SET_MPLS_TTL: ds_put_format(s, "set_mpls_ttl(%"PRIu8")", ofpact_get_SET_MPLS_TTL(a)->ttl); diff --git a/lib/ofp-actions.h b/lib/ofp-actions.h index 41579ce..a17688f 100644 --- a/lib/ofp-actions.h +++ b/lib/ofp-actions.h @@ -78,6 +78,8 @@ DEFINE_OFPACT(STACK_PUSH, ofpact_stack, ofpact) \ DEFINE_OFPACT(STACK_POP, ofpact_stack, ofpact) \ DEFINE_OFPACT(DEC_TTL, ofpact_cnt_ids, cnt_ids) \ + DEFINE_OFPACT(SET_MPLS_LABEL, ofpact_mpls_label, ofpact) \ + DEFINE_OFPACT(SET_MPLS_TC, ofpact_mpls_tc, ofpact) \ DEFINE_OFPACT(SET_MPLS_TTL, ofpact_mpls_ttl, ofpact) \ DEFINE_OFPACT(DEC_MPLS_TTL, ofpact_null, ofpact) \ DEFINE_OFPACT(PUSH_MPLS, ofpact_push_mpls, ofpact) \ @@ -552,9 +554,27 @@ struct ofpact_cnt_ids { uint16_t cnt_ids[]; }; +/* OFPACT_SET_MPLS_LABEL. + * + * Used for OFPAT11_SET_MPLS_LABEL and NXAST_SET_MPLS_LABEL */ +struct ofpact_mpls_label { + struct ofpact ofpact; + + ovs_be32 label; +}; + +/* OFPACT_SET_MPLS_TC. + * + * Used for OFPAT11_SET_MPLS_TC and NXAST_SET_MPLS_TC */ +struct ofpact_mpls_tc { + struct ofpact ofpact; + + uint8_t tc; +}; + /* OFPACT_SET_MPLS_TTL. * - * Used for NXAST_SET_MPLS_TTL */ + * Used for OFPAT11_SET_MPLS_TTL and NXAST_SET_MPLS_TTL */ struct ofpact_mpls_ttl { struct ofpact ofpact; diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c index 7b19dc0..5ad2255 100644 --- a/lib/ofp-parse.c +++ b/lib/ofp-parse.c @@ -438,6 +438,42 @@ parse_dec_ttl(struct ofpbuf *b, char *arg) return NULL; } +/* Parses 'arg' as the argument to a "set_mpls_label" action, and appends such + * an action to 'b'. + * + * Returns NULL if successful, otherwise a malloc()'d string describing the + * error. The caller is responsible for freeing the returned string. */ +static char * WARN_UNUSED_RESULT +parse_set_mpls_label(struct ofpbuf *b, const char *arg) +{ + struct ofpact_mpls_label *mpls_label = ofpact_put_SET_MPLS_LABEL(b); + + if (*arg == '\0') { + return xstrdup("parse_set_mpls_label: expected label."); + } + + mpls_label->label = htonl(atoi(arg)); + return NULL; +} + +/* Parses 'arg' as the argument to a "set_mpls_tc" action, and appends such an + * action to 'b'. + * + * Returns NULL if successful, otherwise a malloc()'d string describing the + * error. The caller is responsible for freeing the returned string. */ +static char * WARN_UNUSED_RESULT +parse_set_mpls_tc(struct ofpbuf *b, const char *arg) +{ + struct ofpact_mpls_tc *mpls_tc = ofpact_put_SET_MPLS_TC(b); + + if (*arg == '\0') { + return xstrdup("parse_set_mpls_tc: expected tc."); + } + + mpls_tc->tc = atoi(arg); + return NULL; +} + /* Parses 'arg' as the argument to a "set_mpls_ttl" action, and appends such an * action to 'ofpacts'. * @@ -815,6 +851,16 @@ parse_named_action(enum ofputil_action_code code, error = parse_dec_ttl(ofpacts, arg); break; + case OFPUTIL_NXAST_SET_MPLS_LABEL: + case OFPUTIL_OFPAT11_SET_MPLS_LABEL: + error = parse_set_mpls_label(ofpacts, arg); + break; + + case OFPUTIL_NXAST_SET_MPLS_TC: + case OFPUTIL_OFPAT11_SET_MPLS_TC: + error = parse_set_mpls_tc(ofpacts, arg); + break; + case OFPUTIL_NXAST_SET_MPLS_TTL: case OFPUTIL_OFPAT11_SET_MPLS_TTL: error = parse_set_mpls_ttl(ofpacts, arg); diff --git a/lib/ofp-util.c b/lib/ofp-util.c index f090539..8828eab 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -436,11 +436,11 @@ ofputil_match_from_ofp11_match(const struct ofp11_match *ofmatch, } if (eth_type_mpls(match->flow.dl_type)) { - enum { OFPFW11_MPLS_ALL = OFPFW11_MPLS_LABEL | OFPFW11_MPLS_TC }; - - if ((wc & OFPFW11_MPLS_ALL) != OFPFW11_MPLS_ALL) { - /* MPLS not supported. */ - return OFPERR_OFPBMC_BAD_TAG; + if (!(wc & OFPFW11_MPLS_LABEL)) { + match_set_mpls_label(match, ofmatch->mpls_label); + } + if (!(wc & OFPFW11_MPLS_TC)) { + match_set_mpls_tc(match, ofmatch->mpls_tc); } } @@ -533,9 +533,17 @@ ofputil_match_to_ofp11_match(const struct match *match, ofmatch->tp_dst = match->flow.tp_dst; } - /* MPLS not supported. */ - wc |= OFPFW11_MPLS_LABEL; - wc |= OFPFW11_MPLS_TC; + if (!(match->wc.masks.mpls_lse & htonl(MPLS_LABEL_MASK))) { + wc |= OFPFW11_MPLS_LABEL; + } else { + ofmatch->mpls_label = htonl(mpls_lse_to_label(match->flow.mpls_lse)); + } + + if (!(match->wc.masks.mpls_lse & htonl(MPLS_TC_MASK))) { + wc |= OFPFW11_MPLS_TC; + } else { + ofmatch->mpls_tc = mpls_lse_to_tc(match->flow.mpls_lse); + } ofmatch->metadata = match->flow.metadata; ofmatch->metadata_mask = ~match->wc.masks.metadata; diff --git a/lib/ofp-util.def b/lib/ofp-util.def index 631a6b1..fae2bf2 100644 --- a/lib/ofp-util.def +++ b/lib/ofp-util.def @@ -30,6 +30,8 @@ OFPAT11_ACTION(OFPAT11_SET_NW_TOS, ofp_action_nw_tos, 0, "mod_nw_tos") OFPAT11_ACTION(OFPAT11_SET_NW_ECN, ofp11_action_nw_ecn, 0, "mod_nw_ecn") OFPAT11_ACTION(OFPAT11_SET_TP_SRC, ofp_action_tp_port, 0, "mod_tp_src") OFPAT11_ACTION(OFPAT11_SET_TP_DST, ofp_action_tp_port, 0, "mod_tp_dst") +OFPAT11_ACTION(OFPAT11_SET_MPLS_LABEL, ofp11_action_mpls_label, 0, "set_mpls_label") +OFPAT11_ACTION(OFPAT11_SET_MPLS_TC, ofp11_action_mpls_tc, 0, "set_mpls_tc") OFPAT11_ACTION(OFPAT11_SET_MPLS_TTL, ofp11_action_mpls_ttl, 0, "set_mpls_ttl") OFPAT11_ACTION(OFPAT11_DEC_MPLS_TTL, ofp_action_header, 0, "dec_mpls_ttl") OFPAT11_ACTION(OFPAT11_PUSH_VLAN, ofp11_action_push, 0, "push_vlan") @@ -68,6 +70,8 @@ NXAST_ACTION(NXAST_CONTROLLER, nx_action_controller, 0, "controller") NXAST_ACTION(NXAST_DEC_TTL_CNT_IDS, nx_action_cnt_ids, 1, NULL) NXAST_ACTION(NXAST_WRITE_METADATA, nx_action_write_metadata, 0, "write_metadata") +NXAST_ACTION(NXAST_SET_MPLS_LABEL, nx_action_mpls_label, 0, "set_mpls_label") +NXAST_ACTION(NXAST_SET_MPLS_TC, nx_action_mpls_tc, 0, "set_mpls_tc") NXAST_ACTION(NXAST_SET_MPLS_TTL, nx_action_mpls_ttl, 0, "set_mpls_ttl") NXAST_ACTION(NXAST_DEC_MPLS_TTL, nx_action_header, 0, "dec_mpls_ttl") NXAST_ACTION(NXAST_PUSH_MPLS, nx_action_push_mpls, 0, "push_mpls") diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index 94c7eec..7626dcb 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -1984,6 +1984,54 @@ compose_dec_ttl(struct xlate_ctx *ctx, struct ofpact_cnt_ids *ids) } static bool +compose_set_mpls_label_action(struct xlate_ctx *ctx, ovs_be32 label) +{ + if (!eth_type_mpls(ctx->xin->flow.dl_type)) { + return true; + } + + /* If mpls_depth_delta is negative then an MPLS POP action has been + * executed and the resulting MPLS label stack is unknown. This means + * a SET MPLS LABEL action can't be executed as it needs to manipulate + * the top-most MPLS LSE. Thus, stop processing. + * + * It is planned that in the future this case will be handled + * by recirculation. + */ + if (ctx->mpls_depth_delta < 0) { + return true; + } + + ctx->xout->wc.masks.mpls_lse |= htonl(MPLS_LABEL_MASK); + set_mpls_lse_label(&ctx->xin->flow.mpls_lse, label); + return false; +} + +static bool +compose_set_mpls_tc_action(struct xlate_ctx *ctx, uint8_t tc) +{ + if (!eth_type_mpls(ctx->xin->flow.dl_type)) { + return true; + } + + /* If mpls_depth_delta is negative then an MPLS POP action has been + * executed and the resulting MPLS label stack is unknown. This means + * a SET MPLS TC action can't be executed as it needs to manipulate + * the top-most MPLS LSE. Thus, stop processing. + * + * It is planned that in the future this case will be handled + * by recirculation. + */ + if (ctx->mpls_depth_delta < 0) { + return true; + } + + ctx->xout->wc.masks.mpls_lse |= htonl(MPLS_TC_MASK); + set_mpls_lse_tc(&ctx->xin->flow.mpls_lse, tc); + return false; +} + +static bool compose_set_mpls_ttl_action(struct xlate_ctx *ctx, uint8_t ttl) { if (!eth_type_mpls(ctx->xin->flow.dl_type)) { @@ -2476,6 +2524,20 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, } break; + case OFPACT_SET_MPLS_LABEL: + if (compose_set_mpls_label_action(ctx, + ofpact_get_SET_MPLS_LABEL(a)->label)) { + return; + } + break; + + case OFPACT_SET_MPLS_TC: + if (compose_set_mpls_tc_action(ctx, + ofpact_get_SET_MPLS_TC(a)->tc)) { + return; + } + break; + case OFPACT_SET_MPLS_TTL: if (compose_set_mpls_ttl_action(ctx, ofpact_get_SET_MPLS_TTL(a)->ttl)) { diff --git a/tests/ovs-ofctl.at b/tests/ovs-ofctl.at index d503149..530c633 100644 --- a/tests/ovs-ofctl.at +++ b/tests/ovs-ofctl.at @@ -1517,15 +1517,16 @@ dnl Ignore tp_dst if not TCP/UDP/SCTP: 0000 00 00 0800 00 16 00000000ffffffff 00000000ffffffff 0000 01bb dnl 00000000 00 000000 0000000000000000ffffffffffffffff -dnl mpls_label not yet supported: -# bad ofp11_match: OFPBMC_BAD_TAG +# mpls,mpls_label=284280 +# 64: 12 -> 00 +# 65: 34 -> 04 0000 0058 00000000 000002f7 dnl 000000000000ffffffffffff 000000000000ffffffffffff dnl 0000 00 00 8847 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl 12345678 00 000000 0000000000000000ffffffffffffffff -dnl mpls_tc not yet supported: -# bad ofp11_match: OFPBMC_BAD_TAG +# mplsm,mpls_tc=2 +# 68: 5a -> 02 0000 0058 00000000 000001f7 dnl 000000000000ffffffffffff 000000000000ffffffffffff dnl 0000 00 00 8848 00 00 00000000ffffffff 00000000ffffffff 0000 0000 dnl -- 1.7.10.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev