From bfe3b4df894304e572a6170c61bef6ebbf166bd0 Mon Sep 17 00:00:00 2001 From: Justin Pettit Date: Fri, 25 Apr 2008 14:00:15 -0700 Subject: [PATCH] - Add support for flow entry priorities. - Fix "flow-add" action for dpctl. --- ChangeLog | 5 ++++- README | 6 ------ configure.ac | 2 +- datapath/datapath.c | 1 + datapath/flow.h | 1 + datapath/forward.c | 1 + datapath/table-linear.c | 18 +++++++++++++----- include/openflow.h | 7 +++++-- lib/ofp-print.c | 3 ++- switch/datapath.c | 2 ++ switch/switch-flow.h | 1 + switch/table-linear.c | 22 ++++++++++++++++------ utilities/dpctl.c | 16 ++++++++++++---- 13 files changed, 59 insertions(+), 26 deletions(-) diff --git a/ChangeLog b/ChangeLog index 97aa4474..0c0ba345 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ -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 diff --git a/README b/README index 3031bfe4..49363229 100644 --- a/README +++ b/README @@ -90,17 +90,11 @@ GCC is the expected compiler. 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 ---------- diff --git a/configure.ac b/configure.ac index 5d0a23ac..7b3ac1c3 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ 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 diff --git a/datapath/datapath.c b/datapath/datapath.c index 8a399fbe..a0395904 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -783,6 +783,7 @@ fill_flow_stats(struct ofp_flow_stats *ofs, struct sw_flow *flow, 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); diff --git a/datapath/flow.h b/datapath/flow.h index 5faeaf9d..3a34a9e4 100644 --- a/datapath/flow.h +++ b/datapath/flow.h @@ -67,6 +67,7 @@ struct sw_flow { 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. */ diff --git a/datapath/forward.c b/datapath/forward.c index d3d27334..aa400002 100644 --- a/datapath/forward.c +++ b/datapath/forward.c @@ -380,6 +380,7 @@ add_flow(struct sw_chain *chain, const struct ofp_flow_mod *ofm) 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; diff --git a/datapath/table-linear.c b/datapath/table-linear.c index cf0e3f8a..a82b63eb 100644 --- a/datapath/table-linear.c +++ b/datapath/table-linear.c @@ -39,10 +39,15 @@ static int table_linear_insert(struct sw_table *swt, struct sw_flow *flow) 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); @@ -50,17 +55,20 @@ static int table_linear_insert(struct sw_table *swt, struct sw_flow *flow) 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; } diff --git a/include/openflow.h b/include/openflow.h index 81b94afe..836c03a4 100644 --- a/include/openflow.h +++ b/include/openflow.h @@ -50,7 +50,7 @@ /* 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 @@ -341,6 +341,7 @@ struct ofp_flow_mod { 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. */ }; @@ -362,8 +363,10 @@ struct ofp_flow_stats { 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 { diff --git a/lib/ofp-print.c b/lib/ofp-print.c index 4983f84f..92eb87d8 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -366,7 +366,7 @@ static void ofp_print_match(struct ds *f, const struct ofp_match *om) { 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)); @@ -468,6 +468,7 @@ ofp_flow_stats_reply(struct ds *string, const void *oh, size_t len, 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)); diff --git a/switch/datapath.c b/switch/datapath.c index 18435676..c465b76a 100644 --- a/switch/datapath.c +++ b/switch/datapath.c @@ -644,6 +644,7 @@ fill_flow_stats(struct ofp_flow_stats *ofs, struct sw_flow *flow, 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); @@ -1061,6 +1062,7 @@ add_flow(struct datapath *dp, const struct ofp_flow_mod *ofm) 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 */ diff --git a/switch/switch-flow.h b/switch/switch-flow.h index 1f31cd2f..5a35c0d9 100644 --- a/switch/switch-flow.h +++ b/switch/switch-flow.h @@ -54,6 +54,7 @@ struct sw_flow { 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. */ diff --git a/switch/table-linear.c b/switch/table-linear.c index 9e7cec32..6da93a23 100644 --- a/switch/table-linear.c +++ b/switch/table-linear.c @@ -63,24 +63,34 @@ static int table_linear_insert(struct sw_table *swt, struct sw_flow *flow) 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; } diff --git a/utilities/dpctl.c b/utilities/dpctl.c index 8637202d..ac770183 100644 --- a/utilities/dpctl.c +++ b/utilities/dpctl.c @@ -455,7 +455,7 @@ str_to_action(const char *str, struct ofp_action *action) 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; @@ -505,6 +505,11 @@ str_to_flow(char *string, struct ofp_match *match, struct ofp_action *action, 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; @@ -557,7 +562,7 @@ static void do_dump_flows(int argc, char *argv[]) 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); @@ -581,6 +586,7 @@ static void do_add_flows(int argc, char *argv[]) while (fgets(line, sizeof line, file)) { struct buffer *buffer; struct ofp_flow_mod *ofm; + uint16_t priority=0; size_t size; char *comment; @@ -603,8 +609,10 @@ static void do_add_flows(int argc, char *argv[]) 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); -- 2.30.2