Skip to content

Commit

Permalink
bundle: New action "bundle_load".
Browse files Browse the repository at this point in the history
The bundle_load action behaves the same as the bundle action,
except instead of outputting, it writes its result to a register.
  • Loading branch information
ejj committed Jul 23, 2011
1 parent 04a8549 commit a368bb5
Show file tree
Hide file tree
Showing 12 changed files with 175 additions and 36 deletions.
24 changes: 18 additions & 6 deletions include/openflow/nicira-ext.h
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,8 @@ enum nx_action_subtype {
NXAST_SET_TUNNEL64, /* struct nx_action_set_tunnel64 */
NXAST_MULTIPATH, /* struct nx_action_multipath */
NXAST_AUTOPATH, /* struct nx_action_autopath */
NXAST_BUNDLE /* struct nx_action_bundle */
NXAST_BUNDLE, /* struct nx_action_bundle */
NXAST_BUNDLE_LOAD /* struct nx_action_bundle */
};

/* Header for Nicira-defined actions. */
Expand Down Expand Up @@ -664,10 +665,11 @@ struct nx_action_autopath {
};
OFP_ASSERT(sizeof(struct nx_action_autopath) == 24);

/* Action structure for NXAST_BUNDLE.
/* Action structure for NXAST_BUNDLE and NXAST_BUNDLE_LOAD.
*
* NXAST_BUNDLE chooses a slave from a supplied list of options, and outputs to
* its selection.
* The bundle actions choose a slave from a supplied list of options.
* NXAST_BUNDLE outputs to its selection. NXAST_BUNDLE_LOAD writes its
* selection to a register.
*
* The list of possible slaves follows the nx_action_bundle structure. The size
* of each slave is governed by its type as indicated by the 'slave_type'
Expand All @@ -693,7 +695,14 @@ OFP_ASSERT(sizeof(struct nx_action_autopath) == 24);
*
* The 'zero' parameter at the end of the action structure is reserved for
* future use. Switches are required to reject actions which have nonzero
* bytes in the 'zero' field. */
* bytes in the 'zero' field.
*
* NXAST_BUNDLE actions should have 'ofs_nbits' and 'dst' zeroed. Switches
* should reject actions which have nonzero bytes in either of these fields.
*
* NXAST_BUNDLE_LOAD stores the OpenFlow port number of the selected slave in
* dst[ofs:ofs+n_bits]. The format and semantics of 'dst' and 'ofs_nbits' are
* similar to those for the NXAST_REG_LOAD action. */
struct nx_action_bundle {
ovs_be16 type; /* OFPAT_VENDOR. */
ovs_be16 len; /* Length including slaves. */
Expand All @@ -710,7 +719,10 @@ struct nx_action_bundle {
ovs_be32 slave_type; /* NXM_OF_IN_PORT. */
ovs_be16 n_slaves; /* Number of slaves. */

uint8_t zero[10]; /* Reserved. Must be zero. */
ovs_be16 ofs_nbits; /* (ofs << 6) | (n_bits - 1). */
ovs_be32 dst; /* Destination. */

uint8_t zero[4]; /* Reserved. Must be zero. */
};
OFP_ASSERT(sizeof(struct nx_action_bundle) == 32);

Expand Down
121 changes: 102 additions & 19 deletions lib/bundle.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,22 @@ bundle_execute(const struct nx_action_bundle *nab, const struct flow *flow,
}
}

void
bundle_execute_load(const struct nx_action_bundle *nab, struct flow *flow,
bool (*slave_enabled)(uint16_t ofp_port, void *aux),
void *aux)
{
nxm_reg_load(nab->dst, nab->ofs_nbits,
bundle_execute(nab, flow, slave_enabled, aux), flow);
}

