#include <netinet/in.h>
#include <stdbool.h>
#include <stdlib.h>
+#include "autopath.h"
#include "byte-order.h"
#include "cfm.h"
#include "classifier.h"
#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"
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. */
};
const struct flow *, bool clone);
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. */
};
/* 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);
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,
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;
/* 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);
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);
}
int
-ofproto_set_snoops(struct ofproto *ofproto, const struct svec *snoops)
+ofproto_set_snoops(struct ofproto *ofproto, const struct sset *snoops)
{
return connmgr_set_snoops(ofproto->connmgr, snoops);
}
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();
}
/* 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){
*
* 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;
}
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;
* '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;
return ofproto->datapath_id;
}
-bool
-ofproto_has_primary_controller(const struct ofproto *ofproto)
-{
- return connmgr_has_controllers(ofproto->connmgr);
-}
-
enum ofproto_fail_mode
ofproto_get_fail_mode(const struct ofproto *p)
{
return connmgr_get_fail_mode(p->connmgr);
}
+bool
+ofproto_has_snoops(const struct ofproto *ofproto)
+{
+ 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)
{
connmgr_get_snoops(ofproto->connmgr, snoops);
}
-void
-ofproto_destroy(struct ofproto *p)
+static void
+ofproto_destroy__(struct ofproto *p, bool delete)
{
struct ofport *ofport, *next_ofport;
return;
}
- shash_find_and_delete(&all_ofprotos, dpif_name(p->dpif));
+ hmap_remove(&all_ofprotos, &p->hmap_node);
- ofproto_flush_flows(p);
+ ofproto_flush_flows__(p);
connmgr_destroy(p->connmgr);
classifier_destroy(&p->cls);
hmap_destroy(&p->facets);
+ if (delete) {
+ int error = dpif_delete(p->dpif);
+ if (error && error != ENOENT) {
+ VLOG_ERR("bridge %s: failed to destroy (%s)",
+ p->name, strerror(error));
+ }
+ }
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);
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)
{
* 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;
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
*
* 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 : "<unknown>";
+ const char *name = ofport ? netdev_get_name(ofport->netdev) : "<unknown>";
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);
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
* 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)
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;
}
}
}
-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;
}
dpif_flow_flush(ofproto->dpif);
+}
+
+void
+ofproto_flush_flows(struct ofproto *ofproto)
+{
+ ofproto_flush_flows__(ofproto);
connmgr_flushed(ofproto->connmgr);
}
\f
sset_init(&devnames);
HMAP_FOR_EACH (ofport, hmap_node, &p->ports) {
- sset_add(&devnames, ofport->opp.name);
+ sset_add(&devnames, netdev_get_name(ofport->netdev));
}
DPIF_PORT_FOR_EACH (&dpif_port, &dump, p->dpif) {
sset_add(&devnames, dpif_port.name);
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;
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
}
}
-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
-ofport_install(struct ofproto *p, struct ofport *ofport)
+ofport_install(struct ofproto *p,
+ struct netdev *netdev, const struct ofp_phy_port *opp)
{
- const char *netdev_name = ofport->opp.name;
+ const char *netdev_name = netdev_get_name(netdev);
+ struct ofport *ofport;
+ connmgr_send_port_status(p->connmgr, opp, OFPPR_ADD);
+
+ /* 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);
}
}
+/* 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
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);
}
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);
- }
- connmgr_send_port_status(p->connmgr,
- new_ofport ? &new_ofport->opp : &old_ofport->opp,
- (!old_ofport ? OFPPR_ADD
- : !new_ofport ? OFPPR_DELETE
- : OFPPR_MODIFY));
- ofport_free(old_ofport);
-
-exit:
dpif_port_destroy(&dpif_port);
}
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);
+ struct ofp_phy_port opp;
+ struct netdev *netdev;
+
+ netdev = ofport_open(&dpif_port, &opp);
+ if (netdev) {
+ ofport_install(p, netdev, &opp);
}
}
}
(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);
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;
}
}
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;
}
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:
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));
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. */
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;
}
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);
}
#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);
}
}
} 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));
}
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));
}
}
+/* 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,
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));
/* 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);
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);
}
return eth_addr_to_uint64(ea);
}
\f
+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);
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)");
/* 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;
default_normal_ofhook_cb,
NULL,
NULL,
+ NULL,
NULL
};