This can happen on ESX. Also adds a test to make sure this works.
Bug #17634. Signed-off-by: Ben Pfaff <b...@nicira.com> --- lib/dpif-netdev.c | 40 ++++++++++++++++++++++++++++++++++++++++ ofproto/ofproto-dpif.c | 18 ++++++++++++++++++ tests/ofproto-dpif.at | 21 +++++++++++++++++++++ 3 files changed, 79 insertions(+), 0 deletions(-) diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 52aedb6..0b21852 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -52,6 +52,7 @@ #include "shash.h" #include "sset.h" #include "timeval.h" +#include "unixctl.h" #include "util.h" #include "vlog.h" @@ -1217,6 +1218,41 @@ const struct dpif_class dpif_netdev_class = { }; static void +dpif_dummy_change_port_number(struct unixctl_conn *conn, int argc OVS_UNUSED, + const char *argv[], void *aux OVS_UNUSED) +{ + struct dp_netdev_port *port; + struct dp_netdev *dp; + int port_no; + + dp = shash_find_data(&dp_netdevs, argv[1]); + if (!dp || !dpif_netdev_class_is_dummy(dp->class)) { + unixctl_command_reply_error(conn, "unknown datapath or not a dummy"); + return; + } + + if (get_port_by_name(dp, argv[2], &port)) { + unixctl_command_reply_error(conn, "unknown port"); + return; + } + + port_no = atoi(argv[3]); + if (port_no <= 0 || port_no >= MAX_PORTS) { + unixctl_command_reply_error(conn, "bad port number"); + return; + } + if (dp->ports[port_no]) { + unixctl_command_reply_error(conn, "port number already in use"); + return; + } + dp->ports[port->port_no] = NULL; + dp->ports[port_no] = port; + port->port_no = port_no; + dp->serial++; + unixctl_command_reply(conn, NULL); +} + +static void dpif_dummy_register__(const char *type) { struct dpif_class *class; @@ -1245,4 +1281,8 @@ dpif_dummy_register(bool override) } dpif_dummy_register__("dummy"); + + unixctl_command_register("dpif-dummy/change-port-number", + "DP PORT NEW-NUMBER", + 3, 3, dpif_dummy_change_port_number, NULL); } diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 8845e71..e453c7e 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -771,6 +771,24 @@ process_dpif_port_change(struct dpif_backer *backer, const char *devname) /* The port was added, but we don't know with which * ofproto we should associate it. Delete it. */ dpif_port_del(backer->dpif, port.port_no); + } else { + struct ofport_dpif *ofport; + + ofport = ofport_dpif_cast(shash_find_data( + &ofproto->up.port_by_name, devname)); + if (ofport + && ofport->odp_port != port.port_no + && !odp_port_to_ofport(backer, port.port_no)) + { + /* 'ofport''s datapath port number has changed from + * 'ofport->odp_port' to 'port.port_no'. Update our internal data + * structures to match. */ + hmap_remove(&backer->odp_to_ofport_map, &ofport->odp_port_node); + ofport->odp_port = port.port_no; + hmap_insert(&backer->odp_to_ofport_map, &ofport->odp_port_node, + hash_int(port.port_no, 0)); + backer->need_revalidate = REV_RECONFIGURE; + } } dpif_port_destroy(&port); } diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at index e8458d0..156bea4 100644 --- a/tests/ofproto-dpif.at +++ b/tests/ofproto-dpif.at @@ -2553,3 +2553,24 @@ in_port=1,vlan_tci=0x0000/0x0fff,dl_src=50:54:00:00:00:0b, n_subfacets:1, used:0 ]) OVS_VSWITCHD_STOP AT_CLEANUP + +AT_SETUP([ofproto-dpif - datapath port number change]) +OVS_VSWITCHD_START([set Bridge br0 fail-mode=standalone]) +ADD_OF_PORTS([br0], 1) + +# Trace a flow that should output to p1. +AT_CHECK([ovs-appctl ofproto/trace br0 in_port=LOCAL,dl_src=10:20:30:40:50:60], + [0], [stdout]) +AT_CHECK([tail -1 stdout], [0], [Datapath actions: 1 +]) + +# Change p1's port number to 5. +AT_CHECK([ovs-appctl dpif-dummy/change-port-number ovs-dummy p1 5]) + +# Trace a flow that should output to p1 in its new location. +AT_CHECK([ovs-appctl ofproto/trace br0 in_port=LOCAL,dl_src=10:20:30:40:50:60], + [0], [stdout]) +AT_CHECK([tail -1 stdout], [0], [Datapath actions: 5 +]) +OVS_VSWITCHD_STOP +AT_CLEANUP -- 1.7.2.5 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev