Merge branch 'mainstream'
[sliver-openvswitch.git] / ofproto / ofproto-dpif-xlate.c
index 30697ac..e7cec14 100644 (file)
@@ -121,7 +121,7 @@ struct xport {
     struct xport *peer;              /* Patch port peer or null. */
 
     enum ofputil_port_config config; /* OpenFlow port configuration. */
-    int stp_port_no;                 /* STP port number or 0 if not in use. */
+    int stp_port_no;                 /* STP port number or -1 if not in use. */
 
     struct hmap skb_priorities;      /* Map of 'skb_priority_to_dscp's. */
 
@@ -201,8 +201,6 @@ static void output_normal(struct xlate_ctx *, const struct xbundle *,
                           uint16_t vlan);
 static void compose_output_action(struct xlate_ctx *, ofp_port_t ofp_port);
 
-static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
-
 static struct xbridge *xbridge_lookup(const struct ofproto_dpif *);
 static struct xbundle *xbundle_lookup(const struct ofbundle *);
 static struct xport *xport_lookup(const struct ofport_dpif *);
@@ -291,6 +289,12 @@ xlate_remove_ofproto(struct ofproto_dpif *ofproto)
     }
 
     hmap_remove(&xbridges, &xbridge->hmap_node);
+    mac_learning_unref(xbridge->ml);
+    mbridge_unref(xbridge->mbridge);
+    dpif_sflow_unref(xbridge->sflow);
+    dpif_ipfix_unref(xbridge->ipfix);
+    stp_unref(xbridge->stp);
+    hmap_destroy(&xbridge->xports);
     free(xbridge->name);
     free(xbridge);
 }
@@ -617,7 +621,7 @@ xport_lookup(const struct ofport_dpif *ofport)
 static struct stp_port *
 xport_get_stp_port(const struct xport *xport)
 {
-    return xport->xbridge->stp && xport->stp_port_no
+    return xport->xbridge->stp && xport->stp_port_no != -1
         ? stp_get_port(xport->xbridge->stp, xport->stp_port_no)
         : NULL;
 }
@@ -1220,6 +1224,7 @@ xlate_normal(struct xlate_ctx *ctx)
     struct xbundle *in_xbundle;
     struct xport *in_port;
     struct mac_entry *mac;
+    void *mac_port;
     uint16_t vlan;
     uint16_t vid;
 
@@ -1282,8 +1287,11 @@ xlate_normal(struct xlate_ctx *ctx)
     /* Determine output bundle. */
     ovs_rwlock_rdlock(&ctx->xbridge->ml->rwlock);
     mac = mac_learning_lookup(ctx->xbridge->ml, flow->dl_dst, vlan);
-    if (mac) {
-        struct xbundle *mac_xbundle = xbundle_lookup(mac->port.p);
+    mac_port = mac ? mac->port.p : NULL;
+    ovs_rwlock_unlock(&ctx->xbridge->ml->rwlock);
+
+    if (mac_port) {
+        struct xbundle *mac_xbundle = xbundle_lookup(mac_port);
         if (mac_xbundle && mac_xbundle != in_xbundle) {
             xlate_report(ctx, "forwarding to learned port");
             output_normal(ctx, mac_xbundle, vlan);
@@ -1306,7 +1314,6 @@ xlate_normal(struct xlate_ctx *ctx)
         }
         ctx->xout->nf_output_iface = NF_OUT_FLOOD;
     }
-    ovs_rwlock_unlock(&ctx->xbridge->ml->rwlock);
 }
 
 /* Compose SAMPLE action for sFlow or IPFIX.  The given probability is
@@ -1519,7 +1526,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
     struct flow_wildcards *wc = &ctx->xout->wc;
     struct flow *flow = &ctx->xin->flow;
     ovs_be16 flow_vlan_tci;
-    uint32_t flow_skb_mark;
+    uint32_t flow_pkt_mark;
     uint8_t flow_nw_tos;
     odp_port_t out_port, odp_port;
     uint8_t dscp;
@@ -1587,7 +1594,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
     }
 
     flow_vlan_tci = flow->vlan_tci;
-    flow_skb_mark = flow->skb_mark;
+    flow_pkt_mark = flow->pkt_mark;
     flow_nw_tos = flow->nw_tos;
 
     if (dscp_from_skb_priority(xport, flow->skb_priority, &dscp)) {
@@ -1633,7 +1640,6 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
             out_port = ofp_port_to_odp_port(ctx->xbridge, vlandev_port);
             flow->vlan_tci = htons(0);
         }
-        flow->skb_mark &= ~IPSEC_MARK;
     }
 
     if (out_port != ODPP_NONE) {
@@ -1650,7 +1656,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
  out:
     /* Restore flow */
     flow->vlan_tci = flow_vlan_tci;
