ofproto: Disable timeouts for flows added by ofproto_add_flow().
[sliver-openvswitch.git] / ofproto / ofproto.c
index 618e8a5..9cb3f91 100644 (file)
@@ -88,7 +88,7 @@ struct rule {
     uint16_t idle_timeout;      /* In seconds from time of last use. */
     uint16_t hard_timeout;      /* In seconds from time of creation. */
     bool send_flow_removed;     /* Send a flow removed message? */
-    long long int used;         /* Last-used time (0 if never used). */
+    long long int used;         /* Time last used; time created if not used. */
     long long int created;      /* Creation time. */
     uint64_t packet_count;      /* Number of packets received. */
     uint64_t byte_count;        /* Number of bytes received. */
@@ -1298,15 +1298,21 @@ ofproto_send_packet(struct ofproto *p, const struct flow *flow,
     return 0;
 }
 
+/* Adds a flow to the OpenFlow flow table in 'p' that matches 'cls_rule' and
+ * performs the 'n_actions' actions in 'actions'.  The new flow will not
+ * timeout.
+ *
+ * If cls_rule->priority is in the range of priorities supported by OpenFlow
+ * (0...65535, inclusive) then the flow will be visible to OpenFlow
+ * controllers; otherwise, it will be hidden.
+ *
+ * The caller retains ownership of 'cls_rule' and 'actions'. */
 void
 ofproto_add_flow(struct ofproto *p, const struct cls_rule *cls_rule,
-                 const union ofp_action *actions, size_t n_actions,
-                 int idle_timeout)
+                 const union ofp_action *actions, size_t n_actions)
 {
     struct rule *rule;
-    rule = rule_create(p, NULL, actions, n_actions,
-                       idle_timeout >= 0 ? idle_timeout : 5 /* XXX */,
-                       0, 0, false);
+    rule = rule_create(p, NULL, actions, n_actions, 0, 0, 0, false);
     rule->cr = *cls_rule;
     rule_insert(p, rule, NULL, 0);
 }
@@ -2669,6 +2675,36 @@ xlate_set_queue_action(struct action_xlate_ctx *ctx,
         = priority;
 }
 
+static void
+xlate_set_dl_tci(struct action_xlate_ctx *ctx)
+{
+    ovs_be16 dl_vlan = ctx->flow.dl_vlan;
+    uint8_t dl_vlan_pcp = ctx->flow.dl_vlan_pcp;
+
+    if (dl_vlan == htons(OFP_VLAN_NONE)) {
+        odp_actions_add(ctx->out, ODPAT_STRIP_VLAN);
+    } else {
+        union odp_action *oa = odp_actions_add(ctx->out, ODPAT_SET_DL_TCI);
+        oa->dl_tci.tci = htons(ntohs(dl_vlan & htons(VLAN_VID_MASK))
+                               | (dl_vlan_pcp << VLAN_PCP_SHIFT)
+                               | VLAN_CFI);
+    }
+}
+
+static void
+xlate_reg_move_action(struct action_xlate_ctx *ctx,
+                      const struct nx_action_reg_move *narm)
+{
+    ovs_be16 old_vlan = ctx->flow.dl_vlan;
+    uint8_t old_pcp = ctx->flow.dl_vlan_pcp;
+
+    nxm_execute_reg_move(narm, &ctx->flow);
+
+    if (ctx->flow.dl_vlan != old_vlan || ctx->flow.dl_vlan_pcp != old_pcp) {
+        xlate_set_dl_tci(ctx);
+    }
+}
+
 static void
 xlate_nicira_action(struct action_xlate_ctx *ctx,
                     const struct nx_action_header *nah)
