/* Strings to describe the manufacturer, hardware, and software. This data
- * is queriable through the version stats message. */
-static char mfr_desc[VERSION_STR_LEN] = "Nicira Networks";
-static char hw_desc[VERSION_STR_LEN] = "Reference Linux Kernel Module";
-static char sw_desc[VERSION_STR_LEN] = VERSION;
+ * is queriable through the switch description stats message. */
+static char mfr_desc[DESC_STR_LEN] = "Nicira Networks";
+static char hw_desc[DESC_STR_LEN] = "Reference Linux Kernel Module";
+static char sw_desc[DESC_STR_LEN] = VERSION;
+static char serial_num[SERIAL_NUM_LEN] = "None";
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
module_param_string(mfr_desc, mfr_desc, sizeof mfr_desc, 0444);
module_param_string(hw_desc, hw_desc, sizeof hw_desc, 0444);
module_param_string(sw_desc, sw_desc, sizeof sw_desc, 0444);
+module_param_string(serial_num, serial_num, sizeof serial_num, 0444);
#else
MODULE_PARM(mfr_desc, "s");
MODULE_PARM(hw_desc, "s");
MODULE_PARM(sw_desc, "s");
+MODULE_PARM(serial_num, "s");
#endif
/* Number of milliseconds between runs of the maintenance thread. */
#define MAINT_SLEEP_MSECS 1000
-enum br_port_flags {
- BRPF_NO_FLOOD = 1 << 0,
-};
-
-enum br_port_status {
- BRPS_PORT_DOWN = 1 << 0,
- BRPS_LINK_DOWN = 1 << 1,
-};
-
#define UINT32_MAX 4294967295U
#define UINT16_MAX 65535
#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
-struct net_bridge_port {
- u16 port_no;
- u32 flags; /* BRPF_* flags */
- u32 status; /* BRPS_* flags */
- spinlock_t lock;
- struct work_struct port_task;
- struct datapath *dp;
- struct net_device *dev;
- struct list_head node; /* Element in datapath.ports. */
-};
-
static struct genl_family dp_genl_family;
static struct genl_multicast_group mc_group;
{
/* Push the Ethernet header back on. */
skb_push(skb, ETH_HLEN);
- fwd_port_input(p->dp->chain, skb, p->port_no);
+ fwd_port_input(p->dp->chain, skb, p);
}
/*
static int
output_all(struct datapath *dp, struct sk_buff *skb, int flood)
{
- u32 disable = flood ? BRPF_NO_FLOOD : 0;
+ u32 disable = flood ? OFPPFL_NO_FLOOD : 0;
struct net_bridge_port *p;
int prev_port = -1;
kfree_skb(skb);
return -ENOMEM;
}
- dp_output_port(dp, clone, prev_port);
+ dp_output_port(dp, clone, prev_port, 0);
}
prev_port = p->port_no;
}
if (prev_port != -1)
- dp_output_port(dp, skb, prev_port);
+ dp_output_port(dp, skb, prev_port, 0);
else
kfree_skb(skb);
/* Takes ownership of 'skb' and transmits it to 'out_port' on 'dp'.
*/
-int dp_output_port(struct datapath *dp, struct sk_buff *skb, int out_port)
+int dp_output_port(struct datapath *dp, struct sk_buff *skb, int out_port,
+ int ignore_no_fwd)
{
BUG_ON(!skb);
switch (out_port){
return xmit_skb(skb);
case OFPP_TABLE: {
- struct net_bridge_port *p = skb->dev->br_port;
- int retval;
- retval = run_flow_through_tables(dp->chain, skb,
- p ? p->port_no : OFPP_LOCAL);
+ int retval = run_flow_through_tables(dp->chain, skb,
+ skb->dev->br_port);
if (retval)
kfree_skb(skb);
return retval;
printk("can't directly forward to input port\n");
return -EINVAL;
}
+ if (p->flags & OFPPFL_NO_FWD && !ignore_no_fwd) {
+ kfree_skb(skb);
+ return 0;
+ }
skb->dev = p->dev;
return xmit_skb(skb);
}
desc->features = 0;
desc->speed = 0;
+ if (p->port_no < 255) {
+ /* FIXME: this is a layering violation and should really be
+ * done in the secchan, as with OFPC_STP in
+ * OFP_SUPPORTED_CAPABILITIES. */
+ desc->features |= OFPPF_STP;
+ }
+
spin_lock_irqsave(&p->lock, flags);
- if (p->flags & BRPF_NO_FLOOD)
- desc->flags |= htonl(OFPPFL_NO_FLOOD);
- else if (p->status & BRPS_PORT_DOWN)
- desc->flags |= htonl(OFPPFL_PORT_DOWN);
- else if (p->status & BRPS_LINK_DOWN)
- desc->flags |= htonl(OFPPFL_LINK_DOWN);
+ desc->flags = htonl(p->flags | p->status);
spin_unlock_irqrestore(&p->lock, flags);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,24)
if (ecmd.supported & SUPPORTED_10000baseT_Full)
desc->features |= OFPPF_10GB_FD;
- desc->features = htonl(desc->features);
desc->speed = htonl(ecmd.speed);
}
}
#endif
+ desc->features = htonl(desc->features);
}
static int
struct net_bridge_port *p;
int port_count = 0;
- ofr->datapath_id = cpu_to_be64(dp->id);
+ ofr->datapath_id = cpu_to_be64(dp->id);
- ofr->n_exact = htonl(2 * TABLE_HASH_MAX_FLOWS);
- ofr->n_compression = 0; /* Not supported */
- ofr->n_general = htonl(TABLE_LINEAR_MAX_FLOWS);
- ofr->buffer_mb = htonl(UINT32_MAX);
- ofr->n_buffers = htonl(N_PKT_BUFFERS);
- ofr->capabilities = htonl(OFP_SUPPORTED_CAPABILITIES);
- ofr->actions = htonl(OFP_SUPPORTED_ACTIONS);
+ ofr->n_buffers = htonl(N_PKT_BUFFERS);
+ ofr->n_tables = dp->chain->n_tables;
+ ofr->capabilities = htonl(OFP_SUPPORTED_CAPABILITIES);
+ ofr->actions = htonl(OFP_SUPPORTED_ACTIONS);
+ memset(ofr->pad, 0, sizeof ofr->pad);
list_for_each_entry_rcu (p, &dp->port_list, node) {
fill_port_desc(p, &ofr->ports[port_count]);
return send_openflow_skb(skb, sender);
}
+int
+dp_send_hello(struct datapath *dp, const struct sender *sender,
+ const struct ofp_header *request)
+{
+ if (request->version < OFP_VERSION) {
+ char err[64];
+ sprintf(err, "Only version 0x%02x supported", OFP_VERSION);
+ dp_send_error_msg(dp, sender, OFPET_HELLO_FAILED,
+ OFPHFC_INCOMPATIBLE, err, strlen(err));
+ return -EINVAL;
+ } else {
+ struct sk_buff *skb;
+ struct ofp_header *reply;
+
+ reply = alloc_openflow_skb(dp, sizeof *reply,
+ OFPT_HELLO, sender, &skb);
+ if (!reply)
+ return -ENOMEM;
+
+ return send_openflow_skb(skb, sender);
+ }
+}
+
/* Callback function for a workqueue to disable an interface */
static void
down_port_cb(struct work_struct *work)
if (net_ratelimit())
printk("problem bringing up port %s\n", p->dev->name);
rtnl_unlock();
- p->status |= BRPS_PORT_DOWN;
+ p->status |= OFPPFL_PORT_DOWN;
}
/* Callback function for a workqueue to enable an interface */
if (net_ratelimit())
printk("problem bringing down port %s\n", p->dev->name);
rtnl_unlock();
- p->status &= ~BRPS_PORT_DOWN;
+ p->status &= ~OFPPFL_PORT_DOWN;
}
int
struct net_bridge_port *p = (port_no < OFPP_MAX ? dp->ports[port_no]
: port_no == OFPP_LOCAL ? dp->local_port
: NULL);
+ uint32_t flag_mask;
+
/* Make sure the port id hasn't changed since this was sent */
if (!p || memcmp(opp->hw_addr, p->dev->dev_addr, ETH_ALEN))
return -1;
spin_lock_irqsave(&p->lock, flags);
- if (opm->mask & htonl(OFPPFL_NO_FLOOD)) {
- if (opp->flags & htonl(OFPPFL_NO_FLOOD))
- p->flags |= BRPF_NO_FLOOD;
- else
- p->flags &= ~BRPF_NO_FLOOD;
+ flag_mask = ntohl(opm->mask) & PORT_FLAG_BITS;
+ if (flag_mask) {
+ p->flags &= ~flag_mask;
+ p->flags |= ntohl(opp->flags) & flag_mask;
}
/* Modifying the status of an interface requires taking a lock
* context. */
if (opm->mask & htonl(OFPPFL_PORT_DOWN)) {
if ((opp->flags & htonl(OFPPFL_PORT_DOWN))
- && (p->status & BRPS_PORT_DOWN) == 0) {
+ && (p->status & OFPPFL_PORT_DOWN) == 0) {
PREPARE_WORK(&p->port_task, down_port_cb);
schedule_work(&p->port_task);
} else if ((opp->flags & htonl(OFPPFL_PORT_DOWN)) == 0
- && (p->status & BRPS_PORT_DOWN)) {
+ && (p->status & OFPPFL_PORT_DOWN)) {
PREPARE_WORK(&p->port_task, up_port_cb);
schedule_work(&p->port_task);
}
orig_status = p->status;
if (p->dev->flags & IFF_UP)
- p->status &= ~BRPS_PORT_DOWN;
+ p->status &= ~OFPPFL_PORT_DOWN;
else
- p->status |= BRPS_PORT_DOWN;
+ p->status |= OFPPFL_PORT_DOWN;
if (netif_carrier_ok(p->dev))
- p->status &= ~BRPS_LINK_DOWN;
+ p->status &= ~OFPPFL_LINK_DOWN;
else
- p->status |= BRPS_LINK_DOWN;
+ p->status |= OFPPFL_LINK_DOWN;
spin_unlock_irqrestore(&p->lock, flags);
return (orig_status != p->status);
int
dp_send_error_msg(struct datapath *dp, const struct sender *sender,
- uint16_t type, uint16_t code, const uint8_t *data, size_t len)
+ uint16_t type, uint16_t code, const void *data, size_t len)
{
struct sk_buff *skb;
struct ofp_error_msg *oem;
- oem = alloc_openflow_skb(dp, sizeof(*oem)+len, OFPT_ERROR_MSG,
+ oem = alloc_openflow_skb(dp, sizeof(*oem)+len, OFPT_ERROR,
sender, &skb);
if (!oem)
return -ENOMEM;
[DP_GENL_A_DP_IDX] = { .type = NLA_U32 },
};
-static int version_stats_dump(struct datapath *dp, void *state,
+static int desc_stats_dump(struct datapath *dp, void *state,
void *body, int *body_len)
{
- struct ofp_version_stats *ovs = body;
- int n_bytes = sizeof *ovs;
+ struct ofp_desc_stats *ods = body;
+ int n_bytes = sizeof *ods;
if (n_bytes > *body_len) {
return -ENOBUFS;
}
*body_len = n_bytes;
- strncpy(ovs->mfr_desc, mfr_desc, sizeof ovs->mfr_desc);
- strncpy(ovs->hw_desc, hw_desc, sizeof ovs->hw_desc);
- strncpy(ovs->sw_desc, sw_desc, sizeof ovs->sw_desc);
+ strncpy(ods->mfr_desc, mfr_desc, sizeof ods->mfr_desc);
+ strncpy(ods->hw_desc, hw_desc, sizeof ods->hw_desc);
+ strncpy(ods->sw_desc, sw_desc, sizeof ods->sw_desc);
+ strncpy(ods->serial_num, serial_num, sizeof ods->serial_num);
return 0;
}
dp->chain->tables[i]->stats(dp->chain->tables[i], &stats);
strncpy(ots->name, stats.name, sizeof ots->name);
ots->table_id = i;
+ ots->wildcards = htonl(stats.wildcards);
memset(ots->pad, 0, sizeof ots->pad);
ots->max_entries = htonl(stats.max_flows);
ots->active_count = htonl(stats.n_flows);
};
static const struct stats_type stats[] = {
- [OFPST_VERSION] = {
+ [OFPST_DESC] = {
0,
0,
NULL,
- version_stats_dump,
+ desc_stats_dump,
NULL
},
[OFPST_FLOW] = {
* struct genl_ops. This kluge supports earlier versions also. */
cb->done = dp_genl_openflow_done;
+ sender.pid = NETLINK_CB(cb->skb).pid;
+ sender.seq = cb->nlh->nlmsg_seq;
if (!cb->args[0]) {
struct nlattr *attrs[DP_GENL_A_MAX + 1];
struct ofp_stats_request *rq;
return -EINVAL;
rq = nla_data(va);
+ sender.xid = rq->header.xid;
type = ntohs(rq->type);
- if (rq->header.version != OFP_VERSION
- || rq->header.type != OFPT_STATS_REQUEST
- || ntohs(rq->header.length) != len
- || type >= ARRAY_SIZE(stats)
- || !stats[type].dump)
+ if (rq->header.version != OFP_VERSION) {
+ dp_send_error_msg(dp, &sender, OFPET_BAD_REQUEST,
+ OFPBRC_BAD_VERSION, rq, len);
return -EINVAL;
+ }
+ if (rq->header.type != OFPT_STATS_REQUEST
+ || ntohs(rq->header.length) != len)
+ return -EINVAL;
+
+ if (type >= ARRAY_SIZE(stats) || !stats[type].dump) {
+ dp_send_error_msg(dp, &sender, OFPET_BAD_REQUEST,
+ OFPBRC_BAD_STAT, rq, len);
+ return -EINVAL;
+ }
s = &stats[type];
body_len = len - offsetof(struct ofp_stats_request, body);
cb->args[4] = (long) state;
}
} else if (cb->args[0] == 1) {
+ sender.xid = cb->args[3];
dp_idx = cb->args[1];
s = &stats[cb->args[2]];
return 0;
}
- sender.xid = cb->args[3];
- sender.pid = NETLINK_CB(cb->skb).pid;
- sender.seq = cb->nlh->nlmsg_seq;
-
osr = put_openflow_headers(dp, skb, OFPT_STATS_REPLY, &sender,
&max_openflow_len);
if (IS_ERR(osr))