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