-    flow->skb_mark = flow_skb_mark;
+    flow->pkt_mark = flow_pkt_mark;
     flow->nw_tos = flow_nw_tos;
 }
 
@@ -1660,32 +1666,26 @@ compose_output_action(struct xlate_ctx *ctx, ofp_port_t ofp_port)
     compose_output_action__(ctx, ofp_port, true);
 }
 
-/* Common rule processing in one place to avoid duplicating code. */
-static struct rule_dpif *
-ctx_rule_hooks(struct xlate_ctx *ctx, struct rule_dpif *rule,
-               bool may_packet_in)
+static void
+xlate_recursively(struct xlate_ctx *ctx, struct rule_dpif *rule)
+    OVS_RELEASES(rule)
 {
-    if (ctx->xin->resubmit_hook) {
-        ctx->xin->resubmit_hook(ctx->xin, rule, ctx->recurse);
-    }
-    if (rule == NULL && may_packet_in) {
-        struct xport *xport;
+    struct rule_dpif *old_rule = ctx->rule;
+    const struct ofpact *ofpacts;
+    size_t ofpacts_len;
 
-        /* XXX
-         * check if table configuration flags
-         * OFPTC_TABLE_MISS_CONTROLLER, default.
-         * OFPTC_TABLE_MISS_CONTINUE,
-         * OFPTC_TABLE_MISS_DROP
-         * When OF1.0, OFPTC_TABLE_MISS_CONTINUE is used. What to do? */
-        xport = get_ofp_port(ctx->xbridge, ctx->xin->flow.in_port.ofp_port);
-        rule = choose_miss_rule(xport ? xport->config : 0,
-                                ctx->xbridge->miss_rule,
-                                ctx->xbridge->no_packet_in_rule);
-    }
-    if (rule && ctx->xin->resubmit_stats) {
-        rule_credit_stats(rule, ctx->xin->resubmit_stats);
+    if (ctx->xin->resubmit_stats) {
+        rule_dpif_credit_stats(rule, ctx->xin->resubmit_stats);
     }
-    return rule;
+
+    ctx->recurse++;
+    ctx->rule = rule;
+    rule_dpif_get_actions(rule, &ofpacts, &ofpacts_len);
+    do_xlate_actions(ofpacts, ofpacts_len, ctx);
+    ctx->rule = old_rule;
+    ctx->recurse--;
+
+    rule_dpif_release(rule);
 }
 
 static void
@@ -1696,29 +1696,39 @@ xlate_table_action(struct xlate_ctx *ctx,
         struct rule_dpif *rule;
         ofp_port_t old_in_port = ctx->xin->flow.in_port.ofp_port;
         uint8_t old_table_id = ctx->table_id;
+        bool got_rule;
 
         ctx->table_id = table_id;
 
-        /* Look up a flow with 'in_port' as the input port. */
+        /* Look up a flow with 'in_port' as the input port.  Then restore the
+         * original input port (otherwise OFPP_NORMAL and OFPP_IN_PORT will
+         * have surprising behavior). */
         ctx->xin->flow.in_port.ofp_port = in_port;
-        rule = rule_dpif_lookup_in_table(ctx->xbridge->ofproto,
-                                         &ctx->xin->flow, &ctx->xout->wc,
-                                         table_id);
-
-        /* Restore the original input port.  Otherwise OFPP_NORMAL and
-         * OFPP_IN_PORT will have surprising behavior. */
+        got_rule = rule_dpif_lookup_in_table(ctx->xbridge->ofproto,
+                                             &ctx->xin->flow, &ctx->xout->wc,
+                                             table_id, &rule);
         ctx->xin->flow.in_port.ofp_port = old_in_port;
 
-        rule = ctx_rule_hooks(ctx, rule, may_packet_in);
+        if (ctx->xin->resubmit_hook) {
+            ctx->xin->resubmit_hook(ctx->xin, rule, ctx->recurse);
+        }
 
-        if (rule) {
-            struct rule_dpif *old_rule = ctx->rule;
+        if (got_rule) {
+            xlate_recursively(ctx, rule);
+        } else if (may_packet_in) {
+            struct xport *xport;
 
-            ctx->recurse++;
-            ctx->rule = rule;
-            do_xlate_actions(rule->up.ofpacts, rule->up.ofpacts_len, ctx);
-            ctx->rule = old_rule;
-            ctx->recurse--;
+            /* XXX
+             * check if table configuration flags
+             * OFPTC_TABLE_MISS_CONTROLLER, default.
+             * OFPTC_TABLE_MISS_CONTINUE,
+             * OFPTC_TABLE_MISS_DROP
+             * When OF1.0, OFPTC_TABLE_MISS_CONTINUE is used. What to do? */
+            xport = get_ofp_port(ctx->xbridge, ctx->xin->flow.in_port.ofp_port);
+            choose_miss_rule(xport ? xport->config : 0,
+                             ctx->xbridge->miss_rule,
+                             ctx->xbridge->no_packet_in_rule, &rule);
+            xlate_recursively(ctx, rule);
         }
 
         ctx->table_id = old_table_id;
@@ -1788,7 +1798,7 @@ execute_controller_action(struct xlate_ctx *ctx, int len,
     packet = ofpbuf_clone(ctx->xin->packet);
 
     key.skb_priority = 0;
-    key.skb_mark = 0;
+    key.pkt_mark = 0;
     memset(&key.tunnel, 0, sizeof key.tunnel);
 
     commit_odp_actions(&ctx->xin->flow, &ctx->base_flow,
@@ -1803,7 +1813,7 @@ execute_controller_action(struct xlate_ctx *ctx, int len,
     pin->reason = reason;
     pin->controller_id = controller_id;
     pin->table_id = ctx->table_id;
-    pin->cookie = ctx->rule ? ctx->rule->up.flow_cookie : 0;
+    pin->cookie = ctx->rule ? rule_dpif_get_flow_cookie(ctx->rule) : 0;
 
     pin->send_len = len;
     flow_get_metadata(&ctx->xin->flow, &pin->fmd);
@@ -2106,33 +2116,13 @@ xlate_learn_action(struct xlate_ctx *ctx,
     ofproto_dpif_flow_mod(ctx->xbridge->ofproto, fm);
 }
 
-/* Reduces '*timeout' to no more than 'max'.  A value of zero in either case
- * means "infinite". */
-static void
-reduce_timeout(uint16_t max, uint16_t *timeout)
-{
-    if (max && (!*timeout || *timeout > max)) {
-        *timeout = max;
-    }
-}
-
 static void
 xlate_fin_timeout(struct xlate_ctx *ctx,
                   const struct ofpact_fin_timeout *oft)
 {
     if (ctx->xin->tcp_flags & (TCP_FIN | TCP_RST) && ctx->rule) {
-        struct rule_dpif *rule = ctx->rule;
-
-        ovs_mutex_lock(&rule->up.ofproto->expirable_mutex);
-        if (list_is_empty(&rule->up.expirable)) {
-            list_insert(&rule->up.ofproto->expirable, &rule->up.expirable);
-        }
-        ovs_mutex_unlock(&rule->up.ofproto->expirable_mutex);
-
-        ovs_mutex_lock(&rule->up.timeout_mutex);
-        reduce_timeout(oft->fin_idle_timeout, &rule->up.idle_timeout);
-        reduce_timeout(oft->fin_hard_timeout, &rule->up.hard_timeout);
-        ovs_mutex_unlock(&rule->up.timeout_mutex);
+        rule_dpif_reduce_timeouts(ctx->rule, oft->fin_idle_timeout,
+                                  oft->fin_hard_timeout);
     }
 }
 
@@ -2174,39 +2164,14 @@ may_receive(const struct xport *xport, struct xlate_ctx *ctx)
     return true;
 }
 
-static bool
-tunnel_ecn_ok(struct xlate_ctx *ctx)
-{
-    if (is_ip_any(&ctx->base_flow)
-        && (ctx->xin->flow.tunnel.ip_tos & IP_ECN_MASK) == IP_ECN_CE) {
-        if ((ctx->base_flow.nw_tos & IP_ECN_MASK) == IP_ECN_NOT_ECT) {
-            VLOG_WARN_RL(&rl, "dropping tunnel packet marked ECN CE"
-                         " but is not ECN capable");
-            return false;
-        } else {
-            /* Set the ECN CE value in the tunneled packet. */
-            ctx->xin->flow.nw_tos |= IP_ECN_CE;
-        }
-    }
-
-    return true;
-}
-
 static void
 do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
                  struct xlate_ctx *ctx)
 {
     struct flow_wildcards *wc = &ctx->xout->wc;
     struct flow *flow = &ctx->xin->flow;
-    bool was_evictable = true;
     const struct ofpact *a;
 
-    if (ctx->rule) {
-        /* Don't let the rule we're working on get evicted underneath us. */
-        was_evictable = ctx->rule->up.evictable;
-        ctx->rule->up.evictable = false;
-    }
-
     OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
         struct ofpact_controller *controller;
         const struct ofpact_metadata *metadata;
@@ -2221,6 +2186,10 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
                                 ofpact_get_OUTPUT(a)->max_len, true);
             break;
 
+        case OFPACT_GROUP:
+            /* XXX not yet implemented */
+            break;
+
         case OFPACT_CONTROLLER:
             controller = ofpact_get_CONTROLLER(a);
             execute_controller_action(ctx, controller->max_len,
@@ -2352,20 +2321,20 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
         case OFPACT_SET_MPLS_TTL:
             if (compose_set_mpls_ttl_action(ctx,
                                             ofpact_get_SET_MPLS_TTL(a)->ttl)) {
-                goto out;
+                return;
             }
             break;
 
         case OFPACT_DEC_MPLS_TTL:
             if (compose_dec_mpls_ttl_action(ctx)) {
-                goto out;
+                return;
             }
             break;
 
         case OFPACT_DEC_TTL:
             wc->masks.nw_ttl = 0xff;
             if (compose_dec_ttl(ctx, ofpact_get_DEC_TTL(a))) {
-                goto out;
+                return;
             }
             break;
 
@@ -2432,11 +2401,6 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
             break;
         }
     }
-
-out:
-    if (ctx->rule) {
-        ctx->rule->up.evictable = was_evictable;
-    }
 }
 
 void
@@ -2554,7 +2518,10 @@ actions_output_to_local_port(const struct xlate_ctx *ctx)
 }
 
 /* Translates the 'ofpacts_len' bytes of "struct ofpacts" starting at 'ofpacts'
- * into datapath actions in 'odp_actions', using 'ctx'. */
+ * into datapath actions in 'odp_actions', using 'ctx'.
+ *
+ * The caller must take responsibility for eventually freeing 'xout', with
+ * xlate_out_uninit(). */
 void
 xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
 {
@@ -2567,6 +2534,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
     struct flow orig_flow;
     struct xlate_ctx ctx;
     size_t ofpacts_len;
+    bool tnl_may_send;
 
     COVERAGE_INC(xlate_actions);
 
@@ -2622,12 +2590,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
     memset(&wc->masks.dl_type, 0xff, sizeof wc->masks.dl_type);
     wc->masks.nw_frag |= FLOW_NW_FRAG_MASK;
 
-    if (tnl_port_should_receive(&ctx.xin->flow)) {
-        memset(&wc->masks.tunnel, 0xff, sizeof wc->masks.tunnel);
-        /* skb_mark is currently used only by tunnels but that will likely
-         * change in the future. */
-        memset(&wc->masks.skb_mark, 0xff, sizeof wc->masks.skb_mark);
-    }
+    tnl_may_send = tnl_xlate_init(&ctx.base_flow, flow, wc);
     if (ctx.xbridge->has_netflow) {
         netflow_mask_wc(flow, wc);
     }
@@ -2641,8 +2604,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
         ofpacts = xin->ofpacts;
         ofpacts_len = xin->ofpacts_len;
     } else if (xin->rule) {
-        ofpacts = xin->rule->up.ofpacts;
-        ofpacts_len = xin->rule->up.ofpacts_len;
+        rule_dpif_get_actions(xin->rule, &ofpacts, &ofpacts_len);
     } else {
         NOT_REACHED();
     }
@@ -2696,7 +2658,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
         add_ipfix_action(&ctx);
         sample_actions_len = ctx.xout->odp_actions.size;
 
-        if (tunnel_ecn_ok(&ctx) && (!in_port || may_receive(in_port, &ctx))) {
+        if (tnl_may_send && (!in_port || may_receive(in_port, &ctx))) {
             do_xlate_actions(ofpacts, ofpacts_len, &ctx);
 
             /* We've let OFPP_NORMAL and the learning action look at the