閱讀956 返回首頁    go 技術社區[雲棲]


網絡子係統82_inet協議族-SOCK_RAW(三)

//	向raw sock傳遞skb
//	步驟:
//		1.根據協議號獲取監聽指定protocol的sock
//		2.向raw sock傳遞skb
1.1 int raw_local_deliver(struct sk_buff *skb, int protocol)
{
	int hash;
	struct sock *raw_sk;

	//獲取監聽指定協議的raw sock
	hash = protocol & (RAW_HTABLE_SIZE - 1);
	raw_sk = sk_head(&raw_v4_hashinfo.ht[hash]);
	//向raw socket傳遞
	if (raw_sk && !raw_v4_input(skb, ip_hdr(skb), hash))
		raw_sk = NULL;

	return raw_sk != NULL;
}

//	向raw sock傳遞skb
//	步驟:
//		1.獲取raw sock鏈表, 查找可接收此skb的sock
//			1.1 如果raw sock指定了協議號,源地址,目的地址,設備號,則逐項匹配
//		2.向sock傳遞skb的拷貝
1.2 static int raw_v4_input(struct sk_buff *skb, const struct iphdr *iph, int hash)
{
	struct sock *sk;
	struct hlist_head *head;
	int delivered = 0;
	struct net *net;

	read_lock(&raw_v4_hashinfo.lock);
	head = &raw_v4_hashinfo.ht[hash];
	if (hlist_empty(head))
		goto out;

	net = dev_net(skb->dev);
	sk = __raw_v4_lookup(net, __sk_head(head), iph->protocol,
			     iph->saddr, iph->daddr,
			     skb->dev->ifindex);

	while (sk) {
		delivered = 1;
		//如果有注冊的sock raw,傳遞一份skb拷貝
		struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC);

		if (clone)
			raw_rcv(sk, clone);
		//匹配sock,協議號,源地址,目的地址,設備號
		sk = __raw_v4_lookup(net, sk_next(sk), iph->protocol,
				     iph->saddr, iph->daddr,
				     skb->dev->ifindex);
	}
out:
	read_unlock(&raw_v4_hashinfo.lock);
	return delivered;
}
//	添加skb到sock隊列
//	步驟:
//		1.調整skb->data指向ip報頭
//		2.添加skb到struct sock的接收隊列
1.3 int raw_rcv(struct sock *sk, struct sk_buff *skb)
{
	
	//調整skb->data指針指向ip報頭
	skb_push(skb, skb->data - skb_network_header(skb));
	//添加skb到struct sock隊列上
	raw_rcv_skb(sk, skb);
	return 0;
}

//	添加skb到sock隊列
//	步驟:
//		1.斷開skb與入口設備之間的聯係
//		2.將skb添加到sock->sk_receive_queue
//		3.通知sock數據已經準備好
1.4 int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
{
	int err;
	int skb_len;
	unsigned long flags;
	struct sk_buff_head *list = &sk->sk_receive_queue;

	//接收緩存用完
	if (atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf) {
		atomic_inc(&sk->sk_drops);
		trace_sock_rcvqueue_full(sk, skb);
		return -ENOMEM;
	}

	//清除skb的入口設備描述符
	skb->dev = NULL;
	//skb由sock擁有
	skb_set_owner_r(skb, sk);
	skb_len = skb->len;

	//接收隊列鎖
	spin_lock_irqsave(&list->lock, flags);
	skb->dropcount = atomic_read(&sk->sk_drops);
	//將skb添加到sock->sk_receive_queue
	__skb_queue_tail(list, skb);
	spin_unlock_irqrestore(&list->lock, flags);

	//在sock_init_data中初始化為sock_def_readable
	sk->sk_data_ready(sk, skb_len);
	return 0;
}

最後更新:2017-04-03 12:55:18

  上一篇:go JAVA線程同步(二)
  下一篇:go 網絡子係統84_sock事件通知進程