ovs-brcompatd: Add rate-limit argument to rate-limited log call
[openvswitch] / ofproto / ofproto.c
index 00fb9b5506e2a0ff2ff9ed0a8753774717caee34..189aa2c827a96ee04eb2b02db178e5fd23064799 100644 (file)
@@ -187,10 +187,10 @@ struct ofproto {
     /* Settings. */
     uint64_t datapath_id;       /* Datapath ID. */
     uint64_t fallback_dpid;     /* Datapath ID if no better choice found. */
-    char *manufacturer;         /* Manufacturer. */
-    char *hardware;             /* Hardware. */
-    char *software;             /* Software version. */
-    char *serial;               /* Serial number. */
+    char *mfr_desc;             /* Manufacturer. */
+    char *hw_desc;              /* Hardware. */
+    char *sw_desc;              /* Software version. */
+    char *serial_desc;          /* Serial number. */
     char *dp_desc;              /* Datapath description. */
 
     /* Datapath. */
@@ -299,11 +299,11 @@ ofproto_create(const char *datapath, const char *datapath_type,
     p = xzalloc(sizeof *p);
     p->fallback_dpid = pick_fallback_dpid();
     p->datapath_id = p->fallback_dpid;
-    p->manufacturer = xstrdup("Nicira Networks, Inc.");
-    p->hardware = xstrdup("Reference Implementation");
-    p->software = xstrdup(VERSION BUILDNR);
-    p->serial = xstrdup("None");
-    p->dp_desc = xstrdup("None");
+    p->mfr_desc = xstrdup(DEFAULT_MFR_DESC);
+    p->hw_desc = xstrdup(DEFAULT_HW_DESC);
+    p->sw_desc = xstrdup(DEFAULT_SW_DESC);
+    p->serial_desc = xstrdup(DEFAULT_SERIAL_DESC);
+    p->dp_desc = xstrdup(DEFAULT_DP_DESC);
 
     /* Initialize datapath. */
     p->dpif = dpif;
@@ -390,27 +390,50 @@ ofproto_set_max_backoff(struct ofproto *p, int max_backoff)
 
 void
 ofproto_set_desc(struct ofproto *p,
-                 const char *manufacturer, const char *hardware,
-                 const char *software, const char *serial,
+                 const char *mfr_desc, const char *hw_desc,
+                 const char *sw_desc, const char *serial_desc,
                  const char *dp_desc)
 {
-    if (manufacturer) {
-        free(p->manufacturer);
-        p->manufacturer = xstrdup(manufacturer);
-    }
-    if (hardware) {
-        free(p->hardware);
-        p->hardware = xstrdup(hardware);
+    struct ofp_desc_stats *ods;
+
+    if (mfr_desc) {
+        if (strlen(mfr_desc) >= sizeof ods->mfr_desc) {
+            VLOG_WARN("truncating mfr_desc, must be less than %zu characters",
+                    sizeof ods->mfr_desc);
+        }
+        free(p->mfr_desc);
+        p->mfr_desc = xstrdup(mfr_desc);
     }
-    if (software) {
-        free(p->software);
-        p->software = xstrdup(software);
+    if (hw_desc) {
+        if (strlen(hw_desc) >= sizeof ods->hw_desc) {
+            VLOG_WARN("truncating hw_desc, must be less than %zu characters",
+                    sizeof ods->hw_desc);
+        }
+        free(p->hw_desc);
+        p->hw_desc = xstrdup(hw_desc);
     }
-    if (serial) {
-        free(p->serial);
-        p->serial = xstrdup(serial);
+    if (sw_desc) {
+        if (strlen(sw_desc) >= sizeof ods->sw_desc) {
+            VLOG_WARN("truncating sw_desc, must be less than %zu characters",
+                    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("truncating serial_desc, must be less than %zu "
+                    "characters",
+                    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("truncating dp_desc, must be less than %zu characters",
+                    sizeof ods->dp_desc);
+        }
         free(p->dp_desc);
         p->dp_desc = xstrdup(dp_desc);
     }
@@ -731,6 +754,14 @@ ofproto_destroy(struct ofproto *p)
 
     mac_learning_destroy(p->ml);
 
+    free(p->mfr_desc);
+    free(p->hw_desc);
+    free(p->sw_desc);
+    free(p->serial_desc);
+    free(p->dp_desc);
+
+    port_array_destroy(&p->ports);
+
     free(p);
 }
 
@@ -1860,8 +1891,7 @@ handle_features_request(struct ofproto *p, struct ofconn *ofconn,
     osf->n_buffers = htonl(pktbuf_capacity());
     osf->n_tables = 2;
     osf->capabilities = htonl(OFPC_FLOW_STATS | OFPC_TABLE_STATS |
-                              OFPC_PORT_STATS | OFPC_MULTI_PHY_TX |
-                              OFPC_ARP_MATCH_IP);
+                              OFPC_PORT_STATS | OFPC_ARP_MATCH_IP);
     osf->actions = htonl((1u << OFPAT_OUTPUT) |
                          (1u << OFPAT_SET_VLAN_VID) |
                          (1u << OFPAT_SET_VLAN_PCP) |
@@ -2183,6 +2213,7 @@ do_xlate_actions(const union ofp_action *in, size_t n_in,
         case OFPAT_SET_NW_DST:
             oa = odp_actions_add(ctx->out, ODPAT_SET_NW_DST);
             oa->nw_addr.nw_addr = ia->nw_addr.nw_addr;
+            break;
 
         case OFPAT_SET_NW_TOS:
             oa = odp_actions_add(ctx->out, ODPAT_SET_NW_TOS);
@@ -2392,11 +2423,12 @@ handle_desc_stats_request(struct ofproto *p, struct ofconn *ofconn,
 
     msg = start_stats_reply(request, sizeof *ods);
     ods = append_stats_reply(sizeof *ods, ofconn, &msg);
-    strncpy(ods->mfr_desc, p->manufacturer, sizeof ods->mfr_desc);
-    strncpy(ods->hw_desc, p->hardware, sizeof ods->hw_desc);
-    strncpy(ods->sw_desc, p->software, sizeof ods->sw_desc);
-    strncpy(ods->serial_num, p->serial, sizeof ods->serial_num);
-    strncpy(ods->dp_desc, p->dp_desc, sizeof ods->dp_desc);
+    memset(ods, 0, 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);
     queue_tx(msg, ofconn, ofconn->reply_counter);
 
     return 0;
@@ -2458,39 +2490,62 @@ handle_table_stats_request(struct ofproto *p, struct ofconn *ofconn,
     return 0;
 }
 
+static void
+append_port_stat(struct ofport *port, uint16_t port_no, struct ofconn *ofconn, 
+                 struct ofpbuf *msg)
+{
+    struct netdev_stats stats;
+    struct ofp_port_stats *ops;
+
+    /* Intentionally ignore return value, since errors will set 
+     * 'stats' to all-1s, which is correct for OpenFlow, and 
+     * netdev_get_stats() will log errors. */
+    netdev_get_stats(port->netdev, &stats);
+
+    ops = append_stats_reply(sizeof *ops, ofconn, &msg);
+    ops->port_no = htons(odp_port_to_ofp_port(port_no));
+    memset(ops->pad, 0, sizeof ops->pad);
+    ops->rx_packets = htonll(stats.rx_packets);
+    ops->tx_packets = htonll(stats.tx_packets);
+    ops->rx_bytes = htonll(stats.rx_bytes);
+    ops->tx_bytes = htonll(stats.tx_bytes);
+    ops->rx_dropped = htonll(stats.rx_dropped);
+    ops->tx_dropped = htonll(stats.tx_dropped);
+    ops->rx_errors = htonll(stats.rx_errors);
+    ops->tx_errors = htonll(stats.tx_errors);
+    ops->rx_frame_err = htonll(stats.rx_frame_errors);
+    ops->rx_over_err = htonll(stats.rx_over_errors);
+    ops->rx_crc_err = htonll(stats.rx_crc_errors);
+    ops->collisions = htonll(stats.collisions);
+}
+
 static int
 handle_port_stats_request(struct ofproto *p, struct ofconn *ofconn,
-                          struct ofp_stats_request *request)
+                          struct ofp_stats_request *osr,
+                          size_t arg_size)
 {
+    struct ofp_port_stats_request *psr;
     struct ofp_port_stats *ops;
     struct ofpbuf *msg;
     struct ofport *port;
     unsigned int port_no;
 
-    msg = start_stats_reply(request, sizeof *ops * 16);
-    PORT_ARRAY_FOR_EACH (port, &p->ports, port_no) {
-        struct netdev_stats stats;
-
-        /* Intentionally ignore return value, since errors will set 'stats' to
-         * all-1s, which is correct for OpenFlow, and netdev_get_stats() will
-         * log errors. */
-        netdev_get_stats(port->netdev, &stats);
-
-        ops = append_stats_reply(sizeof *ops, ofconn, &msg);
-        ops->port_no = htons(odp_port_to_ofp_port(port_no));
-        memset(ops->pad, 0, sizeof ops->pad);
-        ops->rx_packets = htonll(stats.rx_packets);
-        ops->tx_packets = htonll(stats.tx_packets);
-        ops->rx_bytes = htonll(stats.rx_bytes);
-        ops->tx_bytes = htonll(stats.tx_bytes);
-        ops->rx_dropped = htonll(stats.rx_dropped);
-        ops->tx_dropped = htonll(stats.tx_dropped);
-        ops->rx_errors = htonll(stats.rx_errors);
-        ops->tx_errors = htonll(stats.tx_errors);
-        ops->rx_frame_err = htonll(stats.rx_frame_errors);
-        ops->rx_over_err = htonll(stats.rx_over_errors);
-        ops->rx_crc_err = htonll(stats.rx_crc_errors);
-        ops->collisions = htonll(stats.collisions);
+    if (arg_size != sizeof *psr) {
+        return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
+    }
+    psr = (struct ofp_port_stats_request *) osr->body;
+
+    msg = start_stats_reply(osr, sizeof *ops * 16);
+    if (psr->port_no != htons(OFPP_NONE)) {
+        port = port_array_get(&p->ports, 
+                ofp_port_to_odp_port(ntohs(psr->port_no)));
+        if (port) {
+            append_port_stat(port, ntohs(psr->port_no), ofconn, msg);
+        }
+    } else {
+        PORT_ARRAY_FOR_EACH (port, &p->ports, port_no) {
+            append_port_stat(port, port_no, ofconn, msg);
+        }
     }
 
     queue_tx(msg, ofconn, ofconn->reply_counter);
@@ -2553,6 +2608,9 @@ flow_stats_cb(struct cls_rule *rule_, void *cbdata_)
     struct ofp_flow_stats *ofs;
     uint64_t packet_count, byte_count;
     size_t act_len, len;
+    long long int tdiff = time_msec() - rule->created;
+    uint32_t sec = tdiff / 1000;
+    uint32_t msec = tdiff - (sec * 1000);
 
     if (rule_is_hidden(rule) || !rule_has_out_port(rule, cbdata->out_port)) {
         return;
@@ -2568,7 +2626,8 @@ flow_stats_cb(struct cls_rule *rule_, void *cbdata_)
     ofs->table_id = rule->cr.wc.wildcards ? TABLEID_CLASSIFIER : TABLEID_HASH;
     ofs->pad = 0;
     flow_to_match(&rule->cr.flow, rule->cr.wc.wildcards, &ofs->match);
-    ofs->duration = htonl((time_msec() - rule->created) / 1000);
+    ofs->duration_sec = htonl(sec);
+    ofs->duration_nsec = htonl(msec * 1000000);
     ofs->cookie = rule->flow_cookie;
     ofs->priority = htons(rule->cr.priority);
     ofs->idle_timeout = htons(rule->idle_timeout);
@@ -2759,7 +2818,7 @@ handle_stats_request(struct ofproto *p, struct ofconn *ofconn,
         return handle_table_stats_request(p, ofconn, osr);
 
     case OFPST_PORT:
-        return handle_port_stats_request(p, ofconn, osr);
+        return handle_port_stats_request(p, ofconn, osr, arg_size);
 
     case OFPST_VENDOR:
         return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_VENDOR);
@@ -3263,13 +3322,17 @@ compose_flow_removed(const struct rule *rule, long long int now, uint8_t reason)
 {
     struct ofp_flow_removed *ofr;
     struct ofpbuf *buf;
+    long long int tdiff = time_msec() - rule->created;
+    uint32_t sec = tdiff / 1000;
+    uint32_t msec = tdiff - (sec * 1000);
 
     ofr = make_openflow(sizeof *ofr, OFPT_FLOW_REMOVED, &buf);
     flow_to_match(&rule->cr.flow, rule->cr.wc.wildcards, &ofr->match);
     ofr->cookie = rule->flow_cookie;
     ofr->priority = htons(rule->cr.priority);
     ofr->reason = reason;
-    ofr->duration = htonl((now - rule->created) / 1000);
+    ofr->duration_sec = htonl(sec);
+    ofr->duration_nsec = htonl(msec * 1000000);
     ofr->idle_timeout = htons(rule->idle_timeout);
     ofr->packet_count = htonll(rule->packet_count);
     ofr->byte_count = htonll(rule->byte_count);