/depcomp
/distfiles
/install-sh
+ /libtool
/manpage-check
/missing
/missing-distfiles
/package.m4
/stamp-h1
+ /_build-gcc
+ /_build-clang
Module.symvers
TAGS
cscope.*
tags
+myexp/
_debian
SUBDIRS = datapath
AM_CPPFLAGS = $(SSL_CFLAGS)
+
+ if WIN32
+ AM_CPPFLAGS += -I $(top_srcdir)/include/windows
+ endif
+
AM_CPPFLAGS += -I $(top_srcdir)/include
AM_CPPFLAGS += -I $(top_srcdir)/lib
AM_CPPFLAGS += -I $(top_builddir)/lib
INSTALL.Fedora \
INSTALL.KVM \
INSTALL.Libvirt \
+ INSTALL.NetBSD \
INSTALL.RHEL \
INSTALL.SSL \
INSTALL.XenServer \
MAN_ROOTS =
noinst_DATA =
noinst_HEADERS =
- noinst_LIBRARIES =
+ lib_LTLIBRARIES =
noinst_man_MANS =
noinst_PROGRAMS =
noinst_SCRIPTS =
SUFFIXES += .in
.in:
+ @mkdir -p $$(dirname $@)
$(PERL) $(srcdir)/build-aux/soexpand.pl -I$(srcdir) < $< | \
sed \
-e 's,[@]PKIDIR[@],$(PKIDIR),g' \
@if test -e $(srcdir)/.git && (git --version) >/dev/null 2>&1; then \
(cd datapath && $(MAKE) distfiles); \
(cat distfiles; sed 's|^|datapath/|' datapath/distfiles) | \
- sort -u > all-distfiles; \
- LC_ALL=C sort -u > all-distfiles; \
- (cd $(srcdir) && git ls-files) | grep -v '\.gitignore$$' | \
- LC_ALL=C sort -u > all-gitfiles; \
- LC_ALL=C comm -1 -3 all-distfiles all-gitfiles > missing-distfiles; \
++ LC_ALL=C sort -u > all-distfiles; \
+ (cd $(srcdir) && git ls-files) | grep -vFf $(srcdir)/.non-distfiles | \
- sort -u > all-gitfiles; \
- comm -1 -3 all-distfiles all-gitfiles > missing-distfiles; \
++ LC_ALL=C sort -u > all-gitfiles; \
++ LC_ALL=C comm -1 -3 all-distfiles all-gitfiles > missing-distfiles; \
if test -s missing-distfiles; then \
echo "The distribution is missing the following files:"; \
cat missing-distfiles; \
list='$(DISTFILES)'; \
for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
- -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t" | sort -u > $@
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t" | \
+ LC_ALL=C sort -u > $@
CLEANFILES += distfiles
endif
.PHONY: dist-hook-git
cd datapath/linux && $(MAKE) modules_install
endif
+ include m4/automake.mk
include lib/automake.mk
include ofproto/automake.mk
include utilities/automake.mk
include xenserver/automake.mk
include python/automake.mk
include python/compat/automake.mk
+include planetlab/automake.mk
include tutorial/automake.mk
include vtep/automake.mk
# notice and this notice are preserved. This file is offered as-is,
# without warranty of any kind.
- noinst_LIBRARIES += lib/libopenvswitch.a
+ lib_LTLIBRARIES += lib/libopenvswitch.la
- lib_libopenvswitch_a_SOURCES = \
+ lib_libopenvswitch_la_LIBADD = $(SSL_LIBS)
+ lib_libopenvswitch_la_LDFLAGS = -release $(VERSION)
+
+ lib_libopenvswitch_la_SOURCES = \
lib/aes128.c \
lib/aes128.h \
lib/async-append.h \
lib/command-line.c \
lib/command-line.h \
lib/compiler.h \
+ lib/connectivity.c \
+ lib/connectivity.h \
lib/coverage.c \
lib/coverage.h \
lib/crc32c.c \
lib/multipath.c \
lib/multipath.h \
lib/netdev-dummy.c \
+ lib/netdev-tunnel.c \
+ lib/netdev-pltap.c \
lib/netdev-provider.h \
lib/netdev-vport.c \
lib/netdev-vport.h \
lib/stream-unix.c \
lib/stream.c \
lib/stream.h \
+ lib/stdio.c \
lib/string.c \
- lib/string.h \
lib/svec.c \
lib/svec.h \
lib/table.c \
lib/timeval.h \
lib/token-bucket.c \
lib/token-bucket.h \
+ lib/tunalloc.c \
+ lib/tunalloc.h \
lib/type-props.h \
lib/unaligned.h \
lib/unicode.c \
lib/vswitch-idl.h \
lib/vtep-idl.c \
lib/vtep-idl.h
+ EXTRA_DIST += \
+ lib/stdio.h.in \
+ lib/string.h.in
- nodist_lib_libopenvswitch_a_SOURCES = \
+ nodist_lib_libopenvswitch_la_SOURCES = \
lib/dirs.c
- CLEANFILES += $(nodist_lib_libopenvswitch_a_SOURCES)
+ CLEANFILES += $(nodist_lib_libopenvswitch_la_SOURCES)
- noinst_LIBRARIES += lib/libsflow.a
- lib_libsflow_a_SOURCES = \
+ lib_LTLIBRARIES += lib/libsflow.la
+ lib_libsflow_la_LDFLAGS = -release $(VERSION)
+ lib_libsflow_la_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)
+ lib_libsflow_la_CPPFLAGS = $(AM_CPPFLAGS)
+ lib_libsflow_la_CFLAGS = $(AM_CFLAGS)
if HAVE_WNO_UNUSED
- lib_libsflow_a_CFLAGS += -Wno-unused
+ lib_libsflow_la_CFLAGS += -Wno-unused
endif
if HAVE_WNO_UNUSED_PARAMETER
- lib_libsflow_a_CFLAGS += -Wno-unused-parameter
+ lib_libsflow_la_CFLAGS += -Wno-unused-parameter
endif
if LINUX_DATAPATH
- lib_libopenvswitch_a_SOURCES += \
+ lib_libopenvswitch_la_SOURCES += \
lib/dpif-linux.c \
lib/dpif-linux.h \
lib/netdev-linux.c \
endif
if HAVE_POSIX_AIO
- lib_libopenvswitch_a_SOURCES += lib/async-append-aio.c
+ lib_libopenvswitch_la_SOURCES += lib/async-append-aio.c
else
- lib_libopenvswitch_a_SOURCES += lib/async-append-null.c
+ lib_libopenvswitch_la_SOURCES += lib/async-append-null.c
endif
if ESX
- lib_libopenvswitch_a_SOURCES += \
+ lib_libopenvswitch_la_SOURCES += \
lib/route-table-stub.c
endif
if HAVE_IF_DL
- lib_libopenvswitch_a_SOURCES += \
+ lib_libopenvswitch_la_SOURCES += \
lib/netdev-bsd.c \
lib/rtbsd.c \
lib/rtbsd.h \
endif
if HAVE_OPENSSL
- lib_libopenvswitch_a_SOURCES += lib/stream-ssl.c
- nodist_lib_libopenvswitch_a_SOURCES += lib/dhparams.c
+ lib_libopenvswitch_la_SOURCES += lib/stream-ssl.c
+ nodist_lib_libopenvswitch_la_SOURCES += lib/dhparams.c
lib/dhparams.c: lib/dh1024.pem lib/dh2048.pem lib/dh4096.pem
(echo '#include "lib/dhparams.h"' && \
openssl dhparam -C -in $(srcdir)/lib/dh1024.pem -noout && \
| sed 's/\(get_dh[0-9]*\)()/\1(void)/' > lib/dhparams.c.tmp
mv lib/dhparams.c.tmp lib/dhparams.c
else
- lib_libopenvswitch_a_SOURCES += lib/stream-nossl.c
+ lib_libopenvswitch_la_SOURCES += lib/stream-nossl.c
endif
EXTRA_DIST += \
$(MKDIR_P) $(DESTDIR)$(LOGDIR)
$(MKDIR_P) $(DESTDIR)$(DBDIR)
- if !USE_LINKER_SECTIONS
- # All distributed sources, with names adjust properly for referencing
- # from $(builddir).
- all_sources = \
- `for file in $(DIST_SOURCES); do \
- if test -f $$file; then \
- echo $$file; \
- else \
- echo $(VPATH)/$$file; \
- fi; \
- done`
-
- lib/coverage.$(OBJEXT): lib/coverage.def
- lib/coverage.def: $(DIST_SOURCES)
- sed -n 's|^COVERAGE_DEFINE(\([_a-zA-Z0-9]\{1,\}\)).*$$|COVERAGE_COUNTER(\1)|p' $(all_sources) | LC_ALL=C sort -u > $@
- CLEANFILES += lib/coverage.def
-
- lib/vlog.$(OBJEXT): lib/vlog-modules.def
- lib/vlog-modules.def: $(DIST_SOURCES)
- sed -n 's|^VLOG_DEFINE_\(THIS_\)\{0,1\}MODULE(\([_a-zA-Z0-9]\{1,\}\)).*$$|VLOG_MODULE(\2)|p' $(all_sources) | LC_ALL=C sort -u > $@
- CLEANFILES += lib/vlog-modules.def
- endif
#include "flow.h"
#include "hmap.h"
#include "list.h"
+ #include "meta-flow.h"
#include "netdev.h"
#include "netdev-vport.h"
#include "netlink.h"
static int do_del_port(struct dp_netdev *, odp_port_t port_no);
static int dpif_netdev_open(const struct dpif_class *, const char *name,
bool create, struct dpif **);
- static int dp_netdev_output_userspace(struct dp_netdev *, const struct ofpbuf *,
+ static int dp_netdev_output_userspace(struct dp_netdev *, struct ofpbuf *,
int queue_no, const struct flow *,
const struct nlattr *userdata);
static void dp_netdev_execute_actions(struct dp_netdev *, const struct flow *,
- struct ofpbuf *,
+ struct ofpbuf *, struct pkt_metadata *,
const struct nlattr *actions,
size_t actions_len);
- static void dp_netdev_port_input(struct dp_netdev *dp,
- struct dp_netdev_port *port,
- struct ofpbuf *packet, uint32_t skb_priority,
- uint32_t pkt_mark, const struct flow_tnl *tnl);
+ static void dp_netdev_port_input(struct dp_netdev *dp, struct ofpbuf *packet,
+ struct pkt_metadata *md);
static struct dpif_netdev *
dpif_netdev_cast(const struct dpif *dpif)
return class != &dpif_netdev_class;
}
+static bool
+dpif_netdev_class_is_planetlab(const struct dpif_class *class)
+{
+ return class == &dpif_planetlab_class;
+}
+
static const char *
dpif_netdev_port_open_type(const struct dpif_class *class, const char *type)
{
return strcmp(type, "internal") ? type
+ : dpif_netdev_class_is_planetlab(class) ? "pltap"
: dpif_netdev_class_is_dummy(class) ? "dummy"
: "tap";
}
{
uint32_t port_no;
- if (dp->class != &dpif_netdev_class) {
+ if (dp->class != &dpif_netdev_class &&
+ dp->class != &dpif_planetlab_class) {
const char *p;
int start_no = 0;
while (q->tail != q->head) {
struct dp_netdev_upcall *u = &q->upcalls[q->tail++ & QUEUE_MASK];
+ ofpbuf_uninit(&u->upcall.packet);
ofpbuf_uninit(&u->buf);
}
}
stats->n_hit = dp->n_hit;
stats->n_missed = dp->n_missed;
stats->n_lost = dp->n_lost;
- stats->n_masks = UINT64_MAX;
+ stats->n_masks = UINT32_MAX;
stats->n_mask_hit = UINT64_MAX;
ovs_mutex_unlock(&dp_netdev_mutex);
}
static int
- dpif_netdev_flow_mask_from_nlattrs(const struct nlattr *key, uint32_t key_len,
- const struct nlattr *mask_key,
- uint32_t mask_key_len, struct flow *flow,
- struct flow *mask)
+ dpif_netdev_mask_from_nlattrs(const struct nlattr *key, uint32_t key_len,
+ const struct nlattr *mask_key,
+ uint32_t mask_key_len, const struct flow *flow,
+ struct flow *mask)
+ {
+ if (mask_key_len) {
+ if (odp_flow_key_to_mask(mask_key, mask_key_len, mask, flow)) {
+ /* This should not happen: it indicates that
+ * odp_flow_key_from_mask() and odp_flow_key_to_mask()
+ * disagree on the acceptable form of a mask. Log the problem
+ * as an error, with enough details to enable debugging. */
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
+
+ if (!VLOG_DROP_ERR(&rl)) {
+ struct ds s;
+
+ ds_init(&s);
+ odp_flow_format(key, key_len, mask_key, mask_key_len, NULL, &s,
+ true);
+ VLOG_ERR("internal error parsing flow mask %s", ds_cstr(&s));
+ ds_destroy(&s);
+ }
+
+ return EINVAL;
+ }
+ /* Force unwildcard the in_port. */
+ mask->in_port.odp_port = u32_to_odp(UINT32_MAX);
+ } else {
+ enum mf_field_id id;
+ /* No mask key, unwildcard everything except fields whose
+ * prerequisities are not met. */
+ memset(mask, 0x0, sizeof *mask);
+
+ for (id = 0; id < MFF_N_IDS; ++id) {
+ /* Skip registers and metadata. */
+ if (!(id >= MFF_REG0 && id < MFF_REG0 + FLOW_N_REGS)
+ && id != MFF_METADATA) {
+ const struct mf_field *mf = mf_from_id(id);
+ if (mf_are_prereqs_ok(mf, flow)) {
+ mf_mask_field(mf, mask);
+ }
+ }
+ }
+ }
+
+ return 0;
+ }
+
+ static int
+ dpif_netdev_flow_from_nlattrs(const struct nlattr *key, uint32_t key_len,
+ struct flow *flow)
{
odp_port_t in_port;
- if (odp_flow_key_to_flow(key, key_len, flow)
- || (mask_key
- && odp_flow_key_to_mask(mask_key, mask_key_len, mask, flow))) {
+ if (odp_flow_key_to_flow(key, key_len, flow)) {
/* This should not happen: it indicates that odp_flow_key_from_flow()
- * and odp_flow_key_to_flow() disagree on the acceptable form of a flow
- * or odp_flow_key_from_mask() and odp_flow_key_to_mask() disagree on
- * the acceptable form of a mask. Log the problem as an error, with
- * enough details to enable debugging. */
+ * and odp_flow_key_to_flow() disagree on the acceptable form of a
+ * flow. Log the problem as an error, with enough details to enable
+ * debugging. */
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
if (!VLOG_DROP_ERR(&rl)) {
struct ds s;
ds_init(&s);
- odp_flow_format(key, key_len, mask_key, mask_key_len, NULL, &s,
- true);
+ odp_flow_format(key, key_len, NULL, 0, NULL, &s, true);
VLOG_ERR("internal error parsing flow key %s", ds_cstr(&s));
ds_destroy(&s);
}
return EINVAL;
}
- if (mask_key) {
- /* Force unwildcard the in_port. */
- mask->in_port.odp_port = u32_to_odp(UINT32_MAX);
- }
-
in_port = flow->in_port.odp_port;
if (!is_valid_port_number(in_port) && in_port != ODPP_NONE) {
return EINVAL;
return 0;
}
- static int
- dpif_netdev_flow_from_nlattrs(const struct nlattr *key, uint32_t key_len,
- struct flow *flow)
- {
- return dpif_netdev_flow_mask_from_nlattrs(key, key_len, NULL, 0, flow,
- NULL);
- }
-
static int
dpif_netdev_flow_get(const struct dpif *dpif,
const struct nlattr *nl_key, size_t nl_key_len,
struct flow_wildcards wc;
int error;
- error = dpif_netdev_flow_mask_from_nlattrs(put->key, put->key_len,
- put->mask, put->mask_len, &flow, &wc.masks);
+ error = dpif_netdev_flow_from_nlattrs(put->key, put->key_len, &flow);
+ if (error) {
+ return error;
+ }
+ error = dpif_netdev_mask_from_nlattrs(put->key, put->key_len,
+ put->mask, put->mask_len,
+ &flow, &wc.masks);
if (error) {
return error;
}
}
static int
- dpif_netdev_execute(struct dpif *dpif, const struct dpif_execute *execute)
+ dpif_netdev_execute(struct dpif *dpif, struct dpif_execute *execute)
{
struct dp_netdev *dp = get_dp_netdev(dpif);
- struct flow md;
- int error;
+ struct pkt_metadata *md = &execute->md;
+ struct flow key;
if (execute->packet->size < ETH_HEADER_LEN ||
execute->packet->size > UINT16_MAX) {
return EINVAL;
}
- /* Get packet metadata. */
- error = dpif_netdev_flow_from_nlattrs(execute->key, execute->key_len, &md);
- if (!error) {
- struct ofpbuf *copy;
- struct flow key;
-
- /* Make a deep copy of 'packet', because we might modify its data. */
- copy = ofpbuf_clone_with_headroom(execute->packet, DP_NETDEV_HEADROOM);
-
- /* Extract flow key. */
- flow_extract(copy, md.skb_priority, md.pkt_mark, &md.tunnel,
- &md.in_port, &key);
- ovs_mutex_lock(&dp_netdev_mutex);
- dp_netdev_execute_actions(dp, &key, copy,
- execute->actions, execute->actions_len);
- ovs_mutex_unlock(&dp_netdev_mutex);
- ofpbuf_delete(copy);
- }
- return error;
+ /* Extract flow key. */
+ flow_extract(execute->packet, md->skb_priority, md->pkt_mark, &md->tunnel,
+ (union flow_in_port *)&md->in_port, &key);
+ ovs_mutex_lock(&dp_netdev_mutex);
+ dp_netdev_execute_actions(dp, &key, execute->packet, md, execute->actions,
+ execute->actions_len);
+ ovs_mutex_unlock(&dp_netdev_mutex);
+ return 0;
}
static int
struct dp_netdev_upcall *u = &q->upcalls[q->tail++ & QUEUE_MASK];
*upcall = u->upcall;
- upcall->packet = buf;
ofpbuf_uninit(buf);
*buf = u->buf;
}
static void
- dp_netdev_port_input(struct dp_netdev *dp, struct dp_netdev_port *port,
- struct ofpbuf *packet, uint32_t skb_priority,
- uint32_t pkt_mark, const struct flow_tnl *tnl)
+ dp_netdev_port_input(struct dp_netdev *dp, struct ofpbuf *packet,
+ struct pkt_metadata *md)
{
struct dp_netdev_flow *netdev_flow;
struct flow key;
- union flow_in_port in_port_;
if (packet->size < ETH_HEADER_LEN) {
return;
}
- in_port_.odp_port = port->port_no;
- flow_extract(packet, skb_priority, pkt_mark, tnl, &in_port_, &key);
+ flow_extract(packet, md->skb_priority, md->pkt_mark, &md->tunnel,
+ (union flow_in_port *)&md->in_port, &key);
netdev_flow = dp_netdev_lookup_flow(dp, &key);
if (netdev_flow) {
dp_netdev_flow_used(netdev_flow, packet);
- dp_netdev_execute_actions(dp, &key, packet,
+ dp_netdev_execute_actions(dp, &key, packet, md,
netdev_flow->actions,
netdev_flow->actions_len);
dp->n_hit++;
struct dp_netdev_port *port;
struct dp_netdev *dp;
struct ofpbuf packet;
+ size_t buf_size;
ovs_mutex_lock(&dp_netdev_mutex);
dp = get_dp_netdev(dpif);
- ofpbuf_init(&packet,
- DP_NETDEV_HEADROOM + VLAN_ETH_HEADER_LEN + dp->max_mtu);
+ ofpbuf_init(&packet, 0);
+
+ buf_size = DP_NETDEV_HEADROOM + VLAN_ETH_HEADER_LEN + dp->max_mtu;
LIST_FOR_EACH (port, node, &dp->port_list) {
int error;
- /* Reset packet contents. */
+ /* Reset packet contents. Packet data may have been stolen. */
ofpbuf_clear(&packet);
- ofpbuf_reserve(&packet, DP_NETDEV_HEADROOM);
+ ofpbuf_reserve_with_tailroom(&packet, DP_NETDEV_HEADROOM, buf_size);
error = port->rx ? netdev_rx_recv(port->rx, &packet) : EOPNOTSUPP;
if (!error) {
- dp_netdev_port_input(dp, port, &packet, 0, 0, NULL);
+ struct pkt_metadata md = PKT_METADATA_INITIALIZER(port->port_no);
+ dp_netdev_port_input(dp, &packet, &md);
} else if (error != EAGAIN && error != EOPNOTSUPP) {
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
ovs_mutex_unlock(&dp_netdev_mutex);
}
+ static void
+ dp_netdev_output_port(struct dp_netdev *dp, struct ofpbuf *packet,
+ odp_port_t out_port)
+ {
+ struct dp_netdev_port *p = dp->ports[odp_to_u32(out_port)];
+ if (p) {
+ netdev_send(p->netdev, packet);
+ }
+ }
+
static int
- dp_netdev_output_userspace(struct dp_netdev *dp, const struct ofpbuf *packet,
+ dp_netdev_output_userspace(struct dp_netdev *dp, struct ofpbuf *packet,
int queue_no, const struct flow *flow,
const struct nlattr *userdata)
{
upcall->type = queue_no;
/* Allocate buffer big enough for everything. */
- buf_size = ODPUTIL_FLOW_KEY_BYTES + 2 + packet->size;
+ buf_size = ODPUTIL_FLOW_KEY_BYTES;
if (userdata) {
buf_size += NLA_ALIGN(userdata->nla_len);
}
NLA_ALIGN(userdata->nla_len));
}
- /* Put packet.
- *
- * We adjust 'data' and 'size' in 'buf' so that only the packet itself
- * is visible in 'upcall->packet'. The ODP flow and (if present)
- * userdata become part of the headroom. */
- ofpbuf_put_zeros(buf, 2);
- buf->data = ofpbuf_put(buf, packet->data, packet->size);
- buf->size = packet->size;
- upcall->packet = buf;
+ /* Steal packet data. */
+ ovs_assert(packet->source == OFPBUF_MALLOC);
+ upcall->packet = *packet;
+ ofpbuf_use(packet, NULL, 0);
seq_change(dp->queue_seq);
};
static void
- dp_netdev_action_output(void *aux_, struct ofpbuf *packet,
- const struct flow *flow OVS_UNUSED,
- odp_port_t out_port)
+ dp_execute_cb(void *aux_, struct ofpbuf *packet,
+ const struct pkt_metadata *md OVS_UNUSED,
+ const struct nlattr *a, bool may_steal)
{
struct dp_netdev_execute_aux *aux = aux_;
- struct dp_netdev_port *p = aux->dp->ports[odp_to_u32(out_port)];
- if (p) {
- netdev_send(p->netdev, packet);
- }
- }
+ int type = nl_attr_type(a);
- static void
- dp_netdev_action_userspace(void *aux_, struct ofpbuf *packet,
- const struct flow *flow OVS_UNUSED,
- const struct nlattr *a)
- {
- struct dp_netdev_execute_aux *aux = aux_;
- const struct nlattr *userdata;
+ switch ((enum ovs_action_attr)type) {
+ case OVS_ACTION_ATTR_OUTPUT:
+ dp_netdev_output_port(aux->dp, packet, u32_to_odp(nl_attr_get_u32(a)));
+ break;
+
+ case OVS_ACTION_ATTR_USERSPACE: {
+ const struct nlattr *userdata;
+
+ userdata = nl_attr_find_nested(a, OVS_USERSPACE_ATTR_USERDATA);
- userdata = nl_attr_find_nested(a, OVS_USERSPACE_ATTR_USERDATA);
- dp_netdev_output_userspace(aux->dp, packet, DPIF_UC_ACTION, aux->key,
- userdata);
+ /* Make a copy if we are not allowed to steal the packet's data. */
+ if (!may_steal) {
+ packet = ofpbuf_clone_with_headroom(packet, DP_NETDEV_HEADROOM);
+ }
+ dp_netdev_output_userspace(aux->dp, packet, DPIF_UC_ACTION, aux->key,
+ userdata);
+ if (!may_steal) {
+ ofpbuf_uninit(packet);
+ }
+ break;
+ }
+ case OVS_ACTION_ATTR_PUSH_VLAN:
+ case OVS_ACTION_ATTR_POP_VLAN:
+ case OVS_ACTION_ATTR_PUSH_MPLS:
+ case OVS_ACTION_ATTR_POP_MPLS:
+ case OVS_ACTION_ATTR_SET:
+ case OVS_ACTION_ATTR_SAMPLE:
+ case OVS_ACTION_ATTR_UNSPEC:
+ case __OVS_ACTION_ATTR_MAX:
+ OVS_NOT_REACHED();
+ }
}
static void
dp_netdev_execute_actions(struct dp_netdev *dp, const struct flow *key,
- struct ofpbuf *packet,
+ struct ofpbuf *packet, struct pkt_metadata *md,
const struct nlattr *actions, size_t actions_len)
{
struct dp_netdev_execute_aux aux = {dp, key};
- struct flow md = *key; /* Packet metadata, may be modified by actions. */
- odp_execute_actions(&aux, packet, &md, actions, actions_len,
- dp_netdev_action_output, dp_netdev_action_userspace);
+ odp_execute_actions(&aux, packet, md, actions, actions_len, dp_execute_cb);
}
+#define DPIF_NETDEV_CLASS_FUNCTIONS \
+ dpif_netdev_enumerate, \
+ dpif_netdev_port_open_type, \
+ dpif_netdev_open, \
+ dpif_netdev_close, \
+ dpif_netdev_destroy, \
+ dpif_netdev_run, \
+ dpif_netdev_wait, \
+ dpif_netdev_get_stats, \
+ dpif_netdev_port_add, \
+ dpif_netdev_port_del, \
+ dpif_netdev_port_query_by_number, \
+ dpif_netdev_port_query_by_name, \
+ dpif_netdev_get_max_ports, \
+ NULL, /* port_get_pid */ \
+ dpif_netdev_port_dump_start, \
+ dpif_netdev_port_dump_next, \
+ dpif_netdev_port_dump_done, \
+ dpif_netdev_port_poll, \
+ dpif_netdev_port_poll_wait, \
+ dpif_netdev_flow_get, \
+ dpif_netdev_flow_put, \
+ dpif_netdev_flow_del, \
+ dpif_netdev_flow_flush, \
+ dpif_netdev_flow_dump_start, \
+ dpif_netdev_flow_dump_next, \
+ dpif_netdev_flow_dump_done, \
+ dpif_netdev_execute, \
+ NULL, /* operate */ \
+ dpif_netdev_recv_set, \
+ dpif_netdev_queue_to_priority, \
+ dpif_netdev_recv, \
+ dpif_netdev_recv_wait, \
+ dpif_netdev_recv_purge, \
+
const struct dpif_class dpif_netdev_class = {
"netdev",
- dpif_netdev_enumerate,
- dpif_netdev_port_open_type,
- dpif_netdev_open,
- dpif_netdev_close,
- dpif_netdev_destroy,
- dpif_netdev_run,
- dpif_netdev_wait,
- dpif_netdev_get_stats,
- dpif_netdev_port_add,
- dpif_netdev_port_del,
- dpif_netdev_port_query_by_number,
- dpif_netdev_port_query_by_name,
- dpif_netdev_get_max_ports,
- NULL, /* port_get_pid */
- dpif_netdev_port_dump_start,
- dpif_netdev_port_dump_next,
- dpif_netdev_port_dump_done,
- dpif_netdev_port_poll,
- dpif_netdev_port_poll_wait,
- dpif_netdev_flow_get,
- dpif_netdev_flow_put,
- dpif_netdev_flow_del,
- dpif_netdev_flow_flush,
- dpif_netdev_flow_dump_start,
- dpif_netdev_flow_dump_next,
- dpif_netdev_flow_dump_done,
- dpif_netdev_execute,
- NULL, /* operate */
- dpif_netdev_recv_set,
- dpif_netdev_queue_to_priority,
- dpif_netdev_recv,
- dpif_netdev_recv_wait,
- dpif_netdev_recv_purge,
+ DPIF_NETDEV_CLASS_FUNCTIONS
+};
+
+const struct dpif_class dpif_planetlab_class = {
+ "planetlab",
+ DPIF_NETDEV_CLASS_FUNCTIONS
};
static void
"DP PORT NEW-NUMBER",
3, 3, dpif_dummy_change_port_number, NULL);
}
+
int (*flow_dump_done)(const struct dpif *dpif, void *state);
/* Performs the 'execute->actions_len' bytes of actions in
- * 'execute->actions' on the Ethernet frame specified in 'execute->packet'
- * taken from the flow specified in the 'execute->key_len' bytes of
- * 'execute->key'. ('execute->key' is mostly redundant with
- * 'execute->packet', but it contains some metadata that cannot be
- * recovered from 'execute->packet', such as tunnel and in_port.) */
- int (*execute)(struct dpif *dpif, const struct dpif_execute *execute);
+ * 'execute->actions' on the Ethernet frame in 'execute->packet'
+ * and on the packet metadata in 'execute->md'.
+ * May modify both packet and metadata. */
+ int (*execute)(struct dpif *dpif, struct dpif_execute *execute);
/* Executes each of the 'n_ops' operations in 'ops' on 'dpif', in the order
* in which they are specified, placing each operation's results in the
* '*upcall', using 'buf' for storage. Should only be called if 'recv_set'
* has been used to enable receiving packets from 'dpif'.
*
- * The implementation should point 'upcall->packet' and 'upcall->key' into
- * data in the caller-provided 'buf'. If necessary to make room, the
- * implementation may expand the data in 'buf'. (This is hardly a great
- * way to do things but it works out OK for the dpif providers that exist
- * so far.)
+ * The implementation should point 'upcall->key' and 'upcall->userdata'
+ * (if any) into data in the caller-provided 'buf'. The implementation may
+ * also use 'buf' for storing the data of 'upcall->packet'. If necessary
+ * to make room, the implementation may reallocate the data in 'buf'.
+ *
+ * The caller owns the data of 'upcall->packet' and may modify it. If
+ * packet's headroom is exhausted as it is manipulated, 'upcall->packet'
+ * will be reallocated. This requires the data of 'upcall->packet' to be
+ * released with ofpbuf_uninit() before 'upcall' is destroyed. However,
+ * when an error is returned, the 'upcall->packet' may be uninitialized
+ * and should not be released.
*
* This function must not block. If no upcall is pending when it is
* called, it should return EAGAIN without blocking. */
extern const struct dpif_class dpif_linux_class;
extern const struct dpif_class dpif_netdev_class;
+extern const struct dpif_class dpif_planetlab_class;
#ifdef __cplusplus
}
&dpif_linux_class,
#endif
&dpif_netdev_class,
+ &dpif_planetlab_class,
};
struct registered_dpif_class {
int error;
};
+ /* This is called for actions that need the context of the datapath to be
+ * meaningful. */
static void
- dpif_execute_helper_execute__(void *aux_, struct ofpbuf *packet,
- const struct flow *flow,
- const struct nlattr *actions, size_t actions_len)
+ dpif_execute_helper_cb(void *aux_, struct ofpbuf *packet,
+ const struct pkt_metadata *md,
+ const struct nlattr *action, bool may_steal OVS_UNUSED)
{
struct dpif_execute_helper_aux *aux = aux_;
struct dpif_execute execute;
- struct odputil_keybuf key_stub;
- struct ofpbuf key;
- int error;
-
- ofpbuf_use_stub(&key, &key_stub, sizeof key_stub);
- odp_flow_key_from_flow(&key, flow, flow->in_port.odp_port);
-
- execute.key = key.data;
- execute.key_len = key.size;
- execute.actions = actions;
- execute.actions_len = actions_len;
- execute.packet = packet;
- execute.needs_help = false;
-
- error = aux->dpif->dpif_class->execute(aux->dpif, &execute);
- if (error) {
- aux->error = error;
+ int type = nl_attr_type(action);
+
+ switch ((enum ovs_action_attr)type) {
+ case OVS_ACTION_ATTR_OUTPUT:
+ case OVS_ACTION_ATTR_USERSPACE:
+ execute.actions = action;
+ execute.actions_len = NLA_ALIGN(action->nla_len);
+ execute.packet = packet;
+ execute.md = *md;
+ execute.needs_help = false;
+ aux->error = aux->dpif->dpif_class->execute(aux->dpif, &execute);
+ break;
+
+ case OVS_ACTION_ATTR_PUSH_VLAN:
+ case OVS_ACTION_ATTR_POP_VLAN:
+ case OVS_ACTION_ATTR_PUSH_MPLS:
+ case OVS_ACTION_ATTR_POP_MPLS:
+ case OVS_ACTION_ATTR_SET:
+ case OVS_ACTION_ATTR_SAMPLE:
+ case OVS_ACTION_ATTR_UNSPEC:
+ case __OVS_ACTION_ATTR_MAX:
+ OVS_NOT_REACHED();
}
}
- static void
- dpif_execute_helper_output_cb(void *aux, struct ofpbuf *packet,
- const struct flow *flow, odp_port_t out_port)
- {
- uint64_t actions_stub[DIV_ROUND_UP(NL_A_U32_SIZE, 8)];
- struct ofpbuf actions;
-
- ofpbuf_use_stack(&actions, actions_stub, sizeof actions_stub);
- nl_msg_put_u32(&actions, OVS_ACTION_ATTR_OUTPUT, odp_to_u32(out_port));
-
- dpif_execute_helper_execute__(aux, packet, flow,
- actions.data, actions.size);
- }
-
- static void
- dpif_execute_helper_userspace_cb(void *aux, struct ofpbuf *packet,
- const struct flow *flow,
- const struct nlattr *action)
- {
- dpif_execute_helper_execute__(aux, packet, flow,
- action, NLA_ALIGN(action->nla_len));
- }
-
/* Executes 'execute' by performing most of the actions in userspace and
* passing the fully constructed packets to 'dpif' for output and userspace
* actions.
*
* This helps with actions that a given 'dpif' doesn't implement directly. */
static int
- dpif_execute_with_help(struct dpif *dpif, const struct dpif_execute *execute)
+ dpif_execute_with_help(struct dpif *dpif, struct dpif_execute *execute)
{
- struct dpif_execute_helper_aux aux;
- enum odp_key_fitness fit;
- struct ofpbuf *packet;
- struct flow flow;
+ struct dpif_execute_helper_aux aux = {dpif, 0};
COVERAGE_INC(dpif_execute_with_help);
- fit = odp_flow_key_to_flow(execute->key, execute->key_len, &flow);
- if (fit == ODP_FIT_ERROR) {
- return EINVAL;
- }
-
- aux.dpif = dpif;
- aux.error = 0;
-
- packet = ofpbuf_clone_with_headroom(execute->packet, VLAN_HEADER_LEN);
- odp_execute_actions(&aux, packet, &flow,
+ odp_execute_actions(&aux, execute->packet, &execute->md,
execute->actions, execute->actions_len,
- dpif_execute_helper_output_cb,
- dpif_execute_helper_userspace_cb);
- ofpbuf_delete(packet);
-
+ dpif_execute_helper_cb);
return aux.error;
}
- static int
- dpif_execute__(struct dpif *dpif, const struct dpif_execute *execute)
+ /* Causes 'dpif' to perform the 'execute->actions_len' bytes of actions in
+ * 'execute->actions' on the Ethernet frame in 'execute->packet' and on packet
+ * metadata in 'execute->md'. The implementation is allowed to modify both the
+ * '*execute->packet' and 'execute->md'.
+ *
+ * Some dpif providers do not implement every action. The Linux kernel
+ * datapath, in particular, does not implement ARP field modification. If
+ * 'needs_help' is true, the dpif layer executes in userspace all of the
+ * actions that it can, and for OVS_ACTION_ATTR_OUTPUT and
+ * OVS_ACTION_ATTR_USERSPACE actions it passes the packet through to the dpif
+ * implementation.
+ *
+ * This works even if 'execute->actions_len' is too long for a Netlink
+ * attribute.
+ *
+ * Returns 0 if successful, otherwise a positive errno value. */
+ int
+ dpif_execute(struct dpif *dpif, struct dpif_execute *execute)
{
int error;
COVERAGE_INC(dpif_execute);
if (execute->actions_len > 0) {
- error = (execute->needs_help
+ error = (execute->needs_help || nl_attr_oversized(execute->actions_len)
? dpif_execute_with_help(dpif, execute)
: dpif->dpif_class->execute(dpif, execute));
} else {
return error;
}
- /* Causes 'dpif' to perform the 'actions_len' bytes of actions in 'actions' on
- * the Ethernet frame specified in 'packet' taken from the flow specified in
- * the 'key_len' bytes of 'key'. ('key' is mostly redundant with 'packet', but
- * it contains some metadata that cannot be recovered from 'packet', such as
- * tunnel and in_port.)
- *
- * Some dpif providers do not implement every action. The Linux kernel
- * datapath, in particular, does not implement ARP field modification. If
- * 'needs_help' is true, the dpif layer executes in userspace all of the
- * actions that it can, and for OVS_ACTION_ATTR_OUTPUT and
- * OVS_ACTION_ATTR_USERSPACE actions it passes the packet through to the dpif
- * implementation.
- *
- * This works even if 'actions_len' is too long for a Netlink attribute.
- *
- * Returns 0 if successful, otherwise a positive errno value. */
- int
- dpif_execute(struct dpif *dpif,
- const struct nlattr *key, size_t key_len,
- const struct nlattr *actions, size_t actions_len,
- const struct ofpbuf *buf,
- bool needs_help)
- {
- struct dpif_execute execute;
-
- execute.key = key;
- execute.key_len = key_len;
- execute.actions = actions;
- execute.actions_len = actions_len;
- execute.packet = buf;
- execute.needs_help = needs_help || nl_attr_oversized(actions_len);
- return dpif_execute__(dpif, &execute);
- }
-
/* Executes each of the 'n_ops' operations in 'ops' on 'dpif', in the order in
* which they are specified, placing each operation's results in the "output"
* members documented in comments.
/* Help the dpif provider to execute one op. */
struct dpif_op *op = ops[0];
- op->error = dpif_execute__(dpif, &op->u.execute);
+ op->error = dpif_execute(dpif, &op->u.execute);
ops++;
n_ops--;
}
break;
case DPIF_OP_EXECUTE:
- op->error = dpif_execute__(dpif, &op->u.execute);
+ op->error = dpif_execute(dpif, &op->u.execute);
break;
default:
- NOT_REACHED();
+ OVS_NOT_REACHED();
}
}
}
* '*upcall', using 'buf' for storage. Should only be called if
* dpif_recv_set() has been used to enable receiving packets on 'dpif'.
*
- * 'upcall->packet' and 'upcall->key' point into data in the caller-provided
- * 'buf', so their memory cannot be freed separately from 'buf'. (This is
- * hardly a great way to do things but it works out OK for the dpif providers
- * and clients that exist so far.)
+ * 'upcall->key' and 'upcall->userdata' point into data in the caller-provided
+ * 'buf', so their memory cannot be freed separately from 'buf'.
+ *
+ * The caller owns the data of 'upcall->packet' and may modify it. If
+ * packet's headroom is exhausted as it is manipulated, 'upcall->packet'
+ * will be reallocated. This requires the data of 'upcall->packet' to be
+ * released with ofpbuf_uninit() before 'upcall' is destroyed. However,
+ * when an error is returned, the 'upcall->packet' may be uninitialized
+ * and should not be released.
*
* Returns 0 if successful, otherwise a positive errno value. Returns EAGAIN
* if no upcall is immediately available. */
struct ds flow;
char *packet;
- packet = ofp_packet_to_string(upcall->packet->data,
- upcall->packet->size);
+ packet = ofp_packet_to_string(upcall->packet.data,
+ upcall->packet.size);
ds_init(&flow);
odp_flow_key_format(upcall->key, upcall->key_len, &flow);
* Each "dealloc" function frees raw memory that was allocated by the the
* "alloc" function. The memory's base and derived members might not have ever
* been initialized (but if "construct" returned successfully, then it has been
- * "destruct"ed already). The "dealloc" function is not allowed to fail. */
+ * "destruct"ed already). The "dealloc" function is not allowed to fail.
+ *
+ *
+ * Device Change Notification
+ * ==========================
+ *
+ * Minimally, implementations are required to report changes to netdev flags,
+ * features, ethernet address or carrier through connectivity_seq. Changes to
+ * other properties are allowed to cause notification through this interface,
+ * although implementations should try to avoid this. connectivity_seq_get()
+ * can be used to acquire a reference to the struct seq. The interface is
+ * described in detail in seq.h. */
struct netdev_class {
/* Type of netdevs in this class, e.g. "system", "tap", "gre", etc.
*
int (*update_flags)(struct netdev *netdev, enum netdev_flags off,
enum netdev_flags on, enum netdev_flags *old_flags);
- /* Returns a sequence number which indicates changes in one of 'netdev''s
- * properties. The returned sequence number must be nonzero so that
- * callers have a value which they may use as a reset when tracking
- * 'netdev'.
- *
- * Minimally, the returned sequence number is required to change whenever
- * 'netdev''s flags, features, ethernet address, or carrier changes. The
- * returned sequence number is allowed to change even when 'netdev' doesn't
- * change, although implementations should try to avoid this. */
- unsigned int (*change_seq)(const struct netdev *netdev);
-
/* ## ------------------- ## */
/* ## netdev_rx Functions ## */
/* ## ------------------- ## */
extern const struct netdev_class netdev_bsd_class;
#endif
+extern const struct netdev_class netdev_tunnel_class;
+extern const struct netdev_class netdev_pltap_class;
+
#ifdef __cplusplus
}
#endif
#include <string.h>
#include <unistd.h>
+ #include "connectivity.h"
#include "coverage.h"
#include "dpif.h"
#include "dynamic-string.h"
#include "openflow/openflow.h"
#include "packets.h"
#include "poll-loop.h"
+ #include "seq.h"
#include "shash.h"
#include "smap.h"
#include "sset.h"
netdev_register_provider(&netdev_tap_class);
netdev_register_provider(&netdev_bsd_class);
#endif
+ netdev_register_provider(&netdev_tunnel_class);
+ netdev_register_provider(&netdev_pltap_class);
ovsthread_once_done(&once);
}
int old_ref_cnt;
atomic_add(&rc->ref_cnt, 1, &old_ref_cnt);
+ seq_change(connectivity_seq_get());
} else {
free(netdev->name);
ovs_assert(list_is_empty(&netdev->saved_flags_list));
{
if (netdev->netdev_class->set_config) {
const struct smap no_args = SMAP_INITIALIZER(&no_args);
- return netdev->netdev_class->set_config(netdev,
- args ? args : &no_args);
+ int error;
+
+ error = netdev->netdev_class->set_config(netdev,
+ args ? args : &no_args);
+ if (error) {
+ VLOG_WARN("%s: could not set configuration (%s)",
+ netdev_get_name(netdev), ovs_strerror(error));
+ }
+ return error;
} else if (args && !smap_is_empty(args)) {
VLOG_WARN("%s: arguments provided to device that is not configurable",
netdev_get_name(netdev));
}
-
return 0;
}
: EOPNOTSUPP);
}
- /* Returns a sequence number which indicates changes in one of 'netdev''s
- * properties. The returned sequence will be nonzero so that callers have a
- * value which they may use as a reset when tracking 'netdev'.
- *
- * The returned sequence number will change whenever 'netdev''s flags,
- * features, ethernet address, or carrier changes. It may change for other
- * reasons as well, or no reason at all. */
- unsigned int
- netdev_change_seq(const struct netdev *netdev)
- {
- return netdev->netdev_class->change_seq(netdev);
- }
\f
/* Returns the class type of 'netdev'.
*