#include "rconn.h"
#include "vconn.h"
#include "table.h"
+#include "timeval.h"
#include "xtoxll.h"
#define THIS_MODULE VLM_datapath
struct sw_chain *chain; /* Forwarding rules. */
- struct ofp_switch_config config;
+ /* Configuration set from controller. */
+ uint16_t flags;
+ uint16_t miss_send_len;
/* Switch ports. */
struct sw_port ports[OFPP_MAX];
void dp_update_port_flags(struct datapath *dp, const struct ofp_phy_port *opp);
void dp_output_control(struct datapath *, struct buffer *, int in_port,
size_t max_len, int reason);
-static void send_flow_expired(struct datapath *, struct sw_flow *);
+static void send_flow_expired(struct datapath *, struct sw_flow *,
+ enum ofp_flow_expired_reason);
static void send_port_status(struct sw_port *p, uint8_t status);
static void del_switch_port(struct sw_port *p);
static void execute_actions(struct datapath *, struct buffer *,
#define PKT_COOKIE_BITS (32 - PKT_BUFFER_BITS)
+int run_flow_through_tables(struct datapath *, struct buffer *, int in_port);
void fwd_port_input(struct datapath *, struct buffer *, int in_port);
int fwd_control_input(struct datapath *, const struct sender *,
const void *, size_t);
return ENOMEM;
}
- dp->last_timeout = time(0);
+ dp->last_timeout = time_now();
list_init(&dp->remotes);
dp->controller = remote_create(dp, rconn);
dp->listen_vconn = NULL;
}
list_init(&dp->port_list);
- dp->config.flags = 0;
- dp->config.miss_send_len = htons(OFP_DEFAULT_MISS_SEND_LEN);
+ dp->flags = 0;
+ dp->miss_send_len = OFP_DEFAULT_MISS_SEND_LEN;
*dp_ = dp;
return 0;
}
void
dp_run(struct datapath *dp)
{
- time_t now = time(0);
+ time_t now = time_now();
struct sw_port *p, *pn;
struct remote *r, *rn;
struct buffer *buffer = NULL;
chain_timeout(dp->chain, &deleted);
LIST_FOR_EACH_SAFE (f, n, struct sw_flow, node, &deleted) {
- send_flow_expired(dp, f);
+ send_flow_expired(dp, f, f->reason);
list_remove(&f->node);
flow_free(f);
}
} else if (out_port == OFPP_CONTROLLER) {
dp_output_control(dp, buffer, in_port, 0, OFPR_ACTION);
} else if (out_port == OFPP_TABLE) {
- struct sw_flow_key key;
- struct sw_flow *flow;
-
- key.wildcards = 0;
- flow_extract(buffer, in_port, &key.flow);
- flow = chain_lookup(dp->chain, &key);
- if (flow != NULL) {
- flow_used(flow, buffer);
- execute_actions(dp, buffer, in_port, &key,
- flow->actions, flow->n_actions);
- } else {
- buffer_delete(buffer);
+ if (run_flow_through_tables(dp, buffer, in_port)) {
+ buffer_delete(buffer);
}
} else {
output_packet(dp, buffer, out_port);
}
void
-send_flow_expired(struct datapath *dp, struct sw_flow *flow)
+send_flow_expired(struct datapath *dp, struct sw_flow *flow,
+ enum ofp_flow_expired_reason reason)
{
struct buffer *buffer;
struct ofp_flow_expired *ofe;
ofe = make_openflow_xid(sizeof *ofe, OFPT_FLOW_EXPIRED, 0, &buffer);
flow_fill_match(&ofe->match, &flow->key);
- memset(ofe->pad, 0, sizeof ofe->pad);
ofe->priority = htons(flow->priority);
+ ofe->reason = reason;
+ memset(ofe->pad, 0, sizeof ofe->pad);
- ofe->duration = htonl(flow->timeout - flow->max_idle - flow->created);
+ ofe->duration = htonl(time_now() - flow->created);
+ memset(ofe->pad2, 0, sizeof ofe->pad2);
ofe->packet_count = htonll(flow->packet_count);
ofe->byte_count = htonll(flow->byte_count);
send_openflow_buffer(dp, buffer, NULL);
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->idle_timeout = htons(flow->idle_timeout);
+ ofs->hard_timeout = htons(flow->hard_timeout);
+ memset(ofs->pad2, 0, sizeof ofs->pad2);
ofs->packet_count = htonll(flow->packet_count);
ofs->byte_count = htonll(flow->byte_count);
- ofs->priority = htons(flow->priority);
- ofs->max_idle = htons(flow->max_idle);
memcpy(ofs->actions, flow->actions,
sizeof *ofs->actions * flow->n_actions);
}
\f
/* 'buffer' was received on 'in_port', a physical switch port between 0 and
- * OFPP_MAX. Process it according to 'chain'. */
-void fwd_port_input(struct datapath *dp, struct buffer *buffer, int in_port)
+ * OFPP_MAX. Process it according to 'dp''s flow table. Returns 0 if
+ * successful, in which case 'buffer' is destroyed, or -ESRCH if there is no
+ * matching flow, in which case 'buffer' still belongs to the caller. */
+int run_flow_through_tables(struct datapath *dp, struct buffer *buffer,
+ int in_port)
{
struct sw_flow_key key;
struct sw_flow *flow;
key.wildcards = 0;
- flow_extract(buffer, in_port, &key.flow);
+ if (flow_extract(buffer, in_port, &key.flow)
+ && (dp->flags & OFPC_FRAG_MASK) == OFPC_FRAG_DROP) {
+ /* Drop fragment. */
+ buffer_delete(buffer);
+ return 0;
+ }
+
flow = chain_lookup(dp->chain, &key);
if (flow != NULL) {
flow_used(flow, buffer);
execute_actions(dp, buffer, in_port, &key,
flow->actions, flow->n_actions);
+ return 0;
} else {
- dp_output_control(dp, buffer, in_port, ntohs(dp->config.miss_send_len),
+ return -ESRCH;
+ }
+}
+
+/* 'buffer' was received on 'in_port', a physical switch port between 0 and
+ * OFPP_MAX. Process it according to 'dp''s flow table, sending it up to the
+ * controller if no flow matches. Takes ownership of 'buffer'. */
+void fwd_port_input(struct datapath *dp, struct buffer *buffer, int in_port)
+{
+ if (run_flow_through_tables(dp, buffer, in_port)) {
+ dp_output_control(dp, buffer, in_port, dp->miss_send_len,
OFPR_NO_MATCH);
}
}
osc = make_openflow_reply(sizeof *osc, OFPT_GET_CONFIG_REPLY,
sender, &buffer);
- assert(sizeof *osc == sizeof dp->config);
- memcpy(((char *)osc) + sizeof osc->header,
- ((char *)&dp->config) + sizeof dp->config.header,
- sizeof dp->config - sizeof dp->config.header);
+ osc->flags = htons(dp->flags);
+ osc->miss_send_len = htons(dp->miss_send_len);
return send_openflow_buffer(dp, buffer, sender);
}
const void *msg)
{
const struct ofp_switch_config *osc = msg;
- dp->config = *osc;
+ int flags;
+
+ flags = ntohs(osc->flags) & (OFPC_SEND_FLOW_EXP | OFPC_FRAG_MASK);
+ if ((flags & OFPC_FRAG_MASK) != OFPC_FRAG_NORMAL
+ && (flags & OFPC_FRAG_MASK) != OFPC_FRAG_DROP) {
+ flags = (flags & ~OFPC_FRAG_MASK) | OFPC_FRAG_DROP;
+ }
+ dp->flags = flags;
+ dp->miss_send_len = ntohs(osc->miss_send_len);
return 0;
}
/* Fill out flow. */
flow_extract_match(&flow->key, &ofm->match);
- flow->max_idle = ntohs(ofm->max_idle);
flow->priority = flow->key.wildcards ? ntohs(ofm->priority) : -1;
- flow->timeout = time(0) + flow->max_idle; /* FIXME */
+ flow->idle_timeout = ntohs(ofm->idle_timeout);
+ flow->hard_timeout = ntohs(ofm->hard_timeout);
+ flow->used = flow->created = time_now();
flow->n_actions = n_acts;
- flow->created = time(0); /* FIXME */
flow->byte_count = 0;
flow->packet_count = 0;
memcpy(flow->actions, ofm->actions, n_acts * sizeof *flow->actions);
flow_extract_match(&match_key, &s->rq.match);
s->buffer = buffer;
- s->now = time(0);
+ s->now = time_now();
while (s->table_idx < dp->chain->n_tables
&& (s->rq.table_id == 0xff || s->rq.table_id == s->table_idx))
{
if (p->buffer) {
/* Don't buffer packet if existing entry is less than
* OVERWRITE_SECS old. */
- if (time(0) < p->timeout) { /* FIXME */
+ if (time_now() < p->timeout) { /* FIXME */
return -1;
} else {
buffer_delete(p->buffer);
if (++p->cookie >= (1u << PKT_COOKIE_BITS) - 1)
p->cookie = 0;
p->buffer = buffer_clone(buffer); /* FIXME */
- p->timeout = time(0) + OVERWRITE_SECS; /* FIXME */
+ p->timeout = time_now() + OVERWRITE_SECS; /* FIXME */
id = buffer_idx | (p->cookie << PKT_BUFFER_BITS);
return id;