/*
- * Copyright (c) 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc.
+ * Copyright (c) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include "classifier.h"
#include "colors.h"
-#include "dynamic-string.h"
-#include "hmap.h"
-#include "meta-flow.h"
-#include "ofp-actions.h"
-#include "ofp-errors.h"
-#include "ofp-util.h"
-#include "ofpbuf.h"
+#include "openvswitch/hmap.h"
#include "openflow/nicira-ext.h"
+#include "openvswitch/dynamic-string.h"
+#include "openvswitch/meta-flow.h"
+#include "openvswitch/ofp-actions.h"
+#include "openvswitch/ofp-errors.h"
+#include "openvswitch/ofp-util.h"
+#include "openvswitch/ofpbuf.h"
+#include "openvswitch/vlog.h"
#include "packets.h"
-#include "shash.h"
+#include "openvswitch/shash.h"
#include "tun-metadata.h"
#include "unaligned.h"
#include "util.h"
-#include "openvswitch/vlog.h"
VLOG_DEFINE_THIS_MODULE(nx_match);
return is_experimenter_oxm(oxm) ? 0 : oxm >> 32;
}
+/* Returns the 32-bit OXM or NXM header to use for field 'mff'. If 'mff' is
+ * a mapped variable length mf_field, update the header with the configured
+ * length of 'mff'. Returns 0 if 'mff' cannot be expressed with a 32-bit NXM
+ * or OXM header.*/
+uint32_t
+nxm_header_from_mff(const struct mf_field *mff)
+{
+ uint64_t oxm = mf_oxm_header(mff->id, 0);
+
+ if (mff->mapped) {
+ oxm = nxm_no_len(oxm) | ((uint64_t) mff->n_bytes << 32);
+ }
+
+ return is_experimenter_oxm(oxm) ? 0 : oxm >> 32;
+}
+
static const struct mf_field *
-mf_from_oxm_header(uint64_t header)
+mf_from_oxm_header(uint64_t header, const struct vl_mff_map *vl_mff_map)
{
const struct nxm_field *f = nxm_field_by_header(header);
- return f ? mf_from_id(f->id) : NULL;
+
+ if (f) {
+ const struct mf_field *mff = mf_from_id(f->id);
+ const struct mf_field *vl_mff = mf_get_vl_mff(mff, vl_mff_map);
+ return vl_mff ? vl_mff : mff;
+ } else {
+ return NULL;
+ }
}
/* Returns the "struct mf_field" that corresponds to NXM or OXM header
* 'header', or NULL if 'header' doesn't correspond to any known field. */
const struct mf_field *
-mf_from_nxm_header(uint32_t header)
+mf_from_nxm_header(uint32_t header, const struct vl_mff_map *vl_mff_map)
{
- return mf_from_oxm_header((uint64_t) header << 32);
+ return mf_from_oxm_header((uint64_t) header << 32, vl_mff_map);
}
/* Returns the width of the data for a field with the given 'header', in
}
static enum ofperr
-nx_pull_header__(struct ofpbuf *b, bool allow_cookie, uint64_t *header,
+nx_pull_header__(struct ofpbuf *b, bool allow_cookie,
+ const struct vl_mff_map *vl_mff_map, uint64_t *header,
const struct mf_field **field)
{
if (b->size < 4) {
ofpbuf_pull(b, nxm_header_len(*header));
if (field) {
- *field = mf_from_oxm_header(*header);
+ *field = mf_from_oxm_header(*header, vl_mff_map);
if (!*field && !(allow_cookie && is_cookie_pseudoheader(*header))) {
VLOG_DBG_RL(&rl, "OXM header "NXM_HEADER_FMT" is unknown",
NXM_HEADER_ARGS(*header));
return OFPERR_OFPBMC_BAD_FIELD;
+ } else if (mf_vl_mff_invalid(*field, vl_mff_map)) {
+ return OFPERR_NXFMFC_INVALID_TLV_FIELD;
}
}
}
static enum ofperr
-nx_pull_entry__(struct ofpbuf *b, bool allow_cookie, uint64_t *header,
+nx_pull_entry__(struct ofpbuf *b, bool allow_cookie,
+ const struct vl_mff_map *vl_mff_map, uint64_t *header,
const struct mf_field **field_,
union mf_value *value, union mf_value *mask)
{
const uint8_t *payload;
int width;
- header_error = nx_pull_header__(b, allow_cookie, header, &field);
+ header_error = nx_pull_header__(b, allow_cookie, vl_mff_map, header,
+ &field);
if (header_error && header_error != OFPERR_OFPBMC_BAD_FIELD) {
return header_error;
}
* errors (with OFPERR_OFPBMC_BAD_MASK).
*/
enum ofperr
-nx_pull_entry(struct ofpbuf *b, const struct mf_field **field,
- union mf_value *value, union mf_value *mask)
+nx_pull_entry(struct ofpbuf *b, const struct vl_mff_map *vl_mff_map,
+ const struct mf_field **field, union mf_value *value,
+ union mf_value *mask)
{
uint64_t header;
- return nx_pull_entry__(b, false, &header, field, value, mask);
+ return nx_pull_entry__(b, false, vl_mff_map, &header, field, value, mask);
}
/* Attempts to pull an NXM or OXM header from the beginning of 'b'. If
* errors (with OFPERR_OFPBMC_BAD_MASK).
*/
enum ofperr
-nx_pull_header(struct ofpbuf *b, const struct mf_field **field, bool *masked)
+nx_pull_header(struct ofpbuf *b, const struct vl_mff_map *vl_mff_map,
+ const struct mf_field **field, bool *masked)
{
enum ofperr error;
uint64_t header;
- error = nx_pull_header__(b, false, &header, field);
+ error = nx_pull_header__(b, false, vl_mff_map, &header, field);
if (masked) {
*masked = !error && nxm_hasmask(header);
} else if (!error && nxm_hasmask(header)) {
enum ofperr error;
uint64_t header;
- error = nx_pull_entry__(b, allow_cookie, &header, field, value, mask);
+ error = nx_pull_entry__(b, allow_cookie, NULL, &header, field, value,
+ mask);
if (error) {
return error;
}
static enum ofperr
nx_pull_raw(const uint8_t *p, unsigned int match_len, bool strict,
- struct match *match, ovs_be64 *cookie, ovs_be64 *cookie_mask)
+ struct match *match, ovs_be64 *cookie, ovs_be64 *cookie_mask,
+ const struct tun_table *tun_table)
{
ovs_assert((cookie != NULL) == (cookie_mask != NULL));
match_init_catchall(match);
+ match->flow.tunnel.metadata.tab = tun_table;
if (cookie) {
*cookie = *cookie_mask = htonll(0);
}
*cookie = value.be64;
*cookie_mask = mask.be64;
}
- } else if (!mf_are_prereqs_ok(field, &match->flow)) {
+ } else if (!mf_are_prereqs_ok(field, &match->flow, NULL)) {
error = OFPERR_OFPBMC_BAD_PREREQ;
} else if (!mf_is_all_wild(field, &match->wc)) {
error = OFPERR_OFPBMC_DUP_FIELD;
}
}
+ match->flow.tunnel.metadata.tab = NULL;
return 0;
}
static enum ofperr
nx_pull_match__(struct ofpbuf *b, unsigned int match_len, bool strict,
struct match *match,
- ovs_be64 *cookie, ovs_be64 *cookie_mask)
+ ovs_be64 *cookie, ovs_be64 *cookie_mask,
+ const struct tun_table *tun_table)
{
uint8_t *p = NULL;
}
}
- return nx_pull_raw(p, match_len, strict, match, cookie, cookie_mask);
+ return nx_pull_raw(p, match_len, strict, match, cookie, cookie_mask,
+ tun_table);
}
/* Parses the nx_match formatted match description in 'b' with length
* Returns 0 if successful, otherwise an OpenFlow error code. */
enum ofperr
nx_pull_match(struct ofpbuf *b, unsigned int match_len, struct match *match,
- ovs_be64 *cookie, ovs_be64 *cookie_mask)
+ ovs_be64 *cookie, ovs_be64 *cookie_mask,
+ const struct tun_table *tun_table)
{
- return nx_pull_match__(b, match_len, true, match, cookie, cookie_mask);
+ return nx_pull_match__(b, match_len, true, match, cookie, cookie_mask,
+ tun_table);
}
/* Behaves the same as nx_pull_match(), but skips over unknown NXM headers,
enum ofperr
nx_pull_match_loose(struct ofpbuf *b, unsigned int match_len,
struct match *match,
- ovs_be64 *cookie, ovs_be64 *cookie_mask)
+ ovs_be64 *cookie, ovs_be64 *cookie_mask,
+ const struct tun_table *tun_table)
{
- return nx_pull_match__(b, match_len, false, match, cookie, cookie_mask);
+ return nx_pull_match__(b, match_len, false, match, cookie, cookie_mask,
+ tun_table);
}
static enum ofperr
-oxm_pull_match__(struct ofpbuf *b, bool strict, struct match *match)
+oxm_pull_match__(struct ofpbuf *b, bool strict,
+ const struct tun_table *tun_table, struct match *match)
{
struct ofp11_match_header *omh = b->data;
uint8_t *p;
}
return nx_pull_raw(p + sizeof *omh, match_len - sizeof *omh,
- strict, match, NULL, NULL);
+ strict, match, NULL, NULL, tun_table);
}
/* Parses the oxm formatted match description preceded by a struct
*
* Returns 0 if successful, otherwise an OpenFlow error code. */
enum ofperr
-oxm_pull_match(struct ofpbuf *b, struct match *match)
+oxm_pull_match(struct ofpbuf *b, const struct tun_table *tun_table,
+ struct match *match)
{
- return oxm_pull_match__(b, true, match);
+ return oxm_pull_match__(b, true, tun_table, match);
}
/* Behaves the same as oxm_pull_match() with one exception. Skips over unknown
* OXM headers instead of failing with an error when they are encountered. */
enum ofperr
-oxm_pull_match_loose(struct ofpbuf *b, struct match *match)
+oxm_pull_match_loose(struct ofpbuf *b, const struct tun_table *tun_table,
+ struct match *match)
{
- return oxm_pull_match__(b, false, match);
+ return oxm_pull_match__(b, false, tun_table, match);
}
/* Parses the OXM match description in the 'oxm_len' bytes in 'oxm'. Stores
*
* Returns 0 if successful, otherwise an OpenFlow error code. */
enum ofperr
-oxm_decode_match(const void *oxm, size_t oxm_len, struct match *match)
+oxm_decode_match(const void *oxm, size_t oxm_len,
+ const struct tun_table *tun_table, struct match *match)
{
- return nx_pull_raw(oxm, oxm_len, true, match, NULL, NULL);
+ return nx_pull_raw(oxm, oxm_len, true, match, NULL, NULL, tun_table);
}
/* Verify an array of OXM TLVs treating value of each TLV as a mask,
enum ofperr error;
uint64_t header;
- error = nx_pull_entry__(&b, false, &header, &field, &value, NULL);
+ error = nx_pull_entry__(&b, false, NULL, &header, &field, &value,
+ NULL);
if (error) {
VLOG_DBG_RL(&rl, "error pulling field array field");
return error;
match->wc.masks.tp_src);
nxm_put_16m(b, MFF_SCTP_DST, oxm, flow->tp_dst,
match->wc.masks.tp_dst);
- } else if (is_icmpv4(flow)) {
+ } else if (is_icmpv4(flow, NULL)) {
if (match->wc.masks.tp_src) {
nxm_put_8(b, MFF_ICMPV4_TYPE, oxm,
ntohs(flow->tp_src));
nxm_put_8(b, MFF_ICMPV4_CODE, oxm,
ntohs(flow->tp_dst));
}
- } else if (is_icmpv6(flow)) {
+ } else if (is_icmpv6(flow, NULL)) {
if (match->wc.masks.tp_src) {
nxm_put_8(b, MFF_ICMPV6_TYPE, oxm,
ntohs(flow->tp_src));
nxm_put_8(b, MFF_ICMPV6_CODE, oxm,
ntohs(flow->tp_dst));
}
- if (flow->tp_src == htons(ND_NEIGHBOR_SOLICIT) ||
- flow->tp_src == htons(ND_NEIGHBOR_ADVERT)) {
+ if (is_nd(flow, NULL)) {
nxm_put_ipv6(b, MFF_ND_TARGET, oxm,
&flow->nd_target, &match->wc.masks.nd_target);
if (flow->tp_src == htons(ND_NEIGHBOR_SOLICIT)) {
int match_len;
int i;
- BUILD_ASSERT_DECL(FLOW_WC_SEQ == 35);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 36);
/* Metadata. */
if (match->wc.masks.dp_hash) {
oxm_format_field_array(struct ds *ds, const struct field_array *fa)
{
size_t start_len = ds->length;
- int i;
+ size_t i, offset = 0;
- for (i = 0; i < MFF_N_IDS; i++) {
- if (bitmap_is_set(fa->used.bm, i)) {
- nx_format_mask_tlv(ds, i, &fa->value[i]);
- }
+ BITMAP_FOR_EACH_1 (i, MFF_N_IDS, fa->used.bm) {
+ const struct mf_field *mf = mf_from_id(i);
+ union mf_value value;
+
+ memcpy(&value, fa->values + offset, mf->n_bytes);
+ nx_format_mask_tlv(ds, i, &value);
+ offset += mf->n_bytes;
}
if (ds->length > start_len) {
enum ofp_version version)
{
size_t start_len = b->size;
- int i;
/* Field arrays are only used with the group selection method
* property and group properties are only available in OpenFlow 1.5+.
*/
ovs_assert(version >= OFP15_VERSION);
- for (i = 0; i < MFF_N_IDS; i++) {
- if (bitmap_is_set(fa->used.bm, i)) {
- int len = mf_field_len(mf_from_id(i), &fa->value[i], NULL, NULL);
- nxm_put__(b, i, version,
- &fa->value[i].u8 + mf_from_id(i)->n_bytes - len, NULL,
- len);
- }
+ size_t i, offset = 0;
+
+ BITMAP_FOR_EACH_1 (i, MFF_N_IDS, fa->used.bm) {
+ const struct mf_field *mf = mf_from_id(i);
+ union mf_value value;
+
+ memcpy(&value, fa->values + offset, mf->n_bytes);
+
+ int len = mf_field_len(mf, &value, NULL, NULL);
+ nxm_put__(b, i, version, &value + mf->n_bytes - len, NULL, len);
+ offset += mf->n_bytes;
}
return b->size - start_len;
nx_put_header__(b, mf_oxm_header(field, version), masked);
}
+void nx_put_mff_header(struct ofpbuf *b, const struct mf_field *mff,
+ enum ofp_version version, bool masked)
+{
+ if (mff->mapped) {
+ nx_put_header_len(b, mff->id, version, masked, mff->n_bytes);
+ } else {
+ nx_put_header(b, mff->id, version, masked);
+ }
+}
+
static void
nx_put_header_len(struct ofpbuf *b, enum mf_field_id field,
enum ofp_version version, bool masked, size_t n_bytes)
}
void
-nx_put_entry(struct ofpbuf *b,
- enum mf_field_id field, enum ofp_version version,
- const union mf_value *value, const union mf_value *mask)
+nx_put_entry(struct ofpbuf *b, const struct mf_field *mff,
+ enum ofp_version version, const union mf_value *value,
+ const union mf_value *mask)
{
- const struct mf_field *mf = mf_from_id(field);
bool masked;
int len, offset;
- len = mf_field_len(mf, value, mask, &masked);
- offset = mf->n_bytes - len;
+ len = mf_field_len(mff, value, mask, &masked);
+ offset = mff->n_bytes - len;
- nx_put_header_len(b, field, version, masked, len);
+ nx_put_header_len(b, mff->id, version, masked, len);
ofpbuf_put(b, &value->u8 + offset, len);
if (masked) {
ofpbuf_put(b, &mask->u8 + offset, len);
uint64_t header;
int value_len;
- error = nx_pull_entry__(&b, true, &header, NULL, &value, &mask);
+ error = nx_pull_entry__(&b, true, NULL, &header, NULL, &value, &mask);
if (error) {
break;
}
const char *name;
uint64_t header;
ovs_be64 nw_header;
- ovs_be64 *header_ptr;
int name_len;
size_t n;
s += name_len + 1;
- header_ptr = ofpbuf_put_uninit(b, nxm_header_len(header));
+ b->header = ofpbuf_put_uninit(b, nxm_header_len(header));
s = ofpbuf_put_hex(b, s, &n);
if (n != nxm_field_bytes(header)) {
- const struct mf_field *field = mf_from_oxm_header(header);
+ const struct mf_field *field = mf_from_oxm_header(header, NULL);
if (field && field->variable_len) {
if (n <= field->n_bytes) {
}
}
nw_header = htonll(header);
- memcpy(header_ptr, &nw_header, nxm_header_len(header));
+ memcpy(b->header, &nw_header, nxm_header_len(header));
if (nxm_hasmask(header)) {
s += strspn(s, " ");
\f
/* nxm_execute_reg_move(). */
-void
-nxm_execute_reg_move(const struct ofpact_reg_move *move,
- struct flow *flow, struct flow_wildcards *wc)
-{
- union mf_value src_value;
- union mf_value dst_value;
-
- mf_mask_field_and_prereqs(move->dst.field, wc);
- mf_mask_field_and_prereqs(move->src.field, wc);
-
- /* 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
nxm_reg_load(const struct mf_subfield *dst, uint64_t src_data,
struct flow *flow, struct flow_wildcards *wc)
return mf_check_dst(&pop->subfield, flow);
}
-/* nxm_execute_stack_push(), nxm_execute_stack_pop(). */
-static void
-nx_stack_push(struct ofpbuf *stack, union mf_subvalue *v)
+/* nxm_execute_stack_push(), nxm_execute_stack_pop().
+ *
+ * A stack is an ofpbuf with 'data' pointing to the bottom of the stack and
+ * 'size' indexing the top of the stack. Each value of some byte length is
+ * stored to the stack immediately followed by the length of the value as an
+ * unsigned byte. This way a POP operation can first read the length byte, and
+ * then the appropriate number of bytes from the stack. This also means that
+ * it is only possible to traverse the stack from top to bottom. It is
+ * possible, however, to push values also to the bottom of the stack, which is
+ * useful when a stack has been serialized to a wire format in reverse order
+ * (topmost value first).
+ */
+
+/* Push value 'v' of length 'bytes' to the top of 'stack'. */
+void
+nx_stack_push(struct ofpbuf *stack, const void *v, uint8_t bytes)
{
- ofpbuf_put(stack, v, sizeof *v);
+ ofpbuf_put(stack, v, bytes);
+ ofpbuf_put(stack, &bytes, sizeof bytes);
}
-static union mf_subvalue *
-nx_stack_pop(struct ofpbuf *stack)
+/* Push value 'v' of length 'bytes' to the bottom of 'stack'. */
+void
+nx_stack_push_bottom(struct ofpbuf *stack, const void *v, uint8_t bytes)
{
- union mf_subvalue *v = NULL;
-
- if (stack->size) {
+ ofpbuf_push(stack, &bytes, sizeof bytes);
+ ofpbuf_push(stack, v, bytes);
+}
- stack->size -= sizeof *v;
- v = (union mf_subvalue *) ofpbuf_tail(stack);
+/* Pop the topmost value from 'stack', returning a pointer to the value in the
+ * stack and the length of the value in '*bytes'. In case of underflow a NULL
+ * is returned and length is returned as zero via '*bytes'. */
+void *
+nx_stack_pop(struct ofpbuf *stack, uint8_t *bytes)
+{
+ if (!stack->size) {
+ *bytes = 0;
+ return NULL;
}
- return v;
+ stack->size -= sizeof *bytes;
+ memcpy(bytes, ofpbuf_tail(stack), sizeof *bytes);
+
+ ovs_assert(stack->size >= *bytes);
+ stack->size -= *bytes;
+ return ofpbuf_tail(stack);
}
void
const struct flow *flow, struct flow_wildcards *wc,
struct ofpbuf *stack)
{
- union mf_subvalue mask_value;
union mf_subvalue dst_value;
- memset(&mask_value, 0xff, sizeof mask_value);
- mf_write_subfield_flow(&push->subfield, &mask_value, &wc->masks);
+ mf_write_subfield_flow(&push->subfield,
+ (union mf_subvalue *)&exact_match_mask,
+ &wc->masks);
mf_read_subfield(&push->subfield, flow, &dst_value);
- nx_stack_push(stack, &dst_value);
+ uint8_t bytes = DIV_ROUND_UP(push->subfield.n_bits, 8);
+ nx_stack_push(stack, &dst_value.u8[sizeof dst_value - bytes], bytes);
}
-void
+bool
nxm_execute_stack_pop(const struct ofpact_stack *pop,
struct flow *flow, struct flow_wildcards *wc,
struct ofpbuf *stack)
{
- union mf_subvalue *src_value;
-
- src_value = nx_stack_pop(stack);
-
- /* Only pop if stack is not empty. Otherwise, give warning. */
- if (src_value) {
- union mf_subvalue mask_value;
+ uint8_t src_bytes;
+ const void *src = nx_stack_pop(stack, &src_bytes);
+ if (src) {
+ union mf_subvalue src_value;
+ uint8_t dst_bytes = DIV_ROUND_UP(pop->subfield.n_bits, 8);
- memset(&mask_value, 0xff, sizeof mask_value);
- mf_write_subfield_flow(&pop->subfield, &mask_value, &wc->masks);
- mf_write_subfield_flow(&pop->subfield, src_value, flow);
- } else {
- if (!VLOG_DROP_WARN(&rl)) {
- char *flow_str = flow_to_string(flow);
- VLOG_WARN_RL(&rl, "Failed to pop from an empty stack. On flow\n"
- " %s", flow_str);
- free(flow_str);
+ if (src_bytes < dst_bytes) {
+ memset(&src_value.u8[sizeof src_value - dst_bytes], 0,
+ dst_bytes - src_bytes);
}
+ memcpy(&src_value.u8[sizeof src_value - src_bytes], src, src_bytes);
+ mf_write_subfield_flow(&pop->subfield,
+ (union mf_subvalue *)&exact_match_mask,
+ &wc->masks);
+ mf_write_subfield_flow(&pop->subfield, &src_value, flow);
+ return true;
+ } else {
+ /* Attempted to pop from an empty stack. */
+ return false;
}
}
\f
char * OVS_WARN_UNUSED_RESULT
mf_parse_subfield__(struct mf_subfield *sf, const char **sp)
{
- const struct mf_field *field;
+ const struct mf_field *field = NULL;
const struct nxm_field *f;
const char *name;
int start, end;
s = *sp;
name = s;
- name_len = strcspn(s, "[");
- if (s[name_len] != '[') {
- return xasprintf("%s: missing [ looking for field name", *sp);
- }
+ name_len = strcspn(s, "[-");
f = mf_parse_subfield_name(name, name_len, &wild);
- if (!f) {
+ field = f ? mf_from_id(f->id) : mf_from_name_len(name, name_len);
+ if (!field) {
return xasprintf("%s: unknown field `%.*s'", *sp, name_len, s);
}
- field = mf_from_id(f->id);
s += name_len;
- if (ovs_scan(s, "[%d..%d]", &start, &end)) {
- /* Nothing to do. */
- } else if (ovs_scan(s, "[%d]", &start)) {
- end = start;
- } else if (!strncmp(s, "[]", 2)) {
- start = 0;
- end = field->n_bits - 1;
- } else {
- return xasprintf("%s: syntax error expecting [] or [<bit>] or "
- "[<start>..<end>]", *sp);
+ /* Assume full field. */
+ start = 0;
+ end = field->n_bits - 1;
+ if (*s == '[') {
+ if (!strncmp(s, "[]", 2)) {
+ /* Nothing to do. */
+ } else if (ovs_scan(s, "[%d..%d]", &start, &end)) {
+ /* Nothing to do. */
+ } else if (ovs_scan(s, "[%d]", &start)) {
+ end = start;
+ } else {
+ return xasprintf("%s: syntax error expecting [] or [<bit>] or "
+ "[<start>..<end>]", *sp);
+ }
+ s = strchr(s, ']') + 1;
}
- s = strchr(s, ']') + 1;
if (start > end) {
return xasprintf("%s: starting bit %d is after ending bit %d",
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]);
+ ovs_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++) {
hash_uint64(nxm_no_len(nfi->nf.header)));
hmap_insert(&nxm_name_map, &nfi->name_node,
hash_string(nfi->nf.name, 0));
- list_push_back(&nxm_mf_map[nfi->nf.id], &nfi->mf_node);
+ ovs_list_push_back(&nxm_mf_map[nfi->nf.id], &nfi->mf_node);
}
ovsthread_once_done(&once);
}