Skip to content
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

Add psa_switch support #84

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion docker/scripts/mininet/single_switch_mininet.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
type=str, action="store", required=False)
parser.add_argument('--pcap-dump', help='Dump packets on interfaces to pcap files',
action="store_true")
parser.add_argument('--cli-path', help='path to control utility for switch',
type=str, action='store', required=False, default='simple_switch_CLI')
parser.add_argument('--switch-config', help='simple_switch_CLI script to configure switch',
type=str, action="store", required=False, default=False)
parser.add_argument('--cli-message', help='Message to print before starting CLI',
Expand Down Expand Up @@ -114,7 +116,7 @@ def main():
switch_config = config_file.read()

print "Configuring switch..."
proc = Popen(["simple_switch_CLI"], stdin=PIPE)
proc = Popen([args.cli_path], stdin=PIPE)
proc.communicate(input=switch_config)

print "Configuration complete."
Expand Down
29 changes: 22 additions & 7 deletions docker/scripts/p4apprunner.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@
import sys
import tarfile

DEFAULT_BEHAVIORAL_EXE = 'simple_switch'

def default_cli_path(behavioral_exe):
return '%s_CLI' % behavioral_exe

parser = argparse.ArgumentParser(description='p4apprunner')
parser.add_argument('--build-dir', help='Directory to build in.',
type=str, action='store', required=False, default='/tmp')
Expand Down Expand Up @@ -92,6 +97,8 @@ def get_program_name(program_file):
return os.path.basename(program_file).rstrip('.p4')

def run_compile_bmv2(manifest):
compiler = manifest.target_config.get('compiler', 'p4c-bm2-ss')

if 'run-before-compile' in manifest.target_config:
commands = manifest.target_config['run-before-compile']
if not isinstance(commands, list):
Expand Down Expand Up @@ -121,7 +128,7 @@ def run_compile_bmv2(manifest):
output_file = get_program_name(manifest.program_file) + '.json'
compiler_args.append('"%s"' % manifest.program_file)
compiler_args.append('-o "%s"' % output_file)
rv = run_command('p4c-bm2-ss %s' % ' '.join(compiler_args))
rv = run_command('%s %s' % (compiler, ' '.join(compiler_args)))

if 'run-after-compile' in manifest.target_config:
commands = manifest.target_config['run-after-compile']
Expand All @@ -138,6 +145,8 @@ def run_compile_bmv2(manifest):
return output_file

def run_mininet(manifest):
print(manifest)

output_file = run_compile_bmv2(manifest)

# Run the program using the BMV2 Mininet simple switch.
Expand Down Expand Up @@ -187,7 +196,11 @@ def run_mininet(manifest):
if 'switch-config' in manifest.target_config:
switch_args.append('--switch-config "%s"' % manifest.target_config['switch-config'])

switch_args.append('--behavioral-exe "%s"' % 'simple_switch')
behavioral_exe = manifest.target_config.get('behavioral-exe', DEFAULT_BEHAVIORAL_EXE)
cli_path = manifest.target_config.get('cli-path', default_cli_path(behavioral_exe))

switch_args.append('--behavioral-exe "%s"' % behavioral_exe)
switch_args.append('--cli-path "%s"' % cli_path)
switch_args.append('--json "%s"' % output_file)

program = '"%s/mininet/single_switch_mininet.py"' % sys.path[0]
Expand Down Expand Up @@ -220,20 +233,20 @@ def run_multiswitch(manifest):
if model == 'bmv2':
if args.json: json_file = os.path.abspath(args.json)
else: json_file = run_compile_bmv2(manifest)
behavioral_exe = 'simple_switch'
switch_cli = 'simple_switch_CLI'
else:
log_error('Unrecognized model:', model)
sys.exit(1)

behavioral_exe = manifest.target_config.get('behavioral-exe', DEFAULT_BEHAVIORAL_EXE)
cli_path = manifest.target_config.get('cli-path', default_cli_path(behavioral_exe))
script_args = []
script_args.append('--log-dir "/tmp/p4app_logs"')
script_args.append('--manifest "%s"' % args.manifest)
script_args.append('--target "%s"' % manifest.target)
if 'auto-control-plane' in manifest.target_config and manifest.target_config['auto-control-plane']:
script_args.append('--auto-control-plane' )
script_args.append('--behavioral-exe "%s"' % behavioral_exe)
script_args.append('--cli-path "%s"' % switch_cli)
script_args.append('--cli-path "%s"' % cli_path)
script_args.append('--json "%s"' % json_file)

program = '"%s/mininet/multi_switch_mininet.py"' % sys.path[0]
Expand All @@ -260,12 +273,14 @@ def run_stf(manifest):
return rv

def run_custom(manifest):
behavioral_exe = manifest.target_config.get('behavioral-exe', DEFAULT_BEHAVIORAL_EXE)
cli_path = manifest.target_config.get('cli-path', default_cli_path(behavioral_exe))
output_file = run_compile_bmv2(manifest)
python_path = 'PYTHONPATH=$PYTHONPATH:/scripts/mininet/'
script_args = []
script_args.append('--behavioral-exe "%s"' % 'simple_switch')
script_args.append('--behavioral-exe "%s"' % behavioral_exe)
script_args.append('--json "%s"' % output_file)
script_args.append('--cli "%s"' % 'simple_switch_CLI')
script_args.append('--cli "%s"' % cli_path)
if not 'program' in manifest.target_config:
log_error('No mininet program file provided.')
sys.exit(1)
Expand Down
43 changes: 43 additions & 0 deletions examples/simple_switch_psa.p4app/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Implementing a P4 Switch based on PSA

Run this app.

```bash
p4app run examples/simple_switch_psa.p4app
```

Start capture on h2 from another shell.

```bash
p4app exec m h2 tcpdump
```

Send packet from h1 whose length was large than 100 bytes.

```
mininet> h1 python send.py
###[ Ethernet ]###
dst = 00:04:00:00:00:01
src = 00:00:00:00:00:00
type = 0x1234
###[ Raw ]###
load = 'girl drives odd foolishly. girl runs stupid crazily. girl runs clueless foolishly. puppy runs stupid crazily. '
.
Sent 1 packets.
```

See captured packet and find that the packet was truncated to 64 bytes.

```bash
$ p4app exec m h2 tcpdump
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on h2-eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
14:51:48.709887 00:00:00:00:00:00 (oui Ethernet) > 00:04:00:00:00:01 (oui Unknown), ethertype Unknown (0x1234), length 124:
0x0000: 6769 726c 2064 7269 7665 7320 6f64 6420 girl.drives.odd.
0x0010: 666f 6f6c 6973 686c 792e 2067 6972 6c20 foolishly..girl.
0x0020: 7275 6e73 2073 7475 7069 6420 6372 617a runs.stupid.craz
0x0030: 696c 792e 2067 6972 6c20 7275 6e73 2063 ily..girl.runs.c
0x0040: 6c75 656c 6573 7320 666f 6f6c 6973 686c lueless.foolishl
0x0050: 792e 2070 7570 7079 2072 756e 7320 7374 y..puppy.runs.st
0x0060: 7570 6964 2063 7261 7a69 6c79 2e20 upid.crazily..
```
13 changes: 13 additions & 0 deletions examples/simple_switch_psa.p4app/p4app.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"program": "simple_switch.p4",
"language": "p4-16",
"targets": {
"mininet": {
"compiler": "p4c-bm2-psa",
"behavioral-exe": "psa_switch",
"cli-path": "psa_switch_CLI",
"num-hosts": 2,
"switch-config": "simple_switch.config"
}
}
}
27 changes: 27 additions & 0 deletions examples/simple_switch_psa.p4app/send.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/usr/bin/env python

