Skip to content

Commit

Permalink
[PKTGEN]: Add MPLS extension.
Browse files Browse the repository at this point in the history
Signed-off-by: Steven Whitehouse <steve@chygwyn.com>
Signed-off-by: Robert Olsson <robert.olsson@its.uu.se>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Steven Whitehouse authored and David S. Miller committed Mar 23, 2006
1 parent 2e6e33b commit ca6549a
Show file tree
Hide file tree
Showing 2 changed files with 166 additions and 12 deletions.
20 changes: 19 additions & 1 deletion Documentation/networking/pktgen.txt
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,22 @@ Examples:
cycle through the port range.
pgset "udp_dst_max 9" set UDP destination port max.

pgset "mpls 0001000a,0002000a,0000000a" set MPLS labels (in this example
outer label=16,middle label=32,
inner label=0 (IPv4 NULL)) Note that
there must be no spaces between the
arguments. Leading zeros are required.
Do not set the bottom of stack bit,
thats done automatically. If you do
set the bottom of stack bit, that
indicates that you want to randomly
generate that address and the flag
MPLS_RND will be turned on. You
can have any mix of random and fixed
labels in the label stack.

pgset "mpls 0" turn off mpls (or any invalid argument works too!)

pgset stop aborts injection. Also, ^C aborts generator.


Expand Down Expand Up @@ -167,6 +183,8 @@ pkt_size
min_pkt_size
max_pkt_size

mpls

udp_src_min
udp_src_max

Expand Down Expand Up @@ -211,4 +229,4 @@ Grant Grundler for testing on IA-64 and parisc, Harald Welte, Lennert Buytenhek
Stephen Hemminger, Andi Kleen, Dave Miller and many others.


Good luck with the linux net-development.
Good luck with the linux net-development.
158 changes: 147 additions & 11 deletions net/core/pktgen.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@
*
* interruptible_sleep_on_timeout() replaced Nishanth Aravamudan <nacc@us.ibm.com>
* 050103
*
* MPLS support by Steven Whitehouse <steve@chygwyn.com>
*
*/
#include <linux/sys.h>
#include <linux/types.h>
Expand Down Expand Up @@ -154,14 +157,16 @@
#include <asm/div64.h> /* do_div */
#include <asm/timex.h>

#define VERSION "pktgen v2.66: Packet Generator for packet performance testing.\n"
#define VERSION "pktgen v2.67: Packet Generator for packet performance testing.\n"

/* #define PG_DEBUG(a) a */
#define PG_DEBUG(a)

/* The buckets are exponential in 'width' */
#define LAT_BUCKETS_MAX 32
#define IP_NAME_SZ 32
#define MAX_MPLS_LABELS 16 /* This is the max label stack depth */
#define MPLS_STACK_BOTTOM __constant_htonl(0x00000100)

/* Device flag bits */
#define F_IPSRC_RND (1<<0) /* IP-Src Random */
Expand All @@ -172,6 +177,7 @@
#define F_MACDST_RND (1<<5) /* MAC-Dst Random */
#define F_TXSIZE_RND (1<<6) /* Transmit size is random */
#define F_IPV6 (1<<7) /* Interface in IPV6 Mode */
#define F_MPLS_RND (1<<8) /* Random MPLS labels */

/* Thread control flag bits */
#define T_TERMINATE (1<<0)
Expand Down Expand Up @@ -278,6 +284,10 @@ struct pktgen_dev {
__u16 udp_dst_min; /* inclusive, dest UDP port */
__u16 udp_dst_max; /* exclusive, dest UDP port */

/* MPLS */
unsigned nr_labels; /* Depth of stack, 0 = no MPLS */
__be32 labels[MAX_MPLS_LABELS];

__u32 src_mac_count; /* How many MACs to iterate through */
__u32 dst_mac_count; /* How many MACs to iterate through */

Expand Down Expand Up @@ -623,9 +633,19 @@ static int pktgen_if_show(struct seq_file *seq, void *v)
pkt_dev->udp_dst_min, pkt_dev->udp_dst_max);

seq_printf(seq,
" src_mac_count: %d dst_mac_count: %d \n Flags: ",
" src_mac_count: %d dst_mac_count: %d\n",
pkt_dev->src_mac_count, pkt_dev->dst_mac_count);

if (pkt_dev->nr_labels) {
unsigned i;
seq_printf(seq, " mpls: ");
for(i = 0; i < pkt_dev->nr_labels; i++)
seq_printf(seq, "%08x%s", ntohl(pkt_dev->labels[i]),
i == pkt_dev->nr_labels-1 ? "\n" : ", ");
}

seq_printf(seq, " Flags: ");

if (pkt_dev->flags & F_IPV6)
seq_printf(seq, "IPV6 ");

