return false;
}
-static void delete_flow(struct ofproto *, struct wdp_rule *, uint8_t reason);
+static int delete_flow(struct ofproto *, struct wdp_rule *, uint8_t reason);
/* ofproto supports two kinds of OpenFlow connections:
*
error = pktbuf_retrieve(ofconn->pktbuf, ntohl(ofm->buffer_id),
&packet, &in_port);
if (!error) {
- wdp_flow_inject(p->wdp, rule, in_port, packet);
+ error = wdp_flow_inject(p->wdp, rule, in_port, packet);
ofpbuf_delete(packet);
}
}
- return 0;
+ return error;
}
static struct wdp_rule *
return error;
}
- wdp_flow_inject(ofproto->wdp, rule, in_port, packet);
+ error = wdp_flow_inject(ofproto->wdp, rule, in_port, packet);
ofpbuf_delete(packet);
- return 0;
+ return error;
}
\f
/* OFPFC_MODIFY and OFPFC_MODIFY_STRICT. */
};
static int modify_flow(struct ofproto *, const struct ofp_flow_mod *,
- size_t n_actions, struct wdp_rule *);
+ size_t n_actions, struct wdp_rule *)
+ WARN_UNUSED_RESULT;
static int modify_flows_cb(struct wdp_rule *, void *cbdata_);
/* Implements OFPFC_ADD and OFPFC_MODIFY. Returns 0 on success or an OpenFlow
struct modify_flows_cbdata cbdata;
uint8_t table_id;
flow_t target;
+ int error;
cbdata.ofproto = p;
cbdata.ofm = ofm;
&target);
table_id = flow_mod_table_id(ofconn, ofm);
- wdp_flow_for_each_match(p->wdp, &target, table_id_to_include(table_id),
- modify_flows_cb, &cbdata);
+ error = wdp_flow_for_each_match(p->wdp, &target,
+ table_id_to_include(table_id),
+ modify_flows_cb, &cbdata);
+ if (error) {
+ return error;
+ }
+
if (cbdata.match) {
/* This credits the packet to whichever flow happened to match last.
* That's weird. Maybe we should do a lookup for the flow that
* actually matches the packet? Who knows. */
- send_buffered_packet(p, ofconn, cbdata.match, ofm);
- return 0;
+ return send_buffered_packet(p, ofconn, cbdata.match, ofm);
} else {
return add_flow(p, ofconn, ofm, n_actions);
}
{
struct wdp_rule *rule = find_flow_strict(p, ofconn, ofm);
if (rule && !rule_is_hidden(rule)) {
- modify_flow(p, ofm, n_actions, rule);
- return send_buffered_packet(p, ofconn, rule, ofm);
+ int error = modify_flow(p, ofm, n_actions, rule);
+ return error ? error : send_buffered_packet(p, ofconn, rule, ofm);
} else {
return add_flow(p, ofconn, ofm, n_actions);
}
if (!rule_is_hidden(rule)) {
cbdata->match = rule;
- modify_flow(cbdata->ofproto, cbdata->ofm, cbdata->n_actions, rule);
+ return modify_flow(cbdata->ofproto, cbdata->ofm, cbdata->n_actions,
+ rule);
}
return 0;
}
};
static int delete_flows_cb(struct wdp_rule *, void *cbdata_);
-static void delete_flow_core(struct ofproto *, struct wdp_rule *,
+static int delete_flow_core(struct ofproto *, struct wdp_rule *,
uint16_t out_port);
/* Implements OFPFC_DELETE. */
-static void
+static int
delete_flows_loose(struct ofproto *p, const struct ofconn *ofconn,
const struct ofp_flow_mod *ofm)
{
&target);
table_id = flow_mod_table_id(ofconn, ofm);
- wdp_flow_for_each_match(p->wdp, &target, table_id_to_include(table_id),
- delete_flows_cb, &cbdata);
+ return wdp_flow_for_each_match(p->wdp, &target,
+ table_id_to_include(table_id),
+ delete_flows_cb, &cbdata);
}
/* Implements OFPFC_DELETE_STRICT. */
-static void
+static int
delete_flow_strict(struct ofproto *p, const struct ofconn *ofconn,
struct ofp_flow_mod *ofm)
{
struct wdp_rule *rule = find_flow_strict(p, ofconn, ofm);
if (rule) {
- delete_flow_core(p, rule, ofm->out_port);
+ return delete_flow_core(p, rule, ofm->out_port);
}
+ return 0;
}
/* Callback for delete_flows_loose(). */
{
struct delete_flows_cbdata *cbdata = cbdata_;
- delete_flow_core(cbdata->ofproto, rule, cbdata->out_port);
- return 0;
+ return delete_flow_core(cbdata->ofproto, rule, cbdata->out_port);
}
/* Implements core of OFPFC_DELETE and OFPFC_DELETE_STRICT where 'rule' has
* Will not delete 'rule' if it is hidden. Will delete 'rule' only if
* 'out_port' is htons(OFPP_NONE) or if 'rule' actually outputs to the
* specified 'out_port'. */
-static void
+static int
delete_flow_core(struct ofproto *p, struct wdp_rule *rule, uint16_t out_port)
{
if (rule_is_hidden(rule)) {
- return;
+ return 0;
}
if (out_port != htons(OFPP_NONE) && !rule_has_out_port(rule, out_port)) {
- return;
+ return 0;
}
- delete_flow(p, rule, OFPRR_DELETE);
+ return delete_flow(p, rule, OFPRR_DELETE);
}
\f
static int
return modify_flow_strict(p, ofconn, ofm, n_actions);
case OFPFC_DELETE:
- delete_flows_loose(p, ofconn, ofm);
- return 0;
+ return delete_flows_loose(p, ofconn, ofm);
case OFPFC_DELETE_STRICT:
- delete_flow_strict(p, ofconn, ofm);
- return 0;
+ return delete_flow_strict(p, ofconn, ofm);
default:
return ofp_mkerr(OFPET_FLOW_MOD_FAILED, OFPFMFC_BAD_COMMAND);
return buf;
}
-static void
+static int
delete_flow(struct ofproto *p, struct wdp_rule *rule, uint8_t reason)
{
/* We limit the maximum number of queued flow expirations it by accounting
struct ofproto_rule *ofproto_rule = ofproto_rule_cast(rule);
struct wdp_flow_stats stats;
struct ofpbuf *buf;
+ int error;
if (ofproto_rule->send_flow_removed) {
/* Compose most of the ofp_flow_removed before 'rule' is destroyed. */
buf = NULL;
}
- if (wdp_flow_delete(p->wdp, rule, &stats)) {
- return;
+ error = wdp_flow_delete(p->wdp, rule, &stats);
+ if (error) {
+ return error;
}
if (buf) {
}
}
free(ofproto_rule);
+
+ return 0;
}
/* pinsched callback for sending 'packet' on 'ofconn'. */