This is the first in a series of attempts to trim the fat
off of OVS, to make it friendlier for embedded systems.

Signed-off-by: Alexandru Ardelean <ardeleana...@gmail.com>
---
 configure.ac                   |   1 +
 lib/automake.mk                |  10 +-
 lib/ovs-lldp.h                 |  21 +++
 ofproto/ofproto-dpif-monitor.c |   8 +-
 ofproto/ofproto-dpif.c         |   9 ++
 ofproto/ofproto-provider.h     |   2 +
 ofproto/ofproto.c              |   2 +
 ofproto/ofproto.h              |   4 +-
 tests/automake.mk              |  13 +-
 utilities/ovs-vsctl.c          |  14 +-
 vswitchd/automake.mk           |   6 +
 vswitchd/bridge-aa.c           | 344 +++++++++++++++++++++++++++++++++++++++++
 vswitchd/bridge-aa.h           |  35 +++++
 vswitchd/bridge-internal.h     |  88 +++++++++++
 vswitchd/bridge.c              | 336 +---------------------------------------
 15 files changed, 551 insertions(+), 342 deletions(-)
 create mode 100644 vswitchd/bridge-aa.c
 create mode 100644 vswitchd/bridge-aa.h
 create mode 100644 vswitchd/bridge-internal.h

diff --git a/configure.ac b/configure.ac
index 49aa182..3adbc5e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -100,6 +100,7 @@ OVS_CHECK_DOT
 OVS_CHECK_IF_PACKET
 OVS_CHECK_IF_DL
 OVS_CHECK_STRTOK_R
