[ovs-dev] [PATCH ovn v4 9/9] ovn-controller: Install generated pipeline flows into OVS via OpenFlow.

Ben Pfaff blp at nicira.com
Wed Apr 29 17:12:35 UTC 2015


This implementation is really simple, but it seems effective enough in my
minimal testing.

We still need code to generate flows for logical-to-physical and
physical-to-logical translation.  With that, plus code to set up tunnels,
we should be able to start end-to-end testing.

Signed-off-by: Ben Pfaff <blp at nicira.com>
---
 ovn/controller/automake.mk      |   2 +
 ovn/controller/ofctrl.c         | 462 ++++++++++++++++++++++++++++++++++++++++
 ovn/controller/ofctrl.h         |  37 ++++
 ovn/controller/ovn-controller.c |   9 +-
 ovn/controller/pipeline.c       |  27 +--
 5 files changed, 516 insertions(+), 21 deletions(-)
 create mode 100644 ovn/controller/ofctrl.c
 create mode 100644 ovn/controller/ofctrl.h

diff --git a/ovn/controller/automake.mk b/ovn/controller/automake.mk
index 51c73be..74cfb62 100644
--- a/ovn/controller/automake.mk
+++ b/ovn/controller/automake.mk
@@ -4,6 +4,8 @@ ovn_controller_ovn_controller_SOURCES = \
 	ovn/controller/bindings.h \
 	ovn/controller/chassis.c \
 	ovn/controller/chassis.h \
+	ovn/controller/ofctrl.c \
+	ovn/controller/ofctrl.h \
 	ovn/controller/ovn-controller.c \
 	ovn/controller/ovn-controller.h \
 	ovn/controller/pipeline.c \
