Sunday, December 14, 2014

simulated network interface using linux module

this is suitable for fedora 7 and yet to be tested

#include<linux/module.h>
#include<linux/netdevice.h>
#include<linux/kernel.h>
#include<linux/skbuff.h>
int mac_address[10]=0x0a0b0c010203;
struct net_device *my_dev;
#define SIM_DEVICE "sim"
static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev)
{
    printk(KERN_INFO "I got a packet");   
    return NETDEV_TX_OK;
}
static int veth_open(struct net_device *dev)
{

    memcpy(dev->dev_addr, "\0ABCD0", ETH_ALEN);
    netif_start_queue(dev);

    return 0;
}


int veth_close(struct net_device *dev)
{
    printk("releasing mydev\n");
    netif_stop_queue(dev);
    return 0;
}

int veth_dev_init(struct net_device *dev)
{
    printk("initialising\n");
    return 0;
}

static struct net_device_ops veth_ops = {

    .ndo_init         = veth_dev_init,
    .ndo_open         = veth_open,
    .ndo_stop         = veth_close,
    .ndo_start_xmit   = veth_xmit,

};

int sim_dev_open(struct net_device *dev)
{
    printk("opening dev\n");
    netif_start_queue(dev);
    return 0;
}

int sim_dev_stop(struct net_device *dev)
{
    printk("stoping dev\n");
    netif_stop_queue(dev);
    return 0;
}

static netdev_tx_t sim_dev_tx(struct sk_buff *skb, struct net_device *dev)
{
    struct net_device *priv_data== (struct net_device *) dev->priv;
    priv_data->stats.tx_packets++;   
    return NETDEV_TX_OK;
}
static struct net_device_stats *sim_dev_stats(struct net_device *dev)
{
    struct net_device *priv_data = (struct netdevice*) dev->priv;
    return &priv_data->stats;
}


static void sim_init(struct net_device *dev)
{
    dev->open=sim_dev_open;
    dev->stop=sim_dev_stop;
    dev->hard_start_xmit=sim_dev_tx;
    dev->get_stats=sim_dev_stats;
    dev->change_mtu=sim_dev_change_mtu;
}
static int sim_dev_change_mtu(struct net_device *dev, int new_mtu)
{
    if(new_mtu<=1500)
        dev->mtu=new_mtu;
}

static void NetDeviceCreate(unsinged char *name)
{
    struct net_device *sim_dev=NULL;
    sim_dev = alloc_netdev(sizeof(struct net_device), name, ether_setup);
    if (sim_dev == NULL)
        return -ENOMEM;
    strcpy(sim_dev->name,name);
    strcpy(sim_dev->dev_addr,mac_address);
    sim_dev->init=sim_init;
    mac_address[4]++;
}
static int veth_init()
{
    NetDeviceCreate(SIM_DEVICE"0");
    NetDeviceCreate(SIM_DEVICE"1");
    NetDeviceCreate(SIM_DEVICE"2");
    NetDeviceCreate(SIM_DEVICE"3");
    NetDeviceCreate(SIM_DEVICE"4");
    NetDeviceCreate(SIM_DEVICE"5");
    NetDeviceCreate(SIM_DEVICE"6");
    NetDeviceCreate(SIM_DEVICE"7");
    int ret,i;
    my_dev = alloc_netdev(sizeof(struct net_device), "my_dev", ether_setup);
    if (my_dev == NULL)
        return -ENOMEM;
    register_netdev(my_dev);
    return 0;
}
static void NetDeviceDelete()
{
    struct net_device *dev;
    dev = first_net_device(&init_net);
    while (dev)
    {
        if(!strncmp(dev->name,SIM_DEVICE,strlen(SIM_DEVICE)))
        {
            unregister_netdev(my_dev);
            free_netdev(my_dev);
        }
        dev = next_net_device(dev);
    }
}
static void veth_exit()
{
    NetDeviceDelete();
}

module_init(veth_init);
module_exit(veth_exit);




program following below steps:
 ---------------------------------------------------
module init - init will be called while loadin module
loading module will create 10 sim interface
in each create fucntions
- allocating net device structure by linux system call for each interface  as ether_setup
- in allocated net device pointer
  --> copying the interface mac address &
  --> assign init function(inturn calls the call back functions for
  == open - do net interface start queue for the allocated net device
  == stop - do net interface stop queue  for the allocated net device
   == xmit - do extracting private date from the allocated net device and just increment tx_packets. and free skb
  == get_stats - do "return the stats structre from the allocated net device"
  == mtu - do "change the mtu field in the allcoated net device if its less than 1500"
- after assigned init(call back functions) do register with kernel stack



module exit - called to unload the module during rmmod
in this function
-    Scan through the Interfaces available in the system and check
     whether they are created by us
     If so, deregister them from the system & clean the memory associated
     with it
 -- calls system call first net device to get the first interface
 -- from the called system call we can get each net device structure
 -- from this device strucutre take the name and compate its with sim without 1 to 10
 -- if it matches call the delete function
  == in the delete function use the system call get by name and get the strucutre
  == if structure not null then unregister and free it



thats it of module init and module exit


reference:
1. experience
2. http://www.xml.com/ldd/chapter/book/ch14.html  (short -> https://www.sics.se/~amir/files/download/device-driver/network.pdf)(one chapter from this book https://www.rose-hulman.edu/~yoder/Beagle/Linux%20Device%20Drivers%203rd.pdf)
3.  http://stackoverflow.com/questions/14180717/passing-packets-from-ip-layer-to-device-driver
4.  http://searchsrikanth.blogspot.in/2010/03/how-to-write-network-driver-in-linux.html
5. http://stackoverflow.com/questions/4494307/getting-list-of-network-devices-inside-the-linux-kernel



extra:
6. http://stackoverflow.com/questions/15190405/linux-kernel-getting-packets-from-a-netdevice
7.
 8.


TCP/IP packet flow:
a. http://www.cubrid.org/blog/dev-platform/understanding-tcp-ip-network-stack/
 (best)


kernel architecture course:
1.http://www.cs.columbia.edu/~nahum/w6998/lectures/
2. http://thomas.enix.org/pub/conf/rmll2010/kernel-architecture-for-drivers.pdf