/*
- * 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.
{
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));
nan->len = htons(b->size - start_ofs);
}
+static void
+parse_fin_timeout(struct ofpbuf *b, char *arg)
+{
+ struct nx_action_fin_timeout *naft;
+ char *key, *value;
+
+ naft = ofputil_put_NXAST_FIN_TIMEOUT(b);
+ while (ofputil_parse_key_value(&arg, &key, &value)) {
+ if (!strcmp(key, "idle_timeout")) {
+ naft->fin_idle_timeout = htons(str_to_u16(value, key));
+ } else if (!strcmp(key, "hard_timeout")) {
+ naft->fin_hard_timeout = htons(str_to_u16(value, key));
+ } else {
+ ovs_fatal(0, "invalid key '%s' in 'fin_timeout' argument", key);
+ }
+ }
+}
+
static void
parse_named_action(enum ofputil_action_code code, const struct flow *flow,
struct ofpbuf *b, char *arg)
case OFPUTIL_NXAST_EXIT:
ofputil_put_NXAST_EXIT(b);
break;
+
+ case OFPUTIL_NXAST_DEC_TTL:
+ ofputil_put_NXAST_DEC_TTL(b);
+ break;
+
+ case OFPUTIL_NXAST_FIN_TIMEOUT:
+ parse_fin_timeout(b, arg);
+ 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;
fm->idle_timeout = str_to_u16(value, name);
} else if (fields & F_TIMEOUT && !strcmp(name, "hard_timeout")) {
fm->hard_timeout = str_to_u16(value, name);
- } else if (fields & F_COOKIE && !strcmp(name, "cookie")) {
+ } 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
* flow. */
void
parse_ofp_flow_mod_str(struct list *packets, enum nx_flow_format *cur_format,
- bool *flow_mod_table_id, char *string, uint16_t command,
- bool verbose)
+ bool *flow_mod_table_id, const char *string,
+ uint16_t command, bool verbose)
{
enum nx_flow_format min_format, next_format;
struct cls_rule rule_copy;
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);
void
parse_ofp_flow_stats_request_str(struct ofputil_flow_stats_request *fsr,
- bool aggregate, char *string)
+ bool aggregate, const char *string)
{
struct ofputil_flow_mod fm;
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;