Commit ea8c631a authored by cedgar's avatar cedgar
Browse files

week 4 exercise: updated rsvp readme and added rsvp.p4 base code

parent 23eaa64c
......@@ -78,9 +78,9 @@ cd ~/p4-tools/p4-utils
git pull
```
### Network Toplogy
### Network Topology
For this exercise, we provide you with sample configuration for the topology
For this exercise, we provide you with a sample configuration for the topology
shown below. However, feel free to test your solution with your own topologies
too. For example, you can use a very small topology with 2-3 switches while you
develop your solution, and once you have a working prototype move to a bigger
......@@ -120,12 +120,12 @@ type `help` to see the commands (`add_reservation` and `del_reservation` among
the most important ones).
> Note: The controller has dependencies that are implemented in `python2` only.
Make sure you dont use `python3` to run it.
Make sure you don't use `python3` to run it.
### Performance Optimizations
To test the performance of our implementation we will need to send hundreds of
thousands of packets through the switch. Below, we explain how you can increae
thousands of packets through the switch. Below, we explain how you can increase
the performance of `bmv2` to achieve higher throughput.
#### Disabling Debugging in the bmv2 Switch
......@@ -336,14 +336,14 @@ A few hints which will help you to solve this task:
the needed information to update the controller state. For example, the
timeout will be used by the controller to know when to clear the entry, the
`bw` and the `path` can be used to restore links capacities. The table
`handle` to update the the current entry in the switch.
`handle` to update the current entry in the switch.
Your task is now to implement the function `add_reservation` (and its helper functions).
This function should try to allocate bandwidth reservations whenever there is
capacity in the network, otherwise should discard them. Furthermore, it should be
to receive updated reservations for existing allocations, update its attributes,
move them to a new path if required, or even delete them if the updated request
can not be fullfilled anymore. We suggest you to implement `add_reservation` with
can not be fulfilled anymore. We suggest you to implement `add_reservation` with
the following steps:
1. Compute a path from `src` to `dst` which has enough capacity left.
......@@ -379,7 +379,7 @@ the following steps:
- Get the action name `mpls_ingress_X_hop`, where `X` is the number of
labels.
- Get source and destination addresses and build a match variable using a
- Get the source and destination addresses and build a match variable using a
list. Note that the source address needs to be specified as an lpm match
(e.g. `10.0.1.2/32`).
......@@ -558,8 +558,236 @@ allocated as you expected.
At this point, you have competed a basic implementation of RSVP.
Congratulations!
As you may have noticed, there are still one big weakness: We do not limit hosts
to send only at the requested bandwidth. Also, there are many ways to make our
implementation more fancy (for example by introducing priorities for each flow).
As you may have noticed, even tough that the controller takes into account the
bandwidth hosts request when computing the reservations, switches do not perform
any rate limiting. Thus, a host making a 1Mbps reservation is still able to get
full bandwidth. Furthermore, at this point, all the reservations are treated equally.
We will look at all of this (and more) next week. Stay tuned!
\ No newline at end of file
In this second part of the exercise, we will improve our implementation and rate
limit host reservations using meters at ingress switches. Also, by extending our
`add_reservation` controller function, we will introduce the sense of priority to
the reservations.
### Task 1: Reservation rate limiting with meters
During the last [lecture](https://polybox.ethz.ch/index.php/s/A7lGH0JQsGSpBob)
you were taught P4 stateful data structures. There, we showed you
that direct/indirect color `meters` can be used to rate limit traffic.
The `bmv2` software switch implements the so called two-rate three-color marker meters.
You can find more details in the corresponding [RFC](https://tools.ietf.org/html/rfc2698).
The figure below shows how two-rate three-color marker meters work. In the figure we use
the packet size as count unit, however `bmv2` supports both bytes and packet-based meters.
These meters are configured using four parameters:
* CIR(committed information rate): is the rate per unit of time in bytes or packets at which the CBS bucket is filled.
* PIR(peak information rate): is the rate per unit of time in bytes or packets at which the PBS bucket is filled.
* CBS(committed burst size): is the size in bytes or packets of the CBS bucket.
* PBS(peak burst size): is the size in bytes or packets of the PBS bucket.
If we consider a byte-based meter, a packet of size `B` is colored as follows:
1. if `B > Tp` the packet is marked red.
2. if `B < Tp` and `B > Tc` the packet is marked yellow.
3. otherwise, the packet is marked green.
<p align="center">
<img src="images/two-color-meters.png" title="Two color meters">
<p/>
In this task, you will need to extend your `rsvp.p4` program such that each reservation
is metered and all non-green packets get dropped. Furthermore, you will have to extend
your controller code such that after every reservation addition or modification its
associated meter is configured properly.
> Hint: in the last lecture there are some slides in which you can find how to define and use meters.
### Data plane tasks:
1. Whenever a meter is executed, the color is saved into a metadata field. Define that field in your metadata structure.
2. Define a direct meter at the beginning of your ingress pipeline. You can find an example in the slides and
some documentation in the [v1model documentation](https://github.com/p4lang/p4c/blob/master/p4include/v1model.p4).
3. Read the meter in all the `mpls_ingress_x_hop` actions to your metadata field.
4. Update your ingress control logic and drop all the packets for which the meter is yellow or red (not green).
At this point you have all the P4 logic to rate limit your traffic reservations.
However, you still need to add some small modifications to your controller code such
that associated meters get configured with the desired rate.
### Control plane tasks:
1. Understand how two-rate three-color meters work. See the text above, or read the RFC. To configure
meters using our control plane API you will have to use `meter_set_rates(meter_name, handle, rates)`.
`meter_name` is the name you called the meter in `P4`, `handle` is the table handle for the reservation rule and
`rates` is a list of the form `[(CIR, CBS), (PIR, PBS)]`. *IMPORTANT:* in `bmv2` `CIR` and `PIR` are the bucket
filling rate every micro second. For example, if `CIR=1` the bucket is filled at a rate of 1000000/s.
2. Implement the function `get_meter_rates_from_bw(self, bw, burst_size)`. This function has to return
`[(CIR, CBS), (PIR, PBS)]`. Use `bw` (Mbps) to compute `CIR` and `PIR` (in bytes).
To make it easier, in this exercise we will make the committed and peak
parameters the same. Also, you can set `burst_size` to default to 700000.
3. Implement the function `set_direct_meter_bandwidth(self, sw_name, meter_name, handle, bw)`. This function
calls `get_meter_rates_from_bw` and by using the meter name, handle and rates configures
the meter associated with a given table entry (use `meter_set_rates`).
4. Modify your `add_reservation` function such that every time you `add` or `modify` a reservation you
also update its associated meter.
### Test if rate limiting works as desired
1. Start the topology and the controller.
2. Make 2 bidirectional reservations from `h1->h5` and `h2->6`. For the
first use `2Mbps`, for the second `8Mbps`.
```
======================================================================
Welcome to the RSVP CLI
======================================================================
You can now make reservations for your hosts in the network.
To add a reservation run:
add_reservation <src> <dst> <duration> <bw> <priority>
To delete a reservation run:
del_reservation <src> <dst>
rsvp-menu> add_reservation h1 h5 1000 2 1
Adding entry to lpm match table FEC_tbl
match key: LPM-0a:01:01:02/32 EXACT-0a:07:05:02
action: mpls_ingress_3_hop
runtime data: 00:00:03 00:00:03 00:00:04
Entry has been added with handle 2
Successful reservation(h1->h5): path: s1->s3->s6->s7
rsvp-menu> add_reservation h5 h1 1000 2 1
Adding entry to lpm match table FEC_tbl
match key: LPM-0a:07:05:02/32 EXACT-0a:01:01:02
action: mpls_ingress_3_hop
runtime data: 00:00:01 00:00:01 00:00:02
Entry has been added with handle 2
Successful reservation(h5->h1): path: s7->s6->s3->s1
rsvp-menu> add_reservation h2 h6 1000 8 1
Adding entry to lpm match table FEC_tbl
match key: LPM-0a:01:02:02/32 EXACT-0a:07:06:02
action: mpls_ingress_3_hop
runtime data: 00:00:03 00:00:03 00:00:04
Entry has been added with handle 3
Successful reservation(h2->h6): path: s1->s3->s6->s7
rsvp-menu> add_reservation h6 h2 1000 8 1
Adding entry to lpm match table FEC_tbl
match key: LPM-0a:07:06:02/32 EXACT-0a:01:02:02
action: mpls_ingress_3_hop
runtime data: 00:00:01 00:00:01 00:00:02
Entry has been added with handle 3
Successful reservation(h6->h2): path: s7->s6->s3->s1
rsvp-menu>
```
3. Start an iperf server in `h5, h6`:
```
iperf -s -p 5001
```
4. Start an iperf client at `h1, h2` and check if each reservation gets the desired bandwidth.
<p align="center">
<img src="images/rate-limit-test.png" title="Rate limiting test">
<p/>
### Task 2: Reservation with priorities
At this point, you should have a working RSVP centralized controller. However, we
still did not use the `priority` attribute when performing the allocations. In this task,
you will have to modify the `add_reservation` controller function such that some reservations
have a higher priority over others.
When a a high priority reservation comes and there is no space left many different things
could be done. For example, previous reservations can be moved to make space, reservations
with lower priority can be deleted to make space, etc. As a guide we propose you one way,
which is the one we will provide as a solution. Our proposed solution is not perfect, but
does well enough while not needing a major change to the current implementation. In any case,
feel free to implement a different algorithm.
We propose the following algorithm:
1. if the reservation (addition or modification) fits in the current network we do the same than before.
2. if the reservation (addition or modification) does not fit in the network:
1. remove all the reservations with a lower prioiry than the requested one. Hint: you don't need to really remove them from switches, you can just remove its capacities.
2. Check if the requested reservation fits the network without the lower priority ones.
3. if it fits, add or modify it. Now, take all the reservations with lower priority that you `virtually` removed, and allocate them starting with the ones with highest priority. Some will remain in the same path, some will be moved to a new path. If they don't fit anymore, delete them.
4. if it does not fit remove the entry if this is a modification (the entry already existed)
> Hint: make sure `self.links_capacity` is updated properly in each of your steps. Sometimes, when you virtually remove
reservations you will have to add the capacity to links.
### Testing reservations with priorities
Test your final solution. First, start the topology and the controller.
Add reservations between `h1,h2` and `h5,h6`. First, add 3 reservations of 5 Mbps. The first 2 ones with priority 2. The third one with priority 1. The first two allocations should go to `s1->s3->s6->s7`, the third allocation should go to `s1->s2->s5->s7`.
Add a 10Mbps reservation with a higher priority than the others (i.e 3). Since the new allocation does not fit, it should move
everything with lower priority. Thus, it will use the first path, `s1->s3->s6->s7` and then allocate the existing lower priority
reservations to `s1->s2->s5->s7`. However, since not all fit, the reservation with `priority=1` should be removed.
```
rsvp-menu> add_reservation h1 h5 1000 5 2
Adding entry to lpm match table FEC_tbl
match key: LPM-0a:01:01:02/32 EXACT-0a:07:05:02
action: mpls_ingress_3_hop
runtime data: 00:00:03 00:00:03 00:00:04
Entry has been added with handle 16777218
Successful reservation(h1->h5): path: s1->s3->s6->s7
rsvp-menu> add_reservation h1 h6 1000 5 2
Adding entry to lpm match table FEC_tbl
match key: LPM-0a:01:01:02/32 EXACT-0a:07:06:02
action: mpls_ingress_3_hop
runtime data: 00:00:03 00:00:03 00:00:04
Entry has been added with handle 16777219
Successful reservation(h1->h6): path: s1->s3->s6->s7
rsvp-menu> add_reservation h2 h5 1000 5 1
Adding entry to lpm match table FEC_tbl
match key: LPM-0a:01:02:02/32 EXACT-0a:07:05:02
action: mpls_ingress_3_hop
runtime data: 00:00:03 00:00:03 00:00:03
Entry has been added with handle 16777220
Successful reservation(h2->h5): path: s1->s2->s5->s7
rsvp-menu> print_reservations
Current Reservations:
---------------------
0 h1->h5 : s1->s3->s6->s7, bw:5.0, priority:2, timeout:988.0
1 h1->h6 : s1->s3->s6->s7, bw:5.0, priority:2, timeout:993.0
2 h2->h5 : s1->s2->s5->s7, bw:5.0, priority:1, timeout:998.0
rsvp-menu> add_reservation h2 h6 1000 10 3
Adding entry to lpm match table FEC_tbl
match key: LPM-0a:01:02:02/32 EXACT-0a:07:06:02
action: mpls_ingress_3_hop
runtime data: 00:00:03 00:00:03 00:00:04
Entry has been added with handle 16777221
Successful reservation(h2->h6): path: s1->s3->s6->s7
Modifying entry 16777218 for lpm match table FEC_tbl
Successful reservation(h1->h5): path: s1->s2->s5->s7
Modifying entry 16777219 for lpm match table FEC_tbl
Successful reservation(h1->h6): path: s1->s2->s5->s7
Deleting allocation h2->h5 due to a higher priority allocation!
RSVP Deleted/Expired Reservation(h2->h5): path: s1->s2->s5->s7
rsvp-menu> print_reservations
Current Reservations:
---------------------
0 h1->h5 : s1->s2->s5->s7, bw:5.0, priority:2, timeout:981.0
1 h1->h6 : s1->s2->s5->s7, bw:5.0, priority:2, timeout:986.0
2 h2->h6 : s1->s3->s6->s7, bw:10.0, priority:3, timeout:997.0
rsvp-menu>
```
You can test and play with your functional RSVP controller as much as you want!
\ No newline at end of file
......@@ -5,7 +5,7 @@
"options": "--target bmv2 --arch v1model --std p4-16",
"switch_cli": "simple_switch_CLI",
"cli": true,
"pcap_dump": true,
"pcap_dump": false,
"enable_log": true,
"topo_module": {
"file_path": "",
......
/* -*- P4_16 -*- */
#include <core.p4>
#include <v1model.p4>
const bit<16> TYPE_IPV4 = 0x0800;
const bit<16> TYPE_MPLS = 0x8847;
#define CONST_MAX_LABELS 128
#define CONST_MAX_MPLS_HOPS 8
/*************************************************************************
*********************** H E A D E R S ***********************************
*************************************************************************/
typedef bit<9> egressSpec_t;
typedef bit<48> macAddr_t;
typedef bit<32> ip4Addr_t;
typedef bit<20> label_t;
header ethernet_t {
macAddr_t dstAddr;
macAddr_t srcAddr;
bit<16> etherType;
}
header mpls_t {
bit<20> label;
bit<3> exp;
bit<1> s;
bit<8> ttl;
}
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;
ip4Addr_t srcAddr;
ip4Addr_t dstAddr;
}
struct metadata {
// PART 2 TASK 1.1 Add metadata field
}
struct headers {
ethernet_t ethernet;
mpls_t[CONST_MAX_MPLS_HOPS] mpls;
ipv4_t ipv4;
}
/*************************************************************************
*********************** P A R S E R ***********************************
*************************************************************************/
parser MyParser(packet_in packet,
out headers hdr,
inout metadata meta,
inout standard_metadata_t standard_metadata) {
state start {
transition parse_ethernet;
}
state parse_ethernet {
packet.extract(hdr.ethernet);
transition select(hdr.ethernet.etherType) {
TYPE_MPLS: parse_mpls;
TYPE_IPV4: parse_ipv4;
default: accept;
}
}
state parse_mpls {
packet.extract(hdr.mpls.next);
transition select(hdr.mpls.last.s) {
1: parse_ipv4;
default: parse_mpls;
}
}
state parse_ipv4 {
packet.extract(hdr.ipv4);
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 headers hdr, inout metadata meta) {
apply { }
}
/*************************************************************************
************** I N G R E S S P R O C E S S I N G *******************
*************************************************************************/
control MyIngress(inout headers hdr,
inout metadata meta,
inout standard_metadata_t standard_metadata) {
// PART 2 TASK 1.1 Add metadata field
action drop() {
mark_to_drop(standard_metadata);
}
action ipv4_forward(macAddr_t dstAddr, egressSpec_t port) {
hdr.ethernet.srcAddr = hdr.ethernet.dstAddr;
hdr.ethernet.dstAddr = dstAddr;
standard_metadata.egress_spec = port;
hdr.ipv4.ttl = hdr.ipv4.ttl - 1;
}
action mpls_ingress_1_hop(label_t label_1) {
// PART 2 TASK 1.3 Read meter
hdr.ethernet.etherType = TYPE_MPLS;
hdr.mpls.push_front(1);
hdr.mpls[0].setValid();
hdr.mpls[0].label = label_1;
hdr.mpls[0].ttl = hdr.ipv4.ttl - 1;
hdr.mpls[0].s = 1;
}
action mpls_ingress_2_hop(label_t label_1, label_t label_2) {
// PART 2 TASK 1.3 Read meter
hdr.ethernet.etherType = TYPE_MPLS;
hdr.mpls.push_front(1);
hdr.mpls[0].setValid();
hdr.mpls[0].label = label_1;
hdr.mpls[0].ttl = hdr.ipv4.ttl - 1;
hdr.mpls[0].s = 1;
hdr.mpls.push_front(1);
hdr.mpls[0].setValid();
hdr.mpls[0].label = label_2;
hdr.mpls[0].ttl = hdr.ipv4.ttl - 1;
hdr.mpls[0].s = 0;
}
action mpls_ingress_3_hop(label_t label_1, label_t label_2, label_t label_3) {
// PART 2 TASK 1.3 Read meter
hdr.ethernet.etherType = TYPE_MPLS;
hdr.mpls.push_front(1);
hdr.mpls[0].setValid();
hdr.mpls[0].label = label_1;
hdr.mpls[0].ttl = hdr.ipv4.ttl - 1;
hdr.mpls[0].s = 1;
hdr.mpls.push_front(1);
hdr.mpls[0].setValid();
hdr.mpls[0].label = label_2;
hdr.mpls[0].ttl = hdr.ipv4.ttl - 1;
hdr.mpls[0].s = 0;
hdr.mpls.push_front(1);
hdr.mpls[0].setValid();
hdr.mpls[0].label = label_3;
hdr.mpls[0].ttl = hdr.ipv4.ttl - 1;
hdr.mpls[0].s = 0;
}
action mpls_ingress_4_hop(label_t label_1, label_t label_2, label_t label_3, label_t label_4) {
// PART 2 TASK 1.3 Read meter
hdr.ethernet.etherType = TYPE_MPLS;
hdr.mpls.push_front(1);
hdr.mpls[0].setValid();
hdr.mpls[0].label = label_1;
hdr.mpls[0].ttl = hdr.ipv4.ttl - 1;
hdr.mpls[0].s = 1;
hdr.mpls.push_front(1);
hdr.mpls[0].setValid();
hdr.mpls[0].label = label_2;
hdr.mpls[0].ttl = hdr.ipv4.ttl - 1;
hdr.mpls[0].s = 0;
hdr.mpls.push_front(1);
hdr.mpls[0].setValid();
hdr.mpls[0].label = label_3;
hdr.mpls[0].ttl = hdr.ipv4.ttl - 1;
hdr.mpls[0].s = 0;
hdr.mpls.push_front(1);
hdr.mpls[0].setValid();
hdr.mpls[0].label = label_4;
hdr.mpls[0].ttl = hdr.ipv4.ttl - 1;
hdr.mpls[0].s = 0;
}
action mpls_ingress_5_hop(label_t label_1, label_t label_2, label_t label_3, label_t label_4, label_t label_5) {
// PART 2 TASK 1.3 Read meter
hdr.ethernet.etherType = TYPE_MPLS;
hdr.mpls.push_front(1);
hdr.mpls[0].setValid();
hdr.mpls[0].label = label_1;
hdr.mpls[0].ttl = hdr.ipv4.ttl - 1;
hdr.mpls[0].s = 1;
hdr.mpls.push_front(1);
hdr.mpls[0].setValid();
hdr.mpls[0].label = label_2;
hdr.mpls[0].ttl = hdr.ipv4.ttl - 1;
hdr.mpls[0].s = 0;
hdr.mpls.push_front(1);
hdr.mpls[0].setValid();
hdr.mpls[0].label = label_3;
hdr.mpls[0].ttl = hdr.ipv4.ttl - 1;
hdr.mpls[0].s = 0;
hdr.mpls.push_front(1);
hdr.mpls[0].setValid();
hdr.mpls[0].label = label_4;
hdr.mpls[0].ttl = hdr.ipv4.ttl - 1;
hdr.mpls[0].s = 0;
hdr.mpls.push_front(1);
hdr.mpls[0].setValid();
hdr.mpls[0].label = label_5;
hdr.mpls[0].ttl = hdr.ipv4.ttl - 1;
hdr.mpls[0].s = 0;
}
action mpls_ingress_6_hop(label_t label_1, label_t label_2, label_t label_3, label_t label_4, label_t label_5, label_t label_6) {
// PART 2 TASK 1.3 Read meter
hdr.ethernet.etherType = TYPE_MPLS;
hdr.mpls.push_front(1);
hdr.mpls[0].setValid();
hdr.mpls[0].label = label_1;
hdr.mpls[0].ttl = hdr.ipv4.ttl - 1;
hdr.mpls[0].s = 1;
hdr.mpls.push_front(1);
hdr.mpls[0].setValid();
hdr.mpls[0].label = label_2;
hdr.mpls[0].ttl = hdr.ipv4.ttl - 1;
hdr.mpls[0].s = 0;
hdr.mpls.push_front(1);
hdr.mpls[0].setValid();
hdr.mpls[0].label = label_3;
hdr.mpls[0].ttl = hdr.ipv4.ttl - 1;
hdr.mpls[0].s = 0;
hdr.mpls.push_front(1);
hdr.mpls[0].setValid();
hdr.mpls[0].label = label_4;
hdr.mpls[0].ttl = hdr.ipv4.ttl - 1;
hdr.mpls[0].s = 0;
hdr.mpls.push_front(1);
hdr.mpls[0].setValid();
hdr.mpls[0].label = label_5;
hdr.mpls[0].ttl = hdr.ipv4.ttl - 1;
hdr.mpls[0].s = 0;
hdr.mpls.push_front(1);
hdr.mpls[0].setValid();
hdr.mpls[0].label = label_6;
hdr.mpls[0].ttl = hdr.ipv4.ttl - 1;
hdr.mpls[0].s = 0;
}
action mpls_ingress_7_hop(label_t label_1, label_t label_2, label_t label_3, label_t label_4, label_t label_5, label_t label_6, label_t label_7) {
// PART 2 TASK 1.3 Read meter
hdr.ethernet.etherType = TYPE_MPLS;
hdr.mpls.push_front(1);
hdr.mpls[0].setValid();
hdr.mpls[0].label = label_1;
hdr.mpls[0].ttl = hdr.ipv4.ttl - 1;
hdr.mpls[0].s = 1;
hdr.mpls.push_front(1);
hdr.mpls[0].setValid();
hdr.mpls[0].label = label_2;
hdr.mpls[0].ttl = hdr.ipv4.ttl - 1;
hdr.mpls[0].s = 0;
hdr.mpls.push_front(1);
hdr.mpls[0].setValid();
hdr.mpls[0].label = label_3;
hdr.mpls[0].ttl = hdr.ipv4.ttl - 1;
hdr.mpls[0].s = 0;
hdr.mpls.push_front(1);
hdr.mpls[0].setValid();
hdr.mpls[0].label = label_4;
hdr.mpls[0].ttl = hdr.ipv4.ttl - 1;
hdr.mpls[0].s = 0;
hdr.mpls.push_front(1);
hdr.mpls[0].setValid();
hdr.mpls[0].label = label_5;
hdr.mpls[0].ttl = hdr.ipv4.ttl - 1;
hdr.mpls[0].s = 0;
hdr.mpls.push_front(1);
hdr.mpls[0].setValid();
hdr.mpls[0].label = label_6;
hdr.mpls[0].ttl = hdr.ipv4.ttl - 1;
hdr.mpls[0].s = 0;
hdr.mpls.push_front(1);
hdr.mpls[0].setValid();
hdr.mpls[0].label = label_7;
hdr.mpls[0].ttl = hdr.ipv4.ttl - 1;
hdr.mpls[0].s = 0;
}
action mpls_ingress_8_hop(label_t label_1, label_t label_2, label_t label_3, label_t label_4, label_t label_5, label_t label_6, label_t label_7, label_t label_8) {
// PART 2 TASK 1.3 Read meter
hdr.ethernet.etherType = TYPE_MPLS;
hdr.mpls.push_front(1);
hdr.mpls[0].setValid();