The below sample network driver does pretty much nothing. Hence, the term skeleton network driver. It does allow the understanding of basic concepts regarding how a network device driver works in the Linux kernel.
The network devices are connected to the network stack and communicate with the outside world using network packets. The network device drivers register a bunch of callbacks to the Linux networking stack. The interested reader can check the article on the basics of a network driver (In this article here) .
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/init.h>
MODULE_AUTHOR("Vivekananda Uppunda");
MODULE_DESCRIPTION("Simple virtual network device skeleton");
MODULE_LICENSE("GPL");
#define DRIVER_NAME "vivek_net"
/* -------------------
* Transmit function
* -----------------*/
static netdev_tx_t net_xmit(struct sk_buff *skb,
struct net_device *dev)
{
/* We do nothing with the packet */
dev_kfree_skb(skb);
pr_info("%s: packet transmitted\n", dev->name);
return NETDEV_TX_OK;
}
/* ---------------
* Open
* --------------*/
static int net_open(struct net_device *dev)
{
netif_start_queue(dev);
pr_info("%s: device opened\n", dev->name);
return 0;
}
/* ---------------
* Stop
* --------------*/
static int net_stop(struct net_device *dev)
{
netif_stop_queue(dev);
pr_info("%s: device closed\n", dev->name);
return 0;
}
/* --------------------------------
* net_device operations structure
* ------------------------------*/
static const struct net_device_ops net_ops = {
.ndo_open = net_open,
.ndo_stop = net_stop,
.ndo_start_xmit = net_xmit,
};
/* ---------------
* Setup function
* --------------*/
static void net_init(struct net_device *dev)
{
/* provide ethernet generic values */
ether_setup(dev);
dev->netdev_ops = &net_ops;
/* Provide fake MAC address */
eth_hw_addr_random(dev);
}
/* -------------
* Module init
* -----------*/
static struct net_device *net_dev;
static int __init network_init(void)
{
int ret;
net_dev = alloc_netdev(0, "vivek_net%d",
NET_NAME_UNKNOWN, net_init);
if (!net_dev)
return -ENOMEM;
ret = register_netdev(net_dev);
if (ret) {
free_netdev(net_dev);
return ret;
}
pr_info(DRIVER_NAME ": virtual network device registered\n");
pr_info(DRIVER_NAME ": Module loaded\n");
return 0;
}
/* -------------
* Module exit
* -----------*/
static void __exit network_exit(void)
{
unregister_netdev(net_dev);
free_netdev(net_dev);
pr_info(DRIVER_NAME ": Module unloaded\n");
}
module_init(network_init);
module_exit(network_exit);
The Makefile for the above code is provided below
obj-m += virtual_network.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
We will understand the above code by compiling it and loading the compiled module and perform various common network operations
Pingback: Understanding the network device driver sample | Hitch Hiker's Guide to Learning
Pingback: Understanding the network device driver sample – part 2 | Hitch Hiker's Guide to Learning
Pingback: A few other SKB APIs | Hitch Hiker's Guide to Learning