diff options
author | Ben Pfaff <blp@ovn.org> | 2016-11-23 23:15:19 -0800 |
---|---|---|
committer | Ben Pfaff <blp@ovn.org> | 2016-11-30 08:46:53 -0800 |
commit | 4930ea5620375c28bbdd1c85f8f48b9431c73abe (patch) | |
tree | d4f07e580ef2ab05d6030f8e7e4ed32d8c6f2aa5 /lib | |
parent | 65d8810c5521a18399b726f5e62ab35b8b063614 (diff) | |
download | openvswitch-4930ea5620375c28bbdd1c85f8f48b9431c73abe.tar.gz |
ofp-actions: Add "ingress" and "egress" options to "sample" action.
Before Open vSwitch 2.5.90, IPFIX reports from Open vSwitch didn't include
whether the packet was ingressing or egressing the switch. Starting in
OVS 2.5.90, this information was available but only accurate if the action
included a port number that indicated a tunnel. Conflating these two does
not always make sense (not every packet involves a tunnel!), so this patch
makes it possible for the sample action to simply say whether it's for
ingress or egress.
This is difficult to test, since the "tests" directory of OVS does not have
a proper IPFIX listener. This passes those tests, plus a couple that just
verify that the actions are properly parsed and formatted. Benli did test
it end-to-end in a VMware use case.
Requested-by: Benli Ye <daniely@vmware.com>
Tested-by: Benli Ye <daniely@vmware.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Simon Horman <simon.horman@netronome.com>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/odp-util.c | 25 | ||||
-rw-r--r-- | lib/odp-util.h | 6 | ||||
-rw-r--r-- | lib/ofp-actions.c | 92 |
3 files changed, 99 insertions, 24 deletions
diff --git a/lib/odp-util.c b/lib/odp-util.c index 626a82ca2..f09aabe58 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -313,12 +313,18 @@ format_odp_userspace_action(struct ds *ds, const struct nlattr *attr) ",collector_set_id=%"PRIu32 ",obs_domain_id=%"PRIu32 ",obs_point_id=%"PRIu32 - ",output_port=%"PRIu32")", + ",output_port=%"PRIu32, cookie.flow_sample.probability, cookie.flow_sample.collector_set_id, cookie.flow_sample.obs_domain_id, cookie.flow_sample.obs_point_id, cookie.flow_sample.output_odp_port); + if (cookie.flow_sample.direction == NX_ACTION_SAMPLE_INGRESS) { + ds_put_cstr(ds, ",ingress"); + } else if (cookie.flow_sample.direction == NX_ACTION_SAMPLE_EGRESS) { + ds_put_cstr(ds, ",egress"); + } + ds_put_char(ds, ')'); } else if (userdata_len >= sizeof cookie.ipfix && cookie.type == USER_ACTION_COOKIE_IPFIX) { ds_put_format(ds, ",ipfix(output_port=%"PRIu32")", @@ -963,7 +969,7 @@ parse_odp_userspace_action(const char *s, struct ofpbuf *actions) "collector_set_id=%"SCNi32"," "obs_domain_id=%"SCNi32"," "obs_point_id=%"SCNi32"," - "output_port=%"SCNi32")%n", + "output_port=%"SCNi32"%n", &probability, &collector_set_id, &obs_domain_id, &obs_point_id, &output, &n1)) { @@ -977,6 +983,21 @@ parse_odp_userspace_action(const char *s, struct ofpbuf *actions) cookie.flow_sample.output_odp_port = u32_to_odp(output); user_data = &cookie; user_data_size = sizeof cookie.flow_sample; + + if (ovs_scan(&s[n], ",ingress%n", &n1)) { + cookie.flow_sample.direction = NX_ACTION_SAMPLE_INGRESS; + n += n1; + } else if (ovs_scan(&s[n], ",egress%n", &n1)) { + cookie.flow_sample.direction = NX_ACTION_SAMPLE_EGRESS; + n += n1; + } else { + cookie.flow_sample.direction = NX_ACTION_SAMPLE_DEFAULT; + } + if (s[n] != ')') { + res = -EINVAL; + goto out; + } + n++; } else if (ovs_scan(&s[n], ",ipfix(output_port=%"SCNi32")%n", &output, &n1) ) { n += n1; diff --git a/lib/odp-util.h b/lib/odp-util.h index 9c8b05f81..42011bccd 100644 --- a/lib/odp-util.h +++ b/lib/odp-util.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc. + * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,6 +24,7 @@ #include "flow.h" #include "hash.h" #include "openvswitch/hmap.h" +#include "openvswitch/ofp-actions.h" #include "odp-netlink.h" #include "openflow/openflow.h" #include "util.h" @@ -287,6 +288,7 @@ union user_action_cookie { uint32_t obs_domain_id; /* Observation Domain ID. */ uint32_t obs_point_id; /* Observation Point ID. */ odp_port_t output_odp_port; /* The output odp port. */ + enum nx_action_sample_direction direction; } flow_sample; struct { @@ -294,7 +296,7 @@ union user_action_cookie { odp_port_t output_odp_port; /* The output odp port. */ } ipfix; }; -BUILD_ASSERT_DECL(sizeof(union user_action_cookie) == 20); +BUILD_ASSERT_DECL(sizeof(union user_action_cookie) == 24); size_t odp_put_userspace_action(uint32_t pid, const void *userdata, size_t userdata_size, diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c index 16f0f7c09..7507558ca 100644 --- a/lib/ofp-actions.c +++ b/lib/ofp-actions.c @@ -291,6 +291,8 @@ enum ofp_raw_action_type { NXAST_RAW_SAMPLE, /* NX1.0+(38): struct nx_action_sample2. */ NXAST_RAW_SAMPLE2, + /* NX1.0+(41): struct nx_action_sample2. */ + NXAST_RAW_SAMPLE3, /* NX1.0+(34): struct nx_action_conjunction. */ NXAST_RAW_CONJUNCTION, @@ -4824,10 +4826,13 @@ struct nx_action_sample { }; OFP_ASSERT(sizeof(struct nx_action_sample) == 24); -/* Action structure for NXAST_SAMPLE2. +/* Action structure for NXAST_SAMPLE2 and NXAST_SAMPLE3. * - * This replacement for NXAST_SAMPLE makes it support exporting - * egress tunnel information. */ + * NXAST_SAMPLE2 was added in Open vSwitch 2.5.90. Compared to NXAST_SAMPLE, + * it adds support for exporting egress tunnel information. + * + * NXAST_SAMPLE3 was added in Open vSwitch 2.6.90. Compared to NXAST_SAMPLE2, + * it adds support for the 'direction' field. */ struct nx_action_sample2 { ovs_be16 type; /* OFPAT_VENDOR. */ ovs_be16 len; /* Length is 32. */ @@ -4838,7 +4843,8 @@ struct nx_action_sample2 { ovs_be32 obs_domain_id; /* ID of sampling observation domain. */ ovs_be32 obs_point_id; /* ID of sampling observation point. */ ovs_be16 sampling_port; /* Sampling port. */ - uint8_t pad[6]; /* Pad to a multiple of 8 bytes */ + uint8_t direction; /* NXAST_SAMPLE3 only. */ + uint8_t zeros[5]; /* Pad to a multiple of 8 bytes */ }; OFP_ASSERT(sizeof(struct nx_action_sample2) == 32); @@ -4855,8 +4861,8 @@ decode_NXAST_RAW_SAMPLE(const struct nx_action_sample *nas, sample->collector_set_id = ntohl(nas->collector_set_id); sample->obs_domain_id = ntohl(nas->obs_domain_id); sample->obs_point_id = ntohl(nas->obs_point_id); - /* Default value for sampling port is OFPP_NONE */ sample->sampling_port = OFPP_NONE; + sample->direction = NX_ACTION_SAMPLE_DEFAULT; if (sample->probability == 0) { return OFPERR_OFPBAC_BAD_ARGUMENT; @@ -4866,19 +4872,18 @@ decode_NXAST_RAW_SAMPLE(const struct nx_action_sample *nas, } static enum ofperr -decode_NXAST_RAW_SAMPLE2(const struct nx_action_sample2 *nas, - enum ofp_version ofp_version OVS_UNUSED, - struct ofpbuf *out) +decode_SAMPLE2(const struct nx_action_sample2 *nas, + enum ofp_raw_action_type raw, + enum nx_action_sample_direction direction, + struct ofpact_sample *sample) { - struct ofpact_sample *sample; - - sample = ofpact_put_SAMPLE(out); - sample->ofpact.raw = NXAST_RAW_SAMPLE2; + sample->ofpact.raw = raw; sample->probability = ntohs(nas->probability); sample->collector_set_id = ntohl(nas->collector_set_id); sample->obs_domain_id = ntohl(nas->obs_domain_id); sample->obs_point_id = ntohl(nas->obs_point_id); sample->sampling_port = u16_to_ofp(ntohs(nas->sampling_port)); + sample->direction = direction; if (sample->probability == 0) { return OFPERR_OFPBAC_BAD_ARGUMENT; @@ -4887,18 +4892,55 @@ decode_NXAST_RAW_SAMPLE2(const struct nx_action_sample2 *nas, return 0; } +static enum ofperr +decode_NXAST_RAW_SAMPLE2(const struct nx_action_sample2 *nas, + enum ofp_version ofp_version OVS_UNUSED, + struct ofpbuf *out) +{ + return decode_SAMPLE2(nas, NXAST_RAW_SAMPLE2, NX_ACTION_SAMPLE_DEFAULT, + ofpact_put_SAMPLE(out)); +} + +static enum ofperr +decode_NXAST_RAW_SAMPLE3(const struct nx_action_sample2 *nas, + enum ofp_version ofp_version OVS_UNUSED, + struct ofpbuf *out) +{ + struct ofpact_sample *sample = ofpact_put_SAMPLE(out); + if (!is_all_zeros(nas->zeros, sizeof nas->zeros)) { + return OFPERR_NXBRC_MUST_BE_ZERO; + } + if (nas->direction != NX_ACTION_SAMPLE_DEFAULT && + nas->direction != NX_ACTION_SAMPLE_INGRESS && + nas->direction != NX_ACTION_SAMPLE_EGRESS) { + VLOG_WARN_RL(&rl, "invalid sample direction %"PRIu8, nas->direction); + return OFPERR_OFPBAC_BAD_ARGUMENT; + } + return decode_SAMPLE2(nas, NXAST_RAW_SAMPLE3, nas->direction, sample); +} + +static void +encode_SAMPLE2(const struct ofpact_sample *sample, + struct nx_action_sample2 *nas) +{ + nas->probability = htons(sample->probability); + nas->collector_set_id = htonl(sample->collector_set_id); + nas->obs_domain_id = htonl(sample->obs_domain_id); + nas->obs_point_id = htonl(sample->obs_point_id); + nas->sampling_port = htons(ofp_to_u16(sample->sampling_port)); + nas->direction = sample->direction; +} + static void encode_SAMPLE(const struct ofpact_sample *sample, enum ofp_version ofp_version OVS_UNUSED, struct ofpbuf *out) { - if (sample->ofpact.raw == NXAST_RAW_SAMPLE2 - || sample->sampling_port != OFPP_NONE) { - struct nx_action_sample2 *nas = put_NXAST_SAMPLE2(out); - nas->probability = htons(sample->probability); - nas->collector_set_id = htonl(sample->collector_set_id); - nas->obs_domain_id = htonl(sample->obs_domain_id); - nas->obs_point_id = htonl(sample->obs_point_id); - nas->sampling_port = htons(ofp_to_u16(sample->sampling_port)); + if (sample->ofpact.raw == NXAST_RAW_SAMPLE3 + || sample->direction != NX_ACTION_SAMPLE_DEFAULT) { + encode_SAMPLE2(sample, put_NXAST_SAMPLE3(out)); + } else if (sample->ofpact.raw == NXAST_RAW_SAMPLE2 + || sample->sampling_port != OFPP_NONE) { + encode_SAMPLE2(sample, put_NXAST_SAMPLE2(out)); } else { struct nx_action_sample *nas = put_NXAST_SAMPLE(out); nas->probability = htons(sample->probability); @@ -4919,6 +4961,7 @@ parse_SAMPLE(char *arg, struct ofpbuf *ofpacts, { struct ofpact_sample *os = ofpact_put_SAMPLE(ofpacts); os->sampling_port = OFPP_NONE; + os->direction = NX_ACTION_SAMPLE_DEFAULT; char *key, *value; while (ofputil_parse_key_value(&arg, &key, &value)) { @@ -4939,6 +4982,10 @@ parse_SAMPLE(char *arg, struct ofpbuf *ofpacts, if (!ofputil_port_from_string(value, &os->sampling_port)) { error = xasprintf("%s: unknown port", value); } + } else if (!strcmp(key, "ingress")) { + os->direction = NX_ACTION_SAMPLE_INGRESS; + } else if (!strcmp(key, "egress")) { + os->direction = NX_ACTION_SAMPLE_EGRESS; } else { error = xasprintf("invalid key \"%s\" in \"sample\" argument", key); @@ -4970,6 +5017,11 @@ format_SAMPLE(const struct ofpact_sample *a, struct ds *s) ds_put_format(s, ",%ssampling_port=%s%"PRIu16, colors.param, colors.end, a->sampling_port); } + if (a->direction == NX_ACTION_SAMPLE_INGRESS) { + ds_put_format(s, ",%singress%s", colors.param, colors.end); + } else if (a->direction == NX_ACTION_SAMPLE_EGRESS) { + ds_put_format(s, ",%segress%s", colors.param, colors.end); + } ds_put_format(s, "%s)%s", colors.paren, colors.end); } |