# limitations under the License.
AC_PREREQ(2.63)
-AC_INIT(openvswitch, 0.90.6, ovs-bugs@openvswitch.org)
+AC_INIT(openvswitch, 0.99.0, ovs-bugs@openvswitch.org)
NX_BUILDNR
AC_CONFIG_SRCDIR([datapath/datapath.c])
AC_CONFIG_MACRO_DIR([m4])
OVS_ENABLE_OPTION([-Wmissing-prototypes])
OVS_ENABLE_OPTION([-Wmissing-field-initializers])
OVS_ENABLE_OPTION([-Wno-override-init])
+ OVS_CONDITIONAL_CC_OPTION([-Wno-unused], [HAVE_WNO_UNUSED])
AC_ARG_VAR(KARCH, [Kernel Architecture String])
AC_SUBST(KARCH)
/*
- * Copyright (c) 2007, 2008, 2009 Nicira Networks.
+ * Copyright (c) 2007, 2008, 2009, 2010 Nicira Networks.
* Distributed under the terms of the GNU GPL version 2.
*
* Significant portions of this file may be copied from parts of the Linux
p->port_no = port_no;
p->dp = dp;
p->dev = dev;
+ atomic_set(&p->sflow_pool, 0);
if (!is_dp_dev(dev))
rcu_assign_pointer(dev->br_port, p);
else {
out:
return -EPROTO;
}
-#else
-int vswitch_skb_checksum_setup(struct sk_buff *skb) { return 0; }
-#endif /* CONFIG_XEN && linux == 2.6.18 */
+#endif /* CONFIG_XEN && HAVE_PROTO_DATA_VALID */
/* Append each packet in 'skb' list to 'queue'. There will be only one packet
* unless we broke up a GSO packet. */
int err;
WARN_ON_ONCE(skb_shared(skb));
- BUG_ON(queue_no != _ODPL_MISS_NR && queue_no != _ODPL_ACTION_NR);
-
+ BUG_ON(queue_no != _ODPL_MISS_NR && queue_no != _ODPL_ACTION_NR && queue_no != _ODPL_SFLOW_NR);
queue = &dp->queues[queue_no];
err = -ENOBUFS;
if (skb_queue_len(queue) >= DP_MAX_QUEUE_LEN)
int dp_idx = iminor(f->f_dentry->d_inode);
struct datapath *dp;
int drop_frags, listeners, port_no;
+ unsigned int sflow_probability;
int err;
/* Handle commands with special locking requirements up front. */
set_listen_mask(f, listeners);
break;
+ case ODP_GET_SFLOW_PROBABILITY:
+ err = put_user(dp->sflow_probability, (unsigned int __user *)argp);
+ break;
+
+ case ODP_SET_SFLOW_PROBABILITY:
+ err = get_user(sflow_probability, (unsigned int __user *)argp);
+ if (!err)
+ dp->sflow_probability = sflow_probability;
+ break;
+
case ODP_PORT_QUERY:
err = query_port(dp, (struct odp_port __user *)argp);
break;
/*
- * Copyright (c) 2009 Nicira Networks.
+ * Copyright (c) 2009, 2010 Nicira Networks.
* Distributed under the terms of the GNU GPL version 2.
*
* Significant portions of this file may be copied from parts of the Linux
struct sw_flow *flows[];
};
- #define DP_N_QUEUES 2
+ #define DP_N_QUEUES 3
#define DP_MAX_QUEUE_LEN 100
+ /**
+ * struct dp_stats_percpu - per-cpu packet processing statistics for a given
+ * datapath.
+ * @n_frags: Number of IP fragments processed by datapath.
+ * @n_hit: Number of received packets for which a matching flow was found in
+ * the flow table.
+ * @n_miss: Number of received packets that had no matching flow in the flow
+ * table. The sum of @n_hit and @n_miss is the number of packets that have
+ * been received by the datapath.
+ * @n_lost: Number of received packets that had no matching flow in the flow
+ * table that could not be sent to userspace (normally due to an overflow in
+ * one of the datapath's queues).
+ */
struct dp_stats_percpu {
u64 n_frags;
u64 n_hit;
u16 ports[];
};
+ /**
+ * struct datapath - datapath for flow-based packet switching
+ * @mutex: Mutual exclusion for ioctls.
+ * @dp_idx: Datapath number (index into the dps[] array in datapath.c).
+ * @ifobj: Represents /sys/class/net/<devname>/brif.
+ * @drop_frags: Drop all IP fragments if nonzero.
+ * @queues: %DP_N_QUEUES sets of queued packets for userspace to handle.
+ * @waitqueue: Waitqueue, for waiting for new packets in @queues.
+ * @n_flows: Number of flows currently in flow table.
+ * @table: Current flow table (RCU protected).
+ * @groups: Port groups, used by ODPAT_OUTPUT_GROUP action (RCU protected).
+ * @n_ports: Number of ports currently in @ports.
+ * @ports: Map from port number to &struct net_bridge_port. %ODPP_LOCAL port
+ * always exists, other ports may be %NULL.
+ * @port_list: List of all ports in @ports in arbitrary order.
+ * @stats_percpu: Per-CPU datapath statistics.
+ * @sflow_probability: Number of packets out of UINT_MAX to sample to the
+ * %ODPL_SFLOW queue, e.g. (@sflow_probability/UINT_MAX) is the probability of
+ * sampling a given packet.
+ */
struct datapath {
struct mutex mutex;
int dp_idx;
-
struct kobject ifobj;
int drop_frags;
/* Switch ports. */
unsigned int n_ports;
struct net_bridge_port *ports[DP_MAX_PORTS];
- struct list_head port_list; /* All ports, including local_port. */
+ struct list_head port_list;
/* Stats. */
struct dp_stats_percpu *stats_percpu;
+
+ /* sFlow Sampling */
+ unsigned int sflow_probability;
};
+ /**
+ * struct net_bridge_port - one port within a datapath
+ * @port_no: Index into @dp's @ports array.
+ * @dp: Datapath to which this port belongs.
+ * @dev: The network device attached to this port. The @br_port member in @dev
+ * points back to this &struct net_bridge_port.
+ * @kobj: Represents /sys/class/net/<devname>/brport.
+ * @linkname: The name of the link from /sys/class/net/<datapath>/brif to this
+ * &struct net_bridge_port. (We keep this around so that we can delete it
+ * if @dev gets renamed.) Set to the null string when no link exists.
+ * @node: Element in @dp's @port_list.
+ * @sflow_pool: Number of packets that were candidates for sFlow sampling,
+ * regardless of whether they were actually chosen and sent down to userspace.
+ */
struct net_bridge_port {
u16 port_no;
struct datapath *dp;
struct net_device *dev;
struct kobject kobj;
char linkname[IFNAMSIZ];
- struct list_head node; /* Element in datapath.ports. */
+ struct list_head node;
+ atomic_t sflow_pool;
};
extern struct notifier_block dp_device_notifier;
return dp->ports[ODPP_LOCAL]->dev->name;
}
-#ifdef CONFIG_XEN
-int skb_checksum_setup(struct sk_buff *skb);
+#if defined(CONFIG_XEN) && defined(HAVE_PROTO_DATA_VALID)
+int vswitch_skb_checksum_setup(struct sk_buff *skb);
#else
-static inline int skb_checksum_setup(struct sk_buff *skb)
+static inline int vswitch_skb_checksum_setup(struct sk_buff *skb)
{
return 0;
}
#endif
-int vswitch_skb_checksum_setup(struct sk_buff *skb);
-
#endif /* datapath.h */
-# Copyright (C) 2009 Nicira Networks, Inc.
+# Copyright (C) 2009, 2010 Nicira Networks, Inc.
#
# Copying and distribution of this file, with or without modification,
# are permitted in any medium without royalty provided the copyright
lib/socket-util.h \
lib/stp.c \
lib/stp.h \
+ lib/string.h \
lib/svec.c \
lib/svec.h \
lib/tag.c \
lib/dirs.c
CLEANFILES += $(nodist_lib_libopenvswitch_a_SOURCES)
+ noinst_LIBRARIES += lib/libsflow.a
+ lib_libsflow_a_SOURCES = \
+ lib/sflow_api.h \
+ lib/sflow.h \
+ lib/sflow_agent.c \
+ lib/sflow_sampler.c \
+ lib/sflow_poller.c \
+ lib/sflow_receiver.c
+ lib_libsflow_a_CFLAGS = $(AM_CFLAGS)
+ if HAVE_WNO_UNUSED
+ lib_libsflow_a_CFLAGS += -Wno-unused
+ endif
+
if HAVE_NETLINK
lib_libopenvswitch_a_SOURCES += \
lib/netlink-protocol.h \
/*
- * Copyright (c) 2009 Nicira Networks.
+ * Copyright (c) 2009, 2010 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <assert.h>
#include "dpif.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* Open vSwitch datapath interface.
*
* This structure should be treated as opaque by dpif implementations. */
struct dpif {
- const struct dpif_class *class;
+ const struct dpif_class *dpif_class;
char *name;
uint8_t netflow_engine_type;
uint8_t netflow_engine_id;
void dpif_init(struct dpif *, const struct dpif_class *, const char *name,
uint8_t netflow_engine_type, uint8_t netflow_engine_id);
static inline void dpif_assert_class(const struct dpif *dpif,
- const struct dpif_class *class)
+ const struct dpif_class *dpif_class)
{
- assert(dpif->class == class);
+ assert(dpif->dpif_class == dpif_class);
}
/* Datapath interface class structure, to be defined by each implementation of
*
* If successful, 'dpif' will not be used again except as an argument for
* the 'close' member function. */
- int (*delete)(struct dpif *dpif);
+ int (*destroy)(struct dpif *dpif);
/* Retrieves statistics for 'dpif' into 'stats'. */
int (*get_stats)(const struct dpif *dpif, struct odp_stats *stats);
* corresponding type when it calls the recv member function. */
int (*recv_set_mask)(struct dpif *dpif, int listen_mask);
+ /* Retrieves 'dpif''s sFlow sampling probability into '*probability'.
+ * Return value is 0 or a positive errno value. EOPNOTSUPP indicates that
+ * the datapath does not support sFlow, as does a null pointer.
+ *
+ * '*probability' is expressed as the number of packets out of UINT_MAX to
+ * sample, e.g. probability/UINT_MAX is the probability of sampling a given
+ * packet. */
+ int (*get_sflow_probability)(const struct dpif *dpif,
+ uint32_t *probability);
+
+ /* Sets 'dpif''s sFlow sampling probability to 'probability'. Return value
+ * is 0 or a positive errno value. EOPNOTSUPP indicates that the datapath
+ * does not support sFlow, as does a null pointer.
+ *
+ * 'probability' is expressed as the number of packets out of UINT_MAX to
+ * sample, e.g. probability/UINT_MAX is the probability of sampling a given
+ * packet. */
+ int (*set_sflow_probability)(struct dpif *dpif, uint32_t probability);
+
/* Attempts to receive a message from 'dpif'. If successful, stores the
* message into '*packetp'. The message, if one is received, must begin
* with 'struct odp_msg' as a header. Only messages of the types selected
extern const struct dpif_class dpif_linux_class;
extern const struct dpif_class dpif_netdev_class;
+#ifdef __cplusplus
+}
+#endif
+
#endif /* dpif-provider.h */
/*
- * Copyright (c) 2008, 2009 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
{
if (dpif) {
char *name = dpif->name;
- dpif->class->close(dpif);
+ dpif->dpif_class->close(dpif);
free(name);
}
}
int
dpif_get_all_names(const struct dpif *dpif, struct svec *all_names)
{
- if (dpif->class->get_all_names) {
- int error = dpif->class->get_all_names(dpif, all_names);
+ if (dpif->dpif_class->get_all_names) {
+ int error = dpif->dpif_class->get_all_names(dpif, all_names);
if (error) {
VLOG_WARN_RL(&error_rl,
"failed to retrieve names for datpath %s: %s",
COVERAGE_INC(dpif_destroy);
- error = dpif->class->delete(dpif);
+ error = dpif->dpif_class->destroy(dpif);
log_operation(dpif, "delete", error);
return error;
}
int
dpif_get_dp_stats(const struct dpif *dpif, struct odp_stats *stats)
{
- int error = dpif->class->get_stats(dpif, stats);
+ int error = dpif->dpif_class->get_stats(dpif, stats);
if (error) {
memset(stats, 0, sizeof *stats);
}
int
dpif_get_drop_frags(const struct dpif *dpif, bool *drop_frags)
{
- int error = dpif->class->get_drop_frags(dpif, drop_frags);
+ int error = dpif->dpif_class->get_drop_frags(dpif, drop_frags);
if (error) {
*drop_frags = false;
}
int
dpif_set_drop_frags(struct dpif *dpif, bool drop_frags)
{
- int error = dpif->class->set_drop_frags(dpif, drop_frags);
+ int error = dpif->dpif_class->set_drop_frags(dpif, drop_frags);
log_operation(dpif, "set_drop_frags", error);
return error;
}
COVERAGE_INC(dpif_port_add);
- error = dpif->class->port_add(dpif, devname, flags, &port_no);
+ error = dpif->dpif_class->port_add(dpif, devname, flags, &port_no);
if (!error) {
VLOG_DBG_RL(&dpmsg_rl, "%s: added %s as port %"PRIu16,
dpif_name(dpif), devname, port_no);
COVERAGE_INC(dpif_port_del);
- error = dpif->class->port_del(dpif, port_no);
+ error = dpif->dpif_class->port_del(dpif, port_no);
log_operation(dpif, "port_del", error);
return error;
}
dpif_port_query_by_number(const struct dpif *dpif, uint16_t port_no,
struct odp_port *port)
{
- int error = dpif->class->port_query_by_number(dpif, port_no, port);
+ int error = dpif->dpif_class->port_query_by_number(dpif, port_no, port);
if (!error) {
VLOG_DBG_RL(&dpmsg_rl, "%s: port %"PRIu16" is device %s",
dpif_name(dpif), port_no, port->devname);
dpif_port_query_by_name(const struct dpif *dpif, const char *devname,
struct odp_port *port)
{
- int error = dpif->class->port_query_by_name(dpif, devname, port);
+ int error = dpif->dpif_class->port_query_by_name(dpif, devname, port);
if (!error) {
VLOG_DBG_RL(&dpmsg_rl, "%s: device %s is on port %"PRIu16,
dpif_name(dpif), devname, port->port);
}
ports = xcalloc(stats.n_ports, sizeof *ports);
- retval = dpif->class->port_list(dpif, ports, stats.n_ports);
+ retval = dpif->dpif_class->port_list(dpif, ports, stats.n_ports);
if (retval < 0) {
/* Hard error. */
error = -retval;
int
dpif_port_poll(const struct dpif *dpif, char **devnamep)
{
- int error = dpif->class->port_poll(dpif, devnamep);
+ int error = dpif->dpif_class->port_poll(dpif, devnamep);
if (error) {
*devnamep = NULL;
}
void
dpif_port_poll_wait(const struct dpif *dpif)
{
- dpif->class->port_poll_wait(dpif);
+ dpif->dpif_class->port_poll_wait(dpif);
}
/* Retrieves a list of the port numbers in port group 'group' in 'dpif'.
*ports = NULL;
*n_ports = 0;
for (;;) {
- int retval = dpif->class->port_group_get(dpif, group,
- *ports, *n_ports);
+ int retval = dpif->dpif_class->port_group_get(dpif, group,
+ *ports, *n_ports);
if (retval < 0) {
/* Hard error. */
error = -retval;
COVERAGE_INC(dpif_port_group_set);
- error = dpif->class->port_group_set(dpif, group, ports, n_ports);
+ error = dpif->dpif_class->port_group_set(dpif, group, ports, n_ports);
log_operation(dpif, "port_group_set", error);
return error;
}
COVERAGE_INC(dpif_flow_flush);
- error = dpif->class->flow_flush(dpif);
+ error = dpif->dpif_class->flow_flush(dpif);
log_operation(dpif, "flow_flush", error);
return error;
}
COVERAGE_INC(dpif_flow_get);
check_rw_odp_flow(flow);
- error = dpif->class->flow_get(dpif, flow, 1);
+ error = dpif->dpif_class->flow_get(dpif, flow, 1);
if (!error) {
error = flow->stats.error;
}
check_rw_odp_flow(&flows[i]);
}
- error = dpif->class->flow_get(dpif, flows, n);
+ error = dpif->dpif_class->flow_get(dpif, flows, n);
log_operation(dpif, "flow_get_multiple", error);
return error;
}
COVERAGE_INC(dpif_flow_put);
- error = dpif->class->flow_put(dpif, put);
+ error = dpif->dpif_class->flow_put(dpif, put);
if (should_log_flow_message(error)) {
log_flow_put(dpif, error, put);
}
check_rw_odp_flow(flow);
memset(&flow->stats, 0, sizeof flow->stats);
- error = dpif->class->flow_del(dpif, flow);
+ error = dpif->dpif_class->flow_del(dpif, flow);
if (should_log_flow_message(error)) {
log_flow_operation(dpif, "delete flow", error, flow);
}
flows[i].n_actions = 0;
}
}
- retval = dpif->class->flow_list(dpif, flows, n);
+ retval = dpif->dpif_class->flow_list(dpif, flows, n);
if (retval < 0) {
*n_out = 0;
VLOG_WARN_RL(&error_rl, "%s: flow list failed (%s)",
COVERAGE_INC(dpif_execute);
if (n_actions > 0) {
- error = dpif->class->execute(dpif, in_port, actions, n_actions, buf);
+ error = dpif->dpif_class->execute(dpif, in_port, actions,
+ n_actions, buf);
} else {
error = 0;
}
int
dpif_recv_get_mask(const struct dpif *dpif, int *listen_mask)
{
- int error = dpif->class->recv_get_mask(dpif, listen_mask);
+ int error = dpif->dpif_class->recv_get_mask(dpif, listen_mask);
if (error) {
*listen_mask = 0;
}
int
dpif_recv_set_mask(struct dpif *dpif, int listen_mask)
{
- int error = dpif->class->recv_set_mask(dpif, listen_mask);
+ int error = dpif->dpif_class->recv_set_mask(dpif, listen_mask);
log_operation(dpif, "recv_set_mask", error);
return error;
}
- int error = (dpif->class->get_sflow_probability
- ? dpif->class->get_sflow_probability(dpif, probability)
+ /* Retrieve the sFlow sampling probability. '*probability' is expressed as the
+ * number of packets out of UINT_MAX to sample, e.g. probability/UINT_MAX is
+ * the probability of sampling a given packet.
+ *
+ * Returns 0 if successful, otherwise a positive errno value. EOPNOTSUPP
+ * indicates that 'dpif' does not support sFlow sampling. */
+ int
+ dpif_get_sflow_probability(const struct dpif *dpif, uint32_t *probability)
+ {
- int error = (dpif->class->set_sflow_probability
- ? dpif->class->set_sflow_probability(dpif, probability)
++ int error = (dpif->dpif_class->get_sflow_probability
++ ? dpif->dpif_class->get_sflow_probability(dpif, probability)
+ : EOPNOTSUPP);
+ if (error) {
+ *probability = 0;
+ }
+ log_operation(dpif, "get_sflow_probability", error);
+ return error;
+ }
+
+ /* Set the sFlow sampling probability. 'probability' is expressed as the
+ * number of packets out of UINT_MAX to sample, e.g. probability/UINT_MAX is
+ * the probability of sampling a given packet.
+ *
+ * Returns 0 if successful, otherwise a positive errno value. EOPNOTSUPP
+ * indicates that 'dpif' does not support sFlow sampling. */
+ int
+ dpif_set_sflow_probability(struct dpif *dpif, uint32_t probability)
+ {
++ int error = (dpif->dpif_class->set_sflow_probability
++ ? dpif->dpif_class->set_sflow_probability(dpif, probability)
+ : EOPNOTSUPP);
+ log_operation(dpif, "set_sflow_probability", error);
+ return error;
+ }
+
/* Attempts to receive a message from 'dpif'. If successful, stores the
* message into '*packetp'. The message, if one is received, will begin with
* 'struct odp_msg' as a header. Only messages of the types selected with
int
dpif_recv(struct dpif *dpif, struct ofpbuf **packetp)
{
- int error = dpif->class->recv(dpif, packetp);
+ int error = dpif->dpif_class->recv(dpif, packetp);
if (!error) {
if (VLOG_IS_DBG_ENABLED()) {
struct ofpbuf *buf = *packetp;
"%zu on port %"PRIu16": %s", dpif_name(dpif),
(msg->type == _ODPL_MISS_NR ? "miss"
: msg->type == _ODPL_ACTION_NR ? "action"
+ : msg->type == _ODPL_SFLOW_NR ? "sFlow"
: "<unknown>"),
payload_len, msg->port, s);
free(s);
return error;
}
- for (i = 0; i < stats.max_miss_queue + stats.max_action_queue; i++) {
+ for (i = 0; i < stats.max_miss_queue + stats.max_action_queue + stats.max_sflow_queue; i++) {
struct ofpbuf *buf;
error = dpif_recv(dpif, &buf);
if (error) {
void
dpif_recv_wait(struct dpif *dpif)
{
- dpif->class->recv_wait(dpif);
+ dpif->dpif_class->recv_wait(dpif);
}
/* Obtains the NetFlow engine type and engine ID for 'dpif' into '*engine_type'
}
\f
void
-dpif_init(struct dpif *dpif, const struct dpif_class *class, const char *name,
+dpif_init(struct dpif *dpif, const struct dpif_class *dpif_class,
+ const char *name,
uint8_t netflow_engine_type, uint8_t netflow_engine_id)
{
- dpif->class = class;
+ dpif->dpif_class = dpif_class;
dpif->name = xstrdup(name);
dpif->netflow_engine_type = netflow_engine_type;
dpif->netflow_engine_id = netflow_engine_id;
#include "list.h"
#include "netdev-provider.h"
#include "ofpbuf.h"
+ #include "openflow/openflow.h"
#include "packets.h"
#include "poll-loop.h"
#include "shash.h"
}
shash_delete(&netdev_obj_shash, node);
- netdev_obj->class->destroy(netdev_obj);
+ netdev_obj->netdev_class->destroy(netdev_obj);
return 0;
}
return ENODEV;
}
- if (netdev_obj->class->reconfigure) {
- return netdev_obj->class->reconfigure(netdev_obj, args);
+ if (netdev_obj->netdev_class->reconfigure) {
+ return netdev_obj->netdev_class->reconfigure(netdev_obj, args);
}
return 0;
netdev_obj = shash_find_data(&netdev_obj_shash, name);
if (netdev_obj) {
- error = netdev_obj->class->open(name, ethertype, &netdev);
+ error = netdev_obj->netdev_class->open(name, ethertype, &netdev);
} else {
/* Default to "system". */
error = EAFNOSUPPORT;
}
/* Free. */
- netdev->class->close(netdev);
+ netdev->netdev_class->close(netdev);
free(name);
}
}
assert(buffer->size == 0);
assert(ofpbuf_tailroom(buffer) >= ETH_TOTAL_MIN);
- retval = netdev->class->recv(netdev,
- buffer->data, ofpbuf_tailroom(buffer));
+ retval = netdev->netdev_class->recv(netdev,
+ buffer->data, ofpbuf_tailroom(buffer));
if (retval >= 0) {
COVERAGE_INC(netdev_received);
buffer->size += retval;
void
netdev_recv_wait(struct netdev *netdev)
{
- netdev->class->recv_wait(netdev);
+ netdev->netdev_class->recv_wait(netdev);
}
/* Discards all packets waiting to be received from 'netdev'. */
int
netdev_drain(struct netdev *netdev)
{
- return netdev->class->drain(netdev);
+ return netdev->netdev_class->drain(netdev);
}
/* Sends 'buffer' on 'netdev'. Returns 0 if successful, otherwise a positive
int
netdev_send(struct netdev *netdev, const struct ofpbuf *buffer)
{
- int error = netdev->class->send(netdev, buffer->data, buffer->size);
+ int error = netdev->netdev_class->send(netdev, buffer->data, buffer->size);
if (!error) {
COVERAGE_INC(netdev_sent);
}
void
netdev_send_wait(struct netdev *netdev)
{
- return netdev->class->send_wait(netdev);
+ return netdev->netdev_class->send_wait(netdev);
}
/* Attempts to set 'netdev''s MAC address to 'mac'. Returns 0 if successful,
int
netdev_set_etheraddr(struct netdev *netdev, const uint8_t mac[ETH_ADDR_LEN])
{
- return netdev->class->set_etheraddr(netdev, mac);
+ return netdev->netdev_class->set_etheraddr(netdev, mac);
}
/* Retrieves 'netdev''s MAC address. If successful, returns 0 and copies the
int
netdev_get_etheraddr(const struct netdev *netdev, uint8_t mac[ETH_ADDR_LEN])
{
- return netdev->class->get_etheraddr(netdev, mac);
+ return netdev->netdev_class->get_etheraddr(netdev, mac);
}
/* Returns the name of the network device that 'netdev' represents,
int
netdev_get_mtu(const struct netdev *netdev, int *mtup)
{
- int error = netdev->class->get_mtu(netdev, mtup);
+ int error = netdev->netdev_class->get_mtu(netdev, mtup);
if (error) {
VLOG_WARN_RL(&rl, "failed to retrieve MTU for network device %s: %s",
netdev_get_name(netdev), strerror(error));
int
netdev_get_ifindex(const struct netdev *netdev)
{
- return netdev->class->get_ifindex(netdev);
+ return netdev->netdev_class->get_ifindex(netdev);
}
/* Stores the features supported by 'netdev' into each of '*current',
peer = &dummy[3];
}
- error = netdev->class->get_features(netdev, current, advertised, supported,
- peer);
+ error = netdev->netdev_class->get_features(netdev, current, advertised,
+ supported, peer);
if (error) {
*current = *advertised = *supported = *peer = 0;
}
return error;
}
+ /* Returns the maximum speed of a network connection that has the "enum
+ * ofp_port_features" bits in 'features', in bits per second. If no bits that
+ * indicate a speed are set in 'features', assumes 100Mbps. */
+ uint64_t
+ netdev_features_to_bps(uint32_t features)
+ {
+ enum {
+ F_10000MB = OFPPF_10GB_FD,
+ F_1000MB = OFPPF_1GB_HD | OFPPF_1GB_FD,
+ F_100MB = OFPPF_100MB_HD | OFPPF_100MB_FD,
+ F_10MB = OFPPF_10MB_HD | OFPPF_10MB_FD
+ };
+
+ return ( features & F_10000MB ? UINT64_C(10000000000)
+ : features & F_1000MB ? UINT64_C(1000000000)
+ : features & F_100MB ? UINT64_C(100000000)
+ : features & F_10MB ? UINT64_C(10000000)
+ : UINT64_C(100000000));
+ }
+
+ /* Returns true if any of the "enum ofp_port_features" bits that indicate a
+ * full-duplex link are set in 'features', otherwise false. */
+ bool
+ netdev_features_is_full_duplex(uint32_t features)
+ {
+ return (features & (OFPPF_10MB_FD | OFPPF_100MB_FD | OFPPF_1GB_FD
+ | OFPPF_10GB_FD)) != 0;
+ }
+
/* Set the features advertised by 'netdev' to 'advertise'. Returns 0 if
* successful, otherwise a positive errno value. */
int
netdev_set_advertisements(struct netdev *netdev, uint32_t advertise)
{
- return (netdev->class->set_advertisements
- ? netdev->class->set_advertisements(netdev, advertise)
+ return (netdev->netdev_class->set_advertisements
+ ? netdev->netdev_class->set_advertisements(netdev, advertise)
: EOPNOTSUPP);
}
struct in_addr netmask;
int error;
- error = (netdev->class->get_in4
- ? netdev->class->get_in4(netdev, &address, &netmask)
+ error = (netdev->netdev_class->get_in4
+ ? netdev->netdev_class->get_in4(netdev, &address, &netmask)
: EOPNOTSUPP);
if (address_) {
address_->s_addr = error ? 0 : address.s_addr;
int
netdev_set_in4(struct netdev *netdev, struct in_addr addr, struct in_addr mask)
{
- return (netdev->class->set_in4
- ? netdev->class->set_in4(netdev, addr, mask)
+ return (netdev->netdev_class->set_in4
+ ? netdev->netdev_class->set_in4(netdev, addr, mask)
: EOPNOTSUPP);
}
netdev_add_router(struct netdev *netdev, struct in_addr router)
{
COVERAGE_INC(netdev_add_router);
- return (netdev->class->add_router
- ? netdev->class->add_router(netdev, router)
+ return (netdev->netdev_class->add_router
+ ? netdev->netdev_class->add_router(netdev, router)
: EOPNOTSUPP);
}
const struct in_addr *host, struct in_addr *next_hop,
char **netdev_name)
{
- int error = (netdev->class->get_next_hop
- ? netdev->class->get_next_hop(host, next_hop, netdev_name)
+ int error = (netdev->netdev_class->get_next_hop
+ ? netdev->netdev_class->get_next_hop(host, next_hop,
+ netdev_name)
: EOPNOTSUPP);
if (error) {
next_hop->s_addr = 0;
struct in6_addr dummy;
int error;
- error = (netdev->class->get_in6
- ? netdev->class->get_in6(netdev, in6 ? in6 : &dummy)
+ error = (netdev->netdev_class->get_in6
+ ? netdev->netdev_class->get_in6(netdev, in6 ? in6 : &dummy)
: EOPNOTSUPP);
if (error && in6) {
memset(in6, 0, sizeof *in6);
enum netdev_flags old_flags;
int error;
- error = netdev->class->update_flags(netdev, off & ~on, on, &old_flags);
+ error = netdev->netdev_class->update_flags(netdev, off & ~on,
+ on, &old_flags);
if (error) {
VLOG_WARN_RL(&rl, "failed to %s flags for network device %s: %s",
off || on ? "set" : "get", netdev_get_name(netdev),
netdev_arp_lookup(const struct netdev *netdev,
uint32_t ip, uint8_t mac[ETH_ADDR_LEN])
{
- int error = (netdev->class->arp_lookup
- ? netdev->class->arp_lookup(netdev, ip, mac)
+ int error = (netdev->netdev_class->arp_lookup
+ ? netdev->netdev_class->arp_lookup(netdev, ip, mac)
: EOPNOTSUPP);
if (error) {
memset(mac, 0, ETH_ADDR_LEN);
int
netdev_get_carrier(const struct netdev *netdev, bool *carrier)
{
- int error = (netdev->class->get_carrier
- ? netdev->class->get_carrier(netdev, carrier)
+ int error = (netdev->netdev_class->get_carrier
+ ? netdev->netdev_class->get_carrier(netdev, carrier)
: EOPNOTSUPP);
if (error) {
*carrier = false;
int error;
COVERAGE_INC(netdev_get_stats);
- error = (netdev->class->get_stats
- ? netdev->class->get_stats(netdev, stats)
+ error = (netdev->netdev_class->get_stats
+ ? netdev->netdev_class->get_stats(netdev, stats)
: EOPNOTSUPP);
if (error) {
memset(stats, 0xff, sizeof *stats);
netdev_set_policing(struct netdev *netdev, uint32_t kbits_rate,
uint32_t kbits_burst)
{
- return (netdev->class->set_policing
- ? netdev->class->set_policing(netdev, kbits_rate, kbits_burst)
+ return (netdev->netdev_class->set_policing
+ ? netdev->netdev_class->set_policing(netdev,
+ kbits_rate, kbits_burst)
: EOPNOTSUPP);
}
int
netdev_get_vlan_vid(const struct netdev *netdev, int *vlan_vid)
{
- int error = (netdev->class->get_vlan_vid
- ? netdev->class->get_vlan_vid(netdev, vlan_vid)
+ int error = (netdev->netdev_class->get_vlan_vid
+ ? netdev->netdev_class->get_vlan_vid(netdev, vlan_vid)
: ENOENT);
if (error) {
*vlan_vid = 0;
}
\f
/* Initializes 'netdev_obj' as a netdev object named 'name' of the
- * specified 'class'.
+ * specified 'netdev_class'.
*
* This function adds 'netdev_obj' to a netdev-owned shash, so it is
* very important that 'netdev_obj' only be freed after calling
* netdev_destroy(). */
void
netdev_obj_init(struct netdev_obj *netdev_obj, const char *name,
- const struct netdev_class *class, bool created)
+ const struct netdev_class *netdev_class, bool created)
{
assert(!shash_find(&netdev_obj_shash, name));
- netdev_obj->class = class;
+ netdev_obj->netdev_class = netdev_class;
netdev_obj->ref_cnt = 0;
netdev_obj->created = created;
shash_add(&netdev_obj_shash, name, netdev_obj);
}
-/* Initializes 'netdev' as a netdev named 'name' of the specified 'class'.
+/* Initializes 'netdev' as a netdev named 'name' of the specified
+ * 'netdev_class'.
*
* This function adds 'netdev' to a netdev-owned linked list, so it is very
* important that 'netdev' only be freed after calling netdev_close(). */
void
netdev_init(struct netdev *netdev, const char *name,
- const struct netdev_class *class)
+ const struct netdev_class *netdev_class)
{
- netdev->class = class;
+ netdev->netdev_class = netdev_class;
netdev->name = xstrdup(name);
netdev->save_flags = 0;
netdev->changed_flags = 0;
* The caller must not free the returned value. */
const char *netdev_get_type(const struct netdev *netdev)
{
- return netdev->class->type;
+ return netdev->netdev_class->type;
}
/* Initializes 'notifier' as a netdev notifier for 'netdev', for which
SHASH_FOR_EACH (node, &monitor->polled_netdevs) {
struct netdev_notifier *notifier = node->data;
- notifier->netdev->class->poll_remove(notifier);
+ notifier->netdev->netdev_class->poll_remove(notifier);
}
shash_destroy(&monitor->polled_netdevs);
const char *netdev_name = netdev_get_name(netdev);
int error = 0;
if (!shash_find(&monitor->polled_netdevs, netdev_name)
- && netdev->class->poll_add)
+ && netdev->netdev_class->poll_add)
{
struct netdev_notifier *notifier;
- error = netdev->class->poll_add(netdev, netdev_monitor_cb, monitor,
- ¬ifier);
+ error = netdev->netdev_class->poll_add(netdev, netdev_monitor_cb,
+ monitor, ¬ifier);
if (!error) {
assert(notifier->netdev == netdev);
shash_add(&monitor->polled_netdevs, netdev_name, notifier);
if (node) {
/* Cancel future notifications. */
struct netdev_notifier *notifier = node->data;
- netdev->class->poll_remove(notifier);
+ netdev->netdev_class->poll_remove(notifier);
shash_delete(&monitor->polled_netdevs, node);
/* Drop any pending notification. */
if (netdev->changed_flags) {
enum netdev_flags restore = netdev->save_flags & netdev->changed_flags;
enum netdev_flags old_flags;
- return netdev->class->update_flags(netdev,
- netdev->changed_flags & ~restore,
- restore, &old_flags);
+ return netdev->netdev_class->update_flags(netdev,
+ netdev->changed_flags
+ & ~restore,
+ restore, &old_flags);
}
return 0;
}
Disabling learning for the VLAN will cause the switch to correctly
send the packet out all ports configured for that VLAN. If Open
vSwitch is being used as an intermediate switch learning can be disabled
-by setting the key \fBvlan.\fIbrname\fB.learning-disable=\fIvid\fR
+by setting the key \fBvlan.\fIbrname\fB.disable-learning=\fIvid\fR
to the mirrored VLAN.
.ST "Example"
The following \fBovs\-vswitchd\fR configuration copies all frames received
.fi
.RE
+ .SS "sFlow Monitoring"
+ sFlow(R) is a protocol for monitoring switches. A bridge may be
+ configured to send sFlow records to sFlow collectors by defining the
+ key \fBsflow.\fIbridge\fB.host\fR for each collector in the form
+ \fIip\fR[\fB:\fIport\fR]. Records from \fIbridge\fR will be sent to
+ each \fIip\fR on UDP \fIport\fR. The \fIip\fR must be specified
+ numerically, not as a DNS name. If \Iport\fR is omitted, port 6343 is
+ used.
+ .PP
+ By default, 1 out of every 400 packets is sent to the configured sFlow
+ collector. To override this, set \fBsflow.\fIbridge\fB.sampling\fR to
+ the number of switched packets out of which one, on average, will be
+ sent to the sFlow collector, e.g. a value of 1 sends every packet to
+ the collector, a value of 2 sends 50% of the packets to the collector,
+ and so on.
+ .PP
+ \fBovs\-vswitchd\fR also occasionally sends switch port statistics to
+ sFlow collectors, by default every 30 seconds. To override this, set
+ \fBsflow.\fIbridge\fB.polling\fR to a duration in seconds.
+ .PP
+ By default, \fBovs\-vswitchd\fR sends the first 128 bytes of sampled
+ packets to sFlow collectors. To override this, set
+ \fBsflow.\fIbridge\fB.header\fR to a size in bytes.
+ .PP
+ The sFlow module must be able to report an ``agent address'' to sFlow
+ collectors, which should be an IP address for the Open vSwitch that is
+ persistent and reachable over the network, if possible. If a
+ local IP is configured as \fBbridge.\fIbridge\fB.controller.ip\fR,
+ then that IP address is used by default. To override this default,
+ set \fBsflow.\fIbridge\fB.agent\fR to the name of a network device, in
+ which case the IP address set on that device is used. If no IP
+ address can be determined either way, sFlow is disabled.
.SS "Remote Management"
A \fBovs\-vswitchd\fR instance may be remotely managed by a controller that
supports the OpenFlow Management Protocol, such as NOX. This
.TP
\fBdiscover\fR
Use controller discovery to find the local OpenFlow controller.
- Refer to \fB\ovs\-openflowd\fR(8) for information on how to configure a DHCP
+ Refer to \fBovs\-openflowd\fR(8) for information on how to configure a DHCP
server to support controller discovery. The following additional
options control the discovery process:
.