From 1ebeaaa7f0c3f0f94f28377404c52a11cca50d86 Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Mon, 3 Mar 2014 17:23:12 -0800 Subject: [PATCH] ofproto: New function ofproto_refresh_rule(). This function checks for a rule in the classifier: * If the rule exists, reset its modified time. * If an equivalent rule exists, reset that rule's modified time. * If no rule exists, re-install the rule and reset its modified time. * Finally, return the rule that was modified. This function will be used to ensure that hard timeouts for learnt rules are refreshed if traffic consistently hits a rule with a learn action in it. The first user will be the next commit. Signed-off-by: Joe Stringer Acked-by: Ethan Jackson --- v2: Acked. v1: Ensure rule->modified is updated correctly. RFC: First post. --- ofproto/ofproto-dpif.c | 12 ++++++++ ofproto/ofproto-dpif.h | 1 + ofproto/ofproto-provider.h | 2 ++ ofproto/ofproto.c | 62 +++++++++++++++++++++++++++++++++++--- 4 files changed, 73 insertions(+), 4 deletions(-) diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 3648dd743..52e47c298 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -362,6 +362,18 @@ ofproto_dpif_flow_mod(struct ofproto_dpif *ofproto, ofproto_flow_mod(&ofproto->up, fm); } +/* Resets the modified time for 'rule' or an equivalent rule. If 'rule' is not + * in the classifier, but an equivalent rule is, unref 'rule' and ref the new + * rule. Otherwise if 'rule' is no longer installed in the classifier, + * reinstall it. + * + * Returns the rule whose modified time has been reset. */ +struct rule_dpif * +ofproto_dpif_refresh_rule(struct rule_dpif *rule) +{ + return rule_dpif_cast(ofproto_refresh_rule(&rule->up)); +} + /* Appends 'pin' to the queue of "packet ins" to be sent to the controller. * Takes ownership of 'pin' and pin->packet. */ void diff --git a/ofproto/ofproto-dpif.h b/ofproto/ofproto-dpif.h index ed0aa90a8..eb4787c03 100644 --- a/ofproto/ofproto-dpif.h +++ b/ofproto/ofproto-dpif.h @@ -143,6 +143,7 @@ void ofproto_dpif_send_packet_in(struct ofproto_dpif *, bool ofproto_dpif_wants_packet_in_on_miss(struct ofproto_dpif *); int ofproto_dpif_send_packet(const struct ofport_dpif *, struct ofpbuf *); void ofproto_dpif_flow_mod(struct ofproto_dpif *, struct ofputil_flow_mod *); +struct rule_dpif *ofproto_dpif_refresh_rule(struct rule_dpif *); struct ofport_dpif *odp_port_to_ofport(const struct dpif_backer *, odp_port_t); diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h index 0e22b7cb2..0148fe612 100644 --- a/ofproto/ofproto-provider.h +++ b/ofproto/ofproto-provider.h @@ -1727,6 +1727,8 @@ BUILD_ASSERT_DECL(OFPROTO_POSTPONE < OFPERR_OFS); int ofproto_flow_mod(struct ofproto *, struct ofputil_flow_mod *) OVS_EXCLUDED(ofproto_mutex); +struct rule *ofproto_refresh_rule(struct rule *rule) + OVS_EXCLUDED(ofproto_mutex); void ofproto_add_flow(struct ofproto *, const struct match *, unsigned int priority, const struct ofpact *ofpacts, size_t ofpacts_len) diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 436a74527..f16005cec 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -268,6 +268,9 @@ static bool rule_is_modifiable(const struct rule *rule, static enum ofperr add_flow(struct ofproto *, struct ofconn *, struct ofputil_flow_mod *, const struct ofp_header *); +static void do_add_flow(struct ofproto *, struct ofconn *, + const struct ofp_header *request, uint32_t buffer_id, + struct rule *); static enum ofperr modify_flows__(struct ofproto *, struct ofconn *, struct ofputil_flow_mod *, const struct ofp_header *, @@ -2009,6 +2012,47 @@ ofproto_flow_mod(struct ofproto *ofproto, struct ofputil_flow_mod *fm) return handle_flow_mod__(ofproto, NULL, fm, NULL); } +/* Resets the modified time for 'rule' or an equivalent rule. If 'rule' is not + * in the classifier, but an equivalent rule is, unref 'rule' and ref the new + * rule. Otherwise if 'rule' is no longer installed in the classifier, + * reinstall it. + * + * Returns the rule whose modified time has been reset. */ +struct rule * +ofproto_refresh_rule(struct rule *rule) +{ + const struct oftable *table = &rule->ofproto->tables[rule->table_id]; + const struct cls_rule *cr = &rule->cr; + struct rule *r; + + /* do_add_flow() requires that the rule is not installed. We lock the + * ofproto_mutex here so that another thread cannot add the flow before + * we get a chance to add it.*/ + ovs_mutex_lock(&ofproto_mutex); + + fat_rwlock_rdlock(&table->cls.rwlock); + r = rule_from_cls_rule(classifier_find_rule_exactly(&table->cls, cr)); + if (r != rule) { + ofproto_rule_ref(r); + } + fat_rwlock_unlock(&table->cls.rwlock); + + if (!r) { + do_add_flow(rule->ofproto, NULL, NULL, 0, rule); + } else if (r != rule) { + ofproto_rule_unref(rule); + rule = r; + } + ovs_mutex_unlock(&ofproto_mutex); + + /* Refresh the modified time for the rule. */ + ovs_mutex_lock(&rule->mutex); + rule->modified = MAX(rule->modified, time_msec()); + ovs_mutex_unlock(&rule->mutex); + + return rule; +} + /* Searches for a rule with matching criteria exactly equal to 'target' in * ofproto's table 0 and, if it finds one, deletes it. * @@ -3959,7 +4003,6 @@ add_flow(struct ofproto *ofproto, struct ofconn *ofconn, OVS_REQUIRES(ofproto_mutex) { struct oftable *table; - struct ofopgroup *group; struct cls_rule cr; struct rule *rule; uint8_t table_id; @@ -4097,14 +4140,25 @@ add_flow(struct ofproto *ofproto, struct ofconn *ofconn, } /* Insert rule. */ + do_add_flow(ofproto, ofconn, request, fm->buffer_id, rule); + + return error; +} + +static void +do_add_flow(struct ofproto *ofproto, struct ofconn *ofconn, + const struct ofp_header *request, uint32_t buffer_id, + struct rule *rule) + OVS_REQUIRES(ofproto_mutex) +{ + struct ofopgroup *group; + oftable_insert_rule(rule); - group = ofopgroup_create(ofproto, ofconn, request, fm->buffer_id); + group = ofopgroup_create(ofproto, ofconn, request, buffer_id); ofoperation_create(group, rule, OFOPERATION_ADD, 0); ofproto->ofproto_class->rule_insert(rule); ofopgroup_submit(group); - - return error; } /* OFPFC_MODIFY and OFPFC_MODIFY_STRICT. */ -- 2.43.0