SIGCOMM 2019 Tutorial Edits (#272)
* Updated the utils/run_exercise.py to allow exercises to customize host configuration from the topology.json file. Now hosts and `ping` each other in the basic exercise. Other Linux utilities should work as well (e.g. iperf). ``` mininet> h1 ping h2 PING 10.0.2.2 (10.0.2.2) 56(84) bytes of data. 64 bytes from 10.0.2.2: icmp_seq=1 ttl=62 time=3.11 ms 64 bytes from 10.0.2.2: icmp_seq=2 ttl=62 time=2.34 ms 64 bytes from 10.0.2.2: icmp_seq=3 ttl=62 time=2.15 ms ^C --- 10.0.2.2 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2003ms rtt min/avg/max/mdev = 2.153/2.540/3.118/0.416 ms mininet> pingall *** Ping: testing ping reachability h1 -> h2 h3 h2 -> h1 h3 h3 -> h1 h2 *** Results: 0% dropped (6/6 received) ``` Only updated basic exercise, still need to update other exercises. Also, updated the root-bootstrap.sh because I was running into issues with latest version of vagrant. * Accidentially added the solution to the basic exercise in the previous commit. Undoing that here ... * Updated the topology.json file and table entries for the basic_tunnel exercise. * Updated P4Runtime exercise with new topology and table entries. * Fixed MAC addresses in P4Runtime exercise. It is working now. * Fixed MAC addresses in P4Runtime exercise starter code * Updated ECN exercise to use new topology.json file. Updated the table entries / MAC addresses as well. * Updated the topology.json file and table entries for the MRI exercise. * Updated source_routing exercise with new topology file and verified correct functionality. * Updated load_balance exercise with new topology. * Moved basic exercise triangle topology into a separate folder * Added new topology for the basic exercise: a single pod of a fat-tree. * Updated Makefiles and run_exercise.py to allow exercises to configure each switch with a different P4 program. This is mainly for the firewall exercise. * Updated Makefiles of project to work with new utils/Makefile * Updated load_balance and p4runtime exercise Makefiles * Initial commit of the firewall exercise, which is a simple stateful firewall that uses a bloom filter. Need to update README files * Initial commit of the path_monitor exercise. It is working but still need to update the README and figure out what we want the tutorial attendees to implement. * Updated README file in firewall exercise. Also removed the bits from the starter code that we want the tutorial attendees to implement * Renamed path_monitor exercise to link_monitor * Updated the README in the link_monitor exercise and removed the bits from the starter code that we want the tutorial attendees to implement. * Updated README for the firewall exercise * Adding pod-topo.png image to basic exercise * Added firewall-topo.png image to firewall exercise * Added link-monitor-topo.png to link_monitor exercise * Updated README files to point to topology images * Updated top-level README to point to new exercises. * Fixed link for VM dependencies script in README * Updated bmv2/pi/p4c commits * Updated README files for exercises to fix some typos and added a note about the V1Model architecture. * Added a note about food for thought in the link_monitor README * Updated the firewall.p4 program to use two register arrays rather than a single one. This is to make the design more portable to high line rate devices which can only support a single access to each register array. * Minor fix to firewall exercise to get rid of compiler warning. * Updated comment in firewall exercise. * Minor (typo) fixes in the firewall ReadMe * More info in firewall exercise ReadMe step 2 * Updated firewall.p4 to reuse direction variable * More testing steps, small fixes in firewall exercise Readme * Added food for thought to firewall Readme * Cosmetic fixes to firewall ReadMe * Made a few updates to the basic exercise README and added more details to the link_monitor exercise README. Also added a command to install grip when provisioning the VM. This could be useful for rendering the markdown README files offline. * Updated top level README so it can be merged into the master branch. * Moved cmd to install grip from root-bootstrap to user-bootstrap
This commit is contained in:
5
exercises/firewall/Makefile
Normal file
5
exercises/firewall/Makefile
Normal file
@@ -0,0 +1,5 @@
|
||||
BMV2_SWITCH_EXE = simple_switch_grpc
|
||||
TOPO = pod-topo/topology.json
|
||||
DEFAULT_PROG = basic.p4
|
||||
|
||||
include ../../utils/Makefile
|
||||
|
After Width: | Height: | Size: 121 B |
215
exercises/firewall/README.md
Normal file
215
exercises/firewall/README.md
Normal file
@@ -0,0 +1,215 @@
|
||||
# Implementing A Basic Stateful Firewall
|
||||
|
||||
## Introduction
|
||||
|
||||
The objective of this exercise is to write a P4 program that
|
||||
implements a simple stateful firewall. To do this, we will use
|
||||
a bloom filter. This exercise builds upon the basic exercise
|
||||
so be sure to complete that one before trying this one.
|
||||
|
||||
We will use the pod-topology for this exercise, which consists of
|
||||
four hosts connected to four switches, which are wired up as they
|
||||
would be in a single pod of a fat tree topology.
|
||||
|
||||

|
||||
|
||||
Switch s1 will be configured with a P4 program that implements a
|
||||
simple stateful firewall (`firewall.p4`), the rest of the switches will run the
|
||||
basic IPv4 router program (`basic.p4`) from the previous exercise.
|
||||
|
||||
The firewall on s1 should have the following functionality:
|
||||
* Hosts h1 and h2 are on the internal network and can always
|
||||
connect to one another.
|
||||
* Hosts h1 and h2 can freely connect to h3 and h4 on the
|
||||
external network.
|
||||
* Hosts h3 and h4 can only reply to connections once they have been
|
||||
established from either h1 or h2, but cannot initiate new
|
||||
connections to hosts on the internal network.
|
||||
|
||||
**Note**: This stateful firewall is implemented 100% in the dataplane
|
||||
using a simple bloom filter. Thus there is some probability of
|
||||
hash collisions that would let unwanted flows to pass through.
|
||||
|
||||
Our P4 program will be written for the V1Model architecture implemented
|
||||
on P4.org's bmv2 software switch. The architecture file for the V1Model
|
||||
can be found at: /usr/local/share/p4c/p4include/v1model.p4. This file
|
||||
desribes the interfaces of the P4 programmable elements in the architecture,
|
||||
the supported externs, as well as the architecture's standard metadata
|
||||
fields. We encourage you to take a look at it.
|
||||
|
||||
> **Spoiler alert:** There is a reference solution in the `solution`
|
||||
> sub-directory. Feel free to compare your implementation to the
|
||||
> reference.
|
||||
|
||||
## Step 1: Run the (incomplete) starter code
|
||||
|
||||
The directory with this README also contains a skeleton P4 program,
|
||||
`firewall.p4`. Your job will be to extend this skeleton program to
|
||||
properly implement the firewall.
|
||||
|
||||
Before that, let's compile the incomplete `firewall.p4` and bring
|
||||
up a switch in Mininet to test its behavior.
|
||||
|
||||
1. In your shell, run:
|
||||
```bash
|
||||
make run
|
||||
```
|
||||
This will:
|
||||
* compile `firewall.p4`, and
|
||||
* start the pod-topo in Mininet and configure all switches with
|
||||
the appropriate P4 program + table entries, and
|
||||
* configure all hosts with the commands listed in
|
||||
[pod-topo/topology.json](./pod-topo/topology.json)
|
||||
|
||||
2. You should now see a Mininet command prompt. Try to run some iperf
|
||||
TCP flows between the hosts. TCP flows within the internal
|
||||
network should work:
|
||||
```bash
|
||||
mininet> iperf h1 h2
|
||||
```
|
||||
|
||||
TCP flows from hosts in the internal network to the outside hosts
|
||||
should also work:
|
||||
```bash
|
||||
mininet> iperf h1 h3
|
||||
```
|
||||
|
||||
TCP flows from the outside hosts to hosts inside the
|
||||
internal network should NOT work. However, since the firewall is not
|
||||
implemented yet, the following should work:
|
||||
```bash
|
||||
mininet> iperf h3 h1
|
||||
```
|
||||
|
||||
3. Type `exit` to leave the Mininet command line.
|
||||
Then, to stop mininet:
|
||||
```bash
|
||||
make stop
|
||||
```
|
||||
And to delete all pcaps, build files, and logs:
|
||||
```bash
|
||||
make clean
|
||||
```
|
||||
|
||||
### A note about the control plane
|
||||
|
||||
A P4 program defines a packet-processing pipeline, but the rules
|
||||
within each table are inserted by the control plane. When a rule
|
||||
matches a packet, its action is invoked with parameters supplied by
|
||||
the control plane as part of the rule.
|
||||
|
||||
In this exercise, we have already implemented the the control plane
|
||||
logic for you. As part of bringing up the Mininet instance, the
|
||||
`make` command will install packet-processing rules in the tables of
|
||||
each switch. These are defined in the `sX-runtime.json` files, where
|
||||
`X` corresponds to the switch number.
|
||||
|
||||
**Important:** We use P4Runtime to install the control plane rules. The
|
||||
content of files `sX-runtime.json` refer to specific names of tables, keys, and
|
||||
actions, as defined in the P4Info file produced by the compiler (look for the
|
||||
file `build/firewall.p4.p4info.txt` after executing `make run`). Any changes in the P4
|
||||
program that add or rename tables, keys, or actions will need to be reflected in
|
||||
these `sX-runtime.json` files.
|
||||
|
||||
## Step 2: Implement Firewall
|
||||
|
||||
The `firewall.p4` file contains a skeleton P4 program with key pieces of
|
||||
logic replaced by `TODO` comments. Your implementation should follow
|
||||
the structure given in this file --- replace each `TODO` with logic
|
||||
implementing the missing piece.
|
||||
|
||||
**High-level Approach:** We will use a bloom filter with two hash functions
|
||||
to check if a packet coming into the internal network is a part of
|
||||
an already established TCP connection. We will use two different register
|
||||
arrays for the bloom filter, each to be updated by a hash function.
|
||||
Using different register arrays makes our design amenable to high-speed
|
||||
P4 targets that typically allow only one access to a register array per packet.
|
||||
|
||||
A complete `firewall.p4` will contain the following components:
|
||||
|
||||
1. Header type definitions for Ethernet (`ethernet_t`), IPv4 (`ipv4_t`) and TCP (`tcp_t`).
|
||||
2. Parsers for Ethernet, IPv4 and TCP that populate `ethernet_t`, `ipv4_t` and `tcp_t` fields.
|
||||
3. An action to drop a packet, using `mark_to_drop()`.
|
||||
4. An action (called `compute_hashes`) to compute the bloom filter's two hashes using hash
|
||||
algorithms `crc16` and `crc32`. The hashes will be computed on the packet 5-tuple consisting
|
||||
of IPv4 source and destination addresses, source and destination port numbers and
|
||||
the IPv4 protocol type.
|
||||
5. An action (`ipv4_forward`) and a table (`ipv4_lpm`) that will perform basic
|
||||
IPv4 forwarding (adopted from `basic.p4`).
|
||||
6. An action (called `set_direction`) that will simply set a one-bit direction variable
|
||||
as per the action's parameter.
|
||||
7. A table (called `check_ports`) that will read the ingress and egress port of a packet
|
||||
(after IPv4 forwarding) and invoke `set_direction`. The direction will be set to `1`,
|
||||
if the packet is incoming into the internal network. Otherwise, the direction will be set to `0`.
|
||||
To achieve this, the file `pod-topo/s1-runtime.json` contains the appropriate control plane
|
||||
entries for the `check_ports` table.
|
||||
8. A control that will:
|
||||
1. First apply the table `ipv4_lpm` if the packet has a valid IPv4 header.
|
||||
2. Then if the TCP header is valid, apply the `check_ports` table to determine the direction.
|
||||
3. Apply the `compute_hashes` action to compute the two hash values which are the bit positions
|
||||
in the two register arrays of the bloom filter (`reg_pos_one` and `reg_pos_two`).
|
||||
When the direction is `1` i.e. the packet is incoming into the internal network,
|
||||
`compute_hashes` will be invoked by swapping the source and destination IPv4 addresses
|
||||
and the source and destination ports. This is to check against bloom filter's set bits
|
||||
when the TCP connection was initially made from the internal network.
|
||||
4. **TODO:** If the TCP packet is going out of the internal network and is a SYN packet,
|
||||
set both the bloom filter arrays at the computed bit positions (`reg_pos_one` and `reg_pos_two`).
|
||||
Else, if the TCP packet is entering the internal network,
|
||||
read both the bloom filter arrays at the computed bit positions and drop the packet if
|
||||
either is not set.
|
||||
9. A deparser that emits the Ethernet, IPv4 and TCP headers in the right order.
|
||||
10. A `package` instantiation supplied with the parser, control, and deparser.
|
||||
> In general, a package also requires instances of checksum verification
|
||||
> and recomputation controls. These are not necessary for this tutorial
|
||||
> and are replaced with instantiations of empty controls.
|
||||
|
||||
|
||||
## Step 3: Run your solution
|
||||
|
||||
Follow the instructions from Step 1. This time, the `iperf` flow between
|
||||
h3 and h1 should be blocked by the firewall.
|
||||
|
||||
### Food for thought
|
||||
|
||||
You may have noticed that in this simple stateful firewall, we are adding
|
||||
new TCP connections to the bloom filter (based on outgoing SYN packets).
|
||||
However, we are not removing them in case of TCP connection teardown
|
||||
(FIN packets). How would you implement the removal of TCP connections that are
|
||||
no longer active?
|
||||
|
||||
Things to consider:
|
||||
- Can we simply set the bloom filter array bits to `0` on
|
||||
receiving a FIN packet? What happens when there is one hash collision in
|
||||
the bloom filter arrays between two _active_ TCP connections?
|
||||
- How can we modify our bloom filter structure so that the deletion
|
||||
operation can be properly supported?
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
There are several problems that might manifest as you develop your program:
|
||||
|
||||
1. `firewall.p4` might fail to compile. In this case, `make run` will
|
||||
report the error emitted from the compiler and halt.
|
||||
|
||||
2. `firewall.p4` might compile but fail to support the control plane
|
||||
rules in the `s1-runtime.json` file that `make run` tries to install
|
||||
using P4Runtime. In this case, `make run` will report errors if control
|
||||
plane rules cannot be installed. Use these error messages to fix your
|
||||
`firewall.p4` implementation.
|
||||
|
||||
3. `firewall.p4` might compile, and the control plane rules might be
|
||||
installed, but the switch might not process packets in the desired
|
||||
way. The `logs/sX.log` files contain detailed logs that describe
|
||||
how each switch processes each packet. The output is detailed and can
|
||||
help pinpoint logic errors in your implementation.
|
||||
|
||||
#### Cleaning up Mininet
|
||||
|
||||
In the latter two cases above, `make run` may leave a Mininet instance
|
||||
running in the background. Use the following command to clean up
|
||||
these instances:
|
||||
|
||||
```bash
|
||||
make stop
|
||||
```
|
||||
|
||||
176
exercises/firewall/basic.p4
Normal file
176
exercises/firewall/basic.p4
Normal file
@@ -0,0 +1,176 @@
|
||||
/* -*- P4_16 -*- */
|
||||
#include <core.p4>
|
||||
#include <v1model.p4>
|
||||
|
||||
const bit<16> TYPE_IPV4 = 0x800;
|
||||
|
||||
/*************************************************************************
|
||||
*********************** H E A D E R S ***********************************
|
||||
*************************************************************************/
|
||||
|
||||
typedef bit<9> egressSpec_t;
|
||||
typedef bit<48> macAddr_t;
|
||||
typedef bit<32> ip4Addr_t;
|
||||
|
||||
header ethernet_t {
|
||||
macAddr_t dstAddr;
|
||||
macAddr_t srcAddr;
|
||||
bit<16> etherType;
|
||||
}
|
||||
|
||||
header ipv4_t {
|
||||
bit<4> version;
|
||||
bit<4> ihl;
|
||||
bit<8> diffserv;
|
||||
bit<16> totalLen;
|
||||
bit<16> identification;
|
||||
bit<3> flags;
|
||||
bit<13> fragOffset;
|
||||
bit<8> ttl;
|
||||
bit<8> protocol;
|
||||
bit<16> hdrChecksum;
|
||||
ip4Addr_t srcAddr;
|
||||
ip4Addr_t dstAddr;
|
||||
}
|
||||
|
||||
struct metadata {
|
||||
/* empty */
|
||||
}
|
||||
|
||||
struct headers {
|
||||
ethernet_t ethernet;
|
||||
ipv4_t ipv4;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
*********************** P A R S E R ***********************************
|
||||
*************************************************************************/
|
||||
|
||||
parser MyParser(packet_in packet,
|
||||
out headers hdr,
|
||||
inout metadata meta,
|
||||
inout standard_metadata_t standard_metadata) {
|
||||
|
||||
state start {
|
||||
transition parse_ethernet;
|
||||
}
|
||||
|
||||
state parse_ethernet {
|
||||
packet.extract(hdr.ethernet);
|
||||
transition select(hdr.ethernet.etherType) {
|
||||
TYPE_IPV4: parse_ipv4;
|
||||
default: accept;
|
||||
}
|
||||
}
|
||||
|
||||
state parse_ipv4 {
|
||||
packet.extract(hdr.ipv4);
|
||||
transition accept;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
************ C H E C K S U M V E R I F I C A T I O N *************
|
||||
*************************************************************************/
|
||||
|
||||
control MyVerifyChecksum(inout headers hdr, inout metadata meta) {
|
||||
apply { }
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
************** I N G R E S S P R O C E S S I N G *******************
|
||||
*************************************************************************/
|
||||
|
||||
control MyIngress(inout headers hdr,
|
||||
inout metadata meta,
|
||||
inout standard_metadata_t standard_metadata) {
|
||||
action drop() {
|
||||
mark_to_drop(standard_metadata);
|
||||
}
|
||||
|
||||
action ipv4_forward(macAddr_t dstAddr, egressSpec_t port) {
|
||||
standard_metadata.egress_spec = port;
|
||||
hdr.ethernet.srcAddr = hdr.ethernet.dstAddr;
|
||||
hdr.ethernet.dstAddr = dstAddr;
|
||||
hdr.ipv4.ttl = hdr.ipv4.ttl - 1;
|
||||
}
|
||||
|
||||
table ipv4_lpm {
|
||||
key = {
|
||||
hdr.ipv4.dstAddr: lpm;
|
||||
}
|
||||
actions = {
|
||||
ipv4_forward;
|
||||
drop;
|
||||
NoAction;
|
||||
}
|
||||
size = 1024;
|
||||
default_action = drop();
|
||||
}
|
||||
|
||||
apply {
|
||||
if (hdr.ipv4.isValid()) {
|
||||
ipv4_lpm.apply();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
**************** E G R E S S P R O C E S S I N G *******************
|
||||
*************************************************************************/
|
||||
|
||||
control MyEgress(inout headers hdr,
|
||||
inout metadata meta,
|
||||
inout standard_metadata_t standard_metadata) {
|
||||
apply { }
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
************* C H E C K S U M C O M P U T A T I O N **************
|
||||
*************************************************************************/
|
||||
|
||||
control MyComputeChecksum(inout headers hdr, inout metadata meta) {
|
||||
apply {
|
||||
update_checksum(
|
||||
hdr.ipv4.isValid(),
|
||||
{ hdr.ipv4.version,
|
||||
hdr.ipv4.ihl,
|
||||
hdr.ipv4.diffserv,
|
||||
hdr.ipv4.totalLen,
|
||||
hdr.ipv4.identification,
|
||||
hdr.ipv4.flags,
|
||||
hdr.ipv4.fragOffset,
|
||||
hdr.ipv4.ttl,
|
||||
hdr.ipv4.protocol,
|
||||
hdr.ipv4.srcAddr,
|
||||
hdr.ipv4.dstAddr },
|
||||
hdr.ipv4.hdrChecksum,
|
||||
HashAlgorithm.csum16);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
*********************** D E P A R S E R *******************************
|
||||
*************************************************************************/
|
||||
|
||||
control MyDeparser(packet_out packet, in headers hdr) {
|
||||
apply {
|
||||
packet.emit(hdr.ethernet);
|
||||
packet.emit(hdr.ipv4);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
*********************** S W I T C H *******************************
|
||||
*************************************************************************/
|
||||
|
||||
V1Switch(
|
||||
MyParser(),
|
||||
MyVerifyChecksum(),
|
||||
MyIngress(),
|
||||
MyEgress(),
|
||||
MyComputeChecksum(),
|
||||
MyDeparser()
|
||||
) main;
|
||||
BIN
exercises/firewall/firewall-topo.png
Normal file
BIN
exercises/firewall/firewall-topo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 171 KiB |
276
exercises/firewall/firewall.p4
Normal file
276
exercises/firewall/firewall.p4
Normal file
@@ -0,0 +1,276 @@
|
||||
/* -*- P4_16 -*- */
|
||||
#include <core.p4>
|
||||
#include <v1model.p4>
|
||||
|
||||
/* CONSTANTS */
|
||||
|
||||
const bit<16> TYPE_IPV4 = 0x800;
|
||||
const bit<8> TYPE_TCP = 6;
|
||||
|
||||
#define BLOOM_FILTER_ENTRIES 4096
|
||||
#define BLOOM_FILTER_BIT_WIDTH 1
|
||||
|
||||
/*************************************************************************
|
||||
*********************** H E A D E R S ***********************************
|
||||
*************************************************************************/
|
||||
|
||||
typedef bit<9> egressSpec_t;
|
||||
typedef bit<48> macAddr_t;
|
||||
typedef bit<32> ip4Addr_t;
|
||||
|
||||
header ethernet_t {
|
||||
macAddr_t dstAddr;
|
||||
macAddr_t srcAddr;
|
||||
bit<16> etherType;
|
||||
}
|
||||
|
||||
header ipv4_t {
|
||||
bit<4> version;
|
||||
bit<4> ihl;
|
||||
bit<8> diffserv;
|
||||
bit<16> totalLen;
|
||||
bit<16> identification;
|
||||
bit<3> flags;
|
||||
bit<13> fragOffset;
|
||||
bit<8> ttl;
|
||||
bit<8> protocol;
|
||||
bit<16> hdrChecksum;
|
||||
ip4Addr_t srcAddr;
|
||||
ip4Addr_t dstAddr;
|
||||
}
|
||||
|
||||
header tcp_t{
|
||||
bit<16> srcPort;
|
||||
bit<16> dstPort;
|
||||
bit<32> seqNo;
|
||||
bit<32> ackNo;
|
||||
bit<4> dataOffset;
|
||||
bit<4> res;
|
||||
bit<1> cwr;
|
||||
bit<1> ece;
|
||||
bit<1> urg;
|
||||
bit<1> ack;
|
||||
bit<1> psh;
|
||||
bit<1> rst;
|
||||
bit<1> syn;
|
||||
bit<1> fin;
|
||||
bit<16> window;
|
||||
bit<16> checksum;
|
||||
bit<16> urgentPtr;
|
||||
}
|
||||
|
||||
struct metadata {
|
||||
/* empty */
|
||||
}
|
||||
|
||||
struct headers {
|
||||
ethernet_t ethernet;
|
||||
ipv4_t ipv4;
|
||||
tcp_t tcp;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
*********************** P A R S E R ***********************************
|
||||
*************************************************************************/
|
||||
|
||||
parser MyParser(packet_in packet,
|
||||
out headers hdr,
|
||||
inout metadata meta,
|
||||
inout standard_metadata_t standard_metadata) {
|
||||
|
||||
state start {
|
||||
transition parse_ethernet;
|
||||
}
|
||||
|
||||
state parse_ethernet {
|
||||
packet.extract(hdr.ethernet);
|
||||
transition select(hdr.ethernet.etherType) {
|
||||
TYPE_IPV4: parse_ipv4;
|
||||
default: accept;
|
||||
}
|
||||
}
|
||||
|
||||
state parse_ipv4 {
|
||||
packet.extract(hdr.ipv4);
|
||||
transition select(hdr.ipv4.protocol){
|
||||
TYPE_TCP: tcp;
|
||||
default: accept;
|
||||
}
|
||||
}
|
||||
|
||||
state tcp {
|
||||
packet.extract(hdr.tcp);
|
||||
transition accept;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
************ C H E C K S U M V E R I F I C A T I O N *************
|
||||
*************************************************************************/
|
||||
|
||||
control MyVerifyChecksum(inout headers hdr, inout metadata meta) {
|
||||
apply { }
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
************** I N G R E S S P R O C E S S I N G *******************
|
||||
*************************************************************************/
|
||||
|
||||
control MyIngress(inout headers hdr,
|
||||
inout metadata meta,
|
||||
inout standard_metadata_t standard_metadata) {
|
||||
|
||||
register<bit<BLOOM_FILTER_BIT_WIDTH>>(BLOOM_FILTER_ENTRIES) bloom_filter_1;
|
||||
register<bit<BLOOM_FILTER_BIT_WIDTH>>(BLOOM_FILTER_ENTRIES) bloom_filter_2;
|
||||
bit<32> reg_pos_one; bit<32> reg_pos_two;
|
||||
bit<1> reg_val_one; bit<1> reg_val_two;
|
||||
bit<1> direction;
|
||||
|
||||
action drop() {
|
||||
mark_to_drop(standard_metadata);
|
||||
}
|
||||
|
||||
action compute_hashes(ip4Addr_t ipAddr1, ip4Addr_t ipAddr2, bit<16> port1, bit<16> port2){
|
||||
//Get register position
|
||||
hash(reg_pos_one, HashAlgorithm.crc16, (bit<32>)0, {ipAddr1,
|
||||
ipAddr2,
|
||||
port1,
|
||||
port2,
|
||||
hdr.ipv4.protocol},
|
||||
(bit<32>)BLOOM_FILTER_ENTRIES);
|
||||
|
||||
hash(reg_pos_two, HashAlgorithm.crc32, (bit<32>)0, {ipAddr1,
|
||||
ipAddr2,
|
||||
port1,
|
||||
port2,
|
||||
hdr.ipv4.protocol},
|
||||
(bit<32>)BLOOM_FILTER_ENTRIES);
|
||||
}
|
||||
|
||||
action ipv4_forward(macAddr_t dstAddr, egressSpec_t port) {
|
||||
standard_metadata.egress_spec = port;
|
||||
hdr.ethernet.srcAddr = hdr.ethernet.dstAddr;
|
||||
hdr.ethernet.dstAddr = dstAddr;
|
||||
hdr.ipv4.ttl = hdr.ipv4.ttl - 1;
|
||||
}
|
||||
|
||||
table ipv4_lpm {
|
||||
key = {
|
||||
hdr.ipv4.dstAddr: lpm;
|
||||
}
|
||||
actions = {
|
||||
ipv4_forward;
|
||||
drop;
|
||||
NoAction;
|
||||
}
|
||||
size = 1024;
|
||||
default_action = drop();
|
||||
}
|
||||
|
||||
action set_direction(bit<1> dir) {
|
||||
direction = dir;
|
||||
}
|
||||
|
||||
table check_ports {
|
||||
key = {
|
||||
standard_metadata.ingress_port: exact;
|
||||
standard_metadata.egress_spec: exact;
|
||||
}
|
||||
actions = {
|
||||
set_direction;
|
||||
NoAction;
|
||||
}
|
||||
size = 1024;
|
||||
default_action = NoAction();
|
||||
}
|
||||
|
||||
apply {
|
||||
if (hdr.ipv4.isValid()){
|
||||
ipv4_lpm.apply();
|
||||
if (hdr.tcp.isValid()){
|
||||
direction = 0; // default
|
||||
if (check_ports.apply().hit) {
|
||||
// test and set the bloom filter
|
||||
if (direction == 0) {
|
||||
compute_hashes(hdr.ipv4.srcAddr, hdr.ipv4.dstAddr, hdr.tcp.srcPort, hdr.tcp.dstPort);
|
||||
}
|
||||
else {
|
||||
compute_hashes(hdr.ipv4.dstAddr, hdr.ipv4.srcAddr, hdr.tcp.dstPort, hdr.tcp.srcPort);
|
||||
}
|
||||
// Packet comes from internal network
|
||||
if (direction == 0){
|
||||
// TODO: this packet is part of an outgoing TCP connection.
|
||||
// We need to set the bloom filter if this is a SYN packet
|
||||
// E.g. bloom_filter_1.write(<index>, <value>);
|
||||
}
|
||||
// Packet comes from outside
|
||||
else if (direction == 1){
|
||||
// TODO: this packet is part of an incomming TCP connection.
|
||||
// We need to check if this packet is allowed to pass by reading the bloom filter
|
||||
// E.g. bloom_filter_1.read(<value>, <index>);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
**************** E G R E S S P R O C E S S I N G *******************
|
||||
*************************************************************************/
|
||||
|
||||
control MyEgress(inout headers hdr,
|
||||
inout metadata meta,
|
||||
inout standard_metadata_t standard_metadata) {
|
||||
apply { }
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
************* C H E C K S U M C O M P U T A T I O N **************
|
||||
*************************************************************************/
|
||||
|
||||
control MyComputeChecksum(inout headers hdr, inout metadata meta) {
|
||||
apply {
|
||||
update_checksum(
|
||||
hdr.ipv4.isValid(),
|
||||
{ hdr.ipv4.version,
|
||||
hdr.ipv4.ihl,
|
||||
hdr.ipv4.diffserv,
|
||||
hdr.ipv4.totalLen,
|
||||
hdr.ipv4.identification,
|
||||
hdr.ipv4.flags,
|
||||
hdr.ipv4.fragOffset,
|
||||
hdr.ipv4.ttl,
|
||||
hdr.ipv4.protocol,
|
||||
hdr.ipv4.srcAddr,
|
||||
hdr.ipv4.dstAddr },
|
||||
hdr.ipv4.hdrChecksum,
|
||||
HashAlgorithm.csum16);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
*********************** D E P A R S E R *******************************
|
||||
*************************************************************************/
|
||||
|
||||
control MyDeparser(packet_out packet, in headers hdr) {
|
||||
apply {
|
||||
packet.emit(hdr.ethernet);
|
||||
packet.emit(hdr.ipv4);
|
||||
packet.emit(hdr.tcp);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
*********************** S W I T C H *******************************
|
||||
*************************************************************************/
|
||||
|
||||
V1Switch(
|
||||
MyParser(),
|
||||
MyVerifyChecksum(),
|
||||
MyIngress(),
|
||||
MyEgress(),
|
||||
MyComputeChecksum(),
|
||||
MyDeparser()
|
||||
) main;
|
||||
145
exercises/firewall/pod-topo/s1-runtime.json
Normal file
145
exercises/firewall/pod-topo/s1-runtime.json
Normal file
@@ -0,0 +1,145 @@
|
||||
{
|
||||
"target": "bmv2",
|
||||
"p4info": "build/firewall.p4.p4info.txt",
|
||||
"bmv2_json": "build/firewall.json",
|
||||
"table_entries": [
|
||||
{
|
||||
"table": "MyIngress.check_ports",
|
||||
"match": {
|
||||
"standard_metadata.ingress_port": 1,
|
||||
"standard_metadata.egress_spec": 3
|
||||
},
|
||||
"action_name": "MyIngress.set_direction",
|
||||
"action_params": {
|
||||
"dir": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"table": "MyIngress.check_ports",
|
||||
"match": {
|
||||
"standard_metadata.ingress_port": 1,
|
||||
"standard_metadata.egress_spec": 4
|
||||
},
|
||||
"action_name": "MyIngress.set_direction",
|
||||
"action_params": {
|
||||
"dir": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"table": "MyIngress.check_ports",
|
||||
"match": {
|
||||
"standard_metadata.ingress_port": 2,
|
||||
"standard_metadata.egress_spec": 3
|
||||
},
|
||||
"action_name": "MyIngress.set_direction",
|
||||
"action_params": {
|
||||
"dir": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"table": "MyIngress.check_ports",
|
||||
"match": {
|
||||
"standard_metadata.ingress_port": 2,
|
||||
"standard_metadata.egress_spec": 4
|
||||
},
|
||||
"action_name": "MyIngress.set_direction",
|
||||
"action_params": {
|
||||
"dir": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"table": "MyIngress.check_ports",
|
||||
"match": {
|
||||
"standard_metadata.ingress_port": 3,
|
||||
"standard_metadata.egress_spec": 1
|
||||
},
|
||||
"action_name": "MyIngress.set_direction",
|
||||
"action_params": {
|
||||
"dir": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"table": "MyIngress.check_ports",
|
||||
"match": {
|
||||
"standard_metadata.ingress_port": 3,
|
||||
"standard_metadata.egress_spec": 2
|
||||
},
|
||||
"action_name": "MyIngress.set_direction",
|
||||
"action_params": {
|
||||
"dir": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"table": "MyIngress.check_ports",
|
||||
"match": {
|
||||
"standard_metadata.ingress_port": 4,
|
||||
"standard_metadata.egress_spec": 1
|
||||
},
|
||||
"action_name": "MyIngress.set_direction",
|
||||
"action_params": {
|
||||
"dir": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"table": "MyIngress.check_ports",
|
||||
"match": {
|
||||
"standard_metadata.ingress_port": 4,
|
||||
"standard_metadata.egress_spec": 2
|
||||
},
|
||||
"action_name": "MyIngress.set_direction",
|
||||
"action_params": {
|
||||
"dir": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"table": "MyIngress.ipv4_lpm",
|
||||
"default_action": true,
|
||||
"action_name": "MyIngress.drop",
|
||||
"action_params": { }
|
||||
},
|
||||
{
|
||||
"table": "MyIngress.ipv4_lpm",
|
||||
"match": {
|
||||
"hdr.ipv4.dstAddr": ["10.0.1.1", 32]
|
||||
},
|
||||
"action_name": "MyIngress.ipv4_forward",
|
||||
"action_params": {
|
||||
"dstAddr": "08:00:00:00:01:11",
|
||||
"port": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"table": "MyIngress.ipv4_lpm",
|
||||
"match": {
|
||||
"hdr.ipv4.dstAddr": ["10.0.2.2", 32]
|
||||
},
|
||||
"action_name": "MyIngress.ipv4_forward",
|
||||
"action_params": {
|
||||
"dstAddr": "08:00:00:00:02:22",
|
||||
"port": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"table": "MyIngress.ipv4_lpm",
|
||||
"match": {
|
||||
"hdr.ipv4.dstAddr": ["10.0.3.3", 32]
|
||||
},
|
||||
"action_name": "MyIngress.ipv4_forward",
|
||||
"action_params": {
|
||||
"dstAddr": "08:00:00:00:03:00",
|
||||
"port": 3
|
||||
}
|
||||
},
|
||||
{
|
||||
"table": "MyIngress.ipv4_lpm",
|
||||
"match": {
|
||||
"hdr.ipv4.dstAddr": ["10.0.4.4", 32]
|
||||
},
|
||||
"action_name": "MyIngress.ipv4_forward",
|
||||
"action_params": {
|
||||
"dstAddr": "08:00:00:00:04:00",
|
||||
"port": 4
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
57
exercises/firewall/pod-topo/s2-runtime.json
Normal file
57
exercises/firewall/pod-topo/s2-runtime.json
Normal file
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"target": "bmv2",
|
||||
"p4info": "build/basic.p4.p4info.txt",
|
||||
"bmv2_json": "build/basic.json",
|
||||
"table_entries": [
|
||||
{
|
||||
"table": "MyIngress.ipv4_lpm",
|
||||
"default_action": true,
|
||||
"action_name": "MyIngress.drop",
|
||||
"action_params": { }
|
||||
},
|
||||
{
|
||||
"table": "MyIngress.ipv4_lpm",
|
||||
"match": {
|
||||
"hdr.ipv4.dstAddr": ["10.0.1.1", 32]
|
||||
},
|
||||
"action_name": "MyIngress.ipv4_forward",
|
||||
"action_params": {
|
||||
"dstAddr": "08:00:00:00:03:00",
|
||||
"port": 4
|
||||
}
|
||||
},
|
||||
{
|
||||
"table": "MyIngress.ipv4_lpm",
|
||||
"match": {
|
||||
"hdr.ipv4.dstAddr": ["10.0.2.2", 32]
|
||||
},
|
||||
"action_name": "MyIngress.ipv4_forward",
|
||||
"action_params": {
|
||||
"dstAddr": "08:00:00:00:04:00",
|
||||
"port": 3
|
||||
}
|
||||
},
|
||||
{
|
||||
"table": "MyIngress.ipv4_lpm",
|
||||
"match": {
|
||||
"hdr.ipv4.dstAddr": ["10.0.3.3", 32]
|
||||
},
|
||||
"action_name": "MyIngress.ipv4_forward",
|
||||
"action_params": {
|
||||
"dstAddr": "08:00:00:00:03:33",
|
||||
"port": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"table": "MyIngress.ipv4_lpm",
|
||||
"match": {
|
||||
"hdr.ipv4.dstAddr": ["10.0.4.4", 32]
|
||||
},
|
||||
"action_name": "MyIngress.ipv4_forward",
|
||||
"action_params": {
|
||||
"dstAddr": "08:00:00:00:04:44",
|
||||
"port": 2
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
57
exercises/firewall/pod-topo/s3-runtime.json
Normal file
57
exercises/firewall/pod-topo/s3-runtime.json
Normal file
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"target": "bmv2",
|
||||
"p4info": "build/basic.p4.p4info.txt",
|
||||
"bmv2_json": "build/basic.json",
|
||||
"table_entries": [
|
||||
{
|
||||
"table": "MyIngress.ipv4_lpm",
|
||||
"default_action": true,
|
||||
"action_name": "MyIngress.drop",
|
||||
"action_params": { }
|
||||
},
|
||||
{
|
||||
"table": "MyIngress.ipv4_lpm",
|
||||
"match": {
|
||||
"hdr.ipv4.dstAddr": ["10.0.1.1", 32]
|
||||
},
|
||||
"action_name": "MyIngress.ipv4_forward",
|
||||
"action_params": {
|
||||
"dstAddr": "08:00:00:00:01:00",
|
||||
"port": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"table": "MyIngress.ipv4_lpm",
|
||||
"match": {
|
||||
"hdr.ipv4.dstAddr": ["10.0.2.2", 32]
|
||||
},
|
||||
"action_name": "MyIngress.ipv4_forward",
|
||||
"action_params": {
|
||||
"dstAddr": "08:00:00:00:01:00",
|
||||
"port": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"table": "MyIngress.ipv4_lpm",
|
||||
"match": {
|
||||
"hdr.ipv4.dstAddr": ["10.0.3.3", 32]
|
||||
},
|
||||
"action_name": "MyIngress.ipv4_forward",
|
||||
"action_params": {
|
||||
"dstAddr": "08:00:00:00:02:00",
|
||||
"port": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"table": "MyIngress.ipv4_lpm",
|
||||
"match": {
|
||||
"hdr.ipv4.dstAddr": ["10.0.4.4", 32]
|
||||
},
|
||||
"action_name": "MyIngress.ipv4_forward",
|
||||
"action_params": {
|
||||
"dstAddr": "08:00:00:00:02:00",
|
||||
"port": 2
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
57
exercises/firewall/pod-topo/s4-runtime.json
Normal file
57
exercises/firewall/pod-topo/s4-runtime.json
Normal file
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"target": "bmv2",
|
||||
"p4info": "build/basic.p4.p4info.txt",
|
||||
"bmv2_json": "build/basic.json",
|
||||
"table_entries": [
|
||||
{
|
||||
"table": "MyIngress.ipv4_lpm",
|
||||
"default_action": true,
|
||||
"action_name": "MyIngress.drop",
|
||||
"action_params": { }
|
||||
},
|
||||
{
|
||||
"table": "MyIngress.ipv4_lpm",
|
||||
"match": {
|
||||
"hdr.ipv4.dstAddr": ["10.0.1.1", 32]
|
||||
},
|
||||
"action_name": "MyIngress.ipv4_forward",
|
||||
"action_params": {
|
||||
"dstAddr": "08:00:00:00:01:00",
|
||||
"port": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"table": "MyIngress.ipv4_lpm",
|
||||
"match": {
|
||||
"hdr.ipv4.dstAddr": ["10.0.2.2", 32]
|
||||
},
|
||||
"action_name": "MyIngress.ipv4_forward",
|
||||
"action_params": {
|
||||
"dstAddr": "08:00:00:00:01:00",
|
||||
"port": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"table": "MyIngress.ipv4_lpm",
|
||||
"match": {
|
||||
"hdr.ipv4.dstAddr": ["10.0.3.3", 32]
|
||||
},
|
||||
"action_name": "MyIngress.ipv4_forward",
|
||||
"action_params": {
|
||||
"dstAddr": "08:00:00:00:02:00",
|
||||
"port": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"table": "MyIngress.ipv4_lpm",
|
||||
"match": {
|
||||
"hdr.ipv4.dstAddr": ["10.0.4.4", 32]
|
||||
},
|
||||
"action_name": "MyIngress.ipv4_forward",
|
||||
"action_params": {
|
||||
"dstAddr": "08:00:00:00:02:00",
|
||||
"port": 1
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
27
exercises/firewall/pod-topo/topology.json
Normal file
27
exercises/firewall/pod-topo/topology.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"hosts": {
|
||||
"h1": {"ip": "10.0.1.1/24", "mac": "08:00:00:00:01:11",
|
||||
"commands":["route add default gw 10.0.1.10 dev eth0",
|
||||
"arp -i eth0 -s 10.0.1.10 08:00:00:00:01:00"]},
|
||||
"h2": {"ip": "10.0.2.2/24", "mac": "08:00:00:00:02:22",
|
||||
"commands":["route add default gw 10.0.2.20 dev eth0",
|
||||
"arp -i eth0 -s 10.0.2.20 08:00:00:00:02:00"]},
|
||||
"h3": {"ip": "10.0.3.3/24", "mac": "08:00:00:00:03:33",
|
||||
"commands":["route add default gw 10.0.3.30 dev eth0",
|
||||
"arp -i eth0 -s 10.0.3.30 08:00:00:00:03:00"]},
|
||||
"h4": {"ip": "10.0.4.4/24", "mac": "08:00:00:00:04:44",
|
||||
"commands":["route add default gw 10.0.4.40 dev eth0",
|
||||
"arp -i eth0 -s 10.0.4.40 08:00:00:00:04:00"]}
|
||||
},
|
||||
"switches": {
|
||||
"s1": { "runtime_json" : "pod-topo/s1-runtime.json",
|
||||
"program" : "build/firewall.json" },
|
||||
"s2": { "runtime_json" : "pod-topo/s2-runtime.json" },
|
||||
"s3": { "runtime_json" : "pod-topo/s3-runtime.json" },
|
||||
"s4": { "runtime_json" : "pod-topo/s4-runtime.json" }
|
||||
},
|
||||
"links": [
|
||||
["h1", "s1-p1"], ["h2", "s1-p2"], ["s1-p3", "s3-p1"], ["s1-p4", "s4-p2"],
|
||||
["h3", "s2-p1"], ["h4", "s2-p2"], ["s2-p3", "s4-p1"], ["s2-p4", "s3-p2"]
|
||||
]
|
||||
}
|
||||
282
exercises/firewall/solution/firewall.p4
Normal file
282
exercises/firewall/solution/firewall.p4
Normal file
@@ -0,0 +1,282 @@
|
||||
/* -*- P4_16 -*- */
|
||||
#include <core.p4>
|
||||
#include <v1model.p4>
|
||||
|
||||
/* CONSTANTS */
|
||||
|
||||
const bit<16> TYPE_IPV4 = 0x800;
|
||||
const bit<8> TYPE_TCP = 6;
|
||||
|
||||
#define BLOOM_FILTER_ENTRIES 4096
|
||||
#define BLOOM_FILTER_BIT_WIDTH 1
|
||||
|
||||
/*************************************************************************
|
||||
*********************** H E A D E R S ***********************************
|
||||
*************************************************************************/
|
||||
|
||||
typedef bit<9> egressSpec_t;
|
||||
typedef bit<48> macAddr_t;
|
||||
typedef bit<32> ip4Addr_t;
|
||||
|
||||
header ethernet_t {
|
||||
macAddr_t dstAddr;
|
||||
macAddr_t srcAddr;
|
||||
bit<16> etherType;
|
||||
}
|
||||
|
||||
header ipv4_t {
|
||||
bit<4> version;
|
||||
bit<4> ihl;
|
||||
bit<8> diffserv;
|
||||
bit<16> totalLen;
|
||||
bit<16> identification;
|
||||
bit<3> flags;
|
||||
bit<13> fragOffset;
|
||||
bit<8> ttl;
|
||||
bit<8> protocol;
|
||||
bit<16> hdrChecksum;
|
||||
ip4Addr_t srcAddr;
|
||||
ip4Addr_t dstAddr;
|
||||
}
|
||||
|
||||
header tcp_t{
|
||||
bit<16> srcPort;
|
||||
bit<16> dstPort;
|
||||
bit<32> seqNo;
|
||||
bit<32> ackNo;
|
||||
bit<4> dataOffset;
|
||||
bit<4> res;
|
||||
bit<1> cwr;
|
||||
bit<1> ece;
|
||||
bit<1> urg;
|
||||
bit<1> ack;
|
||||
bit<1> psh;
|
||||
bit<1> rst;
|
||||
bit<1> syn;
|
||||
bit<1> fin;
|
||||
bit<16> window;
|
||||
bit<16> checksum;
|
||||
bit<16> urgentPtr;
|
||||
}
|
||||
|
||||
struct metadata {
|
||||
/* empty */
|
||||
}
|
||||
|
||||
struct headers {
|
||||
ethernet_t ethernet;
|
||||
ipv4_t ipv4;
|
||||
tcp_t tcp;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
*********************** P A R S E R ***********************************
|
||||
*************************************************************************/
|
||||
|
||||
parser MyParser(packet_in packet,
|
||||
out headers hdr,
|
||||
inout metadata meta,
|
||||
inout standard_metadata_t standard_metadata) {
|
||||
|
||||
state start {
|
||||
transition parse_ethernet;
|
||||
}
|
||||
|
||||
state parse_ethernet {
|
||||
packet.extract(hdr.ethernet);
|
||||
transition select(hdr.ethernet.etherType) {
|
||||
TYPE_IPV4: parse_ipv4;
|
||||
default: accept;
|
||||
}
|
||||
}
|
||||
|
||||
state parse_ipv4 {
|
||||
packet.extract(hdr.ipv4);
|
||||
transition select(hdr.ipv4.protocol){
|
||||
TYPE_TCP: tcp;
|
||||
default: accept;
|
||||
}
|
||||
}
|
||||
|
||||
state tcp {
|
||||
packet.extract(hdr.tcp);
|
||||
transition accept;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
************ C H E C K S U M V E R I F I C A T I O N *************
|
||||
*************************************************************************/
|
||||
|
||||
control MyVerifyChecksum(inout headers hdr, inout metadata meta) {
|
||||
apply { }
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
************** I N G R E S S P R O C E S S I N G *******************
|
||||
*************************************************************************/
|
||||
|
||||
control MyIngress(inout headers hdr,
|
||||
inout metadata meta,
|
||||
inout standard_metadata_t standard_metadata) {
|
||||
|
||||
register<bit<BLOOM_FILTER_BIT_WIDTH>>(BLOOM_FILTER_ENTRIES) bloom_filter_1;
|
||||
register<bit<BLOOM_FILTER_BIT_WIDTH>>(BLOOM_FILTER_ENTRIES) bloom_filter_2;
|
||||
bit<32> reg_pos_one; bit<32> reg_pos_two;
|
||||
bit<1> reg_val_one; bit<1> reg_val_two;
|
||||
bit<1> direction;
|
||||
|
||||
action drop() {
|
||||
mark_to_drop(standard_metadata);
|
||||
}
|
||||
|
||||
action compute_hashes(ip4Addr_t ipAddr1, ip4Addr_t ipAddr2, bit<16> port1, bit<16> port2){
|
||||
//Get register position
|
||||
hash(reg_pos_one, HashAlgorithm.crc16, (bit<32>)0, {ipAddr1,
|
||||
ipAddr2,
|
||||
port1,
|
||||
port2,
|
||||
hdr.ipv4.protocol},
|
||||
(bit<32>)BLOOM_FILTER_ENTRIES);
|
||||
|
||||
hash(reg_pos_two, HashAlgorithm.crc32, (bit<32>)0, {ipAddr1,
|
||||
ipAddr2,
|
||||
port1,
|
||||
port2,
|
||||
hdr.ipv4.protocol},
|
||||
(bit<32>)BLOOM_FILTER_ENTRIES);
|
||||
}
|
||||
|
||||
action ipv4_forward(macAddr_t dstAddr, egressSpec_t port) {
|
||||
standard_metadata.egress_spec = port;
|
||||
hdr.ethernet.srcAddr = hdr.ethernet.dstAddr;
|
||||
hdr.ethernet.dstAddr = dstAddr;
|
||||
hdr.ipv4.ttl = hdr.ipv4.ttl - 1;
|
||||
}
|
||||
|
||||
table ipv4_lpm {
|
||||
key = {
|
||||
hdr.ipv4.dstAddr: lpm;
|
||||
}
|
||||
actions = {
|
||||
ipv4_forward;
|
||||
drop;
|
||||
NoAction;
|
||||
}
|
||||
size = 1024;
|
||||
default_action = drop();
|
||||
}
|
||||
|
||||
action set_direction(bit<1> dir) {
|
||||
direction = dir;
|
||||
}
|
||||
|
||||
table check_ports {
|
||||
key = {
|
||||
standard_metadata.ingress_port: exact;
|
||||
standard_metadata.egress_spec: exact;
|
||||
}
|
||||
actions = {
|
||||
set_direction;
|
||||
NoAction;
|
||||
}
|
||||
size = 1024;
|
||||
default_action = NoAction();
|
||||
}
|
||||
|
||||
apply {
|
||||
if (hdr.ipv4.isValid()){
|
||||
ipv4_lpm.apply();
|
||||
if (hdr.tcp.isValid()){
|
||||
direction = 0; // default
|
||||
if (check_ports.apply().hit) {
|
||||
// test and set the bloom filter
|
||||
if (direction == 0) {
|
||||
compute_hashes(hdr.ipv4.srcAddr, hdr.ipv4.dstAddr, hdr.tcp.srcPort, hdr.tcp.dstPort);
|
||||
}
|
||||
else {
|
||||
compute_hashes(hdr.ipv4.dstAddr, hdr.ipv4.srcAddr, hdr.tcp.dstPort, hdr.tcp.srcPort);
|
||||
}
|
||||
// Packet comes from internal network
|
||||
if (direction == 0){
|
||||
// If there is a syn we update the bloom filter and add the entry
|
||||
if (hdr.tcp.syn == 1){
|
||||
bloom_filter_1.write(reg_pos_one, 1);
|
||||
bloom_filter_2.write(reg_pos_two, 1);
|
||||
}
|
||||
}
|
||||
// Packet comes from outside
|
||||
else if (direction == 1){
|
||||
// Read bloom filter cells to check if there are 1's
|
||||
bloom_filter_1.read(reg_val_one, reg_pos_one);
|
||||
bloom_filter_2.read(reg_val_two, reg_pos_two);
|
||||
// only allow flow to pass if both entries are set
|
||||
if (reg_val_one != 1 || reg_val_two != 1){
|
||||
drop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
**************** E G R E S S P R O C E S S I N G *******************
|
||||
*************************************************************************/
|
||||
|
||||
control MyEgress(inout headers hdr,
|
||||
inout metadata meta,
|
||||
inout standard_metadata_t standard_metadata) {
|
||||
apply { }
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
************* C H E C K S U M C O M P U T A T I O N **************
|
||||
*************************************************************************/
|
||||
|
||||
control MyComputeChecksum(inout headers hdr, inout metadata meta) {
|
||||
apply {
|
||||
update_checksum(
|
||||
hdr.ipv4.isValid(),
|
||||
{ hdr.ipv4.version,
|
||||
hdr.ipv4.ihl,
|
||||
hdr.ipv4.diffserv,
|
||||
hdr.ipv4.totalLen,
|
||||
hdr.ipv4.identification,
|
||||
hdr.ipv4.flags,
|
||||
hdr.ipv4.fragOffset,
|
||||
hdr.ipv4.ttl,
|
||||
hdr.ipv4.protocol,
|
||||
hdr.ipv4.srcAddr,
|
||||
hdr.ipv4.dstAddr },
|
||||
hdr.ipv4.hdrChecksum,
|
||||
HashAlgorithm.csum16);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
*********************** D E P A R S E R *******************************
|
||||
*************************************************************************/
|
||||
|
||||
control MyDeparser(packet_out packet, in headers hdr) {
|
||||
apply {
|
||||
packet.emit(hdr.ethernet);
|
||||
packet.emit(hdr.ipv4);
|
||||
packet.emit(hdr.tcp);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
*********************** S W I T C H *******************************
|
||||
*************************************************************************/
|
||||
|
||||
V1Switch(
|
||||
MyParser(),
|
||||
MyVerifyChecksum(),
|
||||
MyIngress(),
|
||||
MyEgress(),
|
||||
MyComputeChecksum(),
|
||||
MyDeparser()
|
||||
) main;
|
||||
Reference in New Issue
Block a user