1) Forwarding (fib_table) is an index table that records IP forwarding information, and each record (node) that is forwarded is a description of which output device the IP packet with a certain type of destination address should use to which destination host. The forwarding record is classified by the network area, and each network area describes the forward information of the destination address with different network numbers under the specific network address bit length. The No. 0 Zone has a network address length of 0, matches all IP addresses, describes the default gateway, and the 32nd Zone has a network address bit length of 32, which matches the full IP address. When the network area is set up, they are arranged in the order of the network address bits from large to small, and when searching the IP address, first match from the 32nd area of the whole host address, and the last No. 0 zone matches all the addresses, resulting in the default gateway.
2) The system uses at least two forwarding posts, one is a partial forwarding, describes the forwarding information that matches all local addresses, and the other is the primary forwarding post, which describes the forward information that matches the external address. The specified forwarding table can be selected through the policy tables.
; NET/IPV4/FIB_RULES.C FIB_FRONTEND.C fib_hash.c FIB_SEMANTICS.C
static struct Fib_rule *fib_rules = &local_rule; Forwarding Policy chain List
static struct Fib_rule Default_rule = {NULL, atomic_init (2), 0x7FFF, Rt_table_default, Rtn_unicast,};
static struct Fib_rule Main_rule = {&default_rule, atomic_init (2), 0x7ffe, Rt_table_main, Rtn_unicast,};
static struct Fib_rule Local_rule = {&main_rule, atomic_init (2), 0, Rt_table_local, Rtn_unicast,};
int fib_lookup (const struct Rt_key *key, struct fib_result *res)
{
int err;
struct Fib_rule *r, *policy;
struct fib_table *TB;
U32 daddr = key->dst;
U32 saddr = key->src;
FRPRINTK ("Lookup:%u.%u.%u.%u <-%u.%u.%u.%u",
Nipquad (KEY->DST), Nipquad (KEY->SRC));
Read_lock (&fib_rules_lock);
for (r = fib_rules; r; r=r->r_next) {Scan policy table
if (((SADDR^R->R_SRC) & R->r_srcmask) | | If the source address does not match
((DADDR^R->R_DST) & R->r_dstmask) | | Or the destination address does not match
#ifdef Config_ip_route_tos
(R->r_tos && R->r_tos! = Key->tos) | | or service type
#endif
#ifdef Config_ip_route_fwmark
(R->r_fwmark && R->r_fwmark! = Key->fwmark) | | or forwarding tags are not equal
#endif
(R->r_ifindex && R->r_ifindex! = key->iif)) Or the input device is not equal
Continue Next strategy
FRPRINTK ("TB%d R%d", R->r_table, r->r_action);
Switch (r->r_action) {action represented by policy
Case Rtn_unicast: Monocular forwarding
Case Rtn_nat: Address transformation forwarding
Policy = R; Get a matching policy
Break
Case Rtn_unreachable: Unreachable forwarding
Read_unlock (&fib_rules_lock);
Return-enetunreach;
Default
Case Rtn_blackhole: Forwarding to a black hole
Read_unlock (&fib_rules_lock);
Return-einval;
Case Rtn_prohibit: Disable forwarding
Read_unlock (&fib_rules_lock);
Return-eacces;
}
if (TB = fib_get_table (r->r_table)) = = NULL) fetch policy corresponding to the forwarding publication
Continue
Err = Tb->tb_lookup (TB, key, RES); Find a forwarding Post
if (err = = 0) {Query succeeded
Res->r = policy; Set the policy table address in the forwarding message
if (policy)
Atomic_inc (&POLICY->R_CLNTREF); Referencing the policy table
Read_unlock (&fib_rules_lock);
return 0;
}
if (Err < 0 && Err! =-eagain) {
Read_unlock (&fib_rules_lock);
return err; Error
}
}
FRPRINTK ("failure\n");
Read_unlock (&fib_rules_lock);
Return-enetunreach;
}
Static inline struct fib_table *fib_get_table (int id)
{
if (id = = 0)
id = rt_table_main;
return Fib_tables[id];
}
Static inline struct fib_table *fib_new_table (int id)
{
if (id = = 0) No. 0 forwarding is the main forwarding post
id = rt_table_main;
Return Fib_tables[id]? : __fib_new_table (ID);
}
struct fib_table *__fib_new_table (int id)
{
struct fib_table *TB;
TB = Fib_hash_init (ID);
if (!TB)
return NULL;
Fib_tables[id] = TB;
return TB;
}
/* Reserved Table identifiers */
Enum rt_class_t
{
Rt_table_unspec=0,
/* User defined values */
rt_table_default=253,
rt_table_main=254,
rt_table_local=255
};
#define RT_TABLE_MAX rt_table_local
struct fib_table *fib_tables[rt_table_max+1]; Go to the Post array
#ifdef Config_ip_multiple_tables
struct fib_table * fib_hash_init (int id)
#else
struct fib_table * __init fib_hash_init (int id)
#endif
{
struct fib_table *TB;
if (Fn_hash_kmem = = NULL)
Fn_hash_kmem = Kmem_cache_create ("Ip_fib_hash",
sizeof (struct fib_node),
0, Slab_hwcache_align,
NULL, NULL);
TB = kmalloc (sizeof (struct fib_table) + sizeof (struct fn_hash), gfp_kernel);
if (tb = = NULL) Assign a forwarding operation structure and index structure
return NULL;
tb->tb_id = ID;
Tb->tb_lookup = Fn_hash_lookup; Retrieving a forwarding Post
Tb->tb_insert = Fn_hash_insert; Insert a forwarding post record
Tb->tb_delete = Fn_hash_delete; Delete a forwarding post record
Tb->tb_flush = Fn_hash_flush; Invalid record of scrubbing and forwarding
Tb->tb_select_default = Fn_hash_select_default; Select the default forwarding information
#ifdef Config_rtnetlink
Tb->tb_dump = Fn_hash_dump; Dump a forwarding post record to a link socket
#endif
#ifdef CONFIG_PROC_FS
Tb->tb_get_info = Fn_hash_get_info; Display forwarding information from the proc file system
#endif
memset (tb->tb_data, 0, sizeof (struct fn_hash)); Clear the hash disk
return TB;
}
static int
Fn_hash_lookup (struct fib_table *tb, const struct Rt_key *key, struct fib_result *res)
{
int err;
struct Fn_zone *fz;
struct Fn_hash *t = (struct fn_hash*) tb->tb_data;
Read_lock (&fib_hash_lock);
for (FZ = t->fn_zone_list; FZ; FZ = fz->fz_next) {Scan network area
struct Fib_node *f;
fn_key_t k = Fz_key (KEY->DST, FZ); The network number of the destination address in the network area
for (f = fz_chain (k, FZ); f; f = f->fn_next) {Scan the hash chain of the network number
if (!fn_key_eq (k, F->fn_key)) {If the network number is not equal to the link section
if (Fn_key_leq (k, F->fn_key)) If the network number is smaller than the network number of the link section (the hash chain is ordered from small to large by network number)
Break Next forwarding Area
Else
Continue Next chain section
}
; Search for nodes with network numbers equal
#ifdef Config_ip_route_tos
if (F->fn_tos && f->fn_tos! = Key->tos) If their service type is not equal
Continue Next chain section
#endif
F->fn_state |= fn_s_accessed; Access token
if (F->fn_state&fn_s_zombie) if the node is not valid
Continue Next chain section
if (F->fn_scope < key->scope) If the forwarding domain value of the node is less than the requested forwarding domain value (or the node's forwarding domain is greater than the requested forwarding domain)
Continue Next chain section
Err = Fib_semantic_match (F->fn_type, Fib_info (f), key, RES); Further matching with node forwarding information
if (err = = 0) {Match succeeded
Res->type = f->fn_type; Output Forwarding Type
Res->scope = f->fn_scope; Output forwarding Domain
Res->prefixlen = fz->fz_order; Output the area network address occupies a long position
Goto out; Return
}
if (Err < 0)
Goto out;
}
}
Err = 1;
Out
Read_unlock (&fib_hash_lock);
return err;
}
static struct
{
int error;
U8 Scope;
} Fib_props[rta_max+1] = {
{0, Rt_scope_nowhere},/* Rtn_unspec */cannot be forwarded
{0, Rt_scope_universe},/* rtn_unicast */network-wide forwarding
{0, Rt_scope_host},/* rtn_local */Native range forwarding
{0, Rt_scope_link},/* Rtn_broadcast */Device range forwarding
{0, Rt_scope_link},/* Rtn_anycast */
{0, Rt_scope_universe},/* Rtn_multicast */
{-einval, Rt_scope_universe},/* Rtn_blackhole */
{-ehostunreach, rt_scope_universe},/* rtn_unreachable * *
{-eacces, Rt_scope_universe},/* Rtn_prohibit */
{-eagain, Rt_scope_universe},/* Rtn_throw */
#ifdef Config_ip_route_nat
{0, Rt_scope_host},/* Rtn_nat */
#else
{-einval, Rt_scope_nowhere},/* Rtn_nat */
#endif
{-einval, Rt_scope_nowhere}/* Rtn_xresolve */
};
#define FIB_RES_NH (RES) (res). fi->fib_nh[(res). Nh_sel])
#define FIB_RES_RESET (RES) (res). Nh_sel = 0)
#define For_nexthops (FI) {int nhsel; const struct FIB_NH * NH;
For (nhsel=0, NH = (FI)->fib_nh; Nhsel < (FI)->fib_nhs; nh++, nhsel++)
Int
Fib_semantic_match (int type, struct fib_info *fi, const struct Rt_key *key, struct fib_result *res)
{
int err = Fib_props[type].error; Fetch forwarding Type error code
if (err = = 0) {allowed forwarding type
if (fi->fib_flags&rtnh_f_dead) if the forwarding node does not pass
return 1;
Res->fi = fi; Output forwarding node information
Switch (type) {
#ifdef Config_ip_route_nat
Case Rtn_nat: Address transformation forwarding
Fib_res_reset (*res); Reset forwarding Address Select number
Atomic_inc (&FI->FIB_CLNTREF);
return 0;
#endif
Case Rtn_unicast: Monocular forwarding
Case rtn_local: Local forwarding
Case RTN_BROADCAST: Broadcast forwarding
Case Rtn_anycast: Any forwarding
Case RTN_MULTICAST: Multi-purpose forwarding
For_nexthops (FI) {For each forwarding address in the forwarding message
if (nh->nh_flags&rtnh_f_dead) if the forwarding address does not pass
Continue Next forwarding Address
if (!key->oif | | key->oif = = nh->nh_oif) match the forwarding address of the output device
Break Match success
}
#ifdef Config_ip_route_multipath multipath Routing
if (Nhsel < FI->FIB_NHS) {
Res->nh_sel = Nhsel; Output forwarding Address number
Atomic_inc (&FI->FIB_CLNTREF);
return 0; Successful return
}
#else
if (Nhsel < 1) {Non-multipath routing forwarding address number must be less than 1
Atomic_inc (&FI->FIB_CLNTREF);
return 0; Successful return
}
#endif
Endfor_nexthops (FI);
Res->fi = NULL;
return 1; Match failed
Default
Res->fi = NULL;
PRINTK (kern_debug "Impossible 102\n");
Return-einval;
}
}
return err;
}
The retrieval process for Linux routing forwarding (fib_lookup)