Skip to content

Control blocks

Steffen Lindner edited this page Apr 15, 2019 · 5 revisions

The folder src/components/controls contains the control blocks for the different protocols, e.g. IPv4 or BIER.

Port control block

The Port control block, defined in src/components/controls/Port.p4 handles the initialization of the port information.

control Port(inout headers hdr,
                inout metadata meta,
                inout standard_metadata_t standard_metadata) {


action set_port_status(bit<8> livePorts) {
    meta.ports.status = livePorts;
    meta.ports.mdValid = 1;
}

table port_status {
    actions = {
        set_port_status;
    }
}

apply {
    if(meta.ports.mdValid == 0) {
        port_status.apply();
    }
}

}

The control block consists of a single table that stores the current available ports in a bitstring. When the port meta data is not valid, the port status gets initialized and written to the metadata.

IPv4 control block

The IPv4 control unit, defined in src/components/controls/Ipv4.p4, handles all IPv4 packets.

IPv4 Apply

The entry point is the apply block of the control unit:

apply {
    if(hdr.igmp.isValid()) {
        standard_metadata.egress_spec = 16; // send to controller
    }
    else {
        ipv4.apply();

        if(standard_metadata.instance_type != PKT_INSTANCE_TYPE_INGRESS_RECIRC) { // a recirculated ip packet is a decaped mc packet
            encap_ipv4.apply();
        }
        else {
            ipv4_mc.apply(); // otherwise do normal mc stuff
        }
    }
}

If an IGMP packet arrives at the switch, it forwards the packet to the local controller.

Otherwise the normal IPv4 table (unicast) can be applied. If the IPv4 packet is a multicast packet, no unicast rule applies.

If the IPv4 packet was recirculated, then its has been a BIER packet before (which was decaped), thus this IPv4 packet should not be encapsulated again. If it is not recirculated, the encapsulation table can be applied. If its a recirculated packet, then the native IPMC table should be applied.

IPv4 Multicast table (ipv4_mc)

The IPv4 multicast table (ipv4_mc) represents the native multicast forwarding. The table is implemented as follows:

table ipv4_mc {
        key = {
            hdr.ipv4.dstAddr: exact;
        }
        actions = {
            set_mc_grp;
        }
    }

A table entry is matched against hdr.ipv4.dstAddr using an exact match. If a match occurs, the corresponding native mutlticast group of the v1switch is set.

action set_mc_grp(bit<16> grp) {
        standard_metadata.mcast_grp = grp;
}
```

### IPv4 table (ipv4)

The IPv4 match table (ipv4) represents the normal IPv4 forwarding case using longest prefix matching (lpm). The table is implemented as follows:

```
table ipv4 {
    key = {
        hdr.ipv4.dstAddr: lpm;
        meta.ports.status: ternary;
    }
    actions = {
        forward;
        decap;
    }
}
```

The table matches on the `hdr.ipv4.dstAddr` using a lpm match and the currently available ports identified by `meta.ports.status` using a ternary match. In this way, the normale default forwarding can be distinguished from the IP-FRR case. If the IPv4 dstAddr identifies the switch, the packet gets decapsulated.

The forwarding action is defined as:

```
action forward(egressSpec_t port) {
    standard_metadata.egress_spec = port;
    hdr.ipv4.ttl = hdr.ipv4.ttl - 1;
}
```

The decap action is defined as:

```
action decap() {
    hdr.ethernet.etherType = TYPE_BIER; // it's always a bier packet
    hdr.ipv4.setInvalid(); // remove ipv4 header
    recirculate<metadata>(meta);
}
```

The decap operation removes the IPv4 header (setting it invalid) and adjusts the ethertype of the Ethernet header. IPv4 packets are only decapsulated in the BIER-FRR case, thus it's always an BIER packet underneath.

Afterwards, the packet gets recirculated to invoke the processing of the next header.

### Encap IPv4 (encap_ipv4)

The encap table (encap_ipv4) contains the mapping of IPMC address to corresponding BIER bit string.

The table is defined as follows:

```
table encap_ipv4 {
    key = {
        hdr.ipv4.dstAddr: exact;
    }
    actions = {
        add_bier;
    }
}
```

The table matches on the IPv4 destination address and applies the `add_bier` action.

action add_bier(bierBitmask bs) { hdr.bier.setValid(); // activate bier header hdr.bier.Proto = hdr.ethernet.etherType; hdr.bier.BitString = bs; // set bitstring

    hdr.ethernet.etherType = TYPE_BIER;

    // remove outer ipv4 header and copy it to inner ipv4 header, workaround for (possible) later ip tunnel
    hdr.ipv4_inner = hdr.ipv4;
    hdr.ipv4.setInvalid();
    hdr.ipv4_inner.setValid();

    recirculate<metadata>(meta);
}

The `add_bier` action activates the BIER header and sets the corresponding BIER bit string. The outer IPv4 header (IPMC header) gets copied to the inner IPv4 header and the packet gets recirculated afterwards to process the BIER header.