A network driver framework
Sponsored Links
This presentation is the property of its rightful owner.
1 / 30

A network driver ‘framework’ PowerPoint PPT Presentation


  • 92 Views
  • Uploaded on
  • Presentation posted in: General

A network driver ‘framework’. We construct a ‘skeleton’ module showing just the essential pieces of a Linux network device driver. Overview. user space kernel space. Linux operating system Kernel. standard runtime libraries. networking subsystem.

Download Presentation

A network driver ‘framework’

An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -

Presentation Transcript


A network driver ‘framework’

We construct a ‘skeleton’ module showing just the essential pieces of a Linux network device driver


Overview

user space kernel space

Linux

operating system

Kernel

standard

runtime

libraries

networking subsystem

device driver module

application

program

hardware


Source-code layout

netframe.c

#include <linux/module.h>

#include <linux/etherdevice.h>

typedef struct {

/* driver’s private data */

} MY_DRIVERDATA;

char modname[ ] = “netframe”;

struct net_device *netdev;

my_open()

my_stop()

The network driver’s

“payload” functions

my_hard_start_xmit()

my_isr()

my_get_info()

The mandatory module-

administration functions

my_init

my_exit


module_init()

  • This function will execute when the driver is installed in the kernel (‘/sbin/insmod’)

  • Its role is to allocate and partially initialize a ‘struct net_device’ object for our network interface controller (i.e., hardware device), then “register” that object with the kernel

  • For ethernet NICs there exists a kernel helper-function that drivers can utilize


The ‘key’ statements…

typedefstruct { /* the driver’s private data */ } MY_DRIVERDATA;

struct net_device *netdev;

static int __init my_init( void )

{

netdev = alloc_etherdev( sizeof( MY_DRIVERDATA ) );

if ( !netdev ) return –ENOMEM;

netdev->open= my_open;

netdev->stop= my_stop;

netdev->hard_start_xmit = my_hard_start_xmit;

returnregister_netdev( netdev );

}


module_exit()

  • This function will execute when the driver is removed from the kernel (‘/sbin/rmmod’)

  • Its role is to “unregister” the ‘net_device’ structure and free the memory that was allocated during the module’s initialization


The ‘key’ statements…

struct net_device *netdev;

static void __exit my_exit( void )

{

unregister_netdev( netdev );

free_netdev( netdev );

}


open()

  • The kernel will call this function when the system administrator “configures” the NIC (e.g., with the ‘/sbin/ifconfig’ command) to assign an IP-address to the interface and and bring it UP

  • Thus the role of ‘open()’ would be to reset the hardware to a known working state and initiate packet-queueing by the kernel


The ‘key’ statements…

int my_open( struct net_device *dev )

{

/* initialize any remaining ‘private’ data */

/* prepare the hardware for operation */

/* install an Interrupt Service Routine */

/* enable the NIC to generate interrupts */

netif_start_queue( netdev );

return0; //SUCCESS

}


stop()

  • The kernel will call this function when the NIC is brought DOWN (i.e., to turn off its transmission and reception of packets)

  • This could occur because of a command (such as ‘/sbin/ifconfig’) executed by the System Administrator, or because a user is removing the driver-module from the kernel (with the ‘/sbin/rmmod’ command)


The ‘key’ statements…

int my_stop( struct net_device *dev )

{

netif_stop_queue( netdev );

/* kill any previously scheduled ‘tasklets’ (or other deferred work) */

/* turn off the NIC’s transmit and receive engines */

/* disable the NIC’s ability to generate interrupts */

/* delete the NIC’s Interrupt Service Routine */

return0; //SUCCESS

}


hard_start_xmit()

  • The kernel will call this function whenever it has data that it wants the NIC to transmit

  • The kernel will supply the address for a socket-buffer (‘struct sk_buff’) that holds the packet-data that is to be transmitted

  • So this function’s duties are: to initiate transmission, update relevant statistics, and then release that ‘sk_buff’ structure


The ‘key’ statements…

int my_hard_start_xmit( struct sk_buff *skb, struct net_device *dev )

{

/* code goes here to initiate transmission by the hardware */

dev->trans_start= jiffies;

dev->stats.tx_packets += 1;

dev->stats.tx_bytes += skb->len;

dev_kfree_skb( skb );

return0; //SUCCESS

}


What about reception?

  • The NIC hardware receives data-packets asynchronously – not at a time of its own choosing – and we don’t want our system to be ‘stalled’ doing ‘busy-waiting’

  • Thus an interrupt handler is normally used to detect and arrange for received packets to be validated and dispatched to upper layers in the kernel’s network subsystem


Simulating an interrupt

  • Our network device-driver ‘framework’ was only designed for demonstration purposes; it does not work with any actual hardware

  • But we can use a ‘software interrupt’ that will trigger the execution of our ISR

  • To implement this scheme, we’ll need to employ an otherwise unused IRQ-number, along with its associated ‘Interrupt-ID’


Advanced Programmable Interrupt Controller

Multi-CORE CPU

CPU

0

CPU

1

I/O

APIC

IRQ0

IRQ1

IRQ2

IRQ3

IRQ23

LOCAL

APIC

LOCAL

APIC

The I/O APIC component is programmable – its 24 inputs can be

assigned to interrupt ID-numbers in the range 0x20..0xFF (lower

numbers are reserved by Intel for the CPU’s exception-vectors)

The I/O-APIC’s 24 Redirection Table registers determine these assignments


Two-dozen IRQs

  • The I/O APIC in our classroom machines supports 24 Interrupt-Request input-lines

  • Its 24 programmable registers determine how interrupt-signals get routed to CPUs

Redirection-table


Redirection Table Entry

63 56 55 48 32

destination

extended

destination

reserved

31 16 15 14 13 12 11 10 9 8 7 0

reserved

M

A

S

K

E

/

L

R

I

R

R

H

/

L

S

T

A

T

U

S

L

/

P

delivery

mode

interrupt

vector

ID

000 = Fixed

001 = Lowest Priority

010 = SMI

011 = (reserved)

100 = NMI

101 = INIT

110 = (reserved)

111 = ExtINT

Trigger-Mode (1=Edge-triggered, 0=Level-triggered)

Remote IRR (for Level-Triggered only)

0 = Reset when EOI received from Local-APIC

1 = Set when Local-APICs accept Level-Interrupt

sent by IO-APIC

Interrupt Input-pin Polarity (1=Active-High, 0=Active-Low)

Destination-Mode (1=Logical, 0=Physical)

Delivery-Status (1=Pending, 0=Idle)


Our ‘ioapic.c’ module

  • Last semester we created a module that will show us which IRQ-numbers are not currently being used by our system, and the Interrupt-IDs those IRQ-signals were assigned to by Linux during ‘startup’

Timeout for an in-class demonstration


my_isr()

  • We created a “dummy” Interrupt Service Routine for our ‘netframe.c’ demo-module

#define IRQ4// temporarily unused (normally for serial-UART

#define intID0x49// our I/O-APIC has assigned this ID to to IRQ 4

irqreturn_t my_isr( int irq, void *my_netdev_addr )

{

struct net_device *dev = (struct net_device *)my_netdev_addr;

MY_DRIVERDATA*priv = dev->priv;

// we do processing of the received packet in our “bottom half”

tasklet_schedule( &priv->my_rxtasklet );

returnIRQ_HANDLED;

}


Installing and removing an ISR

option-flags

name for display

entry-point for interrupt-handler

ISR data-argument

IRQ’s signal-number

if ( request_irq( IRQ, my_isr, IRQF_SHARED, dev->name, dev ) < 0 )

return –EBUSY;

This statement would go in the driver’s ‘open()’ function…

…and this statement would go in the driver’s ‘stop()’ function

free_irq( IRQ, dev );

Here ‘dev’ is the address of the interface’s ‘struct net_device’ object


Processing a received packet

  • When the NIC notifies our driver that it has received a new ethernet-packet, our driver must allocate a socket-buffer structure for the received data, initialize the ‘sk_buff’ with that data and supporting parameters, then pass that socket-buffer upward to the kernel’s network subsystem for delivery to the appropriate application-program that is listening for it


The ‘key’ statements…

void my_rxhandler( unsigned long data )

{

struct net_device*dev = (struct net_device *)data;

struct sk_buff*skb;

intrxbytes = 60;// just an artificial value here

skb = dev_alloc_skb( rxbytes + 2 );

skb->dev = dev;

skb->protocol = eth_type_trans( skb, dev );

skb->ip_summed = CHECKSUM_NONE;

dev->stats.rx_packets += 1;

dev->stats.rx_bytes += rxbytes;

netif_rx( skb );

}


Triggering the interrupt…

  • We allow a user to trigger execution of our interrupt-handler (for testing purposes), by reading from a pseudo-file that our driver creates during module-initialization, whose ‘get_info()’ function includes execution of a software-interrupt instruction: ‘int $0x49’

  • This inline assembly language instruction is produced via the GNU ‘asm’ construct


Using the ‘asm-construct’

#define intID0x49

asm(“ int %0 “ : : “i” (intID) );

parameter-value (symbolic)

statement keyword

parameter type (“i” = immediate data)

assembly language opcode

parameter indicator

This example shows how a symbolic constant’s value, defined in the high-level

C programming language using a ‘#define’ preprocessor directive, is able to be

referenced by an “inline” assembly language statement within a C code-module


Testing our ‘framework’

  • You can download, compile, and install our ‘netframe.c’ network driver module

  • It doesn’t do anything with real hardware, but it does illustrate essential interactions of a network device driver with the Linux operating system’s networking subsystem


In-class exercise #1

  • Use the ‘/sbin/ifconfig’ command to assign an IP-address to the ‘struct net_device’ object that our framework-module creates

  • You can discover the interface’s name by using our earlier ‘netdevs.c’ module

  • You should use a ‘private’ IP-address

  • EXAMPLE (for station ‘hrn23501’):

    $ sudo /sbin/ifconfig eth1 192.168.86.1 up


In-class exercise #2

  • Use ‘ifconfig’ to confirm the IP-address, the IRQ, and the interface’s status:

    $ /sbin/ifconfig eth1

  • Use ‘ifconfig’ to examine the interface’s statistics (packets transmitted/received)


In-class exercise #3

  • Use the ‘cat’ command to simulate an interrupt from your device’s interface

  • Verify that your interrupt-handler did get executed, by looking at the statistics, and by displaying the output of a pseudo-file Linux creates (named ‘/proc/interrupts’)

    $ cat /proc/interrupts


In-class exercise #4

  • Try removing the ‘netframe.ko’ module (with the ‘/sbin/rmmod’ command), then use the ‘dmesg’ command to see your system’s log-file messages


  • Login