# How tables work?

**URL:** <https://forum.p4.org/t/how-tables-work/333>\
**Category:** Getting Started with P4\
**Created:** [May 14, 2022, 10:31pm UTC](https://forum.p4.org/t/how-tables-work/333 "2022-05-14T22:31:40Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![Astro](https://avatars.discourse-cdn.com/v4/letter/a/9dc877/32.png) [@Astro](https://forum.p4.org/u/Astro)\
**Post date:** [May 14, 2022, 10:31pm UTC](https://forum.p4.org/t/how-tables-work/333/1 "2022-05-14T22:31:40Z")

</div>

Hi, can someone plz explain how do tables work and what is the relation between key and actions?

---

<div class="post-metadata">

**Author:** ![ederollora](https://sea1.discourse-cdn.com/flex019/user_avatar/forum.p4.org/ederollora/32/21_2.png) [@ederollora](https://forum.p4.org/u/ederollora)\
**Post date:** [May 15, 2022, 10:48pm UTC](https://forum.p4.org/t/how-tables-work/333/2 "2022-05-15T22:48:31Z")

</div>

Welcome to the forum 🙂

**The short version:**

> [@Astro](#):
>
> plz explain how do tables work

Tables act as a reference for defining keys out of header fields or metadata, to name a few (which will hold values to be matched) and the actions that get executed when there is a match. The proper definition is given [in the language specification](https://p4.org/p4-spec/docs/P4-16-v1.2.2.html#sec-tables). Although the concept of a table is not (just) something purely associated to P4.

> [@Astro](#):
>
> what is the relation between key and actions

There is a direct association between the value of a key, and the action that gets executed when this key value is matched.

**The long version:**

Tables are very useful when you want to decide **what** to do with a packet. You don’t always want to decide on how to forward packets, so there is more than one purpose for using a table, but let’s assume you want to decide what to do with them in terms of forwarding criteria. Generally, when learning what tables are, the _basic_ exercise from the P4 tutorial comes to mind. So that is a good exercise to start with. See the tutorial [here](https://github.com/p4lang/tutorials).

Let’s put an example. Imagine you have one switch (S1) and three hosts (Host\_1, Host\_2 and Host\_3), connected to different ports in S1. You know that hosts want to talk to each other. For instance, you know Host\_1 is trying to send packets to Host\_2. You actually know that Host\_1 is connected to port 1 in S1, Host\_2 to port 2 and Host\_3 to port 3. How do devices decide where to forward the packet? Without going into too much detail about a learning switch or routing protocols, let’s say that some devices look into the destination MAC, others the destination IP and so on. Let’s consider the destination IP address for our example. Now, you could write this code in P4:

```auto
# This is not actual P4, just pseudocode

if(hdr.ipv4.dstAddr == 192.168.1.1){ # condtion
  forward_packet(port=1) # action
}else if (hdr.ipv4.dstAddr == 192.168.1.2){ # another condtion
  forward_packet(port=2) # action
}else if (hdr.ipv4.dstAddr == 192.168.1.3){ # a third condtion
  forward_packet(port=3) # action
}

```

This might look like it can work just fine, but…

- What if you have 32 or 64 ports (and hosts) connected to the switch? Are you going to create 64 `if-else` statements? Let’s imagine that you had a 1000 ports and hosts connected to S1… it seems not a very practical way to decide on how to forward packets.
- What if you want to forward based on different blocks of IPs? This is where [LPM](https://en.wikipedia.org/wiki/Longest_prefix_match) type of keys make sense (and the [TCAM](https://en.wikipedia.org/wiki/Content-addressable_memory#Ternary_CAMs) memory in hardware devices), which you will probably see in the tutorial. If you do not know what a [subnetwork](https://en.wikipedia.org/wiki/Subnetwork) or [CIDR](https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing) is, then click on the links.
- What if you want to change the IP of a particular `if` statement? Or the output port? You’d have to change the program and load it again into the switch. So not very practical too, right?

Instead of using multiple `if` statements, you create a table. The controller, which is the part of the network that “thinks” and controls the data plane (i.e., the switch), will tell the switch which entries are going to be _inserted_ or added into the table. For instance, see the table below.

```auto
table ipv4_lpm { 
    # ipv4_lpm is the table name
    key = { 
    # one or more keys are similar to the condition(s) in the if statement of the previous example
        hdr.ipv4.dstAddr: lpm; 
        # this is the left term of the condition, the destination IPv4 address (dstAddr) field of the ipv4 header
    }
    actions = { 
    # this is where you define WHAT you when to do when there is a coincidence based on an entry 
        ipv4_forward; 
        # this action name is defining the output port to be used
        drop; 
        # this action will drop the packet if there is a match 
        NoAction; 
        #this action will do nothing
    }
    size = 1024; 
    # this is how many entries the controller can introduce
    default_action = NoAction(); 
    # if there is no match, the we do nothing
}

action drop() {
    mark_to_drop(standard_metadata);
}

action ipv4_forward(egressSpec_t port) {
    standard_metadata.egress_spec = port;
}

```

The controller (control plane) can tell the switch (data plane) which IPs introduce, acting as keys of the table. Besides, the controller, will associate an action that will be executed every time an IP is matched. Sometimes, controllers will also add an argument to the action, like the number of the output port. For instance, the controller can communicate to the switch to introduce `192.168.1.1` as key, and `ipv4_forward` with number 1 as argument. The controller can also decide to `drop` any packet that has IP address `192.168.1.2` as destination. So your table, that stores entries in memory, would look like this:

| Table: ipv4\_lpm | |
| --- | --- |
| Key (Header-Field) | Value (Action) |
| 192.168.1.1 | ipv4\_forward(port=1) |
| 192.168.1.2 | drop |

And this is the best way I found on how to explain tables. For sure, I missed many details and ways to explain tables. So…feel free to ask.

Cheers,

PD: And just to be clear, I call a P4 device a _switch_, but it can parse L2, L3 and L4 headers, and even application layers headers if that makes sense to your use case. So this is not only a typical L2 switch but rather a device that acts in pretty much all layers. Also, there might be other P4 devices that are not called `switch` es, like when SmartNIcs or NetFPGAs are used as physical hardware.