/* Checks that 'nab' specifies a bundle action which is supported by this
* bundle module. Uses the 'max_ports' parameter to validate each port using
* ofputil_check_output_port(). Returns 0 if 'nab' is supported, otherwise an
* OpenFlow error code (as returned by ofp_mkerr()). */
int
bundle_check(const struct nx_action_bundle *nab, int max_ports)
bundle_check(const struct nx_action_bundle *nab, int max_ports,
const struct flow *flow)
{
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
uint16_t n_slaves, fields, algorithm, subtype;
Expand Down Expand Up @@ -129,6 +139,15 @@ bundle_check(const struct nx_action_bundle *nab, int max_ports)
}
}

if (subtype == NXAST_BUNDLE && (nab->ofs_nbits || nab->dst)) {
VLOG_WARN_RL(&rl, "bundle action has nonzero reserved fields");
error = ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT);
}

if (subtype == NXAST_BUNDLE_LOAD) {
error = nxm_dst_check(nab->dst, nab->ofs_nbits, 16, flow) || error;
}

if (slaves_size < n_slaves * sizeof(ovs_be16)) {
VLOG_WARN_RL(&rl, "Nicira action %"PRIu16" only has %zu bytes "
"allocated for slaves. %zu bytes are required for "
Expand Down Expand Up @@ -158,24 +177,16 @@ bundle_check(const struct nx_action_bundle *nab, int max_ports)
return error;
}

/* Converts a bundle action string contained in 's' to an nx_action_bundle and
* stores it in 'b'. Sets 'b''s l2 pointer to NULL. */
void
bundle_parse(struct ofpbuf *b, const char *s)
/* Helper for bundle_parse and bundle_parse_load. */
static void
bundle_parse__(struct ofpbuf *b, const char *s, char **save_ptr,
const char *fields, const char *basis, const char *algorithm,
const char *slave_type, const char *dst,
const char *slave_delim)
{
char *fields, *basis, *algorithm, *slave_type, *slave_delim;
struct nx_action_bundle *nab;
char *tokstr, *save_ptr;
uint16_t n_slaves;

save_ptr = NULL;
tokstr = xstrdup(s);
fields = strtok_r(tokstr, ", ", &save_ptr);
basis = strtok_r(NULL, ", ", &save_ptr);
algorithm = strtok_r(NULL, ", ", &save_ptr);
slave_type = strtok_r(NULL, ", ", &save_ptr);
slave_delim = strtok_r(NULL, ": ", &save_ptr);

if (!slave_delim) {
ovs_fatal(0, "%s: not enough arguments to bundle action", s);
}
Expand All @@ -192,7 +203,7 @@ bundle_parse(struct ofpbuf *b, const char *s)
ovs_be16 slave_be;
char *slave;

slave = strtok_r(NULL, ", ", &save_ptr);
slave = strtok_r(NULL, ", ", save_ptr);
if (!slave || n_slaves >= BUNDLE_MAX_SLAVES) {
break;
}
Expand All @@ -212,7 +223,7 @@ bundle_parse(struct ofpbuf *b, const char *s)
nab->type = htons(OFPAT_VENDOR);
nab->len = htons(b->size - ((char *) b->l2 - (char *) b->data));
nab->vendor = htonl(NX_VENDOR_ID);
nab->subtype = htons(NXAST_BUNDLE);
nab->subtype = htons(dst ? NXAST_BUNDLE_LOAD: NXAST_BUNDLE);
nab->n_slaves = htons(n_slaves);
nab->basis = htons(atoi(basis));

Expand All @@ -238,15 +249,68 @@ bundle_parse(struct ofpbuf *b, const char *s)
ovs_fatal(0, "%s: unknown slave_type `%s'", s, slave_type);
}

if (dst) {
uint32_t reg;
int ofs, n_bits;

nxm_parse_field_bits(dst, &reg, &ofs, &n_bits);

nab->dst = htonl(reg);
nab->ofs_nbits = nxm_encode_ofs_nbits(ofs, n_bits);
}

b->l2 = NULL;
}

