VLOG_DEFINE_THIS_MODULE(ofproto);
-COVERAGE_DEFINE(odp_overflow);
COVERAGE_DEFINE(ofproto_agg_request);
-COVERAGE_DEFINE(ofproto_costly_flags);
-COVERAGE_DEFINE(ofproto_ctlr_action);
COVERAGE_DEFINE(ofproto_error);
-COVERAGE_DEFINE(ofproto_expiration);
-COVERAGE_DEFINE(ofproto_expired);
COVERAGE_DEFINE(ofproto_flows_req);
COVERAGE_DEFINE(ofproto_flush);
-COVERAGE_DEFINE(ofproto_invalidated);
COVERAGE_DEFINE(ofproto_no_packet_in);
-COVERAGE_DEFINE(ofproto_ofp2odp);
-COVERAGE_DEFINE(ofproto_packet_in);
COVERAGE_DEFINE(ofproto_packet_out);
COVERAGE_DEFINE(ofproto_queue_req);
COVERAGE_DEFINE(ofproto_recv_openflow);
COVERAGE_DEFINE(ofproto_reinit_ports);
-COVERAGE_DEFINE(ofproto_unexpected_rule);
COVERAGE_DEFINE(ofproto_uninstallable);
COVERAGE_DEFINE(ofproto_update_port);
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 *);
static size_t n_ofproto_classes;
static size_t allocated_ofproto_classes;
-/* Map from dpif name to struct ofproto, for use by unixctl commands. */
+/* Map from datapath name to struct ofproto, for use by unixctl commands. */
static struct hmap all_ofprotos = HMAP_INITIALIZER(&all_ofprotos);
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
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);
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);
static void
ofproto_destroy__(struct ofproto *ofproto)
{
+ size_t i;
+
connmgr_destroy(ofproto->connmgr);
hmap_remove(&all_ofprotos, &ofproto->hmap_node);
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);
}
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);
}
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.
*
* (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)
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);
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)
{
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'
rule->ofproto->ofproto_class->rule_dealloc(rule);
}
-/* Destroys 'rule' and iterates through all of its facets and revalidates them,
- * destroying any that no longer has a rule (which is probably all of them).
- *
- * 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
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 (or the statistics for one of its facets) appropriately.
- * 'packet' must have at least sizeof(struct ofp_packet_in) bytes of headroom.
+ * statistics appropriately. 'packet' must have at least sizeof(struct
+ * ofp_packet_in) bytes of headroom.
*
* 'packet' doesn't necessarily have to match 'rule'. 'rule' will be credited
* with statistics for 'packet' either way.
return rule->ofproto->ofproto_class->rule_execute(rule, &flow, packet);
}
-/* Remove 'rule' from 'ofproto' and free up the associated memory:
- *
- * - Removes 'rule' from the classifier.
- *
- * - If 'rule' has facets, revalidates them (and possibly uninstalls and
- * destroys them), via rule_destroy().
- */
-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
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);
*
* 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) {
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 * p->n_tables);
- msg = start_ofp_stats_reply(request, sizeof *ots * 2);
+ 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]));
+ }
- /* 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 */
+ p->ofproto_class->get_tables(p, ots);
ofconn_send_reply(ofconn, msg);
return 0;
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)) {
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);
}
}
-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);
}
{
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;
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);
}
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);
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);
+ }
}
}
{
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;
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);
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);
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
{
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;
+ }
}
}
}
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();
}
}
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));
+ }
}
}
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));
}
}
}
ofproto_rule_send_removed(rule, OFPRR_DELETE);
- ofproto_rule_remove(rule);
+ ofproto_rule_destroy(rule);
}
static void
{
assert(reason == OFPRR_HARD_TIMEOUT || reason == OFPRR_IDLE_TIMEOUT);
ofproto_rule_send_removed(rule, reason);
- ofproto_rule_remove(rule);
+ ofproto_rule_destroy(rule);
}
\f
static int
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;
}
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)
{
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)
{
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;
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);