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
Kirill Smelkov
linux
Commits
e8ea4873
Commit
e8ea4873
authored
Sep 21, 2004
by
David S. Miller
Browse files
Options
Browse Files
Download
Plain Diff
Merge davem@nuts.davemloft.net:/disk1/BK/net-2.6
into kernel.bkbits.net:/home/davem/net-2.6
parents
7bae86e3
f3960ea0
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
427 additions
and
376 deletions
+427
-376
arch/arm/configs/ebsa110_defconfig
arch/arm/configs/ebsa110_defconfig
+0
-1
arch/arm/configs/ixp4xx_defconfig
arch/arm/configs/ixp4xx_defconfig
+0
-1
arch/mips/configs/tb0226_defconfig
arch/mips/configs/tb0226_defconfig
+0
-1
arch/mips/configs/tb0229_defconfig
arch/mips/configs/tb0229_defconfig
+0
-1
net/ipv4/Kconfig
net/ipv4/Kconfig
+0
-10
net/ipv4/fib_hash.c
net/ipv4/fib_hash.c
+427
-360
net/ipv4/fib_rules.c
net/ipv4/fib_rules.c
+0
-2
No files found.
arch/arm/configs/ebsa110_defconfig
View file @
e8ea4873
...
@@ -176,7 +176,6 @@ CONFIG_IP_MULTIPLE_TABLES=y
...
@@ -176,7 +176,6 @@ CONFIG_IP_MULTIPLE_TABLES=y
CONFIG_IP_ROUTE_FWMARK=y
CONFIG_IP_ROUTE_FWMARK=y
CONFIG_IP_ROUTE_NAT=y
CONFIG_IP_ROUTE_NAT=y
# CONFIG_IP_ROUTE_MULTIPATH is not set
# CONFIG_IP_ROUTE_MULTIPATH is not set
# CONFIG_IP_ROUTE_TOS is not set
CONFIG_IP_ROUTE_VERBOSE=y
CONFIG_IP_ROUTE_VERBOSE=y
CONFIG_IP_PNP=y
CONFIG_IP_PNP=y
# CONFIG_IP_PNP_DHCP is not set
# CONFIG_IP_PNP_DHCP is not set
...
...
arch/arm/configs/ixp4xx_defconfig
View file @
e8ea4873
...
@@ -308,7 +308,6 @@ CONFIG_IP_MULTIPLE_TABLES=y
...
@@ -308,7 +308,6 @@ CONFIG_IP_MULTIPLE_TABLES=y
CONFIG_IP_ROUTE_FWMARK=y
CONFIG_IP_ROUTE_FWMARK=y
CONFIG_IP_ROUTE_NAT=y
CONFIG_IP_ROUTE_NAT=y
CONFIG_IP_ROUTE_MULTIPATH=y
CONFIG_IP_ROUTE_MULTIPATH=y
CONFIG_IP_ROUTE_TOS=y
CONFIG_IP_ROUTE_VERBOSE=y
CONFIG_IP_ROUTE_VERBOSE=y
CONFIG_IP_PNP=y
CONFIG_IP_PNP=y
CONFIG_IP_PNP_DHCP=y
CONFIG_IP_PNP_DHCP=y
...
...
arch/mips/configs/tb0226_defconfig
View file @
e8ea4873
...
@@ -272,7 +272,6 @@ CONFIG_IP_ADVANCED_ROUTER=y
...
@@ -272,7 +272,6 @@ CONFIG_IP_ADVANCED_ROUTER=y
CONFIG_IP_MULTIPLE_TABLES=y
CONFIG_IP_MULTIPLE_TABLES=y
CONFIG_IP_ROUTE_NAT=y
CONFIG_IP_ROUTE_NAT=y
CONFIG_IP_ROUTE_MULTIPATH=y
CONFIG_IP_ROUTE_MULTIPATH=y
CONFIG_IP_ROUTE_TOS=y
CONFIG_IP_ROUTE_VERBOSE=y
CONFIG_IP_ROUTE_VERBOSE=y
CONFIG_IP_PNP=y
CONFIG_IP_PNP=y
# CONFIG_IP_PNP_DHCP is not set
# CONFIG_IP_PNP_DHCP is not set
...
...
arch/mips/configs/tb0229_defconfig
View file @
e8ea4873
...
@@ -229,7 +229,6 @@ CONFIG_IP_ADVANCED_ROUTER=y
...
@@ -229,7 +229,6 @@ CONFIG_IP_ADVANCED_ROUTER=y
CONFIG_IP_MULTIPLE_TABLES=y
CONFIG_IP_MULTIPLE_TABLES=y
CONFIG_IP_ROUTE_NAT=y
CONFIG_IP_ROUTE_NAT=y
CONFIG_IP_ROUTE_MULTIPATH=y
CONFIG_IP_ROUTE_MULTIPATH=y
CONFIG_IP_ROUTE_TOS=y
CONFIG_IP_ROUTE_VERBOSE=y
CONFIG_IP_ROUTE_VERBOSE=y
CONFIG_IP_PNP=y
CONFIG_IP_PNP=y
# CONFIG_IP_PNP_DHCP is not set
# CONFIG_IP_PNP_DHCP is not set
...
...
net/ipv4/Kconfig
View file @
e8ea4873
...
@@ -94,16 +94,6 @@ config IP_ROUTE_MULTIPATH
...
@@ -94,16 +94,6 @@ config IP_ROUTE_MULTIPATH
equal "cost" and chooses one of them in a non-deterministic fashion
equal "cost" and chooses one of them in a non-deterministic fashion
if a matching packet arrives.
if a matching packet arrives.
config IP_ROUTE_TOS
bool "IP: use TOS value as routing key"
depends on IP_ADVANCED_ROUTER
help
The header of every IP packet carries a TOS (Type Of Service) value
with which the packet requests a certain treatment, e.g. low
latency (for interactive traffic), high throughput, or high
reliability. If you say Y here, you will be able to specify
different routes for packets with different TOS values.
config IP_ROUTE_VERBOSE
config IP_ROUTE_VERBOSE
bool "IP: verbose route monitoring"
bool "IP: verbose route monitoring"
depends on IP_ADVANCED_ROUTER
depends on IP_ADVANCED_ROUTER
...
...
net/ipv4/fib_hash.c
View file @
e8ea4873
...
@@ -43,49 +43,45 @@
...
@@ -43,49 +43,45 @@
#include <net/sock.h>
#include <net/sock.h>
#include <net/ip_fib.h>
#include <net/ip_fib.h>
#define FTprint(a...)
/*
printk(KERN_DEBUG a)
*/
static
kmem_cache_t
*
fn_hash_kmem
;
static
kmem_cache_t
*
fn_hash_kmem
;
static
kmem_cache_t
*
fn_alias_kmem
;
struct
fib_node
{
struct
fib_node
{
struct
fib_node
*
fn_next
;
struct
hlist_node
fn_hash
;
struct
fib_info
*
fn_info
;
struct
list_head
fn_alias
;
#define FIB_INFO(f) ((f)->fn_info)
u32
fn_key
;
u32
fn_key
;
u8
fn_tos
;
u8
fn_type
;
u8
fn_scope
;
u8
fn_state
;
};
};
#define FN_S_ZOMBIE 1
struct
fib_alias
{
#define FN_S_ACCESSED 2
struct
list_head
fa_list
;
struct
fib_info
*
fa_info
;
u8
fa_tos
;
u8
fa_type
;
u8
fa_scope
;
u8
fa_state
;
};
static
int
fib_hash_zombies
;
#define FN_S_ACCESSED 1
struct
fn_zone
{
struct
fn_zone
{
struct
fn_zone
*
fz_next
;
/* Next not empty zone */
struct
fn_zone
*
fz_next
;
/* Next not empty zone */
struct
fib_node
*
*
fz_hash
;
/* Hash table pointer */
struct
hlist_head
*
fz_hash
;
/* Hash table pointer */
int
fz_nent
;
/* Number of entries */
int
fz_nent
;
/* Number of entries */
int
fz_divisor
;
/* Hash divisor */
int
fz_divisor
;
/* Hash divisor */
u32
fz_hashmask
;
/* (fz_divisor - 1) */
u32
fz_hashmask
;
/* (fz_divisor - 1) */
#define FZ_HASHMASK(fz) ((fz)->fz_hashmask)
#define FZ_HASHMASK(fz)
((fz)->fz_hashmask)
int
fz_order
;
/* Zone order */
int
fz_order
;
/* Zone order */
u32
fz_mask
;
u32
fz_mask
;
#define FZ_MASK(fz) ((fz)->fz_mask)
#define FZ_MASK(fz)
((fz)->fz_mask)
};
};
/* NOTE. On fast computers evaluation of fz_hashmask and fz_mask
/* NOTE. On fast computers evaluation of fz_hashmask and fz_mask
can be cheaper than memory lookup, so that FZ_* macros are used.
*
can be cheaper than memory lookup, so that FZ_* macros are used.
*/
*/
struct
fn_hash
struct
fn_hash
{
{
struct
fn_zone
*
fn_zones
[
33
];
struct
fn_zone
*
fn_zones
[
33
];
struct
fn_zone
*
fn_zone_list
;
struct
fn_zone
*
fn_zone_list
;
};
};
...
@@ -105,65 +101,56 @@ static inline u32 fz_key(u32 dst, struct fn_zone *fz)
...
@@ -105,65 +101,56 @@ static inline u32 fz_key(u32 dst, struct fn_zone *fz)
return
dst
&
FZ_MASK
(
fz
);
return
dst
&
FZ_MASK
(
fz
);
}
}
static
inline
struct
fib_node
**
fz_chain_p
(
u32
key
,
struct
fn_zone
*
fz
)
{
return
&
fz
->
fz_hash
[
fn_hash
(
key
,
fz
)];
}
static
inline
struct
fib_node
*
fz_chain
(
u32
key
,
struct
fn_zone
*
fz
)
{
return
fz
->
fz_hash
[
fn_hash
(
key
,
fz
)];
}
static
rwlock_t
fib_hash_lock
=
RW_LOCK_UNLOCKED
;
static
rwlock_t
fib_hash_lock
=
RW_LOCK_UNLOCKED
;
#define FZ_MAX_DIVISOR ((PAGE_SIZE<<MAX_ORDER) / sizeof(struct
fib_node *
))
#define FZ_MAX_DIVISOR ((PAGE_SIZE<<MAX_ORDER) / sizeof(struct
hlist_head
))
static
struct
fib_node
*
*
fz_hash_alloc
(
int
divisor
)
static
struct
hlist_head
*
fz_hash_alloc
(
int
divisor
)
{
{
unsigned
long
size
=
divisor
*
sizeof
(
struct
fib_node
*
);
unsigned
long
size
=
divisor
*
sizeof
(
struct
hlist_head
);
if
(
divisor
<=
1024
)
{
if
(
divisor
<=
1024
)
{
return
kmalloc
(
size
,
GFP_KERNEL
);
return
kmalloc
(
size
,
GFP_KERNEL
);
}
else
{
}
else
{
return
(
struct
fib_node
*
*
)
return
(
struct
hlist_head
*
)
__get_free_pages
(
GFP_KERNEL
,
get_order
(
size
));
__get_free_pages
(
GFP_KERNEL
,
get_order
(
size
));
}
}
}
}
/* The fib hash lock must be held when this is called. */
/* The fib hash lock must be held when this is called. */
static
inline
void
fn_rebuild_zone
(
struct
fn_zone
*
fz
,
static
inline
void
fn_rebuild_zone
(
struct
fn_zone
*
fz
,
struct
fib_node
*
*
old_ht
,
struct
hlist_head
*
old_ht
,
int
old_divisor
)
int
old_divisor
)
{
{
int
i
;
int
i
;
struct
fib_node
*
f
,
**
fp
,
*
next
;
for
(
i
=
0
;
i
<
old_divisor
;
i
++
)
{
for
(
i
=
0
;
i
<
old_divisor
;
i
++
)
{
struct
hlist_node
*
node
,
*
n
;
for
(
f
=
old_ht
[
i
];
f
;
f
=
next
)
{
struct
fib_node
*
f
;
next
=
f
->
fn_next
;
for
(
fp
=
fz_chain_p
(
f
->
fn_key
,
fz
);
hlist_for_each_entry_safe
(
f
,
node
,
n
,
&
old_ht
[
i
],
fn_hash
)
{
*
fp
&&
((
*
fp
)
->
fn_key
<=
f
->
fn_key
);
struct
hlist_head
*
new_head
;
fp
=
&
(
*
fp
)
->
fn_next
)
/* NONE */
;
hlist_del
(
&
f
->
fn_hash
);
f
->
fn_next
=
*
fp
;
*
fp
=
f
;
new_head
=
&
fz
->
fz_hash
[
fn_hash
(
f
->
fn_key
,
fz
)];
hlist_add_head
(
&
f
->
fn_hash
,
new_head
);
}
}
}
}
}
}
static
void
fz_hash_free
(
struct
fib_node
*
*
hash
,
int
divisor
)
static
void
fz_hash_free
(
struct
hlist_head
*
hash
,
int
divisor
)
{
{
if
(
divisor
<=
1024
)
if
(
divisor
<=
1024
)
kfree
(
hash
);
kfree
(
hash
);
else
else
free_pages
((
unsigned
long
)
hash
,
free_pages
((
unsigned
long
)
hash
,
get_order
(
divisor
*
sizeof
(
struct
fib_node
*
)));
get_order
(
divisor
*
sizeof
(
struct
hlist_head
)));
}
}
static
void
fn_rehash_zone
(
struct
fn_zone
*
fz
)
static
void
fn_rehash_zone
(
struct
fn_zone
*
fz
)
{
{
struct
fib_node
**
ht
,
*
*
old_ht
;
struct
hlist_head
*
ht
,
*
old_ht
;
int
old_divisor
,
new_divisor
;
int
old_divisor
,
new_divisor
;
u32
new_hashmask
;
u32
new_hashmask
;
...
@@ -194,7 +181,7 @@ static void fn_rehash_zone(struct fn_zone *fz)
...
@@ -194,7 +181,7 @@ static void fn_rehash_zone(struct fn_zone *fz)
ht
=
fz_hash_alloc
(
new_divisor
);
ht
=
fz_hash_alloc
(
new_divisor
);
if
(
ht
)
{
if
(
ht
)
{
memset
(
ht
,
0
,
new_divisor
*
sizeof
(
struct
fib_node
*
));
memset
(
ht
,
0
,
new_divisor
*
sizeof
(
struct
hlist_head
));
write_lock_bh
(
&
fib_hash_lock
);
write_lock_bh
(
&
fib_hash_lock
);
old_ht
=
fz
->
fz_hash
;
old_ht
=
fz
->
fz_hash
;
...
@@ -208,12 +195,16 @@ static void fn_rehash_zone(struct fn_zone *fz)
...
@@ -208,12 +195,16 @@ static void fn_rehash_zone(struct fn_zone *fz)
}
}
}
}
static
void
fn_free_node
(
struct
fib_node
*
f
)
static
inline
void
fn_free_node
(
struct
fib_node
*
f
)
{
{
fib_release_info
(
FIB_INFO
(
f
));
kmem_cache_free
(
fn_hash_kmem
,
f
);
kmem_cache_free
(
fn_hash_kmem
,
f
);
}
}
static
inline
void
fn_free_alias
(
struct
fib_alias
*
fa
)
{
fib_release_info
(
fa
->
fa_info
);
kmem_cache_free
(
fn_alias_kmem
,
fa
);
}
static
struct
fn_zone
*
static
struct
fn_zone
*
fn_new_zone
(
struct
fn_hash
*
table
,
int
z
)
fn_new_zone
(
struct
fn_hash
*
table
,
int
z
)
...
@@ -235,7 +226,7 @@ fn_new_zone(struct fn_hash *table, int z)
...
@@ -235,7 +226,7 @@ fn_new_zone(struct fn_hash *table, int z)
kfree
(
fz
);
kfree
(
fz
);
return
NULL
;
return
NULL
;
}
}
memset
(
fz
->
fz_hash
,
0
,
fz
->
fz_divisor
*
sizeof
(
struct
fib_node
*
));
memset
(
fz
->
fz_hash
,
0
,
fz
->
fz_divisor
*
sizeof
(
struct
hlist_head
*
));
fz
->
fz_order
=
z
;
fz
->
fz_order
=
z
;
fz
->
fz_mask
=
inet_make_mask
(
z
);
fz
->
fz_mask
=
inet_make_mask
(
z
);
...
@@ -266,36 +257,39 @@ fn_hash_lookup(struct fib_table *tb, const struct flowi *flp, struct fib_result
...
@@ -266,36 +257,39 @@ fn_hash_lookup(struct fib_table *tb, const struct flowi *flp, struct fib_result
read_lock
(
&
fib_hash_lock
);
read_lock
(
&
fib_hash_lock
);
for
(
fz
=
t
->
fn_zone_list
;
fz
;
fz
=
fz
->
fz_next
)
{
for
(
fz
=
t
->
fn_zone_list
;
fz
;
fz
=
fz
->
fz_next
)
{
struct
hlist_head
*
head
;
struct
hlist_node
*
node
;
struct
fib_node
*
f
;
struct
fib_node
*
f
;
u32
k
=
fz_key
(
flp
->
fl4_dst
,
fz
);
u32
k
=
fz_key
(
flp
->
fl4_dst
,
fz
);
for
(
f
=
fz_chain
(
k
,
fz
);
f
;
f
=
f
->
fn_next
)
{
head
=
&
fz
->
fz_hash
[
fn_hash
(
k
,
fz
)];
if
(
k
!=
f
->
fn_key
)
{
hlist_for_each_entry
(
f
,
node
,
head
,
fn_hash
)
{
if
(
k
<=
f
->
fn_key
)
struct
fib_alias
*
fa
;
break
;
else
continue
;
}
#ifdef CONFIG_IP_ROUTE_TOS
if
(
f
->
fn_tos
&&
f
->
fn_tos
!=
flp
->
fl4_tos
)
continue
;
#endif
f
->
fn_state
|=
FN_S_ACCESSED
;
if
(
f
->
fn_state
&
FN_S_ZOMBIE
)
if
(
f
->
fn_key
!=
k
)
continue
;
if
(
f
->
fn_scope
<
flp
->
fl4_scope
)
continue
;
continue
;
err
=
fib_semantic_match
(
f
->
fn_type
,
FIB_INFO
(
f
),
flp
,
res
);
list_for_each_entry
(
fa
,
&
f
->
fn_alias
,
fa_list
)
{
if
(
err
==
0
)
{
if
(
fa
->
fa_tos
&&
res
->
type
=
f
->
fn_type
;
fa
->
fa_tos
!=
flp
->
fl4_tos
)
res
->
scope
=
f
->
fn_scope
;
continue
;
res
->
prefixlen
=
fz
->
fz_order
;
if
(
fa
->
fa_scope
<
flp
->
fl4_scope
)
goto
out
;
continue
;
fa
->
fa_state
|=
FN_S_ACCESSED
;
err
=
fib_semantic_match
(
fa
->
fa_type
,
fa
->
fa_info
,
flp
,
res
);
if
(
err
==
0
)
{
res
->
type
=
fa
->
fa_type
;
res
->
scope
=
fa
->
fa_scope
;
res
->
prefixlen
=
fz
->
fz_order
;
goto
out
;
}
if
(
err
<
0
)
goto
out
;
}
}
if
(
err
<
0
)
goto
out
;
}
}
}
}
err
=
1
;
err
=
1
;
...
@@ -333,6 +327,7 @@ static void
...
@@ -333,6 +327,7 @@ static void
fn_hash_select_default
(
struct
fib_table
*
tb
,
const
struct
flowi
*
flp
,
struct
fib_result
*
res
)
fn_hash_select_default
(
struct
fib_table
*
tb
,
const
struct
flowi
*
flp
,
struct
fib_result
*
res
)
{
{
int
order
,
last_idx
;
int
order
,
last_idx
;
struct
hlist_node
*
node
;
struct
fib_node
*
f
;
struct
fib_node
*
f
;
struct
fib_info
*
fi
=
NULL
;
struct
fib_info
*
fi
=
NULL
;
struct
fib_info
*
last_resort
;
struct
fib_info
*
last_resort
;
...
@@ -347,36 +342,41 @@ fn_hash_select_default(struct fib_table *tb, const struct flowi *flp, struct fib
...
@@ -347,36 +342,41 @@ fn_hash_select_default(struct fib_table *tb, const struct flowi *flp, struct fib
order
=
-
1
;
order
=
-
1
;
read_lock
(
&
fib_hash_lock
);
read_lock
(
&
fib_hash_lock
);
for
(
f
=
fz
->
fz_hash
[
0
];
f
;
f
=
f
->
fn_next
)
{
hlist_for_each_entry
(
f
,
node
,
&
fz
->
fz_hash
[
0
],
fn_hash
)
{
struct
fib_
info
*
next_fi
=
FIB_INFO
(
f
)
;
struct
fib_
alias
*
fa
;
if
((
f
->
fn_state
&
FN_S_ZOMBIE
)
||
list_for_each_entry
(
fa
,
&
f
->
fn_alias
,
fa_list
)
{
f
->
fn_scope
!=
res
->
scope
||
struct
fib_info
*
next_fi
=
fa
->
fa_info
;
f
->
fn_type
!=
RTN_UNICAST
)
continue
;
if
(
next_fi
->
fib_priority
>
res
->
fi
->
fib_priority
)
if
(
fa
->
fa_scope
!=
res
->
scope
||
break
;
fa
->
fa_type
!=
RTN_UNICAST
)
if
(
!
next_fi
->
fib_nh
[
0
].
nh_gw
||
next_fi
->
fib_nh
[
0
].
nh_scope
!=
RT_SCOPE_LINK
)
continue
;
continue
;
f
->
fn_state
|=
FN_S_ACCESSED
;
if
(
fi
==
NULL
)
{
if
(
next_fi
->
fib_priority
>
res
->
fi
->
fib_priority
)
if
(
next_fi
!=
res
->
fi
)
break
;
break
;
}
else
if
(
!
fib_detect_death
(
fi
,
order
,
&
last_resort
,
&
last_idx
))
{
if
(
!
next_fi
->
fib_nh
[
0
].
nh_gw
||
if
(
res
->
fi
)
next_fi
->
fib_nh
[
0
].
nh_scope
!=
RT_SCOPE_LINK
)
fib_info_put
(
res
->
fi
);
continue
;
res
->
fi
=
fi
;
fa
->
fa_state
|=
FN_S_ACCESSED
;
atomic_inc
(
&
fi
->
fib_clntref
);
fn_hash_last_dflt
=
order
;
if
(
fi
==
NULL
)
{
goto
out
;
if
(
next_fi
!=
res
->
fi
)
break
;
}
else
if
(
!
fib_detect_death
(
fi
,
order
,
&
last_resort
,
&
last_idx
))
{
if
(
res
->
fi
)
fib_info_put
(
res
->
fi
);
res
->
fi
=
fi
;
atomic_inc
(
&
fi
->
fib_clntref
);
fn_hash_last_dflt
=
order
;
goto
out
;
}
fi
=
next_fi
;
order
++
;
}
}
fi
=
next_fi
;
order
++
;
}
}
if
(
order
<=
0
||
fi
==
NULL
)
{
if
(
order
<=
0
||
fi
==
NULL
)
{
fn_hash_last_dflt
=
-
1
;
fn_hash_last_dflt
=
-
1
;
goto
out
;
goto
out
;
}
}
...
@@ -402,45 +402,71 @@ fn_hash_select_default(struct fib_table *tb, const struct flowi *flp, struct fib
...
@@ -402,45 +402,71 @@ fn_hash_select_default(struct fib_table *tb, const struct flowi *flp, struct fib
read_unlock
(
&
fib_hash_lock
);
read_unlock
(
&
fib_hash_lock
);
}
}
#define FIB_SCAN(f, fp) \
static
void
rtmsg_fib
(
int
,
struct
fib_node
*
,
struct
fib_alias
*
,
for ( ; ((f) = *(fp)) != NULL; (fp) = &(f)->fn_next)
int
,
int
,
struct
nlmsghdr
*
n
,
struct
netlink_skb_parms
*
);
#define FIB_SCAN_KEY(f, fp, key) \
/* Insert node F to FZ. */
for ( ; ((f) = *(fp)) != NULL && ((f)->fn_key == (key)); (fp) = &(f)->fn_next)
static
inline
void
fib_insert_node
(
struct
fn_zone
*
fz
,
struct
fib_node
*
f
)
{
struct
hlist_head
*
head
=
&
fz
->
fz_hash
[
fn_hash
(
f
->
fn_key
,
fz
)];
#ifndef CONFIG_IP_ROUTE_TOS
hlist_add_head
(
&
f
->
fn_hash
,
head
);
#define FIB_SCAN_TOS(f, fp, key, tos) FIB_SCAN_KEY(f, fp, key)
}
#else
#define FIB_SCAN_TOS(f, fp, key, tos) \
for ( ; ((f) = *(fp)) != NULL && ((f)->fn_key == (key)) && \
(f)->fn_tos == (tos) ; (fp) = &(f)->fn_next)
#endif
/* Return the node in FZ matching KEY. */
static
struct
fib_node
*
fib_find_node
(
struct
fn_zone
*
fz
,
u32
key
)
{
struct
hlist_head
*
head
=
&
fz
->
fz_hash
[
fn_hash
(
key
,
fz
)];
struct
hlist_node
*
node
;
struct
fib_node
*
f
;
static
void
rtmsg_fib
(
int
,
struct
fib_node
*
,
int
,
int
,
hlist_for_each_entry
(
f
,
node
,
head
,
fn_hash
)
{
struct
nlmsghdr
*
n
,
if
(
f
->
fn_key
==
key
)
struct
netlink_skb_parms
*
);
return
f
;
}
return
NULL
;
}
/* Return the first fib alias matching TOS with
* priority less than or equal to PRIO.
*/
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
;
prev_fa
=
NULL
;
list_for_each_entry
(
fa
,
head
,
fa_list
)
{
if
(
fa
->
fa_tos
!=
tos
)
continue
;
prev_fa
=
fa
;
if
(
prio
<=
fa
->
fa_info
->
fib_priority
)
break
;
}
return
fa
;
}
return
NULL
;
}
static
int
static
int
fn_hash_insert
(
struct
fib_table
*
tb
,
struct
rtmsg
*
r
,
struct
kern_rta
*
rta
,
fn_hash_insert
(
struct
fib_table
*
tb
,
struct
rtmsg
*
r
,
struct
kern_rta
*
rta
,
struct
nlmsghdr
*
n
,
struct
netlink_skb_parms
*
req
)
struct
nlmsghdr
*
n
,
struct
netlink_skb_parms
*
req
)
{
{
struct
fn_hash
*
table
=
(
struct
fn_hash
*
)
tb
->
tb_data
;
struct
fn_hash
*
table
=
(
struct
fn_hash
*
)
tb
->
tb_data
;
struct
fib_node
*
new_f
,
*
f
,
**
fp
,
**
del_fp
;
struct
fib_node
*
new_f
,
*
f
;
struct
fib_alias
*
fa
,
*
new_fa
;
struct
fn_zone
*
fz
;
struct
fn_zone
*
fz
;
struct
fib_info
*
fi
;
struct
fib_info
*
fi
;
int
z
=
r
->
rtm_dst_len
;
int
z
=
r
->
rtm_dst_len
;
int
type
=
r
->
rtm_type
;
int
type
=
r
->
rtm_type
;
#ifdef CONFIG_IP_ROUTE_TOS
u8
tos
=
r
->
rtm_tos
;
u8
tos
=
r
->
rtm_tos
;
#endif
u32
key
;
u32
key
;
int
err
;
int
err
;
FTprint
(
"tb(%d)_insert: %d %08x/%d %d %08x
\n
"
,
tb
->
tb_id
,
r
->
rtm_type
,
rta
->
rta_dst
?
*
(
u32
*
)
rta
->
rta_dst
:
0
,
z
,
rta
->
rta_oif
?
*
rta
->
rta_oif
:
-
1
,
rta
->
rta_prefsrc
?
*
(
u32
*
)
rta
->
rta_prefsrc
:
0
);
if
(
z
>
32
)
if
(
z
>
32
)
return
-
EINVAL
;
return
-
EINVAL
;
fz
=
table
->
fn_zones
[
z
];
fz
=
table
->
fn_zones
[
z
];
...
@@ -464,136 +490,111 @@ rta->rta_prefsrc ? *(u32*)rta->rta_prefsrc : 0);
...
@@ -464,136 +490,111 @@ rta->rta_prefsrc ? *(u32*)rta->rta_prefsrc : 0);
(
z
==
32
||
(
1
<<
z
)
>
fz
->
fz_divisor
))
(
z
==
32
||
(
1
<<
z
)
>
fz
->
fz_divisor
))
fn_rehash_zone
(
fz
);
fn_rehash_zone
(
fz
);
fp
=
fz_chain_p
(
key
,
fz
);
f
=
fib_find_node
(
fz
,
key
);
fa
=
fib_find_alias
(
f
,
tos
,
fi
->
fib_priority
);
/*
/* Now fa, if non-NULL, points to the first fib alias
* Scan list to find the first route with the same destination
* with the same keys [prefix,tos,priority], if such key already
*/
* exists or to the node before which we will insert new one.
FIB_SCAN
(
f
,
fp
)
{
*
if
(
key
<=
f
->
fn_key
)
* If fa is NULL, we will need to allocate a new one and
break
;
* insert to the head of f.
}
*
* If f is NULL, no fib node matched the destination key
#ifdef CONFIG_IP_ROUTE_TOS
* and we need to allocate a new one of those as well.
/*
* Find route with the same destination and tos.
*/
FIB_SCAN_KEY
(
f
,
fp
,
key
)
{
if
(
f
->
fn_tos
<=
tos
)
break
;
}
#endif
del_fp
=
NULL
;
if
(
f
&&
(
f
->
fn_state
&
FN_S_ZOMBIE
)
&&
#ifdef CONFIG_IP_ROUTE_TOS
f
->
fn_tos
==
tos
&&
#endif
(
f
->
fn_key
==
key
))
{
del_fp
=
fp
;
fp
=
&
f
->
fn_next
;
f
=
*
fp
;
goto
create
;
}
FIB_SCAN_TOS
(
f
,
fp
,
key
,
tos
)
{
if
(
fi
->
fib_priority
<=
FIB_INFO
(
f
)
->
fib_priority
)
break
;
}
/* Now f==*fp points to the first node with the same
keys [prefix,tos,priority], if such key already
exists or to the node, before which we will insert new one.
*/
*/
if
(
f
&&
if
(
fa
&&
#ifdef CONFIG_IP_ROUTE_TOS
fa
->
fa_info
->
fib_priority
==
fi
->
fib_priority
)
{
f
->
fn_tos
==
tos
&&
struct
fib_alias
*
fa_orig
;
#endif
(
f
->
fn_key
==
key
)
&&
fi
->
fib_priority
==
FIB_INFO
(
f
)
->
fib_priority
)
{
struct
fib_node
**
ins_fp
;
err
=
-
EEXIST
;
err
=
-
EEXIST
;
if
(
n
->
nlmsg_flags
&
NLM_F_EXCL
)
if
(
n
->
nlmsg_flags
&
NLM_F_EXCL
)
goto
out
;
goto
out
;
if
(
n
->
nlmsg_flags
&
NLM_F_REPLACE
)
{
if
(
n
->
nlmsg_flags
&
NLM_F_REPLACE
)
{
del_fp
=
fp
;
struct
fib_info
*
fi_drop
;
fp
=
&
f
->
fn_next
;
u8
state
;
f
=
*
fp
;
goto
replace
;
}
ins_fp
=
fp
;
write_lock_bh
(
&
fib_hash_lock
);
err
=
-
EEXIST
;
fi_drop
=
fa
->
fa_info
;
fa
->
fa_info
=
fi
;
fa
->
fa_type
=
type
;
fa
->
fa_scope
=
r
->
rtm_scope
;
state
=
fa
->
fa_state
;
fa
->
fa_state
&=
~
FN_S_ACCESSED
;
write_unlock_bh
(
&
fib_hash_lock
);
FIB_SCAN_TOS
(
f
,
fp
,
key
,
tos
)
{
fib_release_info
(
fi_drop
);
if
(
fi
->
fib_priority
!=
FIB_INFO
(
f
)
->
fib_priority
)
if
(
state
&
FN_S_ACCESSED
)
break
;
rt_cache_flush
(
-
1
);
if
(
f
->
fn_type
==
type
&&
f
->
fn_scope
==
r
->
rtm_scope
return
0
;
&&
FIB_INFO
(
f
)
==
fi
)
goto
out
;
}
}
if
(
!
(
n
->
nlmsg_flags
&
NLM_F_APPEND
))
{
/* Error if we find a perfect match which
fp
=
ins_fp
;
* uses the same scope, type, and nexthop
f
=
*
fp
;
* information.
*/
fa_orig
=
fa
;
list_for_each_entry
(
fa
,
fa
->
fa_list
.
prev
,
fa_list
)
{
if
(
fa
->
fa_info
->
fib_priority
!=
fi
->
fib_priority
)
break
;
if
(
fa
->
fa_type
==
type
&&
fa
->
fa_scope
==
r
->
rtm_scope
&&
fa
->
fa_info
==
fi
)
goto
out
;
}
}
if
(
!
(
n
->
nlmsg_flags
&
NLM_F_APPEND
))
fa
=
fa_orig
;
}
}
create:
err
=
-
ENOENT
;
err
=
-
ENOENT
;
if
(
!
(
n
->
nlmsg_flags
&
NLM_F_CREATE
))
if
(
!
(
n
->
nlmsg_flags
&
NLM_F_CREATE
))
goto
out
;
goto
out
;
replace:
err
=
-
ENOBUFS
;
err
=
-
ENOBUFS
;
new_f
=
kmem_cache_alloc
(
fn_hash
_kmem
,
SLAB_KERNEL
);
new_f
a
=
kmem_cache_alloc
(
fn_alias
_kmem
,
SLAB_KERNEL
);
if
(
new_f
==
NULL
)
if
(
new_f
a
==
NULL
)
goto
out
;
goto
out
;
memset
(
new_f
,
0
,
sizeof
(
struct
fib_node
));
new_f
=
NULL
;
if
(
!
f
)
{
new_f
=
kmem_cache_alloc
(
fn_hash_kmem
,
SLAB_KERNEL
);
if
(
new_f
==
NULL
)
goto
out_free_new_fa
;
new_f
->
fn_key
=
key
;
INIT_HLIST_NODE
(
&
new_f
->
fn_hash
);
#ifdef CONFIG_IP_ROUTE_TOS
INIT_LIST_HEAD
(
&
new_f
->
fn_alias
);
new_f
->
fn_tos
=
tos
;
new_f
->
fn_key
=
key
;
#endif
f
=
new_f
;
new_f
->
fn_type
=
type
;
}
new_f
->
fn_scope
=
r
->
rtm_scope
;
FIB_INFO
(
new_f
)
=
fi
;
new_fa
->
fa_info
=
fi
;
new_fa
->
fa_tos
=
tos
;
new_fa
->
fa_type
=
type
;
new_fa
->
fa_scope
=
r
->
rtm_scope
;
new_fa
->
fa_state
=
0
;
/*
/*
* Insert new entry to the list.
* Insert new entry to the list.
*/
*/
new_f
->
fn_next
=
f
;
write_lock_bh
(
&
fib_hash_lock
);
write_lock_bh
(
&
fib_hash_lock
);
*
fp
=
new_f
;
if
(
new_f
)
fib_insert_node
(
fz
,
new_f
);
list_add
(
&
new_fa
->
fa_list
,
(
fa
?
&
fa
->
fa_list
:
&
f
->
fn_alias
));
write_unlock_bh
(
&
fib_hash_lock
);
write_unlock_bh
(
&
fib_hash_lock
);
fz
->
fz_nent
++
;
if
(
del_fp
)
{
if
(
new_f
)
f
=
*
del_fp
;
fz
->
fz_nent
++
;
/* Unlink replaced node */
rt_cache_flush
(
-
1
);
write_lock_bh
(
&
fib_hash_lock
);
*
del_fp
=
f
->
fn_next
;
write_unlock_bh
(
&
fib_hash_lock
);
if
(
!
(
f
->
fn_state
&
FN_S_ZOMBIE
))
rtmsg_fib
(
RTM_NEWROUTE
,
f
,
new_fa
,
z
,
tb
->
tb_id
,
n
,
req
);
rtmsg_fib
(
RTM_DELROUTE
,
f
,
z
,
tb
->
tb_id
,
n
,
req
);
if
(
f
->
fn_state
&
FN_S_ACCESSED
)
rt_cache_flush
(
-
1
);
fn_free_node
(
f
);
fz
->
fz_nent
--
;
}
else
{
rt_cache_flush
(
-
1
);
}
rtmsg_fib
(
RTM_NEWROUTE
,
new_f
,
z
,
tb
->
tb_id
,
n
,
req
);
return
0
;
return
0
;
out_free_new_fa:
kmem_cache_free
(
fn_alias_kmem
,
new_fa
);
out:
out:
fib_release_info
(
fi
);
fib_release_info
(
fi
);
return
err
;
return
err
;
...
@@ -602,20 +603,16 @@ rta->rta_prefsrc ? *(u32*)rta->rta_prefsrc : 0);
...
@@ -602,20 +603,16 @@ rta->rta_prefsrc ? *(u32*)rta->rta_prefsrc : 0);
static
int
static
int
fn_hash_delete
(
struct
fib_table
*
tb
,
struct
rtmsg
*
r
,
struct
kern_rta
*
rta
,
fn_hash_delete
(
struct
fib_table
*
tb
,
struct
rtmsg
*
r
,
struct
kern_rta
*
rta
,
struct
nlmsghdr
*
n
,
struct
netlink_skb_parms
*
req
)
struct
nlmsghdr
*
n
,
struct
netlink_skb_parms
*
req
)
{
{
struct
fn_hash
*
table
=
(
struct
fn_hash
*
)
tb
->
tb_data
;
struct
fn_hash
*
table
=
(
struct
fn_hash
*
)
tb
->
tb_data
;
struct
fib_node
**
fp
,
**
del_fp
,
*
f
;
struct
fib_node
*
f
;
struct
fib_alias
*
fa
,
*
fa_to_delete
;
int
z
=
r
->
rtm_dst_len
;
int
z
=
r
->
rtm_dst_len
;
struct
fn_zone
*
fz
;
struct
fn_zone
*
fz
;
u32
key
;
u32
key
;
int
matched
;
#ifdef CONFIG_IP_ROUTE_TOS
u8
tos
=
r
->
rtm_tos
;
u8
tos
=
r
->
rtm_tos
;
#endif
FTprint
(
"tb(%d)_delete: %d %08x/%d %d
\n
"
,
tb
->
tb_id
,
r
->
rtm_type
,
rta
->
rta_dst
?
*
(
u32
*
)
rta
->
rta_dst
:
0
,
z
,
rta
->
rta_oif
?
*
rta
->
rta_oif
:
-
1
);
if
(
z
>
32
)
if
(
z
>
32
)
return
-
EINVAL
;
return
-
EINVAL
;
if
((
fz
=
table
->
fn_zones
[
z
])
==
NULL
)
if
((
fz
=
table
->
fn_zones
[
z
])
==
NULL
)
...
@@ -630,61 +627,48 @@ FTprint("tb(%d)_delete: %d %08x/%d %d\n", tb->tb_id, r->rtm_type, rta->rta_dst ?
...
@@ -630,61 +627,48 @@ FTprint("tb(%d)_delete: %d %08x/%d %d\n", tb->tb_id, r->rtm_type, rta->rta_dst ?
key
=
fz_key
(
dst
,
fz
);
key
=
fz_key
(
dst
,
fz
);
}
}
fp
=
fz_chain_p
(
key
,
fz
);
f
=
fib_find_node
(
fz
,
key
);
fa
=
fib_find_alias
(
f
,
tos
,
0
);
if
(
!
fa
)
return
-
ESRCH
;
FIB_SCAN
(
f
,
fp
)
{
fa_to_delete
=
NULL
;
if
(
f
->
fn_key
==
key
)
list_for_each_entry
(
fa
,
fa
->
fa_list
.
prev
,
fa_list
)
{
break
;
struct
fib_info
*
fi
=
fa
->
fa_info
;
if
(
key
<=
f
->
fn_key
)
return
-
ESRCH
;
if
((
!
r
->
rtm_type
||
}
fa
->
fa_type
==
r
->
rtm_type
)
&&
#ifdef CONFIG_IP_ROUTE_TOS
(
r
->
rtm_scope
==
RT_SCOPE_NOWHERE
||
FIB_SCAN_KEY
(
f
,
fp
,
key
)
{
fa
->
fa_scope
==
r
->
rtm_scope
)
&&
if
(
f
->
fn_tos
==
tos
)
(
!
r
->
rtm_protocol
||
fi
->
fib_protocol
==
r
->
rtm_protocol
)
&&
fib_nh_match
(
r
,
n
,
rta
,
fi
)
==
0
)
{
fa_to_delete
=
fa
;
break
;
break
;
}
#endif
matched
=
0
;
del_fp
=
NULL
;
FIB_SCAN_TOS
(
f
,
fp
,
key
,
tos
)
{
struct
fib_info
*
fi
=
FIB_INFO
(
f
);
if
(
f
->
fn_state
&
FN_S_ZOMBIE
)
{
return
-
ESRCH
;
}
}
matched
++
;
if
(
del_fp
==
NULL
&&
(
!
r
->
rtm_type
||
f
->
fn_type
==
r
->
rtm_type
)
&&
(
r
->
rtm_scope
==
RT_SCOPE_NOWHERE
||
f
->
fn_scope
==
r
->
rtm_scope
)
&&
(
!
r
->
rtm_protocol
||
fi
->
fib_protocol
==
r
->
rtm_protocol
)
&&
fib_nh_match
(
r
,
n
,
rta
,
fi
)
==
0
)
del_fp
=
fp
;
}
}
if
(
del_fp
)
{
if
(
fa_to_delete
)
{
f
=
*
del_fp
;
int
kill_fn
;
rtmsg_fib
(
RTM_DELROUTE
,
f
,
z
,
tb
->
tb_id
,
n
,
req
);
if
(
matched
!=
1
)
{
fa
=
fa_to_delete
;
write_lock_bh
(
&
fib_hash_lock
);
rtmsg_fib
(
RTM_DELROUTE
,
f
,
fa
,
z
,
tb
->
tb_id
,
n
,
req
);
*
del_fp
=
f
->
fn_next
;
write_unlock_bh
(
&
fib_hash_lock
);
if
(
f
->
fn_state
&
FN_S_ACCESSED
)
kill_fn
=
0
;
rt_cache_flush
(
-
1
);
write_lock_bh
(
&
fib_hash_lock
);
list_del
(
&
fa
->
fa_list
);
if
(
list_empty
(
&
f
->
fn_alias
))
{
hlist_del
(
&
f
->
fn_hash
);
kill_fn
=
1
;
}
write_unlock_bh
(
&
fib_hash_lock
);
if
(
fa
->
fa_state
&
FN_S_ACCESSED
)
rt_cache_flush
(
-
1
);
fn_free_alias
(
fa
);
if
(
kill_fn
)
{
fn_free_node
(
f
);
fn_free_node
(
f
);
fz
->
fz_nent
--
;
fz
->
fz_nent
--
;
}
else
{
f
->
fn_state
|=
FN_S_ZOMBIE
;
if
(
f
->
fn_state
&
FN_S_ACCESSED
)
{
f
->
fn_state
&=
~
FN_S_ACCESSED
;
rt_cache_flush
(
-
1
);
}
if
(
++
fib_hash_zombies
>
128
)
fib_flush
();
}
}
return
0
;
return
0
;
...
@@ -692,43 +676,53 @@ FTprint("tb(%d)_delete: %d %08x/%d %d\n", tb->tb_id, r->rtm_type, rta->rta_dst ?
...
@@ -692,43 +676,53 @@ FTprint("tb(%d)_delete: %d %08x/%d %d\n", tb->tb_id, r->rtm_type, rta->rta_dst ?
return
-
ESRCH
;
return
-
ESRCH
;
}
}
static
inline
int
static
int
fn_flush_list
(
struct
fn_zone
*
fz
,
int
idx
)
fn_flush_list
(
struct
fib_node
**
fp
,
int
z
,
struct
fn_hash
*
table
)
{
{
int
found
=
0
;
struct
hlist_head
*
head
=
&
fz
->
fz_hash
[
idx
];
struct
hlist_node
*
node
,
*
n
;
struct
fib_node
*
f
;
struct
fib_node
*
f
;
int
found
=
0
;
while
((
f
=
*
fp
)
!=
NULL
)
{
hlist_for_each_entry_safe
(
f
,
node
,
n
,
head
,
fn_hash
)
{
struct
fib_info
*
fi
=
FIB_INFO
(
f
);
struct
fib_alias
*
fa
,
*
fa_node
;
int
kill_f
;
if
(
fi
&&
((
f
->
fn_state
&
FN_S_ZOMBIE
)
||
(
fi
->
fib_flags
&
RTNH_F_DEAD
)))
{
write_lock_bh
(
&
fib_hash_lock
);
kill_f
=
0
;
*
fp
=
f
->
fn_next
;
list_for_each_entry_safe
(
fa
,
fa_node
,
&
f
->
fn_alias
,
fa_list
)
{
write_unlock_bh
(
&
fib_hash_lock
);
struct
fib_info
*
fi
=
fa
->
fa_info
;
if
(
fi
&&
(
fi
->
fib_flags
&
RTNH_F_DEAD
))
{
write_lock_bh
(
&
fib_hash_lock
);
list_del
(
&
fa
->
fa_list
);
if
(
list_empty
(
&
f
->
fn_alias
))
{
hlist_del
(
&
f
->
fn_hash
);
kill_f
=
1
;
}
write_unlock_bh
(
&
fib_hash_lock
);
fn_free_alias
(
fa
);
found
++
;
}
}
if
(
kill_f
)
{
fn_free_node
(
f
);
fn_free_node
(
f
);
found
++
;
fz
->
fz_nent
--
;
continue
;
}
}
fp
=
&
f
->
fn_next
;
}
}
return
found
;
return
found
;
}
}
static
int
fn_hash_flush
(
struct
fib_table
*
tb
)
static
int
fn_hash_flush
(
struct
fib_table
*
tb
)
{
{
struct
fn_hash
*
table
=
(
struct
fn_hash
*
)
tb
->
tb_data
;
struct
fn_hash
*
table
=
(
struct
fn_hash
*
)
tb
->
tb_data
;
struct
fn_zone
*
fz
;
struct
fn_zone
*
fz
;
int
found
=
0
;
int
found
=
0
;
fib_hash_zombies
=
0
;
for
(
fz
=
table
->
fn_zone_list
;
fz
;
fz
=
fz
->
fz_next
)
{
for
(
fz
=
table
->
fn_zone_list
;
fz
;
fz
=
fz
->
fz_next
)
{
int
i
;
int
i
;
int
tmp
=
0
;
for
(
i
=
fz
->
fz_divisor
-
1
;
i
>=
0
;
i
--
)
for
(
i
=
fz
->
fz_divisor
-
1
;
i
>=
0
;
i
--
)
tmp
+=
fn_flush_list
(
&
fz
->
fz_hash
[
i
],
fz
->
fz_order
,
table
);
found
+=
fn_flush_list
(
fz
,
i
);
fz
->
fz_nent
-=
tmp
;
found
+=
tmp
;
}
}
return
found
;
return
found
;
}
}
...
@@ -738,21 +732,36 @@ static inline int
...
@@ -738,21 +732,36 @@ static inline int
fn_hash_dump_bucket
(
struct
sk_buff
*
skb
,
struct
netlink_callback
*
cb
,
fn_hash_dump_bucket
(
struct
sk_buff
*
skb
,
struct
netlink_callback
*
cb
,
struct
fib_table
*
tb
,
struct
fib_table
*
tb
,
struct
fn_zone
*
fz
,
struct
fn_zone
*
fz
,
struct
fib_node
*
f
)
struct
hlist_head
*
head
)
{
{
struct
hlist_node
*
node
;
struct
fib_node
*
f
;
int
i
,
s_i
;
int
i
,
s_i
;
s_i
=
cb
->
args
[
3
];
s_i
=
cb
->
args
[
3
];
for
(
i
=
0
;
f
;
i
++
,
f
=
f
->
fn_next
)
{
i
=
0
;
if
(
i
<
s_i
)
continue
;
hlist_for_each_entry
(
f
,
node
,
head
,
fn_hash
)
{
if
(
f
->
fn_state
&
FN_S_ZOMBIE
)
continue
;
struct
fib_alias
*
fa
;
if
(
fib_dump_info
(
skb
,
NETLINK_CB
(
cb
->
skb
).
pid
,
cb
->
nlh
->
nlmsg_seq
,
RTM_NEWROUTE
,
list_for_each_entry
(
fa
,
&
f
->
fn_alias
,
fa_list
)
{
tb
->
tb_id
,
(
f
->
fn_state
&
FN_S_ZOMBIE
)
?
0
:
f
->
fn_type
,
f
->
fn_scope
,
if
(
i
<
s_i
)
&
f
->
fn_key
,
fz
->
fz_order
,
f
->
fn_tos
,
continue
;
f
->
fn_info
)
<
0
)
{
cb
->
args
[
3
]
=
i
;
if
(
fib_dump_info
(
skb
,
NETLINK_CB
(
cb
->
skb
).
pid
,
return
-
1
;
cb
->
nlh
->
nlmsg_seq
,
RTM_NEWROUTE
,
tb
->
tb_id
,
fa
->
fa_type
,
fa
->
fa_scope
,
&
f
->
fn_key
,
fz
->
fz_order
,
fa
->
fa_tos
,
fa
->
fa_info
)
<
0
)
{
cb
->
args
[
3
]
=
i
;
return
-
1
;
}
i
++
;
}
}
}
}
cb
->
args
[
3
]
=
i
;
cb
->
args
[
3
]
=
i
;
...
@@ -770,10 +779,12 @@ fn_hash_dump_zone(struct sk_buff *skb, struct netlink_callback *cb,
...
@@ -770,10 +779,12 @@ fn_hash_dump_zone(struct sk_buff *skb, struct netlink_callback *cb,
for
(
h
=
0
;
h
<
fz
->
fz_divisor
;
h
++
)
{
for
(
h
=
0
;
h
<
fz
->
fz_divisor
;
h
++
)
{
if
(
h
<
s_h
)
continue
;
if
(
h
<
s_h
)
continue
;
if
(
h
>
s_h
)
if
(
h
>
s_h
)
memset
(
&
cb
->
args
[
3
],
0
,
sizeof
(
cb
->
args
)
-
3
*
sizeof
(
cb
->
args
[
0
]));
memset
(
&
cb
->
args
[
3
],
0
,
if
(
fz
->
fz_hash
==
NULL
||
fz
->
fz_hash
[
h
]
==
NULL
)
sizeof
(
cb
->
args
)
-
3
*
sizeof
(
cb
->
args
[
0
]));
if
(
fz
->
fz_hash
==
NULL
||
hlist_empty
(
&
fz
->
fz_hash
[
h
]))
continue
;
continue
;
if
(
fn_hash_dump_bucket
(
skb
,
cb
,
tb
,
fz
,
fz
->
fz_hash
[
h
])
<
0
)
{
if
(
fn_hash_dump_bucket
(
skb
,
cb
,
tb
,
fz
,
&
fz
->
fz_hash
[
h
])
<
0
)
{
cb
->
args
[
2
]
=
h
;
cb
->
args
[
2
]
=
h
;
return
-
1
;
return
-
1
;
}
}
...
@@ -793,7 +804,8 @@ static int fn_hash_dump(struct fib_table *tb, struct sk_buff *skb, struct netlin
...
@@ -793,7 +804,8 @@ static int fn_hash_dump(struct fib_table *tb, struct sk_buff *skb, struct netlin
for
(
fz
=
table
->
fn_zone_list
,
m
=
0
;
fz
;
fz
=
fz
->
fz_next
,
m
++
)
{
for
(
fz
=
table
->
fn_zone_list
,
m
=
0
;
fz
;
fz
=
fz
->
fz_next
,
m
++
)
{
if
(
m
<
s_m
)
continue
;
if
(
m
<
s_m
)
continue
;
if
(
m
>
s_m
)
if
(
m
>
s_m
)
memset
(
&
cb
->
args
[
2
],
0
,
sizeof
(
cb
->
args
)
-
2
*
sizeof
(
cb
->
args
[
0
]));
memset
(
&
cb
->
args
[
2
],
0
,
sizeof
(
cb
->
args
)
-
2
*
sizeof
(
cb
->
args
[
0
]));
if
(
fn_hash_dump_zone
(
skb
,
cb
,
tb
,
fz
)
<
0
)
{
if
(
fn_hash_dump_zone
(
skb
,
cb
,
tb
,
fz
)
<
0
)
{
cb
->
args
[
1
]
=
m
;
cb
->
args
[
1
]
=
m
;
read_unlock
(
&
fib_hash_lock
);
read_unlock
(
&
fib_hash_lock
);
...
@@ -805,7 +817,8 @@ static int fn_hash_dump(struct fib_table *tb, struct sk_buff *skb, struct netlin
...
@@ -805,7 +817,8 @@ static int fn_hash_dump(struct fib_table *tb, struct sk_buff *skb, struct netlin
return
skb
->
len
;
return
skb
->
len
;
}
}
static
void
rtmsg_fib
(
int
event
,
struct
fib_node
*
f
,
int
z
,
int
tb_id
,
static
void
rtmsg_fib
(
int
event
,
struct
fib_node
*
f
,
struct
fib_alias
*
fa
,
int
z
,
int
tb_id
,
struct
nlmsghdr
*
n
,
struct
netlink_skb_parms
*
req
)
struct
nlmsghdr
*
n
,
struct
netlink_skb_parms
*
req
)
{
{
struct
sk_buff
*
skb
;
struct
sk_buff
*
skb
;
...
@@ -817,8 +830,9 @@ static void rtmsg_fib(int event, struct fib_node* f, int z, int tb_id,
...
@@ -817,8 +830,9 @@ static void rtmsg_fib(int event, struct fib_node* f, int z, int tb_id,
return
;
return
;
if
(
fib_dump_info
(
skb
,
pid
,
n
->
nlmsg_seq
,
event
,
tb_id
,
if
(
fib_dump_info
(
skb
,
pid
,
n
->
nlmsg_seq
,
event
,
tb_id
,
f
->
fn_type
,
f
->
fn_scope
,
&
f
->
fn_key
,
z
,
f
->
fn_tos
,
fa
->
fa_type
,
fa
->
fa_scope
,
&
f
->
fn_key
,
z
,
FIB_INFO
(
f
))
<
0
)
{
fa
->
fa_tos
,
fa
->
fa_info
)
<
0
)
{
kfree_skb
(
skb
);
kfree_skb
(
skb
);
return
;
return
;
}
}
...
@@ -844,7 +858,14 @@ struct fib_table * __init fib_hash_init(int id)
...
@@ -844,7 +858,14 @@ struct fib_table * __init fib_hash_init(int id)
0
,
SLAB_HWCACHE_ALIGN
,
0
,
SLAB_HWCACHE_ALIGN
,
NULL
,
NULL
);
NULL
,
NULL
);
tb
=
kmalloc
(
sizeof
(
struct
fib_table
)
+
sizeof
(
struct
fn_hash
),
GFP_KERNEL
);
if
(
fn_alias_kmem
==
NULL
)
fn_alias_kmem
=
kmem_cache_create
(
"ip_fib_alias"
,
sizeof
(
struct
fib_alias
),
0
,
SLAB_HWCACHE_ALIGN
,
NULL
,
NULL
);
tb
=
kmalloc
(
sizeof
(
struct
fib_table
)
+
sizeof
(
struct
fn_hash
),
GFP_KERNEL
);
if
(
tb
==
NULL
)
if
(
tb
==
NULL
)
return
NULL
;
return
NULL
;
...
@@ -865,64 +886,105 @@ struct fib_table * __init fib_hash_init(int id)
...
@@ -865,64 +886,105 @@ struct fib_table * __init fib_hash_init(int id)
struct
fib_iter_state
{
struct
fib_iter_state
{
struct
fn_zone
*
zone
;
struct
fn_zone
*
zone
;
int
bucket
;
int
bucket
;
struct
fib_node
**
hash
;
struct
hlist_head
*
hash_head
;
struct
fib_node
*
node
;
struct
fib_node
*
fn
;
struct
fib_alias
*
fa
;
};
};
static
inline
struct
fib_node
*
fib_get_first
(
struct
seq_file
*
seq
)
static
struct
fib_alias
*
fib_get_first
(
struct
seq_file
*
seq
)
{
{
struct
fib_iter_state
*
iter
=
seq
->
private
;
struct
fib_iter_state
*
iter
=
seq
->
private
;
struct
fn_hash
*
table
=
(
struct
fn_hash
*
)
ip_fib_main_table
->
tb_data
;
struct
fn_hash
*
table
=
(
struct
fn_hash
*
)
ip_fib_main_table
->
tb_data
;
iter
->
bucket
=
0
;
iter
->
bucket
=
0
;
iter
->
hash
=
NULL
;
iter
->
hash_head
=
NULL
;
iter
->
node
=
NULL
;
iter
->
fn
=
NULL
;
iter
->
fa
=
NULL
;
for
(
iter
->
zone
=
table
->
fn_zone_list
;
iter
->
zone
;
for
(
iter
->
zone
=
table
->
fn_zone_list
;
iter
->
zone
;
iter
->
zone
=
iter
->
zone
->
fz_next
)
{
iter
->
zone
=
iter
->
zone
->
fz_next
)
{
int
maxslot
;
int
maxslot
;
if
(
!
iter
->
zone
->
fz_ne
x
t
)
if
(
!
iter
->
zone
->
fz_ne
n
t
)
continue
;
continue
;
iter
->
hash
=
iter
->
zone
->
fz_hash
;
iter
->
hash
_head
=
iter
->
zone
->
fz_hash
;
maxslot
=
iter
->
zone
->
fz_divisor
;
maxslot
=
iter
->
zone
->
fz_divisor
;
for
(
iter
->
bucket
=
0
;
iter
->
bucket
<
maxslot
;
for
(
iter
->
bucket
=
0
;
iter
->
bucket
<
maxslot
;
++
iter
->
bucket
,
++
iter
->
hash
)
{
++
iter
->
bucket
,
++
iter
->
hash_head
)
{
iter
->
node
=
*
iter
->
hash
;
struct
hlist_node
*
node
;
struct
fib_node
*
fn
;
if
(
iter
->
node
)
goto
out
;
hlist_for_each_entry
(
fn
,
node
,
iter
->
hash_head
,
fn_hash
)
{
struct
fib_alias
*
fa
;
list_for_each_entry
(
fa
,
&
fn
->
fn_alias
,
fa_list
)
{
iter
->
fn
=
fn
;
iter
->
fa
=
fa
;
goto
out
;
}
}
}
}
}
}
out:
out:
return
iter
->
node
;
return
iter
->
fa
;
}
}
static
inline
struct
fib_node
*
fib_get_next
(
struct
seq_file
*
seq
)
static
struct
fib_alias
*
fib_get_next
(
struct
seq_file
*
seq
)
{
{
struct
fib_iter_state
*
iter
=
seq
->
private
;
struct
fib_iter_state
*
iter
=
seq
->
private
;
struct
fib_node
*
fn
;
struct
fib_alias
*
fa
;
/* Advance FA, if any. */
fn
=
iter
->
fn
;
fa
=
iter
->
fa
;
if
(
fa
)
{
BUG_ON
(
!
fn
);
list_for_each_entry_continue
(
fa
,
&
fn
->
fn_alias
,
fa_list
)
{
iter
->
fa
=
fa
;
goto
out
;
}
}
if
(
iter
->
node
)
fa
=
iter
->
fa
=
NULL
;
iter
->
node
=
iter
->
node
->
fn_next
;
if
(
iter
->
node
)
/* Advance FN. */
goto
out
;
if
(
fn
)
{
struct
hlist_node
*
node
=
&
fn
->
fn_hash
;
hlist_for_each_entry_continue
(
fn
,
node
,
fn_hash
)
{
iter
->
fn
=
fn
;
list_for_each_entry
(
fa
,
&
fn
->
fn_alias
,
fa_list
)
{
iter
->
fa
=
fa
;
goto
out
;
}
}
}
fn
=
iter
->
fn
=
NULL
;
/* Advance hash chain. */
if
(
!
iter
->
zone
)
if
(
!
iter
->
zone
)
goto
out
;
goto
out
;
for
(;;)
{
for
(;;)
{
struct
hlist_node
*
node
;
int
maxslot
;
int
maxslot
;
maxslot
=
iter
->
zone
->
fz_divisor
;
maxslot
=
iter
->
zone
->
fz_divisor
;
while
(
++
iter
->
bucket
<
maxslot
)
{
while
(
++
iter
->
bucket
<
maxslot
)
{
iter
->
node
=
*++
iter
->
hash
;
iter
->
hash_head
++
;
if
(
iter
->
node
)
hlist_for_each_entry
(
fn
,
node
,
iter
->
hash_head
,
fn_hash
)
{
goto
out
;
list_for_each_entry
(
fa
,
&
fn
->
fn_alias
,
fa_list
)
{
iter
->
fn
=
fn
;
iter
->
fa
=
fa
;
goto
out
;
}
}
}
}
iter
->
zone
=
iter
->
zone
->
fz_next
;
iter
->
zone
=
iter
->
zone
->
fz_next
;
...
@@ -930,14 +992,19 @@ static inline struct fib_node *fib_get_next(struct seq_file *seq)
...
@@ -930,14 +992,19 @@ static inline struct fib_node *fib_get_next(struct seq_file *seq)
if
(
!
iter
->
zone
)
if
(
!
iter
->
zone
)
goto
out
;
goto
out
;
iter
->
hash
=
iter
->
zone
->
fz_hash
;
iter
->
bucket
=
0
;
iter
->
bucket
=
0
;
iter
->
node
=
*
iter
->
hash
;
iter
->
hash_head
=
iter
->
zone
->
fz_hash
;
if
(
iter
->
node
)
break
;
hlist_for_each_entry
(
fn
,
node
,
iter
->
hash_head
,
fn_hash
)
{
list_for_each_entry
(
fa
,
&
fn
->
fn_alias
,
fa_list
)
{
iter
->
fn
=
fn
;
iter
->
fa
=
fa
;
goto
out
;
}
}
}
}
out:
out:
return
iter
->
node
;
return
fa
;
}
}
static
void
*
fib_seq_start
(
struct
seq_file
*
seq
,
loff_t
*
pos
)
static
void
*
fib_seq_start
(
struct
seq_file
*
seq
,
loff_t
*
pos
)
...
@@ -961,7 +1028,7 @@ static void fib_seq_stop(struct seq_file *seq, void *v)
...
@@ -961,7 +1028,7 @@ static void fib_seq_stop(struct seq_file *seq, void *v)
read_unlock
(
&
fib_hash_lock
);
read_unlock
(
&
fib_hash_lock
);
}
}
static
unsigned
fib_flag_trans
(
int
type
,
int
dead
,
u32
mask
,
struct
fib_info
*
fi
)
static
unsigned
fib_flag_trans
(
int
type
,
u32
mask
,
struct
fib_info
*
fi
)
{
{
static
unsigned
type2flags
[
RTN_MAX
+
1
]
=
{
static
unsigned
type2flags
[
RTN_MAX
+
1
]
=
{
[
7
]
=
RTF_REJECT
,
[
8
]
=
RTF_REJECT
,
[
7
]
=
RTF_REJECT
,
[
8
]
=
RTF_REJECT
,
...
@@ -972,8 +1039,7 @@ static unsigned fib_flag_trans(int type, int dead, u32 mask, struct fib_info *fi
...
@@ -972,8 +1039,7 @@ static unsigned fib_flag_trans(int type, int dead, u32 mask, struct fib_info *fi
flags
|=
RTF_GATEWAY
;
flags
|=
RTF_GATEWAY
;
if
(
mask
==
0xFFFFFFFF
)
if
(
mask
==
0xFFFFFFFF
)
flags
|=
RTF_HOST
;
flags
|=
RTF_HOST
;
if
(
!
dead
)
flags
|=
RTF_UP
;
flags
|=
RTF_UP
;
return
flags
;
return
flags
;
}
}
...
@@ -985,11 +1051,12 @@ static unsigned fib_flag_trans(int type, int dead, u32 mask, struct fib_info *fi
...
@@ -985,11 +1051,12 @@ static unsigned fib_flag_trans(int type, int dead, u32 mask, struct fib_info *fi
*/
*/
static
int
fib_seq_show
(
struct
seq_file
*
seq
,
void
*
v
)
static
int
fib_seq_show
(
struct
seq_file
*
seq
,
void
*
v
)
{
{
struct
fib_iter_state
*
iter
;
struct
fib_iter_state
*
iter
;
char
bf
[
128
];
char
bf
[
128
];
u32
prefix
,
mask
;
u32
prefix
,
mask
;
unsigned
flags
;
unsigned
flags
;
struct
fib_node
*
f
;
struct
fib_node
*
f
;
struct
fib_alias
*
fa
;
struct
fib_info
*
fi
;
struct
fib_info
*
fi
;
if
(
v
==
SEQ_START_TOKEN
)
{
if
(
v
==
SEQ_START_TOKEN
)
{
...
@@ -999,13 +1066,13 @@ static int fib_seq_show(struct seq_file *seq, void *v)
...
@@ -999,13 +1066,13 @@ static int fib_seq_show(struct seq_file *seq, void *v)
goto
out
;
goto
out
;
}
}
f
=
v
;
fi
=
FIB_INFO
(
f
);
iter
=
seq
->
private
;
iter
=
seq
->
private
;
f
=
iter
->
fn
;
fa
=
iter
->
fa
;
fi
=
fa
->
fa_info
;
prefix
=
f
->
fn_key
;
prefix
=
f
->
fn_key
;
mask
=
FZ_MASK
(
iter
->
zone
);
mask
=
FZ_MASK
(
iter
->
zone
);
flags
=
fib_flag_trans
(
f
->
fn_type
,
f
->
fn_state
&
FN_S_ZOMBIE
,
flags
=
fib_flag_trans
(
fa
->
fa_type
,
mask
,
fi
);
mask
,
fi
);
if
(
fi
)
if
(
fi
)
snprintf
(
bf
,
sizeof
(
bf
),
snprintf
(
bf
,
sizeof
(
bf
),
"%s
\t
%08X
\t
%08X
\t
%04X
\t
%d
\t
%u
\t
%d
\t
%08X
\t
%d
\t
%u
\t
%u"
,
"%s
\t
%08X
\t
%08X
\t
%04X
\t
%d
\t
%u
\t
%d
\t
%08X
\t
%d
\t
%u
\t
%u"
,
...
...
net/ipv4/fib_rules.c
View file @
e8ea4873
...
@@ -302,9 +302,7 @@ FRprintk("Lookup: %u.%u.%u.%u <- %u.%u.%u.%u ",
...
@@ -302,9 +302,7 @@ FRprintk("Lookup: %u.%u.%u.%u <- %u.%u.%u.%u ",
for
(
r
=
fib_rules
;
r
;
r
=
r
->
r_next
)
{
for
(
r
=
fib_rules
;
r
;
r
=
r
->
r_next
)
{
if
(((
saddr
^
r
->
r_src
)
&
r
->
r_srcmask
)
||
if
(((
saddr
^
r
->
r_src
)
&
r
->
r_srcmask
)
||
((
daddr
^
r
->
r_dst
)
&
r
->
r_dstmask
)
||
((
daddr
^
r
->
r_dst
)
&
r
->
r_dstmask
)
||
#ifdef CONFIG_IP_ROUTE_TOS
(
r
->
r_tos
&&
r
->
r_tos
!=
flp
->
fl4_tos
)
||
(
r
->
r_tos
&&
r
->
r_tos
!=
flp
->
fl4_tos
)
||
#endif
#ifdef CONFIG_IP_ROUTE_FWMARK
#ifdef CONFIG_IP_ROUTE_FWMARK
(
r
->
r_fwmark
&&
r
->
r_fwmark
!=
flp
->
fl4_fwmark
)
||
(
r
->
r_fwmark
&&
r
->
r_fwmark
!=
flp
->
fl4_fwmark
)
||
#endif
#endif
...
...
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