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