While taking a look at '[PATCH net] pktgen: Avoid out-of-range in get_imix_entries' ([1]) and '[PATCH net v2] pktgen: Avoid out-of-bounds access in get_imix_entries' ([2], [3]) and doing some tests and code review I detected that the /proc/net/pktgen/... parsing logic does not honour the user given buffer bounds (resulting in out-of-bounds access).
This can be observed e.g. by the following simple test (sometimes the old/'longer' previous value is re-read from the buffer):
$ echo add_device lo@0 > /proc/net/pktgen/kpktgend_0
$ echo "min_pkt_size 12345" > /proc/net/pktgen/lo@0 && grep min_pkt_size /proc/net/pktgen/lo@0 Params: count 1000 min_pkt_size: 12345 max_pkt_size: 0 Result: OK: min_pkt_size=12345
$ echo -n "min_pkt_size 123" > /proc/net/pktgen/lo@0 && grep min_pkt_size /proc/net/pktgen/lo@0 Params: count 1000 min_pkt_size: 12345 max_pkt_size: 0 Result: OK: min_pkt_size=12345
$ echo "min_pkt_size 123" > /proc/net/pktgen/lo@0 && grep min_pkt_size /proc/net/pktgen/lo@0 Params: count 1000 min_pkt_size: 123 max_pkt_size: 0 Result: OK: min_pkt_size=123
So fix the out-of-bounds access (and two minor findings) and add a simple proc_net_pktgen selftest...
Regards, Peter
[1] https://lore.kernel.org/netdev/20241006221221.3744995-1-artem.chernyshev@red... [2] https://lore.kernel.org/netdev/20250109083039.14004-1-pchelkin@ispras.ru/ [3] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
Peter Seiderer (5): net: pktgen: replace ENOTSUPP with EOPNOTSUPP net: pktgen: enable 'param=value' parsing net: pktgen: fix access outside of user given buffer in pktgen_thread_write() net: pktgen: fix access outside of user given buffer in pktgen_if_write() selftest: net: add proc_net_pktgen
net/core/pktgen.c | 210 ++++--- tools/testing/selftests/net/Makefile | 1 + tools/testing/selftests/net/proc_net_pktgen.c | 575 ++++++++++++++++++ 3 files changed, 712 insertions(+), 74 deletions(-) create mode 100644 tools/testing/selftests/net/proc_net_pktgen.c
Replace ENOTSUPP with EOPNOTSUPP, fixes checkpatch hint
WARNING: ENOTSUPP is not a SUSV4 error code, prefer EOPNOTSUPP
and e.g.
$ echo "clone_skb 1" > /proc/net/pktgen/lo@0 -bash: echo: write error: Unknown error 524
Signed-off-by: Peter Seiderer ps.report@gmx.net --- net/core/pktgen.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 82b6a2c3c141..496aa16773e7 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -1198,7 +1198,7 @@ static ssize_t pktgen_if_write(struct file *file, if ((value > 0) && ((pkt_dev->xmit_mode == M_NETIF_RECEIVE) || !(pkt_dev->odev->priv_flags & IFF_TX_SKB_SHARING))) - return -ENOTSUPP; + return -EOPNOTSUPP; if (value > 0 && (pkt_dev->n_imix_entries > 0 || !(pkt_dev->flags & F_SHARED))) return -EINVAL; @@ -1258,7 +1258,7 @@ static ssize_t pktgen_if_write(struct file *file, ((pkt_dev->xmit_mode == M_QUEUE_XMIT) || ((pkt_dev->xmit_mode == M_START_XMIT) && (!(pkt_dev->odev->priv_flags & IFF_TX_SKB_SHARING))))) - return -ENOTSUPP; + return -EOPNOTSUPP;
if (value > 1 && !(pkt_dev->flags & F_SHARED)) return -EINVAL; @@ -1303,7 +1303,7 @@ static ssize_t pktgen_if_write(struct file *file, } else if (strcmp(f, "netif_receive") == 0) { /* clone_skb set earlier, not supported in this mode */ if (pkt_dev->clone_skb > 0) - return -ENOTSUPP; + return -EOPNOTSUPP;
pkt_dev->xmit_mode = M_NETIF_RECEIVE;
Enable additional to 'parm value' the 'param=value' parsing (otherwise skipping '=' in count_trail_chars() is useless).
Tested with:
$ echo "min_pkt_size 999" > /proc/net/pktgen/lo@0 $ echo "min_pkt_size=999" > /proc/net/pktgen/lo@0 $ echo "min_pkt_size =999" > /proc/net/pktgen/lo@0 $ echo "min_pkt_size= 999" > /proc/net/pktgen/lo@0 $ echo "min_pkt_size = 999" > /proc/net/pktgen/lo@0
Signed-off-by: Peter Seiderer ps.report@gmx.net --- net/core/pktgen.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 496aa16773e7..4f8ec6c9bed4 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -823,6 +823,7 @@ static int strn_len(const char __user * user_buffer, unsigned int maxlen) case '\r': case '\t': case ' ': + case '=': goto done_str; default: break;
Honour the user given buffer size for the strn_len() calls (otherwise strn_len() will access memory outside of the user given buffer).
Signed-off-by: Peter Seiderer ps.report@gmx.net --- net/core/pktgen.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 4f8ec6c9bed4..9536f9c4d9ef 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -1897,8 +1897,8 @@ static ssize_t pktgen_thread_write(struct file *file, i = len;
/* Read variable name */ - - len = strn_len(&user_buffer[i], sizeof(name) - 1); + max = min(sizeof(name) - 1, count - i); + len = strn_len(&user_buffer[i], max); if (len < 0) return len;
@@ -1928,7 +1928,8 @@ static ssize_t pktgen_thread_write(struct file *file, if (!strcmp(name, "add_device")) { char f[32]; memset(f, 0, 32); - len = strn_len(&user_buffer[i], sizeof(f) - 1); + max = min(sizeof(f) - 1, count - i); + len = strn_len(&user_buffer[i], max); if (len < 0) { ret = len; goto out;
Honour the user given buffer size for the hex32_arg(), num_arg() and strn_len() calls (otherwise they will access memory outside of the user given buffer).
In all three functions error out in case no characters a available (maxlen = 0), in num_arg() additional error out in case no valid character is parsed.
Additional remove some superfluous variable initializing and align some variable declarations to the most common pattern.
Signed-off-by: Peter Seiderer ps.report@gmx.net --- net/core/pktgen.c | 196 ++++++++++++++++++++++++++++++---------------- 1 file changed, 128 insertions(+), 68 deletions(-)
diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 9536f9c4d9ef..5f54a056fa7c 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -750,6 +750,9 @@ static int hex32_arg(const char __user *user_buffer, unsigned long maxlen, int i = 0; *num = 0;
+ if (!maxlen) + return -EINVAL; + for (; i < maxlen; i++) { int value; char c; @@ -796,6 +799,9 @@ static long num_arg(const char __user *user_buffer, unsigned long maxlen, int i; *num = 0;
+ if (!maxlen) + return -EINVAL; + for (i = 0; i < maxlen; i++) { char c; if (get_user(c, &user_buffer[i])) @@ -803,6 +809,9 @@ static long num_arg(const char __user *user_buffer, unsigned long maxlen, if ((c >= '0') && (c <= '9')) { *num *= 10; *num += c - '0'; + } else if (i == 0) { + // no valid character parsed, error out + return -EINVAL; } else break; } @@ -813,6 +822,9 @@ static int strn_len(const char __user * user_buffer, unsigned int maxlen) { int i;
+ if (!maxlen) + return -EINVAL; + for (i = 0; i < maxlen; i++) { char c; if (get_user(c, &user_buffer[i])) @@ -839,11 +851,10 @@ static int strn_len(const char __user * user_buffer, unsigned int maxlen) * "size1,weight_1 size2,weight_2 ... size_n,weight_n" for example. */ static ssize_t get_imix_entries(const char __user *buffer, + unsigned int maxlen, struct pktgen_dev *pkt_dev) { - const int max_digits = 10; - int i = 0; - long len; + int i = 0, max, len; char c;
pkt_dev->n_imix_entries = 0; @@ -855,7 +866,8 @@ static ssize_t get_imix_entries(const char __user *buffer, if (pkt_dev->n_imix_entries >= MAX_IMIX_ENTRIES) return -E2BIG;
- len = num_arg(&buffer[i], max_digits, &size); + max = min(10, maxlen - i); + len = num_arg(&buffer[i], max, &size); if (len < 0) return len; i += len; @@ -869,7 +881,8 @@ static ssize_t get_imix_entries(const char __user *buffer, if (size < 14 + 20 + 8) size = 14 + 20 + 8;
- len = num_arg(&buffer[i], max_digits, &weight); + max = min(10, maxlen - i); + len = num_arg(&buffer[i], max, &weight); if (len < 0) return len; if (weight <= 0) @@ -889,18 +902,19 @@ static ssize_t get_imix_entries(const char __user *buffer, return i; }
-static ssize_t get_labels(const char __user *buffer, struct pktgen_dev *pkt_dev) +static ssize_t get_labels(const char __user *buffer, int maxlen, struct pktgen_dev *pkt_dev) { unsigned int n = 0; char c; - ssize_t i = 0; - int len; + int i = 0, max, len;
pkt_dev->nr_labels = 0; do { __u32 tmp; - len = hex32_arg(&buffer[i], 8, &tmp); - if (len <= 0) + + max = min(8, maxlen - i); + len = hex32_arg(&buffer[i], max, &tmp); + if (len < 0) return len; pkt_dev->labels[n] = htonl(tmp); if (pkt_dev->labels[n] & MPLS_STACK_BOTTOM) @@ -957,7 +971,6 @@ static ssize_t pktgen_if_write(struct file *file, char name[16], valstr[32]; unsigned long value = 0; char *pg_result = NULL; - int tmp = 0; char buf[128];
pg_result = &(pkt_dev->result[0]); @@ -967,17 +980,16 @@ static ssize_t pktgen_if_write(struct file *file, return -EINVAL; }
- max = count; - tmp = count_trail_chars(user_buffer, max); - if (tmp < 0) { + len = count_trail_chars(user_buffer, count); + if (len < 0) { pr_warn("illegal format\n"); - return tmp; + return len; } - i = tmp; + i = len;
/* Read variable name */ - - len = strn_len(&user_buffer[i], sizeof(name) - 1); + max = min(sizeof(name) - 1, count - i); + len = strn_len(&user_buffer[i], max); if (len < 0) return len;
@@ -1005,7 +1017,8 @@ static ssize_t pktgen_if_write(struct file *file, }
if (!strcmp(name, "min_pkt_size")) { - len = num_arg(&user_buffer[i], 10, &value); + max = min(10, count - i); + len = num_arg(&user_buffer[i], max, &value); if (len < 0) return len;
@@ -1022,7 +1035,8 @@ static ssize_t pktgen_if_write(struct file *file, }
if (!strcmp(name, "max_pkt_size")) { - len = num_arg(&user_buffer[i], 10, &value); + max = min(10, count - i); + len = num_arg(&user_buffer[i], max, &value); if (len < 0) return len;
@@ -1041,7 +1055,8 @@ static ssize_t pktgen_if_write(struct file *file, /* Shortcut for min = max */
if (!strcmp(name, "pkt_size")) { - len = num_arg(&user_buffer[i], 10, &value); + max = min(10, count - i); + len = num_arg(&user_buffer[i], max, &value); if (len < 0) return len;
@@ -1061,7 +1076,8 @@ static ssize_t pktgen_if_write(struct file *file, if (pkt_dev->clone_skb > 0) return -EINVAL;
- len = get_imix_entries(&user_buffer[i], pkt_dev); + max = count - i; + len = get_imix_entries(&user_buffer[i], max, pkt_dev); if (len < 0) return len;
@@ -1072,7 +1088,8 @@ static ssize_t pktgen_if_write(struct file *file, }
if (!strcmp(name, "debug")) { - len = num_arg(&user_buffer[i], 10, &value); + max = min(10, count - i); + len = num_arg(&user_buffer[i], max, &value); if (len < 0) return len;
@@ -1083,7 +1100,8 @@ static ssize_t pktgen_if_write(struct file *file, }
if (!strcmp(name, "frags")) { - len = num_arg(&user_buffer[i], 10, &value); + max = min(10, count - i); + len = num_arg(&user_buffer[i], max, &value); if (len < 0) return len;
@@ -1093,7 +1111,8 @@ static ssize_t pktgen_if_write(struct file *file, return count; } if (!strcmp(name, "delay")) { - len = num_arg(&user_buffer[i], 10, &value); + max = min(10, count - i); + len = num_arg(&user_buffer[i], max, &value); if (len < 0) return len;
@@ -1108,7 +1127,8 @@ static ssize_t pktgen_if_write(struct file *file, return count; } if (!strcmp(name, "rate")) { - len = num_arg(&user_buffer[i], 10, &value); + max = min(10, count - i); + len = num_arg(&user_buffer[i], max, &value); if (len < 0) return len;
@@ -1123,7 +1143,8 @@ static ssize_t pktgen_if_write(struct file *file, return count; } if (!strcmp(name, "ratep")) { - len = num_arg(&user_buffer[i], 10, &value); + max = min(10, count - i); + len = num_arg(&user_buffer[i], max, &value); if (len < 0) return len;
@@ -1138,7 +1159,8 @@ static ssize_t pktgen_if_write(struct file *file, return count; } if (!strcmp(name, "udp_src_min")) { - len = num_arg(&user_buffer[i], 10, &value); + max = min(10, count - i); + len = num_arg(&user_buffer[i], max, &value); if (len < 0) return len;
@@ -1151,7 +1173,8 @@ static ssize_t pktgen_if_write(struct file *file, return count; } if (!strcmp(name, "udp_dst_min")) { - len = num_arg(&user_buffer[i], 10, &value); + max = min(10, count - i); + len = num_arg(&user_buffer[i], max, &value); if (len < 0) return len;
@@ -1164,7 +1187,8 @@ static ssize_t pktgen_if_write(struct file *file, return count; } if (!strcmp(name, "udp_src_max")) { - len = num_arg(&user_buffer[i], 10, &value); + max = min(10, count - i); + len = num_arg(&user_buffer[i], max, &value); if (len < 0) return len;
@@ -1177,7 +1201,8 @@ static ssize_t pktgen_if_write(struct file *file, return count; } if (!strcmp(name, "udp_dst_max")) { - len = num_arg(&user_buffer[i], 10, &value); + max = min(10, count - i); + len = num_arg(&user_buffer[i], max, &value); if (len < 0) return len;
@@ -1190,7 +1215,8 @@ static ssize_t pktgen_if_write(struct file *file, return count; } if (!strcmp(name, "clone_skb")) { - len = num_arg(&user_buffer[i], 10, &value); + max = min(10, count - i); + len = num_arg(&user_buffer[i], max, &value); if (len < 0) return len; /* clone_skb is not supported for netif_receive xmit_mode and @@ -1211,7 +1237,8 @@ static ssize_t pktgen_if_write(struct file *file, return count; } if (!strcmp(name, "count")) { - len = num_arg(&user_buffer[i], 10, &value); + max = min(10, count - i); + len = num_arg(&user_buffer[i], max, &value); if (len < 0) return len;
@@ -1222,7 +1249,8 @@ static ssize_t pktgen_if_write(struct file *file, return count; } if (!strcmp(name, "src_mac_count")) { - len = num_arg(&user_buffer[i], 10, &value); + max = min(10, count - i); + len = num_arg(&user_buffer[i], max, &value); if (len < 0) return len;
@@ -1236,7 +1264,8 @@ static ssize_t pktgen_if_write(struct file *file, return count; } if (!strcmp(name, "dst_mac_count")) { - len = num_arg(&user_buffer[i], 10, &value); + max = min(10, count - i); + len = num_arg(&user_buffer[i], max, &value); if (len < 0) return len;
@@ -1250,7 +1279,8 @@ static ssize_t pktgen_if_write(struct file *file, return count; } if (!strcmp(name, "burst")) { - len = num_arg(&user_buffer[i], 10, &value); + max = min(10, count - i); + len = num_arg(&user_buffer[i], max, &value); if (len < 0) return len;
@@ -1269,7 +1299,8 @@ static ssize_t pktgen_if_write(struct file *file, return count; } if (!strcmp(name, "node")) { - len = num_arg(&user_buffer[i], 10, &value); + max = min(10, count - i); + len = num_arg(&user_buffer[i], max, &value); if (len < 0) return len;
@@ -1290,11 +1321,12 @@ static ssize_t pktgen_if_write(struct file *file, if (!strcmp(name, "xmit_mode")) { char f[32];
- memset(f, 0, 32); - len = strn_len(&user_buffer[i], sizeof(f) - 1); + max = min(sizeof(f) - 1, count - i); + len = strn_len(&user_buffer[i], max); if (len < 0) return len;
+ memset(f, 0, sizeof(f)); if (copy_from_user(f, &user_buffer[i], len)) return -EFAULT; i += len; @@ -1330,11 +1362,12 @@ static ssize_t pktgen_if_write(struct file *file, char f[32]; char *end;
- memset(f, 0, 32); - len = strn_len(&user_buffer[i], sizeof(f) - 1); + max = min(sizeof(f) - 1, count - i); + len = strn_len(&user_buffer[i], max); if (len < 0) return len;
+ memset(f, 0, 32); if (copy_from_user(f, &user_buffer[i], len)) return -EFAULT; i += len; @@ -1379,7 +1412,8 @@ static ssize_t pktgen_if_write(struct file *file, return count; } if (!strcmp(name, "dst_min") || !strcmp(name, "dst")) { - len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_min) - 1); + max = min(sizeof(pkt_dev->dst_min) - 1, count - i); + len = strn_len(&user_buffer[i], max); if (len < 0) return len;
@@ -1399,7 +1433,8 @@ static ssize_t pktgen_if_write(struct file *file, return count; } if (!strcmp(name, "dst_max")) { - len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_max) - 1); + max = min(sizeof(pkt_dev->dst_max) - 1, count - i); + len = strn_len(&user_buffer[i], max); if (len < 0) return len;
@@ -1419,7 +1454,8 @@ static ssize_t pktgen_if_write(struct file *file, return count; } if (!strcmp(name, "dst6")) { - len = strn_len(&user_buffer[i], sizeof(buf) - 1); + max = min(sizeof(buf) - 1, count - i); + len = strn_len(&user_buffer[i], max); if (len < 0) return len;
@@ -1442,7 +1478,8 @@ static ssize_t pktgen_if_write(struct file *file, return count; } if (!strcmp(name, "dst6_min")) { - len = strn_len(&user_buffer[i], sizeof(buf) - 1); + max = min(sizeof(buf) - 1, count - i); + len = strn_len(&user_buffer[i], max); if (len < 0) return len;
@@ -1464,7 +1501,8 @@ static ssize_t pktgen_if_write(struct file *file, return count; } if (!strcmp(name, "dst6_max")) { - len = strn_len(&user_buffer[i], sizeof(buf) - 1); + max = min(sizeof(buf) - 1, count - i); + len = strn_len(&user_buffer[i], max); if (len < 0) return len;
@@ -1485,7 +1523,8 @@ static ssize_t pktgen_if_write(struct file *file, return count; } if (!strcmp(name, "src6")) { - len = strn_len(&user_buffer[i], sizeof(buf) - 1); + max = min(sizeof(buf) - 1, count - i); + len = strn_len(&user_buffer[i], max); if (len < 0) return len;
@@ -1508,7 +1547,8 @@ static ssize_t pktgen_if_write(struct file *file, return count; } if (!strcmp(name, "src_min")) { - len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_min) - 1); + max = min(sizeof(pkt_dev->src_min) - 1, count - i); + len = strn_len(&user_buffer[i], max); if (len < 0) return len;
@@ -1528,7 +1568,8 @@ static ssize_t pktgen_if_write(struct file *file, return count; } if (!strcmp(name, "src_max")) { - len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_max) - 1); + max = min(sizeof(pkt_dev->src_max) - 1, count - i); + len = strn_len(&user_buffer[i], max); if (len < 0) return len;
@@ -1548,7 +1589,8 @@ static ssize_t pktgen_if_write(struct file *file, return count; } if (!strcmp(name, "dst_mac")) { - len = strn_len(&user_buffer[i], sizeof(valstr) - 1); + max = min(sizeof(valstr) - 1, count - i); + len = strn_len(&user_buffer[i], max); if (len < 0) return len;
@@ -1565,7 +1607,8 @@ static ssize_t pktgen_if_write(struct file *file, return count; } if (!strcmp(name, "src_mac")) { - len = strn_len(&user_buffer[i], sizeof(valstr) - 1); + max = min(sizeof(valstr) - 1, count - i); + len = strn_len(&user_buffer[i], max); if (len < 0) return len;
@@ -1589,7 +1632,8 @@ static ssize_t pktgen_if_write(struct file *file, }
if (!strcmp(name, "flows")) { - len = num_arg(&user_buffer[i], 10, &value); + max = min(10, count - i); + len = num_arg(&user_buffer[i], max, &value); if (len < 0) return len;
@@ -1603,7 +1647,8 @@ static ssize_t pktgen_if_write(struct file *file, } #ifdef CONFIG_XFRM if (!strcmp(name, "spi")) { - len = num_arg(&user_buffer[i], 10, &value); + max = min(10, count - i); + len = num_arg(&user_buffer[i], max, &value); if (len < 0) return len;
@@ -1614,7 +1659,8 @@ static ssize_t pktgen_if_write(struct file *file, } #endif if (!strcmp(name, "flowlen")) { - len = num_arg(&user_buffer[i], 10, &value); + max = min(10, count - i); + len = num_arg(&user_buffer[i], max, &value); if (len < 0) return len;
@@ -1625,7 +1671,8 @@ static ssize_t pktgen_if_write(struct file *file, }
if (!strcmp(name, "queue_map_min")) { - len = num_arg(&user_buffer[i], 5, &value); + max = min(5, count - i); + len = num_arg(&user_buffer[i], max, &value); if (len < 0) return len;
@@ -1636,7 +1683,8 @@ static ssize_t pktgen_if_write(struct file *file, }
if (!strcmp(name, "queue_map_max")) { - len = num_arg(&user_buffer[i], 5, &value); + max = min(5, count - i); + len = num_arg(&user_buffer[i], max, &value); if (len < 0) return len;
@@ -1649,7 +1697,8 @@ static ssize_t pktgen_if_write(struct file *file, if (!strcmp(name, "mpls")) { unsigned int n, cnt;
- len = get_labels(&user_buffer[i], pkt_dev); + max = count - i; + len = get_labels(&user_buffer[i], max, pkt_dev); if (len < 0) return len; i += len; @@ -1670,7 +1719,8 @@ static ssize_t pktgen_if_write(struct file *file, }
if (!strcmp(name, "vlan_id")) { - len = num_arg(&user_buffer[i], 4, &value); + max = min(4, count - i); + len = num_arg(&user_buffer[i], max, &value); if (len < 0) return len;
@@ -1697,7 +1747,8 @@ static ssize_t pktgen_if_write(struct file *file, }
if (!strcmp(name, "vlan_p")) { - len = num_arg(&user_buffer[i], 1, &value); + max = min(1, count - i); + len = num_arg(&user_buffer[i], max, &value); if (len < 0) return len;
@@ -1712,7 +1763,8 @@ static ssize_t pktgen_if_write(struct file *file, }
if (!strcmp(name, "vlan_cfi")) { - len = num_arg(&user_buffer[i], 1, &value); + max = min(1, count - i); + len = num_arg(&user_buffer[i], max, &value); if (len < 0) return len;
@@ -1727,7 +1779,8 @@ static ssize_t pktgen_if_write(struct file *file, }
if (!strcmp(name, "svlan_id")) { - len = num_arg(&user_buffer[i], 4, &value); + max = min(4, count - i); + len = num_arg(&user_buffer[i], max, &value); if (len < 0) return len;
@@ -1754,7 +1807,8 @@ static ssize_t pktgen_if_write(struct file *file, }
if (!strcmp(name, "svlan_p")) { - len = num_arg(&user_buffer[i], 1, &value); + max = min(1, count - i); + len = num_arg(&user_buffer[i], max, &value); if (len < 0) return len;
@@ -1769,7 +1823,8 @@ static ssize_t pktgen_if_write(struct file *file, }
if (!strcmp(name, "svlan_cfi")) { - len = num_arg(&user_buffer[i], 1, &value); + max = min(1, count - i); + len = num_arg(&user_buffer[i], max, &value); if (len < 0) return len;
@@ -1784,8 +1839,10 @@ static ssize_t pktgen_if_write(struct file *file, }
if (!strcmp(name, "tos")) { - __u32 tmp_value = 0; - len = hex32_arg(&user_buffer[i], 2, &tmp_value); + __u32 tmp_value; + + max = min(2, count - i); + len = hex32_arg(&user_buffer[i], max, &tmp_value); if (len < 0) return len;
@@ -1800,8 +1857,10 @@ static ssize_t pktgen_if_write(struct file *file, }
if (!strcmp(name, "traffic_class")) { - __u32 tmp_value = 0; - len = hex32_arg(&user_buffer[i], 2, &tmp_value); + __u32 tmp_value; + + max = min(2, count - i); + len = hex32_arg(&user_buffer[i], max, &tmp_value); if (len < 0) return len;
@@ -1816,7 +1875,8 @@ static ssize_t pktgen_if_write(struct file *file, }
if (!strcmp(name, "skb_priority")) { - len = num_arg(&user_buffer[i], 9, &value); + max = min(9, count - i); + len = num_arg(&user_buffer[i], max, &value); if (len < 0) return len;
Add some test for /proc/net/pktgen/... interface.
Signed-off-by: Peter Seiderer ps.report@gmx.net --- tools/testing/selftests/net/Makefile | 1 + tools/testing/selftests/net/proc_net_pktgen.c | 575 ++++++++++++++++++ 2 files changed, 576 insertions(+) create mode 100644 tools/testing/selftests/net/proc_net_pktgen.c
diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile index 73ee88d6b043..095708cd8345 100644 --- a/tools/testing/selftests/net/Makefile +++ b/tools/testing/selftests/net/Makefile @@ -100,6 +100,7 @@ TEST_PROGS += vlan_bridge_binding.sh TEST_PROGS += bpf_offload.py TEST_PROGS += ipv6_route_update_soft_lockup.sh TEST_PROGS += busy_poll_test.sh +TEST_GEN_PROGS += proc_net_pktgen
# YNL files, must be before "include ..lib.mk" YNL_GEN_FILES := busy_poller netlink-dumps diff --git a/tools/testing/selftests/net/proc_net_pktgen.c b/tools/testing/selftests/net/proc_net_pktgen.c new file mode 100644 index 000000000000..1d01fa2a96e9 --- /dev/null +++ b/tools/testing/selftests/net/proc_net_pktgen.c @@ -0,0 +1,575 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * proc_net_pktgen: kselftest for /proc/net/pktgen interface + * + * Copyright (c) 2025 Peter Seiderer ps.report@gmx.net + * + */ +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> + +#include "../kselftest_harness.h" + +static const char add_loopback_0[] = "add_device lo@0"; +static const char rm_loopback_0[] = "rem_device_all"; + +static const char wrong_ctrl_command[] = "forsureawrongcommand"; +static const char legacy_ctrl_command[] = "max_before_softirq"; + +static const char wrong_device_command[] = "forsurewrongcommand"; +static const char device_command_min_pkt_size_0[] = "min_pkt_size"; +static const char device_command_min_pkt_size_1[] = "min_pkt_size "; +static const char device_command_min_pkt_size_2[] = "min_pkt_size 0"; +static const char device_command_min_pkt_size_3[] = "min_pkt_size 1"; +static const char device_command_min_pkt_size_4[] = "min_pkt_size 100"; +static const char device_command_min_pkt_size_5[] = "min_pkt_size=1001"; +static const char device_command_min_pkt_size_6[] = "min_pkt_size =2002"; +static const char device_command_min_pkt_size_7[] = "min_pkt_size= 3003"; +static const char device_command_min_pkt_size_8[] = "min_pkt_size = 4004"; +static const char device_command_max_pkt_size_0[] = "max_pkt_size 200"; +static const char device_command_pkt_size_0[] = "pkt_size 300"; +static const char device_command_imix_weights_0[] = "imix_weights 0,7 576,4 1500,1"; +static const char device_command_imix_weights_1[] = "imix_weights 101,1 102,2 103,3 104,4 105,5 106,6 107,7 108,8 109,9 110,10 111,11 112,12 113,13 114,14 115,15 116,16 117,17 118,18 119,19 120,20"; +static const char device_command_imix_weights_2[] = "imix_weights 100,1 102,2 103,3 104,4 105,5 106,6 107,7 108,8 109,9 110,10 111,11 112,12 113,13 114,14 115,15 116,16 117,17 118,18 119,19 120,20 121,21"; +static const char device_command_debug_0[] = "debug 1"; +static const char device_command_debug_1[] = "debug 0"; +static const char device_command_frags_0[] = "frags 100"; +static const char device_command_delay_0[] = "delay 100"; +static const char device_command_delay_1[] = "delay 2147483647"; +static const char device_command_rate_0[] = "rate 100"; +static const char device_command_ratep_0[] = "ratep 200"; +static const char device_command_udp_src_min_0[] = "udp_src_min 1"; +static const char device_command_udp_dst_min_0[] = "udp_dst_min 2"; +static const char device_command_udp_src_max_0[] = "udp_src_max 3"; +static const char device_command_udp_dst_max_0[] = "udp_dst_max 4"; +static const char device_command_clone_skb_0[] = "clone_skb 1"; +static const char device_command_clone_skb_1[] = "clone_skb 0"; +static const char device_command_count_0[] = "count 100"; +static const char device_command_src_mac_count_0[] = "src_mac_count 100"; +static const char device_command_dst_mac_count_0[] = "dst_mac_count 100"; +static const char device_command_burst_0[] = "burst 0"; +static const char device_command_node_0[] = "node 100"; +static const char device_command_xmit_mode_0[] = "xmit_mode start_xmit"; +static const char device_command_xmit_mode_1[] = "xmit_mode netif_receive"; +static const char device_command_xmit_mode_2[] = "xmit_mode queue_xmit"; +static const char device_command_xmit_mode_3[] = "xmit_mode nonsense"; +static const char device_command_flag_0[] = "flag UDPCSUM"; +static const char device_command_flag_1[] = "flag !UDPCSUM"; +static const char device_command_flag_2[] = "flag nonsense"; +static const char device_command_dst_min_0[] = "dst_min 101.102.103.104"; +static const char device_command_dst_0[] = "dst 101.102.103.104"; +static const char device_command_dst_max_0[] = "dst_max 201.202.203.204"; +static const char device_command_dst6_0[] = "dst6 2001:db38:1234:0000:0000:0000:0000:0000"; +static const char device_command_dst6_min_0[] = "dst6_min 2001:db8:1234:0000:0000:0000:0000:0000"; +static const char device_command_dst6_max_0[] = "dst6_max 2001:db8:1234:0000:0000:0000:0000:0000"; +static const char device_command_src6_0[] = "src6 2001:db38:1234:0000:0000:0000:0000:0000"; +static const char device_command_src_min_0[] = "src_min 101.102.103.104"; +static const char device_command_src_max_0[] = "src_max 201.202.203.204"; +static const char device_command_dst_mac_0[] = "dst_mac 01:02:03:04:05:06"; +static const char device_command_src_mac_0[] = "src_mac 11:12:13:14:15:16"; +static const char device_command_clear_counters_0[] = "clear_counters"; +static const char device_command_flows_0[] = "flows 100"; +#if 0 // needs CONFIG_XFRM +static const char device_command_spi_0[] = "spi 100"; +#endif +static const char device_command_flowlen_0[] = "flowlen 100"; +static const char device_command_queue_map_min_0[] = "queue_map_min 1"; +static const char device_command_queue_map_max_0[] = "queue_map_max 2"; +static const char device_command_mpls_0[] = "mpls 00000001,000000f2,00000ff3,0000fff4,000ffff5,00fffff6,0ffffff7,fffffff8"; +static const char device_command_vlan_id_0[] = "vlan_id 1"; +static const char device_command_vlan_p_0[] = "vlan_p 1"; +static const char device_command_vlan_cfi_0[] = "vlan_cfi 1"; +static const char device_command_vlan_id_1[] = "vlan_id 4096"; +static const char device_command_svlan_id_0[] = "svlan_id 1"; +static const char device_command_svlan_p_0[] = "svlan_p 1"; +static const char device_command_svlan_cfi_0[] = "svlan_cfi 1"; +static const char device_command_svlan_id_1[] = "svlan_id 4096"; +static const char device_command_tos_0[] = "tos 0"; +static const char device_command_tos_1[] = "tos 0f"; +static const char device_command_tos_2[] = "tos 0ff"; +static const char device_command_traffic_class_0[] = "traffic_class f0"; +static const char device_command_skb_priority_0[] = "skb_priority 999"; + +FIXTURE(proc_net_pktgen) { + int ctrl_fd; + int device_fd; +}; + +FIXTURE_SETUP(proc_net_pktgen) { + ssize_t len; + + self->ctrl_fd = open("/proc/net/pktgen/kpktgend_0", O_RDWR); + ASSERT_GE(self->ctrl_fd, 0) TH_LOG("CONFIG_NET_PKTGEN not enabled, module pktgen nod loaded?"); + + len = write(self->ctrl_fd, add_loopback_0, sizeof(add_loopback_0)); + ASSERT_EQ(len, sizeof(add_loopback_0)) TH_LOG("device lo@0 already registered?"); + + self->device_fd = open("/proc/net/pktgen/lo@0", O_RDWR); + ASSERT_GE(self->device_fd, 0) TH_LOG("device entry for lo@0 missing?"); +} + +FIXTURE_TEARDOWN(proc_net_pktgen) { + int ret; + ssize_t len; + + ret = close(self->device_fd); + EXPECT_EQ(ret, 0); + + len = write(self->ctrl_fd, rm_loopback_0, sizeof(rm_loopback_0)); + EXPECT_EQ(len, sizeof(rm_loopback_0)); + + ret = close(self->ctrl_fd); + EXPECT_EQ(ret, 0); +} + +TEST_F(proc_net_pktgen, wrong_ctrl_command) { + for (int i = 0; i <= sizeof(wrong_ctrl_command); i++) { + ssize_t len = write(self->ctrl_fd, wrong_ctrl_command, i); + EXPECT_EQ(len, -1); + EXPECT_EQ(errno, EINVAL); + } +} + +TEST_F(proc_net_pktgen, legacy_ctrl_command) { + for (int i = 0; i <= sizeof(legacy_ctrl_command); i++) { + ssize_t len = write(self->ctrl_fd, legacy_ctrl_command, i); + if (i < (sizeof(legacy_ctrl_command) - 1)) { + // incomplete command string + EXPECT_EQ(len, -1); + EXPECT_EQ(errno, EINVAL); + } else { + // complete command string without/with trailing '\0' + EXPECT_EQ(len, i); + } + } +} + +TEST_F(proc_net_pktgen, wrong_device_command) { + for (int i = 0; i <= sizeof(wrong_device_command); i++) { + ssize_t len = write(self->device_fd, wrong_device_command, i); + EXPECT_EQ(len, -1); + EXPECT_EQ(errno, EINVAL); + } +} + +TEST_F(proc_net_pktgen, device_command_min_pkt_size) { + ssize_t len; + + // with trailing '\0' + len = write(self->device_fd, device_command_min_pkt_size_0, sizeof(device_command_min_pkt_size_0)); + EXPECT_EQ(len, -1); + EXPECT_EQ(errno, EINVAL); + + // without trailing '\0' + len = write(self->device_fd, device_command_min_pkt_size_0, sizeof(device_command_min_pkt_size_0) - 1); + EXPECT_EQ(len, -1); + EXPECT_EQ(errno, EINVAL); + + // with trailing '\0' + len = write(self->device_fd, device_command_min_pkt_size_1, sizeof(device_command_min_pkt_size_1)); + EXPECT_EQ(len, -1); + EXPECT_EQ(errno, EINVAL); + + // without trailing '\0' + len = write(self->device_fd, device_command_min_pkt_size_1, sizeof(device_command_min_pkt_size_1) - 1); + EXPECT_EQ(len, -1); + EXPECT_EQ(errno, EINVAL); + + // with trailing '\0' + len = write(self->device_fd, device_command_min_pkt_size_2, sizeof(device_command_min_pkt_size_2)); + EXPECT_EQ(len, sizeof(device_command_min_pkt_size_2)); + + // without trailing '\0' + len = write(self->device_fd, device_command_min_pkt_size_2, sizeof(device_command_min_pkt_size_2) - 1); + EXPECT_EQ(len, sizeof(device_command_min_pkt_size_2) - 1); + + len = write(self->device_fd, device_command_min_pkt_size_3, sizeof(device_command_min_pkt_size_3)); + EXPECT_EQ(len, sizeof(device_command_min_pkt_size_3)); + + len = write(self->device_fd, device_command_min_pkt_size_4, sizeof(device_command_min_pkt_size_4)); + EXPECT_EQ(len, sizeof(device_command_min_pkt_size_4)); + + len = write(self->device_fd, device_command_min_pkt_size_5, sizeof(device_command_min_pkt_size_5)); + EXPECT_EQ(len, sizeof(device_command_min_pkt_size_5)); + + len = write(self->device_fd, device_command_min_pkt_size_6, sizeof(device_command_min_pkt_size_6)); + EXPECT_EQ(len, sizeof(device_command_min_pkt_size_6)); + + len = write(self->device_fd, device_command_min_pkt_size_7, sizeof(device_command_min_pkt_size_7)); + EXPECT_EQ(len, sizeof(device_command_min_pkt_size_7)); + + len = write(self->device_fd, device_command_min_pkt_size_8, sizeof(device_command_min_pkt_size_8)); + EXPECT_EQ(len, sizeof(device_command_min_pkt_size_8)); +} + +TEST_F(proc_net_pktgen, device_command_max_pkt_size) { + ssize_t len; + + len = write(self->device_fd, device_command_max_pkt_size_0, sizeof(device_command_max_pkt_size_0)); + EXPECT_EQ(len, sizeof(device_command_max_pkt_size_0)); +} + +TEST_F(proc_net_pktgen, device_command_pkt_size) { + ssize_t len; + + len = write(self->device_fd, device_command_pkt_size_0, sizeof(device_command_pkt_size_0)); + EXPECT_EQ(len, sizeof(device_command_pkt_size_0)); +} + +TEST_F(proc_net_pktgen, device_command_imix_weights) { + ssize_t len; + + len = write(self->device_fd, device_command_imix_weights_0, sizeof(device_command_imix_weights_0)); + EXPECT_EQ(len, sizeof(device_command_imix_weights_0)); + + len = write(self->device_fd, device_command_imix_weights_1, sizeof(device_command_imix_weights_1)); + EXPECT_EQ(len, sizeof(device_command_imix_weights_1)); + + len = write(self->device_fd, device_command_imix_weights_2, sizeof(device_command_imix_weights_2)); + EXPECT_EQ(len, -1); + EXPECT_EQ(errno, E2BIG); +} + +TEST_F(proc_net_pktgen, device_command_debug) { + ssize_t len; + + // debug on + len = write(self->device_fd, device_command_debug_0, sizeof(device_command_debug_0)); + EXPECT_EQ(len, sizeof(device_command_debug_0)); + + // debug off + len = write(self->device_fd, device_command_debug_1, sizeof(device_command_debug_1)); + EXPECT_EQ(len, sizeof(device_command_debug_1)); +} + +TEST_F(proc_net_pktgen, device_command_frags) { + ssize_t len; + + len = write(self->device_fd, device_command_frags_0, sizeof(device_command_frags_0)); + EXPECT_EQ(len, sizeof(device_command_frags_0)); +} + +TEST_F(proc_net_pktgen, device_command_delay) { + ssize_t len; + + len = write(self->device_fd, device_command_delay_0, sizeof(device_command_delay_0)); + EXPECT_EQ(len, sizeof(device_command_delay_0)); + + len = write(self->device_fd, device_command_delay_1, sizeof(device_command_delay_1)); + EXPECT_EQ(len, sizeof(device_command_delay_1)); +} + +TEST_F(proc_net_pktgen, device_command_rate) { + ssize_t len; + + len = write(self->device_fd, device_command_rate_0, sizeof(device_command_rate_0)); + EXPECT_EQ(len, sizeof(device_command_rate_0)); +} + +TEST_F(proc_net_pktgen, device_command_ratep) { + ssize_t len; + + len = write(self->device_fd, device_command_ratep_0, sizeof(device_command_ratep_0)); + EXPECT_EQ(len, sizeof(device_command_ratep_0)); +} + +TEST_F(proc_net_pktgen, device_command_udp_src_min) { + ssize_t len; + + len = write(self->device_fd, device_command_udp_src_min_0, sizeof(device_command_udp_src_min_0)); + EXPECT_EQ(len, sizeof(device_command_udp_src_min_0)); +} + +TEST_F(proc_net_pktgen, device_command_udp_dst_min) { + ssize_t len; + + len = write(self->device_fd, device_command_udp_dst_min_0, sizeof(device_command_udp_dst_min_0)); + EXPECT_EQ(len, sizeof(device_command_udp_dst_min_0)); +} + +TEST_F(proc_net_pktgen, device_command_udp_src_max) { + ssize_t len; + + len = write(self->device_fd, device_command_udp_src_max_0, sizeof(device_command_udp_src_max_0)); + EXPECT_EQ(len, sizeof(device_command_udp_src_max_0)); +} + +TEST_F(proc_net_pktgen, device_command_udp_dst_max) { + ssize_t len; + + len = write(self->device_fd, device_command_udp_dst_max_0, sizeof(device_command_udp_dst_max_0)); + EXPECT_EQ(len, sizeof(device_command_udp_dst_max_0)); +} + +TEST_F(proc_net_pktgen, device_command_clone_skb) { + ssize_t len; + + // clone_skb on (gives EOPNOTSUPP on lo device) + len = write(self->device_fd, device_command_clone_skb_0, sizeof(device_command_clone_skb_0)); + EXPECT_EQ(len, -1); + EXPECT_EQ(errno, EOPNOTSUPP); + + // clone_skb off + len = write(self->device_fd, device_command_clone_skb_1, sizeof(device_command_clone_skb_1)); + EXPECT_EQ(len, sizeof(device_command_clone_skb_1)); +} + +TEST_F(proc_net_pktgen, device_command_count) { + ssize_t len; + + len = write(self->device_fd, device_command_count_0, sizeof(device_command_count_0)); + EXPECT_EQ(len, sizeof(device_command_count_0)); +} + +TEST_F(proc_net_pktgen, device_command_src_mac_count) { + ssize_t len; + + len = write(self->device_fd, device_command_src_mac_count_0, sizeof(device_command_src_mac_count_0)); + EXPECT_EQ(len, sizeof(device_command_src_mac_count_0)); +} + +TEST_F(proc_net_pktgen, device_command_dst_mac_count) { + ssize_t len; + + len = write(self->device_fd, device_command_dst_mac_count_0, sizeof(device_command_dst_mac_count_0)); + EXPECT_EQ(len, sizeof(device_command_dst_mac_count_0)); +} + +TEST_F(proc_net_pktgen, device_command_burst) { + ssize_t len; + + // burst off + len = write(self->device_fd, device_command_burst_0, sizeof(device_command_burst_0)); + EXPECT_EQ(len, sizeof(device_command_burst_0)); +} + +TEST_F(proc_net_pktgen, device_command_node) { + ssize_t len; + + len = write(self->device_fd, device_command_node_0, sizeof(device_command_node_0)); + EXPECT_EQ(len, sizeof(device_command_node_0)); +} + +TEST_F(proc_net_pktgen, device_command_xmit_mode) { + ssize_t len; + + len = write(self->device_fd, device_command_xmit_mode_0, sizeof(device_command_xmit_mode_0)); + EXPECT_EQ(len, sizeof(device_command_xmit_mode_0)); + + len = write(self->device_fd, device_command_xmit_mode_1, sizeof(device_command_xmit_mode_1)); + EXPECT_EQ(len, sizeof(device_command_xmit_mode_1)); + + len = write(self->device_fd, device_command_xmit_mode_2, sizeof(device_command_xmit_mode_2)); + EXPECT_EQ(len, sizeof(device_command_xmit_mode_2)); + + len = write(self->device_fd, device_command_xmit_mode_3, sizeof(device_command_xmit_mode_3)); + EXPECT_EQ(len, sizeof(device_command_xmit_mode_3)); +} + +TEST_F(proc_net_pktgen, device_command_flag) { + ssize_t len; + + // flag UDPCSUM on + len = write(self->device_fd, device_command_flag_0, sizeof(device_command_flag_0)); + EXPECT_EQ(len, sizeof(device_command_flag_0)); + + // flag UDPCSUM off + len = write(self->device_fd, device_command_flag_1, sizeof(device_command_flag_1)); + EXPECT_EQ(len, sizeof(device_command_flag_1)); + + // flag invalid + len = write(self->device_fd, device_command_flag_2, sizeof(device_command_flag_2)); + EXPECT_EQ(len, sizeof(device_command_flag_2)); +} + +TEST_F(proc_net_pktgen, device_command_dst_min) { + ssize_t len; + + len = write(self->device_fd, device_command_dst_min_0, sizeof(device_command_dst_min_0)); + EXPECT_EQ(len, sizeof(device_command_dst_min_0)); +} + +TEST_F(proc_net_pktgen, device_command_dst) { + ssize_t len; + + len = write(self->device_fd, device_command_dst_0, sizeof(device_command_dst_0)); + EXPECT_EQ(len, sizeof(device_command_dst_0)); +} + +TEST_F(proc_net_pktgen, device_command_dst_max) { + ssize_t len; + + len = write(self->device_fd, device_command_dst_max_0, sizeof(device_command_dst_max_0)); + EXPECT_EQ(len, sizeof(device_command_dst_max_0)); +} + +TEST_F(proc_net_pktgen, device_command_dst6) { + ssize_t len; + + len = write(self->device_fd, device_command_dst6_0, sizeof(device_command_dst6_0)); + EXPECT_EQ(len, sizeof(device_command_dst6_0)); +} + +TEST_F(proc_net_pktgen, device_command_dst6_min) { + ssize_t len; + + len = write(self->device_fd, device_command_dst6_min_0, sizeof(device_command_dst6_min_0)); + EXPECT_EQ(len, sizeof(device_command_dst6_min_0)); +} + +TEST_F(proc_net_pktgen, device_command_dst6_max) { + ssize_t len; + + len = write(self->device_fd, device_command_dst6_max_0, sizeof(device_command_dst6_max_0)); + EXPECT_EQ(len, sizeof(device_command_dst6_max_0)); +} + +TEST_F(proc_net_pktgen, device_command_src6) { + ssize_t len; + + len = write(self->device_fd, device_command_src6_0, sizeof(device_command_src6_0)); + EXPECT_EQ(len, sizeof(device_command_src6_0)); +} + +TEST_F(proc_net_pktgen, device_command_src_min) { + ssize_t len; + + len = write(self->device_fd, device_command_src_min_0, sizeof(device_command_src_min_0)); + EXPECT_EQ(len, sizeof(device_command_src_min_0)); +} + +TEST_F(proc_net_pktgen, device_command_src_max) { + ssize_t len; + + len = write(self->device_fd, device_command_src_max_0, sizeof(device_command_src_max_0)); + EXPECT_EQ(len, sizeof(device_command_src_max_0)); +} + +TEST_F(proc_net_pktgen, device_command_dst_mac) { + ssize_t len; + + len = write(self->device_fd, device_command_dst_mac_0, sizeof(device_command_dst_mac_0)); + EXPECT_EQ(len, sizeof(device_command_dst_mac_0)); +} + +TEST_F(proc_net_pktgen, device_command_src_mac) { + ssize_t len; + + len = write(self->device_fd, device_command_src_mac_0, sizeof(device_command_src_mac_0)); + EXPECT_EQ(len, sizeof(device_command_src_mac_0)); +} + +TEST_F(proc_net_pktgen, device_command_clear_counters) { + ssize_t len; + + len = write(self->device_fd, device_command_clear_counters_0, sizeof(device_command_clear_counters_0)); + EXPECT_EQ(len, sizeof(device_command_clear_counters_0)); +} + +TEST_F(proc_net_pktgen, device_command_flows) { + ssize_t len; + + len = write(self->device_fd, device_command_flows_0, sizeof(device_command_flows_0)); + EXPECT_EQ(len, sizeof(device_command_flows_0)); +} + +#if 0 // needs CONFIG_XFRM +TEST_F(proc_net_pktgen, device_command_spi) { + ssize_t len; + + len = write(self->device_fd, device_command_spi_0, sizeof(device_command_spi_0)); + EXPECT_EQ(len, sizeof(device_command_spi_0)); +} +#endif + +TEST_F(proc_net_pktgen, device_command_flowlen) { + ssize_t len; + + len = write(self->device_fd, device_command_flowlen_0, sizeof(device_command_flowlen_0)); + EXPECT_EQ(len, sizeof(device_command_flowlen_0)); +} + +TEST_F(proc_net_pktgen, device_command_queue_map_min) { + ssize_t len; + + len = write(self->device_fd, device_command_queue_map_min_0, sizeof(device_command_queue_map_min_0)); + EXPECT_EQ(len, sizeof(device_command_queue_map_min_0)); +} + +TEST_F(proc_net_pktgen, device_command_queue_map_max) { + ssize_t len; + + len = write(self->device_fd, device_command_queue_map_max_0, sizeof(device_command_queue_map_max_0)); + EXPECT_EQ(len, sizeof(device_command_queue_map_max_0)); +} + +TEST_F(proc_net_pktgen, device_command_mpls) { + ssize_t len; + + len = write(self->device_fd, device_command_mpls_0, sizeof(device_command_mpls_0)); + EXPECT_EQ(len, sizeof(device_command_mpls_0)); +} + +TEST_F(proc_net_pktgen, device_command_vlan_id) { + ssize_t len; + + len = write(self->device_fd, device_command_vlan_id_0, sizeof(device_command_vlan_id_0)); + EXPECT_EQ(len, sizeof(device_command_vlan_id_0)); + + len = write(self->device_fd, device_command_vlan_p_0, sizeof(device_command_vlan_p_0)); + EXPECT_EQ(len, sizeof(device_command_vlan_p_0)); + + len = write(self->device_fd, device_command_vlan_cfi_0, sizeof(device_command_vlan_cfi_0)); + EXPECT_EQ(len, sizeof(device_command_vlan_cfi_0)); + + len = write(self->device_fd, device_command_vlan_id_1, sizeof(device_command_vlan_id_1)); + EXPECT_EQ(len, sizeof(device_command_vlan_id_1)); +} + +TEST_F(proc_net_pktgen, device_command_svlan_id) { + ssize_t len; + + len = write(self->device_fd, device_command_svlan_id_0, sizeof(device_command_svlan_id_0)); + EXPECT_EQ(len, sizeof(device_command_svlan_id_0)); + + len = write(self->device_fd, device_command_svlan_p_0, sizeof(device_command_svlan_p_0)); + EXPECT_EQ(len, sizeof(device_command_svlan_p_0)); + + len = write(self->device_fd, device_command_svlan_cfi_0, sizeof(device_command_svlan_cfi_0)); + EXPECT_EQ(len, sizeof(device_command_svlan_cfi_0)); + + len = write(self->device_fd, device_command_svlan_id_1, sizeof(device_command_svlan_id_1)); + EXPECT_EQ(len, sizeof(device_command_svlan_id_1)); +} + + +TEST_F(proc_net_pktgen, device_command_tos) { + ssize_t len; + + len = write(self->device_fd, device_command_tos_0, sizeof(device_command_tos_0)); + EXPECT_EQ(len, sizeof(device_command_tos_0)); + + len = write(self->device_fd, device_command_tos_1, sizeof(device_command_tos_1)); + EXPECT_EQ(len, sizeof(device_command_tos_1)); + + len = write(self->device_fd, device_command_tos_2, sizeof(device_command_tos_2)); + EXPECT_EQ(len, sizeof(device_command_tos_2)); +} + + +TEST_F(proc_net_pktgen, device_command_traffic_class) { + ssize_t len; + + len = write(self->device_fd, device_command_traffic_class_0, sizeof(device_command_traffic_class_0)); + EXPECT_EQ(len, sizeof(device_command_traffic_class_0)); +} + +TEST_F(proc_net_pktgen, device_command_skb_priority) { + ssize_t len; + + len = write(self->device_fd, device_command_skb_priority_0, sizeof(device_command_skb_priority_0)); + EXPECT_EQ(len, sizeof(device_command_skb_priority_0)); +} + +TEST_HARNESS_MAIN
On Fri, 17 Jan 2025 15:16:13 +0100 Peter Seiderer wrote:
+FIXTURE_SETUP(proc_net_pktgen) {
- ssize_t len;
- self->ctrl_fd = open("/proc/net/pktgen/kpktgend_0", O_RDWR);
- ASSERT_GE(self->ctrl_fd, 0) TH_LOG("CONFIG_NET_PKTGEN not enabled, module pktgen nod loaded?");
nod -> not?
Please take a look at the instructions here: https://github.com/linux-netdev/nipa/wiki/How-to-run-netdev-selftests-CI-sty... the test currently fails in our CI, you need to add it to tools/testing/selftests/net/config, and perhaps try to call modprobe in the test?
- len = write(self->ctrl_fd, add_loopback_0, sizeof(add_loopback_0));
- ASSERT_EQ(len, sizeof(add_loopback_0)) TH_LOG("device lo@0 already registered?");
FWIW we prefer to stick to 80 char line width in networking, but it's not a big deal for a test, up to you.
// complete command string without/with trailing '\0'
EXPECT_EQ(len, i);
Run this patch thru checkpatch, please. This looks misaligned.
}
- }
+}
+#if 0 // needs CONFIG_XFRM
Add it to the config, too, then?
+TEST_F(proc_net_pktgen, device_command_spi) {
- ssize_t len;
- len = write(self->device_fd, device_command_spi_0, sizeof(device_command_spi_0));
- EXPECT_EQ(len, sizeof(device_command_spi_0));
+} +#endif
Thanks for working on a test!
Hello Jakub,
On Fri, 17 Jan 2025 13:11:54 -0800, Jakub Kicinski kuba@kernel.org wrote:
On Fri, 17 Jan 2025 15:16:13 +0100 Peter Seiderer wrote:
+FIXTURE_SETUP(proc_net_pktgen) {
- ssize_t len;
- self->ctrl_fd = open("/proc/net/pktgen/kpktgend_0", O_RDWR);
- ASSERT_GE(self->ctrl_fd, 0) TH_LOG("CONFIG_NET_PKTGEN not enabled, module pktgen nod loaded?");
nod -> not?
Fixed...
Please take a look at the instructions here: https://github.com/linux-netdev/nipa/wiki/How-to-run-netdev-selftests-CI-sty... the test currently fails in our CI, you need to add it to tools/testing/selftests/net/config, and perhaps try to call modprobe in the test?
Thanks for the hint, fixed (modprobe and CONFIG_NET_PKTGEN enabeled)...
- len = write(self->ctrl_fd, add_loopback_0, sizeof(add_loopback_0));
- ASSERT_EQ(len, sizeof(add_loopback_0)) TH_LOG("device lo@0 already registered?");
FWIW we prefer to stick to 80 char line width in networking, but it's not a big deal for a test, up to you.
// complete command string without/with trailing '\0'
EXPECT_EQ(len, i);
Fixed...
Run this patch thru checkpatch, please. This looks misaligned.
O.k.
}
- }
+}
+#if 0 // needs CONFIG_XFRM
Add it to the config, too, then?
+TEST_F(proc_net_pktgen, device_command_spi) {
- ssize_t len;
- len = write(self->device_fd, device_command_spi_0, sizeof(device_command_spi_0));
- EXPECT_EQ(len, sizeof(device_command_spi_0));
+} +#endif
'#if' removed as as CONFIG_XFRM is already enabled via tools/testing/selftests/net/config CONFIG_XFRM_INTERFACE/CONFIG_XFRM_USER...
Thanks for review!
New patch iteration is on the way...
Regards, Peter
Thanks for working on a test!
linux-kselftest-mirror@lists.linaro.org