From 81816a5fe8ddd96a296fabc8ea8069e9a19a2631 Mon Sep 17 00:00:00 2001
From: Justin Pettit
Date: Tue, 2 Oct 2012 22:25:51 -0700
Subject: [PATCH] Allow the OpenFlow port to be requested for a port.
A new "ofport_request" column makes it possible to request the OpenFlow
port number when adding a port.
Signed-off-by: Justin Pettit
---
NEWS | 2 ++
ofproto/ofproto-dpif.c | 2 +-
ofproto/ofproto-provider.h | 9 ++++++---
ofproto/ofproto.c | 14 +++++++++-----
tests/ofproto.at | 27 +++++++++++++++++++++++++++
vswitchd/bridge.c | 32 +++++++++++++++++++-------------
vswitchd/vswitch.ovsschema | 11 +++++++++--
vswitchd/vswitch.xml | 11 +++++++++++
8 files changed, 84 insertions(+), 24 deletions(-)
diff --git a/NEWS b/NEWS
index 203a6623..b3f8f3c5 100644
--- a/NEWS
+++ b/NEWS
@@ -17,6 +17,8 @@ v1.9.0 - xx xxx xxxx
- Allow bitwise masking for SHA and THA fields in ARP, SLL and TLL
fields in IPv6 neighbor discovery messages, and IPv6 flow label.
- Adds support for writing to the metadata field for a flow.
+ - It is possible to request the OpenFlow port number with the
+ "ofport_request" column in the Interface table.
- ovs-ofctl:
- Commands and actions that accept port numbers now also accept keywords
that represent those ports (such as LOCAL, NONE, and ALL). This is
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 97a94eb0..b8b144f9 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -2531,7 +2531,7 @@ static int
port_add(struct ofproto *ofproto_, struct netdev *netdev, uint16_t *ofp_portp)
{
struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
- uint32_t odp_port = UINT32_MAX;
+ uint32_t odp_port = *ofp_portp != OFPP_NONE ? *ofp_portp : UINT32_MAX;
int error;
error = dpif_port_add(ofproto->dpif, netdev, &odp_port);
diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h
index a62473ba..05885d5c 100644
--- a/ofproto/ofproto-provider.h
+++ b/ofproto/ofproto-provider.h
@@ -583,9 +583,12 @@ struct ofproto_class {
int (*port_query_by_name)(const struct ofproto *ofproto,
const char *devname, struct ofproto_port *port);
- /* Attempts to add 'netdev' as a port on 'ofproto'. Returns 0 if
- * successful, otherwise a positive errno value. If successful, sets
- * '*ofp_portp' to the new port's port number.
+ /* Attempts to add 'netdev' as a port on 'ofproto'. If '*ofp_portp'
+ * is not OFPP_NONE, attempts to use that as the port's OpenFlow
+ * port number.
+ *
+ * Returns 0 if successful, otherwise a positive errno value. If
+ * successful, sets '*ofp_portp' to the new port's port number.
*
* It doesn't matter whether the new port will be returned by a later call
* to ->port_poll(); the implementation may do whatever is more
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index 2fb2fc87..743db1f1 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -1345,15 +1345,19 @@ ofproto_port_dump_done(struct ofproto_port_dump *dump)
return dump->error == EOF ? 0 : dump->error;
}
-/* Attempts to add 'netdev' as a port on 'ofproto'. If successful, returns 0
- * and sets '*ofp_portp' to the new port's OpenFlow port number (if 'ofp_portp'
- * is non-null). On failure, returns a positive errno value and sets
- * '*ofp_portp' to OFPP_NONE (if 'ofp_portp' is non-null). */
+/* Attempts to add 'netdev' as a port on 'ofproto'. If 'ofp_portp' is
+ * non-null and '*ofp_portp' is not OFPP_NONE, attempts to use that as
+ * the port's OpenFlow port number.
+ *
+ * If successful, returns 0 and sets '*ofp_portp' to the new port's
+ * OpenFlow port number (if 'ofp_portp' is non-null). On failure,
+ * returns a positive errno value and sets '*ofp_portp' to OFPP_NONE (if
+ * 'ofp_portp' is non-null). */
int
ofproto_port_add(struct ofproto *ofproto, struct netdev *netdev,
uint16_t *ofp_portp)
{
- uint16_t ofp_port;
+ uint16_t ofp_port = ofp_portp ? *ofp_portp : OFPP_NONE;
int error;
error = ofproto->ofproto_class->port_add(ofproto, netdev, &ofp_port);
diff --git a/tests/ofproto.at b/tests/ofproto.at
index cbf07bc0..affc702b 100644
--- a/tests/ofproto.at
+++ b/tests/ofproto.at
@@ -23,6 +23,33 @@ OFPT_GET_CONFIG_REPLY: frags=normal miss_send_len=0
OVS_VSWITCHD_STOP
AT_CLEANUP
+AT_SETUP([ofproto - set OpenFlow port number])
+OVS_VSWITCHD_START(
+ [add-port br0 p1 -- set Interface p1 type=dummy --\
+ add-port br0 p2 -- set Interface p2 type=dummy ofport_request=99])
+AT_CHECK([ovs-ofctl -vwarn show br0], [0], [stdout])
+AT_CHECK([STRIP_XIDS stdout], [0], [dnl
+OFPT_FEATURES_REPLY: dpid:fedcba9876543210
+n_tables:255, n_buffers:256
+capabilities: FLOW_STATS TABLE_STATS PORT_STATS QUEUE_STATS ARP_MATCH_IP
+actions: OUTPUT SET_VLAN_VID SET_VLAN_PCP STRIP_VLAN SET_DL_SRC SET_DL_DST SET_NW_SRC SET_NW_DST SET_NW_TOS SET_TP_SRC SET_TP_DST ENQUEUE
+ 1(p1): addr:aa:55:aa:55:00:01
+ config: PORT_DOWN
+ state: LINK_DOWN
+ speed: 100 Mbps now, 100 Mbps max
+ 99(p2): addr:aa:55:aa:55:00:02
+ config: PORT_DOWN
+ state: LINK_DOWN
+ speed: 100 Mbps now, 100 Mbps max
+ LOCAL(br0): addr:aa:55:aa:55:00:00
+ config: PORT_DOWN
+ state: LINK_DOWN
+ speed: 100 Mbps now, 100 Mbps max
+OFPT_GET_CONFIG_REPLY: frags=normal miss_send_len=0
+])
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
dnl This is really bare-bones.
dnl It at least checks request and reply serialization and deserialization.
AT_SETUP([ofproto - port stats])
diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c
index a481f061..8240d250 100644
--- a/vswitchd/bridge.c
+++ b/vswitchd/bridge.c
@@ -66,6 +66,7 @@ struct if_cfg {
struct hmap_node hmap_node; /* Node in bridge's if_cfg_todo. */
const struct ovsrec_interface *cfg; /* Interface record. */
const struct ovsrec_port *parent; /* Parent port record. */
+ int64_t ofport; /* Requested OpenFlow port number. */
};
/* OpenFlow port slated for removal from ofproto. */
@@ -1261,7 +1262,7 @@ bridge_refresh_ofp_port(struct bridge *br)
}
}
-/* Opens a network device for 'iface_cfg' and configures it. If '*ofp_portp'
+/* Opens a network device for 'if_cfg' and configures it. If '*ofp_portp'
* is negative, adds the network device to br->ofproto and stores the OpenFlow
* port number in '*ofp_portp'; otherwise leaves br->ofproto and '*ofp_portp'
* untouched.
@@ -1270,10 +1271,11 @@ bridge_refresh_ofp_port(struct bridge *br)
* failure, returns a positive errno value and stores NULL in '*netdevp'. */
static int
iface_do_create(const struct bridge *br,
- const struct ovsrec_interface *iface_cfg,
- const struct ovsrec_port *port_cfg,
+ const struct if_cfg *if_cfg,
int *ofp_portp, struct netdev **netdevp)
{
+ const struct ovsrec_interface *iface_cfg = if_cfg->cfg;
+ const struct ovsrec_port *port_cfg = if_cfg->parent;
struct netdev *netdev;
int error;
@@ -1291,7 +1293,7 @@ iface_do_create(const struct bridge *br,
}
if (*ofp_portp < 0) {
- uint16_t ofp_port;
+ uint16_t ofp_port = if_cfg->ofport;
error = ofproto_port_add(br->ofproto, netdev, &ofp_port);
if (error) {
@@ -1335,11 +1337,7 @@ iface_create(struct bridge *br, struct if_cfg *if_cfg, int ofp_port)
struct iface *iface;
struct port *port;
int error;
-
- /* Get rid of 'if_cfg' itself. We already copied out the interesting
- * bits. */
- hmap_remove(&br->if_cfg_todo, &if_cfg->hmap_node);
- free(if_cfg);
+ bool ok = true;
/* Do the bits that can fail up front.
*
@@ -1348,11 +1346,12 @@ iface_create(struct bridge *br, struct if_cfg *if_cfg, int ofp_port)
* additions and deletions are cheaper, these calls should be removed. */
bridge_run_fast();
assert(!iface_lookup(br, iface_cfg->name));
- error = iface_do_create(br, iface_cfg, port_cfg, &ofp_port, &netdev);
+ error = iface_do_create(br, if_cfg, &ofp_port, &netdev);
bridge_run_fast();
if (error) {
iface_clear_db_record(iface_cfg);
- return false;
+ ok = false;
+ goto done;
}
/* Get or create the port structure. */
@@ -1390,7 +1389,9 @@ iface_create(struct bridge *br, struct if_cfg *if_cfg, int ofp_port)
error = netdev_open(port->name, "internal", &netdev);
if (!error) {
- ofproto_port_add(br->ofproto, netdev, NULL);
+ uint16_t ofp_port = if_cfg->ofport;
+
+ ofproto_port_add(br->ofproto, netdev, &ofp_port);
netdev_close(netdev);
} else {
VLOG_WARN("could not open network device %s (%s)",
@@ -1402,7 +1403,11 @@ iface_create(struct bridge *br, struct if_cfg *if_cfg, int ofp_port)
}
}
- return true;
+done:
+ hmap_remove(&br->if_cfg_todo, &if_cfg->hmap_node);
+ free(if_cfg);
+
+ return ok;
}
/* Set Flow eviction threshold */
@@ -2451,6 +2456,7 @@ bridge_queue_if_cfg(struct bridge *br,
if_cfg->cfg = cfg;
if_cfg->parent = parent;
+ if_cfg->ofport = cfg->n_ofport_request ? *cfg->ofport_request : OFPP_NONE;
hmap_insert(&br->if_cfg_todo, &if_cfg->hmap_node,
hash_string(if_cfg->cfg->name, 0));
}
diff --git a/vswitchd/vswitch.ovsschema b/vswitchd/vswitch.ovsschema
index bbfb01f2..12344889 100644
--- a/vswitchd/vswitch.ovsschema
+++ b/vswitchd/vswitch.ovsschema
@@ -1,6 +1,6 @@
{"name": "Open_vSwitch",
- "version": "6.10.0",
- "cksum": "3699312094 16958",
+ "version": "6.11.0",
+ "cksum": "3699219253 17163",
"tables": {
"Open_vSwitch": {
"columns": {
@@ -178,6 +178,13 @@
"ofport": {
"type": {"key": "integer", "min": 0, "max": 1},
"ephemeral": true},
+ "ofport_request": {
+ "type": {
+ "key": {"type": "integer",
+ "minInteger": 1,
+ "maxInteger": 65279},
+ "min": 0,
+ "max": 1}},
"cfm_mpid": {
"type": {
"key": {"type": "integer"},
diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml
index f486d6af..c181b95a 100644
--- a/vswitchd/vswitch.xml
+++ b/vswitchd/vswitch.xml
@@ -1159,6 +1159,17 @@
cannot be added then Open vSwitch sets this column
to -1.
+
+
+ Requested OpenFlow port number for this interface. The port
+ number must be between 1 and 65279, inclusive. Some datapaths
+ cannot satisfy all requests for particular port numbers. When
+ this column is empty or the request cannot be fulfilled, the
+ system will choose a free port. The
+ column reports the assigned OpenFlow port number.
+ The port number must be requested in the same transaction
+ that creates the port.
+
--
2.30.2