OFPR_ACTION);
else if (out_port == OFPP_TABLE) {
struct net_bridge_port *p = skb->dev->br_port;
- struct sw_flow_key key;
- struct sw_flow *flow;
-
- flow_extract(skb, p ? p->port_no : OFPP_LOCAL, &key);
- flow = chain_lookup(dp->chain, &key);
- if (likely(flow != NULL)) {
- flow_used(flow, skb);
- execute_actions(dp, skb, &key, flow->actions, flow->n_actions);
- return 0;
- }
- kfree_skb(skb);
- return -ESRCH;
+ int retval;
+ retval = run_flow_through_tables(dp->chain, skb,
+ p ? p->port_no : OFPP_LOCAL);
+ if (retval)
+ kfree_skb(skb);
+ return retval;
} else if (out_port == OFPP_LOCAL) {
struct net_device *dev = dp->netdev;
return dev ? dp_dev_recv(dev, skb) : -ESRCH;
static void discard_skb(uint32_t id);
/* 'skb' was received on 'in_port', a physical switch port between 0 and
- * OFPP_MAX. Process it according to 'chain'. */
-void fwd_port_input(struct sw_chain *chain, struct sk_buff *skb, int in_port)
+ * OFPP_MAX. Process it according to 'chain'. Returns 0 if successful, in
+ * which case 'skb' is destroyed, or -ESRCH if there is no matching flow, in
+ * which case 'skb' still belongs to the caller. */
+int run_flow_through_tables(struct sw_chain *chain, struct sk_buff *skb,
+ int in_port)
{
struct sw_flow_key key;
struct sw_flow *flow;
flow_used(flow, skb);
execute_actions(chain->dp, skb, &key,
flow->actions, flow->n_actions);
+ return 0;
} else {
+ return -ESRCH;
+ }
+}
+
+/* 'skb' was received on 'in_port', a physical switch port between 0 and
+ * OFPP_MAX. Process it according to 'chain', sending it up to the controller
+ * if no flow matches. Takes ownership of 'skb'. */
+void fwd_port_input(struct sw_chain *chain, struct sk_buff *skb, int in_port)
+{
+ if (run_flow_through_tables(chain, skb, in_port))
dp_output_control(chain->dp, skb, fwd_save_skb(skb),
chain->dp->miss_send_len,
OFPR_NO_MATCH);
- }
}
static int do_output(struct datapath *dp, struct sk_buff *skb, size_t max_len,
#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);
} 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);
\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;
flow_used(flow, buffer);
execute_actions(dp, buffer, in_port, &key,
flow->actions, flow->n_actions);
+ return 0;
} else {
+ 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);
}