Add PPPoE test-cases to the GRO selftest.

Signed-off-by: Qingfang Deng <[email protected]>
---
v6: new patch

I'm not sure if I should include all the existing IPv4/v6 tests for
PPPoE. There are tests that hardcode ETH_HLEN as the NH offset, which
are meant to test the L3 protocol, not the underlying protocol, and
changing all of them seems too invasive.

Comments welcome, thanks.
---
 tools/testing/selftests/drivers/net/config |  2 +
 tools/testing/selftests/drivers/net/gro.py | 25 +++++-
 tools/testing/selftests/net/lib/gro.c      | 97 ++++++++++++++++------
 3 files changed, 98 insertions(+), 26 deletions(-)

diff --git a/tools/testing/selftests/drivers/net/config 
b/tools/testing/selftests/drivers/net/config
index 77ccf83d87e0..caaba209ba3e 100644
--- a/tools/testing/selftests/drivers/net/config
+++ b/tools/testing/selftests/drivers/net/config
@@ -7,4 +7,6 @@ CONFIG_NETCONSOLE=m
 CONFIG_NETCONSOLE_DYNAMIC=y
 CONFIG_NETCONSOLE_EXTENDED_LOG=y
 CONFIG_NETDEVSIM=m
+CONFIG_PPP=y
+CONFIG_PPPOE=y
 CONFIG_XDP_SOCKETS=y
diff --git a/tools/testing/selftests/drivers/net/gro.py 
b/tools/testing/selftests/drivers/net/gro.py
index 70709bf670c7..eb8306a8f4c4 100755
--- a/tools/testing/selftests/drivers/net/gro.py
+++ b/tools/testing/selftests/drivers/net/gro.py
@@ -186,8 +186,17 @@ def _run_gro_bin(cfg, test_name, protocol=None, 
num_flows=None,
 
     dmac = _resolve_dmac(cfg, ipver)
 
-    base_args = [
-        f"--{protocol}",
+    if protocol.startswith("pppoe"):
+        base_args = [
+            f"--ipv{protocol[-1]}",
+            "--pppoe",
+        ]
+    else:
+        base_args = [
+            f"--{protocol}",
+        ]
+
+    base_args += [
         f"--dmac {dmac}",
         f"--smac {cfg.remote_dev['address']}",
         f"--daddr {cfg.addr_v[ipver]}",
@@ -322,6 +331,18 @@ def _gro_variants():
                 for test_name in ipv6_tests:
                     yield mode, protocol, test_name
 
+    for mode in ["sw"]:
+        for protocol in ["pppoev4", "pppoev6"]:
+            for test_name in common_tests:
+                yield mode, protocol, test_name
+
+            if protocol == "pppoev4":
+                for test_name in ipv4_tests:
+                    yield mode, protocol, test_name
+            elif protocol == "pppoev6":
+                for test_name in ipv6_tests:
+                    yield mode, protocol, test_name
+
 
 @ksft_variants(_gro_variants())
 def test(cfg, mode, protocol, test_name):
diff --git a/tools/testing/selftests/net/lib/gro.c 
b/tools/testing/selftests/net/lib/gro.c
index 3e611ae25f61..6148bcdff478 100644
--- a/tools/testing/selftests/net/lib/gro.c
+++ b/tools/testing/selftests/net/lib/gro.c
@@ -64,12 +64,14 @@
 #include <errno.h>
 #include <error.h>
 #include <getopt.h>
+#include <net/ethernet.h>
+#include <net/if.h>
 #include <linux/filter.h>
 #include <linux/if_packet.h>
+#include <linux/if_pppox.h>
 #include <linux/ipv6.h>
 #include <linux/net_tstamp.h>
-#include <net/ethernet.h>
-#include <net/if.h>
+#include <linux/ppp_defs.h>
 #include <netinet/in.h>
 #include <netinet/ip.h>
 #include <netinet/ip6.h>
@@ -92,11 +94,11 @@
 #define START_SEQ 100
 #define START_ACK 100
 #define ETH_P_NONE 0
-#define TOTAL_HDR_LEN (ETH_HLEN + sizeof(struct ipv6hdr) + sizeof(struct 
tcphdr))
+#define TOTAL_HDR_LEN (ETH_HLEN + PPPOE_SES_HLEN + sizeof(struct ipv6hdr) + 
sizeof(struct tcphdr))
 #define MSS (4096 - sizeof(struct tcphdr) - sizeof(struct ipv6hdr))
 #define MAX_PAYLOAD (IP_MAXPACKET - sizeof(struct tcphdr) - sizeof(struct 
