-
Notifications
You must be signed in to change notification settings - Fork 227
Add RawNetworkInterfaceDriver, labgrid-raw-interface helper and example #1157
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
jluebbe
merged 3 commits into
labgrid-project:master
from
Bastian-Krause:bst/network-test
Jan 11, 2024
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| targets: | ||
| main: | ||
| resources: | ||
| NetworkService: | ||
| address: 192.168.1.5 | ||
| username: root | ||
| NetworkInterface: | ||
| ifname: enp2s0f3 | ||
| drivers: | ||
| SSHDriver: {} | ||
| RawNetworkInterfaceDriver: {} | ||
| options: | ||
| local_iface_to_dut_iface: | ||
| enp2s0f3: uplink |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| #!/usr/bin/env python3 | ||
| # Generates an Ethernet frame via scapy using pcap, copies pcap to DUT, replays pcap on interface, | ||
| # records frame locally (or on exporter, adjust env.yaml accordingly), and compares both. | ||
|
|
||
| import logging | ||
| import os | ||
| from tempfile import NamedTemporaryFile, TemporaryDirectory | ||
|
|
||
| from scapy.all import Ether, Raw, rdpcap, wrpcap, conf | ||
|
|
||
| from labgrid import Environment | ||
| from labgrid.logging import basicConfig, StepLogger | ||
|
|
||
| def generate_frame(): | ||
| frame = [Ether(dst="11:22:33:44:55:66", src="66:55:44:33:22:11", type=0x9000)] | ||
| padding = "\x00" * (conf.min_pkt_size - len(frame)) | ||
| frame = frame[0] / Raw(load=padding) | ||
| return frame | ||
|
|
||
|
|
||
| basicConfig(level=logging.INFO) | ||
| StepLogger.start() | ||
| env = Environment("env.yaml") | ||
| target = env.get_target() | ||
|
|
||
| netdrv = target.get_driver("RawNetworkInterfaceDriver") | ||
| ssh = target.get_driver("SSHDriver") | ||
|
|
||
| # get DUT interface | ||
| exporter_iface = netdrv.iface.ifname | ||
| dut_iface = env.config.get_target_option(target.name, "local_iface_to_dut_iface")[exporter_iface] | ||
|
|
||
| # generate test frame | ||
| generated_frame = generate_frame() | ||
|
|
||
| # write pcap, copy to DUT | ||
| remote_pcap = "/tmp/pcap" | ||
| with NamedTemporaryFile() as pcap: | ||
| wrpcap(pcap.name, generated_frame) | ||
| ssh.put(pcap.name, remote_pcap) | ||
|
|
||
| # copy recorded pcap from DUT, compare with generated frame | ||
| with TemporaryDirectory() as tempdir: | ||
| # start record on exporter | ||
| tempf = os.path.join(tempdir, "record.pcap") | ||
| with netdrv.record(tempf, count=1) as record: | ||
| # replay pcap on DUT | ||
| ssh.run_check(f"ip link set {dut_iface} up") | ||
| ssh.run_check(f"tcpreplay -i {dut_iface} {remote_pcap}") | ||
|
|
||
| remote_frame = rdpcap(tempf) | ||
| assert remote_frame[0] == generated_frame[0] | ||
|
|
||
| print("statistics", netdrv.get_statistics()) | ||
| print("address", netdrv.get_address()) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| #!/usr/bin/env python3 | ||
| # | ||
| # Wrapper script to be deployed on machines whose network interfaces should be | ||
| # controllable via the RawNetworkInterfaceDriver. A /etc/labgrid/helpers.yaml | ||
| # can deny access to network interfaces. See below. | ||
| # | ||
| # This is intended to be used via sudo. For example, add via visudo: | ||
| # %developers ALL = NOPASSWD: /usr/sbin/labgrid-raw-interface | ||
|
|
||
| import argparse | ||
| import os | ||
| import sys | ||
|
|
||
| import yaml | ||
|
|
||
|
|
||
| def get_denylist(): | ||
| denylist_file = "/etc/labgrid/helpers.yaml" | ||
| try: | ||
| with open(denylist_file) as stream: | ||
| data = yaml.load(stream, Loader=yaml.SafeLoader) | ||
| except (PermissionError, FileNotFoundError, AttributeError) as e: | ||
| raise Exception(f"No configuration file ({denylist_file}), inaccessable or invalid yaml") from e | ||
|
|
||
| denylist = data.get("raw-interface", {}).get("denied-interfaces", []) | ||
|
|
||
| if not isinstance(denylist, list): | ||
| raise Exception("No explicit denied-interfaces or not a list, please check your configuration") | ||
|
|
||
| denylist.append("lo") | ||
|
|
||
| return denylist | ||
|
|
||
|
|
||
| def main(program, ifname, count): | ||
| if not ifname: | ||
| raise ValueError("Empty interface name.") | ||
| if any((c == "/" or c.isspace()) for c in ifname): | ||
| raise ValueError(f"Interface name '{ifname}' contains invalid characters.") | ||
| if len(ifname) > 16: | ||
| raise ValueError(f"Interface name '{ifname}' is too long.") | ||
Bastian-Krause marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| denylist = get_denylist() | ||
|
|
||
| if ifname in denylist: | ||
| raise ValueError(f"Interface name '{ifname}' is denied in denylist.") | ||
|
|
||
| programs = ["tcpreplay", "tcpdump"] | ||
| if program not in programs: | ||
| raise ValueError(f"Invalid program {program} called with wrapper, valid programs are: {programs}") | ||
|
|
||
| args = [ | ||
| program, | ||
| ] | ||
|
|
||
| if program == "tcpreplay": | ||
| args.append(f"--intf1={ifname}") | ||
| args.append('-') | ||
|
|
||
| if program == "tcpdump": | ||
| args.append("-n") | ||
| args.append(f"--interface={ifname}") | ||
| args.append("-w") | ||
| args.append('-') | ||
|
|
||
| if count: | ||
| args.append("-c") | ||
| args.append(str(count)) | ||
|
|
||
| try: | ||
| os.execvp(args[0], args) | ||
| except FileNotFoundError as e: | ||
| raise RuntimeError(f"Missing {program} binary") from e | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| parser = argparse.ArgumentParser() | ||
| parser.add_argument( | ||
| '-d', | ||
| '--debug', | ||
| action='store_true', | ||
| default=False, | ||
| help="enable debug mode" | ||
| ) | ||
| parser.add_argument('program', type=str, help='program to run, either tcpreplay or tcpdump') | ||
| parser.add_argument('interface', type=str, help='interface name') | ||
| parser.add_argument('count', nargs="?", type=int, default=None, help='amount of frames to capture while recording') | ||
| args = parser.parse_args() | ||
| try: | ||
| main(args.program, args.interface, args.count) | ||
| except Exception as e: # pylint: disable=broad-except | ||
| if args.debug: | ||
| import traceback | ||
| traceback.print_exc(file=sys.stderr) | ||
| print(f"ERROR: {e}", file=sys.stderr) | ||
| exit(1) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.