Skip to content

Commit 7dfa686

Browse files
committed
Exercise 7 in
1 parent 4f4d97f commit 7dfa686

File tree

6 files changed

+300
-5
lines changed

6 files changed

+300
-5
lines changed

EXERCISE-3.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ information on how to use the ONOS web UI please refer to this guide:
318318

319319
There is a way to show the pipeconf details for a given device, can you find it?
320320

321-
### Congratulations!
321+
## Congratulations!
322322

323323
You have completed the third exercise! If there is still time before the end of
324324
this session, you can check the bonus steps below.

EXERCISE-4.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,6 @@ counters.
233233
In this case, you should see ~1 packet/s, as that's the rate of packet-outs
234234
generated by the `lldpprovider` app.
235235

236-
### Congratulations!
236+
## Congratulations!
237237

238238
You have completed the fourth exercise!

EXERCISE-6.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,7 @@ below:
400400

401401
<img src="img/routing-ecmp.png" alt="ECMP Test" width="344"/>
402402

403-
### Congratulations!
403+
## Congratulations!
404404

405-
You have completed Exercise 6! Now your fabric is capable of forwarding IPv6
406-
traffic between any host.
405+
You have completed the sixth exercise! Now your fabric is capable of forwarding
406+
IPv6 traffic between any host.

EXERCISE-7.md