import random

from scapy.all import sendp
from scapy.all import Ether


def random_sentence():
nouns = ("puppy", "car", "rabbit", "girl", "monkey")
verbs = ("runs", "hits", "jumps", "drives", "barfs")
adv = ("crazily. ", "dutifully. ", "foolishly. ", "merrily. ", "occasionally. ")
adj = ("adorable", "clueless", "dirty", "odd", "stupid")
l = [nouns, verbs, adj, adv]
sentence = ' '.join([random.choice(i) for i in l])
while len(sentence) < 100:
sentence += ' '.join([random.choice(i) for i in l])
return sentence

def main():
payload = random_sentence()
pkt = Ether(dst='00:04:00:00:00:01', type=0x1234) / payload
pkt.show()
sendp(pkt)

if __name__ == '__main__':
main()
2 changes: 2 additions & 0 deletions examples/simple_switch_psa.p4app/simple_switch.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
table_add arp_table set_fwd_port 00:04:00:00:00:00 => 1
table_add arp_table set_fwd_port 00:04:00:00:00:01 => 2
139 changes: 139 additions & 0 deletions examples/simple_switch_psa.p4app/simple_switch.p4
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
#include <core.p4>
#include <psa.p4>

typedef bit<48> EthernetAddress;

header ethernet_t {
EthernetAddress dstAddr;
EthernetAddress srcAddr;
bit<16> etherType;
}

struct empty_metadata_t {
}

struct metadata_t {
}

struct headers_t {
ethernet_t ethernet;
}

parser IngressParserImpl(
packet_in pkt,
out headers_t hdr,
inout metadata_t user_meta,
in psa_ingress_parser_input_metadata_t istd,
in empty_metadata_t resubmit_meta,
in empty_metadata_t recirculate_meta
) {
state start {
pkt.extract(hdr.ethernet);
transition accept;
}
}

control cIngress(
inout headers_t hdr,
inout metadata_t user_meta,
in psa_ingress_input_metadata_t istd,
inout psa_ingress_output_metadata_t ostd)
{
action set_fwd_port(PortId_t port) {
send_to_port(ostd, port);
}

table arp_table {
key = {
hdr.ethernet.dstAddr: exact;
}
actions = {
set_fwd_port;
}
size = 24;
}

apply {
arp_table.apply();
}
}

parser EgressParserImpl(
packet_in buffer,
out headers_t hdr,
inout metadata_t user_meta,
in psa_egress_parser_input_metadata_t istd,
in empty_metadata_t normal_meta,
in empty_metadata_t clone_i2e_meta,
in empty_metadata_t clone_e2e_meta
) {
state start {
transition accept;
}
}

control cEgress(
inout headers_t hdr,
inout metadata_t user_meta,
in psa_egress_input_metadata_t istd,
inout psa_egress_output_metadata_t ostd
) {
apply { }
}

control CommonDeparserImpl(packet_out packet,
inout headers_t hdr)
{
apply {
packet.emit(hdr.ethernet);
}
}

control IngressDeparserImpl(
packet_out buffer,
out empty_metadata_t clone_e2e_meta,
out empty_metadata_t recirculate_meta,
out empty_metadata_t normal_meta,
inout headers_t hdr,
in metadata_t meta,
in psa_ingress_output_metadata_t istd
) {
CommonDeparserImpl() cp;
apply {
cp.apply(buffer, hdr);
}
}

control EgressDeparserImpl(
packet_out buffer,
out empty_metadata_t clone_e2e_meta,
out empty_metadata_t recirculate_meta,
inout headers_t hdr,
in metadata_t meta,
in psa_egress_output_metadata_t istd,
in psa_egress_deparser_input_metadata_t edstd
) {
CommonDeparserImpl() cp;
apply {
cp.apply(buffer, hdr);
}
}

IngressPipeline(
IngressParserImpl(),
cIngress(),
IngressDeparserImpl()
) ip;

EgressPipeline(
EgressParserImpl(),
cEgress(),
EgressDeparserImpl()
) ep;

PSA_Switch(
ip,
PacketReplicationEngine(),
ep,
BufferingQueueingEngine()
) main;