OpenFlow 1.6 adds support for EUI-64 addresses for ports, and extends the maximum length of OpenFlow port names from 16 to 64 bytes.
ONF-JIRA: EXT-566 Signed-off-by: Ben Pfaff <b...@ovn.org> --- NEWS | 4 +- include/openflow/automake.mk | 1 + include/openflow/openflow-1.0.h | 7 +- include/openflow/openflow-1.1.h | 3 +- include/openflow/openflow-1.4.h | 4 +- include/openflow/openflow-1.6.h | 98 +++++++++++ include/openflow/openflow-common.h | 1 - include/openflow/openflow.h | 3 +- include/openvswitch/ofp-msgs.h | 16 +- include/openvswitch/ofp-util.h | 15 +- lib/ofp-print.c | 9 + lib/ofp-util.c | 332 +++++++++++++++++++++++++++---------- ofproto/ofproto-dpif-xlate.c | 2 +- ofproto/ofproto-dpif.c | 6 +- ofproto/ofproto.c | 6 +- tests/ofp-print.at | 41 +++++ tests/ofproto.at | 66 ++++++++ utilities/ovs-ofctl.c | 1 + 18 files changed, 505 insertions(+), 110 deletions(-) create mode 100644 include/openflow/openflow-1.6.h diff --git a/NEWS b/NEWS index ec8572a7fc59..6ec1f2f0b7ef 100644 --- a/NEWS +++ b/NEWS @@ -10,13 +10,15 @@ Post-v2.7.0 Log level can be changed in a usual OVS way using 'ovs-appctl vlog' commands for 'dpdk' module. Lower bound still can be configured via extra arguments for DPDK EAL. - - The "learn" action now supports a "limit" option (see ovs-ofctl(8)). - New support for multiple VLANs (802.1ad or "QinQ"), including a new "dot1q-tunnel" port VLAN mode. - OVN: * Make the DHCPv4 router setting optional. * Gratuitous ARP for NAT addresses on a distributed logical router. - Add the command 'ovs-appctl stp/show' (see ovs-vswitchd(8)). + - OpenFlow: + * The "learn" action now supports a "limit" option (see ovs-ofctl(8)). + * Increased support for OpenFlow 1.6 (draft). v2.7.0 - 21 Feb 2017 --------------------- diff --git a/include/openflow/automake.mk b/include/openflow/automake.mk index 18cc649899f8..9755e7c0396e 100644 --- a/include/openflow/automake.mk +++ b/include/openflow/automake.mk @@ -9,6 +9,7 @@ openflowinclude_HEADERS = \ include/openflow/openflow-1.3.h \ include/openflow/openflow-1.4.h \ include/openflow/openflow-1.5.h \ + include/openflow/openflow-1.6.h \ include/openflow/openflow-common.h \ include/openflow/openflow.h diff --git a/include/openflow/openflow-1.0.h b/include/openflow/openflow-1.0.h index 68c79526efcb..ad06610da3a4 100644 --- a/include/openflow/openflow-1.0.h +++ b/include/openflow/openflow-1.0.h @@ -21,6 +21,11 @@ #include <openflow/openflow-common.h> +/* Maximum name of a port. + * + * OpenFlow 1.6 (draft) increases this to 64. */ +#define OFP10_MAX_PORT_NAME_LEN 16 + /* Port number(s) meaning * --------------- -------------------------------------- * 0x0000 not assigned a meaning by OpenFlow 1.0 @@ -97,7 +102,7 @@ enum ofp10_port_features { struct ofp10_phy_port { ovs_be16 port_no; struct eth_addr hw_addr; - char name[OFP_MAX_PORT_NAME_LEN]; /* Null-terminated */ + char name[OFP10_MAX_PORT_NAME_LEN]; /* Null-terminated */ ovs_be32 config; /* Bitmap of OFPPC_* and OFPPC10_* flags. */ ovs_be32 state; /* Bitmap of OFPPS_* and OFPPS10_* flags. */ diff --git a/include/openflow/openflow-1.1.h b/include/openflow/openflow-1.1.h index de28475435fa..a29db8f3ef87 100644 --- a/include/openflow/openflow-1.1.h +++ b/include/openflow/openflow-1.1.h @@ -53,6 +53,7 @@ #define OPENFLOW_11_H 1 #include <openflow/openflow-common.h> +#include <openflow/openflow-1.0.h> /* OpenFlow 1.1 uses 32-bit port numbers. Open vSwitch, for now, uses OpenFlow * 1.0 port numbers internally. We map them to OpenFlow 1.0 as follows: @@ -112,7 +113,7 @@ struct ofp11_port { uint8_t pad[4]; struct eth_addr hw_addr; uint8_t pad2[2]; /* Align to 64 bits. */ - char name[OFP_MAX_PORT_NAME_LEN]; /* Null-terminated */ + char name[OFP10_MAX_PORT_NAME_LEN]; /* Null-terminated */ ovs_be32 config; /* Bitmap of OFPPC_* flags. */ ovs_be32 state; /* Bitmap of OFPPS_* and OFPPS11_* flags. */ diff --git a/include/openflow/openflow-1.4.h b/include/openflow/openflow-1.4.h index fcebe4eb3eb6..9399950b2837 100644 --- a/include/openflow/openflow-1.4.h +++ b/include/openflow/openflow-1.4.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, 2014 The Board of Trustees of The Leland Stanford +/* Copyright (c) 2008, 2014, 2017 The Board of Trustees of The Leland Stanford * Junior University * Copyright (c) 2011, 2012 Open Networking Foundation * @@ -80,7 +80,7 @@ struct ofp14_port { uint8_t pad[2]; struct eth_addr hw_addr; uint8_t pad2[2]; /* Align to 64 bits. */ - char name[OFP_MAX_PORT_NAME_LEN]; /* Null-terminated */ + char name[OFP10_MAX_PORT_NAME_LEN]; /* Null-terminated */ ovs_be32 config; /* Bitmap of OFPPC_* flags. */ ovs_be32 state; /* Bitmap of OFPPS_* flags. */ diff --git a/include/openflow/openflow-1.6.h b/include/openflow/openflow-1.6.h new file mode 100644 index 000000000000..1ba3cbd6fb3d --- /dev/null +++ b/include/openflow/openflow-1.6.h @@ -0,0 +1,98 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * Copyright (c) 2011, 2013, 2014 Open Networking Foundation + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +/* + * Copyright (c) 2017 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 OPENFLOW_16_H +#define OPENFLOW_16_H 1 + +#include <openflow/openflow-common.h> + +#define OFP16_MAX_PORT_NAME_LEN 64 + +/* Bitmap of hardware address types supported by an OpenFlow port. */ +enum ofp16_hardware_address_type { + OFPPHAT16_EUI48 = 1 << 0, /* 48-bit Ethernet address. */ + OFPPHAT16_EUI64 = 1 << 1, /* 64-bit Ethernet address. */ +}; + +struct ofp16_port { + ovs_be32 port_no; + ovs_be16 length; + ovs_be16 hw_addr_type; /* Zero or more OFPPHAT16_*. */ + struct eth_addr hw_addr; /* EUI-48 hardware address. */ + uint8_t pad[2]; /* Align to 64 bits. */ + struct eth_addr64 hw_addr64; /* EUI-64 hardware address */ + char name[OFP16_MAX_PORT_NAME_LEN]; /* Null-terminated */ + + ovs_be32 config; /* Bitmap of OFPPC_* flags. */ + ovs_be32 state; /* Bitmap of OFPPS_* flags. */ + + /* Followed by 0 or more OFPPDPT14_* properties. (OpenFlow 1.6 (draft) + * defines the same properties as OpenFlow 1.4.) */ +}; +OFP_ASSERT(sizeof(struct ofp16_port) == 96); + +struct ofp16_port_mod { + ovs_be32 port_no; + ovs_be16 hw_addr_type; /* Zero or more OFPPHAT16_*. */ + uint8_t pad[2]; /* Align to 64 bits. */ + struct eth_addr hw_addr; + uint8_t pad2[2]; + struct eth_addr64 hw_addr64; /* EUI-64 hardware address */ + + ovs_be32 config; /* Bitmap of OFPPC_* flags. */ + ovs_be32 mask; /* Bitmap of OFPPC_* flags to be changed. */ + + /* Followed by 0 or more OFPPMPT14_* properties. (OpenFlow 1.6 (draft) + * defines the same properties as OpenFlow 1.4.) */ +}; +OFP_ASSERT(sizeof(struct ofp16_port_mod) == 32); + + +#endif /* openflow/openflow-1.6.h */ diff --git a/include/openflow/openflow-common.h b/include/openflow/openflow-common.h index 7b619a997f2f..530c105286ac 100644 --- a/include/openflow/openflow-common.h +++ b/include/openflow/openflow-common.h @@ -111,7 +111,6 @@ enum ofp_version { #define INTEL_VENDOR_ID 0x0000AA01 /* Intel */ #define OFP_MAX_TABLE_NAME_LEN 32 -#define OFP_MAX_PORT_NAME_LEN 16 #define OFP_OLD_PORT 6633 #define OFP_PORT 6653 diff --git a/include/openflow/openflow.h b/include/openflow/openflow.h index 7976fbb5a1b1..fececb5637a3 100644 --- a/include/openflow/openflow.h +++ b/include/openflow/openflow.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc. + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2017 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,5 +23,6 @@ #include <openflow/openflow-1.3.h> #include <openflow/openflow-1.4.h> #include <openflow/openflow-1.5.h> +#include <openflow/openflow-1.6.h> #endif /* openflow/openflow.h */ diff --git a/include/openvswitch/ofp-msgs.h b/include/openvswitch/ofp-msgs.h index 07fd8aa76ac2..34708f3bd846 100644 --- a/include/openvswitch/ofp-msgs.h +++ b/include/openvswitch/ofp-msgs.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, 2014, 2015, 2016 Nicira, Inc. + * Copyright (c) 2012, 2013, 2014, 2015, 2016, 2017 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -170,8 +170,10 @@ enum ofpraw { OFPRAW_OFPT10_PORT_STATUS, /* OFPT 1.1-1.3 (12): struct ofp_port_status, struct ofp11_port. */ OFPRAW_OFPT11_PORT_STATUS, - /* OFPT 1.4+ (12): struct ofp_port_status, struct ofp14_port, uint8_t[8][]. */ + /* OFPT 1.4-1.5 (12): struct ofp_port_status, struct ofp14_port, uint8_t[8][]. */ OFPRAW_OFPT14_PORT_STATUS, + /* OFPT 1.6+ (12): struct ofp_port_status, struct ofp16_port, uint8_t[8][]. */ + OFPRAW_OFPT16_PORT_STATUS, /* OFPT 1.0 (13): struct ofp10_packet_out, uint8_t[]. */ OFPRAW_OFPT10_PACKET_OUT, @@ -194,8 +196,10 @@ enum ofpraw { OFPRAW_OFPT10_PORT_MOD, /* OFPT 1.1-1.3 (16): struct ofp11_port_mod. */ OFPRAW_OFPT11_PORT_MOD, - /* OFPT 1.4+ (16): struct ofp14_port_mod, uint8_t[8][]. */ + /* OFPT 1.4-1.5 (16): struct ofp14_port_mod, uint8_t[8][]. */ OFPRAW_OFPT14_PORT_MOD, + /* OFPT 1.6+ (16): struct ofp16_port_mod, uint8_t[8][]. */ + OFPRAW_OFPT16_PORT_MOD, /* OFPT 1.1-1.3 (17): struct ofp11_table_mod. */ OFPRAW_OFPT11_TABLE_MOD, @@ -552,7 +556,8 @@ enum ofptype { * OFPRAW_NXT_FLOW_REMOVED. */ OFPTYPE_PORT_STATUS, /* OFPRAW_OFPT10_PORT_STATUS. * OFPRAW_OFPT11_PORT_STATUS. - * OFPRAW_OFPT14_PORT_STATUS. */ + * OFPRAW_OFPT14_PORT_STATUS. + * OFPRAW_OFPT16_PORT_STATUS. */ /* Controller command messages. */ OFPTYPE_PACKET_OUT, /* OFPRAW_OFPT10_PACKET_OUT. @@ -564,7 +569,8 @@ enum ofptype { * OFPRAW_OFPT15_GROUP_MOD. */ OFPTYPE_PORT_MOD, /* OFPRAW_OFPT10_PORT_MOD. * OFPRAW_OFPT11_PORT_MOD. - * OFPRAW_OFPT14_PORT_MOD. */ + * OFPRAW_OFPT14_PORT_MOD. + * OFPRAW_OFPT16_PORT_MOD. */ OFPTYPE_TABLE_MOD, /* OFPRAW_OFPT11_TABLE_MOD. * OFPRAW_OFPT14_TABLE_MOD. */ diff --git a/include/openvswitch/ofp-util.h b/include/openvswitch/ofp-util.h index 7cb9e7fd32bd..f664055c3939 100644 --- a/include/openvswitch/ofp-util.h +++ b/include/openvswitch/ofp-util.h @@ -45,7 +45,7 @@ ovs_be32 ofputil_port_to_ofp11(ofp_port_t ofp10_port); bool ofputil_port_from_string(const char *, ofp_port_t *portp); void ofputil_format_port(ofp_port_t port, struct ds *); -void ofputil_port_to_string(ofp_port_t, char namebuf[OFP_MAX_PORT_NAME_LEN], +void ofputil_port_to_string(ofp_port_t, char namebuf[OFP10_MAX_PORT_NAME_LEN], size_t bufsize); /* Group numbers. */ @@ -598,11 +598,19 @@ enum ofputil_port_state { OFPUTIL_PS_STP_MASK = 3 << 8 /* Bit mask for OFPPS10_STP_* values. */ }; -/* Abstract ofp10_phy_port or ofp11_port. */ +/* Abstract ofp10_phy_port, ofp11_port, ofp14_port, or ofp16_port. */ struct ofputil_phy_port { ofp_port_t port_no; + + /* Hardware addresses. + * + * Most hardware has a normal 48-bit Ethernet address, in hw_addr. + * Some hardware might have a 64-bit address in hw_addr64. + * All-bits-0 indicates that a given address is not present. */ struct eth_addr hw_addr; - char name[OFP_MAX_PORT_NAME_LEN]; + struct eth_addr64 hw_addr64; + + char name[OFP16_MAX_PORT_NAME_LEN]; /* 64 bytes in OF1.6+, 16 otherwise. */ enum ofputil_port_config config; enum ofputil_port_state state; @@ -682,6 +690,7 @@ struct ofpbuf *ofputil_encode_port_status(const struct ofputil_port_status *, struct ofputil_port_mod { ofp_port_t port_no; struct eth_addr hw_addr; + struct eth_addr64 hw_addr64; enum ofputil_port_config config; enum ofputil_port_config mask; enum netdev_features advertise; diff --git a/lib/ofp-print.c b/lib/ofp-print.c index 8e82777fad40..a8cdfcbf20b1 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -436,6 +436,11 @@ ofp_print_phy_port(struct ds *string, const struct ofputil_phy_port *port) ds_put_format(string, "(%s): addr:"ETH_ADDR_FMT"\n", name, ETH_ADDR_ARGS(port->hw_addr)); + if (!eth_addr64_is_zero(port->hw_addr64)) { + ds_put_format(string, " addr64: "ETH_ADDR64_FMT"\n", + ETH_ADDR64_ARGS(port->hw_addr64)); + } + ds_put_cstr(string, " config: "); ofp_print_port_config(string, port->config); @@ -1011,6 +1016,10 @@ ofp_print_port_mod(struct ds *string, const struct ofp_header *oh) ofputil_format_port(pm.port_no, string); ds_put_format(string, ": addr:"ETH_ADDR_FMT"\n", ETH_ADDR_ARGS(pm.hw_addr)); + if (!eth_addr64_is_zero(pm.hw_addr64)) { + ds_put_format(string, " addr64: "ETH_ADDR64_FMT"\n", + ETH_ADDR64_ARGS(pm.hw_addr64)); + } ds_put_cstr(string, " config: "); ofp_print_port_config(string, pm.config); diff --git a/lib/ofp-util.c b/lib/ofp-util.c index fac82c40cc18..1f038c61ea97 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -4390,31 +4390,10 @@ parse_ofp14_port_ethernet_property(const struct ofpbuf *payload, } static enum ofperr -ofputil_pull_ofp14_port(struct ofputil_phy_port *pp, struct ofpbuf *msg) +ofputil_pull_ofp14_port_properties(const void *props, size_t len, + struct ofputil_phy_port *pp) { - struct ofp14_port *op = ofpbuf_try_pull(msg, sizeof *op); - if (!op) { - return OFPERR_OFPBRC_BAD_LEN; - } - - size_t len = ntohs(op->length); - if (len < sizeof *op || len - sizeof *op > msg->size) { - return OFPERR_OFPBRC_BAD_LEN; - } - len -= sizeof *op; - - enum ofperr error = ofputil_port_from_ofp11(op->port_no, &pp->port_no); - if (error) { - return error; - } - pp->hw_addr = op->hw_addr; - ovs_strlcpy(pp->name, op->name, OFP_MAX_PORT_NAME_LEN); - - pp->config = ntohl(op->config) & OFPPC11_ALL; - pp->state = ntohl(op->state) & OFPPS11_ALL; - - struct ofpbuf properties = ofpbuf_const_initializer(ofpbuf_pull(msg, len), - len); + struct ofpbuf properties = ofpbuf_const_initializer(props, len); while (properties.size > 0) { struct ofpbuf payload; enum ofperr error; @@ -4443,6 +4422,65 @@ ofputil_pull_ofp14_port(struct ofputil_phy_port *pp, struct ofpbuf *msg) return 0; } +static enum ofperr +ofputil_pull_ofp14_port(struct ofputil_phy_port *pp, struct ofpbuf *msg) +{ + const struct ofp14_port *op = ofpbuf_try_pull(msg, sizeof *op); + if (!op) { + return OFPERR_OFPBRC_BAD_LEN; + } + + size_t len = ntohs(op->length); + if (len < sizeof *op || len - sizeof *op > msg->size) { + return OFPERR_OFPBRC_BAD_LEN; + } + len -= sizeof *op; + + enum ofperr error = ofputil_port_from_ofp11(op->port_no, &pp->port_no); + if (error) { + return error; + } + pp->hw_addr = op->hw_addr; + ovs_strlcpy_arrays(pp->name, op->name); + + pp->config = ntohl(op->config) & OFPPC11_ALL; + pp->state = ntohl(op->state) & OFPPS11_ALL; + + return ofputil_pull_ofp14_port_properties(ofpbuf_pull(msg, len), len, pp); +} + +static enum ofperr +ofputil_pull_ofp16_port(struct ofputil_phy_port *pp, struct ofpbuf *msg) +{ + const struct ofp16_port *op = ofpbuf_try_pull(msg, sizeof *op); + if (!op) { + return OFPERR_OFPBRC_BAD_LEN; + } + + size_t len = ntohs(op->length); + if (len < sizeof *op || len - sizeof *op > msg->size) { + return OFPERR_OFPBRC_BAD_LEN; + } + len -= sizeof *op; + + enum ofperr error = ofputil_port_from_ofp11(op->port_no, &pp->port_no); + if (error) { + return error; + } + if (op->hw_addr_type & htons(OFPPHAT16_EUI48)) { + pp->hw_addr = op->hw_addr; + } + if (op->hw_addr_type & htons(OFPPHAT16_EUI64)) { + pp->hw_addr64 = op->hw_addr64; + } + ovs_strlcpy_arrays(pp->name, op->name); + + pp->config = ntohl(op->config) & OFPPC11_ALL; + pp->state = ntohl(op->state) & OFPPS11_ALL; + + return ofputil_pull_ofp14_port_properties(ofpbuf_pull(msg, len), len, pp); +} + static void ofputil_encode_ofp10_phy_port(const struct ofputil_phy_port *pp, struct ofp10_phy_port *opp) @@ -4485,8 +4523,20 @@ ofputil_encode_ofp11_port(const struct ofputil_phy_port *pp, } static void -ofputil_put_ofp14_port(const struct ofputil_phy_port *pp, - struct ofpbuf *b) +ofputil_encode_ofp14_port_ethernet_prop( + const struct ofputil_phy_port *pp, + struct ofp14_port_desc_prop_ethernet *eth) +{ + eth->curr = netdev_port_features_to_ofp11(pp->curr); + eth->advertised = netdev_port_features_to_ofp11(pp->advertised); + eth->supported = netdev_port_features_to_ofp11(pp->supported); + eth->peer = netdev_port_features_to_ofp11(pp->peer); + eth->curr_speed = htonl(pp->curr_speed); + eth->max_speed = htonl(pp->max_speed); +} + +static void +ofputil_put_ofp14_port(const struct ofputil_phy_port *pp, struct ofpbuf *b) { struct ofp14_port *op; struct ofp14_port_desc_prop_ethernet *eth; @@ -4497,17 +4547,39 @@ ofputil_put_ofp14_port(const struct ofputil_phy_port *pp, op->port_no = ofputil_port_to_ofp11(pp->port_no); op->length = htons(sizeof *op + sizeof *eth); op->hw_addr = pp->hw_addr; - ovs_strlcpy(op->name, pp->name, sizeof op->name); + ovs_strlcpy_arrays(op->name, pp->name); op->config = htonl(pp->config & OFPPC11_ALL); op->state = htonl(pp->state & OFPPS11_ALL); eth = ofpprop_put_zeros(b, OFPPDPT14_ETHERNET, sizeof *eth); - eth->curr = netdev_port_features_to_ofp11(pp->curr); - eth->advertised = netdev_port_features_to_ofp11(pp->advertised); - eth->supported = netdev_port_features_to_ofp11(pp->supported); - eth->peer = netdev_port_features_to_ofp11(pp->peer); - eth->curr_speed = htonl(pp->curr_speed); - eth->max_speed = htonl(pp->max_speed); + ofputil_encode_ofp14_port_ethernet_prop(pp, eth); +} + +static void +ofputil_put_ofp16_port(const struct ofputil_phy_port *pp, struct ofpbuf *b) +{ + struct ofp16_port *op; + struct ofp14_port_desc_prop_ethernet *eth; + + ofpbuf_prealloc_tailroom(b, sizeof *op + sizeof *eth); + + op = ofpbuf_put_zeros(b, sizeof *op); + op->port_no = ofputil_port_to_ofp11(pp->port_no); + op->length = htons(sizeof *op + sizeof *eth); + if (!eth_addr_is_zero(pp->hw_addr)) { + op->hw_addr_type |= htons(OFPPHAT16_EUI48); + op->hw_addr = pp->hw_addr; + } + if (!eth_addr64_is_zero(pp->hw_addr64)) { + op->hw_addr_type |= htons(OFPPHAT16_EUI64); + op->hw_addr64 = pp->hw_addr64; + } + ovs_strlcpy_arrays(op->name, pp->name); + op->config = htonl(pp->config & OFPPC11_ALL); + op->state = htonl(pp->state & OFPPS11_ALL); + + eth = ofpprop_put_zeros(b, OFPPDPT14_ETHERNET, sizeof *eth); + ofputil_encode_ofp14_port_ethernet_prop(pp, eth); } static void @@ -4531,9 +4603,11 @@ ofputil_put_phy_port(enum ofp_version ofp_version, case OFP14_VERSION: case OFP15_VERSION: - case OFP16_VERSION: ofputil_put_ofp14_port(pp, b); break; + case OFP16_VERSION: + ofputil_put_ofp16_port(pp, b); + break; default: OVS_NOT_REACHED(); @@ -4932,10 +5006,13 @@ ofputil_encode_port_status(const struct ofputil_port_status *ps, case OFP14_VERSION: case OFP15_VERSION: - case OFP16_VERSION: raw = OFPRAW_OFPT14_PORT_STATUS; break; + case OFP16_VERSION: + raw = OFPRAW_OFPT16_PORT_STATUS; + break; + default: OVS_NOT_REACHED(); } @@ -4964,74 +5041,126 @@ parse_port_mod_ethernet_property(struct ofpbuf *property, return error; } -/* Decodes the OpenFlow "port mod" message in '*oh' into an abstract form in - * '*pm'. Returns 0 if successful, otherwise an OFPERR_* value. */ -enum ofperr -ofputil_decode_port_mod(const struct ofp_header *oh, - struct ofputil_port_mod *pm, bool loose) +static enum ofperr +ofputil_decode_ofp10_port_mod(const struct ofp10_port_mod *opm, + struct ofputil_port_mod *pm) +{ + pm->port_no = u16_to_ofp(ntohs(opm->port_no)); + pm->hw_addr = opm->hw_addr; + pm->config = ntohl(opm->config) & OFPPC10_ALL; + pm->mask = ntohl(opm->mask) & OFPPC10_ALL; + pm->advertise = netdev_port_features_from_ofp10(opm->advertise); + return 0; +} + +static enum ofperr +ofputil_decode_ofp11_port_mod(const struct ofp11_port_mod *opm, + struct ofputil_port_mod *pm) { - struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); - enum ofpraw raw = ofpraw_pull_assert(&b); - if (raw == OFPRAW_OFPT10_PORT_MOD) { - const struct ofp10_port_mod *opm = b.data; + enum ofperr error; - pm->port_no = u16_to_ofp(ntohs(opm->port_no)); - pm->hw_addr = opm->hw_addr; - pm->config = ntohl(opm->config) & OFPPC10_ALL; - pm->mask = ntohl(opm->mask) & OFPPC10_ALL; - pm->advertise = netdev_port_features_from_ofp10(opm->advertise); - } else if (raw == OFPRAW_OFPT11_PORT_MOD) { - const struct ofp11_port_mod *opm = b.data; + error = ofputil_port_from_ofp11(opm->port_no, &pm->port_no); + if (error) { + return error; + } + + pm->hw_addr = opm->hw_addr; + pm->config = ntohl(opm->config) & OFPPC11_ALL; + pm->mask = ntohl(opm->mask) & OFPPC11_ALL; + pm->advertise = netdev_port_features_from_ofp11(opm->advertise); + + return 0; +} + +static enum ofperr +ofputil_decode_ofp14_port_mod_properties(struct ofpbuf *b, bool loose, + struct ofputil_port_mod *pm) +{ + while (b->size > 0) { + struct ofpbuf property; enum ofperr error; + uint64_t type; - error = ofputil_port_from_ofp11(opm->port_no, &pm->port_no); + error = ofpprop_pull(b, &property, &type); if (error) { return error; } - pm->hw_addr = opm->hw_addr; - pm->config = ntohl(opm->config) & OFPPC11_ALL; - pm->mask = ntohl(opm->mask) & OFPPC11_ALL; - pm->advertise = netdev_port_features_from_ofp11(opm->advertise); - } else if (raw == OFPRAW_OFPT14_PORT_MOD) { - const struct ofp14_port_mod *opm = ofpbuf_pull(&b, sizeof *opm); - enum ofperr error; + switch (type) { + case OFPPMPT14_ETHERNET: + error = parse_port_mod_ethernet_property(&property, pm); + break; - memset(pm, 0, sizeof *pm); + default: + error = OFPPROP_UNKNOWN(loose, "port_mod", type); + break; + } - error = ofputil_port_from_ofp11(opm->port_no, &pm->port_no); if (error) { return error; } + } + return 0; +} - pm->hw_addr = opm->hw_addr; - pm->config = ntohl(opm->config) & OFPPC11_ALL; - pm->mask = ntohl(opm->mask) & OFPPC11_ALL; +static enum ofperr +ofputil_decode_ofp14_port_mod(struct ofpbuf *b, bool loose, + struct ofputil_port_mod *pm) +{ + const struct ofp14_port_mod *opm = ofpbuf_pull(b, sizeof *opm); + enum ofperr error = ofputil_port_from_ofp11(opm->port_no, &pm->port_no); + if (error) { + return error; + } - while (b.size > 0) { - struct ofpbuf property; - enum ofperr error; - uint64_t type; + pm->hw_addr = opm->hw_addr; + pm->config = ntohl(opm->config) & OFPPC11_ALL; + pm->mask = ntohl(opm->mask) & OFPPC11_ALL; - error = ofpprop_pull(&b, &property, &type); - if (error) { - return error; - } + return ofputil_decode_ofp14_port_mod_properties(b, loose, pm); +} - switch (type) { - case OFPPMPT14_ETHERNET: - error = parse_port_mod_ethernet_property(&property, pm); - break; +static enum ofperr +ofputil_decode_ofp16_port_mod(struct ofpbuf *b, bool loose, + struct ofputil_port_mod *pm) +{ + const struct ofp16_port_mod *opm = ofpbuf_pull(b, sizeof *opm); + enum ofperr error = ofputil_port_from_ofp11(opm->port_no, &pm->port_no); + if (error) { + return error; + } - default: - error = OFPPROP_UNKNOWN(loose, "port_mod", type); - break; - } + if (opm->hw_addr_type & htons(OFPPHAT16_EUI48)) { + pm->hw_addr = opm->hw_addr; + } + if (opm->hw_addr_type & htons(OFPPHAT16_EUI64)) { + pm->hw_addr64 = opm->hw_addr64; + } + pm->hw_addr = opm->hw_addr; + pm->config = ntohl(opm->config) & OFPPC11_ALL; + pm->mask = ntohl(opm->mask) & OFPPC11_ALL; - if (error) { - return error; - } - } + return ofputil_decode_ofp14_port_mod_properties(b, loose, pm); +} + +/* Decodes the OpenFlow "port mod" message in '*oh' into an abstract form in + * '*pm'. Returns 0 if successful, otherwise an OFPERR_* value. */ +enum ofperr +ofputil_decode_port_mod(const struct ofp_header *oh, + struct ofputil_port_mod *pm, bool loose) +{ + memset(pm, 0, sizeof *pm); + + struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); + enum ofpraw raw = ofpraw_pull_assert(&b); + if (raw == OFPRAW_OFPT10_PORT_MOD) { + return ofputil_decode_ofp10_port_mod(b.data, pm); + } else if (raw == OFPRAW_OFPT11_PORT_MOD) { + return ofputil_decode_ofp11_port_mod(b.data, pm); + } else if (raw == OFPRAW_OFPT14_PORT_MOD) { + return ofputil_decode_ofp14_port_mod(&b, loose, pm); + } else if (raw == OFPRAW_OFPT16_PORT_MOD) { + return ofputil_decode_ofp16_port_mod(&b, loose, pm); } else { return OFPERR_OFPBRC_BAD_TYPE; } @@ -5079,8 +5208,7 @@ ofputil_encode_port_mod(const struct ofputil_port_mod *pm, break; } case OFP14_VERSION: - case OFP15_VERSION: - case OFP16_VERSION: { + case OFP15_VERSION: { struct ofp14_port_mod *opm; b = ofpraw_alloc(OFPRAW_OFPT14_PORT_MOD, ofp_version, 0); @@ -5096,6 +5224,29 @@ ofputil_encode_port_mod(const struct ofputil_port_mod *pm, } break; } + case OFP16_VERSION: { + struct ofp16_port_mod *opm; + + b = ofpraw_alloc(OFPRAW_OFPT16_PORT_MOD, ofp_version, 0); + opm = ofpbuf_put_zeros(b, sizeof *opm); + opm->port_no = ofputil_port_to_ofp11(pm->port_no); + if (!eth_addr_is_zero(pm->hw_addr)) { + opm->hw_addr_type |= htons(OFPPHAT16_EUI48); + opm->hw_addr = pm->hw_addr; + } + if (!eth_addr64_is_zero(pm->hw_addr64)) { + opm->hw_addr_type |= htons(OFPPHAT16_EUI64); + opm->hw_addr64 = pm->hw_addr64; + } + opm->config = htonl(pm->config & OFPPC11_ALL); + opm->mask = htonl(pm->mask & OFPPC11_ALL); + + if (pm->advertise) { + ofpprop_put_be32(b, OFPPMPT14_ETHERNET, + netdev_port_features_to_ofp11(pm->advertise)); + } + break; + } default: OVS_NOT_REACHED(); } @@ -7103,7 +7254,7 @@ ofputil_port_from_string(const char *s, ofp_port_t *portp) "be translated to %u when talking to an OF1.1 or " "later controller", port32, port32 + OFPP11_OFFSET); } else if (port32 <= ofp_to_u16(OFPP_LAST_RESV)) { - char name[OFP_MAX_PORT_NAME_LEN]; + char name[OFP10_MAX_PORT_NAME_LEN]; ofputil_port_to_string(u16_to_ofp(port32), name, sizeof name); VLOG_WARN_ONCE("referring to port %s as %"PRIu32" is deprecated " @@ -7148,7 +7299,7 @@ ofputil_port_from_string(const char *s, ofp_port_t *portp) void ofputil_format_port(ofp_port_t port, struct ds *s) { - char name[OFP_MAX_PORT_NAME_LEN]; + char name[OFP10_MAX_PORT_NAME_LEN]; ofputil_port_to_string(port, name, sizeof name); ds_put_cstr(s, name); @@ -7160,7 +7311,7 @@ ofputil_format_port(ofp_port_t port, struct ds *s) * by name, e.g. "LOCAL". */ void ofputil_port_to_string(ofp_port_t port, - char namebuf[OFP_MAX_PORT_NAME_LEN], size_t bufsize) + char namebuf[OFP10_MAX_PORT_NAME_LEN], size_t bufsize) { switch (port) { #define OFPUTIL_NAMED_PORT(NAME) \ @@ -7259,8 +7410,9 @@ ofputil_pull_phy_port(enum ofp_version ofp_version, struct ofpbuf *b, } case OFP14_VERSION: case OFP15_VERSION: - case OFP16_VERSION: return b->size ? ofputil_pull_ofp14_port(pp, b) : EOF; + case OFP16_VERSION: + return b->size ? ofputil_pull_ofp16_port(pp, b) : EOF; default: OVS_NOT_REACHED(); } diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index ca286e3720a5..a24aef9a43a1 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -4597,7 +4597,7 @@ xlate_output_trunc_action(struct xlate_ctx *ctx, { bool support_trunc = ctx->xbridge->support.trunc; struct ovs_action_trunc *trunc; - char name[OFP_MAX_PORT_NAME_LEN]; + char name[OFP10_MAX_PORT_NAME_LEN]; switch (port) { case OFPP_TABLE: diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 9556a0e0cd58..6a5ffb94fa94 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -4845,7 +4845,7 @@ ofproto_unixctl_fdb_show(struct unixctl_conn *conn, int argc OVS_UNUSED, ovs_rwlock_rdlock(&ofproto->ml->rwlock); LIST_FOR_EACH (e, lru_node, &ofproto->ml->lrus) { struct ofbundle *bundle = mac_entry_get_port(ofproto->ml, e); - char name[OFP_MAX_PORT_NAME_LEN]; + char name[OFP10_MAX_PORT_NAME_LEN]; ofputil_port_to_string(ofbundle_get_a_port(bundle)->up.ofp_port, name, sizeof name); @@ -4886,7 +4886,7 @@ ofproto_unixctl_mcast_snooping_show(struct unixctl_conn *conn, ovs_rwlock_rdlock(&ofproto->ms->rwlock); LIST_FOR_EACH (grp, group_node, &ofproto->ms->group_lru) { LIST_FOR_EACH(b, bundle_node, &grp->bundle_lru) { - char name[OFP_MAX_PORT_NAME_LEN]; + char name[OFP10_MAX_PORT_NAME_LEN]; bundle = b->port; ofputil_port_to_string(ofbundle_get_a_port(bundle)->up.ofp_port, @@ -4900,7 +4900,7 @@ ofproto_unixctl_mcast_snooping_show(struct unixctl_conn *conn, /* ports connected to multicast routers */ LIST_FOR_EACH(mrouter, mrouter_node, &ofproto->ms->mrouter_lru) { - char name[OFP_MAX_PORT_NAME_LEN]; + char name[OFP10_MAX_PORT_NAME_LEN]; bundle = mrouter->port; ofputil_port_to_string(ofbundle_get_a_port(bundle)->up.ofp_port, diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 84ea95b0c2a2..7440d5b52092 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -2346,6 +2346,7 @@ ofport_open(struct ofproto *ofproto, } pp->port_no = ofproto_port->ofp_port; netdev_get_etheraddr(netdev, &pp->hw_addr); + pp->hw_addr64 = eth_addr64_zero; ovs_strlcpy(pp->name, ofproto_port->name, sizeof pp->name); netdev_get_flags(netdev, &flags); pp->config = flags & NETDEV_UP ? 0 : OFPUTIL_PC_PORT_DOWN; @@ -2366,6 +2367,7 @@ ofport_equal(const struct ofputil_phy_port *a, const struct ofputil_phy_port *b) { return (eth_addr_equals(a->hw_addr, b->hw_addr) + && eth_addr64_equals(a->hw_addr64, b->hw_addr64) && a->state == b->state && !((a->config ^ b->config) & OFPUTIL_PC_PORT_DOWN) && a->curr == b->curr @@ -2460,6 +2462,7 @@ static void ofport_modified(struct ofport *port, struct ofputil_phy_port *pp) { port->pp.hw_addr = pp->hw_addr; + port->pp.hw_addr64 = pp->hw_addr64; port->pp.config = ((port->pp.config & ~OFPUTIL_PC_PORT_DOWN) | (pp->config & OFPUTIL_PC_PORT_DOWN)); port->pp.state = ((port->pp.state & ~OFPUTIL_PS_LINK_DOWN) @@ -3630,7 +3633,8 @@ port_mod_start(struct ofconn *ofconn, struct ofputil_port_mod *pm, if (!*port) { return OFPERR_OFPPMFC_BAD_PORT; } - if (!eth_addr_equals((*port)->pp.hw_addr, pm->hw_addr)) { + if (!eth_addr_equals((*port)->pp.hw_addr, pm->hw_addr) || + !eth_addr64_equals((*port)->pp.hw_addr64, pm->hw_addr64)) { return OFPERR_OFPPMFC_BAD_HW_ADDR; } return 0; diff --git a/tests/ofp-print.at b/tests/ofp-print.at index 5738a9657baa..dfa26e0ce2ae 100644 --- a/tests/ofp-print.at +++ b/tests/ofp-print.at @@ -695,6 +695,32 @@ OFPT_PORT_STATUS (OF1.4) (xid=0x0): MOD: 3(eth0): addr:50:54:00:00:00:01 ]) AT_CLEANUP +AT_SETUP([OFPT_PORT_STATUS - OF1.6]) +AT_KEYWORDS([ofp-print]) +AT_CHECK([ovs-ofctl ofp-print "\ +07 0c 00 90 00 00 00 00 02 00 00 00 00 00 00 00 \ +\ +00 00 00 03 00 80 00 03 50 54 00 00 00 01 00 00 \ +50 54 00 ff fe 00 00 01 \ +65 74 68 30 00 00 00 00 00 00 00 00 00 00 00 00 \ +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \ +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \ +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \ +00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 \ +00 00 20 08 00 00 28 0f 00 00 28 0f 00 00 00 00 \ +00 01 86 a0 00 01 86 a0 \ +"], [0], [dnl +OFPT_PORT_STATUS (OF1.6) (xid=0x0): MOD: 3(eth0): addr:50:54:00:00:00:01 + addr64: 50:54:00:ff:fe:00:00:01 + config: 0 + state: 0 + current: 100MB-FD AUTO_NEG + advertised: 10MB-HD 10MB-FD 100MB-HD 100MB-FD COPPER AUTO_NEG + supported: 10MB-HD 10MB-FD 100MB-HD 100MB-FD COPPER AUTO_NEG + speed: 100 Mbps now, 100 Mbps max +]) +AT_CLEANUP + AT_SETUP([OFPT_PACKET_OUT - OF1.0]) AT_KEYWORDS([ofp-print]) AT_CHECK([ovs-ofctl ofp-print "\ @@ -1124,6 +1150,21 @@ OFPT_PORT_MOD (OF1.4) (xid=0x3): port: 3: addr:50:54:00:00:00:01 ]) AT_CLEANUP +AT_SETUP([OFPT_PORT_MOD - OF1.6]) +AT_KEYWORDS([ofp-print]) +AT_CHECK([ovs-ofctl ofp-print "\ +07 10 00 30 00 00 00 03 00 00 00 03 00 03 00 00 \ +50 54 00 00 00 01 00 00 50 54 00 ff fe 00 00 01 \ +00 00 00 01 00 00 00 01 00 00 00 08 00 00 00 01 +" 3], [0], [dnl +OFPT_PORT_MOD (OF1.6) (xid=0x3): port: 3: addr:50:54:00:00:00:01 + addr64: 50:54:00:ff:fe:00:00:01 + config: PORT_DOWN + mask: PORT_DOWN + advertise: 10MB-HD +]) +AT_CLEANUP + AT_SETUP([OFPT_TABLE_MOD - OF1.1]) AT_KEYWORDS([ofp-print]) AT_CHECK([ovs-ofctl ofp-print "\ diff --git a/tests/ofproto.at b/tests/ofproto.at index b1ce712672be..5c0d0762390f 100644 --- a/tests/ofproto.at +++ b/tests/ofproto.at @@ -179,6 +179,40 @@ OFPST_PORT_DESC reply (OF1.5): OVS_VSWITCHD_STOP AT_CLEANUP +AT_SETUP([ofproto - port-desc stats (OpenFlow 1.6)]) +OVS_VSWITCHD_START +add_of_ports br0 1 2 3 +AT_CHECK([ovs-ofctl -F OXM-OpenFlow16 -O OpenFlow16 -vwarn dump-ports-desc br0], [0], [stdout]) +AT_CHECK([strip_xids < stdout | sed 's/00:0./00:0x/'], [0], [dnl +OFPST_PORT_DESC reply (OF1.6): + 1(p1): addr:aa:55:aa:55:00:0x + config: PORT_DOWN + state: LINK_DOWN + speed: 0 Mbps now, 0 Mbps max + 2(p2): addr:aa:55:aa:55:00:0x + config: PORT_DOWN + state: LINK_DOWN + speed: 0 Mbps now, 0 Mbps max + 3(p3): addr:aa:55:aa:55:00:0x + config: PORT_DOWN + state: LINK_DOWN + speed: 0 Mbps now, 0 Mbps max + LOCAL(br0): addr:aa:55:aa:55:00:0x + config: PORT_DOWN + state: LINK_DOWN + speed: 0 Mbps now, 0 Mbps max +]) +AT_CHECK([ovs-ofctl -F OXM-OpenFlow16 -O OpenFlow16 -vwarn dump-ports-desc br0 2], [0], [stdout]) +AT_CHECK([strip_xids < stdout | sed 's/00:0./00:0x/'], [0], [dnl +OFPST_PORT_DESC reply (OF1.6): + 2(p2): addr:aa:55:aa:55:00:0x + config: PORT_DOWN + state: LINK_DOWN + speed: 0 Mbps now, 0 Mbps max +]) +OVS_VSWITCHD_STOP +AT_CLEANUP + dnl CHECK_QUEUE_STATS(label, option, format) m4_define([CHECK_QUEUE_STATS], [ AT_SETUP([ofproto - queue stats - (OpenFlow $1)]) @@ -1254,6 +1288,38 @@ done OVS_VSWITCHD_STOP AT_CLEANUP +AT_SETUP([ofproto - mod-port (OpenFlow 1.6)]) +OVS_VSWITCHD_START +for command_config_state in \ + 'up 0 0' \ + 'down PORT_DOWN LINK_DOWN' \ + 'no-receive PORT_DOWN,NO_RECV LINK_DOWN' \ + 'no-forward PORT_DOWN,NO_RECV,NO_FWD LINK_DOWN' \ + 'no-packet-in PORT_DOWN,NO_RECV,NO_FWD,NO_PACKET_IN LINK_DOWN' \ + 'forward PORT_DOWN,NO_RECV,NO_PACKET_IN LINK_DOWN' \ + 'packet-in PORT_DOWN,NO_RECV LINK_DOWN' \ + 'up NO_RECV 0' \ + 'receive 0 0' +do + set $command_config_state + command=$[1] config=`echo $[2] | sed 's/,/ /g'` state=$[3] + AT_CHECK([ovs-ofctl -O OpenFlow16 -vwarn mod-port br0 br0 $command]) + AT_CHECK([ovs-ofctl -O OpenFlow16 -vwarn show br0], [0], [stdout]) + AT_CHECK_UNQUOTED([strip_xids < stdout], [0], [dnl +OFPT_FEATURES_REPLY (OF1.6): dpid:fedcba9876543210 +n_tables:254, n_buffers:0 +capabilities: FLOW_STATS TABLE_STATS PORT_STATS GROUP_STATS QUEUE_STATS BUNDLES +OFPST_PORT_DESC reply (OF1.6): + LOCAL(br0): addr:aa:55:aa:55:00:00 + config: $config + state: $state + speed: 0 Mbps now, 0 Mbps max +OFPT_GET_CONFIG_REPLY (OF1.6): frags=normal miss_send_len=0 +]) +done +OVS_VSWITCHD_STOP +AT_CLEANUP + AT_SETUP([ofproto - basic flow_mod commands (NXM)]) OVS_VSWITCHD_START AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip], [0], [NXST_FLOW reply: diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c index 0855fb4e08d2..1a5e2345b7d4 100644 --- a/utilities/ovs-ofctl.c +++ b/utilities/ovs-ofctl.c @@ -2162,6 +2162,7 @@ ofctl_mod_port(struct ovs_cmdl_context *ctx) pm.port_no = pp.port_no; pm.hw_addr = pp.hw_addr; + pm.hw_addr64 = pp.hw_addr64; pm.config = 0; pm.mask = 0; pm.advertise = 0; -- 2.10.2 _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev