ipvlan設(shè)備創(chuàng)建與初始化流程-4.19內(nèi)核

1、ipvlan模塊初始化,注冊netlink的ops

static struct rtnl_link_ops ipvlan_link_ops = {
    .kind       = "ipvlan",
    .priv_size  = sizeof(struct ipvl_dev),

    .setup      = ipvlan_link_setup,
    .newlink    = ipvlan_link_new,
    .dellink    = ipvlan_link_delete,
};

static int __init ipvlan_init_module(void)
{
    register_netdevice_notifier(&ipvlan_notifier_block);
    register_inetaddr_notifier(&ipvlan_addr4_notifier_block);
    register_inetaddr_validator_notifier(&ipvlan_addr4_vtor_notifier_block);
    err = register_pernet_subsys(&ipvlan_net_ops);
    err = ipvlan_link_register(&ipvlan_link_ops);
}

2、netlink接受創(chuàng)建消息

    rtnl_register(PF_UNSPEC, RTM_NEWLINK, rtnl_newlink, NULL, 0);

3、申請并注冊net_device,調(diào)用setup函數(shù)創(chuàng)建queue

rtnl_new_link-> rtnl_creat_link ->
alloc_netdev_mqs -> setup() -> netif_alloc_netdev_queues(還會注冊dev結(jié)構(gòu)的私有變量)

alloc_netdev_mqs() {
        struct net_dev *p = NULL;
    alloc_size = sizeof(struct net_device);
    if (sizeof_priv) {
        /* ensure 32-byte alignment of private area */
        alloc_size = ALIGN(alloc_size, NETDEV_ALIGN);
        alloc_size += sizeof_priv;
    }
    /* ensure 32-byte alignment of whole construct */
    alloc_size += NETDEV_ALIGN - 1;

    p = kvzalloc(alloc_size, GFP_KERNEL | __GFP_RETRY_MAYFAIL);
}

static const struct net_device_ops ipvlan_netdev_ops = {
    .ndo_init       = ipvlan_init,
    .ndo_uninit     = ipvlan_uninit,
    .ndo_open       = ipvlan_open,
    .ndo_stop       = ipvlan_stop,
    .ndo_start_xmit     = ipvlan_start_xmit,
    .ndo_fix_features   = ipvlan_fix_features,
    .ndo_change_rx_flags    = ipvlan_change_rx_flags,
    .ndo_set_rx_mode    = ipvlan_set_multicast_mac_filter,
    .ndo_get_stats64    = ipvlan_get_stats64,
    .ndo_vlan_rx_add_vid    = ipvlan_vlan_rx_add_vid,
    .ndo_vlan_rx_kill_vid   = ipvlan_vlan_rx_kill_vid,
    .ndo_get_iflink     = ipvlan_get_iflink,
};
// setup函數(shù)注冊網(wǎng)卡的ops函數(shù)
void ipvlan_link_setup(struct net_device *dev)
{
    ether_setup(dev);
    dev->netdev_ops = &ipvlan_netdev_ops;
    dev->header_ops = &ipvlan_header_ops;
    dev->ethtool_ops = &ipvlan_ethtool_ops;
}

4、創(chuàng)建關(guān)聯(lián)結(jié)構(gòu)

ops->newlink();
// new link函數(shù)注冊網(wǎng)卡設(shè)備,并調(diào)用ndo_init 
int ipvlan_link_new(struct net *src_net, struct net_device *dev,
            struct nlattr *tb[], struct nlattr *data[],
            struct netlink_ext_ack *extack)
{
    struct ipvl_port *port;
    err = register_netdevice(dev);
        // 填充這個關(guān)聯(lián)結(jié)構(gòu),包括主設(shè)備的mac地址。
    ipvlan->phy_dev = phy_dev;
    ipvlan->dev = dev;
    memcpy(dev->dev_addr, phy_dev->dev_addr, ETH_ALEN);
        // port已經(jīng)在ndo_init中創(chuàng)建過了。
    port = ipvlan_port_get_rtnl(phy_dev);
    ipvlan->port = port;
        // 將該主設(shè)備的所有ipvlan設(shè)備組成一個鏈表。
    list_add_tail_rcu(&ipvlan->pnode, &port->ipvlans);
}

