- 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
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);
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
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);
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])
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. */
}
}
-/* 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.
* 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;
}
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) {
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.
*
* 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. */
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)",
}
}
- return true;
+done:
+ hmap_remove(&br->if_cfg_todo, &if_cfg->hmap_node);
+ free(if_cfg);
+
+ return ok;
}
/* Set Flow eviction threshold */
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));
}
{"name": "Open_vSwitch",
- "version": "6.10.0",
- "cksum": "3699312094 16958",
+ "version": "6.11.0",
+ "cksum": "3699219253 17163",
"tables": {
"Open_vSwitch": {
"columns": {
"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"},
cannot be added then Open vSwitch sets this column
to -1.</p>
</column>
+
+ <column name="ofport_request">
+ <p>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 <ref column="ofport"/>
+ column reports the assigned OpenFlow port number.</p>
+ <p>The port number must be requested in the same transaction
+ that creates the port.</p>
+ </column>
</group>
<group title="System-Specific Details">