linux通過tc控制網路QoS(2)

來源:互聯網
上載者:User

先來看下traffic control在核心裡是如何?的,首先核心在發送資料時,最終會調用到dev_queue_xmit,

    struct Qdisc *q

    if (q->enqueue) {
        rc = __dev_xmit_skb(skb, q, dev, txq);
        goto out;
    }   

如果q->enqueue函數不為空白,此時就進入traffic control的邏輯,下面調用__dev_xmit_skb

static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q,
                 struct net_device *dev,
                 struct netdev_queue *txq)

函數會判斷Qdisc->state狀態,如果__QDISC_STATE_DEACTIVATED,那麼free skb返回NET_XMIT_DROP。如果Qdisc->state狀態為非__QDISC_STATE_RUNNING,同時Qdisc的標籤有TCQ_F_CAN_BYPASS,那麼直接把包發出去。否則調用qdisc_enqueue_skb把skb放到root Qdisc中,再調用qdisc_run

qdisc_run如果判斷Qdisc->state為__QDISC_STATE_RUNNING,則調用__qdisc_run,

void __qdisc_run(struct Qdisc *q)
{
    unsigned long start_time = jiffies;

    while (qdisc_restart(q)) {
        /*
         * Postpone processing if
         * 1. another process needs the CPU;
         * 2. we've been doing it for too long.
         */
        if (need_resched() || jiffies != start_time) {
            __netif_schedule(q);
            break;
        }
    }

    clear_bit(__QDISC_STATE_RUNNING, &q->state);
}

__qdisc_run會迴圈調用qdisc_restart,直到消耗了一個jiffy或者該CPU需要被調度給其他進程(need_resched),此時調用__netif_reschedule把當前CPU的softnet_data->output_queue交給Qdisc->output_queue,並觸發一個NET_TX_SOFTIRQ非強制中斷

qdisc_restart函數如下:

static inline int qdisc_restart(struct Qdisc *q)
{
    struct netdev_queue *txq;
    struct net_device *dev;
    spinlock_t *root_lock;
    struct sk_buff *skb;

    /* Dequeue packet */
    skb = dequeue_skb(q);
    if (unlikely(!skb))
        return 0;

    root_lock = qdisc_lock(q);
    dev = qdisc_dev(q);
    txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb));

    return sch_direct_xmit(skb, q, dev, txq, root_lock);
}

qdisc_restart從Qdisc頭裡取一個skb出來,調用qdisc_lock擷取一個Qdisc根鎖,然後調用netdev_get_tx_queue基於skb雜湊擷取netdev_queue隊列,調用sch_direct_xmit直接把skb發送出去

sch_direct_xmit先調用qdisc_unlock釋放Qdisc根鎖,調用dev_hard_start_xmit通過驅動發送skb,然後判斷傳回值,如果是NETDEV_TX_OK,返回qdisc_qlen的Qdisc隊列長度;如果是NETDEV_TX_LOCKED,此時出現了鎖異常,這裡不深入探討了;如果返回了NETDEV_TX_BUSY,則調用dev_requeue_skb把skb重新入隊列

traffic control還支援對入包進行控制,核心對於入包會調用netif_receive_skb,該函數會調用handle_ing。handle_ing首先判斷skb->dev->rx_queue.qdisc是否是noop_qdisc,如果是noop_qdisc那麼不會有任何QoS控制,否則調用ing_filter

static int ing_filter(struct sk_buff *skb)
{
    struct net_device *dev = skb->dev;
    u32 ttl = G_TC_RTTL(skb->tc_verd);
    struct netdev_queue *rxq;
    int result = TC_ACT_OK;
    struct Qdisc *q;
    
    if (MAX_RED_LOOP < ttl++) {
        printk(KERN_WARNING
               "Redir loop detected Dropping packet (%d->%d)\n",
               skb->iif, dev->ifindex);
        return TC_ACT_SHOT;
    }   

    skb->tc_verd = SET_TC_RTTL(skb->tc_verd, ttl);
    skb->tc_verd = SET_TC_AT(skb->tc_verd, AT_INGRESS);
    rxq = &dev->rx_queue;    
    q = rxq->qdisc;
    if (q != &noop_qdisc) {
        spin_lock(qdisc_lock(q));
        if (likely(!test_bit(__QDISC_STATE_DEACTIVATED, &q->state)))
            result = qdisc_enqueue_root(skb, q);
        spin_unlock(qdisc_lock(q));
    }    
    return result;
}

ing_filter首先找出skb->dev->rx_queue.qdisc,如果不是noop_qdisc,同時狀態為非__QDISC_STATE_DEACTIVATED,則調用qdisc_enqueue_root,把skb入隊列

可以看出,如果網路裝置支援traffic control,其驅動的收發函數必須要支援Qdisc的enqueue/dequeue,從測試結果和代碼上看,xen netback就可以支援,而bridge就無法支援

對於xen netback而言,限制虛擬機器出包QoS有兩種方法,首先要知道,netfront發包到了netback,會觸發netback的net_tx_action tasklet,裡面會調用net_tx_submit,繼而最終調用到netif_rx,還記得這個函數不,核心協議棧處理非NAPI的時候就是調用netif_rx來收包的。netif_rx會調用netif_receive_skb,裡面會有一個和handle_ing函數,用來對ingress的包做QoS,這就是第一種方法,對netback做tc
qdisc ingress規則來進行traffic control;

限制出包的第二鐘方法前面也提過啦,就是在橋接器上做mark神馬的,然後在物理口針對mark做traffic control,由於這裡是egress規則,因此可以用各種tc class來做。

那麼netback上限制虛擬機器入包呢?對於入包而言,首先從物理口進入橋接器,然後從橋接器進入netback,橋接器把包交換到網路裝置的過程中,會調用br_forward_finish,繼而調用br_dev_queue_push_xmit通過dev_queue_xmit把包“發”出去。因此限制虛擬機器入包QoS,只需要在netback上設定tc egress規則即可。由於netback是net_device裝置的一個超集,因此支援dev_queue_xmit方法,也支援egress方向的qdisc規則

最後,來看下ingress QoS的相關設定,核心內建的ingress qdisc的功能是非常簡單的,只支援最基本的rate limit,對於超出的流量一律drop,目前好的做法是通過一個虛擬網路裝置把ingress流量redirect到這個裝置上,再在這個虛擬設備設定traffic control規則

modprobe ifb

ip link set ifb0 up

ip link set ifb1 up

ifb裝置是核心用來做traffic control redirect的,驅動載入之後,可以對該裝置設定和egress相同的規則

tc qdisc add dev ifb0 root handle 1: htb default 100

tc class add dev ifb0 parent 1: classid 1:10 htb rate 100mbit ceil 100mbit

tc filter add dev ifb0 parent 1: protocol ip prio 1 u32 match ip src 0.0.0.0/0 flowid 1:10   #所有流量都match classid 1:10

最後還需要一條規則把peth0的入流量redirect到ifb0裝置上

tc qdisc add dev peth0 ingress

tc filter add dev peth0 parent ffff: protocol ip u32 match u32 0 0 action mirred egress redirect dev ifb0

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.