mirror of
https://github.com/openvswitch/ovs
synced 2025-08-22 01:51:26 +00:00
auto-attach: Add auto-attach support to bridge layer and command set
This is the final commit in the series of commits that deliver initial support for Auto-Attach. Specifically this commit delivers auto-attach support to the OVS bridge layer as well as the new auto-attach commands. The OVSDB schema is modified to define the new auto-attach entries. The man pages, unit tests, and news and license notice files are also updated. A unit test is provided to validate the construction of auto-attach packets. Signed-off-by: Ludovic Beliveau <ludovic.beliveau@windriver.com> Signed-off-by: Dennis Flynn <drflynn@avaya.com> Signed-off-by: Ben Pfaff <blp@nicira.com>
This commit is contained in:
parent
0477baa93b
commit
99eef98b53
3
NEWS
3
NEWS
@ -64,6 +64,9 @@ Post-v2.3.0
|
||||
console or file for vlog logging instead of the previously used term
|
||||
'facility'.
|
||||
- Support for VXLAN Group Policy extension
|
||||
- Initial support for the IETF Auto-Attach SPBM draft standard. This
|
||||
contains rudimentary support for the LLDP protocol as needed for
|
||||
Auto-Attach.
|
||||
|
||||
|
||||
v2.3.0 - 14 Aug 2014
|
||||
|
7
tests/auto-attach.at
Normal file
7
tests/auto-attach.at
Normal file
@ -0,0 +1,7 @@
|
||||
AT_BANNER([auto-attach unit tests])
|
||||
|
||||
AT_SETUP([auto-attach - packet tests])
|
||||
AT_KEYWORDS([auto-attach])
|
||||
AT_CHECK(ovstest test-aa, [], [ignore], [ignore])
|
||||
|
||||
AT_CLEANUP
|
@ -80,7 +80,8 @@ TESTSUITE_AT = \
|
||||
tests/rstp.at \
|
||||
tests/interface-reconfigure.at \
|
||||
tests/vlog.at \
|
||||
tests/vtep-ctl.at
|
||||
tests/vtep-ctl.at \
|
||||
tests/auto-attach.at
|
||||
|
||||
KMOD_TESTSUITE_AT = \
|
||||
tests/kmod-testsuite.at \
|
||||
@ -281,7 +282,8 @@ tests_ovstest_SOURCES = \
|
||||
tests/test-util.c \
|
||||
tests/test-uuid.c \
|
||||
tests/test-bitmap.c \
|
||||
tests/test-vconn.c
|
||||
tests/test-vconn.c \
|
||||
tests/test-aa.c
|
||||
|
||||
if !WIN32
|
||||
tests_ovstest_SOURCES += \
|
||||
|
@ -648,6 +648,7 @@ AT_CHECK([${PERL} $srcdir/uuidfilt.pl out1 out2], [0],
|
||||
|
||||
|
||||
_uuid : <0>
|
||||
auto_attach : []
|
||||
controller : []
|
||||
datapath_id : []
|
||||
datapath_type : ""
|
||||
@ -1147,6 +1148,7 @@ AT_CHECK([RUN_OVS_VSCTL([--id=@br0 create Bridge name=br0 -- add Open_vSwitch .
|
||||
AT_CHECK([${PERL} $srcdir/uuidfilt.pl stdout], [0],
|
||||
[[<0>
|
||||
_uuid : <1>
|
||||
auto_attach : []
|
||||
controller : []
|
||||
datapath_id : []
|
||||
datapath_type : ""
|
||||
|
329
tests/test-aa.c
Normal file
329
tests/test-aa.c
Normal file
@ -0,0 +1,329 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Avaya, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#undef NDEBUG
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "ovs-lldp.h"
|
||||
#include "ovstest.h"
|
||||
|
||||
#define ETH_TYPE_LLDP 0x88cc
|
||||
|
||||
/* Dummy MAC addresses */
|
||||
char chassis_mac[ETHER_ADDR_LEN] = { 0x5e, 0x10, 0x8e, 0xe7, 0x84, 0xad };
|
||||
uint8_t eth_src[ETHER_ADDR_LEN] = { 0x5e, 0x10, 0x8e, 0xe7, 0x84, 0xad };
|
||||
|
||||
/* LLDP multicast address */
|
||||
static const uint8_t eth_addr_lldp[6] = {0x01, 0x80, 0xC2, 0x00, 0x00, 0x0e};
|
||||
|
||||
/* Count of tests run */
|
||||
int num_tests = 0;
|
||||
|
||||
|
||||
/*
|
||||
* Helper function to validate port info
|
||||
*/
|
||||
static void
|
||||
check_received_port(struct lldpd_port *sport,
|
||||
struct lldpd_port *rport)
|
||||
{
|
||||
assert(rport->p_id_subtype == sport->p_id_subtype);
|
||||
assert(rport->p_id_len == sport->p_id_len);
|
||||
assert(strncmp(rport->p_id, sport->p_id, sport->p_id_len) == 0);
|
||||
assert(strcmp(rport->p_descr, sport->p_descr) == 0);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Helper function to validate chassis info
|
||||
*/
|
||||
static void
|
||||
check_received_chassis(struct lldpd_chassis *schassis,
|
||||
struct lldpd_chassis *rchassis)
|
||||
{
|
||||
assert(rchassis->c_id_subtype == schassis->c_id_subtype);
|
||||
assert(rchassis->c_id_len == schassis->c_id_len);
|
||||
assert(strncmp(rchassis->c_id, schassis->c_id, schassis->c_id_len) == 0);
|
||||
assert(strcmp(rchassis->c_name, schassis->c_name) == 0);
|
||||
assert(strcmp(rchassis->c_descr, schassis->c_descr) == 0);
|
||||
assert(rchassis->c_cap_available == schassis->c_cap_available);
|
||||
assert(rchassis->c_cap_enabled == schassis->c_cap_enabled);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Helper function to validate auto-attach info
|
||||
*/
|
||||
static void
|
||||
check_received_aa(struct lldpd_port *sport,
|
||||
struct lldpd_port *rport,
|
||||
struct lldpd_aa_isid_vlan_maps_tlv *smap)
|
||||
{
|
||||
struct lldpd_aa_isid_vlan_maps_tlv *received_map;
|
||||
int i = 0;
|
||||
|
||||
assert(rport->p_element.type == sport->p_element.type);
|
||||
assert(rport->p_element.mgmt_vlan == sport->p_element.mgmt_vlan);
|
||||
assert(rport->p_element.system_id.system_mac[0] ==
|
||||
sport->p_element.system_id.system_mac[0]);
|
||||
assert(rport->p_element.system_id.system_mac[1] ==
|
||||
sport->p_element.system_id.system_mac[1]);
|
||||
assert(rport->p_element.system_id.system_mac[2] ==
|
||||
sport->p_element.system_id.system_mac[2]);
|
||||
assert(rport->p_element.system_id.system_mac[3] ==
|
||||
sport->p_element.system_id.system_mac[3]);
|
||||
assert(rport->p_element.system_id.system_mac[4] ==
|
||||
sport->p_element.system_id.system_mac[4]);
|
||||
assert(rport->p_element.system_id.system_mac[5] ==
|
||||
sport->p_element.system_id.system_mac[5]);
|
||||
assert(rport->p_element.system_id.conn_type ==
|
||||
sport->p_element.system_id.conn_type);
|
||||
assert(rport->p_element.system_id.smlt_id ==
|
||||
sport->p_element.system_id.smlt_id);
|
||||
assert(rport->p_element.system_id.mlt_id[0] ==
|
||||
sport->p_element.system_id.mlt_id[0]);
|
||||
assert(rport->p_element.system_id.mlt_id[1] ==
|
||||
sport->p_element.system_id.mlt_id[1]);
|
||||
|
||||
/* Should receive 2 mappings */
|
||||
assert(!list_is_empty(&rport->p_isid_vlan_maps.m_entries));
|
||||
|
||||
/* For each received isid/vlan mapping */
|
||||
LIST_FOR_EACH (received_map, m_entries,
|
||||
&rport->p_isid_vlan_maps.m_entries) {
|
||||
|
||||
/* Validate against mapping sent */
|
||||
assert(smap[i].isid_vlan_data.status ==
|
||||
received_map->isid_vlan_data.status);
|
||||
assert(smap[i].isid_vlan_data.vlan ==
|
||||
received_map->isid_vlan_data.vlan);
|
||||
assert(smap[i].isid_vlan_data.isid[0] ==
|
||||
received_map->isid_vlan_data.isid[0]);
|
||||
assert(smap[i].isid_vlan_data.isid[1] ==
|
||||
received_map->isid_vlan_data.isid[1]);
|
||||
assert(smap[i].isid_vlan_data.isid[2] ==
|
||||
received_map->isid_vlan_data.isid[2]);
|
||||
|
||||
/* Next mapping sent */
|
||||
i++;
|
||||
}
|
||||
assert(i == 2);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Validate basic send/receive processing
|
||||
*/
|
||||
static int
|
||||
test_aa_send(void)
|
||||
{
|
||||
struct lldp *lldp;
|
||||
struct lldpd_hardware hardware;
|
||||
struct lldpd_chassis chassis;
|
||||
|
||||
struct lldpd_chassis *nchassis = NULL;
|
||||
struct lldpd_port *nport = NULL;
|
||||
|
||||
struct lldpd_hardware *hw = NULL;
|
||||
struct lldpd_chassis *ch = NULL;
|
||||
|
||||
struct lldpd_aa_isid_vlan_maps_tlv map_init[2];
|
||||
struct lldpd_aa_isid_vlan_maps_tlv map[2];
|
||||
|
||||
uint32_t stub[512 / 4];
|
||||
struct ofpbuf packet;
|
||||
|
||||
int n;
|
||||
|
||||
/* Prepare data used to construct and validate LLDPPDU */
|
||||
hardware.h_lport.p_id_subtype = LLDP_PORTID_SUBTYPE_IFNAME;
|
||||
hardware.h_lport.p_id = "FastEthernet 1/5";
|
||||
hardware.h_lport.p_id_len = strlen(hardware.h_lport.p_id);
|
||||
hardware.h_lport.p_descr = "Fake port description";
|
||||
hardware.h_lport.p_mfs = 1516;
|
||||
|
||||
/* Auto attach element discovery info */
|
||||
hardware.h_lport.p_element.type = LLDP_TLV_AA_ELEM_TYPE_TAG_CLIENT;
|
||||
hardware.h_lport.p_element.mgmt_vlan = 0xCDC;
|
||||
hardware.h_lport.p_element.system_id.system_mac[0] = 0x1;
|
||||
hardware.h_lport.p_element.system_id.system_mac[1] = 0x2;
|
||||
hardware.h_lport.p_element.system_id.system_mac[2] = 0x3;
|
||||
hardware.h_lport.p_element.system_id.system_mac[3] = 0x4;
|
||||
hardware.h_lport.p_element.system_id.system_mac[4] = 0x5;
|
||||
hardware.h_lport.p_element.system_id.system_mac[5] = 0x6;
|
||||
|
||||
hardware.h_lport.p_element.system_id.conn_type = 0x5;
|
||||
hardware.h_lport.p_element.system_id.smlt_id = 0x3CC;
|
||||
hardware.h_lport.p_element.system_id.mlt_id[0] = 0xB;
|
||||
hardware.h_lport.p_element.system_id.mlt_id[1] = 0xE;
|
||||
|
||||
/* Local chassis info */
|
||||
chassis.c_id_subtype = LLDP_CHASSISID_SUBTYPE_LLADDR;
|
||||
chassis.c_id = chassis_mac;
|
||||
chassis.c_id_len = ETHER_ADDR_LEN;
|
||||
chassis.c_name = "Dummy chassis";
|
||||
chassis.c_descr = "Long dummy chassis description";
|
||||
chassis.c_cap_available = LLDP_CAP_BRIDGE;
|
||||
chassis.c_cap_enabled = LLDP_CAP_BRIDGE;
|
||||
|
||||
/* ISID/VLAN mappings */
|
||||
map_init[0].isid_vlan_data.status = 0xC;
|
||||
map_init[0].isid_vlan_data.vlan = 0x64;
|
||||
map_init[0].isid_vlan_data.isid[0] = 1;
|
||||
map_init[0].isid_vlan_data.isid[1] = 2;
|
||||
map_init[0].isid_vlan_data.isid[2] = 3;
|
||||
|
||||
map_init[1].isid_vlan_data.status = 0xD;
|
||||
map_init[1].isid_vlan_data.vlan = 0xF;
|
||||
map_init[1].isid_vlan_data.isid[0] = 4;
|
||||
map_init[1].isid_vlan_data.isid[1] = 5;
|
||||
map_init[1].isid_vlan_data.isid[2] = 6;
|
||||
|
||||
/* Prepare an empty packet buffer */
|
||||
ofpbuf_use_stub(&packet, stub, sizeof stub);
|
||||
ofpbuf_clear(&packet);
|
||||
|
||||
/* Create a dummy lldp instance */
|
||||
lldp = lldp_create_dummy();
|
||||
if ((lldp == NULL) ||
|
||||
(lldp->lldpd == NULL) ||
|
||||
(lldp->lldpd->g_hardware.h_entries.next == NULL)) {
|
||||
|
||||
printf("Error: unable to create dummy lldp instance");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Populate instance with local chassis info */
|
||||
hw = (struct lldpd_hardware *) lldp->lldpd->g_hardware.h_entries.next;
|
||||
ch = hw->h_lport.p_chassis;
|
||||
ch->c_id_subtype = chassis.c_id_subtype;
|
||||
ch->c_id = chassis.c_id;
|
||||
ch->c_id_len = chassis.c_id_len;
|
||||
ch->c_name = chassis.c_name;
|
||||
ch->c_descr = chassis.c_descr;
|
||||
ch->c_cap_available = chassis.c_cap_available;
|
||||
ch->c_cap_enabled = chassis.c_cap_enabled;
|
||||
|
||||
/* Populate instance with local port info */
|
||||
hw->h_lport.p_id_subtype = hardware.h_lport.p_id_subtype;
|
||||
hw->h_lport.p_id = hardware.h_lport.p_id;
|
||||
hw->h_lport.p_id_len = strlen(hw->h_lport.p_id);
|
||||
hw->h_lport.p_descr = hardware.h_lport.p_descr;
|
||||
hw->h_lport.p_mfs = hardware.h_lport.p_mfs;
|
||||
|
||||
/* Populate instance with auto attach element discovery info */
|
||||
|
||||
hw->h_lport.p_element.type = hardware.h_lport.p_element.type;
|
||||
hw->h_lport.p_element.mgmt_vlan = hardware.h_lport.p_element.mgmt_vlan;
|
||||
hw->h_lport.p_element.system_id.system_mac[0] =
|
||||
hardware.h_lport.p_element.system_id.system_mac[0];
|
||||
hw->h_lport.p_element.system_id.system_mac[1] =
|
||||
hardware.h_lport.p_element.system_id.system_mac[1];
|
||||
hw->h_lport.p_element.system_id.system_mac[2] =
|
||||
hardware.h_lport.p_element.system_id.system_mac[2];
|
||||
hw->h_lport.p_element.system_id.system_mac[3] =
|
||||
hardware.h_lport.p_element.system_id.system_mac[3];
|
||||
hw->h_lport.p_element.system_id.system_mac[4] =
|
||||
hardware.h_lport.p_element.system_id.system_mac[4];
|
||||
hw->h_lport.p_element.system_id.system_mac[5] =
|
||||
hardware.h_lport.p_element.system_id.system_mac[5];
|
||||
|
||||
hw->h_lport.p_element.system_id.conn_type =
|
||||
hardware.h_lport.p_element.system_id.conn_type;
|
||||
hw->h_lport.p_element.system_id.smlt_id =
|
||||
hardware.h_lport.p_element.system_id.smlt_id;
|
||||
hw->h_lport.p_element.system_id.mlt_id[0] =
|
||||
hardware.h_lport.p_element.system_id.mlt_id[0];
|
||||
hw->h_lport.p_element.system_id.mlt_id[1] =
|
||||
hardware.h_lport.p_element.system_id.mlt_id[1];
|
||||
|
||||
/* Populate instance with two auto attach isid/vlan mappings */
|
||||
map[0].isid_vlan_data.status = map_init[0].isid_vlan_data.status;
|
||||
map[0].isid_vlan_data.vlan = map_init[0].isid_vlan_data.vlan;
|
||||
map[0].isid_vlan_data.isid[0] = map_init[0].isid_vlan_data.isid[0];
|
||||
map[0].isid_vlan_data.isid[1] = map_init[0].isid_vlan_data.isid[1];
|
||||
map[0].isid_vlan_data.isid[2] = map_init[0].isid_vlan_data.isid[2];
|
||||
|
||||
map[1].isid_vlan_data.status = map_init[1].isid_vlan_data.status;
|
||||
map[1].isid_vlan_data.vlan = map_init[1].isid_vlan_data.vlan;
|
||||
map[1].isid_vlan_data.isid[0] = map_init[1].isid_vlan_data.isid[0];
|
||||
map[1].isid_vlan_data.isid[1] = map_init[1].isid_vlan_data.isid[1];
|
||||
map[1].isid_vlan_data.isid[2] = map_init[1].isid_vlan_data.isid[2];
|
||||
|
||||
list_init(&hw->h_lport.p_isid_vlan_maps.m_entries);
|
||||
list_push_back(&hw->h_lport.p_isid_vlan_maps.m_entries,
|
||||
&map[0].m_entries);
|
||||
list_push_back(&hw->h_lport.p_isid_vlan_maps.m_entries,
|
||||
&map[1].m_entries);
|
||||
|
||||
/* Construct LLDPPDU (including Ethernet header) */
|
||||
eth_compose(&packet, eth_addr_lldp, eth_src, ETH_TYPE_LLDP, 0);
|
||||
n = lldp_send(lldp->lldpd, hw, &packet);
|
||||
|
||||
if (n == 0) {
|
||||
printf("Error: unable to build packet\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Decode the constructed LLDPPDU */
|
||||
assert(lldp_decode(NULL, packet.data_, packet.size_, hw,
|
||||
&nchassis, &nport) != -1);
|
||||
|
||||
/* Expecting returned pointers to allocated structures */
|
||||
if (!nchassis || !nport) {
|
||||
printf("Error: unable to decode packet");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Verify chassis values */
|
||||
check_received_chassis(&chassis, nchassis);
|
||||
|
||||
/* Verify port values */
|
||||
check_received_port(&hardware.h_lport, nport);
|
||||
|
||||
/* Verify auto attach values */
|
||||
check_received_aa(&hardware.h_lport, nport, map_init);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
test_aa_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
|
||||
{
|
||||
int num_errors = 0;
|
||||
|
||||
/* Make sure we emit valid auto-attach LLDPPDUs */
|
||||
num_tests++;
|
||||
num_errors += test_aa_send();
|
||||
|
||||
/* Add more tests here */
|
||||
|
||||
printf("executed %d tests, %d errors\n", num_tests, num_errors);
|
||||
|
||||
exit(num_errors != 0);
|
||||
}
|
||||
|
||||
OVSTEST_REGISTER("test-aa", test_aa_main);
|
@ -65,3 +65,4 @@ m4_include([tests/stp.at])
|
||||
m4_include([tests/rstp.at])
|
||||
m4_include([tests/vlog.at])
|
||||
m4_include([tests/vtep-ctl.at])
|
||||
m4_include([tests/auto-attach.at])
|
||||
|
@ -447,7 +447,7 @@ Prints the SSL configuration.
|
||||
Deletes the current SSL configuration.
|
||||
.
|
||||
.IP "[\fB\-\-bootstrap\fR] \fBset\-ssl\fR \fIprivate-key\fR \fIcertificate\fR \fIca-cert\fR"
|
||||
Sets the SSL configuration. The \fB\-\-bootstrap\fR option is described
|
||||
Sets the SSL configuration. The \fB\-\-bootstrap\fR option is described
|
||||
below.
|
||||
.
|
||||
.ST "CA Certificate Bootstrap"
|
||||
@ -470,6 +470,27 @@ This option is only useful if the controller sends its CA certificate
|
||||
as part of the SSL certificate chain. The SSL protocol does not
|
||||
require the controller to send the CA certificate.
|
||||
.
|
||||
.SS "Auto-Attach Commands"
|
||||
.
|
||||
The IETF Auto-Attach SPBM draft standard describes a compact method of using
|
||||
IEEE 802.1AB Link Layer Discovery Protocol (LLDP) together with a IEEE 802.1aq
|
||||
Shortest Path Bridging (SPB) network to automatically attach network devices to
|
||||
individual services in a SPB network. The intent here is to allow network
|
||||
applications and devices using OVS to be able to easily take advantage of
|
||||
features offered by industry standard SPB networks. A fundamental element of
|
||||
the Auto-Attach feature is to map traditional VLANs onto SPB I_SIDs. These
|
||||
commands manage the Auto-Attach I-SID/VLAN mappings.
|
||||
.
|
||||
.IP "\fBadd\-aa\-mapping \fIbridge i-sid vlan\fR"
|
||||
Creates a new Auto-Attach mapping on \fIbridge\fR for \fIi-sid\fR
|
||||
and \fIvlan\fR.
|
||||
.
|
||||
.IP "\fBdel\-aa\-mapping \fIbridge i-sid vlan\fR"
|
||||
Deletes an Auto-Attach mapping on \fIbridge\fR for \fIi-sid\fR
|
||||
and \fIvlan\fR.
|
||||
.IP "\fBget\-aa\-mapping \fIbridge\fR"
|
||||
Lists all of the Auto-Attach mappings within \fIbridge\fR on standard output.
|
||||
.
|
||||
.SS "Database Commands"
|
||||
.
|
||||
These commands query and modify the contents of \fBovsdb\fR tables.
|
||||
@ -533,6 +554,8 @@ identified by bridge name.
|
||||
.IP "\fBFlow_Sample_Collector_Set\fR"
|
||||
An IPFIX exporter configuration attached to a bridge for sampling
|
||||
packets on a per-flow basis using OpenFlow \fBsample\fR actions.
|
||||
.IP "\fBAutoAttach\fR"
|
||||
Configuration for Auto Attach within a bridge.
|
||||
.PP
|
||||
Record names must be specified in full and with correct
|
||||
capitalization. Names of tables and columns are not case-sensitive,
|
||||
@ -806,7 +829,7 @@ Create a new bridge named br0 and add port eth0 to it:
|
||||
.B "ovs\-vsctl add\-port br0 eth0"
|
||||
.PP
|
||||
Alternatively, perform both operations in a single atomic transaction:
|
||||
.IP
|
||||
.IP
|
||||
.B "ovs\-vsctl add\-br br0 \-\- add\-port br0 eth0"
|
||||
.PP
|
||||
Delete bridge \fBbr0\fR, reporting an error if it does not exist:
|
||||
|
@ -693,6 +693,11 @@ SSL commands:\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\
|
||||
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\
|
||||
emer-reset reset switch to known good state\n\
|
||||
\n\
|
||||
@ -1036,6 +1041,7 @@ pre_get_info(struct vsctl_context *ctx)
|
||||
ovsdb_idl_add_column(ctx->idl, &ovsrec_bridge_col_controller);
|
||||
ovsdb_idl_add_column(ctx->idl, &ovsrec_bridge_col_fail_mode);
|
||||
ovsdb_idl_add_column(ctx->idl, &ovsrec_bridge_col_ports);
|
||||
ovsdb_idl_add_column(ctx->idl, &ovsrec_bridge_col_auto_attach);
|
||||
|
||||
ovsdb_idl_add_column(ctx->idl, &ovsrec_port_col_name);
|
||||
ovsdb_idl_add_column(ctx->idl, &ovsrec_port_col_fake_bridge);
|
||||
@ -1043,6 +1049,8 @@ pre_get_info(struct vsctl_context *ctx)
|
||||
ovsdb_idl_add_column(ctx->idl, &ovsrec_port_col_interfaces);
|
||||
|
||||
ovsdb_idl_add_column(ctx->idl, &ovsrec_interface_col_name);
|
||||
|
||||
ovsdb_idl_add_column(ctx->idl, &ovsrec_autoattach_col_mappings);
|
||||
ovsdb_idl_add_column(ctx->idl, &ovsrec_interface_col_ofport);
|
||||
}
|
||||
|
||||
@ -1655,6 +1663,7 @@ cmd_add_br(struct vsctl_context *ctx)
|
||||
|
||||
if (!parent_name) {
|
||||
struct ovsrec_port *port;
|
||||
struct ovsrec_autoattach *aa;
|
||||
struct ovsrec_bridge *br;
|
||||
|
||||
iface = ovsrec_interface_insert(ctx->txn);
|
||||
@ -1665,9 +1674,12 @@ cmd_add_br(struct vsctl_context *ctx)
|
||||
ovsrec_port_set_name(port, br_name);
|
||||
ovsrec_port_set_interfaces(port, &iface, 1);
|
||||
|
||||
aa = ovsrec_autoattach_insert(ctx->txn);
|
||||
|
||||
br = ovsrec_bridge_insert(ctx->txn);
|
||||
ovsrec_bridge_set_name(br, br_name);
|
||||
ovsrec_bridge_set_ports(br, &port, 1);
|
||||
ovsrec_bridge_set_auto_attach(br, aa);
|
||||
|
||||
ovs_insert_bridge(ctx->ovs, br);
|
||||
} else {
|
||||
@ -2523,6 +2535,175 @@ cmd_set_ssl(struct vsctl_context *ctx)
|
||||
|
||||
ovsrec_open_vswitch_set_ssl(ctx->ovs, ssl);
|
||||
}
|
||||
|
||||
static void
|
||||
autoattach_insert_mapping(struct ovsrec_autoattach *aa,
|
||||
int64_t isid,
|
||||
int64_t vlan)
|
||||
{
|
||||
int64_t *key_mappings, *value_mappings;
|
||||
size_t i;
|
||||
|
||||
key_mappings = xmalloc(sizeof *aa->key_mappings * (aa->n_mappings + 1));
|
||||
value_mappings = xmalloc(sizeof *aa->value_mappings * (aa->n_mappings + 1));
|
||||
|
||||
for (i = 0; i < aa->n_mappings; i++) {
|
||||
key_mappings[i] = aa->key_mappings[i];
|
||||
value_mappings[i] = aa->value_mappings[i];
|
||||
}
|
||||
key_mappings[aa->n_mappings] = isid;
|
||||
value_mappings[aa->n_mappings] = vlan;
|
||||
|
||||
ovsrec_autoattach_set_mappings(aa, key_mappings, value_mappings,
|
||||
aa->n_mappings + 1);
|
||||
|
||||
free(key_mappings);
|
||||
free(value_mappings);
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_add_aa_mapping(struct vsctl_context *ctx)
|
||||
{
|
||||
struct vsctl_bridge *br;
|
||||
int64_t isid, vlan;
|
||||
char *nptr = NULL;
|
||||
|
||||
isid = strtoull(ctx->argv[2], &nptr, 10);
|
||||
if (nptr == ctx->argv[2] || nptr == NULL) {
|
||||
vsctl_fatal("Invalid argument %s", ctx->argv[2]);
|
||||
return;
|
||||
}
|
||||
|
||||
vlan = strtoull(ctx->argv[3], &nptr, 10);
|
||||
if (nptr == ctx->argv[3] || nptr == NULL) {
|
||||
vsctl_fatal("Invalid argument %s", ctx->argv[3]);
|
||||
return;
|
||||
}
|
||||
|
||||
vsctl_context_populate_cache(ctx);
|
||||
|
||||
br = find_bridge(ctx, ctx->argv[1], true);
|
||||
if (br->parent) {
|
||||
br = br->parent;
|
||||
}
|
||||
|
||||
if (br && br->br_cfg) {
|
||||
autoattach_insert_mapping(br->br_cfg->auto_attach, isid, vlan);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
del_aa_mapping(struct ovsrec_autoattach *aa,
|
||||
int64_t isid,
|
||||
int64_t vlan)
|
||||
{
|
||||
int64_t *key_mappings, *value_mappings;
|
||||
size_t i, n;
|
||||
|
||||
key_mappings = xmalloc(sizeof *aa->key_mappings * (aa->n_mappings));
|
||||
value_mappings = xmalloc(sizeof *value_mappings * (aa->n_mappings));
|
||||
|
||||
for (i = n = 0; i < aa->n_mappings; i++) {
|
||||
if (aa->key_mappings[i] != isid && aa->value_mappings[i] != vlan) {
|
||||
key_mappings[n] = aa->key_mappings[i];
|
||||
value_mappings[n++] = aa->value_mappings[i];
|
||||
}
|
||||
}
|
||||
|
||||
ovsrec_autoattach_set_mappings(aa, key_mappings, value_mappings, n);
|
||||
|
||||
free(key_mappings);
|
||||
free(value_mappings);
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_del_aa_mapping(struct vsctl_context *ctx)
|
||||
{
|
||||
struct vsctl_bridge *br;
|
||||
int64_t isid, vlan;
|
||||
char *nptr = NULL;
|
||||
|
||||
isid = strtoull(ctx->argv[2], &nptr, 10);
|
||||
if (nptr == ctx->argv[2] || nptr == NULL) {
|
||||
vsctl_fatal("Invalid argument %s", ctx->argv[2]);
|
||||
return;
|
||||
}
|
||||
|
||||
vlan = strtoull(ctx->argv[3], &nptr, 10);
|
||||
if (nptr == ctx->argv[3] || nptr == NULL) {
|
||||
vsctl_fatal("Invalid argument %s", ctx->argv[3]);
|
||||
return;
|
||||
}
|
||||
|
||||
vsctl_context_populate_cache(ctx);
|
||||
|
||||
br = find_bridge(ctx, ctx->argv[1], true);
|
||||
if (br->parent) {
|
||||
br = br->parent;
|
||||
}
|
||||
|
||||
if (br && br->br_cfg && br->br_cfg->auto_attach &&
|
||||
br->br_cfg->auto_attach->key_mappings &&
|
||||
br->br_cfg->auto_attach->value_mappings) {
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < br->br_cfg->auto_attach->n_mappings; i++) {
|
||||
if (br->br_cfg->auto_attach->key_mappings[i] == isid &&
|
||||
br->br_cfg->auto_attach->value_mappings[i] == vlan) {
|
||||
del_aa_mapping(br->br_cfg->auto_attach, isid, vlan);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pre_aa_mapping(struct vsctl_context *ctx)
|
||||
{
|
||||
pre_get_info(ctx);
|
||||
|
||||
ovsdb_idl_add_column(ctx->idl, &ovsrec_autoattach_col_mappings);
|
||||
}
|
||||
|
||||
static void
|
||||
verify_auto_attach(struct ovsrec_bridge *bridge)
|
||||
{
|
||||
if (bridge) {
|
||||
ovsrec_bridge_verify_auto_attach(bridge);
|
||||
|
||||
if (bridge->auto_attach) {
|
||||
ovsrec_autoattach_verify_mappings(bridge->auto_attach);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_get_aa_mapping(struct vsctl_context *ctx)
|
||||
{
|
||||
struct vsctl_bridge *br;
|
||||
|
||||
vsctl_context_populate_cache(ctx);
|
||||
|
||||
br = find_bridge(ctx, ctx->argv[1], true);
|
||||
if (br->parent) {
|
||||
br = br->parent;
|
||||
}
|
||||
|
||||
verify_auto_attach(br->br_cfg);
|
||||
|
||||
if (br && br->br_cfg && br->br_cfg->auto_attach &&
|
||||
br->br_cfg->auto_attach->key_mappings &&
|
||||
br->br_cfg->auto_attach->value_mappings) {
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < br->br_cfg->auto_attach->n_mappings; i++) {
|
||||
ds_put_format(&ctx->output, "%"PRId64" %"PRId64"\n",
|
||||
(long int) br->br_cfg->auto_attach->key_mappings[i],
|
||||
(long int) br->br_cfg->auto_attach->value_mappings[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Parameter commands. */
|
||||
|
||||
@ -2602,6 +2783,12 @@ static const struct vsctl_table_class tables[] = {
|
||||
{&ovsrec_table_flow_sample_collector_set, NULL,
|
||||
&ovsrec_flow_sample_collector_set_col_ipfix}}},
|
||||
|
||||
{&ovsrec_table_autoattach,
|
||||
{{&ovsrec_table_bridge,
|
||||
&ovsrec_bridge_col_name,
|
||||
&ovsrec_bridge_col_auto_attach},
|
||||
{NULL, NULL, NULL}}},
|
||||
|
||||
{&ovsrec_table_flow_sample_collector_set,
|
||||
{{NULL, NULL, NULL},
|
||||
{NULL, NULL, NULL}}},
|
||||
@ -4311,6 +4498,11 @@ static const struct vsctl_command_syntax all_commands[] = {
|
||||
{"del-ssl", 0, 0, pre_cmd_del_ssl, cmd_del_ssl, NULL, "", RW},
|
||||
{"set-ssl", 3, 3, pre_cmd_set_ssl, cmd_set_ssl, NULL, "--bootstrap", RW},
|
||||
|
||||
/* Auto Attach commands. */
|
||||
{"add-aa-mapping", 3, 3, pre_get_info, cmd_add_aa_mapping, NULL, "", RW},
|
||||
{"del-aa-mapping", 3, 3, pre_aa_mapping, cmd_del_aa_mapping, NULL, "", RW},
|
||||
{"get-aa-mapping", 1, 1, pre_aa_mapping, cmd_get_aa_mapping, NULL, "", RO},
|
||||
|
||||
/* Switch commands. */
|
||||
{"emer-reset", 0, 0, pre_cmd_emer_reset, cmd_emer_reset, NULL, "", RW},
|
||||
|
||||
|
@ -33,6 +33,7 @@
|
||||
#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"
|
||||
@ -127,6 +128,9 @@ struct bridge {
|
||||
/* 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;
|
||||
|
||||
@ -136,6 +140,14 @@ struct bridge {
|
||||
struct ovsrec_interface *synth_local_ifacep;
|
||||
};
|
||||
|
||||
struct aa_mapping {
|
||||
struct hmap_node hmap_node; /* In struct bridge's "mappings" hmap. */
|
||||
struct bridge *bridge;
|
||||
int64_t isid;
|
||||
int64_t vlan;
|
||||
char *br_name;
|
||||
};
|
||||
|
||||
/* All bridges, indexed by name. */
|
||||
static struct hmap all_bridges = HMAP_INITIALIZER(&all_bridges);
|
||||
|
||||
@ -194,6 +206,12 @@ static bool status_txn_try_again;
|
||||
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;
|
||||
|
||||
/* In some datapaths, creating and destroying OpenFlow ports can be extremely
|
||||
* expensive. This can cause bridge_reconfigure() to take a long time during
|
||||
* which no other work can be done. To deal with this problem, we limit port
|
||||
@ -234,6 +252,9 @@ static void bridge_configure_stp(struct bridge *);
|
||||
static void bridge_configure_rstp(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);
|
||||
@ -394,7 +415,8 @@ bridge_init(const char *remote)
|
||||
ovsdb_idl_omit_alert(idl, &ovsrec_port_col_statistics);
|
||||
ovsdb_idl_omit_alert(idl, &ovsrec_port_col_bond_active_slave);
|
||||
ovsdb_idl_omit(idl, &ovsrec_port_col_external_ids);
|
||||
|
||||
ovsdb_idl_omit_alert(idl, &ovsrec_port_col_trunks);
|
||||
ovsdb_idl_omit_alert(idl, &ovsrec_port_col_vlan_mode);
|
||||
ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_admin_state);
|
||||
ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_duplex);
|
||||
ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_link_speed);
|
||||
@ -454,6 +476,7 @@ bridge_init(const char *remote)
|
||||
cfm_init();
|
||||
ovs_numa_init();
|
||||
stp_init();
|
||||
lldp_init();
|
||||
rstp_init();
|
||||
}
|
||||
|
||||
@ -633,6 +656,8 @@ 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_configure_mirrors(br);
|
||||
@ -647,6 +672,7 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
|
||||
bridge_configure_rstp(br);
|
||||
bridge_configure_tables(br);
|
||||
bridge_configure_dp_desc(br);
|
||||
bridge_configure_aa(br);
|
||||
}
|
||||
free(managers);
|
||||
|
||||
@ -2768,6 +2794,24 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@ -3104,6 +3148,7 @@ bridge_create(const struct ovsrec_bridge *br_cfg)
|
||||
hmap_init(&br->iface_by_name);
|
||||
hmap_init(&br->mirrors);
|
||||
|
||||
hmap_init(&br->mappings);
|
||||
hmap_insert(&all_bridges, &br->node, hash_string(br->name, 0));
|
||||
}
|
||||
|
||||
@ -3127,6 +3172,7 @@ bridge_destroy(struct bridge *br)
|
||||
hmap_destroy(&br->ports);
|
||||
hmap_destroy(&br->iface_by_name);
|
||||
hmap_destroy(&br->mirrors);
|
||||
hmap_destroy(&br->mappings);
|
||||
free(br->name);
|
||||
free(br->type);
|
||||
free(br);
|
||||
@ -3651,6 +3697,234 @@ bridge_configure_dp_desc(struct bridge *br)
|
||||
ofproto_set_dp_desc(br->ofproto,
|
||||
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=%"PRId64", vlan=%"PRId64,
|
||||
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;
|
||||
|
||||
list_init(list);
|
||||
ofproto_aa_vlan_get_queued(br->ofproto, list);
|
||||
|
||||
LIST_FOR_EACH(node, 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. */
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
{"name": "Open_vSwitch",
|
||||
"version": "7.11.1",
|
||||
"cksum": "1038213587 21518",
|
||||
"version": "7.11.2",
|
||||
"cksum": "320332148 22294",
|
||||
"tables": {
|
||||
"Open_vSwitch": {
|
||||
"columns": {
|
||||
@ -118,7 +118,11 @@
|
||||
"maxInteger": 254},
|
||||
"value": {"type": "uuid",
|
||||
"refTable": "Flow_Table"},
|
||||
"min": 0, "max": "unlimited"}}},
|
||||
"min": 0, "max": "unlimited"}},
|
||||
"auto_attach": {
|
||||
"type": {"key": {"type": "uuid",
|
||||
"refTable": "AutoAttach"},
|
||||
"min": 0, "max": 1}}},
|
||||
"indexes": [["name"]]},
|
||||
"Port": {
|
||||
"columns": {
|
||||
@ -274,6 +278,9 @@
|
||||
"type": {"key": {"type": "boolean"},
|
||||
"min": 0, "max": 1},
|
||||
"ephemeral": true},
|
||||
"lldp": {
|
||||
"type": {"key": "string", "value": "string",
|
||||
"min": 0, "max": "unlimited"}},
|
||||
"other_config": {
|
||||
"type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}},
|
||||
"statistics": {
|
||||
@ -580,4 +587,18 @@
|
||||
"external_ids": {
|
||||
"type": {"key": "string", "value": "string",
|
||||
"min": 0, "max": "unlimited"}}},
|
||||
"maxRows": 1}}}
|
||||
"maxRows": 1},
|
||||
"AutoAttach": {
|
||||
"columns": {
|
||||
"system_name": {
|
||||
"type": "string"},
|
||||
"system_description": {
|
||||
"type": "string"},
|
||||
"mappings": {
|
||||
"type": {"key": {"type": "integer",
|
||||
"minInteger": 0,
|
||||
"maxInteger": 16777215},
|
||||
"value": {"type": "integer",
|
||||
"minInteger": 0,
|
||||
"maxInteger": 4095},
|
||||
"min": 0, "max": "unlimited"}}}}}}
|
||||
|
@ -506,6 +506,10 @@
|
||||
a different type of mirror instead.
|
||||
</p>
|
||||
</column>
|
||||
|
||||
<column name="auto_attach">
|
||||
Auto Attach configuration.
|
||||
</column>
|
||||
</group>
|
||||
|
||||
<group title="OpenFlow Configuration">
|
||||
@ -2926,6 +2930,17 @@
|
||||
</column>
|
||||
</group>
|
||||
|
||||
<group title="Auto Attach Configuration">
|
||||
<p>
|
||||
Auto Attach configuration for a particular interface.
|
||||
</p>
|
||||
|
||||
<column name="lldp" key="enable" type='{"type": "boolean"}'>
|
||||
True to enable LLDP on this <ref table="Interface"/>. If not
|
||||
specified, LLDP will be disabled by default.
|
||||
</column>
|
||||
</group>
|
||||
|
||||
<group title="Common Columns">
|
||||
The overall purpose of these columns is described under <code>Common
|
||||
Columns</code> at the beginning of this document.
|
||||
@ -4490,4 +4505,53 @@
|
||||
</group>
|
||||
</table>
|
||||
|
||||
<table name="AutoAttach">
|
||||
<p>Auto Attach configuration within a bridge. The IETF Auto-Attach SPBM
|
||||
draft standard describes a compact method of using IEEE 802.1AB Link
|
||||
Layer Discovery Protocol (LLDP) together with a IEEE 802.1aq Shortest
|
||||
Path Bridging (SPB) network to automatically attach network devices
|
||||
to individual services in a SPB network. The intent here is to allow
|
||||
network applications and devices using OVS to be able to easily take
|
||||
advantage of features offered by industry standard SPB networks.</p>
|
||||
|
||||
<p>Auto Attach (AA) uses LLDP to communicate between a directly connected
|
||||
Auto Attach Client (AAC) and Auto Attach Server (AAS). The LLDP protocol
|
||||
is extended to add two new Type-Length-Value tuples (TLVs). The first
|
||||
new TLV supports the ongoing discovery of directly connected AA
|
||||
correspondents. Auto Attach operates by regularly transmitting AA
|
||||
discovery TLVs between the AA client and AA server. By exchanging these
|
||||
discovery messages, both the AAC and AAS learn the system name and
|
||||
system description of their peer. In the OVS context, OVS operates as
|
||||
the AA client and the AA server resides on a switch at the edge of the
|
||||
SPB network.</p>
|
||||
|
||||
<p>Once AA discovery has been completed the AAC then uses the
|
||||
second new TLV to deliver identifier mappings from the AAC to the AAS. A primary
|
||||
feature of Auto Attach is to facilitate the mapping of VLANs defined
|
||||
outside the SPB network onto service ids (ISIDs) defined within the SPM
|
||||
network. By doing so individual external VLANs can be mapped onto
|
||||
specific SPB network services. These VLAN id to ISID mappings can be
|
||||
configured and managed locally using new options added to the ovs-vsctl
|
||||
command.</p>
|
||||
|
||||
<p>The Auto Attach OVS feature does not provide a full implementation of
|
||||
the LLDP protocol. Support for the mandatory TLVs as defined by the LLDP
|
||||
standard and support for the AA TLV extensions is provided. LLDP
|
||||
protocol support in OVS can be enabled or disabled on a port by port
|
||||
basis. LLDP support is disabled by default.</p>
|
||||
|
||||
<column name="system_name">
|
||||
The system_name string is exported in LLDP messages. It should uniquely
|
||||
identify the bridge in the network.
|
||||
</column>
|
||||
|
||||
<column name="system_description">
|
||||
The system_description string is exported in LLDP messages. It should
|
||||
describe the type of software and hardware.
|
||||
</column>
|
||||
|
||||
<column name="mappings">
|
||||
A mapping from SPB network Individual Service Identifier (ISID) to VLAN id.
|
||||
</column>
|
||||
</table>
|
||||
</database>
|
||||
|
Loading…
x
Reference in New Issue
Block a user