On Oct 10, 2013, at 2:56 PM, Romain Lenglet <rleng...@vmware.com> wrote:

> On Oct 7, 2013, at 2:33 PM, Ben Pfaff <b...@nicira.com> wrote:
> 
>> This prevents using an older datapath from breaking forwarding.
>> 
>> CC: Romain Lenglet <rleng...@vmware.com>
>> Signed-off-by: Ben Pfaff <b...@nicira.com>
>> ---
>> 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)
> 
> The *_sample() functions are called only by upcalls triggered by the 
> NXAST_SAMPLE actions.
> If the datapath doesn't support that action, there's none, so this function 
> is never called, so there's no need to do this check here.
> 
> Instead, I'd add this check into compose_ipfix_action() in 
> ofproto/ofproto-dpif-xlate.c, to call compose_sample_action() to add 
> NXAST_SAMPLE actions only if supported.

It would even be simpler to just disable IPFIX altogether with a warning log if 
that action is not supported by the datapath.

> 
>> {
>>    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
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to