Expand All @@ -644,6 +664,9 @@ static int pktgen_if_show(struct seq_file *seq, void *v)
if (pkt_dev->flags & F_UDPDST_RND)
seq_printf(seq, "UDPDST_RND ");

if (pkt_dev->flags & F_MPLS_RND)
seq_printf(seq, "MPLS_RND ");

if (pkt_dev->flags & F_MACSRC_RND)
seq_printf(seq, "MACSRC_RND ");

Expand Down Expand Up @@ -691,6 +714,29 @@ static int pktgen_if_show(struct seq_file *seq, void *v)
return 0;
}


static int hex32_arg(const char __user *user_buffer, __u32 *num)
{
int i = 0;
*num = 0;

for(; i < 8; i++) {
char c;
*num <<= 4;
if (get_user(c, &user_buffer[i]))
return -EFAULT;
if ((c >= '0') && (c <= '9'))
*num |= c - '0';
else if ((c >= 'a') && (c <= 'f'))
*num |= c - 'a' + 10;
else if ((c >= 'A') && (c <= 'F'))
*num |= c - 'A' + 10;
else
break;
}
return i;
}

static int count_trail_chars(const char __user * user_buffer,
unsigned int maxlen)
{
Expand Down Expand Up @@ -759,6 +805,35 @@ static int strn_len(const char __user * user_buffer, unsigned int maxlen)
return i;
}

static ssize_t get_labels(const char __user *buffer, struct pktgen_dev *pkt_dev)
{
unsigned n = 0;
char c;
ssize_t i = 0;
int len;

pkt_dev->nr_labels = 0;
do {
__u32 tmp;
len = hex32_arg(&buffer[i], &tmp);
if (len <= 0)
return len;
pkt_dev->labels[n] = htonl(tmp);
if (pkt_dev->labels[n] & MPLS_STACK_BOTTOM)
pkt_dev->flags |= F_MPLS_RND;
i += len;
if (get_user(c, &buffer[i]))
return -EFAULT;
i++;
n++;
if (n >= MAX_MPLS_LABELS)
return -E2BIG;
} while(c == ',');

pkt_dev->nr_labels = n;
return i;
}

static ssize_t pktgen_if_write(struct file *file,
const char __user * user_buffer, size_t count,
loff_t * offset)
Expand Down Expand Up @@ -1059,6 +1134,12 @@ static ssize_t pktgen_if_write(struct file *file,
else if (strcmp(f, "!MACDST_RND") == 0)
pkt_dev->flags &= ~F_MACDST_RND;

else if (strcmp(f, "MPLS_RND") == 0)
pkt_dev->flags |= F_MPLS_RND;

else if (strcmp(f, "!MPLS_RND") == 0)
pkt_dev->flags &= ~F_MPLS_RND;

else {
sprintf(pg_result,
"Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s",
Expand Down Expand Up @@ -1354,6 +1435,19 @@ static ssize_t pktgen_if_write(struct file *file,
return count;
}

if (!strcmp(name, "mpls")) {
unsigned n, offset;
len = get_labels(&user_buffer[i], pkt_dev);
if (len < 0) { return len; }
i += len;
offset = sprintf(pg_result, "OK: mpls=");
for(n = 0; n < pkt_dev->nr_labels; n++)
offset += sprintf(pg_result + offset,
"%08x%s", ntohl(pkt_dev->labels[n]),
n == pkt_dev->nr_labels-1 ? "" : ",");
return count;
}

sprintf(pkt_dev->result, "No such parameter \"%s\"", name);
return -EINVAL;
}
Expand Down Expand Up @@ -1846,6 +1940,15 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
pkt_dev->hh[1] = tmp;
}

if (pkt_dev->flags & F_MPLS_RND) {
unsigned i;
for(i = 0; i < pkt_dev->nr_labels; i++)
if (pkt_dev->labels[i] & MPLS_STACK_BOTTOM)
pkt_dev->labels[i] = MPLS_STACK_BOTTOM |
(pktgen_random() &
htonl(0x000fffff));
}

if (pkt_dev->udp_src_min < pkt_dev->udp_src_max) {
if (pkt_dev->flags & F_UDPSRC_RND)
pkt_dev->cur_udp_src =
Expand Down Expand Up @@ -1968,6 +2071,16 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
pkt_dev->flows[flow].count++;
}

static void mpls_push(__be32 *mpls, struct pktgen_dev *pkt_dev)
{
unsigned i;
for(i = 0; i < pkt_dev->nr_labels; i++) {
*mpls++ = pkt_dev->labels[i] & ~MPLS_STACK_BOTTOM;
}
mpls--;
*mpls |= MPLS_STACK_BOTTOM;
}

static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
struct pktgen_dev *pkt_dev)
{
Expand All @@ -1977,14 +2090,20 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
int datalen, iplen;
struct iphdr *iph;
struct pktgen_hdr *pgh = NULL;
__be16 protocol = __constant_htons(ETH_P_IP);
__be32 *mpls;

if (pkt_dev->nr_labels)
protocol = __constant_htons(ETH_P_MPLS_UC);

/* Update any of the values, used when we're incrementing various
* fields.
*/
mod_cur_headers(pkt_dev);

datalen = (odev->hard_header_len + 16) & ~0xf;
skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + datalen, GFP_ATOMIC);
skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + datalen +
pkt_dev->nr_labels*sizeof(u32), GFP_ATOMIC);
if (!skb) {
sprintf(pkt_dev->result, "No memory");
return NULL;
Expand All @@ -1994,13 +2113,18 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,

/* Reserve for ethernet and IP header */
eth = (__u8 *) skb_push(skb, 14);
mpls = (__be32 *)skb_put(skb, pkt_dev->nr_labels*sizeof(__u32));
if (pkt_dev->nr_labels)
mpls_push(mpls, pkt_dev);
iph = (struct iphdr *)skb_put(skb, sizeof(struct iphdr));
udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr));

