diff mbox series

[ovs-dev,RFC,1/2] datapath: prevent deletion of flows / datapaths

Message ID 20180112191935.1589-2-aconole@redhat.com
State RFC
Headers show
Series 'Graceful restart' of OvS | expand

Commit Message

Aaron Conole Jan. 12, 2018, 7:19 p.m. UTC
Introduce a way of telling the revalidators not to delete flows from the
datapath.  This means that even during the dump/sweep behavior, flows which
might have been expired will stick around in the kernel datapath.  Such
an effect is potentially disastrous (since the kernel flow cache will
never empty, only fill).  On the other hand, in conjunction with other
user actions, this can implement a "graceful restart."

This will be used in an upcoming commit.

Signed-off-by: Aaron Conole <aconole@redhat.com>
---
 lib/dpctl.c         | 27 ++++++++++++++++++++++
 lib/dpif-netdev.c   |  2 ++
 lib/dpif-netlink.c  | 65 ++++++++++++++++++++++++++++++++++++++++-------------
 lib/dpif-provider.h |  8 +++++++
 lib/dpif.c          | 22 ++++++++++++++++++
 lib/dpif.h          |  2 ++
 6 files changed, 110 insertions(+), 16 deletions(-)
diff mbox series

Patch

diff --git a/lib/dpctl.c b/lib/dpctl.c
index 6520788aa..ed4e17f3b 100644
--- a/lib/dpctl.c
+++ b/lib/dpctl.c
@@ -1885,6 +1885,32 @@  out:
 
     return error;
 }
