#include "shash.h"
#include "unaligned.h"
#include "util.h"
-#include "vlog.h"
+#include "openvswitch/vlog.h"
VLOG_DEFINE_THIS_MODULE(nx_match);
return 4 + nxm_experimenter_len(header);
}
-/* Returns true if 'header' is a legacy NXM header, false if it is an OXM
- * header.*/
-static bool
-is_nxm_header(uint64_t header)
-{
- return nxm_class(header) <= 1;
-}
-
#define NXM_HEADER(VENDOR, CLASS, FIELD, HASMASK, LENGTH) \
(((uint64_t) (CLASS) << 48) | \
((uint64_t) (FIELD) << 41) | \
static const struct nxm_field *nxm_field_by_header(uint64_t header);
static const struct nxm_field *nxm_field_by_name(const char *name, size_t len);
-static const struct nxm_field *nxm_field_by_mf_id(enum mf_field_id);
-static const struct nxm_field *oxm_field_by_mf_id(enum mf_field_id);
+static const struct nxm_field *nxm_field_by_mf_id(enum mf_field_id,
+ enum ofp_version);
static void nx_put_header__(struct ofpbuf *, uint64_t header, bool masked);
static const struct nxm_field *
mf_parse_subfield_name(const char *name, int name_len, bool *wild);
-static const struct nxm_field *
-nxm_field_from_mf_field(enum mf_field_id id, enum ofp_version version)
-{
- const struct nxm_field *oxm = oxm_field_by_mf_id(id);
- const struct nxm_field *nxm = nxm_field_by_mf_id(id);
- return oxm && (version >= oxm->version || !nxm) ? oxm : nxm;
-}
-
/* Returns the preferred OXM header to use for field 'id' in OpenFlow version
* 'version'. Specify 0 for 'version' if an NXM legacy header should be
* preferred over any standardized OXM header. Returns 0 if field 'id' cannot
static uint64_t
mf_oxm_header(enum mf_field_id id, enum ofp_version version)
{
- const struct nxm_field *f = nxm_field_from_mf_field(id, version);
+ const struct nxm_field *f = nxm_field_by_mf_id(id, version);
return f ? f->header : 0;
}
unsigned int length = nxm_payload_len(header);
return nxm_hasmask(header) ? length / 2 : length;
}
-
-/* Returns the earliest version of OpenFlow that standardized an OXM header for
- * field 'id', or UINT8_MAX if no version of OpenFlow does. */
-static enum ofp_version
-mf_oxm_version(enum mf_field_id id)
-{
- const struct nxm_field *oxm = oxm_field_by_mf_id(id);
- return oxm ? oxm->version : UINT8_MAX;
-}
- \f
+\f
/* nx_pull_match() and helpers. */
/* Given NXM/OXM value 'value' and mask 'mask' associated with 'header', checks
int match_len;
int i;
- BUILD_ASSERT_DECL(FLOW_WC_SEQ == 27);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 29);
/* Metadata. */
if (match->wc.masks.dp_hash) {
htons(ofp_to_u16(in_port)));
}
}
+ if (match->wc.masks.actset_output) {
+ nxm_put_32(b, MFF_ACTSET_OUTPUT, oxm,
+ ofputil_port_to_ofp11(flow->actset_output));
+ }
/* Ethernet. */
nxm_put_eth_masked(b, MFF_ETH_SRC, oxm,
*
* Returns NULL if successful, otherwise a malloc()'d string describing the
* error. The caller is responsible for freeing the returned string. */
-char * WARN_UNUSED_RESULT
+char * OVS_WARN_UNUSED_RESULT
nxm_parse_reg_move(struct ofpact_reg_move *move, const char *s)
{
const char *full_s = s;
return error;
}
- return mf_check_dst(&move->dst, NULL);
+ return mf_check_dst(&move->dst, flow);
}
\f
/* nxm_execute_reg_move(). */
mf_mask_field_and_prereqs(move->dst.field, &wc->masks);
mf_mask_field_and_prereqs(move->src.field, &wc->masks);
- mf_get_value(move->dst.field, flow, &dst_value);
- mf_get_value(move->src.field, flow, &src_value);
- bitwise_copy(&src_value, move->src.field->n_bytes, move->src.ofs,
- &dst_value, move->dst.field->n_bytes, move->dst.ofs,
- move->src.n_bits);
- mf_set_flow_value(move->dst.field, &dst_value, flow);
+ /* A flow may wildcard nw_frag. Do nothing if setting a transport
+ * header field on a packet that does not have them. */
+ if (mf_are_prereqs_ok(move->dst.field, flow)
+ && mf_are_prereqs_ok(move->src.field, flow)) {
+
+ mf_get_value(move->dst.field, flow, &dst_value);
+ mf_get_value(move->src.field, flow, &src_value);
+ bitwise_copy(&src_value, move->src.field->n_bytes, move->src.ofs,
+ &dst_value, move->dst.field->n_bytes, move->dst.ofs,
+ move->src.n_bits);
+ mf_set_flow_value(move->dst.field, &dst_value, flow);
+ }
}
void
*
* Returns NULL if successful, otherwise a malloc()'d string describing the
* error. The caller is responsible for freeing the returned string. */
-char * WARN_UNUSED_RESULT
+char * OVS_WARN_UNUSED_RESULT
nxm_parse_stack_action(struct ofpact_stack *stack_action, const char *s)
{
char *error;
if (!sf->field) {
ds_put_cstr(s, "<unknown>");
} else {
- const struct nxm_field *f = nxm_field_from_mf_field(sf->field->id, 0);
+ const struct nxm_field *f = nxm_field_by_mf_id(sf->field->id, 0);
ds_put_cstr(s, f ? f->name : sf->field->name);
}
* bit indexes. "..end" may be omitted to indicate a single bit. "start..end"
* may both be omitted (the [] are still required) to indicate an entire
* field. */
-char * WARN_UNUSED_RESULT
+char * OVS_WARN_UNUSED_RESULT
mf_parse_subfield__(struct mf_subfield *sf, const char **sp)
{
const struct mf_field *field;
* bit indexes. "..end" may be omitted to indicate a single bit. "start..end"
* may both be omitted (the [] are still required) to indicate an entire
* field. */
-char * WARN_UNUSED_RESULT
+char * OVS_WARN_UNUSED_RESULT
mf_parse_subfield(struct mf_subfield *sf, const char *s)
{
char *error = mf_parse_subfield__(sf, &s);
struct mf_bitmap fields = MF_BITMAP_INITIALIZER;
for (enum mf_field_id id = 0; id < MFF_N_IDS; id++) {
- if (version >= mf_oxm_version(id)) {
- uint64_t oxm = mf_oxm_header(id, version);
+ uint64_t oxm = mf_oxm_header(id, version);
+ if (oxm && version >= nxm_field_by_header(oxm)->version) {
uint32_t class = nxm_class(oxm);
int field = nxm_field(oxm);
}
\f
struct nxm_field_index {
- struct hmap_node header_node;
- struct hmap_node name_node;
- struct nxm_field nf;
+ struct hmap_node header_node; /* In nxm_header_map. */
+ struct hmap_node name_node; /* In nxm_name_map. */
+ struct ovs_list mf_node; /* In mf_mf_map[nf.id]. */
+ const struct nxm_field nf;
};
#include "nx-match.inc"
static struct hmap nxm_header_map;
static struct hmap nxm_name_map;
-static struct nxm_field *nxm_fields[MFF_N_IDS];
-static struct nxm_field *oxm_fields[MFF_N_IDS];
+static struct ovs_list nxm_mf_map[MFF_N_IDS];
static void
nxm_init(void)
if (ovsthread_once_start(&once)) {
hmap_init(&nxm_header_map);
hmap_init(&nxm_name_map);
+ for (int i = 0; i < MFF_N_IDS; i++) {
+ list_init(&nxm_mf_map[i]);
+ }
for (struct nxm_field_index *nfi = all_nxm_fields;
nfi < &all_nxm_fields[ARRAY_SIZE(all_nxm_fields)]; nfi++) {
hmap_insert(&nxm_header_map, &nfi->header_node,
hash_int(nfi->nf.header, 0));
hmap_insert(&nxm_name_map, &nfi->name_node,
hash_string(nfi->nf.name, 0));
- if (is_nxm_header(nfi->nf.header)) {
- nxm_fields[nfi->nf.id] = &nfi->nf;
- } else {
- oxm_fields[nfi->nf.id] = &nfi->nf;
- }
+ list_push_back(&nxm_mf_map[nfi->nf.id], &nfi->mf_node);
}
ovsthread_once_done(&once);
}
}
static const struct nxm_field *
-nxm_field_by_mf_id(enum mf_field_id id)
+nxm_field_by_mf_id(enum mf_field_id id, enum ofp_version version)
{
- nxm_init();
- return nxm_fields[id];
-}
+ const struct nxm_field_index *nfi;
+ const struct nxm_field *f;
-static const struct nxm_field *
-oxm_field_by_mf_id(enum mf_field_id id)
-{
nxm_init();
- return oxm_fields[id];
-}
+ f = NULL;
+ LIST_FOR_EACH (nfi, mf_node, &nxm_mf_map[id]) {
+ if (!f || version >= nfi->nf.version) {
+ f = &nfi->nf;
+ }
+ }
+ return f;
+}