2005-04-17 02:20:36 +04:00
# ifndef _NET_NEIGHBOUR_H
# define _NET_NEIGHBOUR_H
2006-08-08 04:57:44 +04:00
# include <linux/neighbour.h>
2005-04-17 02:20:36 +04:00
/*
* Generic neighbour manipulation
*
* Authors :
* Pedro Roque < roque @ di . fc . ul . pt >
* Alexey Kuznetsov < kuznet @ ms2 . inr . ac . ru >
*
* Changes :
*
* Harald Welte : < laforge @ gnumonks . org >
* - Add neighbour cache statistics like rtstat
*/
# include <asm/atomic.h>
# include <linux/netdevice.h>
2005-12-27 07:43:12 +03:00
# include <linux/skbuff.h>
2005-04-17 02:20:36 +04:00
# include <linux/rcupdate.h>
# include <linux/seq_file.h>
# include <linux/err.h>
# include <linux/sysctl.h>
2007-03-22 21:50:06 +03:00
# include <net/rtnetlink.h>
2005-04-17 02:20:36 +04:00
# define NUD_IN_TIMER (NUD_INCOMPLETE|NUD_REACHABLE|NUD_DELAY|NUD_PROBE)
# define NUD_VALID (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE|NUD_PROBE|NUD_STALE|NUD_DELAY)
# define NUD_CONNECTED (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE)
struct neighbour ;
struct neigh_parms
{
2005-06-19 09:50:55 +04:00
struct net_device * dev ;
2005-04-17 02:20:36 +04:00
struct neigh_parms * next ;
int ( * neigh_setup ) ( struct neighbour * ) ;
2007-03-24 22:52:16 +03:00
void ( * neigh_cleanup ) ( struct neighbour * ) ;
2005-04-17 02:20:36 +04:00
struct neigh_table * tbl ;
void * sysctl_table ;
int dead ;
atomic_t refcnt ;
struct rcu_head rcu_head ;
int base_reachable_time ;
int retrans_time ;
int gc_staletime ;
int reachable_time ;
int delay_probe_time ;
int queue_len ;
int ucast_probes ;
int app_probes ;
int mcast_probes ;
int anycast_delay ;
int proxy_delay ;
int proxy_qlen ;
int locktime ;
} ;
struct neigh_statistics
{
unsigned long allocs ; /* number of allocated neighs */
unsigned long destroys ; /* number of destroyed neighs */
unsigned long hash_grows ; /* number of hash resizes */
unsigned long res_failed ; /* nomber of failed resolutions */
unsigned long lookups ; /* number of lookups */
unsigned long hits ; /* number of hits (among lookups) */
unsigned long rcv_probes_mcast ; /* number of received mcast ipv6 */
unsigned long rcv_probes_ucast ; /* number of received ucast ipv6 */
unsigned long periodic_gc_runs ; /* number of periodic GC runs */
unsigned long forced_gc_runs ; /* number of forced GC runs */
} ;
# define NEIGH_CACHE_STAT_INC(tbl, field) \
do { \
preempt_disable ( ) ; \
( per_cpu_ptr ( ( tbl ) - > stats , smp_processor_id ( ) ) - > field ) + + ; \
preempt_enable ( ) ; \
} while ( 0 )
struct neighbour
{
struct neighbour * next ;
struct neigh_table * tbl ;
struct neigh_parms * parms ;
struct net_device * dev ;
unsigned long used ;
unsigned long confirmed ;
unsigned long updated ;
__u8 flags ;
__u8 nud_state ;
__u8 type ;
__u8 dead ;
atomic_t probes ;
rwlock_t lock ;
2006-08-11 10:03:23 +04:00
unsigned char ha [ ALIGN ( MAX_ADDR_LEN , sizeof ( unsigned long ) ) ] ;
2005-04-17 02:20:36 +04:00
struct hh_cache * hh ;
atomic_t refcnt ;
int ( * output ) ( struct sk_buff * skb ) ;
struct sk_buff_head arp_queue ;
struct timer_list timer ;
struct neigh_ops * ops ;
u8 primary_key [ 0 ] ;
} ;
struct neigh_ops
{
int family ;
void ( * solicit ) ( struct neighbour * , struct sk_buff * ) ;
void ( * error_report ) ( struct neighbour * , struct sk_buff * ) ;
int ( * output ) ( struct sk_buff * ) ;
int ( * connected_output ) ( struct sk_buff * ) ;
int ( * hh_output ) ( struct sk_buff * ) ;
int ( * queue_xmit ) ( struct sk_buff * ) ;
} ;
struct pneigh_entry
{
struct pneigh_entry * next ;
struct net_device * dev ;
2006-09-23 01:43:19 +04:00
u8 flags ;
2005-04-17 02:20:36 +04:00
u8 key [ 0 ] ;
} ;
/*
* neighbour table manipulation
*/
struct neigh_table
{
struct neigh_table * next ;
int family ;
int entry_size ;
int key_len ;
__u32 ( * hash ) ( const void * pkey , const struct net_device * ) ;
int ( * constructor ) ( struct neighbour * ) ;
int ( * pconstructor ) ( struct pneigh_entry * ) ;
void ( * pdestructor ) ( struct pneigh_entry * ) ;
void ( * proxy_redo ) ( struct sk_buff * skb ) ;
char * id ;
struct neigh_parms parms ;
/* HACK. gc_* shoul follow parms without a gap! */
int gc_interval ;
int gc_thresh1 ;
int gc_thresh2 ;
int gc_thresh3 ;
unsigned long last_flush ;
struct timer_list gc_timer ;
struct timer_list proxy_timer ;
struct sk_buff_head proxy_queue ;
atomic_t entries ;
rwlock_t lock ;
unsigned long last_rand ;
2006-12-07 07:33:20 +03:00
struct kmem_cache * kmem_cachep ;
2005-04-17 02:20:36 +04:00
struct neigh_statistics * stats ;
struct neighbour * * hash_buckets ;
unsigned int hash_mask ;
__u32 hash_rnd ;
unsigned int hash_chain_gc ;
struct pneigh_entry * * phash_buckets ;
# ifdef CONFIG_PROC_FS
struct proc_dir_entry * pde ;
# endif
} ;
/* flags for neigh_update() */
# define NEIGH_UPDATE_F_OVERRIDE 0x00000001
# define NEIGH_UPDATE_F_WEAK_OVERRIDE 0x00000002
# define NEIGH_UPDATE_F_OVERRIDE_ISROUTER 0x00000004
# define NEIGH_UPDATE_F_ISROUTER 0x40000000
# define NEIGH_UPDATE_F_ADMIN 0x80000000
extern void neigh_table_init ( struct neigh_table * tbl ) ;
[NEIGH]: Fix IP-over-ATM and ARP interaction.
The classical IP over ATM code maintains its own IPv4 <-> <ATM stuff>
ARP table, using the standard neighbour-table code. The
neigh_table_init function adds this neighbour table to a linked list
of all neighbor tables which is used by the functions neigh_delete()
neigh_add() and neightbl_set(), all called by the netlink code.
Once the ATM neighbour table is added to the list, there are two
tables with family == AF_INET there, and ARP entries sent via netlink
go into the first table with matching family. This is indeterminate
and often wrong.
To see the bug, on a kernel with CLIP enabled, create a standard IPv4
ARP entry by pinging an unused address on a local subnet. Then attempt
to complete that entry by doing
ip neigh replace <ip address> lladdr <some mac address> nud reachable
Looking at the ARP tables by using
ip neigh show
will reveal two ARP entries for the same address. One of these can be
found in /proc/net/arp, and the other in /proc/net/atm/arp.
This patch adds a new function, neigh_table_init_no_netlink() which
does everything the neigh_table_init() does, except add the table to
the netlink all-arp-tables chain. In addition neigh_table_init() has a
check that all tables on the chain have a distinct address family.
The init call in clip.c is changed to call
neigh_table_init_no_netlink().
Since ATM ARP tables are rather more complicated than can currently be
handled by the available rtattrs in the netlink protocol, no
functionality is lost by this patch, and non-ATM ARP manipulation via
netlink is rescued. A more complete solution would involve a rtattr
for ATM ARP entries and some way for the netlink code to give
neigh_add and friends more information than just address family with
which to find the correct ARP table.
[ I've changed the assertion checking in neigh_table_init() to not
use BUG_ON() while holding neigh_tbl_lock. Instead we remember that
we found an existing tbl with the same family, and after dropping
the lock we'll give a diagnostic kernel log message and a stack dump.
-DaveM ]
Signed-off-by: Simon Kelley <simon@thekelleys.org.uk>
Signed-off-by: David S. Miller <davem@davemloft.net>
2006-05-13 01:56:08 +04:00
extern void neigh_table_init_no_netlink ( struct neigh_table * tbl ) ;
2005-04-17 02:20:36 +04:00
extern int neigh_table_clear ( struct neigh_table * tbl ) ;
extern struct neighbour * neigh_lookup ( struct neigh_table * tbl ,
const void * pkey ,
struct net_device * dev ) ;
extern struct neighbour * neigh_lookup_nodev ( struct neigh_table * tbl ,
const void * pkey ) ;
extern struct neighbour * neigh_create ( struct neigh_table * tbl ,
const void * pkey ,
struct net_device * dev ) ;
extern void neigh_destroy ( struct neighbour * neigh ) ;
extern int __neigh_event_send ( struct neighbour * neigh , struct sk_buff * skb ) ;
extern int neigh_update ( struct neighbour * neigh , const u8 * lladdr , u8 new ,
u32 flags ) ;
extern void neigh_changeaddr ( struct neigh_table * tbl , struct net_device * dev ) ;
extern int neigh_ifdown ( struct neigh_table * tbl , struct net_device * dev ) ;
extern int neigh_resolve_output ( struct sk_buff * skb ) ;
extern int neigh_connected_output ( struct sk_buff * skb ) ;
extern int neigh_compat_output ( struct sk_buff * skb ) ;
extern struct neighbour * neigh_event_ns ( struct neigh_table * tbl ,
u8 * lladdr , void * saddr ,
struct net_device * dev ) ;
extern struct neigh_parms * neigh_parms_alloc ( struct net_device * dev , struct neigh_table * tbl ) ;
extern void neigh_parms_release ( struct neigh_table * tbl , struct neigh_parms * parms ) ;
extern void neigh_parms_destroy ( struct neigh_parms * parms ) ;
extern unsigned long neigh_rand_reach_time ( unsigned long base ) ;
extern void pneigh_enqueue ( struct neigh_table * tbl , struct neigh_parms * p ,
struct sk_buff * skb ) ;
extern struct pneigh_entry * pneigh_lookup ( struct neigh_table * tbl , const void * key , struct net_device * dev , int creat ) ;
extern int pneigh_delete ( struct neigh_table * tbl , const void * key , struct net_device * dev ) ;
extern void neigh_app_ns ( struct neighbour * n ) ;
extern void neigh_for_each ( struct neigh_table * tbl , void ( * cb ) ( struct neighbour * , void * ) , void * cookie ) ;
extern void __neigh_for_each_release ( struct neigh_table * tbl , int ( * cb ) ( struct neighbour * ) ) ;
extern void pneigh_for_each ( struct neigh_table * tbl , void ( * cb ) ( struct pneigh_entry * ) ) ;
struct neigh_seq_state {
struct neigh_table * tbl ;
void * ( * neigh_sub_iter ) ( struct neigh_seq_state * state ,
struct neighbour * n , loff_t * pos ) ;
unsigned int bucket ;
unsigned int flags ;
# define NEIGH_SEQ_NEIGH_ONLY 0x00000001
# define NEIGH_SEQ_IS_PNEIGH 0x00000002
# define NEIGH_SEQ_SKIP_NOARP 0x00000004
} ;
extern void * neigh_seq_start ( struct seq_file * , loff_t * , struct neigh_table * , unsigned int ) ;
extern void * neigh_seq_next ( struct seq_file * , void * , loff_t * ) ;
extern void neigh_seq_stop ( struct seq_file * , void * ) ;
extern int neigh_sysctl_register ( struct net_device * dev ,
struct neigh_parms * p ,
int p_id , int pdev_id ,
char * p_name ,
proc_handler * proc_handler ,
ctl_handler * strategy ) ;
extern void neigh_sysctl_unregister ( struct neigh_parms * p ) ;
static inline void __neigh_parms_put ( struct neigh_parms * parms )
{
atomic_dec ( & parms - > refcnt ) ;
}
static inline void neigh_parms_put ( struct neigh_parms * parms )
{
if ( atomic_dec_and_test ( & parms - > refcnt ) )
neigh_parms_destroy ( parms ) ;
}
static inline struct neigh_parms * neigh_parms_clone ( struct neigh_parms * parms )
{
atomic_inc ( & parms - > refcnt ) ;
return parms ;
}
/*
* Neighbour references
*/
static inline void neigh_release ( struct neighbour * neigh )
{
if ( atomic_dec_and_test ( & neigh - > refcnt ) )
neigh_destroy ( neigh ) ;
}
static inline struct neighbour * neigh_clone ( struct neighbour * neigh )
{
if ( neigh )
atomic_inc ( & neigh - > refcnt ) ;
return neigh ;
}
# define neigh_hold(n) atomic_inc(&(n)->refcnt)
static inline void neigh_confirm ( struct neighbour * neigh )
{
if ( neigh )
neigh - > confirmed = jiffies ;
}
static inline int neigh_is_connected ( struct neighbour * neigh )
{
return neigh - > nud_state & NUD_CONNECTED ;
}
static inline int neigh_is_valid ( struct neighbour * neigh )
{
return neigh - > nud_state & NUD_VALID ;
}
static inline int neigh_event_send ( struct neighbour * neigh , struct sk_buff * skb )
{
neigh - > used = jiffies ;
if ( ! ( neigh - > nud_state & ( NUD_CONNECTED | NUD_DELAY | NUD_PROBE ) ) )
return __neigh_event_send ( neigh , skb ) ;
return 0 ;
}
2006-12-08 02:08:17 +03:00
static inline int neigh_hh_output ( struct hh_cache * hh , struct sk_buff * skb )
{
unsigned seq ;
int hh_len ;
do {
int hh_alen ;
seq = read_seqbegin ( & hh - > hh_lock ) ;
hh_len = hh - > hh_len ;
hh_alen = HH_DATA_ALIGN ( hh_len ) ;
memcpy ( skb - > data - hh_alen , hh - > hh_data , hh_alen ) ;
} while ( read_seqretry ( & hh - > hh_lock , seq ) ) ;
skb_push ( skb , hh_len ) ;
return hh - > hh_output ( skb ) ;
}
2005-04-17 02:20:36 +04:00
static inline struct neighbour *
__neigh_lookup ( struct neigh_table * tbl , const void * pkey , struct net_device * dev , int creat )
{
struct neighbour * n = neigh_lookup ( tbl , pkey , dev ) ;
if ( n | | ! creat )
return n ;
n = neigh_create ( tbl , pkey , dev ) ;
return IS_ERR ( n ) ? NULL : n ;
}
static inline struct neighbour *
__neigh_lookup_errno ( struct neigh_table * tbl , const void * pkey ,
struct net_device * dev )
{
struct neighbour * n = neigh_lookup ( tbl , pkey , dev ) ;
if ( n )
return n ;
return neigh_create ( tbl , pkey , dev ) ;
}
2005-08-15 04:24:31 +04:00
struct neighbour_cb {
unsigned long sched_next ;
unsigned int flags ;
} ;
# define LOCALLY_ENQUEUED 0x1
# define NEIGH_CB(skb) ((struct neighbour_cb *)(skb)->cb)
2005-04-17 02:20:36 +04:00
# endif