]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - net/core/pktgen.c
Merge branch 'for-linus' of git://brick.kernel.dk/data/git/linux-2.6-block
[linux-2.6-omap-h63xx.git] / net / core / pktgen.c
index 033802769e4f8a97096a1766a4a0dca31fe5a568..1897a3a385d803808ac2f30a6abad2de3aa36967 100644 (file)
 #include <asm/div64.h>         /* do_div */
 #include <asm/timex.h>
 
-#define VERSION  "pktgen v2.67: Packet Generator for packet performance testing.\n"
+#define VERSION  "pktgen v2.68: Packet Generator for packet performance testing.\n"
 
 /* #define PG_DEBUG(a) a */
 #define PG_DEBUG(a)
@@ -207,7 +207,7 @@ static struct proc_dir_entry *pg_proc_dir = NULL;
 #define SVLAN_TAG_SIZE(x) ((x)->svlan_id == 0xffff ? 0 : 4)
 
 struct flow_state {
-       __u32 cur_daddr;
+       __be32 cur_daddr;
        int count;
 };
 
@@ -282,16 +282,20 @@ struct pktgen_dev {
        /* If we're doing ranges, random or incremental, then this
         * defines the min/max for those ranges.
         */
-       __u32 saddr_min;        /* inclusive, source IP address */
-       __u32 saddr_max;        /* exclusive, source IP address */
-       __u32 daddr_min;        /* inclusive, dest IP address */
-       __u32 daddr_max;        /* exclusive, dest IP address */
+       __be32 saddr_min;       /* inclusive, source IP address */
+       __be32 saddr_max;       /* exclusive, source IP address */
+       __be32 daddr_min;       /* inclusive, dest IP address */
+       __be32 daddr_max;       /* exclusive, dest IP address */
 
        __u16 udp_src_min;      /* inclusive, source UDP port */
        __u16 udp_src_max;      /* exclusive, source UDP port */
        __u16 udp_dst_min;      /* inclusive, dest UDP port */
        __u16 udp_dst_max;      /* exclusive, dest UDP port */
 
+       /* DSCP + ECN */
+       __u8 tos;            /* six most significant bits of (former) IPv4 TOS are for dscp codepoint */
+       __u8 traffic_class;  /* ditto for the (former) Traffic Class in IPv6 (see RFC 3260, sec. 4) */
+
        /* MPLS */
        unsigned nr_labels;     /* Depth of stack, 0 = no MPLS */
        __be32 labels[MAX_MPLS_LABELS];
@@ -313,8 +317,8 @@ struct pktgen_dev {
 
        __u32 cur_dst_mac_offset;
        __u32 cur_src_mac_offset;
-       __u32 cur_saddr;
-       __u32 cur_daddr;
+       __be32 cur_saddr;
+       __be32 cur_daddr;
        __u16 cur_udp_dst;
        __u16 cur_udp_src;
        __u32 cur_pkt_size;
@@ -346,10 +350,10 @@ struct pktgen_dev {
 };
 
 struct pktgen_hdr {
-       __u32 pgh_magic;
-       __u32 seq_num;
-       __u32 tv_sec;
-       __u32 tv_usec;
+       __be32 pgh_magic;
+       __be32 seq_num;
+       __be32 tv_sec;
+       __be32 tv_usec;
 };
 
 struct pktgen_thread {
@@ -671,6 +675,14 @@ static int pktgen_if_show(struct seq_file *seq, void *v)
                           pkt_dev->svlan_id, pkt_dev->svlan_p, pkt_dev->svlan_cfi);
        }
 
+       if (pkt_dev->tos) {
+               seq_printf(seq, "     tos: 0x%02x\n", pkt_dev->tos);
+       }
+
+       if (pkt_dev->traffic_class) {
+               seq_printf(seq, "     traffic_class: 0x%02x\n", pkt_dev->traffic_class);
+       }
+
        seq_printf(seq, "     Flags: ");
 
        if (pkt_dev->flags & F_IPV6)
@@ -748,12 +760,12 @@ static int pktgen_if_show(struct seq_file *seq, void *v)
 }
 
 
-static int hex32_arg(const char __user *user_buffer, __u32 *num)
+static int hex32_arg(const char __user *user_buffer, unsigned long maxlen, __u32 *num)
 {
        int i = 0;
        *num = 0;
 
-       for(; i < 8; i++) {
+       for(; i < maxlen; i++) {
                char c;
                *num <<= 4;
                if (get_user(c, &user_buffer[i]))
@@ -848,7 +860,7 @@ static ssize_t get_labels(const char __user *buffer, struct pktgen_dev *pkt_dev)
        pkt_dev->nr_labels = 0;
        do {
                __u32 tmp;
-               len = hex32_arg(&buffer[i], &tmp);
+               len = hex32_arg(&buffer[i], 8, &tmp);
                if (len <= 0)
                        return len;
                pkt_dev->labels[n] = htonl(tmp);
@@ -1185,11 +1197,15 @@ static ssize_t pktgen_if_write(struct file *file,
                else if (strcmp(f, "!SVID_RND") == 0)
                        pkt_dev->flags &= ~F_SVID_RND;
 
+               else if (strcmp(f, "!IPV6") == 0)
+                       pkt_dev->flags &= ~F_IPV6;
+
                else {
                        sprintf(pg_result,
                                "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s",
                                f,
-                               "IPSRC_RND, IPDST_RND, TXSIZE_RND, UDPSRC_RND, UDPDST_RND, MACSRC_RND, MACDST_RND\n");
+                               "IPSRC_RND, IPDST_RND, UDPSRC_RND, UDPDST_RND, "
+                               "MACSRC_RND, MACDST_RND, TXSIZE_RND, IPV6, MPLS_RND, VID_RND, SVID_RND\n");
                        return count;
                }
                sprintf(pg_result, "OK: flags=0x%x", pkt_dev->flags);
@@ -1615,6 +1631,38 @@ static ssize_t pktgen_if_write(struct file *file,
                return count;
        }
 
+       if (!strcmp(name, "tos")) {
+               __u32 tmp_value = 0;
+               len = hex32_arg(&user_buffer[i], 2, &tmp_value);
+               if (len < 0) {
+                       return len;
+               }
+               i += len;
+               if (len == 2) {
+                       pkt_dev->tos = tmp_value;
+                       sprintf(pg_result, "OK: tos=0x%02x", pkt_dev->tos);
+               } else {
+                       sprintf(pg_result, "ERROR: tos must be 00-ff");
+               }
+               return count;
+       }
+
+       if (!strcmp(name, "traffic_class")) {
+               __u32 tmp_value = 0;
+               len = hex32_arg(&user_buffer[i], 2, &tmp_value);
+               if (len < 0) {
+                       return len;
+               }
+               i += len;
+               if (len == 2) {
+                       pkt_dev->traffic_class = tmp_value;
+                       sprintf(pg_result, "OK: traffic_class=0x%02x", pkt_dev->traffic_class);
+               } else {
+                       sprintf(pg_result, "ERROR: traffic_class must be 00-ff");
+               }
+               return count;
+       }
+
        sprintf(pkt_dev->result, "No such parameter \"%s\"", name);
        return -EINVAL;
 }
@@ -2112,7 +2160,7 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
                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() &
+                                            ((__force __be32)pktgen_random() &
                                                      htonl(0x000fffff));
        }
 
@@ -2172,29 +2220,25 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
                if (pkt_dev->cflows && pkt_dev->flows[flow].count != 0) {
                        pkt_dev->cur_daddr = pkt_dev->flows[flow].cur_daddr;
                } else {
-
-                       if ((imn = ntohl(pkt_dev->daddr_min)) < (imx =
-                                                                ntohl(pkt_dev->
-                                                                      daddr_max)))
-                       {
+                       imn = ntohl(pkt_dev->daddr_min);
+                       imx = ntohl(pkt_dev->daddr_max);
+                       if (imn < imx) {
                                __u32 t;
+                               __be32 s;
                                if (pkt_dev->flags & F_IPDST_RND) {
 
-                                       t = ((pktgen_random() % (imx - imn)) +
-                                            imn);
-                                       t = htonl(t);
+                                       t = pktgen_random() % (imx - imn) + imn;
+                                       s = htonl(t);
 
-                                       while (LOOPBACK(t) || MULTICAST(t)
-                                              || BADCLASS(t) || ZERONET(t)
-                                              || LOCAL_MCAST(t)) {
-                                               t = ((pktgen_random() %
-                                                     (imx - imn)) + imn);
-                                               t = htonl(t);
+                                       while (LOOPBACK(s) || MULTICAST(s)
+                                              || BADCLASS(s) || ZERONET(s)
+                                              || LOCAL_MCAST(s)) {
+                                               t = (pktgen_random() %
+                                                     (imx - imn)) + imn;
+                                               s = htonl(t);
                                        }
-                                       pkt_dev->cur_daddr = t;
-                               }
-
-                               else {
+                                       pkt_dev->cur_daddr = s;
+                               } else {
                                        t = ntohl(pkt_dev->cur_daddr);
                                        t++;
                                        if (t > imx) {
@@ -2222,7 +2266,7 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
 
                        for (i = 0; i < 4; i++) {
                                pkt_dev->cur_in6_daddr.s6_addr32[i] =
-                                   ((pktgen_random() |
+                                   (((__force __be32)pktgen_random() |
                                      pkt_dev->min_in6_daddr.s6_addr32[i]) &
                                     pkt_dev->max_in6_daddr.s6_addr32[i]);
                        }
@@ -2256,6 +2300,12 @@ static void mpls_push(__be32 *mpls, struct pktgen_dev *pkt_dev)
        *mpls |= MPLS_STACK_BOTTOM;
 }
 
+static inline __be16 build_tci(unsigned int id, unsigned int cfi,
+                              unsigned int prio)
+{
+       return htons(id | (cfi << 12) | (prio << 13));
+}
+
 static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
                                        struct pktgen_dev *pkt_dev)
 {
@@ -2305,16 +2355,16 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
        if (pkt_dev->vlan_id != 0xffff) {
                if(pkt_dev->svlan_id != 0xffff) {
                        svlan_tci = (__be16 *)skb_put(skb, sizeof(__be16));
-                       *svlan_tci = htons(pkt_dev->svlan_id);
-                       *svlan_tci |= pkt_dev->svlan_p << 5;
-                       *svlan_tci |= pkt_dev->svlan_cfi << 4;
+                       *svlan_tci = build_tci(pkt_dev->svlan_id,
+                                              pkt_dev->svlan_cfi,
+                                              pkt_dev->svlan_p);
                        svlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16));
                        *svlan_encapsulated_proto = __constant_htons(ETH_P_8021Q);
                }
                vlan_tci = (__be16 *)skb_put(skb, sizeof(__be16));
-               *vlan_tci = htons(pkt_dev->vlan_id);
-               *vlan_tci |= pkt_dev->vlan_p << 5;
-               *vlan_tci |= pkt_dev->vlan_cfi << 4;
+               *vlan_tci = build_tci(pkt_dev->vlan_id,
+                                     pkt_dev->vlan_cfi,
+                                     pkt_dev->vlan_p);
                vlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16));
                *vlan_encapsulated_proto = __constant_htons(ETH_P_IP);
        }
@@ -2323,7 +2373,7 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
        udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr));
 
        memcpy(eth, pkt_dev->hh, 12);
-       *(u16 *) & eth[12] = protocol;
+       *(__be16 *) & eth[12] = protocol;
 
        /* Eth + IPh + UDPh + mpls */
        datalen = pkt_dev->cur_pkt_size - 14 - 20 - 8 -
@@ -2339,7 +2389,7 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
        iph->ihl = 5;
        iph->version = 4;
        iph->ttl = 32;
-       iph->tos = 0;
+       iph->tos = pkt_dev->tos;
        iph->protocol = IPPROTO_UDP;    /* UDP */
        iph->saddr = pkt_dev->cur_saddr;
        iph->daddr = pkt_dev->cur_daddr;
@@ -2443,7 +2493,7 @@ static unsigned int scan_ip6(const char *s, char ip[16])
        char suffix[16];
        unsigned int prefixlen = 0;
        unsigned int suffixlen = 0;
-       __u32 tmp;
+       __be32 tmp;
 
        for (i = 0; i < 16; i++)
                ip[i] = 0;
@@ -2641,16 +2691,16 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
        if (pkt_dev->vlan_id != 0xffff) {
                if(pkt_dev->svlan_id != 0xffff) {
                        svlan_tci = (__be16 *)skb_put(skb, sizeof(__be16));
-                       *svlan_tci = htons(pkt_dev->svlan_id);
-                       *svlan_tci |= pkt_dev->svlan_p << 5;
-                       *svlan_tci |= pkt_dev->svlan_cfi << 4;
+                       *svlan_tci = build_tci(pkt_dev->svlan_id,
+                                              pkt_dev->svlan_cfi,
+                                              pkt_dev->svlan_p);
                        svlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16));
                        *svlan_encapsulated_proto = __constant_htons(ETH_P_8021Q);
                }
                vlan_tci = (__be16 *)skb_put(skb, sizeof(__be16));
-               *vlan_tci = htons(pkt_dev->vlan_id);
-               *vlan_tci |= pkt_dev->vlan_p << 5;
-               *vlan_tci |= pkt_dev->vlan_cfi << 4;
+               *vlan_tci = build_tci(pkt_dev->vlan_id,
+                                     pkt_dev->vlan_cfi,
+                                     pkt_dev->vlan_p);
                vlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16));
                *vlan_encapsulated_proto = __constant_htons(ETH_P_IPV6);
        }
@@ -2659,7 +2709,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
        udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr));
 
        memcpy(eth, pkt_dev->hh, 12);
-       *(u16 *) & eth[12] = protocol;
+       *(__be16 *) & eth[12] = protocol;
 
        /* Eth + IPh + UDPh + mpls */
        datalen = pkt_dev->cur_pkt_size - 14 -
@@ -2678,7 +2728,12 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
        udph->len = htons(datalen + sizeof(struct udphdr));
        udph->check = 0;        /* No checksum */
 
-       *(u32 *) iph = __constant_htonl(0x60000000);    /* Version + flow */
+       *(__be32 *) iph = __constant_htonl(0x60000000); /* Version + flow */
+
+       if (pkt_dev->traffic_class) {
+               /* Version + traffic class + flow (0) */
+               *(__be32 *)iph |= htonl(0x60000000 | (pkt_dev->traffic_class << 20));
+       }
 
        iph->hop_limit = 32;