2015-07-21 11:43:56 +03:00
# ifndef __NET_DST_METADATA_H
# define __NET_DST_METADATA_H 1
# include <linux/skbuff.h>
# include <net/ip_tunnels.h>
# include <net/dst.h>
2017-06-23 23:11:58 +03:00
enum metadata_type {
METADATA_IP_TUNNEL ,
METADATA_HW_PORT_MUX ,
} ;
struct hw_port_info {
struct net_device * lower_dev ;
u32 port_id ;
} ;
2015-07-21 11:43:56 +03:00
struct metadata_dst {
struct dst_entry dst ;
2017-06-23 23:11:58 +03:00
enum metadata_type type ;
2015-07-21 11:43:58 +03:00
union {
struct ip_tunnel_info tun_info ;
2017-06-23 23:11:58 +03:00
struct hw_port_info port_info ;
2015-07-21 11:43:58 +03:00
} u ;
2015-07-21 11:43:56 +03:00
} ;
static inline struct metadata_dst * skb_metadata_dst ( struct sk_buff * skb )
{
struct metadata_dst * md_dst = ( struct metadata_dst * ) skb_dst ( skb ) ;
if ( md_dst & & md_dst - > dst . flags & DST_METADATA )
return md_dst ;
return NULL ;
}
2015-08-20 14:56:25 +03:00
static inline struct ip_tunnel_info * skb_tunnel_info ( struct sk_buff * skb )
2015-07-21 11:43:58 +03:00
{
struct metadata_dst * md_dst = skb_metadata_dst ( skb ) ;
2015-08-20 14:56:25 +03:00
struct dst_entry * dst ;
2015-07-21 11:43:58 +03:00
2017-06-23 23:11:58 +03:00
if ( md_dst & & md_dst - > type = = METADATA_IP_TUNNEL )
2015-07-21 11:43:58 +03:00
return & md_dst - > u . tun_info ;
2015-08-20 14:56:25 +03:00
dst = skb_dst ( skb ) ;
if ( dst & & dst - > lwtstate )
return lwt_tun_info ( dst - > lwtstate ) ;
2015-07-21 11:44:00 +03:00
2015-07-21 11:43:58 +03:00
return NULL ;
}
2015-07-21 11:43:56 +03:00
static inline bool skb_valid_dst ( const struct sk_buff * skb )
{
struct dst_entry * dst = skb_dst ( skb ) ;
return dst & & ! ( dst - > flags & DST_METADATA ) ;
}
2016-01-21 04:59:49 +03:00
static inline int skb_metadata_dst_cmp ( const struct sk_buff * skb_a ,
const struct sk_buff * skb_b )
{
const struct metadata_dst * a , * b ;
if ( ! ( skb_a - > _skb_refdst | skb_b - > _skb_refdst ) )
return 0 ;
a = ( const struct metadata_dst * ) skb_dst ( skb_a ) ;
b = ( const struct metadata_dst * ) skb_dst ( skb_b ) ;
2017-06-23 23:11:58 +03:00
if ( ! a ! = ! b | | a - > type ! = b - > type )
2016-01-21 04:59:49 +03:00
return 1 ;
2017-06-23 23:11:58 +03:00
switch ( a - > type ) {
case METADATA_HW_PORT_MUX :
return memcmp ( & a - > u . port_info , & b - > u . port_info ,
sizeof ( a - > u . port_info ) ) ;
case METADATA_IP_TUNNEL :
return memcmp ( & a - > u . tun_info , & b - > u . tun_info ,
sizeof ( a - > u . tun_info ) +
a - > u . tun_info . options_len ) ;
default :
return 1 ;
}
2016-01-21 04:59:49 +03:00
}
2016-02-12 17:43:57 +03:00
void metadata_dst_free ( struct metadata_dst * ) ;
2017-06-23 23:11:58 +03:00
struct metadata_dst * metadata_dst_alloc ( u8 optslen , enum metadata_type type ,
gfp_t flags ) ;
struct metadata_dst __percpu *
metadata_dst_alloc_percpu ( u8 optslen , enum metadata_type type , gfp_t flags ) ;
2015-07-21 11:43:56 +03:00
2015-08-31 04:09:38 +03:00
static inline struct metadata_dst * tun_rx_dst ( int md_size )
2015-08-27 09:46:50 +03:00
{
struct metadata_dst * tun_dst ;
2017-06-23 23:11:58 +03:00
tun_dst = metadata_dst_alloc ( md_size , METADATA_IP_TUNNEL , GFP_ATOMIC ) ;
2015-08-27 09:46:50 +03:00
if ( ! tun_dst )
return NULL ;
2015-08-31 04:09:38 +03:00
tun_dst - > u . tun_info . options_len = 0 ;
tun_dst - > u . tun_info . mode = 0 ;
2015-08-27 09:46:50 +03:00
return tun_dst ;
}
2015-10-23 04:17:16 +03:00
static inline struct metadata_dst * tun_dst_unclone ( struct sk_buff * skb )
{
struct metadata_dst * md_dst = skb_metadata_dst ( skb ) ;
2015-11-04 15:49:49 +03:00
int md_size ;
2015-10-23 04:17:16 +03:00
struct metadata_dst * new_md ;
2017-06-23 23:11:58 +03:00
if ( ! md_dst | | md_dst - > type ! = METADATA_IP_TUNNEL )
2015-10-23 04:17:16 +03:00
return ERR_PTR ( - EINVAL ) ;
2015-11-04 15:49:49 +03:00
md_size = md_dst - > u . tun_info . options_len ;
2017-06-23 23:11:58 +03:00
new_md = metadata_dst_alloc ( md_size , METADATA_IP_TUNNEL , GFP_ATOMIC ) ;
2015-10-23 04:17:16 +03:00
if ( ! new_md )
return ERR_PTR ( - ENOMEM ) ;
memcpy ( & new_md - > u . tun_info , & md_dst - > u . tun_info ,
sizeof ( struct ip_tunnel_info ) + md_size ) ;
skb_dst_drop ( skb ) ;
dst_hold ( & new_md - > dst ) ;
skb_dst_set ( skb , & new_md - > dst ) ;
return new_md ;
}
static inline struct ip_tunnel_info * skb_tunnel_info_unclone ( struct sk_buff * skb )
{
struct metadata_dst * dst ;
dst = tun_dst_unclone ( skb ) ;
if ( IS_ERR ( dst ) )
return NULL ;
return & dst - > u . tun_info ;
}
2016-09-08 16:23:46 +03:00
static inline struct metadata_dst * __ip_tun_set_dst ( __be32 saddr ,
__be32 daddr ,
__u8 tos , __u8 ttl ,
2016-11-07 16:14:40 +03:00
__be16 tp_dst ,
2016-09-08 16:23:46 +03:00
__be16 flags ,
__be64 tunnel_id ,
int md_size )
2015-08-27 09:46:50 +03:00
{
struct metadata_dst * tun_dst ;
2015-08-31 04:09:38 +03:00
tun_dst = tun_rx_dst ( md_size ) ;
2015-08-27 09:46:50 +03:00
if ( ! tun_dst )
return NULL ;
2015-08-31 04:09:38 +03:00
ip_tunnel_key_init ( & tun_dst - > u . tun_info . key ,
2016-09-08 16:23:46 +03:00
saddr , daddr , tos , ttl ,
2016-11-07 16:14:40 +03:00
0 , 0 , tp_dst , tunnel_id , flags ) ;
2015-08-27 09:46:50 +03:00
return tun_dst ;
}
2016-09-08 16:23:46 +03:00
static inline struct metadata_dst * ip_tun_rx_dst ( struct sk_buff * skb ,
2015-08-27 09:46:50 +03:00
__be16 flags ,
__be64 tunnel_id ,
int md_size )
{
2016-09-08 16:23:46 +03:00
const struct iphdr * iph = ip_hdr ( skb ) ;
return __ip_tun_set_dst ( iph - > saddr , iph - > daddr , iph - > tos , iph - > ttl ,
2016-11-07 16:14:40 +03:00
0 , flags , tunnel_id , md_size ) ;
2016-09-08 16:23:46 +03:00
}
static inline struct metadata_dst * __ipv6_tun_set_dst ( const struct in6_addr * saddr ,
const struct in6_addr * daddr ,
__u8 tos , __u8 ttl ,
2016-11-07 16:14:40 +03:00
__be16 tp_dst ,
2016-09-08 16:23:46 +03:00
__be32 label ,
__be16 flags ,
__be64 tunnel_id ,
int md_size )
{
2015-08-27 09:46:50 +03:00
struct metadata_dst * tun_dst ;
struct ip_tunnel_info * info ;
2015-08-31 04:09:38 +03:00
tun_dst = tun_rx_dst ( md_size ) ;
2015-08-27 09:46:50 +03:00
if ( ! tun_dst )
return NULL ;
info = & tun_dst - > u . tun_info ;
2015-08-31 04:09:38 +03:00
info - > mode = IP_TUNNEL_INFO_IPV6 ;
info - > key . tun_flags = flags ;
info - > key . tun_id = tunnel_id ;
info - > key . tp_src = 0 ;
2016-11-07 16:14:40 +03:00
info - > key . tp_dst = tp_dst ;
2015-08-31 04:09:38 +03:00
2016-09-08 16:23:46 +03:00
info - > key . u . ipv6 . src = * saddr ;
info - > key . u . ipv6 . dst = * daddr ;
2016-03-09 05:00:02 +03:00
2016-09-08 16:23:46 +03:00
info - > key . tos = tos ;
info - > key . ttl = ttl ;
info - > key . label = label ;
2016-03-09 05:00:02 +03:00
2015-08-27 09:46:50 +03:00
return tun_dst ;
}
2016-09-08 16:23:46 +03:00
static inline struct metadata_dst * ipv6_tun_rx_dst ( struct sk_buff * skb ,
__be16 flags ,
__be64 tunnel_id ,
int md_size )
{
const struct ipv6hdr * ip6h = ipv6_hdr ( skb ) ;
return __ipv6_tun_set_dst ( & ip6h - > saddr , & ip6h - > daddr ,
ipv6_get_dsfield ( ip6h ) , ip6h - > hop_limit ,
2016-11-07 16:14:40 +03:00
0 , ip6_flowlabel ( ip6h ) , flags , tunnel_id ,
2016-09-08 16:23:46 +03:00
md_size ) ;
}
2015-07-21 11:43:56 +03:00
# endif /* __NET_DST_METADATA_H */