网络子系统-2.6.26
作者:guolele
首先讲这问题就要先了解几个网络子系统比较重要的数据结构和函数。Struct net_device ,register_netdev(),unregister_netdev(),struct sk_buff
还有一个,就是网卡驱动是工作在数据链路层的。
Linux设备驱动模型,每一个驱动硬件都是以一个数据结构表示,网卡就是以struct net_device这个结构表示。
而收发的数据就是通过struct sk_buff结构传递到上一层,上一层是协议层。
这里内核描述说这个结构是个错误,因为它把IO数据混淆为高级数据,所以它必须知道每个数据结构被用在INET模块
/* * The DEVICE structure. * Actually, this whole structure is a big mistake. It mixes I/O * data with strictly "high-level" data, and it has to know about * almost every data structure used in the INET module. * * FIXME: cleanup struct net_device such that network protocol info * moves out. */ struct net_device { 。。。 char name[IFNAMSIZ];//注册设备的名字 /* device name hash chain */ struct hlist_node name_hlist; /* * I/O specific fields * FIXME: Merge these and struct ifmap into one */这几个也是成员也比较重要,前两个是共享内存的地址,而第三个是芯片的物理地址,第四个是中断号 unsigned long mem_end; /* shared mem end */ unsigned long mem_start; /* shared mem start */ unsigned long base_addr; /* device I/O address */ unsigned int irq; /* device IRQ number */ /* * Some hardware also needs these fields, but they are not * part of the usual set specified in Space.c. */ If_port是选择芯片类型的,如果是以太网卡,那么就是AUI,那if_port = IF_PORT_10BASET这是10M还有100M的 unsigned char if_port; /* Selectable AUI, TP,..*/ unsigned char dma; /* DMA channel */ 。。。。。 //这是个用来获得struct net__device_stats结构体的函数指针,主要用于统计收发的数据包 struct net_device_stats* (*get_stats)(struct net_device *dev); struct net_device_stats stats; //无线的处理 #ifdef CONFIG_WIRELESS_EXT /* List of functions to handle Wireless Extensions (instead of ioctl). * See <net/iw_handler.h> for details. Jean II */ const struct iw_handler_def * wireless_handlers; /* Instance data managed by the core of Wireless Extensions. */ struct iw_public_data * wireless_data; #endif //这个ethtool_ops是能够提供给用户的操作网卡的函数 const struct ethtool_ops *ethtool_ops; /* Hardware header description */ const struct header_ops *header_ops; /* * This marks the end of the "visible" part of the structure. All * fields hereafter are internal to the system, and may change at * will (read: may be cleaned up at will). */ //这个flags是可以用来选择收发的对象,相当于一个屏蔽 unsigned int flags; /* interface flags (a la BSD) */ 。。。。。。 //协议的特殊指针 /* Protocol specific pointers */ 。。。。。。 /* * Cache line mostly used on receive path (including eth_type_trans()) */ unsigned long last_rx; /* Time of last Rx */ /* Interface address info used in eth_type_trans() */ //dev_addr,这是MAC地址 unsigned char dev_addr[MAX_ADDR_LEN]; /* hw address, (before bcast because most packets are unicast) */ unsigned char broadcast[MAX_ADDR_LEN]; /* hw bcast add */ 。。。。。。 /* * One part is mostly used on xmit path (device) */ /* hard_start_xmit synchronizer */ spinlock_t _xmit_lock ____cacheline_aligned_in_smp; /* cpu id of processor entered to hard_start_xmit or -1, if nobody entered there. */ int xmit_lock_owner; //移有数据指针,一般用来记录收发数据包 void *priv; /* pointer to private data */ //网卡发送函数,当通过设备无关接口要求网卡网卡发送数据时调用 int (*hard_start_xmit) (struct sk_buff *skb, struct net_device *dev); /* These may be needed for future network-power-down code. */ unsigned long trans_start; /* Time (in jiffies) of last Tx */ int watchdog_timeo; /* used by dev_watchdog() */ struct timer_list watchdog_timer; 。。。。。。 /* register/unregister state machine */ enum { NETREG_UNINITIALIZED=0, NETREG_REGISTERED, /* completed register_netdevice */ NETREG_UNREGISTERING, /* called unregister_netdevice */ NETREG_UNREGISTERED, /* completed unregister todo */ NETREG_RELEASED, /* called free_netdev */ } reg_state; //uninit是一个用户退出时得到调用,destructor是所有用户退出得调用,这是为了共享网卡 /* Called after device is detached from network. */ void (*uninit)(struct net_device *dev); /* Called after last user reference disappears. */ void (*destructor)(struct net_device *dev); //open函数是打开接口函数,在调用ifconfig激活时得到调用 //stop相对就是在ifconfig eth%x down时得到调用 /* Pointers to interface service routines. */ int (*open)(struct net_device *dev); int (*stop)(struct net_device *dev); #define HAVE_NETDEV_POLL #define HAVE_CHANGE_RX_FLAGS void (*change_rx_flags)(struct net_device *dev, int flags); #define HAVE_SET_RX_MODE void (*set_rx_mode)(struct net_device *dev); #define HAVE_MULTICAST void (*set_multicast_list)(struct net_device *dev); #define HAVE_SET_MAC_ADDR //改变MAC地址函数,需硬件支持 int (*set_mac_address)(struct net_device *dev, void *addr); #define HAVE_VALIDATE_ADDR int (*validate_addr)(struct net_device *dev); #define HAVE_PRIVATE_IOCTL int (*do_ioctl)(struct net_device *dev, struct ifreq *ifr, int cmd); #define HAVE_SET_CONFIG int (*set_config)(struct net_device *dev, struct ifmap *map); #define HAVE_CHANGE_MTU int (*change_mtu)(struct net_device *dev, int new_mtu); #define HAVE_TX_TIMEOUT //传输超时得到调用 void (*tx_timeout) (struct net_device *dev); void (*vlan_rx_register)(struct net_device *dev, struct vlan_group *grp); void (*vlan_rx_add_vid)(struct net_device *dev, unsigned short vid); void (*vlan_rx_kill_vid)(struct net_device *dev, unsigned short vid); int (*neigh_setup)(struct net_device *dev, struct neigh_parms *); #ifdef CONFIG_NETPOLL 。。。。。 };
驱动的任务就是在模块加载时先填充完这个数据结构,然后在最后调用register_netdev函数时会调用struct net_device 里的init函数指针,而这个init函数就是完成最后的初始化工作,网卡驱动就结束了。
Init主要做几个工作,就是注册中断,设置芯片工作模式, 通知协层,可以开始传输数据包了。
等有数据传来就会产生中断,中断处理函数里会先把数据整理到struct sk_buff,再交给协议层去处理,具体操作就是调用netif_rx。
要传送数据时,也类似,只是不用最后交给协议层。
下面再讲讲struct sk_buff 这个数据结构,
/** * struct sk_buff - socket buffer * @next: Next buffer in list * @prev: Previous buffer in list * @sk: Socket we are owned by * @tstamp: Time we arrived * @dev: Device we arrived on/are leaving by * @transport_header: Transport layer header * @network_header: Network layer header * @mac_header: Link layer header * @dst: destination entry * @sp: the security path, used for xfrm * @cb: Control buffer. Free for use by every layer. Put private vars here * @len: Length of actual data * @data_len: Data length * @mac_len: Length of link layer header * @hdr_len: writable header length of cloned skb * @csum: Checksum (must include start/offset pair) * @csum_start: Offset from skb->head where checksumming should start * @csum_offset: Offset from csum_start where checksum should be stored * @local_df: allow local fragmentation * @cloned: Head may be cloned (check refcnt to be sure) * @nohdr: Payload reference only, must not modify header * @pkt_type: Packet class * @fclone: skbuff clone status * @ip_summed: Driver fed us an IP checksum * @priority: Packet queueing priority * @users: User count - see {datagram,tcp}.c * @protocol: Packet protocol from driver * @truesize: Buffer size * @head: Head of buffer * @data: Data head pointer * @tail: Tail pointer * @end: End pointer * @destructor: Destruct function * @mark: Generic packet mark * @nfct: Associated connection, if any * @ipvs_property: skbuff is owned by ipvs * @peeked: this packet has been seen already, so stats have been * done for it, don't do them again * @nf_trace: netfilter packet trace flag * @nfctinfo: Relationship of this skb to the connection * @nfct_reasm: netfilter conntrack re-assembly pointer * @nf_bridge: Saved data about a bridged frame - see br_netfilter.c * @iif: ifindex of device we arrived on * @queue_mapping: Queue mapping for multiqueue devices * @tc_index: Traffic control index * @tc_verd: traffic control verdict * @ndisc_nodetype: router type (from link layer) * @dma_cookie: a cookie to one of several possible DMA operations * done by skb DMA functions * @secmark: security marking */ struct sk_buff { 。。。 //dev是正在处理这数据包的设备 struct net_device *dev; union { struct dst_entry *dst; struct rtable *rtable; }; struct sec_path *sp; /* * This is the control buffer. It is free to use for every * layer. Please put your private variables there. If you * want to keep them across layers you have to do a skb_clone() * first. This is owned by whoever has the skb queued ATM. */ char cb[48]; unsigned int len, data_len; __u16 mac_len, hdr_len; union { __wsum csum; struct { __u16 csum_start; __u16 csum_offset; }; }; __u32 priority; __u8 local_df:1, cloned:1, ip_summed:2, nohdr:1, nfctinfo:3; __u8 pkt_type:3,//数据包的类型,广播,多播,转发 fclone:2, ipvs_property:1, peeked:1, nf_trace:1; __be16 protocol;// 表示以太层的上层协议,可以是IP,IPv6和ARP。 void (*destructor)(struct sk_buff *skb); #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) struct nf_conntrack *nfct; struct sk_buff *nfct_reasm; #endif #ifdef CONFIG_BRIDGE_NETFILTER struct nf_bridge_info *nf_bridge; #endif int iif; #ifdef CONFIG_NETDEVICES_MULTIQUEUE __u16 queue_mapping; #endif #ifdef CONFIG_NET_SCHED __u16 tc_index; /* traffic control index */ #ifdef CONFIG_NET_CLS_ACT __u16 tc_verd; /* traffic control verdict */ #endif #endif #ifdef CONFIG_IPV6_NDISC_NODETYPE __u8 ndisc_nodetype:2; #endif /* 14 bit hole */ #ifdef CONFIG_NET_DMA dma_cookie_t dma_cookie; #endif #ifdef CONFIG_NETWORK_SECMARK __u32 secmark; #endif __u32 mark; sk_buff_data_t transport_header; sk_buff_data_t network_header; sk_buff_data_t mac_header; /* These elements must be at the end, see alloc_skb() for details. */ sk_buff_data_t tail;//有效数据结束 sk_buff_data_t end;//分配空间结束 unsigned char *head,//分配空间开始 *data;//有效数据开始 unsigned int truesize; atomic_t users; };
大概就这样传给协议层了