Analysis of network-driven migration basic framework of Linux Network Driver

Source: Internet
Author: User
Tags goto

Kernel Source: linux-2.6.38.8.tar.bz2

In summary, writing a Linux network driver can only accomplish two things, one is to allocate and initialize network devices, and the other is to register network devices.

1. Assigning and initializing network devices

Dynamically allocating network devices (from a C-language perspective, it is the definition of a struct net_device struct variable that initializes some members of the struct variable) and the approximate process of its private data (for example, Ethernet devices):

The following is a detailed analysis of the allocation and initialization of network devices in conjunction with the code in linux-2.6.38.8.

[CPP]View PlainCopy
  1. /* Linux-2.6.38.8/include/linux/etherdevice.h */
  2. #define ALLOC_ETHERDEV (Sizeof_priv) alloc_etherdev_mq (Sizeof_priv, 1)
  3. #define ALLOC_ETHERDEV_MQ (Sizeof_priv, Count) Alloc_etherdev_mqs (Sizeof_priv, Count, Count)
  4. /* LINUX-2.6.38.8/NET/ETHERNET/ETH.C */
  5. struct Net_device *alloc_etherdev_mqs (int sizeof_priv, unsigned int txqs,
  6. unsigned int rxqs)
  7. {
  8. return Alloc_netdev_mqs (Sizeof_priv, "eth%d", Ether_setup, Txqs, RXQS);
  9. }
  10. void Ether_setup (struct net_device *dev)
  11. {
  12. Dev->header_ops = &eth_header_ops;
  13. Dev->type = Arphrd_ether;
  14. Dev->hard_header_len = Eth_hlen;
  15. DEV->MTU = Eth_data_len;
  16. Dev->addr_len = Eth_alen;
  17. Dev->tx_queue_len = 1000; / * Ethernet wants good queues * /
  18. Dev->flags = iff_broadcast| Iff_multicast;
  19. memset (Dev->broadcast, 0xFF, Eth_alen);
  20. }

Previously, the distribution functions of various types of network devices (such as the Alloc_etherdev of Ethernet devices) were only encapsulated in the Alloc_netdev function, but not for linux-2.6.38.8.

[CPP]View PlainCopy
    1. /* Linux-2.6.38.8/include/linux/netdevice.h */
    2. #define ALLOC_NETDEV (Sizeof_priv, name, Setup) \
    3. Alloc_netdev_mqs (Sizeof_priv, Name, Setup, 1, 1)

The five parameters of the ALLOC_NETDEV_MQS function are private data size, device name, default initialization function, number of Send queues, and number of receive queues.

The name of the Ethernet device is set to eth%d, the default initialization function is set to Ether_setup, and the number of send and receive queues is set to 1.

The function Alloc_netdev_mqs is defined in the Linux-2.6.38.8/net/core/dev.c file, and presumably the following actions are done:

(1), allocating memory space for struct net_device and private data

[CPP]View PlainCopy
  1. Alloc_size = sizeof (struct net_device);
  2. if (Sizeof_priv) {
  3. Alloc_size = ALIGN (alloc_size, netdev_align); //#define NETDEV_ALIGN
  4. Alloc_size + = Sizeof_priv;
  5. }
  6. Alloc_size + = netdev_align-1;
  7. p = Kzalloc (alloc_size, Gfp_kernel);
  8. if (!p) {
  9. PRINTK (Kern_err "alloc_netdev:unable to allocate device.\n");
  10. return NULL;
  11. }
  12. dev = ptr_align (p, netdev_align);
  13. dev->padded = (char *) Dev-(char *) p;

To align operation-related macros:

[CPP]View PlainCopy
    1. /* Linux-2.6.38.8/include/linux/kernel.h */
    2. #define ALIGN (x, a) __align_kernel ((x), (a))
    3. #define __ALIGN_KERNEL (x, a) __align_kernel_mask (x, (typeof (X)) (a)-1)
    4. #define __ALIGN_KERNEL_MASK (x, Mask) (((x) + (mask)) & ~ (mask))
    5. #define PTR_ALIGN (P, a) ((typeof (P)) ALIGN ((unsigned long) (p), (a)))

(2) Dynamic allocation of PER-CPU variables

[CPP]View PlainCopy
    1. dev->pcpu_refcnt = alloc_percpu (int);
    2. if (!dev->pcpu_refcnt)
    3. Goto free_p;

(3), initialize the hardware address chain list Dev->dev_addrs, and assign the first element to the DEV->DEV_ADDR

[CPP]View PlainCopy
    1. if (Dev_addr_init (dev))
    2. Goto FREE_PCPU;

(4), initialize multicast and unicast address chain list

[CPP]View PlainCopy
    1. Dev_mc_init (Dev);
    2. Dev_uc_init (Dev);

(5), set the network namespace

[CPP]View PlainCopy
    1. Dev_net_set (Dev, &init_net);

(6), set GSO maximum value

[CPP]View PlainCopy
    1. Dev->gso_max_size = gso_max_size;

(7), initialization of various linked lists

[CPP]View PlainCopy
    1. Init_list_head (&dev->ethtool_ntuple_list.list);
    2. Dev->ethtool_ntuple_list.count = 0;
    3. Init_list_head (&dev->napi_list);
    4. Init_list_head (&dev->unreg_list);
    5. Init_list_head (&dev->link_watch_list);

(8), set priv_flags value

[CPP]View PlainCopy
    1. Dev->priv_flags = Iff_xmit_dst_release;

