/*
- * Copyright (c) 2009 Nicira Networks.
+ * Copyright (c) 2009, 2010 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
struct rule {
struct cls_rule cr;
+ uint64_t flow_cookie; /* Controller-issued identifier.
+ (Kept in network-byte order.) */
uint16_t idle_timeout; /* In seconds from time of last use. */
uint16_t hard_timeout; /* In seconds from time of creation. */
bool send_flow_removed; /* Send a flow removed message? */
static struct rule *rule_create(struct ofproto *, struct rule *super,
const union ofp_action *, size_t n_actions,
uint16_t idle_timeout, uint16_t hard_timeout,
- bool send_flow_removed);
+ uint64_t flow_cookie, bool send_flow_removed);
static void rule_free(struct rule *);
static void rule_destroy(struct ofproto *, struct rule *);
static struct rule *rule_from_cls_rule(const struct cls_rule *);
char *hardware; /* Hardware. */
char *software; /* Software version. */
char *serial; /* Serial number. */
+ char *dp_desc; /* Datapath description. */
/* Datapath. */
struct dpif *dpif;
p->hardware = xstrdup("Reference Implementation");
p->software = xstrdup(VERSION BUILDNR);
p->serial = xstrdup("None");
+ p->dp_desc = xstrdup("None");
/* Initialize datapath. */
p->dpif = dpif;
void
ofproto_set_desc(struct ofproto *p,
const char *manufacturer, const char *hardware,
- const char *software, const char *serial)
+ const char *software, const char *serial,
+ const char *dp_desc)
{
if (manufacturer) {
free(p->manufacturer);
free(p->serial);
p->serial = xstrdup(serial);
}
+ if (dp_desc) {
+ free(p->dp_desc);
+ p->dp_desc = xstrdup(dp_desc);
+ }
}
int
mac_learning_destroy(p->ml);
+ free(p->manufacturer);
+ free(p->hardware);
+ free(p->software);
+ free(p->serial);
+ free(p->dp_desc);
+
free(p);
}
struct rule *rule;
rule = rule_create(p, NULL, actions, n_actions,
idle_timeout >= 0 ? idle_timeout : 5 /* XXX */,
- 0, false);
+ 0, 0, false);
cls_rule_from_flow(&rule->cr, flow, wildcards, priority);
rule_insert(p, rule, NULL, 0);
}
rule_create(struct ofproto *ofproto, struct rule *super,
const union ofp_action *actions, size_t n_actions,
uint16_t idle_timeout, uint16_t hard_timeout,
- bool send_flow_removed)
+ uint64_t flow_cookie, bool send_flow_removed)
{
struct rule *rule = xcalloc(1, sizeof *rule);
rule->idle_timeout = idle_timeout;
rule->hard_timeout = hard_timeout;
+ rule->flow_cookie = flow_cookie;
rule->used = rule->created = time_msec();
rule->send_flow_removed = send_flow_removed;
rule->super = super;
{
struct rule *subrule = rule_create(ofproto, rule, NULL, 0,
rule->idle_timeout, rule->hard_timeout,
- false);
+ 0, false);
COVERAGE_INC(ofproto_subrule_create);
cls_rule_from_flow(&subrule->cr, flow, 0,
(rule->cr.priority <= UINT16_MAX ? UINT16_MAX
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_PORT_STATS | OFPC_ARP_MATCH_IP);
osf->actions = htonl((1u << OFPAT_OUTPUT) |
(1u << OFPAT_SET_VLAN_VID) |
(1u << OFPAT_SET_VLAN_PCP) |
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);
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);
queue_tx(msg, ofconn, ofconn->reply_counter);
return 0;
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);
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;
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);
ofs->hard_timeout = htons(rule->hard_timeout);
- ofs->pad2 = 0;
+ memset(ofs->pad2, 0, sizeof ofs->pad2);
ofs->packet_count = htonll(packet_count);
ofs->byte_count = htonll(byte_count);
memcpy(ofs->actions, rule->actions, act_len);
}
query_stats(cbdata->ofproto, rule, &packet_count, &byte_count);
- flow_to_ovs_match(&rule->cr.flow, rule->cr.wc.wildcards, &match);
+ flow_to_match(&rule->cr.flow, rule->cr.wc.wildcards, &match);
ds_put_format(results, "duration=%llds, ",
(time_msec() - rule->created) / 1000);
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);
rule = rule_create(p, NULL, (const union ofp_action *) ofm->actions,
n_actions, ntohs(ofm->idle_timeout),
- ntohs(ofm->hard_timeout),
+ ntohs(ofm->hard_timeout), ofm->cookie,
ofm->flags & htons(OFPFF_SEND_FLOW_REM));
cls_rule_from_match(&rule->cr, &ofm->match, ntohs(ofm->priority));
free(rule->actions);
rule->actions = xmemdup(ofm->actions, actions_len);
rule->n_actions = n_actions;
+ rule->flow_cookie = ofm->cookie;
if (rule->cr.wc.wildcards) {
COVERAGE_INC(ofproto_mod_wc_flow);
struct ofp_flow_removed *ofr;
struct ofpbuf *buf;
long long int last_used = rule->used ? now - rule->used : 0;
+ long long int tdiff = time_msec() - rule->created - last_used;
+ 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 - last_used) / 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);