diff --git a/ovn/controller/ofctrl.c b/ovn/controller/ofctrl.c
new file mode 100644
index 0000000..33a1575
--- /dev/null
+++ b/ovn/controller/ofctrl.c
@@ -0,0 +1,462 @@
+/* Copyright (c) 2015 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+#include "ofctrl.h"
+#include "dirs.h"
+#include "dynamic-string.h"
+#include "hmap.h"
+#include "match.h"
+#include "ofp-actions.h"
+#include "ofp-msgs.h"
+#include "ofp-print.h"
+#include "ofp-util.h"
+#include "ofpbuf.h"
+#include "openflow/openflow.h"
+#include "openvswitch/vlog.h"
+#include "ovn-controller.h"
+#include "rconn.h"
+#include "socket-util.h"
+
+VLOG_DEFINE_THIS_MODULE(ofctrl);
+
+/* An OpenFlow flow. */
+struct ovn_flow {
+    /* Key. */
+    struct hmap_node hmap_node; /* In 'desired_flows' or 'installed_flows'. */
+    uint8_t table_id;
+    uint16_t priority;
+    struct match match;
+
+    /* Data. */
+    struct ofpact *ofpacts;
+    size_t ofpacts_len;
+};
+
+static uint32_t ovn_flow_hash(const struct ovn_flow *);
+static struct ovn_flow *ovn_flow_lookup(struct hmap *flow_table,
+                                        const struct ovn_flow *target);
+static char *ovn_flow_to_string(const struct ovn_flow *);
+static void ovn_flow_log(const struct ovn_flow *, const char *action);
+static void ovn_flow_destroy(struct ovn_flow *);
+
+/* OpenFlow connection to the switch. */
+static struct rconn *swconn;
+
+/* Last seen sequence number for 'swconn'.  When this differs from
+ * rconn_get_connection_seqno(rconn), 'swconn' has reconnected. */
+static unsigned int seqno;
+
+/* Counter for in-flight OpenFlow messages on 'swconn'.  We only send a new
+ * round of flow table modifications to the switch when the counter falls to
+ * zero, to avoid unbounded buffering. */
+static struct rconn_packet_counter *tx_counter;
+
+/* Flow tables.  Each holds "struct ovn_flow"s.
+ *
+ * 'desired_flows' is the flow table that we want the switch to have.
+ * 'installed_flows' is the flow table currently installed in the switch. */
+static struct hmap desired_flows;
+static struct hmap installed_flows;
+
+static void ovn_flow_table_clear(struct hmap *flow_table);
+static void ovn_flow_table_destroy(struct hmap *flow_table);
+
+static void ofctrl_update_flows(void);
+static void ofctrl_recv(const struct ofpbuf *msg);
+
+void
+ofctrl_init(void)
+{
+    swconn = rconn_create(5, 0, DSCP_DEFAULT, 1 << OFP13_VERSION);
+    tx_counter = rconn_packet_counter_create();
+    hmap_init(&desired_flows);
+    hmap_init(&installed_flows);
+}
+
+/* This function should be called in the main loop after anything that updates
+ * the flow table (e.g. after calls to ofctrl_clear_flows() and
+ * ofctrl_add_flow()). */
+void
+ofctrl_run(struct controller_ctx *ctx)
+{
+    char *target;
+    target = xasprintf("unix:%s/%s.mgmt", ovs_rundir(), ctx->br_int_name);
+    if (strcmp(target, rconn_get_target(swconn))) {
+        rconn_connect(swconn, target, target);
+    }
+    free(target);
+
+    rconn_run(swconn);
+
+    if (!rconn_is_connected(swconn)) {
+        return;
+    }
+    if (!rconn_packet_counter_n_packets(tx_counter)) {
+        ofctrl_update_flows();
+    }
+
+    for (int i = 0; i < 50; i++) {
+        struct ofpbuf *msg = rconn_recv(swconn);
+        if (!msg) {
+            break;
+        }
+
+        ofctrl_recv(msg);
+        ofpbuf_delete(msg);
+    }
+}
+
+void
+ofctrl_wait(void)
+{
+    rconn_run_wait(swconn);
+    rconn_recv_wait(swconn);
+}
+
+void
+ofctrl_destroy(void)
+{
+    rconn_destroy(swconn);
+    ovn_flow_table_destroy(&installed_flows);
+    ovn_flow_table_destroy(&desired_flows);
+}
+
+static void
+queue_msg(struct ofpbuf *msg)
+{
+    rconn_send(swconn, msg, tx_counter);
+}
+
+static void
+ofctrl_recv(const struct ofpbuf *msg)
+{
+    enum ofptype type;
+    struct ofpbuf b;
+
+    b = *msg;
+    if (ofptype_pull(&type, &b)) {
+        return;
+    }
+
+    switch (type) {
+    case OFPTYPE_ECHO_REQUEST:
+        queue_msg(make_echo_reply(msg->data));
+        break;
+
+    case OFPTYPE_ECHO_REPLY:
+    case OFPTYPE_PACKET_IN:
+    case OFPTYPE_PORT_STATUS:
+    case OFPTYPE_FLOW_REMOVED:
+        /* Nothing to do. */
+        break;
+
+    case OFPTYPE_HELLO:
+    case OFPTYPE_ERROR:
+    case OFPTYPE_FEATURES_REQUEST:
+    case OFPTYPE_FEATURES_REPLY:
+    case OFPTYPE_GET_CONFIG_REQUEST:
+    case OFPTYPE_GET_CONFIG_REPLY:
+    case OFPTYPE_SET_CONFIG:
+    case OFPTYPE_PACKET_OUT:
+    case OFPTYPE_FLOW_MOD:
+    case OFPTYPE_GROUP_MOD:
+    case OFPTYPE_PORT_MOD:
+    case OFPTYPE_TABLE_MOD:
+    case OFPTYPE_BARRIER_REQUEST:
+    case OFPTYPE_BARRIER_REPLY:
+    case OFPTYPE_QUEUE_GET_CONFIG_REQUEST:
+    case OFPTYPE_QUEUE_GET_CONFIG_REPLY:
+    case OFPTYPE_DESC_STATS_REQUEST:
+    case OFPTYPE_DESC_STATS_REPLY:
+    case OFPTYPE_FLOW_STATS_REQUEST:
+    case OFPTYPE_FLOW_STATS_REPLY:
+    case OFPTYPE_AGGREGATE_STATS_REQUEST:
+    case OFPTYPE_AGGREGATE_STATS_REPLY:
+    case OFPTYPE_TABLE_STATS_REQUEST:
+    case OFPTYPE_TABLE_STATS_REPLY:
+    case OFPTYPE_PORT_STATS_REQUEST:
+    case OFPTYPE_PORT_STATS_REPLY:
+    case OFPTYPE_QUEUE_STATS_REQUEST:
+    case OFPTYPE_QUEUE_STATS_REPLY:
+    case OFPTYPE_PORT_DESC_STATS_REQUEST:
+    case OFPTYPE_PORT_DESC_STATS_REPLY:
+    case OFPTYPE_ROLE_REQUEST:
+    case OFPTYPE_ROLE_REPLY:
+    case OFPTYPE_ROLE_STATUS:
+    case OFPTYPE_SET_FLOW_FORMAT:
+    case OFPTYPE_FLOW_MOD_TABLE_ID:
+    case OFPTYPE_SET_PACKET_IN_FORMAT:
+    case OFPTYPE_FLOW_AGE:
+    case OFPTYPE_SET_CONTROLLER_ID:
+    case OFPTYPE_FLOW_MONITOR_STATS_REQUEST:
+    case OFPTYPE_FLOW_MONITOR_STATS_REPLY:
+    case OFPTYPE_FLOW_MONITOR_CANCEL:
+    case OFPTYPE_FLOW_MONITOR_PAUSED:
+    case OFPTYPE_FLOW_MONITOR_RESUMED:
+    case OFPTYPE_GET_ASYNC_REQUEST:
+    case OFPTYPE_GET_ASYNC_REPLY:
+    case OFPTYPE_SET_ASYNC_CONFIG:
+    case OFPTYPE_METER_MOD:
+    case OFPTYPE_GROUP_STATS_REQUEST:
+    case OFPTYPE_GROUP_STATS_REPLY:
+    case OFPTYPE_GROUP_DESC_STATS_REQUEST:
+    case OFPTYPE_GROUP_DESC_STATS_REPLY:
+    case OFPTYPE_GROUP_FEATURES_STATS_REQUEST:
+    case OFPTYPE_GROUP_FEATURES_STATS_REPLY:
+    case OFPTYPE_METER_STATS_REQUEST:
+    case OFPTYPE_METER_STATS_REPLY:
+    case OFPTYPE_METER_CONFIG_STATS_REQUEST:
+    case OFPTYPE_METER_CONFIG_STATS_REPLY:
+    case OFPTYPE_METER_FEATURES_STATS_REQUEST:
+    case OFPTYPE_METER_FEATURES_STATS_REPLY:
+    case OFPTYPE_TABLE_FEATURES_STATS_REQUEST:
+    case OFPTYPE_TABLE_FEATURES_STATS_REPLY:
+    case OFPTYPE_BUNDLE_CONTROL:
+    case OFPTYPE_BUNDLE_ADD_MESSAGE:
+    default:
+        /* Messages that are generally unexpected. */
+        if (VLOG_IS_DBG_ENABLED()) {
+            static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(30, 300);
+
+            char *s = ofp_to_string(msg->data, msg->size, 2);
+            VLOG_DBG_RL(&rl, "OpenFlow packet ignored: %s", s);
+            free(s);
+        }
+    }
+}
+
+/* Flow table interface to the rest of ovn-controller. */
+
+/* Clears the table of flows desired to be in the switch.  Call this before
+ * adding the desired flows (with ofctrl_add_flow()). */
+void
+ofctrl_clear_flows(void)
+{
+    ovn_flow_table_clear(&desired_flows);
+}
+
+/* Adds a flow with the specified 'match' and 'actions' to the OpenFlow table
+ * numbered 'table_id' with the given 'priority'.
+ *
+ * This just assembles the desired flow table in memory.  Nothing is actually
+ * sent to the switch until a later call to ofctrl_run(). */
+void
+ofctrl_add_flow(uint8_t table_id, uint16_t priority,
+                const struct match *match, const struct ofpbuf *ofpacts)
+{
+    struct ovn_flow *f = xmalloc(sizeof *f);
+    f->table_id = table_id;
+    f->priority = priority;
+    f->match = *match;
+    f->ofpacts = xmemdup(ofpacts->data, ofpacts->size);
+    f->ofpacts_len = ofpacts->size;
+
+    if (ovn_flow_lookup(&desired_flows, f)) {
+        static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5);
+        if (!VLOG_DROP_INFO(&rl)) {
+            char *s = ovn_flow_to_string(f);
+            VLOG_INFO("dropping duplicate flow: %s", s);
+            free(s);
+        }
+
+        ovn_flow_destroy(f);
+        return;
+    }
+
+    hmap_insert(&desired_flows, &f->hmap_node, ovn_flow_hash(f));
+}
+
+/* ovn_flow. */
+
+/* Returns a hash of the key in 'f'. */
+static uint32_t
+ovn_flow_hash(const struct ovn_flow *f)
+{
+    return hash_2words((f->table_id << 16) | f->priority,
+                       match_hash(&f->match, 0));
+
+}
+
+/* Finds and returns an ovn_flow in 'flow_table' whose key is identical to
+ * 'target''s key, or NULL if there is none. */
+static struct ovn_flow *
+ovn_flow_lookup(struct hmap *flow_table, const struct ovn_flow *target)
+{
+    struct ovn_flow *f;
+
+    HMAP_FOR_EACH_WITH_HASH (f, hmap_node, target->hmap_node.hash,
+                             flow_table) {
+        if (f->table_id == target->table_id
+            && f->priority == target->priority
+            && match_equal(&f->match, &target->match)) {
+            return f;
+        }
+    }
+    return NULL;
+}
+
+static char *
+ovn_flow_to_string(const struct ovn_flow *f)
+{
+    struct ds s = DS_EMPTY_INITIALIZER;
+    ds_put_format(&s, "table_id=%"PRIu8", ", f->table_id);
+    ds_put_format(&s, "priority=%"PRIu16", ", f->priority);
+    match_format(&f->match, &s, OFP_DEFAULT_PRIORITY);
+    ds_put_cstr(&s, ", actions=");
+    ofpacts_format(f->ofpacts, f->ofpacts_len, &s);
+    return ds_steal_cstr(&s);
+}
+
+static void
+ovn_flow_log(const struct ovn_flow *f, const char *action)
+{
+    if (VLOG_IS_DBG_ENABLED()) {
+        char *s = ovn_flow_to_string(f);
+        VLOG_DBG("%s flow: %s", action, s);
+        free(s);
+    }
+}
+
+static void
+ovn_flow_destroy(struct ovn_flow *f)
+{
+    if (f) {
+        free(f->ofpacts);
+        free(f);
+    }
+}
+
+/* Flow tables of struct ovn_flow. */
+
+static void
+ovn_flow_table_clear(struct hmap *flow_table)
+{
+    struct ovn_flow *f, *next;
+    HMAP_FOR_EACH_SAFE (f, next, hmap_node, flow_table) {
+        hmap_remove(flow_table, &f->hmap_node);
+        ovn_flow_destroy(f);
+    }
+}
+static void
+ovn_flow_table_destroy(struct hmap *flow_table)
+{
+    ovn_flow_table_clear(flow_table);
+    hmap_destroy(flow_table);
+}
+
+/* Flow table update. */
+
+static void
+queue_flow_mod(struct ofputil_flow_mod *fm)
+{
+    fm->buffer_id = UINT32_MAX;
+    fm->out_port = OFPP_ANY;
+    fm->out_group = OFPG_ALL;
+    queue_msg(ofputil_encode_flow_mod(fm, OFPUTIL_P_OF13_OXM));
+}
+
+static void
+ofctrl_update_flows(void)
+{
+    /* If we've (re)connected, don't make any assumptions about the flows in
+     * the switch: delete all of them.  (We'll immediately repopulate it
+     * below.) */
+    if (seqno != rconn_get_connection_seqno(swconn)) {
+        seqno = rconn_get_connection_seqno(swconn);
+
+        /* Send a flow_mod to delete all flows. */
+        struct ofputil_flow_mod fm = {
+            .match = MATCH_CATCHALL_INITIALIZER,
+            .table_id = 0,
+            .command = OFPFC_DELETE,
+        };
+        queue_flow_mod(&fm);
+        VLOG_DBG("clearing all flows");
+
+        /* Clear installed_flows, to match the state of the switch. */
+        ovn_flow_table_clear(&installed_flows);
+    }
+
+    /* Iterate through all of the installed flows.  If any of them are no
+     * longer desired, delete them; if any of them should have different
+     * actions, update them. */
+    struct ovn_flow *i, *next;
+    HMAP_FOR_EACH_SAFE (i, next, hmap_node, &installed_flows) {
+        struct ovn_flow *d = ovn_flow_lookup(&desired_flows, i);
+        if (!d) {
+            /* Installed flow is no longer desirable.  Delete it from the
+             * switch and from installed_flows. */
+            struct ofputil_flow_mod fm = {
+                .match = i->match,
+                .priority = i->priority,
+                .table_id = i->table_id,
+                .command = OFPFC_DELETE_STRICT,
+            };
+            queue_flow_mod(&fm);
+            ovn_flow_log(i, "removing");
+
+            hmap_remove(&installed_flows, &i->hmap_node);
+            ovn_flow_destroy(i);
+        } else {
+            if (!ofpacts_equal(i->ofpacts, i->ofpacts_len,
+                               d->ofpacts, d->ofpacts_len)) {
+                /* Update actions in installed flow. */
+                struct ofputil_flow_mod fm = {
+                    .match = i->match,
+                    .priority = i->priority,
+                    .table_id = i->table_id,
+                    .ofpacts = i->ofpacts,
+                    .ofpacts_len = i->ofpacts_len,
+                    .command = OFPFC_MODIFY_STRICT,
+                };
+                queue_flow_mod(&fm);
+                ovn_flow_log(i, "updating");
+
+                /* Replace 'i''s actions by 'd''s. */
+                free(i->ofpacts);
+                i->ofpacts = d->ofpacts;
+                i->ofpacts_len = d->ofpacts_len;
+                d->ofpacts = NULL;
+                d->ofpacts_len = 0;
+            }
+
+            hmap_remove(&desired_flows, &d->hmap_node);
+            ovn_flow_destroy(d);
+        }
+    }
+
+    /* The previous loop removed from desired_flows all of the flows that are
+     * already installed.  Thus, any flows remaining in desired_flows need to
+     * be added to the flow table. */
+    struct ovn_flow *d;
+    HMAP_FOR_EACH_SAFE (d, next, hmap_node, &desired_flows) {
+        /* Send flow_mod to add flow. */
+        struct ofputil_flow_mod fm = {
+            .match = d->match,
+            .priority = d->priority,
+            .table_id = d->table_id,
+            .ofpacts = d->ofpacts,
+            .ofpacts_len = d->ofpacts_len,
+            .command = OFPFC_ADD,
+        };
+        queue_flow_mod(&fm);
+        ovn_flow_log(d, "adding");
+
+        /* Move 'd' from desired_flows to installed_flows. */
+        hmap_remove(&desired_flows, &d->hmap_node);
+        hmap_insert(&installed_flows, &d->hmap_node, d->hmap_node.hash);
+    }
+}
diff --git a/ovn/controller/ofctrl.h b/ovn/controller/ofctrl.h
new file mode 100644
index 0000000..8c689e6
--- /dev/null
+++ b/ovn/controller/ofctrl.h
@@ -0,0 +1,37 @@
+/* Copyright (c) 2015 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#ifndef OFCTRL_H
+#define OFCTRL_H 1
+
+#include <stdint.h>
+
+struct controller_ctx;
+struct match;
+struct ofpbuf;
+
+/* Interface for OVN main loop. */
+void ofctrl_init(void);
+void ofctrl_run(struct controller_ctx *);
+void ofctrl_wait(void);
+void ofctrl_destroy(void);
+
+/* Flow table interface to the rest of ovn-controller. */
+void ofctrl_clear_flows(void);
+void ofctrl_add_flow(uint8_t table_id, uint16_t priority,
+                     const struct match *, const struct ofpbuf *ofpacts);
+
+#endif /* ovn/ofctrl.h */
diff --git a/ovn/controller/ovn-controller.c b/ovn/controller/ovn-controller.c
index 12931b5..32bbc67 100644
--- a/ovn/controller/ovn-controller.c
+++ b/ovn/controller/ovn-controller.c
@@ -15,6 +15,8 @@
 
 #include <config.h>
 