ipv6hdr))
 #define NUM_LARGE_PKT (MAX_PAYLOAD / MSS)
-#define MAX_HDR_LEN (ETH_HLEN + sizeof(struct ipv6hdr) + sizeof(struct tcphdr))
+#define MAX_HDR_LEN (ETH_HLEN + PPPOE_SES_HLEN + sizeof(struct ipv6hdr) + 
sizeof(struct tcphdr))
 #define MIN_EXTHDR_SIZE 8
 #define EXT_PAYLOAD_1 "\x00\x00\x00\x00\x00\x00"
 #define EXT_PAYLOAD_2 "\x11\x11\x11\x11\x11\x11"
@@ -129,6 +131,7 @@ static int tcp_offset = -1;
 static int total_hdr_len = -1;
 static int ethhdr_proto = -1;
 static bool ipip;
+static bool pppoe;
 static uint64_t txtime_ns;
 static int num_flows = 4;
 static bool order_check;
@@ -148,12 +151,37 @@ static void vlog(const char *fmt, ...)
        }
 }
 
+static void fill_pppoelayer(void *buf, int payload_len)
+{
+       struct pppoe_ppp_hdr {
+               struct pppoe_hdr eh;
+               __be16 proto;
+       } *ph = buf;
+       int ppp_payload_len;
+
+       ph->eh.type = 1;
+       ph->eh.ver = 1;
+       ph->eh.code = 0;
+       ph->eh.sid = htons(0x1234);
+
+       if (proto == PF_INET6) {
+               ph->proto = htons(PPP_IPV6);
+               ppp_payload_len = sizeof(struct ipv6hdr) + sizeof(struct 
tcphdr) + payload_len;
+       } else {
+               ph->proto = htons(PPP_IP);
+               ppp_payload_len = sizeof(struct iphdr) + sizeof(struct tcphdr) 
+ payload_len;
+       }
+
+       ph->eh.length = htons(ppp_payload_len + sizeof(ph->proto));
+}
+
 static void setup_sock_filter(int fd)
 {
        const int dport_off = tcp_offset + offsetof(struct tcphdr, dest);
        const int ethproto_off = offsetof(struct ethhdr, h_proto);
        int optlen = 0;
        int ipproto_off, opt_ipproto_off;
+       int head_len = ETH_HLEN + (pppoe ? PPPOE_SES_HLEN : 0);
        int next_off;
 
        if (ipip)
@@ -162,7 +190,7 @@ static void setup_sock_filter(int fd)
                next_off = offsetof(struct iphdr, protocol);
        else
                next_off = offsetof(struct ipv6hdr, nexthdr);
-       ipproto_off = ETH_HLEN + next_off;
+       ipproto_off = head_len + next_off;
 
        /* Overridden later if exthdrs are used: */
        opt_ipproto_off = ipproto_off;
@@ -178,7 +206,7 @@ static void setup_sock_filter(int fd)
 
                /* same size for HBH and Fragment extension header types */
                optlen = MIN_EXTHDR_SIZE;
-               opt_ipproto_off = ETH_HLEN + sizeof(struct ipv6hdr)
+               opt_ipproto_off = head_len + sizeof(struct ipv6hdr)
                        + offsetof(struct ip6_ext, ip6e_nxt);
        }
 