+OVS_ARG_ENABLE([auto_attach], [Auto-attach for SPBM networks], [yes])
 AC_CHECK_DECLS([sys_siglist], [], [], [[#include <signal.h>]])
 AC_CHECK_MEMBERS([struct stat.st_mtim.tv_nsec, struct stat.st_mtimensec],
   [], [], [[#include <sys/stat.h>]])
diff --git a/lib/automake.mk b/lib/automake.mk
index 5387d51..48a8170 100644
--- a/lib/automake.mk
+++ b/lib/automake.mk
@@ -168,8 +168,6 @@ lib_libopenvswitch_la_SOURCES = \
        lib/ovs-atomic-pthreads.h \
        lib/ovs-atomic-x86_64.h \
        lib/ovs-atomic.h \
-       lib/ovs-lldp.c \
-       lib/ovs-lldp.h \
        lib/ovs-rcu.c \
        lib/ovs-rcu.h \
        lib/ovs-router.h \
@@ -277,7 +275,12 @@ lib_libopenvswitch_la_SOURCES = \
        lib/vlan-bitmap.h \
        lib/vlandev.c \
        lib/vlandev.h \
-       lib/vlog.c \
+       lib/vlog.c
+
+if ENABLE_AUTO_ATTACH
+lib_libopenvswitch_la_SOURCES += \
+       lib/ovs-lldp.c \
+       lib/ovs-lldp.h \
        lib/lldp/aa-structs.h \
        lib/lldp/lldp.c \
        lib/lldp/lldp-const.h \
@@ -286,6 +289,7 @@ lib_libopenvswitch_la_SOURCES = \
        lib/lldp/lldpd.h \
        lib/lldp/lldpd-structs.c \
        lib/lldp/lldpd-structs.h
+endif
 
 if WIN32
 lib_libopenvswitch_la_SOURCES += \
diff --git a/lib/ovs-lldp.h b/lib/ovs-lldp.h
index e780e5b..ba7142d 100644
--- a/lib/ovs-lldp.h
+++ b/lib/ovs-lldp.h
@@ -19,6 +19,8 @@
 #ifndef OVS_LLDP_H
 #define OVS_LLDP_H
 
+#if ENABLE_AUTO_ATTACH
+
 #include <stdint.h>
 #include "dp-packet.h"
 #include "hmap.h"
@@ -104,4 +106,23 @@ int aa_mapping_unregister(void *aux);
 /* Used by unit tests */
 struct lldp * lldp_create_dummy(void);
 
+#else
+
+/* Stubbing these funcs here, to keep the rest a bit cleaner.
+   The compiler should optimize out a few code paths based on these stubs
+*/
+
+struct lldp;
+
+static inline void lldp_init(void) {}
+static inline long long int lldp_wait(struct lldp *l OVS_UNUSED) { return 
LLONG_MAX; }
+static inline struct lldp * lldp_ref(const struct lldp *l OVS_UNUSED) { return 
NULL; }
+static inline void lldp_unref(struct lldp *l OVS_UNUSED) {}
+static inline bool lldp_should_process_flow(struct lldp *l OVS_UNUSED,
+    const struct flow *f OVS_UNUSED) { return false; }
+static inline void lldp_process_packet(struct lldp *cfg OVS_UNUSED,
+    const struct dp_packet *p OVS_UNUSED) {}
+
+#endif /* ENABLE_AUTO_ATTACH */
+
 #endif /* OVS_LLDP_H */
diff --git a/ofproto/ofproto-dpif-monitor.c b/ofproto/ofproto-dpif-monitor.c
index 0548400..b024a35 100644
--- a/ofproto/ofproto-dpif-monitor.c
+++ b/ofproto/ofproto-dpif-monitor.c
@@ -284,11 +284,16 @@ monitor_mport_run(struct mport *mport, struct dp_packet 
*packet)
         bfd_put_packet(mport->bfd, packet, mport->hw_addr);
         ofproto_dpif_send_packet(mport->ofport, packet);
     }
+#if ENABLE_AUTO_ATTACH
     if (mport->lldp && lldp_should_send_packet(mport->lldp)) {
         dp_packet_clear(packet);
         lldp_put_packet(mport->lldp, packet, mport->hw_addr);
         ofproto_dpif_send_packet(mport->ofport, packet);
     }
+    if (mport->lldp) {
+        lldp_wake_time = lldp_wait(mport->lldp);
+    }
+#endif
 
     if (mport->cfm) {
         cfm_run(mport->cfm);
@@ -298,9 +303,6 @@ monitor_mport_run(struct mport *mport, struct dp_packet 
*packet)
         bfd_run(mport->bfd);
         bfd_wake_time = bfd_wait(mport->bfd);
     }
-    if (mport->lldp) {
-        lldp_wake_time = lldp_wait(mport->lldp);
-    }
     /* Computes the next wakeup time for this mport. */
     next_wake_time = MIN(bfd_wake_time,
                          cfm_wake_time);
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 8186f6b..87b0197 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -2088,6 +2088,7 @@ get_bfd_status(struct ofport *ofport_, struct smap *smap)
     return ret;
 }
 
+#if ENABLE_AUTO_ATTACH
 static int
 set_lldp(struct ofport *ofport_,
          const struct smap *cfg)
@@ -2161,6 +2162,12 @@ aa_vlan_get_queue_size(struct ofproto *ofproto 
OVS_UNUSED)
 {
     return aa_get_vlan_queue_size();
 }
+#else
+static int set_lldp(struct ofport *ofport OVS_UNUSED, const struct smap *cfg 
OVS_UNUSED)
+{
+    return ENOTSUP;
+}
+#endif /* ENABLE_AUTO_ATTACH */
 
 
 /* Spanning Tree. */
@@ -5770,6 +5777,7 @@ const struct ofproto_class ofproto_dpif_class = {
     set_cfm,
     cfm_status_changed,
     get_cfm_status,
+#if ENABLE_AUTO_ATTACH
     set_lldp,
     get_lldp_status,
     set_aa,
@@ -5777,6 +5785,7 @@ const struct ofproto_class ofproto_dpif_class = {
     aa_mapping_unset,
     aa_vlan_get_queued,
     aa_vlan_get_queue_size,
+#endif
     set_bfd,
     bfd_status_changed,
     get_bfd_status,
diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h
index b6aac0a..15c4ba4 100644
--- a/ofproto/ofproto-provider.h
+++ b/ofproto/ofproto-provider.h
@@ -1367,6 +1367,7 @@ struct ofproto_class {
     int (*get_cfm_status)(const struct ofport *ofport,
                           struct cfm_status *status);
 
+#if ENABLE_AUTO_ATTACH
     /* Configures LLDP on 'ofport'.
      *
      * EOPNOTSUPP as a return value indicates that this ofproto_class does not
@@ -1437,6 +1438,7 @@ struct ofproto_class {
      * aa_vlan_get_queued).  Returns 0 if Auto Attach is disabled.
      */
     unsigned int (*aa_vlan_get_queue_size)(struct ofproto *ofproto);
+#endif /* ENABLE_AUTO_ATTACH */
 
     /* Configures BFD on 'ofport'.
      *
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index 528d5ac..fd4a24e 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -1082,6 +1082,7 @@ ofproto_port_set_queues(struct ofproto *ofproto, 
ofp_port_t ofp_port,
             ? ofproto->ofproto_class->set_queues(ofport, queues, n_queues)
             : EOPNOTSUPP);
 }
+#if ENABLE_AUTO_ATTACH
 
 /* LLDP configuration. */
 void
@@ -1159,6 +1160,7 @@ ofproto_aa_vlan_get_queue_size(struct ofproto *ofproto)
     }
     return ofproto->ofproto_class->aa_vlan_get_queue_size(ofproto);
 }
+#endif /* ENABLE_AUTO_ATTACH */
 
 /* Connectivity Fault Management configuration. */
 
diff --git a/ofproto/ofproto.h b/ofproto/ofproto.h
index 7504027..cad447d 100644
--- a/ofproto/ofproto.h
+++ b/ofproto/ofproto.h
@@ -49,7 +49,6 @@ struct simap;
 struct smap;
 struct netdev_stats;
 struct ovs_list;
-struct lldp_status;
 struct aa_settings;
 struct aa_mapping_settings;
 
@@ -441,6 +440,8 @@ int ofproto_mirror_unregister(struct ofproto *, void *aux);
 int ofproto_mirror_get_stats(struct ofproto *, void *aux,
                              uint64_t *packets, uint64_t *bytes);
 
+#if ENABLE_AUTO_ATTACH
+struct lldp_status;
 void ofproto_port_set_lldp(struct ofproto *ofproto, ofp_port_t ofp_port,
                            const struct smap *cfg);
 int ofproto_set_aa(struct ofproto *ofproto, void *aux,
@@ -450,6 +451,7 @@ int ofproto_aa_mapping_register(struct ofproto *ofproto, 
void *aux,
 int ofproto_aa_mapping_unregister(struct ofproto *ofproto, void *aux);
 int ofproto_aa_vlan_get_queued(struct ofproto *ofproto, struct ovs_list *list);
 unsigned int ofproto_aa_vlan_get_queue_size(struct ofproto *ofproto);
+#endif
 
 int ofproto_set_flood_vlans(struct ofproto *, unsigned long *flood_vlans);
 bool ofproto_is_mirror_output_bundle(const struct ofproto *, void *aux);
diff --git a/tests/automake.mk b/tests/automake.mk
index 28078c0..373ca16 100644
--- a/tests/automake.mk
+++ b/tests/automake.mk
@@ -93,6 +93,11 @@ TESTSUITE_AT = \
        tests/ovn-controller.at \
        tests/ovn-controller-vtep.at
 
+if ENABLE_AUTO_ATTACH
+TESTSUITE_AT += \
+    tests/auto-attach.at
+endif
+
 SYSTEM_KMOD_TESTSUITE_AT = \
        tests/system-common-macros.at \
        tests/system-kmod-testsuite.at \
@@ -316,8 +321,12 @@ tests_ovstest_SOURCES = \
        tests/test-util.c \
        tests/test-uuid.c \
        tests/test-bitmap.c \
-       tests/test-vconn.c \
-       tests/test-aa.c
+       tests/test-vconn.c
+
+if ENABLE_AUTO_ATTACH
+tests_ovstest_SOURCES += \
+    tests/test-aa.c
+endif
 
 if !WIN32
 tests_ovstest_SOURCES += \
diff --git a/utilities/ovs-vsctl.c b/utilities/ovs-vsctl.c
index 36290db..4a3d837 100644
--- a/utilities/ovs-vsctl.c
+++ b/utilities/ovs-vsctl.c
@@ -402,13 +402,15 @@ SSL commands:\n\
   get-ssl                     print the SSL configuration\n\
   del-ssl                     delete the SSL configuration\n\
   set-ssl PRIV-KEY CERT CA-CERT  set the SSL configuration\n\
-\n\
-Auto Attach commands:\n\
+\n"
+#if ENABLE_AUTO_ATTACH
+"Auto Attach commands:\n\
   add-aa-mapping BRIDGE I-SID VLAN   add Auto Attach mapping to BRIDGE\n\
   del-aa-mapping BRIDGE I-SID VLAN   delete Auto Attach mapping VLAN from 
BRIDGE\n\
   get-aa-mapping BRIDGE              get Auto Attach mappings from BRIDGE\n\
-\n\
-Switch commands:\n\
+\n"
+#endif
+"Switch commands:\n\
   emer-reset                  reset switch to known good state\n\
 \n\
 %s\
@@ -2100,6 +2102,7 @@ cmd_set_ssl(struct ctl_context *ctx)
     ovsrec_open_vswitch_set_ssl(vsctl_ctx->ovs, ssl);
 }
 
+#if ENABLE_AUTO_ATTACH
 static void
 autoattach_insert_mapping(struct ovsrec_autoattach *aa,
                           int64_t isid,
@@ -2275,6 +2278,7 @@ cmd_get_aa_mapping(struct ctl_context *ctx)
         }
     }
 }
+#endif
 
 
 static const struct ctl_table_class tables[] = {
@@ -2763,6 +2767,7 @@ static const struct ctl_command_syntax vsctl_commands[] = 
{
     {"set-ssl", 3, 3, "PRIVATE-KEY CERTIFICATE CA-CERT", pre_cmd_set_ssl,
      cmd_set_ssl, NULL, "--bootstrap", RW},
 
+#if ENABLE_AUTO_ATTACH
     /* Auto Attach commands. */
     {"add-aa-mapping", 3, 3, "BRIDGE ARG ARG", pre_aa_mapping, 
cmd_add_aa_mapping,
      NULL, "", RW},
@@ -2770,6 +2775,7 @@ static const struct ctl_command_syntax vsctl_commands[] = 
{
      NULL, "", RW},
     {"get-aa-mapping", 1, 1, "BRIDGE", pre_aa_mapping, cmd_get_aa_mapping,
      NULL, "", RO},
+#endif
 
     /* Switch commands. */
     {"emer-reset", 0, 0, "", pre_cmd_emer_reset, cmd_emer_reset, NULL, "", RW},
diff --git a/vswitchd/automake.mk b/vswitchd/automake.mk
index 8d7f3ea..ddd082b 100644
--- a/vswitchd/automake.mk
+++ b/vswitchd/automake.mk
@@ -6,11 +6,17 @@ DISTCLEANFILES += \
 vswitchd_ovs_vswitchd_SOURCES = \
        vswitchd/bridge.c \
        vswitchd/bridge.h \
+       vswitchd/bridge-aa.h \
+       vswitchd/bridge-internal.h \
        vswitchd/ovs-vswitchd.c \
        vswitchd/system-stats.c \
        vswitchd/system-stats.h \
        vswitchd/xenserver.c \
        vswitchd/xenserver.h
+if ENABLE_AUTO_ATTACH
+vswitchd_ovs_vswitchd_SOURCES += \
+       vswitchd/bridge-aa.c
+endif
 vswitchd_ovs_vswitchd_LDADD = \
        ofproto/libofproto.la \
        lib/libsflow.la \
diff --git a/vswitchd/bridge-aa.c b/vswitchd/bridge-aa.c
new file mode 100644
index 0000000..be1a6f7
--- /dev/null
+++ b/vswitchd/bridge-aa.c
@@ -0,0 +1,344 @@
+/* Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 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 "bridge.h"
+#include <errno.h>
+#include <inttypes.h>
+#include <stdlib.h>
+
+#include "async-append.h"
+#include "bfd.h"
+#include "bitmap.h"
+#include "cfm.h"
+#include "connectivity.h"
+#include "coverage.h"
+#include "daemon.h"
+#include "dirs.h"
+#include "dpif.h"
+#include "dynamic-string.h"
+#include "hash.h"
+#include "hmap.h"
+#include "hmapx.h"
+#include "jsonrpc.h"
+#include "lacp.h"
+#include "list.h"
+#include "ovs-lldp.h"
+#include "mac-learning.h"
+#include "mcast-snooping.h"
+#include "meta-flow.h"
+#include "netdev.h"
+#include "nx-match.h"
+#include "ofp-print.h"
+#include "ofp-util.h"
+#include "ofpbuf.h"
+#include "ofproto/bond.h"
+#include "ofproto/ofproto.h"
+#include "ovs-numa.h"
+#include "poll-loop.h"
+#include "if-notifier.h"
+#include "seq.h"
+#include "sha1.h"
+#include "shash.h"
+#include "smap.h"
+#include "socket-util.h"
+#include "stream.h"
+#include "stream-ssl.h"
+#include "sset.h"
+#include "system-stats.h"
+#include "timeval.h"
+#include "util.h"
+#include "unixctl.h"
+#include "vlandev.h"
+#include "lib/vswitch-idl.h"
+#include "xenserver.h"
+#include "openvswitch/vlog.h"
+#include "sflow_api.h"
+#include "vlan-bitmap.h"
+#include "packets.h"
+
+#include "bridge-internal.h"
+#include "bridge-aa.h"
+
+VLOG_DEFINE_THIS_MODULE(bridge_aa);
+
+struct aa_mapping {
+    struct hmap_node hmap_node; /* In struct bridge's "mappings" hmap. */
+    struct bridge *bridge;
+    uint32_t isid;
+    uint16_t vlan;
+    char *br_name;
+};
+
+/* Each time this timer expires, the bridge fetches the list of port/VLAN
+ * membership that has been modified by the AA.
+ */
+#define AA_REFRESH_INTERVAL (1000) /* In milliseconds. */
+static long long int aa_refresh_timer = LLONG_MIN;
+
+/* Whenever system interfaces are added, removed or change state, the bridge
+ * will be reconfigured.
+ */
+static void bridge_aa_refresh_queued(struct bridge *);
+static inline bool bridge_aa_need_refresh(struct bridge *br)
+{
+    return ofproto_aa_vlan_get_queue_size(br->ofproto) > 0;
+}
+
+static struct aa_mapping *
+bridge_aa_mapping_find(struct bridge *br, const int64_t isid)
+{
+    struct aa_mapping *m;
+
+    HMAP_FOR_EACH_IN_BUCKET (m,
+                             hmap_node,
+                             hash_bytes(&isid, sizeof isid, 0),
+                             &br->mappings) {
+        if (isid == m->isid) {
+            return m;
+        }
+    }
+    return NULL;
+}
+
+static struct aa_mapping *
+bridge_aa_mapping_create(struct bridge *br,
+                         const int64_t isid,
+                         const int64_t vlan)
+{
+    struct aa_mapping *m;
+
+    m = xzalloc(sizeof *m);
+    m->bridge = br;
+    m->isid = isid;
+    m->vlan = vlan;
+    m->br_name = xstrdup(br->name);
+    hmap_insert(&br->mappings,
+                &m->hmap_node,
+                hash_bytes(&isid, sizeof isid, 0));
+
+    return m;
+}
+
+static void
+bridge_aa_mapping_destroy(struct aa_mapping *m)
+{
+    if (m) {
+        struct bridge *br = m->bridge;
+
+        if (br->ofproto) {
+            ofproto_aa_mapping_unregister(br->ofproto, m);
+        }
+
+        hmap_remove(&br->mappings, &m->hmap_node);
+        if (m->br_name) {
+            free(m->br_name);
+        }
+        free(m);
+    }
+}
+
+static bool
+bridge_aa_mapping_configure(struct aa_mapping *m)
+{
+    struct aa_mapping_settings s;
+
+    s.isid = m->isid;
+    s.vlan = m->vlan;
+
+    /* Configure. */
+    ofproto_aa_mapping_register(m->bridge->ofproto, m, &s);
+
+    return true;
+}
+
+void
+bridge_configure_aa(struct bridge *br)
+{
+    const struct ovsdb_datum *mc;
+    struct ovsrec_autoattach *auto_attach = br->cfg->auto_attach;
+    struct aa_settings aa_s;
+    struct aa_mapping *m, *next;
+    size_t i;
+
+    if (!auto_attach) {
+        ofproto_set_aa(br->ofproto, NULL, NULL);
+        return;
+    }
+
+    memset(&aa_s, 0, sizeof aa_s);
+    aa_s.system_description = auto_attach->system_description;
+    aa_s.system_name = auto_attach->system_name;
+    ofproto_set_aa(br->ofproto, NULL, &aa_s);
+
+    mc = ovsrec_autoattach_get_mappings(auto_attach,
+                                        OVSDB_TYPE_INTEGER,
+                                        OVSDB_TYPE_INTEGER);
+    HMAP_FOR_EACH_SAFE (m, next, hmap_node, &br->mappings) {
+        union ovsdb_atom atom;
+
+        atom.integer = m->isid;
+        if (ovsdb_datum_find_key(mc, &atom, OVSDB_TYPE_UUID) == UINT_MAX) {
+            VLOG_INFO("Deleting isid=%"PRIu32", vlan=%"PRIu16,
+                      m->isid, m->vlan);
+            bridge_aa_mapping_destroy(m);
+        }
+    }
+
+    /* Add new mappings and reconfigure existing ones. */
+    for (i = 0; i < auto_attach->n_mappings; ++i) {
+        struct aa_mapping *m =
+            bridge_aa_mapping_find(br, auto_attach->key_mappings[i]);
+
+        if (!m) {
+            VLOG_INFO("Adding isid=%"PRId64", vlan=%"PRId64,
+                      auto_attach->key_mappings[i],
+                      auto_attach->value_mappings[i]);
+            m = bridge_aa_mapping_create(br,
+                                         auto_attach->key_mappings[i],
+                                         auto_attach->value_mappings[i]);
+
+            if (!bridge_aa_mapping_configure(m)) {
+                bridge_aa_mapping_destroy(m);
+            }
+        }
+    }
+}
+
+static void
+bridge_aa_update_trunks(struct port *port, struct bridge_aa_vlan *m)
+{
+    int64_t *trunks = NULL;
+    unsigned int i = 0;
+    bool found = false, reconfigure = false;
+
+    for (i = 0; i < port->cfg->n_trunks; i++) {
+        if (port->cfg->trunks[i] == m->vlan) {
+            found = true;
+            break;
+        }
+    }
+
+    switch (m->oper) {
+        case BRIDGE_AA_VLAN_OPER_ADD:
+            if (!found) {
+                trunks = xmalloc(sizeof *trunks * (port->cfg->n_trunks + 1));
+
+                for (i = 0; i < port->cfg->n_trunks; i++) {
+                    trunks[i] = port->cfg->trunks[i];
+                }
+                trunks[i++] = m->vlan;
+                reconfigure = true;
+            }
+
+            break;
+
+        case BRIDGE_AA_VLAN_OPER_REMOVE:
+            if (found) {
+                unsigned int j = 0;
+
+                trunks = xmalloc(sizeof *trunks * (port->cfg->n_trunks - 1));
+
+                for (i = 0; i < port->cfg->n_trunks; i++) {
+                    if (port->cfg->trunks[i] != m->vlan) {
+                        trunks[j++] = port->cfg->trunks[i];
+                    }
+                }
+                i = j;
+                reconfigure = true;
+            }
+
+            break;
+
+        case BRIDGE_AA_VLAN_OPER_UNDEF:
+        default:
+            VLOG_WARN("unrecognized operation %u", m->oper);
+            break;
+    }
+
+    if (reconfigure) {
+        /* VLAN switching under trunk mode cause the trunk port to switch all
+         * VLANs, see ovs-vswitchd.conf.db
+         */
+        if (i == 0)  {
+            static char *vlan_mode_access = "access";
+            ovsrec_port_set_vlan_mode(port->cfg, vlan_mode_access);
+        }
+
+        if (i == 1) {
+            static char *vlan_mode_trunk = "trunk";
+            ovsrec_port_set_vlan_mode(port->cfg, vlan_mode_trunk);
+        }
+
+        ovsrec_port_set_trunks(port->cfg, trunks, i);
+
+        /* Force reconfigure of the port. */
+        port_configure(port);
+    }
+}
+
+/* Whenever system interfaces are added, removed or change state, the bridge
+ * will be reconfigured.
+ */
+static void
+bridge_aa_refresh_queued(struct bridge *br)
+{
+    struct ovs_list *list = xmalloc(sizeof *list);
+    struct bridge_aa_vlan *node, *next;
+
+    list_init(list);
+    ofproto_aa_vlan_get_queued(br->ofproto, list);
+
+    LIST_FOR_EACH_SAFE (node, next, list_node, list) {
+        struct port *port;
+
+        VLOG_INFO("ifname=%s, vlan=%u, oper=%u", node->port_name, node->vlan,
+                  node->oper);
+
+        port = port_lookup(br, node->port_name);
+        if (port) {
+            bridge_aa_update_trunks(port, node);
+        }
+
+        list_remove(&node->list_node);
+        free(node->port_name);
+        free(node);
+    }
+
+    free(list);
+}
+
+void
+bridge_aa_status_update(struct hmap *all_bridges, struct ovsdb_idl *idl)
+{
+    /* Refresh AA port status if necessary. */
+    if (time_msec() >= aa_refresh_timer) {
+        struct bridge *br;
+
+        HMAP_FOR_EACH (br, node, all_bridges) {
+            if (bridge_aa_need_refresh(br)) {
+                struct ovsdb_idl_txn *txn;
+
+                txn = ovsdb_idl_txn_create(idl);
+                bridge_aa_refresh_queued(br);
+                ovsdb_idl_txn_commit(txn);
+                ovsdb_idl_txn_destroy(txn);
+            }
+        }
+
+        aa_refresh_timer = time_msec() + AA_REFRESH_INTERVAL;
+    }
+}
+
diff --git a/vswitchd/bridge-aa.h b/vswitchd/bridge-aa.h
new file mode 100644
index 0000000..176cfc6
--- /dev/null
+++ b/vswitchd/bridge-aa.h
@@ -0,0 +1,35 @@
+/* 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 VSWITCHD_BRIDGE_AA_H
+#define VSWITCHD_BRIDGE_AA_H 1
+
+#include "ovs-lldp.h"
+
+#ifdef ENABLE_AUTO_ATTACH
+static inline void bridge_aa_port_set_lldp(struct bridge *br, struct iface 
*iface) {
+    ofproto_port_set_lldp(br->ofproto, iface->ofp_port, &iface->cfg->lldp);
+}
+void bridge_configure_aa(struct bridge *);
+void bridge_aa_status_update(struct hmap *, struct ovsdb_idl *);
+#else
+static inline void bridge_aa_port_set_lldp(struct bridge *b OVS_UNUSED,
+    struct iface *i OVS_UNUSED) {}
+static inline void bridge_configure_aa(struct bridge *b OVS_UNUSED) {}
+static inline void bridge_aa_status_update(struct hmap *h OVS_UNUSED,
+    struct ovsdb_idl *i OVS_UNUSED) {}
+#endif /* ENABLE_AUTO_ATTACH */
+
+#endif /* bridge_aa.h */
diff --git a/vswitchd/bridge-internal.h b/vswitchd/bridge-internal.h
new file mode 100644
index 0000000..de76521
--- /dev/null
+++ b/vswitchd/bridge-internal.h
@@ -0,0 +1,88 @@
+/* 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 VSWITCHD_BRIDGE_INTERNAL_H
+#define VSWITCHD_BRIDGE_INTERNAL_H 1
+
+/* Data structures and functions shared between bridge.c
+   and bridge-aa.c (and other bridge-*.c that may come)
+*/
+
+struct iface {
+    /* These members are always valid.
+     *
+     * They are immutable: they never change between iface_create() and
+     * iface_destroy(). */
+    struct ovs_list port_elem;  /* Element in struct port's "ifaces" list. */
+    struct hmap_node name_node; /* In struct bridge's "iface_by_name" hmap. */
+    struct hmap_node ofp_port_node; /* In struct bridge's "ifaces" hmap. */
+    struct port *port;          /* Containing port. */
+    char *name;                 /* Host network device name. */
+    struct netdev *netdev;      /* Network device. */
+    ofp_port_t ofp_port;        /* OpenFlow port number. */
+    uint64_t change_seq;
+
+    /* These members are valid only within bridge_reconfigure(). */
+    const char *type;           /* Usually same as cfg->type. */
+    const struct ovsrec_interface *cfg;
+};
+
+struct port {
+    struct hmap_node hmap_node; /* Element in struct bridge's "ports" hmap. */
+    struct bridge *bridge;
+    char *name;
+
+    const struct ovsrec_port *cfg;
+
+    /* An ordinary bridge port has 1 interface.
+     * A bridge port for bonding has at least 2 interfaces. */
+    struct ovs_list ifaces;    /* List of "struct iface"s. */
+};
+
+struct bridge {
+    struct hmap_node node;      /* In 'all_bridges'. */
+    char *name;                 /* User-specified arbitrary name. */
+    char *type;                 /* Datapath type. */
+    struct eth_addr ea;         /* Bridge Ethernet Address. */
+    struct eth_addr default_ea; /* Default MAC. */
+    const struct ovsrec_bridge *cfg;
+
+    /* OpenFlow switch processing. */
+    struct ofproto *ofproto;    /* OpenFlow switch. */
+
+    /* Bridge ports. */
+    struct hmap ports;          /* "struct port"s indexed by name. */
+    struct hmap ifaces;         /* "struct iface"s indexed by ofp_port. */
+    struct hmap iface_by_name;  /* "struct iface"s indexed by name. */
+
+    /* Port mirroring. */
+    struct hmap mirrors;        /* "struct mirror" indexed by UUID. */
+
+    /* Auto Attach */
+    struct hmap mappings;       /* "struct" indexed by UUID */
+
+    /* Used during reconfiguration. */
+    struct shash wanted_ports;
+
+    /* Synthetic local port if necessary. */
+    struct ovsrec_port synth_local_port;
+    struct ovsrec_interface synth_local_iface;
+    struct ovsrec_interface *synth_local_ifacep;
+};
+
+void port_configure(struct port *);
+struct port * port_lookup(const struct bridge *, const char *);
+
+#endif /* bridge-internal.h */
diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c
index f8afe55..0463e58 100644
--- a/vswitchd/bridge.c
+++ b/vswitchd/bridge.c
@@ -35,7 +35,6 @@
 #include "jsonrpc.h"
 #include "lacp.h"
 #include "list.h"
-#include "ovs-lldp.h"
 #include "mac-learning.h"
 #include "mcast-snooping.h"
 #include "meta-flow.h"
@@ -69,29 +68,13 @@
 #include "vlan-bitmap.h"
 #include "packets.h"
 
+#include "bridge-internal.h"
+#include "bridge-aa.h"
+
 VLOG_DEFINE_THIS_MODULE(bridge);
 
 COVERAGE_DEFINE(bridge_reconfigure);
 
-struct iface {
-    /* These members are always valid.
-     *
-     * They are immutable: they never change between iface_create() and
-     * iface_destroy(). */
-    struct ovs_list port_elem;  /* Element in struct port's "ifaces" list. */
-    struct hmap_node name_node; /* In struct bridge's "iface_by_name" hmap. */
-    struct hmap_node ofp_port_node; /* In struct bridge's "ifaces" hmap. */
-    struct port *port;          /* Containing port. */
-    char *name;                 /* Host network device name. */
-    struct netdev *netdev;      /* Network device. */
-    ofp_port_t ofp_port;        /* OpenFlow port number. */
-    uint64_t change_seq;
-
-    /* These members are valid only within bridge_reconfigure(). */
-    const char *type;           /* Usually same as cfg->type. */
-    const struct ovsrec_interface *cfg;
-};
-
 struct mirror {
     struct uuid uuid;           /* UUID of this "mirror" record in database. */
     struct hmap_node hmap_node; /* In struct bridge's "mirrors" hmap. */
@@ -100,57 +83,6 @@ struct mirror {
     const struct ovsrec_mirror *cfg;
 };
 
-struct port {
-    struct hmap_node hmap_node; /* Element in struct bridge's "ports" hmap. */
-    struct bridge *bridge;
-    char *name;
-
-    const struct ovsrec_port *cfg;
-
-    /* An ordinary bridge port has 1 interface.
-     * A bridge port for bonding has at least 2 interfaces. */
-    struct ovs_list ifaces;    /* List of "struct iface"s. */
-};
-
-struct bridge {
-    struct hmap_node node;      /* In 'all_bridges'. */
-    char *name;                 /* User-specified arbitrary name. */
-    char *type;                 /* Datapath type. */
-    struct eth_addr ea;         /* Bridge Ethernet Address. */
-    struct eth_addr default_ea; /* Default MAC. */
-    const struct ovsrec_bridge *cfg;
-
-    /* OpenFlow switch processing. */
-    struct ofproto *ofproto;    /* OpenFlow switch. */
-
-    /* Bridge ports. */
-    struct hmap ports;          /* "struct port"s indexed by name. */
-    struct hmap ifaces;         /* "struct iface"s indexed by ofp_port. */
-    struct hmap iface_by_name;  /* "struct iface"s indexed by name. */
-
-    /* Port mirroring. */
-    struct hmap mirrors;        /* "struct mirror" indexed by UUID. */
-
-    /* Auto Attach */
-    struct hmap mappings;       /* "struct" indexed by UUID */
-
-    /* Used during reconfiguration. */
-    struct shash wanted_ports;
-
-    /* Synthetic local port if necessary. */
-    struct ovsrec_port synth_local_port;
-    struct ovsrec_interface synth_local_iface;
-    struct ovsrec_interface *synth_local_ifacep;
-};
-
-struct aa_mapping {
-    struct hmap_node hmap_node; /* In struct bridge's "mappings" hmap. */
-    struct bridge *bridge;
-    uint32_t isid;
-    uint16_t vlan;
-    char *br_name;
-};
-
 /* All bridges, indexed by name. */
 static struct hmap all_bridges = HMAP_INITIALIZER(&all_bridges);
 
@@ -212,12 +144,6 @@ static struct ovsdb_idl_txn *stats_txn;
 static int stats_timer_interval;
 static long long int stats_timer = LLONG_MIN;
 
-/* Each time this timer expires, the bridge fetches the list of port/VLAN
- * membership that has been modified by the AA.
- */
-#define AA_REFRESH_INTERVAL (1000) /* In milliseconds. */
-static long long int aa_refresh_timer = LLONG_MIN;
-
 /* Whenever system interfaces are added, removed or change state, the bridge
  * will be reconfigured.
  */
@@ -253,9 +179,6 @@ static void bridge_configure_ipfix(struct bridge *);
 static void bridge_configure_spanning_tree(struct bridge *);
 static void bridge_configure_tables(struct bridge *);
 static void bridge_configure_dp_desc(struct bridge *);
-static void bridge_configure_aa(struct bridge *);
-static void bridge_aa_refresh_queued(struct bridge *);
-static bool bridge_aa_need_refresh(struct bridge *);
 static void bridge_configure_remotes(struct bridge *,
                                      const struct sockaddr_in *managers,
                                      size_t n_managers);
@@ -274,8 +197,6 @@ static unixctl_cb_func qos_unixctl_show;
 static struct port *port_create(struct bridge *, const struct ovsrec_port *);
 static void port_del_ifaces(struct port *);
 static void port_destroy(struct port *);
-static struct port *port_lookup(const struct bridge *, const char *name);
-static void port_configure(struct port *);
 static struct lacp_settings *port_configure_lacp(struct port *,
                                                  struct lacp_settings *);
 static void port_configure_bond(struct port *, struct bond_settings *);
@@ -673,8 +594,7 @@ bridge_reconfigure(const struct ovsrec_open_vswitch 
*ovs_cfg)
                 iface_set_mac(br, port, iface);
                 ofproto_port_set_bfd(br->ofproto, iface->ofp_port,
                                      &iface->cfg->bfd);
-                ofproto_port_set_lldp(br->ofproto, iface->ofp_port,
-                                      &iface->cfg->lldp);
+                bridge_aa_port_set_lldp(br, iface);
             }
         }
         bridge_configure_mirrors(br);
@@ -908,7 +828,7 @@ bridge_add_ports(struct bridge *br, const struct shash 
*wanted_ports)
     bridge_add_ports__(br, wanted_ports, false);
 }
 
-static void
+void
 port_configure(struct port *port)
 {
     const struct ovsrec_port *cfg = port->cfg;
@@ -2827,23 +2747,7 @@ run_status_update(void)
         }
     }
 
-    /* Refresh AA port status if necessary. */
-    if (time_msec() >= aa_refresh_timer) {
-        struct bridge *br;
-
-        HMAP_FOR_EACH (br, node, &all_bridges) {
-            if (bridge_aa_need_refresh(br)) {
-                struct ovsdb_idl_txn *txn;
-
-                txn = ovsdb_idl_txn_create(idl);
-                bridge_aa_refresh_queued(br);
-                ovsdb_idl_txn_commit(txn);
-                ovsdb_idl_txn_destroy(txn);
-            }
-        }
-
-        aa_refresh_timer = time_msec() + AA_REFRESH_INTERVAL;
-    }
+    bridge_aa_status_update(&all_bridges, idl);
 }
 
 static void
@@ -3741,232 +3645,6 @@ bridge_configure_dp_desc(struct bridge *br)
                         smap_get(&br->cfg->other_config, "dp-desc"));
 }
 
-static struct aa_mapping *
-bridge_aa_mapping_find(struct bridge *br, const int64_t isid)
-{
-    struct aa_mapping *m;
-
-    HMAP_FOR_EACH_IN_BUCKET (m,
-                             hmap_node,
-                             hash_bytes(&isid, sizeof isid, 0),
-                             &br->mappings) {
-        if (isid == m->isid) {
-            return m;
-        }
-    }
-    return NULL;
-}
-
-static struct aa_mapping *
-bridge_aa_mapping_create(struct bridge *br,
-                         const int64_t isid,
-                         const int64_t vlan)
-{
-    struct aa_mapping *m;
-
-    m = xzalloc(sizeof *m);
-    m->bridge = br;
-    m->isid = isid;
-    m->vlan = vlan;
-    m->br_name = xstrdup(br->name);
-    hmap_insert(&br->mappings,
-                &m->hmap_node,
-                hash_bytes(&isid, sizeof isid, 0));
-
-    return m;
-}
-
-static void
-bridge_aa_mapping_destroy(struct aa_mapping *m)
-{
-    if (m) {
-        struct bridge *br = m->bridge;
-
-        if (br->ofproto) {
-            ofproto_aa_mapping_unregister(br->ofproto, m);
-        }
-
-        hmap_remove(&br->mappings, &m->hmap_node);
-        if (m->br_name) {
-            free(m->br_name);
-        }
-        free(m);
-    }
-}
-
-static bool
-bridge_aa_mapping_configure(struct aa_mapping *m)
-{
-    struct aa_mapping_settings s;
-
-    s.isid = m->isid;
-    s.vlan = m->vlan;
-
-    /* Configure. */
-    ofproto_aa_mapping_register(m->bridge->ofproto, m, &s);
-
-    return true;
-}
-
-static void
-bridge_configure_aa(struct bridge *br)
-{
-    const struct ovsdb_datum *mc;
-    struct ovsrec_autoattach *auto_attach = br->cfg->auto_attach;
-    struct aa_settings aa_s;
-    struct aa_mapping *m, *next;
-    size_t i;
-
-    if (!auto_attach) {
-        ofproto_set_aa(br->ofproto, NULL, NULL);
-        return;
-    }
-
-    memset(&aa_s, 0, sizeof aa_s);
-    aa_s.system_description = auto_attach->system_description;
-    aa_s.system_name = auto_attach->system_name;
-    ofproto_set_aa(br->ofproto, NULL, &aa_s);
-
-    mc = ovsrec_autoattach_get_mappings(auto_attach,
-                                        OVSDB_TYPE_INTEGER,
-                                        OVSDB_TYPE_INTEGER);
-    HMAP_FOR_EACH_SAFE (m, next, hmap_node, &br->mappings) {
-        union ovsdb_atom atom;
-
-        atom.integer = m->isid;
-        if (ovsdb_datum_find_key(mc, &atom, OVSDB_TYPE_UUID) == UINT_MAX) {
-            VLOG_INFO("Deleting isid=%"PRIu32", vlan=%"PRIu16,
-                      m->isid, m->vlan);
-            bridge_aa_mapping_destroy(m);
-        }
-    }
-
-    /* Add new mappings and reconfigure existing ones. */
-    for (i = 0; i < auto_attach->n_mappings; ++i) {
-        struct aa_mapping *m =
-            bridge_aa_mapping_find(br, auto_attach->key_mappings[i]);
-
-        if (!m) {
-            VLOG_INFO("Adding isid=%"PRId64", vlan=%"PRId64,
-                      auto_attach->key_mappings[i],
-                      auto_attach->value_mappings[i]);
-            m = bridge_aa_mapping_create(br,
-                                         auto_attach->key_mappings[i],
-                                         auto_attach->value_mappings[i]);
-
-            if (!bridge_aa_mapping_configure(m)) {
-                bridge_aa_mapping_destroy(m);
-            }
-        }
-    }
-}
-
-static bool
-bridge_aa_need_refresh(struct bridge *br)
-{
-    return ofproto_aa_vlan_get_queue_size(br->ofproto) > 0;
-}
-
-static void
-bridge_aa_update_trunks(struct port *port, struct bridge_aa_vlan *m)
-{
-    int64_t *trunks = NULL;
-    unsigned int i = 0;
-    bool found = false, reconfigure = false;
-
-    for (i = 0; i < port->cfg->n_trunks; i++) {
-        if (port->cfg->trunks[i] == m->vlan) {
-            found = true;
-            break;
-        }
-    }
-
-    switch (m->oper) {
-        case BRIDGE_AA_VLAN_OPER_ADD:
-            if (!found) {
-                trunks = xmalloc(sizeof *trunks * (port->cfg->n_trunks + 1));
-
-                for (i = 0; i < port->cfg->n_trunks; i++) {
-                    trunks[i] = port->cfg->trunks[i];
-                }
-                trunks[i++] = m->vlan;
-                reconfigure = true;
-            }
-
-            break;
-
-        case BRIDGE_AA_VLAN_OPER_REMOVE:
-            if (found) {
-                unsigned int j = 0;
-
-                trunks = xmalloc(sizeof *trunks * (port->cfg->n_trunks - 1));
-
-                for (i = 0; i < port->cfg->n_trunks; i++) {
-                    if (port->cfg->trunks[i] != m->vlan) {
-                        trunks[j++] = port->cfg->trunks[i];
-                    }
-                }
-                i = j;
-                reconfigure = true;
-            }
-
-            break;
-
-        case BRIDGE_AA_VLAN_OPER_UNDEF:
-        default:
-            VLOG_WARN("unrecognized operation %u", m->oper);
-            break;
-    }
-
-    if (reconfigure) {
-        /* VLAN switching under trunk mode cause the trunk port to switch all
-         * VLANs, see ovs-vswitchd.conf.db
-         */
-        if (i == 0)  {
-            static char *vlan_mode_access = "access";
-            ovsrec_port_set_vlan_mode(port->cfg, vlan_mode_access);
-        }
-
-        if (i == 1) {
-            static char *vlan_mode_trunk = "trunk";
-            ovsrec_port_set_vlan_mode(port->cfg, vlan_mode_trunk);
-        }
-
-        ovsrec_port_set_trunks(port->cfg, trunks, i);
-
-        /* Force reconfigure of the port. */
-        port_configure(port);
-    }
-}
-
-static void
-bridge_aa_refresh_queued(struct bridge *br)
-{
-    struct ovs_list *list = xmalloc(sizeof *list);
-    struct bridge_aa_vlan *node, *next;
-
-    list_init(list);
-    ofproto_aa_vlan_get_queued(br->ofproto, list);
-
-    LIST_FOR_EACH_SAFE (node, next, list_node, list) {
-        struct port *port;
-
-        VLOG_INFO("ifname=%s, vlan=%u, oper=%u", node->port_name, node->vlan,
-                  node->oper);
-
-        port = port_lookup(br, node->port_name);
-        if (port) {
-            bridge_aa_update_trunks(port, node);
-        }
-
-        list_remove(&node->list_node);
-        free(node->port_name);
-        free(node);
-    }
-
-    free(list);
-}
-
 
 /* Port functions. */
 
@@ -4034,7 +3712,7 @@ port_destroy(struct port *port)
     }
 }
 
-static struct port *
+struct port *
 port_lookup(const struct bridge *br, const char *name)
 {
     struct port *port;
-- 
1.9.1

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to