Skip to content

Commit d8bed68

Browse files
mishuang2017davem330
authored andcommitted
net: psample: Add tunnel support
Currently, psample can only send the packet bits after decapsulation. The tunnel information is lost. Add the tunnel support. If the sampled packet has no tunnel info, the behavior is the same as before. If it has, add a nested metadata field named PSAMPLE_ATTR_TUNNEL and include the tunnel subfields if applicable. Increase the metadata length for sampled packet with the tunnel info. If new subfields of tunnel info should be included, update the metadata length accordingly. Signed-off-by: Chris Mi <[email protected]> Reviewed-by: Jiri Pirko <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent de1b99e commit d8bed68

File tree

2 files changed

+179
-0
lines changed

2 files changed

+179
-0
lines changed

include/uapi/linux/psample.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ enum {
1111
PSAMPLE_ATTR_GROUP_SEQ,
1212
PSAMPLE_ATTR_SAMPLE_RATE,
1313
PSAMPLE_ATTR_DATA,
14+
PSAMPLE_ATTR_TUNNEL,
1415

1516
/* commands attributes */
1617
PSAMPLE_ATTR_GROUP_REFCOUNT,
@@ -25,6 +26,27 @@ enum psample_command {
2526
PSAMPLE_CMD_DEL_GROUP,
2627
};
2728

29+
enum psample_tunnel_key_attr {
30+
PSAMPLE_TUNNEL_KEY_ATTR_ID, /* be64 Tunnel ID */
31+
PSAMPLE_TUNNEL_KEY_ATTR_IPV4_SRC, /* be32 src IP address. */
32+
PSAMPLE_TUNNEL_KEY_ATTR_IPV4_DST, /* be32 dst IP address. */
33+
PSAMPLE_TUNNEL_KEY_ATTR_TOS, /* u8 Tunnel IP ToS. */
34+
PSAMPLE_TUNNEL_KEY_ATTR_TTL, /* u8 Tunnel IP TTL. */
35+
PSAMPLE_TUNNEL_KEY_ATTR_DONT_FRAGMENT, /* No argument, set DF. */
36+
PSAMPLE_TUNNEL_KEY_ATTR_CSUM, /* No argument. CSUM packet. */
37+
PSAMPLE_TUNNEL_KEY_ATTR_OAM, /* No argument. OAM frame. */
38+
PSAMPLE_TUNNEL_KEY_ATTR_GENEVE_OPTS, /* Array of Geneve options. */
39+
PSAMPLE_TUNNEL_KEY_ATTR_TP_SRC, /* be16 src Transport Port. */
40+
PSAMPLE_TUNNEL_KEY_ATTR_TP_DST, /* be16 dst Transport Port. */
41+
PSAMPLE_TUNNEL_KEY_ATTR_VXLAN_OPTS, /* Nested VXLAN opts* */
42+
PSAMPLE_TUNNEL_KEY_ATTR_IPV6_SRC, /* struct in6_addr src IPv6 address. */
43+
PSAMPLE_TUNNEL_KEY_ATTR_IPV6_DST, /* struct in6_addr dst IPv6 address. */
44+
PSAMPLE_TUNNEL_KEY_ATTR_PAD,
45+
PSAMPLE_TUNNEL_KEY_ATTR_ERSPAN_OPTS, /* struct erspan_metadata */
46+
PSAMPLE_TUNNEL_KEY_ATTR_IPV4_INFO_BRIDGE, /* No argument. IPV4_INFO_BRIDGE mode.*/
47+
__PSAMPLE_TUNNEL_KEY_ATTR_MAX
48+
};
49+
2850
/* Can be overridden at runtime by module option */
2951
#define PSAMPLE_ATTR_MAX (__PSAMPLE_ATTR_MAX - 1)
3052

net/psample/psample.c

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
#include <net/genetlink.h>
1515
#include <net/psample.h>
1616
#include <linux/spinlock.h>
17+
#include <net/ip_tunnels.h>
18+
#include <net/dst_metadata.h>
1719

1820
#define PSAMPLE_MAX_PACKET_SIZE 0xffff
1921

@@ -207,10 +209,155 @@ void psample_group_put(struct psample_group *group)
207209
}
208210
EXPORT_SYMBOL_GPL(psample_group_put);
209211