/* Converts a bundle action string contained in 's' to an nx_action_bundle and
* stores it in 'b'. Sets 'b''s l2 pointer to NULL. */
void
bundle_parse(struct ofpbuf *b, const char *s)
{
char *fields, *basis, *algorithm, *slave_type, *slave_delim;
char *tokstr, *save_ptr;

save_ptr = NULL;
tokstr = xstrdup(s);
fields = strtok_r(tokstr, ", ", &save_ptr);
basis = strtok_r(NULL, ", ", &save_ptr);
algorithm = strtok_r(NULL, ", ", &save_ptr);
slave_type = strtok_r(NULL, ", ", &save_ptr);
slave_delim = strtok_r(NULL, ": ", &save_ptr);

bundle_parse__(b, s, &save_ptr, fields, basis, algorithm, slave_type, NULL,
slave_delim);
free(tokstr);
}

/* Converts a bundle_load action string contained in 's' to an nx_action_bundle
* and stores it in 'b'. Sets 'b''s l2 pointer to NULL. */
void
bundle_parse_load(struct ofpbuf *b, const char *s)
{
char *fields, *basis, *algorithm, *slave_type, *dst, *slave_delim;
char *tokstr, *save_ptr;

save_ptr = NULL;
tokstr = xstrdup(s);
fields = strtok_r(tokstr, ", ", &save_ptr);
basis = strtok_r(NULL, ", ", &save_ptr);
algorithm = strtok_r(NULL, ", ", &save_ptr);
slave_type = strtok_r(NULL, ", ", &save_ptr);
dst = strtok_r(NULL, ", ", &save_ptr);
slave_delim = strtok_r(NULL, ": ", &save_ptr);

bundle_parse__(b, s, &save_ptr, fields, basis, algorithm, slave_type, dst,
slave_delim);

free(tokstr);
}

/* Appends a human-readable representation of 'nab' to 's'. */
void
bundle_format(const struct nx_action_bundle *nab, struct ds *s)
{
const char *fields, *algorithm, *slave_type;
const char *action, *fields, *algorithm, *slave_type;
size_t i;

fields = flow_hash_fields_to_str(ntohs(nab->fields));
Expand All @@ -270,9 +334,28 @@ bundle_format(const struct nx_action_bundle *nab, struct ds *s)
slave_type = "<unknown>";
}

