In a future commit, we will make multiple bridges share a single backing datapath. Our simple mapping from datapath to OpenFlow port numbers won't work, since we'll want the same OpenFlow port numbers on different bridges. For example, the OFPP_LOCAL port must be the same on all bridges, but will have to be a different datapath port on the converged datapath.
This commit makes it the responsibility of ofproto to assign the OpenFlow port numbers instead of doing a simple translation from the datapath ones. Signed-off-by: Justin Pettit <jpet...@nicira.com> --- NEWS | 3 + lib/odp-util.h | 26 --------- ofproto/ofproto-dpif-sflow.c | 15 +++--- ofproto/ofproto-dpif-sflow.h | 4 +- ofproto/ofproto-dpif.c | 123 ++++++++++++++++++++++++++++++----------- ofproto/ofproto-provider.h | 17 +++--- ofproto/ofproto.c | 123 ++++++++++++++++++++++++++++++++++++++---- 7 files changed, 225 insertions(+), 86 deletions(-) diff --git a/NEWS b/NEWS index f9d4ceb..99e239a 100644 --- a/NEWS +++ b/NEWS @@ -29,6 +29,9 @@ post-v1.8.0 - 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. diff --git a/lib/odp-util.h b/lib/odp-util.h index 8aeffdd..68fa850 100644 --- a/lib/odp-util.h +++ b/lib/odp-util.h @@ -34,32 +34,6 @@ struct simap; #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: - 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, diff --git a/ofproto/ofproto-dpif-sflow.c b/ofproto/ofproto-dpif-sflow.c index 999e55b..aacb3e8 100644 --- a/ofproto/ofproto-dpif-sflow.c +++ b/ofproto/ofproto-dpif-sflow.c @@ -46,6 +46,7 @@ struct dpif_sflow_port { 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 { @@ -148,7 +149,7 @@ dpif_sflow_find_port(const struct dpif_sflow *ds, uint32_t odp_port) 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; } } @@ -339,8 +340,7 @@ dpif_sflow_add_poller(struct dpif_sflow *ds, struct dpif_sflow_port *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 @@ -353,10 +353,10 @@ dpif_sflow_add_sampler(struct dpif_sflow *ds, struct dpif_sflow_port *dsp) } 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); @@ -368,6 +368,7 @@ dpif_sflow_add_port(struct dpif_sflow *ds, struct ofport *ofport) 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)); @@ -491,7 +492,7 @@ dpif_sflow_odp_port_to_ifindex(const struct dpif_sflow *ds, 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; @@ -507,7 +508,7 @@ dpif_sflow_received(struct dpif_sflow *ds, struct ofpbuf *packet, /* 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; } diff --git a/ofproto/ofproto-dpif-sflow.h b/ofproto/ofproto-dpif-sflow.h index 3555bc5..c7dc872 100644 --- a/ofproto/ofproto-dpif-sflow.h +++ b/ofproto/ofproto-dpif-sflow.h @@ -37,7 +37,8 @@ void dpif_sflow_set_options(struct dpif_sflow *, 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 *); @@ -46,6 +47,7 @@ void dpif_sflow_wait(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); diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index dc6cda9..ab9e56f 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -485,6 +485,7 @@ static void facet_account(struct facet *); static bool facet_is_controller_flow(struct facet *); struct ofport_dpif { + struct hmap_node hmap_node; /* In ofproto-dpif's "odp_to_ofport_map". */ struct ofport up; uint32_t odp_port; @@ -543,7 +544,12 @@ static bool vsp_adjust_flow(const struct ofproto_dpif *, struct flow *); 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_in_port(uint16_t ofp_port); +static uint32_t ofp_port_to_odp_port(const struct ofproto_dpif *, + uint16_t ofp_port); +static uint32_t ofp_port_to_odp_in_port(const struct ofproto_dpif *ofproto, + 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) @@ -643,6 +649,9 @@ struct ofproto_dpif { /* VLAN splinters. */ struct hmap realdev_vid_map; /* (realdev,vid) -> vlandev. */ struct hmap vlandev_map; /* vlandev -> (realdev,vid). */ + + /* ODP port to ofport mapping. */ + struct hmap odp_to_ofport_map; }; /* Defer flow mod completion until "ovs-appctl ofproto/unclog"? (Useful only @@ -811,6 +820,8 @@ construct(struct ofproto *ofproto_) 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); @@ -935,6 +946,8 @@ destruct(struct ofproto *ofproto_) hmap_destroy(&ofproto->vlandev_map); hmap_destroy(&ofproto->realdev_vid_map); + hmap_destroy(&ofproto->odp_to_ofport_map); + dpif_close(ofproto->dpif); } @@ -1197,9 +1210,10 @@ port_construct(struct ofport *port_) { 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(); @@ -1211,8 +1225,19 @@ port_construct(struct ofport *port_) 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; + hmap_insert(&ofproto->odp_to_ofport_map, &port->hmap_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; @@ -1224,6 +1249,7 @@ port_destruct(struct ofport *port_) 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->hmap_node); ofproto->need_revalidate = REV_RECONFIGURE; bundle_remove(port_); set_cfm(port_, NULL); @@ -1276,7 +1302,7 @@ set_sflow(struct ofproto *ofproto_, 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; } @@ -2448,16 +2474,17 @@ get_ofp_port(const struct ofproto_dpif *ofproto, uint16_t ofp_port) 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 @@ -2530,32 +2557,28 @@ port_query_by_name(const struct ofproto *ofproto_, const char *devname, 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_); + uint32_t odp_port = ofp_port_to_odp_port(ofproto, ofp_port); int error; - error = dpif_port_del(ofproto->dpif, ofp_port_to_odp_port(ofp_port)); + error = dpif_port_del(ofproto->dpif, odp_port); if (!error) { struct ofport_dpif *ofport = get_ofp_port(ofproto, ofp_port); if (ofport) { @@ -2647,11 +2670,12 @@ static int 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); @@ -3053,7 +3077,7 @@ ofproto_dpif_extract_flow_key(const struct ofproto_dpif *ofproto, 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; } @@ -3226,6 +3250,7 @@ handle_sflow_upcall(struct ofproto_dpif *ofproto, 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, @@ -3235,7 +3260,9 @@ handle_sflow_upcall(struct ofproto_dpif *ofproto, } 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 @@ -3686,7 +3713,8 @@ execute_odp_actions(struct ofproto_dpif *ofproto, const struct flow *flow, int error; ofpbuf_use_stack(&key, &keybuf, sizeof keybuf); - odp_flow_key_from_flow(&key, flow, ofp_port_to_odp_in_port(flow->in_port)); + odp_flow_key_from_flow(&key, flow, + ofp_port_to_odp_in_port(ofproto, flow->in_port)); error = dpif_execute(ofproto->dpif, key.data, key.size, odp_actions, actions_len, packet); @@ -4335,7 +4363,7 @@ subfacet_find(struct ofproto_dpif *ofproto, 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; } @@ -4383,12 +4411,15 @@ static void 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); + ofproto = ofproto_dpif_cast(subfacet->facet->rule->up.ofproto); odp_flow_key_from_flow(key, flow, - ofp_port_to_odp_in_port(flow->in_port)); + ofp_port_to_odp_in_port(ofproto, flow->in_port)); } else { ofpbuf_use_const(key, subfacet->key, subfacet->key_len); } @@ -4786,7 +4817,8 @@ send_packet(const struct ofport_dpif *ofport, struct ofpbuf *packet) } ofpbuf_use_stack(&key, &keybuf, sizeof keybuf); - odp_flow_key_from_flow(&key, &flow, ofp_port_to_odp_in_port(flow.in_port)); + odp_flow_key_from_flow(&key, &flow, + ofp_port_to_odp_in_port(ofproto, flow.in_port)); ofpbuf_init(&odp_actions, 32); compose_sflow_action(ofproto, &odp_actions, &flow, odp_port); @@ -4855,7 +4887,7 @@ put_userspace_action(const struct ofproto_dpif *ofproto, 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); } @@ -4963,7 +4995,7 @@ compose_output_action__(struct action_xlate_ctx *ctx, uint16_t ofp_port, 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; @@ -6478,7 +6510,8 @@ packet_out(struct ofproto *ofproto_, struct ofpbuf *packet, struct ofpbuf odp_actions; ofpbuf_use_stack(&key, &keybuf, sizeof keybuf); - odp_flow_key_from_flow(&key, flow, ofp_port_to_odp_in_port(flow->in_port)); + odp_flow_key_from_flow(&key, flow, + ofp_port_to_odp_in_port(ofproto, flow->in_port)); dpif_flow_stats_extract(flow, packet, time_msec(), &stats); @@ -6796,7 +6829,7 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[], const char *tun_id_s = argv[3]; const char *in_port_s = argv[4]; const char *packet_s = argv[5]; - uint32_t in_port = ofp_port_to_odp_port(atoi(in_port_s)); + uint32_t in_port = ofp_port_to_odp_port(ofproto, atoi(in_port_s)); ovs_be64 tun_id = htonll(strtoull(tun_id_s, NULL, 0)); uint32_t priority = atoi(priority_s); const char *msg; @@ -7072,16 +7105,17 @@ vsp_realdev_to_vlandev(const struct ofproto_dpif *ofproto, 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); } } } @@ -7196,15 +7230,38 @@ vsp_add(struct ofport_dpif *port, uint16_t realdev_ofp_port, int vid) VLOG_ERR("duplicate vlan device record"); } } - + +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 uint32_t -ofp_port_to_odp_in_port(uint16_t ofp_port) +ofp_port_to_odp_in_port(const struct ofproto_dpif *ofproto, uint16_t ofp_port) { if (ofp_port == OFPP_NONE || ofp_port == OFPP_CONTROLLER) { return OVSP_NONE; } - return ofp_port_to_odp_port(ofp_port); + return ofp_port_to_odp_port(ofproto, ofp_port); +} + +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, hmap_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 = { diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h index afcfe8d..d308428 100644 --- a/ofproto/ofproto-provider.h +++ b/ofproto/ofproto-provider.h @@ -62,6 +62,8 @@ struct ofproto { /* 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 shash ofp_requests; /* OpenFlow port number requests. */ uint16_t max_ports; /* Max possible OpenFlow port num, plus one. */ /* Flow tables. */ @@ -535,6 +537,8 @@ struct ofproto_class { /* 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 @@ -592,18 +596,15 @@ 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'. If 'ofp_portp' - * is non-null and '*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. diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index ae01c57..42467dd 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -221,6 +221,9 @@ static size_t allocated_ofproto_classes; /* 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. @@ -235,12 +238,26 @@ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); 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); } } @@ -397,6 +414,7 @@ ofproto_create(const char *datapath_name, const char *datapath_type, ofproto->frag_handling = OFPC_FRAG_NORMAL; hmap_init(&ofproto->ports); shash_init(&ofproto->port_by_name); + shash_init(&ofproto->ofp_requests); ofproto->max_ports = OFPP_MAX; ofproto->tables = NULL; ofproto->n_tables = 0; @@ -421,6 +439,11 @@ ofproto_create(const char *datapath_name, const char *datapath_type, 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); @@ -1015,6 +1038,8 @@ ofproto_destroy__(struct ofproto *ofproto) free(ofproto->dp_desc); hmap_destroy(&ofproto->ports); shash_destroy(&ofproto->port_by_name); + bitmap_free(ofproto->ofp_port_ids); + shash_destroy_free_data(&ofproto->ofp_requests); OFPROTO_FOR_EACH_TABLE (table, ofproto) { oftable_destroy(table); @@ -1367,12 +1392,22 @@ ofproto_port_add(struct ofproto *ofproto, struct netdev *netdev, 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)); + uint16_t *ofp_request = xmalloc(sizeof *ofp_request); + const char *netdev_name = netdev_get_name(netdev); + + *ofp_request = ofp_port; + shash_add(&ofproto->ofp_requests, netdev_name, ofp_request); + 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; } @@ -1403,8 +1438,14 @@ ofproto_port_del(struct ofproto *ofproto, uint16_t ofp_port) { struct ofport *ofport = ofproto_get_port(ofproto, ofp_port); const char *name = ofport ? netdev_get_name(ofport->netdev) : "<unknown>"; + uint16_t *ofp_request; int error; + ofp_request = shash_find_and_delete(&ofproto->ofp_requests, name); + if (ofp_request) { + free(ofp_request); + } + 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 @@ -1530,12 +1571,44 @@ reinit_ports(struct ofproto *p) sset_destroy(&devnames); } +static uint16_t +alloc_ofp_port(const struct ofproto *ofproto, const char *netdev_name) +{ + uint16_t *ofp_request; + uint16_t ofp_port; + + ofp_request = shash_find_data(&ofproto->ofp_requests, netdev_name); + ofp_port = ofp_request ? *ofp_request : OFPP_NONE; + + if (ofp_port >= ofproto->max_ports + || bitmap_is_set(ofproto->ofp_port_ids, ofp_port)) { + /* Search for a free OpenFlow port number. */ + for (ofp_port = 1; ofp_port < ofproto->max_ports; ofp_port++) { + if (!bitmap_is_set(ofproto->ofp_port_ids, ofp_port)) { + break; + } + } + if (ofp_port >= ofproto->max_ports) { + 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, + struct ofproto_port *ofproto_port, struct ofputil_phy_port *pp) { enum netdev_flags flags; @@ -1552,6 +1625,14 @@ ofport_open(const struct ofproto *ofproto, 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); @@ -1721,6 +1802,7 @@ static void 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); } @@ -1814,19 +1896,28 @@ init_ports(struct ofproto *p) { 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; + uint16_t *ofp_request = xmalloc(sizeof *ofp_request); + + *ofp_request = iface_hint->ofp_port; + shash_add(&p->ofp_requests, name, ofp_request); + } + netdev = ofport_open(p, &ofproto_port, &pp); if (netdev) { ofport_install(p, netdev, &pp); @@ -1834,6 +1925,16 @@ init_ports(struct ofproto *p) } } + 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; } -- 1.7.5.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev