From: Giuseppe Lettieri Date: Fri, 3 Jan 2014 11:01:47 +0000 (+0100) Subject: Merge branch 'mainstream' X-Git-Tag: sliver-openvswitch-2.1.90-1~9^2 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=4b0424809b823101c969a0691fc1db0c880ae64a;hp=-c;p=sliver-openvswitch.git Merge branch 'mainstream' Conflicts: Makefile.am --- 4b0424809b823101c969a0691fc1db0c880ae64a diff --combined .gitignore index 46b638781,d2052273b..f291668b6 --- a/.gitignore +++ b/.gitignore @@@ -40,14 -40,16 +40,17 @@@ /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 diff --combined Makefile.am index adb901bfa,857708f0c..670f5f0b2 --- a/Makefile.am +++ b/Makefile.am @@@ -10,6 -10,11 +10,11 @@@ ACLOCAL_AMFLAGS = -I m 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 @@@ -56,6 -61,7 +61,7 @@@ EXTRA_DIST = INSTALL.Fedora \ INSTALL.KVM \ INSTALL.Libvirt \ + INSTALL.NetBSD \ INSTALL.RHEL \ INSTALL.SSL \ INSTALL.XenServer \ @@@ -93,7 -99,7 +99,7 @@@ MAN_FRAGMENTS MAN_ROOTS = noinst_DATA = noinst_HEADERS = - noinst_LIBRARIES = + lib_LTLIBRARIES = noinst_man_MANS = noinst_PROGRAMS = noinst_SCRIPTS = @@@ -118,7 -124,6 +124,7 @@@ ro_shell = printf '\043 Generated autom SUFFIXES += .in .in: + @mkdir -p $$(dirname $@) $(PERL) $(srcdir)/build-aux/soexpand.pl -I$(srcdir) < $< | \ sed \ -e 's,[@]PKIDIR[@],$(PKIDIR),g' \ @@@ -159,10 -164,10 +165,10 @@@ dist-hook-git: distfile @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; \ @@@ -177,7 -182,8 +183,8 @@@ distfiles: Makefil 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 @@@ -284,6 -290,7 +291,7 @@@ if LINUX_ENABLE cd datapath/linux && $(MAKE) modules_install endif + include m4/automake.mk include lib/automake.mk include ofproto/automake.mk include utilities/automake.mk @@@ -297,6 -304,5 +305,6 @@@ include rhel/automake.m 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 diff --combined lib/automake.mk index 75608a8d8,ac6ff4ae6..5e90f9f2b --- a/lib/automake.mk +++ b/lib/automake.mk @@@ -5,9 -5,12 +5,12 @@@ # 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 \ @@@ -29,6 -32,8 +32,8 @@@ 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 \ @@@ -95,8 -100,6 +100,8 @@@ 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 \ @@@ -193,8 -196,8 +198,8 @@@ 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 \ @@@ -207,8 -210,6 +212,8 @@@ 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 \ @@@ -234,29 -235,34 +239,34 @@@ 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 \ @@@ -273,18 -279,18 +283,18 @@@ 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 \ @@@ -292,8 -298,8 +302,8 @@@ 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 && \ @@@ -302,7 -308,7 +312,7 @@@ | 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 += \ @@@ -395,25 -401,3 +405,3 @@@ lib-install-data-local $(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 diff --combined lib/dpif-netdev.c index 11f010c84,6ef749566..0de602720 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@@ -40,6 -40,7 +40,7 @@@ #include "flow.h" #include "hmap.h" #include "list.h" + #include "meta-flow.h" #include "netdev.h" #include "netdev-vport.h" #include "netlink.h" @@@ -165,17 -166,15 +166,15 @@@ static int do_add_port(struct dp_netde 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) @@@ -210,17 -209,10 +209,17 @@@ dpif_netdev_class_is_dummy(const struc 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"; } @@@ -248,8 -240,7 +247,8 @@@ choose_port(struct dp_netdev *dp, cons { 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; @@@ -351,6 -342,7 +350,7 @@@ dp_netdev_purge_queues(struct dp_netde 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); } } @@@ -413,7 -405,7 +413,7 @@@ dpif_netdev_get_stats(const struct dpi 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); @@@ -796,29 -788,72 +796,72 @@@ get_dpif_flow_stats(struct dp_netdev_fl } 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); } @@@ -826,11 -861,6 +869,6 @@@ 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; @@@ -839,14 -869,6 +877,6 @@@ 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, @@@ -942,8 -964,13 +972,13 @@@ dpif_netdev_flow_put(struct dpif *dpif 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; } @@@ -1112,36 -1139,25 +1147,25 @@@ dpif_netdev_flow_dump_done(const struc } 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 @@@ -1186,7 -1202,6 +1210,6 @@@ dpif_netdev_recv(struct dpif *dpif, str struct dp_netdev_upcall *u = &q->upcalls[q->tail++ & QUEUE_MASK]; *upcall = u->upcall; - upcall->packet = buf; ofpbuf_uninit(buf); *buf = u->buf; @@@ -1236,23 -1251,21 +1259,21 @@@ dp_netdev_flow_used(struct dp_netdev_fl } 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++; @@@ -1268,22 -1281,25 +1289,25 @@@ dpif_netdev_run(struct dpif *dpif 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); @@@ -1322,8 -1338,18 +1346,18 @@@ dpif_netdev_wait(struct dpif *dpif 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) { @@@ -1337,7 -1363,7 +1371,7 @@@ 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); } @@@ -1354,15 -1380,10 +1388,10 @@@ 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); @@@ -1379,85 -1400,91 +1408,99 @@@ struct dp_netdev_execute_aux }; 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 @@@ -1529,4 -1556,3 +1572,4 @@@ dpif_dummy_register(bool override "DP PORT NEW-NUMBER", 3, 3, dpif_dummy_change_port_number, NULL); } + diff --combined lib/dpif-provider.h index f85a658d2,e16a4263f..522a31dbd --- a/lib/dpif-provider.h +++ b/lib/dpif-provider.h @@@ -311,12 -311,10 +311,10 @@@ struct dpif_class 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 @@@ -341,11 -339,17 +339,17 @@@ * '*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. */ @@@ -363,7 -367,6 +367,7 @@@ 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 } diff --combined lib/dpif.c index 7151ef9fb,2b79a6e34..aa27d62c5 --- a/lib/dpif.c +++ b/lib/dpif.c @@@ -61,7 -61,6 +61,7 @@@ static const struct dpif_class *base_dp &dpif_linux_class, #endif &dpif_netdev_class, + &dpif_planetlab_class, }; struct registered_dpif_class { @@@ -1065,97 -1064,82 +1065,82 @@@ struct dpif_execute_helper_aux 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 { @@@ -1167,40 -1151,6 +1152,6 @@@ 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. @@@ -1256,7 -1206,7 +1207,7 @@@ dpif_operate(struct dpif *dpif, struct /* 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--; } @@@ -1277,11 -1227,11 +1228,11 @@@ 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(); } } } @@@ -1317,10 -1267,15 +1268,15 @@@ dpif_recv_set(struct dpif *dpif, bool e * '*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. */ @@@ -1332,8 -1287,8 +1288,8 @@@ dpif_recv(struct dpif *dpif, struct dpi 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); diff --combined lib/netdev-provider.h index 2442b77b5,40ba944ad..f1b802343 --- a/lib/netdev-provider.h +++ b/lib/netdev-provider.h @@@ -148,7 -148,18 +148,18 @@@ struct netdev *netdev_rx_get_netdev(con * 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. * @@@ -609,17 -620,6 +620,6 @@@ 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 ## */ /* ## ------------------- ## */ @@@ -664,9 -664,6 +664,9 @@@ extern const struct netdev_class netdev 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 diff --combined lib/netdev.c index 74f5f53ee,1bcd80ff7..25d32db2a --- a/lib/netdev.c +++ b/lib/netdev.c @@@ -24,6 -24,7 +24,7 @@@ #include #include + #include "connectivity.h" #include "coverage.h" #include "dpif.h" #include "dynamic-string.h" @@@ -36,6 -37,7 +37,7 @@@ #include "openflow/openflow.h" #include "packets.h" #include "poll-loop.h" + #include "seq.h" #include "shash.h" #include "smap.h" #include "sset.h" @@@ -109,8 -111,6 +111,8 @@@ netdev_initialize(void 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); } @@@ -333,6 -333,7 +335,7 @@@ netdev_open(const char *name, const cha 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)); @@@ -388,13 -389,19 +391,19 @@@ netdev_set_config(struct netdev *netdev { 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; } @@@ -1496,18 -1503,6 +1505,6 @@@ netdev_dump_queue_stats(const struct ne : 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); - } /* Returns the class type of 'netdev'. *