- ovsdb-server now enforces the immutability of immutable columns. This
was not enforced in earlier versions due to an oversight.
- New support for a nonstandard form of GRE that supports a 64-bit key.
+ - The ofproto library is now responsible for assigning OpenFlow port
+ numbers. An ofproto implementation should assign them when
+ port_construct() is called.
- The following features are now deprecated. They will be removed no
earlier than February 2013. Please email dev@openvswitch.org with
concerns.
#define OVSP_NONE UINT32_MAX
-static inline uint32_t
-ofp_port_to_odp_port(uint16_t ofp_port)
-{
- switch (ofp_port) {
- case OFPP_LOCAL:
- return OVSP_LOCAL;
- case OFPP_NONE:
- case OFPP_CONTROLLER:
- return OVSP_NONE;
- default:
- return ofp_port;
- }
-}
-
-static inline uint16_t
-odp_port_to_ofp_port(uint32_t odp_port)
-{
- switch (odp_port) {
- case OVSP_LOCAL:
- return OFPP_LOCAL;
- case OVSP_NONE:
- return OFPP_NONE;
- default:
- return odp_port;
- }
-}
-
void format_odp_actions(struct ds *, const struct nlattr *odp_actions,
size_t actions_len);
int odp_actions_from_string(const char *, const struct simap *port_names,
struct hmap_node hmap_node; /* In struct dpif_sflow's "ports" hmap. */
SFLDataSource_instance dsi; /* sFlow library's notion of port number. */
struct ofport *ofport; /* To retrive port stats. */
+ uint32_t odp_port;
};
struct dpif_sflow {
HMAP_FOR_EACH_IN_BUCKET (dsp, hmap_node,
hash_int(odp_port, 0), &ds->ports) {
- if (ofp_port_to_odp_port(dsp->ofport->ofp_port) == odp_port) {
+ if (dsp->odp_port == odp_port) {
return dsp;
}
}
sflow_agent_get_counters);
sfl_poller_set_sFlowCpInterval(poller, ds->options->polling_interval);
sfl_poller_set_sFlowCpReceiver(poller, RECEIVER_INDEX);
- sfl_poller_set_bridgePort(poller,
- ofp_port_to_odp_port(dsp->ofport->ofp_port));
+ sfl_poller_set_bridgePort(poller, dsp->odp_port);
}
static void
}
void
-dpif_sflow_add_port(struct dpif_sflow *ds, struct ofport *ofport)
+dpif_sflow_add_port(struct dpif_sflow *ds, struct ofport *ofport,
+ uint32_t odp_port)
{
struct dpif_sflow_port *dsp;
- uint32_t odp_port = ofp_port_to_odp_port(ofport->ofp_port);
uint32_t ifindex;
dpif_sflow_del_port(ds, odp_port);
ifindex = (ds->sflow_agent->subId << 16) + odp_port;
}
dsp->ofport = ofport;
+ dsp->odp_port = odp_port;
SFL_DS_SET(dsp->dsi, 0, ifindex, 0);
hmap_insert(&ds->ports, &dsp->hmap_node, hash_int(odp_port, 0));
void
dpif_sflow_received(struct dpif_sflow *ds, struct ofpbuf *packet,
- const struct flow *flow,
+ const struct flow *flow, uint32_t odp_in_port,
const union user_action_cookie *cookie)
{
SFL_FLOW_SAMPLE_TYPE fs;
/* Build a flow sample */
memset(&fs, 0, sizeof fs);
- in_dsp = dpif_sflow_find_port(ds, ofp_port_to_odp_port(flow->in_port));
+ in_dsp = dpif_sflow_find_port(ds, odp_in_port);
if (!in_dsp) {
return;
}
void dpif_sflow_clear(struct dpif_sflow *);
bool dpif_sflow_is_enabled(const struct dpif_sflow *);
-void dpif_sflow_add_port(struct dpif_sflow *ds, struct ofport *ofport);
+void dpif_sflow_add_port(struct dpif_sflow *ds, struct ofport *ofport,
+ uint32_t odp_port);
void dpif_sflow_del_port(struct dpif_sflow *, uint32_t odp_port);
void dpif_sflow_run(struct dpif_sflow *);
void dpif_sflow_received(struct dpif_sflow *,
struct ofpbuf *,
const struct flow *,
+ uint32_t odp_port,
const union user_action_cookie *);
int dpif_sflow_odp_port_to_ifindex(const struct dpif_sflow *, uint32_t);
static bool facet_is_controller_flow(struct facet *);
struct ofport_dpif {
+ struct hmap_node odp_port_node; /* In ofproto-dpif's "odp_to_ofport_map". */
struct ofport up;
uint32_t odp_port;
static void vsp_remove(struct ofport_dpif *);
static void vsp_add(struct ofport_dpif *, uint16_t realdev_ofp_port, int vid);
+static uint32_t ofp_port_to_odp_port(const struct ofproto_dpif *,
+ uint16_t ofp_port);
+static uint16_t odp_port_to_ofp_port(const struct ofproto_dpif *,
+ uint32_t odp_port);
+
static struct ofport_dpif *
ofport_dpif_cast(const struct ofport *ofport)
{
/* VLAN splinters. */
struct hmap realdev_vid_map; /* (realdev,vid) -> vlandev. */
struct hmap vlandev_map; /* vlandev -> (realdev,vid). */
+
+ /* ODP port to ofp_port mapping. */
+ struct hmap odp_to_ofport_map;
};
/* Defer flow mod completion until "ovs-appctl ofproto/unclog"? (Useful only
hmap_init(&ofproto->vlandev_map);
hmap_init(&ofproto->realdev_vid_map);
+ hmap_init(&ofproto->odp_to_ofport_map);
+
hmap_insert(&all_ofproto_dpifs, &ofproto->all_ofproto_dpifs_node,
hash_string(ofproto->up.name, 0));
memset(&ofproto->stats, 0, sizeof ofproto->stats);
hmap_destroy(&ofproto->vlandev_map);
hmap_destroy(&ofproto->realdev_vid_map);
+ hmap_destroy(&ofproto->odp_to_ofport_map);
+
dpif_close(ofproto->dpif);
}
{
struct ofport_dpif *port = ofport_dpif_cast(port_);
struct ofproto_dpif *ofproto = ofproto_dpif_cast(port->up.ofproto);
+ struct dpif_port dpif_port;
+ int error;
ofproto->need_revalidate = REV_RECONFIGURE;
- port->odp_port = ofp_port_to_odp_port(port->up.ofp_port);
port->bundle = NULL;
port->cfm = NULL;
port->tag = tag_create_random();
port->vlandev_vid = 0;
port->carrier_seq = netdev_get_carrier_resets(port->up.netdev);
+ error = dpif_port_query_by_name(ofproto->dpif,
+ netdev_get_name(port->up.netdev),
+ &dpif_port);
+ if (error) {
+ return error;
+ }
+
+ port->odp_port = dpif_port.port_no;
+
+ /* Sanity-check that a mapping doesn't already exist. This
+ * shouldn't happen. */
+ if (odp_port_to_ofp_port(ofproto, port->odp_port) != OFPP_NONE) {
+ VLOG_ERR("port %s already has an OpenFlow port number\n",
+ dpif_port.name);
+ return EBUSY;
+ }
+
+ hmap_insert(&ofproto->odp_to_ofport_map, &port->odp_port_node,
+ hash_int(port->odp_port, 0));
+
if (ofproto->sflow) {
- dpif_sflow_add_port(ofproto->sflow, port_);
+ dpif_sflow_add_port(ofproto->sflow, port_, port->odp_port);
}
return 0;
struct ofport_dpif *port = ofport_dpif_cast(port_);
struct ofproto_dpif *ofproto = ofproto_dpif_cast(port->up.ofproto);
+ hmap_remove(&ofproto->odp_to_ofport_map, &port->odp_port_node);
ofproto->need_revalidate = REV_RECONFIGURE;
bundle_remove(port_);
set_cfm(port_, NULL);
ds = ofproto->sflow = dpif_sflow_create(ofproto->dpif);
HMAP_FOR_EACH (ofport, up.hmap_node, &ofproto->up.ports) {
- dpif_sflow_add_port(ds, &ofport->up);
+ dpif_sflow_add_port(ds, &ofport->up, ofport->odp_port);
}
ofproto->need_revalidate = REV_RECONFIGURE;
}
static struct ofport_dpif *
get_odp_port(const struct ofproto_dpif *ofproto, uint32_t odp_port)
{
- return get_ofp_port(ofproto, odp_port_to_ofp_port(odp_port));
+ return get_ofp_port(ofproto, odp_port_to_ofp_port(ofproto, odp_port));
}
static void
-ofproto_port_from_dpif_port(struct ofproto_port *ofproto_port,
+ofproto_port_from_dpif_port(struct ofproto_dpif *ofproto,
+ struct ofproto_port *ofproto_port,
struct dpif_port *dpif_port)
{
ofproto_port->name = dpif_port->name;
ofproto_port->type = dpif_port->type;
- ofproto_port->ofp_port = odp_port_to_ofp_port(dpif_port->port_no);
+ ofproto_port->ofp_port = odp_port_to_ofp_port(ofproto, dpif_port->port_no);
}
static void
error = dpif_port_query_by_name(ofproto->dpif, devname, &dpif_port);
if (!error) {
- ofproto_port_from_dpif_port(ofproto_port, &dpif_port);
+ ofproto_port_from_dpif_port(ofproto, ofproto_port, &dpif_port);
}
return error;
}
static int
-port_add(struct ofproto *ofproto_, struct netdev *netdev, uint16_t *ofp_portp)
+port_add(struct ofproto *ofproto_, struct netdev *netdev)
{
struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
- uint32_t odp_port = *ofp_portp != OFPP_NONE ? *ofp_portp : UINT32_MAX;
- int error;
+ uint32_t odp_port = UINT32_MAX;
- error = dpif_port_add(ofproto->dpif, netdev, &odp_port);
- if (!error) {
- *ofp_portp = odp_port_to_ofp_port(odp_port);
- }
- return error;
+ return dpif_port_add(ofproto->dpif, netdev, &odp_port);
}
static int
port_del(struct ofproto *ofproto_, uint16_t ofp_port)
{
struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
- int error;
+ uint32_t odp_port = ofp_port_to_odp_port(ofproto, ofp_port);
+ int error = 0;
- error = dpif_port_del(ofproto->dpif, ofp_port_to_odp_port(ofp_port));
+ if (odp_port != OFPP_NONE) {
+ error = dpif_port_del(ofproto->dpif, odp_port);
+ }
if (!error) {
struct ofport_dpif *ofport = get_ofp_port(ofproto, ofp_port);
if (ofport) {
port_dump_next(const struct ofproto *ofproto_ OVS_UNUSED, void *state_,
struct ofproto_port *port)
{
+ struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
struct port_dump_state *state = state_;
struct dpif_port dpif_port;
if (dpif_port_dump_next(&state->dump, &dpif_port)) {
- ofproto_port_from_dpif_port(port, &dpif_port);
+ ofproto_port_from_dpif_port(ofproto, port, &dpif_port);
return 0;
} else {
int error = dpif_port_dump_done(&state->dump);
enum odp_key_fitness fitness;
fitness = odp_flow_key_to_flow(key, key_len, flow);
- flow->in_port = odp_port_to_ofp_port(flow->in_port);
+ flow->in_port = odp_port_to_ofp_port(ofproto, flow->in_port);
if (fitness == ODP_FIT_ERROR) {
return fitness;
}
enum odp_key_fitness fitness;
ovs_be16 initial_tci;
struct flow flow;
+ uint32_t odp_in_port;
fitness = ofproto_dpif_extract_flow_key(ofproto, upcall->key,
upcall->key_len, &flow,
}
memcpy(&cookie, &upcall->userdata, sizeof(cookie));
- dpif_sflow_received(ofproto->sflow, upcall->packet, &flow, &cookie);
+ odp_in_port = ofp_port_to_odp_port(ofproto, flow.in_port);
+ dpif_sflow_received(ofproto->sflow, upcall->packet, &flow,
+ odp_in_port, &cookie);
}
static int
int error;
ofpbuf_use_stack(&key, &keybuf, sizeof keybuf);
- odp_flow_key_from_flow(&key, flow, ofp_port_to_odp_port(flow->in_port));
+ odp_flow_key_from_flow(&key, flow,
+ ofp_port_to_odp_port(ofproto, flow->in_port));
error = dpif_execute(ofproto->dpif, key.data, key.size,
odp_actions, actions_len, packet);
struct flow flow;
fitness = odp_flow_key_to_flow(key, key_len, &flow);
- flow.in_port = odp_port_to_ofp_port(flow.in_port);
+ flow.in_port = odp_port_to_ofp_port(ofproto, flow.in_port);
if (fitness == ODP_FIT_ERROR) {
return NULL;
}
subfacet_get_key(struct subfacet *subfacet, struct odputil_keybuf *keybuf,
struct ofpbuf *key)
{
+
if (!subfacet->key) {
+ struct ofproto_dpif *ofproto;
struct flow *flow = &subfacet->facet->flow;
ofpbuf_use_stack(key, keybuf, sizeof *keybuf);
- odp_flow_key_from_flow(key, flow, ofp_port_to_odp_port(flow->in_port));
+ ofproto = ofproto_dpif_cast(subfacet->facet->rule->up.ofproto);
+ odp_flow_key_from_flow(key, flow,
+ ofp_port_to_odp_port(ofproto, flow->in_port));
} else {
ofpbuf_use_const(key, subfacet->key, subfacet->key_len);
}
}
ofpbuf_use_stack(&key, &keybuf, sizeof keybuf);
- odp_flow_key_from_flow(&key, &flow, ofp_port_to_odp_port(flow.in_port));
+ odp_flow_key_from_flow(&key, &flow,
+ ofp_port_to_odp_port(ofproto, flow.in_port));
ofpbuf_init(&odp_actions, 32);
compose_sflow_action(ofproto, &odp_actions, &flow, odp_port);
uint32_t pid;
pid = dpif_port_get_pid(ofproto->dpif,
- ofp_port_to_odp_port(flow->in_port));
+ ofp_port_to_odp_port(ofproto, flow->in_port));
return odp_put_userspace_action(pid, cookie, odp_actions);
}
bool check_stp)
{
const struct ofport_dpif *ofport = get_ofp_port(ctx->ofproto, ofp_port);
- uint32_t odp_port = ofp_port_to_odp_port(ofp_port);
+ uint32_t odp_port = ofp_port_to_odp_port(ctx->ofproto, ofp_port);
ovs_be16 flow_vlan_tci = ctx->flow.vlan_tci;
uint8_t flow_nw_tos = ctx->flow.nw_tos;
uint16_t out_port;
struct ofpbuf odp_actions;
ofpbuf_use_stack(&key, &keybuf, sizeof keybuf);
- odp_flow_key_from_flow(&key, flow, ofp_port_to_odp_port(flow->in_port));
+ odp_flow_key_from_flow(&key, flow,
+ ofp_port_to_odp_port(ofproto, flow->in_port));
dpif_flow_stats_extract(flow, packet, time_msec(), &stats);
uint32_t realdev_odp_port, ovs_be16 vlan_tci)
{
if (!hmap_is_empty(&ofproto->realdev_vid_map)) {
- uint16_t realdev_ofp_port = odp_port_to_ofp_port(realdev_odp_port);
+ uint16_t realdev_ofp_port;
int vid = vlan_tci_to_vid(vlan_tci);
const struct vlan_splinter *vsp;
+ realdev_ofp_port = odp_port_to_ofp_port(ofproto, realdev_odp_port);
HMAP_FOR_EACH_WITH_HASH (vsp, realdev_vid_node,
hash_realdev_vid(realdev_ofp_port, vid),
&ofproto->realdev_vid_map) {
if (vsp->realdev_ofp_port == realdev_ofp_port
&& vsp->vid == vid) {
- return ofp_port_to_odp_port(vsp->vlandev_ofp_port);
+ return ofp_port_to_odp_port(ofproto, vsp->vlandev_ofp_port);
}
}
}
VLOG_ERR("duplicate vlan device record");
}
}
-\f
+
+static uint32_t
+ofp_port_to_odp_port(const struct ofproto_dpif *ofproto, uint16_t ofp_port)
+{
+ const struct ofport_dpif *ofport = get_ofp_port(ofproto, ofp_port);
+ return ofport ? ofport->odp_port : OVSP_NONE;
+}
+
+static uint16_t
+odp_port_to_ofp_port(const struct ofproto_dpif *ofproto, uint32_t odp_port)
+{
+ struct ofport_dpif *port;
+
+ HMAP_FOR_EACH_IN_BUCKET (port, odp_port_node,
+ hash_int(odp_port, 0),
+ &ofproto->odp_to_ofport_map) {
+ if (port->odp_port == odp_port) {
+ return port->up.ofp_port;
+ }
+ }
+
+ return OFPP_NONE;
+}
+
const struct ofproto_class ofproto_dpif_class = {
init,
enumerate_types,
#include "ofp-errors.h"
#include "ofp-util.h"
#include "shash.h"
+#include "simap.h"
#include "timeval.h"
struct match;
struct ofpact;
struct ofputil_flow_mod;
-struct simap;
/* An OpenFlow switch.
*
/* Datapath. */
struct hmap ports; /* Contains "struct ofport"s. */
struct shash port_by_name;
+ unsigned long *ofp_port_ids;/* Bitmap of used OpenFlow port numbers. */
+ struct simap ofp_requests; /* OpenFlow port number requests. */
+ uint16_t alloc_port_no; /* Last allocated OpenFlow port number. */
uint16_t max_ports; /* Max possible OpenFlow port num, plus one. */
/* Flow tables. */
/* Life-cycle functions for a "struct ofport" (see "Life Cycle" above).
*
* ->port_construct() should not modify any base members of the ofport.
+ * An ofproto implementation should use the 'ofp_port' member of
+ * "struct ofport" as the OpenFlow port number.
*
* ofports are managed by the base ofproto code. The ofproto
* implementation should only create and destroy them in response to calls
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'. 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.
+ /* Attempts to add 'netdev' as a port on 'ofproto'. Returns 0 if
+ * successful, otherwise a positive errno value. The caller should
+ * inform the implementation of the OpenFlow port through the
+ * ->port_construct() method.
*
* 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
* convenient. */
- int (*port_add)(struct ofproto *ofproto, struct netdev *netdev,
- uint16_t *ofp_portp);
+ int (*port_add)(struct ofproto *ofproto, struct netdev *netdev);
/* Deletes port number 'ofp_port' from the datapath for 'ofproto'. Returns
* 0 if successful, otherwise a positive errno value.
/* Map from datapath name to struct ofproto, for use by unixctl commands. */
static struct hmap all_ofprotos = HMAP_INITIALIZER(&all_ofprotos);
+/* Initial mappings of port to OpenFlow number mappings. */
+static struct shash init_ofp_ports = SHASH_INITIALIZER(&init_ofp_ports);
+
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
/* Must be called to initialize the ofproto library.
void
ofproto_init(const struct shash *iface_hints)
{
+ struct shash_node *node;
size_t i;
ofproto_class_register(&ofproto_dpif_class);
+ /* Make a local copy, since we don't own 'iface_hints' elements. */
+ SHASH_FOR_EACH(node, iface_hints) {
+ const struct iface_hint *orig_hint = node->data;
+ struct iface_hint *new_hint = xmalloc(sizeof *new_hint);
+ const char *br_type = ofproto_normalize_type(orig_hint->br_type);
+
+ new_hint->br_name = xstrdup(orig_hint->br_name);
+ new_hint->br_type = xstrdup(br_type);
+ new_hint->ofp_port = orig_hint->ofp_port;
+
+ shash_add(&init_ofp_ports, node->name, new_hint);
+ }
+
for (i = 0; i < n_ofproto_classes; i++) {
- ofproto_classes[i]->init(iface_hints);
+ ofproto_classes[i]->init(&init_ofp_ports);
}
}
ofproto->frag_handling = OFPC_FRAG_NORMAL;
hmap_init(&ofproto->ports);
shash_init(&ofproto->port_by_name);
+ simap_init(&ofproto->ofp_requests);
ofproto->max_ports = OFPP_MAX;
ofproto->tables = NULL;
ofproto->n_tables = 0;
return error;
}
+ /* The "max_ports" member should have been set by ->construct(ofproto).
+ * Port 0 is not a valid OpenFlow port, so mark that as unavailable. */
+ ofproto->ofp_port_ids = bitmap_allocate(ofproto->max_ports);
+ bitmap_set1(ofproto->ofp_port_ids, 0);
+
assert(ofproto->n_tables);
ofproto->datapath_id = pick_datapath_id(ofproto);
free(ofproto->dp_desc);
hmap_destroy(&ofproto->ports);
shash_destroy(&ofproto->port_by_name);
+ bitmap_free(ofproto->ofp_port_ids);
+ simap_destroy(&ofproto->ofp_requests);
OFPROTO_FOR_EACH_TABLE (table, ofproto) {
oftable_destroy(table);
uint16_t ofp_port = ofp_portp ? *ofp_portp : OFPP_NONE;
int error;
- error = ofproto->ofproto_class->port_add(ofproto, netdev, &ofp_port);
+ error = ofproto->ofproto_class->port_add(ofproto, netdev);
if (!error) {
- update_port(ofproto, netdev_get_name(netdev));
+ const char *netdev_name = netdev_get_name(netdev);
+
+ simap_put(&ofproto->ofp_requests, netdev_name, ofp_port);
+ update_port(ofproto, netdev_name);
}
if (ofp_portp) {
- *ofp_portp = error ? OFPP_NONE : ofp_port;
+ struct ofproto_port ofproto_port;
+
+ ofproto_port_query_by_name(ofproto, netdev_get_name(netdev),
+ &ofproto_port);
+ *ofp_portp = error ? OFPP_NONE : ofproto_port.ofp_port;
+ ofproto_port_destroy(&ofproto_port);
}
return error;
}
{
struct ofport *ofport = ofproto_get_port(ofproto, ofp_port);
const char *name = ofport ? netdev_get_name(ofport->netdev) : "<unknown>";
+ struct simap_node *ofp_request_node;
int error;
+ ofp_request_node = simap_find(&ofproto->ofp_requests, name);
+ if (ofp_request_node) {
+ simap_delete(&ofproto->ofp_requests, ofp_request_node);
+ }
+
error = ofproto->ofproto_class->port_del(ofproto, ofp_port);
if (!error && ofport) {
/* 'name' is the netdev's name and update_port() is going to close the
sset_destroy(&devnames);
}
+static uint16_t
+alloc_ofp_port(struct ofproto *ofproto, const char *netdev_name)
+{
+ uint16_t ofp_port;
+
+ ofp_port = simap_get(&ofproto->ofp_requests, netdev_name);
+ ofp_port = ofp_port ? ofp_port : OFPP_NONE;
+
+ if (ofp_port >= ofproto->max_ports
+ || bitmap_is_set(ofproto->ofp_port_ids, ofp_port)) {
+ bool retry = ofproto->alloc_port_no ? true : false;
+
+ /* Search for a free OpenFlow port number. We try not to
+ * immediately reuse them to prevent problems due to old
+ * flows. */
+ while (ofp_port >= ofproto->max_ports) {
+ for (ofproto->alloc_port_no++;
+ ofproto->alloc_port_no < ofproto->max_ports; ) {
+ if (!bitmap_is_set(ofproto->ofp_port_ids,
+ ofproto->alloc_port_no)) {
+ ofp_port = ofproto->alloc_port_no;
+ break;
+ }
+ }
+ if (ofproto->alloc_port_no >= ofproto->max_ports) {
+ if (retry) {
+ ofproto->alloc_port_no = 0;
+ retry = false;
+ } else {
+ return OFPP_NONE;
+ }
+ }
+ }
+ }
+
+ bitmap_set1(ofproto->ofp_port_ids, ofp_port);
+ return ofp_port;
+}
+
+static void
+dealloc_ofp_port(const struct ofproto *ofproto, uint16_t ofp_port)
+{
+ bitmap_set0(ofproto->ofp_port_ids, ofp_port);
+}
+
/* Opens and returns a netdev for 'ofproto_port' in 'ofproto', or a null
* pointer if the netdev cannot be opened. On success, also fills in
* 'opp'. */
static struct netdev *
-ofport_open(const struct ofproto *ofproto,
- const struct ofproto_port *ofproto_port,
+ofport_open(struct ofproto *ofproto,
+ struct ofproto_port *ofproto_port,
struct ofputil_phy_port *pp)
{
enum netdev_flags flags;
return NULL;
}
+ if (ofproto_port->ofp_port == OFPP_NONE) {
+ if (!strcmp(ofproto->name, ofproto_port->name)) {
+ ofproto_port->ofp_port = OFPP_LOCAL;
+ } else {
+ ofproto_port->ofp_port = alloc_ofp_port(ofproto,
+ ofproto_port->name);
+ }
+ }
pp->port_no = ofproto_port->ofp_port;
netdev_get_etheraddr(netdev, pp->hw_addr);
ovs_strlcpy(pp->name, ofproto_port->name, sizeof pp->name);
ofport_destroy(struct ofport *port)
{
if (port) {
+ dealloc_ofp_port(port->ofproto, port->ofp_port);
port->ofproto->ofproto_class->port_destruct(port);
ofport_destroy__(port);
}
{
struct ofproto_port_dump dump;
struct ofproto_port ofproto_port;
+ struct shash_node *node, *next;
OFPROTO_PORT_FOR_EACH (&ofproto_port, &dump, p) {
- uint16_t ofp_port = ofproto_port.ofp_port;
- if (ofproto_get_port(p, ofp_port)) {
- VLOG_WARN_RL(&rl, "%s: ignoring duplicate port %"PRIu16" "
- "in datapath", p->name, ofp_port);
- } else if (shash_find(&p->port_by_name, ofproto_port.name)) {
+ const char *name = ofproto_port.name;
+
+ if (shash_find(&p->port_by_name, name)) {
VLOG_WARN_RL(&rl, "%s: ignoring duplicate device %s in datapath",
- p->name, ofproto_port.name);
+ p->name, name);
} else {
struct ofputil_phy_port pp;
struct netdev *netdev;
+ /* Check if an OpenFlow port number had been requested. */
+ node = shash_find(&init_ofp_ports, name);
+ if (node) {
+ const struct iface_hint *iface_hint = node->data;
+ simap_put(&p->ofp_requests, name, iface_hint->ofp_port);
+ }
+
netdev = ofport_open(p, &ofproto_port, &pp);
if (netdev) {
ofport_install(p, netdev, &pp);
}
}
+ SHASH_FOR_EACH_SAFE(node, next, &init_ofp_ports) {
+ const struct iface_hint *iface_hint = node->data;
+
+ if (!strcmp(iface_hint->br_name, p->name)) {
+ free(iface_hint->br_name);
+ free(iface_hint->br_type);
+ shash_delete(&init_ofp_ports, node);
+ }
+ }
+
return 0;
}
# This is a totally artificial use of the "learn" action. The only purpose
# is to check that specifying fin_idle_timeout or fin_hard_timeout causes
# a corresponding fin_timeout action to end up in the learned flows.
-OVS_VSWITCHD_START
+OVS_VSWITCHD_START(
+ [add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1])
AT_CHECK([[ovs-ofctl add-flow br0 'actions=learn(fin_hard_timeout=10, fin_idle_timeout=5, NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[], output:NXM_OF_IN_PORT[])']])
AT_CHECK([ovs-appctl ofproto/trace br0 'in_port(1),eth(src=50:54:00:00:00:05,dst=ff:ff:ff:ff:ff:ff),eth_type(0x0806),arp(sip=192.168.0.1,tip=192.168.0.2,op=1,sha=50:54:00:00:00:05,tha=00:00:00:00:00:00)' -generate], [0], [ignore])
AT_CHECK([ovs-ofctl dump-flows br0 table=1 | ofctl_strip], [0],
fi
# OFPT_PORT_STATUS, OFPPR_ADD
- ovs-vsctl add-port br0 test -- set Interface test type=dummy
+ ovs-vsctl add-port br0 test -- set Interface test type=dummy ofport_request=1
if test X"$1" = X"OFPPR_ADD"; then shift;
echo >>expout "OFPT_PORT_STATUS: ADD: 1(test): addr:aa:55:aa:55:00:0x
config: PORT_DOWN