add generic size table for qdiscs

Patch adds generic size table that is similiar to rate table, with
difference that size table stores link layer packet size.

Based on patch by Patrick McHardy
 http://marc.info/?l=linux-netdev&m=115201979221729&w=2

Signed-off-by: Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
Signed-off-by: Stephen Hemminger <stephen.hemminger@vyatta.com>
diff --git a/tc/tc_core.c b/tc/tc_core.c
index 855c115..9a0ff39 100644
--- a/tc/tc_core.c
+++ b/tc/tc_core.c
@@ -87,6 +87,21 @@
 	return linksize;
 }
 
+unsigned tc_adjust_size(unsigned sz, unsigned mpu, enum link_layer linklayer)
+{
+	if (sz < mpu)
+		sz = mpu;
+
+	switch (linklayer) {
+	case LINKLAYER_ATM:
+		return tc_align_to_atm(sz);
+	case LINKLAYER_ETHERNET:
+	default:
+		// No size adjustments on Ethernet
+		return sz;
+	}
+}
+
 /*
    rtab[pkt_len>>cell_log] = pkt_xmit_time
  */
@@ -96,6 +111,7 @@
 		   enum link_layer linklayer)
 {
 	int i;
+	unsigned sz;
 	unsigned bps = r->rate;
 	unsigned mpu = r->mpu;
 
@@ -109,21 +125,7 @@
 	}
 
 	for (i=0; i<256; i++) {
-		unsigned sz = (i+1)<<cell_log;
-		if (sz < mpu)
-			sz = mpu;
-
-		switch (linklayer) {
-		case LINKLAYER_ATM:
-			sz = tc_align_to_atm(sz);
-			break;
-		case LINKLAYER_ETHERNET:
-			// No size adjustments on Ethernet
-			break;
-		default:
-			break;
-		}
-
+		sz = tc_adjust_size((i + 1) << cell_log, mpu, linklayer);
 		rtab[i] = tc_calc_xmittime(bps, sz);
 	}
 
@@ -132,6 +134,53 @@
 	return cell_log;
 }
 
+/*
+   stab[pkt_len>>cell_log] = pkt_xmit_size>>size_log
+ */
+
+int tc_calc_size_table(struct tc_sizespec *s, __u16 **stab)
+{
+	int i;
+	enum link_layer linklayer = s->linklayer;
+	unsigned int sz;
+
+	if (linklayer <= LINKLAYER_ETHERNET && s->mpu == 0) {
+		/* don't need data table in this case (only overhead set) */
+		s->mtu = 0;
+		s->tsize = 0;
+		s->cell_log = 0;
+		s->cell_align = 0;
+		*stab = NULL;
+		return 0;
+	}
+
+	if (s->mtu == 0)
+		s->mtu = 2047;
+	if (s->tsize == 0)
+		s->tsize = 512;
+
+	s->cell_log = 0;
+	while ((s->mtu >> s->cell_log) > s->tsize - 1)
+		s->cell_log++;
+
+	*stab = malloc(s->tsize * sizeof(__u16));
+	if (!*stab)
+		return -1;
+
+again:
+	for (i = s->tsize - 1; i >= 0; i--) {
+		sz = tc_adjust_size((i + 1) << s->cell_log, s->mpu, linklayer);
+		if ((sz >> s->size_log) > UINT16_MAX) {
+			s->size_log++;
+			goto again;
+		}
+		(*stab)[i] = sz >> s->size_log;
+	}
+
+	s->cell_align = -1; // Due to the sz calc
+	return 0;
+}
+
 int tc_core_init()
 {
 	FILE *fp;