int table_idx, time_t now)
{
struct ofp_flow_stats *ofs;
- int length = sizeof *ofs + sizeof *ofs->actions * flow->n_actions;
+ int length = sizeof *ofs + sizeof *ofs->actions * flow->sf_acts->n_actions;
- ofs = buffer_put_uninit(buffer, length);
+ ofs = ofpbuf_put_uninit(buffer, length);
ofs->length = htons(length);
ofs->table_id = table_idx;
ofs->pad = 0;
return error;
}
- struct buffer *buffer = retrieve_buffer(ntohl(ofm->buffer_id));
+ static int
+ mod_flow(struct datapath *dp, const struct ofp_flow_mod *ofm)
+ {
+ int error = -ENOMEM;
+ int n_actions;
+ int i;
+ struct sw_flow_key key;
+
+
+ /* To prevent loops, make sure there's no action to send to the
+ * OFP_TABLE virtual port.
+ */
+ n_actions = (ntohs(ofm->header.length) - sizeof *ofm)
+ / sizeof *ofm->actions;
+ for (i=0; i<n_actions; i++) {
+ const struct ofp_action *a = &ofm->actions[i];
+
+ if (a->type == htons(OFPAT_OUTPUT)
+ && (a->arg.output.port == htons(OFPP_TABLE)
+ || a->arg.output.port == htons(OFPP_NONE)
+ || a->arg.output.port == ofm->match.in_port)) {
+ /* xxx Send fancy new error message? */
+ goto error;
+ }
+ }
+
+ flow_extract_match(&key, &ofm->match);
+ chain_modify(dp->chain, &key, ofm->actions, n_actions);
+
+ if (ntohl(ofm->buffer_id) != UINT32_MAX) {
++ struct ofpbuf *buffer = retrieve_buffer(ntohl(ofm->buffer_id));
+ if (buffer) {
+ struct sw_flow_key skb_key;
+ uint16_t in_port = ntohs(ofm->match.in_port);
+ flow_extract(buffer, in_port, &skb_key.flow);
+ execute_actions(dp, buffer, in_port, &skb_key,
+ ofm->actions, n_actions, false);
+ } else {
+ error = -ESRCH;
+ }
+ }
+ return error;
+
+ error:
+ if (ntohl(ofm->buffer_id) != (uint32_t) -1)
+ discard_buffer(ntohl(ofm->buffer_id));
+ return error;
+ }
+
static int
recv_flow(struct datapath *dp, const struct sender *sender UNUSED,
const void *msg)
ofm->priority = htons(priority);
ofm->reserved = htonl(0);
- /* xxx Should we use the buffer library? */
+ /* xxx Should we use the ofpbuf library? */
buffer->size -= (MAX_ADD_ACTS - n_actions) * sizeof ofm->actions[0];
+ open_vconn(argv[1], &vconn);
send_openflow_buffer(vconn, buffer);
vconn_close(vconn);
}
fclose(file);
}
- static void do_del_flows(int argc, char *argv[])
+ static void do_mod_flows(int argc, char *argv[])
{
+ uint16_t idle_timeout, hard_timeout;
struct vconn *vconn;
- uint16_t priority;
- struct buffer *buffer;
++ struct ofpbuf *buffer;
+ struct ofp_flow_mod *ofm;
+ size_t size;
+ int n_actions = MAX_ADD_ACTS;
+
+ /* Parse and send. */
+ size = sizeof *ofm + (sizeof ofm->actions[0] * MAX_ADD_ACTS);
+ ofm = make_openflow(size, OFPT_FLOW_MOD, &buffer);
+ str_to_flow(argv[2], &ofm->match, &ofm->actions[0], &n_actions,
+ NULL, NULL, &idle_timeout, &hard_timeout);
+ ofm->command = htons(OFPFC_MODIFY);
+ ofm->idle_timeout = htons(idle_timeout);
+ ofm->hard_timeout = htons(hard_timeout);
+ ofm->buffer_id = htonl(UINT32_MAX);
+ ofm->priority = htons(0);
+ ofm->reserved = htonl(0);
+
+ /* xxx Should we use the buffer library? */
+ buffer->size -= (MAX_ADD_ACTS - n_actions) * sizeof ofm->actions[0];
open_vconn(argv[1], &vconn);
- struct buffer *buffer;
+ send_openflow_buffer(vconn, buffer);
+ vconn_close(vconn);
+ }
+
+ static void do_del_flows(int argc, char *argv[])
+ {
+ struct vconn *vconn;
+ uint16_t priority;
+ struct ofpbuf *buffer;
struct ofp_flow_mod *ofm;
size_t size;