This commit is contained in:
gatieme
2016-09-06 11:00:22 +08:00
parent 284689f848
commit e2c7456c2a
6 changed files with 195 additions and 268 deletions
+125 -4
View File
@@ -262,17 +262,91 @@ struct sk_buff
![套接字缓冲区在各个协议层之间传递时,对缓冲区的操作](../images/trans_data.png)
在字长32位的系统上,数据类型sk_buff_data_t用来表示各种类型为简单指针的数据, 定义在[`include/linux/skbuff.h?v=4.7, line 626`](http://lxr.free-electrons.com/source/include/linux/skbuff.h?v=4.7#L626), 在64位 CPU上, 可使用一点小技巧来节省一些空间。sk_buff_data_t的定义改为整型变量
内核实现了一些宏用来获取缓冲区数据段的结束位置. 这些函数定义在[`include/linux/skbuff.h?v=4.7, line 1165`](http://lxr.free-electrons.com/source/include/linux/skbuff.h?v=4.7#L1165)
```cpp
#ifdef NET_SKBUFF_DATA_USES_OFFSET
typedef unsigned int sk_buff_data_t;
static inline unsigned char *skb_end_pointer(const struct sk_buff *skb)
{
return skb->head + skb->end;
}
static inline unsigned int skb_end_offset(const struct sk_buff *skb)
{
return skb->end;
}
#else
typedef unsigned char *sk_buff_data_t;
static inline unsigned char *skb_end_pointer(const struct sk_buff *skb)
{
return skb->end;
}
static inline unsigned int skb_end_offset(const struct sk_buff *skb)
{
return skb->end - skb->head;
}
#endif
```
套接字缓冲区需要很多指针来表示缓冲区中内容的不同部分. 由于网络子系统必须保证较低的内存占用和较高的处理速度, 因而对struct sk_buff来说,我们需要保持该结构的长度尽可能小.
内核实现了一些宏用来获取协议数据区域的结束的结束位置tail的函数. 这些函数定义在[`include/linux/skbuff.h?v=4.7, line 1849`](http://lxr.free-electrons.com/source/include/linux/skbuff.h?v=4.7#L1849)
```cpp
#ifdef NET_SKBUFF_DATA_USES_OFFSET /* 64 bit */
static inline unsigned char *skb_tail_pointer(const struct sk_buff *skb)
{
return skb->head + skb->tail;
}
static inline void skb_reset_tail_pointer(struct sk_buff *skb)
{
skb->tail = skb->data - skb->head;
}
static inline void skb_set_tail_pointer(struct sk_buff *skb, const int offset)
{
skb_reset_tail_pointer(skb);
skb->tail += offset;
}
#else /* NET_SKBUFF_DATA_USES_OFFSET */
static inline unsigned char *skb_tail_pointer(const struct sk_buff *skb)
{
return skb->tail;
}
static inline void skb_reset_tail_pointer(struct sk_buff *skb)
{
skb->tail = skb->data;
}
static inline void skb_set_tail_pointer(struct sk_buff *skb, const int offset)
{
skb->tail = skb->data + offset;
}
#endif /* NET_SKBUFF_DATA_USES_OFFSET */
```
在字长32位的系统上,数据类型sk_buff_data_t用来表示各种类型为简单指针的数据(`char *`), 定义在[`include/linux/skbuff.h?v=4.7, line 487`](http://lxr.free-electrons.com/source/include/linux/skbuff.h?v=4.7#L487), 在64位 CPU上, 可使用一点小技巧来节省一些空间. `sk_buff_data_t`的定义改为整型变量
```cpp
#if BITS_PER_LONG > 32 /* 64位的linux系统中long是8个字节 > 4 */
#define NET_SKBUFF_DATA_USES_OFFSET 1
#endif
#ifdef NET_SKBUFF_DATA_USES_OFFSET /* 64位系统 */
typedef unsigned int sk_buff_data_t; /* 4个字节 */
#else /* 32位系统 */
typedef unsigned char *sk_buff_data_t; /* 4个字节 */
#endif
```
套接字缓冲区需要很多指针来表示缓冲区中内容的不同部分. 由于网络子系统必须保证较低的内存占用和较高的处理速度, 因而对`struct sk_buff`来说,我们需要保持该结构的长度尽可能小.
@@ -447,3 +521,50 @@ struct sk_buff_head {
分组通常放置在等待队列中,例如分组等待处理时,或需要重新组合已经分析过的分组时.
![通过双链表管理套接字缓冲区](../images/dou_link.png)
##4.3.3 skb_shared_info结构体
-------
内核`skb_shared_info`结构体该类型用来管理数据包分片信息, 该结构定义在[`include/linux/skbuff.h?v=4.7, line 408`](http://lxr.free-electrons.com/source/include/linux/skbuff.h?v=4.7#L408)
```cpp
/* This data is invariant across clones and lives at
* the end of the header data, ie. at skb->end.
*/
struct skb_shared_info {
unsigned char nr_frags;
__u8 tx_flags;
unsigned short gso_size; /* 尺寸 */
/* Warning: this field is not always filled in (UFO)! */
unsigned short gso_segs; /* 顺序 */
unsigned short gso_type;
struct sk_buff *frag_list;
struct skb_shared_hwtstamps hwtstamps; /* 硬件时间戳 */
u32 tskey;
__be32 ip6_frag_id;
/*
* Warning : all fields before dataref are cleared in __alloc_skb()
*/
atomic_t dataref; /* 使用计数 */
/* Intermediate layers must ensure that destructor_arg
* remains valid until skb destructor */
void * destructor_arg;
/* must be last field, see pskb_expand_head() */
skb_frag_t frags[MAX_SKB_FRAGS];
};
```
通过宏可以表示与skb的关系
```cpp
/* Internal */
#define skb_shinfo(SKB) ((struct skb_shared_info *)(skb_end_pointer(SKB)))
```
+23 -4
View File
@@ -28,10 +28,10 @@ IP在1981年正式定义(在RFC791中), 现在已经进入暮年
-------
IP分组使用的协议首部如图12-14所示.
IP分组使用的协议首部如图所示.
![图12-14 IP首部的结构](../images/)
![图12-14 IP首部的结构](./images/ip_header.png)
| 字段 | 描述 |
@@ -87,9 +87,28 @@ struct iphdr {
`ip_rcv`函数是网络层的入口点. 分组向上穿过内核的路线如下图所示
![图12-15 分组穿过互联网络层的路线](../images/)
![图12-15 分组穿过互联网络层的路线](./images/route.png)
该函数定义在[`net/ipv4/ip_input.c?v=4.7, line 405`](http://lxr.free-electrons.com/source/net/ipv4/ip_input.c?v=4.7#L405)
| 函数 | 功能 | 定义 |
|:-----:|:-----:|:-----:|
| ip_rcv | 对驱动送上来的数据报文进行ip头的合法性检查, 并调用netfilter过滤器上NF_INET_PRE_ROUTING | [net/ipv4/ip_input.c?v=4.7, line 405](http://lxr.free-electrons.com/source/net/ipv4/ip_input.c?v=4.7#L405) |
| ip_local_deliver | | [net/ipv4/ip_input.c?v=4.7, line 192](http://lxr.free-electrons.com/source/net/ipv4/ip_input.c?v=4.7#L192) |
<br>
| 函数 | 功能 | 定义 |
|:-----:|:-----:|:-----:|
| ip_queue_xmit | | [net/ipv4/ip_output.c?v=4.7, line 376](http://lxr.free-electrons.com/source/net/ipv4/ip_output.c?v=4.7#L376) |
| ip_output | | [net/ipv4/ip_output.c?v=4.7, line 346](http://lxr.free-electrons.com/source/net/ipv4/ip_output.c?v=4.7#L346) |
```cpp
```
发送和接收操作的程序流程并不总是分离的, 如果分组只通过当前计算机转发, 那么发送和接收操作是交织的. 这种分组不会传递到更高的协议层(或应用程序), 而是立即离开计算机, 发往新的目的地.
@@ -99,7 +118,7 @@ struct iphdr {
-------
在分组(以及对应的套接字缓冲区其中的指针已经设置了适当的值转发到ip_rcv之后 必须检查接收到的信息 确保它是正确的 主要检查计算的校验和与首部中存储的校验和是否一致.
在分组(以及对应的套接字缓冲区, 其中的指针已经设置了适当的值)转发到ip_rcv之后, 必须检查接收到的信息, 确保它是正确的. 主要检查计算的校验和与首部中存储的校验和是否一致.
其他的检查包括分组是否达到了IP首部的最小长度,分组的协议是否确实是IPv4(IPv6的接收例程是另一个).
Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

-260
View File
@@ -1,260 +0,0 @@
struct net_device {
char name[IFNAMSIZ];
struct hlist_node name_hlist;
char *ifalias;
/*
* I/O specific fields
* FIXME: Merge these and struct ifmap into one
*/
unsigned long mem_end;
unsigned long mem_start;
unsigned long base_addr;
int irq;
atomic_t carrier_changes;
/*
* Some hardware also needs these fields (state,dev_list,
* napi_list,unreg_list,close_list) but they are not
* part of the usual set specified in Space.c.
*/
unsigned long state;
struct list_head dev_list;
struct list_head napi_list;
struct list_head unreg_list;
struct list_head close_list;
struct list_head ptype_all;
struct list_head ptype_specific;
struct {
struct list_head upper;
struct list_head lower;
} adj_list;
struct {
struct list_head upper;
struct list_head lower;
} all_adj_list;
netdev_features_t features;
netdev_features_t hw_features;
netdev_features_t wanted_features;
netdev_features_t vlan_features;
netdev_features_t hw_enc_features;
netdev_features_t mpls_features;
netdev_features_t gso_partial_features;
int ifindex;
int group;
struct net_device_stats stats;
atomic_long_t rx_dropped;
atomic_long_t tx_dropped;
atomic_long_t rx_nohandler;
#ifdef CONFIG_WIRELESS_EXT
const struct iw_handler_def *wireless_handlers;
struct iw_public_data *wireless_data;
#endif
const struct net_device_ops *netdev_ops;
const struct ethtool_ops *ethtool_ops;
#ifdef CONFIG_NET_SWITCHDEV
const struct switchdev_ops *switchdev_ops;
#endif
#ifdef CONFIG_NET_L3_MASTER_DEV
const struct l3mdev_ops *l3mdev_ops;
#endif
const struct header_ops *header_ops;
unsigned int flags;
unsigned int priv_flags;
unsigned short gflags;
unsigned short padded;
unsigned char operstate;
unsigned char link_mode;
unsigned char if_port;
unsigned char dma;
unsigned int mtu;
unsigned short type;
unsigned short hard_header_len;
unsigned short needed_headroom;
unsigned short needed_tailroom;
/* Interface address info. */
unsigned char perm_addr[MAX_ADDR_LEN];
unsigned char addr_assign_type;
unsigned char addr_len;
unsigned short neigh_priv_len;
unsigned short dev_id;
unsigned short dev_port;
spinlock_t addr_list_lock;
unsigned char name_assign_type;
bool uc_promisc;
struct netdev_hw_addr_list uc;
struct netdev_hw_addr_list mc;
struct netdev_hw_addr_list dev_addrs;
#ifdef CONFIG_SYSFS
struct kset *queues_kset;
#endif
unsigned int promiscuity;
unsigned int allmulti;
/* Protocol-specific pointers */
#if IS_ENABLED(CONFIG_VLAN_8021Q)
struct vlan_info __rcu *vlan_info;
#endif
#if IS_ENABLED(CONFIG_NET_DSA)
struct dsa_switch_tree *dsa_ptr;
#endif
#if IS_ENABLED(CONFIG_TIPC)
struct tipc_bearer __rcu *tipc_ptr;
#endif
void *atalk_ptr;
struct in_device __rcu *ip_ptr;
struct dn_dev __rcu *dn_ptr;
struct inet6_dev __rcu *ip6_ptr;
void *ax25_ptr;
struct wireless_dev *ieee80211_ptr;
struct wpan_dev *ieee802154_ptr;
#if IS_ENABLED(CONFIG_MPLS_ROUTING)
struct mpls_dev __rcu *mpls_ptr;
#endif
/*
* Cache lines mostly used on receive path (including eth_type_trans())
*/
unsigned long last_rx;
/* Interface address info used in eth_type_trans() */
unsigned char *dev_addr;
#ifdef CONFIG_SYSFS
struct netdev_rx_queue *_rx;
unsigned int num_rx_queues;
unsigned int real_num_rx_queues;
#endif
unsigned long gro_flush_timeout;
rx_handler_func_t __rcu *rx_handler;
void __rcu *rx_handler_data;
#ifdef CONFIG_NET_CLS_ACT
struct tcf_proto __rcu *ingress_cl_list;
#endif
struct netdev_queue __rcu *ingress_queue;
#ifdef CONFIG_NETFILTER_INGRESS
struct list_head nf_hooks_ingress;
#endif
unsigned char broadcast[MAX_ADDR_LEN];
#ifdef CONFIG_RFS_ACCEL
struct cpu_rmap *rx_cpu_rmap;
#endif
struct hlist_node index_hlist;
/*
* Cache lines mostly used on transmit path
*/
struct netdev_queue *_tx ____cacheline_aligned_in_smp;
unsigned int num_tx_queues;
unsigned int real_num_tx_queues;
struct Qdisc *qdisc;
unsigned long tx_queue_len;
spinlock_t tx_global_lock;
int watchdog_timeo;
#ifdef CONFIG_XPS
struct xps_dev_maps __rcu *xps_maps;
#endif
#ifdef CONFIG_NET_CLS_ACT
struct tcf_proto __rcu *egress_cl_list;
#endif
#ifdef CONFIG_NET_SWITCHDEV
u32 offload_fwd_mark;
#endif
/* These may be needed for future network-power-down code. */
struct timer_list watchdog_timer;
int __percpu *pcpu_refcnt;
struct list_head todo_list;
struct list_head link_watch_list;
enum { NETREG_UNINITIALIZED=0,
NETREG_REGISTERED, /* completed register_netdevice */
NETREG_UNREGISTERING, /* called unregister_netdevice */
NETREG_UNREGISTERED, /* completed unregister todo */
NETREG_RELEASED, /* called free_netdev */
NETREG_DUMMY, /* dummy device for NAPI poll */
} reg_state:8;
bool dismantle;
enum {
RTNL_LINK_INITIALIZED,
RTNL_LINK_INITIALIZING,
} rtnl_link_state:16;
void (*destructor)(struct net_device *dev);
#ifdef CONFIG_NETPOLL
struct netpoll_info __rcu *npinfo;
#endif
possible_net_t nd_net;
/* mid-layer private */
union {
void *ml_priv;
struct pcpu_lstats __percpu *lstats;
struct pcpu_sw_netstats __percpu *tstats;
struct pcpu_dstats __percpu *dstats;
struct pcpu_vstats __percpu *vstats;
};
struct garp_port __rcu *garp_port;
struct mrp_port __rcu *mrp_port;
struct device dev;
const struct attribute_group *sysfs_groups[4];
const struct attribute_group *sysfs_rx_queue_group;
const struct rtnl_link_ops *rtnl_link_ops;
/* for setting kernel sock attribute on TCP connection setup */
#define GSO_MAX_SIZE 65536
unsigned int gso_max_size;
#define GSO_MAX_SEGS 65535
u16 gso_max_segs;
#ifdef CONFIG_DCB
const struct dcbnl_rtnl_ops *dcbnl_ops;
#endif
u8 num_tc;
struct netdev_tc_txq tc_to_txq[TC_MAX_QUEUE];
u8 prio_tc_map[TC_BITMASK + 1];
#if IS_ENABLED(CONFIG_FCOE)
unsigned int fcoe_ddp_xid;
#endif
#if IS_ENABLED(CONFIG_CGROUP_NET_PRIO)
struct netprio_map __rcu *priomap;
#endif
struct phy_device *phydev;
struct lock_class_key *qdisc_tx_busylock;
bool proto_down;
};
+47
View File
@@ -0,0 +1,47 @@
进程虚拟地址空间
=======
| 日期 | 内核版本 | 架构| 作者 | GitHub| CSDN |
| ------- |:-------:|:-------:|:-------:|:-------:|:-------:|
| 2016-06-14 | [Linux-4.7](http://lxr.free-electrons.com/source/?v=4.7) | X86 & arm | [gatieme](http://blog.csdn.net/gatieme) | [LinuxDeviceDrivers](https://github.com/gatieme/LDD-LinuxDeviceDrivers) | [Linux内存管理](http://blog.csdn.net/gatieme/article/category/6225543) |
http://blog.sina.com.cn/s/blog_4b9eab320102vme0.html
http://blog.csdn.net/geekcome/article/details/7971463
http://blog.chinaunix.net/uid-29478572-id-4119158.html
https://yq.aliyun.com/articles/5862
http://blog.sina.com.cn/s/blog_4b9eab320102v9qn.html
http://blog.csdn.net/shanshanpt/article/details/19918171
http://blog.chinaunix.net/uid-21768364-id-2936798.html
http://www.linuxidc.com/Linux/2012-09/70700.htm
http://www.oschina.net/question/234345_47845
http://xuela-net.iteye.com/blog/1899566
http://blog.chinaunix.net/uid-22359610-id-1626525.html
http://www.360doc.com/content/15/0522/07/18252487_472352496.shtml
http://www.openstack.cn/?p=4756
http://weibo.com/p/1001603837806467238143
大家都知道TCP/IP协议栈现在是世界上最流行的网络协议栈,恐怕它的普及的最重要的原因就是其清晰的层次结构以及清晰定义的原语和接口。不仅使得上层应用开发者可以无需关心下层架构或者内部机制,从而相对透明的操作网络。这个明显的层次结构也可以在Linux内核的网络协议栈中观察到。
主要的参考文献是:Linux网络栈剖析(中文版)/Anatomy of Linux networking stack(英文原版)by Tim Jones.
以及:Linux内核2.4.x的网络接口结构
另外一些参考资料可以从这个页面找到:http://www.ecsl.cs.sunysb.edu/elibrary/linux/network/ (纽约州立大学石溪分校的页面)
Linux内核网络协议栈采用了如下的层次结构:
http://www.ibm.com/developerworks/cn/linux/l-linux-networking-stack/
http://www.ibm.com/developerworks/linux/library/l-linux-networking-stack/
http://gjiwwa.blu.livefilestore.com/y1p99O_6n29_58mKHdfUgbvzgKOsD5_7unXA5noegNcJ9Y2h3QMaQ-m0Rb9JGP1v_X4zI7-n7J6aqbOm1xr-HMy56E3YJZbWajO/Linux%E5%86%85%E6%A0%B82.4.x%E7%9A%84%E7%BD%91%E7%BB%9C%E6%8E%A5%E5%8F%A3%E7%BB%93%E6%9E%84.pdf?download
http://www.ecsl.cs.sunysb.edu/elibrary/linux/network/