CORE網路資料包接收傳遞過程分析

來源:互聯網
上載者:User

標籤:

CORE網路資料包接收傳遞過程分析

 

能夠接收實際網路流量是CORE的一個顯著優點,這使得已有的系統能方便地接入虛擬網路進行類比。CORE對網路裝置的虛擬是通過LXC技術來實現的,而對網路的虛擬則是通過虛擬網卡(veth)、橋接器(Bridge)、Quagga來實現的。本文檔主要通過分析CORE中網路資料傳遞過程,來理解CORE網路類比。

拓撲結構

為了方便描述,以1所示拓撲結構為例子,分析資料流從網卡eth0到虛擬節點n2的過程。

 

圖1 樣本拓撲

虛擬網路建立由CORE後台根據前台的拓撲結構和配置,執行相應的命令進行實現,如下:

#建立容器n1

/usr/sbin/vnoded -v -c /tmp/pycore.52385/n1 -l /tmp/pycore.52385/n1.log -p /tmp/pycore.52385/n1.pid -C /tmp/pycore.52385/n1.conf

#建立容器n2

/usr/sbin/vnoded -v -c /tmp/pycore.52385/n2 -l /tmp/pycore.52385/n2.log -p /tmp/pycore.52385/n2.pid -C /tmp/pycore.52385/n2.conf

 

#建立橋接器br.38079.56309

/usr/sbin/brctl  addbr  b.38079.56309

#關閉spanning tree protocol and forwarding delay並啟動橋接器

/usr/sbin/brctl  stp    b.38079.56309  off

/usr/sbin/brctl  setfd  b.38079.56309   0

/sbin/ip link  set  b.38079.56309  up

#建立網路轉寄過濾器ebtables,規則為接收和轉寄

/sbin/ebtables  -N  b.38079.56309  -P  ACCEPT

/sbin/ebtables  -A  FORWARD  --logical- in  b.38079.56309 –j  b.38079.56309

#通過vcmd執行,關閉多播探測

echo‘0’> /sys/devices/virtual/net/b.38079.56311/bridge/multicast_snooping

 

#建立虛擬網卡n1.eth0.44

/sbin/ip  link  add  name  n1.eth0.44  type  veth  peer  name  n1.0.44

#將虛擬網卡加入到容器的命名空間中,並命名為eth0

/sbin/ip  link  set  n1.0.44  netns  17122     #17122為節點n1的vnoded進程的ID

/sbin/ip  link  set  n1.0.44  name  eth0

/sbin/ip  link  set  n1.eth0.44  up

 

#將虛擬網卡綁定到橋接器上

/usr/sbin/brctl  addif   b. 38079.56309   n1.eth0.44

/sbin/ip  link  set  n1.eth0.44  up

#通過vcmd執行,設定網卡mac地址

/sbin/ip  link  set  dev  eth0  address  00:00:00:aa:00:00    #node內執行

/sbin/ip  addr  add  10.0.0.1/24  dev  eth0               #node內執行

/sbin/ip  link  set  eth0  up                                                           #node內執行

 

#通過vcmd執行,在容器n1啟動路由服務

sh  quaggaboot.sh  zebra

sh  quaggaboot.sh  ospfd

sh  quaggaboot.sh  vtysh

不難發現樣本拓撲內部結構為圖2。

 

圖2 樣本拓撲內部結構

       在樣本拓撲中,CORE建立了兩個容器(命名空間),兩個橋接器,三個虛擬網卡對(其中一端放進了容器中),並在命名空間中虛擬路由層,為了接收資料,命名空間中的虛擬網卡被串連到橋接器上,而橋接器可以串連物理網卡或其它虛擬網卡。這樣就實現了虛擬節點、物理網卡之間的互聯。

資料流分析

       以樣本拓撲結構為例,第一步是網卡接收資料包,在網卡硬體中斷響應中完成。為了儘可能快速處理,網卡接收中斷響應函數會將接收資料產生skb結構體,將通過調用netif_rx(skb)將任務以非強制中斷的方式插入到CPU調度隊列,然後立即返回。第二步,ksoftirqd處理非強制中斷。這個過程,ksoftirqd根據非強制中斷類型,調用不同的響應函數。本例中ksoftirqd將調用netif_receive_skb函數對skb包進行處理。netif_receive_skb可以理解為從物理層接收資料包,因此它也算是鏈路層的入口函數。在這個函數中,會調用到handle_bridge函數,將skb交給網卡進行處理(如果配置了橋接器),調用br_handle_frame_hook。第三步,橋接器會依據ebtables規則對skb作轉寄、廣播、丟棄等操作。CORE中定義了ebtables規則為FORWARDING,因此橋接器會將ebtables轉寄給串連到它的另一個(虛擬)網卡,調用veth_xmit。第四步,對於虛擬網卡而言,發送就是接收,於是在veth_xmit中,它將skb重新以非強制中斷的方式插入到CPU調度隊列,此時skb已在容器中運行。第五步,ksoftirqd調用netif_receive_skb函數,由於容器中沒有配置橋接器,netif_receive_skb函數會調用packet_type成員.func = ip_rcv將資料包送至L3層路由層。第六步,路由層從ip_rcv接收skb,調用ip_rcv_finish對skb進行路由(調用skb_rtable),決定本地接收還是轉寄skb。

 

