Emergency flow cache: Add emergency flow cache framework

Emergency flow cache use completely separate flow table from working
and its table ID for stats is 0xfe.
This commit is contained in:
Mikio Hara committed 2009-06-29 06:57:37 -07:00
1 parent e4cbc1e74a
commit 58ee7f213f
24 files changed
+874 -74

No files matched your search

+2
View File
@@ -20,6 +20,7 @@ ofdatapath_sources = \
forward.c \
nx_act.c \
nx_msg.c \
private-msg.c \
table-hash.c \
table-linear.c
@@ -34,6 +35,7 @@ ofdatapath_headers = \
dp_act.h \
nx_act.h \
nx_msg.h \
private-msg.h \
table.h
dist_sources = $(foreach module,$(dist_modules),$($(module)_sources))
+51 -14
View File
@@ -20,7 +20,7 @@ static DEFINE_SPINLOCK(hook_lock);
/* Attempts to append 'table' to the set of tables in 'chain'. Returns 0 or
* negative error. If 'table' is null it is assumed that table creation failed
* due to out-of-memory. */
static int add_table(struct sw_chain *chain, struct sw_table *table)
static int add_table(struct sw_chain *chain, struct sw_table *table, int emerg)
{
if (table == NULL)
return -ENOMEM;
@@ -30,6 +30,9 @@ static int add_table(struct sw_chain *chain, struct sw_table *table)
table->destroy(table);
return -ENOBUFS;
}
if (emerg)
chain->emerg_table = table;
else
chain->tables[chain->n_tables++] = table;
return 0;
}
@@ -45,13 +48,15 @@ struct sw_chain *chain_create(struct datapath *dp)
chain->owner = try_module_get(hw_table_owner) ? hw_table_owner : NULL;
if (chain->owner && create_hw_table_hook) {
struct sw_table *hwtable = create_hw_table_hook();
if (!hwtable || add_table(chain, hwtable))
if (!hwtable || add_table(chain, hwtable, 0))
goto error;
}
if (add_table(chain, table_hash2_create(0x1EDC6F41, TABLE_HASH_MAX_FLOWS,
0x741B8CD7, TABLE_HASH_MAX_FLOWS))
|| add_table(chain, table_linear_create(TABLE_LINEAR_MAX_FLOWS)))
0x741B8CD7, TABLE_HASH_MAX_FLOWS),
0)
|| add_table(chain, table_linear_create(TABLE_LINEAR_MAX_FLOWS), 0)
|| add_table(chain, table_linear_create(TABLE_LINEAR_MAX_FLOWS), 1))
goto error;
return chain;
@@ -66,11 +71,20 @@ error:
*
* Caller must hold rcu_read_lock or dp_mutex. */
struct sw_flow *chain_lookup(struct sw_chain *chain,
const struct sw_flow_key *key)
const struct sw_flow_key *key, int emerg)
{
int i;
BUG_ON(key->wildcards);
if (emerg) {
struct sw_table *t = chain->emerg_table;
struct sw_flow *flow = t->lookup(t, key);
t->n_lookup++;
if (flow) {
t->n_matched++;
return flow;
}
} else {
for (i = 0; i < chain->n_tables; i++) {
struct sw_table *t = chain->tables[i];
struct sw_flow *flow = t->lookup(t, key);
@@ -80,6 +94,7 @@ struct sw_flow *chain_lookup(struct sw_chain *chain,
return flow;
}
}
}
return NULL;
}
@@ -90,17 +105,22 @@ struct sw_flow *chain_lookup(struct sw_chain *chain,
* by the caller.
*
* Caller must hold dp_mutex. */
int chain_insert(struct sw_chain *chain, struct sw_flow *flow)
int chain_insert(struct sw_chain *chain, struct sw_flow *flow, int emerg)
{
int i;
might_sleep();
if (emerg) {
struct sw_table *t = chain->emerg_table;
if (t->insert(t, flow))
return 0;
} else {
for (i = 0; i < chain->n_tables; i++) {
struct sw_table *t = chain->tables[i];
if (t->insert(t, flow))
return 0;
}
}
return -ENOBUFS;
}
@@ -113,16 +133,23 @@ int chain_insert(struct sw_chain *chain, struct sw_flow *flow)
int
chain_modify(struct sw_chain *chain, const struct sw_flow_key *key,
uint16_t priority, int strict,
const struct ofp_action_header *actions, size_t actions_len)
const struct ofp_action_header *actions, size_t actions_len,
int emerg)
{
int count = 0;
int i;
if (emerg) {
struct sw_table *t = chain->emerg_table;
count += t->modify(t, key, priority, strict,
actions, actions_len);
} else {
for (i = 0; i < chain->n_tables; i++) {
struct sw_table *t = chain->tables[i];
count += t->modify(t, key, priority, strict, actions, actions_len);
count += t->modify(t, key, priority, strict,
actions, actions_len);
}
}
return count;
}
@@ -137,17 +164,23 @@ chain_modify(struct sw_chain *chain, const struct sw_flow_key *key,
*
* Caller must hold dp_mutex. */
int chain_delete(struct sw_chain *chain, const struct sw_flow_key *key,
uint16_t out_port, uint16_t priority, int strict)
uint16_t out_port, uint16_t priority, int strict, int emerg)
{
int count = 0;
int i;
might_sleep();
if (emerg) {
struct sw_table *t = chain->emerg_table;
count += t->delete(chain->dp, t, key,
out_port, priority, strict);
} else {
for (i = 0; i < chain->n_tables; i++) {
struct sw_table *t = chain->tables[i];
count += t->delete(chain->dp, t, key, out_port, priority, strict);
count += t->delete(chain->dp, t, key,
out_port, priority, strict);
}
}
return count;
}
@@ -176,13 +209,17 @@ int chain_timeout(struct sw_chain *chain)
void chain_destroy(struct sw_chain *chain)
{
int i;
struct sw_table *t = NULL;
synchronize_rcu();
for (i = 0; i < chain->n_tables; i++) {
struct sw_table *t = chain->tables[i];
t = chain->tables[i];
if (t->destroy)
t->destroy(t);
}
t = chain->emerg_table;
if (t->destroy)
t->destroy(t);
module_put(chain->owner);
kfree(chain);
}
+6 -4
View File
@@ -17,18 +17,20 @@ struct datapath;
struct sw_chain {
int n_tables;
struct sw_table *tables[CHAIN_MAX_TABLES];
struct sw_table *emerg_table;
struct datapath *dp;
struct module *owner;
};
struct sw_chain *chain_create(struct datapath *);
struct sw_flow *chain_lookup(struct sw_chain *, const struct sw_flow_key *);
int chain_insert(struct sw_chain *, struct sw_flow *);
struct sw_flow *chain_lookup(struct sw_chain *, const struct sw_flow_key *,
int);
int chain_insert(struct sw_chain *, struct sw_flow *, int);
int chain_modify(struct sw_chain *, const struct sw_flow_key *,
uint16_t, int, const struct ofp_action_header *, size_t);
uint16_t, int, const struct ofp_action_header *, size_t, int);
int chain_delete(struct sw_chain *, const struct sw_flow_key *, uint16_t,
uint16_t, int);
uint16_t, int, int);
int chain_timeout(struct sw_chain *);
void chain_destroy(struct sw_chain *);
+34 -11
View File
@@ -1467,6 +1467,8 @@ struct flow_stats_state {
int bytes_used, bytes_allocated;
};
#define EMERG_TABLE_ID_FOR_STATS 0xfe
static int flow_stats_init(struct datapath *dp, const void *body, int body_len,
void **state)
{
@@ -1541,19 +1543,28 @@ static int flow_stats_dump(struct datapath *dp, void *state,
s->body = body;
flow_extract_match(&match_key, &s->rq->match);
while (s->table_idx < dp->chain->n_tables
&& (s->rq->table_id == 0xff || s->rq->table_id == s->table_idx))
{
struct sw_table *table = dp->chain->tables[s->table_idx];
if (s->rq->table_id == EMERG_TABLE_ID_FOR_STATS) {
struct sw_table *table = dp->chain->emerg_table;
error = table->iterate(table, &match_key, s->rq->out_port,
&s->position, flow_stats_dump_callback, s);
&s->position, flow_stats_dump_callback,
s);
} else {
while (s->table_idx < dp->chain->n_tables
&& (s->rq->table_id == 0xff
|| s->rq->table_id == s->table_idx)) {
struct sw_table *table = dp->chain->tables[s->table_idx];
error = table->iterate(table, &match_key,
s->rq->out_port, &s->position,
flow_stats_dump_callback, s);
if (error)
break;
s->table_idx++;
memset(&s->position, 0, sizeof s->position);
}
}
*body_len = s->bytes_used;
/* If error is 0, we're done.
@@ -1594,6 +1605,7 @@ static int aggregate_stats_dump(struct datapath *dp, void *state,
struct sw_table_position position;
struct sw_flow_key match_key;
int table_idx;
int error = 0;
if (*body_len < sizeof *rpy)
return -ENOBUFS;
@@ -1605,20 +1617,31 @@ static int aggregate_stats_dump(struct datapath *dp, void *state,
flow_extract_match(&match_key, &rq->match);
table_idx = rq->table_id == 0xff ? 0 : rq->table_id;
memset(&position, 0, sizeof position);
while (table_idx < dp->chain->n_tables
&& (rq->table_id == 0xff || rq->table_id == table_idx))
{
struct sw_table *table = dp->chain->tables[table_idx];
int error;
error = table->iterate(table, &match_key, rq->out_port, &position,
if (rq->table_id == EMERG_TABLE_ID_FOR_STATS) {
struct sw_table *table = dp->chain->emerg_table;
error = table->iterate(table, &match_key, rq->out_port,
&position,
aggregate_stats_dump_callback, rpy);
if (error)
return error;
} else {
while (table_idx < dp->chain->n_tables
&& (rq->table_id == 0xff || rq->table_id == table_idx)) {
struct sw_table *table = dp->chain->tables[table_idx];
error = table->iterate(table, &match_key, rq->out_port,
&position,
aggregate_stats_dump_callback,
rpy);
if (error)
return error;
table_idx++;
memset(&position, 0, sizeof position);
}
}
rpy->packet_count = cpu_to_be64(rpy->packet_count);
rpy->byte_count = cpu_to_be64(rpy->byte_count);
+13 -6
View File
@@ -16,6 +16,7 @@
#include "openflow/private-ext.h"
#include "dp_act.h"
#include "nx_msg.h"
#include "private-msg.h"
#include "chain.h"
#include "flow.h"
@@ -51,7 +52,7 @@ int run_flow_through_tables(struct sw_chain *chain, struct sk_buff *skb,
return 0;
}
flow = chain_lookup(chain, &key);
flow = chain_lookup(chain, &key, 0);
if (likely(flow != NULL)) {
struct sw_flow_actions *sf_acts = rcu_dereference(flow->sf_acts);
flow_used(flow, skb);
@@ -230,7 +231,8 @@ add_flow(struct sw_chain *chain, const struct sender *sender,
flow_setup_actions(flow, ofm->actions, actions_len);
/* Act. */
error = chain_insert(chain, flow);
error = chain_insert(chain, flow,
(ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0);
if (error == -ENOBUFS) {
dp_send_error_msg(chain->dp, sender, OFPET_FLOW_MOD_FAILED,
OFPFMFC_ALL_TABLES_FULL, ofm, ntohs(ofm->header.length));
@@ -284,7 +286,8 @@ mod_flow(struct sw_chain *chain, const struct sender *sender,
priority = key.wildcards ? ntohs(ofm->priority) : -1;
strict = (ofm->command == htons(OFPFC_MODIFY_STRICT)) ? 1 : 0;
chain_modify(chain, &key, priority, strict, ofm->actions, actions_len);
chain_modify(chain, &key, priority, strict, ofm->actions, actions_len,
(ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0);
if (ntohl(ofm->buffer_id) != (uint32_t) -1) {
struct sk_buff *skb = retrieve_skb(ntohl(ofm->buffer_id));
@@ -318,14 +321,17 @@ recv_flow(struct sw_chain *chain, const struct sender *sender, const void *msg)
} else if (command == OFPFC_DELETE) {
struct sw_flow_key key;
flow_extract_match(&key, &ofm->match);
return chain_delete(chain, &key, ofm->out_port, 0, 0) ? 0 : -ESRCH;
return chain_delete(chain, &key, ofm->out_port, 0, 0,
(ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0)
? 0 : -ESRCH;
} else if (command == OFPFC_DELETE_STRICT) {
struct sw_flow_key key;
uint16_t priority;
flow_extract_match(&key, &ofm->match);
priority = key.wildcards ? ntohs(ofm->priority) : -1;
return chain_delete(chain, &key, ofm->out_port,
priority, 1) ? 0 : -ESRCH;
return chain_delete(chain, &key, ofm->out_port, priority, 1,
(ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0)
? 0 : -ESRCH;
} else {
return -ENOTSUPP;
}
@@ -342,6 +348,7 @@ recv_vendor(struct sw_chain *chain, const struct sender *sender,
case NX_VENDOR_ID:
return nx_recv_msg(chain, sender, msg);
case PRIVATE_VENDOR_ID:
return private_recv_msg(chain, sender, msg);
default:
if (net_ratelimit())
printk(KERN_NOTICE "%s: unknown vendor: 0x%x\n",
+134
View File
@@ -0,0 +1,134 @@
/*-
* Copyright (c) 2008, 2009
* The Board of Trustees of The Leland Stanford Junior University
*
* We are making the OpenFlow specification and associated documentation
* (Software) available for public use and benefit with the expectation that
* others will use, modify and enhance the Software and contribute those
* enhancements back to the community. However, since we would like to make the
* Software available for broadest use, with as few restrictions as possible
* permission is hereby granted, free of charge, to any person obtaining a copy
* of this Software to deal in the Software under the copyrights without
* restriction, including without limitation the rights to use, copy, modify,
* merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
* The name and trademarks of copyright holder(s) may NOT be used in
* advertising or publicity pertaining to the Software or any derivatives
* without specific, written prior permission.
*/
#include "openflow/private-ext.h"
#include "chain.h"
#include "datapath.h"
#include "table.h"
#include "private-msg.h"
struct emerg_flow_context {
struct sw_chain *chain;
};
static void flush_working(struct sw_chain *);
static int protection_callback(struct sw_flow *, void *);
static void do_protection(struct sw_chain *);
static void
flush_working(struct sw_chain *chain)
{
struct sw_flow_key key;
int num_deleted = 0;
memset(&key, 0, sizeof(key));
key.wildcards = OFPFW_ALL;
num_deleted = chain_delete(chain, &key, OFPP_NONE, 0, 0, 0);
}
static int
protection_callback(struct sw_flow *flow, void *private_)
{
struct emerg_flow_context *private
= (struct emerg_flow_context *)private_;
struct sw_flow_actions *actions = flow->sf_acts;
struct ofp_match match;
struct sw_flow *tgtflow = NULL;
int error = 0;
tgtflow = flow_alloc(actions->actions_len, GFP_ATOMIC);
if (tgtflow == NULL) {
return -ENOMEM;
}
/* Dup w/o idle and hard timeout. */
memset(&match, 0, sizeof(match));
flow_fill_match(&match, &flow->key);
flow_extract_match(&tgtflow->key, &match);
tgtflow->priority = flow->priority;
tgtflow->idle_timeout = 0;
tgtflow->hard_timeout = 0;
flow_setup_actions(tgtflow, actions->actions, actions->actions_len);
error = chain_insert(private->chain, tgtflow, 0);
if (error)
flow_free(tgtflow);
return error;
}
static void
do_protection(struct sw_chain *chain)
{
struct emerg_flow_context private;
struct sw_flow_key key;
struct sw_table_position position;
struct sw_table *table = chain->emerg_table;
int error = 0;
memset(&private, 0, sizeof(private));
private.chain = chain;
memset(&key, 0, sizeof(key));
key.wildcards = OFPFW_ALL;
memset(&position, 0, sizeof(position));
error = table->iterate(table, &key, OFPP_NONE,
&position, protection_callback, &private);
}
int
private_recv_msg(struct sw_chain *chain, const struct sender *sender,
const void *ofph)
{
int error = 0;
struct private_vxhdr *vxhdr = (struct private_vxhdr *)ofph;
struct private_vxopt *vxopt = (struct private_vxopt *)(vxhdr + 1);
switch (ntohs(vxopt->pvo_type)) {
case PRIVATEOPT_PROTOCOL_STATS_REQUEST:
case PRIVATEOPT_PROTOCOL_STATS_REPLY:
break;
case PRIVATEOPT_EMERG_FLOW_PROTECTION:
flush_working(chain);
do_protection(chain);
break;
case PRIVATEOPT_EMERG_FLOW_RESTORATION:
/* Nothing to do because we assume that a re-connected
* controller will do flush current working flow table. */
break;
default:
error = -EINVAL;
}
return error;
}
+38
View File
@@ -0,0 +1,38 @@
/*-
* Copyright (c) 2008, 2009
* The Board of Trustees of The Leland Stanford Junior University
*
* We are making the OpenFlow specification and associated documentation
* (Software) available for public use and benefit with the expectation that
* others will use, modify and enhance the Software and contribute those
* enhancements back to the community. However, since we would like to make the
* Software available for broadest use, with as few restrictions as possible
* permission is hereby granted, free of charge, to any person obtaining a copy
* of this Software to deal in the Software under the copyrights without
* restriction, including without limitation the rights to use, copy, modify,
* merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
* The name and trademarks of copyright holder(s) may NOT be used in
* advertising or publicity pertaining to the Software or any derivatives
* without specific, written prior permission.
*/
#ifndef PRIVATE_MSG_H_
#define PRIVATE_MSG_H_
int private_recv_msg(struct sw_chain *, const struct sender *, const void *);
#endif
+10 -4
View File
@@ -520,6 +520,12 @@ OFP_ASSERT(sizeof(struct ofp_match) == 36);
/* By default, choose a priority in the middle. */
#define OFP_DEFAULT_PRIORITY 0x8000
enum ofp_flow_mod_flags {
OFPFF_SEND_FLOW_EXP = 1 << 0, /* Send expiration message when flow expires. */
OFPFF_CHECK_OVERLAP = 1 << 1, /* Check for overlapping entries first. */
OFPFF_EMERG = 1 << 2 /* Ramark this is for emergency. */
};
/* Flow setup and teardown (controller -> datapath). */
struct ofp_flow_mod {
struct ofp_header header;
@@ -536,7 +542,7 @@ struct ofp_flow_mod {
matching entries to include this as an
output port. A value of OFPP_NONE
indicates no restriction. */
uint8_t pad[2]; /* Align to 32-bits. */
uint16_t flags; /* One of OFPFF_*. */
uint32_t reserved; /* Reserved for future use. */
struct ofp_action_header actions[0]; /* The action length is inferred
from the length field in the
@@ -689,8 +695,8 @@ OFP_ASSERT(sizeof(struct ofp_desc_stats) == 800);
/* Body for ofp_stats_request of type OFPST_FLOW. */
struct ofp_flow_stats_request {
struct ofp_match match; /* Fields to match. */
uint8_t table_id; /* ID of table to read (from ofp_table_stats)
or 0xff for all tables. */
uint8_t table_id; /* ID of table to read (from ofp_table_stats),
0xff for all tables or 0xfe for emergency. */
uint8_t pad; /* Align to 32 bits. */
uint16_t out_port; /* Require matching entries to include this
as an output port. A value of OFPP_NONE
@@ -720,7 +726,7 @@ OFP_ASSERT(sizeof(struct ofp_flow_stats) == 72);
struct ofp_aggregate_stats_request {
struct ofp_match match; /* Fields to match. */
uint8_t table_id; /* ID of table to read (from ofp_table_stats)
or 0xff for all tables. */
0xff for all tables or 0xfe for emergency. */
uint8_t pad; /* Align to 32 bits. */
uint16_t out_port; /* Require matching entries to include this
as an output port. A value of OFPP_NONE
+16 -8
View File
@@ -50,24 +50,32 @@
#ifdef __BIG_ENDIAN
#define PRIVATE_VENDOR_ID 0x00acde48
#define PRIVATEOPT_PROTOCOL_STATS_REQUEST 0x0123
#define PRIVATEOPT_PROTOCOL_STATS_REPLY 0x0456
#define PRIVATEOPT_PROTOCOL_STATS_REQUEST 0x0001
#define PRIVATEOPT_PROTOCOL_STATS_REPLY 0x0002
#define PRIVATEOPT_EMERG_FLOW_PROTECTION 0x0003
#define PRIVATEOPT_EMERG_FLOW_RESTORATION 0x0004
#else
#define PRIVATE_VENDOR_ID 0x48deac00
#define PRIVATEOPT_PROTOCOL_STATS_REQUEST 0x2301
#define PRIVATEOPT_PROTOCOL_STATS_REPLY 0x5604
#define PRIVATEOPT_PROTOCOL_STATS_REQUEST 0x0100
#define PRIVATEOPT_PROTOCOL_STATS_REPLY 0x0200
#define PRIVATEOPT_EMERG_FLOW_PROTECTION 0x0300
#define PRIVATEOPT_EMERG_FLOW_RESTORATION 0x0400
#endif
#else
#if BYTE_ORDER == BIG_ENDIAN
#define PRIVATE_VENDOR_ID 0x00acde48
#define PRIVATEOPT_PROTOCOL_STATS_REQUEST 0x0123
#define PRIVATEOPT_PROTOCOL_STATS_REPLY 0x0456
#define PRIVATEOPT_PROTOCOL_STATS_REQUEST 0x0001
#define PRIVATEOPT_PROTOCOL_STATS_REPLY 0x0002
#define PRIVATEOPT_EMERG_FLOW_PROTECTION 0x0003
#define PRIVATEOPT_EMERG_FLOW_RESTORATION 0x0004
#else
#define PRIVATE_VENDOR_ID 0x48deac00
#define PRIVATEOPT_PROTOCOL_STATS_REQUEST 0x2301
#define PRIVATEOPT_PROTOCOL_STATS_REPLY 0x5604
#define PRIVATEOPT_PROTOCOL_STATS_REQUEST 0x0100
#define PRIVATEOPT_PROTOCOL_STATS_REPLY 0x0200
#define PRIVATEOPT_EMERG_FLOW_PROTECTION 0x0300
#define PRIVATEOPT_EMERG_FLOW_RESTORATION 0x0400
#endif
#endif
+1
View File
@@ -13,6 +13,7 @@ VLOG_MODULE(dhcp_client)
VLOG_MODULE(discovery)
VLOG_MODULE(dpif)
VLOG_MODULE(dpctl)
VLOG_MODULE(emerg_flow)
VLOG_MODULE(executer)
VLOG_MODULE(fail_open)
VLOG_MODULE(failover)
+2
View File
@@ -6,6 +6,8 @@ secchan_ofprotocol_SOURCES = \
secchan/discovery.h \
secchan/executer.c \
secchan/executer.h \
secchan/emerg-flow.c \
secchan/emerg-flow.h \
secchan/fail-open.c \
secchan/fail-open.h \
secchan/failover.c \
+144
View File
@@ -0,0 +1,144 @@
/*-
* Copyright (c) 2008, 2009
* The Board of Trustees of The Leland Stanford Junior University
*
* We are making the OpenFlow specification and associated documentation
* (Software) available for public use and benefit with the expectation that
* others will use, modify and enhance the Software and contribute those
* enhancements back to the community. However, since we would like to make the
* Software available for broadest use, with as few restrictions as possible
* permission is hereby granted, free of charge, to any person obtaining a copy
* of this Software to deal in the Software under the copyrights without
* restriction, including without limitation the rights to use, copy, modify,
* merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
* The name and trademarks of copyright holder(s) may NOT be used in
* advertising or publicity pertaining to the Software or any derivatives
* without specific, written prior permission.
*/
#include <arpa/inet.h>
#include <config.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <netinet/in.h>
#include <errno.h>
#include "openflow/openflow.h"
#include "openflow/private-ext.h"
#include "util.h"
#include "vconn.h"
#include "rconn.h"
#include "secchan.h"
#include "status.h"
#include "timeval.h"
#include "sat-math.h"
#include "ofpbuf.h"
#include "emerg-flow.h"
#define THIS_MODULE VLM_emerg_flow
#include "vlog.h"
struct emerg_flow_context {
const struct settings *settings;
const struct secchan *secchan;
struct rconn *local_rconn;
struct rconn *remote_rconn;
int prev_state;
int state;
};
static void emerg_flow_status_cb(struct status_reply *, void *);
static void emerg_flow_periodic_cb(void *);
static void
emerg_flow_status_cb(struct status_reply *status_reply, void *context_)
{
struct emerg_flow_context *context = context_;
status_reply_put(status_reply, "state=%s",
context->state == PRIVATEOPT_EMERG_FLOW_RESTORATION
? "restoration"
: context->state == PRIVATEOPT_EMERG_FLOW_PROTECTION
? "protection" : "unknown");
}
static void
emerg_flow_periodic_cb(void *context_)
{
struct emerg_flow_context *context = context_;
struct ofpbuf *buf = NULL;
struct private_vxhdr *vxhdr = NULL;
struct private_vxopt *vxopt = NULL;
int error = 0;
if (rconn_is_connected(context->remote_rconn)) {
if (context->state == PRIVATEOPT_EMERG_FLOW_PROTECTION) {
context->prev_state = context->state;
context->state = PRIVATEOPT_EMERG_FLOW_RESTORATION;
} else {
return;
}
} else {
if (context->state == PRIVATEOPT_EMERG_FLOW_RESTORATION) {
context->prev_state = context->state;
context->state = PRIVATEOPT_EMERG_FLOW_PROTECTION;
} else {
return;
}
}
vxhdr = (struct private_vxhdr *)make_openflow
(sizeof(*vxhdr) + sizeof(*vxopt), OFPT_VENDOR, &buf);
vxopt = (struct private_vxopt *)(vxhdr + 1);
vxhdr->ofp_vxid = htonl(PRIVATE_VENDOR_ID);
vxopt->pvo_type = htons(context->state);
vxopt->pvo_len = htons(0);
error = rconn_send(context->local_rconn, buf, NULL);
if (error && error != EAGAIN) {
VLOG_WARN("send failed (%s)", strerror(error));
}
}
void
emerg_flow_start(struct secchan *secchan, const struct settings *settings,
struct switch_status *switch_status,
struct rconn *local_rconn, struct rconn *remote_rconn)
{
struct emerg_flow_context *context = NULL;
static struct hook_class emerg_flow_hook_class = {
NULL, /* local_packet_cb */
NULL, /* remote_packet_cb */
emerg_flow_periodic_cb, /* periodic_cb */
NULL, /* wait_cb */
NULL, /* closing_cb */
};
context = xmalloc(sizeof(*context));
context->settings = settings;
context->secchan = secchan;
context->local_rconn = local_rconn;
context->remote_rconn = remote_rconn;
context->prev_state = PRIVATEOPT_EMERG_FLOW_PROTECTION;
context->state = PRIVATEOPT_EMERG_FLOW_PROTECTION;
switch_status_register_category(switch_status, "emerg-flow",
emerg_flow_status_cb, context);
add_hook(secchan, &emerg_flow_hook_class, context);
}
+44
View File
@@ -0,0 +1,44 @@
/*-
* Copyright (c) 2008, 2009
* The Board of Trustees of The Leland Stanford Junior University
*
* We are making the OpenFlow specification and associated documentation
* (Software) available for public use and benefit with the expectation that
* others will use, modify and enhance the Software and contribute those
* enhancements back to the community. However, since we would like to make the
* Software available for broadest use, with as few restrictions as possible
* permission is hereby granted, free of charge, to any person obtaining a copy
* of this Software to deal in the Software under the copyrights without
* restriction, including without limitation the rights to use, copy, modify,
* merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
* The name and trademarks of copyright holder(s) may NOT be used in
* advertising or publicity pertaining to the Software or any derivatives
* without specific, written prior permission.
*/
#ifndef EMERG_FLOW_H_
#define EMERG_FLOW_H_ 1
struct rconn;
struct secchan;
struct settings;
struct switch_status;
void emerg_flow_start(struct secchan *, const struct settings *,
struct switch_status *, struct rconn *, struct rconn *);
#endif
+7
View File
@@ -375,6 +375,13 @@ The default will change to \fB--stp\fR at some point in the future.
When flows end on the switch, send NetFlow v5 messages to
\fIhost\fR on UDP \fIport\fR.
.TP
\fB--emerg-flow\fR
Enable emergecny flow protection and restration at the switch. If emergency
flow enabled, \fBofprotocol\fR will attempt to switch flow table to emergency's
one when a controller connection fails. The default is disabled in this
distribution.
.SS "Rate-Limiting Options"
These options configure how the switch applies a ``token bucket'' to
+12
View File
@@ -47,6 +47,7 @@
#include "dirs.h"
#include "discovery.h"
#include "executer.h"
#include "emerg-flow.h"
#include "fail-open.h"
#include "failover.h"
#include "fault.h"
@@ -233,6 +234,9 @@ main(int argc, char *argv[])
if (s.command_acl[0]) {
executer_start(&secchan, &s);
}
if (s.emerg_flow) {
emerg_flow_start(&secchan, &s, switch_status, local_rconn, remote_rconn);
}
while (s.discovery || rconn_is_alive(remote_rconn)) {
struct relay *r, *n;
@@ -593,6 +597,7 @@ parse_options(int argc, char *argv[], struct settings *s)
OPT_COMMAND_ACL,
OPT_COMMAND_DIR,
OPT_NETFLOW,
OPT_EMERG_FLOW,
VLOG_OPTION_ENUMS,
LEAK_CHECKER_OPTION_ENUMS
};
@@ -614,6 +619,7 @@ parse_options(int argc, char *argv[], struct settings *s)
{"command-acl", required_argument, 0, OPT_COMMAND_ACL},
{"command-dir", required_argument, 0, OPT_COMMAND_DIR},
{"netflow", required_argument, 0, OPT_NETFLOW},
{"emerg-flow", no_argument, 0, OPT_EMERG_FLOW},
{"verbose", optional_argument, 0, 'v'},
{"help", no_argument, 0, 'h'},
{"version", no_argument, 0, 'V'},
@@ -645,6 +651,7 @@ parse_options(int argc, char *argv[], struct settings *s)
s->command_acl = "";
s->command_dir = xasprintf("%s/commands", ofp_pkgdatadir);
s->netflow_dst = NULL;
s->emerg_flow = false;
for (;;) {
int c;
@@ -752,6 +759,10 @@ parse_options(int argc, char *argv[], struct settings *s)
s->netflow_dst = optarg;
break;
case OPT_EMERG_FLOW:
s->emerg_flow = true;
break;
case 'l':
if (s->n_listeners >= MAX_MGMT) {
ofp_fatal(0,
@@ -889,6 +900,7 @@ usage(void)
" --stp enable 802.1D Spanning Tree Protocol\n"
" --no-stp disable 802.1D Spanning Tree Protocol\n"
" --netflow=HOST:PORT send NetFlow v5 messages when flows end\n"
" --emerg-flow enable emergency flow protection/restoration\n"
"\nRate-limiting of \"packet-in\" messages to the controller:\n"
" --rate-limit[=PACKETS] max rate, in packets/s (default: 1000)\n"
" --burst-limit=BURST limit on packet credit for idle time\n"
+3
View File
@@ -91,6 +91,9 @@ struct settings {
/* NetFlow logging. */
char *netflow_dst; /* Host and port to send NetFlow traffic. */
/* Emergency flow protection/restoration behavior. */
bool emerg_flow;
};
struct half {
+2
View File
@@ -15,6 +15,8 @@ udatapath_ofdatapath_SOURCES = \
udatapath/nx_msg.c \
udatapath/nx_msg.h \
udatapath/udatapath.c \
udatapath/private-msg.c \
udatapath/private-msg.h \
udatapath/switch-flow.c \
udatapath/switch-flow.h \
udatapath/table.h \
+45 -8
View File
@@ -45,7 +45,7 @@
/* Attempts to append 'table' to the set of tables in 'chain'. Returns 0 or
* negative error. If 'table' is null it is assumed that table creation failed
* due to out-of-memory. */
static int add_table(struct sw_chain *chain, struct sw_table *table)
static int add_table(struct sw_chain *chain, struct sw_table *table, int emerg)
{
if (table == NULL)
return -ENOMEM;
@@ -54,6 +54,9 @@ static int add_table(struct sw_chain *chain, struct sw_table *table)
table->destroy(table);
return -ENOBUFS;
}
if (emerg)
chain->emerg_table = table;
else
chain->tables[chain->n_tables++] = table;
return 0;
}
@@ -68,8 +71,10 @@ struct sw_chain *chain_create(struct datapath *dp)
chain->dp = dp;
if (add_table(chain, table_hash2_create(0x1EDC6F41, TABLE_HASH_MAX_FLOWS,
0x741B8CD7, TABLE_HASH_MAX_FLOWS))
|| add_table(chain, table_linear_create(TABLE_LINEAR_MAX_FLOWS))) {
0x741B8CD7, TABLE_HASH_MAX_FLOWS),
0)
|| add_table(chain, table_linear_create(TABLE_LINEAR_MAX_FLOWS), 0)
|| add_table(chain, table_linear_create(TABLE_LINEAR_MAX_FLOWS), 1)) {
chain_destroy(chain);
return NULL;
}
@@ -80,11 +85,21 @@ struct sw_chain *chain_create(struct datapath *dp)
/* Searches 'chain' for a flow matching 'key', which must not have any wildcard
* fields. Returns the flow if successful, otherwise a null pointer. */
struct sw_flow *
chain_lookup(struct sw_chain *chain, const struct sw_flow_key *key)
chain_lookup(struct sw_chain *chain, const struct sw_flow_key *key, int emerg)
{
int i;
assert(!key->wildcards);
if (emerg) {
struct sw_table *t = chain->emerg_table;
struct sw_flow *flow = t->lookup(t, key);
t->n_lookup++;
if (flow) {
t->n_matched++;
return flow;
}
} else {
for (i = 0; i < chain->n_tables; i++) {
struct sw_table *t = chain->tables[i];
struct sw_flow *flow = t->lookup(t, key);
@@ -94,6 +109,8 @@ chain_lookup(struct sw_chain *chain, const struct sw_flow_key *key)
return flow;
}
}
}
return NULL;
}
@@ -103,15 +120,21 @@ chain_lookup(struct sw_chain *chain, const struct sw_flow_key *key)
* If successful, 'flow' becomes owned by the chain, otherwise it is retained
* by the caller. */
int
chain_insert(struct sw_chain *chain, struct sw_flow *flow)
chain_insert(struct sw_chain *chain, struct sw_flow *flow, int emerg)
{
int i;
if (emerg) {
struct sw_table *t = chain->emerg_table;
if (t->insert(t, flow))
return 0;
} else {
for (i = 0; i < chain->n_tables; i++) {
struct sw_table *t = chain->tables[i];
if (t->insert(t, flow))
return 0;
}
}
return -ENOBUFS;
}
@@ -125,15 +148,21 @@ chain_insert(struct sw_chain *chain, struct sw_flow *flow)
int
chain_modify(struct sw_chain *chain, const struct sw_flow_key *key,
uint16_t priority, int strict,
const struct ofp_action_header *actions, size_t actions_len)
const struct ofp_action_header *actions, size_t actions_len,
int emerg)
{
int count = 0;
int i;
if (emerg) {
struct sw_table *t = chain->emerg_table;
count += t->modify(t, key, priority, strict, actions, actions_len);
} else {
for (i = 0; i < chain->n_tables; i++) {
struct sw_table *t = chain->tables[i];
count += t->modify(t, key, priority, strict, actions, actions_len);
}
}
return count;
}
@@ -148,15 +177,20 @@ chain_modify(struct sw_chain *chain, const struct sw_flow_key *key,
* wildcards. Relatively cheap for fully specified keys. */
int
chain_delete(struct sw_chain *chain, const struct sw_flow_key *key,
uint16_t out_port, uint16_t priority, int strict)
uint16_t out_port, uint16_t priority, int strict, int emerg)
{
int count = 0;
int i;
if (emerg) {
struct sw_table *t = chain->emerg_table;
count += t->delete(chain->dp, t, key, out_port, priority, strict);
} else {
for (i = 0; i < chain->n_tables; i++) {
struct sw_table *t = chain->tables[i];
count += t->delete(chain->dp, t, key, out_port, priority, strict);
}
}
return count;
@@ -183,10 +217,13 @@ void
chain_destroy(struct sw_chain *chain)
{
int i;
struct sw_table *t;
for (i = 0; i < chain->n_tables; i++) {
struct sw_table *t = chain->tables[i];
t = chain->tables[i];
t->destroy(t);
}
t = chain->emerg_table;
t->destroy(t);
free(chain);
}
+7 -5
View File
@@ -51,19 +51,21 @@ struct datapath;
/* Set of tables chained together in sequence from cheap to expensive. */
#define CHAIN_MAX_TABLES 4
struct sw_chain {
int n_tables;
int n_tables; /* Number of working tables, not includes
* protection (emergency) table. */
struct sw_table *tables[CHAIN_MAX_TABLES];
struct sw_table *emerg_table;
struct datapath *dp;
};
struct sw_chain *chain_create(struct datapath *);
struct sw_flow *chain_lookup(struct sw_chain *, const struct sw_flow_key *);
int chain_insert(struct sw_chain *, struct sw_flow *);
struct sw_flow *chain_lookup(struct sw_chain *, const struct sw_flow_key *, int);
int chain_insert(struct sw_chain *, struct sw_flow *, int);
int chain_modify(struct sw_chain *, const struct sw_flow_key *,
uint16_t, int, const struct ofp_action_header *, size_t);
uint16_t, int, const struct ofp_action_header *, size_t, int);
int chain_delete(struct sw_chain *, const struct sw_flow_key *, uint16_t,
uint16_t, int);
uint16_t, int, int);
void chain_timeout(struct sw_chain *, struct list *deleted);
void chain_destroy(struct sw_chain *);
+36 -7
View File
@@ -55,6 +55,7 @@
#include "vconn.h"
#include "xtoxll.h"
#include "nx_msg.h"
#include "private-msg.h"
#include "dp_act.h"
#define THIS_MODULE VLM_datapath
@@ -835,7 +836,8 @@ int run_flow_through_tables(struct datapath *dp, struct ofpbuf *buffer,
return 0;
}
flow = chain_lookup(dp->chain, &key);
flow = chain_lookup(dp->chain, &key, 0);
if (flow != NULL) {
flow_used(flow, buffer);
execute_actions(dp, buffer, &key, flow->sf_acts->actions,
@@ -986,7 +988,8 @@ add_flow(struct datapath *dp, const struct sender *sender,
flow_setup_actions(flow, ofm->actions, actions_len);
/* Act. */
error = chain_insert(dp->chain, flow);
error = chain_insert(dp->chain, flow,
(ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0);
if (error == -ENOBUFS) {
dp_send_error_msg(dp, sender, OFPET_FLOW_MOD_FAILED,
OFPFMFC_ALL_TABLES_FULL, ofm, ntohs(ofm->header.length));
@@ -994,6 +997,7 @@ add_flow(struct datapath *dp, const struct sender *sender,
} else if (error) {
goto error_free_flow;
}
error = 0;
if (ntohl(ofm->buffer_id) != UINT32_MAX) {
struct ofpbuf *buffer = retrieve_buffer(ntohl(ofm->buffer_id));
@@ -1042,7 +1046,8 @@ mod_flow(struct datapath *dp, const struct sender *sender,
priority = key.wildcards ? ntohs(ofm->priority) : -1;
strict = (ofm->command == htons(OFPFC_MODIFY_STRICT)) ? 1 : 0;
chain_modify(dp->chain, &key, priority, strict, ofm->actions, actions_len);
chain_modify(dp->chain, &key, priority, strict, ofm->actions, actions_len,
(ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0);
if (ntohl(ofm->buffer_id) != UINT32_MAX) {
struct ofpbuf *buffer = retrieve_buffer(ntohl(ofm->buffer_id));
@@ -1078,14 +1083,17 @@ recv_flow(struct datapath *dp, const struct sender *sender,
} else if (command == OFPFC_DELETE) {
struct sw_flow_key key;
flow_extract_match(&key, &ofm->match);
return chain_delete(dp->chain, &key, ofm->out_port, 0, 0) ? 0 : -ESRCH;
return chain_delete(dp->chain, &key, ofm->out_port, 0, 0,
(ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0)
? 0 : -ESRCH;
} else if (command == OFPFC_DELETE_STRICT) {
struct sw_flow_key key;
uint16_t priority;
flow_extract_match(&key, &ofm->match);
priority = key.wildcards ? ntohs(ofm->priority) : -1;
return chain_delete(dp->chain, &key, ofm->out_port,
priority, 1) ? 0 : -ESRCH;
return chain_delete(dp->chain, &key, ofm->out_port, priority, 1,
(ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0)
? 0 : -ESRCH;
} else {
return -ENODEV;
}
@@ -1115,6 +1123,7 @@ struct flow_stats_state {
};
#define MAX_FLOW_STATS_BYTES 4096
#define EMERG_TABLE_ID_FOR_STATS 0xfe
static int
flow_stats_init(const void *body, int body_len UNUSED, void **state)
@@ -1144,6 +1153,13 @@ static int flow_stats_dump(struct datapath *dp, void *state,
flow_extract_match(&match_key, &s->rq.match);
s->buffer = buffer;
s->now = time_msec();
if (s->rq.table_id == EMERG_TABLE_ID_FOR_STATS) {
struct sw_table *table = dp->chain->emerg_table;
table->iterate(table, &match_key, s->rq.out_port,
&s->position, flow_stats_dump_callback, s);
} else {
while (s->table_idx < dp->chain->n_tables
&& (s->rq.table_id == 0xff || s->rq.table_id == s->table_idx))
{
@@ -1156,6 +1172,7 @@ static int flow_stats_dump(struct datapath *dp, void *state,
s->table_idx++;
memset(&s->position, 0, sizeof s->position);
}
}
return s->buffer->size >= MAX_FLOW_STATS_BYTES;
}
@@ -1196,6 +1213,7 @@ static int aggregate_stats_dump(struct datapath *dp, void *state,
struct sw_table_position position;
struct sw_flow_key match_key;
int table_idx;
int error;
rpy = ofpbuf_put_uninit(buffer, sizeof *rpy);
memset(rpy, 0, sizeof *rpy);
@@ -1203,11 +1221,19 @@ static int aggregate_stats_dump(struct datapath *dp, void *state,
flow_extract_match(&match_key, &rq->match);
table_idx = rq->table_id == 0xff ? 0 : rq->table_id;
memset(&position, 0, sizeof position);
if (rq->table_id == EMERG_TABLE_ID_FOR_STATS) {
struct sw_table *table = dp->chain->emerg_table;
error = table->iterate(table, &match_key, rq->out_port, &position,
aggregate_stats_dump_callback, rpy);
if (error)
return error;
} else {
while (table_idx < dp->chain->n_tables
&& (rq->table_id == 0xff || rq->table_id == table_idx))
{
struct sw_table *table = dp->chain->tables[table_idx];
int error;
error = table->iterate(table, &match_key, rq->out_port, &position,
aggregate_stats_dump_callback, rpy);
@@ -1217,6 +1243,7 @@ static int aggregate_stats_dump(struct datapath *dp, void *state,
table_idx++;
memset(&position, 0, sizeof position);
}
}
rpy->packet_count = htonll(rpy->packet_count);
rpy->byte_count = htonll(rpy->byte_count);
@@ -1582,6 +1609,8 @@ recv_vendor(struct datapath *dp, const struct sender *sender,
return nx_recv_msg(dp, sender, oh);
case PRIVATE_VENDOR_ID:
return private_recv_msg(dp, sender, oh);
default:
VLOG_WARN_RL(&rl, "unknown vendor: 0x%x\n", ntohl(ovh->vendor));
dp_send_error_msg(dp, sender, OFPET_BAD_REQUEST,
+137
View File
@@ -0,0 +1,137 @@
/*-
* Copyright (c) 2008, 2009
* The Board of Trustees of The Leland Stanford Junior University
*
* We are making the OpenFlow specification and associated documentation
* (Software) available for public use and benefit with the expectation that
* others will use, modify and enhance the Software and contribute those
* enhancements back to the community. However, since we would like to make the
* Software available for broadest use, with as few restrictions as possible
* permission is hereby granted, free of charge, to any person obtaining a copy
* of this Software to deal in the Software under the copyrights without
* restriction, including without limitation the rights to use, copy, modify,
* merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
* The name and trademarks of copyright holder(s) may NOT be used in
* advertising or publicity pertaining to the Software or any derivatives
* without specific, written prior permission.
*/
#include <errno.h>
#include <arpa/inet.h>
#include "openflow/private-ext.h"
#include "chain.h"
#include "datapath.h"
#include "switch-flow.h"
#include "table.h"
#include "private-msg.h"
struct emerg_flow_context {
struct datapath *dp;
};
static void flush_working(struct datapath *);
static int protection_callback(struct sw_flow *, void *);
static void do_protection(struct datapath *);
static void
flush_working(struct datapath *dp)
{
struct sw_flow_key key;
int num_deleted = 0;
memset(&key, 0, sizeof(key));
key.wildcards = OFPFW_ALL;
num_deleted = chain_delete(dp->chain, &key, OFPP_NONE, 0, 0, 0);
}
static int
protection_callback(struct sw_flow *flow, void *private_)
{
struct emerg_flow_context *private
= (struct emerg_flow_context *)private_;
struct sw_flow_actions *actions = flow->sf_acts;
struct ofp_match match;
struct sw_flow *tgtflow = NULL;
int error = 0;
tgtflow = flow_alloc(flow->sf_acts->actions_len);
if (tgtflow == NULL)
return -ENOBUFS;
/* Dup w/o idle and hard timeout. */
memset(&match, 0, sizeof(match));
flow_fill_match(&match, &flow->key.flow, flow->key.wildcards);
flow_extract_match(&tgtflow->key, &match);
tgtflow->priority = flow->priority;
tgtflow->idle_timeout = 0;
tgtflow->hard_timeout = 0;
flow_setup_actions(tgtflow, actions->actions, actions->actions_len);
error = chain_insert(private->dp->chain, tgtflow, 0);
if (error)
flow_free(tgtflow);
return error;
}
static void
do_protection(struct datapath *dp)
{
struct emerg_flow_context private;
struct sw_flow_key key;
struct sw_table_position position;
struct sw_table *table = dp->chain->emerg_table;
int error = 0;
memset(&private, 0, sizeof(private));
private.dp = dp;
memset(&key, 0, sizeof(key));
key.wildcards = OFPFW_ALL;
memset(&position, 0, sizeof(position));
error = table->iterate(table, &key, OFPP_NONE,
&position, protection_callback, &private);
}
int
private_recv_msg(struct datapath *dp, const struct sender *sender,
const void *ofph)
{
struct private_vxhdr *vxhdr = ofph;
struct private_vxopt *vxopt = (vxhdr + 1);
int error = 0;
switch (ntohs(vxopt->pvo_type)) {
case PRIVATEOPT_PROTOCOL_STATS_REQUEST:
case PRIVATEOPT_PROTOCOL_STATS_REPLY:
break;
case PRIVATEOPT_EMERG_FLOW_PROTECTION:
flush_working(dp);
do_protection(dp);
break;
case PRIVATEOPT_EMERG_FLOW_RESTORATION:
/* Nothing to do because we assume that a re-connected
* controller will do flush current working flow table. */
break;
default:
error = -EINVAL;
}
return error;
}
+42
View File
@@ -0,0 +1,42 @@
/*-
* Copyright (c) 2008, 2009
* The Board of Trustees of The Leland Stanford Junior University
*
* We are making the OpenFlow specification and associated documentation
* (Software) available for public use and benefit with the expectation that
* others will use, modify and enhance the Software and contribute those
* enhancements back to the community. However, since we would like to make the
* Software available for broadest use, with as few restrictions as possible
* permission is hereby granted, free of charge, to any person obtaining a copy
* of this Software to deal in the Software under the copyrights without
* restriction, including without limitation the rights to use, copy, modify,
* merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
* The name and trademarks of copyright holder(s) may NOT be used in
* advertising or publicity pertaining to the Software or any derivatives
* without specific, written prior permission.
*/
#ifndef PRIVATE_MSG_H_
#define PRIVATE_MSG_H_
#include "datapath.h"
struct sender;
int private_recv_msg(struct datapath *, const struct sender *, const void *);
#endif
+23 -7
View File
@@ -186,6 +186,12 @@ Add flow entries as described in \fIfile\fR to the datapath \fIswitch\fR's
tables. Each line in \fIfile\fR is a flow entry in the format
described in \fBFLOW SYNTAX\fR, below.
.TP
\fBadd-emerg-flow \fIswitch flow\fR
Add the emergency flow entry as described by \fIflow\fR to the datapath
\fIswitch\fR's tables. The flow entry is in the format described in
\fBFLOW SYNTAX\fR, below.
.TP
\fBmod-flows \fIswitch flow\fR
Modify the actions in entries from the datapath \fIswitch\fR's tables
@@ -202,6 +208,15 @@ omitted and the \fB--strict\fR option is not used, all flows in the
datapath's tables are removed. See \fBFLOW SYNTAX\fR, below, for the
syntax of \fIflows\fR.
.TP
\fBdel-emerg-flows \fIswitch \fR[\fIflow\fR]
Deletes emergency entries from the datapath \fIswitch\fR's tables that match
\fIflow\fR. When invoked with the \fB--strict\fR option, wildcards are
not treated as active for matching purposes. If \fIflow\fR is
omitted and the \fB--strict\fR option is not used, all flows in the
datapath's tables are removed. See \fBFLOW SYNTAX\fR, below, for the
syntax of \fIflows\fR.
.TP
\fBmonitor \fIswitch\fR
Connects to \fIswitch\fR and prints to the console all OpenFlow
@@ -339,7 +354,8 @@ Same as \fBdl_type=0x0800,nw_proto=17\fR.
Same as \fBdl_type=0x0806\fR.
.PP
The \fBadd-flow\fR and \fBadd-flows\fR commands require an additional field:
The \fBadd-flow\fR, \fBadd-flows\fR and \fBadd-emerg-flow\fR commands
require an additional field:
.IP \fIactions\fB=\fItarget\fR[\fB,\fItarget\fR...]\fR
Specifies a comma-separated list of actions to take on a packet when the
@@ -403,8 +419,8 @@ Strips the VLAN tag from a packet if it is present.
not yet expose to the user.)
.PP
The \fBadd-flow\fR, \fBadd-flows\fR, and \fBdel-flows\fR commands
support an additional optional field:
The \fBadd-flow\fR, \fBadd-flows\fR, \fBadd-emerg-flow\fR, \fBdel-flows\fR,
and \fBdel-emerg-flows\fR commands support an additional optional field:
.IP \fBpriority=\fIvalue\fR
Sets the priority of the flow to be added or deleted to \fIvalue\fR,
@@ -412,8 +428,8 @@ which should be a number between 0 and 65535, inclusive. If this
field is not specified, it defaults to 32768.
.PP
The \fBadd-flow\fR and \fBadd-flows\fR commands support additional
optional fields:
The \fBadd-flow\fR, \fBadd-flows\fR and \fBadd-emerg-flow\fR commands support
additional optional fields:
.TP
\fBidle_timeout=\fIseconds\fR
@@ -427,8 +443,8 @@ regardless of activity. A value of 0 (the default) gives the flow no
hard expiration deadline.
.PP
The \fBdump-flows\fR, \fBdump-aggregate\fR, \fBdel-flow\fR
and \fBdel-flows\fR commands support the additional optional field:
The \fBdump-flows\fR, \fBdump-aggregate\fR, \fBdel-flows\fR
and \fBdel-emerg-flows\fR commands support the additional optional field:
.TP
\fBout_port=\fIport\fR
+65
View File
@@ -237,8 +237,10 @@ usage(void)
" dump-aggregate SWITCH FLOW print aggregate stats for FLOWs\n"
" add-flow SWITCH FLOW add flow described by FLOW\n"
" add-flows SWITCH FILE add flows from FILE\n"
" add-emerg-flow SWITCH FLOW add emergency flow described by FLOW\n"
" mod-flows SWITCH FLOW modify actions of matching FLOWs\n"
" del-flows SWITCH [FLOW] delete matching FLOWs\n"
" del-emerg-flows SWITCH [FLOW] delete matching emergency FLOWs\n"
" monitor SWITCH print packets received from SWITCH\n"
" execute SWITCH CMD [ARG...] execute CMD with ARGS on SWITCH\n"
"\nFor local datapaths, remote switches, and controllers:\n"
@@ -1078,6 +1080,36 @@ do_add_flow(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
vconn_close(vconn);
}
static void
do_add_emerg_flow(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
{
struct vconn *vconn;
struct ofpbuf *buffer;
struct ofp_flow_mod *ofm;
uint16_t priority, idle_timeout, hard_timeout, flags;
struct ofp_match match;
/* Parse and send. str_to_flow() will expand and reallocate the data in
* 'buffer', so we can't keep pointers to across the str_to_flow() call. */
make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer);
str_to_flow(argv[2], &match, buffer,
NULL, NULL, &priority, &idle_timeout, &hard_timeout);
ofm = buffer->data;
ofm->match = match;
ofm->command = htons(OFPFC_ADD);
ofm->idle_timeout = htons(idle_timeout);
ofm->hard_timeout = htons(hard_timeout);
ofm->buffer_id = htonl(UINT32_MAX);
ofm->priority = htons(priority);
flags = OFPFF_EMERG;
ofm->flags = htons(flags);
ofm->reserved = htonl(0);
open_vconn(argv[1], &vconn);
send_openflow_buffer(vconn, buffer);
vconn_close(vconn);
}
static void
do_add_flows(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
{
@@ -1188,6 +1220,37 @@ static void do_del_flows(const struct settings *s, int argc, char *argv[])
vconn_close(vconn);
}
static void do_del_emerg_flows(const struct settings *s, int argc, char *argv[])
{
struct vconn *vconn;
uint16_t priority;
uint16_t out_port;
uint16_t flags;
struct ofpbuf *buffer;
struct ofp_flow_mod *ofm;
/* Parse and send. */
ofm = make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer);
str_to_flow(argc > 2 ? argv[2] : "", &ofm->match, NULL, NULL,
&out_port, &priority, NULL, NULL);
if (s->strict) {
ofm->command = htons(OFPFC_DELETE_STRICT);
} else {
ofm->command = htons(OFPFC_DELETE);
}
ofm->idle_timeout = htons(0);
ofm->hard_timeout = htons(0);
ofm->buffer_id = htonl(UINT32_MAX);
ofm->out_port = htons(out_port);
ofm->priority = htons(priority);
flags = OFPFF_EMERG;
ofm->flags = htons(flags);
ofm->reserved = htonl(0);
open_vconn(argv[1], &vconn);
send_openflow_buffer(vconn, buffer);
vconn_close(vconn);
}
static void
do_monitor(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
@@ -1498,8 +1561,10 @@ static struct command all_commands[] = {
{ "dump-aggregate", 1, 2, do_dump_aggregate },
{ "add-flow", 2, 2, do_add_flow },
{ "add-flows", 2, 2, do_add_flows },
{ "add-emerg-flow", 2, 2, do_add_emerg_flow },
{ "mod-flows", 2, 2, do_mod_flows },
{ "del-flows", 1, 2, do_del_flows },
{ "del-emerg-flows", 1, 2, do_del_emerg_flows },
{ "dump-ports", 1, 1, do_dump_ports },
{ "mod-port", 3, 3, do_mod_port },
{ "probe", 1, 1, do_probe },