2015-09-29 20:07:11 -07:00
/*
* include / net / l3mdev . h - L3 master device API
* Copyright ( c ) 2015 Cumulus Networks
* Copyright ( c ) 2015 David Ahern < dsa @ cumulusnetworks . com >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*/
# ifndef _NET_L3MDEV_H_
# define _NET_L3MDEV_H_
2016-06-08 10:55:39 -07:00
# include <net/fib_rules.h>
2015-09-29 20:07:11 -07:00
/**
* struct l3mdev_ops - l3mdev operations
*
* @ l3mdev_fib_table : Get FIB table id to use for lookups
*
* @ l3mdev_get_rtable : Get cached IPv4 rtable ( dst_entry ) for device
2015-10-05 08:51:26 -07:00
*
* @ l3mdev_get_saddr : Get source address for a flow
2015-10-12 11:47:07 -07:00
*
* @ l3mdev_get_rt6_dst : Get cached IPv6 rt6_info ( dst_entry ) for device
2015-09-29 20:07:11 -07:00
*/
struct l3mdev_ops {
u32 ( * l3mdev_fib_table ) ( const struct net_device * dev ) ;
2016-05-10 11:19:50 -07:00
struct sk_buff * ( * l3mdev_l3_rcv ) ( struct net_device * dev ,
struct sk_buff * skb , u16 proto ) ;
2015-10-12 11:47:07 -07:00
/* IPv4 ops */
2015-09-29 20:07:11 -07:00
struct rtable * ( * l3mdev_get_rtable ) ( const struct net_device * dev ,
const struct flowi4 * fl4 ) ;
2016-01-04 09:09:27 -08:00
int ( * l3mdev_get_saddr ) ( struct net_device * dev ,
2015-10-05 08:51:26 -07:00
struct flowi4 * fl4 ) ;
2015-10-12 11:47:07 -07:00
/* IPv6 ops */
struct dst_entry * ( * l3mdev_get_rt6_dst ) ( const struct net_device * dev ,
2016-06-13 13:44:17 -07:00
struct flowi6 * fl6 ) ;
2016-06-16 16:24:25 -07:00
int ( * l3mdev_get_saddr6 ) ( struct net_device * dev ,
const struct sock * sk ,
struct flowi6 * fl6 ) ;
2015-09-29 20:07:11 -07:00
} ;
# ifdef CONFIG_NET_L3_MASTER_DEV
2016-06-08 10:55:39 -07:00
int l3mdev_fib_rule_match ( struct net * net , struct flowi * fl ,
struct fib_lookup_arg * arg ) ;
2016-02-24 11:47:02 -08:00
int l3mdev_master_ifindex_rcu ( const struct net_device * dev ) ;
2015-09-29 20:07:11 -07:00
static inline int l3mdev_master_ifindex ( struct net_device * dev )
{
int ifindex ;
rcu_read_lock ( ) ;
ifindex = l3mdev_master_ifindex_rcu ( dev ) ;
rcu_read_unlock ( ) ;
return ifindex ;
}
2015-12-16 13:20:43 -08:00
static inline int l3mdev_master_ifindex_by_index ( struct net * net , int ifindex )
{
struct net_device * dev ;
int rc = 0 ;
if ( likely ( ifindex ) ) {
rcu_read_lock ( ) ;
dev = dev_get_by_index_rcu ( net , ifindex ) ;
if ( dev )
rc = l3mdev_master_ifindex_rcu ( dev ) ;
rcu_read_unlock ( ) ;
}
return rc ;
}
2016-06-16 16:24:26 -07:00
static inline
const struct net_device * l3mdev_master_dev_rcu ( const struct net_device * _dev )
{
/* netdev_master_upper_dev_get_rcu calls
* list_first_or_null_rcu to walk the upper dev list .
* list_first_or_null_rcu does not handle a const arg . We aren ' t
* making changes , just want the master device from that list so
* typecast to remove the const
*/
struct net_device * dev = ( struct net_device * ) _dev ;
const struct net_device * master ;
if ( ! dev )
return NULL ;
if ( netif_is_l3_master ( dev ) )
master = dev ;
else if ( netif_is_l3_slave ( dev ) )
master = netdev_master_upper_dev_get_rcu ( dev ) ;
else
master = NULL ;
return master ;
}
2015-09-29 20:07:11 -07:00
/* get index of an interface to use for FIB lookups. For devices
* enslaved to an L3 master device FIB lookups are based on the
* master index
*/
static inline int l3mdev_fib_oif_rcu ( struct net_device * dev )
{
return l3mdev_master_ifindex_rcu ( dev ) ? : dev - > ifindex ;
}
static inline int l3mdev_fib_oif ( struct net_device * dev )
{
int oif ;
rcu_read_lock ( ) ;
oif = l3mdev_fib_oif_rcu ( dev ) ;
rcu_read_unlock ( ) ;
return oif ;
}
u32 l3mdev_fib_table_rcu ( const struct net_device * dev ) ;
u32 l3mdev_fib_table_by_index ( struct net * net , int ifindex ) ;
static inline u32 l3mdev_fib_table ( const struct net_device * dev )
{
u32 tb_id ;
rcu_read_lock ( ) ;
tb_id = l3mdev_fib_table_rcu ( dev ) ;
rcu_read_unlock ( ) ;
return tb_id ;
}
static inline struct rtable * l3mdev_get_rtable ( const struct net_device * dev ,
const struct flowi4 * fl4 )
{
if ( netif_is_l3_master ( dev ) & & dev - > l3mdev_ops - > l3mdev_get_rtable )
return dev - > l3mdev_ops - > l3mdev_get_rtable ( dev , fl4 ) ;
return NULL ;
}
2015-09-29 20:07:18 -07:00
static inline bool netif_index_is_l3_master ( struct net * net , int ifindex )
{
struct net_device * dev ;
bool rc = false ;
if ( ifindex = = 0 )
return false ;
rcu_read_lock ( ) ;
dev = dev_get_by_index_rcu ( net , ifindex ) ;
if ( dev )
rc = netif_is_l3_master ( dev ) ;
rcu_read_unlock ( ) ;
return rc ;
}
2016-05-07 16:48:59 -07:00
int l3mdev_get_saddr ( struct net * net , int ifindex , struct flowi4 * fl4 ) ;
2015-10-05 08:51:26 -07:00
2016-06-13 13:44:17 -07:00
struct dst_entry * l3mdev_get_rt6_dst ( struct net * net , struct flowi6 * fl6 ) ;
2016-06-16 16:24:25 -07:00
int l3mdev_get_saddr6 ( struct net * net , const struct sock * sk ,
struct flowi6 * fl6 ) ;
2015-10-12 11:47:07 -07:00
2016-05-10 11:19:50 -07:00
static inline
struct sk_buff * l3mdev_l3_rcv ( struct sk_buff * skb , u16 proto )
{
struct net_device * master = NULL ;
if ( netif_is_l3_slave ( skb - > dev ) )
master = netdev_master_upper_dev_get_rcu ( skb - > dev ) ;
else if ( netif_is_l3_master ( skb - > dev ) )
master = skb - > dev ;
if ( master & & master - > l3mdev_ops - > l3mdev_l3_rcv )
skb = master - > l3mdev_ops - > l3mdev_l3_rcv ( master , skb , proto ) ;
return skb ;
}
static inline
struct sk_buff * l3mdev_ip_rcv ( struct sk_buff * skb )
{
return l3mdev_l3_rcv ( skb , AF_INET ) ;
}
static inline
struct sk_buff * l3mdev_ip6_rcv ( struct sk_buff * skb )
{
return l3mdev_l3_rcv ( skb , AF_INET6 ) ;
}
2015-09-29 20:07:11 -07:00
# else
2016-02-24 11:47:02 -08:00
static inline int l3mdev_master_ifindex_rcu ( const struct net_device * dev )
2015-09-29 20:07:11 -07:00
{
return 0 ;
}
static inline int l3mdev_master_ifindex ( struct net_device * dev )
{
return 0 ;
}
2015-12-16 13:20:43 -08:00
static inline int l3mdev_master_ifindex_by_index ( struct net * net , int ifindex )
{
return 0 ;
}
2016-06-16 16:24:26 -07:00
static inline
const struct net_device * l3mdev_master_dev_rcu ( const struct net_device * dev )
{
return NULL ;
}
2015-09-29 20:07:11 -07:00
static inline int l3mdev_fib_oif_rcu ( struct net_device * dev )
{
return dev ? dev - > ifindex : 0 ;
}
static inline int l3mdev_fib_oif ( struct net_device * dev )
{
return dev ? dev - > ifindex : 0 ;
}
static inline u32 l3mdev_fib_table_rcu ( const struct net_device * dev )
{
return 0 ;
}
static inline u32 l3mdev_fib_table ( const struct net_device * dev )
{
return 0 ;
}
static inline u32 l3mdev_fib_table_by_index ( struct net * net , int ifindex )
{
return 0 ;
}
static inline struct rtable * l3mdev_get_rtable ( const struct net_device * dev ,
const struct flowi4 * fl4 )
{
return NULL ;
}
2015-09-29 20:07:18 -07:00
static inline bool netif_index_is_l3_master ( struct net * net , int ifindex )
{
return false ;
}
2016-01-04 09:09:27 -08:00
static inline int l3mdev_get_saddr ( struct net * net , int ifindex ,
struct flowi4 * fl4 )
2015-10-05 08:51:26 -07:00
{
2016-01-04 09:09:27 -08:00
return 0 ;
2015-10-05 08:51:26 -07:00
}
2015-10-12 11:47:07 -07:00
static inline
2016-06-13 13:44:17 -07:00
struct dst_entry * l3mdev_get_rt6_dst ( struct net * net , struct flowi6 * fl6 )
2015-10-12 11:47:07 -07:00
{
return NULL ;
}
2016-05-10 11:19:50 -07:00
2016-06-16 16:24:25 -07:00
static inline int l3mdev_get_saddr6 ( struct net * net , const struct sock * sk ,
struct flowi6 * fl6 )
{
return 0 ;
}
2016-05-10 11:19:50 -07:00
static inline
struct sk_buff * l3mdev_ip_rcv ( struct sk_buff * skb )
{
return skb ;
}
static inline
struct sk_buff * l3mdev_ip6_rcv ( struct sk_buff * skb )
{
return skb ;
}
2016-06-08 10:55:39 -07:00
static inline
int l3mdev_fib_rule_match ( struct net * net , struct flowi * fl ,
struct fib_lookup_arg * arg )
{
return 1 ;
}
2015-09-29 20:07:11 -07:00
# endif
# endif /* _NET_L3MDEV_H_ */