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 <joestrin...@nicira.com> --- 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 97eb2b8..c7a3f98 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -351,6 +351,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 d09e285..f2820e3 100644 --- a/ofproto/ofproto-dpif.h +++ b/ofproto/ofproto-dpif.h @@ -118,6 +118,7 @@ void ofproto_dpif_send_packet_in(struct ofproto_dpif *, struct ofproto_packet_in *); 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 2c72fbc..ec54038 100644 --- a/ofproto/ofproto-provider.h +++ b/ofproto/ofproto-provider.h @@ -1720,6 +1720,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 19e7091..948a472 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -266,6 +266,9 @@ static bool rule_is_modifiable(const struct 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 *, @@ -1970,6 +1973,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 = 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. * @@ -3946,7 +3990,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; @@ -4075,14 +4118,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. */ -- 1.7.9.5 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev