IP:網際協議

來源:互聯網
上載者:User

標籤:網路

   IP是TCP/IP協議族中最為核心的協議,所有的TCP,UDP,ICMP及IGMP資料都是以IP資料報的形式傳輸的


IP是一種不可靠的協議,也就是說,它並不能保證每個IP資料報都能成功地到達目的地,而只是提供最好的傳輸服務。如果發生某種錯誤(例如:某個路由器暫時用完了緩衝區),IP有一個簡單的錯誤處理演算法,即丟棄該資料報,然後發送ICMP訊息報給發送方。每個資料報的處理是相互獨立的,因此IP資料報可以不按發送順序接收。任何可靠性都必須由上層協議來提供,如TCP

IP資料報的輸入、輸出和轉寄,資料報控制資訊處理以及對端資訊塊的管理涉及以下檔案

include/net/ip.h    定義IP層相關的結構、宏和函數原型

include/linux/inetdevice.h   定義IPv4專用的網路裝置相關的結構、宏等

include/linux/errqueue.h     定義差錯處理相關的結構

include/net/inetpeer.h       定義對端資訊塊的結構、宏和函數原型

include/net/dst.h            定義目的路由緩衝相關結構、宏和函數原型

net/ipv4/ip_output.c         IP資料報的輸出

net/ipv4/ip_sockglue.c       IP層套介面選項

net/ipv4/ip_input.c          IP資料報的輸入

net/ipv4/ip_forward.c        IP資料報的轉寄

net/ipv4/inetpeer.c          對端資訊塊的管理

net/ipv4/af_inet.c           網路層和傳輸層介面

IP資料報的報文格式

參見tcp/ip協議學習筆記(3)Internet Protocol(IP)

IP資料報的輸入與輸出

網路層處於傳輸層和鏈路層之間,同時還需要與路由表以及鄰居子系統打交道。在輸入資料時,提供輸入介面給鏈路層調用,並調用傳輸層的輸入介面將資料傳遞到傳輸層。在資料輸出時,提供輸出介面給傳輸層調用,並調用鏈路層的輸出介面將資料輸出到鏈路層。輸入和輸出過程中,都需要尋找路由,通過netfilter處理等


IP的私人資訊控制區塊

IP層在SKB中有個資訊控制區塊struct inet_skb_parm結構,儲存在skb_buff結構中的cb成員中。IP層用宏IPCB訪問該結構以增強代碼的可讀性。這個私人的資訊控制區塊主要儲存IP選項以及在IP處理中需要設定的標誌。

在IP層,無論是輸入還是輸出都需要處理IP選項。例如,輸入時,ip_rcv_option()會解析IP首部中的選項儲存到inet_skb_parm結構的opt;在輸出時,ip_options_build()會根據inet_skb_parm結構的opt將其組織後在IP首部產生選項,而在轉寄時,ip_forward_options()會根據選項做適當處理。

struct inet_skb_parm{struct ip_optionsopt;/* Compiled IP options*/unsigned charflags;#define IPSKB_FORWARDED1#define IPSKB_XFRM_TUNNEL_SIZE2#define IPSKB_XFRM_TRANSFORMED4#define IPSKB_FRAG_COMPLETE8#define IPSKB_REROUTED16};#define IPCB(skb) ((struct inet_skb_parm*)((skb)->cb))
IP層套介面選項IP層套介面選項入口為ip_setsockopt()。該函數首先判斷選項的層級,如果不是SOL_IP層級,則返回無效的協議,否則調用do_ip_setsockopt()進行具體的選項處理。而在do_ip_setsockopt()中,組播路由相關的選項由ip_mroute_opt()來處理,其他選項則由該函數自己處理。

IP層套介面選項如下:

1)IP_OPTIONS

設定或擷取將由套介面發送的每個資料報IP首部中的IP選項,最長可達40B。該參數是一個指向資料報含選項和選項長度的儲存緩衝區的指標。

2)IP_PKTINFO

控制是否允許通過IP_PKTOPTIONS選項或recvmsg系統調用來擷取與本地地址等資訊相關的IP_PKTOPTIONS選項

3)IP_TTL