(9), execute the default initialization function (Ethernet device defaults to Ether_setup)

[CPP]View PlainCopy
    1. Setup (dev);

(10), Initialize packet send queue

[CPP]View PlainCopy
    1. Dev->num_tx_queues = Txqs;
    2. Dev->real_num_tx_queues = Txqs;
    3. if (netif_alloc_netdev_queues (dev))
    4. Goto Free_all;

(11), Initialize packet receive queue

[CPP]View PlainCopy
    1. Dev->num_rx_queues = Rxqs;
    2. Dev->real_num_rx_queues = Rxqs;
    3. if (netif_alloc_rx_queues (dev))
    4. Goto Free_all;

(12), set the network device name

[CPP]View PlainCopy
    1. strcpy (dev->name, name);

2. Registration of network equipment

The Register_netdev function registers the completed partially initialized net_device struct variable (that is, a network device instance) into the Linux kernel, with the following approximate process:

The following is a detailed analysis of the network device registration process in conjunction with the code in linux-2.6.38.8.

(1), obtain RTNL signal volume

[CPP]View PlainCopy
    1. Rtnl_lock ();

(2), assigning network device name (that is,%d corresponding number)

[CPP]View PlainCopy
    1. if (STRCHR (dev->name, '% ')) {
    2. Err = Dev_alloc_name (dev, dev->name);
    3. if (Err < 0)
    4. goto out;
    5. }

(3), invoke the actual registration function

[CPP]View PlainCopy
    1. Err = Register_netdevice (dev);

3.1. Initialize Dev->addr_list_lock spin lock and set its category according to Dev->type

[CPP]View PlainCopy
    1. Spin_lock_init (&dev->addr_list_lock);
    2. Netdev_set_addr_lockdep_class (Dev);

3.2. Call the Init function

[CPP]View PlainCopy
    1. if (dev->netdev_ops->ndo_init) {
    2. ret = Dev->netdev_ops->ndo_init (dev);
    3. if (ret) {
    4. if (Ret > 0)
    5. ret =-eio;
    6. goto out;
    7. }
    8. }

3.3. Check if the network device name is valid

[CPP]View PlainCopy
    1. ret = Dev_get_valid_name (dev, dev->name, 0);
    2. if (ret)
    3. Goto Err_uninit;

3.4. Assigning unique index numbers to network devices

[CPP]View PlainCopy
    1. Dev->ifindex = Dev_new_index (NET);
    2. if (Dev->iflink = =-1)
    3. Dev->iflink = dev->ifindex;

3.5. Setting Network device characteristics (dev->features)

[CPP]View PlainCopy
  1. if ((Dev->features & Netif_f_hw_csum) &&
  2. (Dev->features & (netif_f_ip_csum| Netif_f_ipv6_csum)) {
  3. PRINTK (Kern_notice "%s:mixed HW and IP checksum settings.\n",
  4. Dev->name);
  5. Dev->features &= ~ (netif_f_ip_csum| Netif_f_ipv6_csum);
  6. }
  7. if ((Dev->features & Netif_f_no_csum) &&
  8. (Dev->features & (netif_f_hw_csum| netif_f_ip_csum| Netif_f_ipv6_csum)) {
  9. PRINTK (Kern_notice "%s:mixed no checksumming and other settings.\n",
  10. Dev->name);
  11. Dev->features &= ~ (netif_f_ip_csum| netif_f_ipv6_csum| Netif_f_hw_csum);
  12. }
  13. Dev->features = Netdev_fix_features (Dev->features, dev->name);
  14. if (Dev->features & Netif_f_sg)
  15. Dev->features |= NETIF_F_GSO;
  16. Dev->vlan_features |= (Netif_f_gro | NETIF_F_HIGHDMA);

3.6. Notify the kernel of other subsystems of the occurrence of an event (such as registering a network device) through a notification chain

[CPP]View PlainCopy
    1. ret = call_netdevice_notifiers (netdev_post_init, Dev);
    2. ret = Notifier_to_errno (ret);
    3. if (ret)
    4. Goto Err_uninit;
    5. ret = call_netdevice_notifiers (netdev_register, Dev);
    6. ret = Notifier_to_errno (ret);
    7. if (ret) {
    8. rollback_registered (Dev);
    9. Dev->reg_state = netreg_unregistered;
    10. }

3.7, create the network device in the Sysfs file system of the entrance

[CPP]View PlainCopy
    1. ret = Netdev_register_kobject (dev);
    2. if (ret)
    3. Goto Err_uninit;

3.8. Set network device as registered status

[CPP]View PlainCopy
    1. Dev->reg_state = netreg_registered;

3.9. Set the network device status to be available

[CPP]View PlainCopy
    1. Set_bit (__link_state_present, &dev->state);

3.10, initialize the network device queue rules

[CPP]View PlainCopy
    1. Dev_init_scheduler (Dev);

3.11. Increase the reference count of network devices

[CPP]View PlainCopy
    1. Dev_hold (Dev);

3.12, added to the device chain list (such as Dev->dev_list, Dev->name_hlist, Dev->index_hlist)

[CPP]View PlainCopy
    1. List_netdevice (Dev);

3.13. Send NetLink (RFC 3549 Protocol) information

[CPP]View PlainCopy
    1. if (!dev->rtnl_link_ops | |
    2. Dev->rtnl_link_state = = rtnl_link_initialized)
    3. Rtmsg_ifinfo (Rtm_newlink, Dev, ~0u);

Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.

Analysis of network-driven migration basic framework of Linux Network Driver

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

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.