From 08d1e2345660f563d95c53719cd305048b67a27e Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Mon, 11 Aug 2014 10:57:03 -0700 Subject: [PATCH] ofp-actions: Add action bitmap abstraction. Until now, sets of actions have been abstracted separately outside ofp-actions, as enum ofputil_action_bitmap. Drawing sets of actions into ofp-actions, as done in this commit, makes for a better overall abstraction of actions, with better consistency. A big part of this commit is shifting from using ofp12_table_stats as if it were an abstraction for OpenFlow table stats, toward using a new struct ofputil_table_stats, which is what we generally do with other OpenFlow structures and fits better with the rest of the code. Signed-off-by: Ben Pfaff Acked-by: Jarno Rajahalme --- include/openflow/openflow-1.2.h | 12 +- lib/ofp-actions.c | 160 ++++++++++++++++++ lib/ofp-actions.h | 148 +++++++++-------- lib/ofp-print.c | 105 +++--------- lib/ofp-util.c | 280 ++++++++++++++++---------------- lib/ofp-util.h | 66 +++----- ofproto/ofproto-dpif.c | 23 +-- ofproto/ofproto-provider.h | 22 ++- ofproto/ofproto.c | 85 +++++----- tests/ofp-print.at | 26 +-- tests/ofproto.at | 20 +-- 11 files changed, 512 insertions(+), 435 deletions(-) diff --git a/include/openflow/openflow-1.2.h b/include/openflow/openflow-1.2.h index 1069f4e0e6d..c7ba6fda657 100644 --- a/include/openflow/openflow-1.2.h +++ b/include/openflow/openflow-1.2.h @@ -306,12 +306,20 @@ struct ofp12_table_stats { }; OFP_ASSERT(sizeof(struct ofp12_table_stats) == 128); +/* Number of types of groups supported by ofp12_group_features_stats. */ +#define OFPGT12_N_TYPES 4 + /* Body of reply to OFPST12_GROUP_FEATURES request. Group features. */ struct ofp12_group_features_stats { ovs_be32 types; /* Bitmap of OFPGT11_* values supported. */ ovs_be32 capabilities; /* Bitmap of OFPGFC12_* capability supported. */ - ovs_be32 max_groups[4]; /* Maximum number of groups for each type. */ - ovs_be32 actions[4]; /* Bitmaps of OFPAT_* that are supported. */ + + /* Each element in the following arrays corresponds to the group type with + * the same number, e.g. max_groups[0] is the maximum number of OFPGT11_ALL + * groups, actions[2] is the actions supported by OFPGT11_INDIRECT + * groups. */ + ovs_be32 max_groups[OFPGT12_N_TYPES]; /* Max number of groups. */ + ovs_be32 actions[OFPGT12_N_TYPES]; /* Bitmaps of supported OFPAT_*. */ }; OFP_ASSERT(sizeof(struct ofp12_group_features_stats) == 40); diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c index e8fd92227e3..d6436c28d65 100644 --- a/lib/ofp-actions.c +++ b/lib/ofp-actions.c @@ -3091,6 +3091,155 @@ ofpacts_put_openflow_instructions(const struct ofpact ofpacts[], } } +/* Sets of supported actions. */ + +/* Two-way translation between OVS's internal "OFPACT_*" representation of + * actions and the "OFPAT_*" representation used in some OpenFlow version. + * (OFPAT_* numbering varies from one OpenFlow version to another, so a given + * instance is specific to one OpenFlow version.) */ +struct ofpact_map { + enum ofpact_type ofpact; /* Internal name for action type. */ + int ofpat; /* OFPAT_* number from OpenFlow spec. */ +}; + +static const struct ofpact_map * +get_ofpact_map(enum ofp_version version) +{ + /* OpenFlow 1.0 actions. */ + static const struct ofpact_map of10[] = { + { OFPACT_OUTPUT, 0 }, + { OFPACT_SET_VLAN_VID, 1 }, + { OFPACT_SET_VLAN_PCP, 2 }, + { OFPACT_STRIP_VLAN, 3 }, + { OFPACT_SET_ETH_SRC, 4 }, + { OFPACT_SET_ETH_DST, 5 }, + { OFPACT_SET_IPV4_SRC, 6 }, + { OFPACT_SET_IPV4_DST, 7 }, + { OFPACT_SET_IP_DSCP, 8 }, + { OFPACT_SET_L4_SRC_PORT, 9 }, + { OFPACT_SET_L4_DST_PORT, 10 }, + { OFPACT_ENQUEUE, 11 }, + { 0, -1 }, + }; + + /* OpenFlow 1.1 actions. */ + static const struct ofpact_map of11[] = { + { OFPACT_OUTPUT, 0 }, + { OFPACT_SET_VLAN_VID, 1 }, + { OFPACT_SET_VLAN_PCP, 2 }, + { OFPACT_SET_ETH_SRC, 3 }, + { OFPACT_SET_ETH_DST, 4 }, + { OFPACT_SET_IPV4_SRC, 5 }, + { OFPACT_SET_IPV4_DST, 6 }, + { OFPACT_SET_IP_DSCP, 7 }, + { OFPACT_SET_IP_ECN, 8 }, + { OFPACT_SET_L4_SRC_PORT, 9 }, + { OFPACT_SET_L4_DST_PORT, 10 }, + /* OFPAT_COPY_TTL_OUT (11) not supported. */ + /* OFPAT_COPY_TTL_IN (12) not supported. */ + { OFPACT_SET_MPLS_LABEL, 13 }, + { OFPACT_SET_MPLS_TC, 14 }, + { OFPACT_SET_MPLS_TTL, 15 }, + { OFPACT_DEC_MPLS_TTL, 16 }, + { OFPACT_PUSH_VLAN, 17 }, + { OFPACT_STRIP_VLAN, 18 }, + { OFPACT_PUSH_MPLS, 19 }, + { OFPACT_POP_MPLS, 20 }, + { OFPACT_SET_QUEUE, 21 }, + { OFPACT_GROUP, 22 }, + { OFPACT_SET_IP_TTL, 23 }, + { OFPACT_DEC_TTL, 24 }, + { 0, -1 }, + }; + + /* OpenFlow 1.2, 1.3, and 1.4 actions. */ + static const struct ofpact_map of12[] = { + { OFPACT_OUTPUT, 0 }, + /* OFPAT_COPY_TTL_OUT (11) not supported. */ + /* OFPAT_COPY_TTL_IN (12) not supported. */ + { OFPACT_SET_MPLS_TTL, 15 }, + { OFPACT_DEC_MPLS_TTL, 16 }, + { OFPACT_PUSH_VLAN, 17 }, + { OFPACT_STRIP_VLAN, 18 }, + { OFPACT_PUSH_MPLS, 19 }, + { OFPACT_POP_MPLS, 20 }, + { OFPACT_SET_QUEUE, 21 }, + { OFPACT_GROUP, 22 }, + { OFPACT_SET_IP_TTL, 23 }, + { OFPACT_DEC_TTL, 24 }, + { OFPACT_SET_FIELD, 25 }, + /* OF1.3+ OFPAT_PUSH_PBB (26) not supported. */ + /* OF1.3+ OFPAT_POP_PBB (27) not supported. */ + { 0, -1 }, + }; + + switch (version) { + case OFP10_VERSION: + return of10; + + case OFP11_VERSION: + return of11; + + case OFP12_VERSION: + case OFP13_VERSION: + case OFP14_VERSION: + case OFP15_VERSION: + default: + return of12; + } +} + +/* Converts 'ofpacts_bitmap', a bitmap whose bits correspond to OFPACT_* + * values, into a bitmap of actions suitable for OpenFlow 'version', and + * returns the result. */ +ovs_be32 +ofpact_bitmap_to_openflow(uint64_t ofpacts_bitmap, enum ofp_version version) +{ + uint32_t openflow_bitmap = 0; + const struct ofpact_map *x; + + for (x = get_ofpact_map(version); x->ofpat >= 0; x++) { + if (ofpacts_bitmap & (UINT64_C(1) << x->ofpact)) { + openflow_bitmap |= 1u << x->ofpat; + } + } + return htonl(openflow_bitmap); +} + +/* Converts 'ofpat_bitmap', a bitmap of actions from an OpenFlow message with + * the given 'version' into a bitmap whose bits correspond to OFPACT_* values, + * and returns the result. */ +uint64_t +ofpact_bitmap_from_openflow(ovs_be32 ofpat_bitmap, enum ofp_version version) +{ + uint64_t ofpact_bitmap = 0; + const struct ofpact_map *x; + + for (x = get_ofpact_map(version); x->ofpat >= 0; x++) { + if (ofpat_bitmap & htonl(1u << x->ofpat)) { + ofpact_bitmap |= UINT64_C(1) << x->ofpact; + } + } + return ofpact_bitmap; +} + +/* Appends to 's' a string representation of the set of OFPACT_* represented + * by 'ofpacts_bitmap'. */ +void +ofpact_bitmap_format(uint64_t ofpacts_bitmap, struct ds *s) +{ + if (!ofpacts_bitmap) { + ds_put_cstr(s, ""); + } else { + while (ofpacts_bitmap) { + ds_put_format(s, "%s ", + ofpact_name(rightmost_1bit_idx(ofpacts_bitmap))); + ofpacts_bitmap = zero_rightmost_1bit(ofpacts_bitmap); + } + ds_chomp(s, ' '); + } +} + /* Returns true if 'action' outputs to 'port', false otherwise. */ static bool ofpact_outputs_to_port(const struct ofpact *ofpact, ofp_port_t port) @@ -3648,3 +3797,14 @@ ofpact_pad(struct ofpbuf *ofpacts) ofpbuf_put_zeros(ofpacts, pad); } } + +const char * +ofpact_name(enum ofpact_type type) +{ + switch (type) { +#define OFPACT(ENUM, STRUCT, MEMBER, NAME) case OFPACT_##ENUM: return NAME; + OFPACTS +#undef OFPACT + } + return ""; +} diff --git a/lib/ofp-actions.h b/lib/ofp-actions.h index 8cb88629cf1..ce61f9db409 100644 --- a/lib/ofp-actions.h +++ b/lib/ofp-actions.h @@ -31,7 +31,7 @@ * This macro is used directly only internally by this header, but the list is * still of interest to developers. * - * Each DEFINE_OFPACT invocation has the following parameters: + * Each OFPACT invocation has the following parameters: * * 1. , used below in the enum definition of OFPACT_, and * elsewhere. @@ -48,81 +48,83 @@ * * - If "struct " is variable-length, it must be the name of the * flexible array member. + * + * 4. , a quoted string that gives the name of the action, for use in + * parsing actions from text. */ -#define OFPACTS \ - /* Output. */ \ - DEFINE_OFPACT(OUTPUT, ofpact_output, ofpact) \ - DEFINE_OFPACT(GROUP, ofpact_group, ofpact) \ - DEFINE_OFPACT(CONTROLLER, ofpact_controller, ofpact) \ - DEFINE_OFPACT(ENQUEUE, ofpact_enqueue, ofpact) \ - DEFINE_OFPACT(OUTPUT_REG, ofpact_output_reg, ofpact) \ - DEFINE_OFPACT(BUNDLE, ofpact_bundle, slaves) \ - \ - /* Header changes. */ \ - DEFINE_OFPACT(SET_FIELD, ofpact_set_field, ofpact) \ - DEFINE_OFPACT(SET_VLAN_VID, ofpact_vlan_vid, ofpact) \ - DEFINE_OFPACT(SET_VLAN_PCP, ofpact_vlan_pcp, ofpact) \ - DEFINE_OFPACT(STRIP_VLAN, ofpact_null, ofpact) \ - DEFINE_OFPACT(PUSH_VLAN, ofpact_null, ofpact) \ - DEFINE_OFPACT(SET_ETH_SRC, ofpact_mac, ofpact) \ - DEFINE_OFPACT(SET_ETH_DST, ofpact_mac, ofpact) \ - DEFINE_OFPACT(SET_IPV4_SRC, ofpact_ipv4, ofpact) \ - DEFINE_OFPACT(SET_IPV4_DST, ofpact_ipv4, ofpact) \ - DEFINE_OFPACT(SET_IP_DSCP, ofpact_dscp, ofpact) \ - DEFINE_OFPACT(SET_IP_ECN, ofpact_ecn, ofpact) \ - DEFINE_OFPACT(SET_IP_TTL, ofpact_ip_ttl, ofpact) \ - DEFINE_OFPACT(SET_L4_SRC_PORT, ofpact_l4_port, ofpact) \ - DEFINE_OFPACT(SET_L4_DST_PORT, ofpact_l4_port, ofpact) \ - DEFINE_OFPACT(REG_MOVE, ofpact_reg_move, ofpact) \ - DEFINE_OFPACT(REG_LOAD, ofpact_reg_load, ofpact) \ - 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) \ - DEFINE_OFPACT(POP_MPLS, ofpact_pop_mpls, ofpact) \ - \ - /* Metadata. */ \ - DEFINE_OFPACT(SET_TUNNEL, ofpact_tunnel, ofpact) \ - DEFINE_OFPACT(SET_QUEUE, ofpact_queue, ofpact) \ - DEFINE_OFPACT(POP_QUEUE, ofpact_null, ofpact) \ - DEFINE_OFPACT(FIN_TIMEOUT, ofpact_fin_timeout, ofpact) \ - \ - /* Flow table interaction. */ \ - DEFINE_OFPACT(RESUBMIT, ofpact_resubmit, ofpact) \ - DEFINE_OFPACT(LEARN, ofpact_learn, specs) \ - \ - /* Arithmetic. */ \ - DEFINE_OFPACT(MULTIPATH, ofpact_multipath, ofpact) \ - \ - /* Other. */ \ - DEFINE_OFPACT(NOTE, ofpact_note, data) \ - DEFINE_OFPACT(EXIT, ofpact_null, ofpact) \ - DEFINE_OFPACT(SAMPLE, ofpact_sample, ofpact) \ - \ - /* Instructions */ \ - DEFINE_OFPACT(METER, ofpact_meter, ofpact) \ - DEFINE_OFPACT(CLEAR_ACTIONS, ofpact_null, ofpact) \ - DEFINE_OFPACT(WRITE_ACTIONS, ofpact_nest, ofpact) \ - DEFINE_OFPACT(WRITE_METADATA, ofpact_metadata, ofpact) \ - DEFINE_OFPACT(GOTO_TABLE, ofpact_goto_table, ofpact) +#define OFPACTS \ + /* Output. */ \ + OFPACT(OUTPUT, ofpact_output, ofpact, "output") \ + OFPACT(GROUP, ofpact_group, ofpact, "group") \ + OFPACT(CONTROLLER, ofpact_controller, ofpact, "controller") \ + OFPACT(ENQUEUE, ofpact_enqueue, ofpact, "enqueue") \ + OFPACT(OUTPUT_REG, ofpact_output_reg, ofpact, "output_reg") \ + OFPACT(BUNDLE, ofpact_bundle, slaves, "bundle") \ + \ + /* Header changes. */ \ + OFPACT(SET_FIELD, ofpact_set_field, ofpact, "set_field") \ + OFPACT(SET_VLAN_VID, ofpact_vlan_vid, ofpact, "set_vlan_vid") \ + OFPACT(SET_VLAN_PCP, ofpact_vlan_pcp, ofpact, "set_vlan_pcp") \ + OFPACT(STRIP_VLAN, ofpact_null, ofpact, "strip_vlan") \ + OFPACT(PUSH_VLAN, ofpact_null, ofpact, "push_vlan") \ + OFPACT(SET_ETH_SRC, ofpact_mac, ofpact, "mod_dl_src") \ + OFPACT(SET_ETH_DST, ofpact_mac, ofpact, "mod_dl_dst") \ + OFPACT(SET_IPV4_SRC, ofpact_ipv4, ofpact, "mod_nw_src") \ + OFPACT(SET_IPV4_DST, ofpact_ipv4, ofpact, "mod_nw_dst") \ + OFPACT(SET_IP_DSCP, ofpact_dscp, ofpact, "mod_nw_tos") \ + OFPACT(SET_IP_ECN, ofpact_ecn, ofpact, "mod_nw_ecn") \ + OFPACT(SET_IP_TTL, ofpact_ip_ttl, ofpact, "mod_nw_ttl") \ + OFPACT(SET_L4_SRC_PORT, ofpact_l4_port, ofpact, "mod_tp_src") \ + OFPACT(SET_L4_DST_PORT, ofpact_l4_port, ofpact, "mod_tp_dst") \ + OFPACT(REG_MOVE, ofpact_reg_move, ofpact, "move") \ + OFPACT(REG_LOAD, ofpact_reg_load, ofpact, "load") \ + OFPACT(STACK_PUSH, ofpact_stack, ofpact, "push") \ + OFPACT(STACK_POP, ofpact_stack, ofpact, "pop") \ + OFPACT(DEC_TTL, ofpact_cnt_ids, cnt_ids, "dec_ttl") \ + OFPACT(SET_MPLS_LABEL, ofpact_mpls_label, ofpact, "set_mpls_label") \ + OFPACT(SET_MPLS_TC, ofpact_mpls_tc, ofpact, "set_mpls_tc") \ + OFPACT(SET_MPLS_TTL, ofpact_mpls_ttl, ofpact, "set_mpls_ttl") \ + OFPACT(DEC_MPLS_TTL, ofpact_null, ofpact, "dec_mpls_ttl") \ + OFPACT(PUSH_MPLS, ofpact_push_mpls, ofpact, "push_mpls") \ + OFPACT(POP_MPLS, ofpact_pop_mpls, ofpact, "pop_mpls") \ + \ + /* Metadata. */ \ + OFPACT(SET_TUNNEL, ofpact_tunnel, ofpact, "set_tunnel") \ + OFPACT(SET_QUEUE, ofpact_queue, ofpact, "set_queue") \ + OFPACT(POP_QUEUE, ofpact_null, ofpact, "pop_queue") \ + OFPACT(FIN_TIMEOUT, ofpact_fin_timeout, ofpact, "fin_timeout") \ + \ + /* Flow table interaction. */ \ + OFPACT(RESUBMIT, ofpact_resubmit, ofpact, "resubmit") \ + OFPACT(LEARN, ofpact_learn, specs, "learn") \ + \ + /* Arithmetic. */ \ + OFPACT(MULTIPATH, ofpact_multipath, ofpact, "multipath") \ + \ + /* Other. */ \ + OFPACT(NOTE, ofpact_note, data, "note") \ + OFPACT(EXIT, ofpact_null, ofpact, "exit") \ + OFPACT(SAMPLE, ofpact_sample, ofpact, "sample") \ + \ + /* Instructions. */ \ + OFPACT(METER, ofpact_meter, ofpact, "meter") \ + OFPACT(CLEAR_ACTIONS, ofpact_null, ofpact, "clear_actions") \ + OFPACT(WRITE_ACTIONS, ofpact_nest, ofpact, "write_actions") \ + OFPACT(WRITE_METADATA, ofpact_metadata, ofpact, "write_metadata") \ + OFPACT(GOTO_TABLE, ofpact_goto_table, ofpact, "goto_table") /* enum ofpact_type, with a member OFPACT_ for each action. */ enum OVS_PACKED_ENUM ofpact_type { -#define DEFINE_OFPACT(ENUM, STRUCT, MEMBER) OFPACT_##ENUM, +#define OFPACT(ENUM, STRUCT, MEMBER, NAME) OFPACT_##ENUM, OFPACTS -#undef DEFINE_OFPACT +#undef OFPACT }; -/* N_OFPACTS, the number of values of "enum ofpact_type". */ +/* Define N_OFPACTS to the number of types of ofpacts. */ enum { - N_OFPACTS = -#define DEFINE_OFPACT(ENUM, STRUCT, MEMBER) + 1 - OFPACTS -#undef DEFINE_OFPACT +#define OFPACT(ENUM, STRUCT, MEMBER, NAME) + 1 + N_OFPACTS = OFPACTS +#undef OFPACT }; /* Header for an action. @@ -611,6 +613,11 @@ void ofpacts_put_openflow_instructions(const struct ofpact[], struct ofpbuf *openflow, enum ofp_version ofp_version); +/* Sets of supported actions. */ +ovs_be32 ofpact_bitmap_to_openflow(uint64_t ofpacts_bitmap, enum ofp_version); +uint64_t ofpact_bitmap_from_openflow(ovs_be32 ofpat_bitmap, enum ofp_version); +void ofpact_bitmap_format(uint64_t ofpacts_bitmap, struct ds *); + /* Working with ofpacts. */ bool ofpacts_output_to_port(const struct ofpact[], size_t ofpacts_len, ofp_port_t port); @@ -624,6 +631,7 @@ uint32_t ofpacts_get_meter(const struct ofpact[], size_t ofpacts_len); * * (For parsing ofpacts, see ofp-parse.h.) */ void ofpacts_format(const struct ofpact[], size_t ofpacts_len, struct ds *); +const char *ofpact_name(enum ofpact_type); /* Internal use by the helpers below. */ void ofpact_init(struct ofpact *, enum ofpact_type, size_t len); @@ -667,7 +675,7 @@ void *ofpact_put(struct ofpbuf *, enum ofpact_type, size_t len); * An integer constant, the value of OFPACT__RAW_SIZE rounded up to a * multiple of OFPACT_ALIGNTO. */ -#define DEFINE_OFPACT(ENUM, STRUCT, MEMBER) \ +#define OFPACT(ENUM, STRUCT, MEMBER, NAME) \ BUILD_ASSERT_DECL(offsetof(struct STRUCT, ofpact) == 0); \ \ enum { OFPACT_##ENUM##_RAW_SIZE \ @@ -699,7 +707,7 @@ void *ofpact_put(struct ofpbuf *, enum ofpact_type, size_t len); OFPACT_##ENUM##_RAW_SIZE); \ } OFPACTS -#undef DEFINE_OFPACT +#undef OFPACT /* Functions to use after adding ofpacts to a buffer. */ void ofpact_update_len(struct ofpbuf *, struct ofpact *); diff --git a/lib/ofp-print.c b/lib/ofp-print.c index 25e0478c301..02c9350a5c6 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -467,45 +467,6 @@ ofputil_capabilities_to_name(uint32_t bit) return NULL; } -static const char * -ofputil_action_bitmap_to_name(uint32_t bit) -{ - enum ofputil_action_bitmap action = bit; - - switch (action) { - case OFPUTIL_A_OUTPUT: return "OUTPUT"; - case OFPUTIL_A_SET_VLAN_VID: return "SET_VLAN_VID"; - case OFPUTIL_A_SET_VLAN_PCP: return "SET_VLAN_PCP"; - case OFPUTIL_A_STRIP_VLAN: return "STRIP_VLAN"; - case OFPUTIL_A_SET_DL_SRC: return "SET_DL_SRC"; - case OFPUTIL_A_SET_DL_DST: return "SET_DL_DST"; - case OFPUTIL_A_SET_NW_SRC: return "SET_NW_SRC"; - case OFPUTIL_A_SET_NW_DST: return "SET_NW_DST"; - case OFPUTIL_A_SET_NW_ECN: return "SET_NW_ECN"; - case OFPUTIL_A_SET_NW_TOS: return "SET_NW_TOS"; - case OFPUTIL_A_SET_TP_SRC: return "SET_TP_SRC"; - case OFPUTIL_A_SET_TP_DST: return "SET_TP_DST"; - case OFPUTIL_A_SET_FIELD: return "SET_FIELD"; - case OFPUTIL_A_ENQUEUE: return "ENQUEUE"; - case OFPUTIL_A_COPY_TTL_OUT: return "COPY_TTL_OUT"; - case OFPUTIL_A_COPY_TTL_IN: return "COPY_TTL_IN"; - case OFPUTIL_A_SET_MPLS_LABEL: return "SET_MPLS_LABEL"; - case OFPUTIL_A_SET_MPLS_TC: return "SET_MPLS_TC"; - case OFPUTIL_A_SET_MPLS_TTL: return "SET_MPLS_TTL"; - case OFPUTIL_A_DEC_MPLS_TTL: return "DEC_MPLS_TTL"; - case OFPUTIL_A_PUSH_VLAN: return "PUSH_VLAN"; - case OFPUTIL_A_POP_VLAN: return "POP_VLAN"; - case OFPUTIL_A_PUSH_MPLS: return "PUSH_MPLS"; - case OFPUTIL_A_POP_MPLS: return "POP_MPLS"; - case OFPUTIL_A_SET_QUEUE: return "SET_QUEUE"; - case OFPUTIL_A_GROUP: return "GROUP"; - case OFPUTIL_A_SET_NW_TTL: return "SET_NW_TTL"; - case OFPUTIL_A_DEC_NW_TTL: return "DEC_NW_TTL"; - } - - return NULL; -} - static void ofp_print_switch_features(struct ds *string, const struct ofp_header *oh) { @@ -536,8 +497,7 @@ ofp_print_switch_features(struct ds *string, const struct ofp_header *oh) switch ((enum ofp_version)oh->version) { case OFP10_VERSION: ds_put_cstr(string, "actions: "); - ofp_print_bit_names(string, features.actions, - ofputil_action_bitmap_to_name, ' '); + ofpact_bitmap_format(features.ofpacts, string); ds_put_char(string, '\n'); break; case OFP11_VERSION: @@ -2458,10 +2418,23 @@ ofp_print_group_stats(struct ds *s, const struct ofp_header *oh) } } +static const char * +group_type_to_string(enum ofp11_group_type type) +{ + switch (type) { + case OFPGT11_ALL: return "all"; + case OFPGT11_SELECT: return "select"; + case OFPGT11_INDIRECT: return "indirect"; + case OFPGT11_FF: return "fast failover"; + default: OVS_NOT_REACHED(); + } +} + static void ofp_print_group_features(struct ds *string, const struct ofp_header *oh) { struct ofputil_group_features features; + int i; ofputil_decode_group_features_reply(oh, &features); @@ -2470,32 +2443,15 @@ ofp_print_group_features(struct ds *string, const struct ofp_header *oh) ds_put_format(string, " Capabilities: 0x%"PRIx32"\n", features.capabilities); - if (features.types & (1u << OFPGT11_ALL)) { - ds_put_format(string, " All group :\n"); - ds_put_format(string, - " max_groups = %#"PRIx32" actions=0x%08"PRIx32"\n", - features.max_groups[0], features.actions[0]); - } - - if (features.types & (1u << OFPGT11_SELECT)) { - ds_put_format(string, " Select group :\n"); - ds_put_format(string, " max_groups = %#"PRIx32" " - "actions=0x%08"PRIx32"\n", - features.max_groups[1], features.actions[1]); - } - - if (features.types & (1u << OFPGT11_INDIRECT)) { - ds_put_format(string, " Indirect group :\n"); - ds_put_format(string, " max_groups = %#"PRIx32" " - "actions=0x%08"PRIx32"\n", - features.max_groups[2], features.actions[2]); - } - - if (features.types & (1u << OFPGT11_FF)) { - ds_put_format(string, " Fast Failover group :\n"); - ds_put_format(string, " max_groups = %#"PRIx32" " - "actions=0x%08"PRIx32"\n", - features.max_groups[3], features.actions[3]); + for (i = 0; i < OFPGT12_N_TYPES; i++) { + if (features.types & (1u << i)) { + ds_put_format(string, " %s group:\n", group_type_to_string(i)); + ds_put_format(string, " max_groups=%#"PRIx32"\n", + features.max_groups[i]); + ds_put_format(string, " actions: "); + ofpact_bitmap_format(features.ofpacts[i], string); + ds_put_char(string, '\n'); + } } } @@ -2535,23 +2491,12 @@ ofp_print_group_mod(struct ds *s, const struct ofp_header *oh) ofp_print_group(s, gm.group_id, gm.type, &gm.buckets); } -static const char * -ofp13_action_to_string(uint32_t bit) -{ - switch (bit) { -#define OFPAT13_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) \ - case 1u << ENUM: return NAME; -#include "ofp-util.def" - } - return NULL; -} - static void print_table_action_features(struct ds *s, const struct ofputil_table_action_features *taf) { ds_put_cstr(s, " actions: "); - ofp_print_bit_names(s, taf->actions, ofp13_action_to_string, ','); + ofpact_bitmap_format(taf->ofpacts, s); ds_put_char(s, '\n'); ds_put_cstr(s, " supported on Set-Field: "); @@ -2572,7 +2517,7 @@ static bool table_action_features_equal(const struct ofputil_table_action_features *a, const struct ofputil_table_action_features *b) { - return (a->actions == b->actions + return (a->ofpacts == b->ofpacts && bitmap_equal(a->set_fields.bm, b->set_fields.bm, MFF_N_IDS)); } diff --git a/lib/ofp-util.c b/lib/ofp-util.c index a0651697205..9a8a868c634 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -4012,42 +4012,6 @@ BUILD_ASSERT_DECL((int) OFPUTIL_C_IP_REASM == OFPC_IP_REASM); BUILD_ASSERT_DECL((int) OFPUTIL_C_QUEUE_STATS == OFPC_QUEUE_STATS); BUILD_ASSERT_DECL((int) OFPUTIL_C_ARP_MATCH_IP == OFPC_ARP_MATCH_IP); -struct ofputil_action_bit_translation { - enum ofputil_action_bitmap ofputil_bit; - int of_bit; -}; - -static const struct ofputil_action_bit_translation of10_action_bits[] = { - { OFPUTIL_A_OUTPUT, OFPAT10_OUTPUT }, - { OFPUTIL_A_SET_VLAN_VID, OFPAT10_SET_VLAN_VID }, - { OFPUTIL_A_SET_VLAN_PCP, OFPAT10_SET_VLAN_PCP }, - { OFPUTIL_A_STRIP_VLAN, OFPAT10_STRIP_VLAN }, - { OFPUTIL_A_SET_DL_SRC, OFPAT10_SET_DL_SRC }, - { OFPUTIL_A_SET_DL_DST, OFPAT10_SET_DL_DST }, - { OFPUTIL_A_SET_NW_SRC, OFPAT10_SET_NW_SRC }, - { OFPUTIL_A_SET_NW_DST, OFPAT10_SET_NW_DST }, - { OFPUTIL_A_SET_NW_TOS, OFPAT10_SET_NW_TOS }, - { OFPUTIL_A_SET_TP_SRC, OFPAT10_SET_TP_SRC }, - { OFPUTIL_A_SET_TP_DST, OFPAT10_SET_TP_DST }, - { OFPUTIL_A_ENQUEUE, OFPAT10_ENQUEUE }, - { 0, 0 }, -}; - -static enum ofputil_action_bitmap -decode_action_bits(ovs_be32 of_actions, - const struct ofputil_action_bit_translation *x) -{ - enum ofputil_action_bitmap ofputil_actions; - - ofputil_actions = 0; - for (; x->ofputil_bit; x++) { - if (of_actions & htonl(1u << x->of_bit)) { - ofputil_actions |= x->ofputil_bit; - } - } - return ofputil_actions; -} - static uint32_t ofputil_capabilities_mask(enum ofp_version ofp_version) { @@ -4096,13 +4060,14 @@ ofputil_decode_switch_features(const struct ofp_header *oh, if (osf->capabilities & htonl(OFPC10_STP)) { features->capabilities |= OFPUTIL_C_STP; } - features->actions = decode_action_bits(osf->actions, of10_action_bits); + features->ofpacts = ofpact_bitmap_from_openflow(osf->actions, + OFP10_VERSION); } else if (raw == OFPRAW_OFPT11_FEATURES_REPLY || raw == OFPRAW_OFPT13_FEATURES_REPLY) { if (osf->capabilities & htonl(OFPC11_GROUP_STATS)) { features->capabilities |= OFPUTIL_C_GROUP_STATS; } - features->actions = 0; + features->ofpacts = 0; if (raw == OFPRAW_OFPT13_FEATURES_REPLY) { features->auxiliary_id = osf->auxiliary_id; } @@ -4153,21 +4118,6 @@ ofputil_switch_features_has_ports(struct ofpbuf *b) return false; } -static ovs_be32 -encode_action_bits(enum ofputil_action_bitmap ofputil_actions, - const struct ofputil_action_bit_translation *x) -{ - uint32_t of_actions; - - of_actions = 0; - for (; x->ofputil_bit; x++) { - if (ofputil_actions & x->ofputil_bit) { - of_actions |= 1 << x->of_bit; - } - } - return htonl(of_actions); -} - /* Returns a buffer owned by the caller that encodes 'features' in the format * required by 'protocol' with the given 'xid'. The caller should append port * information to the buffer with subsequent calls to @@ -4212,7 +4162,8 @@ ofputil_encode_switch_features(const struct ofputil_switch_features *features, if (features->capabilities & OFPUTIL_C_STP) { osf->capabilities |= htonl(OFPC10_STP); } - osf->actions = encode_action_bits(features->actions, of10_action_bits); + osf->actions = ofpact_bitmap_to_openflow(features->ofpacts, + OFP10_VERSION); break; case OFP13_VERSION: case OFP14_VERSION: @@ -4504,20 +4455,25 @@ pull_table_feature_property(struct ofpbuf *msg, struct ofpbuf *payload, } static enum ofperr -parse_table_ids(struct ofpbuf *payload, uint32_t *ids) +parse_action_bitmap(struct ofpbuf *payload, enum ofp_version ofp_version, + uint64_t *ofpacts) { - uint16_t type; + uint32_t types = 0; - *ids = 0; while (ofpbuf_size(payload) > 0) { - enum ofperr error = pull_table_feature_property(payload, NULL, &type); + uint16_t type; + enum ofperr error; + + error = pull_table_feature_property(payload, NULL, &type); if (error) { return error; } - if (type < CHAR_BIT * sizeof *ids) { - *ids |= 1u << type; + if (type < CHAR_BIT * sizeof types) { + types |= 1u << type; } } + + *ofpacts = ofpact_bitmap_from_openflow(htonl(types), ofp_version); return 0; } @@ -4646,12 +4602,14 @@ int ofputil_decode_table_features(struct ofpbuf *msg, struct ofputil_table_features *tf, bool loose) { + const struct ofp_header *oh; struct ofp13_table_features *otf; unsigned int len; if (!msg->frame) { ofpraw_pull_assert(msg); } + oh = ofpbuf_l2(msg); if (!ofpbuf_size(msg)) { return EOF; @@ -4708,17 +4666,21 @@ ofputil_decode_table_features(struct ofpbuf *msg, break; case OFPTFPT13_WRITE_ACTIONS: - error = parse_table_ids(&payload, &tf->nonmiss.write.actions); + error = parse_action_bitmap(&payload, oh->version, + &tf->nonmiss.write.ofpacts); break; case OFPTFPT13_WRITE_ACTIONS_MISS: - error = parse_table_ids(&payload, &tf->miss.write.actions); + error = parse_action_bitmap(&payload, oh->version, + &tf->miss.write.ofpacts); break; case OFPTFPT13_APPLY_ACTIONS: - error = parse_table_ids(&payload, &tf->nonmiss.apply.actions); + error = parse_action_bitmap(&payload, oh->version, + &tf->nonmiss.apply.ofpacts); break; case OFPTFPT13_APPLY_ACTIONS_MISS: - error = parse_table_ids(&payload, &tf->miss.apply.actions); + error = parse_action_bitmap(&payload, oh->version, + &tf->miss.apply.ofpacts); break; case OFPTFPT13_MATCH: @@ -5030,27 +4992,27 @@ ofputil_decode_role_status(const struct ofp_header *oh, /* Table stats. */ static void -ofputil_put_ofp10_table_stats(const struct ofp12_table_stats *in, +ofputil_put_ofp10_table_stats(const struct ofputil_table_stats *in, struct ofpbuf *buf) { struct wc_map { enum ofp10_flow_wildcards wc10; - enum oxm12_ofb_match_fields mf12; + enum mf_field_id mf; }; static const struct wc_map wc_map[] = { - { OFPFW10_IN_PORT, OFPXMT12_OFB_IN_PORT }, - { OFPFW10_DL_VLAN, OFPXMT12_OFB_VLAN_VID }, - { OFPFW10_DL_SRC, OFPXMT12_OFB_ETH_SRC }, - { OFPFW10_DL_DST, OFPXMT12_OFB_ETH_DST}, - { OFPFW10_DL_TYPE, OFPXMT12_OFB_ETH_TYPE }, - { OFPFW10_NW_PROTO, OFPXMT12_OFB_IP_PROTO }, - { OFPFW10_TP_SRC, OFPXMT12_OFB_TCP_SRC }, - { OFPFW10_TP_DST, OFPXMT12_OFB_TCP_DST }, - { OFPFW10_NW_SRC_MASK, OFPXMT12_OFB_IPV4_SRC }, - { OFPFW10_NW_DST_MASK, OFPXMT12_OFB_IPV4_DST }, - { OFPFW10_DL_VLAN_PCP, OFPXMT12_OFB_VLAN_PCP }, - { OFPFW10_NW_TOS, OFPXMT12_OFB_IP_DSCP }, + { OFPFW10_IN_PORT, MFF_IN_PORT }, + { OFPFW10_DL_VLAN, MFF_VLAN_VID }, + { OFPFW10_DL_SRC, MFF_ETH_SRC }, + { OFPFW10_DL_DST, MFF_ETH_DST}, + { OFPFW10_DL_TYPE, MFF_ETH_TYPE }, + { OFPFW10_NW_PROTO, MFF_IP_PROTO }, + { OFPFW10_TP_SRC, MFF_TCP_SRC }, + { OFPFW10_TP_DST, MFF_TCP_DST }, + { OFPFW10_NW_SRC_MASK, MFF_IPV4_SRC }, + { OFPFW10_NW_DST_MASK, MFF_IPV4_DST }, + { OFPFW10_DL_VLAN_PCP, MFF_VLAN_PCP }, + { OFPFW10_NW_TOS, MFF_IP_DSCP }, }; struct ofp10_table_stats *out; @@ -5061,41 +5023,41 @@ ofputil_put_ofp10_table_stats(const struct ofp12_table_stats *in, ovs_strlcpy(out->name, in->name, sizeof out->name); out->wildcards = 0; for (p = wc_map; p < &wc_map[ARRAY_SIZE(wc_map)]; p++) { - if (in->wildcards & htonll(1ULL << p->mf12)) { + if (bitmap_is_set(in->wildcards.bm, p->mf)) { out->wildcards |= htonl(p->wc10); } } - out->max_entries = in->max_entries; - out->active_count = in->active_count; - put_32aligned_be64(&out->lookup_count, in->lookup_count); - put_32aligned_be64(&out->matched_count, in->matched_count); + out->max_entries = htonl(in->max_entries); + out->active_count = htonl(in->active_count); + put_32aligned_be64(&out->lookup_count, htonll(in->lookup_count)); + put_32aligned_be64(&out->matched_count, htonll(in->matched_count)); } static ovs_be32 -oxm12_to_ofp11_flow_match_fields(ovs_be64 oxm12) +fields_to_ofp11_flow_match_fields(const struct mf_bitmap *fields) { struct map { enum ofp11_flow_match_fields fmf11; - enum oxm12_ofb_match_fields mf12; + enum mf_field_id mf; }; static const struct map map[] = { - { OFPFMF11_IN_PORT, OFPXMT12_OFB_IN_PORT }, - { OFPFMF11_DL_VLAN, OFPXMT12_OFB_VLAN_VID }, - { OFPFMF11_DL_VLAN_PCP, OFPXMT12_OFB_VLAN_PCP }, - { OFPFMF11_DL_TYPE, OFPXMT12_OFB_ETH_TYPE }, - { OFPFMF11_NW_TOS, OFPXMT12_OFB_IP_DSCP }, - { OFPFMF11_NW_PROTO, OFPXMT12_OFB_IP_PROTO }, - { OFPFMF11_TP_SRC, OFPXMT12_OFB_TCP_SRC }, - { OFPFMF11_TP_DST, OFPXMT12_OFB_TCP_DST }, - { OFPFMF11_MPLS_LABEL, OFPXMT12_OFB_MPLS_LABEL }, - { OFPFMF11_MPLS_TC, OFPXMT12_OFB_MPLS_TC }, + { OFPFMF11_IN_PORT, MFF_IN_PORT }, + { OFPFMF11_DL_VLAN, MFF_VLAN_VID }, + { OFPFMF11_DL_VLAN_PCP, MFF_VLAN_PCP }, + { OFPFMF11_DL_TYPE, MFF_ETH_TYPE }, + { OFPFMF11_NW_TOS, MFF_IP_DSCP }, + { OFPFMF11_NW_PROTO, MFF_IP_PROTO }, + { OFPFMF11_TP_SRC, MFF_TCP_SRC }, + { OFPFMF11_TP_DST, MFF_TCP_DST }, + { OFPFMF11_MPLS_LABEL, MFF_MPLS_LABEL }, + { OFPFMF11_MPLS_TC, MFF_MPLS_TC }, /* I don't know what OFPFMF11_TYPE means. */ - { OFPFMF11_DL_SRC, OFPXMT12_OFB_ETH_SRC }, - { OFPFMF11_DL_DST, OFPXMT12_OFB_ETH_DST }, - { OFPFMF11_NW_SRC, OFPXMT12_OFB_IPV4_SRC }, - { OFPFMF11_NW_DST, OFPXMT12_OFB_IPV4_DST }, - { OFPFMF11_METADATA, OFPXMT12_OFB_METADATA }, + { OFPFMF11_DL_SRC, MFF_ETH_SRC }, + { OFPFMF11_DL_DST, MFF_ETH_DST }, + { OFPFMF11_NW_SRC, MFF_IPV4_SRC }, + { OFPFMF11_NW_DST, MFF_IPV4_DST }, + { OFPFMF11_METADATA, MFF_METADATA }, }; const struct map *p; @@ -5103,7 +5065,7 @@ oxm12_to_ofp11_flow_match_fields(ovs_be64 oxm12) fmf11 = 0; for (p = map; p < &map[ARRAY_SIZE(map)]; p++) { - if (oxm12 & htonll(1ULL << p->mf12)) { + if (bitmap_is_set(fields->bm, p->mf)) { fmf11 |= p->fmf11; } } @@ -5111,7 +5073,7 @@ oxm12_to_ofp11_flow_match_fields(ovs_be64 oxm12) } static void -ofputil_put_ofp11_table_stats(const struct ofp12_table_stats *in, +ofputil_put_ofp11_table_stats(const struct ofputil_table_stats *in, struct ofpbuf *buf) { struct ofp11_table_stats *out; @@ -5119,50 +5081,84 @@ ofputil_put_ofp11_table_stats(const struct ofp12_table_stats *in, out = ofpbuf_put_zeros(buf, sizeof *out); out->table_id = in->table_id; ovs_strlcpy(out->name, in->name, sizeof out->name); - out->wildcards = oxm12_to_ofp11_flow_match_fields(in->wildcards); - out->match = oxm12_to_ofp11_flow_match_fields(in->match); - out->instructions = in->instructions; - out->write_actions = in->write_actions; - out->apply_actions = in->apply_actions; - out->config = in->config; - out->max_entries = in->max_entries; - out->active_count = in->active_count; - out->lookup_count = in->lookup_count; - out->matched_count = in->matched_count; + out->wildcards = fields_to_ofp11_flow_match_fields(&in->wildcards); + out->match = fields_to_ofp11_flow_match_fields(&in->match); + out->instructions = htonl(in->instructions); + out->write_actions = ofpact_bitmap_to_openflow(in->write_ofpacts, + OFP11_VERSION); + out->apply_actions = ofpact_bitmap_to_openflow(in->apply_ofpacts, + OFP11_VERSION); + out->config = htonl(in->config); + out->max_entries = htonl(in->max_entries); + out->active_count = htonl(in->active_count); + out->lookup_count = htonll(in->lookup_count); + out->matched_count = htonll(in->matched_count); +} + +static ovs_be64 +mf_bitmap_to_oxm_bitmap(const struct mf_bitmap *fields, + enum ofp_version version) +{ + uint64_t oxm_bitmap = 0; + int i; + + BITMAP_FOR_EACH_1 (i, MFF_N_IDS, fields->bm) { + uint32_t oxm = mf_oxm_header(i, version); + uint32_t vendor = NXM_VENDOR(oxm); + int field = NXM_FIELD(oxm); + + if (vendor == OFPXMC12_OPENFLOW_BASIC && field < 64) { + oxm_bitmap |= UINT64_C(1) << field; + } + } + return htonll(oxm_bitmap); } static void -ofputil_put_ofp12_table_stats(const struct ofp12_table_stats *in, +ofputil_put_ofp12_table_stats(const struct ofputil_table_stats *in, struct ofpbuf *buf) { - struct ofp12_table_stats *out = ofpbuf_put(buf, in, sizeof *in); + struct ofp12_table_stats *out; - /* Trim off OF1.3-only capabilities. */ - out->match &= htonll(OFPXMT12_MASK); - out->wildcards &= htonll(OFPXMT12_MASK); - out->write_setfields &= htonll(OFPXMT12_MASK); - out->apply_setfields &= htonll(OFPXMT12_MASK); + out = ofpbuf_put_zeros(buf, sizeof *out); + out->table_id = in->table_id; + ovs_strlcpy(out->name, in->name, sizeof out->name); + out->match = mf_bitmap_to_oxm_bitmap(&in->match, OFP12_VERSION); + out->wildcards = mf_bitmap_to_oxm_bitmap(&in->wildcards, OFP12_VERSION); + out->write_actions = ofpact_bitmap_to_openflow(in->write_ofpacts, + OFP12_VERSION); + out->apply_actions = ofpact_bitmap_to_openflow(in->apply_ofpacts, + OFP12_VERSION); + out->write_setfields = mf_bitmap_to_oxm_bitmap(&in->write_setfields, + OFP12_VERSION); + out->apply_setfields = mf_bitmap_to_oxm_bitmap(&in->apply_setfields, + OFP12_VERSION); + out->metadata_match = in->metadata_match; + out->metadata_write = in->metadata_write; + out->instructions = htonl(in->instructions & OFPIT11_ALL); + out->config = htonl(in->config); + out->max_entries = htonl(in->max_entries); + out->active_count = htonl(in->active_count); + out->lookup_count = htonll(in->lookup_count); + out->matched_count = htonll(in->matched_count); } static void -ofputil_put_ofp13_table_stats(const struct ofp12_table_stats *in, +ofputil_put_ofp13_table_stats(const struct ofputil_table_stats *in, struct ofpbuf *buf) { struct ofp13_table_stats *out; - /* OF 1.3 splits table features off the ofp_table_stats, - * so there is not much here. */ - out = ofpbuf_put_uninit(buf, sizeof *out); out->table_id = in->table_id; - out->active_count = in->active_count; - out->lookup_count = in->lookup_count; - out->matched_count = in->matched_count; + out->active_count = htonl(in->active_count); + out->lookup_count = htonll(in->lookup_count); + out->matched_count = htonll(in->matched_count); } struct ofpbuf * -ofputil_encode_table_stats_reply(const struct ofp12_table_stats stats[], int n, - const struct ofp_header *request) +ofputil_encode_table_stats_reply(const struct ofputil_table_stats stats[], + int n, const struct ofp_header *request) { struct ofpbuf *reply; int i; @@ -6796,20 +6792,18 @@ ofputil_encode_group_features_reply( { struct ofp12_group_features_stats *ogf; struct ofpbuf *reply; + int i; reply = ofpraw_alloc_xid(OFPRAW_OFPST12_GROUP_FEATURES_REPLY, request->version, request->xid, 0); ogf = ofpbuf_put_zeros(reply, sizeof *ogf); ogf->types = htonl(features->types); ogf->capabilities = htonl(features->capabilities); - ogf->max_groups[0] = htonl(features->max_groups[0]); - ogf->max_groups[1] = htonl(features->max_groups[1]); - ogf->max_groups[2] = htonl(features->max_groups[2]); - ogf->max_groups[3] = htonl(features->max_groups[3]); - ogf->actions[0] = htonl(features->actions[0]); - ogf->actions[1] = htonl(features->actions[1]); - ogf->actions[2] = htonl(features->actions[2]); - ogf->actions[3] = htonl(features->actions[3]); + for (i = 0; i < OFPGT12_N_TYPES; i++) { + ogf->max_groups[i] = htonl(features->max_groups[i]); + ogf->actions[i] = ofpact_bitmap_to_openflow(features->ofpacts[i], + request->version); + } return reply; } @@ -6820,17 +6814,15 @@ ofputil_decode_group_features_reply(const struct ofp_header *oh, struct ofputil_group_features *features) { const struct ofp12_group_features_stats *ogf = ofpmsg_body(oh); + int i; features->types = ntohl(ogf->types); features->capabilities = ntohl(ogf->capabilities); - features->max_groups[0] = ntohl(ogf->max_groups[0]); - features->max_groups[1] = ntohl(ogf->max_groups[1]); - features->max_groups[2] = ntohl(ogf->max_groups[2]); - features->max_groups[3] = ntohl(ogf->max_groups[3]); - features->actions[0] = ntohl(ogf->actions[0]); - features->actions[1] = ntohl(ogf->actions[1]); - features->actions[2] = ntohl(ogf->actions[2]); - features->actions[3] = ntohl(ogf->actions[3]); + for (i = 0; i < OFPGT12_N_TYPES; i++) { + features->max_groups[i] = ntohl(ogf->max_groups[i]); + features->ofpacts[i] = ofpact_bitmap_from_openflow( + ogf->actions[i], oh->version); + } } /* Parse a group status request message into a 32 bit OpenFlow 1.1 diff --git a/lib/ofp-util.h b/lib/ofp-util.h index 39e50ed19af..38e7006cd15 100644 --- a/lib/ofp-util.h +++ b/lib/ofp-util.h @@ -528,37 +528,6 @@ enum ofputil_capabilities { OFPUTIL_C_PORT_BLOCKED = 1 << 8, /* Switch will block looping ports */ }; -enum ofputil_action_bitmap { - OFPUTIL_A_OUTPUT = 1 << 0, - OFPUTIL_A_SET_VLAN_VID = 1 << 1, - OFPUTIL_A_SET_VLAN_PCP = 1 << 2, - OFPUTIL_A_STRIP_VLAN = 1 << 3, - OFPUTIL_A_SET_DL_SRC = 1 << 4, - OFPUTIL_A_SET_DL_DST = 1 << 5, - OFPUTIL_A_SET_NW_SRC = 1 << 6, - OFPUTIL_A_SET_NW_DST = 1 << 7, - OFPUTIL_A_SET_NW_ECN = 1 << 8, - OFPUTIL_A_SET_NW_TOS = 1 << 9, - OFPUTIL_A_SET_TP_SRC = 1 << 10, - OFPUTIL_A_SET_TP_DST = 1 << 11, - OFPUTIL_A_ENQUEUE = 1 << 12, - OFPUTIL_A_COPY_TTL_OUT = 1 << 13, - OFPUTIL_A_COPY_TTL_IN = 1 << 14, - OFPUTIL_A_SET_MPLS_LABEL = 1 << 15, - OFPUTIL_A_SET_MPLS_TC = 1 << 16, - OFPUTIL_A_SET_MPLS_TTL = 1 << 17, - OFPUTIL_A_DEC_MPLS_TTL = 1 << 18, - OFPUTIL_A_PUSH_VLAN = 1 << 19, - OFPUTIL_A_POP_VLAN = 1 << 20, - OFPUTIL_A_PUSH_MPLS = 1 << 21, - OFPUTIL_A_POP_MPLS = 1 << 22, - OFPUTIL_A_SET_QUEUE = 1 << 23, - OFPUTIL_A_GROUP = 1 << 24, - OFPUTIL_A_SET_NW_TTL = 1 << 25, - OFPUTIL_A_DEC_NW_TTL = 1 << 26, - OFPUTIL_A_SET_FIELD = 1 << 27, -}; - /* Abstract ofp_switch_features. */ struct ofputil_switch_features { uint64_t datapath_id; /* Datapath unique ID. */ @@ -566,7 +535,7 @@ struct ofputil_switch_features { uint8_t n_tables; /* Number of tables supported by datapath. */ uint8_t auxiliary_id; /* Identify auxiliary connections */ enum ofputil_capabilities capabilities; - enum ofputil_action_bitmap actions; + uint64_t ofpacts; /* Bitmap of OFPACT_* bits. */ }; enum ofperr ofputil_decode_switch_features(const struct ofp_header *, @@ -650,7 +619,7 @@ struct ofputil_table_features { * - 'apply' reports features available in an "apply_actions" * instruction. */ struct ofputil_table_action_features { - uint32_t actions; /* Bitmap of supported OFPAT*. */ + uint64_t ofpacts; /* Bitmap of supported OFPACT_*. */ struct mf_bitmap set_fields; /* Fields for "set-field". */ } write, apply; } nonmiss, miss; @@ -798,13 +767,30 @@ struct ofpbuf *ofputil_encode_role_status( enum ofperr ofputil_decode_role_status(const struct ofp_header *oh, struct ofputil_role_status *rs); -/* Abstract table stats. - * - * For now we use ofp12_table_stats as a superset of the other protocol - * versions' table stats. */ +/* Abstract table stats. */ +struct ofputil_table_stats { + uint8_t table_id; + char name[OFP_MAX_TABLE_NAME_LEN]; + ovs_be64 metadata_match; /* Bits of metadata table can match. */ + ovs_be64 metadata_write; /* Bits of metadata table can write. */ + uint32_t config; /* Bitmap of OFPTC_* values */ + uint32_t max_entries; /* Max number of entries supported. */ + + struct mf_bitmap match; /* Fields table can match. */ + struct mf_bitmap wildcards; /* Fields table can wildcard. */ + uint64_t write_ofpacts; /* OFPACT_* supported on Write-Actions. */ + uint64_t apply_ofpacts; /* OFPACT_* supported on Apply-Actions. */ + struct mf_bitmap write_setfields; /* Fields that can be set in W-A. */ + struct mf_bitmap apply_setfields; /* Fields that can be set in A-A. */ + uint32_t instructions; /* Bitmap of OFPIT_* values supported. */ + + uint32_t active_count; /* Number of active entries. */ + uint64_t lookup_count; /* Number of packets looked up in table. */ + uint64_t matched_count; /* Number of packets that hit table. */ +}; struct ofpbuf *ofputil_encode_table_stats_reply( - const struct ofp12_table_stats[], int n, + const struct ofputil_table_stats[], int n, const struct ofp_header *request); /* Queue configuration request. */ @@ -1099,9 +1085,7 @@ struct ofputil_group_features { uint32_t types; /* Bitmap of OFPGT_* values supported. */ uint32_t capabilities; /* Bitmap of OFPGFC12_* capability supported. */ uint32_t max_groups[4]; /* Maximum number of groups for each type. */ - - /* Bitmaps of OFPAT_* that are supported. OF1.2+ actions only. */ - uint32_t actions[4]; + uint64_t ofpacts[4]; /* Bitmaps of supported OFPACT_* */ }; /* Group desc reply, independent of protocol. */ diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 48d0b820538..92d5718c4d2 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -1500,37 +1500,26 @@ flush(struct ofproto *ofproto_) static void get_features(struct ofproto *ofproto_ OVS_UNUSED, - bool *arp_match_ip, enum ofputil_action_bitmap *actions) + bool *arp_match_ip, uint64_t *ofpacts) { *arp_match_ip = true; - *actions = (OFPUTIL_A_OUTPUT | - OFPUTIL_A_SET_VLAN_VID | - OFPUTIL_A_SET_VLAN_PCP | - OFPUTIL_A_STRIP_VLAN | - OFPUTIL_A_SET_DL_SRC | - OFPUTIL_A_SET_DL_DST | - OFPUTIL_A_SET_NW_SRC | - OFPUTIL_A_SET_NW_DST | - OFPUTIL_A_SET_NW_TOS | - OFPUTIL_A_SET_TP_SRC | - OFPUTIL_A_SET_TP_DST | - OFPUTIL_A_ENQUEUE); + *ofpacts = (UINT64_C(1) << N_OFPACTS) - 1; } static void -get_tables(struct ofproto *ofproto, struct ofp12_table_stats *ots) +get_tables(struct ofproto *ofproto, struct ofputil_table_stats *stats) { int i; - strcpy(ots->name, "classifier"); + strcpy(stats->name, "classifier"); for (i = 0; i < ofproto->n_tables; i++) { unsigned long missed, matched; atomic_read(&ofproto->tables[i].n_matched, &matched); - ots[i].matched_count = htonll(matched); + stats[i].matched_count = matched; atomic_read(&ofproto->tables[i].n_missed, &missed); - ots[i].lookup_count = htonll(matched + missed); + stats[i].lookup_count = matched + missed; } } diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h index 7e6e99bcf14..9c0c94e0115 100644 --- a/ofproto/ofproto-provider.h +++ b/ofproto/ofproto-provider.h @@ -774,30 +774,30 @@ struct ofproto_class { * supports matching IP addresses inside ARP requests and replies, false * otherwise. * - * The implementation should store in '*actions' a bitmap of the supported - * OpenFlow actions. Vendor actions are not included in '*actions'. */ + * The implementation should store in '*ofpacts' a bitmap of the supported + * OFPACT_* actions. */ void (*get_features)(struct ofproto *ofproto, bool *arp_match_ip, - enum ofputil_action_bitmap *actions); + uint64_t *ofpacts); /* Helper for the OpenFlow OFPST_TABLE statistics request. * - * The 'ots' array contains 'ofproto->n_tables' elements. Each element is + * The 'stats' array contains 'ofproto->n_tables' elements. Each element is * initialized as: * * - 'table_id' to the array index. * * - 'name' to "table#" where # is the table ID. * - * - 'match' and 'wildcards' to OFPXMT12_MASK. + * - 'match' and 'wildcards' to all fields. * - * - 'write_actions' and 'apply_actions' to OFPAT12_OUTPUT. + * - 'write_actions' and 'apply_actions' to all actions. * - * - 'write_setfields' and 'apply_setfields' to OFPXMT12_MASK. + * - 'write_setfields' and 'apply_setfields' to all writable fields. * * - 'metadata_match' and 'metadata_write' to OVS_BE64_MAX. * - * - 'instructions' to OFPIT11_ALL. + * - 'instructions' to all instructions. * * - 'config' to OFPTC11_TABLE_MISS_MASK. * @@ -838,11 +838,9 @@ struct ofproto_class { * * - 'matched_count' to the number of packets looked up in this flow * table so far that matched one of the flow entries. - * - * All of the members of struct ofp12_table_stats are in network byte - * order. */ - void (*get_tables)(struct ofproto *ofproto, struct ofp12_table_stats *ots); + void (*get_tables)(struct ofproto *ofproto, + struct ofputil_table_stats *stats); /* ## ---------------- ## */ /* ## ofport Functions ## */ diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index fca7d09e7c4..78b67739ad3 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -524,28 +524,10 @@ ofproto_create(const char *datapath_name, const char *datapath_type, ovs_mutex_unlock(&ofproto_mutex); ofproto->ogf.capabilities = OFPGFC_CHAINING | OFPGFC_SELECT_LIVENESS | OFPGFC_SELECT_WEIGHT; - ofproto->ogf.max_groups[OFPGT11_ALL] = OFPG_MAX; - ofproto->ogf.max_groups[OFPGT11_SELECT] = OFPG_MAX; - ofproto->ogf.max_groups[OFPGT11_INDIRECT] = OFPG_MAX; - ofproto->ogf.max_groups[OFPGT11_FF] = OFPG_MAX; - ofproto->ogf.actions[0] = - (1 << OFPAT11_OUTPUT) | - (1 << OFPAT11_COPY_TTL_OUT) | - (1 << OFPAT11_COPY_TTL_IN) | - (1 << OFPAT11_SET_MPLS_TTL) | - (1 << OFPAT11_DEC_MPLS_TTL) | - (1 << OFPAT11_PUSH_VLAN) | - (1 << OFPAT11_POP_VLAN) | - (1 << OFPAT11_PUSH_MPLS) | - (1 << OFPAT11_POP_MPLS) | - (1 << OFPAT11_SET_QUEUE) | - (1 << OFPAT11_GROUP) | - (1 << OFPAT11_SET_NW_TTL) | - (1 << OFPAT11_DEC_NW_TTL) | - (1 << OFPAT12_SET_FIELD); -/* not supported: - * (1 << OFPAT13_PUSH_PBB) | - * (1 << OFPAT13_POP_PBB) */ + for (i = 0; i < 4; i++) { + ofproto->ogf.max_groups[i] = OFPG_MAX; + ofproto->ogf.ofpacts[i] = (UINT64_C(1) << N_OFPACTS) - 1; + } error = ofproto->ofproto_class->construct(ofproto); if (error) { @@ -2805,8 +2787,8 @@ handle_features_request(struct ofconn *ofconn, const struct ofp_header *oh) struct ofpbuf *b; ofproto->ofproto_class->get_features(ofproto, &arp_match_ip, - &features.actions); - ovs_assert(features.actions & OFPUTIL_A_OUTPUT); /* sanity check */ + &features.ofpacts); + ovs_assert(features.ofpacts & (UINT64_C(1) << OFPACT_OUTPUT)); features.datapath_id = ofproto->datapath_id; features.n_buffers = pktbuf_capacity(); @@ -3081,37 +3063,44 @@ static enum ofperr handle_table_stats_request(struct ofconn *ofconn, const struct ofp_header *request) { + struct mf_bitmap rw_fields = MF_BITMAP_INITIALIZER; struct ofproto *p = ofconn_get_ofproto(ofconn); - struct ofp12_table_stats *ots; + struct ofputil_table_stats *stats; struct ofpbuf *msg; int n_tables; size_t i; + for (i = 0; i < MFF_N_IDS; i++) { + if (mf_from_id(i)->writable) { + bitmap_set1(rw_fields.bm, i); + } + } + /* Set up default values. * * ofp12_table_stats is used as a generic structure as * it is able to hold all the fields for ofp10_table_stats * and ofp11_table_stats (and of course itself). */ - ots = xcalloc(p->n_tables, sizeof *ots); + stats = xcalloc(p->n_tables, sizeof *stats); for (i = 0; i < p->n_tables; i++) { - ots[i].table_id = i; - sprintf(ots[i].name, "table%"PRIuSIZE, i); - ots[i].match = htonll(OFPXMT13_MASK); - ots[i].wildcards = htonll(OFPXMT13_MASK); - ots[i].write_actions = htonl(OFPAT11_OUTPUT); - ots[i].apply_actions = htonl(OFPAT11_OUTPUT); - ots[i].write_setfields = htonll(OFPXMT13_MASK); - ots[i].apply_setfields = htonll(OFPXMT13_MASK); - ots[i].metadata_match = OVS_BE64_MAX; - ots[i].metadata_write = OVS_BE64_MAX; - ots[i].instructions = htonl(OFPIT11_ALL); - ots[i].config = htonl(OFPTC11_TABLE_MISS_MASK); - ots[i].max_entries = htonl(1000000); /* An arbitrary big number. */ - ots[i].active_count = htonl(classifier_count(&p->tables[i].cls)); - } - - p->ofproto_class->get_tables(p, ots); + stats[i].table_id = i; + sprintf(stats[i].name, "table%"PRIuSIZE, i); + bitmap_set_multiple(stats[i].match.bm, 0, MFF_N_IDS, 1); + bitmap_set_multiple(stats[i].wildcards.bm, 0, MFF_N_IDS, 1); + stats[i].write_ofpacts = (UINT64_C(1) << N_OFPACTS) - 1; + stats[i].apply_ofpacts = (UINT64_C(1) << N_OFPACTS) - 1; + stats[i].write_setfields = rw_fields; + stats[i].apply_setfields = rw_fields; + stats[i].metadata_match = OVS_BE64_MAX; + stats[i].metadata_write = OVS_BE64_MAX; + stats[i].instructions = OFPIT13_ALL; + stats[i].config = OFPTC11_TABLE_MISS_MASK; + stats[i].max_entries = 1000000; /* An arbitrary big number. */ + stats[i].active_count = classifier_count(&p->tables[i].cls); + } + + p->ofproto_class->get_tables(p, stats); /* Post-process the tables, dropping hidden tables. */ n_tables = p->n_tables; @@ -3124,18 +3113,18 @@ handle_table_stats_request(struct ofconn *ofconn, } if (table->name) { - ovs_strzcpy(ots[i].name, table->name, sizeof ots[i].name); + ovs_strzcpy(stats[i].name, table->name, sizeof stats[i].name); } - if (table->max_flows < ntohl(ots[i].max_entries)) { - ots[i].max_entries = htonl(table->max_flows); + if (table->max_flows < stats[i].max_entries) { + stats[i].max_entries = table->max_flows; } } - msg = ofputil_encode_table_stats_reply(ots, n_tables, request); + msg = ofputil_encode_table_stats_reply(stats, n_tables, request); ofconn_send_reply(ofconn, msg); - free(ots); + free(stats); return 0; } diff --git a/tests/ofp-print.at b/tests/ofp-print.at index 5871930cee1..3e35baa3c41 100644 --- a/tests/ofp-print.at +++ b/tests/ofp-print.at @@ -203,7 +203,7 @@ ff fe 50 54 00 00 00 01 62 72 30 00 00 00 00 00 \ OFPT_FEATURES_REPLY (xid=0x1): dpid:0000505400000001 n_tables:2, n_buffers:256 capabilities: FLOW_STATS TABLE_STATS PORT_STATS ARP_MATCH_IP -actions: OUTPUT SET_VLAN_VID SET_VLAN_PCP STRIP_VLAN SET_DL_SRC SET_DL_DST SET_NW_SRC SET_NW_DST SET_NW_TOS SET_TP_SRC SET_TP_DST ENQUEUE +actions: output enqueue set_vlan_vid set_vlan_pcp strip_vlan mod_dl_src mod_dl_dst mod_nw_src mod_nw_dst mod_nw_tos mod_tp_src mod_tp_dst 1(eth1): addr:50:54:00:00:00:02 config: 0 state: 0 @@ -1923,20 +1923,24 @@ AT_CHECK([ovs-ofctl ofp-print "\ 03 13 00 38 00 00 00 02 00 08 00 00 00 00 00 00 \ 00 00 00 0f 00 00 00 0f \ 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 04 \ -00 00 00 01 00 00 00 03 00 00 00 07 00 00 00 0f \ +00 00 00 01 00 02 00 01 00 06 00 01 00 0e 00 01 \ "], [0], [dnl OFPST_GROUP_FEATURES reply (OF1.2) (xid=0x2): Group table: Types: 0xf Capabilities: 0xf - All group : - max_groups = 0x1 actions=0x00000001 - Select group : - max_groups = 0x2 actions=0x00000003 - Indirect group : - max_groups = 0x3 actions=0x00000007 - Fast Failover group : - max_groups = 0x4 actions=0x0000000f + all group: + max_groups=0x1 + actions: output + select group: + max_groups=0x2 + actions: output push_vlan + indirect group: + max_groups=0x3 + actions: output strip_vlan push_vlan + fast failover group: + max_groups=0x4 + actions: output strip_vlan push_vlan push_mpls ]) AT_CLEANUP @@ -2275,7 +2279,7 @@ f5 f6 f7 f8 f9 fa fb fc fd 00 00 00 00 00 00 00 \ next tables: 1-253 instructions: apply_actions,clear_actions,write_actions,write_metadata,goto_table Write-Actions and Apply-Actions features: - actions: output,copy_ttl_out,copy_ttl_in,set_mpls_ttl,dec_mpls_ttl,push_vlan,pop_vlan,push_mpls,pop_mpls,set_queue,group,set_nw_ttl,dec_nw_ttl,set_field,push_pbb,pop_pbb + actions: output group set_field strip_vlan push_vlan mod_nw_ttl dec_ttl set_mpls_ttl dec_mpls_ttl push_mpls pop_mpls set_queue supported on Set-Field: tun_id,tun_src,tun_dst,metadata,in_port,in_port_oxm,pkt_mark,reg0,reg1,reg2,reg3,reg4,reg5,reg6,reg7,eth_src,eth_dst,vlan_tci,vlan_vid,vlan_pcp,mpls_label,mpls_tc,ip_src,ip_dst,ipv6_src,ipv6_dst,nw_tos,ip_dscp,nw_ecn,nw_ttl,arp_op,arp_spa,arp_tpa,arp_sha,arp_tha,tcp_src,tcp_dst,udp_src,udp_dst,sctp_src,sctp_dst matching: tun_id: exact match or wildcard diff --git a/tests/ofproto.at b/tests/ofproto.at index 3a55ce37545..06a7df47368 100644 --- a/tests/ofproto.at +++ b/tests/ofproto.at @@ -36,7 +36,7 @@ AT_CHECK([STRIP_XIDS stdout], [0], [dnl OFPT_FEATURES_REPLY: dpid:fedcba9876543210 n_tables:254, n_buffers:256 capabilities: FLOW_STATS TABLE_STATS PORT_STATS QUEUE_STATS ARP_MATCH_IP -actions: OUTPUT SET_VLAN_VID SET_VLAN_PCP STRIP_VLAN SET_DL_SRC SET_DL_DST SET_NW_SRC SET_NW_DST SET_NW_TOS SET_TP_SRC SET_TP_DST ENQUEUE +actions: output enqueue set_vlan_vid set_vlan_pcp strip_vlan mod_dl_src mod_dl_dst mod_nw_src mod_nw_dst mod_nw_tos mod_tp_src mod_tp_dst LOCAL(br0): addr:aa:55:aa:55:00:00 config: PORT_DOWN state: LINK_DOWN @@ -58,7 +58,7 @@ s/00:0.$/00:0x/' < stdout]], OFPT_FEATURES_REPLY: dpid:fedcba9876543210 n_tables:254, n_buffers:256 capabilities: FLOW_STATS TABLE_STATS PORT_STATS QUEUE_STATS ARP_MATCH_IP -actions: OUTPUT SET_VLAN_VID SET_VLAN_PCP STRIP_VLAN SET_DL_SRC SET_DL_DST SET_NW_SRC SET_NW_DST SET_NW_TOS SET_TP_SRC SET_TP_DST ENQUEUE +actions: output enqueue set_vlan_vid set_vlan_pcp strip_vlan mod_dl_src mod_dl_dst mod_nw_src mod_nw_dst mod_nw_tos mod_tp_src mod_tp_dst 1(p1): addr:aa:55:aa:55:00:0x config: PORT_DOWN state: LINK_DOWN @@ -451,7 +451,7 @@ do OFPT_FEATURES_REPLY: dpid:fedcba9876543210 n_tables:254, n_buffers:256 capabilities: FLOW_STATS TABLE_STATS PORT_STATS QUEUE_STATS ARP_MATCH_IP -actions: OUTPUT SET_VLAN_VID SET_VLAN_PCP STRIP_VLAN SET_DL_SRC SET_DL_DST SET_NW_SRC SET_NW_DST SET_NW_TOS SET_TP_SRC SET_TP_DST ENQUEUE +actions: output enqueue set_vlan_vid set_vlan_pcp strip_vlan mod_dl_src mod_dl_dst mod_nw_src mod_nw_dst mod_nw_tos mod_tp_src mod_tp_dst LOCAL(br0): addr:aa:55:aa:55:00:00 config: $config state: $state @@ -1064,13 +1064,13 @@ AT_CLEANUP AT_SETUP([ofproto - flow table configuration (OpenFlow 1.2)]) OVS_VSWITCHD_START # Check the default configuration. -(mid="wild=0xfffffffff, max=1000000," +(mid="wild=0x1ffffffffd, max=1000000," tail=" lookup=0, matched=0 - match=0xfffffffff, instructions=0x00000007, config=0x00000003 - write_actions=0x00000000, apply_actions=0x00000000 - write_setfields=0x0000000fffffffff - apply_setfields=0x0000000fffffffff + match=0x1ffffffffd, instructions=0x00000007, config=0x00000003 + write_actions=0x03ff8001, apply_actions=0x03ff8001 + write_setfields=0x0000000c0fe7fbdd + apply_setfields=0x0000000c0fe7fbdd metadata_match=0xffffffffffffffff metadata_write=0xffffffffffffffff" echo "OFPST_TABLE reply (OF1.2) (xid=0x2): 254 tables @@ -1095,9 +1095,9 @@ AT_CHECK( # Check that the configuration was updated. mv expout orig-expout (echo "OFPST_TABLE reply (OF1.2) (xid=0x2): 254 tables - 0: main : wild=0xfffffffff, max=1000000, active=0" + 0: main : wild=0x1ffffffffd, max=1000000, active=0" tail -n +3 orig-expout | head -7 - echo " 1: table1 : wild=0xfffffffff, max= 1024, active=0" + echo " 1: table1 : wild=0x1ffffffffd, max= 1024, active=0" tail -n +11 orig-expout) > expout AT_CHECK([ovs-ofctl -O OpenFlow12 dump-tables br0], [0], [expout]) OVS_VSWITCHD_STOP