static void rule_free(struct rule *);
static void rule_destroy(struct ofproto *, struct rule *);
static struct rule *rule_from_cls_rule(const struct cls_rule *);
+static void rule_insert(struct ofproto *, struct rule *,
+ struct ofpbuf *packet);
static bool rule_make_actions(struct ofproto *, struct rule *,
const struct ofpbuf *packet);
static void rule_install(struct ofproto *, struct rule *,
const union ofp_action *actions, size_t n_actions,
int idle_timeout)
{
- struct rule *rule, *displaced_rule;
-
+ struct rule *rule;
rule = rule_create(NULL, actions, n_actions,
idle_timeout >= 0 ? idle_timeout : 5 /* XXX */, 0);
cls_rule_from_flow(&rule->cr, flow, wildcards, priority);
-
- displaced_rule = rule_from_cls_rule(classifier_insert(&p->cls, &rule->cr));
- if (displaced_rule) {
- rule_destroy(p, displaced_rule);
- }
-
- if (!wildcards) {
- rule_make_actions(p, rule, NULL);
- rule_install(p, rule, NULL);
- } else {
- /* We might need to change the rules for arbitrary subrules. */
- p->need_revalidate = true;
- }
+ rule_insert(p, rule, NULL);
}
void
return false;
}
+static void
+rule_insert(struct ofproto *p, struct rule *rule, struct ofpbuf *packet)
+{
+ struct rule *displaced_rule;
+
+ displaced_rule = rule_from_cls_rule(classifier_insert(&p->cls, &rule->cr));
+ if (rule->cr.wc.wildcards) {
+ if (displaced_rule) {
+ /* The displaced rule matches exactly the same packets as the new
+ * rule, and it has the same priority, so we could usually transfer
+ * all displaced_rule's subrules to the new rule, then update the
+ * subrules' flow in the datapath. We used to do this. But there
+ * is one case where this optimization doesn't work: when
+ * 'displaced_rule' is a rule selected by NXAST_RESUBMIT, because
+ * in such a case 'displaced_rule' will not be the super-rule of
+ * the subrule that got actions from 'displaced_rule'. We could
+ * add more data to track such situations, but we have no evidence
+ * that the optimization would be worthwhile performance-wise
+ * anyhow. So we just let rule_destroy() check each subrule and
+ * transfer or destroy them as necessary.
+ */
+ }
+
+ /* We might need to change the rules for arbitrary subrules. */
+ p->need_revalidate = true;
+ } else {
+ struct odp_flow_stats stats;
+
+ rule_make_actions(p, rule, packet);
+ rule_install(p, rule, &stats);
+
+ if (displaced_rule && displaced_rule->super) {
+ update_stats(displaced_rule->super, &stats);
+ }
+ }
+ if (displaced_rule) {
+ rule_destroy(p, displaced_rule);
+ }
+}
+
/* Returns true if the actions changed, false otherwise. */
static bool
rule_make_actions(struct ofproto *p, struct rule *rule,
flow_t flow;
int error;
+ *packetp = NULL;
if (!ofconn->pktbuf) {
VLOG_WARN_RL(&rl, "attempt to send buffered packet via connection "
"without buffers");
add_flow(struct ofproto *p, struct ofconn *ofconn,
struct ofp_flow_mod *ofm, size_t n_actions)
{
- struct rule *rule, *displaced_rule;
- struct ofpbuf *packet = NULL;
- int error = 0;
+ struct ofpbuf *packet;
+ struct rule *rule;
+ int error;
rule = rule_create(NULL, (const union ofp_action *) ofm->actions,
n_actions, ntohs(ofm->idle_timeout),
if (ofm->buffer_id != htonl(UINT32_MAX)) {
error = send_buffered(p, ofconn, ntohl(ofm->buffer_id), rule, &packet);
- }
-
- displaced_rule = rule_from_cls_rule(classifier_insert(&p->cls, &rule->cr));
- if (rule->cr.wc.wildcards) {
- if (displaced_rule) {
- /* The displaced rule matches exactly the same packets as the new
- * rule, and it has the same priority, so we could usually transfer
- * all displaced_rule's subrules to the new rule, then update the
- * subrules' flow in the datapath. We used to do this. But there
- * is one case where this optimization doesn't work: when
- * 'displaced_rule' is a rule selected by NXAST_RESUBMIT, because
- * in such a case 'displaced_rule' will not be the super-rule of
- * the subrule that got actions from 'displaced_rule'. We could
- * add more data to track such situations, but we have no evidence
- * that the optimization would be worthwhile performance-wise
- * anyhow. So we just let rule_destroy() check each subrule and
- * transfer or destroy them as necessary.
- */
- rule_destroy(p, displaced_rule);
- }
-
- /* We might need to change the rules for arbitrary subrules. */
- p->need_revalidate = true;
} else {
- struct odp_flow_stats stats;
-
- rule_make_actions(p, rule, packet);
- rule_install(p, rule, &stats);
- if (displaced_rule) {
- if (displaced_rule->super) {
- update_stats(displaced_rule->super, &stats);
- }
- rule_destroy(p, displaced_rule);
- }
+ packet = NULL;
+ error = 0;
}
+
+ rule_insert(p, rule, packet);
ofpbuf_delete(packet);
return error;
}