Signed-off-by: Andy Zhou <az...@nicira.com> --- v1 -> v2: Minor adjustment. v2 -> v3: In comments, discouraging controllers to use newly added recirc_id and dp_hash fields. Reject openflow messages that references recirc_id and dp_hash fields. --- include/openflow/nicira-ext.h | 30 +++++++++++++++++++++ lib/flow.c | 6 +++-- lib/flow.h | 13 ++++++--- lib/match.c | 38 +++++++++++++++++++++++++- lib/match.h | 6 +++++ lib/meta-flow.c | 60 +++++++++++++++++++++++++++++++++++++++++ lib/meta-flow.h | 2 ++ lib/nx-match.c | 15 ++++++++++- lib/ofp-util.c | 2 +- ofproto/ofproto-dpif-xlate.c | 2 +- ofproto/ofproto.c | 15 +++++++++++ 11 files changed, 180 insertions(+), 9 deletions(-)
diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h index 22939f4..9ae7735 100644 --- a/include/openflow/nicira-ext.h +++ b/include/openflow/nicira-ext.h @@ -1803,6 +1803,36 @@ OFP_ASSERT(sizeof(struct nx_action_output_reg) == 24); #define NXM_NX_TCP_FLAGS NXM_HEADER (0x0001, 34, 2) #define NXM_NX_TCP_FLAGS_W NXM_HEADER_W(0x0001, 34, 2) +/* Metadata dp_hash. + * + * Internal use only, not programable from controller. + * + * The dp_hash is used to carry the flow hash computed in the + * datapath. + * + * Prereqs: None. + * + * Format: 32-bit integer in network byte order. + * + * Masking: Fully maskable. */ +#define NXM_NX_DP_HASH NXM_HEADER (0x0001, 35, 4) +#define NXM_NX_DP_HASH_W NXM_HEADER_W(0x0001, 35, 4) + +/* Metadata recirc_id. + * + * Internal use only, not programable from controller. + * + * The recirc_id used for recirculation. 0 is reserved + * for initially received packet. + * + * Prereqs: None. + * + * Format: 32-bit integer in network byte order. + * + * Masking: not maskable. */ +#define NXM_NX_RECIRC_ID NXM_HEADER (0x0001, 36, 4) +#define NXM_NX_RECIRC_ID_W NXM_HEADER_W(0x0001, 36, 4) + /* ## --------------------- ## */ /* ## Requests and replies. ## */ /* ## --------------------- ## */ diff --git a/lib/flow.c b/lib/flow.c index 00e66a4..d625fb3 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -530,8 +530,10 @@ flow_unwildcard_tp_ports(const struct flow *flow, struct flow_wildcards *wc) void flow_get_metadata(const struct flow *flow, struct flow_metadata *fmd) { - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 24); + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 25); + fmd->dp_hash = flow->dp_hash; + fmd->recirc_id = flow->recirc_id; fmd->tun_id = flow->tunnel.tun_id; fmd->tun_src = flow->tunnel.ip_src; fmd->tun_dst = flow->tunnel.ip_dst; @@ -1194,7 +1196,7 @@ flow_push_mpls(struct flow *flow, int n, ovs_be16 mpls_eth_type, flow->mpls_lse[0] = set_mpls_lse_values(ttl, tc, 1, htonl(label)); /* Clear all L3 and L4 fields. */ - BUILD_ASSERT(FLOW_WC_SEQ == 24); + BUILD_ASSERT(FLOW_WC_SEQ == 25); memset((char *) flow + FLOW_SEGMENT_2_ENDS_AT, 0, sizeof(struct flow) - FLOW_SEGMENT_2_ENDS_AT); } diff --git a/lib/flow.h b/lib/flow.h index 8b4ffad..a6f45c9 100644 --- a/lib/flow.h +++ b/lib/flow.h @@ -37,7 +37,7 @@ struct pkt_metadata; /* This sequence number should be incremented whenever anything involving flows * or the wildcarding of flows changes. This will cause build assertion * failures in places which likely need to be updated. */ -#define FLOW_WC_SEQ 24 +#define FLOW_WC_SEQ 25 #define FLOW_N_REGS 8 BUILD_ASSERT_DECL(FLOW_N_REGS <= NXM_NX_MAX_REGS); @@ -97,6 +97,11 @@ union flow_in_port { * be looked at. This enables better wildcarding for datapath flows. */ struct flow { + /* Recirculation */ + uint32_t dp_hash; /* Datapath computed hash value. The exact + computation is opaque to the user space.*/ + uint32_t recirc_id; /* Must be exact match. */ + /* L1 */ struct flow_tnl tunnel; /* Encapsulating tunnel parameters. */ ovs_be64 metadata; /* OpenFlow Metadata. */ @@ -139,8 +144,8 @@ BUILD_ASSERT_DECL(sizeof(struct flow) % 4 == 0); /* Remember to update FLOW_WC_SEQ when changing 'struct flow'. */ BUILD_ASSERT_DECL(offsetof(struct flow, tp_dst) + 2 - == sizeof(struct flow_tnl) + 164 - && FLOW_WC_SEQ == 24); + == sizeof(struct flow_tnl) + 172 + && FLOW_WC_SEQ == 25); /* Incremental points at which flow classification may be performed in * segments. @@ -165,6 +170,8 @@ extern const uint8_t flow_segment_u32s[]; /* Represents the metadata fields of struct flow. */ struct flow_metadata { + uint32_t dp_hash; /* Datapath computed hash field. */ + uint32_t recirc_id; /* Recirculation ID. */ ovs_be64 tun_id; /* Encapsulating tunnel ID. */ ovs_be32 tun_src; /* Tunnel outer IPv4 src addr */ ovs_be32 tun_dst; /* Tunnel outer IPv4 dst addr */ diff --git a/lib/match.c b/lib/match.c index b2a25fd..bb43b6e 100644 --- a/lib/match.c +++ b/lib/match.c @@ -165,6 +165,32 @@ match_zero_wildcarded_fields(struct match *match) } void +match_set_dp_hash(struct match *match, uint32_t value) +{ + match_set_dp_hash_masked(match, value, UINT32_MAX); +} + +void +match_set_dp_hash_masked(struct match *match, uint32_t value, uint32_t mask) +{ + match->wc.masks.dp_hash = mask; + match->flow.dp_hash = value & mask; +} + +void +match_set_recirc_id(struct match *match, uint32_t value) +{ + match_set_recirc_id_masked(match, value, UINT32_MAX); +} + +void +match_set_recirc_id_masked(struct match *match, uint32_t value, uint32_t mask) +{ + match->wc.masks.recirc_id = mask; + match->flow.recirc_id = value & mask; +} + +void match_set_reg(struct match *match, unsigned int reg_idx, uint32_t value) { match_set_reg_masked(match, reg_idx, value, UINT32_MAX); @@ -895,7 +921,7 @@ match_format(const struct match *match, struct ds *s, unsigned int priority) int i; - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 24); + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 25); if (priority != OFP_DEFAULT_PRIORITY) { ds_put_format(s, "priority=%u,", priority); @@ -903,6 +929,16 @@ match_format(const struct match *match, struct ds *s, unsigned int priority) format_uint32_masked(s, "pkt_mark", f->pkt_mark, wc->masks.pkt_mark); + if (wc->masks.recirc_id) { + format_uint32_masked(s, "recirc_id", f->recirc_id, + wc->masks.recirc_id); + } + + if (f->dp_hash && wc->masks.dp_hash) { + format_uint32_masked(s, "dp_hash", f->dp_hash, + wc->masks.dp_hash); + } + if (wc->masks.skb_priority) { ds_put_format(s, "skb_priority=%#"PRIx32",", f->skb_priority); } diff --git a/lib/match.h b/lib/match.h index 7a8ae68..95c8e67 100644 --- a/lib/match.h +++ b/lib/match.h @@ -41,6 +41,12 @@ void match_init_catchall(struct match *); void match_zero_wildcarded_fields(struct match *); +void match_set_dp_hash(struct match *, uint32_t value); +void match_set_dp_hash_masked(struct match *, uint32_t value, uint32_t mask); + +void match_set_recirc_id(struct match *, uint32_t value); +void match_set_recirc_id_masked(struct match *, uint32_t value, uint32_t mask); + void match_set_reg(struct match *, unsigned int reg_idx, uint32_t value); void match_set_reg_masked(struct match *, unsigned int reg_idx, uint32_t value, uint32_t mask); diff --git a/lib/meta-flow.c b/lib/meta-flow.c index d90477a..6ef564e 100644 --- a/lib/meta-flow.c +++ b/lib/meta-flow.c @@ -52,6 +52,30 @@ const struct mf_field mf_fields[MFF_N_IDS] = { /* ## -------- ## */ { + MFF_DP_HASH, "dp_hash", NULL, + MF_FIELD_SIZES(be32), + MFM_FULLY, + MFS_HEXADECIMAL, + MFP_NONE, + false, + NXM_NX_DP_HASH, "NXM_NX_DP_HASH", + NXM_NX_DP_HASH, "NXM_NX_DP_HASH", + OFPUTIL_P_NXM_OXM_ANY, + OFPUTIL_P_NXM_OXM_ANY, + -1, + }, { + MFF_RECIRC_ID, "recirc_id", NULL, + MF_FIELD_SIZES(be32), + MFM_NONE, + MFS_DECIMAL, + MFP_NONE, + false, + NXM_NX_RECIRC_ID, "NXM_NX_RECIRC_ID", + NXM_NX_RECIRC_ID, "NXM_NX_RECIRC_ID", + OFPUTIL_P_NXM_OXM_ANY, + OFPUTIL_P_NXM_OXM_ANY, + -1, + }, { MFF_TUN_ID, "tun_id", "tunnel_id", MF_FIELD_SIZES(be64), MFM_FULLY, @@ -879,6 +903,10 @@ bool mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc) { switch (mf->id) { + case MFF_DP_HASH: + return !wc->masks.dp_hash; + case MFF_RECIRC_ID: + return !wc->masks.recirc_id; case MFF_TUN_SRC: return !wc->masks.tunnel.ip_src; case MFF_TUN_DST: @@ -1124,6 +1152,8 @@ bool mf_is_value_valid(const struct mf_field *mf, const union mf_value *value) { switch (mf->id) { + case MFF_DP_HASH: + case MFF_RECIRC_ID: case MFF_TUN_ID: case MFF_TUN_SRC: case MFF_TUN_DST: @@ -1217,6 +1247,12 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow, union mf_value *value) { switch (mf->id) { + case MFF_DP_HASH: + value->be32 = htonl(flow->dp_hash); + break; + case MFF_RECIRC_ID: + value->be32 = htonl(flow->recirc_id); + break; case MFF_TUN_ID: value->be64 = flow->tunnel.tun_id; break; @@ -1409,6 +1445,12 @@ mf_set_value(const struct mf_field *mf, const union mf_value *value, struct match *match) { switch (mf->id) { + case MFF_DP_HASH: + match_set_dp_hash(match, ntohl(value->be32)); + break; + case MFF_RECIRC_ID: + match_set_recirc_id(match, ntohl(value->be32)); + break; case MFF_TUN_ID: match_set_tun_id(match, value->be64); break; @@ -1622,6 +1664,12 @@ mf_set_flow_value(const struct mf_field *mf, const union mf_value *value, struct flow *flow) { switch (mf->id) { + case MFF_DP_HASH: + flow->dp_hash = ntohl(value->be32); + break; + case MFF_RECIRC_ID: + flow->recirc_id = ntohl(value->be32); + break; case MFF_TUN_ID: flow->tunnel.tun_id = value->be64; break; @@ -1834,6 +1882,14 @@ void mf_set_wild(const struct mf_field *mf, struct match *match) { switch (mf->id) { + case MFF_DP_HASH: + match->flow.dp_hash = 0; + match->wc.masks.dp_hash = 0; + break; + case MFF_RECIRC_ID: + match->flow.recirc_id = 0; + match->wc.masks.recirc_id = 0; + break; case MFF_TUN_ID: match_set_tun_id_masked(match, htonll(0), htonll(0)); break; @@ -2046,6 +2102,7 @@ mf_set(const struct mf_field *mf, } switch (mf->id) { + case MFF_RECIRC_ID: case MFF_IN_PORT: case MFF_IN_PORT_OXM: case MFF_SKB_PRIORITY: @@ -2068,6 +2125,9 @@ mf_set(const struct mf_field *mf, case MFF_ICMPV6_CODE: return OFPUTIL_P_NONE; + case MFF_DP_HASH: + match_set_dp_hash_masked(match, ntohl(value->be32), ntohl(mask->be32)); + break; case MFF_TUN_ID: match_set_tun_id_masked(match, value->be64, mask->be64); break; diff --git a/lib/meta-flow.h b/lib/meta-flow.h index cf92556..91dfecd 100644 --- a/lib/meta-flow.h +++ b/lib/meta-flow.h @@ -33,6 +33,8 @@ struct match; * to represent its value. */ enum OVS_PACKED_ENUM mf_field_id { /* Metadata. */ + MFF_DP_HASH, /* be32 */ + MFF_RECIRC_ID, /* be32 */ MFF_TUN_ID, /* be64 */ MFF_TUN_SRC, /* be32 */ MFF_TUN_DST, /* be32 */ diff --git a/lib/nx-match.c b/lib/nx-match.c index de79009..fe6d80f 100644 --- a/lib/nx-match.c +++ b/lib/nx-match.c @@ -572,9 +572,22 @@ nx_put_raw(struct ofpbuf *b, bool oxm, const struct match *match, int match_len; int i; - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 24); + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 25); /* Metadata. */ + if (match->wc.masks.dp_hash) { + if (!oxm) { + nxm_put_32m(b, NXM_NX_DP_HASH, htonl(flow->dp_hash), + htonl(match->wc.masks.dp_hash)); + } + } + + if (match->wc.masks.recirc_id) { + if (!oxm) { + nxm_put_32(b, NXM_NX_RECIRC_ID, htonl(flow->recirc_id)); + } + } + if (match->wc.masks.in_port.ofp_port) { ofp_port_t in_port = flow->in_port.ofp_port; if (oxm) { diff --git a/lib/ofp-util.c b/lib/ofp-util.c index fca18de..91d5b5a 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -84,7 +84,7 @@ ofputil_netmask_to_wcbits(ovs_be32 netmask) void ofputil_wildcard_from_ofpfw10(uint32_t ofpfw, struct flow_wildcards *wc) { - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 24); + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 25); /* Initialize most of wc. */ flow_wildcards_init_catchall(wc); diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index 9b6ce10..c16fdb9 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -1693,7 +1693,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, /* If 'struct flow' gets additional metadata, we'll need to zero it out * before traversing a patch port. */ - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 24); + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 25); if (!xport) { xlate_report(ctx, "Nonexistent output port"); diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 277c1d7..7b81516 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -4482,6 +4482,21 @@ handle_flow_mod__(struct ofproto *ofproto, struct ofconn *ofconn, { enum ofperr error; + /* Only internal flow mods can set recircualtion fields. */ + if (!(fm->flags & OFPUTIL_FF_INTERNAL)) { + char *err_field = NULL; + + err_field = fm->match.flow.recirc_id ? "recirc_id" : err_field; + err_field = fm->match.flow.dp_hash ? "dp_hash" : err_field; + + if (err_field) { + VLOG_WARN_RL(&rl, "%s: (flow_mod) only internal flows can set %s", + ofproto->name, err_field); + error = OFPERR_OFPFMFC_EPERM; + return error; + } + } + ovs_mutex_lock(&ofproto_mutex); if (ofproto->n_pending < 50) { switch (fm->command) { -- 1.7.9.5 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev