This prevents using an older datapath from breaking forwarding.
CC: Romain Lenglet <[email protected]>
Signed-off-by: Ben Pfaff <[email protected]>
---
ofproto/ofproto-dpif-ipfix.c | 28 ++++++++++---
ofproto/ofproto-dpif-ipfix.h | 5 ++-
ofproto/ofproto-dpif.c | 91 +++++++++++++++++++++++++++++++++++++++++-
3 files changed, 116 insertions(+), 8 deletions(-)
diff --git a/ofproto/ofproto-dpif-ipfix.c b/ofproto/ofproto-dpif-ipfix.c
index a9cc73e..1a0ebae 100644
--- a/ofproto/ofproto-dpif-ipfix.c
+++ b/ofproto/ofproto-dpif-ipfix.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Nicira, Inc.
+ * Copyright (c) 2012, 2013 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -71,6 +71,7 @@ struct dpif_ipfix {
struct dpif_ipfix_bridge_exporter bridge_exporter;
struct hmap flow_exporter_map; /* dpif_ipfix_flow_exporter_map_node. */
atomic_int ref_cnt;
+ bool variable_length_userdata;
};
#define IPFIX_VERSION 0x000a
@@ -632,14 +633,21 @@ dpif_ipfix_set_options(
ovs_mutex_unlock(&mutex);
}
+/* Creates and returns a new dpif_ipfix structure.
+ *
+ * 'variable_length_userdata' specifies whether the datapath supports
+ * variable-length OVS_USERSPACE_ATTR_USERDATA in OVS_ACTION_ATTR_USERSPACE
+ * actions. A datapath that doesn't support such actions cannot support flow
+ * sampling, so the module will suppress its use. */
struct dpif_ipfix *
-dpif_ipfix_create(void)
+dpif_ipfix_create(bool variable_length_userdata)
{
struct dpif_ipfix *di;
di = xzalloc(sizeof *di);
dpif_ipfix_bridge_exporter_init(&di->bridge_exporter);
hmap_init(&di->flow_exporter_map);
atomic_init(&di->ref_cnt, 1);
+ di->variable_length_userdata = variable_length_userdata;
return di;
}
@@ -1239,13 +1247,23 @@ ipfix_send_data_msg(struct dpif_ipfix_exporter
*exporter,
}
static void
-dpif_ipfix_sample(struct dpif_ipfix_exporter *exporter,
+dpif_ipfix_sample(struct dpif_ipfix *di,
+ struct dpif_ipfix_exporter *exporter,
struct ofpbuf *packet, const struct flow *flow,
uint64_t packet_delta_count, uint32_t obs_domain_id,
uint32_t obs_point_id)
{
struct ipfix_flow_cache_entry *entry;
+ if (!di->variable_length_userdata) {
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
+
+ VLOG_ERR_RL(&rl, "ignoring NXAST_SAMPLE action because datapath "
+ "lacks support (needs Linux 3.10+ or kernel module from "
+ "OVS 1.11+)");
+ return;
+ }
+
/* Create a flow cache entry from the sample. */
entry = xmalloc(sizeof *entry);
ipfix_cache_entry_init(entry, packet, flow, packet_delta_count,
@@ -1263,7 +1281,7 @@ dpif_ipfix_bridge_sample(struct dpif_ipfix *di, struct
ofpbuf *packet,
/* Use the sampling probability as an approximation of the number
* of matched packets. */
packet_delta_count = UINT32_MAX / di->bridge_exporter.probability;
- dpif_ipfix_sample(&di->bridge_exporter.exporter, packet, flow,
+ dpif_ipfix_sample(di, &di->bridge_exporter.exporter, packet, flow,
packet_delta_count,
di->bridge_exporter.options->obs_domain_id,
di->bridge_exporter.options->obs_point_id);
@@ -1284,7 +1302,7 @@ dpif_ipfix_flow_sample(struct dpif_ipfix *di, struct
ofpbuf *packet,
ovs_mutex_lock(&mutex);
node = dpif_ipfix_find_flow_exporter_map_node(di, collector_set_id);
if (node) {
- dpif_ipfix_sample(&node->exporter.exporter, packet, flow,
+ dpif_ipfix_sample(di, &node->exporter.exporter, packet, flow,
packet_delta_count, obs_domain_id, obs_point_id);
}
ovs_mutex_unlock(&mutex);
diff --git a/ofproto/ofproto-dpif-ipfix.h b/ofproto/ofproto-dpif-ipfix.h
index 6ebf8b0..a81976c 100644
--- a/ofproto/ofproto-dpif-ipfix.h
+++ b/ofproto/ofproto-dpif-ipfix.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Nicira, Inc.
+ * Copyright (c) 2012, 2013 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
#ifndef OFPROTO_DPIF_IPFIX_H
#define OFPROTO_DPIF_IPFIX_H 1
+#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
@@ -25,7 +26,7 @@ struct ofpbuf;
struct ofproto_ipfix_bridge_exporter_options;
struct ofproto_ipfix_flow_exporter_options;
-struct dpif_ipfix *dpif_ipfix_create(void);
+struct dpif_ipfix *dpif_ipfix_create(bool variable_length_userdata);
struct dpif_ipfix *dpif_ipfix_ref(const struct dpif_ipfix *);
void dpif_ipfix_unref(struct dpif_ipfix *);
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 80e97e0..e1a690b 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -41,6 +41,7 @@
#include "netdev-vport.h"
#include "netdev.h"
#include "netlink.h"
+#include "netlink-socket.h"
#include "nx-match.h"
#include "odp-util.h"
#include "odp-execute.h"
@@ -440,6 +441,10 @@ struct dpif_backer {
/* Number of upcall handling threads. */
unsigned int n_handler_threads;
+
+ /* True if the datapath supports variable-length
+ * OVS_USERSPACE_ATTR_USERDATA in OVS_ACTION_ATTR_USERSPACE actions. */
+ bool variable_length_userdata;
};
/* All existing ofproto_backer instances, indexed by ofproto->up.type. */
@@ -1095,6 +1100,8 @@ struct odp_garbage {
odp_port_t odp_port;
};
+static bool check_variable_length_userdata(struct dpif_backer *backer);
+
static int
open_dpif_backer(const char *type, struct dpif_backer **backerp)
{
@@ -1197,6 +1204,7 @@ open_dpif_backer(const char *type, struct dpif_backer
**backerp)
close_dpif_backer(backer);
return error;
}
+ backer->variable_length_userdata = check_variable_length_userdata(backer);
udpif_recv_set(backer->udpif, n_handler_threads,
backer->recv_set_enable);
backer->n_handler_threads = n_handler_threads;
@@ -1209,6 +1217,86 @@ open_dpif_backer(const char *type, struct dpif_backer
**backerp)
return error;
}
+/* Tests whether 'backer''s datapath supports variable-length
+ * OVS_USERSPACE_ATTR_USERDATA in OVS_ACTION_ATTR_USERSPACE actions. We need
+ * to disable some features on older datapaths that don't support this
+ * feature.
+ *
+ * Returns false if 'backer' definitely does not support variable-length
+ * userdata, true if it seems to support them or if at least the error we get
+ * is ambiguous. */
+static bool
+check_variable_length_userdata(struct dpif_backer *backer)
+{
+ struct eth_header *eth;
+ struct ofpbuf actions;
+ struct ofpbuf key;
+ struct ofpbuf packet;
+ size_t start;
+ int error;
+
+ /* Compose a userspace action that will cause an ERANGE error on older
+ * datapaths that don't support variable-length userdata.
+ *
+ * We really test for using userdata longer than 8 bytes, but older
+ * datapaths accepted these, silently truncating the userdata to 8 bytes.
+ * The same older datapaths rejected userdata shorter than 8 bytes, so we
+ * test for that instead as a proxy for longer userdata support. */
+ ofpbuf_init(&actions, 64);
+ start = nl_msg_start_nested(&actions, OVS_ACTION_ATTR_USERSPACE);
+ nl_msg_put_u32(&actions, OVS_USERSPACE_ATTR_PID,
+ dpif_port_get_pid(backer->dpif, ODPP_NONE));
+ nl_msg_put_unspec_zero(&actions, OVS_USERSPACE_ATTR_USERDATA, 4);
+ nl_msg_end_nested(&actions, start);
+
+ /* Compose an ODP flow key. The key is arbitrary but it must match the
+ * packet that we compose later. */
+ ofpbuf_init(&key, 64);
+ nl_msg_put_u32(&key, OVS_KEY_ATTR_IN_PORT, 0);
+ nl_msg_put_unspec_zero(&key, OVS_KEY_ATTR_ETHERNET,
+ sizeof(struct ovs_key_ethernet));
+ nl_msg_put_be16(&key, OVS_KEY_ATTR_ETHERTYPE, htons(0x1234));
+
+ /* Compose a packet that matches the key. */
+ ofpbuf_init(&packet, ETH_HEADER_LEN);
+ eth = ofpbuf_put_zeros(&packet, ETH_HEADER_LEN);
+ eth->eth_type = htons(0x1234);
+
+ /* Execute the actions. On older datapaths this fails with -ERANGE, on
+ * newer datapaths it succeeds. */
+ error = dpif_execute(backer->dpif, key.data, key.size,
+ actions.data, actions.size, &packet);
+
+ ofpbuf_uninit(&packet);
+ ofpbuf_uninit(&key);
+ ofpbuf_uninit(&actions);
+
+ switch (error) {
+ case 0:
+ /* Variable-length userdata is supported.
+ *
+ * Purge received packets to avoid processing the nonsense packet we
+ * sent to userspace, then report success. */
+ dpif_recv_purge(backer->dpif);
+ return true;
+
+ case ERANGE:
+ /* Variable-length userdata is not supported. */
+ VLOG_WARN("%s: datapath does not support variable-length userdata "
+ "feature (needs Linux 3.10+ or kernel module from OVS "
+ "1..11+). The NXAST_SAMPLE action will be ignored.",
+ dpif_name(backer->dpif));
+ return false;
+
+ default:
+ /* Something odd happened. We're not sure whether variable-length
+ * userdata is supported. Definitely to "yes". */
+ VLOG_WARN("%s: variable-length userdata feature probe failed (%s)",
+ dpif_name(backer->dpif), ovs_strerror(error));
+ return true;
+ }
+}
+
static int
construct(struct ofproto *ofproto_)
{
@@ -1881,7 +1969,8 @@ set_ipfix(
bool has_options = bridge_exporter_options || flow_exporters_options;
if (has_options && !di) {
- di = ofproto->ipfix = dpif_ipfix_create();
+ di = ofproto->ipfix = dpif_ipfix_create(
+ ofproto->backer->variable_length_userdata);
}
if (di) {
--
1.7.10.4
_______________________________________________
dev mailing list
[email protected]
http://openvswitch.org/mailman/listinfo/dev