@@ -2707,6 +2743,15 @@ xlate_nicira_action(struct action_xlate_ctx *ctx,
         odp_actions_add(ctx->out, ODPAT_POP_PRIORITY);
         break;
 
+    case NXAST_REG_MOVE:
+        xlate_reg_move_action(ctx, (const struct nx_action_reg_move *) nah);
+        break;
+
+    case NXAST_REG_LOAD:
+        nxm_execute_reg_load((const struct nx_action_reg_load *) nah,
+                             &ctx->flow);
+        break;
+
     /* If you add a new action here that modifies flow data, don't forget to
      * update the flow key in ctx->flow at the same time. */
 
@@ -2742,23 +2787,19 @@ do_xlate_actions(const union ofp_action *in, size_t n_in,
             break;
 
         case OFPAT_SET_VLAN_VID:
-            oa = odp_actions_add(ctx->out, ODPAT_SET_DL_TCI);
-            oa->dl_tci.tci = ia->vlan_vid.vlan_vid;
-            oa->dl_tci.tci |= htons(ctx->flow.dl_vlan_pcp << VLAN_PCP_SHIFT);
             ctx->flow.dl_vlan = ia->vlan_vid.vlan_vid;
+            xlate_set_dl_tci(ctx);
             break;
 
         case OFPAT_SET_VLAN_PCP:
-            oa = odp_actions_add(ctx->out, ODPAT_SET_DL_TCI);
-            oa->dl_tci.tci = htons(ia->vlan_pcp.vlan_pcp << VLAN_PCP_SHIFT);
-            oa->dl_tci.tci |= ctx->flow.dl_vlan;
             ctx->flow.dl_vlan_pcp = ia->vlan_pcp.vlan_pcp;
+            xlate_set_dl_tci(ctx);
             break;
 
         case OFPAT_STRIP_VLAN:
-            odp_actions_add(ctx->out, ODPAT_STRIP_VLAN);
             ctx->flow.dl_vlan = htons(OFP_VLAN_NONE);
             ctx->flow.dl_vlan_pcp = 0;
+            xlate_set_dl_tci(ctx);
             break;
 
         case OFPAT_SET_DL_SRC:
@@ -2884,24 +2925,37 @@ handle_packet_out(struct ofconn *ofconn, struct ofp_header *oh)
     struct ofproto *p = ofconn->ofproto;
     struct ofp_packet_out *opo;
     struct ofpbuf payload, *buffer;
-    struct odp_actions actions;
+    union ofp_action *ofp_actions;
+    struct odp_actions odp_actions;
+    struct ofpbuf request;
     struct flow flow;
-    int n_actions;
+    size_t n_ofp_actions;
     uint16_t in_port;
     int error;
 
+    COVERAGE_INC(ofproto_packet_out);
+
     error = reject_slave_controller(ofconn, "OFPT_PACKET_OUT");
     if (error) {
         return error;
     }
 
-    error = check_ofp_packet_out(oh, &payload, &n_actions, p->max_ports);
+    /* Get ofp_packet_out. */
+    request.data = oh;
+    request.size = ntohs(oh->length);
+    opo = ofpbuf_try_pull(&request, offsetof(struct ofp_packet_out, actions));
+    if (!opo) {
+        return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
+    }
+
+    /* Get actions. */
+    error = ofputil_pull_actions(&request, ntohs(opo->actions_len),
+                                 &ofp_actions, &n_ofp_actions);
     if (error) {
         return error;
     }
-    opo = (struct ofp_packet_out *) oh;
 
-    COVERAGE_INC(ofproto_packet_out);
+    /* Get payload. */
     if (opo->buffer_id != htonl(UINT32_MAX)) {
         error = pktbuf_retrieve(ofconn->pktbuf, ntohl(opo->buffer_id),
                                 &buffer, &in_port);
@@ -2910,18 +2964,29 @@ handle_packet_out(struct ofconn *ofconn, struct ofp_header *oh)
         }
         payload = *buffer;
     } else {
+        payload = request;
         buffer = NULL;
     }
 
-    flow_extract(&payload, 0, ofp_port_to_odp_port(ntohs(opo->in_port)), &flow);
-    error = xlate_actions((const union ofp_action *) opo->actions, n_actions,
-                          &flow, p, &payload, &actions, NULL, NULL, NULL);
+    /* Extract flow, check actions. */
+    flow_extract(&payload, 0, ofp_port_to_odp_port(ntohs(opo->in_port)),
+                 &flow);
+    error = validate_actions(ofp_actions, n_ofp_actions, &flow, p->max_ports);
+    if (error) {
+        goto exit;
+    }
+
+    /* Send. */
+    error = xlate_actions(ofp_actions, n_ofp_actions, &flow, p, &payload,
+                          &odp_actions, NULL, NULL, NULL);
     if (!error) {
-        dpif_execute(p->dpif, actions.actions, actions.n_actions, &payload);
+        dpif_execute(p->dpif, odp_actions.actions, odp_actions.n_actions,
+                     &payload);
     }
-    ofpbuf_delete(buffer);
 
-    return error;
+exit:
+    ofpbuf_delete(buffer);
+    return 0;
 }
 
 static void
@@ -3640,7 +3705,7 @@ handle_vendor_stats_request(struct ofconn *ofconn,
         return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_VENDOR);
     }
 
-    if (ntohs(nsm->header.length) < sizeof(struct nicira_stats_msg)) {
+    if (ntohs(osr->header.length) < sizeof(struct nicira_stats_msg)) {
         VLOG_WARN_RL(&rl, "truncated Nicira stats request");
         return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
     }
@@ -3998,7 +4063,8 @@ flow_mod_core(struct ofconn *ofconn, struct flow_mod *fm)
         return error;
     }
 
-    error = validate_actions(fm->actions, fm->n_actions, p->max_ports);
+    error = validate_actions(fm->actions, fm->n_actions,
+                             &fm->cr.flow, p->max_ports);
     if (error) {
         return error;
     }
@@ -4763,8 +4829,7 @@ revalidate_rule(struct ofproto *p, struct rule *rule)
             rule->super = super;
             rule->hard_timeout = super->hard_timeout;
             rule->idle_timeout = super->idle_timeout;
-            rule->created = super->created;
-            rule->used = 0;
+            rule->created = rule->used = super->created;
         }
     }