2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-22 01:51:26 +00:00

bridge: Support changing port numbers.

Feature #21293.
Requested-by: Anuprem Chalvadi <achalvadi@vmware.com>
Signed-off-by: Ben Pfaff <blp@nicira.com>
This commit is contained in:
Ben Pfaff 2013-12-11 15:40:52 -08:00
parent 2a73b1d73d
commit 4abb8608af
4 changed files with 152 additions and 18 deletions

3
NEWS
View File

@ -38,6 +38,9 @@ Post-v2.0.0
* OVS limits the OpenFlow port numbers it assigns to port 32767 and
below, leaving port numbers above that range free for assignment
by the controller.
* ovs-vswitchd now honors changes to the "ofport_request" column
in the Interface table by changing the port's OpenFlow port
number.
- ovs-vswitchd.conf.db.5 man page will contain graphviz/dot
diagram only if graphviz package was installed at the build time.
- Support for Linux kernels up to 3.11

View File

@ -2152,3 +2152,58 @@ OFPT_BARRIER_REPLY (OF1.3):
OVS_VSWITCHD_STOP
AT_CLEANUP
AT_SETUP([ofproto - ofport_request])
OVS_VSWITCHD_START
ADD_OF_PORTS([br0], [1], [2], [3])
set_and_check_specific_ofports () {
ovs-vsctl set Interface p1 ofport_request="$1" -- \
set Interface p2 ofport_request="$2" -- \
set Interface p3 ofport_request="$3"
ofports=`ovs-vsctl get Interface p1 ofport -- \
get Interface p2 ofport -- \
get Interface p3 ofport`
AT_CHECK_UNQUOTED([echo $ofports], [0], [$1 $2 $3
])
}
for pre in '1 2 3' '1 3 2' '2 1 3' '2 3 1' '3 1 2' '3 2 1'; do
for post in '1 2 3' '1 3 2' '2 1 3' '2 3 1' '3 1 2' '3 2 1'; do
echo -----------------------------------------------------------
echo "Check changing port numbers from $pre to $post"
set_and_check_ofports $pre
set_and_check_ofports $post
done
done
ovs-vsctl del-port p3
set_and_check_poorly_specified_ofports () {
ovs-vsctl set Interface p1 ofport_request="$1" -- \
set Interface p2 ofport_request="$2"
p1=`ovs-vsctl get Interface p1 ofport`
p2=`ovs-vsctl get Interface p2 ofport`
echo $p1 $p2
AT_CHECK([test "$p1" != "$p2"])
if test "$1" = "$2" && test "$1" != '[[]]'; then
# One port number must be the requested one.
AT_CHECK([test "$p1" = "$1" || test "$p2" = "$1"])
# The other port number must be different (already tested above).
else
AT_CHECK([test "$1" = '[[]]' || test "$p1" == "$1"])
AT_CHECK([test "$2" = '[[]]' || test "$p2" == "$2"])
fi
}
for pre in '1 2' '[[]] 2' '1 [[]]' '[[]] [[]]' '2 1' '[[]] 1' '2 [[]]' \
'1 1' '2 2'; do
for post in '1 2' '[[]] 2' '1 [[]]' '[[]] [[]]' '2 1' '[[]] 1' '2 [[]]' \
'1 1' '2 2'; do
echo -----------------------------------------------------------
echo "Check changing port numbers from $pre to $post"
set_and_check_poorly_specified_ofports $pre
set_and_check_poorly_specified_ofports $post
done
done
OVS_VSWITCHD_STOP
AT_CLEANUP

View File

