Created new subdirectory for Fall developer day. (#60)
This commit is contained in:
174
P4D2_2017_Spring/exercises/arp/README.md
Normal file
174
P4D2_2017_Spring/exercises/arp/README.md
Normal file
@@ -0,0 +1,174 @@
|
||||
# Implementing an ARP/ICMP Responder
|
||||
|
||||
## Introduction
|
||||
|
||||
This exercise extends the [IPv4 Forwarding](../ipv4_forward) program to
|
||||
allow your switches to respond to ARP and ICMP requests. Once implemented,
|
||||
your hosts will be able to `ping` other hosts connected to the switch, and
|
||||
have the switch respond.
|
||||
|
||||
This exercise makes several simplifying assumptions:
|
||||
|
||||
1. The network topology contains exactly one switch and two hosts.
|
||||
1. ARP and ICMP requests to the hosts are ignored; only requests sent to the
|
||||
switch receive responses.
|
||||
|
||||
Implementing the full functionality of ARP and ICMP is straightforward but
|
||||
beyond the scope of this tutorial and left as an exercise to the reader.
|
||||
|
||||
> **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,
|
||||
`arp.p4`, which initially drops all packets. Your job will be to
|
||||
extend it to reply to ARP and ICMP requests.
|
||||
|
||||
As a first step, compile the incomplete `arp.p4` and bring up a
|
||||
switch in Mininet to test its behavior.
|
||||
|
||||
1. In your shell, run:
|
||||
```bash
|
||||
./run.sh
|
||||
```
|
||||
This will:
|
||||
* compile `arp.p4`, and
|
||||
* start a Mininet instance with one switch (`s1`) connected to two hosts (`h1`, `h2`).
|
||||
* The hosts are assigned IPs of `10.0.1.10` and `10.0.2.10`.
|
||||
|
||||
2. Once the P4 source compiles without error, you can test your program at the
|
||||
mininet prompt using the `ping` utility.
|
||||
|
||||
``` mininet> h1 ping h2 ```
|
||||
|
||||
Once the program is implemented correctly, you will see a response to the
|
||||
ping in the mininet window.
|
||||
|
||||
3. Type `exit` in the mininet terminal to exit.
|
||||
|
||||
|
||||
### A note about the control plane
|
||||
|
||||
P4 programs define a packet-processing pipeline, but the rules governing packet
|
||||
processing are inserted into the pipeline 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, the control plane logic has already been implemented. As
|
||||
part of bringing up the Mininet instance, the `run.sh` script will install
|
||||
packet-processing rules in the tables of each switch. These are defined in the
|
||||
`simple_router.config` file.
|
||||
|
||||
|
||||
## Step 2: Implement ARP/ICMP Replies
|
||||
|
||||
In this exercise, we are using entries in the `ipv4_lpm` table as a
|
||||
database, which we can reference when responding to ARP and ICMP requests.
|
||||
Without the proper entries in the table, the solution will not work.
|
||||
|
||||
From a high-level, the task involves implementing two main components: ARP
|
||||
replies and ICMP replies.
|
||||
|
||||
### ARP Reply
|
||||
|
||||
When the switch receives and ARP request asking to resolve the switch's IP
|
||||
address, it will need to perform the following actions:
|
||||
|
||||
1. Swap the source and destination MAC addresses in the Ethernet header,
|
||||
1. set the ARP operation to ARP_REPLY (`2`) in the ARP header,
|
||||
1. update the sender hardware address (SHA) and sender protocol address (SPA) in the ARP header to
|
||||
be the MAC and IP addresses of the switch, and
|
||||
1. set the target hardware address (THA) and target protocol address (TPA) to be the SHA
|
||||
and SPA of the arriving ARP packet.
|
||||
|
||||
### ICMP Reply
|
||||
|
||||
When the switch receives and ICMP request containing the switch's IP and MAC
|
||||
addresses, it will need to perform the following actions:
|
||||
|
||||
1. Swap the source and destination MAC addresses in the Ethernet header,
|
||||
1. swap the source and destination IP addresses in the ICMP header, and
|
||||
1. set the type field in the ICMP header to `ICMP_ECHO_REPLY` (`0`).
|
||||
1. To simplify the exercise, we can ignore the checksum by setting to checksum
|
||||
field to 0.
|
||||
|
||||
|
||||
We have provided a skeleton `arp.p4` file to get you started. In this
|
||||
file, places to modify are marked by `TODO`.
|
||||
|
||||
There are, of course, different possible solutions. We describe one approach
|
||||
below. It builds on the [IPv4 Forwarding](../ipv4_forward) solution, which
|
||||
used the table `ipv4_lpm` for L3 forwarding, by adding a second table named
|
||||
`forward`, which checks if a packet is an ARP or ICMP packet and invokes
|
||||
actions to send an ARP reply, forward an IPv4 packet, or send an ICMP reply.
|
||||
|
||||
Broadly speaking, a complete solution will contain the following components:
|
||||
|
||||
1. Header type definitions for `ethernet_t`, `arp_t`, `ipv4_t`, and `icmp_t`.
|
||||
|
||||
1. A structure (named `my_metadata_t` in `arp.p4`) with metadata fields for the
|
||||
packet's souce and destination MAC addresses, IPv4 address, egress port, as
|
||||
well as a hard-coded MAC address for the switch.
|
||||
|
||||
1. **TODO:** Parsers for Ethernet, ARP, IPv4, and ICMP packet header types.
|
||||
|
||||
1. **TODO:** A control type declaration for ingress processing, containing:
|
||||
|
||||
1. An action for `drop`.
|
||||
|
||||
1. An action (named `set_dst_info`) to store information in the metadata
|
||||
structure, rather than immediately writing to the packet header.
|
||||
|
||||
1. A table (named `ipv4_lpm`) that will match on the destination IP address
|
||||
and invoke the `set_dst_info` action.
|
||||
|
||||
1. An action to send an ICMP reply.
|
||||
|
||||
1. An action to send an ARP reply.
|
||||
|
||||
1. A table (named `forward`) that will forward IPv4 packets, send an ARP
|
||||
reply, send an ICMP reply, or drop a packet.
|
||||
|
||||
1. An `apply` block that implements the control logic to invoke the two
|
||||
tables.
|
||||
|
||||
1. A deparser that emits headers in the proper order.
|
||||
|
||||
To keep the exercise simple, we will ignore the `ipv4_checksum`. You should not
|
||||
need any control plane rules for this exercise.
|
||||
|
||||
## Step 3: Run your solution
|
||||
|
||||
Follow the instructions from Step 1. This time, you should be able to
|
||||
successfully `ping` the switch.
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
There are several ways that problems might manifest:
|
||||
|
||||
1. `arp.p4` fails to compile. In this case, `run.sh` will report the
|
||||
error emitted from the compiler and stop.
|
||||
|
||||
1. `arp.p4` compiles, but the switch does not process packets in the desired
|
||||
way. The `build/logs/<switch-name>.log` files contain trace messages
|
||||
describing how each switch processes each packet. The output is detailed and
|
||||
can help pinpoint logic errors in your implementation.
|
||||
|
||||
> Note that there are no control plane rules installed in this example, and so
|
||||
> the `receive.py` and `send.py` scripts from the [IPv4
|
||||
> Forwarding](../ipv4_forward) example will not work.
|
||||
|
||||
#### Cleaning up Mininet
|
||||
|
||||
In the latter case above, `run.sh` may leave a Mininet instance running in
|
||||
the background. Use the following command to clean up these instances:
|
||||
|
||||
```bash
|
||||
mn -c
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
Congratulations, your implementation works! Move on to the next exercise:
|
||||
turning your switch into a [Calculator](../calc).
|
||||
243
P4D2_2017_Spring/exercises/arp/arp.p4
Normal file
243
P4D2_2017_Spring/exercises/arp/arp.p4
Normal file
@@ -0,0 +1,243 @@
|
||||
/* -*- P4_16 -*- */
|
||||
|
||||
#include <core.p4>
|
||||
#include <v1model.p4>
|
||||
|
||||
/*************************************************************************
|
||||
*********************** C O N S T A N T S *****************************
|
||||
*************************************************************************/
|
||||
/* Define the useful global constants for your program */
|
||||
const bit<16> ETHERTYPE_IPV4 = 0x0800;
|
||||
const bit<16> ETHERTYPE_ARP = 0x0806;
|
||||
const bit<8> IPPROTO_ICMP = 0x01;
|
||||
|
||||
/*************************************************************************
|
||||
*********************** H E A D E R S *********************************
|
||||
*************************************************************************/
|
||||
/* Define the headers the program will recognize */
|
||||
|
||||
/*
|
||||
* Standard ethernet header
|
||||
*/
|
||||
typedef bit<48> mac_addr_t;
|
||||
typedef bit<32> ipv4_addr_t;
|
||||
typedef bit<9> port_id_t;
|
||||
|
||||
header ethernet_t {
|
||||
mac_addr_t dstAddr;
|
||||
mac_addr_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;
|
||||
ipv4_addr_t srcAddr;
|
||||
ipv4_addr_t dstAddr;
|
||||
}
|
||||
|
||||
const bit<16> ARP_HTYPE_ETHERNET = 0x0001;
|
||||
const bit<16> ARP_PTYPE_IPV4 = 0x0800;
|
||||
const bit<8> ARP_HLEN_ETHERNET = 6;
|
||||
const bit<8> ARP_PLEN_IPV4 = 4;
|
||||
const bit<16> ARP_OPER_REQUEST = 1;
|
||||
const bit<16> ARP_OPER_REPLY = 2;
|
||||
|
||||
header arp_t {
|
||||
bit<16> htype;
|
||||
bit<16> ptype;
|
||||
bit<8> hlen;
|
||||
bit<8> plen;
|
||||
bit<16> oper;
|
||||
}
|
||||
|
||||
header arp_ipv4_t {
|
||||
mac_addr_t sha;
|
||||
ipv4_addr_t spa;
|
||||
mac_addr_t tha;
|
||||
ipv4_addr_t tpa;
|
||||
}
|
||||
|
||||
const bit<8> ICMP_ECHO_REQUEST = 8;
|
||||
const bit<8> ICMP_ECHO_REPLY = 0;
|
||||
|
||||
header icmp_t {
|
||||
bit<8> type;
|
||||
bit<8> code;
|
||||
bit<16> checksum;
|
||||
}
|
||||
|
||||
/* Assemble headers in a single struct */
|
||||
struct my_headers_t {
|
||||
ethernet_t ethernet;
|
||||
arp_t arp;
|
||||
arp_ipv4_t arp_ipv4;
|
||||
ipv4_t ipv4;
|
||||
icmp_t icmp;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
*********************** M E T A D A T A *******************************
|
||||
*************************************************************************/
|
||||
/* Define the global metadata for your program */
|
||||
|
||||
struct my_metadata_t {
|
||||
ipv4_addr_t dst_ipv4;
|
||||
mac_addr_t mac_da;
|
||||
mac_addr_t mac_sa;
|
||||
port_id_t egress_port;
|
||||
mac_addr_t my_mac;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
*********************** P A R S E R ***********************************
|
||||
*************************************************************************/
|
||||
parser MyParser(
|
||||
packet_in packet,
|
||||
out my_headers_t hdr,
|
||||
inout my_metadata_t meta,
|
||||
inout standard_metadata_t standard_metadata)
|
||||
{
|
||||
state start {
|
||||
packet.extract(hdr.ethernet);
|
||||
transition select(hdr.ethernet.etherType) {
|
||||
ETHERTYPE_IPV4 : parse_ipv4;
|
||||
ETHERTYPE_ARP : parse_arp;
|
||||
default : accept;
|
||||
}
|
||||
}
|
||||
|
||||
state parse_arp {
|
||||
/*
|
||||
* TODO: parse ARP. If the ARP protocol field is
|
||||
* IPV4, transtion to parse_arp_ipv4
|
||||
*/
|
||||
transition accept;
|
||||
}
|
||||
|
||||
state parse_arp_ipv4 {
|
||||
/*
|
||||
* TODO: parse ARP_IPV4. Hint: one
|
||||
* possible solution is to store the
|
||||
* target packet address in a meta data
|
||||
* field when parsing.
|
||||
*/
|
||||
transition accept;
|
||||
}
|
||||
|
||||
state parse_ipv4 {
|
||||
packet.extract(hdr.ipv4);
|
||||
meta.dst_ipv4 = hdr.ipv4.dstAddr;
|
||||
transition select(hdr.ipv4.protocol) {
|
||||
IPPROTO_ICMP : parse_icmp;
|
||||
default : accept;
|
||||
}
|
||||
}
|
||||
|
||||
state parse_icmp {
|
||||
/* TODO: parse ICMP */
|
||||
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 my_headers_t hdr,
|
||||
inout my_metadata_t meta)
|
||||
{
|
||||
apply { }
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
************** I N G R E S S P R O C E S S I N G *******************
|
||||
*************************************************************************/
|
||||
control MyIngress(
|
||||
inout my_headers_t hdr,
|
||||
inout my_metadata_t meta,
|
||||
inout standard_metadata_t standard_metadata)
|
||||
{
|
||||
action drop() {
|
||||
mark_to_drop();
|
||||
exit;
|
||||
}
|
||||
|
||||
/* TODO: Define actions and tables here */
|
||||
|
||||
|
||||
action set_dst_info(mac_addr_t mac_da,
|
||||
mac_addr_t mac_sa,
|
||||
port_id_t egress_port)
|
||||
{
|
||||
/*
|
||||
* TODO: add logic to store mac addresses and
|
||||
* egress ports in meta data
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
table ipv4_lpm {
|
||||
key = { meta.dst_ipv4 : lpm; }
|
||||
actions = { set_dst_info; drop; }
|
||||
default_action = drop();
|
||||
}
|
||||
|
||||
|
||||
apply {
|
||||
meta.my_mac = 0x000102030405;
|
||||
ipv4_lpm.apply();
|
||||
/* TODO: add contol logic */
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
**************** E G R E S S P R O C E S S I N G *******************
|
||||
*************************************************************************/
|
||||
control MyEgress(
|
||||
inout my_headers_t hdr,
|
||||
inout my_metadata_t 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 my_headers_t hdr,
|
||||
inout my_metadata_t meta)
|
||||
{
|
||||
|
||||
apply { }
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
*********************** D E P A R S E R *******************************
|
||||
*************************************************************************/
|
||||
control MyDeparser(
|
||||
packet_out packet,
|
||||
in my_headers_t hdr)
|
||||
{
|
||||
apply {
|
||||
/* TODO: Implement deparser */
|
||||
}
|
||||
}
|
||||
|
||||
V1Switch(
|
||||
MyParser(),
|
||||
MyVerifyChecksum(),
|
||||
MyIngress(),
|
||||
MyEgress(),
|
||||
MyComputeChecksum(),
|
||||
MyDeparser()
|
||||
) main;
|
||||
10
P4D2_2017_Spring/exercises/arp/p4app.json
Normal file
10
P4D2_2017_Spring/exercises/arp/p4app.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"program": "arp.p4",
|
||||
"language": "p4-16",
|
||||
"targets": {
|
||||
"mininet": {
|
||||
"num-hosts": 2,
|
||||
"switch-config": "simple_router.config"
|
||||
}
|
||||
}
|
||||
}
|
||||
5
P4D2_2017_Spring/exercises/arp/run.sh
Executable file
5
P4D2_2017_Spring/exercises/arp/run.sh
Executable file
@@ -0,0 +1,5 @@
|
||||
P4APPRUNNER=../../utils/p4apprunner.py
|
||||
mkdir -p build
|
||||
tar -czf build/p4app.tgz * --exclude='build'
|
||||
#cd build
|
||||
sudo python $P4APPRUNNER p4app.tgz --build-dir ./build
|
||||
1
P4D2_2017_Spring/exercises/arp/simple_router.config
Normal file
1
P4D2_2017_Spring/exercises/arp/simple_router.config
Normal file
@@ -0,0 +1 @@
|
||||
table_add ipv4_lpm set_dst_info 10.0.1.10/24 => 00:00:01:00:00:01 00:00:02:00:00:02 1
|
||||
305
P4D2_2017_Spring/exercises/arp/solution/arp.p4
Normal file
305
P4D2_2017_Spring/exercises/arp/solution/arp.p4
Normal file
@@ -0,0 +1,305 @@
|
||||
/* -*- P4_16 -*- */
|
||||
|
||||
#include <core.p4>
|
||||
#include <v1model.p4>
|
||||
|
||||
/*************************************************************************
|
||||
*********************** C O N S T A N T S *****************************
|
||||
*************************************************************************/
|
||||
/* Define the useful global constants for your program */
|
||||
const bit<16> ETHERTYPE_IPV4 = 0x0800;
|
||||
const bit<16> ETHERTYPE_ARP = 0x0806;
|
||||
const bit<8> IPPROTO_ICMP = 0x01;
|
||||
|
||||
/*************************************************************************
|
||||
*********************** H E A D E R S *********************************
|
||||
*************************************************************************/
|
||||
/* Define the headers the program will recognize */
|
||||
|
||||
/*
|
||||
* Standard ethernet header
|
||||
*/
|
||||
typedef bit<48> mac_addr_t;
|
||||
typedef bit<32> ipv4_addr_t;
|
||||
typedef bit<9> port_id_t;
|
||||
|
||||
header ethernet_t {
|
||||
mac_addr_t dstAddr;
|
||||
mac_addr_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;
|
||||
ipv4_addr_t srcAddr;
|
||||
ipv4_addr_t dstAddr;
|
||||
}
|
||||
|
||||
const bit<16> ARP_HTYPE_ETHERNET = 0x0001;
|
||||
const bit<16> ARP_PTYPE_IPV4 = 0x0800;
|
||||
const bit<8> ARP_HLEN_ETHERNET = 6;
|
||||
const bit<8> ARP_PLEN_IPV4 = 4;
|
||||
const bit<16> ARP_OPER_REQUEST = 1;
|
||||
const bit<16> ARP_OPER_REPLY = 2;
|
||||
|
||||
header arp_t {
|
||||
bit<16> htype;
|
||||
bit<16> ptype;
|
||||
bit<8> hlen;
|
||||
bit<8> plen;
|
||||
bit<16> oper;
|
||||
}
|
||||
|
||||
header arp_ipv4_t {
|
||||
mac_addr_t sha;
|
||||
ipv4_addr_t spa;
|
||||
mac_addr_t tha;
|
||||
ipv4_addr_t tpa;
|
||||
}
|
||||
|
||||
const bit<8> ICMP_ECHO_REQUEST = 8;
|
||||
const bit<8> ICMP_ECHO_REPLY = 0;
|
||||
|
||||
header icmp_t {
|
||||
bit<8> type;
|
||||
bit<8> code;
|
||||
bit<16> checksum;
|
||||
}
|
||||
|
||||
/* Assemble headers in a single struct */
|
||||
struct my_headers_t {
|
||||
ethernet_t ethernet;
|
||||
arp_t arp;
|
||||
arp_ipv4_t arp_ipv4;
|
||||
ipv4_t ipv4;
|
||||
icmp_t icmp;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
*********************** M E T A D A T A *******************************
|
||||
*************************************************************************/
|
||||
/* Define the global metadata for your program */
|
||||
|
||||
struct my_metadata_t {
|
||||
ipv4_addr_t dst_ipv4;
|
||||
mac_addr_t mac_da;
|
||||
mac_addr_t mac_sa;
|
||||
port_id_t egress_port;
|
||||
mac_addr_t my_mac;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
*********************** P A R S E R ***********************************
|
||||
*************************************************************************/
|
||||
parser MyParser(
|
||||
packet_in packet,
|
||||
out my_headers_t hdr,
|
||||
inout my_metadata_t meta,
|
||||
inout standard_metadata_t standard_metadata)
|
||||
{
|
||||
state start {
|
||||
packet.extract(hdr.ethernet);
|
||||
transition select(hdr.ethernet.etherType) {
|
||||
ETHERTYPE_IPV4 : parse_ipv4;
|
||||
ETHERTYPE_ARP : parse_arp;
|
||||
default : accept;
|
||||
}
|
||||
}
|
||||
|
||||
state parse_arp {
|
||||
packet.extract(hdr.arp);
|
||||
transition select(hdr.arp.htype, hdr.arp.ptype,
|
||||
hdr.arp.hlen, hdr.arp.plen) {
|
||||
(ARP_HTYPE_ETHERNET, ARP_PTYPE_IPV4,
|
||||
ARP_HLEN_ETHERNET, ARP_PLEN_IPV4) : parse_arp_ipv4;
|
||||
default : accept;
|
||||
}
|
||||
}
|
||||
|
||||
state parse_arp_ipv4 {
|
||||
packet.extract(hdr.arp_ipv4);
|
||||
meta.dst_ipv4 = hdr.arp_ipv4.tpa;
|
||||
transition accept;
|
||||
}
|
||||
|
||||
state parse_ipv4 {
|
||||
packet.extract(hdr.ipv4);
|
||||
meta.dst_ipv4 = hdr.ipv4.dstAddr;
|
||||
transition select(hdr.ipv4.protocol) {
|
||||
IPPROTO_ICMP : parse_icmp;
|
||||
default : accept;
|
||||
}
|
||||
}
|
||||
|
||||
state parse_icmp {
|
||||
packet.extract(hdr.icmp);
|
||||
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 my_headers_t hdr,
|
||||
inout my_metadata_t meta)
|
||||
{
|
||||
apply { }
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
************** I N G R E S S P R O C E S S I N G *******************
|
||||
*************************************************************************/
|
||||
control MyIngress(
|
||||
inout my_headers_t hdr,
|
||||
inout my_metadata_t meta,
|
||||
inout standard_metadata_t standard_metadata)
|
||||
{
|
||||
action drop() {
|
||||
mark_to_drop();
|
||||
exit;
|
||||
}
|
||||
|
||||
action set_dst_info(mac_addr_t mac_da,
|
||||
mac_addr_t mac_sa,
|
||||
port_id_t egress_port)
|
||||
{
|
||||
meta.mac_da = mac_da;
|
||||
meta.mac_sa = mac_sa;
|
||||
meta.egress_port = egress_port;
|
||||
}
|
||||
|
||||
table ipv4_lpm {
|
||||
key = { meta.dst_ipv4 : lpm; }
|
||||
actions = { set_dst_info; drop; }
|
||||
default_action = drop();
|
||||
}
|
||||
|
||||
action forward_ipv4() {
|
||||
hdr.ethernet.dstAddr = meta.mac_da;
|
||||
hdr.ethernet.srcAddr = meta.mac_sa;
|
||||
hdr.ipv4.ttl = hdr.ipv4.ttl - 1;
|
||||
|
||||
standard_metadata.egress_spec = meta.egress_port;
|
||||
}
|
||||
|
||||
action send_arp_reply() {
|
||||
hdr.ethernet.dstAddr = hdr.arp_ipv4.sha;
|
||||
hdr.ethernet.srcAddr = meta.mac_da;
|
||||
|
||||
hdr.arp.oper = ARP_OPER_REPLY;
|
||||
|
||||
hdr.arp_ipv4.tha = hdr.arp_ipv4.sha;
|
||||
hdr.arp_ipv4.tpa = hdr.arp_ipv4.spa;
|
||||
hdr.arp_ipv4.sha = meta.mac_da;
|
||||
hdr.arp_ipv4.spa = meta.dst_ipv4;
|
||||
|
||||
standard_metadata.egress_spec = standard_metadata.ingress_port;
|
||||
}
|
||||
|
||||
action send_icmp_reply() {
|
||||
mac_addr_t tmp_mac;
|
||||
ipv4_addr_t tmp_ip;
|
||||
|
||||
tmp_mac = hdr.ethernet.dstAddr;
|
||||
hdr.ethernet.dstAddr = hdr.ethernet.srcAddr;
|
||||
hdr.ethernet.srcAddr = tmp_mac;
|
||||
|
||||
tmp_ip = hdr.ipv4.dstAddr;
|
||||
hdr.ipv4.dstAddr = hdr.ipv4.srcAddr;
|
||||
hdr.ipv4.srcAddr = tmp_ip;
|
||||
|
||||
hdr.icmp.type = ICMP_ECHO_REPLY;
|
||||
hdr.icmp.checksum = 0; // For now
|
||||
|
||||
standard_metadata.egress_spec = standard_metadata.ingress_port;
|
||||
}
|
||||
|
||||
table forward {
|
||||
key = {
|
||||
hdr.arp.isValid() : exact;
|
||||
hdr.arp.oper : ternary;
|
||||
hdr.arp_ipv4.isValid() : exact;
|
||||
hdr.ipv4.isValid() : exact;
|
||||
hdr.icmp.isValid() : exact;
|
||||
hdr.icmp.type : ternary;
|
||||
}
|
||||
actions = {
|
||||
forward_ipv4;
|
||||
send_arp_reply;
|
||||
send_icmp_reply;
|
||||
drop;
|
||||
}
|
||||
const default_action = drop();
|
||||
const entries = {
|
||||
( true, ARP_OPER_REQUEST, true, false, false, _ ) :
|
||||
send_arp_reply();
|
||||
( false, _, false, true, false, _ ) :
|
||||
forward_ipv4();
|
||||
( false, _, false, true, true, ICMP_ECHO_REQUEST ) :
|
||||
send_icmp_reply();
|
||||
}
|
||||
}
|
||||
|
||||
apply {
|
||||
meta.my_mac = 0x000102030405;
|
||||
ipv4_lpm.apply();
|
||||
forward.apply();
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
**************** E G R E S S P R O C E S S I N G *******************
|
||||
*************************************************************************/
|
||||
control MyEgress(
|
||||
inout my_headers_t hdr,
|
||||
inout my_metadata_t 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 my_headers_t hdr,
|
||||
inout my_metadata_t meta)
|
||||
{
|
||||
apply { }
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
*********************** D E P A R S E R *******************************
|
||||
*************************************************************************/
|
||||
control MyDeparser(
|
||||
packet_out packet,
|
||||
in my_headers_t hdr)
|
||||
{
|
||||
apply {
|
||||
packet.emit(hdr.ethernet);
|
||||
/* ARP Case */
|
||||
packet.emit(hdr.arp);
|
||||
packet.emit(hdr.arp_ipv4);
|
||||
/* IPv4 case */
|
||||
packet.emit(hdr.ipv4);
|
||||
packet.emit(hdr.icmp);
|
||||
}
|
||||
}
|
||||
|
||||
V1Switch(
|
||||
MyParser(),
|
||||
MyVerifyChecksum(),
|
||||
MyIngress(),
|
||||
MyEgress(),
|
||||
MyComputeChecksum(),
|
||||
MyDeparser()
|
||||
) main;
|
||||
Reference in New Issue
Block a user