public inbox for bpf@vger.kernel.org
 help / color / mirror / Atom feed
From: Kui-Feng Lee <sinquersw@gmail.com>
To: Martin KaFai Lau <martin.lau@linux.dev>,
	Kui-Feng Lee <thinker.li@gmail.com>
Cc: bpf@vger.kernel.org, ast@kernel.org, song@kernel.org,
	kernel-team@meta.com, andrii@kernel.org, sdf@fomichev.me,
	geliang@kernel.org, kuifeng@meta.com
Subject: Re: [PATCH bpf-next v6 1/6] selftests/bpf: Add traffic monitor functions.
Date: Fri, 9 Aug 2024 09:01:23 -0700	[thread overview]
Message-ID: <91890a6a-19fa-4b7c-b69b-e2b7c9a42a4a@gmail.com> (raw)
In-Reply-To: <be108b0b-202c-4a87-8ac3-1b9f61dca3c4@linux.dev>



On 8/8/24 14:35, Martin KaFai Lau wrote:
> On 8/7/24 11:31 AM, Kui-Feng Lee wrote:
>> +static bool is_ethernet(const u_char *packet)
>> +{
>> +    u16 arphdr_type;
>> +
>> +    memcpy(&arphdr_type, packet + 8, 2);
>> +    arphdr_type = ntohs(arphdr_type);
>> +
>> +    /* Except the following cases, the protocol type contains the
>> +     * Ethernet protocol type for the packet.
>> +     *
>> +     * https://www.tcpdump.org/linktypes/LINKTYPE_LINUX_SLL2.html
>> +     */
>> +    switch (arphdr_type) {
>> +    case 770: /* ARPHRD_FRAD */
>> +    case 778: /* ARPHDR_IPGRE */
>> +    case 803: /* ARPHRD_IEEE80211_RADIOTAP */
>> +        return false;
>> +    }
>> +    return true;
>> +}
>> +
>> +static const char * const pkt_types[] = {
>> +    "In",
>> +    "B",            /* Broadcast */
>> +    "M",            /* Multicast */
>> +    "C",            /* Captured with the promiscuous mode */
>> +    "Out",
>> +};
>> +
>> +static const char *pkt_type_str(u16 pkt_type)
>> +{
>> +    if (pkt_type < ARRAY_SIZE(pkt_types))
>> +        return pkt_types[pkt_type];
>> +    return "Unknown";
>> +}
>> +
>> +/* Show the information of the transport layer in the packet */
>> +static void show_transport(const u_char *packet, u16 len, u32 ifindex,
>> +               const char *src_addr, const char *dst_addr,
>> +               u16 proto, bool ipv6, u8 pkt_type)
>> +{
>> +    char *ifname, _ifname[IF_NAMESIZE];
>> +    const char *transport_str;
>> +    u16 src_port, dst_port;
>> +    struct udphdr *udp;
>> +    struct tcphdr *tcp;
>> +
>> +    ifname = if_indextoname(ifindex, _ifname);
>> +    if (!ifname) {
>> +        snprintf(_ifname, sizeof(_ifname), "unknown(%d)", ifindex);
>> +        ifname = _ifname;
>> +    }
>> +
>> +    if (proto == IPPROTO_UDP) {
>> +        udp = (struct udphdr *)packet;
>> +        src_port = ntohs(udp->source);
>> +        dst_port = ntohs(udp->dest);
>> +        transport_str = "UDP";
>> +    } else if (proto == IPPROTO_TCP) {
>> +        tcp = (struct tcphdr *)packet;
>> +        src_port = ntohs(tcp->source);
>> +        dst_port = ntohs(tcp->dest);
>> +        transport_str = "TCP"
>> +;
> 
> nit. ";" spilled over to a newline.

Got it!
> 
>> +    } else if (proto == IPPROTO_ICMP) {
>> +        printf("IPv4 ICMP packet: %s -> %s, len %d, type %d, code %d, 
>> ifname %s (%s)\n",
>> +               src_addr, dst_addr, len, packet[0], packet[1], ifname,
>> +               pkt_type_str(pkt_type));
> 
> nit. Move pkt_type_str(pkt_type) to the front. That will resemble the 
> tcpdump output to make the output familiar to most people. Same for the 
> other proto below.

Sure!

> 
>> +        return;
>> +    } else if (proto == IPPROTO_ICMPV6) {
>> +        printf("IPv6 ICMPv6 packet: %s -> %s, len %d, type %d, code 
>> %d, ifname %s (%s)\n",
>> +               src_addr, dst_addr, len, packet[0], packet[1], ifname,
>> +               pkt_type_str(pkt_type));
>> +        return;
>> +    } else {
>> +        printf("%s (proto %d): %s -> %s, ifname %s (%s)\n",
>> +               ipv6 ? "IPv6" : "IPv4", proto, src_addr, dst_addr,
>> +               ifname, pkt_type_str(pkt_type));
>> +        return;
>> +    }
>> +
>> +    /* TCP */
>> +
>> +    flockfile(stdout);
>> +    if (ipv6)
>> +        printf("IPv6 %s packet: [%s]:%d -> [%s]:%d, len %d, ifname %s 
>> (%s)",
>> +               transport_str, src_addr, src_port,
>> +               dst_addr, dst_port, len, ifname, pkt_type_str(pkt_type));
>> +    else
>> +        printf("IPv4 %s packet: %s:%d -> %s:%d, len %d, ifname %s (%s)",
>> +               transport_str, src_addr, src_port,
>> +               dst_addr, dst_port, len, ifname, pkt_type_str(pkt_type));
>> +
>> +    if (proto == IPPROTO_TCP) {
>> +        if (tcp->fin)
>> +            printf(", FIN");
>> +        if (tcp->syn)
>> +            printf(", SYN");
>> +        if (tcp->rst)
>> +            printf(", RST");
>> +        if (tcp->ack)
>> +            printf(", ACK");
>> +    }
>> +
>> +    printf("\n");
>> +    funlockfile(stdout);
>> +}
>> +
>> +static void show_ipv6_packet(const u_char *packet, u32 ifindex, u8 
>> pkt_type)
>> +{
>> +    char src_str[INET6_ADDRSTRLEN], dst_str[INET6_ADDRSTRLEN];
>> +    struct ipv6hdr *pkt = (struct ipv6hdr *)packet;
>> +    struct in6_addr src;
>> +    struct in6_addr dst;
>> +    u_char proto;
>> +
>> +    memcpy(&src, &pkt->saddr, sizeof(src));
>> +    memcpy(&dst, &pkt->daddr, sizeof(dst));
>> +    inet_ntop(AF_INET6, &src, src_str, sizeof(src_str));
> 
> nit. In v2, I think Stan has mentioned a similar point that &pkt->saddr 
> can be directly used instead of memcpy. I don't see this mentioned in 
> the changelog also. Re-mentioning here just in case it is an overlook.

Got it!

> 
> Does it need to check inet_ntop error or it will never fail for whatever 
> address a bpf prog may have written to a packet?
> 
> Does the src/dst_str need to be initialized if there was a inet_ntop error?

It will never fail if passing valid parameters.
In our case, the size of src_str & dst_str is big enough for v6 here for
v4 below. And, the address family is valid for sure. It should not
return any error for any address.

However, I will check it since you have concern about it.

> 
>> +    inet_ntop(AF_INET6, &dst, dst_str, sizeof(dst_str));
>> +    proto = pkt->nexthdr;
>> +    show_transport(packet + sizeof(struct ipv6hdr),
>> +               ntohs(pkt->payload_len),
>> +               ifindex, src_str, dst_str, proto, true, pkt_type);
>> +}
>> +
>> +static void show_ipv4_packet(const u_char *packet, u32 ifindex, u8 
>> pkt_type)
>> +{
>> +    char src_str[INET_ADDRSTRLEN], dst_str[INET_ADDRSTRLEN];
>> +    struct iphdr *pkt = (struct iphdr *)packet;
>> +    struct in_addr src;
>> +    struct in_addr dst;
>> +    u_char proto;
>> +
>> +    memcpy(&src, &pkt->saddr, sizeof(src));
>> +    memcpy(&dst, &pkt->daddr, sizeof(dst));
>> +    inet_ntop(AF_INET, &src, src_str, sizeof(src_str));
>> +    inet_ntop(AF_INET, &dst, dst_str, sizeof(dst_str));
>> +    proto = pkt->protocol;
>> +    show_transport(packet + sizeof(struct iphdr),
>> +               ntohs(pkt->tot_len),
>> +               ifindex, src_str, dst_str, proto, false, pkt_type);
>> +}
>> +
>> +static void *traffic_monitor_thread(void *arg)
>> +{
>> +    char *ifname, _ifname[IF_NAMESIZE];
>> +    const u_char *packet, *payload;
>> +    struct tmonitor_ctx *ctx = arg;
>> +    pcap_dumper_t *dumper = ctx->dumper;
>> +    int fd = ctx->pcap_fd, nfds, r;
>> +    int wake_fd = ctx->wake_fd_r;
>> +    struct pcap_pkthdr header;
>> +    pcap_t *pcap = ctx->pcap;
>> +    u32 ifindex;
>> +    fd_set fds;
>> +    u16 proto;
>> +    u8 ptype;
>> +
>> +    nfds = (fd > wake_fd ? fd : wake_fd) + 1;
>> +    FD_ZERO(&fds);
>> +
>> +    while (!ctx->done) {
>> +        FD_SET(fd, &fds);
>> +        FD_SET(wake_fd, &fds);
>> +        r = select(nfds, &fds, NULL, NULL, NULL);
>> +        if (!r)
>> +            continue;
>> +        if (r < 0) {
>> +            if (errno == EINTR)
>> +                continue;
>> +            log_err("Fail to select on pcap fd and wake fd: %s", 
>> strerror(errno));
> 
> nit. log_err already has the strerror(errno). There is at least another 
> case in this patch. Please check.

Got it!
> 
>> +            break;
>> +        }
>> +
>> +        packet = pcap_next(pcap, &header);
>> +        if (!packet)
>> +            continue;
>> +
>> +        /* According to the man page of pcap_dump(), first argument
>> +         * is the pcap_dumper_t pointer even it's argument type is
>> +         * u_char *.
>> +         */
>> +        pcap_dump((u_char *)dumper, &header, packet);
>> +
>> +        /* Not sure what other types of packets look like. Here, we
>> +         * parse only Ethernet and compatible packets.
>> +         */
>> +        if (!is_ethernet(packet)) {
>> +            printf("Packet captured\n");
> 
> nit. print the value of the arphdr_type.

Sure!

> 
>> +            continue;
>> +        }
>> +
>> +        /* Skip SLL2 header
>> +         * https://www.tcpdump.org/linktypes/LINKTYPE_LINUX_SLL2.html
>> +         *
>> +         * Although the document doesn't mention that, the payload
>> +         * doesn't include the Ethernet header. The payload starts
>> +         * from the first byte of the network layer header.
>> +         */
>> +        payload = packet + 20;
>> +
>> +        memcpy(&proto, packet, 2);
>> +        proto = ntohs(proto);
>> +        memcpy(&ifindex, packet + 4, 4);
>> +        ifindex = ntohl(ifindex);
>> +        ptype = packet[10];
>> +
>> +        if (proto == ETH_P_IPV6) {
>> +            show_ipv6_packet(payload, ifindex, ptype);
>> +        } else if (proto == ETH_P_IP) {
>> +            show_ipv4_packet(payload, ifindex, ptype);
>> +        } else {
>> +            ifname = if_indextoname(ifindex, _ifname);
>> +            if (!ifname) {
>> +                snprintf(_ifname, sizeof(_ifname), "unknown(%d)", 
>> ifindex);
>> +                ifname = _ifname;
>> +            }
>> +
>> +            printf("Unknown network protocol type %x, ifname %s (%s)\n",
>> +                   proto, ifname, pkt_type_str(ptype));
>> +        }
>> +    }
>> +
>> +    return NULL;
>> +}

  reply	other threads:[~2024-08-09 16:01 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-08-07 18:31 [PATCH bpf-next v6 0/6] monitor network traffic for flaky test cases Kui-Feng Lee
2024-08-07 18:31 ` [PATCH bpf-next v6 1/6] selftests/bpf: Add traffic monitor functions Kui-Feng Lee
2024-08-08 21:35   ` Martin KaFai Lau
2024-08-09 16:01     ` Kui-Feng Lee [this message]
2024-08-07 18:31 ` [PATCH bpf-next v6 2/6] selftests/bpf: Add the traffic monitor option to test_progs Kui-Feng Lee
2024-08-08 19:44   ` Martin KaFai Lau
2024-08-08 20:23     ` Kui-Feng Lee
2024-08-07 18:31 ` [PATCH bpf-next v6 3/6] selftests/bpf: netns_new() and netns_free() helpers Kui-Feng Lee
2024-08-08 20:27   ` Martin KaFai Lau
2024-08-08 20:38     ` Kui-Feng Lee
2024-08-08 21:56       ` Martin KaFai Lau
2024-08-09 16:54         ` Kui-Feng Lee
2024-08-07 18:31 ` [PATCH bpf-next v6 4/6] selftests/bpf: Monitor traffic for tc_redirect Kui-Feng Lee
2024-08-07 18:31 ` [PATCH bpf-next v6 5/6] selftests/bpf: Monitor traffic for sockmap_listen Kui-Feng Lee
2024-08-07 18:31 ` [PATCH bpf-next v6 6/6] selftests/bpf: Monitor traffic for select_reuseport Kui-Feng Lee

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=91890a6a-19fa-4b7c-b69b-e2b7c9a42a4a@gmail.com \
    --to=sinquersw@gmail.com \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=geliang@kernel.org \
    --cc=kernel-team@meta.com \
    --cc=kuifeng@meta.com \
    --cc=martin.lau@linux.dev \
    --cc=sdf@fomichev.me \
    --cc=song@kernel.org \
    --cc=thinker.li@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox