読者です 読者をやめる 読者になる 読者になる

TenForward

技術ブログ。はてなダイアリーから移転しました

Linux 3.3 の新機能 Network priority cgroup (2)

Linux

前回,Linux 3.3 の新機能 Network priority cgroup - TenForwardの日記で行った Network priority cgroup を久々に調べていました.調べたのはこの優先度の設定がどこで設定されるか?って所ですが,この機能のコミットは結構シンプルなので,すぐにわかりました.

優先度を調整しているのは net/core/dev.c 内の skb_update_prio という関数ですね.

#if IS_ENABLED(CONFIG_NETPRIO_CGROUP)
static void skb_update_prio(struct sk_buff *skb)
{
       struct netprio_map *map = rcu_dereference(skb->dev->priomap);

       if ((!skb->priority) && (skb->sk) && map)
               skb->priority = map->priomap[skb->sk->sk_cgrp_prioidx];
}
#else
#define skb_update_prio(skb)
#endif

詳しくは追ってないですが,ここで文字通り優先度の設定をやってるみたいですね.この関数はというと,同じく dev.c 内の実際に送信を行う関数 dev_queue_xmit 内の最初の方で呼ばれています.

int dev_queue_xmit(struct sk_buff *skb)
{
	struct net_device *dev = skb->dev;
	struct netdev_queue *txq;
	struct Qdisc *q;
	int rc = -ENOMEM;

	/* Disable soft irqs for various locks below. Also
	 * stops preemption for RCU.
	 */
	rcu_read_lock_bh();

	skb_update_prio(skb);

	txq = dev_pick_tx(dev, skb);
	q = rcu_dereference_bh(txq->qdisc);

#ifdef CONFIG_NET_CLS_ACT
	skb->tc_verd = SET_TC_AT(skb->tc_verd, AT_EGRESS);
#endif
	trace_net_dev_queue(skb);
	if (q->enqueue) {
		rc = __dev_xmit_skb(skb, q, dev, txq);
		goto out;
	}

__dev_xmit_skb 内で送信キューに積んだり,送信を開始したりしていますから,その直前に入れ替えてるみたいですね.

優先度の設定はというと,net/core/socket.c 内で sock_update_netprioidx という関数があり,ここで sock 構造体の優先度を表すメンバを更新しています.この関数は net/core/sock.c の sk_alloc というソケットをアロケートしている (っぽい) 関数で呼ばれていますね.(他にも net/socket.c の __sock_sendmsg_nosec でも呼ばれていますね,こちらはまた時間があれば後日...)

struct sock *sk_alloc(struct net *net, int family, gfp_t priority,
		      struct proto *prot)
{
	struct sock *sk;

	sk = sk_prot_alloc(prot, priority | __GFP_ZERO, family);
	if (sk) {
		sk->sk_family = family;
		/*
		 * See comment in struct sock definition to understand
		 * why we need sk_prot_creator -acme
		 */
		sk->sk_prot = sk->sk_prot_creator = prot;
		sock_lock_init(sk);
		sock_net_set(sk, get_net(net));
		atomic_set(&sk->sk_wmem_alloc, 1);

		sock_update_classid(sk);
		sock_update_netprioidx(sk);
	}

	return sk;
}