- Fix "flow-add" action for dpctl.
-v0.2.2 - 13 Apr 2008
+v0.8.0 - 13 Apr 2008
--------------------
+ - Added support for flow entry priorities
+ - Added support for all stats messages
+ - Added support for OFPP_TABLE virtual port
- Removed MAC tables
- Various bug fixes and tweaks
Bugs/Shortcomings
-----------------
-- The current flowtable does not support all statistics messages
- mentioned in the Type 0 OpenFlow spec.
-
- The flowtable does not support the "normal processing" action.
- Configure/build system does not support separate build directory for
the datapath. ./configure must be run from the source root.
-- dpctl dump-flows may freeze when large numbers of flows are in the
- flow table. This has no effect on the datapath.
-
References
----------
AC_PREREQ(2.59)
-AC_INIT(openflow, v0.2.2a2, info@openflowswitch.org)
+AC_INIT(openflow, v0.2.2a5, info@openflowswitch.org)
AM_INIT_AUTOMAKE
AC_PROG_CC
ofs->match.tp_src = flow->key.tp_src;
ofs->match.tp_dst = flow->key.tp_dst;
ofs->duration = htonl((jiffies - flow->init_time) / HZ);
+ ofs->priority = htons(flow->priority);
ofs->table_id = table_idx;
ofs->packet_count = cpu_to_be64(flow->packet_count);
ofs->byte_count = cpu_to_be64(flow->byte_count);
uint32_t group_id; /* Flow group ID (for QoS). */
uint16_t max_idle; /* Idle time before discarding (seconds). */
+ uint16_t priority; /* Only used on entries with wildcards. */
unsigned long timeout; /* Expiration time (in jiffies). */
/* FIXME? Probably most flows have only a single action. */
flow_extract_match(&flow->key, &ofm->match);
flow->group_id = ntohl(ofm->group_id);
flow->max_idle = ntohs(ofm->max_idle);
+ flow->priority = ntohs(ofm->priority);
flow->timeout = jiffies + flow->max_idle * HZ;
flow->n_actions = n_acts;
flow->init_time = jiffies;
unsigned long int flags;
struct sw_flow *f;
- /* Replace flows that match exactly. */
+
+ /* Loop through the existing list of entries. New entries will
+ * always be placed behind those with equal priority. Just replace
+ * any flows that match exactly.
+ */
spin_lock_irqsave(&tl->lock, flags);
list_for_each_entry_rcu (f, &tl->flows, u.node) {
- if (f->key.wildcards == flow->key.wildcards
+ if (f->priority == flow->priority
+ && f->key.wildcards == flow->key.wildcards
&& flow_matches(&f->key, &flow->key)
&& flow_del(f)) {
list_replace_rcu(&f->u.node, &flow->u.node);
flow_deferred_free(f);
return 1;
}
+
+ if (f->priority < flow->priority)
+ break;
}
- /* Table overflow? */
+ /* Make sure there's room in the table. */
if (atomic_read(&tl->n_flows) >= tl->max_flows) {
spin_unlock_irqrestore(&tl->lock, flags);
return 0;
}
atomic_inc(&tl->n_flows);
- /* FIXME: need to order rules from most to least specific. */
- list_add_rcu(&flow->u.node, &tl->flows);
+ /* Insert the entry immediately in front of where we're pointing. */
+ list_add_tail_rcu(&flow->u.node, &f->u.node);
spin_unlock_irqrestore(&tl->lock, flags);
return 1;
}
/* The most significant bit being set in the version field indicates an
* experimental OpenFlow version.
*/
-#define OFP_VERSION 0x80
+#define OFP_VERSION 0x81
#define OFP_MAX_TABLE_NAME_LEN 32
#define OFP_MAX_PORT_NAME_LEN 16
uint32_t group_id; /* Flow group ID (for QoS). */
uint16_t priority; /* Priority level of flow entry. */
uint8_t pad[2]; /* Align to 32-bits. */
+ uint32_t reserved; /* Reserved for future use. */
struct ofp_action actions[0]; /* The number of actions is inferred from
the length field in the header. */
};
used for non-aggregated results. */
uint64_t packet_count; /* Number of packets in flow. */
uint64_t byte_count; /* Number of bytes in flow. */
+ uint16_t priority; /* Priority of the entry. Only meaningful
+ when this is not an exact-match entry. */
uint8_t table_id; /* ID of table flow came from. */
- uint8_t pad[7]; /* Align to 64-bits. */
+ uint8_t pad[5]; /* Align to 64-bits. */
};
enum ofp_stats_type {
{
uint16_t w = ntohs(om->wildcards);
- print_wild(f, "inport", w & OFPFW_IN_PORT, "%04x", ntohs(om->in_port));
+ print_wild(f, "inport", w & OFPFW_IN_PORT, "%d", ntohs(om->in_port));
print_wild(f, ":vlan", w & OFPFW_DL_VLAN, "%04x", ntohs(om->dl_vlan));
print_wild(f, " mac[", w & OFPFW_DL_SRC,
ETH_ADDR_FMT, ETH_ADDR_ARGS(om->dl_src));
for (fs = &fsr->flows[0]; fs < &fsr->flows[n]; fs++) {
ds_put_format(string, " duration=%"PRIu32" s, ", ntohs(fs->duration));
ds_put_format(string, "table_id=%"PRIu8", ", fs->table_id);
+ ds_put_format(string, "priority=%"PRIu16", ", fs->match.wildcards ? ntohs(fs->priority) : (uint16_t)-1);
ds_put_format(string, "n_packets=%"PRIu64", ",
ntohll(fs->packet_count));
ds_put_format(string, "n_bytes=%"PRIu64", ", ntohll(fs->byte_count));
ofs->match.tp_src = flow->key.flow.tp_src;
ofs->match.tp_dst = flow->key.flow.tp_dst;
ofs->duration = htonl(now - flow->created);
+ ofs->priority = htons(flow->priority);
ofs->table_id = table_idx;
ofs->packet_count = htonll(flow->packet_count);
ofs->byte_count = htonll(flow->byte_count);
flow_extract_match(&flow->key, &ofm->match);
flow->group_id = ntohl(ofm->group_id);
flow->max_idle = ntohs(ofm->max_idle);
+ flow->priority = ntohs(ofm->priority);
flow->timeout = time(0) + flow->max_idle; /* FIXME */
flow->n_actions = n_acts;
flow->created = time(0); /* FIXME */
uint32_t group_id; /* Flow group ID (for QoS). */
uint16_t max_idle; /* Idle time before discarding (seconds). */
+ uint16_t priority; /* Only used on entries with wildcards. */
time_t created; /* When the flow was created. */
time_t timeout; /* When the flow expires (if idle). */
uint64_t packet_count; /* Number of packets seen. */
struct sw_table_linear *tl = (struct sw_table_linear *) swt;
struct sw_flow *f;
- /* Replace flows that match exactly. */
+ /* Loop through the existing list of entries. New entries will
+ * always be placed behind those with equal priority. Just replace
+ * any flows that match exactly.
+ */
LIST_FOR_EACH (f, struct sw_flow, node, &tl->flows) {
- if (f->key.wildcards == flow->key.wildcards
- && flow_matches(&f->key, &flow->key)) {
+ if (f->priority == flow->priority
+ && f->key.wildcards == flow->key.wildcards
+ && flow_matches(&f->key, &flow->key)) {
list_replace(&flow->node, &f->node);
flow_free(f);
return 1;
}
+
+ if (f->priority < flow->priority)
+ break;
}
- /* Table overflow? */
+ /* Make sure there's room in the table. */
if (tl->n_flows >= tl->max_flows) {
return 0;
}
tl->n_flows++;
- /* FIXME: need to order rules from most to least specific. */
- list_push_back(&tl->flows, &flow->node);
+ /* Insert the entry immediately in front of where we're pointing. */
+ if (f)
+ list_push_back(&f->node, &flow->node);
+ else
+ list_push_back(&tl->flows, &flow->node);
return 1;
}
static void
str_to_flow(char *string, struct ofp_match *match, struct ofp_action *action,
- uint8_t *table_idx)
+ uint8_t *table_idx, uint16_t *priority)
{
struct field {
const char *name;
continue;
}
+ if (priority && !strcmp(name, "priority")) {
+ *priority = atoi(value);
+ continue;
+ }
+
for (f = fields; f < &fields[ARRAY_SIZE(fields)]; f++) {
if (!strcmp(f->name, name)) {
goto found;
run(vconn_open_block(argv[1], &vconn), "connecting to %s", argv[1]);
fsr = alloc_openflow_buffer(sizeof *fsr, OFPT_FLOW_STATS_REQUEST, &request);
- str_to_flow(argc > 2 ? argv[2] : "", &fsr->match, NULL, &fsr->table_id);
+ str_to_flow(argc > 2 ? argv[2] : "", &fsr->match, NULL, &fsr->table_id, NULL);
fsr->type = OFPFS_INDIV;
fsr->pad = 0;
reply = transact_openflow(vconn, request);
while (fgets(line, sizeof line, file)) {
struct buffer *buffer;
struct ofp_flow_mod *ofm;
+ uint16_t priority=0;
size_t size;
char *comment;
ofm->max_idle = htons(50);
ofm->buffer_id = htonl(UINT32_MAX);
ofm->group_id = htonl(0);
- str_to_flow(line, &ofm->match, &ofm->actions[0], NULL);
- run(vconn_send_block(vconn, buffer), "send OpenFlow packet");
+ str_to_flow(line, &ofm->match, &ofm->actions[0], NULL, &priority);
+ ofm->priority = htons(priority);
+
+ send_openflow_buffer(vconn, buffer);
}
vconn_close(vconn);
fclose(file);