Homework 5

Changelog

  • v1: November 14, 2019

Overview

In this homework assignment, you will develop a simple form of in-band network telemetry using the P4 language. You will also see some of the shortcomings of the language with respect to modularity.

Due Date

  • 11:59pm, November 26, 2019

Academic Integrity

This assignment must be completed individually. All work you submit must be your own and sharing or receiving code is forbidden, with the exception of your partner. Do not look for or submit code you find on the Internet, and do not post solutions or partial solutions on the discussion site. If you make use of any outside materials, you must give attribution. You may ask general questions about the development environment, p4c, bmv2, Mininet, etc., and you may discuss high-level details of the exercises with your classmates. If you have any questions about what is allowed and what is not allowed, please ask the instructor first!

Starter Code

You can download starter code for this assignment as a zipfile from CMS.

Exercise 0: Warmup

To familiarize yourself with the starter code, take a look at the files in the homework05 directory. It includes two sub-directories, source_routing and tunnel, which implement basic point-to-point forwarding based on solutions to previous homework assignments. Note that we have factored out the headers a common file headers.p4 which is included in the switch.p4 for each solution.

Test that each forwarding solution works by linking its switch.p4 file in the top-level directory and running it as follows:

% ln -s source_route/switch.p4 switch.p4
% make
...
mininet> xterm h1 h2

You can use the provided send.py and receive.py scripts in each directory to send data between hosts.

For example, using the source_routing code, the send.py script will prompt you for a sequence of hops (associated with ports) that connect the source to the destination. With the topology supplied in the topology.json file, you could either use the sequence 2 1 or the sequence 2 3 2 2 1 to reach h2 from h1. In either case, on the receiver side, you should see an output like this:

sniffing on eth0
0000   FF FF FF FF FF FF 08 00  00 00 01 11 08 00 45 00   ..............E.
0010   00 21 00 01 00 00 3E 11  63 AB 0A 00 01 0B 0A 00   .!....>.c.......
0020   02 16 04 D2 10 E1 00 0D  D3 00 00 00 00 00 00      ...............
###[ Ethernet ]###
  dst       = ff:ff:ff:ff:ff:ff
  src       = 08:00:00:00:01:11
  type      = 0x800
###[ IP ]###
     version   = 4L
     ihl       = 5L
     tos       = 0x0
     len       = 33
     id        = 1
     flags     = 
     frag      = 0L
     ttl       = 62
     proto     = udp
     chksum    = 0x63ab
     src       = 10.0.1.11
     dst       = 10.0.2.22
     \options   \
###[ UDP ]###
        sport     = 1234
        dport     = 4321
        len       = 13
        chksum    = 0xd300
###[ Telemetry ]###
           count     = 0
           maxBytes  = 0
           \hops      \

For the tunnel code, you will need to run the P4 Runtime controller provided in tunnel/mycontroller.py.

To submit: Nothing.

Exercise 1: Modular In-Band Telemetry

In-band network telemetry refers to a family of applications that collect information about how the network is forwarding packets using (certain) data packets rather than separate monitoring probes. For example, one could keep track of the forwarding paths that packets take (useful when the network uses multi-path forwarding such as ECMP), or characteristics of the path itself such as the peak utilization aggregated across each link.

In this exercise we will implement a simple form of in-band telemetry that collects two pieces of information:

  • The sequence of ports used to forward the packet through the network, stored in reverse order

  • The approximate maximum number of bytes transmitted on any of those ports, calculated using an expotentially-weighted moving average.

The headers.p4 file defines a pair of headers that represent this data:

header telemetry_t {
    bit<8> count;
    bit<32> maxBytes;
}

header hop_t {
    bit<16> portId;
}

struct headers {
    ...
    telemetry_t telemetry;
    hop_t[MAX_HOPS] hops;
}

Note that count indicates the number of hop_t headers that follow while maxBytes is populated with the approximate maximum number of bytes.

Your job is to fill in the missing code in telemetry.p4 so it collects this data. However, for full credit, your solution should work with any reasonable forwarding scheme. That is, as long as the base forwarding scheme invokes your parser, egress control, and deparser at the appropriate program point, the combined program should collect correct telemetry data. You can check that your solution meets this requirement by testing that it works with both source_route/switch.p4 and tunnel/switch.p4.

Implementation Steps

To complete this exericse, you should extend the starter code in telemetry.p4 as follows:

  • Fill in the parser to extract the telemetry and hops headers from the packet data. For simplicity, you may assume that telemetry packets all have UDP destination port 4321.

  • Fill in the deparser to emit the telemetry and hops headers.

  • Fill in the egress control to populate the hops stack with the list of the ports used to forward the packet through the network. Recall that in the egress control, standard_metadata.egress_port contains the port selected by the ingress control.

  • Note that for the supplied receive.py script to work correctly, you will likely need to update some fields in the ipv4 and udp headers to reflect the fact the new size of the packet.

  • Now extend your solution to keep track of an exponentially weighted moving average of the number of bytes transmitted on each port. You may assume that the switch has at most 16 ports. More specifically, on each packet, you should update the estimate as follows:
    new_estimate = .75 * old_estimate + .25 * packet_size
    

    Note that the packet size can be obtained from the IP header or from standard_metadata.packet_length. Also note that while P4 does not have floating-point numbers, you can implement division by powers of 2 using shifting.

  • Finally, use these estimates to compute an approximate value for the number of bytes seen at the most congested port as this packet traversed the network.

Testing

To test that your solution is working correctly, you can use the supplied send.py and receive.py scripts. Your solution should work in an arbitrary (connected) topology and you should be able to verify that it is working as expected by examining the telemetry data printed by the receive.py script.

To submit: Submit telemetry.p4 and submit on CMS.

Karma: Other path properties

Note: Karma exercises are suggested problems that are completely optional. Feel free to try them if you are so inclined, or skip them if you are busy!

  • Verify that your solution works with a multi-path routing scheme such as ECMP. Write a script to visualize or analyze the load balancing properties of the network using collected telemetry data.

  • Explore adding other forms of telemetry such as timestamps, or the depth of the queue in the traffic manager.

To submit: Assemble your solution into a file karma.zip and submit on CMS.

Debriefing

  • How many hours did you spend on this assignment?

  • Would you rate it as easy, moderate, or difficult?

  • If you worked with a partner, please briefly describe both of your contributions to the solution you submitted.

  • How deeply do you feel you understand the material it covers (0%-100%)?

  • If you have any other comments, I would like to hear them! Please write them down or send email to jnfoster@cs.cornell.edu

To submit: debriefing.txt