// register_netdevice 調(diào)用ndo_init初始化,并調(diào)用callback回調(diào)函數(shù)
int register_netdevice(struct net_device *dev)
{
    ret = dev->netdev_ops->ndo_init(dev);
    ret = call_netdevice_notifiers(NETDEV_POST_INIT, dev);
    ret = call_netdevice_notifiers(NETDEV_REGISTER, dev);
}
// ipvlan_init 創(chuàng)建ipvl_dev,關(guān)聯(lián)ipvlan設(shè)備和物理設(shè)備
static int ipvlan_init(struct net_device *dev)
{
    err = ipvlan_port_create(phy_dev);
        // 關(guān)鍵一步,注冊rx_handler,__netif_receive_skb_core函數(shù)中會調(diào)用
        // 意味著該設(shè)備收的包要單獨處理(如bond,brige,ipvlan,macvlan的從設(shè)備),而不是送到協(xié)議棧。
    err = netdev_rx_handler_register(dev, ipvlan_handle_frame, port);
    err = ipvlan_port_create(phy_dev);
        // 處理廣播包
    INIT_WORK(&port->wq, ipvlan_process_multicast);
}
static int __netif_receive_skb_core(struct sk_buff *skb, bool pfmemalloc,
                    struct packet_type **ppt_prev)
{
    rx_handler = rcu_dereference(skb->dev->rx_handler);
    if (rx_handler) {
        switch (rx_handler(&skb)) {
        case RX_HANDLER_CONSUMED:
            ret = NET_RX_SUCCESS;
            goto out;
          }
}

利用perf查看函數(shù)調(diào)用關(guān)系

關(guān)于設(shè)備的函數(shù)調(diào)用先后順序,如何查看呢?可以通過perf查看函數(shù)調(diào)用堆棧

1、 通過probe添加tracepoint
    perf probe -m ipvlan --add ipvlan_link_setup 
2、開始記錄
   perf  record -ag -e "probe:ipvlan_link_setup"
3、創(chuàng)建ipvlan設(shè)備
   ip link add link eth0 ba type ipvlan mode l2
4、查看perf報告
   perf report -ns comm
5、查看調(diào)用關(guān)系
   do_syscall_64
   sock_sendmsg
   netlink_sendmsg
   netlink_unicast
   rtnetlink_rcv
   netlink_rcv_skb
   rtnetlink_rcv_msg
   rtnl_newlink
   rtnl_create_link
   ipvlan_link_setup

收發(fā)包

有了網(wǎng)絡(luò)協(xié)議棧的基礎(chǔ),收發(fā)包都是常規(guī)流程。如net_device接口,dev的私有變量,napi等等。
1、 發(fā)包
ipvlan_start_xmit -> ipvlan_queue_xmit
2層口 ipvlan_xmit_mode_l2
3層口 ipvlan_xmit_mode_l3
ipvlan_addr_lookup 根據(jù)地址找到虛擬口,
如果是同物理口的不同ipvlan口,ipvlan_rcv_frame -> dev_forward_skb
-> netif_rx_internal -> enqueue_to_backlog -> ___napi_schedule -> raise軟中斷
net_rx_action -> n->poll -> process_backlog -> __netif_receive_skb_one_core進入上層協(xié)議棧處理
更新統(tǒng)計信息
2、 收包
ipvlan_handle_frame
2 層口 ipvlan_handle_mode_l2
3 層口 ipvlan_handle_mode_l3

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 話不多說,我們直奔主題,從0開始手寫實現(xiàn)Vue3初始化流程! Vue3初始化流程 在手寫實現(xiàn)之前,我們首先來看看V...
    深度剖析JavaScript閱讀 2,510評論 0 13
  • 本文記錄的是ijkplayer的初始化流程(重點在分析底層c代碼的邏輯),為了更好的理解這部分內(nèi)容,建議大家下載i...
    ce0b74704937閱讀 3,210評論 0 1
  • 2. 初始化 初始化主要分為幾個部分,SM注冊service,app層和framework層去打開相機操作,底層的...
    Lemon_Home閱讀 6,243評論 0 10
  • 16宿命:用概率思維提高你的勝算 以前的我是風(fēng)險厭惡者,不喜歡去冒險,但是人生放棄了冒險,也就放棄了無數(shù)的可能。 ...
    yichen大刀閱讀 8,087評論 0 4
  • 公元:2019年11月28日19時42分農(nóng)歷:二零一九年 十一月 初三日 戌時干支:己亥乙亥己巳甲戌當月節(jié)氣:立冬...
    石放閱讀 7,510評論 0 2

友情鏈接更多精彩內(nèi)容