ds_put_format(s, "bundle(%s,%"PRIu16",%s,%s,slaves:", fields,
switch (ntohs(nab->subtype)) {
case NXAST_BUNDLE:
action = "bundle";
break;
case NXAST_BUNDLE_LOAD:
action = "bundle_load";
break;
default:
NOT_REACHED();
}

ds_put_format(s, "%s(%s,%"PRIu16",%s,%s,", action, fields,
ntohs(nab->basis), algorithm, slave_type);

if (nab->subtype == htons(NXAST_BUNDLE_LOAD)) {
nxm_format_field_bits(s, ntohl(nab->dst),
nxm_decode_ofs(nab->ofs_nbits),
nxm_decode_n_bits(nab->ofs_nbits));
ds_put_cstr(s, ",");
}

ds_put_cstr(s, "slaves:");
for (i = 0; i < ntohs(nab->n_slaves); i++) {
if (i) {
ds_put_cstr(s, ",");
Expand Down
7 changes: 6 additions & 1 deletion lib/bundle.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,13 @@ struct ofpbuf;
uint16_t bundle_execute(const struct nx_action_bundle *, const struct flow *,
bool (*slave_enabled)(uint16_t ofp_port, void *aux),
void *aux);
int bundle_check(const struct nx_action_bundle *, int max_ports);
void bundle_execute_load(const struct nx_action_bundle *, struct flow *,
bool (*slave_enabled)(uint16_t ofp_port, void *aux),
void *aux);
int bundle_check(const struct nx_action_bundle *, int max_ports,
const struct flow *);
void bundle_parse(struct ofpbuf *, const char *);
void bundle_parse_load(struct ofpbuf *b, const char *);
void bundle_format(const struct nx_action_bundle *, struct ds *);

/* Returns the 'i'th slave in 'nab'. */
Expand Down
2 changes: 2 additions & 0 deletions lib/ofp-parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,8 @@ str_to_action(char *str, struct ofpbuf *b)
autopath_parse(naa, arg);
} else if (!strcasecmp(act, "bundle")) {
bundle_parse(b, arg);
} else if (!strcasecmp(act, "bundle_load")) {
bundle_parse_load(b, arg);
} else if (!strcasecmp(act, "output")) {
put_output_action(b, str_to_u32(arg));
} else if (!strcasecmp(act, "enqueue")) {
Expand Down
1 change: 1 addition & 0 deletions lib/ofp-print.c
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,7 @@ ofp_print_action(struct ds *s, const union ofp_action *a,
break;

case OFPUTIL_NXAST_BUNDLE:
case OFPUTIL_NXAST_BUNDLE_LOAD:
bundle_format((const struct nx_action_bundle *) a, s);
break;

Expand Down
4 changes: 3 additions & 1 deletion lib/ofp-util.c
Original file line number Diff line number Diff line change
Expand Up @@ -2039,8 +2039,9 @@ validate_actions(const union ofp_action *actions, size_t n_actions,
break;

case OFPUTIL_NXAST_BUNDLE:
case OFPUTIL_NXAST_BUNDLE_LOAD:
error = bundle_check((const struct nx_action_bundle *) a,
max_ports);
max_ports, flow);
break;

case OFPUTIL_OFPAT_STRIP_VLAN:
Expand Down Expand Up @@ -2116,6 +2117,7 @@ static const struct ofputil_nxast_action nxast_actions[] = {
{ OFPUTIL_NXAST_MULTIPATH, 32, 32 },
{ OFPUTIL_NXAST_AUTOPATH, 24, 24 },
{ OFPUTIL_NXAST_BUNDLE, 32, UINT_MAX },
{ OFPUTIL_NXAST_BUNDLE_LOAD, 32, UINT_MAX },
};

static int
Expand Down
3 changes: 2 additions & 1 deletion lib/ofp-util.h
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,8 @@ enum ofputil_action_code {
OFPUTIL_NXAST_SET_TUNNEL64,
OFPUTIL_NXAST_MULTIPATH,
OFPUTIL_NXAST_AUTOPATH,
OFPUTIL_NXAST_BUNDLE
OFPUTIL_NXAST_BUNDLE,
OFPUTIL_NXAST_BUNDLE_LOAD,
};

int ofputil_decode_action(const union ofp_action *);
Expand Down
7 changes: 7 additions & 0 deletions ofproto/ofproto-dpif.c
Original file line number Diff line number Diff line change
Expand Up @@ -3228,6 +3228,13 @@ do_xlate_actions(const union ofp_action *in, size_t n_in,
slave_enabled_cb,
ctx->ofproto), 0);
break;

case OFPUTIL_NXAST_BUNDLE_LOAD:
ctx->ofproto->has_bundle_action = true;
nab = (const struct nx_action_bundle *) ia;
bundle_execute_load(nab, &ctx->flow, slave_enabled_cb,
ctx->ofproto);
break;
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions tests/bundle.at
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ AT_BANNER([bundle link selection])
# if the test does fail.

AT_SETUP([hrw bundle link selection])
AT_CHECK([[test-bundle 'symmetric_l4,60,hrw,ofport,slaves:1,2,3,4,5,6']],
AT_CHECK([[test-bundle 'symmetric_l4,60,hrw,ofport,NXM_NX_REG0[],slaves:1,2,3,4,5']],
[0], [ignore])
# 100000: disruption=1.00 (perfect=1.00) 1.00 0.00 0.00 0.00 0.00 0.00
# 110000: disruption=0.50 (perfect=0.50) 0.50 0.50 0.00 0.00 0.00 0.00
Expand Down Expand Up @@ -78,7 +78,7 @@ AT_CHECK([[test-bundle 'symmetric_l4,60,hrw,ofport,slaves:1,2,3,4,5,6']],
AT_CLEANUP

AT_SETUP([active_backup bundle link selection])
AT_CHECK([[test-bundle 'symmetric_l4,60,active_backup,ofport,slaves:1,2,3,4,5,6']],
AT_CHECK([[test-bundle 'symmetric_l4,60,active_backup,ofport,NXM_NX_REG0[],slaves:1,2,3,4,5,6']],
[0],
[100000: disruption=1.00 (perfect=1.00) 1.00 0.00 0.00 0.00 0.00 0.00
110000: disruption=0.00 (perfect=0.00) 1.00 0.00 0.00 0.00 0.00 0.00
Expand Down Expand Up @@ -149,15 +149,15 @@ AT_CHECK([[test-bundle 'symmetric_l4,60,active_backup,ofport,slaves:1,2,3,4,5,6'
AT_CLEANUP

AT_SETUP([hrw bundle single link selection])
AT_CHECK([[test-bundle 'symmetric_l4,60,hrw,ofport,slaves:1']],
AT_CHECK([[test-bundle 'symmetric_l4,60,hrw,ofport,NXM_NX_REG0[],slaves:1']],
[0], [ignore])
# 1: disruption=1.00 (perfect=1.00) 1.00
# 0: disruption=1.00 (perfect=1.00) 0.00
# 1: disruption=1.00 (perfect=1.00) 1.00
AT_CLEANUP

AT_SETUP([hrw bundle no link selection])
AT_CHECK([[test-bundle 'symmetric_l4,60,hrw,ofport,slaves:']],
AT_CHECK([[test-bundle 'symmetric_l4,60,hrw,ofport,NXM_NX_REG0[],slaves:']],
[0], [ignore])
AT_CLEANUP
#: disruption=0.00 (perfect=0.00)
Expand Down
8 changes: 8 additions & 0 deletions tests/ovs-ofctl.at
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ actions=bundle(eth_src,50,active_backup,ofport,slaves:1)
actions=bundle(symmetric_l4,60,hrw,ofport,slaves:2,3)
actions=bundle(symmetric_l4,60,hrw,ofport,slaves:)
actions=output:1,bundle(eth_src,0,hrw,ofport,slaves:1),output:2
actions=bundle_load(eth_src,50,active_backup,ofport,NXM_NX_REG0[],slaves:1)
actions=bundle_load(symmetric_l4,60,hrw,ofport,NXM_NX_REG0[0..15],slaves:2,3)
actions=bundle_load(symmetric_l4,60,hrw,ofport,NXM_NX_REG0[0..30],slaves:)
actions=output:1,bundle_load(eth_src,0,hrw,ofport,NXM_NX_REG0[16..31],slaves:1),output:2
]])
AT_CHECK([ovs-ofctl parse-flows flows.txt
], [0], [stdout])
Expand All @@ -41,6 +45,10 @@ NXT_FLOW_MOD: ADD table:255 actions=bundle(eth_src,50,active_backup,ofport,slave
NXT_FLOW_MOD: ADD table:255 actions=bundle(symmetric_l4,60,hrw,ofport,slaves:2,3)
NXT_FLOW_MOD: ADD table:255 actions=bundle(symmetric_l4,60,hrw,ofport,slaves:)
NXT_FLOW_MOD: ADD table:255 actions=output:1,bundle(eth_src,0,hrw,ofport,slaves:1),output:2
NXT_FLOW_MOD: ADD table:255 actions=bundle_load(eth_src,50,active_backup,ofport,NXM_NX_REG0[],slaves:1)
NXT_FLOW_MOD: ADD table:255 actions=bundle_load(symmetric_l4,60,hrw,ofport,NXM_NX_REG0[0..15],slaves:2,3)
NXT_FLOW_MOD: ADD table:255 actions=bundle_load(symmetric_l4,60,hrw,ofport,NXM_NX_REG0[0..30],slaves:)
NXT_FLOW_MOD: ADD table:255 actions=output:1,bundle_load(eth_src,0,hrw,ofport,NXM_NX_REG0[16..31],slaves:1),output:2
]])
AT_CLEANUP

Expand Down
Loading

0 comments on commit a368bb5

Please sign in to comment.