I think you and I might have slightly different models in mind. The model that I'm after at the moment is that the ofproto generic layer checks that a set of actions is valid (which can be done without knowing anything about the hardware) and then the implementation checks that it can actually implement those valid actions.
I agree that the approach you suggest would work too, and that it could work with either the model I have in mind or a model where the implementation has to do all of the validation as well as the implement-ability checking. So, I'm inclined to leave it the way I have it, but I remain open to further discussion. On Mon, Jul 30, 2012 at 02:45:26PM -0700, Ethan Jackson wrote: > Looks good to me. > > I had a thought but I don't feel strongly about it. What if we made a > new hook for ofproto implementations: > > enum ofperr (*validate_actions)(const struct ofpact ofpacts[], size_t > ofpacts_len, const struct flow *, int max_ports). > > In the ofproto-dpif implementation this would simply pass through to > ofpacts_check(), but in other implementations it could reject action > lists which are not implementable by their dpif. This would allow us > to make *packet_out() and *rule_construct() assume that the actions > are both valid and implementable. Then they could return void instead > of an ofperr. Also if we did this, rule_modify_actions() may be > completely unnecessary. The complete_operation() calls could be > pulled into ofproto. > > At any rate, this seems marginally cleaner to me, but you may feel > strongly in the other direction in which case the current approach is > fine. > > Ethan > > On Fri, Jul 20, 2012 at 4:25 PM, Ben Pfaff <b...@nicira.com> wrote: > > Signed-off-by: Ben Pfaff <b...@nicira.com> > > --- > > ofproto/ofproto-dpif.c | 58 > > ++++++++++++++----------------------------- > > ofproto/ofproto-provider.h | 14 ++++------- > > ofproto/ofproto.c | 16 +++++++++--- > > 3 files changed, 36 insertions(+), 52 deletions(-) > > > > diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c > > index f1d2ae0..44cbd17 100644 > > --- a/ofproto/ofproto-dpif.c > > +++ b/ofproto/ofproto-dpif.c > > @@ -4592,13 +4592,6 @@ rule_construct(struct rule *rule_) > > struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto); > > struct rule_dpif *victim; > > uint8_t table_id; > > - enum ofperr error; > > - > > - error = ofpacts_check(rule->up.ofpacts, rule->up.ofpacts_len, > > - &rule->up.cr.flow, ofproto->up.max_ports); > > - if (error) { > > - return error; > > - } > > > > rule->packet_count = 0; > > rule->byte_count = 0; > > @@ -4701,15 +4694,6 @@ static void > > rule_modify_actions(struct rule *rule_) > > { > > struct rule_dpif *rule = rule_dpif_cast(rule_); > > - struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto); > > - enum ofperr error; > > - > > - error = ofpacts_check(rule->up.ofpacts, rule->up.ofpacts_len, > > - &rule->up.cr.flow, ofproto->up.max_ports); > > - if (error) { > > - ofoperation_complete(rule->up.pending, error); > > - return; > > - } > > > > complete_operation(rule); > > } > > @@ -6359,36 +6343,32 @@ packet_out(struct ofproto *ofproto_, struct ofpbuf > > *packet, > > const struct ofpact *ofpacts, size_t ofpacts_len) > > { > > struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_); > > - enum ofperr error; > > + struct odputil_keybuf keybuf; > > + struct dpif_flow_stats stats; > > > > - error = ofpacts_check(ofpacts, ofpacts_len, flow, > > ofproto->up.max_ports); > > - if (!error) { > > - struct odputil_keybuf keybuf; > > - struct dpif_flow_stats stats; > > + struct ofpbuf key; > > > > - struct ofpbuf key; > > + struct action_xlate_ctx ctx; > > + uint64_t odp_actions_stub[1024 / 8]; > > + struct ofpbuf odp_actions; > > > > - struct action_xlate_ctx ctx; > > - uint64_t odp_actions_stub[1024 / 8]; > > - struct ofpbuf odp_actions; > > + ofpbuf_use_stack(&key, &keybuf, sizeof keybuf); > > + odp_flow_key_from_flow(&key, flow); > > > > - ofpbuf_use_stack(&key, &keybuf, sizeof keybuf); > > - odp_flow_key_from_flow(&key, flow); > > + dpif_flow_stats_extract(flow, packet, &stats); > > > > - dpif_flow_stats_extract(flow, packet, &stats); > > + action_xlate_ctx_init(&ctx, ofproto, flow, flow->vlan_tci, NULL, > > + packet_get_tcp_flags(packet, flow), packet); > > + ctx.resubmit_stats = &stats; > > > > - action_xlate_ctx_init(&ctx, ofproto, flow, flow->vlan_tci, NULL, > > - packet_get_tcp_flags(packet, flow), packet); > > - ctx.resubmit_stats = &stats; > > + ofpbuf_use_stub(&odp_actions, > > + odp_actions_stub, sizeof odp_actions_stub); > > + xlate_actions(&ctx, ofpacts, ofpacts_len, &odp_actions); > > + dpif_execute(ofproto->dpif, key.data, key.size, > > + odp_actions.data, odp_actions.size, packet); > > + ofpbuf_uninit(&odp_actions); > > > > - ofpbuf_use_stub(&odp_actions, > > - odp_actions_stub, sizeof odp_actions_stub); > > - xlate_actions(&ctx, ofpacts, ofpacts_len, &odp_actions); > > - dpif_execute(ofproto->dpif, key.data, key.size, > > - odp_actions.data, odp_actions.size, packet); > > - ofpbuf_uninit(&odp_actions); > > - } > > - return error; > > + return 0; > > } > > > > /* NetFlow. */ > > diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h > > index 2f62473..80cd55f 100644 > > --- a/ofproto/ofproto-provider.h > > +++ b/ofproto/ofproto-provider.h > > @@ -803,11 +803,7 @@ struct ofproto_class { > > * registers, then it is an error if 'rule->cr' does not wildcard > > all > > * registers. > > * > > - * - Validate that 'rule->ofpacts' is a sequence of well-formed > > actions > > - * that the datapath can correctly implement. If your ofproto > > - * implementation only implements a subset of the actions that Open > > - * vSwitch understands, then you should implement your own action > > - * validation. > > + * - Validate that the datapath can correctly implement > > 'rule->ofpacts'. > > * > > * - If the rule is valid, update the datapath flow table, adding > > the new > > * rule or replacing the existing one. > > @@ -889,8 +885,8 @@ struct ofproto_class { > > * > > * ->rule_modify_actions() should set the following in motion: > > * > > - * - Validate that the actions now in 'rule' are well-formed OpenFlow > > - * actions that the datapath can correctly implement. > > + * - Validate that the datapath can correctly implement the actions > > now > > + * in 'rule'. > > * > > * - Update the datapath flow table with the new actions. > > * > > @@ -943,8 +939,8 @@ struct ofproto_class { > > * The caller retains ownership of 'packet' and of 'ofpacts', so > > * ->packet_out() should not modify or free them. > > * > > - * This function must validate that it can implement 'ofpacts'. If > > not, > > - * then it should return an OpenFlow error code. > > + * This function must validate that it can correctly implement > > 'ofpacts'. > > + * If not, then it should return an OpenFlow error code. > > * > > * 'flow' reflects the flow information for 'packet'. All of the > > * information in 'flow' is extracted from 'packet', except for > > diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c > > index cbcf0d2..17131ca 100644 > > --- a/ofproto/ofproto.c > > +++ b/ofproto/ofproto.c > > @@ -2138,10 +2138,13 @@ handle_packet_out(struct ofconn *ofconn, const > > struct ofp_packet_out *opo) > > ofpbuf_use_const(payload, po.packet, po.packet_len); > > } > > > > - /* Send out packet. */ > > + /* Verify actions against packet, then send packet if successful. */ > > flow_extract(payload, 0, 0, po.in_port, &flow); > > - error = p->ofproto_class->packet_out(p, payload, &flow, > > - po.ofpacts, po.ofpacts_len); > > + error = ofpacts_check(po.ofpacts, po.ofpacts_len, &flow, p->max_ports); > > + if (!error) { > > + error = p->ofproto_class->packet_out(p, payload, &flow, > > + po.ofpacts, po.ofpacts_len); > > + } > > ofpbuf_delete(payload); > > > > exit_free_ofpacts: > > @@ -3237,7 +3240,12 @@ handle_flow_mod(struct ofconn *ofconn, const struct > > ofp_header *oh) > > * dropped from OpenFlow in the near future. There is no good > > error > > * code, so just state that the flow table is full. */ > > error = OFPERR_OFPFMFC_ALL_TABLES_FULL; > > - } else { > > + } > > + if (!error) { > > + error = ofpacts_check(fm.ofpacts, fm.ofpacts_len, > > + &fm.cr.flow, ofproto->max_ports); > > + } > > + if (!error) { > > error = handle_flow_mod__(ofconn_get_ofproto(ofconn), ofconn, &fm, > > oh); > > } > > if (error) { > > -- > > 1.7.2.5 > > _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev