}
}
-static int
-ofp_print_action(struct ds *string, const struct ofp_action_header *ah,
- size_t actions_len)
+static void
+ofp_print_action(struct ds *string, const struct ofp_action_header *ah)
{
enum ofp_action_type type;
int required_len;
size_t len;
- if (actions_len < sizeof *ah) {
- ds_put_format(string, "***action array too short for next action***\n");
- return -1;
- }
-
type = ntohs(ah->type);
len = ntohs(ah->len);
- if (actions_len < len) {
- ds_put_format(string, "***truncated action %d***\n", (int) type);
- return -1;
- }
-
- if (!len) {
- ds_put_format(string, "***zero-length action***\n");
- return 8;
- }
-
- if ((len % OFP_ACTION_ALIGN) != 0) {
- ds_put_format(string,
- "***action %d length not a multiple of %d***\n",
- (int) type, OFP_ACTION_ALIGN);
- return -1;
- }
required_len = ofp_action_len(type);
if (required_len >= 0 && len != required_len) {
ds_put_format(string,
"***action %d wrong length: %zu***\n", (int) type, len);
- return -1;
+ return;
}
switch (type) {
= (struct ofp_action_vendor_header *)ah;
if (len < sizeof *avh) {
ds_put_format(string, "***ofpat_vendor truncated***\n");
- return -1;
+ return;
}
if (avh->vendor == htonl(NX_VENDOR_ID)) {
ofp_print_nx_action(string, (struct nx_action_header *)avh);
ds_put_format(string, "(decoder %d not implemented)", (int) type);
break;
}
-
- return len;
}
void
-ofp_print_actions(struct ds *string, const struct ofp_action_header *action,
- size_t actions_len)
+ofp_print_actions(struct ds *string, const union ofp_action *actions,
+ size_t n_actions)
{
- uint8_t *p = (uint8_t *)action;
- int len = 0;
+ const union ofp_action *a;
+ size_t left;
ds_put_cstr(string, "actions=");
- if (!actions_len) {
+ if (!n_actions) {
ds_put_cstr(string, "drop");
}
- while (actions_len > 0) {
- if (len) {
+ OFPUTIL_ACTION_FOR_EACH (a, left, actions, n_actions) {
+ if (a != actions) {
ds_put_cstr(string, ",");
}
- len = ofp_print_action(string, (struct ofp_action_header *)p,
- actions_len);
- if (len < 0) {
- return;
- }
- p += len;
- actions_len -= len;
+ ofp_print_action(string, (struct ofp_action_header *)a);
+ }
+ if (left > 0) {
+ ds_put_format(string, " ***%zu leftover bytes following actions",
+ left * sizeof *a);
}
}
ds_put_format(string, "***packet too short for action length***\n");
return;
}
- ofp_print_actions(string, opo->actions, actions_len);
+ if (actions_len % sizeof(union ofp_action)) {
+ ds_put_format(string, "***action length not a multiple of %zu***\n",
+ sizeof(union ofp_action));
+ }
+ ofp_print_actions(string, (const union ofp_action *) opo->actions,
+ actions_len / sizeof(union ofp_action));
if (ntohl(opo->buffer_id) == UINT32_MAX) {
int data_len = len - sizeof *opo - actions_len;
ds_put_format(s, "flags:0x%"PRIx16" ", fm.flags);
}
- ofp_print_actions(s, (const struct ofp_action_header *) fm.actions,
- fm.n_actions * sizeof *fm.actions);
+ ofp_print_actions(s, fm.actions, fm.n_actions);
}
static void
cls_rule_format(&fs.rule, string);
ds_put_char(string, ' ');
- ofp_print_actions(string,
- (const struct ofp_action_header *) fs.actions,
- fs.n_actions * sizeof *fs.actions);
+ ofp_print_actions(string, fs.actions, fs.n_actions);
}
}
/*
- * Copyright (c) 2008, 2009 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2011 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
struct ofp_flow_mod;
struct ofp_match;
struct ds;
-struct ofp_action_header;
+union ofp_action;
#ifdef __cplusplus
extern "C" {
void ofp_print(FILE *, const void *, size_t, int verbosity);
void ofp_print_packet(FILE *stream, const void *data, size_t len, size_t total_len);
-void ofp_print_actions(struct ds *, const struct ofp_action_header *, size_t);
+void ofp_print_actions(struct ds *, const union ofp_action *, size_t);
void ofp_print_match(struct ds *, const struct ofp_match *, int verbosity);
char *ofp_to_string(const void *, size_t, int verbosity);
}
}
-/* The set of actions must either come from a trusted source or have been
- * previously validated with validate_actions(). */
-const union ofp_action *
-actions_first(struct actions_iterator *iter,
- const union ofp_action *oa, size_t n_actions)
-{
- iter->pos = oa;
- iter->end = oa + n_actions;
- return actions_next(iter);
-}
-
-const union ofp_action *
-actions_next(struct actions_iterator *iter)
-{
- if (iter->pos != iter->end) {
- const union ofp_action *a = iter->pos;
- unsigned int len = ntohs(a->header.len);
- iter->pos += len / OFP_ACTION_ALIGN;
- return a;
- } else {
- return NULL;
- }
-}
-
/* "Normalizes" the wildcards in 'rule'. That means:
*
* 1. If the type of level N is known, then only the valid fields for that
#define OFP_ACTION_ALIGN 8 /* Alignment of ofp_actions. */
-struct actions_iterator {
- const union ofp_action *pos, *end;
-};
-const union ofp_action *actions_first(struct actions_iterator *,
- const union ofp_action *,
- size_t n_actions);
-const union ofp_action *actions_next(struct actions_iterator *);
+static inline union ofp_action *
+ofputil_action_next(const union ofp_action *a)
+{
+ return (void *) ((uint8_t *) a + ntohs(a->header.len));
+}
+
+static inline bool
+ofputil_action_is_valid(const union ofp_action *a, size_t n_actions)
+{
+ uint16_t len = ntohs(a->header.len);
+ return (!(len % OFP_ACTION_ALIGN)
+ && len >= sizeof *a
+ && len / sizeof *a <= n_actions);
+}
+
+/* This macro is careful to check for actions with bad lengths. */
+#define OFPUTIL_ACTION_FOR_EACH(ITER, LEFT, ACTIONS, N_ACTIONS) \
+ for ((ITER) = (ACTIONS), (LEFT) = (N_ACTIONS); \
+ (LEFT) > 0 && ofputil_action_is_valid(ITER, LEFT); \
+ ((LEFT) -= ntohs((ITER)->header.len) / sizeof(union ofp_action), \
+ (ITER) = ofputil_action_next(ITER)))
+
+/* This macro does not check for actions with bad lengths. It should only be
+ * used with actions from trusted sources or with actions that have already
+ * been validated (e.g. with OFPUTIL_ACTION_FOR_EACH). */
+#define OFPUTIL_ACTION_FOR_EACH_UNSAFE(ITER, LEFT, ACTIONS, N_ACTIONS) \
+ for ((ITER) = (ACTIONS), (LEFT) = (N_ACTIONS); \
+ (LEFT) > 0; \
+ ((LEFT) -= ntohs((ITER)->header.len) / sizeof(union ofp_action), \
+ (ITER) = ofputil_action_next(ITER)))
int validate_actions(const union ofp_action *, size_t n_actions,
const struct flow *, int max_ports);
struct action_xlate_ctx *ctx)
{
const struct ofport_dpif *port;
- struct actions_iterator iter;
const union ofp_action *ia;
+ size_t left;
port = get_ofp_port(ctx->ofproto, ctx->flow.in_port);
if (port
return;
}
- for (ia = actions_first(&iter, in, n_in); ia; ia = actions_next(&iter)) {
- enum ofp_action_type type = ntohs(ia->type);
+ OFPUTIL_ACTION_FOR_EACH_UNSAFE (ia, left, in, n_in) {
const struct ofp_action_dl_addr *oada;
+ enum ofp_action_type type = ntohs(ia->type);
switch (type) {
case OFPAT_OUTPUT:
ds_put_char_multiple(result, '\t', level);
ds_put_cstr(result, "OpenFlow ");
- ofp_print_actions(result, (const struct ofp_action_header *) rule->actions,
- rule->n_actions * sizeof *rule->actions);
+ ofp_print_actions(result, rule->actions, rule->n_actions);
ds_put_char(result, '\n');
}
rule_has_out_port(const struct rule *rule, uint16_t out_port)
{
const union ofp_action *oa;
- struct actions_iterator i;
+ size_t left;
if (out_port == OFPP_NONE) {
return true;
}
- for (oa = actions_first(&i, rule->actions, rule->n_actions); oa;
- oa = actions_next(&i)) {
+ OFPUTIL_ACTION_FOR_EACH_UNSAFE (oa, left, rule->actions, rule->n_actions) {
if (action_outputs_to_port(oa, htons(out_port))) {
return true;
}
flow_stats_ds(struct rule *rule, struct ds *results)
{
uint64_t packet_count, byte_count;
- size_t act_len = sizeof *rule->actions * rule->n_actions;
rule->ofproto->ofproto_class->rule_get_stats(rule,
&packet_count, &byte_count);
ds_put_format(results, "n_bytes=%"PRIu64", ", byte_count);
cls_rule_format(&rule->cr, results);
ds_put_char(results, ',');
- if (act_len > 0) {
- ofp_print_actions(results, &rule->actions->header, act_len);
+ if (rule->n_actions > 0) {
+ ofp_print_actions(results, rule->actions, rule->n_actions);
} else {
ds_put_cstr(results, "drop");
}
}
ds_init(&s);
- ofp_print_actions(&s, (const struct ofp_action_header *) version->actions,
- version->n_actions * sizeof *version->actions);
+ ofp_print_actions(&s, version->actions, version->n_actions);
printf(" %s\n", ds_cstr(&s));
ds_destroy(&s);
}