aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Graf <tgraf@suug.ch>2015-01-14 21:53:59 -0500
committerDavid S. Miller <davem@davemloft.net>2015-01-15 01:11:41 -0500
commit1dd144cf5b4b47e12438c2c6883925ce1a9b499f (patch)
treed5442581624a3ff7f3b4d91d193ba5928cc98328
parent81bfe3c3cf153441588e50a57f53bc9816f37d37 (diff)
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 <tgraf@suug.ch> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/ip_tunnels.h5
-rw-r--r--include/uapi/linux/openvswitch.h11
-rw-r--r--net/openvswitch/flow_netlink.c114
-rw-r--r--net/openvswitch/vport-geneve.c15
-rw-r--r--net/openvswitch/vport-vxlan.c82
-rw-r--r--net/openvswitch/vport-vxlan.h11
6 files changed, 218 insertions, 20 deletions
diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h
index 25a59eb388a6..ce4db3cc5647 100644
--- a/include/net/ip_tunnels.h
+++ b/include/net/ip_tunnels.h
@@ -97,7 +97,10 @@ struct ip_tunnel {
97#define TUNNEL_DONT_FRAGMENT __cpu_to_be16(0x0100) 97#define TUNNEL_DONT_FRAGMENT __cpu_to_be16(0x0100)
98#define TUNNEL_OAM __cpu_to_be16(0x0200) 98#define TUNNEL_OAM __cpu_to_be16(0x0200)
99#define TUNNEL_CRIT_OPT __cpu_to_be16(0x0400) 99#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)
101 104
102struct tnl_ptk_info { 105struct tnl_ptk_info {
103 __be16 flags; 106 __be16 flags;
diff --git a/include/uapi/linux/openvswitch.h b/include/uapi/linux/openvswitch.h
index f714e8633352..cd8d933963c2 100644
--- a/include/uapi/linux/openvswitch.h
+++ b/include/uapi/linux/openvswitch.h
@@ -252,11 +252,21 @@ enum ovs_vport_attr {
252 252
253#define OVS_VPORT_ATTR_MAX (__OVS_VPORT_ATTR_MAX - 1) 253#define OVS_VPORT_ATTR_MAX (__OVS_VPORT_ATTR_MAX - 1)
254 254
255enum {
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
255/* OVS_VPORT_ATTR_OPTIONS attributes for tunnels. 264/* OVS_VPORT_ATTR_OPTIONS attributes for tunnels.
256 */ 265 */
257enum { 266enum {
258 OVS_TUNNEL_ATTR_UNSPEC, 267 OVS_TUNNEL_ATTR_UNSPEC,
259 OVS_TUNNEL_ATTR_DST_PORT, /* 16-bit UDP port, used by L4 tunnels. */ 268 OVS_TUNNEL_ATTR_DST_PORT, /* 16-bit UDP port, used by L4 tunnels. */
269 OVS_TUNNEL_ATTR_EXTENSION,
260 __OVS_TUNNEL_ATTR_MAX 270 __OVS_TUNNEL_ATTR_MAX
261}; 271};
262 272
@@ -328,6 +338,7 @@ enum ovs_tunnel_key_attr {
328 OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS, /* Array of Geneve options. */ 338 OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS, /* Array of Geneve options. */
329 OVS_TUNNEL_KEY_ATTR_TP_SRC, /* be16 src Transport Port. */ 339 OVS_TUNNEL_KEY_ATTR_TP_SRC, /* be16 src Transport Port. */
330 OVS_TUNNEL_KEY_ATTR_TP_DST, /* be16 dst Transport Port. */ 340 OVS_TUNNEL_KEY_ATTR_TP_DST, /* be16 dst Transport Port. */
341 OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS, /* Nested OVS_VXLAN_EXT_* */
331 __OVS_TUNNEL_KEY_ATTR_MAX 342 __OVS_TUNNEL_KEY_ATTR_MAX
332}; 343};
333 344
diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c
index 518941c5bdf1..d210d1be3470 100644
--- a/net/openvswitch/flow_netlink.c
+++ b/net/openvswitch/flow_netlink.c
@@ -49,6 +49,7 @@
49#include <net/mpls.h> 49#include <net/mpls.h>
50 50
51#include "flow_netlink.h" 51#include "flow_netlink.h"
52#include "vport-vxlan.h"
52 53
53struct ovs_len_tbl { 54struct ovs_len_tbl {
54 int len; 55 int len;
@@ -268,6 +269,9 @@ size_t ovs_tun_key_attr_size(void)
268 + nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_CSUM */ 269 + nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_CSUM */
269 + nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_OAM */ 270 + nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_OAM */
270 + nla_total_size(256) /* OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS */ 271 + 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 */
271 + nla_total_size(2) /* OVS_TUNNEL_KEY_ATTR_TP_SRC */ 275 + nla_total_size(2) /* OVS_TUNNEL_KEY_ATTR_TP_SRC */
272 + nla_total_size(2); /* OVS_TUNNEL_KEY_ATTR_TP_DST */ 276 + nla_total_size(2); /* OVS_TUNNEL_KEY_ATTR_TP_DST */
273} 277}
@@ -308,6 +312,7 @@ static const struct ovs_len_tbl ovs_tunnel_key_lens[OVS_TUNNEL_KEY_ATTR_MAX + 1]
308 [OVS_TUNNEL_KEY_ATTR_TP_DST] = { .len = sizeof(u16) }, 312 [OVS_TUNNEL_KEY_ATTR_TP_DST] = { .len = sizeof(u16) },
309 [OVS_TUNNEL_KEY_ATTR_OAM] = { .len = 0 }, 313 [OVS_TUNNEL_KEY_ATTR_OAM] = { .len = 0 },
310 [OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS] = { .len = OVS_ATTR_NESTED }, 314 [OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS] = { .len = OVS_ATTR_NESTED },
315 [OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS] = { .len = OVS_ATTR_NESTED },
311}; 316};
312 317
313/* The size of the argument for each %OVS_KEY_ATTR_* Netlink attribute. */ 318/* 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,
460 return 0; 465 return 0;
461} 466}
462 467
468static const struct nla_policy vxlan_opt_policy[OVS_VXLAN_EXT_MAX + 1] = {
469 [OVS_VXLAN_EXT_GBP] = { .type = NLA_U32 },
470};
471
472static 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
463static int ipv4_tun_from_nlattr(const struct nlattr *attr, 503static int ipv4_tun_from_nlattr(const struct nlattr *attr,
464 struct sw_flow_match *match, bool is_mask, 504 struct sw_flow_match *match, bool is_mask,
465 bool log) 505 bool log)
@@ -468,6 +508,7 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr,
468 int rem; 508 int rem;
469 bool ttl = false; 509 bool ttl = false;
470 __be16 tun_flags = 0; 510 __be16 tun_flags = 0;
511 int opts_type = 0;
471 512
472 nla_for_each_nested(a, attr, rem) { 513 nla_for_each_nested(a, attr, rem) {
473 int type = nla_type(a); 514 int type = nla_type(a);
@@ -527,11 +568,30 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr,
527 tun_flags |= TUNNEL_OAM; 568 tun_flags |= TUNNEL_OAM;
528 break; 569 break;
529 case OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS: 570 case OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS:
571 if (opts_type) {
572 OVS_NLERR(log, "Multiple metadata blocks provided");
573 return -EINVAL;
574 }
575
530 err = genev_tun_opt_from_nlattr(a, match, is_mask, log); 576 err = genev_tun_opt_from_nlattr(a, match, is_mask, log);
531 if (err) 577 if (err)
532 return err; 578 return err;
533 579
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;
535 break; 595 break;
536 default: 596 default:
537 OVS_NLERR(log, "Unknown IPv4 tunnel attribute %d", 597 OVS_NLERR(log, "Unknown IPv4 tunnel attribute %d",
@@ -560,6 +620,23 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr,
560 } 620 }
561 } 621 }
562 622
623 return opts_type;
624}
625
626static 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);
563 return 0; 640 return 0;
564} 641}
565 642
@@ -596,10 +673,15 @@ static int __ipv4_tun_to_nlattr(struct sk_buff *skb,
596 if ((output->tun_flags & TUNNEL_OAM) && 673 if ((output->tun_flags & TUNNEL_OAM) &&
597 nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_OAM)) 674 nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_OAM))
598 return -EMSGSIZE; 675 return -EMSGSIZE;
599 if (tun_opts && 676 if (tun_opts) {
600 nla_put(skb, OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS, 677 if (output->tun_flags & TUNNEL_GENEVE_OPT &&
601 swkey_tun_opts_len, tun_opts)) 678 nla_put(skb, OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS,
602 return -EMSGSIZE; 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 }
603 685
604 return 0; 686 return 0;
605} 687}
@@ -680,7 +762,7 @@ static int metadata_from_nlattrs(struct sw_flow_match *match, u64 *attrs,
680 } 762 }
681 if (*attrs & (1 << OVS_KEY_ATTR_TUNNEL)) { 763 if (*attrs & (1 << OVS_KEY_ATTR_TUNNEL)) {
682 if (ipv4_tun_from_nlattr(a[OVS_KEY_ATTR_TUNNEL], match, 764 if (ipv4_tun_from_nlattr(a[OVS_KEY_ATTR_TUNNEL], match,
683 is_mask, log)) 765 is_mask, log) < 0)
684 return -EINVAL; 766 return -EINVAL;
685 *attrs &= ~(1 << OVS_KEY_ATTR_TUNNEL); 767 *attrs &= ~(1 << OVS_KEY_ATTR_TUNNEL);
686 } 768 }
@@ -1578,17 +1660,23 @@ static int validate_and_copy_set_tun(const struct nlattr *attr,
1578 struct sw_flow_key key; 1660 struct sw_flow_key key;
1579 struct ovs_tunnel_info *tun_info; 1661 struct ovs_tunnel_info *tun_info;
1580 struct nlattr *a; 1662 struct nlattr *a;
1581 int err, start; 1663 int err, start, opts_type;
1582 1664
1583 ovs_match_init(&match, &key, NULL); 1665 ovs_match_init(&match, &key, NULL);
1584 err = ipv4_tun_from_nlattr(nla_data(attr), &match, false, log); 1666 opts_type = ipv4_tun_from_nlattr(nla_data(attr), &match, false, log);
1585 if (err) 1667 if (opts_type < 0)
1586 return err; 1668 return opts_type;
1587 1669
1588 if (key.tun_opts_len) { 1670 if (key.tun_opts_len) {
1589 err = validate_geneve_opts(&key); 1671 switch (opts_type) {
1590 if (err < 0) 1672 case OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS:
1591 return err; 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 }
1592 }; 1680 };
1593 1681
1594 start = add_nested_action_start(sfa, OVS_ACTION_ATTR_SET, log); 1682 start = add_nested_action_start(sfa, OVS_ACTION_ATTR_SET, log);
diff --git a/net/openvswitch/vport-geneve.c b/net/openvswitch/vport-geneve.c
index 88a010c98c05..7ca3d454ff3b 100644
--- a/net/openvswitch/vport-geneve.c
+++ b/net/openvswitch/vport-geneve.c
@@ -88,7 +88,7 @@ static void geneve_rcv(struct geneve_sock *gs, struct sk_buff *skb)
88 88
89 opts_len = geneveh->opt_len * 4; 89 opts_len = geneveh->opt_len * 4;
90 90
91 flags = TUNNEL_KEY | TUNNEL_OPTIONS_PRESENT | 91 flags = TUNNEL_KEY | TUNNEL_GENEVE_OPT |
92 (udp_hdr(skb)->check != 0 ? TUNNEL_CSUM : 0) | 92 (udp_hdr(skb)->check != 0 ? TUNNEL_CSUM : 0) |
93 (geneveh->oam ? TUNNEL_OAM : 0) | 93 (geneveh->oam ? TUNNEL_OAM : 0) |
94 (geneveh->critical ? TUNNEL_CRIT_OPT : 0); 94 (geneveh->critical ? TUNNEL_CRIT_OPT : 0);
@@ -178,7 +178,7 @@ static int geneve_tnl_send(struct vport *vport, struct sk_buff *skb)
178 __be16 sport; 178 __be16 sport;
179 struct rtable *rt; 179 struct rtable *rt;
180 struct flowi4 fl; 180 struct flowi4 fl;
181 u8 vni[3]; 181 u8 vni[3], opts_len, *opts;
182 __be16 df; 182 __be16 df;
183 int err; 183 int err;
184 184
@@ -200,11 +200,18 @@ static int geneve_tnl_send(struct vport *vport, struct sk_buff *skb)
200 tunnel_id_to_vni(tun_key->tun_id, vni); 200 tunnel_id_to_vni(tun_key->tun_id, vni);
201 skb->ignore_df = 1; 201 skb->ignore_df = 1;
202 202
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
203 err = geneve_xmit_skb(geneve_port->gs, rt, skb, fl.saddr, 211 err = geneve_xmit_skb(geneve_port->gs, rt, skb, fl.saddr,
204 tun_key->ipv4_dst, tun_key->ipv4_tos, 212 tun_key->ipv4_dst, tun_key->ipv4_tos,
205 tun_key->ipv4_ttl, df, sport, dport, 213 tun_key->ipv4_ttl, df, sport, dport,
206 tun_key->tun_flags, vni, 214 tun_key->tun_flags, vni, opts_len, opts,
207 tun_info->options_len, (u8 *)tun_info->options,
208 false); 215 false);
209 if (err < 0) 216 if (err < 0)
210 ip_rt_put(rt); 217 ip_rt_put(rt);
diff --git a/net/openvswitch/vport-vxlan.c b/net/openvswitch/vport-vxlan.c
index 9919d71c52c3..8a2d54cba9ba 100644
--- a/net/openvswitch/vport-vxlan.c
+++ b/net/openvswitch/vport-vxlan.c
@@ -40,6 +40,7 @@
40 40
41#include "datapath.h" 41#include "datapath.h"
42#include "vport.h" 42#include "vport.h"
43#include "vport-vxlan.h"
43 44
44/** 45/**
45 * struct vxlan_port - Keeps track of open UDP ports 46 * struct vxlan_port - Keeps track of open UDP ports
@@ -49,6 +50,7 @@
49struct vxlan_port { 50struct vxlan_port {
50 struct vxlan_sock *vs; 51 struct vxlan_sock *vs;
51 char name[IFNAMSIZ]; 52 char name[IFNAMSIZ];
53 u32 exts; /* VXLAN_F_* in <net/vxlan.h> */
52}; 54};
53 55
54static struct vport_ops ovs_vxlan_vport_ops; 56static struct vport_ops ovs_vxlan_vport_ops;
@@ -63,16 +65,26 @@ static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb,
63 struct vxlan_metadata *md) 65 struct vxlan_metadata *md)
64{ 66{
65 struct ovs_tunnel_info tun_info; 67 struct ovs_tunnel_info tun_info;
68 struct vxlan_port *vxlan_port;
66 struct vport *vport = vs->data; 69 struct vport *vport = vs->data;
67 struct iphdr *iph; 70 struct iphdr *iph;
71 struct ovs_vxlan_opts opts = {
72 .gbp = md->gbp,
73 };
68 __be64 key; 74 __be64 key;
75 __be16 flags;
76
77 flags = TUNNEL_KEY;
78 vxlan_port = vxlan_vport(vport);
79 if (vxlan_port->exts & VXLAN_F_GBP)
80 flags |= TUNNEL_VXLAN_OPT;
69 81
70 /* Save outer tunnel values */ 82 /* Save outer tunnel values */
71 iph = ip_hdr(skb); 83 iph = ip_hdr(skb);
72 key = cpu_to_be64(ntohl(md->vni) >> 8); 84 key = cpu_to_be64(ntohl(md->vni) >> 8);
73 ovs_flow_tun_info_init(&tun_info, iph, 85 ovs_flow_tun_info_init(&tun_info, iph,
74 udp_hdr(skb)->source, udp_hdr(skb)->dest, 86 udp_hdr(skb)->source, udp_hdr(skb)->dest,
75 key, TUNNEL_KEY, NULL, 0); 87 key, flags, &opts, sizeof(opts));
76 88
77 ovs_vport_receive(vport, skb, &tun_info); 89 ovs_vport_receive(vport, skb, &tun_info);
78} 90}
@@ -84,6 +96,21 @@ static int vxlan_get_options(const struct vport *vport, struct sk_buff *skb)
84 96
85 if (nla_put_u16(skb, OVS_TUNNEL_ATTR_DST_PORT, ntohs(dst_port))) 97 if (nla_put_u16(skb, OVS_TUNNEL_ATTR_DST_PORT, ntohs(dst_port)))
86 return -EMSGSIZE; 98 return -EMSGSIZE;
99
100 if (vxlan_port->exts) {
101 struct nlattr *exts;
102
103 exts = nla_nest_start(skb, OVS_TUNNEL_ATTR_EXTENSION);
104 if (!exts)
105 return -EMSGSIZE;
106
107 if (vxlan_port->exts & VXLAN_F_GBP &&
108 nla_put_flag(skb, OVS_VXLAN_EXT_GBP))
109 return -EMSGSIZE;
110
111 nla_nest_end(skb, exts);
112 }
113
87 return 0; 114 return 0;
88} 115}
89 116
@@ -96,6 +123,31 @@ static void vxlan_tnl_destroy(struct vport *vport)
96 ovs_vport_deferred_free(vport); 123 ovs_vport_deferred_free(vport);
97} 124}
98 125
126static const struct nla_policy exts_policy[OVS_VXLAN_EXT_MAX+1] = {
127 [OVS_VXLAN_EXT_GBP] = { .type = NLA_FLAG, },
128};
129
130static int vxlan_configure_exts(struct vport *vport, struct nlattr *attr)
131{
132 struct nlattr *exts[OVS_VXLAN_EXT_MAX+1];
133 struct vxlan_port *vxlan_port;
134 int err;
135
136 if (nla_len(attr) < sizeof(struct nlattr))
137 return -EINVAL;
138
139 err = nla_parse_nested(exts, OVS_VXLAN_EXT_MAX, attr, exts_policy);
140 if (err < 0)
141 return err;
142
143 vxlan_port = vxlan_vport(vport);
144
145 if (exts[OVS_VXLAN_EXT_GBP])
146 vxlan_port->exts |= VXLAN_F_GBP;
147
148 return 0;
149}
150
99static struct vport *vxlan_tnl_create(const struct vport_parms *parms) 151static struct vport *vxlan_tnl_create(const struct vport_parms *parms)
100{ 152{
101 struct net *net = ovs_dp_get_net(parms->dp); 153 struct net *net = ovs_dp_get_net(parms->dp);
@@ -128,7 +180,17 @@ static struct vport *vxlan_tnl_create(const struct vport_parms *parms)
128 vxlan_port = vxlan_vport(vport); 180 vxlan_port = vxlan_vport(vport);
129 strncpy(vxlan_port->name, parms->name, IFNAMSIZ); 181 strncpy(vxlan_port->name, parms->name, IFNAMSIZ);
130 182
131 vs = vxlan_sock_add(net, htons(dst_port), vxlan_rcv, vport, true, 0); 183 a = nla_find_nested(options, OVS_TUNNEL_ATTR_EXTENSION);
184 if (a) {
185 err = vxlan_configure_exts(vport, a);
186 if (err) {
187 ovs_vport_free(vport);
188 goto error;
189 }
190 }
191
192 vs = vxlan_sock_add(net, htons(dst_port), vxlan_rcv, vport, true,
193 vxlan_port->exts);
132 if (IS_ERR(vs)) { 194 if (IS_ERR(vs)) {
133 ovs_vport_free(vport); 195 ovs_vport_free(vport);
134 return (void *)vs; 196 return (void *)vs;
@@ -141,6 +203,21 @@ error:
141 return ERR_PTR(err); 203 return ERR_PTR(err);
142} 204}
143 205
206static int vxlan_ext_gbp(struct sk_buff *skb)
207{
208 const struct ovs_tunnel_info *tun_info;
209 const struct ovs_vxlan_opts *opts;
210
211 tun_info = OVS_CB(skb)->egress_tun_info;
212 opts = tun_info->options;
213
214 if (tun_info->tunnel.tun_flags & TUNNEL_VXLAN_OPT &&
215 tun_info->options_len >= sizeof(*opts))
216 return opts->gbp;
217 else
218 return 0;
219}
220
144static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb) 221static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb)
145{ 222{
146 struct net *net = ovs_dp_get_net(vport->dp); 223 struct net *net = ovs_dp_get_net(vport->dp);
@@ -173,6 +250,7 @@ static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb)
173 250
174 src_port = udp_flow_src_port(net, skb, 0, 0, true); 251 src_port = udp_flow_src_port(net, skb, 0, 0, true);
175 md.vni = htonl(be64_to_cpu(tun_key->tun_id) << 8); 252 md.vni = htonl(be64_to_cpu(tun_key->tun_id) << 8);
253 md.gbp = vxlan_ext_gbp(skb);
176 254
177 err = vxlan_xmit_skb(vxlan_port->vs, rt, skb, 255 err = vxlan_xmit_skb(vxlan_port->vs, rt, skb,
178 fl.saddr, tun_key->ipv4_dst, 256 fl.saddr, tun_key->ipv4_dst,
diff --git a/net/openvswitch/vport-vxlan.h b/net/openvswitch/vport-vxlan.h
new file mode 100644
index 000000000000..4b08233e73d5
--- /dev/null
+++ b/net/openvswitch/vport-vxlan.h
@@ -0,0 +1,11 @@
1#ifndef VPORT_VXLAN_H
2#define VPORT_VXLAN_H 1
3
4#include <linux/kernel.h>
5#include <linux/types.h>
6
7struct ovs_vxlan_opts {
8 __u32 gbp;
9};
10
11#endif