`
sunzixun
  • 浏览: 76013 次
  • 性别: Icon_minigender_1
  • 来自: 苏州
社区版块
存档分类
最新评论

<Linux Network 2.6.38> L2-L3

阅读更多

 

__netif_receive_skb 是一个很关键的函数 ,可以看成L2-L3 的分水岭(如果该协议需要到L3的话)

 

net_rx_action 做完了之后基本上 

 

struct sk_buff

{

        //... ... ...

        unsigned short  protocol;

       // ... ... ...

}; 就已经被设置了

 

 

在看 __netif_receive_skb 之前 先看一下这几个东西

 

  这是网络协议解包的主要注册结构体

 

 

struct net_protocol {
	int			(*handler)(struct sk_buff *skb);
	void			(*err_handler)(struct sk_buff *skb, u32 info);
	int			(*gso_send_check)(struct sk_buff *skb);
	struct sk_buff	       *(*gso_segment)(struct sk_buff *skb,
					       int features);
	struct sk_buff	      **(*gro_receive)(struct sk_buff **head,
					       struct sk_buff *skb);
	int			(*gro_complete)(struct sk_buff *skb);
	unsigned int		no_policy:1,
				netns_ok:1;
};

 

 

他们会用一个 hash 链表链接起来

 

 

#define PTYPE_HASH_SIZE (16)

#define PTYPE_HASH_MASK (PTYPE_HASH_SIZE - 1)

 


static struct list_head ptype_base[PTYPE_HASH_SIZE] __read_mostly;

 

 

kernel 写道
Why 16. Because with 16 the only overlap we get on a hash of the
low nibble of the protocol value is RARP/SNAP/X.25.

 

还有一个可调文件系统接口

 

 

netdev_tstamp_prequeue

----------------------

 

If set to 0, RX packet timestamps can be sampled after RPS processing, when

the target CPU processes packets. It might give some delay on timestamps, but

permit to distribute the load on several cpus.

 

If set to 1 (default), timestamps are sampled as soon as possible, before

queueing.

/sys/net/core/netdev_tstamp_prequeue

 

 

由于这个函数涉及很多特殊协议的处理,vlan实现我也只知道皮毛,这里只简单介绍一下

 

static int __netif_receive_skb(struct sk_buff *skb)
{
    struct packet_type *ptype, *pt_prev;
    rx_handler_func_t *rx_handler;
    struct net_device *orig_dev;
    struct net_device *master;
    struct net_device *null_or_orig;
    struct net_device *orig_or_bond;
    int ret = NET_RX_DROP;
    __be16 type;
    /*如果设置了 可能会有一些timestamps的延迟,默认是!1 ,不启用*/
    if (!netdev_tstamp_prequeue)
        net_timestamp_check(skb);
    trace_netif_receive_skb(skb);


    /*netpoll 需要处理这个帧吗,要的话用netpoll_rx 处理*/
    if (netpoll_receive_skb(skb))
        return NET_RX_DROP;

    /*赋值设备的接口序号*/
    if (!skb->skb_iif)
        skb->skb_iif = skb->dev->ifindex;
/*决定包的命运和走向*/
 null_or_orig = NULL;
    orig_dev = skb->dev;
    master = ACCESS_ONCE(orig_dev->master);

    if (skb->deliver_no_wcard)
        null_or_orig = orig_dev;
    else if (master) {
        if (skb_bond_should_drop(skb, master)) {
            skb->deliver_no_wcard = 1;
            null_or_orig = orig_dev; /* deliver only exact match */
        } else
            skb->dev = master;
    }
 /*为L3的处理,校准相应的指针和赋值*/
    __this_cpu_inc(softnet_data.processed);
    skb_reset_network_header(skb);
    skb_reset_transport_header(skb);
    skb->mac_len = skb->network_header - skb->mac_header;



    //...
    /* 处理 bridge or macvlan 的情况*/
    //...

    /*这里就是主要的根据 注册了的协议处理函数 去调用处理 deliver_skb()*/
    type = skb->protocol;
    list_for_each_entry_rcu(ptype,
            &ptype_base[ntohs(type) & PTYPE_HASH_MASK], list) {
        if (ptype->type == type && (ptype->dev == null_or_orig ||
             ptype->dev == skb->dev || ptype->dev == orig_dev ||
             ptype->dev == orig_or_bond)) {
            if (pt_prev)
                ret = deliver_skb(skb, pt_prev, orig_dev);
            pt_prev = ptype;
        }
    }

    if (pt_prev) {
        ret = pt_prev->func(skb, skb->dev, pt_prev, orig_dev);
    } else {
        atomic_long_inc(&skb->dev->rx_dropped);
        kfree_skb(skb);
        ret = NET_RX_DROP;
    }

out:
    rcu_read_unlock();
    return ret;
}
 

 

INET TCP/IP协议实现的linux版本

INET is implemented using the  BSD Socket

 * interface as the means of communication with the user level.

 

 

INET里面可以看到 

fs_initcall(inet_init);

 

 

 

Protocol.h:

struct net_protocol __rcu *inet_protos[MAX_INET_PROTOS];

#define MAX_INET_PROTOS 256

 

 

 

static int __init inet_init(void)
{
	struct sk_buff *dummy_skb;
	struct inet_protosw *q;
	struct list_head *r;
	int rc = -EINVAL;
	

	/*保存端口的位图结构 
	*Inet_connection_sock.c : unsigned long *sysctl_local_reserved_ports;*/
	sysctl_local_reserved_ports = kzalloc(65536 / 8, GFP_KERNEL);
	if (!sysctl_local_reserved_ports)
		goto out;

	/*socket 层 到 transport 层 接口的注册<struct proto >,都是BSD接口		*<accept,setsockopt,recvmsg......>*/
	rc = proto_register(&tcp_prot, 1);
	if (rc)
		goto out_free_reserved_ports;

	rc = proto_register(&udp_prot, 1);
	if (rc)
		goto out_unregister_tcp_proto;

	rc = proto_register(&raw_prot, 1);
	if (rc)
		goto out_unregister_udp_proto;

	/*PF_INET 协议族的注册<struct net_proto_family> */
	
	(void)sock_register(&inet_family_ops);

#ifdef CONFIG_SYSCTL
	/*文件系统接口*/
	ip_static_sysctl_init();
#endif

	/*
	 *	Add all the base protocols.
	 */
	/*直接用了cmpxchg 指令来把协议设置到 inet_protos[256]对应位中*/
	if (inet_add_protocol(&icmp_protocol, IPPROTO_ICMP) < 0)
		printk(KERN_CRIT "inet_init: Cannot add ICMP protocol\n");
	if (inet_add_protocol(&udp_protocol, IPPROTO_UDP) < 0)
		printk(KERN_CRIT "inet_init: Cannot add UDP protocol\n");
	if (inet_add_protocol(&tcp_protocol, IPPROTO_TCP) < 0)
		printk(KERN_CRIT "inet_init: Cannot add TCP protocol\n");
#ifdef CONFIG_IP_MULTICAST
	if (inet_add_protocol(&igmp_protocol, IPPROTO_IGMP) < 0)
		printk(KERN_CRIT "inet_init: Cannot add IGMP protocol\n");
#endif

	/* Register the socket-side information for inet_create. */
	for (r = &inetsw[0]; r < &inetsw[SOCK_MAX]; ++r)
		INIT_LIST_HEAD(r);

	for (q = inetsw_array; q < &inetsw_array[INETSW_ARRAY_LEN]; ++q)
		inet_register_protosw(q);

	/*
	 *	Set the ARP module up
	 */

	arp_init();

	/*
	 *	Set the IP module up
	 */

	ip_init();

	tcp_v4_init();

	/* Setup TCP slab cache for open requests. */
	tcp_init();

	/* Setup UDP memory threshold */
	udp_init();

	/* Add UDP-Lite (RFC 3828) */
	udplite4_register();

	/*
	 *	Set the ICMP layer up
	 */

	if (icmp_init() < 0)
		panic("Failed to create the ICMP control socket.\n");

	/*
	 *	Initialise the multicast router
	 */
#if defined(CONFIG_IP_MROUTE)
	if (ip_mr_init())
		printk(KERN_CRIT "inet_init: Cannot init ipv4 mroute\n");
#endif
	/*
	 *	Initialise per-cpu ipv4 mibs
	 */

	if (init_ipv4_mibs())
		printk(KERN_CRIT "inet_init: Cannot init ipv4 mibs\n");

	ipv4_proc_init();

	ipfrag_init();
	/*这里用 ptype_head() 在 ptype_base[16] (如果设置了ETH_P_ALL 就在	*ptype_all)里面设置相应位 */
	dev_add_pack(&ip_packet_type);

	rc = 0;
out:
	return rc;
out_unregister_udp_proto:
	proto_unregister(&udp_prot);
out_unregister_tcp_proto:
	proto_unregister(&tcp_prot);
out_free_reserved_ports:
	kfree(sysctl_local_reserved_ports);
	goto out;
}

static inline struct list_head *ptype_head(const struct packet_type *pt)
{
	if (pt->type == htons(ETH_P_ALL))
		return &ptype_all;
	else
		return &ptype_base[ntohs(pt->type) & PTYPE_HASH_MASK];
}
 

 

分享到:
评论

相关推荐

    CS8900A移植到linux-2.6.38和linux-2.6.35内核

    在本文中,我们将深入探讨如何将CS8900A网络控制器从Linux 2.6.35内核移植到2.6.38内核的过程。CS8900A是一款广泛使用的以太网控制器,尤其适用于嵌入式系统。在基于FS2410的开发板上进行移植工作,我们需要理解内核...

    Linux-2.6.38.4

    最新的Linux2.6操作系统,Linux-2.6.38.4,加入了新的功能,下载体验吧

    Linux kernel-2.6.38.1-i686.cfg

    Linux kernel-2.6.38.1-i686.cfg

    Mini6410 kernel-patch Linux-2.6.38

    Mini6410 Kernel-patch Linux-2.6.38

    linux内核2.6.38 正品行货

    Linux内核2.6.38是Linux操作系统的核心部分,负责管理系统的硬件资源,调度进程,实现硬件抽象层,提供系统调用接口等关键功能。对于开发者而言,它是一个极其重要的基础,尤其对于那些需要定制化操作系统的专业人员...

    ubuntu编译Tiny6410内核linux-2.6.38所需mkimage工具

    ubuntu编译ARM内核linux-2.6.38所需的工具

    linux内核编译实验报告

    - 解压完成后,会在主目录中生成一个名为`linux-2.6.38`的文件夹。 **4.4 配置内核** - 进入内核源代码目录`linux-2.6.38`。 - 使用`.config`文件作为基础配置,可以通过`make menuconfig`命令进行交互式配置。 - ...

    ubuntu下编译linux kernel 2.6.38

    在Ubuntu 10.10环境下编译Linux内核2.6.38涉及一系列步骤,需要对操作系统、内核版本、编译工具和配置选项有深入理解。以下是详细的编译流程和注意事项: 首先,确保你的环境是Pentium 4架构的Ubuntu 10.10(内核...

    KVM安装文档 指南

    erver01&gt; tar xvf linux-2.6.38.tar.bz2 server01&gt; cd linux-2.6.38 server01&gt; make mrproper server01&gt; cp ../linux-2.6.18-xxx/.config .config #此处为了防止遗漏某些模块的添加,将原来的内核配置文件拷贝过来...

    基于 linux-2.6.38 内核的嵌入式驱动常用的函数调用

    ### 基于 Linux-2.6.38 内核的嵌入式驱动常用函数调用解析 #### 一、`copy_from_user()` **函数定义:** ```c static inline unsigned long copy_from_user(void __user *to, const void *from, unsigned long n)...

    linux-2.6.38-tiny6410:tiny6410开发板,Linux内核源码学习

    在"linux-2.6.38-tiny6410"这个项目中,我们将关注的是Linux内核的一个特定版本,针对tiny6410开发板进行了优化和适配。 tiny6410开发板是基于三星S5PV210处理器的嵌入式平台,常用于教学、实验和产品原型设计。S5...

    蜂窝模块Linux驱动文件Quectel-Linux-USB-Serial-Option-Driver-20220902

    v2.6.38 v2.6.39 v3.0.1 v3.0.11 v3.0.51 v3.1.1 v3.2.1 v3.2.51 v3.3.1 v3.4.1 v3.4.11 v3.4.51 v3.4.111 v3.5.1 v3.6.1 v3.7.1 v3.8.1 v3.8.11 v3.9.1 v3.9.11 v3.10.1 v3.10.11 v3.10.51 v3.11.1 v3.12.1 v3.12....

    6410-linux驱动程序的位置

    - **驱动程序源代码位置**:`Linux-2.6.38/fs/yaffs2` - **设备名**:无特定设备名 - **备注**:YAFFS2(Yet Another Flash File System)是一种专为闪存设计的文件系统,主要用于嵌入式系统中。它能够有效管理非易...

    linux 单驱动程序动态编译环境配置

    - 这里假设你已经拥有名为`linux-2.6.38-20110325.tar.gz`的内核压缩包,并将其解压到`/srv/linux`目录下。 **步骤2:配置内核** - 进入解压后的内核源码目录: ```bash cd /srv/linux/linux-2.6.38 ``` - 在...

    mini6410_2.6.38内核_uart1_platform_device驱动

    请将压缩包中的s3c6400_qrj.c Kconfig Makefile复制到友善之臂给的linux-2.6.38-20111112内核源码的 drivers/tty/serial目录下,执行 make menuconfig ARCH=arm CROSS_COMPILE=arm-linux-, 将Device Driver--&gt;...

    嵌入式Linux下LED报警灯驱动设计及编程.doc

    * #include &lt;linux/miscdevice.h&gt; * #include &lt;linux/delay.h&gt; * #include &lt;asm/irq.h&gt; * #include &lt;mach/regs-gpio.h&gt; * #include &lt;mach/hardware.h&gt; * #include &lt;linux/kernel.h&gt; * #include &lt;linux/module.h&gt; 本...

    基于Tiny6410上移植_kernel-2.6.38

    在本文中,我们将深入探讨如何在Tiny6410开发板上移植Linux内核2.6.38。Tiny6410是一款基于ARM Cortex-A8处理器的嵌入式开发板,具有2GB NAND Flash存储和256MB RAM。移植内核到这样的硬件平台涉及多个步骤,包括...

    linux2.6.38内核驱动常用函数.pdf

    Linux 2.6.38内核是Linux操作系统的一个版本,它包含了多种驱动开发所需的函数和API。在开发基于Linux内核的设备驱动程序时,熟练使用这些内核提供的函数是至关重要的。下面将详细介绍文档中提及的一些内核驱动常用...

    linux2.6.38wifi的初步分析

    对2.6.38内核中wifi驱动中出现的SD卡热插拔,wifi驱动进行了一个初步的分析.有什么不对的地方,还希望高手指点!

    Linux-2.6.38驱动的几个结构体关系总结

    在Linux 2.6.38版本中,驱动程序设计涉及到多个关键的结构体,包括`struct file_operations`, `struct inode`, 和 `struct file`。下面是对这些结构体及其关系的详细解释。 1. **struct file_operations** 这个...

Global site tag (gtag.js) - Google Analytics