212+
static int __psample_ip_tun_to_nlattr(struct sk_buff *skb,
213+
struct ip_tunnel_info *tun_info)
214+
{
215+
unsigned short tun_proto = ip_tunnel_info_af(tun_info);
216+
const void *tun_opts = ip_tunnel_info_opts(tun_info);
217+
const struct ip_tunnel_key *tun_key = &tun_info->key;
218+
int tun_opts_len = tun_info->options_len;
219+
220+
if (tun_key->tun_flags & TUNNEL_KEY &&
221+
nla_put_be64(skb, PSAMPLE_TUNNEL_KEY_ATTR_ID, tun_key->tun_id,
222+
PSAMPLE_TUNNEL_KEY_ATTR_PAD))
223+
return -EMSGSIZE;
224+
225+
if (tun_info->mode & IP_TUNNEL_INFO_BRIDGE &&
226+
nla_put_flag(skb, PSAMPLE_TUNNEL_KEY_ATTR_IPV4_INFO_BRIDGE))
227+
return -EMSGSIZE;
228+
229+
switch (tun_proto) {
230+
case AF_INET:
231+
if (tun_key->u.ipv4.src &&
232+
nla_put_in_addr(skb, PSAMPLE_TUNNEL_KEY_ATTR_IPV4_SRC,
233+
tun_key->u.ipv4.src))
234+
return -EMSGSIZE;
235+
if (tun_key->u.ipv4.dst &&
236+
nla_put_in_addr(skb, PSAMPLE_TUNNEL_KEY_ATTR_IPV4_DST,
237+
tun_key->u.ipv4.dst))
238+
return -EMSGSIZE;
239+
break;
240+
case AF_INET6:
241+
if (!ipv6_addr_any(&tun_key->u.ipv6.src) &&
242+
nla_put_in6_addr(skb, PSAMPLE_TUNNEL_KEY_ATTR_IPV6_SRC,
243+
&tun_key->u.ipv6.src))
244+
return -EMSGSIZE;
245+
if (!ipv6_addr_any(&tun_key->u.ipv6.dst) &&
246+
nla_put_in6_addr(skb, PSAMPLE_TUNNEL_KEY_ATTR_IPV6_DST,
247+
&tun_key->u.ipv6.dst))
248+
return -EMSGSIZE;
249+
break;
250+
}
251+
if (tun_key->tos &&
252+
nla_put_u8(skb, PSAMPLE_TUNNEL_KEY_ATTR_TOS, tun_key->tos))
253+
return -EMSGSIZE;
254+
if (nla_put_u8(skb, PSAMPLE_TUNNEL_KEY_ATTR_TTL, tun_key->ttl))
255+
return -EMSGSIZE;
256+
if ((tun_key->tun_flags & TUNNEL_DONT_FRAGMENT) &&
257+
nla_put_flag(skb, PSAMPLE_TUNNEL_KEY_ATTR_DONT_FRAGMENT))
258+
return -EMSGSIZE;
259+
if ((tun_key->tun_flags & TUNNEL_CSUM) &&
260+
nla_put_flag(skb, PSAMPLE_TUNNEL_KEY_ATTR_CSUM))
261+
return -EMSGSIZE;
262+
if (tun_key->tp_src &&
263+
nla_put_be16(skb, PSAMPLE_TUNNEL_KEY_ATTR_TP_SRC, tun_key->tp_src))
264+
return -EMSGSIZE;
265+
if (tun_key->tp_dst &&
266+
nla_put_be16(skb, PSAMPLE_TUNNEL_KEY_ATTR_TP_DST, tun_key->tp_dst))
267+
return -EMSGSIZE;
268+
if ((tun_key->tun_flags & TUNNEL_OAM) &&
269+
nla_put_flag(skb, PSAMPLE_TUNNEL_KEY_ATTR_OAM))
270+
return -EMSGSIZE;
271+
if (tun_opts_len) {
272+
if (tun_key->tun_flags & TUNNEL_GENEVE_OPT &&
273+
nla_put(skb, PSAMPLE_TUNNEL_KEY_ATTR_GENEVE_OPTS,
274+
tun_opts_len, tun_opts))
275+
return -EMSGSIZE;
276+
else if (tun_key->tun_flags & TUNNEL_ERSPAN_OPT &&
277+
nla_put(skb, PSAMPLE_TUNNEL_KEY_ATTR_ERSPAN_OPTS,
278+
tun_opts_len, tun_opts))
279+
return -EMSGSIZE;
280+
}
281+
282+
return 0;
283+
}
284+
285+
static int psample_ip_tun_to_nlattr(struct sk_buff *skb,
286+
struct ip_tunnel_info *tun_info)
287+
{
288+
struct nlattr *nla;
289+
int err;
290+
291+
nla = nla_nest_start_noflag(skb, PSAMPLE_ATTR_TUNNEL);
292+
if (!nla)
293+
return -EMSGSIZE;
294+
295+
err = __psample_ip_tun_to_nlattr(skb, tun_info);
296+
if (err) {
297+
nla_nest_cancel(skb, nla);
298+
return err;
299+
}
300+
301+
nla_nest_end(skb, nla);
302+
303+
return 0;
304+
}
305+
306+
static int psample_tunnel_meta_len(struct ip_tunnel_info *tun_info)
307+
{
308+
unsigned short tun_proto = ip_tunnel_info_af(tun_info);
309+
const struct ip_tunnel_key *tun_key = &tun_info->key;
310+
int tun_opts_len = tun_info->options_len;
311+
int sum = 0;
312+
313+
if (tun_key->tun_flags & TUNNEL_KEY)
314+
sum += nla_total_size(sizeof(u64));
315+
316+
if (tun_info->mode & IP_TUNNEL_INFO_BRIDGE)
317+
sum += nla_total_size(0);
318+
319+
switch (tun_proto) {
320+
case AF_INET:
321+
if (tun_key->u.ipv4.src)
322+
sum += nla_total_size(sizeof(u32));
323+
if (tun_key->u.ipv4.dst)
324+
sum += nla_total_size(sizeof(u32));
325+
break;
326+
case AF_INET6:
327+
if (!ipv6_addr_any(&tun_key->u.ipv6.src))
328+
sum += nla_total_size(sizeof(struct in6_addr));
329+
if (!ipv6_addr_any(&tun_key->u.ipv6.dst))
330+
sum += nla_total_size(sizeof(struct in6_addr));
331+
break;
332+
}
333+
if (tun_key->tos)
334+
sum += nla_total_size(sizeof(u8));
335+
sum += nla_total_size(sizeof(u8)); /* TTL */
336+
if (tun_key->tun_flags & TUNNEL_DONT_FRAGMENT)
337+
sum += nla_total_size(0);
338+
if (tun_key->tun_flags & TUNNEL_CSUM)
339+
sum += nla_total_size(0);
340+
if (tun_key->tp_src)
341+
sum += nla_total_size(sizeof(u16));
342+
if (tun_key->tp_dst)
343+
sum += nla_total_size(sizeof(u16));
344+
if (tun_key->tun_flags & TUNNEL_OAM)
345+
sum += nla_total_size(0);
346+
if (tun_opts_len) {
347+
if (tun_key->tun_flags & TUNNEL_GENEVE_OPT)
348+
sum += nla_total_size(tun_opts_len);
349+
else if (tun_key->tun_flags & TUNNEL_ERSPAN_OPT)
350+
sum += nla_total_size(tun_opts_len);
351+
}
352+
353+
return sum;
354+
}
355+
210356
void psample_sample_packet(struct psample_group *group, struct sk_buff *skb,
211357
u32 trunc_size, int in_ifindex, int out_ifindex,
212358
u32 sample_rate)
213359
{
360+
struct ip_tunnel_info *tun_info;
214361
struct sk_buff *nl_skb;
215362
int data_len;
216363
int meta_len;
@@ -224,6 +371,10 @@ void psample_sample_packet(struct psample_group *group, struct sk_buff *skb,
224371
nla_total_size(sizeof(u32)) + /* group_num */
225372
nla_total_size(sizeof(u32)); /* seq */
226373

374+
tun_info = skb_tunnel_info(skb);
375+
if (tun_info)
376+
meta_len += psample_tunnel_meta_len(tun_info);
377+
227378
data_len = min(skb->len, trunc_size);
228379
if (meta_len + nla_total_size(data_len) > PSAMPLE_MAX_PACKET_SIZE)
229380
data_len = PSAMPLE_MAX_PACKET_SIZE - meta_len - NLA_HDRLEN
@@ -278,6 +429,12 @@ void psample_sample_packet(struct psample_group *group, struct sk_buff *skb,
278429
goto error;
279430
}
280431

432+
if (tun_info) {
433+
ret = psample_ip_tun_to_nlattr(nl_skb, tun_info);
434+
if (unlikely(ret < 0))
435+
goto error;
436+
}
437+
281438
genlmsg_end(nl_skb, data);
282439
genlmsg_multicast_netns(&psample_nl_family, group->net, nl_skb, 0,
283440
PSAMPLE_NL_MCGRP_SAMPLE, GFP_ATOMIC);

0 commit comments

Comments
 (0)