Implement new "fin_timeout" action and "learn" feature.
[sliver-openvswitch.git] / lib / learn.c
index 1676462..d749ce2 100644 (file)
@@ -125,7 +125,7 @@ learn_check(const struct nx_action_learn *learn, const struct flow *flow)
     cls_rule_init_catchall(&rule, 0);
 
     if (learn->flags & ~htons(OFPFF_SEND_FLOW_REM)
-        || !is_all_zeros(learn->pad, sizeof learn->pad)
+        || learn->pad
         || learn->table_id == 0xff) {
         return OFPERR_OFPBAC_BAD_ARGUMENT;
     }
@@ -209,6 +209,14 @@ learn_execute(const struct nx_action_learn *learn, const struct flow *flow,
 
     ofpbuf_init(&actions, 64);
 
+    if (learn->fin_idle_timeout || learn->fin_hard_timeout) {
+        struct nx_action_fin_timeout *naft;
+
+        naft = ofputil_put_NXAST_FIN_TIMEOUT(&actions);
+        naft->fin_idle_timeout = learn->fin_idle_timeout;
+        naft->fin_hard_timeout = learn->fin_hard_timeout;
+    }
+
     for (p = learn + 1, end = (char *) learn + ntohs(learn->len); p != end; ) {
         uint16_t header = ntohs(get_be16(&p));
         int n_bits = header & NX_LEARN_N_BITS_MASK;
@@ -384,6 +392,17 @@ learn_parse_spec(const char *orig, char *name, char *value,
     }
 }
 
+/* Parses 'arg' as a set of arguments to the "learn" action and appends a
+ * matching NXAST_LEARN action to 'b'.  The format parsed is described in
+ * ovs-ofctl(8).
+ *
+ * Prints an error on stderr and aborts the program if 'arg' syntax is invalid.
+ *
+ * If 'flow' is nonnull, then it should be the flow from a cls_rule that is
+ * the matching rule for the learning action.  This helps to better validate
+ * the action's arguments.
+ *
+ * Modifies 'arg'. */
 void
 learn_parse(struct ofpbuf *b, char *arg, const struct flow *flow)
 {
@@ -420,6 +439,10 @@ learn_parse(struct ofpbuf *b, char *arg, const struct flow *flow)
             learn->idle_timeout = htons(atoi(value));
         } else if (!strcmp(name, "hard_timeout")) {
             learn->hard_timeout = htons(atoi(value));
+        } else if (!strcmp(name, "fin_idle_timeout")) {
+            learn->fin_idle_timeout = htons(atoi(value));
+        } else if (!strcmp(name, "fin_hard_timeout")) {
+            learn->fin_hard_timeout = htons(atoi(value));
         } else if (!strcmp(name, "cookie")) {
             learn->cookie = htonll(strtoull(value, NULL, 0));
         } else {
@@ -429,7 +452,7 @@ learn_parse(struct ofpbuf *b, char *arg, const struct flow *flow)
 
             /* Check prerequisites. */
             if (spec.src_type == NX_LEARN_SRC_FIELD
-                && !mf_are_prereqs_ok(spec.src.field, flow)) {
+                && flow && !mf_are_prereqs_ok(spec.src.field, flow)) {
                 ovs_fatal(0, "%s: cannot specify source field %s because "
                           "prerequisites are not satisfied",
                           orig, spec.src.field->name);
@@ -487,9 +510,11 @@ learn_parse(struct ofpbuf *b, char *arg, const struct flow *flow)
     learn->len = htons(b->size - learn_ofs);
 
     /* In theory the above should have caught any errors, but... */
-    error = learn_check(learn, flow);
-    if (error) {
-        ovs_fatal(0, "%s: %s", orig, ofperr_to_string(error));
+    if (flow) {
+        error = learn_check(learn, flow);
+        if (error) {
+            ovs_fatal(0, "%s: %s", orig, ofperr_to_string(error));
+        }
     }
     free(orig);
 }
@@ -509,6 +534,14 @@ learn_format(const struct nx_action_learn *learn, struct ds *s)
     if (learn->hard_timeout != htons(OFP_FLOW_PERMANENT)) {
         ds_put_format(s, ",hard_timeout=%"PRIu16, ntohs(learn->hard_timeout));
     }
+    if (learn->fin_idle_timeout) {
+        ds_put_format(s, ",fin_idle_timeout=%"PRIu16,
+                      ntohs(learn->fin_idle_timeout));
+    }
+    if (learn->fin_hard_timeout) {
+        ds_put_format(s, ",fin_hard_timeout=%"PRIu16,
+                      ntohs(learn->fin_hard_timeout));
+    }
     if (learn->priority != htons(OFP_DEFAULT_PRIORITY)) {
         ds_put_format(s, ",priority=%"PRIu16, ntohs(learn->priority));
     }
@@ -522,7 +555,7 @@ learn_format(const struct nx_action_learn *learn, struct ds *s)
     if (learn->cookie != htonll(0)) {
         ds_put_format(s, ",cookie=0x%"PRIx64, ntohll(learn->cookie));
     }
-    if (!is_all_zeros(learn->pad, sizeof learn->pad)) {
+    if (learn->pad != 0) {
         ds_put_cstr(s, ",***nonzero pad***");
     }