summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorNeil McKee <neil.mckee@inmon.com>2015-07-17 21:37:02 -0700
committerBen Pfaff <blp@nicira.com>2015-07-21 14:19:04 -0700
commit7321bda384c366ae36bbca445f235a65d8f2b1f8 (patch)
tree6f76129ee3fb02512389632a3b4a2d82b63ad7ab /lib
parent4b8df0378747a83ec2478ded1e9cefe64d6a9f86 (diff)
downloadopenvswitch-7321bda384c366ae36bbca445f235a65d8f2b1f8.tar.gz
Extend sFlow agent to report tunnel and MPLS structures
Packets are still sampled at ingress only, so the egress tunnel and/or MPLS structures are only included when there is just 1 output port. The actions are either provided by the datapath in the sample upcall or looked up in the userspace cache. The former is preferred because it is more reliable and does not present any new demands or constraints on the userspace cache, however the code falls back on the userspace lookup so that this solution can work with existing kernel datapath modules. If the lookup fails it is not critical: the compiled user-action-cookie is still available and provides the essential output port and output VLAN forwarding information just as before. The openvswitch actions can express almost any tunneling/mangling so the only totally faithful representation would be to somehow encode the whole list of flow actions in the sFlow output. However the standard sFlow tunnel structures can express most common real-world scenarios, so in parsing the actions we look for those and skip the encoding if we see anything unusual. For example, a single set(tunnel()) or tnl_push() is interpreted, but if a second such action is encountered then the egress tunnel reporting is suppressed. The sFlow standard allows "best effort" encoding so that if a field is not knowable or too onerous to look up then it can be left out. This is often the case for the layer-4 source port or even the src ip address of a tunnel. The assumption is that monitoring is enabled everywhere so a missing field can typically be seen at ingress to the next switch in the path. This patch also adds unit tests to check the sFlow encoding of set(tunnel()), tnl_push() and push_mpls() actions. The netlink attribute to request that actions be included in the upcall from the datapath is inserted for sFlow sampling only. To make that option be explicit would require further changes to the printing and parsing of actions in lib/odp-util.c, and to scripts in the test suite. Further enhancements to report on 802.1AD QinQ, 64-bit tunnel IDs, and NAT transformations can follow in future patches that make only incremental changes. Signed-off-by: Neil McKee <neil.mckee@inmon.com> [blp@nicira.com made stylistic and semantic changes] Signed-off-by: Ben Pfaff <blp@nicira.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/dpif-netlink.c2
-rw-r--r--lib/dpif.h1
-rw-r--r--lib/odp-util.c27
-rw-r--r--lib/odp-util.h1
4 files changed, 28 insertions, 3 deletions
diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c
index 3650682ff..8884a9f29 100644
--- a/lib/dpif-netlink.c
+++ b/lib/dpif-netlink.c
@@ -1969,6 +1969,7 @@ parse_odp_packet(const struct dpif_netlink *dpif, struct ofpbuf *buf,
/* OVS_PACKET_CMD_ACTION only. */
[OVS_PACKET_ATTR_USERDATA] = { .type = NL_A_UNSPEC, .optional = true },
[OVS_PACKET_ATTR_EGRESS_TUN_KEY] = { .type = NL_A_NESTED, .optional = true },
+ [OVS_PACKET_ATTR_ACTIONS] = { .type = NL_A_NESTED, .optional = true },
};
struct ovs_header *ovs_header;
@@ -2005,6 +2006,7 @@ parse_odp_packet(const struct dpif_netlink *dpif, struct ofpbuf *buf,
dpif_flow_hash(&dpif->dpif, upcall->key, upcall->key_len, &upcall->ufid);
upcall->userdata = a[OVS_PACKET_ATTR_USERDATA];
upcall->out_tun_key = a[OVS_PACKET_ATTR_EGRESS_TUN_KEY];
+ upcall->actions = a[OVS_PACKET_ATTR_ACTIONS];
/* Allow overwriting the netlink attribute header without reallocating. */
dp_packet_use_stub(&upcall->packet,
diff --git a/lib/dpif.h b/lib/dpif.h
index ba5d59763..ea9caf8bb 100644
--- a/lib/dpif.h
+++ b/lib/dpif.h
@@ -784,6 +784,7 @@ struct dpif_upcall {
/* DPIF_UC_ACTION only. */
struct nlattr *userdata; /* Argument to OVS_ACTION_ATTR_USERSPACE. */
struct nlattr *out_tun_key; /* Output tunnel key. */
+ struct nlattr *actions; /* Argument to OVS_ACTION_ATTR_USERSPACE. */
};
/* A callback to process an upcall, currently implemented only by dpif-netdev.
diff --git a/lib/odp-util.c b/lib/odp-util.c
index 0e82b12e8..eec0bfb7e 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -251,6 +251,8 @@ format_odp_userspace_action(struct ds *ds, const struct nlattr *attr)
.optional = true },
[OVS_USERSPACE_ATTR_EGRESS_TUN_PORT] = { .type = NL_A_U32,
.optional = true },
+ [OVS_USERSPACE_ATTR_ACTIONS] = { .type = NL_A_UNSPEC,
+ .optional = true },
};
struct nlattr *a[ARRAY_SIZE(ovs_userspace_policy)];
const struct nlattr *userdata_attr;
@@ -322,6 +324,10 @@ format_odp_userspace_action(struct ds *ds, const struct nlattr *attr)
}
}
+ if (a[OVS_USERSPACE_ATTR_ACTIONS]) {
+ ds_put_cstr(ds, ",actions");
+ }
+
tunnel_out_port_attr = a[OVS_USERSPACE_ATTR_EGRESS_TUN_PORT];
if (tunnel_out_port_attr) {
ds_put_format(ds, ",tunnel_out_port=%"PRIu32,
@@ -666,6 +672,7 @@ parse_odp_userspace_action(const char *s, struct ofpbuf *actions)
int n = -1;
void *user_data = NULL;
size_t user_data_size = 0;
+ bool include_actions = false;
if (!ovs_scan(s, "userspace(pid=%"SCNi32"%n", &pid, &n)) {
return -EINVAL;
@@ -754,12 +761,22 @@ parse_odp_userspace_action(const char *s, struct ofpbuf *actions)
{
int n1 = -1;
+ if (ovs_scan(&s[n], ",actions%n", &n1)) {
+ n += n1;
+ include_actions = true;
+ }
+ }
+
+ {
+ int n1 = -1;
if (ovs_scan(&s[n], ",tunnel_out_port=%"SCNi32")%n",
&tunnel_out_port, &n1)) {
- odp_put_userspace_action(pid, user_data, user_data_size, tunnel_out_port, actions);
+ odp_put_userspace_action(pid, user_data, user_data_size,
+ tunnel_out_port, include_actions, actions);
return n + n1;
} else if (s[n] == ')') {
- odp_put_userspace_action(pid, user_data, user_data_size, ODPP_NONE, actions);
+ odp_put_userspace_action(pid, user_data, user_data_size,
+ ODPP_NONE, include_actions, actions);
return n + 1;
}
}
@@ -4251,6 +4268,7 @@ size_t
odp_put_userspace_action(uint32_t pid,
const void *userdata, size_t userdata_size,
odp_port_t tunnel_out_port,
+ bool include_actions,
struct ofpbuf *odp_actions)
{
size_t userdata_ofs;
@@ -4281,6 +4299,9 @@ odp_put_userspace_action(uint32_t pid,
nl_msg_put_odp_port(odp_actions, OVS_USERSPACE_ATTR_EGRESS_TUN_PORT,
tunnel_out_port);
}
+ if (include_actions) {
+ nl_msg_put_flag(odp_actions, OVS_USERSPACE_ATTR_ACTIONS);
+ }
nl_msg_end_nested(odp_actions, offset);
return userdata_ofs;
diff --git a/lib/odp-util.h b/lib/odp-util.h
index 989bb81d3..1eaa06b04 100644
--- a/lib/odp-util.h
+++ b/lib/odp-util.h
@@ -288,6 +288,7 @@ BUILD_ASSERT_DECL(sizeof(union user_action_cookie) == 16);
size_t odp_put_userspace_action(uint32_t pid,
const void *userdata, size_t userdata_size,
odp_port_t tunnel_out_port,
+ bool include_actions,
struct ofpbuf *odp_actions);
void odp_put_tunnel_action(const struct flow_tnl *tunnel,
struct ofpbuf *odp_actions);