mirror of
https://github.com/openvswitch/ovs
synced 2025-09-01 06:45:17 +00:00
ofp-actions: Waste less memory in learn actions.
Make the immediate data member 'src_imm' of a learn spec allocated at the end of the action for just the right size. This, together with some structure packing saves on average of ~128 bytes for each learn spec in each learn action. Typical learn actions have about 4 specs each, so this amounts to saving about 0.5kb for each learn action. Signed-off-by: Jarno Rajahalme <jarno@ovn.org> Acked-by: Ben Pfaff <blp@ovn.org>
This commit is contained in:
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <string.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <netinet/ip6.h>
|
#include <netinet/ip6.h>
|
||||||
@@ -2044,6 +2045,16 @@ int mf_subvalue_width(const union mf_subvalue *);
|
|||||||
void mf_subvalue_shift(union mf_subvalue *, int n);
|
void mf_subvalue_shift(union mf_subvalue *, int n);
|
||||||
void mf_subvalue_format(const union mf_subvalue *, struct ds *);
|
void mf_subvalue_format(const union mf_subvalue *, struct ds *);
|
||||||
|
|
||||||
|
static inline void mf_subvalue_from_value(const struct mf_subfield *sf,
|
||||||
|
union mf_subvalue *sv,
|
||||||
|
const void *value)
|
||||||
|
{
|
||||||
|
unsigned int n_bytes = DIV_ROUND_UP(sf->n_bits, 8);
|
||||||
|
memset(sv, 0, sizeof *sv - n_bytes);
|
||||||
|
memcpy(&sv->u8[sizeof sv->u8 - n_bytes], value, n_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Set of field values. 'values' only includes the actual data bytes for each
|
/* Set of field values. 'values' only includes the actual data bytes for each
|
||||||
* field for which is used, as marked by 1-bits in 'used'. */
|
* field for which is used, as marked by 1-bits in 'used'. */
|
||||||
struct field_array {
|
struct field_array {
|
||||||
@@ -2115,6 +2126,9 @@ void mf_write_subfield_flow(const struct mf_subfield *,
|
|||||||
const union mf_subvalue *, struct flow *);
|
const union mf_subvalue *, struct flow *);
|
||||||
void mf_write_subfield(const struct mf_subfield *, const union mf_subvalue *,
|
void mf_write_subfield(const struct mf_subfield *, const union mf_subvalue *,
|
||||||
struct match *);
|
struct match *);
|
||||||
|
void mf_write_subfield_value(const struct mf_subfield *, const void *src,
|
||||||
|
struct match *);
|
||||||
|
|
||||||
void mf_mask_subfield(const struct mf_field *,
|
void mf_mask_subfield(const struct mf_field *,
|
||||||
const union mf_subvalue *value,
|
const union mf_subvalue *value,
|
||||||
const union mf_subvalue *mask,
|
const union mf_subvalue *mask,
|
||||||
|
@@ -651,19 +651,6 @@ struct ofpact_resubmit {
|
|||||||
uint8_t table_id;
|
uint8_t table_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Part of struct ofpact_learn, below. */
|
|
||||||
struct ofpact_learn_spec {
|
|
||||||
int n_bits; /* Number of bits in source and dest. */
|
|
||||||
|
|
||||||
int src_type; /* One of NX_LEARN_SRC_*. */
|
|
||||||
struct mf_subfield src; /* NX_LEARN_SRC_FIELD only. */
|
|
||||||
union mf_subvalue src_imm; /* NX_LEARN_SRC_IMMEDIATE only. */
|
|
||||||
|
|
||||||
int dst_type; /* One of NX_LEARN_DST_*. */
|
|
||||||
struct mf_subfield dst; /* NX_LEARN_DST_MATCH, NX_LEARN_DST_LOAD only. */
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/* Bits for 'flags' in struct nx_action_learn.
|
/* Bits for 'flags' in struct nx_action_learn.
|
||||||
*
|
*
|
||||||
* If NX_LEARN_F_SEND_FLOW_REM is set, then the learned flows will have their
|
* If NX_LEARN_F_SEND_FLOW_REM is set, then the learned flows will have their
|
||||||
@@ -708,6 +695,33 @@ enum nx_learn_flags {
|
|||||||
#define NX_LEARN_DST_RESERVED (3 << 11) /* Not yet defined. */
|
#define NX_LEARN_DST_RESERVED (3 << 11) /* Not yet defined. */
|
||||||
#define NX_LEARN_DST_MASK (3 << 11)
|
#define NX_LEARN_DST_MASK (3 << 11)
|
||||||
|
|
||||||
|
/* Part of struct ofpact_learn, below. */
|
||||||
|
struct ofpact_learn_spec {
|
||||||
|
struct mf_subfield src; /* NX_LEARN_SRC_FIELD only. */
|
||||||
|
struct mf_subfield dst; /* NX_LEARN_DST_MATCH, NX_LEARN_DST_LOAD only. */
|
||||||
|
uint16_t src_type; /* One of NX_LEARN_SRC_*. */
|
||||||
|
uint16_t dst_type; /* One of NX_LEARN_DST_*. */
|
||||||
|
uint8_t n_bits; /* Number of bits in source and dest. */
|
||||||
|
uint64_t src_imm[]; /* OFPACT_ALIGNTO (uint64_t) aligned. */
|
||||||
|
};
|
||||||
|
BUILD_ASSERT_DECL(offsetof(struct ofpact_learn_spec, src_imm)
|
||||||
|
% OFPACT_ALIGNTO == 0);
|
||||||
|
BUILD_ASSERT_DECL(offsetof(struct ofpact_learn_spec, src_imm)
|
||||||
|
== sizeof(struct ofpact_learn_spec));
|
||||||
|
|
||||||
|
static inline const struct ofpact_learn_spec *
|
||||||
|
ofpact_learn_spec_next(const struct ofpact_learn_spec *spec)
|
||||||
|
{
|
||||||
|
if (spec->src_type == NX_LEARN_SRC_IMMEDIATE) {
|
||||||
|
unsigned int n_uint64s
|
||||||
|
= OFPACT_ALIGN(DIV_ROUND_UP(spec->n_bits, 8)) / sizeof (uint64_t);
|
||||||
|
return (const struct ofpact_learn_spec *)
|
||||||
|
((const uint64_t *)(spec + 1) + n_uint64s);
|
||||||
|
} else {
|
||||||
|
return spec + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* OFPACT_LEARN.
|
/* OFPACT_LEARN.
|
||||||
*
|
*
|
||||||
* Used for NXAST_LEARN. */
|
* Used for NXAST_LEARN. */
|
||||||
@@ -718,8 +732,8 @@ struct ofpact_learn {
|
|||||||
uint16_t hard_timeout; /* Max time before discarding (seconds). */
|
uint16_t hard_timeout; /* Max time before discarding (seconds). */
|
||||||
uint16_t priority; /* Priority level of flow entry. */
|
uint16_t priority; /* Priority level of flow entry. */
|
||||||
uint8_t table_id; /* Table to insert flow entry. */
|
uint8_t table_id; /* Table to insert flow entry. */
|
||||||
ovs_be64 cookie; /* Cookie for new flow. */
|
|
||||||
enum nx_learn_flags flags; /* NX_LEARN_F_*. */
|
enum nx_learn_flags flags; /* NX_LEARN_F_*. */
|
||||||
|
ovs_be64 cookie; /* Cookie for new flow. */
|
||||||
uint16_t fin_idle_timeout; /* Idle timeout after FIN, if nonzero. */
|
uint16_t fin_idle_timeout; /* Idle timeout after FIN, if nonzero. */
|
||||||
uint16_t fin_hard_timeout; /* Hard timeout after FIN, if nonzero. */
|
uint16_t fin_hard_timeout; /* Hard timeout after FIN, if nonzero. */
|
||||||
|
|
||||||
|
72
lib/learn.c
72
lib/learn.c
@@ -41,7 +41,8 @@ learn_check(const struct ofpact_learn *learn, const struct flow *flow)
|
|||||||
struct match match;
|
struct match match;
|
||||||
|
|
||||||
match_init_catchall(&match);
|
match_init_catchall(&match);
|
||||||
for (spec = learn->specs; spec < &learn->specs[learn->n_specs]; spec++) {
|
for (spec = learn->specs; spec < &learn->specs[learn->n_specs];
|
||||||
|
spec = ofpact_learn_spec_next(spec)) {
|
||||||
enum ofperr error;
|
enum ofperr error;
|
||||||
|
|
||||||
/* Check the source. */
|
/* Check the source. */
|
||||||
@@ -59,8 +60,7 @@ learn_check(const struct ofpact_learn *learn, const struct flow *flow)
|
|||||||
if (error) {
|
if (error) {
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
mf_write_subfield_value(&spec->dst, spec->src_imm, &match);
|
||||||
mf_write_subfield(&spec->dst, &spec->src_imm, &match);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NX_LEARN_DST_LOAD:
|
case NX_LEARN_DST_LOAD:
|
||||||
@@ -120,14 +120,15 @@ learn_execute(const struct ofpact_learn *learn, const struct flow *flow,
|
|||||||
oft->fin_hard_timeout = learn->fin_hard_timeout;
|
oft->fin_hard_timeout = learn->fin_hard_timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (spec = learn->specs; spec < &learn->specs[learn->n_specs]; spec++) {
|
for (spec = learn->specs; spec < &learn->specs[learn->n_specs];
|
||||||
|
spec = ofpact_learn_spec_next(spec)) {
|
||||||
struct ofpact_set_field *sf;
|
struct ofpact_set_field *sf;
|
||||||
union mf_subvalue value;
|
union mf_subvalue value;
|
||||||
|
|
||||||
if (spec->src_type == NX_LEARN_SRC_FIELD) {
|
if (spec->src_type == NX_LEARN_SRC_FIELD) {
|
||||||
mf_read_subfield(&spec->src, flow, &value);
|
mf_read_subfield(&spec->src, flow, &value);
|
||||||
} else {
|
} else {
|
||||||
value = spec->src_imm;
|
mf_subvalue_from_value(&spec->dst, &value, spec->src_imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (spec->dst_type) {
|
switch (spec->dst_type) {
|
||||||
@@ -175,7 +176,8 @@ learn_mask(const struct ofpact_learn *learn, struct flow_wildcards *wc)
|
|||||||
union mf_subvalue value;
|
union mf_subvalue value;
|
||||||
|
|
||||||
memset(&value, 0xff, sizeof value);
|
memset(&value, 0xff, sizeof value);
|
||||||
for (spec = learn->specs; spec < &learn->specs[learn->n_specs]; spec++) {
|
for (spec = learn->specs; spec < &learn->specs[learn->n_specs];
|
||||||
|
spec = ofpact_learn_spec_next(spec)) {
|
||||||
if (spec->src_type == NX_LEARN_SRC_FIELD) {
|
if (spec->src_type == NX_LEARN_SRC_FIELD) {
|
||||||
mf_write_subfield_flow(&spec->src, &value, &wc->masks);
|
mf_write_subfield_flow(&spec->src, &value, &wc->masks);
|
||||||
}
|
}
|
||||||
@@ -185,7 +187,8 @@ learn_mask(const struct ofpact_learn *learn, struct flow_wildcards *wc)
|
|||||||
/* Returns NULL if successful, otherwise a malloc()'d string describing the
|
/* Returns NULL if successful, otherwise a malloc()'d string describing the
|
||||||
* error. The caller is responsible for freeing the returned string. */
|
* error. The caller is responsible for freeing the returned string. */
|
||||||
static char * OVS_WARN_UNUSED_RESULT
|
static char * OVS_WARN_UNUSED_RESULT
|
||||||
learn_parse_load_immediate(const char *s, struct ofpact_learn_spec *spec)
|
learn_parse_load_immediate(const char *s, struct ofpact_learn_spec *spec,
|
||||||
|
struct ofpbuf *ofpacts)
|
||||||
{
|
{
|
||||||
const char *full_s = s;
|
const char *full_s = s;
|
||||||
struct mf_subfield dst;
|
struct mf_subfield dst;
|
||||||
@@ -220,9 +223,14 @@ learn_parse_load_immediate(const char *s, struct ofpact_learn_spec *spec)
|
|||||||
|
|
||||||
spec->n_bits = dst.n_bits;
|
spec->n_bits = dst.n_bits;
|
||||||
spec->src_type = NX_LEARN_SRC_IMMEDIATE;
|
spec->src_type = NX_LEARN_SRC_IMMEDIATE;
|
||||||
spec->src_imm = imm;
|
|
||||||
spec->dst_type = NX_LEARN_DST_LOAD;
|
spec->dst_type = NX_LEARN_DST_LOAD;
|
||||||
spec->dst = dst;
|
spec->dst = dst;
|
||||||
|
|
||||||
|
/* Push value last, as this may reallocate 'spec'! */
|
||||||
|
unsigned int n_bytes = DIV_ROUND_UP(dst.n_bits, 8);
|
||||||
|
uint8_t *src_imm = ofpbuf_put_zeros(ofpacts, OFPACT_ALIGN(n_bytes));
|
||||||
|
memcpy(src_imm, &imm.u8[sizeof imm.u8 - n_bytes], n_bytes);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,7 +238,8 @@ learn_parse_load_immediate(const char *s, struct ofpact_learn_spec *spec)
|
|||||||
* error. The caller is responsible for freeing the returned string. */
|
* error. The caller is responsible for freeing the returned string. */
|
||||||
static char * OVS_WARN_UNUSED_RESULT
|
static char * OVS_WARN_UNUSED_RESULT
|
||||||
learn_parse_spec(const char *orig, char *name, char *value,
|
learn_parse_spec(const char *orig, char *name, char *value,
|
||||||
struct ofpact_learn_spec *spec)
|
struct ofpact_learn_spec *spec,
|
||||||
|
struct ofpbuf *ofpacts, struct match *match)
|
||||||
{
|
{
|
||||||
if (mf_from_name(name)) {
|
if (mf_from_name(name)) {
|
||||||
const struct mf_field *dst = mf_from_name(name);
|
const struct mf_field *dst = mf_from_name(name);
|
||||||
@@ -244,13 +253,19 @@ learn_parse_spec(const char *orig, char *name, char *value,
|
|||||||
|
|
||||||
spec->n_bits = dst->n_bits;
|
spec->n_bits = dst->n_bits;
|
||||||
spec->src_type = NX_LEARN_SRC_IMMEDIATE;
|
spec->src_type = NX_LEARN_SRC_IMMEDIATE;
|
||||||
memset(&spec->src_imm, 0, sizeof spec->src_imm);
|
|
||||||
memcpy(&spec->src_imm.u8[sizeof spec->src_imm - dst->n_bytes],
|
|
||||||
&imm, dst->n_bytes);
|
|
||||||
spec->dst_type = NX_LEARN_DST_MATCH;
|
spec->dst_type = NX_LEARN_DST_MATCH;
|
||||||
spec->dst.field = dst;
|
spec->dst.field = dst;
|
||||||
spec->dst.ofs = 0;
|
spec->dst.ofs = 0;
|
||||||
spec->dst.n_bits = dst->n_bits;
|
spec->dst.n_bits = dst->n_bits;
|
||||||
|
|
||||||
|
/* Update 'match' to allow for satisfying destination
|
||||||
|
* prerequisites. */
|
||||||
|
mf_set_value(dst, &imm, match, NULL);
|
||||||
|
|
||||||
|
/* Push value last, as this may reallocate 'spec'! */
|
||||||
|
uint8_t *src_imm = ofpbuf_put_zeros(ofpacts,
|
||||||
|
OFPACT_ALIGN(dst->n_bytes));
|
||||||
|
memcpy(src_imm, &imm, dst->n_bytes);
|
||||||
} else if (strchr(name, '[')) {
|
} else if (strchr(name, '[')) {
|
||||||
/* Parse destination and check prerequisites. */
|
/* Parse destination and check prerequisites. */
|
||||||
char *error;
|
char *error;
|
||||||
@@ -284,7 +299,7 @@ learn_parse_spec(const char *orig, char *name, char *value,
|
|||||||
spec->dst_type = NX_LEARN_DST_MATCH;
|
spec->dst_type = NX_LEARN_DST_MATCH;
|
||||||
} else if (!strcmp(name, "load")) {
|
} else if (!strcmp(name, "load")) {
|
||||||
if (value[strcspn(value, "[-")] == '-') {
|
if (value[strcspn(value, "[-")] == '-') {
|
||||||
char *error = learn_parse_load_immediate(value, spec);
|
char *error = learn_parse_load_immediate(value, spec, ofpacts);
|
||||||
if (error) {
|
if (error) {
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
@@ -363,20 +378,12 @@ learn_parse__(char *orig, char *arg, struct ofpbuf *ofpacts)
|
|||||||
char *error;
|
char *error;
|
||||||
|
|
||||||
spec = ofpbuf_put_zeros(ofpacts, sizeof *spec);
|
spec = ofpbuf_put_zeros(ofpacts, sizeof *spec);
|
||||||
learn = ofpacts->header;
|
error = learn_parse_spec(orig, name, value, spec, ofpacts, &match);
|
||||||
learn->n_specs++;
|
|
||||||
|
|
||||||
error = learn_parse_spec(orig, name, value, spec);
|
|
||||||
if (error) {
|
if (error) {
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
learn = ofpacts->header;
|
||||||
/* Update 'match' to allow for satisfying destination
|
learn->n_specs++;
|
||||||
* prerequisites. */
|
|
||||||
if (spec->src_type == NX_LEARN_SRC_IMMEDIATE
|
|
||||||
&& spec->dst_type == NX_LEARN_DST_MATCH) {
|
|
||||||
mf_write_subfield(&spec->dst, &spec->src_imm, &match);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ofpact_finish_LEARN(ofpacts, &learn);
|
ofpact_finish_LEARN(ofpacts, &learn);
|
||||||
@@ -449,19 +456,20 @@ learn_format(const struct ofpact_learn *learn, struct ds *s)
|
|||||||
colors.param, colors.end, ntohll(learn->cookie));
|
colors.param, colors.end, ntohll(learn->cookie));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (spec = learn->specs; spec < &learn->specs[learn->n_specs]; spec++) {
|
for (spec = learn->specs; spec < &learn->specs[learn->n_specs];
|
||||||
|
spec = ofpact_learn_spec_next(spec)) {
|
||||||
|
unsigned int n_bytes = DIV_ROUND_UP(spec->dst.n_bits, 8);
|
||||||
ds_put_char(s, ',');
|
ds_put_char(s, ',');
|
||||||
|
|
||||||
switch (spec->src_type | spec->dst_type) {
|
switch (spec->src_type | spec->dst_type) {
|
||||||
case NX_LEARN_SRC_IMMEDIATE | NX_LEARN_DST_MATCH:
|
case NX_LEARN_SRC_IMMEDIATE | NX_LEARN_DST_MATCH: {
|
||||||
if (spec->dst.ofs == 0
|
if (spec->dst.ofs == 0
|
||||||
&& spec->dst.n_bits == spec->dst.field->n_bits) {
|
&& spec->dst.n_bits == spec->dst.field->n_bits) {
|
||||||
union mf_value value;
|
union mf_value value;
|
||||||
|
|
||||||
memset(&value, 0, sizeof value);
|
memset(&value, 0, sizeof value);
|
||||||
bitwise_copy(&spec->src_imm, sizeof spec->src_imm, 0,
|
memcpy(&value.b[spec->dst.field->n_bytes - n_bytes],
|
||||||
&value, spec->dst.field->n_bytes, 0,
|
spec->src_imm, n_bytes);
|
||||||
spec->dst.field->n_bits);
|
|
||||||
ds_put_format(s, "%s%s=%s", colors.param,
|
ds_put_format(s, "%s%s=%s", colors.param,
|
||||||
spec->dst.field->name, colors.end);
|
spec->dst.field->name, colors.end);
|
||||||
mf_format(spec->dst.field, &value, NULL, s);
|
mf_format(spec->dst.field, &value, NULL, s);
|
||||||
@@ -469,10 +477,10 @@ learn_format(const struct ofpact_learn *learn, struct ds *s)
|
|||||||
ds_put_format(s, "%s", colors.param);
|
ds_put_format(s, "%s", colors.param);
|
||||||
mf_format_subfield(&spec->dst, s);
|
mf_format_subfield(&spec->dst, s);
|
||||||
ds_put_format(s, "=%s", colors.end);
|
ds_put_format(s, "=%s", colors.end);
|
||||||
mf_format_subvalue(&spec->src_imm, s);
|
ds_put_hex(s, spec->src_imm, n_bytes);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case NX_LEARN_SRC_FIELD | NX_LEARN_DST_MATCH:
|
case NX_LEARN_SRC_FIELD | NX_LEARN_DST_MATCH:
|
||||||
ds_put_format(s, "%s", colors.param);
|
ds_put_format(s, "%s", colors.param);
|
||||||
mf_format_subfield(&spec->dst, s);
|
mf_format_subfield(&spec->dst, s);
|
||||||
@@ -486,7 +494,7 @@ learn_format(const struct ofpact_learn *learn, struct ds *s)
|
|||||||
|
|
||||||
case NX_LEARN_SRC_IMMEDIATE | NX_LEARN_DST_LOAD:
|
case NX_LEARN_SRC_IMMEDIATE | NX_LEARN_DST_LOAD:
|
||||||
ds_put_format(s, "%sload:%s", colors.special, colors.end);
|
ds_put_format(s, "%sload:%s", colors.special, colors.end);
|
||||||
mf_format_subvalue(&spec->src_imm, s);
|
ds_put_hex(s, spec->src_imm, n_bytes);
|
||||||
ds_put_format(s, "%s->%s", colors.special, colors.end);
|
ds_put_format(s, "%s->%s", colors.special, colors.end);
|
||||||
mf_format_subfield(&spec->dst, s);
|
mf_format_subfield(&spec->dst, s);
|
||||||
break;
|
break;
|
||||||
|
@@ -2535,6 +2535,20 @@ mf_write_subfield(const struct mf_subfield *sf, const union mf_subvalue *x,
|
|||||||
mf_set(field, &value, &mask, match, NULL);
|
mf_set(field, &value, &mask, match, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mf_write_subfield_value(const struct mf_subfield *sf, const void *src,
|
||||||
|
struct match *match)
|
||||||
|
{
|
||||||
|
const struct mf_field *field = sf->field;
|
||||||
|
union mf_value value, mask;
|
||||||
|
unsigned int size = DIV_ROUND_UP(sf->n_bits, 8);
|
||||||
|
|
||||||
|
mf_get(field, match, &value, &mask);
|
||||||
|
bitwise_copy(src, size, 0, &value, field->n_bytes, sf->ofs, sf->n_bits);
|
||||||
|
bitwise_one ( &mask, field->n_bytes, sf->ofs, sf->n_bits);
|
||||||
|
mf_set(field, &value, &mask, match, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/* 'v' and 'm' correspond to values of 'field'. This function copies them into
|
/* 'v' and 'm' correspond to values of 'field'. This function copies them into
|
||||||
* 'match' in the correspond positions. */
|
* 'match' in the correspond positions. */
|
||||||
void
|
void
|
||||||
|
@@ -4293,15 +4293,16 @@ decode_NXAST_RAW_LEARN(const struct nx_action_learn *nal,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Get the source. */
|
/* Get the source. */
|
||||||
|
const uint8_t *imm = NULL;
|
||||||
|
unsigned int imm_bytes = 0;
|
||||||
if (spec->src_type == NX_LEARN_SRC_FIELD) {
|
if (spec->src_type == NX_LEARN_SRC_FIELD) {
|
||||||
get_subfield(spec->n_bits, &p, &spec->src);
|
get_subfield(spec->n_bits, &p, &spec->src);
|
||||||
} else {
|
} else {
|
||||||
int p_bytes = 2 * DIV_ROUND_UP(spec->n_bits, 16);
|
int p_bytes = 2 * DIV_ROUND_UP(spec->n_bits, 16);
|
||||||
|
|
||||||
bitwise_copy(p, p_bytes, 0,
|
|
||||||
&spec->src_imm, sizeof spec->src_imm, 0,
|
|
||||||
spec->n_bits);
|
|
||||||
p = (const uint8_t *) p + p_bytes;
|
p = (const uint8_t *) p + p_bytes;
|
||||||
|
|
||||||
|
imm_bytes = DIV_ROUND_UP(spec->n_bits, 8);
|
||||||
|
imm = (const uint8_t *) p - imm_bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the destination. */
|
/* Get the destination. */
|
||||||
@@ -4309,6 +4310,14 @@ decode_NXAST_RAW_LEARN(const struct nx_action_learn *nal,
|
|||||||
spec->dst_type == NX_LEARN_DST_LOAD) {
|
spec->dst_type == NX_LEARN_DST_LOAD) {
|
||||||
get_subfield(spec->n_bits, &p, &spec->dst);
|
get_subfield(spec->n_bits, &p, &spec->dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (imm) {
|
||||||
|
uint8_t *src_imm = ofpbuf_put_zeros(ofpacts,
|
||||||
|
OFPACT_ALIGN(imm_bytes));
|
||||||
|
memcpy(src_imm, imm, imm_bytes);
|
||||||
|
|
||||||
|
learn = ofpacts->header;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ofpact_finish_LEARN(ofpacts, &learn);
|
ofpact_finish_LEARN(ofpacts, &learn);
|
||||||
|
|
||||||
@@ -4362,7 +4371,8 @@ encode_LEARN(const struct ofpact_learn *learn,
|
|||||||
nal->flags = htons(learn->flags);
|
nal->flags = htons(learn->flags);
|
||||||
nal->table_id = learn->table_id;
|
nal->table_id = learn->table_id;
|
||||||
|
|
||||||
for (spec = learn->specs; spec < &learn->specs[learn->n_specs]; spec++) {
|
for (spec = learn->specs; spec < &learn->specs[learn->n_specs];
|
||||||
|
spec = ofpact_learn_spec_next(spec)) {
|
||||||
put_u16(out, spec->n_bits | spec->dst_type | spec->src_type);
|
put_u16(out, spec->n_bits | spec->dst_type | spec->src_type);
|
||||||
|
|
||||||
if (spec->src_type == NX_LEARN_SRC_FIELD) {
|
if (spec->src_type == NX_LEARN_SRC_FIELD) {
|
||||||
@@ -4371,9 +4381,9 @@ encode_LEARN(const struct ofpact_learn *learn,
|
|||||||
} else {
|
} else {
|
||||||
size_t n_dst_bytes = 2 * DIV_ROUND_UP(spec->n_bits, 16);
|
size_t n_dst_bytes = 2 * DIV_ROUND_UP(spec->n_bits, 16);
|
||||||
uint8_t *bits = ofpbuf_put_zeros(out, n_dst_bytes);
|
uint8_t *bits = ofpbuf_put_zeros(out, n_dst_bytes);
|
||||||
bitwise_copy(&spec->src_imm, sizeof spec->src_imm, 0,
|
unsigned int n_bytes = DIV_ROUND_UP(spec->dst.n_bits, 8);
|
||||||
bits, n_dst_bytes, 0,
|
|
||||||
spec->n_bits);
|
memcpy(bits + n_dst_bytes - n_bytes, spec->src_imm, n_bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (spec->dst_type == NX_LEARN_DST_MATCH ||
|
if (spec->dst_type == NX_LEARN_DST_MATCH ||
|
||||||
|
Reference in New Issue
Block a user