X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fofp-util.c;h=5f7937f642e26516ad3e788994cb491cb507d8b2;hb=f613a0d72c521ca3a4eeb2c29ac523f6fdf72667;hp=bcb1b9ef60a131ba4c66aa3f37f9022141e3bf33;hpb=39dc90822efc67cee8485e3e410f239a2a9e6e00;p=sliver-openvswitch.git diff --git a/lib/ofp-util.c b/lib/ofp-util.c index bcb1b9ef6..5f7937f64 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -25,6 +25,7 @@ #include "byte-order.h" #include "classifier.h" #include "dynamic-string.h" +#include "learn.h" #include "multipath.h" #include "nx-match.h" #include "ofp-errors.h" @@ -343,9 +344,6 @@ static int ofputil_decode_vendor(const struct ofp_header *oh, const struct ofputil_msg_type **typep) { - BUILD_ASSERT_DECL(sizeof(struct nxt_set_flow_format) - != sizeof(struct nxt_flow_mod_table_id)); - static const struct ofputil_msg_type nxt_messages[] = { { OFPUTIL_NXT_ROLE_REQUEST, NXT_ROLE_REQUEST, "NXT_ROLE_REQUEST", @@ -1825,10 +1823,7 @@ make_add_simple_flow(const struct cls_rule *rule, struct ofpbuf *buffer; buffer = make_add_flow(rule, buffer_id, idle_timeout, sizeof *oao); - oao = ofpbuf_put_zeros(buffer, sizeof *oao); - oao->type = htons(OFPAT_OUTPUT); - oao->len = htons(sizeof *oao); - oao->port = htons(out_port); + ofputil_put_OFPAT_OUTPUT(buffer)->port = htons(out_port); return buffer; } else { return make_add_flow(rule, buffer_id, idle_timeout, 0); @@ -2135,6 +2130,10 @@ validate_actions(const union ofp_action *actions, size_t n_actions, (const struct nx_action_resubmit *) a); break; + case OFPUTIL_NXAST_LEARN: + error = learn_check((const struct nx_action_learn *) a, flow); + break; + case OFPUTIL_OFPAT_STRIP_VLAN: case OFPUTIL_OFPAT_SET_NW_SRC: case OFPUTIL_OFPAT_SET_NW_DST: @@ -2187,26 +2186,16 @@ ofputil_decode_ofpat_action(const union ofp_action *a) enum ofp_action_type type = ntohs(a->type); switch (type) { -#define OFPAT_ACTION(ENUM, TYPE) \ +#define OFPAT_ACTION(ENUM, STRUCT, NAME) \ case ENUM: { \ static const struct ofputil_action action = { \ - OFPUTIL_##ENUM, sizeof(TYPE), sizeof(TYPE) \ + OFPUTIL_##ENUM, \ + sizeof(struct STRUCT), \ + sizeof(struct STRUCT) \ }; \ return &action; \ } - OFPAT_ACTION(OFPAT_OUTPUT, struct ofp_action_output); - OFPAT_ACTION(OFPAT_SET_VLAN_VID, struct ofp_action_vlan_vid); - OFPAT_ACTION(OFPAT_SET_VLAN_PCP, struct ofp_action_vlan_pcp); - OFPAT_ACTION(OFPAT_STRIP_VLAN, struct ofp_action_header); - OFPAT_ACTION(OFPAT_SET_DL_SRC, struct ofp_action_dl_addr); - OFPAT_ACTION(OFPAT_SET_DL_DST, struct ofp_action_dl_addr); - OFPAT_ACTION(OFPAT_SET_NW_SRC, struct ofp_action_nw_addr); - OFPAT_ACTION(OFPAT_SET_NW_DST, struct ofp_action_nw_addr); - OFPAT_ACTION(OFPAT_SET_NW_TOS, struct ofp_action_nw_tos); - OFPAT_ACTION(OFPAT_SET_TP_SRC, struct ofp_action_tp_port); - OFPAT_ACTION(OFPAT_SET_TP_DST, struct ofp_action_tp_port); - OFPAT_ACTION(OFPAT_ENQUEUE, struct ofp_action_enqueue); -#undef OFPAT_ACTION +#include "ofp-util.def" case OFPAT_VENDOR: default: @@ -2221,30 +2210,16 @@ ofputil_decode_nxast_action(const union ofp_action *a) enum nx_action_subtype subtype = ntohs(nah->subtype); switch (subtype) { -#define NXAST_ACTION(ENUM, TYPE, EXTENSIBLE) \ - case ENUM: { \ - static const struct ofputil_action action = { \ - OFPUTIL_##ENUM, \ - sizeof(TYPE), \ - EXTENSIBLE ? UINT_MAX : sizeof(TYPE) \ - }; \ - return &action; \ +#define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) \ + case ENUM: { \ + static const struct ofputil_action action = { \ + OFPUTIL_##ENUM, \ + sizeof(struct STRUCT), \ + EXTENSIBLE ? UINT_MAX : sizeof(struct STRUCT) \ + }; \ + return &action; \ } - NXAST_ACTION(NXAST_RESUBMIT, struct nx_action_resubmit, false); - NXAST_ACTION(NXAST_SET_TUNNEL, struct nx_action_set_tunnel, false); - NXAST_ACTION(NXAST_SET_QUEUE, struct nx_action_set_queue, false); - NXAST_ACTION(NXAST_POP_QUEUE, struct nx_action_pop_queue, false); - NXAST_ACTION(NXAST_REG_MOVE, struct nx_action_reg_move, false); - NXAST_ACTION(NXAST_REG_LOAD, struct nx_action_reg_load, false); - NXAST_ACTION(NXAST_NOTE, struct nx_action_note, true); - NXAST_ACTION(NXAST_SET_TUNNEL64, struct nx_action_set_tunnel64, false); - NXAST_ACTION(NXAST_MULTIPATH, struct nx_action_multipath, false); - NXAST_ACTION(NXAST_AUTOPATH, struct nx_action_autopath, false); - NXAST_ACTION(NXAST_BUNDLE, struct nx_action_bundle, true); - NXAST_ACTION(NXAST_BUNDLE_LOAD, struct nx_action_bundle, true); - NXAST_ACTION(NXAST_RESUBMIT_TABLE, struct nx_action_resubmit, false); - NXAST_ACTION(NXAST_OUTPUT_REG, struct nx_action_output_reg, false); -#undef NXAST_ACTION +#include "ofp-util.def" case NXAST_SNAT__OBSOLETE: case NXAST_DROP_SPOOFED_ARP__OBSOLETE: @@ -2308,6 +2283,84 @@ ofputil_decode_action_unsafe(const union ofp_action *a) return action->code; } +/* Returns the 'enum ofputil_action_code' corresponding to 'name' (e.g. if + * 'name' is "output" then the return value is OFPUTIL_OFPAT_OUTPUT), or -1 if + * 'name' is not the name of any action. + * + * ofp-util.def lists the mapping from names to action. */ +int +ofputil_action_code_from_name(const char *name) +{ + static const char *names[OFPUTIL_N_ACTIONS] = { +#define OFPAT_ACTION(ENUM, STRUCT, NAME) NAME, +#define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) NAME, +#include "ofp-util.def" + }; + + const char **p; + + for (p = names; p < &names[ARRAY_SIZE(names)]; p++) { + if (*p && !strcasecmp(name, *p)) { + return p - names; + } + } + return -1; +} + +/* Appends an action of the type specified by 'code' to 'buf' and returns the + * action. Initializes the parts of 'action' that identify it as having type + * and length 'sizeof *action' and zeros the rest. For actions that + * have variable length, the length used and cleared is that of struct + * . */ +void * +ofputil_put_action(enum ofputil_action_code code, struct ofpbuf *buf) +{ + switch (code) { +#define OFPAT_ACTION(ENUM, STRUCT, NAME) \ + case OFPUTIL_##ENUM: return ofputil_put_##ENUM(buf); +#define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) \ + case OFPUTIL_##ENUM: return ofputil_put_##ENUM(buf); +#include "ofp-util.def" + } + NOT_REACHED(); +} + +#define OFPAT_ACTION(ENUM, STRUCT, NAME) \ + void \ + ofputil_init_##ENUM(struct STRUCT *s) \ + { \ + memset(s, 0, sizeof *s); \ + s->type = htons(ENUM); \ + s->len = htons(sizeof *s); \ + } \ + \ + struct STRUCT * \ + ofputil_put_##ENUM(struct ofpbuf *buf) \ + { \ + struct STRUCT *s = ofpbuf_put_uninit(buf, sizeof *s); \ + ofputil_init_##ENUM(s); \ + return s; \ + } +#define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) \ + void \ + ofputil_init_##ENUM(struct STRUCT *s) \ + { \ + memset(s, 0, sizeof *s); \ + s->type = htons(OFPAT_VENDOR); \ + s->len = htons(sizeof *s); \ + s->vendor = htonl(NX_VENDOR_ID); \ + s->subtype = htons(ENUM); \ + } \ + \ + struct STRUCT * \ + ofputil_put_##ENUM(struct ofpbuf *buf) \ + { \ + struct STRUCT *s = ofpbuf_put_uninit(buf, sizeof *s); \ + ofputil_init_##ENUM(s); \ + return s; \ + } +#include "ofp-util.def" + /* Returns true if 'action' outputs to 'port', false otherwise. */ bool action_outputs_to_port(const union ofp_action *action, ovs_be16 port) @@ -2684,3 +2737,72 @@ ofputil_actions_clone(const union ofp_action *actions, size_t n) { return n ? xmemdup(actions, n * sizeof *actions) : NULL; } + +/* Parses a key or a key-value pair from '*stringp'. + * + * On success: Stores the key into '*keyp'. Stores the value, if present, into + * '*valuep', otherwise an empty string. Advances '*stringp' past the end of + * the key-value pair, preparing it for another call. '*keyp' and '*valuep' + * are substrings of '*stringp' created by replacing some of its bytes by null + * terminators. Returns true. + * + * If '*stringp' is just white space or commas, sets '*keyp' and '*valuep' to + * NULL and returns false. */ +bool +ofputil_parse_key_value(char **stringp, char **keyp, char **valuep) +{ + char *pos, *key, *value; + size_t key_len; + + pos = *stringp; + pos += strspn(pos, ", \t\r\n"); + if (*pos == '\0') { + *keyp = *valuep = NULL; + return false; + } + + key = pos; + key_len = strcspn(pos, ":=(, \t\r\n"); + if (key[key_len] == ':' || key[key_len] == '=') { + /* The value can be separated by a colon. */ + size_t value_len; + + value = key + key_len + 1; + value_len = strcspn(value, ", \t\r\n"); + pos = value + value_len + (value[value_len] != '\0'); + value[value_len] = '\0'; + } else if (key[key_len] == '(') { + /* The value can be surrounded by balanced parentheses. The outermost + * set of parentheses is removed. */ + int level = 1; + size_t value_len; + + value = key + key_len + 1; + for (value_len = 0; level > 0; value_len++) { + switch (value[value_len]) { + case '\0': + ovs_fatal(0, "unbalanced parentheses in argument to %s", key); + + case '(': + level++; + break; + + case ')': + level--; + break; + } + } + value[value_len - 1] = '\0'; + pos = value + value_len; + } else { + /* There might be no value at all. */ + value = key + key_len; /* Will become the empty string below. */ + pos = key + key_len + (key[key_len] != '\0'); + } + key[key_len] = '\0'; + + *stringp = pos; + *keyp = key; + *valuep = value; + return true; +}