VXLAN Group Policy Extension
Subsystems (4)
v6 cover VXLAN Group Policy Extension
Implements supports for the Group Policy VXLAN extension [0] to provide a lightweight and simple security label mechanism across network peers based on VXLAN. The security context and associated metadata is mapped to/from skb->mark. This allows further mapping to a SELinux context using SECMARK, to implement ACLs directly with nftables, iptables, OVS, tc, etc.
The extension is disabled by default and should be run on a distinct port in mixed Linux VXLAN VTEP environments. Liberal VXLAN VTEPs which ignore unknown reserved bits will be able to receive VXLAN-GBP frames.
Simple usage example:
10.1.1.1:
# ip link add vxlan0 type vxlan id 10 remote 10.1.1.2 gbp # iptables -I OUTPUT -m owner --uid-owner 101 -j MARK --set-mark 0x200
10.1.1.2:
# ip link add vxlan0 type vxlan id 10 remote 10.1.1.1 gbp # iptables -I INPUT -m mark --mark 0x200 -j DROP
iproute2 [1] and OVS [2] support will be provided in separate patches.
[0] https://tools.ietf.org/html/draft-smith-vxlan-group-policy
[1] https://github.com/tgraf/iproute2/tree/vxlan-gbp
[2] https://github.com/tgraf/ovs/tree/vxlan-gbp
Thomas Graf (5):
vxlan: Group Policy extension
vxlan: Only bind to sockets with compatible flags enabled
openvswitch: Rename GENEVE_TUN_OPTS() to TUN_METADATA_OPTS()
openvswitch: Allow for any level of nesting in flow attributes
openvswitch: Support VXLAN Group Policy extension
drivers/net/vxlan.c | 113 ++++++++++++---- include/net/ip_tunnels.h | 5 +- include/net/vxlan.h | 82 ++++++++++- include/uapi/linux/if_link.h | 1 + include/uapi/linux/openvswitch.h | 11 ++ net/openvswitch/flow.c | 2 +- net/openvswitch/flow.h | 14 +- net/openvswitch/flow_netlink.c | 286 ++++++++++++++++++++++++++------------- net/openvswitch/vport-geneve.c | 15 +- net/openvswitch/vport-vxlan.c | 91 ++++++++++++- net/openvswitch/vport-vxlan.h | 11 ++ 11 files changed, 491 insertions(+), 140 deletions(-) create mode 100644 net/openvswitch/vport-vxlan.h
Signature · 1 line
1.9.3
A message that is not in the archive (sent off-list or not yet received): cover.1421290198.git.tgraf-G/[email protected]
PATCH 4/5 openvswitch: Allow for any level of nesting in flow attributes
nlattr_set() is currently hardcoded to two levels of nesting. This change introduces struct ovs_len_tbl to define minimal length requirements plus next level nesting tables to traverse the key attributes to arbitrary depth.
---v5->v6:
- No changev4->v5:
- No changev3->v4:
- No change. The spotted bug is unrelatd to this series and will be fixed in a separate patchv2->v3:
- No changev1->v2:
- New patch to allow nested Netlink attributes inside OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS
net/openvswitch/flow_netlink.c | 106 ++++++++++++++++++++++------------------- 1 file changed, 56 insertions(+), 50 deletions(-)
net/openvswitch/flow_netlink.c +56 -50
@@ -50,6 +50,13 @@#include "flow_netlink.h" +struct ovs_len_tbl { +int len; +const struct ovs_len_tbl *next; +}; + +#define OVS_ATTR_NESTED -1 +static void update_range (struct sw_flow_match *match,size_t offset,size_t size,bool is_mask) {
@@ -289,29 +296,44 @@ size_t ovs_key_attr_size(void) +nla_total_size (28 );/* OVS_KEY_ATTR_ND */ } +static const struct ovs_len_tbl ovs_tunnel_key_lens[OVS_TUNNEL_KEY_ATTR_MAX +1 ] = { + [OVS_TUNNEL_KEY_ATTR_ID ] = { .len =sizeof (u64) }, + [OVS_TUNNEL_KEY_ATTR_IPV4_SRC ] = { .len =sizeof (u32) }, + [OVS_TUNNEL_KEY_ATTR_IPV4_DST ] = { .len =sizeof (u32) }, + [OVS_TUNNEL_KEY_ATTR_TOS ] = { .len =1 }, + [OVS_TUNNEL_KEY_ATTR_TTL ] = { .len =1 }, + [OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT ] = { .len =0 }, + [OVS_TUNNEL_KEY_ATTR_CSUM ] = { .len =0 }, + [OVS_TUNNEL_KEY_ATTR_TP_SRC ] = { .len =sizeof (u16) }, + [OVS_TUNNEL_KEY_ATTR_TP_DST ] = { .len =sizeof (u16) }, + [OVS_TUNNEL_KEY_ATTR_OAM ] = { .len =0 }, + [OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS ] = { .len =OVS_ATTR_NESTED }, +}; +/* The size of the argument for each %OVS_KEY_ATTR_* Netlink attribute. */ -static const int ovs_key_lens[OVS_KEY_ATTR_MAX +1 ] = { - [OVS_KEY_ATTR_ENCAP ] =-1 , - [OVS_KEY_ATTR_PRIORITY ] =sizeof (u32), - [OVS_KEY_ATTR_IN_PORT ] =sizeof (u32), - [OVS_KEY_ATTR_SKB_MARK ] =sizeof (u32), - [OVS_KEY_ATTR_ETHERNET ] =sizeof (struct ovs_key_ethernet ), - [OVS_KEY_ATTR_VLAN ] =sizeof (__be16), - [OVS_KEY_ATTR_ETHERTYPE ] =sizeof (__be16), - [OVS_KEY_ATTR_IPV4 ] =sizeof (struct ovs_key_ipv4 ), - [OVS_KEY_ATTR_IPV6 ] =sizeof (struct ovs_key_ipv6 ), - [OVS_KEY_ATTR_TCP ] =sizeof (struct ovs_key_tcp ), - [OVS_KEY_ATTR_TCP_FLAGS ] =sizeof (__be16), - [OVS_KEY_ATTR_UDP ] =sizeof (struct ovs_key_udp ), - [OVS_KEY_ATTR_SCTP ] =sizeof (struct ovs_key_sctp ), - [OVS_KEY_ATTR_ICMP ] =sizeof (struct ovs_key_icmp ), - [OVS_KEY_ATTR_ICMPV6 ] =sizeof (struct ovs_key_icmpv6 ), - [OVS_KEY_ATTR_ARP ] =sizeof (struct ovs_key_arp ), - [OVS_KEY_ATTR_ND ] =sizeof (struct ovs_key_nd ), - [OVS_KEY_ATTR_RECIRC_ID ] =sizeof (u32), - [OVS_KEY_ATTR_DP_HASH ] =sizeof (u32), - [OVS_KEY_ATTR_TUNNEL ] =-1 , - [OVS_KEY_ATTR_MPLS ] =sizeof (struct ovs_key_mpls ), +static const struct ovs_len_tbl ovs_key_lens[OVS_KEY_ATTR_MAX +1 ] = { + [OVS_KEY_ATTR_ENCAP ] = { .len =OVS_ATTR_NESTED }, + [OVS_KEY_ATTR_PRIORITY ] = { .len =sizeof (u32) }, + [OVS_KEY_ATTR_IN_PORT ] = { .len =sizeof (u32) }, + [OVS_KEY_ATTR_SKB_MARK ] = { .len =sizeof (u32) }, + [OVS_KEY_ATTR_ETHERNET ] = { .len =sizeof (struct ovs_key_ethernet ) }, + [OVS_KEY_ATTR_VLAN ] = { .len =sizeof (__be16) }, + [OVS_KEY_ATTR_ETHERTYPE ] = { .len =sizeof (__be16) }, + [OVS_KEY_ATTR_IPV4 ] = { .len =sizeof (struct ovs_key_ipv4 ) }, + [OVS_KEY_ATTR_IPV6 ] = { .len =sizeof (struct ovs_key_ipv6 ) }, + [OVS_KEY_ATTR_TCP ] = { .len =sizeof (struct ovs_key_tcp ) }, + [OVS_KEY_ATTR_TCP_FLAGS ] = { .len =sizeof (__be16) }, + [OVS_KEY_ATTR_UDP ] = { .len =sizeof (struct ovs_key_udp ) }, + [OVS_KEY_ATTR_SCTP ] = { .len =sizeof (struct ovs_key_sctp ) }, + [OVS_KEY_ATTR_ICMP ] = { .len =sizeof (struct ovs_key_icmp ) }, + [OVS_KEY_ATTR_ICMPV6 ] = { .len =sizeof (struct ovs_key_icmpv6 ) }, + [OVS_KEY_ATTR_ARP ] = { .len =sizeof (struct ovs_key_arp ) }, + [OVS_KEY_ATTR_ND ] = { .len =sizeof (struct ovs_key_nd ) }, + [OVS_KEY_ATTR_RECIRC_ID ] = { .len =sizeof (u32) }, + [OVS_KEY_ATTR_DP_HASH ] = { .len =sizeof (u32) }, + [OVS_KEY_ATTR_TUNNEL ] = { .len =OVS_ATTR_NESTED , + .next = ovs_tunnel_key_lens, }, + [OVS_KEY_ATTR_MPLS ] = { .len =sizeof (struct ovs_key_mpls ) }, };static bool is_all_zero (const u8 *fp,size_t size)
@@ -352,8 +374,8 @@ static int __parse_flow_nlattrs(const struct nlattr *attr,return -EINVAL ; } - expected_len = ovs_key_lens[type]; -if (nla_len (nla) != expected_len && expected_len !=-1 ) { + expected_len = ovs_key_lens[type].len; +if (nla_len (nla) != expected_len && expected_len !=OVS_ATTR_NESTED ) {OVS_NLERR (log,"Key %d has unexpected len %d expected %d" , type,nla_len (nla), expected_len);return -EINVAL ;
@@ -451,30 +473,16 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr,int type =nla_type (a);int err; -static const u32 ovs_tunnel_key_lens[OVS_TUNNEL_KEY_ATTR_MAX +1 ] = { - [OVS_TUNNEL_KEY_ATTR_ID ] =sizeof (u64), - [OVS_TUNNEL_KEY_ATTR_IPV4_SRC ] =sizeof (u32), - [OVS_TUNNEL_KEY_ATTR_IPV4_DST ] =sizeof (u32), - [OVS_TUNNEL_KEY_ATTR_TOS ] =1 , - [OVS_TUNNEL_KEY_ATTR_TTL ] =1 , - [OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT ] =0 , - [OVS_TUNNEL_KEY_ATTR_CSUM ] =0 , - [OVS_TUNNEL_KEY_ATTR_TP_SRC ] =sizeof (u16), - [OVS_TUNNEL_KEY_ATTR_TP_DST ] =sizeof (u16), - [OVS_TUNNEL_KEY_ATTR_OAM ] =0 , - [OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS ] =-1 , - }; -if (type >OVS_TUNNEL_KEY_ATTR_MAX ) {OVS_NLERR (log,"Tunnel attr %d out of range max %d" , type,OVS_TUNNEL_KEY_ATTR_MAX );return -EINVAL ; } -if (ovs_tunnel_key_lens[type] !=nla_len (a) && - ovs_tunnel_key_lens[type] !=-1 ) { +if (ovs_tunnel_key_lens[type].len !=nla_len (a) && + ovs_tunnel_key_lens[type].len !=OVS_ATTR_NESTED ) {OVS_NLERR (log,"Tunnel attr %d has unexpected len %d expected %d" , - type,nla_len (a), ovs_tunnel_key_lens[type]); + type,nla_len (a), ovs_tunnel_key_lens[type].len);return -EINVAL ; }
@@ -912,18 +920,16 @@ static int ovs_key_from_nlattrs(struct sw_flow_match *match, u64 attrs,return 0 ; } -static void nlattr_set (struct nlattr *attr,u8 val,bool is_attr_mask_key) +static void nlattr_set (struct nlattr *attr,u8 val, +const struct ovs_len_tbl *tbl) {struct nlattr *nla;int rem;/* The nlattr stream should already have been validated */ nla_for_each_nested (nla, attr, rem) { -/* We assume that ovs_key_lens[type] == -1 means that type is a -* nested attribute -*/ -if (is_attr_mask_key && ovs_key_lens[nla_type (nla)] ==-1 ) -nlattr_set (nla, val, false); +if (tbl && tbl[nla_type (nla)].len ==OVS_ATTR_NESTED ) +nlattr_set (nla, val, tbl[nla_type (nla)].next);else memset (nla_data (nla), val,nla_len (nla)); }
@@ -931,7 +937,7 @@ static void nlattr_set(struct nlattr *attr, u8 val, bool is_attr_mask_key)static void mask_set_nlattr (struct nlattr *attr,u8 val) { -nlattr_set (attr, val, true); +nlattr_set (attr, val, ovs_key_lens); }/**
@@ -1628,8 +1634,8 @@ static int validate_set(const struct nlattr *a,return -EINVAL ;if (key_type >OVS_KEY_ATTR_MAX || - (ovs_key_lens[key_type] !=nla_len (ovs_key) && - ovs_key_lens[key_type] !=-1 )) + (ovs_key_lens[key_type].len !=nla_len (ovs_key) && + ovs_key_lens[key_type].len !=OVS_ATTR_NESTED ))return -EINVAL ;switch (key_type) {
Signature · 6 lines
1.9.3 _______________________________________________ dev mailing list [email protected] http://openvswitch.org/mailman/listinfo/dev
PATCH v6 1/5 vxlan: Group Policy extension
In reply to Thomas GrafImplements supports for the Group Policy VXLAN extension [0] to provide a lightweight and simple security label mechanism across network peers based on VXLAN. The security context and associated metadata is mapped to/from skb->mark. This allows further mapping to a SELinux context using SECMARK, to implement ACLs directly with nftables, iptables, OVS, tc, etc.
The group membership is defined by the lower 16 bits of skb->mark, the upper 16 bits are used for flags.
SELinux allows to manage label to secure local resources. However, distributed applications require ACLs to implemented across hosts. This is typically achieved by matching on L2-L4 fields to identify the original sending host and process on the receiver. On top of that, netlabel and specifically CIPSO [1] allow to map security contexts to universal labels. However, netlabel and CIPSO are relatively complex. This patch provides a lightweight alternative for overlay network environments with a trusted underlay. No additional control protocol is required.
Host 1: Host 2:
Group A Group B Group B Group A
+-----+ +-------------+ +-------+ +-----+
| lxc | | SELinux CTX | | httpd | | VM |
+--+--+ +--+----------+ +---+---+ +--+--+
\---+---/ \----+---/
| |
+---+---+ +---+---+
| vxlan | | vxlan |
+---+---+ +---+---+
+------------------------------+Backwards compatibility:
A VXLAN-GBP socket can receive standard VXLAN frames and will assign the default group 0x0000 to such frames. A Linux VXLAN socket will drop VXLAN-GBP frames. The extension is therefore disabled by default and needs to be specifically enabled:
ip link add [...] type vxlan [...] gbp
In a mixed environment with VXLAN and VXLAN-GBP sockets, the GBP socket must run on a separate port number.
Examples:
iptables:
host1# iptables -I OUTPUT -m owner --uid-owner 101 -j MARK --set-mark 0x200 host2# iptables -I INPUT -m mark --mark 0x200 -j DROP
OVS:
# ovs-ofctl add-flow br0 'in_port=1,actions=load:0x200->NXM_NX_TUN_GBP_ID[],NORMAL' # ovs-ofctl add-flow br0 'in_port=2,tun_gbp_id=0x200,actions=drop'
[0] https://tools.ietf.org/html/draft-smith-vxlan-group-policy
[1] http://lwn.net/Articles/204905/
---v5->v6:
- Use flags instead of exts member to store enablement of GBP as suggested by Tomv4->v5:
- Rebased on top of Tom's RCO work
- Dropped IFLA_VXLAN_EXTENSION container attribute and embedded IFLA_VXLAN_GBP as top level VXLAN attribute like RCO for consistency.v3->v4:
- Patch 1 was no longer needed due to Tom Herbert's 3bf394 ("vxlan: Improve support for header flags"). Moved remaining header description to this patch.
- Zero out vxlan_metadata in vxlan_tnl_send() as suggested by Jesse.
- Reported enabled extensions to user space as requested by Nicolas.
- Use VXLAN_HF_GBP instead of bitfield to be in line with Tom's work.v2->v3:
- Removed empty struct vxlan_gbp as spotted by Alexeiv1->v2:
- split GBP header definition into separate struct vxlanhdr_gbp as requested by Alexei
drivers/net/vxlan.c | 84 ++++++++++++++++++++++++++++++++++++------- include/net/vxlan.h | 79 +++++++++++++++++++++++++++++++++++++--- include/uapi/linux/if_link.h | 1 + net/openvswitch/vport-vxlan.c | 9 +++-- 4 files changed, 152 insertions(+), 21 deletions(-)
drivers/net/vxlan.c +71 -13
@@ -620,7 +620,8 @@ static struct sk_buff **vxlan_gro_receive(struct sk_buff **head,continue ; vh2 = (struct vxlanhdr *)(p->data + off_vx); -if (vh->vx_vni != vh2->vx_vni) { +if (vh->vx_flags != vh2->vx_flags || + vh->vx_vni != vh2->vx_vni) {NAPI_GRO_CB (p)->same_flow =0 ;continue ; }
@@ -1183,6 +1184,7 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)struct vxlan_sock *vs;struct vxlanhdr *vxh;u32 flags, vni; +struct vxlan_metadata md = {0 };/* Need Vxlan and inner Ethernet header to be present */ if (!pskb_may_pull (skb,VXLAN_HLEN ))
@@ -1216,6 +1218,24 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb) vni &=VXLAN_VID_MASK ; } +/* For backwards compatibility, only allow reserved fields to be +* used by VXLAN extensions if explicitly requested. +*/ +if ((flags &VXLAN_HF_GBP ) && (vs->flags &VXLAN_F_GBP )) { +struct vxlanhdr_gbp *gbp; + + gbp = (struct vxlanhdr_gbp *)vxh; + md.gbp =ntohs (gbp->policy_id); + +if (gbp->dont_learn) + md.gbp |=VXLAN_GBP_DONT_LEARN ; + +if (gbp->policy_applied) + md.gbp |=VXLAN_GBP_POLICY_APPLIED ; + + flags &= ~VXLAN_GBP_USED_BITS ; + } +if (flags || (vni & ~VXLAN_VID_MASK )) {/* If there are any unprocessed flags remaining treat * this as a malformed packet. This behavior diverges from
@@ -1229,7 +1249,8 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb) goto bad_flags; } - vs->rcv (vs, skb, vxh->vx_vni); + md.vni = vxh->vx_vni; + vs->rcv (vs, skb, &md);return 0 ; drop:
@@ -1246,8 +1267,8 @@ error:return 1 ; } -static void vxlan_rcv (struct vxlan_sock *vs, -struct sk_buff *skb,__be32 vx_vni) +static void vxlan_rcv (struct vxlan_sock *vs,struct sk_buff *skb, +struct vxlan_metadata *md) {struct iphdr *oip =NULL ;struct ipv6hdr *oip6 =NULL ;
@@ -1258,7 +1279,7 @@ static void vxlan_rcv(struct vxlan_sock *vs,int err =0 ;union vxlan_addr *remote_ip; - vni =ntohl (vx_vni) >>8 ; + vni =ntohl (md->vni) >>8 ;/* Is this VNI defined? */ vxlan =vxlan_vs_find_vni (vs, vni);if (!vxlan)
@@ -1292,6 +1313,7 @@ static void vxlan_rcv(struct vxlan_sock *vs, goto drop;skb_reset_network_header (skb); + skb->mark = md->gbp;if (oip6) err =IP6_ECN_decapsulate (oip6, skb);
@@ -1641,13 +1663,30 @@ static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb)return false; } +static void vxlan_build_gbp_hdr (struct vxlanhdr *vxh,struct vxlan_sock *vs, +struct vxlan_metadata *md) +{ +struct vxlanhdr_gbp *gbp; + + gbp = (struct vxlanhdr_gbp *)vxh; + vxh->vx_flags |=htonl (VXLAN_HF_GBP ); + +if (md->gbp &VXLAN_GBP_DONT_LEARN ) + gbp->dont_learn =1 ; + +if (md->gbp &VXLAN_GBP_POLICY_APPLIED ) + gbp->policy_applied =1 ; + + gbp->policy_id =htons (md->gbp &VXLAN_GBP_ID_MASK ); +} +#if IS_ENABLED (CONFIG_IPV6 )static int vxlan6_xmit_skb (struct vxlan_sock *vs,struct dst_entry *dst,struct sk_buff *skb,struct net_device *dev,struct in6_addr *saddr,struct in6_addr *daddr,__u8 prio,__u8 ttl, -__be16 src_port,__be16 dst_port,__be32 vni, -bool xnet) +__be16 src_port,__be16 dst_port, +struct vxlan_metadata *md,bool xnet) {struct vxlanhdr *vxh;int min_headroom;
@@ -1696,7 +1735,7 @@ static int vxlan6_xmit_skb(struct vxlan_sock *vs, vxh = (struct vxlanhdr *)__skb_push (skb,sizeof (*vxh)); vxh->vx_flags =htonl (VXLAN_HF_VNI ); - vxh->vx_vni = vni; + vxh->vx_vni = md->vni;if (type &SKB_GSO_TUNNEL_REMCSUM ) { u32 data = (skb_checksum_start_offset(skb) - hdrlen) >>
@@ -1714,6 +1753,9 @@ static int vxlan6_xmit_skb(struct vxlan_sock *vs, } } +if (vs->flags &VXLAN_F_GBP ) +vxlan_build_gbp_hdr (vxh, vs, md); +skb_set_inner_protocol (skb,htons (ETH_P_TEB )); udp_tunnel6_xmit_skb(vs->sock, dst, skb, dev, saddr, daddr, prio,
@@ -1728,7 +1770,8 @@ err:int vxlan_xmit_skb (struct vxlan_sock *vs,struct rtable *rt,struct sk_buff *skb,__be32 src,__be32 dst,__u8 tos,__u8 ttl,__be16 df, -__be16 src_port,__be16 dst_port,__be32 vni,bool xnet) +__be16 src_port,__be16 dst_port, +struct vxlan_metadata *md,bool xnet) {struct vxlanhdr *vxh;int min_headroom;
@@ -1771,7 +1814,7 @@ int vxlan_xmit_skb(struct vxlan_sock *vs, vxh = (struct vxlanhdr *)__skb_push (skb,sizeof (*vxh)); vxh->vx_flags =htonl (VXLAN_HF_VNI ); - vxh->vx_vni = vni; + vxh->vx_vni = md->vni;if (type &SKB_GSO_TUNNEL_REMCSUM ) { u32 data = (skb_checksum_start_offset(skb) - hdrlen) >>
@@ -1789,6 +1832,9 @@ int vxlan_xmit_skb(struct vxlan_sock *vs, } } +if (vs->flags &VXLAN_F_GBP ) +vxlan_build_gbp_hdr (vxh, vs, md); +skb_set_inner_protocol (skb,htons (ETH_P_TEB )); return udp_tunnel_xmit_skb(vs->sock, rt, skb, src, dst, tos,
@@ -1849,6 +1895,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,const struct iphdr *old_iph;struct flowi4 fl4;union vxlan_addr *dst; +struct vxlan_metadata md;__be16 src_port =0 , dst_port;u32 vni;__be16 df =0 ;
@@ -1919,11 +1966,12 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, tos =ip_tunnel_ecn_encap (tos, old_iph, skb); ttl = ttl ? :ip4_dst_hoplimit (&rt->dst); + md.vni =htonl (vni <<8 ); + md.gbp = skb->mark; err =vxlan_xmit_skb (vxlan->vn_sock, rt, skb, fl4.saddr, dst->sin.sin_addr.s_addr, - tos, ttl, df, src_port, dst_port, -htonl (vni <<8 ), + tos, ttl, df, src_port, dst_port, &md, !net_eq (vxlan->net,dev_net (vxlan->dev)));if (err <0 ) {/* skb is already freed. */
@@ -1976,10 +2024,12 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, } ttl = ttl ? :ip6_dst_hoplimit (ndst); + md.vni =htonl (vni <<8 ); + md.gbp = skb->mark; err =vxlan6_xmit_skb (vxlan->vn_sock, ndst, skb, dev, &fl6.saddr, &fl6.daddr,0 , ttl, - src_port, dst_port,htonl (vni <<8 ), + src_port, dst_port, &md, !net_eq (vxlan->net,dev_net (vxlan->dev)));#endif }
@@ -2382,6 +2432,7 @@ static const struct nla_policy vxlan_policy[IFLA_VXLAN_MAX + 1] = { [IFLA_VXLAN_UDP_ZERO_CSUM6_RX] = { .type = NLA_U8 }, [IFLA_VXLAN_REMCSUM_TX] = { .type = NLA_U8 }, [IFLA_VXLAN_REMCSUM_RX] = { .type = NLA_U8 }, + [IFLA_VXLAN_GBP] = { .type = NLA_FLAG, }, };static int vxlan_validate (struct nlattr *tb[],struct nlattr *data[])
@@ -2706,6 +2757,9 @@ static int vxlan_newlink(struct net *net, struct net_device *dev, nla_get_u8(data[IFLA_VXLAN_REMCSUM_RX])) vxlan->flags |= VXLAN_F_REMCSUM_RX; +if (data[IFLA_VXLAN_GBP ]) + vxlan->flags |=VXLAN_F_GBP ; +if (vxlan_find_vni (net, vni, use_ipv6 ?AF_INET6 :AF_INET , vxlan->dst_port)) {pr_info ("duplicate VNI %u\n" , vni);
@@ -2851,6 +2905,10 @@ static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev)if (nla_put (skb,IFLA_VXLAN_PORT_RANGE ,sizeof (ports), &ports)) goto nla_put_failure; +if (vxlan->flags &VXLAN_F_GBP && +nla_put_flag (skb,IFLA_VXLAN_GBP )) + goto nla_put_failure; +return 0 ; nla_put_failure:
include/net/vxlan.h +74 -5
110 lines not on this page · raw message
include/uapi/linux/if_link.h +1 -0
@@ -372,6 +372,7 @@ enum {IFLA_VXLAN_UDP_ZERO_CSUM6_RX ,IFLA_VXLAN_REMCSUM_TX ,IFLA_VXLAN_REMCSUM_RX , +IFLA_VXLAN_GBP , __IFLA_VXLAN_MAX };#define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1)
net/openvswitch/vport-vxlan.c +6 -3
@@ -59,7 +59,8 @@ static inline struct vxlan_port *vxlan_vport(const struct vport *vport) }/* Called with rcu_read_lock and BH disabled. */ -static void vxlan_rcv (struct vxlan_sock *vs,struct sk_buff *skb,__be32 vx_vni) +static void vxlan_rcv (struct vxlan_sock *vs,struct sk_buff *skb, +struct vxlan_metadata *md) {struct ovs_tunnel_info tun_info;struct vport *vport = vs->data;
@@ -68,7 +69,7 @@ static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb, __be32 vx_vni)/* Save outer tunnel values */ iph =ip_hdr (skb); - key =cpu_to_be64 (ntohl (vx_vni) >>8 ); + key =cpu_to_be64 (ntohl (md->vni) >>8 );ovs_flow_tun_info_init (&tun_info, iph,udp_hdr (skb)->source,udp_hdr (skb)->dest, key,TUNNEL_KEY ,NULL ,0 );
@@ -146,6 +147,7 @@ static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb)struct vxlan_port *vxlan_port =vxlan_vport (vport);__be16 dst_port =inet_sk (vxlan_port->vs->sock->sk)->inet_sport;struct ovs_key_ipv4_tunnel *tun_key; +struct vxlan_metadata md = {0 };struct rtable *rt;struct flowi4 fl;__be16 src_port;
@@ -178,12 +180,13 @@ static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb) skb->ignore_df =1 ; src_port =udp_flow_src_port (net, skb,0 ,0 , true); + md.vni =htonl (be64_to_cpu (tun_key->tun_id) <<8 ); err =vxlan_xmit_skb (vxlan_port->vs, rt, skb, fl.saddr, tun_key->ipv4_dst, tun_key->ipv4_tos, tun_key->ipv4_ttl, df, src_port, dst_port, -htonl (be64_to_cpu (tun_key->tun_id) <<8 ), + &md, false);if (err <0 )ip_rt_put (rt);
Signature · 1 line
1.9.3
Re: [PATCH 1/5] vxlan: Group Policy extension
include/net/vxlan.h struct vxlanhdr { · line 98
Quoted 3 lines
include/net/vxlan.h +3
-0+struct vxlan_metadata { +__be32 vni; +u32 gbp;
Should this be __be32 also and use ntohl/htonl when setting to/from skb->mark?
Quoted 2 lines
(quoted diff) +2
-0+}; +
Re: [PATCH 1/5] vxlan: Group Policy extension
Quoted 5 lines · Tom Herbert
include/net/vxlan.h struct vxlanhdr { · line 98
Quoted 3 lines
include/net/vxlan.h +3
-0+struct vxlan_metadata { +__be32 vni; +u32 gbp;Should this be
__be32also and use ntohl/htonl when setting to/fromskb->mark?
The bitmask is stored in host byte order in vxlan_metadata to be compatible with skb->mark and converted to network byte order on the wire, see:
gbp = (struct vxlanhdr_gbp *)vxh;
md.gbp = ntohs(gbp->policy_id);and:
gbp->policy_id = htons(md->gbp & VXLAN_GBP_ID_MASK);
PATCH v6 2/5 vxlan: Only bind to sockets with compatible flags enabled
In reply to Thomas GrafA VXLAN net_device looking for an appropriate socket may only consider a socket which has a matching set of flags/extensions enabled. If incompatible flags are enabled, return a conflict to have the caller create a distinct socket with distinct port.
The OVS VXLAN port is kept unaware of extensions at this point.
---v5->v6:
- Keep sharing logic but base it off unsharable flags instead of exts member as suggested by Tomv4->v5:
- No changev3->v4:
- No changev2->v3:
- No changev1->v2:
- Improved commit message, reported by Jesse
drivers/net/vxlan.c | 29 ++++++++++++++++++----------- include/net/vxlan.h | 3 +++ 2 files changed, 21 insertions(+), 11 deletions(-)
drivers/net/vxlan.c +18 -11
@@ -263,15 +263,19 @@ static inline struct vxlan_rdst *first_remote_rtnl(struct vxlan_fdb *fdb) return list_first_entry(&fdb->remotes, struct vxlan_rdst, list); } -/* Find VXLAN socket based on network namespace, address family and UDP port */ -static struct vxlan_sock *vxlan_find_sock (struct net *net, -sa_family_t family,__be16 port) +/* Find VXLAN socket based on network namespace, address family and UDP port +* and enabled unshareable flags. +*/ +static struct vxlan_sock *vxlan_find_sock (struct net *net,sa_family_t family, +__be16 port,u32 flags) {struct vxlan_sock *vs; +u32 match_flags = flags &VXLAN_F_UNSHAREABLE ;hlist_for_each_entry_rcu (vs,vs_head (net, port), hlist) {if (inet_sk (vs->sock->sk)->inet_sport == port && -inet_sk (vs->sock->sk)->sk.sk_family == family) +inet_sk (vs->sock->sk)->sk.sk_family == family && + (vs->flags &VXLAN_F_UNSHAREABLE ) == match_flags)return vs; }return NULL ;
@@ -291,11 +295,12 @@ static struct vxlan_dev *vxlan_vs_find_vni(struct vxlan_sock *vs, u32 id)/* Look up VNI in a per net namespace table */ static struct vxlan_dev *vxlan_find_vni (struct net *net,u32 id, -sa_family_t family,__be16 port) +sa_family_t family,__be16 port, +u32 flags) {struct vxlan_sock *vs; - vs =vxlan_find_sock (net, family, port); + vs =vxlan_find_sock (net, family, port, flags);if (!vs)return NULL ;
@@ -1957,7 +1962,8 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,ip_rt_put (rt); dst_vxlan =vxlan_find_vni (vxlan->net, vni, - dst->sa.sa_family, dst_port); + dst->sa.sa_family, dst_port, + vxlan->flags);if (!dst_vxlan) goto tx_error;vxlan_encap_bypass (skb, vxlan, dst_vxlan);
@@ -2016,7 +2022,8 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,dst_release (ndst); dst_vxlan =vxlan_find_vni (vxlan->net, vni, - dst->sa.sa_family, dst_port); + dst->sa.sa_family, dst_port, + vxlan->flags);if (!dst_vxlan) goto tx_error;vxlan_encap_bypass (skb, vxlan, dst_vxlan);
@@ -2186,7 +2193,7 @@ static int vxlan_init(struct net_device *dev)spin_lock (&vn->sock_lock); vs =vxlan_find_sock (vxlan->net, ipv6 ?AF_INET6 :AF_INET , - vxlan->dst_port); + vxlan->dst_port, vxlan->flags);if (vs &&atomic_add_unless (&vs->refcnt,1 ,0 )) {/* If we have a socket with same port already, reuse it */ vxlan_vs_add_dev (vs, vxlan);
@@ -2593,7 +2600,7 @@ struct vxlan_sock *vxlan_sock_add(struct net *net, __be16 port,return vs;spin_lock (&vn->sock_lock); - vs =vxlan_find_sock (net, ipv6 ?AF_INET6 :AF_INET , port); + vs =vxlan_find_sock (net, ipv6 ?AF_INET6 :AF_INET , port, flags);if (vs && ((vs->rcv != rcv) || !atomic_add_unless (&vs->refcnt,1 ,0 ))) vs =ERR_PTR (-EBUSY );
@@ -2761,7 +2768,7 @@ static int vxlan_newlink(struct net *net, struct net_device *dev, vxlan->flags |=VXLAN_F_GBP ;if (vxlan_find_vni (net, vni, use_ipv6 ?AF_INET6 :AF_INET , - vxlan->dst_port)) { + vxlan->dst_port, vxlan->flags)) {pr_info ("duplicate VNI %u\n" , vni);return -EEXIST ; }
include/net/vxlan.h +3 -0
@@ -129,6 +129,9 @@ struct vxlan_sock {#define VXLAN_F_REMCSUM_RX 0x400#define VXLAN_F_GBP 0x800 +/* These flags must match in order for a socket to be shareable */ +#define VXLAN_F_UNSHAREABLE VXLAN_F_GBP +struct vxlan_sock *vxlan_sock_add (struct net *net,__be16 port,vxlan_rcv_t *rcv,void *data,bool no_share,u32 flags);
Signature · 1 line
1.9.3
PATCH v6 3/5 openvswitch: Rename GENEVE_TUN_OPTS() to TUN_METADATA_OPTS()
In reply to Thomas GrafAlso factors out Geneve validation code into a new separate function validate_and_copy_geneve_opts().
A subsequent patch will introduce VXLAN options. Rename the existing GENEVE_TUN_OPTS() to reflect its extended purpose of carrying generic tunnel metadata options.
---v5->v6:
- No changev4->v5:
- No changev3->v4:
- Renamed validate_and_copy_geneve_opts() to validate_geneve_opts() as suggested by Jessev2->v3:
- No changev1->v2:
- Don't rename genev_tun_opt_from_nlattr() and keep it Geneve specific, pointed out by Jesse.
- Factor out Geneve specific validation code into separate function as requested by Jesse.
net/openvswitch/flow.c | 2 +- net/openvswitch/flow.h | 14 ++++---- net/openvswitch/flow_netlink.c | 72 +++++++++++++++++++++++------------------- 3 files changed, 47 insertions(+), 41 deletions(-)
net/openvswitch/flow.c +1 -1
@@ -691,7 +691,7 @@ int ovs_flow_key_extract(const struct ovs_tunnel_info *tun_info,BUILD_BUG_ON ((1 << (sizeof (tun_info->options_len) *8 )) -1 >sizeof (key->tun_opts)); -memcpy (GENEVE_OPTS (key, tun_info->options_len), +memcpy (TUN_METADATA_OPTS (key, tun_info->options_len), tun_info->options, tun_info->options_len); key->tun_opts_len = tun_info->options_len; }else {
net/openvswitch/flow.h +7 -7
@@ -53,7 +53,7 @@ struct ovs_key_ipv4_tunnel {struct ovs_tunnel_info {struct ovs_key_ipv4_tunnel tunnel; -const struct geneve_opt *options; +const void *options;u8 options_len; };
@@ -61,10 +61,10 @@ struct ovs_tunnel_info {* maximum size. This allows us to get the benefits of variable length * matching for small options. */ -#define GENEVE_OPTS (flow_key, opt_len) \ - ((struct geneve_opt *)((flow_key)->tun_opts + \ - FIELD_SIZEOF(struct sw_flow_key, tun_opts) - \ - opt_len)) +#define TUN_METADATA_OFFSET (opt_len) \ + (FIELD_SIZEOF(struct sw_flow_key, tun_opts) - opt_len) +#define TUN_METADATA_OPTS (flow_key, opt_len) \ + ((void *)((flow_key)->tun_opts + TUN_METADATA_OFFSET(opt_len))) static inline void __ovs_flow_tun_info_init(struct ovs_tunnel_info *tun_info, __be32 saddr, __be32 daddr,
@@ -73,7 +73,7 @@ static inline void __ovs_flow_tun_info_init(struct ovs_tunnel_info *tun_info,__be16 tp_dst, __be64 tun_id, __be16 tun_flags, - const struct geneve_opt *opts, + const void *opts, u8 opts_len) { tun_info->tunnel.tun_id = tun_id;
@@ -105,7 +105,7 @@ static inline void ovs_flow_tun_info_init(struct ovs_tunnel_info *tun_info, __be16 tp_dst, __be64 tun_id, __be16 tun_flags, - const struct geneve_opt *opts, + const void *opts, u8 opts_len) { __ovs_flow_tun_info_init(tun_info, iph->saddr, iph->daddr,
net/openvswitch/flow_netlink.c +39 -33
116 lines not on this page · raw message
Signature · 1 line
1.9.3
PATCH v6 5/5 openvswitch: Support VXLAN Group Policy extension
In reply to Thomas GrafIntroduces 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=gbpThe 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.
---v5->v6:
- No changev4->v5:
- No changev3->v4:
- Fixed OVS_VXLAN_EXT_MAX->OVS_VXLAN_EXT_GBP typo as spotted by Jesse
- Only applied tunnel options if they are of the right type as suggested by Jessev2->v3:
- No changev1->v2:
- Addressed Jesse's request to transport VXLAN options as Netlink attributes instead of a binary blob. Allows a partial transport of VXLAN extensions. Internally, the datapath continues to use a binary blob (defined in vport-vxlan.h) for performance reasons.
- Added new TUNNEL_GENEVE_OPT and TUNNEL_VXLAN_OPT flags to mark tunnel option flavour
- Correctly report VXLAN options to user space
include/net/ip_tunnels.h | 5 +- include/uapi/linux/openvswitch.h | 11 ++++ net/openvswitch/flow_netlink.c | 114 ++++++++++++++++++++++++++++++++++----- net/openvswitch/vport-geneve.c | 15 ++++-- net/openvswitch/vport-vxlan.c | 82 +++++++++++++++++++++++++++- net/openvswitch/vport-vxlan.h | 11 ++++ 6 files changed, 218 insertions(+), 20 deletions(-) create mode 100644 net/openvswitch/vport-vxlan.h
include/net/ip_tunnels.h +4 -1
@@ -97,7 +97,10 @@ struct ip_tunnel {#define TUNNEL_DONT_FRAGMENT __cpu_to_be16(0x0100)#define TUNNEL_OAM __cpu_to_be16(0x0200)#define TUNNEL_CRIT_OPT __cpu_to_be16(0x0400) -#define TUNNEL_OPTIONS_PRESENT __cpu_to_be16(0x0800) +#define TUNNEL_GENEVE_OPT __cpu_to_be16(0x0800) +#define TUNNEL_VXLAN_OPT __cpu_to_be16(0x1000) + +#define TUNNEL_OPTIONS_PRESENT (TUNNEL_GENEVE_OPT | TUNNEL_VXLAN_OPT)struct tnl_ptk_info {__be16 flags;
include/uapi/linux/openvswitch.h +11 -0
@@ -248,11 +248,21 @@ enum ovs_vport_attr {#define OVS_VPORT_ATTR_MAX (__OVS_VPORT_ATTR_MAX - 1) +enum { +OVS_VXLAN_EXT_UNSPEC , +OVS_VXLAN_EXT_GBP ,/* Flag or __u32 */ + __OVS_VXLAN_EXT_MAX, +}; + +#define OVS_VXLAN_EXT_MAX (__OVS_VXLAN_EXT_MAX - 1) + +/* OVS_VPORT_ATTR_OPTIONS attributes for tunnels. */ enum {OVS_TUNNEL_ATTR_UNSPEC ,OVS_TUNNEL_ATTR_DST_PORT ,/* 16-bit UDP port, used by L4 tunnels. */ +OVS_TUNNEL_ATTR_EXTENSION , __OVS_TUNNEL_ATTR_MAX };
@@ -324,6 +334,7 @@ enum ovs_tunnel_key_attr {OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS ,/* Array of Geneve options. */ OVS_TUNNEL_KEY_ATTR_TP_SRC ,/* be16 src Transport Port. */ OVS_TUNNEL_KEY_ATTR_TP_DST ,/* be16 dst Transport Port. */ +OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS ,/* Nested OVS_VXLAN_EXT_* */ __OVS_TUNNEL_KEY_ATTR_MAX };
net/openvswitch/flow_netlink.c +101 -13
182 lines not on this page · raw message
net/openvswitch/vport-geneve.c +11 -4
@@ -88,7 +88,7 @@ static void geneve_rcv(struct geneve_sock *gs, struct sk_buff *skb) opts_len = geneveh->opt_len *4 ; - flags =TUNNEL_KEY |TUNNEL_OPTIONS_PRESENT | + flags =TUNNEL_KEY |TUNNEL_GENEVE_OPT | (udp_hdr (skb)->check !=0 ?TUNNEL_CSUM :0 ) | (geneveh->oam ?TUNNEL_OAM :0 ) | (geneveh->critical ?TUNNEL_CRIT_OPT :0 );
@@ -178,7 +178,7 @@ static int geneve_tnl_send(struct vport *vport, struct sk_buff *skb)__be16 sport;struct rtable *rt;struct flowi4 fl; -u8 vni[3 ]; +u8 vni[3 ], opts_len, *opts;__be16 df;int err;
@@ -209,11 +209,18 @@ static int geneve_tnl_send(struct vport *vport, struct sk_buff *skb)tunnel_id_to_vni (tun_key->tun_id, vni); skb->ignore_df =1 ; +if (tun_key->tun_flags &TUNNEL_GENEVE_OPT ) { + opts = (u8 *)tun_info->options; + opts_len = tun_info->options_len; + }else { + opts =NULL ; + opts_len =0 ; + } + err =geneve_xmit_skb (geneve_port->gs, rt, skb, fl.saddr, tun_key->ipv4_dst, tun_key->ipv4_tos, tun_key->ipv4_ttl, df, sport, dport, - tun_key->tun_flags, vni, - tun_info->options_len, (u8 *)tun_info->options, + tun_key->tun_flags, vni, opts_len, opts, false);if (err <0 )ip_rt_put (rt);
net/openvswitch/vport-vxlan.c +80 -2
139 lines not on this page · raw message
net/openvswitch/vport-vxlan.h new file +11 -0
@@ -0,0 +1,11 @@ +#ifndef VPORT_VXLAN_H +#define VPORT_VXLAN_H 1 + +#include <linux/kernel.h> +#include <linux/types.h> + +struct ovs_vxlan_opts { +__u32 gbp; +}; + +#endif
Signature · 1 line
1.9.3
From: Thomas Graf <[email protected]>
Date: Thu, 15 Jan 2015 03:53:54 +0100
Quoted 19 lines
Implements supports for the Group Policy VXLAN extension [0] to provide a lightweight and simple security label mechanism across network peers based on VXLAN. The security context and associated metadata is mapped to/from
skb->mark. This allows further mapping to a SELinux context using SECMARK, to implement ACLs directly with nftables, iptables, OVS, tc, etc.The extension is disabled by default and should be run on a distinct port in mixed Linux VXLAN VTEP environments. Liberal VXLAN VTEPs which ignore unknown reserved bits will be able to receive VXLAN-GBP frames.
Simple usage example:
10.1.1.1:
# ip link add vxlan0 type vxlan id 10 remote 10.1.1.2 gbp # iptables -I OUTPUT -m owner --uid-owner 101 -j MARK --set-mark 0x20010.1.1.2:
Quoted 8 lines
# ip link add vxlan0 type vxlan id 10 remote 10.1.1.1 gbp # iptables -I INPUT -m mark --mark 0x200 -j DROPiproute2 [1] and OVS [2] support will be provided in separate patches.
[0] https://tools.ietf.org/html/draft-smith-vxlan-group-policy
[1] https://github.com/tgraf/iproute2/tree/vxlan-gbp
[2] https://github.com/tgraf/ovs/tree/vxlan-gbp
Applied, thanks a lot Thomas.