ofproto: Create and delete tnl_backers in type_run()
[sliver-openvswitch.git] / ofproto / ofproto-dpif.c
index c1b9b69..a4d7e59 100644 (file)
@@ -721,7 +721,6 @@ static struct ofport_dpif *get_odp_port(const struct ofproto_dpif *,
 static void ofproto_trace(struct ofproto_dpif *, const struct flow *,
                           const struct ofpbuf *, ovs_be16 initial_tci,
                           struct ds *);
-static bool may_dpif_port_del(struct ofport_dpif *);
 
 /* Packet processing. */
 static void update_learning_table(struct ofproto_dpif *,
@@ -849,6 +848,58 @@ type_run(const char *type)
         struct tag_set revalidate_set = backer->revalidate_set;
         bool need_revalidate = backer->need_revalidate;
         struct ofproto_dpif *ofproto;
+        struct simap_node *node;
+        struct simap tmp_backers;
+
+        /* Handle tunnel garbage collection. */
+        simap_init(&tmp_backers);
+        simap_swap(&backer->tnl_backers, &tmp_backers);
+
+        HMAP_FOR_EACH (ofproto, all_ofproto_dpifs_node, &all_ofproto_dpifs) {
+            struct ofport_dpif *iter;
+
+            if (backer != ofproto->backer) {
+                continue;
+            }
+
+            HMAP_FOR_EACH (iter, up.hmap_node, &ofproto->up.ports) {
+                const char *dp_port;
+
+                if (!iter->tnl_port) {
+                    continue;
+                }
+
+                dp_port = netdev_vport_get_dpif_port(iter->up.netdev);
+                node = simap_find(&tmp_backers, dp_port);
+                if (node) {
+                    simap_put(&backer->tnl_backers, dp_port, node->data);
+                    simap_delete(&tmp_backers, node);
+                    node = simap_find(&backer->tnl_backers, dp_port);
+                } else {
+                    node = simap_find(&backer->tnl_backers, dp_port);
+                    if (!node) {
+                        uint32_t odp_port = UINT32_MAX;
+
+                        if (!dpif_port_add(backer->dpif, iter->up.netdev,
+                                           &odp_port)) {
+                            simap_put(&backer->tnl_backers, dp_port, odp_port);
+                            node = simap_find(&backer->tnl_backers, dp_port);
+                        }
+                    }
+                }
+
+                iter->odp_port = node ? node->data : OVSP_NONE;
+                if (tnl_port_reconfigure(&iter->up, iter->odp_port,
+                                         &iter->tnl_port)) {
+                    backer->need_revalidate = REV_RECONFIGURE;
+                }
+            }
+        }
+
+        SIMAP_FOR_EACH (node, &tmp_backers) {
+            dpif_port_del(backer->dpif, node->data);
+        }
+        simap_destroy(&tmp_backers);
 
         switch (backer->need_revalidate) {
         case REV_RECONFIGURE:   COVERAGE_INC(rev_reconfigure);   break;
@@ -1622,14 +1673,15 @@ port_destruct(struct ofport *port_)
     const char *dp_port_name = netdev_vport_get_dpif_port(port->up.netdev);
     const char *devname = netdev_get_name(port->up.netdev);
 
-    if (dpif_port_exists(ofproto->backer->dpif, dp_port_name)
-        && may_dpif_port_del(port)) {
+    if (dpif_port_exists(ofproto->backer->dpif, dp_port_name)) {
         /* The underlying device is still there, so delete it.  This
          * happens when the ofproto is being destroyed, since the caller
          * assumes that removal of attached ports will happen as part of
          * destruction. */
-        dpif_port_del(ofproto->backer->dpif, port->odp_port);
-        simap_find_and_delete(&ofproto->backer->tnl_backers, dp_port_name);
+        if (!port->tnl_port) {
+            dpif_port_del(ofproto->backer->dpif, port->odp_port);
+        }
+        ofproto->backer->need_revalidate = REV_RECONFIGURE;
     }
 
     if (port->odp_port != OVSP_NONE && !port->tnl_port) {
@@ -3034,43 +3086,6 @@ port_add(struct ofproto *ofproto_, struct netdev *netdev)
     return 0;
 }
 
-/* Returns true if the odp_port backing 'ofport' may be deleted from the
- * datapath. In most cases, this function simply returns true. However, for
- * tunnels it's possible that multiple ofports use the same odp_port, in which
- * case we need to keep the odp_port backer around until the last ofport is
- * deleted. */
-static bool
-may_dpif_port_del(struct ofport_dpif *ofport)
-{
-    struct dpif_backer *backer = ofproto_dpif_cast(ofport->up.ofproto)->backer;
-    struct ofproto_dpif *ofproto_iter;
-
-    if (!ofport->tnl_port) {
-        return true;
-    }
-
-    HMAP_FOR_EACH (ofproto_iter, all_ofproto_dpifs_node, &all_ofproto_dpifs) {
-        struct ofport_dpif *iter;
-
-        if (backer != ofproto_iter->backer) {
-            continue;
-        }
-
-        HMAP_FOR_EACH (iter, up.hmap_node, &ofproto_iter->up.ports) {
-            if (ofport == iter) {
-                continue;
-            }
-
-            if (!strcmp(netdev_vport_get_dpif_port(ofport->up.netdev),
-                        netdev_vport_get_dpif_port(iter->up.netdev))) {
-                return false;
-            }
-        }
-    }
-
-    return true;
-}
-
 static int
 port_del(struct ofproto *ofproto_, uint16_t ofp_port)
 {
@@ -3084,17 +3099,14 @@ port_del(struct ofproto *ofproto_, uint16_t ofp_port)
 
     sset_find_and_delete(&ofproto->ghost_ports,
                          netdev_get_name(ofport->up.netdev));
-    if (may_dpif_port_del(ofport)) {
+    ofproto->backer->need_revalidate = REV_RECONFIGURE;
+    if (!ofport->tnl_port) {
         error = dpif_port_del(ofproto->backer->dpif, ofport->odp_port);
         if (!error) {
-            const char *dpif_port;
-
             /* The caller is going to close ofport->up.netdev.  If this is a
              * bonded port, then the bond is using that netdev, so remove it
              * from the bond.  The client will need to reconfigure everything
              * after deleting ports, so then the slave will get re-added. */
-            dpif_port = netdev_vport_get_dpif_port(ofport->up.netdev);
-            simap_find_and_delete(&ofproto->backer->tnl_backers, dpif_port);
             bundle_remove(&ofport->up);
         }
     }
@@ -3341,12 +3353,13 @@ process_special(struct ofproto_dpif *ofproto, const struct flow *flow,
 }
 
 static struct flow_miss *
-flow_miss_find(struct hmap *todo, const struct flow *flow, uint32_t hash)
+flow_miss_find(struct hmap *todo, const struct ofproto_dpif *ofproto,
+               const struct flow *flow, uint32_t hash)
 {
     struct flow_miss *miss;
 
     HMAP_FOR_EACH_WITH_HASH (miss, hmap_node, hash, todo) {
-        if (flow_equal(&miss->flow, flow)) {
+        if (miss->ofproto == ofproto && flow_equal(&miss->flow, flow)) {
             return miss;
         }
     }
@@ -3814,7 +3827,7 @@ handle_miss_upcalls(struct dpif_backer *backer, struct dpif_upcall *upcalls,
 
         /* Add other packets to a to-do list. */
         hash = flow_hash(&miss->flow, 0);
-        existing_miss = flow_miss_find(&todo, &miss->flow, hash);
+        existing_miss = flow_miss_find(&todo, ofproto, &miss->flow, hash);
         if (!existing_miss) {
             hmap_insert(&todo, &miss->hmap_node, hash);
             miss->ofproto = ofproto;
@@ -3888,7 +3901,16 @@ classify_upcall(const struct dpif_upcall *upcall)
     }
 
     /* "action" upcalls need a closer look. */
-    memcpy(&cookie, &upcall->userdata, sizeof(cookie));
+    if (!upcall->userdata) {
+        VLOG_WARN_RL(&rl, "action upcall missing cookie");
+        return BAD_UPCALL;
+    }
+    if (nl_attr_get_size(upcall->userdata) != sizeof(cookie)) {
+        VLOG_WARN_RL(&rl, "action upcall cookie has unexpected size %zu",
+                     nl_attr_get_size(upcall->userdata));
+        return BAD_UPCALL;
+    }
+    memcpy(&cookie, nl_attr_get(upcall->userdata), sizeof(cookie));
     switch (cookie.type) {
     case USER_ACTION_COOKIE_SFLOW:
         return SFLOW_UPCALL;
@@ -3898,7 +3920,8 @@ classify_upcall(const struct dpif_upcall *upcall)
 
     case USER_ACTION_COOKIE_UNSPEC:
     default:
-        VLOG_WARN_RL(&rl, "invalid user cookie : 0x%"PRIx64, upcall->userdata);
+        VLOG_WARN_RL(&rl, "invalid user cookie : 0x%"PRIx64,
+                     nl_attr_get_u64(upcall->userdata));
         return BAD_UPCALL;
     }
 }
@@ -3918,7 +3941,7 @@ handle_sflow_upcall(struct dpif_backer *backer,
         return;
     }
 
-    memcpy(&cookie, &upcall->userdata, sizeof(cookie));
+    memcpy(&cookie, nl_attr_get(upcall->userdata), sizeof(cookie));
     dpif_sflow_received(ofproto->sflow, upcall->packet, &flow,
                         odp_in_port, &cookie);
 }
@@ -5515,6 +5538,7 @@ send_packet(const struct ofport_dpif *ofport, struct ofpbuf *packet)
         dpif_flow_stats_extract(&flow, packet, time_msec(), &stats);
         netdev_vport_inc_tx(ofport->up.netdev, &stats);
         odp_put_tunnel_action(&flow.tunnel, &odp_actions);
+        odp_put_skb_mark_action(flow.skb_mark, &odp_actions);
     } else {
         odp_port = vsp_realdev_to_vlandev(ofproto, ofport->odp_port,
                                           flow.vlan_tci);
@@ -5578,7 +5602,7 @@ compose_slow_path(const struct ofproto_dpif *ofproto, const struct flow *flow,
     ofpbuf_use_stack(&buf, stub, stub_size);
     if (slow & (SLOW_CFM | SLOW_LACP | SLOW_STP)) {
         uint32_t pid = dpif_port_get_pid(ofproto->backer->dpif, UINT32_MAX);
-        odp_put_userspace_action(pid, &cookie, &buf);
+        odp_put_userspace_action(pid, &cookie, sizeof cookie, &buf);
     } else {
         put_userspace_action(ofproto, &buf, flow, &cookie);
     }
@@ -5597,7 +5621,7 @@ put_userspace_action(const struct ofproto_dpif *ofproto,
     pid = dpif_port_get_pid(ofproto->backer->dpif,
                             ofp_port_to_odp_port(ofproto, flow->in_port));
 
-    return odp_put_userspace_action(pid, cookie, odp_actions);
+    return odp_put_userspace_action(pid, cookie, sizeof *cookie, odp_actions);
 }
 
 static void
@@ -5728,6 +5752,7 @@ compose_output_action__(struct action_xlate_ctx *ctx, uint16_t ofp_port,
         struct ofport_dpif *peer = ofport_get_peer(ofport);
         struct flow old_flow = ctx->flow;
         const struct ofproto_dpif *peer_ofproto;
+        enum slow_path_reason special;
         struct ofport_dpif *in_port;
 
         if (!peer) {
@@ -5748,7 +5773,11 @@ compose_output_action__(struct action_xlate_ctx *ctx, uint16_t ofp_port,
         memset(ctx->flow.regs, 0, sizeof ctx->flow.regs);
 
         in_port = get_ofp_port(ctx->ofproto, ctx->flow.in_port);
-        if (!in_port || may_receive(in_port, ctx)) {
+        special = process_special(ctx->ofproto, &ctx->flow, in_port,
+                                  ctx->packet);
+        if (special) {
+            ctx->slow |= special;
+        } else if (!in_port || may_receive(in_port, ctx)) {
             if (!in_port || stp_forward_in_state(in_port->stp_state)) {
                 xlate_table_action(ctx, ctx->flow.in_port, 0, true);
             } else {