Skip to content

Commit

Permalink
Extend sFlow agent to report tunnel and MPLS structures
Browse files Browse the repository at this point in the history
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 <[email protected]>
[[email protected] made stylistic and semantic changes]
Signed-off-by: Ben Pfaff <[email protected]>
  • Loading branch information
sflow authored and blp committed Jul 21, 2015
1 parent 4b8df03 commit 7321bda
Show file tree
Hide file tree
Showing 13 changed files with 948 additions and 29 deletions.
1 change: 1 addition & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Post-v2.4.0
Geneve tunnels.
- Support Multicast Listener Discovery (MLDv1 and MLDv2).
- Add 'symmetric_l3l4' and 'symmetric_l3l4+udp' hash functions.
- sFlow agent now reports tunnel and MPLS structures.


v2.4.0 - xx xxx xxxx
Expand Down
1 change: 1 addition & 0 deletions include/sparse/netinet/in.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ struct sockaddr_in6 {
#define IPPROTO_ROUTING 43
#define IPPROTO_FRAGMENT 44
#define IPPROTO_GRE 47
#define IPPROTO_ESP 50
#define IPPROTO_AH 51
#define IPPROTO_ICMPV6 58
#define IPPROTO_NONE 59
Expand Down
2 changes: 2 additions & 0 deletions lib/dpif-netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions lib/dpif.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
27 changes: 24 additions & 3 deletions lib/odp-util.c
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -752,14 +759,24 @@ 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;
}
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions lib/odp-util.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Loading

0 comments on commit 7321bda

Please sign in to comment.