Lines changed: 295 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,295 @@
1+
## Exercise 7: Segment Routing v6 (SRv6)
2+
3+
In this exercise, you will be implementing a simplified version of segment
4+
routing, a source routing method that steers traffic through a specified set of
5+
nodes.
6+
7+
This exercise is based on an IETF draft specification called SRv6, which uses
8+
IPv6 packets to frame traffic that follows an SRv6 policy. SRv6 packets use the
9+
IPv6 routing header, and they can either encapsulate IPv6 (or IPv4) packets
10+
entirely or they can just inject an IPv6 routing header into an existing IPv6
11+
packet.
12+
13+
The IPv6 routing header looks as follows:
14+
```
15+
0 1 2 3
16+
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
17+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
18+
| Next Header | Hdr Ext Len | Routing Type | Segments Left |
19+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
20+
| Last Entry | Flags | Tag |
21+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
22+
| |
23+
| Segment List[0] (128 bits IPv6 address) |
24+
| |
25+
| |
26+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
27+
| |
28+
| |
29+
...
30+
| |
31+
| |
32+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
33+
| |
34+
| Segment List[n] (128 bits IPv6 address) |
35+
| |
36+
| |
37+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
38+
```
39+
40+
The **Next Header** field is the type of either the next IPv6 header or the
41+
payload.
42+
43+
For SRv6, the **Routing Type** is 4.
44+
45+
**Segments Left** points to the index of the current segment in the segment
46+
list. In properly formed SRv6 packets, the IPv6 destination address equals
47+
`Segment List[Segments Left]`. The original IPv6 address should be `Segment
48+
List[0]` in our exercise so that traffic is routed to the correct destination
49+
eventually.
50+
51+
**Last Entry** is the index of the last entry in the segment list.
52+
53+
Note: This means it should be one less than the length of the list. (In the
54+
example above, the list is `n+1` entries and last entry should be `n`.)
55+
56+
Finally, the **Segment List** is a reverse-sorted list of IPv6 addresses to be
57+
traversed in a specific SRv6 policy. The last entry in the list is the first
58+
segment in the SRv6 policy. The list is not typically mutated; the entire header
59+
is inserted or removed as a whole.
60+
61+
To keep things simple and because we are already using IPv6, your solution will
62+
just be adding the routing header to the existing IPv6 packet. (We won't be
63+
embedding entire packets inside of new IPv6 packets with an SRv6 policy,
64+
although the spec allows it and there are valid use cases for doing so.)
65+
66+
As you may have already noticed, SRv6 uses IPv6 addresses to identify segments
67+
in a policy. While the format of the addresses is the same as IPv6, the address
68+
space is typically different from the space used for switch's internal IPv6
69+
addresses. The format of the address also differs. A typical IPv6 unicast
70+
address is broken into a network prefix and host identifier pieces, and a subnet
71+
mask is used to delineate the boundary between the two. A typical SRv6 segment
72+
identifier (SID) is broken into a locator, a function identifier, and
73+
optionally, function arguments. The locator must be routable, which enables both
74+
SRv6-enable and unaware nodes to participate in forwarding.
75+
76+
HINT: Due to optional arguments, longest prefix match on the 128-bit SID is
77+
preferred to exact match.
78+
79+
There are three types of nodes of interest in a segment routed network:
80+
81+
1. Source Node - the node (either host or switch) that injects the SRv6 policy.
82+
2. Transit Node - a node that forwards an SRv6 packet, but is not the
83+
destination for the traffic
84+
3. Endpoint Node - a participating waypoint in an SRv6 policy that will modify
85+
the SRv6 header and perform a specified function
86+
87+
In our implementation, we simplify these types into two roles:
88+
89+
* Endpoint Node - for traffic to the switch's SID, update the SRv6 header
90+
(decrement segments left), set the IPv6 destination address to the next
91+
segment, and forward the packets ("End" behavior). For simplicity, we will
92+
always remove the SRv6 header on the penultimate segment in the policy (called
93+
Penultimate Segment Pop or PSP in the spec).
94+
95+
* Transit Node - by default, forward traffic normally if it is not destined for
96+
the switch's IP address or its SID ("T" behavior). Allow the control plane to
97+
add rules to inject SRv6 policy for traffic destined to specific IPv6
98+
addresses ("T.Insert" behavior).
99+
100+
For more details, you can read the draft specification here:
101+
https://tools.ietf.org/id/draft-filsfils-spring-srv6-network-programming-06.html
102+
103+
## Exercise steps
104+
105+
### 1. Adding tables for SRv6
106+
107+
We have already defined the SRv6 header as well as included the logic for
108+
parsing the header in `main.p4`.
109+
110+
The next step is to add two for each of the two roles specified above.
111+
In addition to the tables, you will also need to write the action for the
112+
endpoint node table (otherwise called the "My SID" table); in `snippets.p4`, we
113+
have provided the `t_insert` actions for policies of length 2 and 3, which
114+
should be sufficient to get you started.
115+
116+
Once you've finished that, you will need to apply the tables in the `apply`
117+
block at the bottom of your `EgressPipeImpl` section. You will want to apply the
118+
tables after checking that the L2 destination address matches the switch's, and
119+
before the L3 table is applied (because you'll want to use the same routing
120+
entries to forward traffic after the SRv6 policy is applied). You can also apply
121+
the PSP behavior as part of your `apply` logic because we will always be
122+
applying it if we are the penultimate SID.
123+
124+
### 2. Testing the pipeline with Packet Test Framework (PTF)
125+
126+
In this exercise, you will be modifying tests in [srv6.py](ptf/tests/srv6.py) to
127+
verify the SRv6 behavior of the pipeline.
128+
129+
There are four tests in `srv6.py`:
130+
131+
* Srv6InsertTest: Tests SRv6 insert behavior, where the switch receives an IPv6
132+
packet and inserts the SRv6 header.
133+
134+
* Srv6TransitTest: Tests SRv6 transit behavior, where the switch ignores the
135+
SRv6 header and routes the packet normally, without applying any SRv6-related
136+
modifications.
137+
138+
* Srv6EndTest: Tests SRv6 end behavior (without pop), where the switch forwards
139+
the packet to the next SID found in the SRv6 header.
140+
141+
* Srv6EndPspTest: Tests SRv6 End with Penultimate Segment Pop (PSP) behavior,
142+
where the switch SID is the penultimate in the SID list and the switch removes
143+
the SRv6 header before routing the packet to it's final destination (last SID
144+
in the list).
145+
146+
You should be able to find `TODO EXERCISE 7` in [srv6.py](ptf/tests/srv6.py)
147+
with some hints.
148+
149+
To run all the tests for this exercise:
150+
151+
make p4-test TEST=srv6
152+
153+
This command will run all tests in the `srv6` group (i.e. the content of
154+
`ptf/tests/srv6.py`). To run a specific test case you can use:
155+
156+
make p4-test TEST=<PYTHON MODULE>.<TEST CLASS NAME>
157+
158+
For example:
159+
160+
make p4-test TEST=srv6.Srv6InsertTest
161+
162+
**Check for regressions**
163+
164+
At this point, our P4 program should be complete. We can check to make sure that
165+
we haven't broken anything from the previous exercises by running all tests from
166+
the `ptf/tests` directory:
167+
168+
```
169+
$ make p4-test
170+
```
171+
172+
Now we have shown that we can install basic rules and pass SRv6 traffic using BMv2.
173+
174+
### 3. Building the ONOS App
175+
176+
For the ONOS application, you will need to update `Srv6Component.java` in the
177+
following ways:
178+
179+
* Complete the `setUpMySidTable` method which will insert an entry into the M
180+
SID table that matches the specified device's SID and performs the `end`
181+
action. This function is called whenever a new device is connected.
182+
183+
* Complete the `insertSrv6InsertRule` function, which creates a `t_insert` rule
184+
along for the provided SRv6 policy. This function is called by the
185+
`srv6-insert` CLI command.
186+
187+
* Complete the `clearSrv6InsertRules`, which is called by the `srv6-clear` CLI
188+
command.
189+
190+
Once you are finished, you should rebuild and reload your app. This will also
191+
rebuild and republish any changes to your P4 code and the ONOS pipeconf. Don't
192+
forget to enable your Srv6Component at the top of the file.
193+
194+
As with previous exercises, you can use the following command to build and
195+
reload the app:
196+
197+
```
198+
$ make app-build app-reload
199+
```
200+
201+
### 4. Inserting SRv6 policies
202+
203+
The next step is to show that traffic can be steered using an SRv6 policy.
204+
205+
You should start a ping between `h2` and `h4`:
206+
```
207+
mininet> h2 ping h4
208+
```
209+
210+
Using the ONOS UI, you can observe which paths are being used for the ping
211+
packets.
212+
213+
- Press `a` until you see "Port stats (packets/second)"
214+
- Press `l` to show device labels
215+
216+
<img src="img/srv6-ping-1.png" alt="Ping Test" width="344"/>
217+
218+
Once you determine which of the spines your packets are being hashed to (and it
219+
could be both, with requests and replies taking different paths), you should
220+
insert a set of SRv6 policies that sends the ping packets via the other spine
221+
(or the spine of your choice).
222+
223+
To add new SRv6 policies, you should use the `srv6-insert` command.
224+
225+
```
226+
onos> srv6-insert <device ID> <segment list>
227+
```
228+
229+
Note: In our topology, the SID for spine1 is `3:201:2::` and the SID for spine
230+
is `3:202:2::`.
231+
232+
For example, to add a policy that forwards traffic between h2 and h4 though
233+
spine1 and leaf2, you can use the following command:
234+
235+
* Insert the SRv6 policy from h2 to h4 on leaf1 (through spine1 and leaf2)
236+
```
237+
onos> srv6-insert device:leaf1 3:201:2:: 3:102:2:: 2001:1:4::1
238+
Installing path on device device:leaf1: 3:201:2::, 3:102:2::, 2001:1:4::1
239+
```
240+
* Insert the SRv6 policy from h4 to h2 on leaf2 (through spine1 and leaf1)
241+
```
242+
onos> srv6-insert device:leaf2 3:201:2:: 3:101:2:: 2001:1:2::1
243+
Installing path on device device:leaf2: 3:201:2::, 3:101:2::, 2001:1:2::1
244+
```
245+
246+
These commands will match on traffic to the last segment on the specified device
247+
(e.g. match `2001:1:4::1` on `leaf1`). You can update the command to allow for
248+
more specific match criteria as extra credit.
249+
250+
You can confirm that your rule has been added using a variant of the following:
251+
252+
(HINT: Make sure to update the tableId to match the one in your P4 program.)
253+
254+
```
255+
onos> flows any device:leaf1 | grep tableId=IngressPipeImpl.srv6_transit
256+
id=c000006d73f05e, state=ADDED, bytes=0, packets=0, duration=871, liveType=UNKNOWN, priority=10,
257+
tableId=IngressPipeImpl.srv6_transit,
258+
appId=org.p4.srv6-tutorial,
259+
selector=[hdr.ipv6.dst_addr=0x20010001000400000000000000000001/128],
260+
treatment=DefaultTrafficTreatment{immediate=[
261+
IngressPipeImpl.srv6_t_insert_3(
262+
s3=0x20010001000400000000000000000001,
263+
s1=0x30201000200000000000000000000,
264+
s2=0x30102000200000000000000000000)],
265+
deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null}
266+
```
267+
268+
You should now return to the ONOS UI to confirm that traffic is flowing through
269+
the specified spine.
270+
271+
<img src="img/srv6-ping-2.png" alt="SRv6 Ping Test" width="335"/>
272+
273+
### Debugging and Clean Up
274+
275+
If you need to remove your SRv6 policies, you can use the `srv6-clear` command
276+
to clear all SRv6 policies from a specific device. For example to remove flows
277+
from `leaf1`, use this command:
278+
279+
```
280+
onos> srv6-clear device:leaf1
281+
```
282+
283+
To verify that the device inserts the correct SRv6 header, you can use
284+
**Wireshark** to capture packet from each device port.
285+
286+
For example, if you want to capture packet from port 1 of spine1, capture
287+
packets from interface `spine1-eth1`.
288+
289+
NOTE: `spine1-eth1` is connected to leaf1, and `spine1-eth2` is connected to
290+
leaf2; spine two follows the same pattern.
291+
292+
## Congratulations!
293+
294+
You have completed the seventh exercise! Now your fabric is capable of steering
295+
traffic using SRv6.

img/srv6-ping-1.png

35.9 KB
Loading

img/srv6-ping-2.png

33.9 KB
Loading

0 commit comments

Comments
 (0)