- Today
- Total
Byeo
2. P4 - basic_tunnel 본문
이번에는 basic_tunnel 예제를 채워보려고 합니다.
https://github.com/p4lang/tutorials/tree/master/exercises/basic_tunnel
이번에도 열심히 p4-guid 문서를 참고합니다. https://p4.org/p4-spec/docs/P4-16-v1.2.0.html#sec-packet-parsing
이와 함께 cornell university의 자료를 참고합니다. https://cornell-pl.github.io/cs6114/lecture06.html lecture번호만 바꾸면 다른 문서도 참조할 수 있습니다.
마찬가지로 skeleton code: basic_tunnel.p4가 주어졌는데요, 이 파일은 basic tutorial의 정답 파일입니다.
0. topology
1. A new header type has been added called myTunnel_t that contains two 16-bit fields: proto_id and dst_id.
2. The myTunnel_t header has been added to the headers struct.
새로운 header가 정의되었다고 합니다.
// NOTE: added new header type
header myTunnel_t {
bit<16> proto_id;
bit<16> dst_id;
}
...
// NOTE: Added new header type to headers struct
struct headers {
ethernet_t ethernet;
myTunnel_t myTunnel;
ipv4_t ipv4;
}
생김새는 위와 같습니다. 16 bits의 proto_id와 16 bits의 dst_id가 추가되었습니다. 여기서 dst_id를 기준으로 routing을 해야 합니다.
3. TODO: Update the parser to extract either the myTunnel header or ipv4 header based on the etherType field in the Ethernet header.
The etherType corresponding to the myTunnel header is 0x1212. The parser should also extract the ipv4 header after the myTunnel header if proto_id == TYPE_IPV4 (i.e. 0x0800).
basic.p4를 한 번 해봤다면 익숙합니다. state parse_ethernet에서 TYPE_TUNNEL인 케이스를 추가해주면 되겠죠?
위 패킷 해더를 구분해서 프로그래밍 해줍시다! 설명에 적힌대로 my_tunnel을 parsing하고나서 IPv4를 parsing하는 것도 잊지 않도록 합시다.
/*************************************************************************
*********************** P A R S E R ***********************************
*************************************************************************/
// TODO: Update the parser to parse the myTunnel header as well
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_IPV4 : parse_ipv4;
TYPE_MYTUNNEL : parse_mytunnel;
default : accept;
}
}
state parse_mytunnel {
packet.extract(hdr.myTunnel);
transition select(hdr.myTunnel.proto_id) {
TYPE_IPV4 : parse_ipv4;
default: accept;
}
}
state parse_ipv4 {
packet.extract(hdr.ipv4);
transition accept;
}
}
4. TODO: Define a new action called myTunnel_forward that simply sets the egress port (i.e. egress_spec field of the standard_metadata bus) to the port number provided by the control plane.
설명만 읽으면 간단합니다. MyIngress control에서 action 하나를 추가하고 standard_metadata.egress_spec을 port로 지정해주면 됩니다.
control MyIngress(inout headers hdr,
...
// TODO: declare a new action: myTunnel_forward(egressSpec_t port)
action myTunnel_forward(egressSpec_t port) {
standard_metadata.egress_spec = port;
}
...
}
5. TODO: Define a new table called myTunnel_exact that perfoms an exact match on the dst_id field of the myTunnel header.
This table should invoke either the myTunnel_forward action if there is a match in the table and it should invoke the drop action otherwise.
table을 하나 지정해야 합니다. table 명은 주어진대로 myTunnel_exact이고, 이와 관련있는 정보가 무엇이 있을지는 s1-runtime.json을 통해 확인할 수 있습니다.
{
"table": "MyIngress.myTunnel_exact",
"match": {
"hdr.myTunnel.dst_id": [1]
},
"action_name": "MyIngress.myTunnel_forward",
"action_params": {
"port": 1
}
table에 들어갈 내용으로는 우리가 basic.p4를 작성하면서 봤던 table ipv4_lpm을 참고하면 눈치껏 작성할 수 있습니다!
// TODO: declare a new table: myTunnel_exact
// TODO: also remember to add table entries!
table myTunnel_exact {
key = {
hdr.myTunnel.dst_id: exact;
}
actions = {
myTunnel_forward;
drop;
}
size = 1024;
default_action = drop();
}
주의할 점은 key의 매칭 조건으로 lpm이 아니라 exact를 사용해야 합니다!
6. TODO: Update the apply statement in the MyIngress control block to apply your newly defined myTunnel_exact table if the myTunnel header is valid.
Otherwise, invoke the ipv4_lpm table if the ipv4 header is valid.
apply에 myTunnel이 isvalid인지 추가해줍니다. 기존의 ipv4는 else if로 감싸줍시다. 그렇지 않으면 마지막이 적용되는 것 같더라구요.
apply {
// TODO: Update control flow
if (hdr.myTunnel.isValid()) {
myTunnel_exact.apply();
} else if (hdr.ipv4.isValid()) {
ipv4_lpm.apply();
}
}
7. TODO: Update the deparser to emit the ethernet, then myTunnel, then ipv4 headers.
Remember that the deparser will only emit a header if it is valid. A header's implicit validity bit is set by the parser upon extraction. So there is no need to check header validity here.
우리는 basic.p4에서 packet.emit을 통해 MyDeparser를 완성했습니다. 이번에는 tunnel까지 포함시켜줍니다.
/*************************************************************************
*********************** D E P A R S E R *******************************
*************************************************************************/
control MyDeparser(packet_out packet, in headers hdr) {
apply {
packet.emit(hdr.ethernet);
// TODO: emit myTunnel header as well
packet.emit(hdr.myTunnel);
packet.emit(hdr.ipv4);
}
}
8. TODO: Add static rules for your newly defined table so that the switches will forward correctly for each possible value of dst_id.
See the diagram below for the topology's port configuration as well as how we will assign IDs to hosts. For this step you will need to add your forwarding rules to the sX-runtime.json files.
이 부분은 사실 할 게 없었습니다. s*-runtime.json을 보면 스위치별로 dst_id가 모두 알맞게 잘 들어가있었습니다.
테스트
1. pingall
pingall은 문제가 없습니다.
2. xterm 실행
xterm은 GUI가 실행 가능한 환경이어야 합니다.
xterm h1 h2
위와 같이 입력하면 h1, h2 쉘이 나타납니다.
3. send.py receive.py 실행
h2> ./receive.py
h1> ./send.py 10.0.2.2 "P4 is cool"
위를 각각 호스트의 쉘에 맞춰서 순서대로 입력해줍니다. receive.py와 send.py는 scapy 패키지를 이용해 작성된 raw packet 수신/전송 패키지입니다.
잘 전송이 되었네요! 화면이 작아서 잘 안보이지만 확대해보면 수신측에서도 P4 is cool을 받았음을 확인할 수 있습니다. 다만, 현재 사용한 명령어는 tunneling을 하지 않았습니다. basic.p4와 동일한 상황이죠.
4. tunneling test (10.0.2.2)
h1> ./send.py 10.0.2.2 "P4 is cool" --dst_id 2
이번에는 tunneling 옵션을 넣어서 전송해봅시다.
type에 TYPE_MYTUNNEL의 값인 0x1212, dst_id에는 옵션으로 준 2가 잘 들어갔음을 확인할 수 있었습니다.
5. tunneling test (10.0.3.3)
h1> ./send.py 10.0.3.3 "P4 is cool" --dst_id 2
이번에는 다른 호스트의 ip를 적습니다. 단, dst_id는 그대로 2를 유지합니다.
이번에는 내 호스트가 아닌데도 패킷이 도착했음을 확인할 수 있었습니다!! 이는 라우팅 기준이 ip가 아니라 MyTunnel의 dst_id이다보니 2를 기준으로 라우팅이 된 것을 확인할 수 있었습니다.
즉, 어떠한 IP를 입력해도 상관없이 dst_id만 2로 입력하면 h2에 도달합니다.
추가 질문
To make this tunneling exercise a bit more interesting (and realistic) how might you change the P4 code to have the switches add the myTunnel header to an IP packet upon ingress to the network and then remove the myTunnel header as the packet leaves to the network to an end host?
일반적인 vlan tag처럼 switch에 들어갈 때 목적지 IP를 기반으로 encapsulation하고, 마지막 스위치에서 host로 보낼 때에는 decapsulation하는 과정을 질문으로 남겼습니다. 이 부분도 추후에 기회가 되면 다시 돌아오겠습니다~
'프로그래밍 (Programming) > P4' 카테고리의 다른 글
5. P4 - ecn (0) | 2024.06.29 |
---|---|
4. P4 - P4runtime (0) | 2024.06.25 |
3. P4 - calc (0) | 2024.06.21 |
1. P4 - Basic (0) | 2024.06.17 |
0. P4 tutorial 환경 구성 (1) | 2024.06.16 |