-
Notifications
You must be signed in to change notification settings - Fork 64
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement packet capture on VM- or container interfaces (netlab captu…
- Loading branch information
Showing
14 changed files
with
283 additions
and
8 deletions.
There are no files selected for viewing
This file contains 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 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 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,92 @@ | ||
(netlab-capture)= | ||
# Packet Capture | ||
|
||
The **netlab capture** command can be used to capture packets on [*libvirt* virtual machines](libvirt-capture) or [*containerlab*-created Docker containers](lab-clab). The default packet capturing program is `tcpdump`; you can change that with the [default settings](defaults). | ||
|
||
```{warning} | ||
You cannot capture traffic on point-to-point links between *libvirt* virtual machines; you have to change them into Linux bridges ([more details](libvirt-capture)). | ||
``` | ||
|
||
## Usage | ||
|
||
The **netlab capture** command takes two parameters: the node you want to perform packet capture on and the interface name within that node. | ||
|
||
```text | ||
$ netlab capture -h | ||
usage: netlab capture [-h] [--snapshot [SNAPSHOT]] node [intf] | ||
Start a packet capture on the specified node/interface | ||
positional arguments: | ||
node Node on which you want to capture traffic | ||
intf Interface on which you want to capture traffic | ||
options: | ||
-h, --help show this help message and exit | ||
--snapshot [SNAPSHOT] | ||
Transformed topology snapshot file | ||
All other arguments are passed directly to the packet-capturing utility | ||
``` | ||
|
||
## Examples | ||
|
||
Let's assume we're using this simple topology: | ||
|
||
``` | ||
defaults.device: cumulus | ||
provider: clab | ||
module: [ ospf ] | ||
nodes: [ r1, r2 ] | ||
links: [ r1-r2 ] | ||
``` | ||
|
||
After starting the lab, you can use the **netlab capture r1 swp1** command to capture all the traffic on the R1-R2 link: | ||
|
||
```bash | ||
$ netlab capture r1 swp1 | ||
Starting packet capture on r1/swp1: sudo ip netns exec clab-X-r1 tcpdump -i swp1 -l -v | ||
tcpdump: listening on swp1, link-type EN10MB (Ethernet), snapshot length 262144 bytes | ||
17:37:39.031667 IP6 (flowlabel 0xa854f, hlim 255, next-header ICMPv6 (58) payload length: 24) fe80::a8c1:abff:fe84:1dfb > ip6-allnodes: [icmp6 sum ok] ICMP6, router advertisement, length 24 | ||
hop limit 64, Flags [none], pref medium, router lifetime 15s, reachable time 0ms, retrans timer 0ms | ||
source link-address option (1), length 8 (1): aa:c1:ab:84:1d:fb | ||
``` | ||
|
||
```{tip} | ||
If you don't specify additional parameters, **netlab capture** adds `-l -v` (unbuffered, verbose) flags to the **tcpdump** command line | ||
``` | ||
|
||
If you want to capture a subset of traffic, use **tcpdump** traffic filters (you will also have to specify the `-l -v` flags if you wish to have an immediate verbose printout). For example, you can use the following command to display OSPF traffic: | ||
|
||
```bash | ||
$ netlab capture r1 swp1 proto ospf -l -v | ||
Starting packet capture on r1/swp1: sudo ip netns exec clab-X-r1 tcpdump -i swp1 proto ospf -l -v | ||
tcpdump: listening on swp1, link-type EN10MB (Ethernet), snapshot length 262144 bytes | ||
17:39:30.143019 IP (tos 0xc0, ttl 1, id 42863, offset 0, flags [none], proto OSPF (89), length 68) | ||
10.1.0.2 > 224.0.0.5: OSPFv2, Hello, length 48 | ||
Router-ID 10.0.0.2, Backbone Area, Authentication Type: none (0) | ||
Options [External] | ||
Hello Timer 10s, Dead Timer 40s, Mask 255.255.255.252, Priority 1 | ||
Neighbor List: | ||
10.0.0.1 | ||
``` | ||
|
||
## Changing the Packet-Capturing Utility | ||
|
||
**netlab capture** uses **tcpdump** as the default packet-capturing utility. You can change that with the **defaults.netlab.capture.command** parameter ([default changing details](defaults)). The command you specify must include the `{intf}` string at the point where the packet-capturing utility expects the interface name. | ||
|
||
To change the default parameters passed to the packet-capturing utility, change the **defaults.netlab.capture.command_args** parameter. | ||
|
||
To display the default settings, use the **netlab show defaults netlab.capture** command. | ||
|
||
```bash | ||
$ netlab show defaults netlab.capture | ||
|
||
netlab default settings within the netlab.capture subtree | ||
============================================================================= | ||
|
||
command: tcpdump -i {intf} | ||
command_args: -l -v | ||
``` | ||
|
This file contains 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 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,92 @@ | ||
# | ||
# netlab capture command | ||
# | ||
# Starts packet capturing on specified node/interface | ||
# | ||
import sys | ||
import typing | ||
import argparse | ||
|
||
from . import load_snapshot,_nodeset,external_commands | ||
from .. import providers | ||
from ..augment import devices | ||
from ..utils import strings,log | ||
|
||
# | ||
# CLI parser for 'netlab capture' command | ||
# | ||
def capture_parse(args: typing.List[str]) -> typing.Tuple[argparse.Namespace, typing.List[str]]: | ||
parser = argparse.ArgumentParser( | ||
prog="netlab capture", | ||
description='Start a packet capture on the specified node/interface', | ||
epilog='All other arguments are passed directly to the packet-capturing utility') | ||
parser.add_argument( | ||
'--snapshot', | ||
dest='snapshot', | ||
action='store', | ||
nargs='?', | ||
default='netlab.snapshot.yml', | ||
const='netlab.snapshot.yml', | ||
help='Transformed topology snapshot file') | ||
parser.add_argument( | ||
dest='node', action='store', | ||
help='Node on which you want to capture traffic') | ||
parser.add_argument( | ||
dest='intf', action='store', | ||
nargs='?', | ||
help='Interface on which you want to capture traffic') | ||
|
||
return parser.parse_known_args(args) | ||
|
||
def run(cli_args: typing.List[str]) -> None: | ||
(args,rest) = capture_parse(cli_args) | ||
|
||
topology = load_snapshot(args) | ||
|
||
if args.node and args.node not in topology.nodes: | ||
log.error( | ||
f'Unknown node {args.node}', | ||
category=log.FatalError, | ||
module='capture', | ||
skip_header=True, | ||
exit_on_error=True, | ||
more_hints=[ 'Use "netlab status" to display the node names in the current lab topology' ]) | ||
|
||
ndata = topology.nodes[args.node] | ||
if not args.intf or args.intf not in [ intf.ifname for intf in ndata.interfaces ]: | ||
errmsg = f'Invalid interface name {args.intf} for node {args.node} (device {ndata.device})' if args.intf \ | ||
else 'Missing interface name' | ||
log.error( | ||
errmsg, | ||
category=log.FatalError, | ||
module='capture', | ||
skip_header=True, | ||
exit_on_error=True, | ||
more_hints=[ f'Use "netlab report --node {args.node} addressing" to display valid interface names and their descriptions' ]) | ||
sys.exit(1) | ||
|
||
node_provider = devices.get_provider(ndata,topology.defaults) | ||
p_module = providers.get_provider_module(topology,node_provider) | ||
p_cmd = p_module.call('capture_command',ndata,topology,args) | ||
|
||
if p_cmd is None: | ||
log.error( | ||
f'Cannot perform packet capture for node {args.node} using provider {node_provider}', | ||
module='capture', | ||
category=log.FatalError, | ||
exit_on_error=True, | ||
skip_header=True) | ||
|
||
if not rest: | ||
rest = strings.string_to_list(topology.defaults.netlab.capture.command_args) | ||
|
||
p_cmd += rest | ||
print(f'Starting packet capture on {args.node}/{args.intf}: {" ".join(p_cmd)}') | ||
status = external_commands.run_command(p_cmd,ignore_errors=True,return_exitcode=True) | ||
if status == 1: | ||
log.error( | ||
f'Packet capturing utility reported an error', | ||
category=log.FatalError, | ||
module='capture', | ||
skip_header=True, | ||
exit_on_error=True) |
This file contains 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 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 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,3 @@ | ||
capture: | ||
command: "tcpdump -i {intf}" | ||
command_args: "-l -v" |
This file contains 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 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 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 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 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.