圖3 資料流接收轉寄過程

各組成部分

      

物理網卡eth0

       物理網卡,也叫乙太網路卡,在核心的表現形式為ethernet_device(簡寫為eth0)。它的實現是由網卡驅動提供的。網卡既是PCI裝置,也是網路裝置。它在開啟時需要註冊中斷響應函數xxx_interrupt。

request_irq(dev->irq, &xxx_interrupt,

                     lp->shared_irq ? IRQF_SHARED : 0, dev->name,

                     (void *)dev)

       當接收資料包時,會觸發網卡中斷,網卡驅動會為新到來的資料包申請skb, 並將網卡中的資料讀到skb, 並通過netif_rx發送到核心協議棧上層。

if (rtl8169_rx_vlan_skb(tp, desc, skb) < 0)

               netif_rx(skb);

        dev->stats.rx_bytes += pkt_size;

        dev->stats.rx_packets++;

這裡有必要說一下skb,它用於儲存網路資料包,結構。skb由網卡產生。由於它包含了net_device,協議類型,地址等。每一層在遇到skb時都能根據自己的商務邏輯進行處理。

 

圖4 skb結構

橋接器Bridge

       橋接器(Bridge)是L2層(資料連結層)裝置,用於實現乙太網路裝置之間的橋接。橋接器可以綁定若干個乙太網路介面裝置(利用brctl addif命令),從而實現網卡之間的互聯。

(1)    模組初始化

在Linux中,橋接器由動態載入模組Bridge完成。模組初始化時,除了完成自身模組初始化外,最重要一點就是向系統註冊橋接器處理HOOK。該HOOK將在handle_bridgge中調用。

br_handle_frame_hook = br_handle_frame;

(2)    與網卡綁定

 

圖4  net_bridge結構體

橋接器與網卡綁定通過與橋接器連接埠綁定來實現。4所示,net_bridge結構體中維護了一個net_bridge_port結構體鏈表,而net_device(包含在eth裝置結構體中)有指向net_bridge_port結構體的指標,該指標可以指向net_bridge_port結構體鏈表中的元素。

(3)    橋接處理

橋接處理一方面是接收資料,另一方面是發送資料。本例中沒有通過橋接器來發送資料,在此不作討論。接收資料從br_handle_frame開始。

 const unsigned char *dest = eth_hdr(skb)->h_dest;

 int (*rhook)(struct sk_buff *skb);

 //判斷是否為有效物理地址,非全0地址以及非廣播位址

 if (!is_valid_ether_addr(eth_hdr(skb)->h_source))goto drop;

 //判斷skb包是否被共用skb->users != 1,若是,則複製一份,否則直接返回

 skb = skb_share_check(skb, GFP_ATOMIC);

 if (!skb) return NULL;

 const unsigned char *dest = eth_hdr(skb)->h_dest;

 int (*rhook)(struct sk_buff *skb);

 //判斷是否為有效物理地址,非全0地址以及非廣播位址

 if (!is_valid_ether_addr(eth_hdr(skb)->h_source))goto drop;

 //判斷skb包是否被共用skb->users != 1,若是,則複製一份,否則直接返回

 skb = skb_share_check(skb, GFP_ATOMIC);

 if (!skb)  return NULL;

 //這個函數是在判斷是否為鏈路本地多播地址,01:80:c2:00:00:0x

 if (unlikely(is_link_local(dest))) {

 /* Pause frames shouldn‘t be passed up by driver anyway */

 if (skb->protocol == htons(ETH_P_PAUSE))  goto drop;

 /* If STP is turned off, then forward */

 if (p->br->stp_enabled == BR_NO_STP && dest[5] == 0)   goto forward;

 if (NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev,

  NULL, br_handle_local_finish))  return NULL;  /* frame consumed by filter */

 else  return skb;      /* continue processing */

 }

 forward:

  switch (p->state) {

  case BR_STATE_FORWARDING:

  //如果橋接器處於forwarding狀態,且該報文要走L3層進行轉寄,則直接返回

  //br_should_route_hook鉤子函數在ebtable裡面設定為ebt_broute函數,它根據使用者的規決定該報文是否要通過L3層來轉寄;一般rhook為空白

  rhook = rcu_dereference(br_should_route_hook);

  if (rhook != NULL) {

  if (rhook(skb))

  return skb;

  dest = eth_hdr(skb)->h_dest;

  }

  /* fall through */

  case BR_STATE_LEARNING:

  //如果資料包的目的mac地址為虛擬橋接器裝置的mac地址,則標記為host

  if (!compare_ether_addr(p->br->dev->dev_addr, dest))

         skb->pkt_type = PACKET_HOST;

  //調用橋接器在NF_BR_PREROUTING處掛載的鉤子函數,

  NF_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,

  br_handle_frame_finish);

  break;

  default:

  drop:

  kfree_skb(skb);

  }

  return NULL;

  FORWARDING以及LEARNING為橋接器的狀態,橋接器連接埠一般有5種狀態:

  1)  disable 被管理員禁用

  2)  blcok 休息,不參與資料包轉寄

  3)  listening 監聽

  4)  learning 學習ARP資訊,準備向工作狀態改變

  5)  forwarding 正常工作,轉寄資料包

