前回,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; }