网卡是是网络中最基本的硬件之一。
在内核中,每个网络设备都一个一个net_device 结构体实例,在进行初始化完成之后,会将该结构注册到内核中。然能内核知道该结构的存在。
这会创建一个sysfs项,这,关联到该设备的对应目录中。该目录为
[root@localhost ~]# ls -l /sys/class/net 总计 0 drwxr-xr-x 3 root root 0 10-08 00:17 eth0 drwxr-xr-x 3 root root 0 10-08 00:17 lo drwxr-xr-x 4 root root 0 10-08 00:17 peth0 drwxr-xr-x 3 root root 0 10-08 00:17 sit0 drwxr-xr-x 3 root root 0 10-08 00:17 veth1 drwxr-xr-x 3 root root 0 10-08 00:17 veth2 drwxr-xr-x 3 root root 0 10-08 00:17 veth3 drwxr-xr-x 4 root root 0 10-08 00:17 vif0.0 drwxr-xr-x 3 root root 0 10-08 00:17 vif0.1 drwxr-xr-x 3 root root 0 10-08 00:17 vif0.2 drwxr-xr-x 3 root root 0 10-08 00:17 vif0.3 drwxr-xr-x 5 root root 0 10-08 00:17 xenbr0
可以看到 我虚拟机上的网络设备有以上的设备。eth0 是第一个网卡。其他的我也不知道干嘛的。
该设备不是全局的。因此也是在一个命名空间的。
所有网络设备都保存在一个单链表中。表头为dev_base.
按设备名散列。
按接口索引散列
下面我就不得不晓得linux中 最大的一个结构体数据结构。几百行代码
如下代码
/* * 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 { /* * This is the first field of the "visible" part of this structure * (i.e. as seen by users in the "Space.c" file). It is the name * the interface. */ char name[IFNAMSIZ]; /* * 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. */ unsigned char if_port; /* Selectable AUI, TP,..*/ unsigned char dma; /* DMA channel */ unsigned long state; struct net_device *next; /* The device initialization function. Called only once. */ int (*init)(struct net_device *dev); /* ------- Fields preinitialized in Space.c finish here ------- */ struct net_device *next_sched; /* Interface index. Unique device identifier */ int ifindex; int iflink; struct net_device_stats* (*get_stats)(struct net_device *dev); struct iw_statistics* (*get_wireless_stats)(struct net_device *dev); /* List of functions to handle Wireless Extensions (instead of ioctl). * See <net/iw_handler.h> for details. Jean II */ struct iw_handler_def * wireless_handlers; struct ethtool_ops *ethtool_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). */ /* These may be needed for future network-power-down code. */ unsigned long trans_start; /* Time (in jiffies) of last Tx */ unsigned long last_rx; /* Time of last Rx */ unsigned short flags; /* interface flags (a la BSD) */ unsigned short gflags; unsigned short priv_flags; /* Like 'flags' but invisible to userspace. */ unsigned short unused_alignment_fixer; /* Because we need priv_flags, * and we want to be 32-bit aligned. */ unsigned mtu; /* interface MTU value */ unsigned short type; /* interface hardware type */ unsigned short hard_header_len; /* hardware hdr length */ void *priv; /* pointer to private data */ struct net_device *master; /* Pointer to master device of a group, * which this device is member of. */ /* Interface address info. */ unsigned char broadcast[MAX_ADDR_LEN]; /* hw bcast add */ unsigned char dev_addr[MAX_ADDR_LEN]; /* hw address */ unsigned char addr_len; /* hardware address length */ struct dev_mc_list *mc_list; /* Multicast mac addresses */ int mc_count; /* Number of installed mcasts */ int promiscuity; int allmulti; int watchdog_timeo; struct timer_list watchdog_timer; /* Protocol specific pointers */ void *atalk_ptr; /* AppleTalk link */ void *ip_ptr; /* IPv4 specific data */ void *dn_ptr; /* DECnet specific data */ void *ip6_ptr; /* IPv6 specific data */ void *ec_ptr; /* Econet specific data */ void *ax25_ptr; /* AX.25 specific data */ struct list_head poll_list; /* Link to poll list */ int quota; int weight; struct Qdisc *qdisc; struct Qdisc *qdisc_sleeping; struct Qdisc *qdisc_list; struct Qdisc *qdisc_ingress; unsigned long tx_queue_len; /* Max frames per queue allowed */ /* hard_start_xmit synchronizer */ spinlock_t xmit_lock; /* cpu id of processor entered to hard_start_xmit or -1, if nobody entered there. */ int xmit_lock_owner; /* device queue lock */ spinlock_t queue_lock; /* Number of references to this device */ atomic_t refcnt; /* delayed register/unregister */ struct list_head todo_list; /* register/unregister state machine */ enum { NETREG_UNINITIALIZED=0, NETREG_REGISTERING, /* called register_netdevice */ NETREG_REGISTERED, /* completed register todo */ NETREG_UNREGISTERING, /* called unregister_netdevice */ NETREG_UNREGISTERED, /* completed unregister todo */ NETREG_RELEASED, /* called free_netdev */ } reg_state; /* Net device features */ int features; #define NETIF_F_SG 1 /* Scatter/gather IO. */ #define NETIF_F_IP_CSUM 2 /* Can checksum only TCP/UDP over IPv4. */ #define NETIF_F_NO_CSUM 4 /* Does not require checksum. F.e. loopack. */ #define NETIF_F_HW_CSUM 8 /* Can checksum all the packets. */ #define NETIF_F_HIGHDMA 32 /* Can DMA to high memory. */ #define NETIF_F_FRAGLIST 64 /* Scatter/gather IO. */ #define NETIF_F_HW_VLAN_TX 128 /* Transmit VLAN hw acceleration */ #define NETIF_F_HW_VLAN_RX 256 /* Receive VLAN hw acceleration */ #define NETIF_F_HW_VLAN_FILTER 512 /* Receive filtering on VLAN */ #define NETIF_F_VLAN_CHALLENGED 1024 /* Device cannot handle VLAN packets */ #define NETIF_F_TSO 2048 /* Can offload TCP/IP segmentation */ /* 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); /* Pointers to interface service routines. */ int (*open)(struct net_device *dev); int (*stop)(struct net_device *dev); int (*hard_start_xmit) (struct sk_buff *skb, struct net_device *dev); #define HAVE_NETDEV_POLL int (*poll) (struct net_device *dev, int *quota); int (*hard_header) (struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len); int (*rebuild_header)(struct sk_buff *skb); #define HAVE_MULTICAST void (*set_multicast_list)(struct net_device *dev); #define HAVE_SET_MAC_ADDR int (*set_mac_address)(struct net_device *dev, void *addr); #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_HEADER_CACHE int (*hard_header_cache)(struct neighbour *neigh, struct hh_cache *hh); void (*header_cache_update)(struct hh_cache *hh, struct net_device *dev, unsigned char * haddr); #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 (*hard_header_parse)(struct sk_buff *skb, unsigned char *haddr); int (*neigh_setup)(struct net_device *dev, struct neigh_parms *); int (*accept_fastpath)(struct net_device *, struct dst_entry*); /* bridge stuff */ struct net_bridge_port *br_port; #ifdef CONFIG_NET_FASTROUTE #define NETDEV_FASTROUTE_HMASK 0xF /* Semi-private data. Keep it at the end of device struct. */ rwlock_t fastpath_lock; struct dst_entry *fastpath[NETDEV_FASTROUTE_HMASK+1]; #endif #ifdef CONFIG_NET_DIVERT /* this will get initialized at each interface type init routine */ struct divert_blk *divert; #endif /* CONFIG_NET_DIVERT */ /* class/net/name entry */ struct class_device class_dev; struct net_device_stats* (*last_stats)(struct net_device *); };
每个网络设备都有个结构体,然后按照链表的形式。每个字段都有相应的注释,就不详细介绍。
注意一点就是这里定义了mtu,也就是一个传输帧的最大长度。因此,网络层必须遵守改最大值。进行拆分数据包。type定义了设备的常数。dev_addr,表示硬件地址。
下面在展示一个结构体
struct packet_type { unsigned short type; /* This is really htons(ether_type). */ struct net_device *dev; /* NULL is wildcarded here */ int (*func) (struct sk_buff *, struct net_device *, struct packet_type *); void *af_packet_priv; struct list_head list; };
此结构将之前介绍的struct sk_buff 和struct net_device关联起来。进行处理。
有大量的函数
extern void dev_add_pack(struct packet_type *pt); extern void dev_remove_pack(struct packet_type *pt); extern void __dev_remove_pack(struct packet_type *pt);
具体的函数作用要细细的分析,在这里,就不做详细分析,需要看代码一点点分析。
只给大家展示一下将网络设备注册到内核的一个核心方法
/** * register_netdevice - register a network device * @dev: device to register * * Take a completed network device structure and add it to the kernel * interfaces. A %NETDEV_REGISTER message is sent to the netdev notifier * chain. 0 is returned on success. A negative errno code is returned * on a failure to set up the device, or if the name is a duplicate. * * Callers must hold the rtnl semaphore. See the comment at the * end of Space.c for details about the locking. You may want * register_netdev() instead of this. * * BUGS: * The locking appears insufficient to guarantee two parallel registers * will not get the same name. */ int register_netdevice(struct net_device *dev) { struct net_device *d, **dp; int ret; BUG_ON(dev_boot_phase); ASSERT_RTNL(); /* When net_device's are persistent, this will be fatal. */ BUG_ON(dev->reg_state != NETREG_UNINITIALIZED); spin_lock_init(&dev->queue_lock); ///队列锁 spin_lock_init(&dev->xmit_lock); dev->xmit_lock_owner = -1; #ifdef CONFIG_NET_FASTROUTE dev->fastpath_lock = RW_LOCK_UNLOCKED; #endif ret = alloc_divert_blk(dev); if (ret) goto out; dev->iflink = -1; /* Init, if this function is available */ if (dev->init) { ret = dev->init(dev); if (ret) { if (ret > 0) ret = -EIO; goto out_err; } } dev->ifindex = dev_new_index(); if (dev->iflink == -1) dev->iflink = dev->ifindex; /* Check for existence, and append to tail of chain */ ret = -EEXIST; for (dp = &dev_base; (d = *dp) != NULL; dp = &d->next) { if (d == dev || !strcmp(d->name, dev->name)) goto out_err; } /* Fix illegal SG+CSUM combinations. */ if ((dev->features & NETIF_F_SG) && !(dev->features & (NETIF_F_IP_CSUM | NETIF_F_NO_CSUM | NETIF_F_HW_CSUM))) { printk("%s: Dropping NETIF_F_SG since no checksum feature.\n", dev->name); dev->features &= ~NETIF_F_SG; } /* * nil rebuild_header routine, * that should be never called and used as just bug trap. */ if (!dev->rebuild_header) dev->rebuild_header = default_rebuild_header; /* * Default initial state at registry is that the * device is present. */ set_bit(__LINK_STATE_PRESENT, &dev->state); dev->next = NULL; dev_init_scheduler(dev); write_lock_bh(&dev_base_lock); *dp = dev; dev_hold(dev); dev->reg_state = NETREG_REGISTERING; write_unlock_bh(&dev_base_lock); /* Notify protocols, that a new device appeared. */ notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev); /* Finish registration after unlock */ net_set_todo(dev); ret = 0; out: return ret; out_err: free_divert_blk(dev); goto out; }
今天休写到这里。更多文章,欢迎访问 http://blog.csdn.net/wallwind