(4)    橋接器過濾器ebtables_filter

橋接器提供可配置的過濾轉寄規則,這一功能通過ebtables_filter來實現。ebtables_filter,ebtables和xt_tables都是可裝載模組。ebtables用於儲存過濾規則,每條過濾規則都對應ebtables中一個表項。5所示,在ebtables_filter模組初始化時向Bridge註冊了各類HOOK函數。Bridge在接受、發送、轉寄資料包時調用相應的HOOK函數,實現過濾功能。

 

圖5  net_filter結構體

虛擬網卡對veth pair

    為了與容器中的節點通訊,CORE會為每個節點建立一個虛擬網卡對,並將一端移至容器中。

#將虛擬網卡對

/sbin/ip  link  add  name  n1.eth0.44  type  veth  peer  name  n1.0.44

#將虛擬網卡對的一端加入到容器的命名空間中,並命名為eth0

/sbin/ip  link  set  n1.0.44  netns  17122     #17122為節點n1的vnoded進程的ID

   

虛擬網卡是去掉了硬體相關操作的網路卡驅動程式。與物理網卡不一樣,它沒有接收外部資料的功能,只能由別的模組給它發送資料,通過調用veth_xmit實現。

stats->tx_bytes += length;

       stats->tx_packets++;

       rcv_stats->rx_bytes += length;

       rcv_stats->rx_packets++;

       netif_rx(skb);

       在veth_xmit實現中,veth會同時將自己的接收和發送資料統計增加,並調用netif_rx(skb)將skb包交給上層處理。

丟包分析

       CORE在虛擬網路裡傳遞資料包時,都是通過Linux的非強制中斷機制進行。當資料流量特別大的時候,非強制中斷守護進程(ksoftirqd)負載會很大,有時候會達到100%,這時候可能發生丟包。這種丟包與網路通訊協定會對格式、校正進行檢查後做的丟棄壞包不一樣,是CORE網路模擬系統的瓶頸。我們看一下netif_rx函數。

int netif_rx(struct sk_buff *skb)

{

       struct softnet_data *queue;

       unsigned long flags;

       /* if netpoll wants it, pretend we never saw it */

       if (netpoll_rx(skb))     return NET_RX_DROP; 

       if (!skb->tstamp.tv64)   net_timestamp(skb);     /* 時間戳記處理*/

 

       local_irq_save(flags);                         /* 儲存當前中斷狀態,關中斷*/

       queue = &__get_cpu_var(softnet_data);           /* 時間戳記處理*/

       __get_cpu_var(netdev_rx_stat).total++;

       if (queue->input_pkt_queue.qlen <= netdev_max_backlog) {

              if (queue->input_pkt_queue.qlen) {                   /* 插入調度隊列*/

enqueue:

                     __skb_queue_tail(&queue->input_pkt_queue, skb);   /* 插入調度隊列*/

                     local_irq_restore(flags);               /* 開啟中斷*/

                     return NET_RX_SUCCESS;          

              }

              napi_schedule(&queue->backlog);           /*喚醒ksoftirqd進行隊列處理*/

              goto enqueue;

       }

       __get_cpu_var(netdev_rx_stat).dropped++;       

       local_irq_restore(flags);                        /* 開啟中斷*/

       kfree_skb(skb);

       return NET_RX_DROP;

}

netif_rx函數會將skb包加入到當前cpu的softnet_data隊列,如果隊列為滿,則丟棄資料包操作。可以通過cpu的netdev_rx_stat狀態查看到丟包的狀態。

 

CORE網路資料包接收傳遞過程分析

聯繫我們

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