mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	pfcp: always set pfcp metadata
In PFCP receive path set metadata needed by flower code to do correct classification based on this metadata. Signed-off-by: Michal Swiatkowski <michal.swiatkowski@linux.intel.com> Signed-off-by: Marcin Szycik <marcin.szycik@linux.intel.com> Reviewed-by: Simon Horman <horms@kernel.org> Signed-off-by: Alexander Lobakin <aleksander.lobakin@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									76c8764ef3
								
							
						
					
					
						commit
						6dd514f481
					
				
					 7 changed files with 282 additions and 6 deletions
				
			
		| 
						 | 
					@ -21,6 +21,8 @@ struct pfcp_dev {
 | 
				
			||||||
	struct socket		*sock;
 | 
						struct socket		*sock;
 | 
				
			||||||
	struct net_device	*dev;
 | 
						struct net_device	*dev;
 | 
				
			||||||
	struct net		*net;
 | 
						struct net		*net;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct gro_cells	gro_cells;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static unsigned int pfcp_net_id __read_mostly;
 | 
					static unsigned int pfcp_net_id __read_mostly;
 | 
				
			||||||
| 
						 | 
					@ -29,6 +31,78 @@ struct pfcp_net {
 | 
				
			||||||
	struct list_head	pfcp_dev_list;
 | 
						struct list_head	pfcp_dev_list;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					pfcp_session_recv(struct pfcp_dev *pfcp, struct sk_buff *skb,
 | 
				
			||||||
 | 
							  struct pfcp_metadata *md)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct pfcphdr_session *unparsed = pfcp_hdr_session(skb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						md->seid = unparsed->seid;
 | 
				
			||||||
 | 
						md->type = PFCP_TYPE_SESSION;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					pfcp_node_recv(struct pfcp_dev *pfcp, struct sk_buff *skb,
 | 
				
			||||||
 | 
						       struct pfcp_metadata *md)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						md->type = PFCP_TYPE_NODE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int pfcp_encap_recv(struct sock *sk, struct sk_buff *skb)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						IP_TUNNEL_DECLARE_FLAGS(flags) = { };
 | 
				
			||||||
 | 
						struct metadata_dst *tun_dst;
 | 
				
			||||||
 | 
						struct pfcp_metadata *md;
 | 
				
			||||||
 | 
						struct pfcphdr *unparsed;
 | 
				
			||||||
 | 
						struct pfcp_dev *pfcp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (unlikely(!pskb_may_pull(skb, PFCP_HLEN)))
 | 
				
			||||||
 | 
							goto drop;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pfcp = rcu_dereference_sk_user_data(sk);
 | 
				
			||||||
 | 
						if (unlikely(!pfcp))
 | 
				
			||||||
 | 
							goto drop;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						unparsed = pfcp_hdr(skb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ip_tunnel_flags_zero(flags);
 | 
				
			||||||
 | 
						tun_dst = udp_tun_rx_dst(skb, sk->sk_family, flags, 0,
 | 
				
			||||||
 | 
									 sizeof(*md));
 | 
				
			||||||
 | 
						if (unlikely(!tun_dst))
 | 
				
			||||||
 | 
							goto drop;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						md = ip_tunnel_info_opts(&tun_dst->u.tun_info);
 | 
				
			||||||
 | 
						if (unlikely(!md))
 | 
				
			||||||
 | 
							goto drop;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (unparsed->flags & PFCP_SEID_FLAG)
 | 
				
			||||||
 | 
							pfcp_session_recv(pfcp, skb, md);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							pfcp_node_recv(pfcp, skb, md);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						__set_bit(IP_TUNNEL_PFCP_OPT_BIT, flags);
 | 
				
			||||||
 | 
						ip_tunnel_info_opts_set(&tun_dst->u.tun_info, md, sizeof(*md),
 | 
				
			||||||
 | 
									flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (unlikely(iptunnel_pull_header(skb, PFCP_HLEN, skb->protocol,
 | 
				
			||||||
 | 
										  !net_eq(sock_net(sk),
 | 
				
			||||||
 | 
										  dev_net(pfcp->dev)))))
 | 
				
			||||||
 | 
							goto drop;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						skb_dst_set(skb, (struct dst_entry *)tun_dst);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						skb_reset_network_header(skb);
 | 
				
			||||||
 | 
						skb_reset_mac_header(skb);
 | 
				
			||||||
 | 
						skb->dev = pfcp->dev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gro_cells_receive(&pfcp->gro_cells, skb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					drop:
 | 
				
			||||||
 | 
						kfree_skb(skb);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void pfcp_del_sock(struct pfcp_dev *pfcp)
 | 
					static void pfcp_del_sock(struct pfcp_dev *pfcp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	udp_tunnel_sock_release(pfcp->sock);
 | 
						udp_tunnel_sock_release(pfcp->sock);
 | 
				
			||||||
| 
						 | 
					@ -39,6 +113,7 @@ static void pfcp_dev_uninit(struct net_device *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pfcp_dev *pfcp = netdev_priv(dev);
 | 
						struct pfcp_dev *pfcp = netdev_priv(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gro_cells_destroy(&pfcp->gro_cells);
 | 
				
			||||||
	pfcp_del_sock(pfcp);
 | 
						pfcp_del_sock(pfcp);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -48,7 +123,7 @@ static int pfcp_dev_init(struct net_device *dev)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pfcp->dev = dev;
 | 
						pfcp->dev = dev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return gro_cells_init(&pfcp->gro_cells, dev);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct net_device_ops pfcp_netdev_ops = {
 | 
					static const struct net_device_ops pfcp_netdev_ops = {
 | 
				
			||||||
| 
						 | 
					@ -94,6 +169,10 @@ static struct socket *pfcp_create_sock(struct pfcp_dev *pfcp)
 | 
				
			||||||
	if (err)
 | 
						if (err)
 | 
				
			||||||
		return ERR_PTR(err);
 | 
							return ERR_PTR(err);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tuncfg.sk_user_data = pfcp;
 | 
				
			||||||
 | 
						tuncfg.encap_rcv = pfcp_encap_recv;
 | 
				
			||||||
 | 
						tuncfg.encap_type = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	setup_udp_tunnel_sock(net, sock, &tuncfg);
 | 
						setup_udp_tunnel_sock(net, sock, &tuncfg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return sock;
 | 
						return sock;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -216,6 +216,7 @@ static inline void ip_tunnel_set_options_present(unsigned long *flags)
 | 
				
			||||||
	__set_bit(IP_TUNNEL_VXLAN_OPT_BIT, present);
 | 
						__set_bit(IP_TUNNEL_VXLAN_OPT_BIT, present);
 | 
				
			||||||
	__set_bit(IP_TUNNEL_ERSPAN_OPT_BIT, present);
 | 
						__set_bit(IP_TUNNEL_ERSPAN_OPT_BIT, present);
 | 
				
			||||||
	__set_bit(IP_TUNNEL_GTP_OPT_BIT, present);
 | 
						__set_bit(IP_TUNNEL_GTP_OPT_BIT, present);
 | 
				
			||||||
 | 
						__set_bit(IP_TUNNEL_PFCP_OPT_BIT, present);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ip_tunnel_flags_or(flags, flags, present);
 | 
						ip_tunnel_flags_or(flags, flags, present);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -228,6 +229,7 @@ static inline void ip_tunnel_clear_options_present(unsigned long *flags)
 | 
				
			||||||
	__set_bit(IP_TUNNEL_VXLAN_OPT_BIT, present);
 | 
						__set_bit(IP_TUNNEL_VXLAN_OPT_BIT, present);
 | 
				
			||||||
	__set_bit(IP_TUNNEL_ERSPAN_OPT_BIT, present);
 | 
						__set_bit(IP_TUNNEL_ERSPAN_OPT_BIT, present);
 | 
				
			||||||
	__set_bit(IP_TUNNEL_GTP_OPT_BIT, present);
 | 
						__set_bit(IP_TUNNEL_GTP_OPT_BIT, present);
 | 
				
			||||||
 | 
						__set_bit(IP_TUNNEL_PFCP_OPT_BIT, present);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	__ipt_flag_op(bitmap_andnot, flags, flags, present);
 | 
						__ipt_flag_op(bitmap_andnot, flags, flags, present);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -240,6 +242,7 @@ static inline bool ip_tunnel_is_options_present(const unsigned long *flags)
 | 
				
			||||||
	__set_bit(IP_TUNNEL_VXLAN_OPT_BIT, present);
 | 
						__set_bit(IP_TUNNEL_VXLAN_OPT_BIT, present);
 | 
				
			||||||
	__set_bit(IP_TUNNEL_ERSPAN_OPT_BIT, present);
 | 
						__set_bit(IP_TUNNEL_ERSPAN_OPT_BIT, present);
 | 
				
			||||||
	__set_bit(IP_TUNNEL_GTP_OPT_BIT, present);
 | 
						__set_bit(IP_TUNNEL_GTP_OPT_BIT, present);
 | 
				
			||||||
 | 
						__set_bit(IP_TUNNEL_PFCP_OPT_BIT, present);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return ip_tunnel_flags_intersect(flags, present);
 | 
						return ip_tunnel_flags_intersect(flags, present);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,12 +2,85 @@
 | 
				
			||||||
#ifndef _PFCP_H_
 | 
					#ifndef _PFCP_H_
 | 
				
			||||||
#define _PFCP_H_
 | 
					#define _PFCP_H_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <uapi/linux/if_ether.h>
 | 
				
			||||||
 | 
					#include <net/dst_metadata.h>
 | 
				
			||||||
#include <linux/netdevice.h>
 | 
					#include <linux/netdevice.h>
 | 
				
			||||||
 | 
					#include <uapi/linux/ipv6.h>
 | 
				
			||||||
 | 
					#include <net/udp_tunnel.h>
 | 
				
			||||||
 | 
					#include <uapi/linux/udp.h>
 | 
				
			||||||
 | 
					#include <uapi/linux/ip.h>
 | 
				
			||||||
#include <linux/string.h>
 | 
					#include <linux/string.h>
 | 
				
			||||||
#include <linux/types.h>
 | 
					#include <linux/types.h>
 | 
				
			||||||
 | 
					#include <linux/bits.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define PFCP_PORT 8805
 | 
					#define PFCP_PORT 8805
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* PFCP protocol header */
 | 
				
			||||||
 | 
					struct pfcphdr {
 | 
				
			||||||
 | 
						u8	flags;
 | 
				
			||||||
 | 
						u8	message_type;
 | 
				
			||||||
 | 
						__be16	message_length;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* PFCP header flags */
 | 
				
			||||||
 | 
					#define PFCP_SEID_FLAG		BIT(0)
 | 
				
			||||||
 | 
					#define PFCP_MP_FLAG		BIT(1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define PFCP_VERSION_MASK	GENMASK(4, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define PFCP_HLEN (sizeof(struct udphdr) + sizeof(struct pfcphdr))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* PFCP node related messages */
 | 
				
			||||||
 | 
					struct pfcphdr_node {
 | 
				
			||||||
 | 
						u8	seq_number[3];
 | 
				
			||||||
 | 
						u8	reserved;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* PFCP session related messages */
 | 
				
			||||||
 | 
					struct pfcphdr_session {
 | 
				
			||||||
 | 
						__be64	seid;
 | 
				
			||||||
 | 
						u8	seq_number[3];
 | 
				
			||||||
 | 
					#ifdef __LITTLE_ENDIAN_BITFIELD
 | 
				
			||||||
 | 
						u8	message_priority:4,
 | 
				
			||||||
 | 
							reserved:4;
 | 
				
			||||||
 | 
					#elif defined(__BIG_ENDIAN_BITFIELD)
 | 
				
			||||||
 | 
						u8	reserved:4,
 | 
				
			||||||
 | 
							message_priprity:4;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#error "Please fix <asm/byteorder>"
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct pfcp_metadata {
 | 
				
			||||||
 | 
						u8 type;
 | 
				
			||||||
 | 
						__be64 seid;
 | 
				
			||||||
 | 
					} __packed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum {
 | 
				
			||||||
 | 
						PFCP_TYPE_NODE		= 0,
 | 
				
			||||||
 | 
						PFCP_TYPE_SESSION	= 1,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define PFCP_HEADROOM (sizeof(struct iphdr) + sizeof(struct udphdr) + \
 | 
				
			||||||
 | 
							       sizeof(struct pfcphdr) + sizeof(struct ethhdr))
 | 
				
			||||||
 | 
					#define PFCP6_HEADROOM (sizeof(struct ipv6hdr) + sizeof(struct udphdr) + \
 | 
				
			||||||
 | 
								sizeof(struct pfcphdr) + sizeof(struct ethhdr))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline struct pfcphdr *pfcp_hdr(struct sk_buff *skb)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return (struct pfcphdr *)(udp_hdr(skb) + 1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline struct pfcphdr_node *pfcp_hdr_node(struct sk_buff *skb)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return (struct pfcphdr_node *)(pfcp_hdr(skb) + 1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline struct pfcphdr_session *pfcp_hdr_session(struct sk_buff *skb)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return (struct pfcphdr_session *)(pfcp_hdr(skb) + 1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline bool netif_is_pfcp(const struct net_device *dev)
 | 
					static inline bool netif_is_pfcp(const struct net_device *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return dev->rtnl_link_ops &&
 | 
						return dev->rtnl_link_ops &&
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -212,6 +212,9 @@ enum {
 | 
				
			||||||
	IP_TUNNEL_VTI_BIT,
 | 
						IP_TUNNEL_VTI_BIT,
 | 
				
			||||||
	IP_TUNNEL_SIT_ISATAP_BIT	= IP_TUNNEL_VTI_BIT,
 | 
						IP_TUNNEL_SIT_ISATAP_BIT	= IP_TUNNEL_VTI_BIT,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Flags starting from here are not available via the old UAPI */
 | 
				
			||||||
 | 
						IP_TUNNEL_PFCP_OPT_BIT,		/* OPTIONS_PRESENT */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	__IP_TUNNEL_FLAG_NUM,
 | 
						__IP_TUNNEL_FLAG_NUM,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -587,6 +587,10 @@ enum {
 | 
				
			||||||
					 * TCA_FLOWER_KEY_ENC_OPT_GTP_
 | 
										 * TCA_FLOWER_KEY_ENC_OPT_GTP_
 | 
				
			||||||
					 * attributes
 | 
										 * attributes
 | 
				
			||||||
					 */
 | 
										 */
 | 
				
			||||||
 | 
						TCA_FLOWER_KEY_ENC_OPTS_PFCP,	/* Nested
 | 
				
			||||||
 | 
										 * TCA_FLOWER_KEY_ENC_IPT_PFCP
 | 
				
			||||||
 | 
										 * attributes
 | 
				
			||||||
 | 
										 */
 | 
				
			||||||
	__TCA_FLOWER_KEY_ENC_OPTS_MAX,
 | 
						__TCA_FLOWER_KEY_ENC_OPTS_MAX,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -636,6 +640,16 @@ enum {
 | 
				
			||||||
#define TCA_FLOWER_KEY_ENC_OPT_GTP_MAX \
 | 
					#define TCA_FLOWER_KEY_ENC_OPT_GTP_MAX \
 | 
				
			||||||
		(__TCA_FLOWER_KEY_ENC_OPT_GTP_MAX - 1)
 | 
							(__TCA_FLOWER_KEY_ENC_OPT_GTP_MAX - 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum {
 | 
				
			||||||
 | 
						TCA_FLOWER_KEY_ENC_OPT_PFCP_UNSPEC,
 | 
				
			||||||
 | 
						TCA_FLOWER_KEY_ENC_OPT_PFCP_TYPE,		/* u8 */
 | 
				
			||||||
 | 
						TCA_FLOWER_KEY_ENC_OPT_PFCP_SEID,		/* be64 */
 | 
				
			||||||
 | 
						__TCA_FLOWER_KEY_ENC_OPT_PFCP_MAX,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define TCA_FLOWER_KEY_ENC_OPT_PFCP_MAX \
 | 
				
			||||||
 | 
							(__TCA_FLOWER_KEY_ENC_OPT_PFCP_MAX - 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum {
 | 
					enum {
 | 
				
			||||||
	TCA_FLOWER_KEY_MPLS_OPTS_UNSPEC,
 | 
						TCA_FLOWER_KEY_MPLS_OPTS_UNSPEC,
 | 
				
			||||||
	TCA_FLOWER_KEY_MPLS_OPTS_LSE,
 | 
						TCA_FLOWER_KEY_MPLS_OPTS_LSE,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -335,11 +335,8 @@ static const struct ip_tunnel_flags_test ip_tunnel_flags_test[] = {
 | 
				
			||||||
			     ip_tunnel_flags_1),
 | 
								     ip_tunnel_flags_1),
 | 
				
			||||||
	IP_TUNNEL_FLAGS_TEST("conflict", ip_tunnel_flags_2_src, true,
 | 
						IP_TUNNEL_FLAGS_TEST("conflict", ip_tunnel_flags_2_src, true,
 | 
				
			||||||
			     VTI_ISVTI, ip_tunnel_flags_2_exp),
 | 
								     VTI_ISVTI, ip_tunnel_flags_2_exp),
 | 
				
			||||||
	IP_TUNNEL_FLAGS_TEST("new", ip_tunnel_flags_3_src,
 | 
						IP_TUNNEL_FLAGS_TEST("new", ip_tunnel_flags_3_src, false,
 | 
				
			||||||
			     /* This must be set to ``false`` once
 | 
								     cpu_to_be16(BIT(IP_TUNNEL_VXLAN_OPT_BIT)),
 | 
				
			||||||
			      * ``__IP_TUNNEL_FLAG_NUM`` goes above 17.
 | 
					 | 
				
			||||||
			      */
 | 
					 | 
				
			||||||
			     true, cpu_to_be16(BIT(IP_TUNNEL_VXLAN_OPT_BIT)),
 | 
					 | 
				
			||||||
			     ip_tunnel_flags_3_exp),
 | 
								     ip_tunnel_flags_3_exp),
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,6 +28,7 @@
 | 
				
			||||||
#include <net/vxlan.h>
 | 
					#include <net/vxlan.h>
 | 
				
			||||||
#include <net/erspan.h>
 | 
					#include <net/erspan.h>
 | 
				
			||||||
#include <net/gtp.h>
 | 
					#include <net/gtp.h>
 | 
				
			||||||
 | 
					#include <net/pfcp.h>
 | 
				
			||||||
#include <net/tc_wrapper.h>
 | 
					#include <net/tc_wrapper.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <net/dst.h>
 | 
					#include <net/dst.h>
 | 
				
			||||||
| 
						 | 
					@ -741,6 +742,7 @@ enc_opts_policy[TCA_FLOWER_KEY_ENC_OPTS_MAX + 1] = {
 | 
				
			||||||
	[TCA_FLOWER_KEY_ENC_OPTS_VXLAN]         = { .type = NLA_NESTED },
 | 
						[TCA_FLOWER_KEY_ENC_OPTS_VXLAN]         = { .type = NLA_NESTED },
 | 
				
			||||||
	[TCA_FLOWER_KEY_ENC_OPTS_ERSPAN]        = { .type = NLA_NESTED },
 | 
						[TCA_FLOWER_KEY_ENC_OPTS_ERSPAN]        = { .type = NLA_NESTED },
 | 
				
			||||||
	[TCA_FLOWER_KEY_ENC_OPTS_GTP]		= { .type = NLA_NESTED },
 | 
						[TCA_FLOWER_KEY_ENC_OPTS_GTP]		= { .type = NLA_NESTED },
 | 
				
			||||||
 | 
						[TCA_FLOWER_KEY_ENC_OPTS_PFCP]		= { .type = NLA_NESTED },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct nla_policy
 | 
					static const struct nla_policy
 | 
				
			||||||
| 
						 | 
					@ -770,6 +772,12 @@ gtp_opt_policy[TCA_FLOWER_KEY_ENC_OPT_GTP_MAX + 1] = {
 | 
				
			||||||
	[TCA_FLOWER_KEY_ENC_OPT_GTP_QFI]	   = { .type = NLA_U8 },
 | 
						[TCA_FLOWER_KEY_ENC_OPT_GTP_QFI]	   = { .type = NLA_U8 },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct nla_policy
 | 
				
			||||||
 | 
					pfcp_opt_policy[TCA_FLOWER_KEY_ENC_OPT_PFCP_MAX + 1] = {
 | 
				
			||||||
 | 
						[TCA_FLOWER_KEY_ENC_OPT_PFCP_TYPE]	   = { .type = NLA_U8 },
 | 
				
			||||||
 | 
						[TCA_FLOWER_KEY_ENC_OPT_PFCP_SEID]	   = { .type = NLA_U64 },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct nla_policy
 | 
					static const struct nla_policy
 | 
				
			||||||
mpls_stack_entry_policy[TCA_FLOWER_KEY_MPLS_OPT_LSE_MAX + 1] = {
 | 
					mpls_stack_entry_policy[TCA_FLOWER_KEY_MPLS_OPT_LSE_MAX + 1] = {
 | 
				
			||||||
	[TCA_FLOWER_KEY_MPLS_OPT_LSE_DEPTH]    = { .type = NLA_U8 },
 | 
						[TCA_FLOWER_KEY_MPLS_OPT_LSE_DEPTH]    = { .type = NLA_U8 },
 | 
				
			||||||
| 
						 | 
					@ -1419,6 +1427,44 @@ static int fl_set_gtp_opt(const struct nlattr *nla, struct fl_flow_key *key,
 | 
				
			||||||
	return sizeof(*sinfo);
 | 
						return sizeof(*sinfo);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int fl_set_pfcp_opt(const struct nlattr *nla, struct fl_flow_key *key,
 | 
				
			||||||
 | 
								   int depth, int option_len,
 | 
				
			||||||
 | 
								   struct netlink_ext_ack *extack)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct nlattr *tb[TCA_FLOWER_KEY_ENC_OPT_PFCP_MAX + 1];
 | 
				
			||||||
 | 
						struct pfcp_metadata *md;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						md = (struct pfcp_metadata *)&key->enc_opts.data[key->enc_opts.len];
 | 
				
			||||||
 | 
						memset(md, 0xff, sizeof(*md));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!depth)
 | 
				
			||||||
 | 
							return sizeof(*md);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (nla_type(nla) != TCA_FLOWER_KEY_ENC_OPTS_PFCP) {
 | 
				
			||||||
 | 
							NL_SET_ERR_MSG_MOD(extack, "Non-pfcp option type for mask");
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = nla_parse_nested(tb, TCA_FLOWER_KEY_ENC_OPT_PFCP_MAX, nla,
 | 
				
			||||||
 | 
								       pfcp_opt_policy, extack);
 | 
				
			||||||
 | 
						if (err < 0)
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!option_len && !tb[TCA_FLOWER_KEY_ENC_OPT_PFCP_TYPE]) {
 | 
				
			||||||
 | 
							NL_SET_ERR_MSG_MOD(extack, "Missing tunnel key pfcp option type");
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (tb[TCA_FLOWER_KEY_ENC_OPT_PFCP_TYPE])
 | 
				
			||||||
 | 
							md->type = nla_get_u8(tb[TCA_FLOWER_KEY_ENC_OPT_PFCP_TYPE]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (tb[TCA_FLOWER_KEY_ENC_OPT_PFCP_SEID])
 | 
				
			||||||
 | 
							md->seid = nla_get_be64(tb[TCA_FLOWER_KEY_ENC_OPT_PFCP_SEID]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return sizeof(*md);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int fl_set_enc_opt(struct nlattr **tb, struct fl_flow_key *key,
 | 
					static int fl_set_enc_opt(struct nlattr **tb, struct fl_flow_key *key,
 | 
				
			||||||
			  struct fl_flow_key *mask,
 | 
								  struct fl_flow_key *mask,
 | 
				
			||||||
			  struct netlink_ext_ack *extack)
 | 
								  struct netlink_ext_ack *extack)
 | 
				
			||||||
| 
						 | 
					@ -1576,6 +1622,36 @@ static int fl_set_enc_opt(struct nlattr **tb, struct fl_flow_key *key,
 | 
				
			||||||
				return -EINVAL;
 | 
									return -EINVAL;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
							case TCA_FLOWER_KEY_ENC_OPTS_PFCP:
 | 
				
			||||||
 | 
								if (key->enc_opts.dst_opt_type) {
 | 
				
			||||||
 | 
									NL_SET_ERR_MSG_MOD(extack, "Duplicate type for pfcp options");
 | 
				
			||||||
 | 
									return -EINVAL;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								option_len = 0;
 | 
				
			||||||
 | 
								key->enc_opts.dst_opt_type = IP_TUNNEL_PFCP_OPT_BIT;
 | 
				
			||||||
 | 
								option_len = fl_set_pfcp_opt(nla_opt_key, key,
 | 
				
			||||||
 | 
											     key_depth, option_len,
 | 
				
			||||||
 | 
											     extack);
 | 
				
			||||||
 | 
								if (option_len < 0)
 | 
				
			||||||
 | 
									return option_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								key->enc_opts.len += option_len;
 | 
				
			||||||
 | 
								/* At the same time we need to parse through the mask
 | 
				
			||||||
 | 
								 * in order to verify exact and mask attribute lengths.
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
								mask->enc_opts.dst_opt_type = IP_TUNNEL_PFCP_OPT_BIT;
 | 
				
			||||||
 | 
								option_len = fl_set_pfcp_opt(nla_opt_msk, mask,
 | 
				
			||||||
 | 
											     msk_depth, option_len,
 | 
				
			||||||
 | 
											     extack);
 | 
				
			||||||
 | 
								if (option_len < 0)
 | 
				
			||||||
 | 
									return option_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								mask->enc_opts.len += option_len;
 | 
				
			||||||
 | 
								if (key->enc_opts.len != mask->enc_opts.len) {
 | 
				
			||||||
 | 
									NL_SET_ERR_MSG_MOD(extack, "Key and mask miss aligned");
 | 
				
			||||||
 | 
									return -EINVAL;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			NL_SET_ERR_MSG(extack, "Unknown tunnel option type");
 | 
								NL_SET_ERR_MSG(extack, "Unknown tunnel option type");
 | 
				
			||||||
			return -EINVAL;
 | 
								return -EINVAL;
 | 
				
			||||||
| 
						 | 
					@ -3118,6 +3194,32 @@ static int fl_dump_key_gtp_opt(struct sk_buff *skb,
 | 
				
			||||||
	return -EMSGSIZE;
 | 
						return -EMSGSIZE;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int fl_dump_key_pfcp_opt(struct sk_buff *skb,
 | 
				
			||||||
 | 
									struct flow_dissector_key_enc_opts *enc_opts)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct pfcp_metadata *md;
 | 
				
			||||||
 | 
						struct nlattr *nest;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						nest = nla_nest_start_noflag(skb, TCA_FLOWER_KEY_ENC_OPTS_PFCP);
 | 
				
			||||||
 | 
						if (!nest)
 | 
				
			||||||
 | 
							goto nla_put_failure;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						md = (struct pfcp_metadata *)&enc_opts->data[0];
 | 
				
			||||||
 | 
						if (nla_put_u8(skb, TCA_FLOWER_KEY_ENC_OPT_PFCP_TYPE, md->type))
 | 
				
			||||||
 | 
							goto nla_put_failure;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (nla_put_be64(skb, TCA_FLOWER_KEY_ENC_OPT_PFCP_SEID,
 | 
				
			||||||
 | 
								 md->seid, 0))
 | 
				
			||||||
 | 
							goto nla_put_failure;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						nla_nest_end(skb, nest);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					nla_put_failure:
 | 
				
			||||||
 | 
						nla_nest_cancel(skb, nest);
 | 
				
			||||||
 | 
						return -EMSGSIZE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int fl_dump_key_ct(struct sk_buff *skb,
 | 
					static int fl_dump_key_ct(struct sk_buff *skb,
 | 
				
			||||||
			  struct flow_dissector_key_ct *key,
 | 
								  struct flow_dissector_key_ct *key,
 | 
				
			||||||
			  struct flow_dissector_key_ct *mask)
 | 
								  struct flow_dissector_key_ct *mask)
 | 
				
			||||||
| 
						 | 
					@ -3223,6 +3325,11 @@ static int fl_dump_key_options(struct sk_buff *skb, int enc_opt_type,
 | 
				
			||||||
		if (err)
 | 
							if (err)
 | 
				
			||||||
			goto nla_put_failure;
 | 
								goto nla_put_failure;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
						case IP_TUNNEL_PFCP_OPT_BIT:
 | 
				
			||||||
 | 
							err = fl_dump_key_pfcp_opt(skb, enc_opts);
 | 
				
			||||||
 | 
							if (err)
 | 
				
			||||||
 | 
								goto nla_put_failure;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		goto nla_put_failure;
 | 
							goto nla_put_failure;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue