|
@@ -251,6 +251,7 @@ struct pktgen_dev {
|
|
|
int max_pkt_size; /* = ETH_ZLEN; */
|
|
|
int pkt_overhead; /* overhead for MPLS, VLANs, IPSEC etc */
|
|
|
int nfrags;
|
|
|
+ struct page *page;
|
|
|
u64 delay; /* nano-seconds */
|
|
|
|
|
|
__u64 count; /* Default No packets to send */
|
|
@@ -1134,6 +1135,10 @@ static ssize_t pktgen_if_write(struct file *file,
|
|
|
if (node_possible(value)) {
|
|
|
pkt_dev->node = value;
|
|
|
sprintf(pg_result, "OK: node=%d", pkt_dev->node);
|
|
|
+ if (pkt_dev->page) {
|
|
|
+ put_page(pkt_dev->page);
|
|
|
+ pkt_dev->page = NULL;
|
|
|
+ }
|
|
|
}
|
|
|
else
|
|
|
sprintf(pg_result, "ERROR: node not possible");
|
|
@@ -2605,6 +2610,90 @@ static inline __be16 build_tci(unsigned int id, unsigned int cfi,
|
|
|
return htons(id | (cfi << 12) | (prio << 13));
|
|
|
}
|
|
|
|
|
|
+static void pktgen_finalize_skb(struct pktgen_dev *pkt_dev, struct sk_buff *skb,
|
|
|
+ int datalen)
|
|
|
+{
|
|
|
+ struct timeval timestamp;
|
|
|
+ struct pktgen_hdr *pgh;
|
|
|
+
|
|
|
+ pgh = (struct pktgen_hdr *)skb_put(skb, sizeof(*pgh));
|
|
|
+ datalen -= sizeof(*pgh);
|
|
|
+
|
|
|
+ if (pkt_dev->nfrags <= 0) {
|
|
|
+ pgh = (struct pktgen_hdr *)skb_put(skb, datalen);
|
|
|
+ memset(pgh + 1, 0, datalen);
|
|
|
+ } else {
|
|
|
+ int frags = pkt_dev->nfrags;
|
|
|
+ int i, len;
|
|
|
+
|
|
|
+
|
|
|
+ if (frags > MAX_SKB_FRAGS)
|
|
|
+ frags = MAX_SKB_FRAGS;
|
|
|
+ len = datalen - frags * PAGE_SIZE;
|
|
|
+ if (len > 0) {
|
|
|
+ memset(skb_put(skb, len), 0, len);
|
|
|
+ datalen = frags * PAGE_SIZE;
|
|
|
+ }
|
|
|
+
|
|
|
+ i = 0;
|
|
|
+ while (datalen > 0) {
|
|
|
+ if (unlikely(!pkt_dev->page)) {
|
|
|
+ int node = numa_node_id();
|
|
|
+
|
|
|
+ if (pkt_dev->node >= 0 && (pkt_dev->flags & F_NODE))
|
|
|
+ node = pkt_dev->node;
|
|
|
+ pkt_dev->page = alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO, 0);
|
|
|
+ if (!pkt_dev->page)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ skb_shinfo(skb)->frags[i].page = pkt_dev->page;
|
|
|
+ get_page(pkt_dev->page);
|
|
|
+ skb_shinfo(skb)->frags[i].page_offset = 0;
|
|
|
+ skb_shinfo(skb)->frags[i].size =
|
|
|
+ (datalen < PAGE_SIZE ? datalen : PAGE_SIZE);
|
|
|
+ datalen -= skb_shinfo(skb)->frags[i].size;
|
|
|
+ skb->len += skb_shinfo(skb)->frags[i].size;
|
|
|
+ skb->data_len += skb_shinfo(skb)->frags[i].size;
|
|
|
+ i++;
|
|
|
+ skb_shinfo(skb)->nr_frags = i;
|
|
|
+ }
|
|
|
+
|
|
|
+ while (i < frags) {
|
|
|
+ int rem;
|
|
|
+
|
|
|
+ if (i == 0)
|
|
|
+ break;
|
|
|
+
|
|
|
+ rem = skb_shinfo(skb)->frags[i - 1].size / 2;
|
|
|
+ if (rem == 0)
|
|
|
+ break;
|
|
|
+
|
|
|
+ skb_shinfo(skb)->frags[i - 1].size -= rem;
|
|
|
+
|
|
|
+ skb_shinfo(skb)->frags[i] =
|
|
|
+ skb_shinfo(skb)->frags[i - 1];
|
|
|
+ get_page(skb_shinfo(skb)->frags[i].page);
|
|
|
+ skb_shinfo(skb)->frags[i].page =
|
|
|
+ skb_shinfo(skb)->frags[i - 1].page;
|
|
|
+ skb_shinfo(skb)->frags[i].page_offset +=
|
|
|
+ skb_shinfo(skb)->frags[i - 1].size;
|
|
|
+ skb_shinfo(skb)->frags[i].size = rem;
|
|
|
+ i++;
|
|
|
+ skb_shinfo(skb)->nr_frags = i;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Stamp the time, and sequence number,
|
|
|
+ * convert them to network byte order
|
|
|
+ */
|
|
|
+ pgh->pgh_magic = htonl(PKTGEN_MAGIC);
|
|
|
+ pgh->seq_num = htonl(pkt_dev->seq_num);
|
|
|
+
|
|
|
+ do_gettimeofday(×tamp);
|
|
|
+ pgh->tv_sec = htonl(timestamp.tv_sec);
|
|
|
+ pgh->tv_usec = htonl(timestamp.tv_usec);
|
|
|
+}
|
|
|
+
|
|
|
static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
|
|
|
struct pktgen_dev *pkt_dev)
|
|
|
{
|
|
@@ -2613,7 +2702,6 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
|
|
|
struct udphdr *udph;
|
|
|
int datalen, iplen;
|
|
|
struct iphdr *iph;
|
|
|
- struct pktgen_hdr *pgh = NULL;
|
|
|
__be16 protocol = htons(ETH_P_IP);
|
|
|
__be32 *mpls;
|
|
|
__be16 *vlan_tci = NULL; /* Encapsulates priority and VLAN ID */
|
|
@@ -2729,76 +2817,7 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
|
|
|
pkt_dev->pkt_overhead);
|
|
|
skb->dev = odev;
|
|
|
skb->pkt_type = PACKET_HOST;
|
|
|
-
|
|
|
- if (pkt_dev->nfrags <= 0) {
|
|
|
- pgh = (struct pktgen_hdr *)skb_put(skb, datalen);
|
|
|
- memset(pgh + 1, 0, datalen - sizeof(struct pktgen_hdr));
|
|
|
- } else {
|
|
|
- int frags = pkt_dev->nfrags;
|
|
|
- int i, len;
|
|
|
-
|
|
|
- pgh = (struct pktgen_hdr *)(((char *)(udph)) + 8);
|
|
|
-
|
|
|
- if (frags > MAX_SKB_FRAGS)
|
|
|
- frags = MAX_SKB_FRAGS;
|
|
|
- if (datalen > frags * PAGE_SIZE) {
|
|
|
- len = datalen - frags * PAGE_SIZE;
|
|
|
- memset(skb_put(skb, len), 0, len);
|
|
|
- datalen = frags * PAGE_SIZE;
|
|
|
- }
|
|
|
-
|
|
|
- i = 0;
|
|
|
- while (datalen > 0) {
|
|
|
- struct page *page = alloc_pages(GFP_KERNEL | __GFP_ZERO, 0);
|
|
|
- skb_shinfo(skb)->frags[i].page = page;
|
|
|
- skb_shinfo(skb)->frags[i].page_offset = 0;
|
|
|
- skb_shinfo(skb)->frags[i].size =
|
|
|
- (datalen < PAGE_SIZE ? datalen : PAGE_SIZE);
|
|
|
- datalen -= skb_shinfo(skb)->frags[i].size;
|
|
|
- skb->len += skb_shinfo(skb)->frags[i].size;
|
|
|
- skb->data_len += skb_shinfo(skb)->frags[i].size;
|
|
|
- i++;
|
|
|
- skb_shinfo(skb)->nr_frags = i;
|
|
|
- }
|
|
|
-
|
|
|
- while (i < frags) {
|
|
|
- int rem;
|
|
|
-
|
|
|
- if (i == 0)
|
|
|
- break;
|
|
|
-
|
|
|
- rem = skb_shinfo(skb)->frags[i - 1].size / 2;
|
|
|
- if (rem == 0)
|
|
|
- break;
|
|
|
-
|
|
|
- skb_shinfo(skb)->frags[i - 1].size -= rem;
|
|
|
-
|
|
|
- skb_shinfo(skb)->frags[i] =
|
|
|
- skb_shinfo(skb)->frags[i - 1];
|
|
|
- get_page(skb_shinfo(skb)->frags[i].page);
|
|
|
- skb_shinfo(skb)->frags[i].page =
|
|
|
- skb_shinfo(skb)->frags[i - 1].page;
|
|
|
- skb_shinfo(skb)->frags[i].page_offset +=
|
|
|
- skb_shinfo(skb)->frags[i - 1].size;
|
|
|
- skb_shinfo(skb)->frags[i].size = rem;
|
|
|
- i++;
|
|
|
- skb_shinfo(skb)->nr_frags = i;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /* Stamp the time, and sequence number,
|
|
|
- * convert them to network byte order
|
|
|
- */
|
|
|
- if (pgh) {
|
|
|
- struct timeval timestamp;
|
|
|
-
|
|
|
- pgh->pgh_magic = htonl(PKTGEN_MAGIC);
|
|
|
- pgh->seq_num = htonl(pkt_dev->seq_num);
|
|
|
-
|
|
|
- do_gettimeofday(×tamp);
|
|
|
- pgh->tv_sec = htonl(timestamp.tv_sec);
|
|
|
- pgh->tv_usec = htonl(timestamp.tv_usec);
|
|
|
- }
|
|
|
+ pktgen_finalize_skb(pkt_dev, skb, datalen);
|
|
|
|
|
|
#ifdef CONFIG_XFRM
|
|
|
if (!process_ipsec(pkt_dev, skb, protocol))
|
|
@@ -2980,7 +2999,6 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
|
|
|
struct udphdr *udph;
|
|
|
int datalen;
|
|
|
struct ipv6hdr *iph;
|
|
|
- struct pktgen_hdr *pgh = NULL;
|
|
|
__be16 protocol = htons(ETH_P_IPV6);
|
|
|
__be32 *mpls;
|
|
|
__be16 *vlan_tci = NULL; /* Encapsulates priority and VLAN ID */
|
|
@@ -3083,75 +3101,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
|
|
|
skb->dev = odev;
|
|
|
skb->pkt_type = PACKET_HOST;
|
|
|
|
|
|
- if (pkt_dev->nfrags <= 0)
|
|
|
- pgh = (struct pktgen_hdr *)skb_put(skb, datalen);
|
|
|
- else {
|
|
|
- int frags = pkt_dev->nfrags;
|
|
|
- int i;
|
|
|
-
|
|
|
- pgh = (struct pktgen_hdr *)(((char *)(udph)) + 8);
|
|
|
-
|
|
|
- if (frags > MAX_SKB_FRAGS)
|
|
|
- frags = MAX_SKB_FRAGS;
|
|
|
- if (datalen > frags * PAGE_SIZE) {
|
|
|
- skb_put(skb, datalen - frags * PAGE_SIZE);
|
|
|
- datalen = frags * PAGE_SIZE;
|
|
|
- }
|
|
|
-
|
|
|
- i = 0;
|
|
|
- while (datalen > 0) {
|
|
|
- struct page *page = alloc_pages(GFP_KERNEL, 0);
|
|
|
- skb_shinfo(skb)->frags[i].page = page;
|
|
|
- skb_shinfo(skb)->frags[i].page_offset = 0;
|
|
|
- skb_shinfo(skb)->frags[i].size =
|
|
|
- (datalen < PAGE_SIZE ? datalen : PAGE_SIZE);
|
|
|
- datalen -= skb_shinfo(skb)->frags[i].size;
|
|
|
- skb->len += skb_shinfo(skb)->frags[i].size;
|
|
|
- skb->data_len += skb_shinfo(skb)->frags[i].size;
|
|
|
- i++;
|
|
|
- skb_shinfo(skb)->nr_frags = i;
|
|
|
- }
|
|
|
-
|
|
|
- while (i < frags) {
|
|
|
- int rem;
|
|
|
-
|
|
|
- if (i == 0)
|
|
|
- break;
|
|
|
-
|
|
|
- rem = skb_shinfo(skb)->frags[i - 1].size / 2;
|
|
|
- if (rem == 0)
|
|
|
- break;
|
|
|
-
|
|
|
- skb_shinfo(skb)->frags[i - 1].size -= rem;
|
|
|
-
|
|
|
- skb_shinfo(skb)->frags[i] =
|
|
|
- skb_shinfo(skb)->frags[i - 1];
|
|
|
- get_page(skb_shinfo(skb)->frags[i].page);
|
|
|
- skb_shinfo(skb)->frags[i].page =
|
|
|
- skb_shinfo(skb)->frags[i - 1].page;
|
|
|
- skb_shinfo(skb)->frags[i].page_offset +=
|
|
|
- skb_shinfo(skb)->frags[i - 1].size;
|
|
|
- skb_shinfo(skb)->frags[i].size = rem;
|
|
|
- i++;
|
|
|
- skb_shinfo(skb)->nr_frags = i;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /* Stamp the time, and sequence number,
|
|
|
- * convert them to network byte order
|
|
|
- * should we update cloned packets too ?
|
|
|
- */
|
|
|
- if (pgh) {
|
|
|
- struct timeval timestamp;
|
|
|
-
|
|
|
- pgh->pgh_magic = htonl(PKTGEN_MAGIC);
|
|
|
- pgh->seq_num = htonl(pkt_dev->seq_num);
|
|
|
-
|
|
|
- do_gettimeofday(×tamp);
|
|
|
- pgh->tv_sec = htonl(timestamp.tv_sec);
|
|
|
- pgh->tv_usec = htonl(timestamp.tv_usec);
|
|
|
- }
|
|
|
- /* pkt_dev->seq_num++; FF: you really mean this? */
|
|
|
+ pktgen_finalize_skb(pkt_dev, skb, datalen);
|
|
|
|
|
|
return skb;
|
|
|
}
|
|
@@ -3884,6 +3834,8 @@ static int pktgen_remove_device(struct pktgen_thread *t,
|
|
|
free_SAs(pkt_dev);
|
|
|
#endif
|
|
|
vfree(pkt_dev->flows);
|
|
|
+ if (pkt_dev->page)
|
|
|
+ put_page(pkt_dev->page);
|
|
|
kfree(pkt_dev);
|
|
|
return 0;
|
|
|
}
|