175 lines
6.4 KiB
Markdown
175 lines
6.4 KiB
Markdown
# 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).
|