@@ -390,6 +418,10 @@ static void create_packet(void *buf, int seq_offset, int 
ack_offset,
                                  IPPROTO_IPIP);
                fill_networklayer(buf + ETH_HLEN + sizeof(struct iphdr),
                                  payload_len, IPPROTO_TCP);
+       } else if (pppoe) {
+               fill_pppoelayer(buf + ETH_HLEN, payload_len);
+               fill_networklayer(buf + ETH_HLEN + PPPOE_SES_HLEN,
+                                 payload_len, IPPROTO_TCP);
        } else {
                fill_networklayer(buf + ETH_HLEN, payload_len, IPPROTO_TCP);
        }
@@ -501,7 +533,7 @@ static void send_flags(int fd, struct sockaddr_ll *daddr, 
int psh, int syn,
 static void send_data_pkts(int fd, struct sockaddr_ll *daddr,
                           int payload_len1, int payload_len2)
 {
-       static char buf[ETH_HLEN + IP_MAXPACKET];
+       static char buf[ETH_HLEN + PPPOE_SES_HLEN + IP_MAXPACKET];
 
        create_packet(buf, 0, 0, payload_len1, 0);
        write_packet(fd, buf, total_hdr_len + payload_len1, daddr);
@@ -745,7 +777,7 @@ static void add_ipv4_ts_option(void *buf, void *optpkt)
        memcpy(optpkt + tcp_offset + optlen, buf + tcp_offset,
               sizeof(struct tcphdr) + PAYLOAD_LEN);
 
-       iph = (struct iphdr *)(optpkt + ETH_HLEN);
+       iph = (struct iphdr *)(optpkt + ETH_HLEN + (pppoe ? PPPOE_SES_HLEN : 
0));
        iph->ihl = 5 + (optlen / 4);
        iph->tot_len = htons(ntohs(iph->tot_len) + optlen);
        iph->check = 0;
@@ -755,7 +787,7 @@ static void add_ipv4_ts_option(void *buf, void *optpkt)
 static void add_ipv6_exthdr(void *buf, void *optpkt, __u8 exthdr_type, char 
*ext_payload)
 {
        struct ipv6_opt_hdr *exthdr = (struct ipv6_opt_hdr *)(optpkt + 
tcp_offset);
-       struct ipv6hdr *iph = (struct ipv6hdr *)(optpkt + ETH_HLEN);
+       struct ipv6hdr *iph = (struct ipv6hdr *)(optpkt + ETH_HLEN + (pppoe ? 
PPPOE_SES_HLEN : 0));
        char *exthdr_payload_start = (char *)(exthdr + 1);
 
        exthdr->hdrlen = 0;
@@ -908,7 +940,7 @@ static void send_ip_options(int fd, struct sockaddr_ll 
*daddr)
 static void send_fragment4(int fd, struct sockaddr_ll *daddr)
 {
        static char buf[IP_MAXPACKET];
-       struct iphdr *iph = (struct iphdr *)(buf + ETH_HLEN);
+       struct iphdr *iph = (struct iphdr *)(buf + ETH_HLEN + (pppoe ? 
PPPOE_SES_HLEN : 0));
        int pkt_size = total_hdr_len + PAYLOAD_LEN;
 
        create_packet(buf, 0, 0, PAYLOAD_LEN, 0);
@@ -920,7 +952,8 @@ static void send_fragment4(int fd, struct sockaddr_ll 
*daddr)
         */
        memset(buf + total_hdr_len, 'a', PAYLOAD_LEN * 2);
        fill_transportlayer(buf + tcp_offset, PAYLOAD_LEN, 0, PAYLOAD_LEN * 2, 
0);
-       fill_networklayer(buf + ETH_HLEN, PAYLOAD_LEN, IPPROTO_TCP);
+       fill_networklayer(buf + ETH_HLEN + (pppoe ? PPPOE_SES_HLEN : 0),
+                         PAYLOAD_LEN, IPPROTO_TCP);
        fill_datalinklayer(buf);
 
        iph->frag_off = htons(0x6000); // DF = 1, MF = 1
@@ -934,7 +967,7 @@ static void send_changed_ttl(int fd, struct sockaddr_ll 
*daddr)
 {
        int pkt_size = total_hdr_len + PAYLOAD_LEN;
        static char buf[MAX_HDR_LEN + PAYLOAD_LEN];
-       struct iphdr *iph = (struct iphdr *)(buf + ETH_HLEN);
+       struct iphdr *iph = (struct iphdr *)(buf + ETH_HLEN + (pppoe ? 
PPPOE_SES_HLEN : 0));
 
        create_packet(buf, 0, 0, PAYLOAD_LEN, 0);
        write_packet(fd, buf, pkt_size, daddr);
@@ -951,8 +984,8 @@ static void send_changed_tos(int fd, struct sockaddr_ll 
*daddr)
 {
        int pkt_size = total_hdr_len + PAYLOAD_LEN;
        static char buf[MAX_HDR_LEN + PAYLOAD_LEN];
-       struct iphdr *iph = (struct iphdr *)(buf + ETH_HLEN);
-       struct ipv6hdr *ip6h = (struct ipv6hdr *)(buf + ETH_HLEN);
+       struct iphdr *iph = (struct iphdr *)(buf + ETH_HLEN + (pppoe ? 
PPPOE_SES_HLEN : 0));
+       struct ipv6hdr *ip6h = (struct ipv6hdr *)(buf + ETH_HLEN + (pppoe ? 
PPPOE_SES_HLEN : 0));
 
        create_packet(buf, 0, 0, PAYLOAD_LEN, 0);
        write_packet(fd, buf, pkt_size, daddr);
@@ -980,7 +1013,8 @@ static void send_changed_ECN(int fd, struct sockaddr_ll 
*daddr)
 
        create_packet(buf, PAYLOAD_LEN, 0, PAYLOAD_LEN, 0);
        if (proto == PF_INET) {
-               buf[ETH_HLEN + 1] ^= 0x2; // ECN set to 10
+               int ecn_off = ETH_HLEN + (pppoe ? PPPOE_SES_HLEN : 0) + 1;
+               buf[ecn_off] ^= 0x2; // ECN set to 10
                iph->check = 0;
                iph->check = checksum_fold(iph, sizeof(struct iphdr), 0);
        } else {
@@ -995,7 +1029,7 @@ static void send_fragment6(int fd, struct sockaddr_ll 
*daddr)
        static char buf[MAX_HDR_LEN + PAYLOAD_LEN];
        static char extpkt[MAX_HDR_LEN + PAYLOAD_LEN +
                           sizeof(struct ip6_frag)];
-       struct ipv6hdr *ip6h = (struct ipv6hdr *)(buf + ETH_HLEN);
+       struct ipv6hdr *ip6h = (struct ipv6hdr *)(buf + ETH_HLEN + (pppoe ? 
PPPOE_SES_HLEN : 0));
        struct ip6_frag *frag = (void *)(extpkt + tcp_offset);
        int extlen = sizeof(struct ip6_frag);
        int bufpkt_len = total_hdr_len + PAYLOAD_LEN;
@@ -1073,9 +1107,10 @@ static void recv_error(int fd, int rcv_errno)
 static void check_recv_pkts(int fd, int *correct_payload,
                            int correct_num_pkts)
 {
-       static char buffer[IP_MAXPACKET + ETH_HLEN + 1];
-       struct iphdr *iph = (struct iphdr *)(buffer + ETH_HLEN);
-       struct ipv6hdr *ip6h = (struct ipv6hdr *)(buffer + ETH_HLEN);
+       static char buffer[IP_MAXPACKET + ETH_HLEN + PPPOE_SES_HLEN + 1];
+       int nhoff = ETH_HLEN + (pppoe ? PPPOE_SES_HLEN : 0);
+       struct iphdr *iph = (struct iphdr *)(buffer + nhoff);
+       struct ipv6hdr *ip6h = (struct ipv6hdr *)(buffer + nhoff);
        struct tcphdr *tcph;
        bool bad_packet = false;
        int tcp_ext_len = 0;
@@ -1092,7 +1127,7 @@ static void check_recv_pkts(int fd, int *correct_payload,
 
        while (1) {
                ip_ext_len = 0;
-               pkt_size = recv(fd, buffer, IP_MAXPACKET + ETH_HLEN + 1, 0);
+               pkt_size = recv(fd, buffer, sizeof(buffer), 0);
                if (pkt_size < 0)
                        recv_error(fd, errno);
 
@@ -1134,9 +1169,10 @@ static void check_recv_pkts(int fd, int *correct_payload,
 
 static void check_capacity_pkts(int fd)
 {
-       static char buffer[IP_MAXPACKET + ETH_HLEN + 1];
-       struct iphdr *iph = (struct iphdr *)(buffer + ETH_HLEN);
-       struct ipv6hdr *ip6h = (struct ipv6hdr *)(buffer + ETH_HLEN);
+       static char buffer[IP_MAXPACKET + ETH_HLEN + PPPOE_SES_HLEN + 1];
+       int nhoff = ETH_HLEN + (pppoe ? PPPOE_SES_HLEN : 0);
+       struct iphdr *iph = (struct iphdr *)(buffer + nhoff);
+       struct ipv6hdr *ip6h = (struct ipv6hdr *)(buffer + nhoff);
        int num_pkt = 0, num_coal = 0, pkt_idx;
        const char *fail_reason = NULL;
        int flow_order[num_flows * 2];
@@ -1154,7 +1190,7 @@ static void check_capacity_pkts(int fd)
 
        while (total_data < num_flows * CAPACITY_PAYLOAD_LEN * 2) {
                ip_ext_len = 0;
-               pkt_size = recv(fd, buffer, IP_MAXPACKET + ETH_HLEN + 1, 0);
+               pkt_size = recv(fd, buffer, sizeof(buffer), 0);
                if (pkt_size < 0)
                        recv_error(fd, errno);
 
@@ -1645,6 +1681,7 @@ static void parse_args(int argc, char **argv)
                { "ipv4", no_argument, NULL, '4' },
                { "ipv6", no_argument, NULL, '6' },
                { "ipip", no_argument, NULL, 'e' },
+               { "pppoe", no_argument, NULL, 'p' },
                { "num-flows", required_argument, NULL, 'n' },
                { "rx", no_argument, NULL, 'r' },
                { "saddr", required_argument, NULL, 's' },
@@ -1671,6 +1708,9 @@ static void parse_args(int argc, char **argv)
                        proto = PF_INET;
                        ethhdr_proto = htons(ETH_P_IP);
                        break;
+               case 'p':
+                       pppoe = true;
+                       break;
                case 'd':
                        addr4_dst = addr6_dst = optarg;
                        break;
@@ -1715,6 +1755,15 @@ int main(int argc, char **argv)
        if (ipip) {
                tcp_offset = ETH_HLEN + sizeof(struct iphdr) * 2;
                total_hdr_len = tcp_offset + sizeof(struct tcphdr);
+       } else if (pppoe) {
+               if (proto == PF_INET)
+                       tcp_offset = ETH_HLEN + PPPOE_SES_HLEN + sizeof(struct 
iphdr);
+               else if (proto == PF_INET6)
+                       tcp_offset = ETH_HLEN + PPPOE_SES_HLEN + sizeof(struct 
ipv6hdr);
+               else
+                       error(1, 0, "Protocol family is not ipv4 or ipv6");
+               total_hdr_len = tcp_offset + sizeof(struct tcphdr);
+               ethhdr_proto = htons(ETH_P_PPP_SES);
        } else if (proto == PF_INET) {
                tcp_offset = ETH_HLEN + sizeof(struct iphdr);
                total_hdr_len = tcp_offset + sizeof(struct tcphdr);
-- 
2.43.0


Reply via email to