Skip to content

Commit 8f0aad6

Browse files
WenyuZhangPravin B Shelar
authored andcommitted
openvswitch: Extend packet attribute for egress tunnel info
OVS vswitch has extended IPFIX exporter to export tunnel headers to improve network visibility. To export this information userspace needs to know egress tunnel for given packet. By extending packet attributes datapath can export egress tunnel info for given packet. So that userspace can ask for egress tunnel info in userspace action. This information is used to build IPFIX data for given flow. Signed-off-by: Wenyu Zhang <wenyuz@vmware.com> Acked-by: Romain Lenglet <rlenglet@vmware.com> Acked-by: Ben Pfaff <blp@nicira.com> Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
1 parent 9ba559d commit 8f0aad6

File tree

12 files changed

+275
-31
lines changed

12 files changed

+275
-31
lines changed

include/uapi/linux/openvswitch.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,11 @@ enum ovs_packet_cmd {
157157
* notification if the %OVS_ACTION_ATTR_USERSPACE action specified an
158158
* %OVS_USERSPACE_ATTR_USERDATA attribute, with the same length and content
159159
* specified there.
160+
* @OVS_PACKET_ATTR_EGRESS_TUN_KEY: Present for an %OVS_PACKET_CMD_ACTION
161+
* notification if the %OVS_ACTION_ATTR_USERSPACE action specified an
162+
* %OVS_USERSPACE_ATTR_EGRESS_TUN_PORT attribute, which is sent only if the
163+
* output port is actually a tunnel port. Contains the output tunnel key
164+
* extracted from the packet as nested %OVS_TUNNEL_KEY_ATTR_* attributes.
160165
*
161166
* These attributes follow the &struct ovs_header within the Generic Netlink
162167
* payload for %OVS_PACKET_* commands.
@@ -167,6 +172,8 @@ enum ovs_packet_attr {
167172
OVS_PACKET_ATTR_KEY, /* Nested OVS_KEY_ATTR_* attributes. */
168173
OVS_PACKET_ATTR_ACTIONS, /* Nested OVS_ACTION_ATTR_* attributes. */
169174
OVS_PACKET_ATTR_USERDATA, /* OVS_ACTION_ATTR_USERSPACE arg. */
175+
OVS_PACKET_ATTR_EGRESS_TUN_KEY, /* Nested OVS_TUNNEL_KEY_ATTR_*
176+
attributes. */
170177
__OVS_PACKET_ATTR_MAX
171178
};
172179

@@ -315,6 +322,8 @@ enum ovs_tunnel_key_attr {
315322
OVS_TUNNEL_KEY_ATTR_CSUM, /* No argument. CSUM packet. */
316323
OVS_TUNNEL_KEY_ATTR_OAM, /* No argument. OAM frame. */
317324
OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS, /* Array of Geneve options. */
325+
OVS_TUNNEL_KEY_ATTR_TP_SRC, /* be16 src Transport Port. */
326+
OVS_TUNNEL_KEY_ATTR_TP_DST, /* be16 dst Transport Port. */
318327
__OVS_TUNNEL_KEY_ATTR_MAX
319328
};
320329

@@ -480,11 +489,15 @@ enum ovs_sample_attr {
480489
* message should be sent. Required.
481490
* @OVS_USERSPACE_ATTR_USERDATA: If present, its variable-length argument is
482491
* copied to the %OVS_PACKET_CMD_ACTION message as %OVS_PACKET_ATTR_USERDATA.
492+
* @OVS_USERSPACE_ATTR_EGRESS_TUN_PORT: If present, u32 output port to get
493+
* tunnel info.
483494
*/
484495
enum ovs_userspace_attr {
485496
OVS_USERSPACE_ATTR_UNSPEC,
486497
OVS_USERSPACE_ATTR_PID, /* u32 Netlink PID to receive upcalls. */
487498
OVS_USERSPACE_ATTR_USERDATA, /* Optional user-specified cookie. */
499+
OVS_USERSPACE_ATTR_EGRESS_TUN_PORT, /* Optional, u32 output port
500+
* to get tunnel info. */
488501
__OVS_USERSPACE_ATTR_MAX
489502
};
490503

net/openvswitch/actions.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,7 @@ static void do_output(struct datapath *dp, struct sk_buff *skb, int out_port)
564564
static int output_userspace(struct datapath *dp, struct sk_buff *skb,
565565
struct sw_flow_key *key, const struct nlattr *attr)
566566
{
567+
struct ovs_tunnel_info info;
567568
struct dp_upcall_info upcall;
568569
const struct nlattr *a;
569570
int rem;
@@ -572,6 +573,7 @@ static int output_userspace(struct datapath *dp, struct sk_buff *skb,
572573
upcall.key = key;
573574
upcall.userdata = NULL;
574575
upcall.portid = 0;
576+
upcall.egress_tun_info = NULL;
575577

576578
for (a = nla_data(attr), rem = nla_len(attr); rem > 0;
577579
a = nla_next(a, &rem)) {
@@ -583,7 +585,24 @@ static int output_userspace(struct datapath *dp, struct sk_buff *skb,
583585
case OVS_USERSPACE_ATTR_PID:
584586
upcall.portid = nla_get_u32(a);
585587
break;
588+
589+
case OVS_USERSPACE_ATTR_EGRESS_TUN_PORT: {
590+
/* Get out tunnel info. */
591+
struct vport *vport;
592+
593+
vport = ovs_vport_rcu(dp, nla_get_u32(a));
594+
if (vport) {
595+
int err;
596+
597+
err = ovs_vport_get_egress_tun_info(vport, skb,
598+
&info);
599+
if (!err)
600+
upcall.egress_tun_info = &info;
601+
}
602+
break;
586603
}
604+
605+
} /* End of switch. */
587606
}
588607

589608
return ovs_dp_upcall(dp, skb, &upcall);

net/openvswitch/datapath.c

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,7 @@ void ovs_dp_process_packet(struct sk_buff *skb, struct sw_flow_key *key)
274274
upcall.key = key;
275275
upcall.userdata = NULL;
276276
upcall.portid = ovs_vport_find_upcall_portid(p, skb);
277+
upcall.egress_tun_info = NULL;
277278
error = ovs_dp_upcall(dp, skb, &upcall);
278279
if (unlikely(error))
279280
kfree_skb(skb);
@@ -375,16 +376,20 @@ static int queue_gso_packets(struct datapath *dp, struct sk_buff *skb,
375376
return err;
376377
}
377378

378-
static size_t upcall_msg_size(const struct nlattr *userdata,
379+
static size_t upcall_msg_size(const struct dp_upcall_info *upcall_info,
379380
unsigned int hdrlen)
380381
{
381382
size_t size = NLMSG_ALIGN(sizeof(struct ovs_header))
382383
+ nla_total_size(hdrlen) /* OVS_PACKET_ATTR_PACKET */
383384
+ nla_total_size(ovs_key_attr_size()); /* OVS_PACKET_ATTR_KEY */
384385

385386
/* OVS_PACKET_ATTR_USERDATA */
386-
if (userdata)
387-
size += NLA_ALIGN(userdata->nla_len);
387+
if (upcall_info->userdata)
388+
size += NLA_ALIGN(upcall_info->userdata->nla_len);
389+
390+
/* OVS_PACKET_ATTR_EGRESS_TUN_KEY */
391+
if (upcall_info->egress_tun_info)
392+
size += nla_total_size(ovs_tun_key_attr_size());
388393

389394
return size;
390395
}
@@ -440,7 +445,7 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
440445
else
441446
hlen = skb->len;
442447

443-
len = upcall_msg_size(upcall_info->userdata, hlen);
448+
len = upcall_msg_size(upcall_info, hlen);
444449
user_skb = genlmsg_new_unicast(len, &info, GFP_ATOMIC);
445450
if (!user_skb) {
446451
err = -ENOMEM;
@@ -461,6 +466,14 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
461466
nla_len(upcall_info->userdata),
462467
nla_data(upcall_info->userdata));
463468

469+
if (upcall_info->egress_tun_info) {
470+
nla = nla_nest_start(user_skb, OVS_PACKET_ATTR_EGRESS_TUN_KEY);
471+
err = ovs_nla_put_egress_tunnel_key(user_skb,
472+
upcall_info->egress_tun_info);
473+
BUG_ON(err);
474+
nla_nest_end(user_skb, nla);
475+
}
476+
464477
/* Only reserve room for attribute header, packet data is added
465478
* in skb_zerocopy() */
466479
if (!(nla = nla_reserve(user_skb, OVS_PACKET_ATTR_PACKET, 0))) {

net/openvswitch/datapath.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,12 +114,14 @@ struct ovs_skb_cb {
114114
* @pid: Netlink PID to which packet should be sent. If @pid is 0 then no
115115
* packet is sent and the packet is accounted in the datapath's @n_lost
116116
* counter.
117+
* @egress_tun_info: If nonnull, becomes %OVS_PACKET_ATTR_EGRESS_TUN_KEY.
117118
*/
118119
struct dp_upcall_info {
119120
u8 cmd;
120121
const struct sw_flow_key *key;
121122
const struct nlattr *userdata;
122123
u32 portid;
124+
const struct ovs_tunnel_info *egress_tun_info;
123125
};
124126

125127
/**

net/openvswitch/flow.h

Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ struct sk_buff;
3737

3838
/* Used to memset ovs_key_ipv4_tunnel padding. */
3939
#define OVS_TUNNEL_KEY_SIZE \
40-
(offsetof(struct ovs_key_ipv4_tunnel, ipv4_ttl) + \
41-
FIELD_SIZEOF(struct ovs_key_ipv4_tunnel, ipv4_ttl))
40+
(offsetof(struct ovs_key_ipv4_tunnel, tp_dst) + \
41+
FIELD_SIZEOF(struct ovs_key_ipv4_tunnel, tp_dst))
4242

4343
struct ovs_key_ipv4_tunnel {
4444
__be64 tun_id;
@@ -47,6 +47,8 @@ struct ovs_key_ipv4_tunnel {
4747
__be16 tun_flags;
4848
u8 ipv4_tos;
4949
u8 ipv4_ttl;
50+
__be16 tp_src;
51+
__be16 tp_dst;
5052
} __packed __aligned(4); /* Minimize padding. */
5153

5254
struct ovs_tunnel_info {
@@ -64,27 +66,59 @@ struct ovs_tunnel_info {
6466
FIELD_SIZEOF(struct sw_flow_key, tun_opts) - \
6567
opt_len))
6668

67-
static inline void ovs_flow_tun_info_init(struct ovs_tunnel_info *tun_info,
68-
const struct iphdr *iph,
69-
__be64 tun_id, __be16 tun_flags,
70-
struct geneve_opt *opts,
71-
u8 opts_len)
69+
static inline void __ovs_flow_tun_info_init(struct ovs_tunnel_info *tun_info,
70+
__be32 saddr, __be32 daddr,
71+
u8 tos, u8 ttl,
72+
__be16 tp_src,
73+
__be16 tp_dst,
74+
__be64 tun_id,
75+
__be16 tun_flags,
76+
struct geneve_opt *opts,
77+
u8 opts_len)
7278
{
7379
tun_info->tunnel.tun_id = tun_id;
74-
tun_info->tunnel.ipv4_src = iph->saddr;
75-
tun_info->tunnel.ipv4_dst = iph->daddr;
76-
tun_info->tunnel.ipv4_tos = iph->tos;
77-
tun_info->tunnel.ipv4_ttl = iph->ttl;
80+
tun_info->tunnel.ipv4_src = saddr;
81+
tun_info->tunnel.ipv4_dst = daddr;
82+
tun_info->tunnel.ipv4_tos = tos;
83+
tun_info->tunnel.ipv4_ttl = ttl;
7884
tun_info->tunnel.tun_flags = tun_flags;
7985

80-
/* clear struct padding. */
81-
memset((unsigned char *)&tun_info->tunnel + OVS_TUNNEL_KEY_SIZE, 0,
82-
sizeof(tun_info->tunnel) - OVS_TUNNEL_KEY_SIZE);
86+
/* For the tunnel types on the top of IPsec, the tp_src and tp_dst of
87+
* the upper tunnel are used.
88+
* E.g: GRE over IPSEC, the tp_src and tp_port are zero.
89+
*/
90+
tun_info->tunnel.tp_src = tp_src;
91+
tun_info->tunnel.tp_dst = tp_dst;
92+
93+
/* Clear struct padding. */
94+
if (sizeof(tun_info->tunnel) != OVS_TUNNEL_KEY_SIZE)
95+
memset((unsigned char *)&tun_info->tunnel + OVS_TUNNEL_KEY_SIZE,
96+
0, sizeof(tun_info->tunnel) - OVS_TUNNEL_KEY_SIZE);
8397

8498
tun_info->options = opts;
8599
tun_info->options_len = opts_len;
86100
}
87101

102+
static inline void ovs_flow_tun_info_init(struct ovs_tunnel_info *tun_info,
103+
const struct iphdr *iph,
104+
__be16 tp_src,
105+
__be16 tp_dst,
106+
__be64 tun_id,
107+
__be16 tun_flags,
108+
struct geneve_opt *opts,
109+
u8 opts_len)
110+
{
111+
__ovs_flow_tun_info_init(tun_info, iph->saddr, iph->daddr,
112+
iph->tos, iph->ttl,
113+
tp_src, tp_dst,
114+
tun_id, tun_flags,
115+
opts, opts_len);
116+
}
117+
118+
#define OVS_SW_FLOW_KEY_METADATA_SIZE \
119+
(offsetof(struct sw_flow_key, recirc_id) + \
120+
FIELD_SIZEOF(struct sw_flow_key, recirc_id))
121+
88122
struct sw_flow_key {
89123
u8 tun_opts[255];
90124
u8 tun_opts_len;

net/openvswitch/flow_netlink.c

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,24 @@ static bool match_validate(const struct sw_flow_match *match,
245245
return true;
246246
}
247247

248+
size_t ovs_tun_key_attr_size(void)
249+
{
250+
/* Whenever adding new OVS_TUNNEL_KEY_ FIELDS, we should consider
251+
* updating this function.
252+
*/
253+
return nla_total_size(8) /* OVS_TUNNEL_KEY_ATTR_ID */
254+
+ nla_total_size(4) /* OVS_TUNNEL_KEY_ATTR_IPV4_SRC */
255+
+ nla_total_size(4) /* OVS_TUNNEL_KEY_ATTR_IPV4_DST */
256+
+ nla_total_size(1) /* OVS_TUNNEL_KEY_ATTR_TOS */
257+
+ nla_total_size(1) /* OVS_TUNNEL_KEY_ATTR_TTL */
258+
+ nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT */
259+
+ nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_CSUM */
260+
+ nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_OAM */
261+
+ nla_total_size(256) /* OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS */
262+
+ nla_total_size(2) /* OVS_TUNNEL_KEY_ATTR_TP_SRC */
263+
+ nla_total_size(2); /* OVS_TUNNEL_KEY_ATTR_TP_DST */
264+
}
265+
248266
size_t ovs_key_attr_size(void)
249267
{
250268
/* Whenever adding new OVS_KEY_ FIELDS, we should consider
@@ -254,15 +272,7 @@ size_t ovs_key_attr_size(void)
254272

255273
return nla_total_size(4) /* OVS_KEY_ATTR_PRIORITY */
256274
+ nla_total_size(0) /* OVS_KEY_ATTR_TUNNEL */
257-
+ nla_total_size(8) /* OVS_TUNNEL_KEY_ATTR_ID */
258-
+ nla_total_size(4) /* OVS_TUNNEL_KEY_ATTR_IPV4_SRC */
259-
+ nla_total_size(4) /* OVS_TUNNEL_KEY_ATTR_IPV4_DST */
260-
+ nla_total_size(1) /* OVS_TUNNEL_KEY_ATTR_TOS */
261-
+ nla_total_size(1) /* OVS_TUNNEL_KEY_ATTR_TTL */
262-
+ nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT */
263-
+ nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_CSUM */
264-
+ nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_OAM */
265-
+ nla_total_size(256) /* OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS */
275+
+ ovs_tun_key_attr_size()
266276
+ nla_total_size(4) /* OVS_KEY_ATTR_IN_PORT */
267277
+ nla_total_size(4) /* OVS_KEY_ATTR_SKB_MARK */
268278
+ nla_total_size(4) /* OVS_KEY_ATTR_DP_HASH */
@@ -393,6 +403,8 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr,
393403
[OVS_TUNNEL_KEY_ATTR_TTL] = 1,
394404
[OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT] = 0,
395405
[OVS_TUNNEL_KEY_ATTR_CSUM] = 0,
406+
[OVS_TUNNEL_KEY_ATTR_TP_SRC] = sizeof(u16),
407+
[OVS_TUNNEL_KEY_ATTR_TP_DST] = sizeof(u16),
396408
[OVS_TUNNEL_KEY_ATTR_OAM] = 0,
397409
[OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS] = -1,
398410
};
@@ -440,6 +452,14 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr,
440452
case OVS_TUNNEL_KEY_ATTR_CSUM:
441453
tun_flags |= TUNNEL_CSUM;
442454
break;
455+
case OVS_TUNNEL_KEY_ATTR_TP_SRC:
456+
SW_FLOW_KEY_PUT(match, tun_key.tp_src,
457+
nla_get_be16(a), is_mask);
458+
break;
459+
case OVS_TUNNEL_KEY_ATTR_TP_DST:
460+
SW_FLOW_KEY_PUT(match, tun_key.tp_dst,
461+
nla_get_be16(a), is_mask);
462+
break;
443463
case OVS_TUNNEL_KEY_ATTR_OAM:
444464
tun_flags |= TUNNEL_OAM;
445465
break;
@@ -548,6 +568,12 @@ static int __ipv4_tun_to_nlattr(struct sk_buff *skb,
548568
if ((output->tun_flags & TUNNEL_CSUM) &&
549569
nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_CSUM))
550570
return -EMSGSIZE;
571+
if (output->tp_src &&
572+
nla_put_be16(skb, OVS_TUNNEL_KEY_ATTR_TP_SRC, output->tp_src))
573+
return -EMSGSIZE;
574+
if (output->tp_dst &&
575+
nla_put_be16(skb, OVS_TUNNEL_KEY_ATTR_TP_DST, output->tp_dst))
576+
return -EMSGSIZE;
551577
if ((output->tun_flags & TUNNEL_OAM) &&
552578
nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_OAM))
553579
return -EMSGSIZE;
@@ -559,7 +585,6 @@ static int __ipv4_tun_to_nlattr(struct sk_buff *skb,
559585
return 0;
560586
}
561587

562-
563588
static int ipv4_tun_to_nlattr(struct sk_buff *skb,
564589
const struct ovs_key_ipv4_tunnel *output,
565590
const struct geneve_opt *tun_opts,
@@ -580,6 +605,14 @@ static int ipv4_tun_to_nlattr(struct sk_buff *skb,
580605
return 0;
581606
}
582607

608+
int ovs_nla_put_egress_tunnel_key(struct sk_buff *skb,
609+
const struct ovs_tunnel_info *egress_tun_info)
610+
{
611+
return __ipv4_tun_to_nlattr(skb, &egress_tun_info->tunnel,
612+
egress_tun_info->options,
613+
egress_tun_info->options_len);
614+
}
615+
583616
static int metadata_from_nlattrs(struct sw_flow_match *match, u64 *attrs,
584617
const struct nlattr **a, bool is_mask)
585618
{
@@ -1653,6 +1686,7 @@ static int validate_userspace(const struct nlattr *attr)
16531686
static const struct nla_policy userspace_policy[OVS_USERSPACE_ATTR_MAX + 1] = {
16541687
[OVS_USERSPACE_ATTR_PID] = {.type = NLA_U32 },
16551688
[OVS_USERSPACE_ATTR_USERDATA] = {.type = NLA_UNSPEC },
1689+
[OVS_USERSPACE_ATTR_EGRESS_TUN_PORT] = {.type = NLA_U32 },
16561690
};
16571691
struct nlattr *a[OVS_USERSPACE_ATTR_MAX + 1];
16581692
int error;

net/openvswitch/flow_netlink.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737

3838
#include "flow.h"
3939

40+
size_t ovs_tun_key_attr_size(void);
4041
size_t ovs_key_attr_size(void);
4142

4243
void ovs_match_init(struct sw_flow_match *match,
@@ -49,6 +50,8 @@ int ovs_nla_get_flow_metadata(const struct nlattr *, struct sw_flow_key *);
4950
int ovs_nla_get_match(struct sw_flow_match *match,
5051
const struct nlattr *,
5152
const struct nlattr *);
53+
int ovs_nla_put_egress_tunnel_key(struct sk_buff *,
54+
const struct ovs_tunnel_info *);
5255

5356
int ovs_nla_copy_actions(const struct nlattr *attr,
5457
const struct sw_flow_key *key,

0 commit comments

Comments
 (0)