We briefly understand how the L4 layer protocol and the raw IP interact with the IP layer.
L4 Layer Protocol
The L4 layer protocol can be added to the kernel through both static compilation and module configuration.
More important protocols such as TCP, UDP, and ICMP are usually statically compiled into the kernel.
Some infrequently used or more special protocols are added to the kernel through kernel configuration. such as Igmp,sctp,ipip and so on.
Registration of the L4 layer protocol
The L4 layer protocol has a NET_PROTOCOL structure definition:
/* This is used to register protocols. */struct net_protocol { int (*handler) (struct sk_buff *skb)///protocol registered, function for handling ingress packets //functions used by the ICMP protocol handler function, Notifies L4 layer void (*err_handler) when ICMP unreachable is received (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,//Make protocol exempt from IPSec check netns_ok:1;};
The protocol is registered as Inet_add_protocol, and if the protocol is in the form of a module, it can be de-inet_del_protocol (the module has a delisting function).
/* * ADD a protocol handler to the hash tables */int inet_add_protocol (const struct NET_PROTOCOL *prot, unsigned char Pro Tocol) { int hash, ret; hash = protocol & (MAX_INET_PROTOS-1); SPIN_LOCK_BH (&inet_proto_lock); if (Inet_protos[hash]) {ret =-1; } else {Inet_protos[hash] = prot; ret = 0; } spin_unlock_bh (&inet_proto_lock); return ret;} /* * Remove a protocol from the hash tables. */int inet_del_protocol (const struct NET_PROTOCOL *prot, unsigned char protocol) {int hash, ret; hash = protocol & (MAX_INET_PROTOS-1); SPIN_LOCK_BH (&inet_proto_lock); if (inet_protos[hash] = = Prot) {Inet_protos[hash] = NULL; ret = 0; } else {ret =-1; } spin_unlock_bh (&inet_proto_lock); Synchronize_net (); return ret;} Export_symbol ( INET_ADD_PROTOCOL); Export_symbol (Inet_del_protocol);
Let's look at a concrete example:
The following is the initialization of TCP, UDP, and ICMP protocol structures, which should be done first:
static const struct Net_protocol Tcp_protocol = { . Handler = Tcp_v4_rcv, . Err_handler = Tcp_v4_err, . Gso_send_check = Tcp_v4_gso_send_check, . gso_segment = tcp_tso_segment, . gro_receive = tcp4_ Gro_receive, . Gro_complete = Tcp4_gro_complete, . No_policy = 1, . NETNS_OK = 1,};static const struct Net_protocol Udp_protocol = { . Handler = Udp_rcv, . Err_handler = Udp_err, . Gso_send_ Check = Udp4_ufo_send_check, . gso_segment = Udp4_ufo_fragment, . No_policy = 1, . NETNS_OK = 1,}; static const struct Net_protocol Icmp_protocol = { . Handler = Icmp_rcv, . No_policy = 1, . NETNS_OK = 1,};
After initialization of the protocol structure, in Inet_init, the various protocols are added to the kernel.
static int __init inet_init (void) {struct Sk_buff *dummy_skb; struct INET_PROTOSW *q; struct List_head *r; int rc =-einval; build_bug_on (sizeof (struct inet_skb_parm) > sizeof (DUMMY_SKB->CB)); rc = Proto_register (&tcp_prot, 1); if (RC) goto out; 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; /* Tell sockets that we are alive ... */(void) sock_register (&inet_family_ops); #ifdef config_sysctl Ip_ Static_sysctl_init (); #endif/* * ADD all the base protocols. */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 th e 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 (); Dev_add_pack (&ip_packet_type); rc = 0;out:return rc;out_unregister_udp_proto:proto_unregister (&udp_prot); Out_unregister_tcp_proto:proto_u Nregister (&tcp_prot); Goto out;}
As can be seen from the code, TCP, UDP, ICMP, etc. are directly statically compiled to the kernel. IGMP only has the kernel configured for multicast to be added to the kernel in the form of a module.
L3 to L4 packet delivery: Ip_local_deliver_finishraw sockets and Raw IP
We need to know that not all L4 layer processing is implemented in the kernel. Applications can bypass the L4 layer protocol through RAW sockets and raw IP, interacting directly with the IP layer.
In-depth understanding of Linux Network Technology Insider--L4 layer protocol and raw IP processing