/* FIXME: do we need to use GFP_ATOMIC everywhere here? */
-static void execute_actions(struct datapath *, struct sk_buff *,
- const struct sw_flow_key *,
- const struct ofp_action *, int n_actions);
static int make_writable(struct sk_buff **);
static struct sk_buff *retrieve_skb(uint32_t id);
flow->actions, flow->n_actions);
} else {
dp_output_control(chain->dp, skb, fwd_save_skb(skb),
- chain->dp->config.miss_send_len,
+ ntohs(chain->dp->config.miss_send_len),
OFPR_NO_MATCH);
}
}
max_len, OFPR_ACTION));
}
-static void execute_actions(struct datapath *dp, struct sk_buff *skb,
+void execute_actions(struct datapath *dp, struct sk_buff *skb,
const struct sw_flow_key *key,
const struct ofp_action *actions, int n_actions)
{
add_flow(struct sw_chain *chain, const struct ofp_flow_mod *ofm)
{
int error = -ENOMEM;
+ int i;
int n_acts;
struct sw_flow *flow;
goto error;
}
+ /* To prevent loops, make sure there's no action to send to the
+ * OFP_TABLE virtual port.
+ */
+ for (i=0; i<n_acts; i++) {
+ const struct ofp_action *a = &ofm->actions[i];
+
+ if (a->type == htons(OFPAT_OUTPUT)
+ && a->arg.output.port == htons(OFPP_TABLE)) {
+ /* xxx Send fancy new error message? */
+ goto error;
+ }
+ }
+
/* Allocate memory. */
flow = flow_alloc(n_acts, GFP_ATOMIC);
if (flow == NULL)
}
}
+static int
+recv_flow_status_request(struct sw_chain *chain, const struct sender *sender,
+ const void *msg)
+{
+ const struct ofp_flow_stat_request *fsr = msg;
+ if (fsr->type == OFPFS_INDIV) {
+ return dp_send_flow_stats(chain->dp, sender, &fsr->match);
+ } else {
+ /* FIXME */
+ return -ENOTSUPP;
+ }
+}
+
+static int
+recv_port_status_request(struct sw_chain *chain, const struct sender *sender,
+ const void *msg)
+{
+ return dp_send_port_stats(chain->dp, sender);
+}
+
+static int
+recv_table_status_request(struct sw_chain *chain, const struct sender *sender,
+ const void *msg)
+{
+ return dp_send_table_stats(chain->dp, sender);
+}
+
/* 'msg', which is 'length' bytes long, was received across Netlink from
* 'sender'. Apply it to 'chain'. */
int
sizeof (struct ofp_port_mod),
recv_port_mod,
},
+ [OFPT_FLOW_STAT_REQUEST] = {
+ sizeof (struct ofp_flow_stat_request),
+ recv_flow_status_request,
+ },
+ [OFPT_PORT_STAT_REQUEST] = {
+ sizeof (struct ofp_port_stat_request),
+ recv_port_status_request,
+ },
+ [OFPT_TABLE_STAT_REQUEST] = {
+ sizeof (struct ofp_table_stat_request),
+ recv_table_status_request,
+ },
};
const struct openflow_packet *pkt;