Nice cleanup, especially like the way wire formats are now hidden inside lib/ofp-actions.c.
Some small comments below, Jarno Acked-by: Jarno Rajahalme <jrajaha...@nicira.com> On Aug 7, 2014, at 4:14 PM, Ben Pfaff <b...@nicira.com> wrote: > Until now, knowledge about OpenFlow has been somewhat scattered around the > tree. Some of it is in ofp-actions, some of it is in ofp-util, some in > separate files for individual actions, and most of the wire format > declarations are in include/openflow. This commit centralizes all of that > in ofp-actions. > > Encoding and decoding OpenFlow actions was previously broken up by OpenFlow > version. This was OK with only OpenFlow 1.0 and 1.1, but each additional > version added a new wrapper around the existing ones, which started to > become hard to understand. This commit merges all of the processing for > the different versions, to the extent that they are similar, making the > version differences clearer. > > Previously, ofp-actions contained OpenFlow encoding and decoding, plus > ofpact formatting, but OpenFlow parsing was separated into ofp-parse, which > seems an odd division. This commit moves the parsing code into ofp-actions > with the rest of the code. > > Before this commit, the four main bits of code associated with a particular > ofpact--OpenFlow encoding and decoding, ofpact formatting and parsing--were > all found far away from each other. This often made it hard to see what > was going on for a particular ofpact, since you had to search around to > many different pieces of code. This commit reorganizes so that all of the > code for a given ofpact is in a single place. > > As a code refactoring, this commit has little visible behavioral change. > The update to ofproto-dpif.at illustrates one minor bug fix as a side > effect: a flow that was added with the action "dec_ttl" (a standard > OpenFlow action) was previously formatted as "dec_ttl(0)" (using a Nicira > extension to specifically direct packets bounced to the controller because > of too-low TTL), but after this commit it is correctly formatted as > "dec_ttl". > > The other visible effect is to drop support for the Nicira extension > dec_ttl action in OpenFlow 1.1 and later in favor of the equivalent > standard action. It seems unlikely that anyone was really using the > Nicira extension in OF1.1 or later. > > Signed-off-by: Ben Pfaff <b...@nicira.com> > --- > build-aux/extract-ofp-actions | 376 ++ > include/openflow/nicira-ext.h | 1014 ----- > include/openflow/openflow-1.0.h | 50 +- > include/openflow/openflow-1.1.h | 123 - > include/openflow/openflow-1.2.h | 20 - > include/openflow/openflow-1.3.h | 21 - > include/openflow/openflow-common.h | 76 - > lib/automake.mk | 8 +- > lib/bundle.c | 115 +- > lib/bundle.h | 7 +- > lib/learn.c | 212 - > lib/learn.h | 6 +- > lib/multipath.c | 60 +- > lib/multipath.h | 11 +- > lib/nx-match.c | 121 - > lib/nx-match.h | 19 - > lib/ofp-actions.c | 8045 +++++++++++++++++++++++------------- > lib/ofp-actions.h | 150 +- > lib/ofp-msgs.h | 2 +- > lib/ofp-parse.c | 1104 +---- > lib/ofp-parse.h | 4 - > lib/ofp-util.c | 115 - > lib/ofp-util.def | 104 - > lib/ofp-util.h | 93 - > ofproto/ofproto-dpif.c | 3 +- > ofproto/ofproto.c | 2 +- > tests/ofp-actions.at | 4 - > tests/ofproto-dpif.at | 8 +- > utilities/ovs-ofctl.c | 2 +- > 29 files changed, 5743 insertions(+), 6132 deletions(-) > create mode 100755 build-aux/extract-ofp-actions > delete mode 100644 lib/ofp-util.def > > (snip) > +/* Parses 'str' as a series of instructions, and appends them to 'ofpacts'. > + * > + * Returns NULL if successful, otherwise a malloc()'d string describing the > + * error. The caller is responsible for freeing the returned string. */ > +static char * WARN_UNUSED_RESULT > +ofpacts_parse__(char *str, struct ofpbuf *ofpacts, > + enum ofputil_protocol *usable_protocols, > + bool allow_instructions) > +{ > + int prev_inst = -1; > + enum ofperr retval; > + char *key, *value; > + bool drop = false; > + char *pos; > + > + pos = str; > + while (ofputil_parse_key_value(&pos, &key, &value)) { > + enum ovs_instruction_type inst = OVSINST_OFPIT11_APPLY_ACTIONS; > + enum ofpact_type type; > + char *error = NULL; > + ofp_port_t port; > + > + if (ofpact_type_from_name(key, &type)) { > + error = ofpact_parse(type, value, ofpacts, usable_protocols); > + inst = ovs_instruction_type_from_ofpact_type(type); > + } else if (!strcasecmp(key, "mod_vlan_vid")) { > + error = parse_set_vlan_vid(value, ofpacts, true); > + } else if (!strcasecmp(key, "mod_vlan_pcp")) { > + error = parse_set_vlan_pcp(value, ofpacts, true); > + } else if (!strcasecmp(key, "set_nw_ttl")) { > + error = parse_SET_IP_TTL(value, ofpacts, usable_protocols); > + } else if (!strcasecmp(key, "pop_vlan")) { > + error = parse_pop_vlan(ofpacts); > + } else if (!strcasecmp(key, "set_tunnel64")) { > + error = parse_set_tunnel(value, ofpacts, > + NXAST_RAW_SET_TUNNEL64); > + } else if (!strcasecmp(key, "bundle_load")) { > + error = parse_bundle_load(value, ofpacts); > + } else if (!strcasecmp(key, "drop")) { > + drop = true; > + } else if (!strcasecmp(key, "apply_actions")) { > + return xstrdup("apply_actions is the default instruction"); > + } else if (ofputil_port_from_string(key, &port)) { > + ofpact_put_OUTPUT(ofpacts)->port = port; > + } else { > + return xasprintf("unknown action %s", key); > + } > + if (error) { > + return error; > + } > + > + if (inst != OVSINST_OFPIT11_APPLY_ACTIONS) { > + if (!allow_instructions) { > + return xasprintf("only actions are allowed here (not " > + "instruction %s)", > + ovs_instruction_name_from_type(inst)); > + } > + if (inst == prev_inst) { > + return xasprintf("instruction %s may be specified only once", > + ovs_instruction_name_from_type(inst)); > + } > + } > + if (prev_inst != -1 && inst < prev_inst) { > + return xasprintf("instruction %s must be specified before %s", > + ovs_instruction_name_from_type(inst), > + ovs_instruction_name_from_type(prev_inst)); > + } > + prev_inst = inst; > + } > + ofpact_pad(ofpacts); > + > + if (drop && ofpbuf_size(ofpacts)) { > + return xstrdup("\"drop\" must not be accompanied by any other action > " > + "or instruction"); > + } > + > + /* XXX > + * > + * If write_metadata is specified as an action AND an instruction, > ofpacts > + * could be invalid. */ Could this be resolved by not allowing the action for OpenFlow versions which support the instruction? > + retval = ofpacts_verify(ofpbuf_data(ofpacts), ofpbuf_size(ofpacts), > + (allow_instructions > + ? (1u << N_OVS_INSTRUCTIONS) - 1 > + : 1u << OVSINST_OFPIT11_APPLY_ACTIONS)); > + if (retval) { > + return xstrdup("Incorrect instruction ordering"); > + } > + > + return NULL; > +} > + (snip) > @@ -2096,53 +1086,59 @@ static char * WARN_UNUSED_RESULT > parse_bucket_str(struct ofputil_bucket *bucket, char *str_, > enum ofputil_protocol *usable_protocols) > { > + char *pos, *key, *value; > struct ofpbuf ofpacts; > - char *pos, *act, *arg; > - int n_actions; > + struct ds actions; > + char *error; > > bucket->weight = 1; > bucket->watch_port = OFPP_ANY; > bucket->watch_group = OFPG11_ANY; > > - pos = str_; > - n_actions = 0; > - ofpbuf_init(&ofpacts, 64); > - while (ofputil_parse_key_value(&pos, &act, &arg)) { > - char *error = NULL; > + ds_init(&actions); > > - if (!strcasecmp(act, "weight")) { > - error = str_to_u16(arg, "weight", &bucket->weight); > - } else if (!strcasecmp(act, "watch_port")) { > - if (!ofputil_port_from_string(arg, &bucket->watch_port) > + pos = str_; > + error = NULL; > + while (ofputil_parse_key_value(&pos, &key, &value)) { > + if (!strcasecmp(key, "weight")) { > + error = str_to_u16(value, "weight", &bucket->weight); > + } else if (!strcasecmp(key, "watch_port")) { > + if (!ofputil_port_from_string(value, &bucket->watch_port) > || (ofp_to_u16(bucket->watch_port) >= ofp_to_u16(OFPP_MAX) > && bucket->watch_port != OFPP_ANY)) { > - error = xasprintf("%s: invalid watch_port", arg); > + error = xasprintf("%s: invalid watch_port", value); > } > - } else if (!strcasecmp(act, "watch_group")) { > - error = str_to_u32(arg, &bucket->watch_group); > + } else if (!strcasecmp(key, "watch_group")) { > + error = str_to_u32(value, &bucket->watch_group); > if (!error && bucket->watch_group > OFPG_MAX) { > error = xasprintf("invalid watch_group id %"PRIu32, > bucket->watch_group); > } > - } else if (!strcasecmp(act, "actions")) { > - if (ofputil_parse_key_value(&arg, &act, &arg)) { > - error = str_to_ofpact__(pos, act, arg, &ofpacts, n_actions, > - usable_protocols); > - n_actions++; > - } > + } else if (!strcasecmp(key, "action") || !strcasecmp(key, > "actions")) { > + ds_put_format(&actions, "%s,", value); > } else { > - error = str_to_ofpact__(pos, act, arg, &ofpacts, n_actions, > - usable_protocols); > - n_actions++; > + ds_put_format(&actions, "%s(%s),", key, value); > } > > if (error) { > - ofpbuf_uninit(&ofpacts); > + ds_destroy(&actions); > return error; > } > } > > - ofpact_pad(&ofpacts); > + if (!actions.length) { > + return xstrdup("bucket must specify actions"); > + } > + ds_chomp(&actions, ','); > + > + ofpbuf_init(&ofpacts, 0); > + error = ofpacts_parse_actions(ds_cstr(&actions), &ofpacts, > + usable_protocols); > + ds_destroy(&actions); > + if (error) { > + ofpbuf_uninit(&ofpacts); > + return error; > + } > bucket->ofpacts = ofpbuf_data(&ofpacts); > bucket->ofpacts_len = ofpbuf_size(&ofpacts); > Should bucket parsing go to ofp-actions.c as well? (snip) > diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c > index 7bf53a4..e17377f 100644 > --- a/ofproto/ofproto-dpif.c > +++ b/ofproto/ofproto-dpif.c > @@ -1246,7 +1246,6 @@ add_internal_flows(struct ofproto_dpif *ofproto) > * (priority=2), recirc=0, actions=resubmit(, 0) > */ > resubmit = ofpact_put_RESUBMIT(&ofpacts); > - resubmit->ofpact.compat = 0; Doesn’t this leave the renamed ‘raw’ member as ‘-1’? Does this matter? > resubmit->in_port = OFPP_IN_PORT; > resubmit->table_id = 0; (snip) _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev