├── .gitignore
├── .gitmodules
├── .travis.yml
├── LICENSE
├── MANIFEST.in
├── PCAP
└── .gitignore
├── README.md
├── TODO.md
├── dependencies.sh
├── examples
└── p4_src
│ ├── l2_fwd.p4
│ ├── l3_fwd_ipv4.p4
│ ├── l3_fwd_ipv6.p4
│ ├── l3_routing_test.p4
│ ├── push_pop.p4
│ ├── simple_router.p4
│ ├── vlan_prfs.p4
│ ├── vlan_simple.p4
│ └── vxlan.p4
├── lib
├── __init__.py
└── arg_parse.py
├── main.py
├── setup.py
└── src
├── .gitignore
├── __init__.py
├── contrib
├── __init__.py
└── vxlan.py
├── data.py
├── p4_support
├── .gitignore
├── __init__.py
├── p4_prot.generator.py
├── transpiler.py
└── utils
│ ├── .gitignore
│ ├── __init__.py
│ ├── hlir.py
│ ├── json2hlir.py
│ ├── misc.py
│ ├── p4ast.py
│ └── primitives.json
├── packets.py
├── settings.py
└── type.py
/.gitignore:
--------------------------------------------------------------------------------
1 | #built using gitignore template from "https://github.com/github/gitignore"
2 | *.pyc
3 | MANIFEST
4 | /dist
5 | /build
6 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "p4-hlir"]
2 | path = p4-hlir
3 | url = https://github.com/p4lang/p4-hlir.git
4 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: python
2 | sudo: required
3 | dist: trusty
4 |
5 | python:
6 | - 2.7
7 |
8 | before_install:
9 | - sudo apt-get install -y python-pip git python-yaml graphviz python-setuptools
10 | - sudo pip install scapy
11 | - git submodule update --init --recursive
12 | - cd p4-hlir
13 | - sudo python setup.py install
14 | - cd ..
15 |
16 | script:
17 | - sudo python main.py
18 |
19 | notifications:
20 | email:
21 | on_success: never
22 | # More details: https://docs.travis-ci.com/user/notifications#Configuring-email-notifications
23 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2018, Fabricio Rodriguez, UNICAMP, Brazil
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | * Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | * Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | * Neither the name of the copyright holder nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include README.md setup.py LICENSE
2 | include *.txt
3 | include main.py
4 | recursive-include src *.txt *.py
5 | recursive-include lib *.txt *.py
6 | prune PCAP dist
--------------------------------------------------------------------------------
/PCAP/.gitignore:
--------------------------------------------------------------------------------
1 | #built using gitignore template from "https://github.com/github/gitignore"
2 | *.pcap
3 | *.txt
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | BB-Gen
2 | ===
3 |
4 | ## About BB-Gen
5 | BB-Gen is simple CLI based packet crafter written in Python over Scapy library to generate packet flows formatted as PCAP files by taking user-defined parameters as inputs based on the headers defined in a P414 program. It can natively crafts packets for different standard and custom protocols. It aims to create PCAP files to be used with a wide set of Traffic Generators (e.g., pktgen-dpdk, NFPA, TCPDUMP, etc.) helping network developers to validate the network and execute performance tests over the targets.
6 |
7 | [](https://travis-ci.org/intrig-unicamp/BB-Gen)
8 | [](LICENSE)
9 |
10 |
11 |
12 |
13 | If you find this useful, please don't forget to star ⭐️ the repo, as this will help to promote the project.
14 | Follow us on GitHub to keep updated about this project and others.
15 |
16 |
17 |
18 |
19 | ## Installation
20 | step 1: $ `sudo apt-get install git`
21 | step 2: $ `git clone --recursive https://github.com/intrig-unicamp/BB-Gen.git`
22 | step 3: $ `cd BB-Gen`
23 | step 4: $ `sudo ./dependencies.py`
24 | step 5: $ `cd p4-hlir`
25 | step 6: $ `sudo python setup.py install`
26 | step 7: $ `cd ..`
27 | step 8: $ `python main.py`
28 |
29 | BB-Gen generates a PCAP and Trace files.
30 | The PCAPs can be used for testing together with tools such as NFPA.
31 |
32 | ## Usage
33 |
34 | main.py [-h] [-p] [-t] [-n] [-nm] [-rnip] [-rnmac] [-rnport] [-pkt]
35 | [-p4] [-u] [-udata] [-perf] [-d] [-v]
36 |
37 | BB-Gen PCAP generator
38 |
39 | optional arguments:
40 | -h, --help show this help message and exit
41 | -p , --protocol Type of packet:
42 | ipv4, ipv6, vxlan, gre, l2
43 | Default: ipv4
44 | -t , --tansport Specifies the transport protocol:
45 | tcp or udp
46 | For VXLAN and GRE is the encapsulated protocol
47 | Default: tcp
48 | -n , --number Number of entries
49 | Default: 100
50 | -nm , --name PCAP name
51 | Default: ipv4
52 | -rnip Random IP
53 | Default: False
54 | -rnmac Random MAC
55 | Default: False
56 | -rnport Random Port
57 | Default: False
58 | -pkt , --packetsize Specify here the required packetsize
59 | In case of more than one, separated the list with coma
60 | e.g. 64,215,514.
61 | Default: 64
62 | -p4 Specify a P4 code to autogenerates the traces
63 | Default: none
64 | -u , --usecase Use Case:
65 | macsad
66 | Default: none
67 | -udata , --userdata User Specified Data
68 | -perf, --performance Performance PCAPs
69 | 64, 128, 254, 512, 1024, 1280, 1518 pkt size
70 | Default: False
71 | -d, --debug Debug enable
72 | -v show program's version number and exit
73 |
74 | ## Running BB-Gen
75 |
76 | Designed for simplicity, BB-Gen delivers an intuitive CLI based interface. By specifying only a few flags, can be created a set of traces files.
77 |
78 | ### Examples:
79 |
80 | Generation of 100 vxlan traces with packet size of 64B:
81 |
82 | $ `python main.py -p vxlan -n 100`
83 |
84 | Generation of random 1k IPv4 traces for performance test:
85 |
86 | $ `python main.py -p ipv4 -n 1000 -rnip -rnmac -rnport --performance`
87 |
88 | MACSAD use case:
89 |
90 | $ `python main.py -u macsad`
91 |
92 | Using a P414 code to autogenerate 100 traces:
93 |
94 | $ `python main.py -p4 examples/p4_src/l3_fwd_ipv6.p4 -n 100`
95 |
96 | ## Supported Protocols:
97 | - Ethernet
98 | - IPv4 / IPv6
99 | - UDP
100 | - TCP
101 | - GRE
102 | - VXLAN
103 |
104 | ## Contributing
105 | PRs are very much appreciated. For bugs/features consider creating an issue before sending a PR.
106 |
107 | ## Team
108 | We are members of [INTRIG (Information & Networking Technologies Research & Innovation Group)](http://intrig.dca.fee.unicamp.br) at University of Campinas - Unicamp, SP, Brazil.
109 | Thanks to all [contributors](https://github.com/intrig-unicamp/BB-Gen/graphs/contributors)!
110 |
111 |
112 | | [
Fabricio Rodríguez](https://github.com/ecwolf)
(frodri@dca.fee.unicamp.br)
[💻](https://github.com/intrig-unicamp/BB-Gen/commits?author=ecwolf) 🔌 👀 | [
Gyanesh Patra](https://github.com/c3m3gyanesh)
(gyanesh@dca.fee.unicamp.br)
[💻](https://github.com/intrig-unicamp/BB-Gen/commits?author=c3m3gyanesh) 🔌 👀 | [
Christian Esteve Rothenberg](https://github.com/chesteve)
(chesteve@dca.fee.unicamp.br)
📢 🎨 |
113 | | :---: | :---: | :---: |
114 |
115 | Team member list is generated by the [all-contributors](https://github.com/kentcdodds/all-contributors) specification ([emoji key](https://github.com/kentcdodds/all-contributors#emoji-key)).
116 |
117 |
120 |
121 | ## Acknowledgments
122 | This work was supported by the Innovation Center, Ericsson Telecomunicações S.A., Brazil under grant agreement UNI.61.
123 |
--------------------------------------------------------------------------------
/TODO.md:
--------------------------------------------------------------------------------
1 | ## TODO
2 | - [ ] Support P4 16
3 | - [x] Add more P4 examples
4 | - [ ] Clean transpiler and p4_prot
5 | - [ ] Add support for json
--------------------------------------------------------------------------------
/dependencies.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # BSD 3-Clause License
4 |
5 | # Copyright (c) 2018, Fabricio Rodriguez, UNICAMP, Brazil
6 | # All rights reserved.
7 |
8 | # Redistribution and use in source and binary forms, with or without
9 | # modification, are permitted provided that the following conditions are met:
10 |
11 | # * Redistributions of source code must retain the above copyright notice, this
12 | # list of conditions and the following disclaimer.
13 |
14 | # * Redistributions in binary form must reproduce the above copyright notice,
15 | # this list of conditions and the following disclaimer in the documentation
16 | # and/or other materials provided with the distribution.
17 |
18 | # * Neither the name of the copyright holder nor the names of its
19 | # contributors may be used to endorse or promote products derived from
20 | # this software without specific prior written permission.
21 |
22 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
26 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 | #Install packages necessary for BB-Gen
33 | sudo apt-get install -y python python-pip python-dev build-essential python-yaml graphviz python-setuptools
34 | sudo pip install scapy
35 | git submodule update --init --recursive
36 | cd p4-hlir
37 | sudo python setup.py install
38 | cd ..
39 |
--------------------------------------------------------------------------------
/examples/p4_src/l2_fwd.p4:
--------------------------------------------------------------------------------
1 | header_type ethernet_t {
2 | fields {
3 | dstAddr : 48;
4 | srcAddr : 48;
5 | etherType : 16;
6 | }
7 | }
8 |
9 | header ethernet_t ethernet;
10 |
11 | parser start {
12 | return parse_ethernet;
13 | }
14 |
15 | parser parse_ethernet {
16 | extract(ethernet);
17 | return ingress;
18 | }
19 |
20 | action _drop() {
21 | drop();
22 | }
23 |
24 | action _nop() {
25 | }
26 |
27 | #define MAC_LEARN_RECEIVER 1024
28 |
29 | field_list mac_learn_digest {
30 | ethernet.srcAddr;
31 | standard_metadata.ingress_port;
32 | }
33 |
34 | action mac_learn() {
35 | generate_digest(MAC_LEARN_RECEIVER, mac_learn_digest);
36 | }
37 |
38 | table smac {
39 | reads {
40 | ethernet.srcAddr : exact;
41 | }
42 | actions {mac_learn; _nop;}
43 | size : 512;
44 | }
45 |
46 | action forward(port) {
47 | modify_field(standard_metadata.egress_port, port);
48 | }
49 |
50 | action bcast() {
51 | modify_field(standard_metadata.egress_port, 100);
52 |
53 | }
54 |
55 | table dmac {
56 | reads {
57 | ethernet.dstAddr : exact;
58 | }
59 | actions {forward; bcast;}
60 | size : 512;
61 | }
62 |
63 | control ingress {
64 | apply(smac);
65 | apply(dmac);
66 | }
67 |
68 | control egress {
69 | }
70 |
--------------------------------------------------------------------------------
/examples/p4_src/l3_fwd_ipv4.p4:
--------------------------------------------------------------------------------
1 | header_type ethernet_t {
2 | fields {
3 | dstAddr : 48;
4 | srcAddr : 48;
5 | etherType : 16;
6 | }
7 | }
8 |
9 | header_type ipv4_t {
10 | fields {
11 | versionIhl : 8;
12 | diffserv : 8;
13 | totalLen : 16;
14 | identification : 16;
15 | fragOffset : 16;
16 | ttl : 8;
17 | protocol : 8;
18 | hdrChecksum : 16;
19 | srcAddr : 32;
20 | dstAddr: 32;
21 | }
22 | }
23 |
24 | parser start {
25 | return parse_ethernet;
26 | }
27 |
28 | #define ETHERTYPE_IPV4 0x0800
29 |
30 | header ethernet_t ethernet;
31 |
32 | parser parse_ethernet {
33 | extract(ethernet);
34 | return select(latest.etherType) {
35 | ETHERTYPE_IPV4 : parse_ipv4;
36 | default: ingress;
37 | }
38 | }
39 |
40 | header ipv4_t ipv4;
41 |
42 | parser parse_ipv4 {
43 | extract(ipv4);
44 | return ingress;
45 | }
46 |
47 | action on_miss() {
48 | }
49 |
50 | action fib_hit_nexthop(dmac, port) {
51 | modify_field(ethernet.dstAddr, dmac);
52 | modify_field(standard_metadata.egress_port, port);
53 | add_to_field(ipv4.ttl, -1);
54 | }
55 |
56 | table ipv4_fib_lpm {
57 | reads {
58 | ipv4.dstAddr : lpm;
59 | }
60 | actions {
61 | fib_hit_nexthop;
62 | on_miss;
63 | }
64 | size : 512;
65 | }
66 |
67 | action rewrite_src_mac(smac) {
68 | modify_field(ethernet.srcAddr, smac);
69 | }
70 |
71 | table sendout {
72 | reads {
73 | standard_metadata.egress_port : exact;
74 | }
75 | actions {
76 | on_miss;
77 | rewrite_src_mac;
78 | }
79 | size : 512;
80 | }
81 |
82 | control ingress {
83 | /* fib lookup, set dst mac and standard_metadata.egress_port */
84 | apply(ipv4_fib_lpm);
85 |
86 | /* set smac from standard_metadata.egress_port */
87 | apply(sendout);
88 | }
89 |
90 | control egress {
91 | }
92 |
--------------------------------------------------------------------------------
/examples/p4_src/l3_fwd_ipv6.p4:
--------------------------------------------------------------------------------
1 | header_type ethernet_t {
2 | fields {
3 | dstAddr : 48;
4 | srcAddr : 48;
5 | etherType : 16;
6 | }
7 | }
8 |
9 | header_type ipv6_t {
10 | fields {
11 | version : 4;
12 | trafficClass : 8;
13 | flowLabel : 20;
14 | payloadLen : 16;
15 | nextHdr : 8;
16 | hopLimit : 8;
17 | srcAddr : 128;
18 | dstAddr : 128;
19 | }
20 | }
21 |
22 | parser start {
23 | return parse_ethernet;
24 | }
25 |
26 | #define ETHERTYPE_IPV6 0x86DD
27 |
28 | header ethernet_t ethernet;
29 |
30 | parser parse_ethernet {
31 | extract(ethernet);
32 | return select(latest.etherType) {
33 | ETHERTYPE_IPV6 : parse_ipv6;
34 | default: ingress;
35 | }
36 | }
37 |
38 | header ipv6_t ipv6;
39 |
40 | parser parse_ipv6 {
41 | extract(ipv6);
42 | return ingress;
43 | }
44 |
45 | action on_miss() {
46 | }
47 |
48 | action fib_hit_nexthop(dmac, port) {
49 | modify_field(ethernet.dstAddr, dmac);
50 | modify_field(standard_metadata.egress_port, port);
51 | add_to_field(ipv6.hopLimit, -1);
52 | }
53 |
54 | table ipv6_fib_lpm {
55 | reads {
56 | ipv6.dstAddr : lpm;
57 | }
58 | actions {
59 | fib_hit_nexthop;
60 | on_miss;
61 | }
62 | size : 512;
63 | }
64 |
65 | action rewrite_src_mac(smac) {
66 | modify_field(ethernet.srcAddr, smac);
67 | }
68 |
69 | table sendout {
70 | reads {
71 | standard_metadata.egress_port : exact;
72 | }
73 | actions {
74 | on_miss;
75 | rewrite_src_mac;
76 | }
77 | size : 512;
78 | }
79 |
80 | control ingress {
81 | /* fib lookup, set dst mac and standard_metadata.egress_port */
82 | apply(ipv6_fib_lpm);
83 |
84 | /* set smac from standard_metadata.egress_port */
85 | apply(sendout);
86 | }
87 |
88 | control egress {
89 | }
90 |
--------------------------------------------------------------------------------
/examples/p4_src/l3_routing_test.p4:
--------------------------------------------------------------------------------
1 | header_type ethernet_t {
2 | fields {
3 | eth_dst : 48;
4 | eth_src : 48;
5 | eth_type : 16;
6 | }
7 | }
8 |
9 | header_type ipv4_t {
10 | fields {
11 | versionIhl : 8;
12 | diffserv : 8;
13 | totalLen : 16;
14 | identification : 16;
15 | fragOffset : 16;
16 | ttl : 8;
17 | protocol : 8;
18 | hdrChecksum : 16;
19 | srcAddr : 32;
20 | dstAddr: 32;
21 | }
22 | }
23 |
24 | parser start {
25 | return parse_ethernet;
26 | }
27 |
28 | #define ETHERTYPE_IPV4 0x0800
29 |
30 | header ethernet_t ethernet;
31 |
32 | parser parse_ethernet {
33 | extract(ethernet);
34 | return select(latest.eth_type) {
35 | ETHERTYPE_IPV4 : parse_ipv4;
36 | default: ingress;
37 | }
38 | }
39 |
40 | header ipv4_t ipv4;
41 |
42 | parser parse_ipv4 {
43 | extract(ipv4);
44 | return ingress;
45 | }
46 |
47 | action on_miss() {
48 | }
49 |
50 | action fib_hit_nexthop(dmac, port) {
51 | modify_field(ethernet.eth_dst, dmac);
52 | modify_field(standard_metadata.egress_port, port);
53 | add_to_field(ipv4.ttl, -1);
54 | }
55 |
56 | table ipv4_fib_lpm {
57 | reads {
58 | ipv4.dstAddr : lpm;
59 | }
60 | actions {
61 | fib_hit_nexthop;
62 | on_miss;
63 | }
64 | size : 512;
65 | }
66 |
67 | action rewrite_src_mac(smac) {
68 | modify_field(ethernet.eth_src, smac);
69 | }
70 |
71 | table sendout {
72 | reads {
73 | standard_metadata.egress_port : exact;
74 | }
75 | actions {
76 | on_miss;
77 | rewrite_src_mac;
78 | }
79 | size : 512;
80 | }
81 |
82 | control ingress {
83 | /* fib lookup, set dst mac and standard_metadata.egress_port */
84 | apply(ipv4_fib_lpm);
85 |
86 | /* set smac from standard_metadata.egress_port */
87 | apply(sendout);
88 | }
89 |
90 | control egress {
91 | }
92 |
--------------------------------------------------------------------------------
/examples/p4_src/push_pop.p4:
--------------------------------------------------------------------------------
1 | header_type ethernet_t {
2 | fields {
3 | dst : 48;
4 | src : 48;
5 | type_ : 16;
6 | }
7 | }
8 | header_type vlan_t {
9 | fields {
10 | prio : 3;
11 | id : 1;
12 | vlan : 12;
13 | type_ : 16;
14 | }
15 | }
16 | header_type ipv4_t {
17 | fields {
18 | version : 4;
19 | ihl : 4;
20 | tos : 8;
21 | Len : 16;
22 | id : 16;
23 | flags : 3;
24 | frag : 13;
25 | ttl : 8;
26 | proto : 8;
27 | chksum : 16;
28 | src : 32;
29 | dst : 32;
30 | }
31 | }
32 | header ethernet_t ethernet;
33 | header vlan_t vlan_0[3];
34 | header ipv4_t ipv4;
35 |
36 | parser start {
37 | return parse_ethernet;
38 | }
39 | parser parse_ethernet {
40 | extract(ethernet);
41 | return select(latest.type_) {
42 | 0x8100 : parse_vlan_0;
43 | 0x0800 : parse_ipv4;
44 | default : ingress;
45 | }
46 | }
47 | parser parse_vlan_0 {
48 | extract(vlan_0[next]);
49 | return select(latest.type_) {
50 | 0x8100 : parse_vlan_0;
51 | 0x0800 : parse_ipv4;
52 | default : ingress;
53 | }
54 | }
55 | parser parse_ipv4 {
56 | extract(ipv4);
57 | return ingress;
58 | }
59 |
60 |
61 | action action_0() {
62 | pop(vlan_0, 1);
63 | }
64 | table table_0 {
65 | reads { ethernet.dst : exact; }
66 | actions { action_0; }
67 | size : 64;
68 | }
69 |
70 | action action_1() {
71 | push(vlan_0, 1);
72 |
73 | modify_field(vlan_0[0].prio, 0);
74 | modify_field(vlan_0[0].id, 0);
75 | modify_field(vlan_0[0].vlan, 1);
76 | modify_field(vlan_0[0].type_, ethernet.type_);
77 | modify_field(ethernet.type_, 0x8100);
78 | }
79 | table table_1 {
80 | reads { ethernet.dst : exact; }
81 | actions { action_1; }
82 | size : 64;
83 | }
84 |
85 | control ingress {
86 | if (valid(vlan_0[1])) {
87 | apply(table_0); // pop
88 | }
89 | else {
90 | apply(table_1); // push
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/examples/p4_src/simple_router.p4:
--------------------------------------------------------------------------------
1 | /* Copyright 2013-present Barefoot Networks, Inc.
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | header_type ethernet_t {
17 | fields {
18 | dstAddr : 48;
19 | srcAddr : 48;
20 | etherType : 16;
21 | }
22 | }
23 |
24 | header_type ipv4_t {
25 | fields {
26 | version : 4;
27 | ihl : 4;
28 | diffserv : 8;
29 | totalLen : 16;
30 | identification : 16;
31 | flags : 3;
32 | fragOffset : 13;
33 | ttl : 8;
34 | protocol : 8;
35 | hdrChecksum : 16;
36 | srcAddr : 32;
37 | dstAddr: 32;
38 | }
39 | }
40 |
41 | parser start {
42 | return parse_ethernet;
43 | }
44 |
45 | #define ETHERTYPE_IPV4 0x0800
46 |
47 | header ethernet_t ethernet;
48 |
49 | parser parse_ethernet {
50 | extract(ethernet);
51 | return select(latest.etherType) {
52 | ETHERTYPE_IPV4 : parse_ipv4;
53 | default: ingress;
54 | }
55 | }
56 |
57 | header ipv4_t ipv4;
58 |
59 | field_list ipv4_checksum_list {
60 | ipv4.version;
61 | ipv4.ihl;
62 | ipv4.diffserv;
63 | ipv4.totalLen;
64 | ipv4.identification;
65 | ipv4.flags;
66 | ipv4.fragOffset;
67 | ipv4.ttl;
68 | ipv4.protocol;
69 | ipv4.srcAddr;
70 | ipv4.dstAddr;
71 | }
72 |
73 | field_list_calculation ipv4_checksum {
74 | input {
75 | ipv4_checksum_list;
76 | }
77 | algorithm : csum16;
78 | output_width : 16;
79 | }
80 |
81 | calculated_field ipv4.hdrChecksum {
82 | verify ipv4_checksum;
83 | update ipv4_checksum;
84 | }
85 |
86 | parser parse_ipv4 {
87 | extract(ipv4);
88 | return ingress;
89 | }
90 |
91 |
92 | action _drop() {
93 | drop();
94 | }
95 |
96 | header_type routing_metadata_t {
97 | fields {
98 | nhop_ipv4 : 32;
99 | }
100 | }
101 |
102 | metadata routing_metadata_t routing_metadata;
103 |
104 | action set_nhop(nhop_ipv4, port) {
105 | modify_field(routing_metadata.nhop_ipv4, nhop_ipv4);
106 | modify_field(standard_metadata.egress_spec, port);
107 | modify_field(ipv4.ttl, ipv4.ttl - 1);
108 | }
109 |
110 | table ipv4_lpm {
111 | reads {
112 | ipv4.dstAddr : lpm;
113 | }
114 | actions {
115 | set_nhop;
116 | _drop;
117 | }
118 | size: 1024;
119 | }
120 |
121 | action set_dmac(dmac) {
122 | modify_field(ethernet.dstAddr, dmac);
123 | }
124 |
125 | table forward {
126 | reads {
127 | routing_metadata.nhop_ipv4 : exact;
128 | }
129 | actions {
130 | set_dmac;
131 | _drop;
132 | }
133 | size: 512;
134 | }
135 |
136 | action rewrite_mac(smac) {
137 | modify_field(ethernet.srcAddr, smac);
138 | }
139 |
140 | table send_frame {
141 | reads {
142 | standard_metadata.egress_port: exact;
143 | }
144 | actions {
145 | rewrite_mac;
146 | _drop;
147 | }
148 | size: 256;
149 | }
150 |
151 | control ingress {
152 | if(valid(ipv4) and ipv4.ttl > 0) {
153 | apply(ipv4_lpm);
154 | apply(forward);
155 | }
156 | apply(send_frame);
157 | }
158 |
159 | control egress {
160 | }
161 |
--------------------------------------------------------------------------------
/examples/p4_src/vlan_prfs.p4:
--------------------------------------------------------------------------------
1 | header_type ethernet_t {
2 | fields {
3 | dstAddr : 48;
4 | srcAddr : 48;
5 | etherType : 16;
6 | }
7 | }
8 | header ethernet_t ethernet;
9 |
10 | header_type vlan_tag_t {
11 | fields {
12 | pcp : 3;
13 | cfi : 1;
14 | vid : 12;
15 | etherType : 16;
16 | }
17 | }
18 |
19 | #define VLAN_DEPTH 1
20 | //header vlan_tag_t vlan_tag_[VLAN_DEPTH];
21 | header vlan_tag_t vlan;
22 |
23 | header_type intrinsic_metadata_t {
24 | fields {
25 | vlan_vid : 16;
26 | vid_valid : 1;
27 | }
28 | }
29 | metadata intrinsic_metadata_t intrinsic_metadata;
30 |
31 | parser start {
32 | return parse_ethernet;
33 | }
34 |
35 | parser parse_ethernet {
36 | extract(ethernet);
37 | return parse_vlan;
38 | }
39 |
40 | parser parse_vlan {
41 | // extract(vlan_tag_[0]);
42 | extract(vlan);
43 | // set_metadata(intrinsic_metadata.vid, vlan_tag_[0].vid);
44 | set_metadata(intrinsic_metadata.vlan_vid, vlan.vid);
45 | set_metadata(intrinsic_metadata.vid_valid, 1);
46 | return ingress;
47 | }
48 |
49 | action forward(port) {
50 | modify_field(standard_metadata.egress_port, port);
51 | }
52 |
53 | action broadcast() {
54 | modify_field(standard_metadata.egress_port, 100);
55 | }
56 |
57 | action unt_fwd() {
58 | remove_header(vlan);
59 |
60 | }
61 |
62 | action _drop() {
63 | drop();
64 | }
65 |
66 | action _nop() {
67 | }
68 |
69 | table isTagd {
70 | reads {
71 | intrinsic_metadata.vlan_vid : exact;
72 | }
73 | actions {_nop;}
74 | }
75 |
76 | table unTag {
77 | reads {
78 | intrinsic_metadata.vlan_vid : exact;
79 | }
80 | actions {unt_fwd; _drop;}
81 | size : 512;
82 | }
83 |
84 | table fwd {
85 | reads {
86 | ethernet.dstAddr : exact;
87 | }
88 | actions {forward; broadcast;}
89 | size : 512;
90 | }
91 |
92 | control ingress {
93 | apply(isTagd){ // if valid(vlan_tag_0)
94 | hit {
95 | apply(unTag);
96 | }
97 | }
98 | apply(fwd);
99 | }
100 |
101 | control egress {
102 | }
103 |
--------------------------------------------------------------------------------
/examples/p4_src/vlan_simple.p4:
--------------------------------------------------------------------------------
1 | header_type ethernet_t {
2 | fields {
3 | dstAddr : 48;
4 | srcAddr : 48;
5 | etherType : 16;
6 | }
7 | }
8 | header ethernet_t ethernet;
9 |
10 | header_type vlan_tag_t {
11 | fields {
12 | pcp : 3;
13 | cfi : 1;
14 | vid : 12;
15 | etherType : 16;
16 | }
17 | }
18 | #define VLAN_DEPTH 1
19 | //header vlan_tag_t vlan_tag_[VLAN_DEPTH];
20 | header vlan_tag_t vlan_tag_0;
21 |
22 | header_type intrinsic_metadata_t {
23 | fields {
24 | vid : 16;
25 | vid_valid : 1;
26 | }
27 | }
28 | metadata intrinsic_metadata_t intrinsic_metadata;
29 |
30 | parser start {
31 | return parse_ethernet;
32 | }
33 |
34 | parser parse_ethernet {
35 | extract(ethernet);
36 | return parse_vlan;
37 | }
38 |
39 | parser parse_vlan {
40 | // extract(vlan_tag_[0]);
41 | extract(vlan_tag_0);
42 | // set_metadata(intrinsic_metadata.vid, vlan_tag_[0].vid);
43 | set_metadata(intrinsic_metadata.vid, vlan_tag_0.vid);
44 | set_metadata(intrinsic_metadata.vid_valid, 1);
45 | return ingress;
46 | }
47 |
48 | action _nop() {
49 | }
50 |
51 | #define MAC_LEARN_RECEIVER 1024
52 | field_list mac_learn_digest {
53 | ethernet.srcAddr;
54 | intrinsic_metadata.vid;
55 | standard_metadata.ingress_port;
56 | }
57 |
58 | action mac_learn() {
59 | generate_digest(MAC_LEARN_RECEIVER, mac_learn_digest);
60 | }
61 |
62 | table smac {
63 | reads {
64 | ethernet.srcAddr : exact;
65 | }
66 | actions {mac_learn; _nop;}
67 | size : 512;
68 | }
69 |
70 | action forward(port) {
71 | modify_field(standard_metadata.egress_spec, port);
72 | }
73 |
74 | action bcast() {
75 | modify_field(standard_metadata.egress_port, 100);
76 | }
77 |
78 | table dmac {
79 | reads {
80 | ethernet.dstAddr : exact;
81 | intrinsic_metadata.vid : exact;
82 | }
83 | actions {forward; bcast;}
84 | size : 512;
85 | }
86 |
87 | control ingress {
88 | apply(smac);
89 | apply(dmac);
90 | }
91 |
92 | control egress {
93 | }
94 |
--------------------------------------------------------------------------------
/examples/p4_src/vxlan.p4:
--------------------------------------------------------------------------------
1 | //----------header----------//
2 |
3 | header_type ethernet_t {
4 | fields {
5 | dstAddr : 48;
6 | srcAddr : 48;
7 | etherType : 16;
8 | }
9 | }
10 |
11 | header ethernet_t ethernet;
12 |
13 | header_type ipv4_t {
14 | fields {
15 | version : 4;
16 | ihl : 4;
17 | diffserv : 8;
18 | totalLen : 16;
19 | identification : 16;
20 | flags : 3;
21 | fragOffset : 13;
22 | ttl : 8;
23 | protocol : 8;
24 | hdrChecksum : 16;
25 | srcAddr : 32;
26 | dstAddr: 32;
27 | }
28 | }
29 |
30 | header ipv4_t ipv4;
31 |
32 | header_type udp_t {
33 | fields {
34 | srcPort : 16;
35 | dstPort : 16;
36 | length_ : 16;
37 | checksum : 16;
38 | }
39 | }
40 |
41 | header udp_t udp;
42 |
43 | header_type vxlan_t {
44 | fields {
45 | flags : 8;
46 | reserved : 24;
47 | vni : 24;
48 | reserved2 : 8;
49 | }
50 | }
51 |
52 | header vxlan_t vxlan;
53 |
54 | header_type arp_t {
55 | fields {
56 | htype : 16;
57 | ptype : 16;
58 | hlength : 8;
59 | plength: 8;
60 | opcode: 16;
61 | }
62 | }
63 |
64 | header arp_t arp;
65 | header ethernet_t inner_ethernet;
66 | header ipv4_t inner_ipv4;
67 |
68 | //--------parser---------//
69 |
70 | #define MAC_LEARN_RECEIVER 1024
71 | #define ETHERTYPE_IPV4 0x0800
72 | #define ETHERTYPE_ARP 0x0806
73 |
74 | #define IP_PROTOCOLS_IPHL_UDP 0x511
75 | #define UDP_PORT_VXLAN 4789
76 |
77 | #define BONE 1
78 | #define BTWO 2
79 | #define BTHREE 3
80 |
81 | #define BIT_WIDTH 16
82 |
83 | parser start {
84 | return parse_ethernet;
85 | }
86 |
87 | parser parse_ethernet {
88 | extract(ethernet);
89 | return select(latest.etherType) {
90 | ETHERTYPE_IPV4 : parse_ipv4;
91 | ETHERTYPE_ARP : parse_arp;
92 | default: ingress;
93 | }
94 | }
95 |
96 | parser parse_arp{
97 | extract(arp);
98 | return ingress;
99 | }
100 |
101 | parser parse_ipv4 {
102 | extract(ipv4);
103 | return select(latest.fragOffset, latest.ihl, latest.protocol) {
104 | IP_PROTOCOLS_IPHL_UDP : parse_udp;
105 | default: ingress;
106 | }
107 | }
108 |
109 | parser parse_udp {
110 | extract(udp);
111 | return select (latest.dstPort) {
112 | UDP_PORT_VXLAN : parse_vxlan;
113 | default : ingress;
114 | }
115 | }
116 |
117 | parser parse_vxlan {
118 | extract(vxlan);
119 | return parse_inner_ethernet;
120 | }
121 |
122 | parser parse_inner_ethernet {
123 | extract(inner_ethernet);
124 | return select(latest.etherType) {
125 | ETHERTYPE_IPV4 : parse_inner_ipv4;
126 | default: ingress;
127 | }
128 | }
129 |
130 | parser parse_inner_ipv4 {
131 | extract(inner_ipv4);
132 | return ingress;
133 | }
134 |
135 | //--------action--------//
136 |
137 | action _drop() {
138 | drop();
139 | }
140 |
141 | action _nop() {
142 | }
143 |
144 | field_list ipv4_checksum_list {
145 | ipv4.version;
146 | ipv4.ihl;
147 | ipv4.diffserv;
148 | ipv4.totalLen;
149 | ipv4.identification;
150 | ipv4.flags;
151 | ipv4.fragOffset;
152 | ipv4.ttl;
153 | ipv4.protocol;
154 | ipv4.srcAddr;
155 | ipv4.dstAddr;
156 | }
157 |
158 |
159 | field_list mac_learn_digest {
160 | ethernet.srcAddr;
161 | routing_metadata.ingress_port;
162 | }
163 |
164 | field_list inner_ipv4_checksum_list {
165 | inner_ipv4.version;
166 | inner_ipv4.ihl;
167 | inner_ipv4.diffserv;
168 | inner_ipv4.totalLen;
169 | inner_ipv4.identification;
170 | inner_ipv4.flags;
171 | inner_ipv4.fragOffset;
172 | inner_ipv4.ttl;
173 | inner_ipv4.protocol;
174 | inner_ipv4.srcAddr;
175 | inner_ipv4.dstAddr;
176 | }
177 |
178 | field_list_calculation inner_ipv4_checksum {
179 | input {
180 | inner_ipv4_checksum_list;
181 | }
182 | algorithm : csum16;
183 | output_width : 16;
184 | }
185 |
186 | action mac_learn() {
187 | generate_digest(MAC_LEARN_RECEIVER, mac_learn_digest);
188 | }
189 |
190 | table MAClearn {
191 | reads {
192 | ethernet.srcAddr : exact;
193 | }
194 | actions {
195 | mac_learn;
196 | _nop;
197 | }
198 | size : 512;
199 | }
200 |
201 | header_type routing_metadata_t {
202 | fields {
203 | outport: 2;
204 | res: 2;
205 | aux : 2;
206 | egress_port : 2;
207 | ingress_port : 8;
208 | lb_hash: 16;
209 | }
210 | }
211 |
212 | metadata routing_metadata_t routing_metadata;
213 |
214 | action forward(port, nhop, mac) {
215 | modify_field(standard_metadata.egress_port, port);
216 | modify_field(ethernet.dstAddr, mac);
217 | modify_field(routing_metadata.res, BTHREE);
218 | }
219 |
220 | action Tcast() {
221 | modify_field(routing_metadata.res, BONE);
222 | }
223 |
224 | action Tmac() {
225 | modify_field(routing_metadata.res, BTWO);
226 | }
227 |
228 | table MACfwd {
229 | reads {
230 | ethernet.dstAddr : exact;
231 | }
232 | actions {
233 | forward;
234 | _drop;
235 | Tcast;
236 | Tmac;
237 | }
238 | size : 512;
239 | }
240 |
241 | table ownMAC{
242 | reads {
243 | ethernet.srcAddr : exact;
244 | }
245 | actions {
246 | _nop;
247 | forward;
248 | }
249 | }
250 |
251 | action arp() {
252 | generate_digest(ETHERTYPE_ARP, mac_learn_digest);
253 | modify_field(routing_metadata.res, BTWO);
254 | }
255 |
256 | table ARPselect {
257 | reads {
258 | ethernet.etherType: exact;
259 | }
260 | actions {
261 | arp;
262 | _nop;
263 | }
264 | size : 2;
265 | }
266 |
267 |
268 |
269 | action balancer(){
270 | modify_field(routing_metadata.aux, BONE);
271 | modify_field(routing_metadata.lb_hash,1);
272 | }
273 |
274 | action _pop(){
275 | modify_field(routing_metadata.aux, BTWO);
276 | }
277 |
278 | action jump(){
279 | modify_field(routing_metadata.aux, BTHREE);
280 | }
281 |
282 | table LBselector{
283 | reads {
284 | ipv4.dstAddr : exact;
285 | }
286 | actions {
287 | jump;
288 | _pop;
289 | balancer;
290 | }
291 | size: 128;
292 | }
293 |
294 | action _pop_vxlan(){
295 | remove_header(ethernet);
296 | remove_header(ipv4);
297 | remove_header(vxlan);
298 | modify_field(udp.dstPort, 700);
299 | }
300 |
301 | table vpop{
302 | reads {
303 | ipv4.srcAddr : exact;
304 | }
305 | actions {
306 | _pop_vxlan;
307 | _nop;
308 | }
309 | }
310 |
311 | action press(vnid, nhop, srcAddr){
312 | add_header(vxlan);
313 | add_header(udp);
314 | add_header(inner_ipv4);
315 | copy_header(inner_ipv4, ipv4);
316 | add_header(inner_ethernet);
317 | copy_header(inner_ethernet, ethernet);
318 |
319 | modify_field(ipv4.dstAddr, nhop);
320 | modify_field(ipv4.srcAddr, srcAddr);
321 | modify_field(ipv4.protocol, 0x11);
322 | modify_field(ipv4.ttl, 64);
323 | modify_field(ipv4.version, 0x4);
324 | modify_field(ipv4.ihl, 0x5);
325 | modify_field(ipv4.identification, 0);
326 | modify_field(inner_ipv4.totalLen, ipv4.totalLen);
327 | modify_field(ethernet.etherType, ETHERTYPE_IPV4);
328 | modify_field(udp.dstPort, UDP_PORT_VXLAN);
329 | modify_field(udp.checksum, 0);
330 | modify_field(udp.length_, ipv4.totalLen + 30);
331 | modify_field(vxlan.flags, 0x8);
332 | modify_field(vxlan.reserved, 0);
333 | modify_field(vxlan.vni, vnid);
334 | modify_field(vxlan.reserved2, 0);
335 | }
336 |
337 | table LB{
338 | reads {
339 | ipv4.srcAddr : exact;
340 | }
341 | actions {
342 | press;
343 | _nop;
344 | }
345 | size:1024;
346 | }
347 |
348 | action nhop_ipv4(nhop_ipv4) {
349 | modify_field(ipv4.dstAddr, nhop_ipv4);
350 | }
351 |
352 | table LBipv4 {
353 | reads {
354 | routing_metadata.lb_hash : exact;
355 | }
356 | actions {
357 | nhop_ipv4;
358 | _nop;
359 | }
360 | size:1024;
361 | }
362 |
363 | action nhop(port, dmac){
364 | modify_field(standard_metadata.egress_port, port);
365 | modify_field(ethernet.dstAddr, dmac);
366 | modify_field(ipv4.ttl,ipv4.ttl - 1);
367 | }
368 |
369 | table L3{
370 | reads {
371 | inner_ipv4.dstAddr : lpm;
372 | }
373 | actions {
374 | nhop;
375 | _nop;
376 | }
377 | }
378 |
379 | action rewrite_src_mac(smac) {
380 | modify_field(ethernet.srcAddr, smac);
381 | }
382 |
383 | table sendout {
384 | reads {
385 | standard_metadata.egress_port : exact;
386 | }
387 | actions {
388 | _nop;
389 | rewrite_src_mac;
390 | }
391 | size : 512;
392 | }
393 |
394 | //-------control-------//
395 |
396 | control ingress {
397 | apply(MAClearn);
398 | apply(MACfwd);
399 | if (routing_metadata.res == BONE){
400 | apply(ARPselect);
401 | }
402 | else if (routing_metadata.res == BTWO){
403 | apply(ownMAC);
404 | apply(LBselector);
405 |
406 | if (routing_metadata.aux == BONE){
407 | apply(LB);
408 | apply(LBipv4);
409 | }
410 |
411 | apply(L3);
412 | apply(sendout);
413 | if (routing_metadata.aux == BTWO){
414 | apply(vpop);
415 | }
416 | }
417 | }
418 |
419 | control egress {
420 | }
421 |
422 |
--------------------------------------------------------------------------------
/lib/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/intrig-unicamp/BB-Gen/845299e5b7c5b786afad2001728bb805f38cf553/lib/__init__.py
--------------------------------------------------------------------------------
/lib/arg_parse.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # BSD 3-Clause License
4 |
5 | # Copyright (c) 2018, Fabricio Rodriguez, UNICAMP, Brazil
6 | # All rights reserved.
7 |
8 | # Redistribution and use in source and binary forms, with or without
9 | # modification, are permitted provided that the following conditions are met:
10 |
11 | # * Redistributions of source code must retain the above copyright notice, this
12 | # list of conditions and the following disclaimer.
13 |
14 | # * Redistributions in binary form must reproduce the above copyright notice,
15 | # this list of conditions and the following disclaimer in the documentation
16 | # and/or other materials provided with the distribution.
17 |
18 | # * Neither the name of the copyright holder nor the names of its
19 | # contributors may be used to endorse or promote products derived from
20 | # this software without specific prior written permission.
21 |
22 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
26 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 |
33 | import argparse
34 |
35 | class SmartFormatter(argparse.HelpFormatter):
36 |
37 | def _split_lines(self, text, width):
38 | if text.startswith('R|'):
39 | return text[2:].splitlines()
40 | # this is the RawTextHelpFormatter._split_lines
41 | return argparse.HelpFormatter._split_lines(self, text, width)
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # BSD 3-Clause License
4 |
5 | # Copyright (c) 2018, Fabricio Rodriguez, UNICAMP, Brazil
6 | # All rights reserved.
7 |
8 | # Redistribution and use in source and binary forms, with or without
9 | # modification, are permitted provided that the following conditions are met:
10 |
11 | # * Redistributions of source code must retain the above copyright notice, this
12 | # list of conditions and the following disclaimer.
13 |
14 | # * Redistributions in binary form must reproduce the above copyright notice,
15 | # this list of conditions and the following disclaimer in the documentation
16 | # and/or other materials provided with the distribution.
17 |
18 | # * Neither the name of the copyright holder nor the names of its
19 | # contributors may be used to endorse or promote products derived from
20 | # this software without specific prior written permission.
21 |
22 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
26 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 |
33 |
34 | import os
35 | import string
36 | import sys
37 | import random
38 | from random import shuffle
39 | import argparse
40 | from argparse import ArgumentParser
41 | import subprocess
42 |
43 | import src.settings
44 | from src.data import *
45 | from src.type import *
46 | from src.packets import *
47 | from lib.arg_parse import *
48 | from src.contrib.vxlan import *
49 | from src.p4_support.transpiler import *
50 |
51 | src.settings.init()
52 |
53 | debug_flag = False
54 |
55 | def log(s):
56 | global debug_flag
57 | if debug_flag == True:
58 | print s
59 |
60 | parser = ArgumentParser(description='BB-gen PCAP generator', formatter_class=SmartFormatter)
61 |
62 | parser.add_argument('-p','--protocol', metavar='',
63 | help="R|Type of packet:\n"
64 | " ipv4, ipv6, vxlan, gre, l2\n"
65 | " Default: ipv4",
66 | dest='type', action="store", default='ipv4')
67 | parser.add_argument('-t','--tansport', metavar='',
68 | help="R|Specifies the transport protocol:\n"
69 | " tcp or udp\n"
70 | " For VXLAN and GRE is the encapsulated protocol\n"
71 | " Default: tcp",
72 | dest='transport', action="store",
73 | choices=['tcp', 'udp'], default='tcp')
74 | parser.add_argument('-n','--number', metavar='',
75 | help="R|Number of entries\n"
76 | " Default: 10",
77 | dest='num', action="store",
78 | type=int, default=10)
79 | parser.add_argument('-nm','--name', metavar='',
80 | help="R|PCAP name\n"
81 | " Default: ipv4",
82 | dest='name', action="store",
83 | default="noname")
84 | parser.add_argument('-rnip',
85 | help="R|Random IP\n"
86 | " Default: False",
87 | dest='rnip', action='store_true',
88 | default=False)
89 | parser.add_argument('-rnmac',
90 | help="R|Random MAC\n"
91 | " Default: False",
92 | dest='rnmac', action='store_true',
93 | default=False)
94 | parser.add_argument('-rnport',
95 | help="R|Random Port\n"
96 | " Default: False", dest='rnport', action='store_true',
97 | default=False)
98 | parser.add_argument('-pkt','--packetsize',nargs=1, metavar='',
99 | help="R|Specify here the required packetsize\n"
100 | " In case of more than one, separated the list with coma\n"
101 | " e.g. 64,215,514.\n"
102 | " Default: 64",
103 | dest='packetsizes',
104 | required=False,
105 | default=['64'])
106 | parser.add_argument('-p4',metavar='',
107 | help="R|Specify a P4 code to autogenerates the traces\n"
108 | " Default: none",
109 | dest='p4_code', action="store",
110 | default="none")
111 | parser.add_argument('-u', '--usecase',metavar='',
112 | help="R|Use Case:\n"
113 | " macsad\n"
114 | " Default: none",
115 | dest='use_case', action="store",
116 | choices=['macsad'], default="none")
117 | parser.add_argument('-udata', '--userdata', metavar='',
118 | help="R|User Specified Data\n",
119 | dest='udata', action="store",
120 | default="")
121 | parser.add_argument('-perf', '--performance',
122 | help="R|Performance PCAPs\n"
123 | " 64, 128, 254, 512, 1024, 1280, 1518 pkt size\n"
124 | " Default: False",
125 | dest='performance', action='store_true',
126 | default=False)
127 | parser.add_argument('-d','--debug',
128 | help='Debug enable',
129 | dest='debug_flag',
130 | action='store_true',
131 | default=False)
132 |
133 | parser.add_argument('-v', action='version', version='BB-gen 1.0')
134 |
135 | args = parser.parse_args()
136 |
137 | #Number of Entries
138 | entries = args.num
139 | log("Number of Entries: %s" % (entries))
140 |
141 | #PCAP name TODO
142 | pname = args.name
143 | log("PCAP and Trace name: %s" % (pname))
144 |
145 | #Select random data
146 | val_random = [args.rnip, args.rnmac, args.rnport]
147 |
148 | #Get Pakcet sizes
149 | packet_sizes = [int(e) for e in (args.packetsizes[0]).split(',')]
150 |
151 | #Enable debug
152 | debug_flag = args.debug_flag
153 |
154 | #P4 Code
155 | p4_code = args.p4_code
156 |
157 | #Use Case
158 | use_case = args.use_case
159 |
160 | #Performance
161 | performance = args.performance
162 |
163 | #User specified data
164 | #For this case the packet_sizes should have the default list i.e., ['64']
165 | usr_data = args.udata
166 | packet_sizes = [64]
167 | log("User Specified Data: %s" % (usr_data))
168 |
169 | #Get Protocol type, transport protocol and distribution
170 | e = pkt_type('Protocol')
171 |
172 | #If P4 code is defined, then run the transpiler and get the Protocol
173 | #The Headers information will be stored at src.settings
174 | if p4_code != 'none':
175 | p = run_transpiler('A')
176 | p.principal(p4_code)
177 |
178 | e.get_prot(src.settings.header_list_len, src.settings.header_list_val)
179 | log("List of P4 headers lenght %s" % (src.settings.header_list_len))
180 | log("List of P4 headers values %s" % (src.settings.header_list_val))
181 |
182 | e.get_tra_type(e.transport)
183 | log("Transport: %s, reference value: %d" % (e.transport, e.tra))
184 | e.get_prot_type(e.protocol, e.tra)
185 | log("Protocol: %s, reference value: %d - %s" % (e.protocol, e.protoID, e.protoName))
186 |
187 | #if is not a P4 code input
188 | else:
189 | e.get_tra_type(args.transport)
190 | log("Transport: %s, reference value: %d" % (args.transport, e.tra))
191 | e.get_prot_type(args.type, e.tra)
192 | log("Protocol: %s, reference value: %d - %s" % (args.type, e.protoID, e.protoName))
193 |
194 | e.get_random(val_random)
195 | log("Random IP %s, Random MAC %s, Random Protocol %s" % (val_random[0], val_random[1], val_random[2]))
196 | log("Random data size: %s" % (e.pktsize))
197 |
198 | #Get IP, MAC and Port list
199 | log("Principal Headers info")
200 | f = generator('principal')
201 | f.ip_gen(entries,e.ranip,e.protoID)
202 | log("IP source list: \n %s" % (f.ipsrc))
203 | log("IP destination list: \n %s" % (f.ipdst))
204 | f.mac_gen(entries,e.ranmac)
205 | log("MAC source list: \n %s" % (f.macsrc))
206 | log("MAC destination list: \n %s" % (f.macdst))
207 | f.port_gen(entries,e.ranport)
208 | log("Port source list: \n %s" % (f.portsrc))
209 | log("Port destination list: \n %s" % (f.portdst))
210 |
211 | #Get encapsulated IP, MAC and Port list, for VXLAN and GRE
212 | log("Encapsulated Headers info")
213 | g = generator('encap')
214 | g.ip_gen(entries,e.ranip,e.protoID)
215 | log("IP source list: \n %s" % (g.ipsrc))
216 | log("IP destination list: \n %s" % (g.ipdst))
217 | g.mac_gen(entries,e.ranmac)
218 | log("MAC source list: \n %s" % (g.macsrc))
219 | log("MAC destination list: \n %s" % (g.macdst))
220 | g.port_gen(entries,e.ranport)
221 | log("Port source list: \n %s" % (g.portsrc))
222 | log("Port destination list: \n %s" % (g.portdst))
223 |
224 | #Create PCAP
225 | h = create_pkt('A')
226 | h.pkt_gen(
227 | entries,
228 | packet_sizes,
229 | f.macdst,
230 | f.macsrc,
231 | f.ipdst,
232 | f.ipsrc,
233 | f.portdst,
234 | f.portsrc,
235 | e.protoID,
236 | e.protoName,
237 | e.tra,
238 | pname,
239 | g.macdst,
240 | g.macsrc,
241 | g.ipdst,
242 | g.ipsrc,
243 | g.portdst,
244 | g.portsrc,
245 | use_case,
246 | usr_data,
247 | f.macsrc_h,
248 | f.macdst_h,
249 | e.dist_name,
250 | performance
251 | )
252 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # BSD 3-Clause License
4 |
5 | # Copyright (c) 2018, Fabricio Rodriguez, UNICAMP, Brazil
6 | # All rights reserved.
7 |
8 | # Redistribution and use in source and binary forms, with or without
9 | # modification, are permitted provided that the following conditions are met:
10 |
11 | # * Redistributions of source code must retain the above copyright notice, this
12 | # list of conditions and the following disclaimer.
13 |
14 | # * Redistributions in binary form must reproduce the above copyright notice,
15 | # this list of conditions and the following disclaimer in the documentation
16 | # and/or other materials provided with the distribution.
17 |
18 | # * Neither the name of the copyright holder nor the names of its
19 | # contributors may be used to endorse or promote products derived from
20 | # this software without specific prior written permission.
21 |
22 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
26 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 |
33 | from distutils.core import setup
34 |
35 | setup(name='bbgen',
36 | version='0.1dev',
37 | description='BB-gen Simple Packet Crafter',
38 | long_description=open('README.md').read(),
39 | author='Fabricio',
40 | author_email='frodri@dca.fee.unicamp.br',
41 | url='https://github.com/ecwolf/BB-gen/',
42 | license='BSD-3',
43 | packages=['src','lib',],
44 | )
45 |
--------------------------------------------------------------------------------
/src/.gitignore:
--------------------------------------------------------------------------------
1 | #built using gitignore template from "https://github.com/github/gitignore"
2 | *.pyc
3 |
--------------------------------------------------------------------------------
/src/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/intrig-unicamp/BB-Gen/845299e5b7c5b786afad2001728bb805f38cf553/src/__init__.py
--------------------------------------------------------------------------------
/src/contrib/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/intrig-unicamp/BB-Gen/845299e5b7c5b786afad2001728bb805f38cf553/src/contrib/__init__.py
--------------------------------------------------------------------------------
/src/contrib/vxlan.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # BSD 3-Clause License
4 |
5 | # Copyright (c) 2018, Fabricio Rodriguez, UNICAMP, Brazil
6 | # All rights reserved.
7 |
8 | # Redistribution and use in source and binary forms, with or without
9 | # modification, are permitted provided that the following conditions are met:
10 |
11 | # * Redistributions of source code must retain the above copyright notice, this
12 | # list of conditions and the following disclaimer.
13 |
14 | # * Redistributions in binary form must reproduce the above copyright notice,
15 | # this list of conditions and the following disclaimer in the documentation
16 | # and/or other materials provided with the distribution.
17 |
18 | # * Neither the name of the copyright holder nor the names of its
19 | # contributors may be used to endorse or promote products derived from
20 | # this software without specific prior written permission.
21 |
22 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
26 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 |
33 | from scapy.packet import *
34 | from scapy.fields import *
35 | from scapy.all import *
36 |
37 | class VXLAN(Packet):
38 | name = "VXLAN"
39 | fields_desc = [ FlagsField("flags", 0x08, 8, ['R', 'R', 'R', 'I', 'R', 'R', 'R', 'R']),
40 | X3BytesField("reserved1", 0x000000),
41 | ThreeBytesField("vni", 0),
42 | XByteField("reserved2", 0x00)]
43 |
44 | def mysummary(self):
45 | return self.sprintf("VXLAN (vni=%VXLAN.vni%)")
46 |
47 | bind_layers(UDP, VXLAN, dport=4789)
48 | bind_layers(VXLAN, Ether)
--------------------------------------------------------------------------------
/src/data.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # BSD 3-Clause License
4 |
5 | # Copyright (c) 2018, Fabricio Rodriguez, UNICAMP, Brazil
6 | # All rights reserved.
7 |
8 | # Redistribution and use in source and binary forms, with or without
9 | # modification, are permitted provided that the following conditions are met:
10 |
11 | # * Redistributions of source code must retain the above copyright notice, this
12 | # list of conditions and the following disclaimer.
13 |
14 | # * Redistributions in binary form must reproduce the above copyright notice,
15 | # this list of conditions and the following disclaimer in the documentation
16 | # and/or other materials provided with the distribution.
17 |
18 | # * Neither the name of the copyright holder nor the names of its
19 | # contributors may be used to endorse or promote products derived from
20 | # this software without specific prior written permission.
21 |
22 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
26 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 |
33 | import string
34 | import sys
35 | import random
36 | from random import shuffle
37 |
38 | # The generator Class creates the list of IP address, MAC address and Port numbers
39 | # with the defined distribution:
40 | # If dist = 0 Generates randorm distibution
41 | # If dist = 1 Generates simple distibution
42 |
43 | class generator:
44 |
45 | def __init__(self, name):
46 | self.name = name
47 | self.ipdst = []
48 | self.ipsrc = []
49 | self.macsrc = []
50 | self.macdst = []
51 | self.macsrc_h = []
52 | self.macdst_h = []
53 | self.portsrc = []
54 | self.portdst = []
55 |
56 | #Generates IP address
57 | def ip_gen(self, entries, dist, data):
58 | pkts = []
59 | r = []
60 | for i in range(1,254):
61 | r.append(i)
62 | shuffle(r)
63 | k = []
64 | for i in range(16):
65 | k.append(i)
66 | shuffle(k)
67 | ipsrc_c = ""
68 | ipdst_c = ""
69 | s = 0
70 | #For IPv6
71 | if data == 1:
72 | for m in range(entries):
73 | l = 0
74 | ipsrc_c = ""
75 | ipdst_c = ""
76 | for i in range(32):
77 | if l == 4:
78 | ipdst_c = ipdst_c + ":" + format(k[0], '01x')
79 | ipsrc_c = ipsrc_c + ":" + format(k[1], '01x')
80 | l = 0
81 | else:
82 | ipdst_c = ipdst_c + format(k[0], '01x')
83 | ipsrc_c = ipsrc_c + format(k[1], '01x')
84 | l = l + 1
85 | shuffle(k)
86 | self.ipdst.append(ipdst_c)
87 | self.ipsrc.append(ipsrc_c)
88 | #For ipv4
89 | else:
90 | for m in range(entries):
91 | if s == 0:
92 | l = 0
93 | ipsrc_c = ""
94 | ipdst_c = ""
95 | for i in range(4):
96 | if l == 1:
97 | ipdst_c = ipdst_c + "." + str(r[0])
98 | ipsrc_c = ipsrc_c + "." + str(r[1])
99 | l = 0
100 | else:
101 | ipdst_c = ipdst_c + str(r[0])
102 | ipsrc_c = ipsrc_c + str(r[1])
103 | l = l + 1
104 | shuffle(r)
105 | #Disable main loop for simple traffic
106 | if dist == 1:
107 | s = 1
108 | self.ipdst.append(ipdst_c)
109 | self.ipsrc.append(ipsrc_c)
110 |
111 | #Generates MAC address
112 | def mac_gen(self, entries, dist):
113 | pkts = []
114 | k = []
115 | for i in range(16):
116 | k.append(i)
117 | shuffle(k)
118 | l = 0
119 | macsrc_c = ""
120 | macdst_c = ""
121 | macsrc_hex = ""
122 | macdst_hex = ""
123 | s = 0
124 | for m in range(entries):
125 | if s == 0:
126 | macsrc_c = "f0:76:1c:"
127 | macdst_c = "f0:76:1c:"
128 | macsrc_hex = "0xf0:0x76:0x1c:"
129 | macdst_hex = "0xf0:0x76:0x1c:"
130 | l = 0
131 | n = 0
132 | for i in range(6):
133 | if l == 2:
134 | n = 0
135 | macsrc_c = macsrc_c + ":" + format(k[0], '01x')
136 | macdst_c = macdst_c + ":" + format(k[1], '01x')
137 | if n == 0:
138 | macsrc_hex = macsrc_hex + ":" + format(k[0], '#01x')
139 | macdst_hex = macdst_hex + ":" + format(k[1], '#01x')
140 | n = 1
141 | l = 0
142 | else:
143 | macsrc_c = macsrc_c + format(k[0], '01x')
144 | macdst_c = macdst_c + format(k[1], '01x')
145 | if n == 0:
146 | macsrc_hex = macsrc_hex + format(k[0], '#01x')
147 | macdst_hex = macdst_hex + format(k[1], '#01x')
148 | n = 1
149 | else:
150 | macsrc_hex = macsrc_hex + format(k[0], '01x')
151 | macdst_hex = macdst_hex + format(k[1], '01x')
152 | l = l + 1
153 | shuffle(k)
154 | #Disable main loop for simple traffic
155 | if dist == 1:
156 | s = 1
157 | self.macdst.append(macdst_c)
158 | self.macsrc.append(macsrc_c)
159 | self.macdst_h.append(macdst_hex)
160 | self.macsrc_h.append(macsrc_hex)
161 |
162 | #Generates Port numbers from 49152 to 65535
163 | def port_gen(self, entries, dist):
164 | u = []
165 | portsrc_c = 0
166 | porrdst_c = 0
167 | for i in range(49152,65535):
168 | u.append(i)
169 | shuffle(u)
170 | for m in range(entries):
171 | portsrc_c = u[0]
172 | porrdst_c = u[1]
173 | self.portsrc.append(portsrc_c)
174 | self.portdst.append(porrdst_c)
175 | #Disable shuffle for simple traffic
176 | if dist == 0:
177 | shuffle(u)
--------------------------------------------------------------------------------
/src/p4_support/.gitignore:
--------------------------------------------------------------------------------
1 | #built using gitignore template from "https://github.com/github/gitignore"
2 | *.pyc
3 |
--------------------------------------------------------------------------------
/src/p4_support/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/intrig-unicamp/BB-Gen/845299e5b7c5b786afad2001728bb805f38cf553/src/p4_support/__init__.py
--------------------------------------------------------------------------------
/src/p4_support/p4_prot.generator.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # BSD 3-Clause License
4 |
5 | # Copyright (c) 2018, Fabricio Rodriguez, UNICAMP, Brazil
6 | # All rights reserved.
7 |
8 | # Redistribution and use in source and binary forms, with or without
9 | # modification, are permitted provided that the following conditions are met:
10 |
11 | # * Redistributions of source code must retain the above copyright notice, this
12 | # list of conditions and the following disclaimer.
13 |
14 | # * Redistributions in binary form must reproduce the above copyright notice,
15 | # this list of conditions and the following disclaimer in the documentation
16 | # and/or other materials provided with the distribution.
17 |
18 | # * Neither the name of the copyright holder nor the names of its
19 | # contributors may be used to endorse or promote products derived from
20 | # this software without specific prior written permission.
21 |
22 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
26 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 |
33 | import p4_hlir.hlir.p4 as p4
34 | from p4_hlir.hlir.p4_sized_integer import *
35 | from p4_hlir.hlir.p4_headers import *
36 | from p4_hlir.hlir.p4_imperatives import p4_signature_ref
37 | from src.p4_support.utils.hlir import *
38 | from src.p4_support.utils.misc import addError, addWarning
39 | import math
40 |
41 | import src.settings
42 |
43 | #[//ERFS file Created!!
44 |
45 | OfPorts = {100:"ALL", 200:"CONTROLLER"}
46 | unkwnPrimtv = 0
47 | drpPrimtv = 0
48 |
49 | ofCmd=""
50 |
51 | header_lenght = []
52 | header_value = []
53 |
54 |
55 | #[//Header Details:-
56 | for header_val in hlir.p4_headers.values():
57 | #["${header_val.name}"
58 | #["${header_val.attributes}"
59 | #["${header_val.length}"
60 | #header_len = ','.join([str(hn) for hn in header_val.layout.values()])
61 | for hn in header_val.layout.values():
62 | header_lenght.append(str(hn))
63 | ##[ Header length = ${header_len}
64 | #[ Header length = ${header_lenght}
65 | #header_valo = ','.join([str(hn) for hn in header_val.layout.keys()])
66 | for hn in header_val.layout.keys():
67 | header_value.append(str(hn))
68 | ##[ Header value = ${header_valo}
69 | #[ Header value = ${header_value}
70 |
71 | src.settings.header_list_len.append(list(header_lenght))
72 | src.settings.header_list_val.append(list(header_value))
73 |
74 | del header_lenght[:]
75 | del header_value[:]
76 | #[
77 |
78 | #[//Header Details 2:-
79 | for header_val in hlir.p4_header_instances.values():
80 | #["${header_val.name}"
81 | #["${header_val.header_type}"
82 | #["${header_val.metadata}"
83 | #["${header_val.virtual}"
84 | #[
85 |
86 | #[//Table Details:-
87 | for table in hlir.p4_tables.values():
88 | table_type, key_length = getTypeAndLength(table)
89 | #["${table.name}"
90 | #["${table.match_fields}"
91 | matchFields = ','.join([str(fld.name) for fld, tp, msk in table.match_fields])
92 | #[ Match Fields = ${matchFields}
93 | #["${table.actions}"
94 | actionList = ','.join([str(act.name) for act in table.actions])
95 | #[ Action List = ${actionList}
96 | #[
97 |
98 | def cmd_select():
99 | return "add"
100 |
101 | cmdTypeList = ["flow-mod"]
102 | def cmd_type_select():
103 | return cmdTypeList[0]
104 |
105 | def tbl_select(name):
106 | tableList = [table.name for table in hlir.p4_tables.values()]
107 | # #[Table list is: ${tableList}
108 | return tableList.index(name)
109 |
110 | def format_p4_node(node):
111 | if node is None:
112 | return " "
113 | elif isinstance(node, p4.p4_table):
114 | # return "goto:%s" % node.name
115 | return "goto:%s" % tbl_select(node.name)
116 | elif isinstance(node, p4.p4_conditional_node):
117 | #[//table_next_ conditional node not supported
118 | addWarning("generating modify_field", "field '" + str(dst.name) + "' not supported")
119 | return "0"
120 | #return "if (%s) { %s } else { %s }" % (format_expr(node.condition), format_p4_node(node.next_[True]), format_p4_node(node.next_[False]))
121 |
122 |
123 | # =============================================================================
124 | # DROP
125 | def drop(fun, call):
126 | # return generated_code;
127 | global drpPrimtv
128 | drpPrimtv = 1
129 | return "clear:"
130 |
131 | # =============================================================================
132 | # GENERATE_DIGEST
133 | def generate_digest(fun, call):
134 | extracted_params = []
135 | for p in call[1]:
136 | if isinstance(p, int):
137 | extracted_params += "0" #[str(p)]
138 | elif isinstance(p, p4_field_list):
139 | field_list = p
140 | extracted_params += ["&fields"]
141 | else:
142 | addError("generating prfs.sh", "Unhandled parameter type in generate_digest: " + str(p))
143 | #return generated_code
144 | return "output=CONTROLLER"
145 |
146 | actHdrList = ["vlan"]
147 | actFieldList = ["eth_dst","eth_src","eth_type"]
148 | actFieldExpList = {"egress_port":"output"}
149 |
150 | # ========================================================================
151 | # ADD_HEADER
152 | def add_header(fun, call):
153 | generated_code = ""
154 | args = call[1]
155 | hdrInst = args[0]
156 | if len(args)>1:
157 | addError("generating add_header", "Unsupported number of args")
158 | if not isinstance(hdrInst, p4_header_instance):
159 | addError("generating add_header", "need header_instance as arg")
160 | if hdrInst.name not in actHdrList:
161 | addWarning("generating add_header", "header '" + str(hdrInst.name) + "' not supported")
162 | global unkwnPrimtv
163 | unkwnPrimtv = 1
164 | return fun.name
165 | return "push_vlan"
166 |
167 | # ========================================================================
168 | # REMOVE_HEADER
169 | def remove_header(fun, call):
170 | generated_code = ""
171 | args = call[1]
172 | hdrInst = args[0]
173 | if len(args)>1:
174 | addError("generating remove_header", "Unsupported number of args")
175 | if not isinstance(hdrInst, p4_header_instance):
176 | addError("generating remove_header", "need header instance as args")
177 | if hdrInst.name not in actHdrList:
178 | addWarning("generating remove_header", "header '" + str(hdrInst.name) + "' not supported")
179 | global unkwnPrimtv
180 | unkwnPrimtv = 1
181 | return fun.name
182 | return "pop_vlan"
183 |
184 | # ========================================================================
185 | # MODIFY_FIELD
186 | def modify_field(fun, call):
187 | actName = "set_field"
188 | generated_code = ""
189 | args = call[1]
190 | dst = args[0]
191 | src = args[1]
192 | mask = ''
193 | if len(args)==3:
194 | addError("generating modify_field", "Mask not supported")
195 | if not isinstance(dst, p4_field):
196 | addError("generating modify_field", "We do not allow changing an R-REF yet")
197 | #prfs code
198 | if is_vwf(dst):
199 | addError("generating modify_field", "variable width field not supported")
200 | if dst.name in actFieldExpList.keys():
201 | #[//egress port presetn
202 | if isinstance(src, int):
203 | if src in OfPorts.keys():
204 | return actFieldExpList[dst.name]+"="+OfPorts[src]
205 | return actFieldExpList[dst.name]+"="
206 | if dst.name not in actFieldList:
207 | addWarning("generating modify_field", "field '" + str(dst.name) + "' not supported")
208 | global unkwnPrimtv
209 | unkwnPrimtv = 1
210 | return fun.name
211 | return actName+"="+dst.name+":"
212 |
213 | #==================================================
214 | #dpctl connection cmd_type table,cmd,prio match_fields instructin:actions
215 |
216 | #[Example of a DPCTL rule:-
217 | #[//$d $s flow-mod table=0,cmd=add,prio=12 in_port=2 apply:output=2
218 | #[
219 |
220 | #Set dpctl
221 | #d="/home/ethmola/bin/dpctl"
222 | d="$1"
223 | #Set Of connection details
224 | s="$2"
225 | #s="tcp:localhost:16633"
226 | ofCmd = ofCmd + d + " " + s + " "
227 |
228 | #Set OF command type
229 | cmdType = cmd_type_select()
230 | ofCmd = ofCmd + cmdType + " "
231 | ofCmdDef = ofCmd
232 |
233 | #table, cmd, prio
234 | #set cmd
235 | CMD = cmd_select()
236 |
237 | #Set Priority
238 | ofPrio = 10
239 |
240 | # for table in hlir.p4_tables.values():
241 | # #[
242 | # #[//For Table : ${table.name} ${tbl_select(table.name)}
243 | # #[
244 | # tblId = tbl_select(table.name)
245 |
246 | # #set table, cmd, prio
247 | # ofCmd = ofCmd + ','.join(("table="+str(tblId),"cmd="+CMD,"prio="+str(ofPrio)))+" "
248 |
249 | # #Set match fields
250 | # matchFields = ','.join([str(fld.name) for fld, tp, msk in table.match_fields])
251 | # ofCmd = ofCmd + matchFields + " "
252 |
253 | # tblName = tbl_select(table.name)
254 | # actionList = []
255 | # actionListFlag = 0
256 |
257 | # ofCmdTemp = ofCmd
258 |
259 | # if 'hit' in table.next_:
260 | # if table.next_['hit'] is not None:
261 | # ofCmd = ofCmd + format_p4_node(table.next_['hit'])
262 | # #[${ofCmd}
263 | # ofCmd = ofCmdTemp
264 | # if table.next_['miss'] is not None:
265 | # ofCmd = ofCmd + format_p4_node(table.next_['miss'])
266 | # #[${ofCmd}
267 | # ofCmd = ofCmdTemp
268 | # else:
269 | # for action, nextnode in table.next_.items():
270 | # # #[${table.name} -> ${nextnode}
271 | # if action.name == "drop":
272 | # ofCmd = ofCmd + "clear:"
273 | # #[${ofCmd}
274 | # elif action.name != "_nop":
275 | # if not primitive(action):
276 | # hasParam = action.signature
277 | # modifiers = ""
278 | # ret_val_type = "void"
279 | # name = action.name
280 | # for i,call in enumerate(action.call_sequence):
281 | # ##[${i} + ${call}
282 | # name = call[0].name
283 | # # Generates a primitive action call to `name'
284 | # # locals() returns a dictionary of current namesapce
285 | # if name in locals().keys():
286 | # # #[locals ${name}
287 | # aName = locals()[name](action, call)
288 | # # #[local return ${aName}
289 | # actionList.append(aName)
290 | # actionListFlag = 1
291 | # # #[unkwnPrimtv is ${unkwnPrimtv}, ${aName}
292 | # if unkwnPrimtv:
293 | # unkwnPrimtv = 0
294 | # break
295 | # else:
296 | # addWarning("generating prfs","Unhandled primitive function: " + name)
297 | # if drpPrimtv:
298 | # drpPrimtv = 0
299 | # ofCmd = ofCmd + "clear:"
300 | # #[${ofCmd}
301 | # ofCmd = ofCmdTemp
302 | # elif actionListFlag:
303 | # actionListString = ",".join(actionList)
304 | # ofCmd = ofCmd + "apply:"+ actionListString + " " + format_p4_node(nextnode)
305 | # #[${ofCmd}
306 | # ofCmd = ofCmdTemp
307 | # actionListFlag = 0
308 | # actionList = []
309 | # else:
310 | # ofCmd = ofCmd + "apply:"+ action.name + " " + format_p4_node(nextnode)
311 | # #[${ofCmd}
312 | # ofCmd = ofCmdTemp
313 | # ofCmd = ofCmdDef
314 | # #for condP4 in hlir.p4_conditional_nodes.values():
315 | # # #[${condP4.condition}
316 | # # #[${condP4.next_}
317 | # #[
318 |
--------------------------------------------------------------------------------
/src/p4_support/transpiler.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # BSD 3-Clause License
4 |
5 | # Copyright (c) 2018, Fabricio Rodriguez, UNICAMP, Brazil
6 | # All rights reserved.
7 |
8 | # Redistribution and use in source and binary forms, with or without
9 | # modification, are permitted provided that the following conditions are met:
10 |
11 | # * Redistributions of source code must retain the above copyright notice, this
12 | # list of conditions and the following disclaimer.
13 |
14 | # * Redistributions in binary form must reproduce the above copyright notice,
15 | # this list of conditions and the following disclaimer in the documentation
16 | # and/or other materials provided with the distribution.
17 |
18 | # * Neither the name of the copyright holder nor the names of its
19 | # contributors may be used to endorse or promote products derived from
20 | # this software without specific prior written permission.
21 |
22 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
26 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 |
33 |
34 | from utils.misc import *
35 | from utils.json2hlir import *
36 |
37 | from subprocess import call
38 |
39 | import collections
40 |
41 | from p4_hlir.main import HLIR
42 | from p4_hlir.hlir import p4_parser
43 | from p4_hlir.hlir import p4_tables
44 |
45 | import re
46 | import os
47 | import sys
48 | from os.path import isfile, join
49 |
50 | # Possible values are "pragma", "comment" and anything else
51 | #To add line number in generated code
52 | #generate_orig_lines = "comment"
53 | generate_orig_lines = ""
54 | generate_code_files = True
55 | show_code = False
56 |
57 | def __init__(self, name):
58 | self.name = name
59 | self.p4_code = p4_code
60 |
61 | def translate_line_with_insert(file, line_idx, line):
62 | """Gets a line that contains an insert
63 | and transforms it to a Python code section."""
64 | # since Python code is generated, indentation has to be respected
65 | indentation = re.sub(r'^([ \t]*)#\[.*$', r'\1', line)
66 |
67 | # get the #[ part
68 | content = re.sub(r'^[ \t]*#\[([ \t]*[^\n]*)[ \t]*', r'\1', line)
69 | # escape sequences like \n may appear in #[ parts
70 | content = re.sub(r'\\', r'\\\\', content)
71 | # quotes may appear in #[ parts
72 | content = re.sub(r'"', r'\"', content)
73 | # replace ${var} and ${call()} inserts
74 | content = re.sub(r'\${([ \t\f\v]*)([^}]+)([ \t\f\v]*)}', r'" + str(\2) + "', content)
75 |
76 | # add a comment that shows where the line is generated at
77 | is_nonempty_line = bool(content.strip())
78 | if is_nonempty_line:
79 | if generate_orig_lines == "comment":
80 | content += "// line@%d" % (line_idx)
81 | if generate_orig_lines == "pragma":
82 | content = '#line %d \\"%s\\"\\n%s' % (line_idx, "../../" + file, content)
83 |
84 | return indentation + "generated_code += \"" + content + "\\n\""
85 |
86 |
87 | def translate_file_contents(file, code):
88 | """Returns the code transformed into runnable Python code.
89 | Translated are #[generated_code and ${var} constructs."""
90 | has_translateable_comment = re.compile(r'^[ \t]*#\[[ \t]*.*$')
91 |
92 | new_lines = []
93 | code_lines = code.splitlines()
94 | for line_idx, code_line in enumerate(code_lines):
95 | new_line = code_line
96 | if has_translateable_comment.match(code_line):
97 | new_line = translate_line_with_insert(file, line_idx+1, code_line)
98 |
99 | new_lines.append(new_line)
100 | return '\n'.join(new_lines)
101 |
102 |
103 | def generate_code(file, genfile, localvars={}):
104 | """The file contains Python code with #[ inserts.
105 | The comments (which have to be indented properly)
106 | contain code to be output,
107 | their contents are collected in the variable generated_code.
108 | Inside the comments, refer to Python variables as ${variable_name}."""
109 | with open(file, "r") as orig_file:
110 | code = orig_file.read()
111 | code = translate_file_contents(file, code)
112 |
113 | if generate_code_files:
114 | write_file(genfile, code)
115 |
116 | if show_code:
117 | print(file + " -------------------------------------------------")
118 | print(code)
119 | print(file + " *************************************************")
120 |
121 | localvars['generated_code'] = ""
122 |
123 | #print "Desugaring %s..." % file
124 |
125 | exec(code, localvars, localvars)
126 |
127 | return localvars['generated_code']
128 |
129 |
130 | def generate_all_in_dir(dir, gendir, outdir, hlir):
131 |
132 | for file in os.listdir(dir):
133 | full_file = join(dir, file)
134 | #print full_file
135 | if not isfile(full_file):
136 | continue
137 |
138 | if not full_file.endswith(".generator.py"):
139 | continue
140 |
141 | genfile = join(gendir, re.sub(r'\.(generator)\.py$', r'.\1.desugared.py', file))
142 | #print genfile
143 | code = generate_code(full_file, genfile, {'hlir': hlir})
144 |
145 | outfile = join(outdir, re.sub(r'\.(generator)\.py$', r'', file))
146 |
147 | write_file(outfile, code)
148 |
149 |
150 | def make_dirs(compiler_files_path, desugared_path, generated_path):
151 | """Makes directories if they do not exist"""
152 | if not os.path.isdir(compiler_files_path):
153 | #print("Compiler files path is missing")
154 | sys.exit(1)
155 |
156 | if not os.path.isdir(desugared_path):
157 | os.makedirs(desugared_path)
158 | #print("Generating path for desugared compiler files: {0}".format(desugared_path))
159 |
160 | if not os.path.isdir(generated_path):
161 | os.makedirs(generated_path)
162 | #print("Generating path for generated files: {0}".format(generated_path))
163 |
164 |
165 | def setup_paths(p4_code):
166 | """Gets paths from the command line arguments (or defaults)
167 | and makes sure that they exist in the file system."""
168 | argidx_p4, argidx_genpath, argidx_srcpath = 1, 2, 3
169 |
170 | #p4_path = sys.argv[argidx_p4]
171 | p4_path = p4_code
172 | #compiler_files_path = sys.argv[argidx_srcpath] if len(sys.argv) > argidx_srcpath else join("src", "p4_support")
173 | compiler_files_path = join("src", "p4_support")
174 | #print compiler_files_path
175 | desugared_path = join("build", "util", "desugared_compiler")
176 | #print desugared_path
177 | generated_path = join("build", "src_p4_support")
178 | #print generated_path
179 | #generated_path = sys.argv[argidx_genpath] if len(sys.argv) > argidx_genpath else join("output", "src_hardware_indep")
180 |
181 | make_dirs(compiler_files_path, desugared_path, generated_path)
182 |
183 | return p4_path, compiler_files_path, desugared_path, generated_path
184 |
185 |
186 | def write_file(filename, text):
187 | """Writes the given text to the given file with optional beautification."""
188 | with open(filename, "w") as genfile:
189 | genfile.write(text)
190 |
191 |
192 | class run_transpiler:
193 |
194 | def __init__(self, name):
195 | self.pkts = []
196 |
197 | def principal(self, p4_code):
198 |
199 | #print "Transpiler started"
200 |
201 | # if len(sys.argv) <= 1:
202 | # print("Usage: %s p4_file [compiler_files_dir] [generated_dir]" % (os.path.basename(__file__)))
203 | # sys.exit(1)
204 |
205 | filepath, compiler_files_path, desugared_path, generated_path = setup_paths(p4_code)
206 |
207 | # if p4_code is False:
208 | # print("FILE NOT FOUND: %s" % filepath)
209 | # sys.exit(1)
210 |
211 | _, ext = os.path.splitext(filepath)
212 | if ext == '.p4':
213 | hlir = HLIR(filepath)
214 | success = build_hlir(hlir)
215 | # elif ext == '.json':
216 | # hlir = json2hlir(filepath)
217 | # success = True
218 | else:
219 | print("EXTENSION NOT SUPPORTED: %s" % ext)
220 | sys.exit(1)
221 |
222 | if not success:
223 | print("Transpiler failed for use-case %s" % (os.path.basename(__file__)))
224 | sys.exit(1)
225 |
226 | generate_all_in_dir(compiler_files_path, desugared_path, generated_path, hlir)
227 |
228 | showErrors()
229 | showWarnings()
230 |
231 | # global errors
232 | # if len(errors) > 0:
233 | # sys.exit(1)
234 |
235 |
236 | #principal("","")
237 |
--------------------------------------------------------------------------------
/src/p4_support/utils/.gitignore:
--------------------------------------------------------------------------------
1 | #built using gitignore template from "https://github.com/github/gitignore"
2 | *.pyc
3 |
--------------------------------------------------------------------------------
/src/p4_support/utils/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/intrig-unicamp/BB-Gen/845299e5b7c5b786afad2001728bb805f38cf553/src/p4_support/utils/__init__.py
--------------------------------------------------------------------------------
/src/p4_support/utils/hlir.py:
--------------------------------------------------------------------------------
1 | #Utility functions for analyzing HLIR and for generating some code parts from HLIR
2 |
3 | from p4_hlir.hlir.p4_tables import p4_match_type
4 | import re
5 | import p4_hlir.hlir.p4 as p4
6 | from misc import addError
7 |
8 | # TODO note that this current implementation is true for all fields modified by at least one primitive action;
9 | # this should be refined in the future to reflect the intent of selecting frequently accessed field instances only
10 | def parsed_field(hlir, field):
11 | if field.instance.metadata or is_vwf(field) or field.width > 32: return False
12 | for fun in userActions(hlir):
13 | for call in fun.call_sequence:
14 | act = call[0]
15 | args = call[1]
16 | if act.name in ["modify_field", "add_to_field"]:
17 | dst = args[0]
18 | src = args[1]
19 | if dst == field or src == field:
20 | return True
21 | return False
22 |
23 | def format_p4_node(node):
24 | if node is None:
25 | return ""
26 | elif isinstance(node, p4.p4_table):
27 | return "return apply_table_%s(pd, tables);" % node.name
28 | elif isinstance(node, p4.p4_conditional_node):
29 | return "if (%s) { %s } else { %s }" % (format_expr(node.condition), format_p4_node(node.next_[True]), format_p4_node(node.next_[False]))
30 |
31 | def format_op(op):
32 | if op is "not":
33 | return "!"
34 | elif op is "and":
35 | return "&&"
36 | elif op is "or":
37 | return "||"
38 | else:
39 | return str(op)
40 |
41 | def format_expr(e):
42 | if e is None:
43 | return ""
44 | elif isinstance(e, bool):
45 | return "1" if e else "0"
46 | elif isinstance(e, int):
47 | return str(e)
48 | elif isinstance(e, p4.p4_field):
49 | return "GET_INT32_AUTO(pd, %s)"%fld_id(e)
50 | elif isinstance(e, p4.p4_expression):
51 | if e.op is 'valid' and isinstance(e.right, p4.p4_header_instance):
52 | return "pd->headers[%s].pointer != NULL" % hdr_prefix(e.right.name)
53 | else:
54 | if e.left is None:
55 | return format_op(e.op) + "(" + format_expr(e.right) + ")"
56 | else:
57 | return "(" + format_expr(e.left) + ")" + format_op(e.op) + "(" + format_expr(e.right) + ")"
58 | else:
59 | addError("pretty-printing an expression", "expression type %s is not supported yet"%type(e))
60 | return ""
61 |
62 | def valid_expression(hi):
63 | if isinstance(hi, p4.p4_field): hi = hi.instance
64 | return p4.p4_expression(None, "valid", hi)
65 |
66 | def resolve_field_ref(hlir, hi, exp):
67 | if exp.op=="valid": return exp
68 | if isinstance(exp.left, p4.p4_expression):
69 | resolve_field_ref(hlir, hi, exp.left)
70 | elif isinstance(exp.left, str):
71 | exp.left = hlir.p4_fields[hi.name + "." + exp.left]
72 | if isinstance(exp.right, p4.p4_expression):
73 | resolve_field_ref(hlir, hi, exp.right)
74 | elif isinstance(exp.right, str):
75 | exp.right = hlir.p4_fields[hi.name + "." + exp.right]
76 | return exp
77 |
78 |
79 | def hdr_name(name): return re.sub(r'\[([0-9]+)\]', r'_\1', name)
80 |
81 | def hdr_prefix(name): return re.sub(r'\[([0-9]+)\]', r'_\1', "header_instance_"+name)
82 | def fld_prefix(name): return "field_instance_"+name
83 |
84 | def hstack(name): return re.find(r'\[([0-9]+)\]', name)
85 |
86 | def fld_id(f):
87 | return fld_prefix(hdr_name(f.instance.name) + "_" + f.name)
88 |
89 | def instances4stack(hlir, s):
90 | stack_instances = filter(lambda i: i.max_index > 0 and not i.virtual and i.base_name is s, hlir.p4_header_instances.values())
91 | return map(lambda i: hdr_prefix(i.name), stack_instances)
92 |
93 | def header_stack_ids(hlir):
94 | stack_instances = filter(lambda i: i.max_index > 0 and not i.virtual, hlir.p4_header_instances.values())
95 | stack_base_names = list(set(map(lambda i: i.base_name, stack_instances)))
96 | return map(lambda n: "header_stack_" + n, stack_base_names)
97 |
98 | def stack_instance_ids(hlir):
99 | return map(hdr_prefix, filter(hstack, hlir.p4_header_instances))
100 |
101 | def header_instances(hlir):
102 | return filter(lambda i: not i.virtual, hlir.p4_header_instances.values())
103 |
104 | def header_instance_ids(hlir):
105 | x = filter(lambda i: not i.virtual, hlir.p4_header_instances.values())
106 | return map(lambda i: hdr_prefix(i.name), x)
107 |
108 | def field_instance_ids(hlir):
109 | names = [hdr_name(hi.name)+"_"+fn for hi in header_instances(hlir) for fn,fw in hi.header_type.layout.items()]
110 | return map(fld_prefix, names)
111 |
112 | def variable_width_field_ids(hlir):
113 | var_ids = []
114 | for hi in header_instances(hlir):
115 | field_id = "-1 /* fixed-width header */"
116 | for name,length in hi.header_type.layout.items():
117 | if length == p4.P4_AUTO_WIDTH:
118 | field_id = fld_prefix(hdr_name(hi.name)+"_"+name)
119 | break
120 | var_ids.append(field_id)
121 | return var_ids
122 |
123 | def field_offsets(header_type):
124 | offsets = []
125 | o = 0
126 | for name,length in header_type.layout.items():
127 | offsets.append(o)
128 | if length != p4.P4_AUTO_WIDTH:
129 | o += length
130 | else:
131 | fixed_length = sum([f[1] if f[1] != p4.P4_AUTO_WIDTH else 0 for f in header_type.layout.items()])
132 | o += (-fixed_length) % 8
133 | return offsets
134 |
135 | def field_mask(bitoffset, bitwidth):
136 | if bitwidth == p4.P4_AUTO_WIDTH: return "0x0 /* variable-width field */"
137 | if bitoffset+bitwidth > 32: return hex(0) # FIXME do something about this
138 | pos = bitoffset;
139 | mask = 0;
140 | while pos < bitoffset + bitwidth:
141 | d,m = divmod(pos, 8)
142 | mask |= (1 << (8*d+7-m))
143 | pos += 1
144 | return hex(mask)
145 |
146 | # TODO: better condition...
147 | def primitive(action):
148 | return action.signature_flags != {} and action.name not in ["drop", "no_op"]
149 |
150 | def userActions(hlir):
151 | return filter(lambda act: not primitive(act), hlir.p4_actions.values())
152 |
153 | def compoundAction(action):
154 | return (lambda act: not primitive(act), action)
155 |
156 | def getTypeAndLength(table) :
157 | key_length = 0
158 | lpm = 0
159 | ternary = 0
160 | #match_fields: (field, type, mask)
161 | for field, typ, mx in table.match_fields:
162 | if typ == p4_match_type.P4_MATCH_TERNARY:
163 | ternary = 1
164 | elif typ == p4_match_type.P4_MATCH_LPM:
165 | lpm += 1
166 | if not is_vwf(field): #Variable width field in table match key is not supported
167 | key_length += field.width
168 | if (ternary) or (lpm > 1):
169 | table_type = "LOOKUP_TERNARY"
170 | elif lpm:
171 | table_type = "LOOKUP_LPM"
172 | key_length += 1 #insert the depth value inside the Key[4]
173 | else:
174 | table_type = "LOOKUP_EXACT"
175 | return (table_type, (key_length+7)/8)
176 |
177 | def int_to_big_endian_byte_array(val): # CAUTION: the result array contains the bytes in big endian order!
178 | """
179 | :param val: int
180 | :rtype: (int, [int])
181 | """
182 | nbytes = 0
183 | res = []
184 | while val > 0:
185 | nbytes += 1
186 | res.append(int(val % 256))
187 | val /= 256
188 | res.reverse()
189 | return nbytes, res
190 |
191 | def int_to_big_endian_byte_array_with_length(value, width): # CAUTION: the result array contains the bytes in big endian order!
192 | value_len, l = int_to_big_endian_byte_array(value)
193 | result = [0 for i in range(width-value_len)] + l[value_len-min(value_len, width) : value_len]
194 | return result
195 |
196 | def is_vwf(f): #Returns if the given field instance is a variable width field
197 | return f.width == p4.P4_AUTO_WIDTH
198 |
199 | def field_max_width(f): #For normal fields returns their width, for variable width fields returns the maximum possible width in bits
200 | if not is_vwf(f): return f.width
201 | return (f.instance.header_type.max_length * 8) - sum([field[1] if field[1] != p4.P4_AUTO_WIDTH else 0 for field in f.instance.header_type.layout.items()])
202 |
203 | def is_field_byte_aligned(f): #Returns if the given field is byte-aligned
204 | return field_max_width(f) % 8 == 0 and f.offset % 8 == 0;
205 |
--------------------------------------------------------------------------------
/src/p4_support/utils/json2hlir.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import json
3 |
4 | from p4_hlir.main import HLIR
5 | from p4_hlir.hlir.p4 import *
6 | from p4_hlir.frontend.dumper import *
7 | from p4_hlir.frontend.semantic_check import *
8 | from p4_hlir.hlir.p4_expressions import *
9 |
10 | from p4ast import *
11 |
12 | # ==============================================================================
13 |
14 | def parse_state(ps):
15 | ops = []
16 | for op in ps['parser_ops']:
17 | if op['op'] == 'extract':
18 | p = op['parameters'][0]
19 | # p['type']
20 | name = p['value']
21 | ops += [ParserExtract(RefExpression(name))]
22 |
23 | if len(ps['transition_key']) == 0:
24 | t = ps['transitions'][0]
25 | next_state = t['next_state']
26 | if next_state is None:
27 | next_state = 'ingress'
28 | next_state = RefExpression(next_state)
29 | ret = ParserImmediateReturn(next_state)
30 | else:
31 | select = []
32 | for tk in ps['transition_key']:
33 | if tk['type'] == "field":
34 | headername = tk['value'][0]
35 | fieldname = tk['value'][1]
36 | select += [FieldRefExpression(RefExpression(headername), fieldname)]
37 | # TODO
38 | # elif tk['type'] == "latest":
39 | # elif tk['type'] == "current":
40 | cases = []
41 | for t in ps['transitions']:
42 | next_state = t['next_state']
43 | if next_state is None:
44 | next_state = 'ingress'
45 | next_state = RefExpression(next_state)
46 | if t['value'] == "default":
47 | c = ParserSelectDefaultCase(next_state)
48 | elif t['mask'] is None:
49 | value = int(t['value'], 16)
50 | c = ParserSelectCase([(Integer(value),)], next_state)
51 | else:
52 | value = int(t['value'], 16)
53 | mask = int(t['mask'], 16)
54 | c = ParserSelectCase([(Integer(value),Integer(mask))], next_state)
55 | cases.append(c)
56 | ret = ParserSelectReturn(select, cases)
57 | name = ps['name']
58 | return ParserFunction(name, ops, ret)
59 |
60 | # ------------------------------------------------------------------------------
61 |
62 | def table(t):
63 | name = t['name']
64 | match_type = t['match_type']
65 | min_size = Integer(t['min_size']) if 'min_size' in t else None
66 | max_size = Integer(t['max_size']) if 'max_size' in t else None
67 | size = Integer(t['size']) if 'size' in t else None
68 | actionspec = []
69 | for aname in t['actions']:
70 | actionspec += [RefExpression(aname)]
71 | reads = []
72 | for k in t['key']:
73 | ref = k['target']
74 | fieldref = FieldRefExpression(RefExpression(ref[0]), ref[1])
75 | TableFieldMatch((fieldref,), k['match_type'])
76 | #TODO TableFieldMatch((fieldref,mask), k['match_type'])
77 | timeout = None
78 | return Table(name, actionspec, None, reads, min_size, max_size, size, timeout)
79 |
80 | def table_apply(name, tables):
81 | cases = []
82 | for t in tables:
83 | if t['name'] != name:
84 | continue
85 | for a in t['next_tables']:
86 | name2 = t['next_tables'][a]
87 | if name2 is None:
88 | continue
89 | cases += [ControlFunctionApplyActionCase([RefExpression(a)], [table_apply(name2, tables)])]
90 | return ControlFunctionApplyAndSelect(RefExpression(name), cases)
91 |
92 | def control(p):
93 | body = [table_apply(p['init_table'], p['tables'])]
94 | o = [ControlFunction(p['name'], body)]
95 | for t in p['tables']:
96 | o += [table(t)]
97 | return o
98 |
99 | # ------------------------------------------------------------------------------
100 |
101 | def expression(rd, p):
102 | if p['type'] == "hexstr":
103 | val = p['value']
104 | return Integer(int(val, 16))
105 | elif p['type'] == "field":
106 | ref = p['value']
107 | return FieldRefExpression(RefExpression(ref[0]), ref[1])
108 | elif p['type'] == "runtime_data":
109 | index = p['value']
110 | pname = rd[index]['name']
111 | return RefExpression(pname)
112 | elif p['type'] == "expression":
113 | e = p['value']
114 | if 'type' in e:
115 | return expression(rd, e)
116 | else:
117 | op = e['op']
118 | left = e['left']
119 | right = e['right']
120 | #op = str_ops[op][0]
121 | return BinaryExpression(op,expression(rd, left), expression(rd, right))
122 |
123 | def primitive_action(rd, a):
124 | name = a['op']
125 | parameters = []
126 | for p in a['parameters']:
127 | parameters.append(expression(rd, p))
128 | if parameters == []:
129 | return ActionCall(RefExpression(name))
130 | else:
131 | return ActionCallWP(RefExpression(name), parameters)
132 |
133 | def action(a):
134 | name = a['name']
135 | params = []
136 | for rd in a['runtime_data']:
137 | params += [str(rd['name'])]
138 | body = []
139 | for pa in a['primitives']:
140 | body += [primitive_action(a['runtime_data'], pa)]
141 | return ActionFunction(name, params, body)
142 |
143 | # ------------------------------------------------------------------------------
144 |
145 | def header_type(ht):
146 | length = 0
147 | max_length = 0
148 | layout = []
149 | for f in ht['fields']:
150 | field_name = f[0]
151 | width = f[1]
152 | length += width
153 | # TODO signed, saturating attributes
154 | layout += [(str(field_name), Integer(width), [])]
155 | max_length = length
156 | return HeaderType(ht['name'], layout, Integer(length), Integer(max_length))
157 |
158 | # ------------------------------------------------------------------------------
159 |
160 | def header_instance(h):
161 | name = h['name']
162 | ht = h['header_type']
163 | if h['metadata']:
164 | return HeaderInstanceMetadata(ht, name)
165 | else:
166 | return HeaderInstanceRegular(ht, name)
167 |
168 |
169 | def json2hlir(filepath):
170 |
171 | # Loading and processing JSON...
172 |
173 | with open(filepath) as data_file:
174 | data = json.load(data_file)
175 |
176 | # Creating the P4 objects described in JSON...
177 |
178 | all_p4_objects = []
179 |
180 | for ht in data["header_types"]:
181 | if ht['name'] == 'standard_metadata_t':
182 | continue
183 | all_p4_objects.append(header_type(ht))
184 |
185 | for h in data["headers"]:
186 | all_p4_objects.append(header_instance(h))
187 |
188 | # for x in data["header_stacks"]:
189 | # for x in data["field_lists"]:
190 |
191 | for p in data["parsers"]:
192 | for ps in p["parse_states"]:
193 | all_p4_objects.append(parse_state(ps))
194 |
195 | # for x in data["deparsers"]:
196 | # for x in data["meter_arrays"]:
197 | # for x in data["counter_arrays"]:
198 | # for x in data["register_arrays"]:
199 | # for x in data["calculations"]:
200 | # for x in data["learn_lists"]:
201 |
202 | for a in data["actions"]:
203 | all_p4_objects.append(action(a))
204 |
205 | for p in data["pipelines"]:
206 | all_p4_objects += control(p)
207 |
208 | # for x in data["checksums"]:
209 | # for x in data["force_arith"]:
210 |
211 | # Synthesising the P4 AST...
212 |
213 | p4_program = P4Program("", -1, all_p4_objects)
214 |
215 | with open('src/p4_support/utils/primitives.json') as data_file:
216 | primitives = json.load(data_file)
217 |
218 | sc = P4SemanticChecker()
219 | sc.semantic_check(p4_program, primitives)
220 |
221 | # Translating the P4 AST to HLIR...
222 |
223 | h = HLIR()
224 |
225 | d = P4HlirDumper()
226 | d.dump_to_p4(h, p4_program, primitives)
227 |
228 | p4_validate(h)
229 | p4_dependencies(h)
230 | p4_field_access(h)
231 |
232 | return h
233 |
--------------------------------------------------------------------------------
/src/p4_support/utils/misc.py:
--------------------------------------------------------------------------------
1 | # Miscellaneous utility functions (not using HLIR)
2 |
3 | import sys
4 | import os
5 |
6 | errors = []
7 |
8 | warnings = []
9 |
10 | def addError(where, msg):
11 | global errors
12 | errors += ["ERROR: " + msg + " (While " + where + ").\n"]
13 |
14 | def addWarning(where, msg):
15 | global warnings
16 | warnings += ["WARNING: " + msg + " (While " + where + ").\n"]
17 |
18 | def showErrors():
19 | global errors
20 | for e in errors: print e
21 |
22 | def showWarnings():
23 | global warnings
24 | for w in warnings: print w
25 |
26 | disable_hlir_messages = False
27 |
28 | def build_hlir(hlir):
29 | """Builds the P4 internal representation, optionally disabling its output messages.
30 | Returns True on success"""
31 | if disable_hlir_messages:
32 | old_stdout = sys.stdout
33 | old_stderr = sys.stderr
34 | sys.stdout = open(os.devnull, 'w')
35 | sys.stderr = open(os.devnull, 'w')
36 |
37 | success = hlir.build()
38 |
39 | if disable_hlir_messages:
40 | sys.stdout = old_stdout
41 | sys.stderr = old_stderr
42 |
43 | return success
44 |
--------------------------------------------------------------------------------
/src/p4_support/utils/p4ast.py:
--------------------------------------------------------------------------------
1 | from p4_hlir.frontend.ast import *
2 |
3 | ################################################################################
4 |
5 | def Integer(value): return P4Integer('', 42, value)
6 | def FieldRefExpression(headerref, fieldname): return P4FieldRefExpression('', 42, headerref, str(fieldname))
7 | def RefExpression(name): return P4RefExpression('', 42, str(name))
8 | def ParserImmediateReturn(next_state): return P4ParserImmediateReturn('', 42, next_state)
9 | def ParserSelectReturn(select, cases): return P4ParserSelectReturn('', 42, select, cases)
10 | def ParserFunction(name, ops, ret): return P4ParserFunction('', 42, str(name), ops, ret)
11 | def ParserSelectDefaultCase(next_state): return P4ParserSelectDefaultCase('', 42, next_state)
12 | def ParserSelectCase(case, next_state): return P4ParserSelectCase('', 42, case, next_state)
13 | def Table(name, action_spec, action_prof, reads, min_size, max_size, size, timeout): return P4Table('', 42, str(name), action_spec, action_prof, reads, min_size, max_size, size, timeout)
14 | def ParserExtract(header): return P4ParserExtract('', 42, header)
15 | def TableFieldMatch(field, typ): return P4TableFieldMatch('', 42, field, typ)
16 | def ControlFunction(name, body): return P4ControlFunction('', 42, str(name), body)
17 | def HeaderType(name, layout, length, max_length): return P4HeaderType('', 42, str(name), layout, length, max_length)
18 | def HeaderInstanceRegular(header_type, name): return P4HeaderInstanceRegular('', 42, header_type, str(name))
19 | def HeaderInstanceMetadata(header_type, name): return P4HeaderInstanceMetadata('', 42, header_type, str(name))
20 | def ActionCall(action): return P4ActionCall('', 42, action)
21 | def ActionCallWP(action, parameters): return P4ActionCall('', 42, action, parameters)
22 | def ActionFunction(name, params, body): return P4ActionFunction('', 42, str(name), params, body)
23 | def BinaryExpression(op, left, right): return P4BinaryExpression('', 42, str(op), left, right)
24 | def ControlFunction(name, body): return P4ControlFunction('', 42, name, body)
25 | def ControlFunctionApply(name): return P4ControlFunctionApply('', 42, name)
26 | def ControlFunctionApplyAndSelect(name, cases): return P4ControlFunctionApplyAndSelect('', 42, name, cases)
27 | def ControlFunctionApplyActionCase(case, next): return P4ControlFunctionApplyActionCase('', 42, case, next)
28 |
29 |
--------------------------------------------------------------------------------
/src/p4_support/utils/primitives.json:
--------------------------------------------------------------------------------
1 | {
2 | "add_header" :
3 | {
4 | "num_args" : 1,
5 | "args" : ["header"],
6 | "properties" : {
7 | "header": {
8 | "type" : ["header_instance"],
9 | "access" : "write"
10 | }
11 | }
12 | },
13 | "remove_header" :
14 | {
15 | "num_args" : 1,
16 | "args" : ["header"],
17 | "properties" : {
18 | "header": {
19 | "type" : ["header_instance"],
20 | "access" : "write"
21 | }
22 | }
23 | },
24 | "copy_header" :
25 | {
26 | "num_args" : 2,
27 | "args" : ["dst_header", "src_header"],
28 | "properties" : {
29 | "dst_header" : {
30 | "type" : ["header_instance"],
31 | "access" : "write"
32 | },
33 | "src_header" : {
34 | "type" : ["header_instance"],
35 | "access" : "read"
36 | }
37 | }
38 | },
39 | "modify_field" :
40 | {
41 | "num_args" : 3,
42 | "args" : ["dst", "src", "mask"],
43 | "properties" : {
44 | "dst" : {
45 | "type" : ["field"],
46 | "access" : "write"
47 | },
48 | "src" : {
49 | "type" : ["field", "int", "table_entry_data"],
50 | "access" : "read",
51 | "data_width" : "dst"
52 | },
53 | "mask" : {
54 | "type" : ["int", "table_entry_data"],
55 | "access" : "read",
56 | "data_width" : "dst",
57 | "optional" : true
58 | }
59 | }
60 | },
61 | "register_read" :
62 | {
63 | "num_args" : 3,
64 | "args" : ["dst", "reg", "idx"],
65 | "properties" : {
66 | "dst" : {
67 | "type" : ["field"],
68 | "access" : "write"
69 | },
70 | "reg" : {
71 | "type" : ["register"],
72 | "access" : "read"
73 | },
74 | "idx" : {
75 | "type" : ["int", "table_entry_data", "field"],
76 | "access" : "read",
77 | "data_width" : 32
78 | }
79 | }
80 | },
81 | "register_write" :
82 | {
83 | "num_args" : 3,
84 | "args" : ["reg", "idx", "src"],
85 | "properties" : {
86 | "reg" : {
87 | "type" : ["register"],
88 | "access" : "write"
89 | },
90 | "idx" : {
91 | "type" : ["int", "table_entry_data", "field"],
92 | "access" : "read",
93 | "data_width" : 32
94 | },
95 | "src" : {
96 | "type" : ["field", "int", "table_entry_data"],
97 | "access" : "read",
98 | "data_width" : "reg"
99 | }
100 | }
101 | },
102 | "add_to_field" :
103 | {
104 | "num_args" : 2,
105 | "args" : ["field", "value"],
106 | "properties" : {
107 | "field" : {
108 | "type" : ["field"],
109 | "access" : "write"
110 | },
111 | "value" : {
112 | "type" : ["field", "int", "table_entry_data"],
113 | "access" : "read",
114 | "data_width" : "field"
115 | }
116 | }
117 | },
118 | "add" :
119 | {
120 | "num_args" : 3,
121 | "args" : ["field", "value1", "value2"],
122 | "properties" : {
123 | "field" : {
124 | "type" : ["field"],
125 | "access" : "write"
126 | },
127 | "value1" : {
128 | "type" : ["field", "int", "table_entry_data"],
129 | "access" : "read",
130 | "data_width" : "field"
131 | },
132 | "value2" : {
133 | "type" : ["field", "int", "table_entry_data"],
134 | "access" : "read",
135 | "data_width" : "field"
136 | }
137 | }
138 | },
139 | "subtract_from_field" :
140 | {
141 | "num_args" : 2,
142 | "args" : ["field", "value"],
143 | "properties" : {
144 | "field" : {
145 | "type" : ["field"],
146 | "access" : "write"
147 | },
148 | "value" : {
149 | "type" : ["field", "int", "table_entry_data"],
150 | "access" : "read",
151 | "data_width" : "field"
152 | }
153 | }
154 | },
155 | "subtract" :
156 | {
157 | "num_args" : 3,
158 | "args" : ["field", "value1", "value2"],
159 | "properties" : {
160 | "field" : {
161 | "type" : ["field"],
162 | "access" : "write"
163 | },
164 | "value1" : {
165 | "type" : ["field", "int", "table_entry_data"],
166 | "access" : "read",
167 | "data_width" : "field"
168 | },
169 | "value2" : {
170 | "type" : ["field", "int", "table_entry_data"],
171 | "access" : "read",
172 | "data_width" : "field"
173 | }
174 | }
175 | },
176 | "generate_digest" :
177 | {
178 | "num_args" : 2,
179 | "args" : ["receiver", "field_list"],
180 | "properties" : {
181 | "receiver" : {
182 | "type" : ["int", "table_entry_data"],
183 | "access" : "write",
184 | "data_width" : "standard_metadata.clone_spec"
185 | },
186 | "field_list" : {
187 | "type" : ["field_list"],
188 | "access" : "read",
189 | "optional" : true
190 | }
191 | }
192 | },
193 | "clone_ingress_pkt_to_egress" :
194 | {
195 | "num_args" : 2,
196 | "args" : ["clone_spec", "field_list"],
197 | "properties" : {
198 | "clone_spec" : {
199 | "type" : ["int", "table_entry_data"],
200 | "access" : "write",
201 | "data_width" : "standard_metadata.clone_spec"
202 | },
203 | "field_list" : {
204 | "type" : ["field_list"],
205 | "access" : "read",
206 | "optional" : true
207 | }
208 | }
209 | },
210 | "clone_egress_pkt_to_egress" :
211 | {
212 | "num_args" : 2,
213 | "args" : ["clone_spec", "field_list"],
214 | "properties" : {
215 | "clone_spec" : {
216 | "type" : ["int", "table_entry_data"],
217 | "access" : "write",
218 | "data_width" : "standard_metadata.clone_spec"
219 | },
220 | "field_list" : {
221 | "type" : ["field_list"],
222 | "access" : "read",
223 | "optional" : true
224 | }
225 | }
226 | },
227 | "resubmit" :
228 | {
229 | "num_args" : 1,
230 | "args" : ["field_list"],
231 | "properties" : {
232 | "field_list" : {
233 | "type" : ["field_list"],
234 | "access" : "read",
235 | "optional" : true
236 | }
237 | }
238 | },
239 | "modify_field_with_hash_based_offset":
240 | {
241 | "num_args" : 4,
242 | "args" : ["dst", "base", "hash", "size"],
243 | "properties" : {
244 | "dst" : {
245 | "type" : ["field"],
246 | "access" : "write"
247 | },
248 | "base" : {
249 | "type" : ["int", "table_entry_data"],
250 | "access" : "read",
251 | "data_width" : "dst"
252 | },
253 | "hash" : {
254 | "type" : ["field_list_calculation"],
255 | "access" : "read"
256 | },
257 | "size" : {
258 | "type" : ["int", "table_entry_data"],
259 | "access" : "read",
260 | "data_width" : "dst"
261 | }
262 | }
263 | },
264 | "no_op":
265 | {
266 | "num_args" : 0,
267 | "args" : [],
268 | "properties" : {
269 | }
270 | },
271 | "drop":
272 | {
273 | "num_args" : 0,
274 | "args" : [],
275 | "properties" : {
276 | }
277 | },
278 | "count":
279 | {
280 | "num_args" : 2,
281 | "args" : ["counter_ref", "index"],
282 | "properties" : {
283 | "counter_ref" : {
284 | "type" : ["counter"],
285 | "access" : "write"
286 | },
287 | "index" : {
288 | "type" : ["int", "table_entry_data", "field"],
289 | "access" : "read",
290 | "data_width" : 32
291 | }
292 | }
293 | },
294 | "truncate":
295 | {
296 | "num_args" : 1,
297 | "args" : ["length"],
298 | "properties" : {
299 | "length" : {
300 | "type" : ["int", "table_entry_data"],
301 | "access" : "read",
302 | "data_width" : 32
303 | }
304 | }
305 | },
306 | "execute_meter":
307 | {
308 | "num_args" : 3,
309 | "args" : ["meter_ref", "index", "field"],
310 | "properties" : {
311 | "meter_ref" : {
312 | "type" : ["meter"],
313 | "access" : "write"
314 | },
315 | "index" : {
316 | "type" : ["int", "table_entry_data"],
317 | "access" : "read",
318 | "data_width" : 32
319 | },
320 | "field" : {
321 | "type" : ["field"],
322 | "access" : "write"
323 | }
324 | }
325 | },
326 | "bit_xor" :
327 | {
328 | "num_args" : 3,
329 | "args" : ["dst", "src", "src"],
330 | "properties" : {
331 | "dst" : {
332 | "type" : ["field"],
333 | "access" : "write"
334 | },
335 | "src" : {
336 | "type" : ["field", "int", "table_entry_data"],
337 | "access" : "read",
338 | "data_width" : "dst"
339 | },
340 | "src1" : {
341 | "type" : ["field", "int", "table_entry_data"],
342 | "access" : "read",
343 | "data_width" : "dst"
344 | }
345 | }
346 | },
347 | "bit_or" :
348 | {
349 | "num_args" : 3,
350 | "args" : ["dst", "src", "src"],
351 | "properties" : {
352 | "dst" : {
353 | "type" : ["field"],
354 | "access" : "write"
355 | },
356 | "src" : {
357 | "type" : ["field", "int", "table_entry_data"],
358 | "access" : "read",
359 | "data_width" : "dst"
360 | },
361 | "src1" : {
362 | "type" : ["field", "int", "table_entry_data"],
363 | "access" : "read",
364 | "data_width" : "dst"
365 | }
366 | }
367 | },
368 | "bit_and" :
369 | {
370 | "num_args" : 3,
371 | "args" : ["dst", "src", "src"],
372 | "properties" : {
373 | "dst" : {
374 | "type" : ["field"],
375 | "access" : "write"
376 | },
377 | "src" : {
378 | "type" : ["field", "int", "table_entry_data"],
379 | "access" : "read",
380 | "data_width" : "dst"
381 | },
382 | "src1" : {
383 | "type" : ["field", "int", "table_entry_data"],
384 | "access" : "read",
385 | "data_width" : "dst"
386 | }
387 | }
388 | },
389 | "push":
390 | {
391 | "num_args" : 2,
392 | "args" : ["header_stack", "count"],
393 | "properties" : {
394 | "header_stack" : {
395 | "type" : ["header_instance"],
396 | "access" : "write"
397 | },
398 | "count" : {
399 | "type" : ["int"],
400 | "access" : "read",
401 | "optional" : true
402 | }
403 | }
404 | },
405 | "pop":
406 | {
407 | "num_args" : 2,
408 | "args" : ["header_stack", "count"],
409 | "properties" : {
410 | "header_stack" : {
411 | "type" : ["header_instance"],
412 | "access" : "write"
413 | },
414 | "count" : {
415 | "type" : ["int"],
416 | "access" : "read",
417 | "optional" : true
418 | }
419 | }
420 | }
421 | }
422 |
--------------------------------------------------------------------------------
/src/packets.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # BSD 3-Clause License
4 |
5 | # Copyright (c) 2018, Fabricio Rodriguez, UNICAMP, Brazil
6 | # All rights reserved.
7 |
8 | # Redistribution and use in source and binary forms, with or without
9 | # modification, are permitted provided that the following conditions are met:
10 |
11 | # * Redistributions of source code must retain the above copyright notice, this
12 | # list of conditions and the following disclaimer.
13 |
14 | # * Redistributions in binary form must reproduce the above copyright notice,
15 | # this list of conditions and the following disclaimer in the documentation
16 | # and/or other materials provided with the distribution.
17 |
18 | # * Neither the name of the copyright holder nor the names of its
19 | # contributors may be used to endorse or promote products derived from
20 | # this software without specific prior written permission.
21 |
22 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
26 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 |
33 | import string
34 | import sys
35 | import random
36 | from random import shuffle
37 | from scapy.all import *
38 |
39 | # The create_pkt class generates the pkts list to be added to the output file
40 | # creates the traces and PCAP from the data.
41 | # If the number of entries is more than 1M the PCAP is going to be splited in
42 | # PCAPs of 10000 entires and then all the files are going to be joined
43 | #
44 | # Protocols prot
45 | # 0 IPv4
46 | # 1 IPv6
47 | # 2 VXLAN
48 | # 3 GRE
49 | # 4 L2
50 |
51 | proto_list = ["ipv4", "ipv6", "vxlan", "gre", "l2"]
52 | plist = list(enumerate(proto_list, start=0))
53 |
54 | pkt_size_list_performance = [64, 128, 256, 512, 1024, 1280, 1518]
55 | # pkt_wsize_list = [60, 124, 252, 508, 1020, 1276, 1514]
56 |
57 | info_line = 0
58 |
59 | #Generates the Traces files
60 | def create_trace(prot, macsrc, macdst, ipsrc, ipdst, portsrc, portdst, entries, mil, p, macsrc_e, macdst_e, ipsrc_e, ipdst_e, portsrc_e, portdst_e, use_case, macsrc_h, macdst_h, tprefix, dist_name, cfile):
61 | global info_line
62 | if cfile == 0:
63 | nfile = ">"
64 | else:
65 | nfile = ">>"
66 | if prot == 0:
67 | if use_case == "macsad":
68 | FILE = "echo " + str(ipdst[p]) + " " + macdst_h[p] + " 1 " + nfile + " " + tprefix + "_ipv4_" + str(entries*mil) + "_" + dist_name + ".txt"
69 | if cfile == 0:
70 | FILE2 = "echo " + macsrc[p] + " 0 " + nfile + " " + tprefix + "_l2_" + str(entries*mil) + "_" + dist_name + ".txt"
71 | os.system(FILE2)
72 | FILE2 = "echo " + macdst[p] + " 1 >> " + tprefix + "_l2_" + str(entries) + "_" + dist_name + ".txt"
73 | os.system(FILE2)
74 | else:
75 | FILE2 = "echo " + macsrc[p] + " 0 " + nfile + " " + tprefix + "_l2_" + str(entries*mil) + "_" + dist_name + ".txt"
76 | os.system(FILE2)
77 | FILE2 = "echo " + macdst[p] + " 1 " + nfile + " " + tprefix + "_l2_" + str(entries) + "_" + dist_name + ".txt"
78 | os.system(FILE2)
79 | else:
80 | if info_line == 0:
81 | FILE = "echo \"src MAC,dst MAC,src IP,dst IP,src Port,dst Port\" " + " " + nfile + " " + tprefix + "_ipv4_" + str(entries*mil) + "_" + dist_name + ".txt"
82 | os.system(FILE)
83 | info_line = 1
84 | FILE = "echo " + macsrc[p] + "," + macdst[p] + "," + str(ipsrc[p]) + "," + str(ipdst[p]) + "," + str(portsrc[p]) + "," + str(portdst[p]) + " " + nfile + " " + tprefix + "_ipv4_" + str(entries*mil) + "_" + dist_name + ".txt"
85 | if prot == 1:
86 | if use_case == "macsad":
87 | FILE = "echo " + str(ipdst[p]) + " " + macdst_h[p] + " 1 " + nfile + " " + tprefix + "_ipv6_" + str(entries*mil) + "_" + dist_name + ".txt"
88 | else:
89 | if info_line == 0:
90 | FILE = "echo \"src MAC, dst MAC, src IP, dst IP, src Port, dst Port\" " + "" + nfile + " " + tprefix + "_ipv6_" + str(entries*mil) + "_" + dist_name + ".txt"
91 | os.system(FILE)
92 | info_line = 1
93 | FILE = "echo " + macsrc[p] + "," + macdst[p] + "," + str(ipsrc[p]) + "," + str(ipdst[p]) + "," + str(portsrc[p]) + "," + str(portdst[p]) + " " + nfile + " " + tprefix + "_ipv6_" + str(entries*mil) + "_" + dist_name + ".txt"
94 | if prot == 2:
95 | if use_case == "macsad":
96 | FILE = "echo " + str(ipdst[p]) + " 1 " + nfile + " " + tprefix + "_vxlan_" + str(entries) + "_" + dist_name + ".txt"
97 | else:
98 | if info_line == 0:
99 | FILE = "echo \"src MAC, dst MAC, src IP, dst IP, src Port, dst Port, enc src MAC, enc dst MAC, enc src IP, enc dst IP, enc src Port, enc dst Port\" " + "" + nfile + " " + tprefix + "_vxlan_" + str(entries*mil) + "_" + dist_name + ".txt"
100 | os.system(FILE)
101 | info_line = 1
102 | FILE = "echo " + macsrc[p] + "," + macdst[p] + "," + str(ipsrc[p]) + "," + str(ipdst[p]) + "," + str(portsrc[p]) + "," + str(4789) + macsrc_e[p] + "," + macdst_e[p] + "," + str(ipsrc_e[p]) + "," + str(ipdst_e[p]) + "," + str(portsrc_e[p]) + "," + str(portdst_e[p]) + " " + nfile + " " + tprefix + "_vxlan_" + str(entries*mil) + "_" + dist_name + ".txt"
103 | if prot == 3:
104 | if use_case == "macsad":
105 | FILE = "echo " + macsrc_h[p] + " " + str(ipsrc[p]) + " " + str(ipdst[p]) + " 1 " + nfile + " " + tprefix + "_gre_" + str(entries) + "_" + dist_name + ".txt"
106 | else:
107 | if info_line == 0:
108 | FILE = "echo \"src MAC, dst MAC, src IP, dst IP, src Port, dst Port, enc src MAC, enc dst MAC, enc src IP, enc dst IP, enc src Port, enc dst Port\" " + "" + nfile + " " + tprefix + "_gre_" + str(entries*mil) + "_" + dist_name + ".txt"
109 | os.system(FILE)
110 | info_line = 1
111 | FILE = "echo " + macsrc[p] + "," + macdst[p] + "," + str(ipsrc[p]) + "," + str(ipdst[p]) + "," + str(portsrc[p]) + "," + str(portdst[p]) + macsrc_e[p] + "," + macdst_e[p] + "," + str(ipsrc_e[p]) + "," + str(ipdst_e[p]) + "," + str(portsrc_e[p]) + "," + str(portdst_e[p]) + " " + nfile + " " + tprefix + "_gre_" + str(entries*mil) + "_" + dist_name + ".txt"
112 | if prot == 4:
113 | if info_line == 0:
114 | FILE = "echo \"src MAC, dst MAC\" " + "" + nfile + " " + tprefix + "_l2_" + str(entries*mil) + "_" + dist_name + ".txt"
115 | os.system(FILE)
116 | info_line = 1
117 | FILE = "echo " + macsrc[p] + "," + macdst[p] + " " + nfile + " " + tprefix + "_l2_" + str(entries*mil) + "_" + dist_name + ".txt"
118 | cfile = 1
119 | os.system(FILE)
120 | return cfile
121 |
122 | def remove_copy_pcap(fprefix, prot, entries, dist_name):
123 | if prot == 0:
124 | rem = "rm %s_ipv4_%d_%s_*" % (fprefix, entries, dist_name)
125 | if prot == 1:
126 | rem = "rm %s_ipv6_%d_%s_*" % (fprefix, entries, dist_name)
127 | if prot == 2:
128 | rem = "rm %s_vxlan_%d_%s_*" % (fprefix, entries, dist_name)
129 | if prot == 3:
130 | rem = "rm %s_gre_%d_%s_*" % (fprefix, entries, dist_name)
131 | if prot == 4:
132 | rem = "rm %s_l2_%d_%s_*" % (fprefix, entries, dist_name)
133 | os.system(rem)
134 | return
135 |
136 | def create_pkt_hdrs(protoName, p, macdst, macsrc, ipdst, ipsrc, portdst, portsrc, tra, macdst_e, macsrc_e, ipdst_e, ipsrc_e, portdst_e, portsrc_e):
137 | if protoName == "ipv4":
138 | if tra == 0:
139 | pkt_hdr = Ether(dst=macdst[p],src=macsrc[p])/IP(dst=ipdst[p],src=ipsrc[p])/TCP(dport=portdst[p],sport=portsrc[p])
140 | else:
141 | pkt_hdr = Ether(dst=macdst[p],src=macsrc[p])/IP(dst=ipdst[p],src=ipsrc[p])/UDP(dport=portdst[p],sport=portsrc[p])
142 | elif protoName == "ipv6":
143 | #ipv6 # If we dont use TCP/UDP, why this if clause is here?
144 | if tra == 0:
145 | pkt_hdr = Ether(dst=macdst[p],src=macsrc[p])/IPv6(dst=ipdst[p],src=ipsrc[p])
146 | else:
147 | pkt_hdr = Ether(dst=macdst[p],src=macsrc[p])/IPv6(dst=ipdst[p],src=ipsrc[p])
148 | elif protoName == "vxlan":
149 | pkt_hdr = Ether(dst=macdst[p],src=macsrc[p])/IP(dst=ipdst[p],src=ipsrc[p])/UDP(sport=portdst[p],dport=4789)/VXLAN(vni=100)/Ether(dst=macdst_e[p],src=macsrc_e[p])/IP(dst=ipdst_e[p],src=ipsrc_e[p])/TCP(dport=portdst_e[p],sport=portsrc_e[p])
150 | elif protoName == "gre":
151 | if tra == 0:
152 | pkt_hdr = Ether(dst=macdst[p],src=macsrc[p])/IP(dst=ipdst[p],src=ipsrc[p])/GRE()/IP(dst=ipdst[p],src=ipsrc[p])/TCP(dport=portdst[p], sport=portsrc[p])
153 | else:
154 | pkt_hdr = Ether(dst=macdst[p],src=macsrc[p])/IP(dst=ipdst[p],src=ipsrc[p])/GRE()/IP(dst=ipdst[p],src=ipsrc[p])/UDP(dport=portdst[p], sport=portsrc[p])
155 | elif protoName == "l2":
156 | pkt_hdr = Ether(dst=macdst[p],src=macsrc[p])
157 |
158 | return pkt_hdr
159 |
160 | class create_pkt:
161 |
162 | def __init__(self, name):
163 | self.pkts = []
164 |
165 |
166 | def pkt_gen(self, entries, pkt_size_list, macdst, macsrc, ipdst, ipsrc, portdst, portsrc, protoID, protoName, tra, pname_arg, macdst_e, macsrc_e, ipdst_e, ipsrc_e, portdst_e, portsrc_e, use_case, usr_data, macsrc_h, macdst_h, dist_name, performance):
167 |
168 | mil = 1
169 | if entries == 1000000:
170 | entries = 10000
171 | mil = 100
172 | f = 0
173 | filenames = []
174 | first = 0
175 |
176 | #Enable performance sizes
177 | if performance == True:
178 | pkt_size_list = pkt_size_list_performance
179 |
180 | #Set the PCAP and Trace names:
181 | if pname_arg == "noname":
182 | pprefix = "./PCAP/nfpa.trPR"
183 | tprefix = "./PCAP/trace_trPR"
184 | else:
185 | pprefix = "./PCAP/" + pname_arg
186 | tprefix = "./PCAP/" + pname_arg
187 |
188 | # usr_data = "1234"
189 | cfile = 0
190 | for val in pkt_size_list:
191 | pkt_size_proto = 82 if ((protoName=="gre") & (val < 82)) else (114 if ((protoName=="vxlan") & (val < 114)) else val)
192 | pkt_wsize_proto = pkt_size_proto - 4
193 | for j in range(0, mil):
194 | for p in range(0, entries):
195 |
196 | pkt_tmp = create_pkt_hdrs(protoName, p, macdst, macsrc, ipdst, ipsrc, portdst, portsrc, tra, macdst_e, macsrc_e, ipdst_e, ipsrc_e, portdst_e, portsrc_e)
197 |
198 | # print "pkt_wsize_list %d, pkt_tmp len %d, rand string length %d" %(pkt_wsize_list[i], len(pkt_tmp), pkt_wsize_list[i]-len(pkt_tmp))
199 | if (usr_data==""):
200 | self.pkts.append(pkt_tmp/Raw(RandString(size=(pkt_wsize_proto-len(pkt_tmp)))))
201 | else:
202 | pkt_tmp = pkt_tmp/Raw(load=usr_data)
203 | self.pkts.append(pkt_tmp) if (len(pkt_tmp) >= pkt_wsize_proto) else (self.pkts.append(pkt_tmp/Raw(RandString(size=(pkt_wsize_proto-len(pkt_tmp))))))
204 | pkt_size_proto = len(pkt_tmp) + 4
205 |
206 | if f == 0:
207 | cfile = create_trace(protoID, macsrc, macdst, ipsrc, ipdst, portsrc, portdst, entries, mil, p, macsrc_e, macdst_e, ipsrc_e, ipdst_e, portsrc_e, portdst_e, use_case, macsrc_h, macdst_h, tprefix, dist_name, cfile)
208 |
209 | pname = "%s_%s_%d_%s_%d.%dbytes.pcap" % (pprefix, protoName, entries, dist_name, j, pkt_size_proto)
210 | namef = "%s_%s_%d_%s.%dbytes.pcap" % (pprefix, protoName, entries*mil, dist_name, pkt_size_proto)
211 |
212 | filenames.append(pname)
213 |
214 | #Create partials PCAPs
215 | wrpcap(pname,self.pkts)
216 | del self.pkts[:] #Don't delete this line
217 |
218 | #Create final PCAP
219 | with open(namef, 'w') as outfile:
220 | for fname in filenames:
221 | with open(fname) as infile:
222 | if first == 1:
223 | infile.seek(24)
224 | first = 1
225 | for line in infile:
226 | outfile.write(line)
227 | first = 0
228 | del filenames[:]
229 | f = 1
230 |
231 | #Remove temporary files
232 | remove_copy_pcap(pprefix, protoID, entries, dist_name)
233 |
--------------------------------------------------------------------------------
/src/settings.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # BSD 3-Clause License
4 |
5 | # Copyright (c) 2018, Fabricio Rodriguez, UNICAMP, Brazil
6 | # All rights reserved.
7 |
8 | # Redistribution and use in source and binary forms, with or without
9 | # modification, are permitted provided that the following conditions are met:
10 |
11 | # * Redistributions of source code must retain the above copyright notice, this
12 | # list of conditions and the following disclaimer.
13 |
14 | # * Redistributions in binary form must reproduce the above copyright notice,
15 | # this list of conditions and the following disclaimer in the documentation
16 | # and/or other materials provided with the distribution.
17 |
18 | # * Neither the name of the copyright holder nor the names of its
19 | # contributors may be used to endorse or promote products derived from
20 | # this software without specific prior written permission.
21 |
22 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
26 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 |
33 | def init():
34 | global header_list_len
35 | global header_list_val
36 | header_list_len = []
37 | header_list_val = []
--------------------------------------------------------------------------------
/src/type.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # BSD 3-Clause License
4 |
5 | # Copyright (c) 2018, Fabricio Rodriguez, UNICAMP, Brazil
6 | # All rights reserved.
7 |
8 | # Redistribution and use in source and binary forms, with or without
9 | # modification, are permitted provided that the following conditions are met:
10 |
11 | # * Redistributions of source code must retain the above copyright notice, this
12 | # list of conditions and the following disclaimer.
13 |
14 | # * Redistributions in binary form must reproduce the above copyright notice,
15 | # this list of conditions and the following disclaimer in the documentation
16 | # and/or other materials provided with the distribution.
17 |
18 | # * Neither the name of the copyright holder nor the names of its
19 | # contributors may be used to endorse or promote products derived from
20 | # this software without specific prior written permission.
21 |
22 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
26 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 |
33 |
34 | import string
35 | import sys
36 | import random
37 | from random import shuffle
38 |
39 | # The pkt_type Class defines the type of pkts to create, the transport protocol UDP/TCP
40 | # and defines the distribution of the data
41 | #
42 | # Protocols -p
43 | # 0 IPv4
44 | # 1 IPv6
45 | # 2 VXLAN
46 | # 3 GRE
47 | # 4 L2
48 | #
49 | # Transport Protol -t
50 | # 0 TCP
51 | # 1 UDP
52 | #
53 | # Random IP, MAC, PORT
54 | # 0 random
55 | # 1 simple
56 |
57 | ethernet = [[],[]]
58 | ipv4 = [[],[]]
59 | ipv4_2 = [[],[]]
60 | ipv6 = [[],[]]
61 | udp = [[],[]]
62 | tcp = [[],[]]
63 | vxlan = [[],[]]
64 | arp_t = [[],[]]
65 | arp_ipv4_t = [[],[]]
66 | gre = [[],[]]
67 |
68 | class pkt_type:
69 |
70 | def __init__(self, name):
71 | self.name = name
72 | self.pktsize = []
73 | self.protoID = 0
74 | self.protoName = ""
75 | self.tra = 0
76 | self.ranip = 1
77 | self.ranmac = 1
78 | self.ranport = 1
79 | self.dist_name = "simple"
80 | self.protocol = ""
81 | self.transport = ""
82 |
83 | def get_prot_type(self, data, tra):
84 | if data == 'ipv6':
85 | self.protoID = 1
86 | self.protoName = data
87 | elif data == 'vxlan':
88 | self.protoID = 2
89 | self.protoName = data
90 | elif data == 'gre':
91 | self.protoID = 3
92 | self.protoName = data
93 | elif data == 'l2':
94 | self.protoID = 4
95 | self.protoName = data
96 | else: #ipv4
97 | self.protoID = 0
98 | self.protoName = "ipv4"
99 |
100 | def get_tra_type(self, data):
101 | if data == 'udp':
102 | self.tra = 1
103 | else:
104 | self.tra = 0
105 |
106 | def get_random(self, data):
107 | if data[0] == True:
108 | self.ranip = 0
109 | ipname = "rip"
110 | else:
111 | self.ranip = 1
112 | ipname = "sip"
113 | if data[1] == True:
114 | self.ranmac = 0
115 | macname = "rmac"
116 | else:
117 | self.ranmac = 1
118 | macname = "smac"
119 | if data[2] == True:
120 | self.ranport = 0
121 | portname = "rport"
122 | else:
123 | self.ranport = 1
124 | portname = "sport"
125 |
126 | if data[0] == True and data[1] == True and data[2] == True:
127 | self.dist_name = "random"
128 | elif data[0] == False and data[1] == False and data[2] == False:
129 | self.dist_name = "simple"
130 | else:
131 | self.dist_name = ipname + "_" + macname + "_" + portname
132 |
133 | def get_prot(self, header_list_len, header_list_val):
134 |
135 | header_list = ['l2', 'arp', 'arp', 'ipv4', 'ipv4', 'ipv6', 'udp', 'tcp', 'vxlan', 'gre']
136 |
137 | ethernet[0] = ['48', '48', '16']
138 | ethernet[1] = ['dstAddr', 'srcAddr', 'etherType']
139 |
140 | ipv4[0] = ['4', '4', '8', '16', '16', '3', '13', '8', '8', '16', '32', '32']
141 | ipv4[1] = ['version', 'ihl', 'diffserv', 'totalLen', 'identification', 'frag', 'Offset', 'ttl', 'protocol', 'hdrChecksum', 'srcAddr', 'dstAddr']
142 |
143 | ipv4_2[0] = ['8', '8', '16', '16', '16', '8', '8', '16', '32', '32']
144 | ipv4_2[1] = ['versionIhl', 'diffserv', 'totalLen', 'identification', 'fragOffset', 'ttl', 'protocol', 'hdrChecksum', 'srcAddr', 'dstAddr']
145 |
146 | ipv6[0] = ['4', '8', '20', '16', '8', '8', '128', '128']
147 | ipv6[1] = ['version', 'trafficClass', 'flowLabel', 'payloadLen', 'nextHdr', 'hopLimit', 'srcAddr', 'dstAddr']
148 |
149 | udp[0] = ['16', '16', '16', '16']
150 | udp[1] = ['srcPort', 'dstPort', 'length_', 'checksum']
151 |
152 | tcp[0] = ['16', '16', '32', '32', '4', '4', '8', '16', '16', '16']
153 | tcp[1] = ['srcPort', 'dstPort', 'seqNo', 'ackNo', 'dataOffset', 'res', 'flags', 'window', 'checksum', 'urgentPtr']
154 |
155 | vxlan[0] = ['8', '24', '24', '8']
156 | vxlan[1] = ['flags', 'reserved', 'vni', 'reserved2']
157 |
158 | arp_t[0] = ['16', '16', '8', '8', '16']
159 | arp_t[1] = ['htype', 'ptype', 'hlength', 'plength', 'opcode']
160 |
161 | arp_ipv4_t[0] = ['16', '16', '8', '8', '16']
162 | arp_ipv4_t[1] = ['htype', 'ptype', 'hlength', 'plength', 'opcode']
163 |
164 | gre[0] = ['1', '1', '1', '1', '1', '3', '5', '3', '16']
165 | gre[1] = ['C', 'R', 'K', 'S', 's', 'recurse', 'flags', 'ver', 'proto']
166 |
167 | headers = [ethernet, arp_t, arp_ipv4_t, ipv4, ipv4_2, ipv6, udp, tcp, vxlan, gre]
168 |
169 | for val in xrange(0,len(headers)):
170 | for hed in xrange(0,len(header_list_len)):
171 | if header_list_len[hed] == headers[val][0]:
172 | self.protocol = header_list[val]
173 | if self.protocol == 'tcp':
174 | self.transport = 'tcp'
175 | elif self.protocol == 'udp':
176 | self.transport = 'udp'
177 |
--------------------------------------------------------------------------------