+
+static int
+dpctl_icing_dp(int argc, const char *argv[], struct dpctl_params *dpctl_p)
+{
+    struct dpif *dpif;
+    int error;
+
+    error = parsed_dpif_open(argv[1], false, &dpif);
+    if (error) {
+        dpctl_error(dpctl_p, error, "icing_dp");
+        return error;
+    }
+
+    if (argc > 2) {
+        bool icing_status = false;
+        if (!strcmp(argv[2], "enabled")) {
+            icing_status = true;
+        }
+        dpif_set_ice_status(dpif, icing_status);
+    }
+
+    dpctl_print(dpctl_p, dpif_get_ice_status(dpif) ? "enabled" : "disabled");
+    dpif_close(dpif);
+    return 0;
+}
+
 
 static const struct dpctl_command all_commands[] = {
     { "add-dp", "dp [iface...]", 1, INT_MAX, dpctl_add_dp, DP_RW },
@@ -1913,6 +1939,7 @@  static const struct dpctl_command all_commands[] = {
     { "parse-actions", "actions", 1, INT_MAX, dpctl_parse_actions, DP_RO },
     { "normalize-actions", "actions",
       2, INT_MAX, dpctl_normalize_actions, DP_RO },
+    { "datapath-icing", "dp [enabled|disabled]", 1, 2, dpctl_icing_dp, DP_RW },
 
     { NULL, NULL, 0, 0, NULL, DP_RO },
 };
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index 0a62630c2..08a8503b0 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -5790,6 +5790,8 @@  const struct dpif_class dpif_netdev_class = {
     dpif_netdev_meter_set,
     dpif_netdev_meter_get,
     dpif_netdev_meter_del,
+    NULL,
+    NULL
 };
 
 static void
diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c
index c265909f8..05a04b1fb 100644
--- a/lib/dpif-netlink.c
+++ b/lib/dpif-netlink.c
@@ -196,6 +196,7 @@  struct dpif_netlink {
     /* Change notification. */
     struct nl_sock *port_notifier; /* vport multicast group subscriber. */
     bool refresh_channels;
+
 };
 
 static void report_loss(struct dpif_netlink *, struct dpif_channel *,
@@ -211,6 +212,8 @@  static int ovs_vport_family;
 static int ovs_flow_family;
 static int ovs_packet_family;
 
+static bool ice_status = false;
+
 /* Generic Netlink multicast groups for OVS.
  *
  * Initialized by dpif_netlink_init(). */
@@ -707,6 +710,9 @@  dpif_netlink_destroy(struct dpif *dpif_)
     dpif_netlink_dp_init(&dp);
     dp.cmd = OVS_DP_CMD_DEL;
     dp.dp_ifindex = dpif->dp_ifindex;
+    if (ice_status) {
+        return 0;
+    }
     return dpif_netlink_dp_transact(&dp, NULL, NULL);
 }
 
@@ -1159,6 +1165,10 @@  dpif_netlink_flow_flush(struct dpif *dpif_)
     flow.cmd = OVS_FLOW_CMD_DEL;
     flow.dp_ifindex = dpif->dp_ifindex;
 
+    if (ice_status) {
+        return 0;
+    }
+
     if (netdev_is_flow_api_enabled()) {
         netdev_ports_flow_flush(dpif_->dpif_class);
     }
@@ -1916,13 +1926,15 @@  dpif_netlink_operate__(struct dpif_netlink *dpif,
             break;
 
         case DPIF_OP_FLOW_DEL:
-            del = &op->u.flow_del;
-            dpif_netlink_init_flow_del(dpif, del, &flow);
-            if (del->stats) {
-                flow.nlmsg_flags |= NLM_F_ECHO;
-                aux->txn.reply = &aux->reply;
+            if (!ice_status) {
+                del = &op->u.flow_del;
+                dpif_netlink_init_flow_del(dpif, del, &flow);
+                if (del->stats) {
+                    flow.nlmsg_flags |= NLM_F_ECHO;
+                    aux->txn.reply = &aux->reply;
+                }
+                dpif_netlink_flow_to_ofpbuf(&flow, &aux->request);
             }
-            dpif_netlink_flow_to_ofpbuf(&flow, &aux->request);
             break;
 
         case DPIF_OP_EXECUTE:
@@ -1990,15 +2002,17 @@  dpif_netlink_operate__(struct dpif_netlink *dpif,
             break;
 
         case DPIF_OP_FLOW_DEL:
-            del = &op->u.flow_del;
-            if (del->stats) {
-                if (!op->error) {
-                    struct dpif_netlink_flow reply;
-
-                    op->error = dpif_netlink_flow_from_ofpbuf(&reply,
-                                                              txn->reply);
+            if (!ice_status) {
+                del = &op->u.flow_del;
+                if (del->stats) {
                     if (!op->error) {
-                        dpif_netlink_flow_get_stats(&reply, del->stats);
+                        struct dpif_netlink_flow reply;
+
+                        op->error = dpif_netlink_flow_from_ofpbuf(&reply,
+                                                                  txn->reply);
+                        if (!op->error) {
+                            dpif_netlink_flow_get_stats(&reply, del->stats);
+                        }
                     }
                 }
             }
@@ -2156,7 +2170,9 @@  parse_flow_put(struct dpif_netlink *dpif, struct dpif_flow_put *put)
             op.u.flow_del.terse = false;
 
             opp = &op;
-            dpif_netlink_operate__(dpif, &opp, 1);
+            if (!ice_status) {
+                dpif_netlink_operate__(dpif, &opp, 1);
+            }
         }
 
         VLOG_DBG("added flow");
@@ -2207,7 +2223,7 @@  try_send_to_netdev(struct dpif_netlink *dpif, struct dpif_op *op)
     case DPIF_OP_FLOW_DEL: {
         struct dpif_flow_del *del = &op->u.flow_del;
 
-        if (!del->ufid) {
+        if (ice_status || !del->ufid) {
             break;
         }
 
@@ -2941,6 +2957,21 @@  dpif_netlink_meter_del(struct dpif *dpif OVS_UNUSED,
 }
 
 
+
+static int
+dpif_netlink_set_ice_status(struct dpif *dpif_ OVS_UNUSED, bool set_ice_status)
+{
+    ice_status = set_ice_status;
+    return 0;
+}
+
+static bool
+dpif_netlink_get_ice_status(struct dpif *dpif_ OVS_UNUSED)
+{
+    return ice_status;
+}
+
+
 const struct dpif_class dpif_netlink_class = {
     "system",
     NULL,                       /* init */
@@ -2990,6 +3021,8 @@  const struct dpif_class dpif_netlink_class = {
     dpif_netlink_meter_set,
     dpif_netlink_meter_get,
     dpif_netlink_meter_del,
+    dpif_netlink_set_ice_status,
+    dpif_netlink_get_ice_status
 };
 
 static int
diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h
index 1d82a0939..d2582418a 100644
--- a/lib/dpif-provider.h
+++ b/lib/dpif-provider.h
@@ -456,6 +456,14 @@  struct dpif_class {
      * zero. */
     int (*meter_del)(struct dpif *, ofproto_meter_id meter_id,
                      struct ofputil_meter_stats *, uint16_t n_bands);
+
+    /* Set / clear the 'ice' status of the 'dpif'.  If this is set to 'true'
+     * the ice flag will stop any deletion or purging of flows from the flow
+     * tables which are implemented by 'dpif'. */
+    int (*set_ice_status)(struct dpif *, bool ice);
+
+    /* Get the 'ice' status of the 'dpif'. */
+    bool (*get_ice_status)(const struct dpif *);
 };
 
 extern const struct dpif_class dpif_netlink_class;
diff --git a/lib/dpif.c b/lib/dpif.c
index 310dec146..202670055 100644
--- a/lib/dpif.c
+++ b/lib/dpif.c
@@ -1953,3 +1953,25 @@  dpif_meter_del(struct dpif *dpif, ofproto_meter_id meter_id,
     }
     return error;
 }
+
+int
+dpif_set_ice_status(struct dpif *dpif, bool ice)
+{
+    int error = EOPNOTSUPP;
+
+    if (dpif->dpif_class->set_ice_status) {
+        error = dpif->dpif_class->set_ice_status(dpif, ice);
+    }
+
+    return error;
+}
+
+bool
+dpif_get_ice_status(struct dpif *dpif)
+{
+    if (dpif->dpif_class->get_ice_status) {
+        return dpif->dpif_class->get_ice_status(dpif);
+    }
+
+    return false;
+}
diff --git a/lib/dpif.h b/lib/dpif.h
index ab898f4be..539bda71e 100644
--- a/lib/dpif.h
+++ b/lib/dpif.h
@@ -871,6 +871,8 @@  int dpif_meter_del(struct dpif *, ofproto_meter_id meter_id,
                    struct ofputil_meter_stats *, uint16_t n_bands);
 
 /* Miscellaneous. */
+int dpif_set_ice_status(struct dpif *, bool ice);
+bool dpif_get_ice_status(struct dpif *);
 
 void dpif_get_netflow_ids(const struct dpif *,
                           uint8_t *engine_type, uint8_t *engine_id);