+#include "ovn-controller.h"
+
 #include <errno.h>
 #include <getopt.h>
 #include <signal.h>
@@ -37,7 +39,7 @@
 #include "unixctl.h"
 #include "util.h"
 
-#include "ovn-controller.h"
+#include "ofctrl.h"
 #include "bindings.h"
 #include "chassis.h"
 #include "pipeline.h"
@@ -166,6 +168,8 @@ main(int argc, char *argv[])
     ovsrec_init();
     sbrec_init();
 
+    ofctrl_init();
+
     /* Connect to OVS OVSDB instance.  We do not monitor all tables by
      * default, so modules must register their interest explicitly.  */
     ctx.ovs_idl = ovsdb_idl_create(ovs_remote, &ovsrec_idl_class, false, true);
@@ -220,6 +224,7 @@ main(int argc, char *argv[])
         chassis_run(&ctx);
         bindings_run(&ctx);
         pipeline_run(&ctx);
+        ofctrl_run(&ctx);
         unixctl_server_run(unixctl);
 
         unixctl_server_wait(unixctl);
@@ -229,11 +234,13 @@ main(int argc, char *argv[])
 
         ovsdb_idl_wait(ctx.ovs_idl);
         ovsdb_idl_wait(ctx.ovnsb_idl);
+        ofctrl_wait();
         poll_block();
     }
 
     unixctl_server_destroy(unixctl);
     pipeline_destroy(&ctx);
