Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
b938377b
Commit
b938377b
authored
Sep 26, 2004
by
David S. Miller
Browse files
Options
Browse Files
Download
Plain Diff
Merge
bk://bk.skbuff.net:20609/linux-2.6-refcnt/
into nuts.davemloft.net:/disk1/BK/net-2.6
parents
4758b642
c390466b
Changes
15
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
749 additions
and
599 deletions
+749
-599
include/linux/tcp.h
include/linux/tcp.h
+8
-2
include/net/dn_neigh.h
include/net/dn_neigh.h
+0
-1
include/net/neighbour.h
include/net/neighbour.h
+26
-5
include/net/tcp.h
include/net/tcp.h
+15
-13
net/atm/clip.c
net/atm/clip.c
+121
-140
net/core/neighbour.c
net/core/neighbour.c
+422
-51
net/decnet/dn_neigh.c
net/decnet/dn_neigh.c
+53
-147
net/decnet/dn_route.c
net/decnet/dn_route.c
+1
-1
net/ipv4/arp.c
net/ipv4/arp.c
+23
-172
net/ipv4/fib_hash.c
net/ipv4/fib_hash.c
+11
-13
net/ipv4/tcp_diag.c
net/ipv4/tcp_diag.c
+27
-13
net/ipv4/tcp_input.c
net/ipv4/tcp_input.c
+31
-31
net/ipv4/tcp_minisocks.c
net/ipv4/tcp_minisocks.c
+2
-1
net/ipv4/tcp_output.c
net/ipv4/tcp_output.c
+2
-2
net/ipv6/ndisc.c
net/ipv6/ndisc.c
+7
-7
No files found.
include/linux/tcp.h
View file @
b938377b
...
...
@@ -205,6 +205,13 @@ typedef struct tcp_pcount {
__u32
val
;
}
tcp_pcount_t
;
enum
tcp_congestion_algo
{
TCP_RENO
=
0
,
TCP_VEGAS
,
TCP_WESTWOOD
,
TCP_BIC
,
};
struct
tcp_opt
{
int
tcp_header_len
;
/* Bytes of tcp header to send */
...
...
@@ -265,7 +272,7 @@ struct tcp_opt {
__u8
frto_counter
;
/* Number of new acks after RTO */
__u32
frto_highmark
;
/* snd_nxt when RTO occurred */
__u8
unused_pad
;
__u8
adv_cong
;
/* Using Vegas, Westwood, or BIC */
__u8
defer_accept
;
/* User waits for some data after accept() */
/* one byte hole, try to pack */
...
...
@@ -412,7 +419,6 @@ struct tcp_opt {
__u32
beg_snd_nxt
;
/* right edge during last RTT */
__u32
beg_snd_una
;
/* left edge during last RTT */
__u32
beg_snd_cwnd
;
/* saves the size of the cwnd */
__u8
do_vegas
;
/* do vegas for this connection */
__u8
doing_vegas_now
;
/* if true, do vegas for this RTT */
__u16
cntRTT
;
/* # of RTTs measured within last RTT */
__u32
minRTT
;
/* min of RTTs measured within last RTT (in usec) */
...
...
include/net/dn_neigh.h
View file @
b938377b
...
...
@@ -18,7 +18,6 @@ struct dn_neigh {
extern
void
dn_neigh_init
(
void
);
extern
void
dn_neigh_cleanup
(
void
);
extern
struct
neighbour
*
dn_neigh_lookup
(
struct
neigh_table
*
tbl
,
const
void
*
ptr
);
extern
int
dn_neigh_router_hello
(
struct
sk_buff
*
skb
);
extern
int
dn_neigh_endnode_hello
(
struct
sk_buff
*
skb
);
extern
void
dn_neigh_pointopoint_hello
(
struct
sk_buff
*
skb
);
...
...
include/net/neighbour.h
View file @
b938377b
...
...
@@ -47,6 +47,7 @@
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/rcupdate.h>
#include <linux/seq_file.h>
#include <linux/err.h>
#include <linux/sysctl.h>
...
...
@@ -139,9 +140,6 @@ struct pneigh_entry
u8
key
[
0
];
};
#define NEIGH_HASHMASK 0x1F
#define PNEIGH_HASHMASK 0xF
/*
* neighbour table manipulation
*/
...
...
@@ -175,8 +173,11 @@ struct neigh_table
struct
neigh_parms
*
parms_list
;
kmem_cache_t
*
kmem_cachep
;
struct
neigh_statistics
stats
;
struct
neighbour
*
hash_buckets
[
NEIGH_HASHMASK
+
1
];
struct
pneigh_entry
*
phash_buckets
[
PNEIGH_HASHMASK
+
1
];
struct
neighbour
**
hash_buckets
;
unsigned
int
hash_mask
;
__u32
hash_rnd
;
unsigned
int
hash_chain_gc
;
struct
pneigh_entry
**
phash_buckets
;
};
/* flags for neigh_update() */
...
...
@@ -191,6 +192,8 @@ 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
);
...
...
@@ -224,6 +227,24 @@ extern int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg);
extern
int
neigh_delete
(
struct
sk_buff
*
skb
,
struct
nlmsghdr
*
nlh
,
void
*
arg
);
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
,
...
...
include/net/tcp.h
View file @
b938377b
...
...
@@ -1271,6 +1271,13 @@ static __inline__ unsigned int tcp_packets_in_flight(struct tcp_opt *tp)
tcp_get_pcount
(
&
tp
->
retrans_out
));
}
/*
* Which congestion algorithim is in use on the connection.
*/
#define tcp_is_vegas(__tp) ((__tp)->adv_cong == TCP_VEGAS)
#define tcp_is_westwood(__tp) ((__tp)->adv_cong == TCP_WESTWOOD)
#define tcp_is_bic(__tp) ((__tp)->adv_cong == TCP_BIC)
/* Recalculate snd_ssthresh, we want to set it to:
*
* Reno:
...
...
@@ -1283,7 +1290,7 @@ static __inline__ unsigned int tcp_packets_in_flight(struct tcp_opt *tp)
*/
static
inline
__u32
tcp_recalc_ssthresh
(
struct
tcp_opt
*
tp
)
{
if
(
sysctl_tcp_bic
)
{
if
(
tcp_is_bic
(
tp
)
)
{
if
(
sysctl_tcp_bic_fast_convergence
&&
tp
->
snd_cwnd
<
tp
->
bictcp
.
last_max_cwnd
)
tp
->
bictcp
.
last_max_cwnd
...
...
@@ -1302,11 +1309,6 @@ static inline __u32 tcp_recalc_ssthresh(struct tcp_opt *tp)
/* Stop taking Vegas samples for now. */
#define tcp_vegas_disable(__tp) ((__tp)->vegas.doing_vegas_now = 0)
/* Is this TCP connection using Vegas (regardless of whether it is taking
* Vegas measurements at the current time)?
*/
#define tcp_is_vegas(__tp) ((__tp)->vegas.do_vegas)
static
inline
void
tcp_vegas_enable
(
struct
tcp_opt
*
tp
)
{
...
...
@@ -1340,7 +1342,7 @@ static inline void tcp_vegas_enable(struct tcp_opt *tp)
/* Should we be taking Vegas samples right now? */
#define tcp_vegas_enabled(__tp) ((__tp)->vegas.doing_vegas_now)
extern
void
tcp_
vegas
_init
(
struct
tcp_opt
*
tp
);
extern
void
tcp_
ca
_init
(
struct
tcp_opt
*
tp
);
static
inline
void
tcp_set_ca_state
(
struct
tcp_opt
*
tp
,
u8
ca_state
)
{
...
...
@@ -2024,7 +2026,7 @@ extern void tcp_proc_unregister(struct tcp_seq_afinfo *afinfo);
static
inline
void
tcp_westwood_update_rtt
(
struct
tcp_opt
*
tp
,
__u32
rtt_seq
)
{
if
(
sysctl_tcp_westwood
)
if
(
tcp_is_westwood
(
tp
)
)
tp
->
westwood
.
rtt
=
rtt_seq
;
}
...
...
@@ -2033,13 +2035,13 @@ void __tcp_westwood_slow_bw(struct sock *, struct sk_buff *);
static
inline
void
tcp_westwood_fast_bw
(
struct
sock
*
sk
,
struct
sk_buff
*
skb
)
{
if
(
sysctl_tcp_westwood
)
if
(
tcp_is_westwood
(
tcp_sk
(
sk
))
)
__tcp_westwood_fast_bw
(
sk
,
skb
);
}
static
inline
void
tcp_westwood_slow_bw
(
struct
sock
*
sk
,
struct
sk_buff
*
skb
)
{
if
(
sysctl_tcp_westwood
)
if
(
tcp_is_westwood
(
tcp_sk
(
sk
))
)
__tcp_westwood_slow_bw
(
sk
,
skb
);
}
...
...
@@ -2052,14 +2054,14 @@ static inline __u32 __tcp_westwood_bw_rttmin(const struct tcp_opt *tp)
static
inline
__u32
tcp_westwood_bw_rttmin
(
const
struct
tcp_opt
*
tp
)
{
return
sysctl_tcp_westwood
?
__tcp_westwood_bw_rttmin
(
tp
)
:
0
;
return
tcp_is_westwood
(
tp
)
?
__tcp_westwood_bw_rttmin
(
tp
)
:
0
;
}
static
inline
int
tcp_westwood_ssthresh
(
struct
tcp_opt
*
tp
)
{
__u32
ssthresh
=
0
;
if
(
sysctl_tcp_westwood
)
{
if
(
tcp_is_westwood
(
tp
)
)
{
ssthresh
=
__tcp_westwood_bw_rttmin
(
tp
);
if
(
ssthresh
)
tp
->
snd_ssthresh
=
ssthresh
;
...
...
@@ -2072,7 +2074,7 @@ static inline int tcp_westwood_cwnd(struct tcp_opt *tp)
{
__u32
cwnd
=
0
;
if
(
sysctl_tcp_westwood
)
{
if
(
tcp_is_westwood
(
tp
)
)
{
cwnd
=
__tcp_westwood_bw_rttmin
(
tp
);
if
(
cwnd
)
tp
->
snd_cwnd
=
cwnd
;
...
...
net/atm/clip.c
View file @
b938377b
...
...
@@ -27,6 +27,7 @@
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/rcupdate.h>
#include <linux/jhash.h>
#include <net/route.h>
/* for struct rtable and routing */
#include <net/icmp.h>
/* icmp_send */
#include <asm/param.h>
/* for HZ */
...
...
@@ -123,64 +124,49 @@ static void unlink_clip_vcc(struct clip_vcc *clip_vcc)
spin_unlock_bh
(
&
entry
->
neigh
->
dev
->
xmit_lock
);
}
static
void
idle_timer_check
(
unsigned
long
dummy
)
/* The neighbour entry n->lock is held. */
static
int
neigh_check_cb
(
struct
neighbour
*
n
)
{
int
i
;
struct
atmarp_entry
*
entry
=
NEIGH2ENTRY
(
n
);
struct
clip_vcc
*
cv
;
/*DPRINTK("idle_timer_check\n");*/
write_lock
(
&
clip_tbl
.
lock
);
for
(
i
=
0
;
i
<=
NEIGH_HASHMASK
;
i
++
)
{
struct
neighbour
**
np
;
for
(
np
=
&
clip_tbl
.
hash_buckets
[
i
];
*
np
;)
{
struct
neighbour
*
n
=
*
np
;
struct
atmarp_entry
*
entry
=
NEIGH2ENTRY
(
n
);
struct
clip_vcc
*
clip_vcc
;
write_lock
(
&
n
->
lock
);
for
(
clip_vcc
=
entry
->
vccs
;
clip_vcc
;
clip_vcc
=
clip_vcc
->
next
)
if
(
clip_vcc
->
idle_timeout
&&
time_after
(
jiffies
,
clip_vcc
->
last_use
+
clip_vcc
->
idle_timeout
))
{
DPRINTK
(
"releasing vcc %p->%p of "
"entry %p
\n
"
,
clip_vcc
,
clip_vcc
->
vcc
,
entry
);
vcc_release_async
(
clip_vcc
->
vcc
,
-
ETIMEDOUT
);
}
if
(
entry
->
vccs
||
time_before
(
jiffies
,
entry
->
expires
))
{
np
=
&
n
->
next
;
write_unlock
(
&
n
->
lock
);
continue
;
}
if
(
atomic_read
(
&
n
->
refcnt
)
>
1
)
{
struct
sk_buff
*
skb
;
DPRINTK
(
"destruction postponed with ref %d
\n
"
,
atomic_read
(
&
n
->
refcnt
));
while
((
skb
=
skb_dequeue
(
&
n
->
arp_queue
))
!=
NULL
)
dev_kfree_skb
(
skb
);
np
=
&
n
->
next
;
write_unlock
(
&
n
->
lock
);
continue
;
}
*
np
=
n
->
next
;
DPRINTK
(
"expired neigh %p
\n
"
,
n
);
n
->
dead
=
1
;
write_unlock
(
&
n
->
lock
);
neigh_release
(
n
);
for
(
cv
=
entry
->
vccs
;
cv
;
cv
=
cv
->
next
)
{
unsigned
long
exp
=
cv
->
last_use
+
cv
->
idle_timeout
;
if
(
cv
->
idle_timeout
&&
time_after
(
jiffies
,
exp
))
{
DPRINTK
(
"releasing vcc %p->%p of entry %p
\n
"
,
cv
,
cv
->
vcc
,
entry
);
vcc_release_async
(
cv
->
vcc
,
-
ETIMEDOUT
);
}
}
if
(
entry
->
vccs
||
time_before
(
jiffies
,
entry
->
expires
))
return
0
;
if
(
atomic_read
(
&
n
->
refcnt
)
>
1
)
{
struct
sk_buff
*
skb
;
DPRINTK
(
"destruction postponed with ref %d
\n
"
,
atomic_read
(
&
n
->
refcnt
));
while
((
skb
=
skb_dequeue
(
&
n
->
arp_queue
))
!=
NULL
)
dev_kfree_skb
(
skb
);
return
0
;
}
DPRINTK
(
"expired neigh %p
\n
"
,
n
);
return
1
;
}
static
void
idle_timer_check
(
unsigned
long
dummy
)
{
write_lock
(
&
clip_tbl
.
lock
);
__neigh_for_each_release
(
&
clip_tbl
,
neigh_check_cb
);
mod_timer
(
&
idle_timer
,
jiffies
+
CLIP_CHECK_INTERVAL
*
HZ
);
write_unlock
(
&
clip_tbl
.
lock
);
}
static
int
clip_arp_rcv
(
struct
sk_buff
*
skb
)
{
struct
atm_vcc
*
vcc
;
...
...
@@ -343,15 +329,7 @@ static int clip_constructor(struct neighbour *neigh)
static
u32
clip_hash
(
const
void
*
pkey
,
const
struct
net_device
*
dev
)
{
u32
hash_val
;
hash_val
=
*
(
u32
*
)
pkey
;
hash_val
^=
(
hash_val
>>
16
);
hash_val
^=
hash_val
>>
8
;
hash_val
^=
hash_val
>>
3
;
hash_val
=
(
hash_val
^
dev
->
ifindex
)
&
NEIGH_HASHMASK
;
return
hash_val
;
return
jhash_2words
(
*
(
u32
*
)
pkey
,
dev
->
ifindex
,
clip_tbl
.
hash_rnd
);
}
static
struct
neigh_table
clip_tbl
=
{
...
...
@@ -833,120 +811,126 @@ static void svc_addr(struct seq_file *seq, struct sockaddr_atmsvc *addr)
}
}
/* This means the neighbour entry has no attached VCC objects. */
#define SEQ_NO_VCC_TOKEN ((void *) 2)
static
void
atmarp_info
(
struct
seq_file
*
seq
,
struct
net_device
*
dev
,
struct
atmarp_entry
*
entry
,
struct
clip_vcc
*
clip_vcc
)
{
unsigned
long
exp
;
char
buf
[
17
];
int
svc
,
off
;
int
svc
,
llc
,
off
;
svc
=
((
clip_vcc
==
SEQ_NO_VCC_TOKEN
)
||
(
clip_vcc
->
vcc
->
sk
->
sk_family
==
AF_ATMSVC
));
llc
=
((
clip_vcc
==
SEQ_NO_VCC_TOKEN
)
||
clip_vcc
->
encap
);
svc
=
!
clip_vcc
||
clip_vcc
->
vcc
->
sk
->
sk_family
==
AF_ATMSVC
;
seq_printf
(
seq
,
"%-6s%-4s%-4s%5ld "
,
dev
->
name
,
svc
?
"SVC"
:
"PVC"
,
!
clip_vcc
||
clip_vcc
->
encap
?
"LLC"
:
"NULL"
,
(
jiffies
-
(
clip_vcc
?
clip_vcc
->
last_use
:
entry
->
neigh
->
used
))
/
HZ
)
;
if
(
clip_vcc
==
SEQ_NO_VCC_TOKEN
)
exp
=
entry
->
neigh
->
used
;
else
exp
=
clip_vcc
->
last_use
;
off
=
scnprintf
(
buf
,
sizeof
(
buf
)
-
1
,
"%d.%d.%d.%d"
,
NIPQUAD
(
entry
->
ip
));
exp
=
(
jiffies
-
exp
)
/
HZ
;
seq_printf
(
seq
,
"%-6s%-4s%-4s%5ld "
,
dev
->
name
,
svc
?
"SVC"
:
"PVC"
,
llc
?
"LLC"
:
"NULL"
,
exp
);
off
=
scnprintf
(
buf
,
sizeof
(
buf
)
-
1
,
"%d.%d.%d.%d"
,
NIPQUAD
(
entry
->
ip
));
while
(
off
<
16
)
buf
[
off
++
]
=
' '
;
buf
[
off
]
=
'\0'
;
seq_printf
(
seq
,
"%s"
,
buf
);
if
(
!
clip_vcc
)
{
if
(
clip_vcc
==
SEQ_NO_VCC_TOKEN
)
{
if
(
time_before
(
jiffies
,
entry
->
expires
))
seq_printf
(
seq
,
"(resolving)
\n
"
);
else
seq_printf
(
seq
,
"(expired, ref %d)
\n
"
,
atomic_read
(
&
entry
->
neigh
->
refcnt
));
}
else
if
(
!
svc
)
{
seq_printf
(
seq
,
"%d.%d.%d
\n
"
,
clip_vcc
->
vcc
->
dev
->
number
,
clip_vcc
->
vcc
->
vpi
,
clip_vcc
->
vcc
->
vci
);
seq_printf
(
seq
,
"%d.%d.%d
\n
"
,
clip_vcc
->
vcc
->
dev
->
number
,
clip_vcc
->
vcc
->
vpi
,
clip_vcc
->
vcc
->
vci
);
}
else
{
svc_addr
(
seq
,
&
clip_vcc
->
vcc
->
remote
);
seq_putc
(
seq
,
'\n'
);
}
}
struct
arp_state
{
int
bucket
;
struct
neighbour
*
n
;
struct
clip_seq_state
{
/* This member must be first. */
struct
neigh_seq_state
ns
;
/* Local to clip specific iteration. */
struct
clip_vcc
*
vcc
;
};
static
void
*
arp_vcc_walk
(
struct
arp_state
*
state
,
struct
atmarp_entry
*
e
,
loff_t
*
l
)
{
struct
clip_vcc
*
vcc
=
state
->
vcc
;
if
(
!
vcc
)
vcc
=
e
->
vccs
;
if
(
vcc
==
(
void
*
)
1
)
{
vcc
=
e
->
vccs
;
--*
l
;
}
for
(;
vcc
;
vcc
=
vcc
->
next
)
{
if
(
--*
l
<
0
)
break
;
}
state
->
vcc
=
vcc
;
return
(
*
l
<
0
)
?
state
:
NULL
;
}
static
void
*
arp_get_idx
(
struct
arp_state
*
state
,
loff_t
l
)
static
struct
clip_vcc
*
clip_seq_next_vcc
(
struct
atmarp_entry
*
e
,
struct
clip_vcc
*
curr
)
{
void
*
v
=
NULL
;
for
(;
state
->
bucket
<=
NEIGH_HASHMASK
;
state
->
bucket
++
)
{
for
(;
state
->
n
;
state
->
n
=
state
->
n
->
next
)
{
v
=
arp_vcc_walk
(
state
,
NEIGH2ENTRY
(
state
->
n
),
&
l
);
if
(
v
)
goto
done
;
}
state
->
n
=
clip_tbl
.
hash_buckets
[
state
->
bucket
+
1
];
if
(
!
curr
)
{
curr
=
e
->
vccs
;
if
(
!
curr
)
return
SEQ_NO_VCC_TOKEN
;
return
curr
;
}
done:
return
v
;
if
(
curr
==
SEQ_NO_VCC_TOKEN
)
return
NULL
;
curr
=
curr
->
next
;
return
curr
;
}
static
void
*
arp_seq_start
(
struct
seq_file
*
seq
,
loff_t
*
pos
)
static
void
*
clip_seq_vcc_walk
(
struct
clip_seq_state
*
state
,
struct
atmarp_entry
*
e
,
loff_t
*
pos
)
{
struct
arp_state
*
state
=
seq
->
private
;
void
*
ret
=
(
void
*
)
1
;
read_lock_bh
(
&
clip_tbl
.
lock
);
state
->
bucket
=
0
;
state
->
n
=
clip_tbl
.
hash_buckets
[
0
];
state
->
vcc
=
(
void
*
)
1
;
if
(
*
pos
)
ret
=
arp_get_idx
(
state
,
*
pos
);
return
ret
;
}
struct
clip_vcc
*
vcc
=
state
->
vcc
;
static
void
arp_seq_stop
(
struct
seq_file
*
seq
,
void
*
v
)
vcc
=
clip_seq_next_vcc
(
e
,
vcc
);
if
(
vcc
&&
pos
!=
NULL
)
{
while
(
*
pos
)
{
vcc
=
clip_seq_next_vcc
(
e
,
vcc
);
if
(
!
vcc
)
break
;
--
(
*
pos
);
}
}
state
->
vcc
=
vcc
;
return
vcc
;
}
static
void
*
clip_seq_sub_iter
(
struct
neigh_seq_state
*
_state
,
struct
neighbour
*
n
,
loff_t
*
pos
)
{
struct
arp_state
*
state
=
seq
->
priv
ate
;
struct
clip_seq_state
*
state
=
(
struct
clip_seq_state
*
)
_st
ate
;
if
(
state
->
bucket
!=
-
1
)
read_unlock_bh
(
&
clip_tbl
.
lock
);
return
clip_seq_vcc_walk
(
state
,
NEIGH2ENTRY
(
n
),
pos
);
}
static
void
*
arp_seq_next
(
struct
seq_file
*
seq
,
void
*
v
,
loff_t
*
pos
)
static
void
*
clip_seq_start
(
struct
seq_file
*
seq
,
loff_t
*
pos
)
{
struct
arp_state
*
state
=
seq
->
private
;
v
=
arp_get_idx
(
state
,
1
);
*
pos
+=
!!
PTR_ERR
(
v
);
return
v
;
return
neigh_seq_start
(
seq
,
pos
,
&
clip_tbl
,
NEIGH_SEQ_NEIGH_ONLY
);
}
static
int
ar
p_seq_show
(
struct
seq_file
*
seq
,
void
*
v
)
static
int
cli
p_seq_show
(
struct
seq_file
*
seq
,
void
*
v
)
{
static
char
atm_arp_banner
[]
=
"IPitf TypeEncp Idle IP address ATM address
\n
"
;
if
(
v
==
(
void
*
)
1
)
if
(
v
==
SEQ_START_TOKEN
)
{
seq_puts
(
seq
,
atm_arp_banner
);
else
{
struct
arp
_state
*
state
=
seq
->
private
;
struct
neighbour
*
n
=
state
->
n
;
}
else
{
struct
clip_seq
_state
*
state
=
seq
->
private
;
struct
neighbour
*
n
=
v
;
struct
clip_vcc
*
vcc
=
state
->
vcc
;
atmarp_info
(
seq
,
n
->
dev
,
NEIGH2ENTRY
(
n
),
vcc
);
...
...
@@ -955,15 +939,15 @@ static int arp_seq_show(struct seq_file *seq, void *v)
}
static
struct
seq_operations
arp_seq_ops
=
{
.
start
=
ar
p_seq_start
,
.
next
=
arp
_seq_next
,
.
stop
=
arp
_seq_stop
,
.
show
=
ar
p_seq_show
,
.
start
=
cli
p_seq_start
,
.
next
=
neigh
_seq_next
,
.
stop
=
neigh
_seq_stop
,
.
show
=
cli
p_seq_show
,
};
static
int
arp_seq_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
struct
arp
_state
*
state
;
struct
clip_seq
_state
*
state
;
struct
seq_file
*
seq
;
int
rc
=
-
EAGAIN
;
...
...
@@ -972,6 +956,8 @@ static int arp_seq_open(struct inode *inode, struct file *file)
rc
=
-
ENOMEM
;
goto
out_kfree
;
}
memset
(
state
,
0
,
sizeof
(
*
state
));
state
->
ns
.
neigh_sub_iter
=
clip_seq_sub_iter
;
rc
=
seq_open
(
file
,
&
arp_seq_ops
);
if
(
rc
)
...
...
@@ -987,16 +973,11 @@ static int arp_seq_open(struct inode *inode, struct file *file)
goto
out
;
}
static
int
arp_seq_release
(
struct
inode
*
inode
,
struct
file
*
file
)
{
return
seq_release_private
(
inode
,
file
);
}
static
struct
file_operations
arp_seq_fops
=
{
.
open
=
arp_seq_open
,
.
read
=
seq_read
,
.
llseek
=
seq_lseek
,
.
release
=
arp_seq_releas
e
,
.
release
=
seq_release_privat
e
,
.
owner
=
THIS_MODULE
};
#endif
...
...
net/core/neighbour.c
View file @
b938377b
...
...
@@ -29,6 +29,7 @@
#include <net/dst.h>
#include <net/sock.h>
#include <linux/rtnetlink.h>
#include <linux/random.h>
#define NEIGH_DEBUG 1
...
...
@@ -47,6 +48,8 @@
#define NEIGH_PRINTK2 NEIGH_PRINTK
#endif
#define PNEIGH_HASHMASK 0xF
static
void
neigh_timer_handler
(
unsigned
long
arg
);
#ifdef CONFIG_ARPD
static
void
neigh_app_notify
(
struct
neighbour
*
n
);
...
...
@@ -113,27 +116,19 @@ static int neigh_forced_gc(struct neigh_table *tbl)
int
shrunk
=
0
;
int
i
;
for
(
i
=
0
;
i
<=
NEIGH_HASHMASK
;
i
++
)
{
write_lock_bh
(
&
tbl
->
lock
);
for
(
i
=
0
;
i
<=
tbl
->
hash_mask
;
i
++
)
{
struct
neighbour
*
n
,
**
np
;
np
=
&
tbl
->
hash_buckets
[
i
];
write_lock_bh
(
&
tbl
->
lock
);
while
((
n
=
*
np
)
!=
NULL
)
{
/* Neighbour record may be discarded if:
- nobody refers to it.
- it is not permanent
- (NEW and probably wrong)
INCOMPLETE entries are kept at least for
n->parms->retrans_time, otherwise we could
flood network with resolution requests.
It is not clear, what is better table overflow
or flooding.
* - nobody refers to it.
* - it is not permanent
*/
write_lock
(
&
n
->
lock
);
if
(
atomic_read
(
&
n
->
refcnt
)
==
1
&&
!
(
n
->
nud_state
&
NUD_PERMANENT
)
&&
(
n
->
nud_state
!=
NUD_INCOMPLETE
||
time_after
(
jiffies
,
n
->
used
+
n
->
parms
->
retrans_time
)))
{
!
(
n
->
nud_state
&
NUD_PERMANENT
))
{
*
np
=
n
->
next
;
n
->
dead
=
1
;
shrunk
=
1
;
...
...
@@ -144,10 +139,12 @@ static int neigh_forced_gc(struct neigh_table *tbl)
write_unlock
(
&
n
->
lock
);
np
=
&
n
->
next
;
}
write_unlock_bh
(
&
tbl
->
lock
);
}
tbl
->
last_flush
=
jiffies
;
write_unlock_bh
(
&
tbl
->
lock
);
return
shrunk
;
}
...
...
@@ -177,7 +174,7 @@ void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev)
write_lock_bh
(
&
tbl
->
lock
);
for
(
i
=
0
;
i
<=
NEIGH_HASHMASK
;
i
++
)
{
for
(
i
=
0
;
i
<=
tbl
->
hash_mask
;
i
++
)
{
struct
neighbour
*
n
,
**
np
;
np
=
&
tbl
->
hash_buckets
[
i
];
...
...
@@ -204,7 +201,7 @@ int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
write_lock_bh
(
&
tbl
->
lock
);
for
(
i
=
0
;
i
<=
NEIGH_HASHMASK
;
i
++
)
{
for
(
i
=
0
;
i
<=
tbl
->
hash_mask
;
i
++
)
{
struct
neighbour
*
n
,
**
np
=
&
tbl
->
hash_buckets
[
i
];
while
((
n
=
*
np
)
!=
NULL
)
{
...
...
@@ -286,12 +283,73 @@ static struct neighbour *neigh_alloc(struct neigh_table *tbl)
return
n
;
}
static
struct
neighbour
**
neigh_hash_alloc
(
unsigned
int
entries
)
{
unsigned
long
size
=
entries
*
sizeof
(
struct
neighbour
*
);
struct
neighbour
**
ret
;
if
(
size
<=
PAGE_SIZE
)
{
ret
=
kmalloc
(
size
,
GFP_ATOMIC
);
}
else
{
ret
=
(
struct
neighbour
**
)
__get_free_pages
(
GFP_ATOMIC
,
get_order
(
size
));
}
if
(
ret
)
memset
(
ret
,
0
,
size
);
return
ret
;
}
static
void
neigh_hash_free
(
struct
neighbour
**
hash
,
unsigned
int
entries
)
{
unsigned
long
size
=
entries
*
sizeof
(
struct
neighbour
*
);
if
(
size
<=
PAGE_SIZE
)
kfree
(
hash
);
else
free_pages
((
unsigned
long
)
hash
,
get_order
(
size
));
}
static
void
neigh_hash_grow
(
struct
neigh_table
*
tbl
,
unsigned
long
new_entries
)
{
struct
neighbour
**
new_hash
,
**
old_hash
;
unsigned
int
i
,
new_hash_mask
,
old_entries
;
BUG_ON
(
new_entries
&
(
new_entries
-
1
));
new_hash
=
neigh_hash_alloc
(
new_entries
);
if
(
!
new_hash
)
return
;
old_entries
=
tbl
->
hash_mask
+
1
;
new_hash_mask
=
new_entries
-
1
;
old_hash
=
tbl
->
hash_buckets
;
get_random_bytes
(
&
tbl
->
hash_rnd
,
sizeof
(
tbl
->
hash_rnd
));
for
(
i
=
0
;
i
<
old_entries
;
i
++
)
{
struct
neighbour
*
n
,
*
next
;
for
(
n
=
old_hash
[
i
];
n
;
n
=
next
)
{
unsigned
int
hash_val
=
tbl
->
hash
(
n
->
primary_key
,
n
->
dev
);
hash_val
&=
new_hash_mask
;
next
=
n
->
next
;
n
->
next
=
new_hash
[
hash_val
];
new_hash
[
hash_val
]
=
n
;
}
}
tbl
->
hash_buckets
=
new_hash
;
tbl
->
hash_mask
=
new_hash_mask
;
neigh_hash_free
(
old_hash
,
old_entries
);
}
struct
neighbour
*
neigh_lookup
(
struct
neigh_table
*
tbl
,
const
void
*
pkey
,
struct
net_device
*
dev
)
{
struct
neighbour
*
n
;
int
key_len
=
tbl
->
key_len
;
u32
hash_val
=
tbl
->
hash
(
pkey
,
dev
);
u32
hash_val
=
tbl
->
hash
(
pkey
,
dev
)
&
tbl
->
hash_mask
;
read_lock_bh
(
&
tbl
->
lock
);
for
(
n
=
tbl
->
hash_buckets
[
hash_val
];
n
;
n
=
n
->
next
)
{
...
...
@@ -304,6 +362,23 @@ struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
return
n
;
}
struct
neighbour
*
neigh_lookup_nodev
(
struct
neigh_table
*
tbl
,
const
void
*
pkey
)
{
struct
neighbour
*
n
;
int
key_len
=
tbl
->
key_len
;
u32
hash_val
=
tbl
->
hash
(
pkey
,
NULL
)
&
tbl
->
hash_mask
;
read_lock_bh
(
&
tbl
->
lock
);
for
(
n
=
tbl
->
hash_buckets
[
hash_val
];
n
;
n
=
n
->
next
)
{
if
(
!
memcmp
(
n
->
primary_key
,
pkey
,
key_len
))
{
neigh_hold
(
n
);
break
;
}
}
read_unlock_bh
(
&
tbl
->
lock
);
return
n
;
}
struct
neighbour
*
neigh_create
(
struct
neigh_table
*
tbl
,
const
void
*
pkey
,
struct
net_device
*
dev
)
{
...
...
@@ -317,6 +392,12 @@ struct neighbour *neigh_create(struct neigh_table *tbl, const void *pkey,
goto
out
;
}
if
(
tbl
->
entries
>
(
tbl
->
hash_mask
+
1
))
{
write_lock_bh
(
&
tbl
->
lock
);
neigh_hash_grow
(
tbl
,
(
tbl
->
hash_mask
+
1
)
<<
1
);
write_unlock_bh
(
&
tbl
->
lock
);
}
memcpy
(
n
->
primary_key
,
pkey
,
key_len
);
n
->
dev
=
dev
;
dev_hold
(
dev
);
...
...
@@ -336,9 +417,10 @@ struct neighbour *neigh_create(struct neigh_table *tbl, const void *pkey,
n
->
confirmed
=
jiffies
-
(
n
->
parms
->
base_reachable_time
<<
1
);
hash_val
=
tbl
->
hash
(
pkey
,
dev
);
write_lock_bh
(
&
tbl
->
lock
);
hash_val
=
tbl
->
hash
(
pkey
,
dev
)
&
tbl
->
hash_mask
;
if
(
n
->
parms
->
dead
)
{
rc
=
ERR_PTR
(
-
EINVAL
);
goto
out_tbl_unlock
;
...
...
@@ -428,10 +510,10 @@ int pneigh_delete(struct neigh_table *tbl, const void *pkey,
hash_val
^=
hash_val
>>
4
;
hash_val
&=
PNEIGH_HASHMASK
;
write_lock_bh
(
&
tbl
->
lock
);
for
(
np
=
&
tbl
->
phash_buckets
[
hash_val
];
(
n
=
*
np
)
!=
NULL
;
np
=
&
n
->
next
)
{
if
(
!
memcmp
(
n
->
key
,
pkey
,
key_len
)
&&
n
->
dev
==
dev
)
{
write_lock_bh
(
&
tbl
->
lock
);
*
np
=
n
->
next
;
write_unlock_bh
(
&
tbl
->
lock
);
if
(
tbl
->
pdestructor
)
...
...
@@ -440,6 +522,7 @@ int pneigh_delete(struct neigh_table *tbl, const void *pkey,
return
0
;
}
}
write_unlock_bh
(
&
tbl
->
lock
);
return
-
ENOENT
;
}
...
...
@@ -545,9 +628,8 @@ static void neigh_connect(struct neighbour *neigh)
static
void
neigh_periodic_timer
(
unsigned
long
arg
)
{
struct
neigh_table
*
tbl
=
(
struct
neigh_table
*
)
arg
;
unsigned
long
now
=
jiffies
;
int
i
;
struct
neighbour
*
n
,
**
np
;
unsigned
long
expire
,
now
=
jiffies
;
write_lock
(
&
tbl
->
lock
);
...
...
@@ -563,41 +645,49 @@ static void neigh_periodic_timer(unsigned long arg)
neigh_rand_reach_time
(
p
->
base_reachable_time
);
}
for
(
i
=
0
;
i
<=
NEIGH_HASHMASK
;
i
++
)
{
struct
neighbour
*
n
,
**
np
;
np
=
&
tbl
->
hash_buckets
[
tbl
->
hash_chain_gc
];
tbl
->
hash_chain_gc
=
((
tbl
->
hash_chain_gc
+
1
)
&
tbl
->
hash_mask
)
;
np
=
&
tbl
->
hash_buckets
[
i
];
while
((
n
=
*
np
)
!=
NULL
)
{
unsigned
state
;
while
((
n
=
*
np
)
!=
NULL
)
{
unsigned
int
state
;
write_lock
(
&
n
->
lock
);
write_lock
(
&
n
->
lock
);
state
=
n
->
nud_state
;
if
(
state
&
(
NUD_PERMANENT
|
NUD_IN_TIMER
))
{
write_unlock
(
&
n
->
lock
);
goto
next_elt
;
}
state
=
n
->
nud_state
;
if
(
state
&
(
NUD_PERMANENT
|
NUD_IN_TIMER
))
{
write_unlock
(
&
n
->
lock
);
goto
next_elt
;
}
if
(
time_before
(
n
->
used
,
n
->
confirmed
))
n
->
used
=
n
->
confirmed
;
if
(
time_before
(
n
->
used
,
n
->
confirmed
))
n
->
used
=
n
->
confirmed
;
if
(
atomic_read
(
&
n
->
refcnt
)
==
1
&&
(
state
==
NUD_FAILED
||
time_after
(
now
,
n
->
used
+
n
->
parms
->
gc_staletime
)))
{
*
np
=
n
->
next
;
n
->
dead
=
1
;
write_unlock
(
&
n
->
lock
);
neigh_release
(
n
);
continue
;
}
if
(
atomic_read
(
&
n
->
refcnt
)
==
1
&&
(
state
==
NUD_FAILED
||
time_after
(
now
,
n
->
used
+
n
->
parms
->
gc_staletime
)))
{
*
np
=
n
->
next
;
n
->
dead
=
1
;
write_unlock
(
&
n
->
lock
);
neigh_release
(
n
);
continue
;
}
write_unlock
(
&
n
->
lock
);
next_elt:
np
=
&
n
->
next
;
}
np
=
&
n
->
next
;
}
mod_timer
(
&
tbl
->
gc_timer
,
now
+
tbl
->
gc_interval
);
/* Cycle through all hash buckets every base_reachable_time/2 ticks.
* ARP entry timeouts range from 1/2 base_reachable_time to 3/2
* base_reachable_time.
*/
expire
=
tbl
->
parms
.
base_reachable_time
>>
1
;
expire
/=
(
tbl
->
hash_mask
+
1
);
if
(
!
expire
)
expire
=
1
;
mod_timer
(
&
tbl
->
gc_timer
,
now
+
expire
);
write_unlock
(
&
tbl
->
lock
);
}
...
...
@@ -1205,6 +1295,7 @@ void neigh_parms_destroy(struct neigh_parms *parms)
void
neigh_table_init
(
struct
neigh_table
*
tbl
)
{
unsigned
long
now
=
jiffies
;
unsigned
long
phsize
;
atomic_set
(
&
tbl
->
parms
.
refcnt
,
1
);
INIT_RCU_HEAD
(
&
tbl
->
parms
.
rcu_head
);
...
...
@@ -1220,12 +1311,24 @@ void neigh_table_init(struct neigh_table *tbl)
if
(
!
tbl
->
kmem_cachep
)
panic
(
"cannot create neighbour cache"
);
tbl
->
hash_mask
=
1
;
tbl
->
hash_buckets
=
neigh_hash_alloc
(
tbl
->
hash_mask
+
1
);
phsize
=
(
PNEIGH_HASHMASK
+
1
)
*
sizeof
(
struct
pneigh_entry
*
);
tbl
->
phash_buckets
=
kmalloc
(
phsize
,
GFP_KERNEL
);
if
(
!
tbl
->
hash_buckets
||
!
tbl
->
phash_buckets
)
panic
(
"cannot allocate neighbour cache hashes"
);
memset
(
tbl
->
phash_buckets
,
0
,
phsize
);
get_random_bytes
(
&
tbl
->
hash_rnd
,
sizeof
(
tbl
->
hash_rnd
));
tbl
->
lock
=
RW_LOCK_UNLOCKED
;
init_timer
(
&
tbl
->
gc_timer
);
tbl
->
gc_timer
.
data
=
(
unsigned
long
)
tbl
;
tbl
->
gc_timer
.
function
=
neigh_periodic_timer
;
tbl
->
gc_timer
.
expires
=
now
+
tbl
->
gc_interval
+
tbl
->
parms
.
reachable_time
;
tbl
->
gc_timer
.
expires
=
now
+
1
;
add_timer
(
&
tbl
->
gc_timer
);
init_timer
(
&
tbl
->
proxy_timer
);
...
...
@@ -1260,6 +1363,13 @@ int neigh_table_clear(struct neigh_table *tbl)
}
}
write_unlock
(
&
neigh_tbl_lock
);
neigh_hash_free
(
tbl
->
hash_buckets
,
tbl
->
hash_mask
+
1
);
tbl
->
hash_buckets
=
NULL
;
kfree
(
tbl
->
phash_buckets
);
tbl
->
phash_buckets
=
NULL
;
return
0
;
}
...
...
@@ -1439,7 +1549,7 @@ static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
int
rc
,
h
,
s_h
=
cb
->
args
[
1
];
int
idx
,
s_idx
=
idx
=
cb
->
args
[
2
];
for
(
h
=
0
;
h
<=
NEIGH_HASHMASK
;
h
++
)
{
for
(
h
=
0
;
h
<=
tbl
->
hash_mask
;
h
++
)
{
if
(
h
<
s_h
)
continue
;
if
(
h
>
s_h
)
...
...
@@ -1489,6 +1599,266 @@ int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
return
skb
->
len
;
}
void
neigh_for_each
(
struct
neigh_table
*
tbl
,
void
(
*
cb
)(
struct
neighbour
*
,
void
*
),
void
*
cookie
)
{
int
chain
;
read_lock_bh
(
&
tbl
->
lock
);
for
(
chain
=
0
;
chain
<=
tbl
->
hash_mask
;
chain
++
)
{
struct
neighbour
*
n
;
for
(
n
=
tbl
->
hash_buckets
[
chain
];
n
;
n
=
n
->
next
)
cb
(
n
,
cookie
);
}
read_unlock_bh
(
&
tbl
->
lock
);
}
EXPORT_SYMBOL
(
neigh_for_each
);
/* The tbl->lock must be held as a writer and BH disabled. */
void
__neigh_for_each_release
(
struct
neigh_table
*
tbl
,
int
(
*
cb
)(
struct
neighbour
*
))
{
int
chain
;
for
(
chain
=
0
;
chain
<=
tbl
->
hash_mask
;
chain
++
)
{
struct
neighbour
*
n
,
**
np
;
np
=
&
tbl
->
hash_buckets
[
chain
];
while
((
n
=
*
np
)
!=
NULL
)
{
int
release
;
write_lock
(
&
n
->
lock
);
release
=
cb
(
n
);
if
(
release
)
{
*
np
=
n
->
next
;
n
->
dead
=
1
;
}
else
np
=
&
n
->
next
;
write_unlock
(
&
n
->
lock
);
if
(
release
)
neigh_release
(
n
);
}
}
}
EXPORT_SYMBOL
(
__neigh_for_each_release
);
#ifdef CONFIG_PROC_FS
static
struct
neighbour
*
neigh_get_first
(
struct
seq_file
*
seq
)
{
struct
neigh_seq_state
*
state
=
seq
->
private
;
struct
neigh_table
*
tbl
=
state
->
tbl
;
struct
neighbour
*
n
=
NULL
;
int
bucket
=
state
->
bucket
;
state
->
flags
&=
~
NEIGH_SEQ_IS_PNEIGH
;
for
(
bucket
=
0
;
bucket
<=
tbl
->
hash_mask
;
bucket
++
)
{
n
=
tbl
->
hash_buckets
[
bucket
];
while
(
n
)
{
if
(
state
->
neigh_sub_iter
)
{
loff_t
fakep
=
0
;
void
*
v
;
v
=
state
->
neigh_sub_iter
(
state
,
n
,
&
fakep
);
if
(
!
v
)
goto
next
;
}
if
(
!
(
state
->
flags
&
NEIGH_SEQ_SKIP_NOARP
))
break
;
if
(
n
->
nud_state
&
~
NUD_NOARP
)
break
;
next:
n
=
n
->
next
;
}
if
(
n
)
break
;
}
state
->
bucket
=
bucket
;
return
n
;
}
static
struct
neighbour
*
neigh_get_next
(
struct
seq_file
*
seq
,
struct
neighbour
*
n
,
loff_t
*
pos
)
{
struct
neigh_seq_state
*
state
=
seq
->
private
;
struct
neigh_table
*
tbl
=
state
->
tbl
;
if
(
state
->
neigh_sub_iter
)
{
void
*
v
=
state
->
neigh_sub_iter
(
state
,
n
,
pos
);
if
(
v
)
return
n
;
}
n
=
n
->
next
;
while
(
1
)
{
while
(
n
)
{
if
(
state
->
neigh_sub_iter
)
{
void
*
v
=
state
->
neigh_sub_iter
(
state
,
n
,
pos
);
if
(
v
)
return
n
;
goto
next
;
}
if
(
!
(
state
->
flags
&
NEIGH_SEQ_SKIP_NOARP
))
break
;
if
(
n
->
nud_state
&
~
NUD_NOARP
)
break
;
next:
n
=
n
->
next
;
}
if
(
n
)
break
;
if
(
++
state
->
bucket
>
tbl
->
hash_mask
)
break
;
n
=
tbl
->
hash_buckets
[
state
->
bucket
];
}
if
(
n
&&
pos
)
--
(
*
pos
);
return
n
;
}
static
struct
neighbour
*
neigh_get_idx
(
struct
seq_file
*
seq
,
loff_t
*
pos
)
{
struct
neighbour
*
n
=
neigh_get_first
(
seq
);
if
(
n
)
{
while
(
*
pos
)
{
n
=
neigh_get_next
(
seq
,
n
,
pos
);
if
(
!
n
)
break
;
}
}
return
*
pos
?
NULL
:
n
;
}
static
struct
pneigh_entry
*
pneigh_get_first
(
struct
seq_file
*
seq
)
{
struct
neigh_seq_state
*
state
=
seq
->
private
;
struct
neigh_table
*
tbl
=
state
->
tbl
;
struct
pneigh_entry
*
pn
=
NULL
;
int
bucket
=
state
->
bucket
;
state
->
flags
|=
NEIGH_SEQ_IS_PNEIGH
;
for
(
bucket
=
0
;
bucket
<=
PNEIGH_HASHMASK
;
bucket
++
)
{
pn
=
tbl
->
phash_buckets
[
bucket
];
if
(
pn
)
break
;
}
state
->
bucket
=
bucket
;
return
pn
;
}
static
struct
pneigh_entry
*
pneigh_get_next
(
struct
seq_file
*
seq
,
struct
pneigh_entry
*
pn
,
loff_t
*
pos
)
{
struct
neigh_seq_state
*
state
=
seq
->
private
;
struct
neigh_table
*
tbl
=
state
->
tbl
;
pn
=
pn
->
next
;
while
(
!
pn
)
{
if
(
++
state
->
bucket
>
PNEIGH_HASHMASK
)
break
;
pn
=
tbl
->
phash_buckets
[
state
->
bucket
];
if
(
pn
)
break
;
}
if
(
pn
&&
pos
)
--
(
*
pos
);
return
pn
;
}
static
struct
pneigh_entry
*
pneigh_get_idx
(
struct
seq_file
*
seq
,
loff_t
*
pos
)
{
struct
pneigh_entry
*
pn
=
pneigh_get_first
(
seq
);
if
(
pn
)
{
while
(
*
pos
)
{
pn
=
pneigh_get_next
(
seq
,
pn
,
pos
);
if
(
!
pn
)
break
;
}
}
return
*
pos
?
NULL
:
pn
;
}
static
void
*
neigh_get_idx_any
(
struct
seq_file
*
seq
,
loff_t
*
pos
)
{
struct
neigh_seq_state
*
state
=
seq
->
private
;
void
*
rc
;
rc
=
neigh_get_idx
(
seq
,
pos
);
if
(
!
rc
&&
!
(
state
->
flags
&
NEIGH_SEQ_NEIGH_ONLY
))
rc
=
pneigh_get_idx
(
seq
,
pos
);
return
rc
;
}
void
*
neigh_seq_start
(
struct
seq_file
*
seq
,
loff_t
*
pos
,
struct
neigh_table
*
tbl
,
unsigned
int
neigh_seq_flags
)
{
struct
neigh_seq_state
*
state
=
seq
->
private
;
loff_t
pos_minus_one
;
state
->
tbl
=
tbl
;
state
->
bucket
=
0
;
state
->
flags
=
(
neigh_seq_flags
&
~
NEIGH_SEQ_IS_PNEIGH
);
read_lock_bh
(
&
tbl
->
lock
);
pos_minus_one
=
*
pos
-
1
;
return
*
pos
?
neigh_get_idx_any
(
seq
,
&
pos_minus_one
)
:
SEQ_START_TOKEN
;
}
EXPORT_SYMBOL
(
neigh_seq_start
);
void
*
neigh_seq_next
(
struct
seq_file
*
seq
,
void
*
v
,
loff_t
*
pos
)
{
struct
neigh_seq_state
*
state
;
void
*
rc
;
if
(
v
==
SEQ_START_TOKEN
)
{
rc
=
neigh_get_idx
(
seq
,
pos
);
goto
out
;
}
state
=
seq
->
private
;
if
(
!
(
state
->
flags
&
NEIGH_SEQ_IS_PNEIGH
))
{
rc
=
neigh_get_next
(
seq
,
v
,
NULL
);
if
(
rc
)
goto
out
;
if
(
!
(
state
->
flags
&
NEIGH_SEQ_NEIGH_ONLY
))
rc
=
pneigh_get_first
(
seq
);
}
else
{
BUG_ON
(
state
->
flags
&
NEIGH_SEQ_NEIGH_ONLY
);
rc
=
pneigh_get_next
(
seq
,
v
,
NULL
);
}
out:
++
(
*
pos
);
return
rc
;
}
EXPORT_SYMBOL
(
neigh_seq_next
);
void
neigh_seq_stop
(
struct
seq_file
*
seq
,
void
*
v
)
{
struct
neigh_seq_state
*
state
=
seq
->
private
;
struct
neigh_table
*
tbl
=
state
->
tbl
;
read_unlock_bh
(
&
tbl
->
lock
);
}
EXPORT_SYMBOL
(
neigh_seq_stop
);
#endif
/* CONFIG_PROC_FS */
#ifdef CONFIG_ARPD
void
neigh_app_ns
(
struct
neighbour
*
n
)
{
...
...
@@ -1785,6 +2155,7 @@ EXPORT_SYMBOL(neigh_dump_info);
EXPORT_SYMBOL
(
neigh_event_ns
);
EXPORT_SYMBOL
(
neigh_ifdown
);
EXPORT_SYMBOL
(
neigh_lookup
);
EXPORT_SYMBOL
(
neigh_lookup_nodev
);
EXPORT_SYMBOL
(
neigh_parms_alloc
);
EXPORT_SYMBOL
(
neigh_parms_release
);
EXPORT_SYMBOL
(
neigh_rand_reach_time
);
...
...
net/decnet/dn_neigh.c
View file @
b938377b
...
...
@@ -36,6 +36,7 @@
#include <linux/spinlock.h>
#include <linux/seq_file.h>
#include <linux/rcupdate.h>
#include <linux/jhash.h>
#include <asm/atomic.h>
#include <net/neighbour.h>
#include <net/dst.h>
...
...
@@ -122,13 +123,7 @@ struct neigh_table dn_neigh_table = {
static
u32
dn_neigh_hash
(
const
void
*
pkey
,
const
struct
net_device
*
dev
)
{
u32
hash_val
;
hash_val
=
*
(
dn_address
*
)
pkey
;
hash_val
^=
(
hash_val
>>
10
);
hash_val
^=
(
hash_val
>>
3
);
return
hash_val
&
NEIGH_HASHMASK
;
return
jhash_2words
(
*
(
dn_address
*
)
pkey
,
0
,
dn_neigh_table
.
hash_rnd
);
}
static
int
dn_neigh_construct
(
struct
neighbour
*
neigh
)
...
...
@@ -359,27 +354,6 @@ static int dn_phase3_output(struct sk_buff *skb)
* basically does a neigh_lookup(), but without comparing the device
* field. This is required for the On-Ethernet cache
*/
struct
neighbour
*
dn_neigh_lookup
(
struct
neigh_table
*
tbl
,
const
void
*
ptr
)
{
struct
neighbour
*
neigh
;
u32
hash_val
;
hash_val
=
tbl
->
hash
(
ptr
,
NULL
);
read_lock_bh
(
&
tbl
->
lock
);
for
(
neigh
=
tbl
->
hash_buckets
[
hash_val
];
neigh
!=
NULL
;
neigh
=
neigh
->
next
)
{
if
(
memcmp
(
neigh
->
primary_key
,
ptr
,
tbl
->
key_len
)
==
0
)
{
atomic_inc
(
&
neigh
->
refcnt
);
read_unlock_bh
(
&
tbl
->
lock
);
return
neigh
;
}
}
read_unlock_bh
(
&
tbl
->
lock
);
return
NULL
;
}
/*
* Any traffic on a pointopoint link causes the timer to be reset
* for the entry in the neighbour table.
...
...
@@ -514,141 +488,66 @@ static char *dn_find_slot(char *base, int max, int priority)
return
(
*
min
<
priority
)
?
(
min
-
6
)
:
NULL
;
}
int
dn_neigh_elist
(
struct
net_device
*
dev
,
unsigned
char
*
ptr
,
int
n
)
{
int
t
=
0
;
int
i
;
struct
neighbour
*
neigh
;
struct
dn_neigh
*
dn
;
struct
neigh_table
*
tbl
=
&
dn_neigh_table
;
unsigned
char
*
rs
=
ptr
;
struct
dn_dev
*
dn_db
=
(
struct
dn_dev
*
)
dev
->
dn_ptr
;
read_lock_bh
(
&
tbl
->
lock
);
for
(
i
=
0
;
i
<
NEIGH_HASHMASK
;
i
++
)
{
for
(
neigh
=
tbl
->
hash_buckets
[
i
];
neigh
!=
NULL
;
neigh
=
neigh
->
next
)
{
if
(
neigh
->
dev
!=
dev
)
continue
;
dn
=
(
struct
dn_neigh
*
)
neigh
;
if
(
!
(
dn
->
flags
&
(
DN_NDFLAG_R1
|
DN_NDFLAG_R2
)))
continue
;
if
(
dn_db
->
parms
.
forwarding
==
1
&&
(
dn
->
flags
&
DN_NDFLAG_R2
))
continue
;
if
(
t
==
n
)
rs
=
dn_find_slot
(
ptr
,
n
,
dn
->
priority
);
else
t
++
;
if
(
rs
==
NULL
)
continue
;
dn_dn2eth
(
rs
,
dn
->
addr
);
rs
+=
6
;
*
rs
=
neigh
->
nud_state
&
NUD_CONNECTED
?
0x80
:
0x0
;
*
rs
|=
dn
->
priority
;
rs
++
;
}
}
read_unlock_bh
(
&
tbl
->
lock
);
return
t
;
}
#ifdef CONFIG_PROC_FS
struct
dn_neigh_iter_state
{
int
bucket
;
struct
elist_cb_state
{
struct
net_device
*
dev
;
unsigned
char
*
ptr
;
unsigned
char
*
rs
;
int
t
,
n
;
};
static
struct
neighbour
*
neigh_get_first
(
struct
seq_file
*
seq
)
{
struct
dn_neigh_iter_state
*
state
=
seq
->
private
;
struct
neighbour
*
n
=
NULL
;
for
(
state
->
bucket
=
0
;
state
->
bucket
<=
NEIGH_HASHMASK
;
++
state
->
bucket
)
{
n
=
dn_neigh_table
.
hash_buckets
[
state
->
bucket
];
if
(
n
)
break
;
}
return
n
;
}
static
struct
neighbour
*
neigh_get_next
(
struct
seq_file
*
seq
,
struct
neighbour
*
n
)
static
void
neigh_elist_cb
(
struct
neighbour
*
neigh
,
void
*
_info
)
{
struct
dn_neigh_iter_state
*
state
=
seq
->
private
;
n
=
n
->
next
;
try_again:
if
(
n
)
goto
out
;
if
(
++
state
->
bucket
>
NEIGH_HASHMASK
)
goto
out
;
n
=
dn_neigh_table
.
hash_buckets
[
state
->
bucket
];
goto
try_again
;
out:
return
n
;
}
struct
elist_cb_state
*
s
=
_info
;
struct
dn_dev
*
dn_db
;
struct
dn_neigh
*
dn
;
static
struct
neighbour
*
neigh_get_idx
(
struct
seq_file
*
seq
,
loff_t
*
pos
)
{
struct
neighbour
*
n
=
neigh_get_first
(
seq
);
if
(
neigh
->
dev
!=
s
->
dev
)
return
;
if
(
n
)
while
(
*
pos
&&
(
n
=
neigh_get_next
(
seq
,
n
)))
--*
pos
;
return
*
pos
?
NULL
:
n
;
}
dn
=
(
struct
dn_neigh
*
)
neigh
;
if
(
!
(
dn
->
flags
&
(
DN_NDFLAG_R1
|
DN_NDFLAG_R2
)))
return
;
static
void
*
dn_neigh_get_idx
(
struct
seq_file
*
seq
,
loff_t
pos
)
{
void
*
rc
;
read_lock_bh
(
&
dn_neigh_table
.
lock
);
rc
=
neigh_get_idx
(
seq
,
&
pos
);
if
(
!
rc
)
{
read_unlock_bh
(
&
dn_neigh_table
.
lock
);
}
return
rc
;
}
dn_db
=
(
struct
dn_dev
*
)
s
->
dev
->
dn_ptr
;
if
(
dn_db
->
parms
.
forwarding
==
1
&&
(
dn
->
flags
&
DN_NDFLAG_R2
))
return
;
static
void
*
dn_neigh_seq_start
(
struct
seq_file
*
seq
,
loff_t
*
pos
)
{
return
*
pos
?
dn_neigh_get_idx
(
seq
,
*
pos
-
1
)
:
SEQ_START_TOKEN
;
if
(
s
->
t
==
s
->
n
)
s
->
rs
=
dn_find_slot
(
s
->
ptr
,
s
->
n
,
dn
->
priority
);
else
s
->
t
++
;
if
(
s
->
rs
==
NULL
)
return
;
dn_dn2eth
(
s
->
rs
,
dn
->
addr
);
s
->
rs
+=
6
;
*
(
s
->
rs
)
=
neigh
->
nud_state
&
NUD_CONNECTED
?
0x80
:
0x0
;
*
(
s
->
rs
)
|=
dn
->
priority
;
s
->
rs
++
;
}
static
void
*
dn_neigh_seq_next
(
struct
seq_file
*
seq
,
void
*
v
,
loff_t
*
pos
)
int
dn_neigh_elist
(
struct
net_device
*
dev
,
unsigned
char
*
ptr
,
int
n
)
{
void
*
rc
;
struct
elist_cb_state
state
;
state
.
dev
=
dev
;
state
.
t
=
0
;
state
.
n
=
n
;
state
.
ptr
=
ptr
;
state
.
rs
=
ptr
;
if
(
v
==
SEQ_START_TOKEN
)
{
rc
=
dn_neigh_get_idx
(
seq
,
0
);
goto
out
;
}
neigh_for_each
(
&
dn_neigh_table
,
neigh_elist_cb
,
&
state
);
rc
=
neigh_get_next
(
seq
,
v
);
if
(
rc
)
goto
out
;
read_unlock_bh
(
&
dn_neigh_table
.
lock
);
out:
++*
pos
;
return
rc
;
return
state
.
t
;
}
static
void
dn_neigh_seq_stop
(
struct
seq_file
*
seq
,
void
*
v
)
{
if
(
v
&&
v
!=
SEQ_START_TOKEN
)
read_unlock_bh
(
&
dn_neigh_table
.
lock
);
}
#ifdef CONFIG_PROC_FS
static
inline
void
dn_neigh_format_entry
(
struct
seq_file
*
seq
,
struct
neighbour
*
n
)
{
struct
dn_neigh
*
dn
=
(
struct
dn_neigh
*
)
n
;
struct
dn_neigh
*
dn
=
(
struct
dn_neigh
*
)
n
;
char
buf
[
DN_ASCBUF_LEN
];
read_lock
(
&
n
->
lock
);
...
...
@@ -675,10 +574,16 @@ static int dn_neigh_seq_show(struct seq_file *seq, void *v)
return
0
;
}
static
void
*
dn_neigh_seq_start
(
struct
seq_file
*
seq
,
loff_t
*
pos
)
{
return
neigh_seq_start
(
seq
,
pos
,
&
dn_neigh_table
,
NEIGH_SEQ_NEIGH_ONLY
);
}
static
struct
seq_operations
dn_neigh_seq_ops
=
{
.
start
=
dn_neigh_seq_start
,
.
next
=
dn_
neigh_seq_next
,
.
stop
=
dn_
neigh_seq_stop
,
.
next
=
neigh_seq_next
,
.
stop
=
neigh_seq_stop
,
.
show
=
dn_neigh_seq_show
,
};
...
...
@@ -686,11 +591,12 @@ static int dn_neigh_seq_open(struct inode *inode, struct file *file)
{
struct
seq_file
*
seq
;
int
rc
=
-
ENOMEM
;
struct
dn_neigh_iter
_state
*
s
=
kmalloc
(
sizeof
(
*
s
),
GFP_KERNEL
);
struct
neigh_seq
_state
*
s
=
kmalloc
(
sizeof
(
*
s
),
GFP_KERNEL
);
if
(
!
s
)
goto
out
;
memset
(
s
,
0
,
sizeof
(
*
s
));
rc
=
seq_open
(
file
,
&
dn_neigh_seq_ops
);
if
(
rc
)
goto
out_kfree
;
...
...
net/decnet/dn_route.c
View file @
b938377b
...
...
@@ -996,7 +996,7 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowi *old
* here
*/
if
(
!
try_hard
)
{
neigh
=
dn_neigh_lookup
(
&
dn_neigh_table
,
&
fl
.
fld_dst
);
neigh
=
neigh_lookup_nodev
(
&
dn_neigh_table
,
&
fl
.
fld_dst
);
if
(
neigh
)
{
if
((
oldflp
->
oif
&&
(
neigh
->
dev
->
ifindex
!=
oldflp
->
oif
))
||
...
...
net/ipv4/arp.c
View file @
b938377b
...
...
@@ -71,6 +71,7 @@
* arp_xmit so intermediate drivers like
* bonding can change the skb before
* sending (e.g. insert 8021q tag).
* Harald Welte : convert to make use of jenkins hash
*/
#include <linux/module.h>
...
...
@@ -97,6 +98,7 @@
#include <linux/init.h>
#include <linux/net.h>
#include <linux/rcupdate.h>
#include <linux/jhash.h>
#ifdef CONFIG_SYSCTL
#include <linux/sysctl.h>
#endif
...
...
@@ -223,15 +225,7 @@ int arp_mc_map(u32 addr, u8 *haddr, struct net_device *dev, int dir)
static
u32
arp_hash
(
const
void
*
pkey
,
const
struct
net_device
*
dev
)
{
u32
hash_val
;
hash_val
=
*
(
u32
*
)
pkey
;
hash_val
^=
(
hash_val
>>
16
);
hash_val
^=
hash_val
>>
8
;
hash_val
^=
hash_val
>>
3
;
hash_val
=
(
hash_val
^
dev
->
ifindex
)
&
NEIGH_HASHMASK
;
return
hash_val
;
return
jhash_2words
(
*
(
u32
*
)
pkey
,
dev
->
ifindex
,
arp_tbl
.
hash_rnd
);
}
static
int
arp_constructor
(
struct
neighbour
*
neigh
)
...
...
@@ -1269,162 +1263,10 @@ static char *ax2asc2(ax25_address *a, char *buf)
}
#endif
/* CONFIG_AX25 */
struct
arp_iter_state
{
int
is_pneigh
,
bucket
;
};
static
struct
neighbour
*
neigh_get_first
(
struct
seq_file
*
seq
)
{
struct
arp_iter_state
*
state
=
seq
->
private
;
struct
neighbour
*
n
=
NULL
;
state
->
is_pneigh
=
0
;
for
(
state
->
bucket
=
0
;
state
->
bucket
<=
NEIGH_HASHMASK
;
++
state
->
bucket
)
{
n
=
arp_tbl
.
hash_buckets
[
state
->
bucket
];
while
(
n
&&
!
(
n
->
nud_state
&
~
NUD_NOARP
))
n
=
n
->
next
;
if
(
n
)
break
;
}
return
n
;
}
static
struct
neighbour
*
neigh_get_next
(
struct
seq_file
*
seq
,
struct
neighbour
*
n
)
{
struct
arp_iter_state
*
state
=
seq
->
private
;
do
{
n
=
n
->
next
;
/* Don't confuse "arp -a" w/ magic entries */
try_again:
;
}
while
(
n
&&
!
(
n
->
nud_state
&
~
NUD_NOARP
));
if
(
n
)
goto
out
;
if
(
++
state
->
bucket
>
NEIGH_HASHMASK
)
goto
out
;
n
=
arp_tbl
.
hash_buckets
[
state
->
bucket
];
goto
try_again
;
out:
return
n
;
}
static
struct
neighbour
*
neigh_get_idx
(
struct
seq_file
*
seq
,
loff_t
*
pos
)
{
struct
neighbour
*
n
=
neigh_get_first
(
seq
);
if
(
n
)
while
(
*
pos
&&
(
n
=
neigh_get_next
(
seq
,
n
)))
--*
pos
;
return
*
pos
?
NULL
:
n
;
}
static
struct
pneigh_entry
*
pneigh_get_first
(
struct
seq_file
*
seq
)
{
struct
arp_iter_state
*
state
=
seq
->
private
;
struct
pneigh_entry
*
pn
;
state
->
is_pneigh
=
1
;
for
(
state
->
bucket
=
0
;
state
->
bucket
<=
PNEIGH_HASHMASK
;
++
state
->
bucket
)
{
pn
=
arp_tbl
.
phash_buckets
[
state
->
bucket
];
if
(
pn
)
break
;
}
return
pn
;
}
static
struct
pneigh_entry
*
pneigh_get_next
(
struct
seq_file
*
seq
,
struct
pneigh_entry
*
pn
)
{
struct
arp_iter_state
*
state
=
seq
->
private
;
pn
=
pn
->
next
;
while
(
!
pn
)
{
if
(
++
state
->
bucket
>
PNEIGH_HASHMASK
)
break
;
pn
=
arp_tbl
.
phash_buckets
[
state
->
bucket
];
}
return
pn
;
}
static
struct
pneigh_entry
*
pneigh_get_idx
(
struct
seq_file
*
seq
,
loff_t
pos
)
{
struct
pneigh_entry
*
pn
=
pneigh_get_first
(
seq
);
if
(
pn
)
while
(
pos
&&
(
pn
=
pneigh_get_next
(
seq
,
pn
)))
--
pos
;
return
pos
?
NULL
:
pn
;
}
static
void
*
arp_get_idx
(
struct
seq_file
*
seq
,
loff_t
pos
)
{
void
*
rc
;
read_lock_bh
(
&
arp_tbl
.
lock
);
rc
=
neigh_get_idx
(
seq
,
&
pos
);
if
(
!
rc
)
{
read_unlock_bh
(
&
arp_tbl
.
lock
);
rc
=
pneigh_get_idx
(
seq
,
pos
);
}
return
rc
;
}
static
void
*
arp_seq_start
(
struct
seq_file
*
seq
,
loff_t
*
pos
)
{
struct
arp_iter_state
*
state
=
seq
->
private
;
state
->
is_pneigh
=
0
;
state
->
bucket
=
0
;
return
*
pos
?
arp_get_idx
(
seq
,
*
pos
-
1
)
:
SEQ_START_TOKEN
;
}
static
void
*
arp_seq_next
(
struct
seq_file
*
seq
,
void
*
v
,
loff_t
*
pos
)
{
void
*
rc
;
struct
arp_iter_state
*
state
;
if
(
v
==
SEQ_START_TOKEN
)
{
rc
=
arp_get_idx
(
seq
,
0
);
goto
out
;
}
state
=
seq
->
private
;
if
(
!
state
->
is_pneigh
)
{
rc
=
neigh_get_next
(
seq
,
v
);
if
(
rc
)
goto
out
;
read_unlock_bh
(
&
arp_tbl
.
lock
);
rc
=
pneigh_get_first
(
seq
);
}
else
rc
=
pneigh_get_next
(
seq
,
v
);
out:
++*
pos
;
return
rc
;
}
static
void
arp_seq_stop
(
struct
seq_file
*
seq
,
void
*
v
)
{
struct
arp_iter_state
*
state
=
seq
->
private
;
if
(
!
state
->
is_pneigh
&&
v
!=
SEQ_START_TOKEN
)
read_unlock_bh
(
&
arp_tbl
.
lock
);
}
#define HBUFFERLEN 30
static
__inline__
void
arp_format_neigh_entry
(
struct
seq_file
*
seq
,
struct
neighbour
*
n
)
static
void
arp_format_neigh_entry
(
struct
seq_file
*
seq
,
struct
neighbour
*
n
)
{
char
hbuffer
[
HBUFFERLEN
];
const
char
hexbuf
[]
=
"0123456789ABCDEF"
;
...
...
@@ -1455,8 +1297,8 @@ static __inline__ void arp_format_neigh_entry(struct seq_file *seq,
read_unlock
(
&
n
->
lock
);
}
static
__inline__
void
arp_format_pneigh_entry
(
struct
seq_file
*
seq
,
struct
pneigh_entry
*
n
)
static
void
arp_format_pneigh_entry
(
struct
seq_file
*
seq
,
struct
pneigh_entry
*
n
)
{
struct
net_device
*
dev
=
n
->
dev
;
int
hatype
=
dev
?
dev
->
type
:
0
;
...
...
@@ -1470,13 +1312,13 @@ static __inline__ void arp_format_pneigh_entry(struct seq_file *seq,
static
int
arp_seq_show
(
struct
seq_file
*
seq
,
void
*
v
)
{
if
(
v
==
SEQ_START_TOKEN
)
if
(
v
==
SEQ_START_TOKEN
)
{
seq_puts
(
seq
,
"IP address HW type Flags "
"HW address Mask Device
\n
"
);
else
{
struct
arp_iter_state
*
state
=
seq
->
private
;
}
else
{
struct
neigh_seq_state
*
state
=
seq
->
private
;
if
(
state
->
is_pneigh
)
if
(
state
->
flags
&
NEIGH_SEQ_IS_PNEIGH
)
arp_format_pneigh_entry
(
seq
,
v
);
else
arp_format_neigh_entry
(
seq
,
v
);
...
...
@@ -1485,12 +1327,20 @@ static int arp_seq_show(struct seq_file *seq, void *v)
return
0
;
}
static
void
*
arp_seq_start
(
struct
seq_file
*
seq
,
loff_t
*
pos
)
{
/* Don't want to confuse "arp -a" w/ magic entries,
* so we tell the generic iterator to skip NUD_NOARP.
*/
return
neigh_seq_start
(
seq
,
pos
,
&
arp_tbl
,
NEIGH_SEQ_SKIP_NOARP
);
}
/* ------------------------------------------------------------------------ */
static
struct
seq_operations
arp_seq_ops
=
{
.
start
=
arp_seq_start
,
.
next
=
arp
_seq_next
,
.
stop
=
arp
_seq_stop
,
.
next
=
neigh
_seq_next
,
.
stop
=
neigh
_seq_stop
,
.
show
=
arp_seq_show
,
};
...
...
@@ -1498,11 +1348,12 @@ static int arp_seq_open(struct inode *inode, struct file *file)
{
struct
seq_file
*
seq
;
int
rc
=
-
ENOMEM
;
struct
arp_iter
_state
*
s
=
kmalloc
(
sizeof
(
*
s
),
GFP_KERNEL
);
struct
neigh_seq
_state
*
s
=
kmalloc
(
sizeof
(
*
s
),
GFP_KERNEL
);
if
(
!
s
)
goto
out
;
memset
(
s
,
0
,
sizeof
(
*
s
));
rc
=
seq_open
(
file
,
&
arp_seq_ops
);
if
(
rc
)
goto
out_kfree
;
...
...
net/ipv4/fib_hash.c
View file @
b938377b
...
...
@@ -438,17 +438,15 @@ static struct fib_alias *fib_find_alias(struct fib_node *fn, u8 tos, u32 prio)
{
if
(
fn
)
{
struct
list_head
*
head
=
&
fn
->
fn_alias
;
struct
fib_alias
*
fa
,
*
prev_fa
;
struct
fib_alias
*
fa
;
prev_fa
=
NULL
;
list_for_each_entry
(
fa
,
head
,
fa_list
)
{
if
(
fa
->
fa_tos
!=
tos
)
if
(
fa
->
fa_tos
>
tos
)
continue
;
prev_fa
=
fa
;
if
(
prio
<=
fa
->
fa_info
->
fib_priority
)
break
;
if
(
fa
->
fa_info
->
fib_priority
>=
prio
||
fa
->
fa_tos
<
tos
)
return
fa
;
}
return
prev_fa
;
}
return
NULL
;
}
...
...
@@ -505,7 +503,7 @@ fn_hash_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
* and we need to allocate a new one of those as well.
*/
if
(
fa
&&
if
(
fa
&&
fa
->
fa_tos
==
tos
&&
fa
->
fa_info
->
fib_priority
==
fi
->
fib_priority
)
{
struct
fib_alias
*
fa_orig
;
...
...
@@ -537,7 +535,8 @@ fn_hash_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
* information.
*/
fa_orig
=
fa
;
list_for_each_entry
(
fa
,
fa_orig
->
fa_list
.
prev
,
fa_list
)
{
fa
=
list_entry
(
fa
->
fa_list
.
prev
,
struct
fib_alias
,
fa_list
);
list_for_each_entry_continue
(
fa
,
&
f
->
fn_alias
,
fa_list
)
{
if
(
fa
->
fa_tos
!=
tos
)
break
;
if
(
fa
->
fa_info
->
fib_priority
!=
fi
->
fib_priority
)
...
...
@@ -585,7 +584,7 @@ fn_hash_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
write_lock_bh
(
&
fib_hash_lock
);
if
(
new_f
)
fib_insert_node
(
fz
,
new_f
);
list_add
(
&
new_fa
->
fa_list
,
list_add
_tail
(
&
new_fa
->
fa_list
,
(
fa
?
&
fa
->
fa_list
:
&
f
->
fn_alias
));
write_unlock_bh
(
&
fib_hash_lock
);
...
...
@@ -611,7 +610,6 @@ fn_hash_delete(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
struct
fn_hash
*
table
=
(
struct
fn_hash
*
)
tb
->
tb_data
;
struct
fib_node
*
f
;
struct
fib_alias
*
fa
,
*
fa_to_delete
;
struct
list_head
*
fa_head
;
int
z
=
r
->
rtm_dst_len
;
struct
fn_zone
*
fz
;
u32
key
;
...
...
@@ -637,8 +635,8 @@ fn_hash_delete(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
return
-
ESRCH
;
fa_to_delete
=
NULL
;
fa
_head
=
fa
->
fa_list
.
prev
;
list_for_each_entry
(
fa
,
fa_head
,
fa_list
)
{
fa
=
list_entry
(
fa
->
fa_list
.
prev
,
struct
fib_alias
,
fa_list
)
;
list_for_each_entry
_continue
(
fa
,
&
f
->
fn_alias
,
fa_list
)
{
struct
fib_info
*
fi
=
fa
->
fa_info
;
if
(
fa
->
fa_tos
!=
tos
)
...
...
net/ipv4/tcp_diag.c
View file @
b938377b
...
...
@@ -41,6 +41,12 @@ static struct sock *tcpnl;
rta->rta_len = rtalen; \
RTA_DATA(rta); })
static
inline
unsigned
int
jiffies_to_usecs
(
const
unsigned
long
j
)
{
return
1000
*
jiffies_to_msecs
(
j
);
}
/* Return information about state of tcp endpoint in API format. */
void
tcp_get_info
(
struct
sock
*
sk
,
struct
tcp_info
*
info
)
{
...
...
@@ -68,8 +74,8 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info)
if
(
tp
->
ecn_flags
&
TCP_ECN_OK
)
info
->
tcpi_options
|=
TCPI_OPT_ECN
;
info
->
tcpi_rto
=
(
1000000
*
tp
->
rto
)
/
HZ
;
info
->
tcpi_ato
=
(
1000000
*
tp
->
ack
.
ato
)
/
HZ
;
info
->
tcpi_rto
=
jiffies_to_usecs
(
tp
->
rto
)
;
info
->
tcpi_ato
=
jiffies_to_usecs
(
tp
->
ack
.
ato
)
;
info
->
tcpi_snd_mss
=
tp
->
mss_cache_std
;
info
->
tcpi_rcv_mss
=
tp
->
ack
.
rcv_mss
;
...
...
@@ -79,20 +85,20 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info)
info
->
tcpi_retrans
=
tcp_get_pcount
(
&
tp
->
retrans_out
);
info
->
tcpi_fackets
=
tcp_get_pcount
(
&
tp
->
fackets_out
);
info
->
tcpi_last_data_sent
=
((
now
-
tp
->
lsndtime
)
*
1000
)
/
HZ
;
info
->
tcpi_last_data_recv
=
((
now
-
tp
->
ack
.
lrcvtime
)
*
1000
)
/
HZ
;
info
->
tcpi_last_ack_recv
=
((
now
-
tp
->
rcv_tstamp
)
*
1000
)
/
HZ
;
info
->
tcpi_last_data_sent
=
jiffies_to_msecs
(
now
-
tp
->
lsndtime
)
;
info
->
tcpi_last_data_recv
=
jiffies_to_msecs
(
now
-
tp
->
ack
.
lrcvtime
)
;
info
->
tcpi_last_ack_recv
=
jiffies_to_msecs
(
now
-
tp
->
rcv_tstamp
)
;
info
->
tcpi_pmtu
=
tp
->
pmtu_cookie
;
info
->
tcpi_rcv_ssthresh
=
tp
->
rcv_ssthresh
;
info
->
tcpi_rtt
=
((
1000000
*
tp
->
srtt
)
/
HZ
)
>>
3
;
info
->
tcpi_rttvar
=
((
1000000
*
tp
->
mdev
)
/
HZ
)
>>
2
;
info
->
tcpi_rtt
=
jiffies_to_usecs
(
tp
->
srtt
)
>>
3
;
info
->
tcpi_rttvar
=
jiffies_to_usecs
(
tp
->
mdev
)
>>
2
;
info
->
tcpi_snd_ssthresh
=
tp
->
snd_ssthresh
;
info
->
tcpi_snd_cwnd
=
tp
->
snd_cwnd
;
info
->
tcpi_advmss
=
tp
->
advmss
;
info
->
tcpi_reordering
=
tp
->
reordering
;
info
->
tcpi_rcv_rtt
=
((
1000000
*
tp
->
rcv_rtt_est
.
rtt
)
/
HZ
)
>>
3
;
info
->
tcpi_rcv_rtt
=
jiffies_to_usecs
(
tp
->
rcv_rtt_est
.
rtt
)
>>
3
;
info
->
tcpi_rcv_space
=
tp
->
rcvq_space
.
space
;
}
...
...
@@ -116,7 +122,8 @@ static int tcpdiag_fill(struct sk_buff *skb, struct sock *sk,
if
(
ext
&
(
1
<<
(
TCPDIAG_INFO
-
1
)))
info
=
TCPDIAG_PUT
(
skb
,
TCPDIAG_INFO
,
sizeof
(
*
info
));
if
(
tcp_is_vegas
(
tp
)
&&
(
ext
&
(
1
<<
(
TCPDIAG_VEGASINFO
-
1
))))
if
((
tcp_is_westwood
(
tp
)
||
tcp_is_vegas
(
tp
))
&&
(
ext
&
(
1
<<
(
TCPDIAG_VEGASINFO
-
1
))))
vinfo
=
TCPDIAG_PUT
(
skb
,
TCPDIAG_VEGASINFO
,
sizeof
(
*
vinfo
));
}
r
->
tcpdiag_family
=
sk
->
sk_family
;
...
...
@@ -209,10 +216,17 @@ static int tcpdiag_fill(struct sk_buff *skb, struct sock *sk,
tcp_get_info
(
sk
,
info
);
if
(
vinfo
)
{
vinfo
->
tcpv_enabled
=
tp
->
vegas
.
doing_vegas_now
;
vinfo
->
tcpv_rttcnt
=
tp
->
vegas
.
cntRTT
;
vinfo
->
tcpv_rtt
=
tp
->
vegas
.
baseRTT
;
vinfo
->
tcpv_minrtt
=
tp
->
vegas
.
minRTT
;
if
(
tcp_is_vegas
(
tp
))
{
vinfo
->
tcpv_enabled
=
tp
->
vegas
.
doing_vegas_now
;
vinfo
->
tcpv_rttcnt
=
tp
->
vegas
.
cntRTT
;
vinfo
->
tcpv_rtt
=
jiffies_to_usecs
(
tp
->
vegas
.
baseRTT
);
vinfo
->
tcpv_minrtt
=
jiffies_to_usecs
(
tp
->
vegas
.
minRTT
);
}
else
{
vinfo
->
tcpv_enabled
=
0
;
vinfo
->
tcpv_rttcnt
=
0
;
vinfo
->
tcpv_rtt
=
jiffies_to_usecs
(
tp
->
westwood
.
rtt
);
vinfo
->
tcpv_minrtt
=
jiffies_to_usecs
(
tp
->
westwood
.
rtt_min
);
}
}
nlh
->
nlmsg_len
=
skb
->
tail
-
b
;
...
...
net/ipv4/tcp_input.c
View file @
b938377b
...
...
@@ -555,17 +555,20 @@ static void tcp_event_data_recv(struct sock *sk, struct tcp_opt *tp, struct sk_b
tcp_grow_window
(
sk
,
tp
,
skb
);
}
/*
Set up a new TCP connection, depending on whether it should be
*
using Vegas or not
.
*/
void
tcp_
vegas
_init
(
struct
tcp_opt
*
tp
)
/*
When starting a new connection, pin down the current choice of
*
congestion algorithm
.
*/
void
tcp_
ca
_init
(
struct
tcp_opt
*
tp
)
{
if
(
sysctl_tcp_vegas_cong_avoid
)
{
tp
->
vegas
.
do_vegas
=
1
;
if
(
sysctl_tcp_westwood
)
tp
->
adv_cong
=
TCP_WESTWOOD
;
else
if
(
sysctl_tcp_bic
)
tp
->
adv_cong
=
TCP_BIC
;
else
if
(
sysctl_tcp_vegas_cong_avoid
)
{
tp
->
adv_cong
=
TCP_VEGAS
;
tp
->
vegas
.
baseRTT
=
0x7fffffff
;
tcp_vegas_enable
(
tp
);
}
else
tcp_vegas_disable
(
tp
);
}
}
/* Do RTT sampling needed for Vegas.
...
...
@@ -2039,7 +2042,7 @@ tcp_ack_update_rtt(struct tcp_opt *tp, int flag, s32 seq_rtt)
static
inline
__u32
bictcp_cwnd
(
struct
tcp_opt
*
tp
)
{
/* orignal Reno behaviour */
if
(
!
sysctl_tcp_bic
)
if
(
!
tcp_is_bic
(
tp
)
)
return
tp
->
snd_cwnd
;
if
(
tp
->
bictcp
.
last_cwnd
==
tp
->
snd_cwnd
&&
...
...
@@ -2617,18 +2620,16 @@ static void westwood_filter(struct sock *sk, __u32 delta)
* WESTWOOD_RTT_MIN minimum bound since we could be on a LAN!
*/
static
inline
__u32
westwood_update_rttmin
(
struct
sock
*
sk
)
static
inline
__u32
westwood_update_rttmin
(
const
struct
sock
*
sk
)
{
struct
tcp_opt
*
tp
=
tcp_sk
(
sk
);
const
struct
tcp_opt
*
tp
=
tcp_sk
(
sk
);
__u32
rttmin
=
tp
->
westwood
.
rtt_min
;
if
(
tp
->
westwood
.
rtt
==
0
)
return
(
rttmin
);
if
(
tp
->
westwood
.
rtt
<
tp
->
westwood
.
rtt_min
||
!
rttmin
)
if
(
tp
->
westwood
.
rtt
!=
0
&&
(
tp
->
westwood
.
rtt
<
tp
->
westwood
.
rtt_min
||
!
rttmin
))
rttmin
=
tp
->
westwood
.
rtt
;
return
(
rttmin
)
;
return
rttmin
;
}
/*
...
...
@@ -2636,11 +2637,11 @@ static inline __u32 westwood_update_rttmin(struct sock *sk)
* Evaluate increases for dk.
*/
static
inline
__u32
westwood_acked
(
struct
sock
*
sk
)
static
inline
__u32
westwood_acked
(
const
struct
sock
*
sk
)
{
struct
tcp_opt
*
tp
=
tcp_sk
(
sk
);
const
struct
tcp_opt
*
tp
=
tcp_sk
(
sk
);
return
((
tp
->
snd_una
)
-
(
tp
->
westwood
.
snd_una
))
;
return
tp
->
snd_una
-
tp
->
westwood
.
snd_una
;
}
/*
...
...
@@ -2652,9 +2653,9 @@ static inline __u32 westwood_acked(struct sock *sk)
* window, 1 if the sample has to be considered in the next window.
*/
static
int
westwood_new_window
(
struct
sock
*
sk
)
static
int
westwood_new_window
(
const
struct
sock
*
sk
)
{
struct
tcp_opt
*
tp
=
tcp_sk
(
sk
);
const
struct
tcp_opt
*
tp
=
tcp_sk
(
sk
);
__u32
left_bound
;
__u32
rtt
;
int
ret
=
0
;
...
...
@@ -2688,14 +2689,13 @@ static void __westwood_update_window(struct sock *sk, __u32 now)
struct
tcp_opt
*
tp
=
tcp_sk
(
sk
);
__u32
delta
=
now
-
tp
->
westwood
.
rtt_win_sx
;
if
(
!
delta
)
return
;
if
(
tp
->
westwood
.
rtt
)
westwood_filter
(
sk
,
delta
);
if
(
delta
)
{
if
(
tp
->
westwood
.
rtt
)
westwood_filter
(
sk
,
delta
);
tp
->
westwood
.
bk
=
0
;
tp
->
westwood
.
rtt_win_sx
=
tcp_time_stamp
;
tp
->
westwood
.
bk
=
0
;
tp
->
westwood
.
rtt_win_sx
=
tcp_time_stamp
;
}
}
...
...
@@ -2739,7 +2739,7 @@ static void westwood_dupack_update(struct sock *sk)
static
inline
int
westwood_may_change_cumul
(
struct
tcp_opt
*
tp
)
{
return
(
(
tp
->
westwood
.
cumul_ack
)
>
tp
->
mss_cache_std
);
return
(
tp
->
westwood
.
cumul_ack
>
tp
->
mss_cache_std
);
}
static
inline
void
westwood_partial_update
(
struct
tcp_opt
*
tp
)
...
...
@@ -2760,7 +2760,7 @@ static inline void westwood_complete_update(struct tcp_opt *tp)
* delayed or partial acks.
*/
static
__u32
westwood_acked_count
(
struct
sock
*
sk
)
static
inline
__u32
westwood_acked_count
(
struct
sock
*
sk
)
{
struct
tcp_opt
*
tp
=
tcp_sk
(
sk
);
...
...
@@ -2774,7 +2774,7 @@ static __u32 westwood_acked_count(struct sock *sk)
if
(
westwood_may_change_cumul
(
tp
))
{
/* Partial or delayed ack */
if
(
(
tp
->
westwood
.
accounted
)
>=
(
tp
->
westwood
.
cumul_ack
)
)
if
(
tp
->
westwood
.
accounted
>=
tp
->
westwood
.
cumul_ack
)
westwood_partial_update
(
tp
);
else
westwood_complete_update
(
tp
);
...
...
net/ipv4/tcp_minisocks.c
View file @
b938377b
...
...
@@ -841,7 +841,8 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct open_request *req,
if
(
newtp
->
ecn_flags
&
TCP_ECN_OK
)
newsk
->
sk_no_largesend
=
1
;
tcp_vegas_init
(
newtp
);
tcp_ca_init
(
newtp
);
TCP_INC_STATS_BH
(
TCP_MIB_PASSIVEOPENS
);
}
return
newsk
;
...
...
net/ipv4/tcp_output.c
View file @
b938377b
...
...
@@ -1359,7 +1359,7 @@ static inline void tcp_connect_init(struct sock *sk)
tp
->
window_clamp
=
dst_metric
(
dst
,
RTAX_WINDOW
);
tp
->
advmss
=
dst_metric
(
dst
,
RTAX_ADVMSS
);
tcp_initialize_rcv_mss
(
sk
);
tcp_
vegas
_init
(
tp
);
tcp_
ca
_init
(
tp
);
tcp_select_initial_window
(
tcp_full_space
(
sk
),
tp
->
advmss
-
(
tp
->
ts_recent_stamp
?
tp
->
tcp_header_len
-
sizeof
(
struct
tcphdr
)
:
0
),
...
...
@@ -1411,7 +1411,7 @@ int tcp_connect(struct sock *sk)
TCP_SKB_CB
(
buff
)
->
end_seq
=
tp
->
write_seq
;
tp
->
snd_nxt
=
tp
->
write_seq
;
tp
->
pushed_seq
=
tp
->
write_seq
;
tcp_
vegas
_init
(
tp
);
tcp_
ca
_init
(
tp
);
/* Send it off. */
TCP_SKB_CB
(
buff
)
->
when
=
tcp_time_stamp
;
...
...
net/ipv6/ndisc.c
View file @
b938377b
...
...
@@ -66,6 +66,7 @@
#include <linux/if_arp.h>
#include <linux/ipv6.h>
#include <linux/icmpv6.h>
#include <linux/jhash.h>
#include <net/sock.h>
#include <net/snmp.h>
...
...
@@ -270,15 +271,14 @@ int ndisc_mc_map(struct in6_addr *addr, char *buf, struct net_device *dev, int d
static
u32
ndisc_hash
(
const
void
*
pkey
,
const
struct
net_device
*
dev
)
{
u32
hash_val
;
const
u32
*
p32
=
pkey
;
u32
addr_hash
,
i
;
hash_val
=
*
(
u32
*
)(
pkey
+
sizeof
(
struct
in6_addr
)
-
4
);
hash_val
^=
(
hash_val
>>
16
);
hash_val
^=
hash_val
>>
8
;
hash_val
^=
hash_val
>>
3
;
hash_val
=
(
hash_val
^
dev
->
ifindex
)
&
NEIGH_HASHMASK
;
addr_hash
=
0
;
for
(
i
=
0
;
i
<
(
sizeof
(
struct
in6_addr
)
/
sizeof
(
u32
));
i
++
)
addr_hash
^=
*
p32
++
;
return
hash_val
;
return
jhash_2words
(
addr_hash
,
dev
->
ifindex
,
nd_tbl
.
hash_rnd
)
;
}
static
int
ndisc_constructor
(
struct
neighbour
*
neigh
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment