All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH]     pktgen: create packet use  IPv6 source address between src6_min and src6_max.
@ 2020-01-10 10:28 Niu Xilei
  2020-01-10 15:50 ` Stephen Hemminger
  2020-01-10 19:13 ` David Miller
  0 siblings, 2 replies; 3+ messages in thread
From: Niu Xilei @ 2020-01-10 10:28 UTC (permalink / raw)
  To: davem
  Cc: tglx, fw, peterz, pabeni, anshuman.khandual, linyunsheng,
	bigeasy, jonathan.lemon, netdev, linux-kernel, Niu Xilei

    Pktgen can use only one IPv6 source address from output device, or src6 command
    setting. When in pressure test need create lots of session more than 65536.
    If IPSRC_RND flag is use random  address between src6_min and src6_max.

    The GCC  generates code that calls functions in the libgcc library to implement
    the / and % operations with 128-bit operands on 64-bit CPUs. So kernel need
    implement the function  to do / and % operation.

    Signed-off-by: Niu Xilei <niu_xilei@163.com>
---
 net/core/pktgen.c | 183 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 183 insertions(+)

diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index 294bfcf0ce0e..b07ab5984fa8 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -254,6 +254,111 @@ struct flow_state {
 /* flow flag bits */
 #define F_INIT   (1<<0)		/* flow has been initialized */
 
+#ifdef CONFIG_ARCH_SUPPORTS_INT128
+
+__extension__ typedef  unsigned __int128 u128;
+
+/* Kernel not implement __int128's divide and modulo operator. Implement these
+ * operation use shift-subtract division algorithm  adpater from
+ * https://chromium.googlesource.com/chromium/src/third_party/+/master/abseil-cpp/absl/numeric/int128.cc */
+
+/* find first bit set of u128 */
+static inline int fls128(u128 n)
+{
+	u64 hi = n >> 64;
+
+	if (hi)
+		return fls64(hi) + 64;
+
+	return fls64((__u64)n);
+}
+
+/**
+ * div128_u128 - unsigned 128bit int divide with unsigned 128bit int divisor
+ * @dividend:   128bit dividend
+ * @divisor:    128bit divisor
+ * @remainder:  128bit  remainder
+ * @return:     128bit quotient
+ */
+u128 div128_u128(u128 dividend, u128 divisor, u128 *remainder)
+{
+	int i;
+	int shift;
+	u128 quotient = 0;
+	u128 denominator = divisor;
+
+	if (divisor > dividend) {
+		*remainder = dividend;
+		return 0;
+	}
+	if (divisor == dividend) {
+		*remainder = 0;
+		return 1;
+	}
+
+	/* Left aligns the MSB of the dividend and the dividend. */
+	shift = fls128(dividend) - fls128(denominator);
+	denominator <<= shift;
+	/* Uses shift-subtract algorithm to divide dividend by denominator. The
+	 * remainder will be left in dividend. */
+	for (i = 0; i <= shift; ++i) {
+		quotient <<= 1;
+		if (dividend >= denominator) {
+			dividend -= denominator;
+			quotient |= 1;
+		}
+		denominator >>= 1;
+	}
+	*remainder = dividend;
+	return quotient;
+}
+
+#ifdef __LITTLE_ENDIAN
+
+static inline u128 be128_to_cpu(u128 net128)
+{
+#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
+	u64 *pnet = (u64 *)&net128;
+
+	return (((__force u128)swab64(pnet[0]) << 64) |
+		(__force u128)swab64(pnet[1]));
+#else
+
+	u32 *pnet = (u32 *)&net128;
+
+	return (((__force u128)swap32(pnet[0])) << 96 |
+		((__force u128)swap32(pnet[1])) << 64 |
+		((__force u128)swap32(pnet[2])) << 32 |
+		(__force u128)swap32(pnet[3]));
+
+#endif
+}
+
+static inline u128 cpu_to_be128(u128 host128)
+{
+#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
+	u64 *phost = (u64 *)&host128;
+
+	return  (((__force u128)swab64(phost[0])) << 64 |
+		(__force u128)swab64(phost[1]));
+#else
+	u32 *phost = (u32 *)&host128;
+
+	return (((__force u128)swap32(phost[0])) << 96 |
+		((__force u128)swap32(phost[1])) << 64 |
+		((__force u128)swap32(phost[2])) << 32 |
+		(__force u128)swap32(phost[3]));
+#endif
+}
+
+#else /* !__LITTLE_ENDIAN  */
+
+#define be128_to_cpu(x) (x)
+#define cpu_to_be128(x) (x)
+
+#endif /* __LITTLE_ENDIAN */
+#endif /* CONFIG_ARCH_SUPPORTS_INT128 */
+
 struct pktgen_dev {
 	/*
 	 * Try to keep frequent/infrequent used vars. separated.
@@ -1355,6 +1460,49 @@ static ssize_t pktgen_if_write(struct file *file,
 		sprintf(pg_result, "OK: dst6_max=%s", buf);
 		return count;
 	}
+	if (!strcmp(name, "src6_min")) {
+		len = strn_len(&user_buffer[i], sizeof(buf) - 1);
+		if (len < 0)
+			return len;
+
+		pkt_dev->flags |= F_IPV6;
+
+		if (copy_from_user(buf, &user_buffer[i], len))
+			return -EFAULT;
+		buf[len] = 0;
+
+		in6_pton(buf, -1, pkt_dev->min_in6_saddr.s6_addr, -1, NULL);
+		snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->min_in6_saddr);
+
+		pkt_dev->cur_in6_saddr = pkt_dev->min_in6_saddr;
+		if (debug)
+			pr_debug("src6_min set to: %s\n", buf);
+
+		i += len;
+		sprintf(pg_result, "OK: src6_min=%s", buf);
+		return count;
+	}
+	if (!strcmp(name, "src6_max")) {
+		len = strn_len(&user_buffer[i], sizeof(buf) - 1);
+		if (len < 0)
+			return len;
+
+		pkt_dev->flags |= F_IPV6;
+
+		if (copy_from_user(buf, &user_buffer[i], len))
+			return -EFAULT;
+		buf[len] = 0;
+
+		in6_pton(buf, -1, pkt_dev->max_in6_saddr.s6_addr, -1, NULL);
+		snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->max_in6_saddr);
+
+		if (debug)
+			pr_debug("dst6_max set to: %s\n", buf);
+
+		i += len;
+		sprintf(pg_result, "OK: dst6_max=%s", buf);
+		return count;
+	}
 	if (!strcmp(name, "src6")) {
 		len = strn_len(&user_buffer[i], sizeof(buf) - 1);
 		if (len < 0)
@@ -2286,6 +2434,38 @@ static void set_cur_queue_map(struct pktgen_dev *pkt_dev)
 	pkt_dev->cur_queue_map  = pkt_dev->cur_queue_map % pkt_dev->odev->real_num_tx_queues;
 }
 
+/* create ipv6 source addr, random generator or iterator between the range  */
+static inline void set_src_in6_addr(struct pktgen_dev *pkt_dev)
+{
+	u128 t;
+	u128 imn6, imx6;
+
+	if (!ipv6_addr_any(&pkt_dev->min_in6_saddr)) {
+#ifdef CONFIG_ARCH_SUPPORTS_INT128
+		imn6 = be128_to_cpu(*(u128 *)pkt_dev->min_in6_saddr.s6_addr);
+		imx6 = be128_to_cpu(*(u128 *)pkt_dev->max_in6_saddr.s6_addr);
+		if (imn6 < imx6) {
+			if (pkt_dev->flags & F_IPSRC_RND) {
+				do {
+					prandom_bytes(&t, sizeof(t));
+					/*t = t % range */
+					div128_u128(t, imx6 - imn6, &t);
+					t = imn6 + t;
+				} while (ipv6_addr_loopback((struct in6_addr *)&t) ||
+					 ipv6_addr_v4mapped((struct in6_addr *)&t) ||
+					 ipv6_addr_is_multicast((struct in6_addr *)(&t)));
+			} else {
+				t = be128_to_cpu(*(u128 *)pkt_dev->cur_in6_saddr.s6_addr);
+				t++;
+				if (t > imx6)
+					t = imn6;
+			}
+			t = cpu_to_be128(t);
+			pkt_dev->cur_in6_saddr = *(struct in6_addr *)&t;
+		}
+#endif
+	}
+}
 /* Increment/randomize headers according to flags and current values
  * for IP src/dest, UDP src/dst port, MAC-Addr src/dst
  */
@@ -2293,6 +2473,7 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
 {
 	__u32 imn;
 	__u32 imx;
+
 	int flow = 0;
 
 	if (pkt_dev->cflows)
@@ -2454,6 +2635,8 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
 		}
 	} else {		/* IPV6 * */
 
+		set_src_in6_addr(pkt_dev);
+
 		if (!ipv6_addr_any(&pkt_dev->min_in6_daddr)) {
 			int i;
 
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2020-01-10 19:13 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-01-10 10:28 [PATCH] pktgen: create packet use IPv6 source address between src6_min and src6_max Niu Xilei
2020-01-10 15:50 ` Stephen Hemminger
2020-01-10 19:13 ` David Miller

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.