設定輸出IP資料報的存留時間,有效值為1至255。IP資料報每經過一個路由器,路由器都會判斷TTL的值,並將該值遞減1,一旦發現其為0,即丟棄資料報,以免由於路由迴圈,造成資料報無休止地在網路中的”遊盪“

具體選擇如下,不一一列舉了

include/linux/in.h

#define IP_TOS1#define IP_TTL2#define IP_HDRINCL3#define IP_OPTIONS4#define IP_ROUTER_ALERT5#define IP_RECVOPTS6#define IP_RETOPTS7#define IP_PKTINFO8#define IP_PKTOPTIONS9#define IP_MTU_DISCOVER10#define IP_RECVERR11#define IP_RECVTTL12#defineIP_RECVTOS13#define IP_MTU14#define IP_FREEBIND15#define IP_IPSEC_POLICY16#define IP_XFRM_POLICY17#define IP_PASSSEC18#define IP_TRANSPARENT19/* BSD compatibility */#define IP_RECVRETOPTSIP_RETOPTS/* TProxy original addresses */#define IP_ORIGDSTADDR       20
ipv4_devconfipv4_devconf結構是網路裝置介面的IPv4系統配置。在核心中有一個名為ipv4_devconf的系統全域變數,該配置對所有介面有效。另外,每個網路裝置的IP控制塊中也都存在一份配置,但該配置只對所在網路裝置有效。

enum{NET_IPV4_CONF_FORWARDING=1,NET_IPV4_CONF_MC_FORWARDING=2,NET_IPV4_CONF_PROXY_ARP=3,NET_IPV4_CONF_ACCEPT_REDIRECTS=4,NET_IPV4_CONF_SECURE_REDIRECTS=5,NET_IPV4_CONF_SEND_REDIRECTS=6,NET_IPV4_CONF_SHARED_MEDIA=7,NET_IPV4_CONF_RP_FILTER=8,NET_IPV4_CONF_ACCEPT_SOURCE_ROUTE=9,NET_IPV4_CONF_BOOTP_RELAY=10,NET_IPV4_CONF_LOG_MARTIANS=11,NET_IPV4_CONF_TAG=12,NET_IPV4_CONF_ARPFILTER=13,NET_IPV4_CONF_MEDIUM_ID=14,NET_IPV4_CONF_NOXFRM=15,NET_IPV4_CONF_NOPOLICY=16,NET_IPV4_CONF_FORCE_IGMP_VERSION=17,NET_IPV4_CONF_ARP_ANNOUNCE=18,NET_IPV4_CONF_ARP_IGNORE=19,NET_IPV4_CONF_PROMOTE_SECONDARIES=20,NET_IPV4_CONF_ARP_ACCEPT=21,NET_IPV4_CONF_ARP_NOTIFY=22,NET_IPV4_CONF_SRC_VMARK=24,__NET_IPV4_CONF_MAX};struct ipv4_devconf{void*sysctl;intdata[__NET_IPV4_CONF_MAX - 1];DECLARE_BITMAP(state, __NET_IPV4_CONF_MAX - 1);};
NET_IPV4_CONF_FORWARDING

標識是否啟用IP資料報轉寄功能

NET_IPV4_CONF_PROXY_ARP

標識是否啟用ARP代理功能

套介面錯誤隊列

在傳輸控制塊中有一個用於儲存錯誤資訊的隊列sk_error_queue,當ICMP接收到差錯資訊或者UDP套介面和RAW套介面輸出報文出錯時,會產生描述錯誤資訊的SKB添加到該隊列上。應用程式為能通過系統調用擷取詳細的錯誤資訊,需要設定IP_RECVERR套介面選項,之後可通過參數flags為MSG_ERRQUEUE的recvmsg系統調用來擷取詳細的出錯資訊。

錯誤資訊的資料流及函數調用關係


在基於串連的套介面上,IP_RECVERR意義則會有所不同。並不儲存錯誤資訊到錯誤隊列中,而是立即傳遞所有接收到的錯誤資訊給使用者進程。這對於基於短串連的TCP應用是很有用的,因為TCP要求快速的錯誤處理。需要注意的是,TCP沒有錯誤隊列,MSG_ERRQUEUE對於基於串連的套介面時無效的。

