Excerpt from: http://blog.chinaunix.net/uid-20788636-id-4398392.html
Impact analysis of Ip_forward parameters on Linux kernel forwarding 2014-08-07 20:40:59
Category: LINUX
In the Linux kernel forwarding, you need to set the forwarded parameters in the Proc/sys directory of the proc file system, and you can use the following method to view the value Cat/proc/sys/net/ipv4/ip_forward of the parameter, which defaults to 0. You can use the following method to modify this value to enable the data in the IP layer of the Linux kernel to be scratched, but the following method will not take effect until the system restarts.
Echo 1 >/proc/sys/net/ipv4/ip_forward
The Linux system also provides a system Configuration tool sysctl, which can be used to read and configure some of the parameters of the Linux kernel. However, this method is related to the proc file system, and the Linux kernel of the tool needs to support the proc file system. The following is a forwarding parameter that uses SYSCTL to configure the kernel.
# sysctl Net.ipv4.ip_forward
Net.ipv4.ip_forward = 0
/# Sysctl-w Net.ipv4.ip_forward=1
Net.ipv4.ip_forward = 1
/# Sysctl Net.ipv4.ip_forward
Net.ipv4.ip_forward = 1
/ #
Note that the parameter net.ipv4.ip_forward is actually the corresponding proc directory/proc/sys/net/ipv4/ip_forward, option-W indicates that the kernel configuration parameter is configured, there is no option to read kernel configuration parameters, without any option information, Represents a read operation.
The above method allows us to set and read the IP forwarding parameters. However, the focus of this article is not on how this parameter is configured, but how it will work during the forwarding of the kernel after the configuration is complete, and how to configure it into the kernel. Since this parameter is configured to enable forwarding of the IP layer, it should be judged in the forwarding part of the Linux kernel, which is actually judged in the lookup route, and the following diagram shows the invocation relationship,
In the process of Challo, if the packet being forwarded calls the following macro to determine whether the forwarded parameter is open. In the function Ip_route_input_slow.
if (! In_dev_forward (In_dev))
Goto E_hostunreach;
Take a look at how the macro is defined, and the following macro is defined in the Include/linux/inetdevice.h file.
#define In_dev_forward (In_dev) in_dev_conf_get ((In_dev), forwarding)
In the further expansion of the In_dev_conf_get macro look:
#define In_dev_conf_get (In_dev, attr) \
Ipv4_devconf_get (In_dev), Net_ipv4_conf_ # attr)//Here's # #表示连接两个字符串.
The following is the definition of the Ipv4_devconf_get function:
static inline int ipv4_devconf_get (struct in_device *in_dev, int index)
{
index--;//here the index is equivalent to net_ipv4_conf_forwarding
Return in_dev->cnf.data[index];//Init_net->ipv4.devconf_dfl.data[0]
}
(1) The macro net_ipv4_conf_ forwarding, defined in the Include/linux/sysctl.h file, is an enumerated type.
Enum
{
Net_ipv4_conf_forwarding=1,
net_ipv4_conf_mc_forwarding=2,
Net_ipv4_conf_proxy_arp=3,
Net_ipv4_conf_accept_redirects=4,
Net_ipv4_conf_secure_redirects=5,
Net_ipv4_conf_send_redirects=6,
Net_ipv4_conf_shared_media=7,
Net_ipv4_conf_rp_filter=8,
Net_ipv4_conf_accept_source_route=9,
NET_IPV4_CONF_BOOTP_RELAY=10,
Net_ipv4_conf_log_martians=11,
NET_IPV4_CONF_TAG=12,
Net_ipv4_conf_arpfilter=13,
Net_ipv4_conf_medium_id=14,
Net_ipv4_conf_noxfrm=15,
Net_ipv4_conf_nopolicy=16,
Net_ipv4_conf_force_igmp_version=17,
Net_ipv4_conf_arp_announce=18,
Net_ipv4_conf_arp_ignore=19,
Net_ipv4_conf_promote_secondaries=20,
Net_ipv4_conf_arp_accept=21,
Net_ipv4_conf_arp_notify=22,
Net_ipv4_conf_src_vmark=24,
__net_ipv4_conf_max
};
(2) for return in_dev->cnf.data[index]; the equivalent of in_dev->cnf.data[0], let's look at how the initial value is generated.
First, how In_dev is acquired, in the Ip_route_input_slow function, through struct in_device *in_dev = in_dev_get (dev); function fetch, call in_dev_get in the __in_dev function _GET_RCU, the assignment struct in_device *in_dev = dev->ip_ptr; by the following assignment statement
Static inline struct In_device *__in_dev_get_rcu (const struct Net_device)
{
struct In_device *in_dev = dev->ip_ptr;
if (In_dev)
In_dev = Rcu_dereference (In_dev);
return In_dev;
}
static __inline__ struct In_device *
In_dev_get (const struct Net_device *dev)
{
struct In_device *in_dev;
Rcu_read_lock ();
In_dev = __in_dev_get_rcu (dev);
if (In_dev)
Atomic_inc (&IN_DEV->REFCNT);
Rcu_read_unlock ();
return In_dev;
}
When is dev->ip_ptr; to be assigned a value? The answer is in the Net_device registration initialization function Inetdev_init,
static struct In_device *inetdev_init (struct net_device *dev)
{
struct In_device *in_dev;
ASSERT_RTNL ();
In_dev = Kzalloc (sizeof (*in_dev), Gfp_kernel);
if (!in_dev)
Goto out;
memcpy (&in_dev->cnf, dev_net (Dev)->ipv4.devconf_dflt,
sizeof (IN_DEV->CNF))//This initializes the IN_DEV->CNT,---(1)
In_dev->cnf.sysctl = NULL;
In_dev->dev = Dev;
if ((in_dev->arp_parms = Neigh_parms_alloc (Dev, &arp_tbl)) = = NULL)
Goto Out_kfree;
if (ipv4_devconf (in_dev->cnf, forwarding))
Dev_disable_lro (Dev);
/* Reference In_dev->dev * *
Dev_hold (Dev);
/* Account for reference dev->ip_ptr (below) * *
In_dev_hold (In_dev);
Devinet_sysctl_register (In_dev);
Ip_mc_init_dev (In_dev);
if (Dev->flags & iff_up)
IP_MC_UP (In_dev);
/* We can receive as soon as IP_PTR is set-does this last * *
Rcu_assign_pointer (Dev->ip_ptr, In_dev);//use RCU protection lock mechanism to assign values to Dev->ip_ptr
Out
return In_dev;
Out_kfree:
Kfree (In_dev);
In_dev = NULL;
Goto out;
}
(1) dev_net (Dev)->IPV4.DEVCONF_DFL is also equivalent to INIT_NET->IPV4.DEVCONF_DFL, while DEVCONF_DFL initialization occurs in/net/ipv4/ devinet.c file, in the Devinet_init_net function,
static struct ipv4_devconf Ipv4_devconf_dflt = {
. data = {
[Net_ipv4_conf_accept_redirects-1] = 1,
[Net_ipv4_conf_send_redirects-1] = 1,
[Net_ipv4_conf_secure_redirects-1] = 1,
[Net_ipv4_conf_shared_media-1] = 1,
[Net_ipv4_conf_accept_source_route-1] = 1,
},
};//there is no assignment to forwarding
static __net_init int devinet_init_net (struct net *net)
{
int err;
struct ipv4_devconf *all, *dflt;
#ifdef CONFIG_SYSCTL
struct ctl_table *tbl = ctl_forward_entry;
struct Ctl_table_header *forw_hdr;
#endif
err =-enomem;
all = &ipv4_devconf; ----------------------------Initialize the operation
Dflt = &ipv4_devconf_dflt;
if (net!= &init_net) {
all = Kmemdup (all, sizeof (ipv4_devconf), Gfp_kernel);
if (all = NULL)
&nb