+    ofctrl_destroy();
     bindings_destroy(&ctx);
     chassis_destroy(&ctx);
 
diff --git a/ovn/controller/pipeline.c b/ovn/controller/pipeline.c
index f124354..5013060 100644
--- a/ovn/controller/pipeline.c
+++ b/ovn/controller/pipeline.c
@@ -16,6 +16,7 @@
 #include <config.h>
 #include "pipeline.h"
 #include "dynamic-string.h"
+#include "ofctrl.h"
 #include "ofp-actions.h"
 #include "ofpbuf.h"
 #include "openvswitch/vlog.h"
@@ -241,20 +242,6 @@ pipeline_init(struct controller_ctx *ctx)
     ovsdb_idl_add_column(ctx->ovnsb_idl, &sbrec_pipeline_col_actions);
 }
 
-static void
-add_ovn_flow(uint8_t table_id, uint16_t priority, const struct match *match,
-             const struct ofpbuf *ofpacts)
-{
-    struct ds s = DS_EMPTY_INITIALIZER;
-    ds_put_format(&s, "table_id=%"PRIu8", ", table_id);
-    ds_put_format(&s, "priority=%"PRIu16", ", priority);
-    match_format(match, &s, OFP_DEFAULT_PRIORITY);
-    ds_put_cstr(&s, ", actions=");
-    ofpacts_format(ofpacts->data, ofpacts->size, &s);
-    VLOG_INFO("%s", ds_cstr(&s));
-    ds_destroy(&s);
-}
-
 /* Translates logical flows in the Pipeline table in the OVN_SB database
  * into OpenFlow flows. */
 void