memcpy(eth, pkt_dev->hh, 12);
*(u16 *) & eth[12] = __constant_htons(ETH_P_IP);
*(u16 *) & eth[12] = protocol;

datalen = pkt_dev->cur_pkt_size - 14 - 20 - 8; /* Eth + IPh + UDPh */
/* Eth + IPh + UDPh + mpls */
datalen = pkt_dev->cur_pkt_size - 14 - 20 - 8 -
pkt_dev->nr_labels*sizeof(u32);
if (datalen < sizeof(struct pktgen_hdr))
datalen = sizeof(struct pktgen_hdr);

Expand All @@ -2021,8 +2145,8 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
iph->tot_len = htons(iplen);
iph->check = 0;
iph->check = ip_fast_csum((void *)iph, iph->ihl);
skb->protocol = __constant_htons(ETH_P_IP);
skb->mac.raw = ((u8 *) iph) - 14;
skb->protocol = protocol;
skb->mac.raw = ((u8 *) iph) - 14 - pkt_dev->nr_labels*sizeof(u32);
skb->dev = odev;
skb->pkt_type = PACKET_HOST;

Expand Down Expand Up @@ -2274,13 +2398,19 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
int datalen;
struct ipv6hdr *iph;
struct pktgen_hdr *pgh = NULL;
__be16 protocol = __constant_htons(ETH_P_IPV6);
__be32 *mpls;

if (pkt_dev->nr_labels)
protocol = __constant_htons(ETH_P_MPLS_UC);

/* Update any of the values, used when we're incrementing various
* fields.
*/
mod_cur_headers(pkt_dev);

skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + 16, GFP_ATOMIC);
skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + 16 +
pkt_dev->nr_labels*sizeof(u32), GFP_ATOMIC);
if (!skb) {
sprintf(pkt_dev->result, "No memory");
return NULL;
Expand All @@ -2290,13 +2420,19 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,

/* Reserve for ethernet and IP header */
eth = (__u8 *) skb_push(skb, 14);
mpls = (__be32 *)skb_put(skb, pkt_dev->nr_labels*sizeof(__u32));
if (pkt_dev->nr_labels)
mpls_push(mpls, pkt_dev);
iph = (struct ipv6hdr *)skb_put(skb, sizeof(struct ipv6hdr));
udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr));

memcpy(eth, pkt_dev->hh, 12);
*(u16 *) & eth[12] = __constant_htons(ETH_P_IPV6);

datalen = pkt_dev->cur_pkt_size - 14 - sizeof(struct ipv6hdr) - sizeof(struct udphdr); /* Eth + IPh + UDPh */
/* Eth + IPh + UDPh + mpls */
datalen = pkt_dev->cur_pkt_size - 14 -
sizeof(struct ipv6hdr) - sizeof(struct udphdr) -
pkt_dev->nr_labels*sizeof(u32);

if (datalen < sizeof(struct pktgen_hdr)) {
datalen = sizeof(struct pktgen_hdr);
Expand All @@ -2320,8 +2456,8 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
ipv6_addr_copy(&iph->daddr, &pkt_dev->cur_in6_daddr);
ipv6_addr_copy(&iph->saddr, &pkt_dev->cur_in6_saddr);

skb->mac.raw = ((u8 *) iph) - 14;
skb->protocol = __constant_htons(ETH_P_IPV6);
skb->mac.raw = ((u8 *) iph) - 14 - pkt_dev->nr_labels*sizeof(u32);
skb->protocol = protocol;
skb->dev = odev;
skb->pkt_type = PACKET_HOST;

Expand Down

0 comments on commit ca6549a

Please sign in to comment.