Commit ca6549af authored by Steven Whitehouse's avatar Steven Whitehouse Committed by David S. Miller

[PKTGEN]: Add MPLS extension.

Signed-off-by: default avatarSteven Whitehouse <steve@chygwyn.com>
Signed-off-by: default avatarRobert Olsson <robert.olsson@its.uu.se>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 2e6e33ba
...@@ -109,6 +109,22 @@ Examples: ...@@ -109,6 +109,22 @@ Examples:
cycle through the port range. cycle through the port range.
pgset "udp_dst_max 9" set UDP destination port max. 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. pgset stop aborts injection. Also, ^C aborts generator.
...@@ -167,6 +183,8 @@ pkt_size ...@@ -167,6 +183,8 @@ pkt_size
min_pkt_size min_pkt_size
max_pkt_size max_pkt_size
mpls
udp_src_min udp_src_min
udp_src_max udp_src_max
......
...@@ -106,6 +106,9 @@ ...@@ -106,6 +106,9 @@
* *
* interruptible_sleep_on_timeout() replaced Nishanth Aravamudan <nacc@us.ibm.com> * interruptible_sleep_on_timeout() replaced Nishanth Aravamudan <nacc@us.ibm.com>
* 050103 * 050103
*
* MPLS support by Steven Whitehouse <steve@chygwyn.com>
*
*/ */
#include <linux/sys.h> #include <linux/sys.h>
#include <linux/types.h> #include <linux/types.h>
...@@ -154,7 +157,7 @@ ...@@ -154,7 +157,7 @@
#include <asm/div64.h> /* do_div */ #include <asm/div64.h> /* do_div */
#include <asm/timex.h> #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) a */
#define PG_DEBUG(a) #define PG_DEBUG(a)
...@@ -162,6 +165,8 @@ ...@@ -162,6 +165,8 @@
/* The buckets are exponential in 'width' */ /* The buckets are exponential in 'width' */
#define LAT_BUCKETS_MAX 32 #define LAT_BUCKETS_MAX 32
#define IP_NAME_SZ 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 */ /* Device flag bits */
#define F_IPSRC_RND (1<<0) /* IP-Src Random */ #define F_IPSRC_RND (1<<0) /* IP-Src Random */
...@@ -172,6 +177,7 @@ ...@@ -172,6 +177,7 @@
#define F_MACDST_RND (1<<5) /* MAC-Dst Random */ #define F_MACDST_RND (1<<5) /* MAC-Dst Random */
#define F_TXSIZE_RND (1<<6) /* Transmit size is random */ #define F_TXSIZE_RND (1<<6) /* Transmit size is random */
#define F_IPV6 (1<<7) /* Interface in IPV6 Mode */ #define F_IPV6 (1<<7) /* Interface in IPV6 Mode */
#define F_MPLS_RND (1<<8) /* Random MPLS labels */
/* Thread control flag bits */ /* Thread control flag bits */
#define T_TERMINATE (1<<0) #define T_TERMINATE (1<<0)
...@@ -278,6 +284,10 @@ struct pktgen_dev { ...@@ -278,6 +284,10 @@ struct pktgen_dev {
__u16 udp_dst_min; /* inclusive, dest UDP port */ __u16 udp_dst_min; /* inclusive, dest UDP port */
__u16 udp_dst_max; /* exclusive, 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 src_mac_count; /* How many MACs to iterate through */
__u32 dst_mac_count; /* How many MACs to iterate through */ __u32 dst_mac_count; /* How many MACs to iterate through */
...@@ -623,9 +633,19 @@ static int pktgen_if_show(struct seq_file *seq, void *v) ...@@ -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); pkt_dev->udp_dst_min, pkt_dev->udp_dst_max);
seq_printf(seq, 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); 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) if (pkt_dev->flags & F_IPV6)
seq_printf(seq, "IPV6 "); seq_printf(seq, "IPV6 ");
...@@ -644,6 +664,9 @@ static int pktgen_if_show(struct seq_file *seq, void *v) ...@@ -644,6 +664,9 @@ static int pktgen_if_show(struct seq_file *seq, void *v)
if (pkt_dev->flags & F_UDPDST_RND) if (pkt_dev->flags & F_UDPDST_RND)
seq_printf(seq, "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) if (pkt_dev->flags & F_MACSRC_RND)
seq_printf(seq, "MACSRC_RND "); seq_printf(seq, "MACSRC_RND ");
...@@ -691,6 +714,29 @@ static int pktgen_if_show(struct seq_file *seq, void *v) ...@@ -691,6 +714,29 @@ static int pktgen_if_show(struct seq_file *seq, void *v)
return 0; 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, static int count_trail_chars(const char __user * user_buffer,
unsigned int maxlen) unsigned int maxlen)
{ {
...@@ -759,6 +805,35 @@ static int strn_len(const char __user * user_buffer, unsigned int maxlen) ...@@ -759,6 +805,35 @@ static int strn_len(const char __user * user_buffer, unsigned int maxlen)
return i; 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, static ssize_t pktgen_if_write(struct file *file,
const char __user * user_buffer, size_t count, const char __user * user_buffer, size_t count,
loff_t * offset) loff_t * offset)
...@@ -1059,6 +1134,12 @@ static ssize_t pktgen_if_write(struct file *file, ...@@ -1059,6 +1134,12 @@ static ssize_t pktgen_if_write(struct file *file,
else if (strcmp(f, "!MACDST_RND") == 0) else if (strcmp(f, "!MACDST_RND") == 0)
pkt_dev->flags &= ~F_MACDST_RND; 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 { else {
sprintf(pg_result, sprintf(pg_result,
"Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s", "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s",
...@@ -1354,6 +1435,19 @@ static ssize_t pktgen_if_write(struct file *file, ...@@ -1354,6 +1435,19 @@ static ssize_t pktgen_if_write(struct file *file,
return count; 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); sprintf(pkt_dev->result, "No such parameter \"%s\"", name);
return -EINVAL; return -EINVAL;
} }
...@@ -1846,6 +1940,15 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev) ...@@ -1846,6 +1940,15 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
pkt_dev->hh[1] = tmp; 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->udp_src_min < pkt_dev->udp_src_max) {
if (pkt_dev->flags & F_UDPSRC_RND) if (pkt_dev->flags & F_UDPSRC_RND)
pkt_dev->cur_udp_src = pkt_dev->cur_udp_src =
...@@ -1968,6 +2071,16 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev) ...@@ -1968,6 +2071,16 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
pkt_dev->flows[flow].count++; 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, static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
struct pktgen_dev *pkt_dev) struct pktgen_dev *pkt_dev)
{ {
...@@ -1977,6 +2090,11 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev, ...@@ -1977,6 +2090,11 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
int datalen, iplen; int datalen, iplen;
struct iphdr *iph; struct iphdr *iph;
struct pktgen_hdr *pgh = NULL; 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 /* Update any of the values, used when we're incrementing various
* fields. * fields.
...@@ -1984,7 +2102,8 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev, ...@@ -1984,7 +2102,8 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
mod_cur_headers(pkt_dev); mod_cur_headers(pkt_dev);
datalen = (odev->hard_header_len + 16) & ~0xf; 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) { if (!skb) {
sprintf(pkt_dev->result, "No memory"); sprintf(pkt_dev->result, "No memory");
return NULL; return NULL;
...@@ -1994,13 +2113,18 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev, ...@@ -1994,13 +2113,18 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
/* Reserve for ethernet and IP header */ /* Reserve for ethernet and IP header */
eth = (__u8 *) skb_push(skb, 14); 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)); iph = (struct iphdr *)skb_put(skb, sizeof(struct iphdr));
udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr)); udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr));
memcpy(eth, pkt_dev->hh, 12); 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)) if (datalen < sizeof(struct pktgen_hdr))
datalen = sizeof(struct pktgen_hdr); datalen = sizeof(struct pktgen_hdr);
...@@ -2021,8 +2145,8 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev, ...@@ -2021,8 +2145,8 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
iph->tot_len = htons(iplen); iph->tot_len = htons(iplen);
iph->check = 0; iph->check = 0;
iph->check = ip_fast_csum((void *)iph, iph->ihl); iph->check = ip_fast_csum((void *)iph, iph->ihl);
skb->protocol = __constant_htons(ETH_P_IP); skb->protocol = protocol;
skb->mac.raw = ((u8 *) iph) - 14; skb->mac.raw = ((u8 *) iph) - 14 - pkt_dev->nr_labels*sizeof(u32);
skb->dev = odev; skb->dev = odev;
skb->pkt_type = PACKET_HOST; skb->pkt_type = PACKET_HOST;
...@@ -2274,13 +2398,19 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev, ...@@ -2274,13 +2398,19 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
int datalen; int datalen;
struct ipv6hdr *iph; struct ipv6hdr *iph;
struct pktgen_hdr *pgh = NULL; 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 /* Update any of the values, used when we're incrementing various
* fields. * fields.
*/ */
mod_cur_headers(pkt_dev); 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) { if (!skb) {
sprintf(pkt_dev->result, "No memory"); sprintf(pkt_dev->result, "No memory");
return NULL; return NULL;
...@@ -2290,13 +2420,19 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev, ...@@ -2290,13 +2420,19 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
/* Reserve for ethernet and IP header */ /* Reserve for ethernet and IP header */
eth = (__u8 *) skb_push(skb, 14); 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)); iph = (struct ipv6hdr *)skb_put(skb, sizeof(struct ipv6hdr));
udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr)); udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr));
memcpy(eth, pkt_dev->hh, 12); memcpy(eth, pkt_dev->hh, 12);
*(u16 *) & eth[12] = __constant_htons(ETH_P_IPV6); *(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)) { if (datalen < sizeof(struct pktgen_hdr)) {
datalen = sizeof(struct pktgen_hdr); datalen = sizeof(struct pktgen_hdr);
...@@ -2320,8 +2456,8 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev, ...@@ -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->daddr, &pkt_dev->cur_in6_daddr);
ipv6_addr_copy(&iph->saddr, &pkt_dev->cur_in6_saddr); ipv6_addr_copy(&iph->saddr, &pkt_dev->cur_in6_saddr);
skb->mac.raw = ((u8 *) iph) - 14; skb->mac.raw = ((u8 *) iph) - 14 - pkt_dev->nr_labels*sizeof(u32);
skb->protocol = __constant_htons(ETH_P_IPV6); skb->protocol = protocol;
skb->dev = odev; skb->dev = odev;
skb->pkt_type = PACKET_HOST; skb->pkt_type = PACKET_HOST;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment