2015-09-30 06:07:11 +03: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-09-10 22:09:53 +03:00
# include <net/dst.h>
2016-06-08 20:55:39 +03:00
# include <net/fib_rules.h>
2015-09-30 06:07:11 +03:00
/**
* struct l3mdev_ops - l3mdev operations
*
* @ l3mdev_fib_table : Get FIB table id to use for lookups
*
2016-09-10 22:09:53 +03:00
* @ l3mdev_l3_rcv : Hook in L3 receive path
*
* @ l3mdev_l3_out : Hook in L3 output path
*
2015-09-30 06:07:11 +03:00
* @ l3mdev_get_rtable : Get cached IPv4 rtable ( dst_entry ) for device
2015-10-05 18:51:26 +03:00
*
* @ l3mdev_get_saddr : Get source address for a flow
2015-10-12 21:47:07 +03:00
*
* @ l3mdev_get_rt6_dst : Get cached IPv6 rt6_info ( dst_entry ) for device
2015-09-30 06:07:11 +03:00
*/
struct l3mdev_ops {
u32 ( * l3mdev_fib_table ) ( const struct net_device * dev ) ;
2016-05-10 21:19:50 +03:00
struct sk_buff * ( * l3mdev_l3_rcv ) ( struct net_device * dev ,
struct sk_buff * skb , u16 proto ) ;
2016-09-10 22:09:53 +03:00
struct sk_buff * ( * l3mdev_l3_out ) ( struct net_device * dev ,
struct sock * sk , struct sk_buff * skb ,
u16 proto ) ;
2015-10-12 21:47:07 +03:00
/* IPv4 ops */
2015-09-30 06:07:11 +03:00
struct rtable * ( * l3mdev_get_rtable ) ( const struct net_device * dev ,
const struct flowi4 * fl4 ) ;
2016-01-04 20:09:27 +03:00
int ( * l3mdev_get_saddr ) ( struct net_device * dev ,
2015-10-05 18:51:26 +03:00
struct flowi4 * fl4 ) ;
2015-10-12 21:47:07 +03:00
/* IPv6 ops */
struct dst_entry * ( * l3mdev_get_rt6_dst ) ( const struct net_device * dev ,
2016-06-13 23:44:17 +03:00
struct flowi6 * fl6 ) ;
2016-06-17 02:24:25 +03:00
int ( * l3mdev_get_saddr6 ) ( struct net_device * dev ,
const struct sock * sk ,
struct flowi6 * fl6 ) ;
2015-09-30 06:07:11 +03:00
} ;
# ifdef CONFIG_NET_L3_MASTER_DEV
2016-06-08 20:55:39 +03:00
int l3mdev_fib_rule_match ( struct net * net , struct flowi * fl ,
struct fib_lookup_arg * arg ) ;
2016-09-10 22:09:52 +03:00
void l3mdev_update_flow ( struct net * net , struct flowi * fl ) ;
2016-02-24 22:47:02 +03:00
int l3mdev_master_ifindex_rcu ( const struct net_device * dev ) ;
2015-09-30 06:07:11 +03: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-17 00:20:43 +03: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-17 02:24:26 +03: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-30 06:07:11 +03: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-30 06:07:18 +03: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-08 02:48:59 +03:00
int l3mdev_get_saddr ( struct net * net , int ifindex , struct flowi4 * fl4 ) ;
2015-10-05 18:51:26 +03:00
2016-06-13 23:44:17 +03:00
struct dst_entry * l3mdev_get_rt6_dst ( struct net * net , struct flowi6 * fl6 ) ;
2016-06-17 02:24:25 +03:00
int l3mdev_get_saddr6 ( struct net * net , const struct sock * sk ,
struct flowi6 * fl6 ) ;
2015-10-12 21:47:07 +03:00
2016-05-10 21:19:50 +03: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 ) ;
}
2016-09-10 22:09:53 +03:00
static inline
struct sk_buff * l3mdev_l3_out ( struct sock * sk , struct sk_buff * skb , u16 proto )
{
struct net_device * dev = skb_dst ( skb ) - > dev ;
if ( netif_is_l3_slave ( dev ) ) {
struct net_device * master ;
master = netdev_master_upper_dev_get_rcu ( dev ) ;
if ( master & & master - > l3mdev_ops - > l3mdev_l3_out )
skb = master - > l3mdev_ops - > l3mdev_l3_out ( master , sk ,
skb , proto ) ;
}
return skb ;
}
static inline
struct sk_buff * l3mdev_ip_out ( struct sock * sk , struct sk_buff * skb )
{
return l3mdev_l3_out ( sk , skb , AF_INET ) ;
}
static inline
struct sk_buff * l3mdev_ip6_out ( struct sock * sk , struct sk_buff * skb )
{
return l3mdev_l3_out ( sk , skb , AF_INET6 ) ;
}
2015-09-30 06:07:11 +03:00
# else
2016-02-24 22:47:02 +03:00
static inline int l3mdev_master_ifindex_rcu ( const struct net_device * dev )
2015-09-30 06:07:11 +03:00
{
return 0 ;
}
static inline int l3mdev_master_ifindex ( struct net_device * dev )
{
return 0 ;
}
2015-12-17 00:20:43 +03:00
static inline int l3mdev_master_ifindex_by_index ( struct net * net , int ifindex )
{
return 0 ;
}
2016-06-17 02:24:26 +03:00
static inline
const struct net_device * l3mdev_master_dev_rcu ( const struct net_device * dev )
{
return NULL ;
}
2015-09-30 06:07:11 +03: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-30 06:07:18 +03:00
static inline bool netif_index_is_l3_master ( struct net * net , int ifindex )
{
return false ;
}
2016-01-04 20:09:27 +03:00
static inline int l3mdev_get_saddr ( struct net * net , int ifindex ,
struct flowi4 * fl4 )
2015-10-05 18:51:26 +03:00
{
2016-01-04 20:09:27 +03:00
return 0 ;
2015-10-05 18:51:26 +03:00
}
2015-10-12 21:47:07 +03:00
static inline
2016-06-13 23:44:17 +03:00
struct dst_entry * l3mdev_get_rt6_dst ( struct net * net , struct flowi6 * fl6 )
2015-10-12 21:47:07 +03:00
{
return NULL ;
}
2016-05-10 21:19:50 +03:00
2016-06-17 02:24:25 +03:00
static inline int l3mdev_get_saddr6 ( struct net * net , const struct sock * sk ,
struct flowi6 * fl6 )
{
return 0 ;
}
2016-05-10 21:19:50 +03: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 20:55:39 +03:00
2016-09-10 22:09:53 +03:00
static inline
struct sk_buff * l3mdev_ip_out ( struct sock * sk , struct sk_buff * skb )
{
return skb ;
}
static inline
struct sk_buff * l3mdev_ip6_out ( struct sock * sk , struct sk_buff * skb )
{
return skb ;
}
2016-06-08 20:55:39 +03:00
static inline
int l3mdev_fib_rule_match ( struct net * net , struct flowi * fl ,
struct fib_lookup_arg * arg )
{
return 1 ;
}
2016-09-10 22:09:52 +03:00
static inline
void l3mdev_update_flow ( struct net * net , struct flowi * fl )
{
}
2015-09-30 06:07:11 +03:00
# endif
# endif /* _NET_L3MDEV_H_ */