diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index ab30856..a04d9d4 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -236,6 +236,11 @@ struct flow_state {
 /* flow flag bits */
 #define F_INIT   (1<<0)		/* flow has been initialized */
 
+struct frag_param {
+	int offset;
+	int length;
+};
+
 struct pktgen_dev {
 	/*
 	 * Try to keep frequent/infrequent used vars. separated.
@@ -258,6 +263,11 @@ struct pktgen_dev {
 	int max_pkt_size;
 	int pkt_overhead;	/* overhead for MPLS, VLANs, IPSEC etc */
 	int nfrags;
+	/* offset-length pairs for the frags, only the first nfrags are valid,
+	 * and only if frags[0].length != 0, as zero frag size is not valid
+	 * (and neither negative)
+	 */
+	struct frag_param frags[MAX_SKB_FRAGS];
 	struct page *pages[MAX_SKB_FRAGS];
 	u64 delay;		/* nano-seconds */
 
@@ -541,6 +551,18 @@ static int pktgen_if_show(struct seq_file *seq, void *v)
 		   pkt_dev->nfrags, (unsigned long long) pkt_dev->delay,
 		   pkt_dev->clone_skb, pkt_dev->odevname);
 
+	if (pkt_dev->frags[0].length) {
+		int n;
+
+		for (n = 0; n < pkt_dev->nfrags; n++)
+			seq_printf(seq, "     %d. offset: %d length: %d%s\n", n,
+				   pkt_dev->frags[n].offset,
+				   pkt_dev->frags[n].length,
+				   n == pkt_dev->nfrags-1 ? "" : ",");
+	} else {
+			seq_puts(seq, "     No frag parameters defined\n");
+	}
+
 	seq_printf(seq, "     flows: %u flowlen: %u\n", pkt_dev->cflows,
 		   pkt_dev->lflow);
 
@@ -845,6 +867,50 @@ static ssize_t get_labels(const char __user *buffer, struct pktgen_dev *pkt_dev)
 	return i;
 }
 
+static ssize_t get_sizes(const char __user *buffer, struct pktgen_dev *pkt_dev)
+{
+	unsigned int n = 0;
+	char c;
+	ssize_t i = 0;
+	int len;
+
+	pkt_dev->nfrags = 0;
+	do {
+		unsigned long tmp;
+
+		len = num_arg(&buffer[i], 5, &tmp);
+		if (len <= 0)
+			return len;
+		/* Maximum skb size minus 1 */
+		if (tmp >= 65536)
+			return -EINVAL;
+		pkt_dev->frags[n].offset = tmp;
+		i += len;
+		if (get_user(c, &buffer[i]))
+			return -EFAULT;
+		if (c != '-')
+			return -EINVAL;
+		i++;
+
+		len = num_arg(&buffer[i], 5, &tmp);
+		if (len <= 0)
+			return len;
+		if (tmp < 1 || tmp > 65536)
+			return -EINVAL;
+		pkt_dev->frags[n].length = tmp;
+		i += len;
+		if (get_user(c, &buffer[i]))
+			return -EFAULT;
+		i++;
+		n++;
+		if (n > MAX_SKB_FRAGS)
+			return -E2BIG;
+	} while (c == ',');
+
+	pkt_dev->nfrags = n;
+	return i;
+}
+
 static ssize_t pktgen_if_write(struct file *file,
 			       const char __user * user_buffer, size_t count,
 			       loff_t * offset)
@@ -972,9 +1038,30 @@ static ssize_t pktgen_if_write(struct file *file,
 
 		i += len;
 		pkt_dev->nfrags = value;
+		/* Invalidate whatever was specified before */
+		pkt_dev->frags[0].length = 0;
 		sprintf(pg_result, "OK: frags=%u", pkt_dev->nfrags);
 		return count;
 	}
+
+	if (!strcmp(name, "frag_off-len")) {
+		unsigned int n, cnt;
+
+		len = get_sizes(&user_buffer[i], pkt_dev);
+		if (len < 0)
+			return len;
+		i += len;
+		cnt = sprintf(pg_result, "OK: frags=%u frag offsets-sizes=",
+			      pkt_dev->nfrags);
+		for (n = 0; n < pkt_dev->nfrags; n++)
+			cnt += sprintf(pg_result + cnt, "%d-%d%s",
+				       pkt_dev->frags[n].offset,
+				       pkt_dev->frags[n].length,
+				       n == pkt_dev->nfrags-1 ? "" : ",");
+
+		return count;
+	}
+
 	if (!strcmp(name, "delay")) {
 		len = num_arg(&user_buffer[i], 10, &value);
 		if (len < 0)
@@ -2734,12 +2821,25 @@ static void pktgen_finalize_skb(struct pktgen_dev *pkt_dev, struct sk_buff *skb,
 	} else {
 		int frags = pkt_dev->nfrags;
 		int i, len;
-		int frag_len;
+		int frag_len = 0;
 
 
 		if (frags > MAX_SKB_FRAGS)
 			frags = MAX_SKB_FRAGS;
-		len = datalen - frags * PAGE_SIZE;
+
+		if (pkt_dev->frags[0].length) {
+			for (i = 0; i < frags; ++i)
+				frag_len += pkt_dev->frags[i].length;
+			if (frag_len > datalen) {
+				pr_err("Payload length (%d) smaller than frags (%d)\n",
+				       datalen, frag_len);
+				return;
+			}
+		} else {
+			frag_len = frags * PAGE_SIZE;
+		}
+
+		len = datalen - frag_len;
 		if (len > 0) {
 			if (pkt_dev->flags & F_PATTERN)
 				offset = pattern_to_packet(skb_put(skb, len),
@@ -2747,28 +2847,44 @@ static void pktgen_finalize_skb(struct pktgen_dev *pkt_dev, struct sk_buff *skb,
 							   &incomplete);
 			else
 				memset(skb_put(skb, len), 0, len);
-			datalen = frags * PAGE_SIZE;
+			datalen = frag_len;
 		}
 
 		i = 0;
 		frag_len = (datalen/frags) < PAGE_SIZE ?
 			   (datalen/frags) : PAGE_SIZE;
 		while (datalen > 0) {
-			int fragpage;
+			int fragpage, order = 0;
 			gfp_t flags = GFP_KERNEL | __GFP_ZERO;
 
-			if (pkt_dev->flags & F_PATTERN)
+			if (pkt_dev->flags & F_PATTERN ||
+			    pkt_dev->frags[0].length)
 				fragpage = i;
 			else
 				fragpage = 0;
 
+			/* Free this page if we gonna need a different order */
+			if (pkt_dev->frags[0].length) {
+				int max_off = pkt_dev->frags[i].offset +
+					      pkt_dev->frags[i].length;
+				order = get_order(max_off);
+				if (pkt_dev->pages[fragpage] &&
+				    order != compound_order(pkt_dev->pages[fragpage])) {
+					if (pkt_dev->pages[fragpage]) {
+						put_page(pkt_dev->pages[fragpage]);
+						pkt_dev->pages[fragpage] = NULL;
+					}
+				}
+			}
+
 			if (unlikely(!pkt_dev->pages[fragpage])) {
 				int node = numa_node_id();
 
 				if (pkt_dev->node >= 0 && (pkt_dev->flags & F_NODE))
 					node = pkt_dev->node;
+				order ? flags |= __GFP_COMP : 0;
 				pkt_dev->pages[fragpage] =
-					alloc_pages_node(node, flags, 0);
+					alloc_pages_node(node, flags, order);
 				if (!pkt_dev->pages[fragpage])
 					break;
 			}
@@ -2776,8 +2892,14 @@ static void pktgen_finalize_skb(struct pktgen_dev *pkt_dev, struct sk_buff *skb,
 			skb_frag_set_page(skb, i, pkt_dev->pages[fragpage]);
 
 			skb_shinfo(skb)->frags[i].page_offset = 0;
+			if (pkt_dev->frags[0].length) {
+				skb_shinfo(skb)->frags[i].page_offset =
+					pkt_dev->frags[i].offset;
+				skb_frag_size_set(&skb_shinfo(skb)->frags[i],
+						  pkt_dev->frags[i].length);
+			}
 			/*last fragment, fill rest of data*/
-			if (i == (frags - 1))
+			else if (i == (frags - 1))
 				skb_frag_size_set(&skb_shinfo(skb)->frags[i],
 				    (datalen < PAGE_SIZE ? datalen : PAGE_SIZE));
 			else
@@ -3826,8 +3948,10 @@ static int pktgen_remove_device(struct pktgen_thread *t,
 #endif
 	vfree(pkt_dev->flows);
 	for (i = 0; i < MAX_SKB_FRAGS; ++i)
-		if (pkt_dev->pages[i])
+		if (pkt_dev->pages[i]) {
 			put_page(pkt_dev->pages[i]);
+			pkt_dev->pages[i] = NULL;
+		}
 	kfree_rcu(pkt_dev, rcu);
 	return 0;
 }