錯誤資訊傳遞給使用者時,並不將錯誤資訊作為報文的內容傳遞給使用者進程,而是以錯誤資訊塊的形式儲存在SKB控制塊中,通過SKB_EXT_ERR來訪問SKB控制塊中的錯誤資訊塊

#define SKB_EXT_ERR(skb) ((struct sock_exterr_skb *) ((skb)->cb))struct sock_exterr_skb{union {struct inet_skb_parmh4;#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)struct inet6_skb_parmh6;#endif} header;struct sock_extended_erree;u16addr_offset;__be16port;};

由於該錯誤也在IP層中處理,為了與IP控制塊兼用,錯誤資訊塊的前部由IP控制塊組成,之後才是出錯資訊

添加ICMP差錯資訊

當接收到ICMP差錯資訊時,ICMP模組會根據出錯的未經處理資料報的傳輸層協議,調用傳輸層的差錯處理常式,而傳輸層的差錯處理常式會進而調用ip_icmp_error()將出錯資訊添加到輸出該錯誤資料報的傳輸控制塊錯誤隊列上。

void ip_icmp_error(struct sock *sk, struct sk_buff *skb, int err,   __be16 port, u32 info, u8 *payload){struct inet_sock *inet = inet_sk(sk);struct sock_exterr_skb *serr;if (!inet->recverr)return;skb = skb_clone(skb, GFP_ATOMIC);if (!skb)return;serr = SKB_EXT_ERR(skb);serr->ee.ee_errno = err;serr->ee.ee_origin = SO_EE_ORIGIN_ICMP;serr->ee.ee_type = icmp_hdr(skb)->type;serr->ee.ee_code = icmp_hdr(skb)->code;serr->ee.ee_pad = 0;serr->ee.ee_info = info;serr->ee.ee_data = 0;serr->addr_offset = (u8 *)&(((struct iphdr *)(icmp_hdr(skb) + 1))->daddr) -   skb_network_header(skb);serr->port = port;if (skb_pull(skb, payload - skb->data) != NULL) {skb_reset_transport_header(skb);if (sock_queue_err_skb(sk, skb) == 0)return;}kfree_skb(skb);}
sk,輸出錯誤資料報的傳輸控制塊

skb,從ICMP模組傳遞到傳輸層的ICMP差錯報文

err,發生錯誤的錯誤碼

port,對於UDP是出錯報文的目的連接埠,其他情況下都為0

info,錯誤資訊的擴充資訊

payload,指向產生ICMP差錯的未經處理資料報中應用程式層的內容

添加由本地產生的差錯資訊

當UDP套介面或RAW套介面發送資料時,如果待發送資料的長度超過IP資料報能負載的長度,會調用ip_local_error()將資料報資料超長的出錯資訊添加到輸出該出錯報文的傳輸控制塊錯誤隊列上。ip_local_error()的實現和ip_icmp_error()的實作類別似,區別在於出錯資訊來源為本地

void ip_local_error(struct sock *sk, int err, __be32 daddr, __be16 port, u32 info){struct inet_sock *inet = inet_sk(sk);struct sock_exterr_skb *serr;struct iphdr *iph;struct sk_buff *skb;if (!inet->recverr)return;skb = alloc_skb(sizeof(struct iphdr), GFP_ATOMIC);if (!skb)return;skb_put(skb, sizeof(struct iphdr));skb_reset_network_header(skb);iph = ip_hdr(skb);iph->daddr = daddr;serr = SKB_EXT_ERR(skb);serr->ee.ee_errno = err;serr->ee.ee_origin = SO_EE_ORIGIN_LOCAL;serr->ee.ee_type = 0;serr->ee.ee_code = 0;serr->ee.ee_pad = 0;serr->ee.ee_info = info;serr->ee.ee_data = 0;serr->addr_offset = (u8 *)&iph->daddr - skb_network_header(skb);serr->port = port;__skb_pull(skb, skb_tail_pointer(skb) - skb->data);skb_reset_transport_header(skb);if (sock_queue_err_skb(sk, skb))kfree_skb(skb);}
讀取錯誤資訊

通常,recvmsg()是用來接收遠端發送到到所在套介面的資料的,但也可通過設定flags為MSG_ERRQUEUE來讀取傳輸控制塊錯誤隊列上的錯誤資訊。在UDP套介面和RAW套介面的recvmsg()的實現中,先檢測是否存在MSG_ERRQUEUE標誌,如果有,則直接調用ip_recv_error()從傳輸控制塊的錯誤隊列中讀取錯誤資訊後返回。

/* *Handle MSG_ERRQUEUE */int ip_recv_error(struct sock *sk, struct msghdr *msg, int len){struct sock_exterr_skb *serr;struct sk_buff *skb, *skb2;struct sockaddr_in *sin;struct {struct sock_extended_err ee;struct sockaddr_in offender;} errhdr;int err;int copied;err = -EAGAIN;skb = skb_dequeue(&sk->sk_error_queue);if (skb == NULL)goto out;copied = skb->len;if (copied > len) {msg->msg_flags |= MSG_TRUNC;copied = len;}err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);if (err)goto out_free_skb;sock_recv_timestamp(msg, sk, skb);serr = SKB_EXT_ERR(skb);sin = (struct sockaddr_in *)msg->msg_name;if (sin) {sin->sin_family = AF_INET;sin->sin_addr.s_addr = *(__be32 *)(skb_network_header(skb) +   serr->addr_offset);sin->sin_port = serr->port;memset(&sin->sin_zero, 0, sizeof(sin->sin_zero));}memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err));sin = &errhdr.offender;sin->sin_family = AF_UNSPEC;if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP) {struct inet_sock *inet = inet_sk(sk);sin->sin_family = AF_INET;sin->sin_addr.s_addr = ip_hdr(skb)->saddr;sin->sin_port = 0;memset(&sin->sin_zero, 0, sizeof(sin->sin_zero));if (inet->cmsg_flags)ip_cmsg_recv(msg, skb);}put_cmsg(msg, SOL_IP, IP_RECVERR, sizeof(errhdr), &errhdr);/* Now we could try to dump offended packet options */msg->msg_flags |= MSG_ERRQUEUE;err = copied;/* Reset and regenerate socket error */spin_lock_bh(&sk->sk_error_queue.lock);sk->sk_err = 0;skb2 = skb_peek(&sk->sk_error_queue);if (skb2 != NULL) {sk->sk_err = SKB_EXT_ERR(skb2)->ee.ee_errno;spin_unlock_bh(&sk->sk_error_queue.lock);sk->sk_error_report(sk);} elsespin_unlock_bh(&sk->sk_error_queue.lock);out_free_skb:kfree_skb(skb);out:return err;}
對端資訊塊

對端資訊塊由inet_peer結構描述,用來儲存對端的一些資訊,包括對端的地址以及傳輸層使用的時間戳記等。主要用於在組裝IP資料報時防止分區攻擊,在建立TCP串連時檢測串連請求段是否有效以及其序號是否迴繞。

struct inet_peer{/* group together avl_left,avl_right,v4daddr to speedup lookups */struct inet_peer*avl_left, *avl_right;__be32v4daddr;/* peer's address */__u16avl_height;__u16ip_id_count;/* IP ID for the next packet */struct list_headunused;__u32dtime;/* the time of last use of not * referenced entries */atomic_trefcnt;atomic_trid;/* Frag reception counter */__u32tcp_ts;unsigned longtcp_ts_stamp;};
對端資訊塊的建立和尋找

對端資訊塊的建立和尋找都是通過inet_getpeer()來實現的,由參數create來區分是建立還是尋找

/* Called with or without local BH being disabled. */struct inet_peer *inet_getpeer(__be32 daddr, int create){struct inet_peer *p, *n;struct inet_peer **stack[PEER_MAXDEPTH], ***stackptr;/* Look up for the address quickly. */read_lock_bh(&peer_pool_lock);p = lookup(daddr, NULL);if (p != peer_avl_empty)atomic_inc(&p->refcnt);read_unlock_bh(&peer_pool_lock);if (p != peer_avl_empty) {/* The existing node has been found. *//* Remove the entry from unused list if it was there. */unlink_from_unused(p);return p;}if (!create)return NULL;/* Allocate the space outside the locked region. */n = kmem_cache_alloc(peer_cachep, GFP_ATOMIC);if (n == NULL)return NULL;n->v4daddr = daddr;atomic_set(&n->refcnt, 1);atomic_set(&n->rid, 0);n->ip_id_count = secure_ip_id(daddr);n->tcp_ts_stamp = 0;write_lock_bh(&peer_pool_lock);/* Check if an entry has suddenly appeared. */p = lookup(daddr, stack);if (p != peer_avl_empty)goto out_free;/* Link the node. */link_to_pool(n);INIT_LIST_HEAD(&n->unused);peer_total++;write_unlock_bh(&peer_pool_lock);if (peer_total >= inet_peer_threshold)/* Remove one less-recently-used entry. */cleanup_once(0);return n;out_free:/* The appropriate node is already in the pool. */atomic_inc(&p->refcnt);write_unlock_bh(&peer_pool_lock);/* Remove the entry from unused list if it was there. */unlink_from_unused(p);/* Free preallocated the preallocated node. */kmem_cache_free(peer_cachep, n);return p;}
對端資訊塊的刪除

當使用完對端資訊塊之後,需要將其刪除並釋放。實際上,inet_putpeer()只是將該對端資訊塊添加到unused_peers鏈表中,表示該對端資訊塊當前沒有被使用。而真正的刪除和釋放,由記憶體回收機制來處理

void inet_putpeer(struct inet_peer *p){spin_lock_bh(&inet_peer_unused_lock);if (atomic_dec_and_test(&p->refcnt)) {list_add_tail(&p->unused, &unused_peers);p->dtime = (__u32)jiffies;}spin_unlock_bh(&inet_peer_unused_lock);}
記憶體回收

處理記憶體回收的方式有兩種---同步和非同步。同步方式通常是在建立對端資訊塊時發現當前對端資訊塊數達到inet_peer_threshold時觸發,而非同步方式則是在定時器逾時觸發。

正在使用的對端資訊塊是不會到期的,只有閑置的對端資訊塊才有可能到期,因為對端資訊塊一旦閑置,就會被添加到unused_peers鏈表中,並記錄閑置的時間。在同步或非同步清理是,一旦發現閑置時間達到閾值,對端資訊塊就會到期。對端資訊塊的到期與inet_peer_minttl、inet_peer_maxttl和inet_peer_threshold有關

同步清理

struct inet_peer *inet_getpeer(__be32 daddr, int create)
{

...
if (peer_total >= inet_peer_threshold)
/* Remove one less-recently-used entry. */
cleanup_once(0);

...
}

非同步清理

同步回收來及用於處理記憶體壓力較大的特殊情況,事實上這種情況比較少見,同時也是非常影響效能的。因此為了避免這種特殊情況的出現或降低其出現的機率,使用peer_periodic_timer定時器來進行周期性回收,該定時器處理常式為peer_check_expire()。其時間間隔在inet_initpeers()中設定

/* Called with local BH disabled. */static void peer_check_expire(unsigned long dummy){unsigned long now = jiffies;int ttl;if (peer_total >= inet_peer_threshold)ttl = inet_peer_minttl;elsettl = inet_peer_maxttl- (inet_peer_maxttl - inet_peer_minttl) / HZ *peer_total / inet_peer_threshold * HZ;while (!cleanup_once(ttl)) {if (jiffies != now)break;}/* Trigger the timer after inet_peer_gc_mintime .. inet_peer_gc_maxtime * interval depending on the total number of entries (more entries, * less interval). */if (peer_total >= inet_peer_threshold)peer_periodic_timer.expires = jiffies + inet_peer_gc_mintime;elsepeer_periodic_timer.expires = jiffies+ inet_peer_gc_maxtime- (inet_peer_gc_maxtime - inet_peer_gc_mintime) / HZ *peer_total / inet_peer_threshold * HZ;add_timer(&peer_periodic_timer);}

IP:網際協議

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

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.