@ -255,6 +255,8 @@ static void iface_refresh_cfm_stats(struct iface *);
static void iface_refresh_stats(struct iface *);
static void iface_refresh_status(struct iface *);
static bool iface_is_synthetic(const struct iface *);
static ofp_port_t iface_get_requested_ofp_port(
const struct ovsrec_interface *);
static ofp_port_t iface_pick_ofport(const struct ovsrec_interface *);
/* Linux VLAN device support (e.g. "eth0.10" for VLAN 10.)
@ -652,6 +654,7 @@ bridge_delete_or_reconfigure_ports(struct bridge *br)
n = allocated = 0;
OFPROTO_PORT_FOR_EACH (&ofproto_port, &dump, br->ofproto) {
ofp_port_t requested_ofp_port;
struct iface *iface;
iface = iface_lookup(br, ofproto_port.name);
@ -675,6 +678,43 @@ bridge_delete_or_reconfigure_ports(struct bridge *br)
goto delete;
}
/* If the requested OpenFlow port for 'iface' changed, and it's not
* already the correct port, then we might want to temporarily delete
* this interface, so we can add it back again with the new OpenFlow
* port number. */
requested_ofp_port = iface_get_requested_ofp_port(iface->cfg);
if (iface->ofp_port != OFPP_LOCAL &&
requested_ofp_port != OFPP_NONE &&
requested_ofp_port != iface->ofp_port) {
ofp_port_t victim_request;
struct iface *victim;
/* Check for an existing OpenFlow port currently occupying
* 'iface''s requested port number. If there isn't one, then
* delete this port. Otherwise we need to consider further. */
victim = iface_from_ofp_port(br, requested_ofp_port);
if (!victim) {
goto delete;
}
/* 'victim' is a port currently using 'iface''s requested port
* number. Unless 'victim' specifically requested that port
* number, too, then we can delete both 'iface' and 'victim'
* temporarily. (We'll add both of them back again later with new
* OpenFlow port numbers.)
*
* If 'victim' did request port number 'requested_ofp_port', just
* like 'iface', then that's a configuration inconsistency that we
* can't resolve. We might as well let it keep its current port
* number. */
victim_request = iface_get_requested_ofp_port(victim->cfg);
if (victim_request != requested_ofp_port) {
del = add_ofp_port(victim->ofp_port, del, &n, &allocated);
iface_destroy(victim);
goto delete;
}
}
/* Keep it. */
continue;
@ -690,7 +730,8 @@ bridge_delete_or_reconfigure_ports(struct bridge *br)
}
static void
bridge_add_ports(struct bridge *br, const struct shash *wanted_ports)
bridge_add_ports__(struct bridge *br, const struct shash *wanted_ports,
bool with_requested_port)
{
struct shash_node *port_node;
@ -700,15 +741,32 @@ bridge_add_ports(struct bridge *br, const struct shash *wanted_ports)
for (i = 0; i < port_cfg->n_interfaces; i++) {
const struct ovsrec_interface *iface_cfg = port_cfg->interfaces[i];
struct iface *iface = iface_lookup(br, iface_cfg->name);
ofp_port_t requested_ofp_port;
if (!iface) {
iface_create(br, iface_cfg, port_cfg);
requested_ofp_port = iface_get_requested_ofp_port(iface_cfg);
if ((requested_ofp_port != OFPP_NONE) == with_requested_port) {
struct iface *iface = iface_lookup(br, iface_cfg->name);
if (!iface) {
iface_create(br, iface_cfg, port_cfg);
}
}
}
}
}
static void
bridge_add_ports(struct bridge *br, const struct shash *wanted_ports)
{
/* First add interfaces that request a particular port number. */
bridge_add_ports__(br, wanted_ports, true);
/* Then add interfaces that want automatic port number assignment.
* We add these afterward to avoid accidentally taking a specifically
* requested port number. */
bridge_add_ports__(br, wanted_ports, false);
}
static void
port_configure(struct port *port)
{
@ -1458,7 +1516,7 @@ iface_create(struct bridge *br, const struct ovsrec_interface *iface_cfg,
error = netdev_open(port->name, "internal", &netdev);
if (!error) {
ofp_port_t fake_ofp_port = iface_pick_ofport(iface_cfg);
ofp_port_t fake_ofp_port = OFPP_NONE;
ofproto_port_add(br->ofproto, netdev, &fake_ofp_port);
netdev_close(netdev);
} else {
@ -3636,14 +3694,27 @@ iface_is_synthetic(const struct iface *iface)
}
static ofp_port_t
iface_pick_ofport(const struct ovsrec_interface *cfg)
iface_validate_ofport__(size_t n, int64_t *ofport)
{
ofp_port_t ofport = cfg->n_ofport ? u16_to_ofp(*cfg->ofport)
: OFPP_NONE;
return cfg->n_ofport_request ? u16_to_ofp(*cfg->ofport_request)
: ofport;
return (n && *ofport >= 1 && *ofport < ofp_to_u16(OFPP_MAX)
? u16_to_ofp(*ofport)
: OFPP_NONE);
}
static ofp_port_t
iface_get_requested_ofp_port(const struct ovsrec_interface *cfg)
{
return iface_validate_ofport__(cfg->n_ofport_request, cfg->ofport_request);
}
static ofp_port_t
iface_pick_ofport(const struct ovsrec_interface *cfg)
{
ofp_port_t requested_ofport = iface_get_requested_ofp_port(cfg);
return (requested_ofport != OFPP_NONE
? requested_ofport
: iface_validate_ofport__(cfg->n_ofport, cfg->ofport));
}
/* Port mirroring. */

View File

@ -1306,14 +1306,19 @@
</p>
<p>
Open vSwitch currently assigns the OpenFlow port number for an
interface once, when the client first adds the interface. It does
not change the port number later if the client sets or changes or
clears <ref column="ofport_request"/>. Therefore, to ensure that
<ref column="ofport_request"/> takes effect, the client should set
it in the same database transaction that creates the interface.
(Future versions of Open vSwitch might honor changes to <ref
column="ofport_request"/>.)
A client should ideally set this column's value in the same
database transaction that it uses to create the interface. Open
vSwitch version 2.1 and later will honor a later request for a
specific port number, althuogh it might confuse some controllers:
OpenFlow does not have a way to announce a port number change, so
Open vSwitch represents it over OpenFlow as a port deletion
followed immediately by a port addition.
</p>
<p>
If <ref column="ofport_request"/> is set or changed to some other
port's automatically assigned port number, Open vSwitch chooses a
new port number for the latter port.
</p>
</column>
</group>