虛擬網卡和loopback的思想

來源:互聯網
上載者:User

在linux上卸載了loopback網卡裝置之後,本地地址全部不通,這是不應該的嗎?所有的本地網卡在配置ip地址的時候會調用fib_add_ifaddr函數:
void fib_add_ifaddr(struct in_ifaddr *ifa)
{
...
    fib_magic(RTM_NEWROUTE, RTN_LOCAL, addr, 32, prim);
//如此一來,加入一條路由,所有的目的地址是本網卡地址的資料包將通過loopback發送,這實現在ip_route_output_slow函數中。
...
}
在ip_route_output_slow中有以下的語句:
if (res.type == RTN_LOCAL) {
...
    dev_out = &loopback_dev; //如果loopback被ifdown了,那麼資料從何發送呢
...

    goto make_route;
...

}
因此loopback實際上是很重要的,如果你很在意自己的地址的話,比如你在開發一個網路程式,你又只有一台機器,因此你必然需要自己使用自己的ip地址來調試,那麼此時loopback就有了用武之地了。之所以需要loopback來支援本機資料的路由是因為真實的網卡只能將資料發送給物理線路或者從物理線路上接收資料,而不能從別的地方接收或者發送資料,這和虛擬網卡是一致的,然而此時我們也明白了loopback和虛擬網卡的本質區別,loopback只是需要把資料環回過來而已,原封不動的環回,所以我們並不需要一個“物理層”,即使協議棧需要一個物理層,我們缺失的物理層並不會帶來問題,反觀虛擬網卡就不一樣了,虛擬網卡的資料並不是原封不動的環回,而是需要被修改之後環回或者從應用程式層重發,於是就需要實現一個“物理層”,然後將該物理層截斷,在斷裂處加入我們的修改,也就是掛載一個鉤子,該物理層就是虛擬網卡出口到字元裝置出口加上字元裝置入口到虛擬網卡入口以及字元裝置出入口之間的部分,於是虛擬網卡有四個出入口,而loopback僅有兩個,就是使用者空間應用程式層訪問本機地址的進程,它在網卡層次是沒有出口的。
     loopback的資料流是:發送資料->路由->loopback->路由->接收資料;而虛擬網卡有好幾種資料流,它們是:(環回方式)發送資料->路由->虛擬網卡send->字元裝置read->應用程式層->字元裝置write->虛擬網卡receive->路由->接收資料,(隧道方式1)發送資料->路由->虛擬網卡send->字元裝置read->應用程式層->socket->路由->...(forward),(隧道方式2)...->...,(自組包方式)自己封裝物理層資料流->字元設別write->虛擬網卡receive->路由->...總之四個出入口的任何一個地方都能作為資料的起點和終點,換句話說,我們既可以通過虛擬網卡加其字元裝置從物理層接收或發送資料,也可以通過通訊端加路由從應用程式層發送或接收資料,因此才如此靈活。
     最後看看虛擬網卡的驅動以及loopback的驅動:先看看loopback的hard_start_xmit函數:
static int loopback_xmit(struct sk_buff *skb, struct net_device *dev)
{
    struct net_device_stats *lb_stats;
    skb_orphan(skb);
    skb->protocol = eth_type_trans(skb,dev);
    skb->dev = dev;
    dev->last_rx = jiffies;
...
    put_cpu();
    netif_rx(skb); //接收
    return(0);
}
可以看出這個xmit函數名字是發送,實質上已經包含了接收邏輯。而虛擬網卡的xmit函數是下面的樣子:
static int tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
{
    struct tun_struct *tun = netdev_priv(dev);
    if (!tun->attached)
        goto drop;
...
    skb_queue_tail(&tun->readq, skb); //加入字元裝置的讀取隊列
    dev->trans_start = jiffies;
    if (tun->flags & TUN_FASYNC)
        kill_fasync(&tun->fasync, SIGIO, POLL_IN);
    wake_up_interruptible(&tun->read_wait); //喚醒等待在字元裝置上的進程,舉個例子,openvpn
    return 0;
drop:
    tun->stats.tx_dropped++;
    kfree_skb(skb);
    return 0;
}
和上面的tun_net_xmit相關聯的是字元裝置的讀寫函數,很顯然的,write往虛擬網卡中寫資料,其實就是直接調用netif_rx_ni(skb),而read則從tun->readq中讀取資料,然後直接將資料不經任何處理拷貝入使用者空間進程。

聯繫我們

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