From patchwork Fri Feb 7 14:45:52 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aaron Conole X-Patchwork-Id: 2043837 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=IEs/E1lD; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::136; helo=smtp3.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=patchwork.ozlabs.org) Received: from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4YqGxP3HXmz1xyG for ; Sat, 8 Feb 2025 01:46:01 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 0616A61059; Fri, 7 Feb 2025 14:46:01 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id Keezu7phSBc4; Fri, 7 Feb 2025 14:46:00 +0000 (UTC) X-Comment: SPF check N/A for local connections - client-ip=2605:bc80:3010:104::8cd3:938; helo=lists.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver= DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org E813B60758 Authentication-Results: smtp3.osuosl.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=IEs/E1lD Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp3.osuosl.org (Postfix) with ESMTPS id E813B60758; Fri, 7 Feb 2025 14:45:59 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id C7DA3C003A; Fri, 7 Feb 2025 14:45:59 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp2.osuosl.org (smtp2.osuosl.org [IPv6:2605:bc80:3010::133]) by lists.linuxfoundation.org (Postfix) with ESMTP id 37B1AC0004 for ; Fri, 7 Feb 2025 14:45:59 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 2830B405CC for ; Fri, 7 Feb 2025 14:45:59 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp2.osuosl.org ([127.0.0.1]) by localhost (smtp2.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id cB8Vj2uok0t7 for ; Fri, 7 Feb 2025 14:45:58 +0000 (UTC) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=170.10.133.124; helo=us-smtp-delivery-124.mimecast.com; envelope-from=aconole@redhat.com; receiver= DMARC-Filter: OpenDMARC Filter v1.4.2 smtp2.osuosl.org 0625040137 Authentication-Results: smtp2.osuosl.org; dmarc=pass (p=none dis=none) header.from=redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org 0625040137 Authentication-Results: smtp2.osuosl.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=IEs/E1lD Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by smtp2.osuosl.org (Postfix) with ESMTPS id 0625040137 for ; Fri, 7 Feb 2025 14:45:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1738939556; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=QcrVwiojZhYvRdILlNORUEulKMvGTi2iiWmXWHcnuyY=; b=IEs/E1lDZOuJVA09IGBHzk0o2kntYleUy/1PtNnQ3I3rjA7pkqPEtSAcjARXeHTvJTxcjz /wiXK1aJvC12KQD64EU3FxlMupmt4q+9irBXUheJkCZcYiNcKg5nypMYvdLmb6pgH/vKDE Vcuj+zVQhIsz1lyjSq7zr18IUQKDhss= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-240-rEOpQnwFNVuMgjIMTEUrqg-1; Fri, 07 Feb 2025 09:45:55 -0500 X-MC-Unique: rEOpQnwFNVuMgjIMTEUrqg-1 X-Mimecast-MFC-AGG-ID: rEOpQnwFNVuMgjIMTEUrqg Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 320541800991 for ; Fri, 7 Feb 2025 14:45:54 +0000 (UTC) Received: from RHTRH0061144.redhat.com (unknown [10.22.80.197]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id B09381800352 for ; Fri, 7 Feb 2025 14:45:53 +0000 (UTC) From: Aaron Conole To: dev@openvswitch.org Date: Fri, 7 Feb 2025 09:45:52 -0500 Message-ID: <20250207144552.1702528-1-aconole@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: KOzHpDUz_DzIVGmPorEwEvklAyyEmwyi7g3eH4YI-5c_1738939554 X-Mimecast-Originator: redhat.com Subject: [ovs-dev] [RFC] sendpkt: Allow definitions via Scapy as well as hex bytes. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" When writing tests it can be very difficult to understand what the test is doing without properly documenting the test. Added to that difficulty is when a stream of bytes gets posted with the patch as a packet definition. We then need to write out detailed descriptions of the packets, and tend to get packet strings that break line length parsers (leading to errors applying patches. With this change, we can write out clear descriptions of packets that make use of Scapy to generate the actual bytes strings. This should serve as accurate documentation, while also trimming the amount of bytes a developer needs to write to represent a packet. Signed-off-by: Aaron Conole --- NOTE: I'm submitting it here as RFC, because I'm a bit nervous with the eval() call I've baked into the parser routine. Probably it's okay because users just trust the test suite anyway. tests/sendpkt.py | 64 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/tests/sendpkt.py b/tests/sendpkt.py index 7cbea51654..32af99b308 100755 --- a/tests/sendpkt.py +++ b/tests/sendpkt.py @@ -25,10 +25,66 @@ # +import re import socket import sys from optparse import OptionParser +try: + from scapy.all import Ether, IP, IPv6, TCP, UDP, ARP, ICMP, ICMPv6ND_RA + from scapy.all import ICMPv6NDOptSrcLLAddr, ICMPv6NDOptMTU + from scapy.all import ICMPv6NDOptPrefixInfo + from scapy.all import ICMPv6EchoRequest, ICMPv6EchoReply + SCAPY_PROTO = { + "Ether": Ether, + "IP": IP, + "IPv6": IPv6, + "TCP": TCP, + "UDP": UDP, + "ARP": ARP, + "ICMP": ICMP, + "ICMPv6ND_RA": ICMPv6ND_RA, + "ICMPv6NDOptSrcLLAddr": ICMPv6NDOptSrcLLAddr, + "ICMPv6NDOptMTU": ICMPv6NDOptMTU, + "ICMPv6NDOptPrefixInfo": ICMPv6NDOptPrefixInfo, + "ICMPv6EchoRequest": ICMPv6EchoRequest, + "ICMPv6EchoReply": ICMPv6EchoReply, + } + + def scapy_parse(packet_def): + pkt_layers = packet_def.split("/") + + pkt = None + + for layer in pkt_layers: + # Word(...) match + lm = re.match(r'(\w+)\((.*?)\)', layer) + if not lm: + raise ValueError( + f"Invalid definition {packet_def} at layer {layer}") + + proto, proto_args_str = lm.groups() + if proto not in SCAPY_PROTO: + raise ValueError("Unable to construct a packet with {proto}.") + + proto_args = {} + if proto_args_str: + kvp = re.findall(r'(\w)=(?:\'([^\']*)\'|([\w.]+))', + proto_args_str) + for key, str_type, n_type in kvp: + proto_args[key] = str_type if str_type else eval(n_type) + + layer_obj = SCAPY_PROTO[proto](**proto_args) + if pkt is None: + pkt = layer_obj + else: + pkt /= layer_obj + + return pkt + +except: + def scapy_parse(packet_def): + raise RuntimeError("No scapy module while trying to parse scapy def.") usage = "usage: %prog [OPTIONS] OUT-INTERFACE HEX-BYTES \n \ bytes in HEX-BYTES must be separated by space(s)" @@ -50,8 +106,12 @@ if options.packet_type != "eth": # Strip '0x' prefixes from hex input, combine into a single string and # convert to bytes. -hex_str = "".join([a[2:] if a.startswith("0x") else a for a in args[1:]]) -pkt = bytes.fromhex(hex_str) +try: + hex_str = "".join([a[2:] if a.startswith("0x") else a for a in args[1:]]) + pkt = bytes.fromhex(hex_str) +except ValueError: + parsed_pkt_obj = scapy_parse(args[1]) + pkt = bytes(parsed_pkt_obj) try: sockfd = socket.socket(socket.AF_PACKET, socket.SOCK_RAW)