Linux protocol stack Learning Section 5 link layer and network layer Interfaces

Source: Internet
Author: User

After the network driver receives the packet, the skb-> protocol field is initialized. The receiving function netif_receive_skb at the link layer determines based on this field and sends the message to the protocol module for further processing.


Ethernet device callEth_type_trans) To assign values to skb-> protocol.

_ Be16 eth_type_trans (struct sk_buff * skb, struct net_device * dev) {struct ethhdr * eth; unsigned char * rawp; net/* assign the received net_device to skb */skb-> dev = dev;/* assign a value to the mac header pointer of skb */skb_reset_mac_header (skb ); /* Move skb-> data down and skip the Ethernet header */skb_pull (skb, ETH_HLEN); eth = eth_hdr (skb ); if (unlikely (is_multicast_ether_addr (eth-> h_dest) {/* determines whether it is a broadcast or multicast file. if yes, it assigns a value to skb-> pkt_type */if (! Compare_ether_addr_64bits (eth-> h_dest, dev-> broadcast) skb-> pkt_type = PACKET_BROADCAST; else skb-> pkt_type = PACKET_MULTICAST ;} /* if the target MAC of the message is not the MAC of the receiving device, set skb-> pkt_type */else if (1/* dev-> flags & IFF_PROMISC */) {if (unlikely (compare_ether_addr_64bits (eth-> h_dest, dev-> dev_addr) skb-> pkt_type = PACKET_OTHERHOST ;} /* Marvell switch chip dsa header */if (netdev_uses_dsa_tags (dev) return htons (ETH_P_DSA); if (netdev_uses_trailer_tags (dev) return htons (ETH_P_TRAILER ); /* the Ethernet header returns */if (ntohs (eth-> h_proto)> = 1536) return eth-> h_proto;/* the following processes non-Ethernet packets, do not discuss */rawp = skb-> data; if (* (unsigned short *) rawp = 0 xFFFF) return htons (ETH_P_802_3 ); /* Real 802.2 LLC */return htons (ETH_P_802_2 );}

The network device driver calls eth_type_trans before calling netif_receive_skb () or netif_rx ):

Skb-> protocol = eth_type_trans (skb, dev );


Each network layer protocol initializes a function for receiving packets. The Linux kernel uses the data structure struct packet_type to describe a single network layer protocol.

Struct packet_type {/* protocol type, such as ip (0x0800), vlan (0x8100) */_ be16 type;/* This is really htons (ether_type ). * // * specify the network device to be received. If it is null, it receives data from all network devices. If it is specified, it only receives data from the specified device */struct net_device * dev; /* NULL is wildcarded here * // * protocol receiving function */int (* func) (struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *); /* The following describes how to use the gso function. Each protocol uses the gso function to implement its own function */struct sk_buff * (* gso_segment) (struct sk_buff * skb, int features ); int (* gso_send_check) (struct sk_buff * skb);/* The gro function is used below, each protocol uses the gro function to implement its own function */struct sk_buff ** (* gro_receive) (struct sk_buff ** head, struct sk_buff * skb); int (* gro_complete) (struct sk_buff * skb);/* points to the Private Data Pointer used by the Protocol. Generally, */void * af_packet_priv is not used; /* connect the struct to the corresponding hash linked list */struct list_head list ;};


The linux kernel defines a hash table ptype_base. The hash key is the type field in struct packet_type. Each element in the table points to a chain table of struct packet_type.


A chain table ptype_all of struct packet_type is also defined. The protocol processing program on this linked list receives packets of the Protocol. It is mainly used for network tools and network sniffer to receive packets. For example, the tcpdump package capture program and the original socket use this type of packet_type structure.

/*      0800    IP *      8100    802.1Q VLAN *      0001    802.3 *      0002    AX.25 *      0004    802.2 *      8035    RARP *      0005    SNAP *      0805    X.25 *      0806    ARP *      8137    IPX *      0009    Localtalk *      86DD    IPv6 */#define PTYPE_HASH_SIZE (16)#define PTYPE_HASH_MASK (PTYPE_HASH_SIZE - 1)static DEFINE_SPINLOCK(ptype_lock);static struct list_head ptype_base[PTYPE_HASH_SIZE] __read_mostly;static struct list_head ptype_all __read_mostly;    /* Taps */


This hash table and a linked list form an interface for receiving data between the data link layer and the network layer.


In linux, use the following functions to add and delete protocols:


Add protocol:

Void dev_add_pack (struct packet_type * pt) {int hash;/* The ptype_all linked list is protected by the ptype_lock spin lock. This spin lock is used to protect the ptype_bash hash table when writing data, and rcu lock is used to protect the read data. In essence, it is forbidden to preemptible the space when reading the data */spin_lock_bh (& ptype_lock ); if (pt-> type = htons (ETH_P_ALL) list_add_rcu (& pt-> list, & ptype_all); else {hash = ntohs (pt-> type) & PTYPE_HASH_MASK; list_add_rcu (& pt-> list, & ptype_base [hash]);} spin_unlock_bh (& ptype_lock );}


If the protocol type is defined as ETH_P_ALL, all types of packets are received. Add the packet_type to the ptyte_all linked list.


Remove protocol:

Void _ dev_remove_pack (struct packet_type * pt) {struct list_head * head; struct packet_type * pt1; spin_lock_bh (& ptype_lock); if (pt-> type = htons (ETH_P_ALL )) head = & ptype_all; else head = & ptype_base [ntohs (pt-> type) & PTYPE_HASH_MASK]; list_for_each_entry (pt1, head, list) {if (pt = pt1) {list_del_rcu (& pt-> list); goto out;} out: FIG (& ptype_lock);} void dev_remove_pack (struct packet_type * pt) {_ dev_remove_pack (pt ); /* after the ptype is removed, wait until all processes on the cpu core are switched over and then return. This indicates that no process is in use for the removed ptype, you can safely perform the next step, such as releasing the memory occupied by the struct */synchronize_net ();}


Each Protocol needs to define its own paket_type variable and initialize its own data. Then called during self-protocol module initialization

Dev_add_packet adds its packet_type to the packet_base hash table.


Real entry functions of the protocol stackNetif_receive_skb ():


Int round (struct sk_buff * skb) {struct packet_type * ptype, * pt_prev; struct net_device * orig_dev; struct net_device * null_or_orig; int ret = NET_RX_DROP; _ be16 type; /* assign a value to skb to receive the timestamp */if (! Skb-> tstamp. tv64) net_timestamp (skb);/* If a vlan tag is included, determine whether the packet is sent to the layer-3 port of the local vlan. If yes, assign the received dev to the vlan dev */if (skb-> vlan_tci & vlan_hwaccel_do_receive (skb) return NET_RX_SUCCESS; /* netpoll is a virtual network card used to send and receive packets when the network device and I/O are not initialized, it is mainly used for remote debugging and network control terminal * // * if we 've gotten here through NAPI, check netpoll */if (netpoll_receive_skb (skb) return NET_RX_DROP; if (! Skb-> iif) skb-> iif = skb-> dev-> ifindex;/* process link aggregation. If the received dev is added to the aggregation group, replace the received dev with the aggregation port */null_or_orig = NULL; orig_dev = skb-> dev; if (orig_dev-> master) {if (skb_bond_should_drop (skb) null_or_orig = orig_dev; /* deliver only exact match */else skb-> dev = orig_dev-> master;}/* increase the number of pack Statistics */_ get_cpu_var (netdev_rx_stat ). total ++;/* initialize the following pointer in skb */skb_reset_network_header (skb); skb_reset_transport_header (skb ); Skb-> mac_len = skb-> network_header-skb-> mac_header; pt_prev = NULL;/* In ptype_base and ptype_base, use the rcu read lock to protect the critical zone */rcu_read_lock (); /* If the kernel registers a protocol sniffer, copy the skb and send it for processing. Note: after this round of loop, the execution function of the last protocol sniffer is not called and is put below for calling, because the last processing function of message processing is called without adding 1 to the skb user reference count, the next processing function passes the last ptype, if the function needs to process this skb, it should first execute the ptype processing function and then execute its own processing program */list_for_each_entry_rcu (ptype, & ptype_all, list) {if (ptype-> dev = null_or_orig | ptype-> dev = skb-> dev | ptype-> dev = orig_dev) {if (pt_prev) ret = deliver_skb (skb, pt_prev, orig_dev); pt_prev = ptype ;}/ * enter the bridge for layer-2 processing. If skb = NUL is returned L. It indicates that skb is directly forwarded by Layer 2 and no more network layer is required. The function returns */skb = handle_bridge (skb, & pt_prev, & ret, orig_dev); if (! Skb) goto out;/* processing vlan */skb = handle_macvlan (skb, & pt_prev, & ret, orig_dev); if (! Skb) goto out;/* after the preceding processing, the Protocol receiving function of the message is found in the ptype_base hash table, send to the corresponding protocol for processing */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 )) {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 {kfree_skb (skb);/* Jamal, now you will not able to escape explaining * me how you were going to use this. :-) */ret = NET_RX_DROP;} out: rcu_read_unlock (); return ret;} EXPORT_SYMBOL (netif_receive_skb );


Static inline int deliver_skb (struct sk_buff * skb, struct packet_type * pt_prev, struct net_device * orig_dev) {/* adds a reference count of skb when sending the corresponding protocol to receive functions, prevent being released during use. Because a message can be processed by receiving functions of multiple protocols. However, the receiving function of the last protocol does not need to add one to the reference count of skb, because the receiving function of the last protocol is responsible for releasing the memory occupied by the message */atomic_inc (& skb-> users ); return pt_prev-> func (skb, skb-> dev, pt_prev, orig_dev );}


This article is from the "Yao Yang blog" blog, please be sure to keep this source http://yaoyang.blog.51cto.com/7657153/1269713

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.