X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=ofproto%2Fofproto.c;h=beab99ca97b832780b42028e4855114d772c71eb;hb=b2fda3effc787f265b5ad5dfa967ac00627bd075;hp=1c6b8a90f0eab91e075e28a8415be377aa4a2ff8;hpb=806cd5c7cc1adbb4696b96d1429650f2ade5c848;p=sliver-openvswitch.git diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 1c6b8a90f..beab99ca9 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -78,7 +78,6 @@ static void ofproto_flush_flows__(struct ofproto *); static void ofproto_rule_destroy__(struct rule *); static void ofproto_rule_send_removed(struct rule *, uint8_t reason); -static void ofproto_rule_remove(struct rule *); static void handle_openflow(struct ofconn *, struct ofpbuf *); @@ -262,7 +261,8 @@ ofproto_create(const char *datapath_name, const char *datapath_type, ofproto->netdev_monitor = netdev_monitor_create(); hmap_init(&ofproto->ports); shash_init(&ofproto->port_by_name); - classifier_init(&ofproto->cls); + ofproto->tables = NULL; + ofproto->n_tables = 0; ofproto->connmgr = connmgr_create(ofproto, datapath_name, datapath_name); error = ofproto->ofproto_class->construct(ofproto); @@ -272,6 +272,7 @@ ofproto_create(const char *datapath_name, const char *datapath_type, ofproto_destroy__(ofproto); return error; } + assert(ofproto->n_tables > 0); ofproto->datapath_id = pick_datapath_id(ofproto); VLOG_INFO("using datapath ID %016"PRIx64, ofproto->datapath_id); @@ -589,6 +590,8 @@ ofproto_get_snoops(const struct ofproto *ofproto, struct sset *snoops) static void ofproto_destroy__(struct ofproto *ofproto) { + size_t i; + connmgr_destroy(ofproto->connmgr); hmap_remove(&all_ofprotos, &ofproto->hmap_node); @@ -601,7 +604,11 @@ ofproto_destroy__(struct ofproto *ofproto) netdev_monitor_destroy(ofproto->netdev_monitor); hmap_destroy(&ofproto->ports); shash_destroy(&ofproto->port_by_name); - classifier_destroy(&ofproto->cls); + + for (i = 0; i < ofproto->n_tables; i++) { + classifier_destroy(&ofproto->tables[i]); + } + free(ofproto->tables); ofproto->ofproto_class->dealloc(ofproto); } @@ -617,7 +624,6 @@ ofproto_destroy(struct ofproto *p) ofproto_flush_flows__(p); HMAP_FOR_EACH_SAFE (ofport, next_ofport, hmap_node, &p->ports) { - hmap_remove(&p->ports, &ofport->hmap_node); ofport_destroy(ofport); } @@ -864,7 +870,7 @@ ofproto_port_del(struct ofproto *ofproto, uint16_t ofp_port) return error; } -/* Adds a flow to the OpenFlow flow table in 'p' that matches 'cls_rule' and +/* Adds a flow to OpenFlow flow table 0 in 'p' that matches 'cls_rule' and * performs the 'n_actions' actions in 'actions'. The new flow will not * timeout. * @@ -872,7 +878,9 @@ ofproto_port_del(struct ofproto *ofproto, uint16_t ofp_port) * (0...65535, inclusive) then the flow will be visible to OpenFlow * controllers; otherwise, it will be hidden. * - * The caller retains ownership of 'cls_rule' and 'actions'. */ + * The caller retains ownership of 'cls_rule' and 'actions'. + * + * This is a helper function for in-band control and fail-open. */ void ofproto_add_flow(struct ofproto *p, const struct cls_rule *cls_rule, const union ofp_action *actions, size_t n_actions) @@ -881,23 +889,24 @@ ofproto_add_flow(struct ofproto *p, const struct cls_rule *cls_rule, rule_create(p, cls_rule, actions, n_actions, 0, 0, 0, false, &rule); } +/* Searches for a rule with matching criteria exactly equal to 'target' in + * ofproto's table 0 and, if it finds one, deletes it. + * + * This is a helper function for in-band control and fail-open. */ void ofproto_delete_flow(struct ofproto *ofproto, const struct cls_rule *target) { struct rule *rule; - rule = rule_from_cls_rule(classifier_find_rule_exactly(&ofproto->cls, - target)); - if (rule) { - ofproto_rule_remove(rule); - } + rule = rule_from_cls_rule(classifier_find_rule_exactly( + &ofproto->tables[0], target)); + ofproto_rule_destroy(rule); } static void ofproto_flush_flows__(struct ofproto *ofproto) { - struct rule *rule, *next_rule; - struct cls_cursor cursor; + size_t i; COVERAGE_INC(ofproto_flush); @@ -905,12 +914,19 @@ ofproto_flush_flows__(struct ofproto *ofproto) ofproto->ofproto_class->flush(ofproto); } - cls_cursor_init(&cursor, &ofproto->cls, NULL); - CLS_CURSOR_FOR_EACH_SAFE (rule, next_rule, cr, &cursor) { - ofproto_rule_remove(rule); + for (i = 0; i < ofproto->n_tables; i++) { + struct rule *rule, *next_rule; + struct cls_cursor cursor; + + cls_cursor_init(&cursor, &ofproto->tables[i], NULL); + CLS_CURSOR_FOR_EACH_SAFE (rule, next_rule, cr, &cursor) { + ofproto_rule_destroy(rule); + } } } +/* Deletes all of the flows from all of ofproto's flow tables, then + * reintroduces rules required by in-band control and fail open. */ void ofproto_flush_flows(struct ofproto *ofproto) { @@ -1153,21 +1169,25 @@ update_port(struct ofproto *ofproto, const char *name) if (netdev) { port = ofproto_get_port(ofproto, ofproto_port.ofp_port); if (port && !strcmp(netdev_get_name(port->netdev), name)) { + struct netdev *old_netdev = port->netdev; + /* 'name' hasn't changed location. Any properties changed? */ if (!ofport_equal(&port->opp, &opp)) { ofport_modified(port, &opp); } - /* Install the newly opened netdev in case it has changed. */ + /* Install the newly opened netdev in case it has changed. + * Don't close the old netdev yet in case port_modified has to + * remove a retained reference to it.*/ netdev_monitor_remove(ofproto->netdev_monitor, port->netdev); netdev_monitor_add(ofproto->netdev_monitor, netdev); - - netdev_close(port->netdev); port->netdev = netdev; if (port->ofproto->ofproto_class->port_modified) { port->ofproto->ofproto_class->port_modified(port); } + + netdev_close(old_netdev); } else { /* If 'port' is nonnull then its name differs from 'name' and thus * we should delete it. If we think there's a port named 'name' @@ -1269,14 +1289,14 @@ ofproto_rule_destroy__(struct rule *rule) rule->ofproto->ofproto_class->rule_dealloc(rule); } -/* Destroys 'rule' and removes it from the datapath. - * - * The caller must have already removed 'rule' from the classifier. */ +/* Destroys 'rule' and removes it from the flow table and the datapath. */ void ofproto_rule_destroy(struct rule *rule) { - rule->ofproto->ofproto_class->rule_destruct(rule); - ofproto_rule_destroy__(rule); + if (rule) { + rule->ofproto->ofproto_class->rule_destruct(rule); + ofproto_rule_destroy__(rule); + } } /* Returns true if 'rule' has an OpenFlow OFPAT_OUTPUT or OFPAT_ENQUEUE action @@ -1300,12 +1320,6 @@ rule_has_out_port(const struct rule *rule, ovs_be16 out_port) return false; } -struct rule * -ofproto_rule_lookup(struct ofproto *ofproto, const struct flow *flow) -{ - return rule_from_cls_rule(classifier_lookup(&ofproto->cls, flow)); -} - /* Executes the actions indicated by 'rule' on 'packet' and credits 'rule''s * statistics appropriately. 'packet' must have at least sizeof(struct * ofp_packet_in) bytes of headroom. @@ -1325,15 +1339,6 @@ rule_execute(struct rule *rule, uint16_t in_port, struct ofpbuf *packet) return rule->ofproto->ofproto_class->rule_execute(rule, &flow, packet); } -/* Removes 'rule' from 'ofproto' and frees up the associated memory. Removes - * 'rule' from the classifier. */ -void -ofproto_rule_remove(struct rule *rule) -{ - rule->ofproto->ofproto_class->rule_remove(rule); - ofproto_rule_destroy(rule); -} - /* Returns true if 'rule' should be hidden from the controller. * * Rules with priority higher than UINT16_MAX are set up by ofproto itself @@ -1370,25 +1375,22 @@ handle_features_request(struct ofconn *ofconn, const struct ofp_header *oh) struct ofp_switch_features *osf; struct ofpbuf *buf; struct ofport *port; + bool arp_match_ip; + uint32_t actions; + + ofproto->ofproto_class->get_features(ofproto, &arp_match_ip, &actions); + assert(actions & (1 << OFPAT_OUTPUT)); /* sanity check */ osf = make_openflow_xid(sizeof *osf, OFPT_FEATURES_REPLY, oh->xid, &buf); osf->datapath_id = htonll(ofproto->datapath_id); osf->n_buffers = htonl(pktbuf_capacity()); - osf->n_tables = 2; + osf->n_tables = ofproto->n_tables; osf->capabilities = htonl(OFPC_FLOW_STATS | OFPC_TABLE_STATS | - OFPC_PORT_STATS | OFPC_ARP_MATCH_IP); - osf->actions = htonl((1u << OFPAT_OUTPUT) | - (1u << OFPAT_SET_VLAN_VID) | - (1u << OFPAT_SET_VLAN_PCP) | - (1u << OFPAT_STRIP_VLAN) | - (1u << OFPAT_SET_DL_SRC) | - (1u << OFPAT_SET_DL_DST) | - (1u << OFPAT_SET_NW_SRC) | - (1u << OFPAT_SET_NW_DST) | - (1u << OFPAT_SET_NW_TOS) | - (1u << OFPAT_SET_TP_SRC) | - (1u << OFPAT_SET_TP_DST) | - (1u << OFPAT_ENQUEUE)); + OFPC_PORT_STATS); + if (arp_match_ip) { + osf->capabilities |= htonl(OFPC_ARP_MATCH_IP); + } + osf->actions = htonl(actions); HMAP_FOR_EACH (port, hmap_node, &ofproto->ports) { ofpbuf_put(buf, &port->opp, sizeof port->opp); @@ -1453,7 +1455,7 @@ handle_set_config(struct ofconn *ofconn, const struct ofp_switch_config *osc) * * The log message mentions 'msg_type'. */ static int -reject_slave_controller(struct ofconn *ofconn, const const char *msg_type) +reject_slave_controller(struct ofconn *ofconn, const char *msg_type) { if (ofconn_get_type(ofconn) == OFCONN_PRIMARY && ofconn_get_role(ofconn) == NX_ROLE_SLAVE) { @@ -1669,19 +1671,20 @@ handle_table_stats_request(struct ofconn *ofconn, struct ofproto *p = ofconn_get_ofproto(ofconn); struct ofp_table_stats *ots; struct ofpbuf *msg; + size_t i; - msg = start_ofp_stats_reply(request, sizeof *ots * 2); + msg = start_ofp_stats_reply(request, sizeof *ots * p->n_tables); - /* Classifier table. */ - ots = append_ofp_stats_reply(sizeof *ots, ofconn, &msg); - memset(ots, 0, sizeof *ots); - strcpy(ots->name, "classifier"); - ots->wildcards = (ofconn_get_flow_format(ofconn) == NXFF_OPENFLOW10 - ? htonl(OFPFW_ALL) : htonl(OVSFW_ALL)); - ots->max_entries = htonl(1024 * 1024); /* An arbitrary big number. */ - ots->active_count = htonl(classifier_count(&p->cls)); - put_32aligned_be64(&ots->lookup_count, htonll(0)); /* XXX */ - put_32aligned_be64(&ots->matched_count, htonll(0)); /* XXX */ + ots = ofpbuf_put_zeros(msg, sizeof *ots * p->n_tables); + for (i = 0; i < p->n_tables; i++) { + ots[i].table_id = i; + sprintf(ots[i].name, "table%d", i); + ots[i].wildcards = htonl(OFPFW_ALL); + ots[i].max_entries = htonl(1000000); /* An arbitrary big number. */ + ots[i].active_count = htonl(classifier_count(&p->tables[i])); + } + + p->ofproto_class->get_tables(p, ots); ofconn_send_reply(ofconn, msg); return 0; @@ -1766,7 +1769,6 @@ put_ofp_flow_stats(struct ofconn *ofconn, struct rule *rule, struct ofproto *ofproto = ofconn_get_ofproto(ofconn); struct ofp_flow_stats *ofs; uint64_t packet_count, byte_count; - ovs_be64 cookie; size_t act_len, len; if (rule_is_hidden(rule) || !rule_has_out_port(rule, out_port)) { @@ -1780,11 +1782,10 @@ put_ofp_flow_stats(struct ofconn *ofconn, struct rule *rule, ofs = append_ofp_stats_reply(len, ofconn, replyp); ofs->length = htons(len); - ofs->table_id = 0; + ofs->table_id = rule->table_id; ofs->pad = 0; - ofputil_cls_rule_to_match(&rule->cr, ofconn_get_flow_format(ofconn), - &ofs->match, rule->flow_cookie, &cookie); - put_32aligned_be64(&ofs->cookie, cookie); + ofputil_cls_rule_to_match(&rule->cr, &ofs->match); + put_32aligned_be64(&ofs->cookie, rule->flow_cookie); calc_flow_duration(rule->created, &ofs->duration_sec, &ofs->duration_nsec); ofs->priority = htons(rule->cr.priority); ofs->idle_timeout = htons(rule->idle_timeout); @@ -1797,38 +1798,68 @@ put_ofp_flow_stats(struct ofconn *ofconn, struct rule *rule, } } -static bool -is_valid_table(uint8_t table_id) +static struct classifier * +first_matching_table(struct ofproto *ofproto, uint8_t table_id) { - if (table_id == 0 || table_id == 0xff) { - return true; + if (table_id == 0xff) { + return &ofproto->tables[0]; + } else if (table_id < ofproto->n_tables) { + return &ofproto->tables[table_id]; } else { /* It would probably be better to reply with an error but there doesn't * seem to be any appropriate value, so that might just be * confusing. */ VLOG_WARN_RL(&rl, "controller asked for invalid table %"PRIu8, table_id); - return false; + return NULL; } } +static struct classifier * +next_matching_table(struct ofproto *ofproto, + struct classifier *cls, uint8_t table_id) +{ + return (table_id == 0xff && cls != &ofproto->tables[ofproto->n_tables - 1] + ? cls + 1 + : NULL); +} + +/* Assigns CLS to each classifier table, in turn, that matches TABLE_ID in + * OFPROTO: + * + * - If TABLE_ID is 0xff, this iterates over every classifier table in + * OFPROTO. + * + * - If TABLE_ID is the number of a table in OFPROTO, then the loop iterates + * only once, for that table. + * + * - Otherwise, TABLE_ID isn't valid for OFPROTO, so ofproto logs a warning + * and does not enter the loop at all. + * + * All parameters are evaluated multiple times. + */ +#define FOR_EACH_MATCHING_TABLE(CLS, TABLE_ID, OFPROTO) \ + for ((CLS) = first_matching_table(OFPROTO, TABLE_ID); \ + (CLS) != NULL; \ + (CLS) = next_matching_table(OFPROTO, CLS, TABLE_ID)) + static int handle_flow_stats_request(struct ofconn *ofconn, const struct ofp_header *oh) { const struct ofp_flow_stats_request *fsr = ofputil_stats_body(oh); struct ofproto *ofproto = ofconn_get_ofproto(ofconn); + struct classifier *cls; + struct cls_rule target; struct ofpbuf *reply; COVERAGE_INC(ofproto_flows_req); reply = start_ofp_stats_reply(oh, 1024); - if (is_valid_table(fsr->table_id)) { + ofputil_cls_rule_from_match(&fsr->match, 0, &target); + FOR_EACH_MATCHING_TABLE (cls, fsr->table_id, ofproto) { struct cls_cursor cursor; - struct cls_rule target; struct rule *rule; - ofputil_cls_rule_from_match(&fsr->match, 0, NXFF_OPENFLOW10, 0, - &target); - cls_cursor_init(&cursor, &ofproto->cls, &target); + cls_cursor_init(&cursor, cls, &target); CLS_CURSOR_FOR_EACH (rule, cr, &cursor) { put_ofp_flow_stats(ofconn, rule, fsr->out_port, &reply); } @@ -1883,6 +1914,7 @@ handle_nxst_flow(struct ofconn *ofconn, const struct ofp_header *oh) { struct ofproto *ofproto = ofconn_get_ofproto(ofconn); struct nx_flow_stats_request *nfsr; + struct classifier *cls; struct cls_rule target; struct ofpbuf *reply; struct ofpbuf b; @@ -1902,11 +1934,11 @@ handle_nxst_flow(struct ofconn *ofconn, const struct ofp_header *oh) COVERAGE_INC(ofproto_flows_req); reply = start_nxstats_reply(&nfsr->nsm, 1024); - if (is_valid_table(nfsr->table_id)) { + FOR_EACH_MATCHING_TABLE (cls, nfsr->table_id, ofproto) { struct cls_cursor cursor; struct rule *rule; - cls_cursor_init(&cursor, &ofproto->cls, &target); + cls_cursor_init(&cursor, cls, &target); CLS_CURSOR_FOR_EACH (rule, cr, &cursor) { put_nx_flow_stats(ofconn, rule, nfsr->out_port, &reply); } @@ -1925,6 +1957,9 @@ flow_stats_ds(struct rule *rule, struct ds *results) rule->ofproto->ofproto_class->rule_get_stats(rule, &packet_count, &byte_count); + if (rule->table_id != 0) { + ds_put_format(results, "table_id=%"PRIu8", ", rule->table_id); + } ds_put_format(results, "duration=%llds, ", (time_msec() - rule->created) / 1000); ds_put_format(results, "priority=%u, ", rule->cr.priority); @@ -1945,12 +1980,16 @@ flow_stats_ds(struct rule *rule, struct ds *results) void ofproto_get_all_flows(struct ofproto *p, struct ds *results) { - struct cls_cursor cursor; - struct rule *rule; + struct classifier *cls; + + for (cls = &p->tables[0]; cls < &p->tables[p->n_tables]; cls++) { + struct cls_cursor cursor; + struct rule *rule; - cls_cursor_init(&cursor, &p->cls, NULL); - CLS_CURSOR_FOR_EACH (rule, cr, &cursor) { - flow_stats_ds(rule, results); + cls_cursor_init(&cursor, cls, NULL); + CLS_CURSOR_FOR_EACH (rule, cr, &cursor) { + flow_stats_ds(rule, results); + } } } @@ -1970,15 +2009,16 @@ query_aggregate_stats(struct ofproto *ofproto, struct cls_rule *target, { uint64_t total_packets = 0; uint64_t total_bytes = 0; + struct classifier *cls; int n_flows = 0; COVERAGE_INC(ofproto_agg_request); - if (is_valid_table(table_id)) { + FOR_EACH_MATCHING_TABLE (cls, table_id, ofproto) { struct cls_cursor cursor; struct rule *rule; - cls_cursor_init(&cursor, &ofproto->cls, target); + cls_cursor_init(&cursor, cls, target); CLS_CURSOR_FOR_EACH (rule, cr, &cursor) { if (!rule_is_hidden(rule) && rule_has_out_port(rule, out_port)) { uint64_t packet_count; @@ -2010,8 +2050,7 @@ handle_aggregate_stats_request(struct ofconn *ofconn, struct cls_rule target; struct ofpbuf *msg; - ofputil_cls_rule_from_match(&request->match, 0, NXFF_OPENFLOW10, 0, - &target); + ofputil_cls_rule_from_match(&request->match, 0, &target); msg = start_ofp_stats_reply(oh, sizeof *reply); reply = append_ofp_stats_reply(sizeof *reply, ofconn, &msg); @@ -2162,9 +2201,14 @@ add_flow(struct ofconn *ofconn, struct flow_mod *fm) int buf_err; int error; - if (fm->flags & OFPFF_CHECK_OVERLAP - && classifier_rule_overlaps(&p->cls, &fm->cr)) { - return ofp_mkerr(OFPET_FLOW_MOD_FAILED, OFPFMFC_OVERLAP); + if (fm->flags & OFPFF_CHECK_OVERLAP) { + struct classifier *cls; + + FOR_EACH_MATCHING_TABLE (cls, fm->table_id, p) { + if (classifier_rule_overlaps(cls, &fm->cr)) { + return ofp_mkerr(OFPET_FLOW_MOD_FAILED, OFPFMFC_OVERLAP); + } + } } buf_err = ofconn_pktbuf_retrieve(ofconn, fm->buffer_id, &packet, &in_port); @@ -2183,10 +2227,35 @@ add_flow(struct ofconn *ofconn, struct flow_mod *fm) return buf_err; } -static struct rule * -find_flow_strict(struct ofproto *p, const struct flow_mod *fm) +/* Searches 'p' for an exact match for 'fm', in the table or tables indicated + * by fm->table_id. Returns 0 if no match was found, 1 if exactly one match + * was found, 2 if more than one match was found. If exactly one match is + * found, sets '*rulep' to the match, otherwise to NULL. + * + * This implements the rules for "strict" matching explained in the comment on + * struct nxt_flow_mod_table_id in nicira-ext.h. + * + * Ignores hidden rules. */ +static int +find_flow_strict(struct ofproto *p, const struct flow_mod *fm, + struct rule **rulep) { - return rule_from_cls_rule(classifier_find_rule_exactly(&p->cls, &fm->cr)); + struct classifier *cls; + + *rulep = NULL; + FOR_EACH_MATCHING_TABLE (cls, fm->table_id, p) { + struct rule *rule; + + rule = rule_from_cls_rule(classifier_find_rule_exactly(cls, &fm->cr)); + if (rule && !rule_is_hidden(rule)) { + if (*rulep) { + *rulep = NULL; + return 2; + } + *rulep = rule; + } + } + return *rulep != NULL; } static int @@ -2229,19 +2298,23 @@ modify_flows_loose(struct ofconn *ofconn, struct flow_mod *fm) { struct ofproto *p = ofconn_get_ofproto(ofconn); struct rule *match = NULL; - struct cls_cursor cursor; - struct rule *rule; + struct classifier *cls; int error; error = 0; - cls_cursor_init(&cursor, &p->cls, &fm->cr); - CLS_CURSOR_FOR_EACH (rule, cr, &cursor) { - if (!rule_is_hidden(rule)) { - int retval = modify_flow(fm, rule); - if (!retval) { - match = rule; - } else { - error = retval; + FOR_EACH_MATCHING_TABLE (cls, fm->table_id, p) { + struct cls_cursor cursor; + struct rule *rule; + + cls_cursor_init(&cursor, cls, &fm->cr); + CLS_CURSOR_FOR_EACH (rule, cr, &cursor) { + if (!rule_is_hidden(rule)) { + int retval = modify_flow(fm, rule); + if (!retval) { + match = rule; + } else { + error = retval; + } } } } @@ -2268,15 +2341,25 @@ static int modify_flow_strict(struct ofconn *ofconn, struct flow_mod *fm) { struct ofproto *p = ofconn_get_ofproto(ofconn); - struct rule *rule = find_flow_strict(p, fm); - if (rule && !rule_is_hidden(rule)) { - int error = modify_flow(fm, rule); + struct rule *rule; + int error; + + switch (find_flow_strict(p, fm, &rule)) { + case 0: + return add_flow(ofconn, fm); + + case 1: + error = modify_flow(fm, rule); if (!error) { error = send_buffered_packet(ofconn, rule, fm->buffer_id); } return error; - } else { - return add_flow(ofconn, fm); + + case 2: + return 0; + + default: + NOT_REACHED(); } } @@ -2321,12 +2404,16 @@ static void delete_flow(struct rule *, ovs_be16 out_port); static void delete_flows_loose(struct ofproto *p, const struct flow_mod *fm) { - struct rule *rule, *next_rule; - struct cls_cursor cursor; + struct classifier *cls; - cls_cursor_init(&cursor, &p->cls, &fm->cr); - CLS_CURSOR_FOR_EACH_SAFE (rule, next_rule, cr, &cursor) { - delete_flow(rule, htons(fm->out_port)); + FOR_EACH_MATCHING_TABLE (cls, fm->table_id, p) { + struct rule *rule, *next_rule; + struct cls_cursor cursor; + + cls_cursor_init(&cursor, cls, &fm->cr); + CLS_CURSOR_FOR_EACH_SAFE (rule, next_rule, cr, &cursor) { + delete_flow(rule, htons(fm->out_port)); + } } } @@ -2334,8 +2421,8 @@ delete_flows_loose(struct ofproto *p, const struct flow_mod *fm) static void delete_flow_strict(struct ofproto *p, struct flow_mod *fm) { - struct rule *rule = find_flow_strict(p, fm); - if (rule) { + struct rule *rule; + if (find_flow_strict(p, fm, &rule) == 1) { delete_flow(rule, htons(fm->out_port)); } } @@ -2360,7 +2447,7 @@ delete_flow(struct rule *rule, ovs_be16 out_port) } ofproto_rule_send_removed(rule, OFPRR_DELETE); - ofproto_rule_remove(rule); + ofproto_rule_destroy(rule); } static void @@ -2394,7 +2481,7 @@ ofproto_rule_expire(struct rule *rule, uint8_t reason) { assert(reason == OFPRR_HARD_TIMEOUT || reason == OFPRR_IDLE_TIMEOUT); ofproto_rule_send_removed(rule, reason); - ofproto_rule_remove(rule); + ofproto_rule_destroy(rule); } static int @@ -2409,7 +2496,8 @@ handle_flow_mod(struct ofconn *ofconn, const struct ofp_header *oh) return error; } - error = ofputil_decode_flow_mod(&fm, oh, ofconn_get_flow_format(ofconn)); + error = ofputil_decode_flow_mod(&fm, oh, + ofconn_get_flow_mod_table_id(ofconn)); if (error) { return error; } @@ -2441,23 +2529,14 @@ handle_flow_mod(struct ofconn *ofconn, const struct ofp_header *oh) return 0; default: + if (fm.command > 0xff) { + VLOG_WARN_RL(&rl, "flow_mod has explicit table_id but " + "flow_mod_table_id extension is not enabled"); + } return ofp_mkerr(OFPET_FLOW_MOD_FAILED, OFPFMFC_BAD_COMMAND); } } -static int -handle_tun_id_from_cookie(struct ofconn *ofconn, const struct ofp_header *oh) -{ - const struct nxt_tun_id_cookie *msg - = (const struct nxt_tun_id_cookie *) oh; - enum nx_flow_format flow_format; - - flow_format = msg->set ? NXFF_TUN_ID_FROM_COOKIE : NXFF_OPENFLOW10; - ofconn_set_flow_format(ofconn, flow_format); - - return 0; -} - static int handle_role_request(struct ofconn *ofconn, const struct ofp_header *oh) { @@ -2489,6 +2568,17 @@ handle_role_request(struct ofconn *ofconn, const struct ofp_header *oh) return 0; } +static int +handle_nxt_flow_mod_table_id(struct ofconn *ofconn, + const struct ofp_header *oh) +{ + const struct nxt_flow_mod_table_id *msg + = (const struct nxt_flow_mod_table_id *) oh; + + ofconn_set_flow_mod_table_id(ofconn, msg->set != 0); + return 0; +} + static int handle_nxt_set_flow_format(struct ofconn *ofconn, const struct ofp_header *oh) { @@ -2498,7 +2588,6 @@ handle_nxt_set_flow_format(struct ofconn *ofconn, const struct ofp_header *oh) format = ntohl(msg->format); if (format == NXFF_OPENFLOW10 - || format == NXFF_TUN_ID_FROM_COOKIE || format == NXFF_NXM) { ofconn_set_flow_format(ofconn, format); return 0; @@ -2563,12 +2652,12 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg) return 0; /* Nicira extension requests. */ - case OFPUTIL_NXT_TUN_ID_FROM_COOKIE: - return handle_tun_id_from_cookie(ofconn, oh); - case OFPUTIL_NXT_ROLE_REQUEST: return handle_role_request(ofconn, oh); + case OFPUTIL_NXT_FLOW_MOD_TABLE_ID: + return handle_nxt_flow_mod_table_id(ofconn, oh); + case OFPUTIL_NXT_SET_FLOW_FORMAT: return handle_nxt_set_flow_format(ofconn, oh);