#include <errno.h>
#include <stdlib.h>
-#include "autopath.h"
#include "bundle.h"
#include "byte-order.h"
#include "dynamic-string.h"
}
}
+static void
+parse_set_mpls_ttl(struct ofpbuf *b, const char *arg)
+{
+ struct ofpact_mpls_ttl *mpls_ttl = ofpact_put_SET_MPLS_TTL(b);
+
+ if (*arg == '\0') {
+ ovs_fatal(0, "parse_set_mpls_ttl: expected ttl.");
+ }
+
+ mpls_ttl->ttl = atoi(arg);
+}
+
static void
set_field_parse(const char *arg, struct ofpbuf *ofpacts)
{
free(orig);
}
+static void
+parse_metadata(struct ofpbuf *b, char *arg)
+{
+ struct ofpact_metadata *om;
+ char *mask = strchr(arg, '/');
+
+ om = ofpact_put_WRITE_METADATA(b);
+
+ if (mask) {
+ *mask = '\0';
+ om->mask = htonll(str_to_u64(mask + 1));
+ } else {
+ om->mask = htonll(UINT64_MAX);
+ }
+
+ om->metadata = htonll(str_to_u64(arg));
+}
+
+static void
+parse_sample(struct ofpbuf *b, char *arg)
+{
+ struct ofpact_sample *os = ofpact_put_SAMPLE(b);
+ char *key, *value;
+
+ while (ofputil_parse_key_value(&arg, &key, &value)) {
+ if (!strcmp(key, "probability")) {
+ os->probability = str_to_u16(value, "probability");
+ if (os->probability == 0) {
+ ovs_fatal(0, "invalid probability value \"%s\"", value);
+ }
+ } else if (!strcmp(key, "collector_set_id")) {
+ os->collector_set_id = str_to_u32(value);
+ } else if (!strcmp(key, "obs_domain_id")) {
+ os->obs_domain_id = str_to_u32(value);
+ } else if (!strcmp(key, "obs_point_id")) {
+ os->obs_point_id = str_to_u32(value);
+ } else {
+ ovs_fatal(0, "invalid key \"%s\" in \"sample\" argument",
+ key);
+ }
+ }
+ if (os->probability == 0) {
+ ovs_fatal(0, "non-zero \"probability\" must be specified on sample");
+ }
+}
+
static void
parse_named_action(enum ofputil_action_code code, const struct flow *flow,
char *arg, struct ofpbuf *ofpacts)
{
struct ofpact_tunnel *tunnel;
uint16_t vid;
+ uint16_t ethertype;
ovs_be32 ip;
uint8_t pcp;
uint8_t tos;
ofpact_put_STRIP_VLAN(ofpacts);
break;
+ case OFPUTIL_OFPAT11_PUSH_VLAN:
+ ethertype = str_to_u16(arg, "ethertype");
+ if (ethertype != ETH_TYPE_VLAN_8021Q) {
+ /* XXX ETH_TYPE_VLAN_8021AD case isn't supported */
+ ovs_fatal(0, "%s: not a valid VLAN ethertype", arg);
+ }
+ ofpact_put_PUSH_VLAN(ofpacts);
+ break;
+
+ case OFPUTIL_OFPAT11_SET_QUEUE:
+ ofpact_put_SET_QUEUE(ofpacts)->queue_id = str_to_u32(arg);
+ break;
+
+
case OFPUTIL_OFPAT10_SET_DL_SRC:
case OFPUTIL_OFPAT11_SET_DL_SRC:
str_to_mac(arg, ofpact_put_SET_ETH_SRC(ofpacts)->mac);
tunnel->tun_id = str_to_u64(arg);
break;
+ case OFPUTIL_NXAST_WRITE_METADATA:
+ parse_metadata(ofpacts, arg);
+ break;
+
case OFPUTIL_NXAST_SET_QUEUE:
ofpact_put_SET_QUEUE(ofpacts)->queue_id = str_to_u32(arg);
break;
multipath_parse(ofpact_put_MULTIPATH(ofpacts), arg);
break;
- case OFPUTIL_NXAST_AUTOPATH__DEPRECATED:
- autopath_parse(ofpact_put_AUTOPATH(ofpacts), arg);
- break;
-
case OFPUTIL_NXAST_BUNDLE:
bundle_parse(arg, ofpacts);
break;
parse_dec_ttl(ofpacts, arg);
break;
+ case OFPUTIL_NXAST_SET_MPLS_TTL:
+ case OFPUTIL_OFPAT11_SET_MPLS_TTL:
+ parse_set_mpls_ttl(ofpacts, arg);
+ break;
+
+ case OFPUTIL_OFPAT11_DEC_MPLS_TTL:
+ case OFPUTIL_NXAST_DEC_MPLS_TTL:
+ ofpact_put_DEC_MPLS_TTL(ofpacts);
+ break;
+
case OFPUTIL_NXAST_FIN_TIMEOUT:
parse_fin_timeout(ofpacts, arg);
break;
case OFPUTIL_NXAST_CONTROLLER:
parse_controller(ofpacts, arg);
break;
+
+ case OFPUTIL_OFPAT11_PUSH_MPLS:
+ case OFPUTIL_NXAST_PUSH_MPLS:
+ ofpact_put_PUSH_MPLS(ofpacts)->ethertype =
+ htons(str_to_u16(arg, "push_mpls"));
+ break;
+
+ case OFPUTIL_OFPAT11_POP_MPLS:
+ case OFPUTIL_NXAST_POP_MPLS:
+ ofpact_put_POP_MPLS(ofpacts)->ethertype =
+ htons(str_to_u16(arg, "pop_mpls"));
+ break;
+
+ case OFPUTIL_NXAST_STACK_PUSH:
+ nxm_parse_stack_action(ofpact_put_STACK_PUSH(ofpacts), arg);
+ break;
+ case OFPUTIL_NXAST_STACK_POP:
+ nxm_parse_stack_action(ofpact_put_STACK_POP(ofpacts), arg);
+ break;
+
+ case OFPUTIL_NXAST_SAMPLE:
+ parse_sample(ofpacts, arg);
+ break;
}
}
str_to_ofpacts(const struct flow *flow, char *str, struct ofpbuf *ofpacts)
{
char *pos, *act, *arg;
+ enum ofperr error;
int n_actions;
pos = str;
}
n_actions++;
}
+
+ error = ofpacts_verify(ofpacts->data, ofpacts->size);
+ if (error) {
+ ovs_fatal(0, "Incorrect action ordering");
+ }
+
ofpact_pad(ofpacts);
}
parse_named_instruction(enum ovs_instruction_type type,
char *arg, struct ofpbuf *ofpacts)
{
+ enum ofperr error;
+
switch (type) {
case OVSINST_OFPIT11_APPLY_ACTIONS:
NOT_REACHED(); /* This case is handled by str_to_inst_ofpacts() */
break;
case OVSINST_OFPIT11_WRITE_ACTIONS:
- /* TODO:XXX */
+ /* XXX */
ovs_fatal(0, "instruction write-actions is not supported yet");
break;
break;
case OVSINST_OFPIT11_WRITE_METADATA:
- /* TODO:XXX */
- ovs_fatal(0, "instruction write-metadata is not supported yet");
+ parse_metadata(ofpacts, arg);
break;
case OVSINST_OFPIT11_GOTO_TABLE: {
break;
}
}
+
+ /* If write_metadata is specified as an action AND an instruction, ofpacts
+ could be invalid. */
+ error = ofpacts_verify(ofpacts->data, ofpacts->size);
+ if (error) {
+ ovs_fatal(0, "Incorrect instruction ordering");
+ }
}
static void
{ "icmp6", ETH_TYPE_IPV6, IPPROTO_ICMPV6 },
{ "tcp6", ETH_TYPE_IPV6, IPPROTO_TCP },
{ "udp6", ETH_TYPE_IPV6, IPPROTO_UDP },
+ { "rarp", ETH_TYPE_RARP, 0},
+ { "mpls", ETH_TYPE_MPLS, 0 },
+ { "mplsm", ETH_TYPE_MPLS_MCAST, 0 },
};
const struct protocol *p;
fm->idle_timeout = OFP_FLOW_PERMANENT;
fm->hard_timeout = OFP_FLOW_PERMANENT;
fm->buffer_id = UINT32_MAX;
- fm->out_port = OFPP_NONE;
+ fm->out_port = OFPP_ANY;
fm->flags = 0;
if (fields & F_ACTIONS) {
act_str = strstr(string, "action");
fm->flags |= OFPFF_SEND_FLOW_REM;
} else if (fields & F_FLAGS && !strcmp(name, "check_overlap")) {
fm->flags |= OFPFF_CHECK_OVERLAP;
+ } else if (fields & F_FLAGS && !strcmp(name, "reset_counts")) {
+ fm->flags |= OFPFF12_RESET_COUNTS;
+ } else if (fields & F_FLAGS && !strcmp(name, "no_packet_counts")) {
+ fm->flags |= OFPFF13_NO_PKT_COUNTS;
+ } else if (fields & F_FLAGS && !strcmp(name, "no_byte_counts")) {
+ fm->flags |= OFPFF13_NO_BYT_COUNTS;
} else {
char *value;
parse_field(mf_from_name(name), value, &fm->match);
} else if (!strcmp(name, "duration")
|| !strcmp(name, "n_packets")
- || !strcmp(name, "n_bytes")) {
+ || !strcmp(name, "n_bytes")
+ || !strcmp(name, "idle_age")
+ || !strcmp(name, "hard_age")) {
/* Ignore these, so that users can feed the output of
* "ovs-ofctl dump-flows" back into commands that parse
* flows. */
}
}
+ if (!flow->in_port) {
+ flow->in_port = OFPP_NONE;
+ }
+
exit:
free(copy);