- Today
- Total
Byeo
7. P4 - source routing 본문
패킷은 도착지까지 안전하게 도착하기 위하여 항상 경로가 적절하게 설정되어야 합니다. 일반적인 라우팅은 ISP가 적절히 이를 설정해 주기 때문에 우리가 신경 쓸 필요가 없습니다.
Source routing은 IP header option의 지원을 받아서 packet의 길을 sender가 정하는 기법입니다. (RFC 791)
이번 P4 tutorial은 source routing입니다. https://github.com/p4lang/tutorials/tree/master/exercises/source_routing
tutorials/exercises/source_routing at master · p4lang/tutorials
P4 language tutorials. Contribute to p4lang/tutorials development by creating an account on GitHub.
github.com
0. topology
bklee@bklee:~/p4/tutorials/exercises/source_routing$ cat topology.json
{
"hosts": {
"h1": {"ip": "10.0.1.1/24", "mac": "08:00:00:00:01:11",
"commands":["route add default gw 10.0.1.10 dev eth0",
"arp -i eth0 -s 10.0.1.10 08:00:00:00:01:00"]},
"h2": {"ip": "10.0.2.2/24", "mac": "08:00:00:00:02:22",
"commands":["route add default gw 10.0.2.20 dev eth0",
"arp -i eth0 -s 10.0.2.20 08:00:00:00:02:00"]},
"h3": {"ip": "10.0.3.3/24", "mac": "08:00:00:00:03:33",
"commands":["route add default gw 10.0.3.30 dev eth0",
"arp -i eth0 -s 10.0.3.30 08:00:00:00:03:00"]}
},
"switches": {
"s1": { "runtime_json" : "s1-runtime.json" },
"s2": { "runtime_json" : "s2-runtime.json" },
"s3": { "runtime_json" : "s3-runtime.json" }
},
"links": [
["h1", "s1-p1"], ["s1-p2", "s2-p2"], ["s1-p3", "s3-p2"],
["s3-p3", "s2-p3"], ["h2", "s2-p1"], ["h3", "s3-p1"]
]
}
1. Test run
튜토리얼에서 제안한 대로 테스트 실행을 해봅니다.
make run
h1, h2에 대해 xterm을 실행합니다.
mininet> xterm h1 h2
h1, h2 각각에 python program을 실행합니다.
h2> ./receive.py
h1> ./send.py 10.0.2.2
Type space separated port nums (example: "2 3 2 2 1") or "q" to quit: 2 3 2 2 1
h1에서 send.py를 실행하면 경로를 입력하라는 안내메시지가 출력됩니다. 여기에 2 3 2 2 1을 입력해 줍니다. 이 경로는 다음과 같습니다.
아쉽게도 h2에 도착하는 packet이 없습니다. source routing이 구현되지 않았기 때문이죠.
2. Headers
P4 튜토리얼을 몇 번 반복하다 보니 이제는 header를 먼저 보는 것이 익숙해졌습니다.
const bit<16> TYPE_IPV4 = 0x800;
const bit<16> TYPE_SRCROUTING = 0x1234;
#define MAX_HOPS 9
/*************************************************************************
*********************** H E A D E R S ***********************************
*************************************************************************/
typedef bit<9> egressSpec_t;
typedef bit<48> macAddr_t;
typedef bit<32> ip4Addr_t;
header ethernet_t {
macAddr_t dstAddr;
macAddr_t srcAddr;
bit<16> etherType;
}
header srcRoute_t {
bit<1> bos;
bit<15> port;
}
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 {
/* empty */
}
struct headers {
ethernet_t ethernet;
srcRoute_t[MAX_HOPS] srcRoutes;
ipv4_t ipv4;
}
이 튜토리얼에서는 packet header가 ethernet 다음으로 최대 9개까지의 routing 경로를 지정할 수 있는 srcRoutes, 그리고 마지막으로 ipv4가 오는 구성임을 알 수 있습니다.
srcRoute_t는 1 bit의 bos와 15 bits의 port로 구성되어 있습니다.
bos는 마지막일 경우에만 1로 set이 되는 변수입니다.
3. parser 구현
/*************************************************************************
*********************** 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);
/*
* TODO: Modify the next line to select on hdr.ethernet.etherType
* If the value is TYPE_SRCROUTING transition to parse_srcRouting
* otherwise transition to accept.
*/
transition accept;
}
state parse_srcRouting {
/*
* TODO: extract the next entry of hdr.srcRoutes
* while hdr.srcRoutes.last.bos is 0 transition to this state
* otherwise parse ipv4
*/
transition accept;
}
state parse_ipv4 {
packet.extract(hdr.ipv4);
transition accept;
}
}
parser를 구현합니다. TODO를 우리 hdr 구조에 맞게 작성하면 됩니다.
/*************************************************************************
*********************** 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_SRCROUTING: parse_srcRouting;
default: accept;
}
}
state parse_srcRouting {
packet.extract(hdr.srcRoutes.next);
transition select(hdr.srcRoutes.last.bos) {
1w0: parse_srcRouting;
default: parse_ipv4;
}
}
state parse_ipv4 {
packet.extract(hdr.ipv4);
transition accept;
}
}
4. Ingress Control
/*************************************************************************
************** 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) {
action drop() {
mark_to_drop(standard_metadata);
}
action srcRoute_nhop() {
/*
* TODO: set standard_metadata.egress_spec
* to the port in hdr.srcRoutes[0] and
* pop an entry from hdr.srcRoutes
*/
}
action srcRoute_finish() {
hdr.ethernet.etherType = TYPE_IPV4;
}
action update_ttl(){
hdr.ipv4.ttl = hdr.ipv4.ttl - 1;
}
apply {
if (hdr.srcRoutes[0].isValid()){
/*
* TODO: add logic to:
* - If final srcRoutes (top of stack has bos==1):
* - change etherType to IP
* - choose next hop and remove top of srcRoutes stack
*/
if (hdr.ipv4.isValid()){
update_ttl();
}
}else{
drop();
}
}
}
ingess control은 srcRoute_nhop과 apply block을 채우면 됩니다.
srcRoute_nhop에서는 설명대로 port를 지정하고, source routing path에서 한 엔트리를 제거합니다.
action srcRoute_nhop() {
standard_metadata.egress_spec = (bit<9>)hdr.srcRoutes[0].port;
hdr.srcRoutes.pop_front(1);
}
- hdr.srcRoutes[0].port는 15 bits인데 반해, egress_spec은 9 bits입니다. 캐스팅이 없으면 컴파일할 때 에러가 발생하므로, (bit<9>)를 앞에 붙여서 캐스팅해줍시다.
- 배열을 하나씩 당기는 것은 이전 튜토리얼에서도 다뤘지만 pop_front를 통해서 쉽게할 수 있습니다.
apply {
if (hdr.srcRoutes[0].isValid()){
if (hdr.srcRoutes[0].bos == 1) {
hdr.ethernet.etherType = TYPE_IPV4;
}
srcRoute_nhop();
if (hdr.ipv4.isValid()){
update_ttl();
}
}else{
drop();
}
}
apply logic은 별 내용 없습니다. 주석에 적힌대로 코드를 작성해주기만 하면 됩니다.
Run
receiver쪽에서 잘 받은 것을 확인할 수 있었습니다.
그다지 어렵지 않은 예제였습니다~
'프로그래밍 (Programming) > P4' 카테고리의 다른 글
9. P4 - QoS (0) | 2024.07.06 |
---|---|
8. P4 - load balancing (0) | 2024.07.06 |
6. P4 - mri (0) | 2024.06.29 |
5. P4 - ecn (0) | 2024.06.29 |
4. P4 - P4runtime (0) | 2024.06.25 |