@@ -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
---------------------
@@ -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
@@ -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. */
@@ -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. */
@@ -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. */
new file mode 100644
@@ -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 */
@@ -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
@@ -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 */
@@ -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. */
@@ -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;
@@ -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);
@@ -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();
}
@@ -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:
@@ -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,
@@ -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;
@@ -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 "\
@@ -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:
@@ -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;
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 <blp@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