ofproto: Avoid wild write removing OFPP_LOCAL port in dealloc_ofp_port().
[sliver-openvswitch.git] / ofproto / ofproto.c
index f95d6ef..b6cd082 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
  * Copyright (c) 2010 Jean Tourrilhes - HP-Labs.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -407,11 +407,11 @@ ofproto_create(const char *datapath_name, const char *datapath_type,
                                         OFPROTO_FLOW_EVICTION_THRESHOLD_DEFAULT);
     ofproto->forward_bpdu = false;
     ofproto->fallback_dpid = pick_fallback_dpid();
-    ofproto->mfr_desc = xstrdup(DEFAULT_MFR_DESC);
-    ofproto->hw_desc = xstrdup(DEFAULT_HW_DESC);
-    ofproto->sw_desc = xstrdup(DEFAULT_SW_DESC);
-    ofproto->serial_desc = xstrdup(DEFAULT_SERIAL_DESC);
-    ofproto->dp_desc = xstrdup(DEFAULT_DP_DESC);
+    ofproto->mfr_desc = NULL;
+    ofproto->hw_desc = NULL;
+    ofproto->sw_desc = NULL;
+    ofproto->serial_desc = NULL;
+    ofproto->dp_desc = NULL;
     ofproto->frag_handling = OFPC_FRAG_NORMAL;
     hmap_init(&ofproto->ports);
     shash_init(&ofproto->port_by_name);
@@ -446,12 +446,12 @@ ofproto_create(const char *datapath_name, const char *datapath_type,
     bitmap_set1(ofproto->ofp_port_ids, 0);
 
     /* Check that hidden tables, if any, are at the end. */
-    assert(ofproto->n_tables);
+    ovs_assert(ofproto->n_tables);
     for (i = 0; i + 1 < ofproto->n_tables; i++) {
         enum oftable_flags flags = ofproto->tables[i].flags;
         enum oftable_flags next_flags = ofproto->tables[i + 1].flags;
 
-        assert(!(flags & OFTABLE_HIDDEN) || next_flags & OFTABLE_HIDDEN);
+        ovs_assert(!(flags & OFTABLE_HIDDEN) || next_flags & OFTABLE_HIDDEN);
     }
 
     ofproto->datapath_id = pick_datapath_id(ofproto);
@@ -469,8 +469,8 @@ ofproto_init_tables(struct ofproto *ofproto, int n_tables)
 {
     struct oftable *table;
 
-    assert(!ofproto->n_tables);
-    assert(n_tables >= 1 && n_tables <= 255);
+    ovs_assert(!ofproto->n_tables);
+    ovs_assert(n_tables >= 1 && n_tables <= 255);
 
     ofproto->n_tables = n_tables;
     ofproto->tables = xmalloc(n_tables * sizeof *ofproto->tables);
@@ -493,7 +493,7 @@ ofproto_init_tables(struct ofproto *ofproto, int n_tables)
 void
 ofproto_init_max_ports(struct ofproto *ofproto, uint16_t max_ports)
 {
-    assert(max_ports <= OFPP_MAX);
+    ovs_assert(max_ports <= OFPP_MAX);
     ofproto->max_ports = max_ports;
 }
 
@@ -598,53 +598,10 @@ ofproto_set_mac_table_config(struct ofproto *ofproto, unsigned idle_time,
 }
 
 void
-ofproto_set_desc(struct ofproto *p,
-                 const char *mfr_desc, const char *hw_desc,
-                 const char *sw_desc, const char *serial_desc,
-                 const char *dp_desc)
+ofproto_set_dp_desc(struct ofproto *p, const char *dp_desc)
 {
-    struct ofp_desc_stats *ods;
-
-    if (mfr_desc) {
-        if (strlen(mfr_desc) >= sizeof ods->mfr_desc) {
-            VLOG_WARN("%s: truncating mfr_desc, must be less than %zu bytes",
-                      p->name, sizeof ods->mfr_desc);
-        }
-        free(p->mfr_desc);
-        p->mfr_desc = xstrdup(mfr_desc);
-    }
-    if (hw_desc) {
-        if (strlen(hw_desc) >= sizeof ods->hw_desc) {
-            VLOG_WARN("%s: truncating hw_desc, must be less than %zu bytes",
-                      p->name, sizeof ods->hw_desc);
-        }
-        free(p->hw_desc);
-        p->hw_desc = xstrdup(hw_desc);
-    }
-    if (sw_desc) {
-        if (strlen(sw_desc) >= sizeof ods->sw_desc) {
-            VLOG_WARN("%s: truncating sw_desc, must be less than %zu bytes",
-                      p->name, sizeof ods->sw_desc);
-        }
-        free(p->sw_desc);
-        p->sw_desc = xstrdup(sw_desc);
-    }
-    if (serial_desc) {
-        if (strlen(serial_desc) >= sizeof ods->serial_num) {
-            VLOG_WARN("%s: truncating serial_desc, must be less than %zu "
-                      "bytes", p->name, sizeof ods->serial_num);
-        }
-        free(p->serial_desc);
-        p->serial_desc = xstrdup(serial_desc);
-    }
-    if (dp_desc) {
-        if (strlen(dp_desc) >= sizeof ods->dp_desc) {
-            VLOG_WARN("%s: truncating dp_desc, must be less than %zu bytes",
-                      p->name, sizeof ods->dp_desc);
-        }
-        free(p->dp_desc);
-        p->dp_desc = xstrdup(dp_desc);
-    }
+    free(p->dp_desc);
+    p->dp_desc = dp_desc ? xstrdup(dp_desc) : NULL;
 }
 
 int
@@ -953,7 +910,7 @@ ofproto_configure_table(struct ofproto *ofproto, int table_id,
 {
     struct oftable *table;
 
-    assert(table_id >= 0 && table_id < ofproto->n_tables);
+    ovs_assert(table_id >= 0 && table_id < ofproto->n_tables);
     table = &ofproto->tables[table_id];
 
     oftable_set_name(table, s->name);
@@ -1035,8 +992,8 @@ ofproto_destroy__(struct ofproto *ofproto)
 {
     struct oftable *table;
 
-    assert(list_is_empty(&ofproto->pending));
-    assert(!ofproto->n_pending);
+    ovs_assert(list_is_empty(&ofproto->pending));
+    ovs_assert(!ofproto->n_pending);
 
     connmgr_destroy(ofproto->connmgr);
 
@@ -1656,38 +1613,30 @@ static uint16_t
 alloc_ofp_port(struct ofproto *ofproto, const char *netdev_name)
 {
     uint16_t ofp_port;
+    uint16_t end_port_no = ofproto->alloc_port_no;
 
     ofp_port = simap_get(&ofproto->ofp_requests, netdev_name);
     ofp_port = ofp_port ? ofp_port : OFPP_NONE;
 
     if (ofp_port >= ofproto->max_ports
             || bitmap_is_set(ofproto->ofp_port_ids, ofp_port)) {
-        bool retry = ofproto->alloc_port_no ? true : false;
-
         /* Search for a free OpenFlow port number.  We try not to
          * immediately reuse them to prevent problems due to old
          * flows. */
-        while (ofp_port >= ofproto->max_ports) {
-            for (ofproto->alloc_port_no++;
-                 ofproto->alloc_port_no < ofproto->max_ports;
-                 ofproto->alloc_port_no++) {
-                if (!bitmap_is_set(ofproto->ofp_port_ids,
-                                   ofproto->alloc_port_no)) {
-                    ofp_port = ofproto->alloc_port_no;
-                    break;
-                }
+        for (;;) {
+            if (++ofproto->alloc_port_no >= ofproto->max_ports) {
+                ofproto->alloc_port_no = 0;
             }
-            if (ofproto->alloc_port_no >= ofproto->max_ports) {
-                if (retry) {
-                    ofproto->alloc_port_no = 0;
-                    retry = false;
-                } else {
-                    return OFPP_NONE;
-                }
+            if (!bitmap_is_set(ofproto->ofp_port_ids,
+                               ofproto->alloc_port_no)) {
+                ofp_port = ofproto->alloc_port_no;
+                break;
+            }
+            if (ofproto->alloc_port_no == end_port_no) {
+                return OFPP_NONE;
             }
         }
     }
-
     bitmap_set1(ofproto->ofp_port_ids, ofp_port);
     return ofp_port;
 }
@@ -1695,7 +1644,9 @@ alloc_ofp_port(struct ofproto *ofproto, const char *netdev_name)
 static void
 dealloc_ofp_port(const struct ofproto *ofproto, uint16_t ofp_port)
 {
-    bitmap_set0(ofproto->ofp_port_ids, ofp_port);
+    if (ofp_port < ofproto->max_ports) {
+        bitmap_set0(ofproto->ofp_port_ids, ofp_port);
+    }
 }
 
 /* Opens and returns a netdev for 'ofproto_port' in 'ofproto', or a null
@@ -2018,11 +1969,12 @@ init_ports(struct ofproto *p)
     }
 
     SHASH_FOR_EACH_SAFE(node, next, &init_ofp_ports) {
-        const struct iface_hint *iface_hint = node->data;
+        struct iface_hint *iface_hint = node->data;
 
         if (!strcmp(iface_hint->br_name, p->name)) {
             free(iface_hint->br_name);
             free(iface_hint->br_type);
+            free(iface_hint);
             shash_delete(&init_ofp_ports, node);
         }
     }
@@ -2122,7 +2074,7 @@ ofproto_rule_destroy__(struct rule *rule)
 void
 ofproto_rule_destroy(struct rule *rule)
 {
-    assert(!rule->pending);
+    ovs_assert(!rule->pending);
     oftable_remove_rule(rule);
     ofproto_rule_destroy__(rule);
 }
@@ -2172,7 +2124,7 @@ rule_execute(struct rule *rule, uint16_t in_port, struct ofpbuf *packet)
 {
     struct flow flow;
 
-    assert(ofpbuf_headroom(packet) >= sizeof(struct ofp10_packet_in));
+    ovs_assert(ofpbuf_headroom(packet) >= sizeof(struct ofp10_packet_in));
 
     flow_extract(packet, 0, 0, NULL, in_port, &flow);
     return rule->ofproto->ofproto_class->rule_execute(rule, &flow, packet);
@@ -2221,7 +2173,7 @@ handle_features_request(struct ofconn *ofconn, const struct ofp_header *oh)
 
     ofproto->ofproto_class->get_features(ofproto, &arp_match_ip,
                                          &features.actions);
-    assert(features.actions & OFPUTIL_A_OUTPUT); /* sanity check */
+    ovs_assert(features.actions & OFPUTIL_A_OUTPUT); /* sanity check */
 
     /* Count only non-hidden tables in the number of tables.  (Hidden tables,
      * if present, are always at the end.) */
@@ -2289,7 +2241,7 @@ handle_set_config(struct ofconn *ofconn, const struct ofp_header *oh)
         enum ofp_config_flags cur = ofproto->frag_handling;
         enum ofp_config_flags next = flags & OFPC_FRAG_MASK;
 
-        assert((cur & OFPC_FRAG_MASK) == cur);
+        ovs_assert((cur & OFPC_FRAG_MASK) == cur);
         if (cur != next) {
             if (ofproto->ofproto_class->set_frag_handling(ofproto, next)) {
                 ofproto->frag_handling = next;
@@ -2442,17 +2394,29 @@ static enum ofperr
 handle_desc_stats_request(struct ofconn *ofconn,
                           const struct ofp_header *request)
 {
+    static const char *default_mfr_desc = "Nicira, Inc.";
+    static const char *default_hw_desc = "Open vSwitch";
+    static const char *default_sw_desc = VERSION;
+    static const char *default_serial_desc = "None";
+    static const char *default_dp_desc = "None";
+
     struct ofproto *p = ofconn_get_ofproto(ofconn);
     struct ofp_desc_stats *ods;
     struct ofpbuf *msg;
 
     msg = ofpraw_alloc_stats_reply(request, 0);
     ods = ofpbuf_put_zeros(msg, sizeof *ods);
-    ovs_strlcpy(ods->mfr_desc, p->mfr_desc, sizeof ods->mfr_desc);
-    ovs_strlcpy(ods->hw_desc, p->hw_desc, sizeof ods->hw_desc);
-    ovs_strlcpy(ods->sw_desc, p->sw_desc, sizeof ods->sw_desc);
-    ovs_strlcpy(ods->serial_num, p->serial_desc, sizeof ods->serial_num);
-    ovs_strlcpy(ods->dp_desc, p->dp_desc, sizeof ods->dp_desc);
+    ovs_strlcpy(ods->mfr_desc, p->mfr_desc ? p->mfr_desc : default_mfr_desc,
+                sizeof ods->mfr_desc);
+    ovs_strlcpy(ods->hw_desc, p->hw_desc ? p->hw_desc : default_hw_desc,
+                sizeof ods->hw_desc);
+    ovs_strlcpy(ods->sw_desc, p->sw_desc ? p->sw_desc : default_sw_desc,
+                sizeof ods->sw_desc);
+    ovs_strlcpy(ods->serial_num,
+                p->serial_desc ? p->serial_desc : default_serial_desc,
+                sizeof ods->serial_num);
+    ovs_strlcpy(ods->dp_desc, p->dp_desc ? p->dp_desc : default_dp_desc,
+                sizeof ods->dp_desc);
     ofconn_send_reply(ofconn, msg);
 
     return 0;
@@ -2847,11 +2811,7 @@ flow_stats_ds(struct rule *rule, struct ds *results)
     ds_put_format(results, "n_bytes=%"PRIu64", ", byte_count);
     cls_rule_format(&rule->cr, results);
     ds_put_char(results, ',');
-    if (rule->ofpacts_len > 0) {
-        ofpacts_format(rule->ofpacts, rule->ofpacts_len, results);
-    } else {
-        ds_put_cstr(results, "drop");
-    }
+    ofpacts_format(rule->ofpacts, rule->ofpacts_len, results);
     ds_put_cstr(results, "\n");
 }
 
@@ -3149,7 +3109,7 @@ add_flow(struct ofproto *ofproto, struct ofconn *ofconn,
             if (error) {
                 return error;
             }
-            assert(table_id < ofproto->n_tables);
+            ovs_assert(table_id < ofproto->n_tables);
             table = &ofproto->tables[table_id];
         } else {
             table = &ofproto->tables[0];
@@ -3507,7 +3467,7 @@ ofproto_rule_expire(struct rule *rule, uint8_t reason)
     struct ofproto *ofproto = rule->ofproto;
     struct ofopgroup *group;
 
-    assert(reason == OFPRR_HARD_TIMEOUT || reason == OFPRR_IDLE_TIMEOUT);
+    ovs_assert(reason == OFPRR_HARD_TIMEOUT || reason == OFPRR_IDLE_TIMEOUT);
 
     ofproto_rule_send_removed(rule, reason);
 
@@ -3541,12 +3501,12 @@ handle_flow_mod(struct ofconn *ofconn, const struct ofp_header *oh)
                               &fm.match.flow, ofproto->max_ports);
     }
     if (!error) {
-        error = handle_flow_mod__(ofconn_get_ofproto(ofconn), ofconn, &fm, oh);
+        error = handle_flow_mod__(ofproto, ofconn, &fm, oh);
     }
     if (error) {
         goto exit_free_ofpacts;
     }
-    
+
     /* Record the operation for logging a summary report. */
     switch (fm.command) {
     case OFPFC_ADD:
@@ -3585,7 +3545,7 @@ handle_flow_mod__(struct ofproto *ofproto, struct ofconn *ofconn,
                   const struct ofp_header *oh)
 {
     if (ofproto->n_pending >= 50) {
-        assert(!list_is_empty(&ofproto->pending));
+        ovs_assert(!list_is_empty(&ofproto->pending));
         return OFPROTO_POSTPONE;
     }
 
@@ -3618,27 +3578,38 @@ handle_flow_mod__(struct ofproto *ofproto, struct ofconn *ofconn,
 static enum ofperr
 handle_role_request(struct ofconn *ofconn, const struct ofp_header *oh)
 {
-    const struct nx_role_request *nrr = ofpmsg_body(oh);
-    struct nx_role_request *reply;
+    struct ofputil_role_request rr;
     struct ofpbuf *buf;
     uint32_t role;
+    enum ofperr error;
 
-    role = ntohl(nrr->role);
-    if (role != NX_ROLE_OTHER && role != NX_ROLE_MASTER
-        && role != NX_ROLE_SLAVE) {
-        return OFPERR_OFPRRFC_BAD_ROLE;
+    error = ofputil_decode_role_message(oh, &rr);
+    if (error) {
+        return error;
     }
 
+    if (rr.request_current_role_only) {
+        role = ofconn_get_role(ofconn); /* NX_ROLE_* */
+        goto reply;
+    }
+
+    role = rr.role;
+
     if (ofconn_get_role(ofconn) != role
         && ofconn_has_pending_opgroups(ofconn)) {
         return OFPROTO_POSTPONE;
     }
 
+    if (rr.have_generation_id) {
+        if (!ofconn_set_master_election_id(ofconn, rr.generation_id)) {
+            return OFPERR_OFPRRFC_STALE;
+        }
+    }
+
     ofconn_set_role(ofconn, role);
 
-    buf = ofpraw_alloc_reply(OFPRAW_NXT_ROLE_REPLY, oh, 0);
-    reply = ofpbuf_put_zeros(buf, sizeof *reply);
-    reply->role = htonl(role);
+reply:
+    buf = ofputil_encode_role_reply(oh, role);
     ofconn_send_reply(ofconn, buf);
 
     return 0;
@@ -3893,7 +3864,7 @@ ofproto_collect_ofmonitor_refresh_rules(const struct ofmonitor *m,
 
         cls_cursor_init(&cursor, &table->cls, &target);
         CLS_CURSOR_FOR_EACH (rule, cr, &cursor) {
-            assert(!rule->pending); /* XXX */
+            ovs_assert(!rule->pending); /* XXX */
             ofproto_collect_ofmonitor_refresh_rule(m, rule, seqno, rules);
         }
     }
@@ -4049,14 +4020,14 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg)
     case OFPTYPE_BARRIER_REQUEST:
         return handle_barrier_request(ofconn, oh);
 
+    case OFPTYPE_ROLE_REQUEST:
+        return handle_role_request(ofconn, oh);
+
         /* OpenFlow replies. */
     case OFPTYPE_ECHO_REPLY:
         return 0;
 
         /* Nicira extension requests. */
-    case OFPTYPE_ROLE_REQUEST:
-        return handle_role_request(ofconn, oh);
-
     case OFPTYPE_FLOW_MOD_TABLE_ID:
         return handle_nxt_flow_mod_table_id(ofconn, oh);
 
@@ -4199,7 +4170,7 @@ ofopgroup_create(struct ofproto *ofproto, struct ofconn *ofconn,
     if (ofconn) {
         size_t request_len = ntohs(request->length);
 
-        assert(ofconn_get_ofproto(ofconn) == ofproto);
+        ovs_assert(ofconn_get_ofproto(ofconn) == ofproto);
 
         ofconn_add_opgroup(ofconn, &group->ofconn_node);
         group->ofconn = ofconn;
@@ -4237,7 +4208,7 @@ ofopgroup_complete(struct ofopgroup *group)
     struct ofoperation *op, *next_op;
     int error;
 
-    assert(!group->n_running);
+    ovs_assert(!group->n_running);
 
     error = 0;
     LIST_FOR_EACH (op, group_node, &group->ops) {
@@ -4256,7 +4227,7 @@ ofopgroup_complete(struct ofopgroup *group)
                 error = ofconn_pktbuf_retrieve(group->ofconn, group->buffer_id,
                                                &packet, &in_port);
                 if (packet) {
-                    assert(!error);
+                    ovs_assert(!error);
                     error = rule_execute(op->rule, in_port, packet);
                 }
                 break;
@@ -4316,7 +4287,7 @@ ofopgroup_complete(struct ofopgroup *group)
             break;
 
         case OFOPERATION_DELETE:
-            assert(!op->error);
+            ovs_assert(!op->error);
             ofproto_rule_destroy__(rule);
             op->rule = NULL;
             break;
@@ -4346,7 +4317,7 @@ ofopgroup_complete(struct ofopgroup *group)
     ofmonitor_flush(ofproto->connmgr);
 
     if (!list_is_empty(&group->ofproto_node)) {
-        assert(ofproto->n_pending > 0);
+        ovs_assert(ofproto->n_pending > 0);
         ofproto->n_pending--;
         list_remove(&group->ofproto_node);
     }
@@ -4377,7 +4348,7 @@ ofoperation_create(struct ofopgroup *group, struct rule *rule,
     struct ofproto *ofproto = group->ofproto;
     struct ofoperation *op;
 
-    assert(!rule->pending);
+    ovs_assert(!rule->pending);
 
     op = rule->pending = xzalloc(sizeof *op);
     op->group = group;
@@ -4447,9 +4418,9 @@ ofoperation_complete(struct ofoperation *op, enum ofperr error)
 {
     struct ofopgroup *group = op->group;
 
-    assert(op->rule->pending == op);
-    assert(group->n_running > 0);
-    assert(!error || op->type != OFOPERATION_DELETE);
+    ovs_assert(op->rule->pending == op);
+    ovs_assert(group->n_running > 0);
+    ovs_assert(!error || op->type != OFOPERATION_DELETE);
 
     op->error = error;
     if (!--group->n_running && !list_is_empty(&group->ofproto_node)) {
@@ -4460,7 +4431,7 @@ ofoperation_complete(struct ofoperation *op, enum ofperr error)
 struct rule *
 ofoperation_get_victim(struct ofoperation *op)
 {
-    assert(op->type == OFOPERATION_ADD);
+    ovs_assert(op->type == OFOPERATION_ADD);
     return op->victim;
 }
 \f
@@ -4760,7 +4731,7 @@ oftable_init(struct oftable *table)
 static void
 oftable_destroy(struct oftable *table)
 {
-    assert(classifier_is_empty(&table->cls));
+    ovs_assert(classifier_is_empty(&table->cls));
     oftable_disable_eviction(table);
     classifier_destroy(&table->cls);
     free(table->name);
@@ -4987,7 +4958,7 @@ ofproto_port_set_realdev(struct ofproto *ofproto, uint16_t vlandev_ofp_port,
     struct ofport *ofport;
     int error;
 
-    assert(vlandev_ofp_port != realdev_ofp_port);
+    ovs_assert(vlandev_ofp_port != realdev_ofp_port);
 
     ofport = ofproto_get_port(ofproto, vlandev_ofp_port);
     if (!ofport) {