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
*
2016-09-10 22:09:56 +03:00
* @ l3mdev_link_scope_lookup : IPv6 lookup for linklocal and mcast destinations
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
/* IPv6 ops */
2016-09-10 22:09:56 +03:00
struct dst_entry * ( * l3mdev_link_scope_lookup ) ( const struct net_device * dev ,
2016-06-13 23:44:17 +03:00
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
2016-09-10 22:09:54 +03:00
struct net_device * l3mdev_master_dev_rcu ( const struct net_device * _dev )
2016-06-17 02:24:26 +03:00
{
/* 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 ;
2016-09-10 22:09:54 +03:00
struct net_device * master ;
2016-06-17 02:24:26 +03:00
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
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 ;
}
2016-10-12 23:20:11 +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-09-10 22:09:56 +03:00
struct dst_entry * l3mdev_link_scope_lookup ( struct net * net , 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
2016-09-10 22:09:54 +03:00
struct net_device * l3mdev_master_dev_rcu ( const struct net_device * dev )
2016-06-17 02:24:26 +03:00
{
return NULL ;
}
2015-09-30 06:07:11 +03:00
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 ;
}
2016-10-12 23:20:11 +03:00
static inline bool netif_index_is_l3_master ( struct net * net , int ifindex )
{
return false ;
}
2015-10-12 21:47:07 +03:00
static inline
2016-09-10 22:09:56 +03:00
struct dst_entry * l3mdev_link_scope_lookup ( struct net * net , struct flowi6 * fl6 )
2015-10-12 21:47:07 +03:00
{
return NULL ;
}
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_ */