linux内核学习之网络篇——网络物理层的设备初步

网卡是是网络中最基本的硬件之一。

在内核中,每个网络设备都一个一个net_device 结构体实例,在进行初始化完成之后,会将该结构注册到内核中。然能内核知道该结构的存在。

这会创建一个sysfs项,这,关联到该设备的对应目录中。该目录为

[root@localhost ~]# ls -l /sys/class/net总计 0drwxr-xr-x 3 root root 0 10-08 00:17 eth0drwxr-xr-x 3 root root 0 10-08 00:17 lodrwxr-xr-x 4 root root 0 10-08 00:17 peth0drwxr-xr-x 3 root root 0 10-08 00:17 sit0drwxr-xr-x 3 root root 0 10-08 00:17 veth1drwxr-xr-x 3 root root 0 10-08 00:17 veth2drwxr-xr-x 3 root root 0 10-08 00:17 veth3drwxr-xr-x 4 root root 0 10-08 00:17 vif0.0drwxr-xr-x 3 root root 0 10-08 00:17 vif0.1drwxr-xr-x 3 root root 0 10-08 00:17 vif0.2drwxr-xr-x 3 root root 0 10-08 00:17 vif0.3drwxr-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. */charname[IFNAMSIZ];/* *I/O specific fields *FIXME: Merge these and struct ifmap into one */unsigned longmem_end;/* shared mem end*/unsigned longmem_start;/* shared mem start*/unsigned longbase_addr;/* device I/O address*/unsigned intirq;/* device IRQ number*//* *Some hardware also needs these fields, but they are not *part of the usual set specified in Space.c. */unsigned charif_port;/* Selectable AUI, TP,..*/unsigned chardma;/* DMA channel*/unsigned longstate;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*/intifindex;intiflink;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 longtrans_start;/* Time (in jiffies) of last Tx*/unsigned longlast_rx;/* Time of last Rx*/unsigned shortflags;/* interface flags (a la BSD)*/unsigned shortgflags;        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.                                                         */unsignedmtu;/* interface MTU value*/unsigned shorttype;/* interface hardware type*/unsigned shorthard_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 charbroadcast[MAX_ADDR_LEN];/* hw bcast add*/unsigned chardev_addr[MAX_ADDR_LEN];/* hw address*/unsigned charaddr_len;/* hardware address length*/struct dev_mc_list*mc_list;/* Multicast mac addresses*/intmc_count;/* Number of installed mcasts*/intpromiscuity;intallmulti;intwatchdog_timeo;struct timer_listwatchdog_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_headpoll_list;/* Link to poll list*/intquota;intweight;struct Qdisc*qdisc;struct Qdisc*qdisc_sleeping;struct Qdisc*qdisc_list;struct Qdisc*qdisc_ingress;unsigned longtx_queue_len;/* Max frames per queue allowed *//* hard_start_xmit synchronizer */spinlock_txmit_lock;/* cpu id of processor entered to hard_start_xmit or -1,   if nobody entered there. */intxmit_lock_owner;/* device queue lock */spinlock_tqueue_lock;/* Number of references to this device */atomic_trefcnt;/* delayed register/unregister */struct list_headtodo_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 */intfeatures;#define NETIF_F_SG1/* Scatter/gather IO. */#define NETIF_F_IP_CSUM2/* Can checksum only TCP/UDP over IPv4. */#define NETIF_F_NO_CSUM4/* Does not require checksum. F.e. loopack. */#define NETIF_F_HW_CSUM8/* Can checksum all the packets. */#define NETIF_F_HIGHDMA32/* Can DMA to high memory. */#define NETIF_F_FRAGLIST64/* Scatter/gather IO. */#define NETIF_F_HW_VLAN_TX128/* Transmit VLAN hw acceleration */#define NETIF_F_HW_VLAN_RX256/* Receive VLAN hw acceleration */#define NETIF_F_HW_VLAN_FILTER512/* Receive filtering on VLAN */#define NETIF_F_VLAN_CHALLENGED1024/* Device cannot handle VLAN packets */#define NETIF_F_TSO2048/* 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_POLLint(*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_IOCTLint(*do_ioctl)(struct net_device *dev,    struct ifreq *ifr, int cmd);#define HAVE_SET_CONFIGint(*set_config)(struct net_device *dev,      struct ifmap *map);#define HAVE_HEADER_CACHEint(*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_MTUint(*change_mtu)(struct net_device *dev, int new_mtu);#define HAVE_TX_TIMEOUTvoid(*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_tfastpath_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_deviceclass_dev;struct net_device_stats* (*last_stats)(struct net_device *);};

每个网络设备都有个结构体,然后按照链表的形式。每个字段都有相应的注释,就不详细介绍。

注意一点就是这里定义了mtu,也就是一个传输帧的最大长度。因此,网络层必须遵守改最大值。进行拆分数据包。type定义了设备的常数。dev_addr,表示硬件地址。

下面在展示一个结构体

struct packet_type {unsigned shorttype;/* 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_headlist;};

此结构将之前介绍的struct sk_buff 和struct net_device关联起来。进行处理。

有大量的函数

extern voiddev_add_pack(struct packet_type *pt);extern voiddev_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_FASTROUTEdev->fastpath_lock = RW_LOCK_UNLOCKED;#endifret = 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

总结失败的原因能够让人越来越谨慎。

linux内核学习之网络篇——网络物理层的设备初步

相关文章:

你感兴趣的文章:

标签云: