Can i use dev_queue_xmit()
From: K.Anantha Kiran
Date: Thu Apr 08 2004 - 14:26:24 EST
We wrote a KernelModule for fetching internet packets through certain
interface, and reforwarding them through another interface of our choice
based on IP-address,Port values of packet.
This module is working fine for less rate of traffic(< 200 Mbps) , But
same module is dropping some of the packets(4 lakhs out of 10 lakhs) for
highier speeds(> 200Mbps).Function *dev_queue_xmit()* in the kernel
module, is returning NET_XMIT_DROP for dropped packets.This is due to
the function call *q->enqueue(skb,q)* in dev_queue_xmit().What might be
the reason for that return value.
Is it the problem with s/w or h/w ? We are using Linux-2.4 and Gigabyte
Eth cards.And we are genrating traffic by resending same packet for many
times.How can we figure out the location of problem.
We are attaching our module file.
I will be very thankful to your help.
Thanks in advance,
K.AnanthaKiran
#define MODULE
#define __KERNEL__
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/icmp.h>
#include <linux/netdevice.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/if_arp.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <asm-i386/types.h>
/* This is the structure we shall use to register our function */
static struct nf_hook_ops nfho; /* Initialisation routine */
int hook_func(unsigned int hooknum,
struct sk_buff **skbuff,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
struct sk_buff* skb=*skbuff;
struct iphdr *iph;
struct tcphdr *th;
struct ethhdr *ether;
unsigned char ea1[7] = {0x00,0x07,0xe9,0x24,0x71,0x15};
unsigned int devno;
static int cnt[3];
struct net_device *dev;
u32 saddr,daddr;
u16 source,dest;
/*
* Checking whether skb and IP_Header are not null
*/
if (!skb ) return NF_ACCEPT;
if (!(skb->nh.iph)) return NF_ACCEPT;
if(strcmp(in->name,"eth0") != 0)
return NF_ACCEPT;
/*
* Checking whether Packet is from Ethernet device or not
* Doubt: What is the better place to put it !
*/
if(skb->dev->type!=ARPHRD_ETHER)
return NF_ACCEPT;
iph = skb->nh.iph;
/*
* Checking whether packet is TCP or UDP packet
* otherwise ignore it
*/
if ( iph -> protocol != IPPROTO_TCP && iph -> protocol != IPPROTO_UDP )
return NF_ACCEPT;
th = (struct tcphdr *) (skb->data + (skb->nh.iph->ihl * 4) ) ;
// Getting source and destination ip addresses from ip header
saddr = iph->saddr;
daddr = iph->daddr;
// Getting source and destination ports from TCP header
source = th->source;
dest = th->dest;
// Computing Hash
devno = (saddr + daddr + source + dest) % 2;
// Starting address of ethernet frame
if((ether = (struct ethhdr *)skb->mac.ethernet)== NULL)
return NF_ACCEPT;
// Selecting device
switch(devno)
{
case 0:
if( (dev = dev_get_by_name("eth1")) == NULL)
return NF_ACCEPT;
memcpy(ether->h_source,dev->dev_addr,ETH_ALEN);
break;
case 1:
if( (dev = dev_get_by_name("eth2")) == NULL)
return NF_ACCEPT;
memcpy(ether->h_source,dev->dev_addr,ETH_ALEN);
break;
case 2:
if( (dev = dev_get_by_name("eth1")) == NULL)
return NF_ACCEPT;
memcpy(ether->h_source,dev->dev_addr,ETH_ALEN);
break;
}
//Setting Destination as ea1
memcpy(ether->h_dest,ea1,ETH_ALEN);
skb->data = (unsigned char *)skb->mac.ethernet;
skb->len += ETH_HLEN;
// Setting it as outgoing packet
skb->pkt_type=PACKET_OUTGOING;
// changing the dev to output device we need
skb->dev = dev;
// Transmitting the packet
if((cnt[2]=dev_queue_xmit(skb))==NET_XMIT_SUCCESS)
cnt[0]++;
else
if(cnt[2] != 1)
printk("%d ",cnt[2]);
cnt[1]++;
if((cnt[1]%100000)==0) printk("%d %d\n",cnt[0],cnt[1]);
return NF_STOLEN;
}
int init_module()
{
/* Fill in our hook structure */
nfho.hook = (nf_hookfn *)hook_func;
/* Handler function */
nfho.hooknum = NF_IP_PRE_ROUTING; /* First hook for IPv4 */
nfho.pf = PF_INET;
nfho.priority = NF_IP_PRI_FIRST; /* Make our function first */
nf_register_hook(&nfho);
return 0;
}
/* Cleanup routine */
void cleanup_module()
{
nf_unregister_hook(&nfho);
}