@@ -265,7 +252,8 @@ pipeline_run(struct controller_ctx *ctx)
 
     ldp_run(ctx);
 
-    VLOG_INFO("starting run...");
+    ofctrl_clear_flows();
+
     const struct sbrec_pipeline *pipeline;
     SBREC_PIPELINE_FOR_EACH (pipeline, ctx->ovnsb_idl) {
         /* Find the "struct logical_datapath" asssociated with this Pipeline
@@ -335,8 +323,8 @@ pipeline_run(struct controller_ctx *ctx)
                 m->match.flow.conj_id += conj_id_ofs;
             }
             if (!m->n) {
-                add_ovn_flow(pipeline->table_id + 16, pipeline->priority,
-                             &m->match, &ofpacts);
+                ofctrl_add_flow(pipeline->table_id + 16, pipeline->priority,
+                                &m->match, &ofpacts);
             } else {
                 uint64_t conj_stubs[64 / 8];
                 struct ofpbuf conj;
@@ -351,8 +339,8 @@ pipeline_run(struct controller_ctx *ctx)
                     dst->clause = src->clause;
                     dst->n_clauses = src->n_clauses;
                 }
-                add_ovn_flow(pipeline->table_id + 16, pipeline->priority,
-                             &m->match, &conj);
+                ofctrl_add_flow(pipeline->table_id + 16, pipeline->priority,
+                                &m->match, &conj);
                 ofpbuf_uninit(&conj);
             }
         }
@@ -362,7 +350,6 @@ pipeline_run(struct controller_ctx *ctx)
         ofpbuf_uninit(&ofpacts);
         conj_id_ofs += n_conjs;
     }
-    VLOG_INFO("...done");
 }
 
 void
-- 
2.1.3




More information about the dev mailing list