/*
- * Copyright (c) 2010, 2011 Nicira Networks.
+ * Copyright (c) 2010, 2011, 2012 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
VLOG_DEFINE_THIS_MODULE(ofp_parse);
+static uint8_t
+str_to_table_id(const char *str)
+{
+ int table_id;
+
+ if (!str_to_int(str, 10, &table_id) || table_id < 0 || table_id > 255) {
+ ovs_fatal(0, "invalid table \"%s\"", str);
+ }
+ return table_id;
+}
+
+static uint16_t
+str_to_u16(const char *str, const char *name)
+{
+ int value;
+
+ if (!str_to_int(str, 0, &value) || value < 0 || value > 65535) {
+ ovs_fatal(0, "invalid %s \"%s\"", name, str);
+ }
+ return value;
+}
+
static uint32_t
str_to_u32(const char *str)
{
{
if (strchr(arg, '[')) {
struct nx_action_output_reg *naor;
- int ofs, n_bits;
- uint32_t src;
+ struct mf_subfield src;
- nxm_parse_field_bits(arg, &src, &ofs, &n_bits);
+ mf_parse_subfield(&src, arg);
naor = ofputil_put_NXAST_OUTPUT_REG(b);
- naor->ofs_nbits = nxm_encode_ofs_nbits(ofs, n_bits);
- naor->src = htonl(src);
+ naor->ofs_nbits = nxm_encode_ofs_nbits(src.ofs, src.n_bits);
+ naor->src = htonl(src.field->nxm_header);
naor->max_len = htons(UINT16_MAX);
} else {
put_output_action(b, str_to_u32(arg));
case OFPUTIL_NXAST_LEARN:
learn_parse(b, arg, flow);
break;
+
+ case OFPUTIL_NXAST_EXIT:
+ ofputil_put_NXAST_EXIT(b);
+ break;
+
+ case OFPUTIL_NXAST_DEC_TTL:
+ ofputil_put_NXAST_DEC_TTL(b);
+ break;
}
}
enum {
F_OUT_PORT = 1 << 0,
F_ACTIONS = 1 << 1,
- F_COOKIE = 1 << 2,
F_TIMEOUT = 1 << 3,
- F_PRIORITY = 1 << 4
+ F_PRIORITY = 1 << 4,
+ F_FLAGS = 1 << 5,
} fields;
char *string = xstrdup(str_);
char *save_ptr = NULL;
break;
case OFPFC_ADD:
- fields = F_ACTIONS | F_COOKIE | F_TIMEOUT | F_PRIORITY;
+ fields = F_ACTIONS | F_TIMEOUT | F_PRIORITY | F_FLAGS;
break;
case OFPFC_DELETE:
break;
case OFPFC_MODIFY:
- fields = F_ACTIONS | F_COOKIE;
+ fields = F_ACTIONS | F_TIMEOUT | F_PRIORITY | F_FLAGS;
break;
case OFPFC_MODIFY_STRICT:
- fields = F_ACTIONS | F_COOKIE | F_PRIORITY;
+ fields = F_ACTIONS | F_TIMEOUT | F_PRIORITY | F_FLAGS;
break;
default:
cls_rule_init_catchall(&fm->cr, OFP_DEFAULT_PRIORITY);
fm->cookie = htonll(0);
+ fm->cookie_mask = htonll(0);
fm->table_id = 0xff;
fm->command = command;
fm->idle_timeout = OFP_FLOW_PERMANENT;
if (p->nw_proto) {
cls_rule_set_nw_proto(&fm->cr, p->nw_proto);
}
+ } else if (fields & F_FLAGS && !strcmp(name, "send_flow_rem")) {
+ fm->flags |= OFPFF_SEND_FLOW_REM;
+ } else if (fields & F_FLAGS && !strcmp(name, "check_overlap")) {
+ fm->flags |= OFPFF_CHECK_OVERLAP;
} else {
char *value;
}
if (!strcmp(name, "table")) {
- fm->table_id = atoi(value);
+ fm->table_id = str_to_table_id(value);
} else if (!strcmp(name, "out_port")) {
fm->out_port = atoi(value);
} else if (fields & F_PRIORITY && !strcmp(name, "priority")) {
- fm->cr.priority = atoi(value);
+ fm->cr.priority = str_to_u16(value, name);
} else if (fields & F_TIMEOUT && !strcmp(name, "idle_timeout")) {
- fm->idle_timeout = atoi(value);
+ fm->idle_timeout = str_to_u16(value, name);
} else if (fields & F_TIMEOUT && !strcmp(name, "hard_timeout")) {
- fm->hard_timeout = atoi(value);
- } else if (fields & F_COOKIE && !strcmp(name, "cookie")) {
+ fm->hard_timeout = str_to_u16(value, name);
+ } else if (!strcmp(name, "cookie")) {
+ char *mask = strchr(value, '/');
+ if (mask) {
+ if (command == OFPFC_ADD) {
+ ofp_fatal(str_, verbose, "flow additions cannot use "
+ "a cookie mask");
+ }
+ *mask = '\0';
+ fm->cookie_mask = htonll(str_to_u64(mask+1));
+ } else {
+ fm->cookie_mask = htonll(UINT64_MAX);
+ }
fm->cookie = htonll(str_to_u64(value));
} else if (mf_from_name(name)) {
parse_field(mf_from_name(name), value, &fm->cr);
free(string);
}
+/* Parses 's' as a set of OpenFlow actions and appends the actions to
+ * 'actions'.
+ *
+ * Prints an error on stderr and aborts the program if 's' syntax is
+ * invalid. */
+void
+parse_ofp_actions(const char *s_, struct ofpbuf *actions)
+{
+ char *s = xstrdup(s_);
+ str_to_action(NULL, s, actions);
+ free(s);
+}
+
/* Parses 'string' as an OFPT_FLOW_MOD or NXT_FLOW_MOD with command 'command'
* (one of OFPFC_*) and appends the parsed OpenFlow message to 'packets'.
* '*cur_format' should initially contain the flow format currently configured
parse_ofp_str(&fm, command, string, verbose);
min_format = ofputil_min_flow_format(&fm.cr);
+ if (command != OFPFC_ADD && fm.cookie_mask != htonll(0)) {
+ min_format = NXFF_NXM;
+ }
next_format = MAX(*cur_format, min_format);
if (next_format != *cur_format) {
struct ofpbuf *sff = ofputil_make_set_flow_format(next_format);
parse_ofp_str(&fm, -1, string, false);
fsr->aggregate = aggregate;
+ fsr->cookie = fm.cookie;
+ fsr->cookie_mask = fm.cookie_mask;
fsr->match = fm.cr;
fsr->out_port = fm.out_port;
fsr->table_id = fm.table_id;