Skip to content

Commit 1dd144c

Browse files
tgrafdavem330
authored andcommitted
openvswitch: Support VXLAN Group Policy extension
Introduces support for the group policy extension to the VXLAN virtual port. The extension is disabled by default and only enabled if the user has provided the respective configuration. ovs-vsctl add-port br0 vxlan0 -- \ set Interface vxlan0 type=vxlan options:exts=gbp The configuration interface to enable the extension is based on a new attribute OVS_VXLAN_EXT_GBP nested inside OVS_TUNNEL_ATTR_EXTENSION which can carry additional extensions as needed in the future. The group policy metadata is stored as binary blob (struct ovs_vxlan_opts) internally just like Geneve options but transported as nested Netlink attributes to user space. Renames the existing TUNNEL_OPTIONS_PRESENT to TUNNEL_GENEVE_OPT with the binary value kept intact, a new flag TUNNEL_VXLAN_OPT is introduced. The attributes OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS and existing OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS are implemented mutually exclusive. Signed-off-by: Thomas Graf <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 81bfe3c commit 1dd144c

File tree

6 files changed

+218
-20
lines changed

6 files changed

+218
-20
lines changed

include/net/ip_tunnels.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,10 @@ struct ip_tunnel {
9797
#define TUNNEL_DONT_FRAGMENT __cpu_to_be16(0x0100)
9898
#define TUNNEL_OAM __cpu_to_be16(0x0200)
9999
#define TUNNEL_CRIT_OPT __cpu_to_be16(0x0400)
100-
#define TUNNEL_OPTIONS_PRESENT __cpu_to_be16(0x0800)
100+
#define TUNNEL_GENEVE_OPT __cpu_to_be16(0x0800)
101+
#define TUNNEL_VXLAN_OPT __cpu_to_be16(0x1000)
102+
103+
#define TUNNEL_OPTIONS_PRESENT (TUNNEL_GENEVE_OPT | TUNNEL_VXLAN_OPT)
101104

102105
struct tnl_ptk_info {
103106
__be16 flags;

include/uapi/linux/openvswitch.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,11 +252,21 @@ enum ovs_vport_attr {
252252

253253
#define OVS_VPORT_ATTR_MAX (__OVS_VPORT_ATTR_MAX - 1)
254254

255+
enum {
256+
OVS_VXLAN_EXT_UNSPEC,
257+
OVS_VXLAN_EXT_GBP, /* Flag or __u32 */
258+
__OVS_VXLAN_EXT_MAX,
259+
};
260+
261+
#define OVS_VXLAN_EXT_MAX (__OVS_VXLAN_EXT_MAX - 1)
262+
263+
255264
/* OVS_VPORT_ATTR_OPTIONS attributes for tunnels.
256265
*/
257266
enum {
258267
OVS_TUNNEL_ATTR_UNSPEC,
259268
OVS_TUNNEL_ATTR_DST_PORT, /* 16-bit UDP port, used by L4 tunnels. */
269+
OVS_TUNNEL_ATTR_EXTENSION,
260270
__OVS_TUNNEL_ATTR_MAX
261271
};
262272

@@ -328,6 +338,7 @@ enum ovs_tunnel_key_attr {
328338
OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS, /* Array of Geneve options. */
329339
OVS_TUNNEL_KEY_ATTR_TP_SRC, /* be16 src Transport Port. */
330340
OVS_TUNNEL_KEY_ATTR_TP_DST, /* be16 dst Transport Port. */
341+
OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS, /* Nested OVS_VXLAN_EXT_* */
331342
__OVS_TUNNEL_KEY_ATTR_MAX
332343
};
333344

net/openvswitch/flow_netlink.c

Lines changed: 101 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
#include <net/mpls.h>
5050

5151
#include "flow_netlink.h"
52+
#include "vport-vxlan.h"
5253

5354
struct ovs_len_tbl {
5455
int len;
@@ -268,6 +269,9 @@ size_t ovs_tun_key_attr_size(void)
268269
+ nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_CSUM */
269270
+ nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_OAM */
270271
+ nla_total_size(256) /* OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS */
272+
/* OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS is mutually exclusive with
273+
* OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS and covered by it.
274+
*/
271275
+ nla_total_size(2) /* OVS_TUNNEL_KEY_ATTR_TP_SRC */
272276
+ nla_total_size(2); /* OVS_TUNNEL_KEY_ATTR_TP_DST */
273277
}
@@ -308,6 +312,7 @@ static const struct ovs_len_tbl ovs_tunnel_key_lens[OVS_TUNNEL_KEY_ATTR_MAX + 1]
308312
[OVS_TUNNEL_KEY_ATTR_TP_DST] = { .len = sizeof(u16) },
309313
[OVS_TUNNEL_KEY_ATTR_OAM] = { .len = 0 },
310314
[OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS] = { .len = OVS_ATTR_NESTED },
315+
[OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS] = { .len = OVS_ATTR_NESTED },
311316
};
312317

313318
/* The size of the argument for each %OVS_KEY_ATTR_* Netlink attribute. */
@@ -460,6 +465,41 @@ static int genev_tun_opt_from_nlattr(const struct nlattr *a,
460465
return 0;
461466
}
462467

468+
static const struct nla_policy vxlan_opt_policy[OVS_VXLAN_EXT_MAX + 1] = {
469+
[OVS_VXLAN_EXT_GBP] = { .type = NLA_U32 },
470+
};
471+
472+
static int vxlan_tun_opt_from_nlattr(const struct nlattr *a,
473+
struct sw_flow_match *match, bool is_mask,
474+
bool log)
475+
{
476+
struct nlattr *tb[OVS_VXLAN_EXT_MAX+1];
477+
unsigned long opt_key_offset;
478+
struct ovs_vxlan_opts opts;
479+
int err;
480+
481+
BUILD_BUG_ON(sizeof(opts) > sizeof(match->key->tun_opts));
482+
483+
err = nla_parse_nested(tb, OVS_VXLAN_EXT_MAX, a, vxlan_opt_policy);
484+
if (err < 0)
485+
return err;
486+
487+
memset(&opts, 0, sizeof(opts));
488+
489+
if (tb[OVS_VXLAN_EXT_GBP])
490+
opts.gbp = nla_get_u32(tb[OVS_VXLAN_EXT_GBP]);
491+
492+
if (!is_mask)
493+
SW_FLOW_KEY_PUT(match, tun_opts_len, sizeof(opts), false);
494+
else
495+
SW_FLOW_KEY_PUT(match, tun_opts_len, 0xff, true);
496+
497+
opt_key_offset = TUN_METADATA_OFFSET(sizeof(opts));
498+
SW_FLOW_KEY_MEMCPY_OFFSET(match, opt_key_offset, &opts, sizeof(opts),
499+
is_mask);
500+
return 0;
501+
}
502+
463503
static int ipv4_tun_from_nlattr(const struct nlattr *attr,
464504
struct sw_flow_match *match, bool is_mask,
465505
bool log)
@@ -468,6 +508,7 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr,
468508
int rem;
469509
bool ttl = false;
470510
__be16 tun_flags = 0;
511+
int opts_type = 0;
471512

472513
nla_for_each_nested(a, attr, rem) {
473514
int type = nla_type(a);
@@ -527,11 +568,30 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr,
527568
tun_flags |= TUNNEL_OAM;
528569
break;
529570
case OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS:
571+
if (opts_type) {
572+
OVS_NLERR(log, "Multiple metadata blocks provided");
573+
return -EINVAL;
574+
}
575+
530576
err = genev_tun_opt_from_nlattr(a, match, is_mask, log);
531577
if (err)
532578
return err;
533579

534-
tun_flags |= TUNNEL_OPTIONS_PRESENT;
580+
tun_flags |= TUNNEL_GENEVE_OPT;
581+
opts_type = type;
582+
break;
583+
case OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS:
584+
if (opts_type) {
585+
OVS_NLERR(log, "Multiple metadata blocks provided");
586+
return -EINVAL;
587+
}
588+
589+
err = vxlan_tun_opt_from_nlattr(a, match, is_mask, log);
590+
if (err)
591+
return err;
592+
593+
tun_flags |= TUNNEL_VXLAN_OPT;
594+
opts_type = type;
535595
break;
536596
default:
537597
OVS_NLERR(log, "Unknown IPv4 tunnel attribute %d",
@@ -560,6 +620,23 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr,
560620
}
561621
}
562622

623+
return opts_type;
624+
}
625+
626+
static int vxlan_opt_to_nlattr(struct sk_buff *skb,
627+
const void *tun_opts, int swkey_tun_opts_len)
628+
{
629+
const struct ovs_vxlan_opts *opts = tun_opts;
630+
struct nlattr *nla;
631+
632+
nla = nla_nest_start(skb, OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS);
633+
if (!nla)
634+
return -EMSGSIZE;
635+
636+
if (nla_put_u32(skb, OVS_VXLAN_EXT_GBP, opts->gbp) < 0)
637+
return -EMSGSIZE;
638+
639+
nla_nest_end(skb, nla);
563640
return 0;
564641
}
565642

@@ -596,10 +673,15 @@ static int __ipv4_tun_to_nlattr(struct sk_buff *skb,
596673
if ((output->tun_flags & TUNNEL_OAM) &&
597674
nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_OAM))
598675
return -EMSGSIZE;
599-
if (tun_opts &&
600-
nla_put(skb, OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS,
601-
swkey_tun_opts_len, tun_opts))
602-
return -EMSGSIZE;
676+
if (tun_opts) {
677+
if (output->tun_flags & TUNNEL_GENEVE_OPT &&
678+
nla_put(skb, OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS,
679+
swkey_tun_opts_len, tun_opts))
680+
return -EMSGSIZE;
681+
else if (output->tun_flags & TUNNEL_VXLAN_OPT &&
682+
vxlan_opt_to_nlattr(skb, tun_opts, swkey_tun_opts_len))
683+
return -EMSGSIZE;
684+
}
603685

604686
return 0;
605687
}
@@ -680,7 +762,7 @@ static int metadata_from_nlattrs(struct sw_flow_match *match, u64 *attrs,
680762
}
681763
if (*attrs & (1 << OVS_KEY_ATTR_TUNNEL)) {
682764
if (ipv4_tun_from_nlattr(a[OVS_KEY_ATTR_TUNNEL], match,
683-
is_mask, log))
765+
is_mask, log) < 0)
684766
return -EINVAL;
685767
*attrs &= ~(1 << OVS_KEY_ATTR_TUNNEL);
686768
}
@@ -1578,17 +1660,23 @@ static int validate_and_copy_set_tun(const struct nlattr *attr,
15781660
struct sw_flow_key key;
15791661
struct ovs_tunnel_info *tun_info;
15801662
struct nlattr *a;
1581-
int err, start;
1663+
int err, start, opts_type;
15821664

15831665
ovs_match_init(&match, &key, NULL);
1584-
err = ipv4_tun_from_nlattr(nla_data(attr), &match, false, log);
1585-
if (err)
1586-
return err;
1666+
opts_type = ipv4_tun_from_nlattr(nla_data(attr), &match, false, log);
1667+
if (opts_type < 0)
1668+
return opts_type;
15871669

15881670
if (key.tun_opts_len) {
1589-
err = validate_geneve_opts(&key);
1590-
if (err < 0)
1591-
return err;
1671+
switch (opts_type) {
1672+
case OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS:
1673+
err = validate_geneve_opts(&key);
1674+
if (err < 0)
1675+
return err;
1676+
break;
1677+
case OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS:
1678+
break;
1679+
}
15921680
};
15931681

15941682
start = add_nested_action_start(sfa, OVS_ACTION_ATTR_SET, log);

net/openvswitch/vport-geneve.c

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ static void geneve_rcv(struct geneve_sock *gs, struct sk_buff *skb)
8888

8989
opts_len = geneveh->opt_len * 4;
9090

91-
flags = TUNNEL_KEY | TUNNEL_OPTIONS_PRESENT |
91+
flags = TUNNEL_KEY | TUNNEL_GENEVE_OPT |
9292
(udp_hdr(skb)->check != 0 ? TUNNEL_CSUM : 0) |
9393
(geneveh->oam ? TUNNEL_OAM : 0) |
9494
(geneveh->critical ? TUNNEL_CRIT_OPT : 0);
@@ -178,7 +178,7 @@ static int geneve_tnl_send(struct vport *vport, struct sk_buff *skb)
178178
__be16 sport;
179179
struct rtable *rt;
180180
struct flowi4 fl;
181-
u8 vni[3];
181+
u8 vni[3], opts_len, *opts;
182182
__be16 df;
183183
int err;
184184

@@ -200,11 +200,18 @@ static int geneve_tnl_send(struct vport *vport, struct sk_buff *skb)
200200
tunnel_id_to_vni(tun_key->tun_id, vni);
201201
skb->ignore_df = 1;
202202

203+
if (tun_key->tun_flags & TUNNEL_GENEVE_OPT) {
204+
opts = (u8 *)tun_info->options;
205+
opts_len = tun_info->options_len;
206+
} else {
207+
opts = NULL;
208+
opts_len = 0;
209+
}
210+
203211
err = geneve_xmit_skb(geneve_port->gs, rt, skb, fl.saddr,
204212
tun_key->ipv4_dst, tun_key->ipv4_tos,
205213
tun_key->ipv4_ttl, df, sport, dport,
206-
tun_key->tun_flags, vni,
207-
tun_info->options_len, (u8 *)tun_info->options,
214+
tun_key->tun_flags, vni, opts_len, opts,
208215
false);
209216
if (err < 0)
210217
ip_rt_put(rt);

0 commit comments

Comments
 (0)