├── .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 | [![Build Status](https://travis-ci.org/intrig-unicamp/BB-Gen.svg?branch=master)](https://travis-ci.org/intrig-unicamp/BB-Gen) 8 | [![License: BSD v3](https://img.shields.io/badge/License-BSD%20v3-blue.svg)](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
Fabricio Rodríguez](https://github.com/ecwolf)
(frodri@dca.fee.unicamp.br)
[💻](https://github.com/intrig-unicamp/BB-Gen/commits?author=ecwolf) 🔌 👀 | [Gyanesh Patra
Gyanesh Patra](https://github.com/c3m3gyanesh)
(gyanesh@dca.fee.unicamp.br)
[💻](https://github.com/intrig-unicamp/BB-Gen/commits?author=c3m3gyanesh) 🔌 👀 | [Christian Esteve Rothenberg
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 | --------------------------------------------------------------------------------