Jarno pointed out that modify_flows__() didn't really need to check every instance of the flow separately. After some further investigation I decided that this was even more of an improvement.
CC: Jarno Rajahalme <jrajaha...@nicira.com> Signed-off-by: Ben Pfaff <b...@nicira.com> --- lib/ofp-actions.c | 23 ++++++++++++++--------- lib/ofp-actions.h | 5 +++-- lib/ofp-parse.c | 5 +++-- lib/ofp-print.c | 3 ++- lib/ofp-util.c | 7 +++++-- lib/ofp-util.h | 4 +++- ofproto/ofproto.c | 50 +++++++++++-------------------------------------- utilities/ovs-ofctl.c | 5 +++-- 8 files changed, 44 insertions(+), 58 deletions(-) diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c index 6fa80a2..65e0437 100644 --- a/lib/ofp-actions.c +++ b/lib/ofp-actions.c @@ -1565,8 +1565,9 @@ ofpact_check_output_port(ofp_port_t port, ofp_port_t max_ports) /* May modify flow->dl_type, caller must restore it. */ static enum ofperr -ofpact_check__(const struct ofpact *a, struct flow *flow, ofp_port_t max_ports, - uint8_t table_id, bool enforce_consistency) +ofpact_check__(const struct ofpact *a, struct flow *flow, + bool enforce_consistency, ofp_port_t max_ports, + uint8_t table_id, uint8_t n_tables) { const struct ofpact_enqueue *enqueue; @@ -1700,7 +1701,7 @@ ofpact_check__(const struct ofpact *a, struct flow *flow, ofp_port_t max_ports, case OFPACT_WRITE_ACTIONS: { struct ofpact_nest *on = ofpact_get_WRITE_ACTIONS(a); return ofpacts_check(on->actions, ofpact_nest_get_action_len(on), - flow, max_ports, table_id, false); + flow, false, max_ports, table_id, n_tables); } case OFPACT_WRITE_METADATA: @@ -1714,11 +1715,14 @@ ofpact_check__(const struct ofpact *a, struct flow *flow, ofp_port_t max_ports, return 0; } - case OFPACT_GOTO_TABLE: - if (ofpact_get_GOTO_TABLE(a)->table_id <= table_id) { + case OFPACT_GOTO_TABLE: { + uint8_t goto_table = ofpact_get_GOTO_TABLE(a)->table_id; + if ((table_id != 255 && goto_table <= table_id) + || (n_tables != 255 && goto_table >= n_tables)) { return OFPERR_OFPBRC_BAD_TABLE_ID; } return 0; + } case OFPACT_GROUP: return 0; @@ -1741,16 +1745,17 @@ ofpact_check__(const struct ofpact *a, struct flow *flow, ofp_port_t max_ports, * May temporarily modify 'flow', but restores the changes before returning. */ enum ofperr ofpacts_check(const struct ofpact ofpacts[], size_t ofpacts_len, - struct flow *flow, ofp_port_t max_ports, uint8_t table_id, - bool enforce_consistency) + struct flow *flow, bool enforce_consistency, + ofp_port_t max_ports, + uint8_t table_id, uint8_t n_tables) { const struct ofpact *a; ovs_be16 dl_type = flow->dl_type; enum ofperr error = 0; OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) { - error = ofpact_check__(a, flow, max_ports, table_id, - enforce_consistency); + error = ofpact_check__(a, flow, enforce_consistency, + max_ports, table_id, n_tables); if (error) { break; } diff --git a/lib/ofp-actions.h b/lib/ofp-actions.h index dd8f35f..2312121 100644 --- a/lib/ofp-actions.h +++ b/lib/ofp-actions.h @@ -564,8 +564,9 @@ enum ofperr ofpacts_pull_openflow11_instructions(struct ofpbuf *openflow, unsigned int instructions_len, struct ofpbuf *ofpacts); enum ofperr ofpacts_check(const struct ofpact[], size_t ofpacts_len, - struct flow *, ofp_port_t max_ports, - uint8_t table_id, bool enforce_consistency); + struct flow *, bool enforce_consistency, + ofp_port_t max_ports, + uint8_t table_id, uint8_t n_tables); enum ofperr ofpacts_verify(const struct ofpact ofpacts[], size_t ofpacts_len); enum ofperr ofpact_check_output_port(ofp_port_t port, ofp_port_t max_ports); diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c index 757b971..0abd068 100644 --- a/lib/ofp-parse.c +++ b/lib/ofp-parse.c @@ -1361,7 +1361,7 @@ parse_ofp_str__(struct ofputil_flow_mod *fm, int command, char *string, enum ofperr err; err = ofpacts_check(ofpacts.data, ofpacts.size, &fm->match.flow, - OFPP_MAX, 0, true); + true, OFPP_MAX, fm->table_id, 255); if (err) { if (!enforce_consistency && err == OFPERR_OFPBAC_MATCH_INCONSISTENT) { @@ -1370,7 +1370,8 @@ parse_ofp_str__(struct ofputil_flow_mod *fm, int command, char *string, /* Try again, allowing for inconsistency. * XXX: As a side effect, logging may be duplicated. */ err = ofpacts_check(ofpacts.data, ofpacts.size, - &fm->match.flow, OFPP_MAX, 0, false); + &fm->match.flow, false, + OFPP_MAX, fm->table_id, 255); } if (err) { error = xasprintf("actions are invalid with specified match " diff --git a/lib/ofp-print.c b/lib/ofp-print.c index 1dc4598..37e1f4f 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -757,7 +757,8 @@ ofp_print_flow_mod(struct ds *s, const struct ofp_header *oh, int verbosity) protocol = ofputil_protocol_set_tid(protocol, true); ofpbuf_init(&ofpacts, 64); - error = ofputil_decode_flow_mod(&fm, oh, protocol, &ofpacts); + error = ofputil_decode_flow_mod(&fm, oh, protocol, &ofpacts, + OFPP_MAX, 255); if (error) { ofpbuf_uninit(&ofpacts); ofp_print_error(s, error); diff --git a/lib/ofp-util.c b/lib/ofp-util.c index e6a9494..e78cac2 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -1484,7 +1484,8 @@ enum ofperr ofputil_decode_flow_mod(struct ofputil_flow_mod *fm, const struct ofp_header *oh, enum ofputil_protocol protocol, - struct ofpbuf *ofpacts) + struct ofpbuf *ofpacts, + ofp_port_t max_port, uint8_t max_table) { ovs_be16 raw_flags; enum ofperr error; @@ -1661,7 +1662,9 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm, : OFPERR_OFPFMFC_TABLE_FULL); } - return 0; + return ofpacts_check(fm->ofpacts, fm->ofpacts_len, &fm->match.flow, + oh->version > OFP10_VERSION, max_port, + fm->table_id, max_table); } static enum ofperr diff --git a/lib/ofp-util.h b/lib/ofp-util.h index a77c301..cf36dce 100644 --- a/lib/ofp-util.h +++ b/lib/ofp-util.h @@ -293,7 +293,9 @@ struct ofputil_flow_mod { enum ofperr ofputil_decode_flow_mod(struct ofputil_flow_mod *, const struct ofp_header *, enum ofputil_protocol, - struct ofpbuf *ofpacts); + struct ofpbuf *ofpacts, + ofp_port_t max_port, + uint8_t max_table); struct ofpbuf *ofputil_encode_flow_mod(const struct ofputil_flow_mod *, enum ofputil_protocol); diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 76baaa4..7888bc9 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -2817,26 +2817,14 @@ reject_slave_controller(struct ofconn *ofconn) } } -/* Checks that the 'ofpacts_len' bytes of actions in 'ofpacts' are appropriate - * for a packet with the prerequisites satisfied by 'flow' in table 'table_id'. - * 'flow' may be temporarily modified, but is restored at return. - */ +/* Checks that, if the 'ofpacts_len' bytes of action in 'ofpacts' use a meter, + * then that meter is one configured in 'ofproto'. */ static enum ofperr -ofproto_check_ofpacts(struct ofproto *ofproto, - const struct ofpact ofpacts[], size_t ofpacts_len, - struct flow *flow, uint8_t table_id, - const struct ofp_header *oh) +ofproto_check_meter(struct ofproto *ofproto, + const struct ofpact ofpacts[], size_t ofpacts_len) { - enum ofperr error; uint32_t mid; - error = ofpacts_check(ofpacts, ofpacts_len, flow, - u16_to_ofp(ofproto->max_ports), table_id, - oh && oh->version > OFP10_VERSION); - if (error) { - return error; - } - mid = ofpacts_get_meter(ofpacts, ofpacts_len); if (mid && get_provider_meter_id(ofproto, mid) == UINT32_MAX) { return OFPERR_OFPMMFC_INVALID_METER; @@ -2890,7 +2878,7 @@ handle_packet_out(struct ofconn *ofconn, const struct ofp_header *oh) /* Verify actions against packet, then send packet if successful. */ in_port_.ofp_port = po.in_port; flow_extract(payload, 0, 0, NULL, &in_port_, &flow); - error = ofproto_check_ofpacts(p, po.ofpacts, po.ofpacts_len, &flow, 0, oh); + error = ofproto_check_meter(p, po.ofpacts, po.ofpacts_len); if (!error) { error = p->ofproto_class->packet_out(p, payload, &flow, po.ofpacts, po.ofpacts_len); @@ -3938,14 +3926,6 @@ add_flow(struct ofproto *ofproto, struct ofconn *ofconn, } } - /* Verify actions. */ - error = ofproto_check_ofpacts(ofproto, fm->ofpacts, fm->ofpacts_len, - &fm->match.flow, table_id, request); - if (error) { - cls_rule_destroy(&cr); - return error; - } - /* Serialize against pending deletion. */ if (is_flow_deletion_pending(ofproto, &cr, table_id)) { cls_rule_destroy(&cr); @@ -4044,19 +4024,6 @@ modify_flows__(struct ofproto *ofproto, struct ofconn *ofconn, enum ofperr error; size_t i; - /* Verify actions before we start to modify any rules, to avoid partial - * flow table modifications. */ - for (i = 0; i < rules->n; i++) { - struct rule *rule = rules->rules[i]; - - error = ofproto_check_ofpacts(ofproto, fm->ofpacts, fm->ofpacts_len, - &fm->match.flow, rule->table_id, - request); - if (error) { - return error; - } - } - type = fm->command == OFPFC_ADD ? OFOPERATION_REPLACE : OFOPERATION_MODIFY; group = ofopgroup_create(ofproto, ofconn, request, fm->buffer_id); error = OFPERR_OFPBRC_EPERM; @@ -4389,7 +4356,12 @@ handle_flow_mod(struct ofconn *ofconn, const struct ofp_header *oh) ofpbuf_use_stub(&ofpacts, ofpacts_stub, sizeof ofpacts_stub); error = ofputil_decode_flow_mod(&fm, oh, ofconn_get_protocol(ofconn), - &ofpacts); + &ofpacts, + u16_to_ofp(ofproto->max_ports), + ofproto->n_tables); + if (!error) { + error = ofproto_check_meter(ofproto, fm.ofpacts, fm.ofpacts_len); + } if (!error) { error = handle_flow_mod__(ofproto, ofconn, &fm, oh); } diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c index da0a54b..96c1b7b 100644 --- a/utilities/ovs-ofctl.c +++ b/utilities/ovs-ofctl.c @@ -3074,8 +3074,9 @@ ofctl_parse_ofp11_instructions(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) /* Verify actions, enforce consistency. */ struct flow flow; memset(&flow, 0, sizeof flow); - error = ofpacts_check(ofpacts.data, ofpacts.size, &flow, OFPP_MAX, - table_id ? atoi(table_id) : 0, true); + error = ofpacts_check(ofpacts.data, ofpacts.size, &flow, + true, OFPP_MAX, + table_id ? atoi(table_id) : 0, 255); } if (error) { printf("bad OF1.1 instructions: %s\n\n", ofperr_get_name(error)); -- 1.7.10.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev