X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=ofproto%2Fofproto.c;h=01b44e7f30c7028a17c9b897b1093ed2dbfe954c;hb=2ac6beddbf6a85299c449939a2086126f1f47dbc;hp=25a9db68c5ac5b74bc03ed4ab5ca4c4b810897cb;hpb=10d0a1d2a9be4c01e1b2b4e8fbd5c61d9b9e60cd;p=openvswitch diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 25a9db68..01b44e7f 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -24,9 +24,11 @@ #include #include #include +#include "autopath.h" #include "byte-order.h" #include "cfm.h" #include "classifier.h" +#include "connmgr.h" #include "coverage.h" #include "dpif.h" #include "dynamic-string.h" @@ -52,11 +54,13 @@ #include "pinsched.h" #include "pktbuf.h" #include "poll-loop.h" +#include "private.h" #include "rconn.h" #include "shash.h" +#include "sset.h" #include "stream-ssl.h" -#include "svec.h" #include "tag.h" +#include "timer.h" #include "timeval.h" #include "unaligned.h" #include "unixctl.h" @@ -79,7 +83,6 @@ COVERAGE_DEFINE(ofproto_flows_req); COVERAGE_DEFINE(ofproto_flush); COVERAGE_DEFINE(ofproto_invalidated); COVERAGE_DEFINE(ofproto_no_packet_in); -COVERAGE_DEFINE(ofproto_ofconn_stuck); COVERAGE_DEFINE(ofproto_ofp2odp); COVERAGE_DEFINE(ofproto_packet_in); COVERAGE_DEFINE(ofproto_packet_out); @@ -99,7 +102,7 @@ struct rule; struct ofport { struct hmap_node hmap_node; /* In struct ofproto's "ports" hmap. */ struct netdev *netdev; - struct ofp_phy_port opp; /* In host byte order. */ + struct ofp_phy_port opp; uint16_t odp_port; struct cfm *cfm; /* Connectivity Fault Management, if any. */ }; @@ -270,109 +273,13 @@ static void facet_update_stats(struct ofproto *, struct facet *, const struct dpif_flow_stats *); static void facet_push_stats(struct ofproto *, struct facet *); -/* ofproto supports two kinds of OpenFlow connections: - * - * - "Primary" connections to ordinary OpenFlow controllers. ofproto - * maintains persistent connections to these controllers and by default - * sends them asynchronous messages such as packet-ins. - * - * - "Service" connections, e.g. from ovs-ofctl. When these connections - * drop, it is the other side's responsibility to reconnect them if - * necessary. ofproto does not send them asynchronous messages by default. - * - * Currently, active (tcp, ssl, unix) connections are always "primary" - * connections and passive (ptcp, pssl, punix) connections are always "service" - * connections. There is no inherent reason for this, but it reflects the - * common case. - */ -enum ofconn_type { - OFCONN_PRIMARY, /* An ordinary OpenFlow controller. */ - OFCONN_SERVICE /* A service connection, e.g. "ovs-ofctl". */ -}; - -/* A listener for incoming OpenFlow "service" connections. */ -struct ofservice { - struct hmap_node node; /* In struct ofproto's "services" hmap. */ - struct pvconn *pvconn; /* OpenFlow connection listener. */ - - /* These are not used by ofservice directly. They are settings for - * accepted "struct ofconn"s from the pvconn. */ - int probe_interval; /* Max idle time before probing, in seconds. */ - int rate_limit; /* Max packet-in rate in packets per second. */ - int burst_limit; /* Limit on accumulating packet credits. */ -}; - -static struct ofservice *ofservice_lookup(struct ofproto *, - const char *target); -static int ofservice_create(struct ofproto *, - const struct ofproto_controller *); -static void ofservice_reconfigure(struct ofservice *, - const struct ofproto_controller *); -static void ofservice_destroy(struct ofproto *, struct ofservice *); - -/* An OpenFlow connection. */ -struct ofconn { - struct ofproto *ofproto; /* The ofproto that owns this connection. */ - struct list node; /* In struct ofproto's "all_conns" list. */ - struct rconn *rconn; /* OpenFlow connection. */ - enum ofconn_type type; /* Type. */ - enum nx_flow_format flow_format; /* Currently selected flow format. */ - - /* OFPT_PACKET_IN related data. */ - struct rconn_packet_counter *packet_in_counter; /* # queued on 'rconn'. */ -#define N_SCHEDULERS 2 - struct pinsched *schedulers[N_SCHEDULERS]; - struct pktbuf *pktbuf; /* OpenFlow packet buffers. */ - int miss_send_len; /* Bytes to send of buffered packets. */ - - /* Number of OpenFlow messages queued on 'rconn' as replies to OpenFlow - * requests, and the maximum number before we stop reading OpenFlow - * requests. */ -#define OFCONN_REPLY_MAX 100 - struct rconn_packet_counter *reply_counter; - - /* type == OFCONN_PRIMARY only. */ - enum nx_role role; /* Role. */ - struct hmap_node hmap_node; /* In struct ofproto's "controllers" map. */ - enum ofproto_band band; /* In-band or out-of-band? */ -}; - - -static struct ofconn *ofconn_create(struct ofproto *, struct rconn *, - enum ofconn_type); -static void ofconn_destroy(struct ofconn *); -static void ofconn_run(struct ofconn *); -static void ofconn_wait(struct ofconn *); - -static bool ofconn_receives_async_msgs(const struct ofconn *); -static char *ofconn_make_name(const struct ofproto *, const char *target); -static void ofconn_set_rate_limit(struct ofconn *, int rate, int burst); - -static struct ofproto *ofconn_get_ofproto(struct ofconn *); - -static enum nx_flow_format ofconn_get_flow_format(struct ofconn *); -static void ofconn_set_flow_format(struct ofconn *, enum nx_flow_format); - -static int ofconn_get_miss_send_len(const struct ofconn *); -static void ofconn_set_miss_send_len(struct ofconn *, int miss_send_len); - -static enum ofconn_type ofconn_get_type(const struct ofconn *); - -static enum nx_role ofconn_get_role(const struct ofconn *); -static void ofconn_set_role(struct ofconn *, enum nx_role); - -static int ofconn_pktbuf_retrieve(struct ofconn *, uint32_t id, - struct ofpbuf **bufferp, uint16_t *in_port); - - -static void queue_tx(struct ofpbuf *msg, const struct ofconn *ofconn, - struct rconn_packet_counter *counter); - static void send_packet_in(struct ofproto *, struct dpif_upcall *, const struct flow *, bool clone); -static void do_send_packet_in(struct ofpbuf *ofp_packet_in, void *ofconn); struct ofproto { + char *name; /* Datapath name. */ + struct hmap_node hmap_node; /* In global 'all_ofprotos' hmap. */ + /* Settings. */ uint64_t datapath_id; /* Datapath ID. */ uint64_t fallback_dpid; /* Datapath ID if no better choice found. */ @@ -390,20 +297,12 @@ struct ofproto { uint32_t max_ports; /* Configuration. */ - struct fail_open *fail_open; struct netflow *netflow; struct ofproto_sflow *sflow; - /* In-band control. */ - struct in_band *in_band; - long long int next_in_band_update; - struct sockaddr_in *extra_in_band_remotes; - size_t n_extra_remotes; - int in_band_queue; - /* Flow table. */ struct classifier cls; - long long int next_expiration; + struct timer next_expiration; /* Facets. */ struct hmap facets; @@ -411,14 +310,7 @@ struct ofproto { struct tag_set revalidate_set; /* OpenFlow connections. */ - struct hmap controllers; /* Controller "struct ofconn"s. */ - struct list all_conns; /* Contains "struct ofconn"s. */ - enum ofproto_fail_mode fail_mode; - - /* OpenFlow listeners. */ - struct hmap services; /* Contains "struct ofservice"s. */ - struct pvconn **snoops; - size_t n_snoops; + struct connmgr *connmgr; /* Hooks for ovs-vswitchd. */ const struct ofhooks *ofhooks; @@ -429,7 +321,7 @@ struct ofproto { }; /* Map from dpif name to struct ofproto, for use by unixctl commands. */ -static struct shash all_ofprotos = SHASH_INITIALIZER(&all_ofprotos); +static struct hmap all_ofprotos = HMAP_INITIALIZER(&all_ofprotos); static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); @@ -438,6 +330,7 @@ static const struct ofhooks default_ofhooks; static uint64_t pick_datapath_id(const struct ofproto *); static uint64_t pick_fallback_dpid(void); +static void ofproto_flush_flows__(struct ofproto *); static int ofproto_expire(struct ofproto *); static void flow_push_stats(struct ofproto *, const struct rule *, struct flow *, uint64_t packets, uint64_t bytes, @@ -459,6 +352,7 @@ ofproto_create(const char *datapath, const char *datapath_type, const struct ofhooks *ofhooks, void *aux, struct ofproto **ofprotop) { + char local_name[IF_NAMESIZE]; struct ofproto *p; struct dpif *dpif; int error; @@ -468,7 +362,7 @@ ofproto_create(const char *datapath, const char *datapath_type, ofproto_unixctl_init(); /* Connect to datapath and start listening for messages. */ - error = dpif_open(datapath, datapath_type, &dpif); + error = dpif_create_and_open(datapath, datapath_type, &dpif); if (error) { VLOG_ERR("failed to open datapath %s: %s", datapath, strerror(error)); return error; @@ -486,8 +380,18 @@ ofproto_create(const char *datapath, const char *datapath_type, dpif_flow_flush(dpif); dpif_recv_purge(dpif); + error = dpif_port_get_name(dpif, ODPP_LOCAL, + local_name, sizeof local_name); + if (error) { + VLOG_ERR("%s: cannot get name of datapath local port (%s)", + datapath, strerror(error)); + return error; + } + /* Initialize settings. */ p = xzalloc(sizeof *p); + p->name = xstrdup(dpif_name(dpif)); + hmap_insert(&all_ofprotos, &p->hmap_node, hash_string(p->name, 0)); p->fallback_dpid = pick_fallback_dpid(); p->datapath_id = p->fallback_dpid; p->mfr_desc = xstrdup(DEFAULT_MFR_DESC); @@ -504,30 +408,18 @@ ofproto_create(const char *datapath, const char *datapath_type, p->max_ports = dpif_get_max_ports(dpif); /* Initialize submodules. */ - p->fail_open = NULL; p->netflow = NULL; p->sflow = NULL; - /* Initialize in-band control. */ - p->in_band = NULL; - p->in_band_queue = -1; - /* Initialize flow table. */ classifier_init(&p->cls); - p->next_expiration = time_msec() + 1000; + timer_set_duration(&p->next_expiration, 1000); /* Initialize facet table. */ hmap_init(&p->facets); p->need_revalidate = false; tag_set_init(&p->revalidate_set); - /* Initialize OpenFlow connections. */ - list_init(&p->all_conns); - hmap_init(&p->controllers); - hmap_init(&p->services); - p->snoops = NULL; - p->n_snoops = 0; - /* Initialize hooks. */ if (ofhooks) { p->ofhooks = ofhooks; @@ -543,7 +435,8 @@ ofproto_create(const char *datapath, const char *datapath_type, p->datapath_id = pick_datapath_id(p); VLOG_INFO("using datapath ID %016"PRIx64, p->datapath_id); - shash_add_once(&all_ofprotos, dpif_name(p->dpif), p); + /* Initialize OpenFlow connections. */ + p->connmgr = connmgr_create(p, datapath, local_name); *ofprotop = p; return 0; @@ -563,212 +456,18 @@ ofproto_set_datapath_id(struct ofproto *p, uint64_t datapath_id) } } -/* Creates a new controller in 'ofproto'. Some of the settings are initially - * drawn from 'c', but update_controller() needs to be called later to finish - * the new ofconn's configuration. */ -static void -add_controller(struct ofproto *ofproto, const struct ofproto_controller *c) -{ - char *name = ofconn_make_name(ofproto, c->target); - struct ofconn *ofconn; - - ofconn = ofconn_create(ofproto, rconn_create(5, 8), OFCONN_PRIMARY); - ofconn->pktbuf = pktbuf_create(); - ofconn->miss_send_len = OFP_DEFAULT_MISS_SEND_LEN; - rconn_connect(ofconn->rconn, c->target, name); - hmap_insert(&ofproto->controllers, &ofconn->hmap_node, - hash_string(c->target, 0)); - - free(name); -} - -/* Reconfigures 'ofconn' to match 'c'. This function cannot update an ofconn's - * target (this is done by creating new ofconns and deleting old ones), but it - * can update the rest of an ofconn's settings. */ -static void -update_controller(struct ofconn *ofconn, const struct ofproto_controller *c) -{ - int probe_interval; - - ofconn->band = c->band; - - rconn_set_max_backoff(ofconn->rconn, c->max_backoff); - - probe_interval = c->probe_interval ? MAX(c->probe_interval, 5) : 0; - rconn_set_probe_interval(ofconn->rconn, probe_interval); - - ofconn_set_rate_limit(ofconn, c->rate_limit, c->burst_limit); -} - -static const char * -ofconn_get_target(const struct ofconn *ofconn) -{ - return rconn_get_target(ofconn->rconn); -} - -static struct ofconn * -find_controller_by_target(struct ofproto *ofproto, const char *target) -{ - struct ofconn *ofconn; - - HMAP_FOR_EACH_WITH_HASH (ofconn, hmap_node, - hash_string(target, 0), &ofproto->controllers) { - if (!strcmp(ofconn_get_target(ofconn), target)) { - return ofconn; - } - } - return NULL; -} - -static void -update_in_band_remotes(struct ofproto *ofproto) -{ - const struct ofconn *ofconn; - struct sockaddr_in *addrs; - size_t max_addrs, n_addrs; - size_t i; - - /* Allocate enough memory for as many remotes as we could possibly have. */ - max_addrs = ofproto->n_extra_remotes + hmap_count(&ofproto->controllers); - addrs = xmalloc(max_addrs * sizeof *addrs); - n_addrs = 0; - - /* Add all the remotes. */ - HMAP_FOR_EACH (ofconn, hmap_node, &ofproto->controllers) { - struct sockaddr_in *sin = &addrs[n_addrs]; - - if (ofconn->band == OFPROTO_OUT_OF_BAND) { - continue; - } - - sin->sin_addr.s_addr = rconn_get_remote_ip(ofconn->rconn); - if (sin->sin_addr.s_addr) { - sin->sin_port = rconn_get_remote_port(ofconn->rconn); - n_addrs++; - } - } - for (i = 0; i < ofproto->n_extra_remotes; i++) { - addrs[n_addrs++] = ofproto->extra_in_band_remotes[i]; - } - - /* Create or update or destroy in-band. */ - if (n_addrs) { - if (!ofproto->in_band) { - in_band_create(ofproto, ofproto->dpif, &ofproto->in_band); - } - if (ofproto->in_band) { - in_band_set_remotes(ofproto->in_band, addrs, n_addrs); - } - in_band_set_queue(ofproto->in_band, ofproto->in_band_queue); - ofproto->next_in_band_update = time_msec() + 1000; - } else { - in_band_destroy(ofproto->in_band); - ofproto->in_band = NULL; - } - - /* Clean up. */ - free(addrs); -} - -static void -update_fail_open(struct ofproto *p) -{ - struct ofconn *ofconn; - - if (!hmap_is_empty(&p->controllers) - && p->fail_mode == OFPROTO_FAIL_STANDALONE) { - struct rconn **rconns; - size_t n; - - if (!p->fail_open) { - p->fail_open = fail_open_create(p); - } - - n = 0; - rconns = xmalloc(hmap_count(&p->controllers) * sizeof *rconns); - HMAP_FOR_EACH (ofconn, hmap_node, &p->controllers) { - rconns[n++] = ofconn->rconn; - } - - fail_open_set_controllers(p->fail_open, rconns, n); - /* p->fail_open takes ownership of 'rconns'. */ - } else { - fail_open_destroy(p->fail_open); - p->fail_open = NULL; - } -} - void ofproto_set_controllers(struct ofproto *p, const struct ofproto_controller *controllers, size_t n_controllers) { - struct shash new_controllers; - struct ofconn *ofconn, *next_ofconn; - struct ofservice *ofservice, *next_ofservice; - size_t i; - - /* Create newly configured controllers and services. - * Create a name to ofproto_controller mapping in 'new_controllers'. */ - shash_init(&new_controllers); - for (i = 0; i < n_controllers; i++) { - const struct ofproto_controller *c = &controllers[i]; - - if (!vconn_verify_name(c->target)) { - if (!find_controller_by_target(p, c->target)) { - add_controller(p, c); - } - } else if (!pvconn_verify_name(c->target)) { - if (!ofservice_lookup(p, c->target) && ofservice_create(p, c)) { - continue; - } - } else { - VLOG_WARN_RL(&rl, "%s: unsupported controller \"%s\"", - dpif_name(p->dpif), c->target); - continue; - } - - shash_add_once(&new_controllers, c->target, &controllers[i]); - } - - /* Delete controllers that are no longer configured. - * Update configuration of all now-existing controllers. */ - HMAP_FOR_EACH_SAFE (ofconn, next_ofconn, hmap_node, &p->controllers) { - struct ofproto_controller *c; - - c = shash_find_data(&new_controllers, ofconn_get_target(ofconn)); - if (!c) { - ofconn_destroy(ofconn); - } else { - update_controller(ofconn, c); - } - } - - /* Delete services that are no longer configured. - * Update configuration of all now-existing services. */ - HMAP_FOR_EACH_SAFE (ofservice, next_ofservice, node, &p->services) { - struct ofproto_controller *c; - - c = shash_find_data(&new_controllers, - pvconn_get_name(ofservice->pvconn)); - if (!c) { - ofservice_destroy(p, ofservice); - } else { - ofservice_reconfigure(ofservice, c); - } - } - - shash_destroy(&new_controllers); - - update_in_band_remotes(p); - update_fail_open(p); + connmgr_set_controllers(p->connmgr, controllers, n_controllers); } void ofproto_set_fail_mode(struct ofproto *p, enum ofproto_fail_mode fail_mode) { - p->fail_mode = fail_mode; - update_fail_open(p); + connmgr_set_fail_mode(p->connmgr, fail_mode); } /* Drops the connections between 'ofproto' and all of its controllers, forcing @@ -776,34 +475,7 @@ ofproto_set_fail_mode(struct ofproto *p, enum ofproto_fail_mode fail_mode) void ofproto_reconnect_controllers(struct ofproto *ofproto) { - struct ofconn *ofconn; - - LIST_FOR_EACH (ofconn, node, &ofproto->all_conns) { - rconn_reconnect(ofconn->rconn); - } -} - -static bool -any_extras_changed(const struct ofproto *ofproto, - const struct sockaddr_in *extras, size_t n) -{ - size_t i; - - if (n != ofproto->n_extra_remotes) { - return true; - } - - for (i = 0; i < n; i++) { - const struct sockaddr_in *old = &ofproto->extra_in_band_remotes[i]; - const struct sockaddr_in *new = &extras[i]; - - if (old->sin_addr.s_addr != new->sin_addr.s_addr || - old->sin_port != new->sin_port) { - return true; - } - } - - return false; + connmgr_reconnect(ofproto->connmgr); } /* Sets the 'n' TCP port addresses in 'extras' as ones to which 'ofproto''s @@ -813,15 +485,7 @@ void ofproto_set_extra_in_band_remotes(struct ofproto *ofproto, const struct sockaddr_in *extras, size_t n) { - if (!any_extras_changed(ofproto, extras, n)) { - return; - } - - free(ofproto->extra_in_band_remotes); - ofproto->n_extra_remotes = n; - ofproto->extra_in_band_remotes = xmemdup(extras, n * sizeof *extras); - - update_in_band_remotes(ofproto); + connmgr_set_extra_in_band_remotes(ofproto->connmgr, extras, n); } /* Sets the OpenFlow queue used by flows set up by in-band control on @@ -830,10 +494,7 @@ ofproto_set_extra_in_band_remotes(struct ofproto *ofproto, void ofproto_set_in_band_queue(struct ofproto *ofproto, int queue_id) { - if (queue_id != ofproto->in_band_queue) { - ofproto->in_band_queue = queue_id; - update_in_band_remotes(ofproto); - } + connmgr_set_in_band_queue(ofproto->connmgr, queue_id); } void @@ -887,55 +548,17 @@ ofproto_set_desc(struct ofproto *p, } } -static int -set_pvconns(struct pvconn ***pvconnsp, size_t *n_pvconnsp, - const struct svec *svec) -{ - struct pvconn **pvconns = *pvconnsp; - size_t n_pvconns = *n_pvconnsp; - int retval = 0; - size_t i; - - for (i = 0; i < n_pvconns; i++) { - pvconn_close(pvconns[i]); - } - free(pvconns); - - pvconns = xmalloc(svec->n * sizeof *pvconns); - n_pvconns = 0; - for (i = 0; i < svec->n; i++) { - const char *name = svec->names[i]; - struct pvconn *pvconn; - int error; - - error = pvconn_open(name, &pvconn); - if (!error) { - pvconns[n_pvconns++] = pvconn; - } else { - VLOG_ERR("failed to listen on %s: %s", name, strerror(error)); - if (!retval) { - retval = error; - } - } - } - - *pvconnsp = pvconns; - *n_pvconnsp = n_pvconns; - - return retval; -} - int -ofproto_set_snoops(struct ofproto *ofproto, const struct svec *snoops) +ofproto_set_snoops(struct ofproto *ofproto, const struct sset *snoops) { - return set_pvconns(&ofproto->snoops, &ofproto->n_snoops, snoops); + return connmgr_set_snoops(ofproto->connmgr, snoops); } int ofproto_set_netflow(struct ofproto *ofproto, const struct netflow_options *nf_options) { - if (nf_options && nf_options->collectors.n) { + if (nf_options && !sset_is_empty(&nf_options->collectors)) { if (!ofproto->netflow) { ofproto->netflow = netflow_create(); } @@ -973,7 +596,7 @@ ofproto_set_sflow(struct ofproto *ofproto, /* Clears the CFM configuration from 'port_no' on 'ofproto'. */ void -ofproto_iface_clear_cfm(struct ofproto *ofproto, uint32_t port_no) +ofproto_port_clear_cfm(struct ofproto *ofproto, uint32_t port_no) { struct ofport *ofport = get_port(ofproto, port_no); if (ofport && ofport->cfm){ @@ -989,16 +612,16 @@ ofproto_iface_clear_cfm(struct ofproto *ofproto, uint32_t port_no) * * This function has no effect if 'ofproto' does not have a port 'port_no'. */ void -ofproto_iface_set_cfm(struct ofproto *ofproto, uint32_t port_no, - const struct cfm *cfm, - const uint16_t *remote_mps, size_t n_remote_mps) +ofproto_port_set_cfm(struct ofproto *ofproto, uint32_t port_no, + const struct cfm *cfm, + const uint16_t *remote_mps, size_t n_remote_mps) { struct ofport *ofport; ofport = get_port(ofproto, port_no); if (!ofport) { VLOG_WARN("%s: cannot configure CFM on nonexistent port %"PRIu32, - dpif_name(ofproto->dpif), port_no); + ofproto->name, port_no); return; } @@ -1014,7 +637,7 @@ ofproto_iface_set_cfm(struct ofproto *ofproto, uint32_t port_no, if (!cfm_configure(ofport->cfm)) { VLOG_WARN("%s: CFM configuration on port %"PRIu32" (%s) failed", - dpif_name(ofproto->dpif), port_no, + ofproto->name, port_no, netdev_get_name(ofport->netdev)); cfm_destroy(ofport->cfm); ofport->cfm = NULL; @@ -1026,7 +649,7 @@ ofproto_iface_set_cfm(struct ofproto *ofproto, uint32_t port_no, * 'port_no' or if that port does not have CFM configured. The caller must not * modify or destroy the returned object. */ const struct cfm * -ofproto_iface_get_cfm(struct ofproto *ofproto, uint32_t port_no) +ofproto_port_get_cfm(struct ofproto *ofproto, uint32_t port_no) { struct ofport *ofport = get_port(ofproto, port_no); return ofport ? ofport->cfm : NULL; @@ -1038,60 +661,49 @@ ofproto_get_datapath_id(const struct ofproto *ofproto) return ofproto->datapath_id; } -bool -ofproto_has_primary_controller(const struct ofproto *ofproto) +enum ofproto_fail_mode +ofproto_get_fail_mode(const struct ofproto *p) { - return !hmap_is_empty(&ofproto->controllers); + return connmgr_get_fail_mode(p->connmgr); } -enum ofproto_fail_mode -ofproto_get_fail_mode(const struct ofproto *p) +bool +ofproto_has_snoops(const struct ofproto *ofproto) { - return p->fail_mode; + return connmgr_has_snoops(ofproto->connmgr); } void -ofproto_get_snoops(const struct ofproto *ofproto, struct svec *snoops) +ofproto_get_snoops(const struct ofproto *ofproto, struct sset *snoops) { - size_t i; - - for (i = 0; i < ofproto->n_snoops; i++) { - svec_add(snoops, pvconn_get_name(ofproto->snoops[i])); - } + connmgr_get_snoops(ofproto->connmgr, snoops); } -void -ofproto_destroy(struct ofproto *p) +static void +ofproto_destroy__(struct ofproto *p, bool delete) { - struct ofservice *ofservice, *next_ofservice; - struct ofconn *ofconn, *next_ofconn; struct ofport *ofport, *next_ofport; - size_t i; if (!p) { return; } - shash_find_and_delete(&all_ofprotos, dpif_name(p->dpif)); - - /* Destroy fail-open and in-band early, since they touch the classifier. */ - fail_open_destroy(p->fail_open); - p->fail_open = NULL; + hmap_remove(&all_ofprotos, &p->hmap_node); - in_band_destroy(p->in_band); - p->in_band = NULL; - free(p->extra_in_band_remotes); - - ofproto_flush_flows(p); + ofproto_flush_flows__(p); + connmgr_destroy(p->connmgr); classifier_destroy(&p->cls); hmap_destroy(&p->facets); - LIST_FOR_EACH_SAFE (ofconn, next_ofconn, node, &p->all_conns) { - ofconn_destroy(ofconn); + if (delete) { + int error = dpif_delete(p->dpif); + if (error && error != ENOENT) { + VLOG_ERR("bridge %s: failed to destroy (%s)", + p->name, strerror(error)); + } } - hmap_destroy(&p->controllers); - dpif_close(p->dpif); + netdev_monitor_destroy(p->netdev_monitor); HMAP_FOR_EACH_SAFE (ofport, next_ofport, hmap_node, &p->ports) { hmap_remove(&p->ports, &ofport->hmap_node); @@ -1102,16 +714,6 @@ ofproto_destroy(struct ofproto *p) netflow_destroy(p->netflow); ofproto_sflow_destroy(p->sflow); - HMAP_FOR_EACH_SAFE (ofservice, next_ofservice, node, &p->services) { - ofservice_destroy(p, ofservice); - } - hmap_destroy(&p->services); - - for (i = 0; i < p->n_snoops; i++) { - pvconn_close(p->snoops[i]); - } - free(p->snoops); - mac_learning_destroy(p->ml); free(p->mfr_desc); @@ -1122,9 +724,22 @@ ofproto_destroy(struct ofproto *p) hmap_destroy(&p->ports); + free(p->name); free(p); } +void +ofproto_destroy(struct ofproto *p) +{ + ofproto_destroy__(p, false); +} + +void +ofproto_destroy_and_delete(struct ofproto *p) +{ + ofproto_destroy__(p, true); +} + int ofproto_run(struct ofproto *p) { @@ -1146,54 +761,9 @@ process_port_change(struct ofproto *ofproto, int error, char *devname) } } -/* Returns a "preference level" for snooping 'ofconn'. A higher return value - * means that 'ofconn' is more interesting for monitoring than a lower return - * value. */ -static int -snoop_preference(const struct ofconn *ofconn) -{ - switch (ofconn_get_role(ofconn)) { - case NX_ROLE_MASTER: - return 3; - case NX_ROLE_OTHER: - return 2; - case NX_ROLE_SLAVE: - return 1; - default: - /* Shouldn't happen. */ - return 0; - } -} - -/* One of ofproto's "snoop" pvconns has accepted a new connection on 'vconn'. - * Connects this vconn to a controller. */ -static void -add_snooper(struct ofproto *ofproto, struct vconn *vconn) -{ - struct ofconn *ofconn, *best; - - /* Pick a controller for monitoring. */ - best = NULL; - LIST_FOR_EACH (ofconn, node, &ofproto->all_conns) { - if (ofconn_get_type(ofconn) == OFCONN_PRIMARY - && (!best || snoop_preference(ofconn) > snoop_preference(best))) { - best = ofconn; - } - } - - if (best) { - rconn_add_monitor(best->rconn, vconn); - } else { - VLOG_INFO_RL(&rl, "no controller connection to snoop"); - vconn_close(vconn); - } -} - int ofproto_run1(struct ofproto *p) { - struct ofconn *ofconn, *next_ofconn; - struct ofservice *ofservice; struct ofport *ofport; char *devname; int error; @@ -1214,7 +784,7 @@ ofproto_run1(struct ofproto *p) * spin from here on out. */ static struct vlog_rate_limit rl2 = VLOG_RATE_LIMIT_INIT(1, 5); VLOG_ERR_RL(&rl2, "%s: datapath was destroyed externally", - dpif_name(p->dpif)); + p->name); return ENODEV; } break; @@ -1235,60 +805,11 @@ ofproto_run1(struct ofproto *p) ofport_run(p, ofport); } - if (p->in_band) { - if (time_msec() >= p->next_in_band_update) { - update_in_band_remotes(p); - } - in_band_run(p->in_band); - } - - LIST_FOR_EACH_SAFE (ofconn, next_ofconn, node, &p->all_conns) { - ofconn_run(ofconn); - } - - /* Fail-open maintenance. Do this after processing the ofconns since - * fail-open checks the status of the controller rconn. */ - if (p->fail_open) { - fail_open_run(p->fail_open); - } - - HMAP_FOR_EACH (ofservice, node, &p->services) { - struct vconn *vconn; - int retval; - - retval = pvconn_accept(ofservice->pvconn, OFP_VERSION, &vconn); - if (!retval) { - struct rconn *rconn; - char *name; - - rconn = rconn_create(ofservice->probe_interval, 0); - name = ofconn_make_name(p, vconn_get_name(vconn)); - rconn_connect_unreliably(rconn, vconn, name); - free(name); - - ofconn = ofconn_create(p, rconn, OFCONN_SERVICE); - ofconn_set_rate_limit(ofconn, ofservice->rate_limit, - ofservice->burst_limit); - } else if (retval != EAGAIN) { - VLOG_WARN_RL(&rl, "accept failed (%s)", strerror(retval)); - } - } - - for (i = 0; i < p->n_snoops; i++) { - struct vconn *vconn; - int retval; - - retval = pvconn_accept(p->snoops[i], OFP_VERSION, &vconn); - if (!retval) { - add_snooper(p, vconn); - } else if (retval != EAGAIN) { - VLOG_WARN_RL(&rl, "accept failed (%s)", strerror(retval)); - } - } + connmgr_run(p->connmgr, handle_openflow); - if (time_msec() >= p->next_expiration) { + if (timer_expired(&p->next_expiration)) { int delay = ofproto_expire(p); - p->next_expiration = time_msec() + delay; + timer_set_duration(&p->next_expiration, delay); COVERAGE_INC(ofproto_expiration); } @@ -1333,27 +854,14 @@ ofproto_run2(struct ofproto *p, bool revalidate_all) void ofproto_wait(struct ofproto *p) { - struct ofservice *ofservice; - struct ofconn *ofconn; struct ofport *ofport; - size_t i; - dpif_recv_wait(p->dpif); - dpif_port_poll_wait(p->dpif); - netdev_monitor_poll_wait(p->netdev_monitor); HMAP_FOR_EACH (ofport, hmap_node, &p->ports) { ofport_wait(ofport); } - LIST_FOR_EACH (ofconn, node, &p->all_conns) { - ofconn_wait(ofconn); - } - if (p->in_band) { - poll_timer_wait_until(p->next_in_band_update); - in_band_wait(p->in_band); - } - if (p->fail_open) { - fail_open_wait(p->fail_open); - } + dpif_recv_wait(p->dpif); + dpif_port_poll_wait(p->dpif); + netdev_monitor_poll_wait(p->netdev_monitor); if (p->sflow) { ofproto_sflow_wait(p->sflow); } @@ -1364,15 +872,10 @@ ofproto_wait(struct ofproto *p) /* Shouldn't happen, but if it does just go around again. */ VLOG_DBG_RL(&rl, "need revalidate in ofproto_wait_cb()"); poll_immediate_wake(); - } else if (p->next_expiration != LLONG_MAX) { - poll_timer_wait_until(p->next_expiration); - } - HMAP_FOR_EACH (ofservice, node, &p->services) { - pvconn_wait(ofservice->pvconn); - } - for (i = 0; i < p->n_snoops; i++) { - pvconn_wait(p->snoops[i]); + } else { + timer_wait(&p->next_expiration); } + connmgr_wait(p->connmgr); } void @@ -1390,54 +893,14 @@ ofproto_get_revalidate_set(struct ofproto *ofproto) bool ofproto_is_alive(const struct ofproto *p) { - return !hmap_is_empty(&p->controllers); + return connmgr_has_controllers(p->connmgr); } void ofproto_get_ofproto_controller_info(const struct ofproto *ofproto, struct shash *info) { - const struct ofconn *ofconn; - - shash_init(info); - - HMAP_FOR_EACH (ofconn, hmap_node, &ofproto->controllers) { - const struct rconn *rconn = ofconn->rconn; - time_t now = time_now(); - time_t last_connection = rconn_get_last_connection(rconn); - time_t last_disconnect = rconn_get_last_disconnect(rconn); - const int last_error = rconn_get_last_error(rconn); - struct ofproto_controller_info *cinfo = xmalloc(sizeof *cinfo); - - shash_add(info, rconn_get_target(rconn), cinfo); - - cinfo->is_connected = rconn_is_connected(rconn); - cinfo->role = ofconn_get_role(ofconn); - - cinfo->pairs.n = 0; - - if (last_error) { - cinfo->pairs.keys[cinfo->pairs.n] = "last_error"; - cinfo->pairs.values[cinfo->pairs.n++] = - xstrdup(ovs_retval_to_string(last_error)); - } - - cinfo->pairs.keys[cinfo->pairs.n] = "state"; - cinfo->pairs.values[cinfo->pairs.n++] = - xstrdup(rconn_get_state(rconn)); - - if (last_connection != TIME_MIN) { - cinfo->pairs.keys[cinfo->pairs.n] = "sec_since_connect"; - cinfo->pairs.values[cinfo->pairs.n++] - = xasprintf("%ld", (long int) (now - last_connection)); - } - - if (last_disconnect != TIME_MIN) { - cinfo->pairs.keys[cinfo->pairs.n] = "sec_since_disconnect"; - cinfo->pairs.values[cinfo->pairs.n++] - = xasprintf("%ld", (long int) (now - last_disconnect)); - } - } + connmgr_get_controller_info(ofproto->connmgr, info); } void @@ -1455,7 +918,134 @@ ofproto_free_ofproto_controller_info(struct shash *info) shash_destroy(info); } -/* Deletes port number 'odp_port' from the datapath for 'ofproto'. +/* Makes a deep copy of 'old' into 'port'. */ +void +ofproto_port_clone(struct ofproto_port *port, const struct ofproto_port *old) +{ + port->name = xstrdup(old->name); + port->type = xstrdup(old->type); + port->ofp_port = old->ofp_port; +} + +/* Frees memory allocated to members of 'ofproto_port'. + * + * Do not call this function on an ofproto_port obtained from + * ofproto_port_dump_next(): that function retains ownership of the data in the + * ofproto_port. */ +void +ofproto_port_destroy(struct ofproto_port *ofproto_port) +{ + free(ofproto_port->name); + free(ofproto_port->type); +} + +/* Converts a dpif_port into an ofproto_port. + * + * This only makes a shallow copy, so make sure that the dpif_port doesn't get + * freed while the ofproto_port is still in use. You can choose to free the + * ofproto_port instead of the dpif_port. */ +static void +ofproto_port_from_dpif_port(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); +} + +/* Initializes 'dump' to begin dumping the ports in an ofproto. + * + * This function provides no status indication. An error status for the entire + * dump operation is provided when it is completed by calling + * ofproto_port_dump_done(). + */ +void +ofproto_port_dump_start(struct ofproto_port_dump *dump, + const struct ofproto *ofproto) +{ + struct dpif_port_dump *dpif_dump; + + dump->state = dpif_dump = xmalloc(sizeof *dpif_dump); + dpif_port_dump_start(dpif_dump, ofproto->dpif); +} + +/* Attempts to retrieve another port from 'dump', which must have been created + * with ofproto_port_dump_start(). On success, stores a new ofproto_port into + * 'port' and returns true. On failure, returns false. + * + * Failure might indicate an actual error or merely that the last port has been + * dumped. An error status for the entire dump operation is provided when it + * is completed by calling ofproto_port_dump_done(). + * + * The ofproto owns the data stored in 'port'. It will remain valid until at + * least the next time 'dump' is passed to ofproto_port_dump_next() or + * ofproto_port_dump_done(). */ +bool +ofproto_port_dump_next(struct ofproto_port_dump *dump, + struct ofproto_port *port) +{ + struct dpif_port_dump *dpif_dump = dump->state; + struct dpif_port dpif_port; + bool ok; + + ok = dpif_port_dump_next(dpif_dump, &dpif_port); + if (ok) { + ofproto_port_from_dpif_port(port, &dpif_port); + } + return ok; +} + +/* Completes port table dump operation 'dump', which must have been created + * with ofproto_port_dump_start(). Returns 0 if the dump operation was + * error-free, otherwise a positive errno value describing the problem. */ +int +ofproto_port_dump_done(struct ofproto_port_dump *dump) +{ + struct dpif_port_dump *dpif_dump = dump->state; + int error = dpif_port_dump_done(dpif_dump); + free(dpif_dump); + return error; +} + +/* Attempts to add 'netdev' as a port on 'ofproto'. If successful, returns 0 + * and sets '*ofp_portp' to the new port's port OpenFlow 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 odp_port; + int error; + + error = dpif_port_add(ofproto->dpif, netdev, &odp_port); + if (ofp_portp) { + *ofp_portp = error ? OFPP_NONE : odp_port_to_ofp_port(odp_port); + } + return error; +} + +/* Looks up a port named 'devname' in 'ofproto'. On success, returns 0 and + * initializes '*port' appropriately; on failure, returns a positive errno + * value. + * + * The caller owns the data in 'port' and must free it with + * ofproto_port_destroy() when it is no longer needed. */ +int +ofproto_port_query_by_name(const struct ofproto *ofproto, const char *devname, + struct ofproto_port *port) +{ + struct dpif_port dpif_port; + int error; + + error = dpif_port_query_by_name(ofproto->dpif, devname, &dpif_port); + if (!error) { + ofproto_port_from_dpif_port(port, &dpif_port); + } + return error; +} + +/* Deletes port number 'ofp_port' from the datapath for 'ofproto'. * * This is almost the same as calling dpif_port_del() directly on the * datapath, but it also makes 'ofproto' close its open netdev for the port @@ -1466,19 +1056,20 @@ ofproto_free_ofproto_controller_info(struct shash *info) * * Returns 0 if successful, otherwise a positive errno. */ int -ofproto_port_del(struct ofproto *ofproto, uint16_t odp_port) +ofproto_port_del(struct ofproto *ofproto, uint16_t ofp_port) { + uint32_t odp_port = ofp_port_to_odp_port(ofp_port); struct ofport *ofport = get_port(ofproto, odp_port); - const char *name = ofport ? ofport->opp.name : ""; + const char *name = ofport ? netdev_get_name(ofport->netdev) : ""; int error; error = dpif_port_del(ofproto->dpif, odp_port); if (error) { VLOG_ERR("%s: failed to remove port %"PRIu16" (%s) interface (%s)", - dpif_name(ofproto->dpif), odp_port, name, strerror(error)); + ofproto->name, odp_port, name, strerror(error)); } else if (ofport) { - /* 'name' is ofport->opp.name and update_port() is going to destroy - * 'ofport'. Just in case update_port() refers to 'name' after it + /* 'name' is the netdev's name and update_port() is going to close the + * netdev. Just in case update_port() refers to 'name' after it * destroys 'ofport', make a copy of it around the update_port() * call. */ char *devname = xstrdup(name); @@ -1494,7 +1085,7 @@ bool ofproto_port_is_floodable(struct ofproto *ofproto, uint16_t odp_port) { struct ofport *ofport = get_port(ofproto, odp_port); - return ofport && !(ofport->opp.config & OFPPC_NO_FLOOD); + return ofport && !(ofport->opp.config & htonl(OFPPC_NO_FLOOD)); } /* Sends 'packet' out of port 'port_no' within 'p'. If 'vlan_tci' is zero the @@ -1502,7 +1093,7 @@ ofproto_port_is_floodable(struct ofproto *ofproto, uint16_t odp_port) * will be sent with the VLAN TCI specified by 'vlan_tci & ~VLAN_CFI'. * * Returns 0 if successful, otherwise a positive errno value. */ -int +static int ofproto_send_packet(struct ofproto *ofproto, uint32_t port_no, uint16_t vlan_tci, const struct ofpbuf *packet) @@ -1522,7 +1113,7 @@ ofproto_send_packet(struct ofproto *ofproto, if (error) { VLOG_WARN_RL(&rl, "%s: failed to send packet on port %"PRIu32" (%s)", - dpif_name(ofproto->dpif), port_no, strerror(error)); + ofproto->name, port_no, strerror(error)); } return error; } @@ -1557,8 +1148,8 @@ ofproto_delete_flow(struct ofproto *ofproto, const struct cls_rule *target) } } -void -ofproto_flush_flows(struct ofproto *ofproto) +static void +ofproto_flush_flows__(struct ofproto *ofproto) { struct facet *facet, *next_facet; struct rule *rule, *next_rule; @@ -1583,45 +1174,48 @@ ofproto_flush_flows(struct ofproto *ofproto) } dpif_flow_flush(ofproto->dpif); - if (ofproto->in_band) { - in_band_flushed(ofproto->in_band); - } - if (ofproto->fail_open) { - fail_open_flushed(ofproto->fail_open); - } +} + +void +ofproto_flush_flows(struct ofproto *ofproto) +{ + ofproto_flush_flows__(ofproto); + connmgr_flushed(ofproto->connmgr); } static void reinit_ports(struct ofproto *p) { struct dpif_port_dump dump; - struct shash_node *node; - struct shash devnames; + struct sset devnames; struct ofport *ofport; struct dpif_port dpif_port; + const char *devname; COVERAGE_INC(ofproto_reinit_ports); - shash_init(&devnames); + sset_init(&devnames); HMAP_FOR_EACH (ofport, hmap_node, &p->ports) { - shash_add_once (&devnames, ofport->opp.name, NULL); + sset_add(&devnames, netdev_get_name(ofport->netdev)); } DPIF_PORT_FOR_EACH (&dpif_port, &dump, p->dpif) { - shash_add_once (&devnames, dpif_port.name, NULL); + sset_add(&devnames, dpif_port.name); } - SHASH_FOR_EACH (node, &devnames) { - update_port(p, node->name); + SSET_FOR_EACH (devname, &devnames) { + update_port(p, devname); } - shash_destroy(&devnames); + sset_destroy(&devnames); } -static struct ofport * -make_ofport(const struct dpif_port *dpif_port) +/* Opens and returns a netdev for 'dpif_port', or a null pointer if the netdev + * cannot be opened. On success, also fills in 'opp'. */ +static struct netdev * +ofport_open(const struct dpif_port *dpif_port, struct ofp_phy_port *opp) { + uint32_t curr, advertised, supported, peer; struct netdev_options netdev_options; enum netdev_flags flags; - struct ofport *ofport; struct netdev *netdev; int error; @@ -1639,22 +1233,20 @@ make_ofport(const struct dpif_port *dpif_port) return NULL; } - ofport = xzalloc(sizeof *ofport); - ofport->netdev = netdev; - ofport->odp_port = dpif_port->port_no; - ofport->opp.port_no = odp_port_to_ofp_port(dpif_port->port_no); - netdev_get_etheraddr(netdev, ofport->opp.hw_addr); - ovs_strlcpy(ofport->opp.name, dpif_port->name, sizeof ofport->opp.name); - netdev_get_flags(netdev, &flags); - ofport->opp.config = flags & NETDEV_UP ? 0 : OFPPC_PORT_DOWN; + netdev_get_features(netdev, &curr, &advertised, &supported, &peer); - ofport->opp.state = netdev_get_carrier(netdev) ? 0 : OFPPS_LINK_DOWN; + opp->port_no = htons(odp_port_to_ofp_port(dpif_port->port_no)); + netdev_get_etheraddr(netdev, opp->hw_addr); + ovs_strzcpy(opp->name, dpif_port->name, sizeof opp->name); + opp->config = flags & NETDEV_UP ? 0 : htonl(OFPPC_PORT_DOWN); + opp->state = netdev_get_carrier(netdev) ? 0 : htonl(OFPPS_LINK_DOWN); + opp->curr = htonl(curr); + opp->advertised = htonl(advertised); + opp->supported = htonl(supported); + opp->peer = htonl(peer); - netdev_get_features(netdev, - &ofport->opp.curr, &ofport->opp.advertised, - &ofport->opp.supported, &ofport->opp.peer); - return ofport; + return netdev; } static bool @@ -1673,54 +1265,42 @@ ofport_conflicts(const struct ofproto *p, const struct dpif_port *dpif_port) } } -static int -ofport_equal(const struct ofport *a_, const struct ofport *b_) +/* Returns true if most fields of 'a' and 'b' are equal. Differences in name, + * port number, and 'config' bits other than OFPPC_PORT_DOWN are + * disregarded. */ +static bool +ofport_equal(const struct ofp_phy_port *a, const struct ofp_phy_port *b) { - const struct ofp_phy_port *a = &a_->opp; - const struct ofp_phy_port *b = &b_->opp; - BUILD_ASSERT_DECL(sizeof *a == 48); /* Detect ofp_phy_port changes. */ - return (a->port_no == b->port_no - && !memcmp(a->hw_addr, b->hw_addr, sizeof a->hw_addr) - && !strcmp(a->name, b->name) + return (!memcmp(a->hw_addr, b->hw_addr, sizeof a->hw_addr) && a->state == b->state - && a->config == b->config + && !((a->config ^ b->config) & htonl(OFPPC_PORT_DOWN)) && a->curr == b->curr && a->advertised == b->advertised && a->supported == b->supported && a->peer == b->peer); } +/* Adds an ofport to 'p' initialized based on the given 'netdev' and 'opp'. + * The caller must ensure that 'p' does not have a conflicting ofport (that is, + * one with the same name or port number). */ static void -send_port_status(struct ofproto *p, const struct ofport *ofport, - uint8_t reason) +ofport_install(struct ofproto *p, + struct netdev *netdev, const struct ofp_phy_port *opp) { - /* XXX Should limit the number of queued port status change messages. */ - struct ofconn *ofconn; - LIST_FOR_EACH (ofconn, node, &p->all_conns) { - struct ofp_port_status *ops; - struct ofpbuf *b; - - /* Primary controllers, even slaves, should always get port status - updates. Otherwise obey ofconn_receives_async_msgs(). */ - if (ofconn_get_type(ofconn) != OFCONN_PRIMARY - && !ofconn_receives_async_msgs(ofconn)) { - continue; - } + const char *netdev_name = netdev_get_name(netdev); + struct ofport *ofport; - ops = make_openflow_xid(sizeof *ops, OFPT_PORT_STATUS, 0, &b); - ops->reason = reason; - ops->desc = ofport->opp; - hton_ofp_phy_port(&ops->desc); - queue_tx(b, ofconn, NULL); - } -} + connmgr_send_port_status(p->connmgr, opp, OFPPR_ADD); -static void -ofport_install(struct ofproto *p, struct ofport *ofport) -{ - const char *netdev_name = ofport->opp.name; + /* Create ofport. */ + ofport = xmalloc(sizeof *ofport); + ofport->netdev = netdev; + ofport->opp = *opp; + ofport->odp_port = ofp_port_to_odp_port(ntohs(opp->port_no)); + ofport->cfm = NULL; + /* Add port to 'p'. */ netdev_monitor_add(p->netdev_monitor, ofport->netdev); hmap_insert(&p->ports, &ofport->hmap_node, hash_int(ofport->odp_port, 0)); shash_add(&p->port_by_name, netdev_name, ofport); @@ -1729,16 +1309,59 @@ ofport_install(struct ofproto *p, struct ofport *ofport) } } +/* Removes 'ofport' from 'p' and destroys it. */ static void ofport_remove(struct ofproto *p, struct ofport *ofport) { + connmgr_send_port_status(p->connmgr, &ofport->opp, OFPPR_DELETE); + netdev_monitor_remove(p->netdev_monitor, ofport->netdev); hmap_remove(&p->ports, &ofport->hmap_node); shash_delete(&p->port_by_name, - shash_find(&p->port_by_name, ofport->opp.name)); + shash_find(&p->port_by_name, + netdev_get_name(ofport->netdev))); if (p->sflow) { ofproto_sflow_del_port(p->sflow, ofport->odp_port); } + + ofport_free(ofport); +} + +/* If 'ofproto' contains an ofport named 'name', removes it from 'ofproto' and + * destroys it. */ +static void +ofport_remove_with_name(struct ofproto *ofproto, const char *name) +{ + struct ofport *port = shash_find_data(&ofproto->port_by_name, name); + if (port) { + ofport_remove(ofproto, port); + } +} + +/* Updates 'port' within 'ofproto' with the new 'netdev' and 'opp'. + * + * Does not handle a name or port number change. The caller must implement + * such a change as a delete followed by an add. */ +static void +ofport_modified(struct ofproto *ofproto, struct ofport *port, + struct netdev *netdev, struct ofp_phy_port *opp) +{ + memcpy(port->opp.hw_addr, opp->hw_addr, ETH_ADDR_LEN); + port->opp.config = ((port->opp.config & ~htonl(OFPPC_PORT_DOWN)) + | (opp->config & htonl(OFPPC_PORT_DOWN))); + port->opp.state = opp->state; + port->opp.curr = opp->curr; + port->opp.advertised = opp->advertised; + port->opp.supported = opp->supported; + port->opp.peer = opp->peer; + + netdev_monitor_remove(ofproto->netdev_monitor, port->netdev); + netdev_monitor_add(ofproto->netdev_monitor, netdev); + + netdev_close(port->netdev); + port->netdev = netdev; + + connmgr_send_port_status(ofproto->connmgr, &port->opp, OFPPR_MODIFY); } static void @@ -1752,8 +1375,8 @@ ofport_run(struct ofproto *ofproto, struct ofport *ofport) struct ccm *ccm; ofpbuf_init(&packet, 0); - ccm = compose_packet(&packet, eth_addr_ccm, ofport->opp.hw_addr, - ETH_TYPE_CFM, sizeof *ccm); + ccm = eth_compose(&packet, eth_addr_ccm, ofport->opp.hw_addr, + ETH_TYPE_CFM, sizeof *ccm); cfm_compose_ccm(ofport->cfm, ccm); ofproto_send_packet(ofproto, ofport->odp_port, 0, &packet); ofpbuf_uninit(&packet); @@ -1794,74 +1417,42 @@ get_port(const struct ofproto *ofproto, uint16_t odp_port) } static void -update_port(struct ofproto *p, const char *devname) +update_port(struct ofproto *ofproto, const char *name) { struct dpif_port dpif_port; - struct ofport *old_ofport; - struct ofport *new_ofport; - int error; + struct ofp_phy_port opp; + struct netdev *netdev; + struct ofport *port; COVERAGE_INC(ofproto_update_port); - /* Query the datapath for port information. */ - error = dpif_port_query_by_name(p->dpif, devname, &dpif_port); - - /* Find the old ofport. */ - old_ofport = shash_find_data(&p->port_by_name, devname); - if (!error) { - if (!old_ofport) { - /* There's no port named 'devname' but there might be a port with - * the same port number. This could happen if a port is deleted - * and then a new one added in its place very quickly, or if a port - * is renamed. In the former case we want to send an OFPPR_DELETE - * and an OFPPR_ADD, and in the latter case we want to send a - * single OFPPR_MODIFY. We can distinguish the cases by comparing - * the old port's ifindex against the new port, or perhaps less - * reliably but more portably by comparing the old port's MAC - * against the new port's MAC. However, this code isn't that smart - * and always sends an OFPPR_MODIFY (XXX). */ - old_ofport = get_port(p, dpif_port.port_no); - } - } else if (error != ENOENT && error != ENODEV) { - VLOG_WARN_RL(&rl, "dpif_port_query_by_name returned unexpected error " - "%s", strerror(error)); - goto exit; - } - - /* Create a new ofport. */ - new_ofport = !error ? make_ofport(&dpif_port) : NULL; - - /* Eliminate a few pathological cases. */ - if (!old_ofport && !new_ofport) { - goto exit; - } else if (old_ofport && new_ofport) { - /* Most of the 'config' bits are OpenFlow soft state, but - * OFPPC_PORT_DOWN is maintained by the kernel. So transfer the - * OpenFlow bits from old_ofport. (make_ofport() only sets - * OFPPC_PORT_DOWN and leaves the other bits 0.) */ - new_ofport->opp.config |= old_ofport->opp.config & ~OFPPC_PORT_DOWN; - - if (ofport_equal(old_ofport, new_ofport)) { - /* False alarm--no change. */ - ofport_free(new_ofport); - goto exit; + /* Fetch 'name''s location and properties from the datapath. */ + netdev = (!dpif_port_query_by_name(ofproto->dpif, name, &dpif_port) + ? ofport_open(&dpif_port, &opp) + : NULL); + if (netdev) { + port = get_port(ofproto, dpif_port.port_no); + if (port && !strcmp(netdev_get_name(port->netdev), name)) { + /* 'name' hasn't changed location. Any properties changed? */ + if (!ofport_equal(&port->opp, &opp)) { + ofport_modified(ofproto, port, netdev, &opp); + } else { + netdev_close(netdev); + } + } else { + /* If 'port' is nonnull then its name differs from 'name' and thus + * we should delete it. If we think there's a port named 'name' + * then its port number must be wrong now so delete it too. */ + if (port) { + ofport_remove(ofproto, port); + } + ofport_remove_with_name(ofproto, name); + ofport_install(ofproto, netdev, &opp); } + } else { + /* Any port named 'name' is gone now. */ + ofport_remove_with_name(ofproto, name); } - - /* Now deal with the normal cases. */ - if (old_ofport) { - ofport_remove(p, old_ofport); - } - if (new_ofport) { - ofport_install(p, new_ofport); - } - send_port_status(p, new_ofport ? new_ofport : old_ofport, - (!old_ofport ? OFPPR_ADD - : !new_ofport ? OFPPR_DELETE - : OFPPR_MODIFY)); - ofport_free(old_ofport); - -exit: dpif_port_destroy(&dpif_port); } @@ -1873,259 +1464,18 @@ init_ports(struct ofproto *p) DPIF_PORT_FOR_EACH (&dpif_port, &dump, p->dpif) { if (!ofport_conflicts(p, &dpif_port)) { - struct ofport *ofport = make_ofport(&dpif_port); - if (ofport) { - ofport_install(p, ofport); - } - } - } - - return 0; -} - -static struct ofconn * -ofconn_create(struct ofproto *p, struct rconn *rconn, enum ofconn_type type) -{ - struct ofconn *ofconn = xzalloc(sizeof *ofconn); - ofconn->ofproto = p; - list_push_back(&p->all_conns, &ofconn->node); - ofconn->rconn = rconn; - ofconn->type = type; - ofconn->flow_format = NXFF_OPENFLOW10; - ofconn->role = NX_ROLE_OTHER; - ofconn->packet_in_counter = rconn_packet_counter_create (); - ofconn->pktbuf = NULL; - ofconn->miss_send_len = 0; - ofconn->reply_counter = rconn_packet_counter_create (); - return ofconn; -} - -static void -ofconn_destroy(struct ofconn *ofconn) -{ - struct ofproto *ofproto = ofconn_get_ofproto(ofconn); - - if (ofconn_get_type(ofconn) == OFCONN_PRIMARY) { - hmap_remove(&ofproto->controllers, &ofconn->hmap_node); - } - - list_remove(&ofconn->node); - rconn_destroy(ofconn->rconn); - rconn_packet_counter_destroy(ofconn->packet_in_counter); - rconn_packet_counter_destroy(ofconn->reply_counter); - pktbuf_destroy(ofconn->pktbuf); - free(ofconn); -} - -static void -ofconn_run(struct ofconn *ofconn) -{ - struct ofproto *p = ofconn_get_ofproto(ofconn); - int iteration; - size_t i; - - for (i = 0; i < N_SCHEDULERS; i++) { - pinsched_run(ofconn->schedulers[i], do_send_packet_in, ofconn); - } - - rconn_run(ofconn->rconn); - - if (rconn_packet_counter_read (ofconn->reply_counter) < OFCONN_REPLY_MAX) { - /* Limit the number of iterations to prevent other tasks from - * starving. */ - for (iteration = 0; iteration < 50; iteration++) { - struct ofpbuf *of_msg = rconn_recv(ofconn->rconn); - if (!of_msg) { - break; - } - if (p->fail_open) { - fail_open_maybe_recover(p->fail_open); - } - handle_openflow(ofconn, of_msg); - ofpbuf_delete(of_msg); - } - } + struct ofp_phy_port opp; + struct netdev *netdev; - if (!rconn_is_alive(ofconn->rconn)) { - ofconn_destroy(ofconn); - } -} - -static void -ofconn_wait(struct ofconn *ofconn) -{ - int i; - - for (i = 0; i < N_SCHEDULERS; i++) { - pinsched_wait(ofconn->schedulers[i]); - } - rconn_run_wait(ofconn->rconn); - if (rconn_packet_counter_read (ofconn->reply_counter) < OFCONN_REPLY_MAX) { - rconn_recv_wait(ofconn->rconn); - } else { - COVERAGE_INC(ofproto_ofconn_stuck); - } -} - -/* Returns true if 'ofconn' should receive asynchronous messages. */ -static bool -ofconn_receives_async_msgs(const struct ofconn *ofconn) -{ - if (ofconn_get_type(ofconn) == OFCONN_PRIMARY) { - /* Primary controllers always get asynchronous messages unless they - * have configured themselves as "slaves". */ - return ofconn_get_role(ofconn) != NX_ROLE_SLAVE; - } else { - /* Service connections don't get asynchronous messages unless they have - * explicitly asked for them by setting a nonzero miss send length. */ - return ofconn->miss_send_len > 0; - } -} - -/* Returns a human-readable name for an OpenFlow connection between 'ofproto' - * and 'target', suitable for use in log messages for identifying the - * connection. - * - * The name is dynamically allocated. The caller should free it (with free()) - * when it is no longer needed. */ -static char * -ofconn_make_name(const struct ofproto *ofproto, const char *target) -{ - return xasprintf("%s<->%s", dpif_base_name(ofproto->dpif), target); -} - -static void -ofconn_set_rate_limit(struct ofconn *ofconn, int rate, int burst) -{ - int i; - - for (i = 0; i < N_SCHEDULERS; i++) { - struct pinsched **s = &ofconn->schedulers[i]; - - if (rate > 0) { - if (!*s) { - *s = pinsched_create(rate, burst); - } else { - pinsched_set_limits(*s, rate, burst); + netdev = ofport_open(&dpif_port, &opp); + if (netdev) { + ofport_install(p, netdev, &opp); } - } else { - pinsched_destroy(*s); - *s = NULL; } } -} - -static struct ofproto * -ofconn_get_ofproto(struct ofconn *ofconn) -{ - return ofconn->ofproto; -} - -static enum nx_flow_format -ofconn_get_flow_format(struct ofconn *ofconn) -{ - return ofconn->flow_format; -} - -static void -ofconn_set_flow_format(struct ofconn *ofconn, enum nx_flow_format flow_format) -{ - ofconn->flow_format = flow_format; -} - -static int -ofconn_get_miss_send_len(const struct ofconn *ofconn) -{ - return ofconn->miss_send_len; -} - -static void -ofconn_set_miss_send_len(struct ofconn *ofconn, int miss_send_len) -{ - ofconn->miss_send_len = miss_send_len; -} - -static enum ofconn_type -ofconn_get_type(const struct ofconn *ofconn) -{ - return ofconn->type; -} - -static enum nx_role -ofconn_get_role(const struct ofconn *ofconn) -{ - return ofconn->role; -} - -static void -ofconn_set_role(struct ofconn *ofconn, enum nx_role role) -{ - ofconn->role = role; -} - -static int -ofconn_pktbuf_retrieve(struct ofconn *ofconn, uint32_t id, - struct ofpbuf **bufferp, uint16_t *in_port) -{ - return pktbuf_retrieve(ofconn->pktbuf, id, bufferp, in_port); -} - -static void -ofservice_reconfigure(struct ofservice *ofservice, - const struct ofproto_controller *c) -{ - ofservice->probe_interval = c->probe_interval; - ofservice->rate_limit = c->rate_limit; - ofservice->burst_limit = c->burst_limit; -} - -/* Creates a new ofservice in 'ofproto'. Returns 0 if successful, otherwise a - * positive errno value. */ -static int -ofservice_create(struct ofproto *ofproto, const struct ofproto_controller *c) -{ - struct ofservice *ofservice; - struct pvconn *pvconn; - int error; - - error = pvconn_open(c->target, &pvconn); - if (error) { - return error; - } - - ofservice = xzalloc(sizeof *ofservice); - hmap_insert(&ofproto->services, &ofservice->node, - hash_string(c->target, 0)); - ofservice->pvconn = pvconn; - - ofservice_reconfigure(ofservice, c); return 0; } - -static void -ofservice_destroy(struct ofproto *ofproto, struct ofservice *ofservice) -{ - hmap_remove(&ofproto->services, &ofservice->node); - pvconn_close(ofservice->pvconn); - free(ofservice); -} - -/* Finds and returns the ofservice within 'ofproto' that has the given - * 'target', or a null pointer if none exists. */ -static struct ofservice * -ofservice_lookup(struct ofproto *ofproto, const char *target) -{ - struct ofservice *ofservice; - - HMAP_FOR_EACH_WITH_HASH (ofservice, node, hash_string(target, 0), - &ofproto->services) { - if (!strcmp(pvconn_get_name(ofservice->pvconn), target)) { - return ofservice; - } - } - return NULL; -} /* Returns true if 'rule' should be hidden from the controller. * @@ -2439,7 +1789,7 @@ facet_put__(struct ofproto *ofproto, struct facet *facet, const struct nlattr *actions, size_t actions_len, struct dpif_flow_stats *stats) { - uint32_t keybuf[ODPUTIL_FLOW_KEY_U32S]; + struct odputil_keybuf keybuf; enum dpif_flow_put_flags flags; struct ofpbuf key; @@ -2450,9 +1800,8 @@ facet_put__(struct ofproto *ofproto, struct facet *facet, facet->dp_byte_count = 0; } - ofpbuf_use_stack(&key, keybuf, sizeof keybuf); + ofpbuf_use_stack(&key, &keybuf, sizeof keybuf); odp_flow_key_from_flow(&key, &facet->flow); - assert(key.base == keybuf); return dpif_flow_put(ofproto->dpif, flags, key.data, key.size, actions, actions_len, stats); @@ -2496,13 +1845,12 @@ static void facet_uninstall(struct ofproto *p, struct facet *facet) { if (facet->installed) { - uint32_t keybuf[ODPUTIL_FLOW_KEY_U32S]; + struct odputil_keybuf keybuf; struct dpif_flow_stats stats; struct ofpbuf key; - ofpbuf_use_stack(&key, keybuf, sizeof keybuf); + ofpbuf_use_stack(&key, &keybuf, sizeof keybuf); odp_flow_key_from_flow(&key, &facet->flow); - assert(key.base == keybuf); if (!dpif_flow_del(p->dpif, key.data, key.size, &stats)) { facet_update_stats(p, facet, &stats); @@ -2686,22 +2034,6 @@ facet_revalidate(struct ofproto *ofproto, struct facet *facet) return true; } -static void -queue_tx(struct ofpbuf *msg, const struct ofconn *ofconn, - struct rconn_packet_counter *counter) -{ - update_openflow_length(msg); - if (rconn_send(ofconn->rconn, msg, counter)) { - ofpbuf_delete(msg); - } -} - -static void -ofconn_send_reply(const struct ofconn *ofconn, struct ofpbuf *msg) -{ - queue_tx(msg, ofconn, ofconn->reply_counter); -} - static void send_error_oh(const struct ofconn *ofconn, const struct ofp_header *oh, int error) @@ -2748,7 +2080,7 @@ handle_features_request(struct ofconn *ofconn, const struct ofp_header *oh) (1u << OFPAT_ENQUEUE)); HMAP_FOR_EACH (port, hmap_node, &ofproto->ports) { - hton_ofp_phy_port(ofpbuf_put(buf, &port->opp, sizeof port->opp)); + ofpbuf_put(buf, &port->opp, sizeof port->opp); } ofconn_send_reply(ofconn, buf); @@ -2813,7 +2145,7 @@ add_output_action(struct action_xlate_ctx *ctx, uint16_t port) const struct ofport *ofport = get_port(ctx->ofproto, port); if (ofport) { - if (ofport->opp.config & OFPPC_NO_FWD) { + if (ofport->opp.config & htonl(OFPPC_NO_FWD)) { /* Forwarding disabled on port. */ return; } @@ -2868,7 +2200,7 @@ xlate_table_action(struct action_xlate_ctx *ctx, uint16_t in_port) } static void -flood_packets(struct ofproto *ofproto, uint16_t odp_in_port, uint32_t mask, +flood_packets(struct ofproto *ofproto, uint16_t odp_in_port, ovs_be32 mask, uint16_t *nf_output_iface, struct ofpbuf *odp_actions) { struct ofport *ofport; @@ -2908,11 +2240,11 @@ xlate_output_action__(struct action_xlate_ctx *ctx, } break; case OFPP_FLOOD: - flood_packets(ctx->ofproto, ctx->flow.in_port, OFPPC_NO_FLOOD, + flood_packets(ctx->ofproto, ctx->flow.in_port, htonl(OFPPC_NO_FLOOD), &ctx->nf_output_iface, ctx->odp_actions); break; case OFPP_ALL: - flood_packets(ctx->ofproto, ctx->flow.in_port, 0, + flood_packets(ctx->ofproto, ctx->flow.in_port, htonl(0), &ctx->nf_output_iface, ctx->odp_actions); break; case OFPP_CONTROLLER: @@ -3071,8 +2403,11 @@ xlate_nicira_action(struct action_xlate_ctx *ctx, const struct nx_action_set_tunnel *nast; const struct nx_action_set_queue *nasq; const struct nx_action_multipath *nam; + const struct nx_action_autopath *naa; enum nx_action_subtype subtype = ntohs(nah->subtype); + const struct ofhooks *ofhooks = ctx->ofproto->ofhooks; struct xlate_reg_state state; + uint16_t autopath_port; ovs_be64 tun_id; assert(nah->vendor == htonl(NX_VENDOR_ID)); @@ -3134,6 +2469,15 @@ xlate_nicira_action(struct action_xlate_ctx *ctx, multipath_execute(nam, &ctx->flow); break; + case NXAST_AUTOPATH: + naa = (const struct nx_action_autopath *) nah; + autopath_port = (ofhooks->autopath_cb + ? ofhooks->autopath_cb(&ctx->flow, ntohl(naa->id), + &ctx->tags, ctx->ofproto->aux) + : OFPP_NONE); + autopath_execute(naa, &ctx->flow, autopath_port); + break; + /* If you add a new action here that modifies flow data, don't forget to * update the flow key in ctx->flow at the same time. */ @@ -3153,9 +2497,10 @@ do_xlate_actions(const union ofp_action *in, size_t n_in, const struct ofport *port; port = get_port(ctx->ofproto, ctx->flow.in_port); - if (port && port->opp.config & (OFPPC_NO_RECV | OFPPC_NO_RECV_STP) && + if (port && port->opp.config & htonl(OFPPC_NO_RECV | OFPPC_NO_RECV_STP) && port->opp.config & (eth_addr_equals(ctx->flow.dl_dst, eth_addr_stp) - ? OFPPC_NO_RECV_STP : OFPPC_NO_RECV)) { + ? htonl(OFPPC_NO_RECV_STP) + : htonl(OFPPC_NO_RECV))) { /* Drop this flow. */ return; } @@ -3301,8 +2646,9 @@ xlate_actions(struct action_xlate_ctx *ctx, /* Check with in-band control to see if we're allowed to set up this * flow. */ - if (!in_band_rule_check(ctx->ofproto->in_band, &ctx->flow, - ctx->odp_actions->data, ctx->odp_actions->size)) { + if (!connmgr_may_set_up_flow(ctx->ofproto->connmgr, &ctx->flow, + ctx->odp_actions->data, + ctx->odp_actions->size)) { ctx->may_set_up_flow = false; } @@ -3396,11 +2742,11 @@ exit: static void update_port_config(struct ofproto *p, struct ofport *port, - uint32_t config, uint32_t mask) + ovs_be32 config, ovs_be32 mask) { mask &= config ^ port->opp.config; - if (mask & OFPPC_PORT_DOWN) { - if (config & OFPPC_PORT_DOWN) { + if (mask & htonl(OFPPC_PORT_DOWN)) { + if (config & htonl(OFPPC_PORT_DOWN)) { netdev_turn_flags_off(port->netdev, NETDEV_UP, true); } else { netdev_turn_flags_on(port->netdev, NETDEV_UP, true); @@ -3408,14 +2754,14 @@ update_port_config(struct ofproto *p, struct ofport *port, } #define REVALIDATE_BITS (OFPPC_NO_RECV | OFPPC_NO_RECV_STP | \ OFPPC_NO_FWD | OFPPC_NO_FLOOD) - if (mask & REVALIDATE_BITS) { + if (mask & htonl(REVALIDATE_BITS)) { COVERAGE_INC(ofproto_costly_flags); - port->opp.config ^= mask & REVALIDATE_BITS; + port->opp.config ^= mask & htonl(REVALIDATE_BITS); p->need_revalidate = true; } #undef REVALIDATE_BITS - if (mask & OFPPC_NO_PACKET_IN) { - port->opp.config ^= OFPPC_NO_PACKET_IN; + if (mask & htonl(OFPPC_NO_PACKET_IN)) { + port->opp.config ^= htonl(OFPPC_NO_PACKET_IN); } } @@ -3438,7 +2784,7 @@ handle_port_mod(struct ofconn *ofconn, const struct ofp_header *oh) } else if (memcmp(port->opp.hw_addr, opm->hw_addr, OFP_ETH_ALEN)) { return ofp_mkerr(OFPET_PORT_MOD_FAILED, OFPPMFC_BAD_HW_ADDR); } else { - update_port_config(p, port, ntohl(opm->config), ntohl(opm->mask)); + update_port_config(p, port, opm->config, opm->mask); if (opm->advertise) { netdev_set_advertisements(port->netdev, ntohl(opm->advertise)); } @@ -3577,7 +2923,7 @@ append_port_stat(struct ofport *port, struct ofconn *ofconn, netdev_get_stats(port->netdev, &stats); ops = append_ofp_stats_reply(sizeof *ops, ofconn, msgp); - ops->port_no = htons(port->opp.port_no); + ops->port_no = port->opp.port_no; memset(ops->pad, 0, sizeof ops->pad); put_32aligned_be64(&ops->rx_packets, htonll(stats.rx_packets)); put_32aligned_be64(&ops->tx_packets, htonll(stats.tx_packets)); @@ -3829,6 +3175,15 @@ ofproto_get_all_flows(struct ofproto *p, struct ds *results) } } +/* Obtains the NetFlow engine type and engine ID for 'ofproto' into + * '*engine_type' and '*engine_id', respectively. */ +void +ofproto_get_netflow_ids(const struct ofproto *ofproto, + uint8_t *engine_type, uint8_t *engine_id) +{ + dpif_get_netflow_ids(ofproto->dpif, engine_type, engine_id); +} + static void query_aggregate_stats(struct ofproto *ofproto, struct cls_rule *target, ovs_be16 out_port, uint8_t table_id, @@ -3933,7 +3288,7 @@ put_queue_stats(struct queue_stats_cbdata *cbdata, uint32_t queue_id, struct ofp_queue_stats *reply; reply = append_ofp_stats_reply(sizeof *reply, cbdata->ofconn, &cbdata->msg); - reply->port_no = htons(cbdata->ofport->opp.port_no); + reply->port_no = cbdata->ofport->opp.port_no; memset(reply->pad, 0, sizeof reply->pad); reply->queue_id = htonl(queue_id); put_32aligned_be64(&reply->tx_bytes, htonll(stats->tx_bytes)); @@ -4387,8 +3742,7 @@ handle_role_request(struct ofconn *ofconn, const struct ofp_header *oh) uint32_t role; if (ofconn_get_type(ofconn) != OFCONN_PRIMARY) { - VLOG_WARN_RL(&rl, "ignoring role request on non-controller " - "connection"); + VLOG_WARN_RL(&rl, "ignoring role request on service connection"); return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_EPERM); } @@ -4401,16 +3755,6 @@ handle_role_request(struct ofconn *ofconn, const struct ofp_header *oh) return ofp_mkerr(OFPET_BAD_REQUEST, -1); } - if (role == NX_ROLE_MASTER) { - struct ofproto *ofproto = ofconn_get_ofproto(ofconn); - struct ofconn *other; - - HMAP_FOR_EACH (other, hmap_node, &ofproto->controllers) { - if (ofconn_get_role(other) == NX_ROLE_MASTER) { - ofconn_set_role(other, NX_ROLE_SLAVE); - } - } - } ofconn_set_role(ofconn, role); reply = make_nxmsg_xid(sizeof *reply, NXT_ROLE_REPLY, oh->xid, &buf); @@ -4601,7 +3945,7 @@ handle_miss_upcall(struct ofproto *p, struct dpif_upcall *upcall) /* Check with in-band control to see if this packet should be sent * to the local port regardless of the flow table. */ - if (in_band_msg_in_hook(p->in_band, &flow, upcall->packet)) { + if (connmgr_msg_in_hook(p->connmgr, &flow, upcall->packet)) { ofproto_send_packet(p, ODPP_LOCAL, 0, upcall->packet); } @@ -4612,7 +3956,7 @@ handle_miss_upcall(struct ofproto *p, struct dpif_upcall *upcall) /* Don't send a packet-in if OFPPC_NO_PACKET_IN asserted. */ struct ofport *port = get_port(p, flow.in_port); if (port) { - if (port->opp.config & OFPPC_NO_PACKET_IN) { + if (port->opp.config & htonl(OFPPC_NO_PACKET_IN)) { COVERAGE_INC(ofproto_no_packet_in); /* XXX install 'drop' flow entry */ ofpbuf_delete(upcall->packet); @@ -4877,8 +4221,7 @@ ofproto_dp_max_idle(const struct ofproto *ofproto) ds_put_format(&s, " %d:%d", i * BUCKET_WIDTH, buckets[i]); } } - VLOG_INFO("%s: %s (msec:count)", - dpif_name(ofproto->dpif), ds_cstr(&s)); + VLOG_INFO("%s: %s (msec:count)", ofproto->name, ds_cstr(&s)); ds_destroy(&s); } @@ -4962,7 +4305,6 @@ static void rule_send_removed(struct ofproto *p, struct rule *rule, uint8_t reason) { struct ofputil_flow_removed fr; - struct ofconn *ofconn; if (!rule->send_flow_removed) { return; @@ -4976,22 +4318,7 @@ rule_send_removed(struct ofproto *p, struct rule *rule, uint8_t reason) fr.packet_count = rule->packet_count; fr.byte_count = rule->byte_count; - LIST_FOR_EACH (ofconn, node, &p->all_conns) { - struct ofpbuf *msg; - - if (!rconn_is_connected(ofconn->rconn) - || !ofconn_receives_async_msgs(ofconn)) { - continue; - } - - /* This accounts flow expirations as if they were replies to OpenFlow - * requests. That works because preventing OpenFlow requests from - * being processed also prevents new flows from being added (and - * expiring). (It also prevents processing OpenFlow requests that - * would not add new flows, so it is imperfect.) */ - msg = ofputil_encode_flow_removed(&fr, ofconn_get_flow_format(ofconn)); - ofconn_send_reply(ofconn, msg); - } + connmgr_send_flow_removed(p->connmgr, &fr); } /* Obtains statistics for 'rule' and stores them in '*packets' and '*bytes'. @@ -5019,64 +4346,6 @@ rule_get_stats(const struct rule *rule, uint64_t *packets, uint64_t *bytes) *bytes = b; } -/* pinsched callback for sending 'ofp_packet_in' on 'ofconn'. */ -static void -do_send_packet_in(struct ofpbuf *ofp_packet_in, void *ofconn_) -{ - struct ofconn *ofconn = ofconn_; - - rconn_send_with_limit(ofconn->rconn, ofp_packet_in, - ofconn->packet_in_counter, 100); -} - -/* Takes 'upcall', whose packet has the flow specified by 'flow', composes an - * OpenFlow packet-in message from it, and passes it to 'ofconn''s packet - * scheduler for sending. - * - * If 'clone' is true, the caller retains ownership of 'upcall->packet'. - * Otherwise, ownership is transferred to this function. */ -static void -schedule_packet_in(struct ofconn *ofconn, struct dpif_upcall *upcall, - const struct flow *flow, bool clone) -{ - struct ofproto *ofproto = ofconn_get_ofproto(ofconn); - struct ofputil_packet_in pin; - struct ofpbuf *msg; - - /* Figure out the easy parts. */ - pin.packet = upcall->packet; - pin.in_port = odp_port_to_ofp_port(flow->in_port); - pin.reason = upcall->type == DPIF_UC_MISS ? OFPR_NO_MATCH : OFPR_ACTION; - - /* Get OpenFlow buffer_id. */ - if (upcall->type == DPIF_UC_ACTION) { - pin.buffer_id = UINT32_MAX; - } else if (ofproto->fail_open && fail_open_is_active(ofproto->fail_open)) { - pin.buffer_id = pktbuf_get_null(); - } else if (!ofconn->pktbuf) { - pin.buffer_id = UINT32_MAX; - } else { - pin.buffer_id = pktbuf_save(ofconn->pktbuf, upcall->packet, - flow->in_port); - } - - /* Figure out how much of the packet to send. */ - pin.send_len = upcall->packet->size; - if (pin.buffer_id != UINT32_MAX) { - pin.send_len = MIN(pin.send_len, ofconn->miss_send_len); - } - if (upcall->type == DPIF_UC_ACTION) { - pin.send_len = MIN(pin.send_len, upcall->userdata); - } - - /* Make OFPT_PACKET_IN and hand over to packet scheduler. It might - * immediately call into do_send_packet_in() or it might buffer it for a - * while (until a later call to pinsched_run()). */ - msg = ofputil_encode_packet_in(&pin, clone ? NULL : upcall->packet); - pinsched_send(ofconn->schedulers[upcall->type == DPIF_UC_MISS ? 0 : 1], - flow->in_port, msg, do_send_packet_in, ofconn); -} - /* Given 'upcall', of type DPIF_UC_ACTION or DPIF_UC_MISS, sends an * OFPT_PACKET_IN message to each OpenFlow controller as necessary according to * their individual configurations. @@ -5087,22 +4356,15 @@ static void send_packet_in(struct ofproto *ofproto, struct dpif_upcall *upcall, const struct flow *flow, bool clone) { - struct ofconn *ofconn, *prev; + struct ofputil_packet_in pin; - prev = NULL; - LIST_FOR_EACH (ofconn, node, &ofproto->all_conns) { - if (ofconn_receives_async_msgs(ofconn)) { - if (prev) { - schedule_packet_in(prev, upcall, flow, true); - } - prev = ofconn; - } - } - if (prev) { - schedule_packet_in(prev, upcall, flow, clone); - } else if (!clone) { - ofpbuf_delete(upcall->packet); - } + pin.packet = upcall->packet; + pin.in_port = odp_port_to_ofp_port(flow->in_port); + pin.reason = upcall->type == DPIF_UC_MISS ? OFPR_NO_MATCH : OFPR_ACTION; + pin.buffer_id = 0; /* not yet known */ + pin.send_len = upcall->userdata; + connmgr_send_packet_in(ofproto->connmgr, upcall, flow, + clone ? NULL : upcall->packet); } static uint64_t @@ -5133,16 +4395,30 @@ pick_fallback_dpid(void) return eth_addr_to_uint64(ea); } +static struct ofproto * +ofproto_lookup(const char *name) +{ + struct ofproto *ofproto; + + HMAP_FOR_EACH_WITH_HASH (ofproto, hmap_node, hash_string(name, 0), + &all_ofprotos) { + if (!strcmp(ofproto->name, name)) { + return ofproto; + } + } + return NULL; +} + static void ofproto_unixctl_list(struct unixctl_conn *conn, const char *arg OVS_UNUSED, void *aux OVS_UNUSED) { - const struct shash_node *node; + struct ofproto *ofproto; struct ds results; ds_init(&results); - SHASH_FOR_EACH (node, &all_ofprotos) { - ds_put_format(&results, "%s\n", node->name); + HMAP_FOR_EACH (ofproto, hmap_node, &all_ofprotos) { + ds_put_format(&results, "%s\n", ofproto->name); } unixctl_command_reply(conn, 200, ds_cstr(&results)); ds_destroy(&results); @@ -5229,7 +4505,7 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, const char *args_, goto exit; } - ofproto = shash_find_data(&all_ofprotos, dpname); + ofproto = ofproto_lookup(dpname); if (!ofproto) { unixctl_command_reply(conn, 501, "Unknown ofproto (use ofproto/list " "for help)"); @@ -5336,7 +4612,7 @@ default_normal_ofhook_cb(const struct flow *flow, const struct ofpbuf *packet, /* Determine output port. */ dst_mac = mac_learning_lookup(ofproto->ml, flow->dl_dst, 0, tags); if (!dst_mac) { - flood_packets(ofproto, flow->in_port, OFPPC_NO_FLOOD, + flood_packets(ofproto, flow->in_port, htonl(OFPPC_NO_FLOOD), nf_output_iface, odp_actions); } else { int out_port = dst_mac->port.i; @@ -5355,5 +4631,6 @@ static const struct ofhooks default_ofhooks = { default_normal_ofhook_cb, NULL, NULL, + NULL, NULL };