- Today
- Total
Byeo
8. P4 - load balancing 본문
이번 튜토리얼은 ECMP (Equal-Cost Multi-Path)을 활용한 load balancing switching 구현입니다. ECMP란, 기존에 lpm 등의 방식으로 단 하나의 routing entry를 선택하는 것과는 달리, ECMP는 서로 다른 routing entry에 가중치를 동일하게 두고 hash value를 통해 결정짓는 기법입니다. 이를 통해서 하나의 호스트에서 출발한 packet은 ECMP의 지원을 받아 여러 호스트에 분산되어 도착할 수 있게 됩니다.
2개의 테이블이 존재하며, 첫 번째 테이블은 5-tuple에 따른 hash 계산을, 두 번째 테이블은 계산된 hash value를 기반으로 목적지 host를 결정합니다.
https://github.com/p4lang/tutorials/tree/master/exercises/load_balance
0. Topology
1. Test Run
이번에도 먼저 테스트를 진행해 봅니다. 컴파일 후, h1 h2 h3을 모두 켜본 뒤에 h2 h3은 receive.py를, h1은 send.py를 실행합니다.
이 경우 h1에서 send.py를 몇 번 실행해도 h3에는 패킷이 도달하지 않는 것을 확인할 수 있습니다. 참고로 host IP가 아닌, 10.0.0.1이라는 게이트웨이 ip로 packet을 전송하는 구조입니다.
make run
mininet> xterm h1 h2 h3
h2> ./receive.py
h3> ./receive.py
h1> ./send.py 10.0.0.1 "P4 is cool"
h1> ./send.py 10.0.0.1 "P4 is cool"
h1> ./send.py 10.0.0.1 "P4 is cool"
h1> ./send.py 10.0.0.1 "P4 is cool"
2. Parser
/*************************************************************************
*********************** H E A D E R S ***********************************
*************************************************************************/
header ethernet_t {
bit<48> dstAddr;
bit<48> srcAddr;
bit<16> etherType;
}
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;
bit<32> srcAddr;
bit<32> dstAddr;
}
header tcp_t {
bit<16> srcPort;
bit<16> dstPort;
bit<32> seqNo;
bit<32> ackNo;
bit<4> dataOffset;
bit<3> res;
bit<3> ecn;
bit<6> ctrl;
bit<16> window;
bit<16> checksum;
bit<16> urgentPtr;
}
struct metadata {
bit<14> ecmp_select;
}
struct headers {
ethernet_t ethernet;
ipv4_t ipv4;
tcp_t tcp;
}
이번에 헤더는 수정할 내용이 없습니다. 특이한 점은 header tcp_t까지 구현이 되어있네요.
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);
transition select(hdr.ethernet.etherType) {
0x800: parse_ipv4;
default: accept;
}
}
state parse_ipv4 {
packet.extract(hdr.ipv4);
transition select(hdr.ipv4.protocol) {
6: parse_tcp;
default: accept;
}
}
state parse_tcp {
packet.extract(hdr.tcp);
transition accept;
}
}
parser도 마찬가지로 수정할 내용은 없습니다. tcp까지 지원하는지 확인하고 tcp hdr까지 모두 파싱 합니다.
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 set_ecmp_select(bit<16> ecmp_base, bit<32> ecmp_count) {
/* TODO: hash on 5-tuple and save the hash result in meta.ecmp_select
so that the ecmp_nhop table can use it to make a forwarding decision accordingly */
}
action set_nhop(bit<48> nhop_dmac, bit<32> nhop_ipv4, bit<9> port) {
hdr.ethernet.dstAddr = nhop_dmac;
hdr.ipv4.dstAddr = nhop_ipv4;
standard_metadata.egress_spec = port;
hdr.ipv4.ttl = hdr.ipv4.ttl - 1;
}
table ecmp_group {
key = {
hdr.ipv4.dstAddr: lpm;
}
actions = {
drop;
set_ecmp_select;
}
size = 1024;
}
table ecmp_nhop {
key = {
meta.ecmp_select: exact;
}
actions = {
drop;
set_nhop;
}
size = 2;
}
apply {
/* TODO: apply ecmp_group table and ecmp_nhop table if IPv4 header is
* valid and TTL hasn't reached zero
*/
ecmp_group.apply();
ecmp_nhop.apply();
}
}
ingress control에는 구현할 내용이 있습니다. 먼저 apply부터 수정해 보죠. ipv4 header가 valid고 TTL이 0이 아니라면 두 action들을 실행하도록 수정합니다.
apply {
if (hdr.ipv4.isValid() && hdr.ipv4.ttl >0) {
ecmp_group.apply();
ecmp_nhop.apply();
}
}
다음은 ecmp_select를 수정해 줍니다. 이 부분은 튜토리얼의 설명에서 해결이 불가능하여 솔루션을 참조했습니다. hash 함수 구조는 extern void hash<O, T, D, M>(out O result, in HashAlgorithm algo, in T base, in D data, in M max); 와 같으며, /usr/local/share/p4c/p4include/v1model.p4 에 선언되어 있습니다.
/***
* Calculate a hash function of the value specified by the data
* parameter. The value written to the out parameter named result
* will always be in the range [base, base+max-1] inclusive, if max >=
* 1. If max=0, the value written to result will always be base.
*
* Note that the types of all of the parameters may be the same as, or
* different from, each other, and thus their bit widths are allowed
* to be different.
*
* @param O Must be a type bit<W>
* @param D Must be a tuple type where all the fields are bit-fields (type bit<W> or int<W>) or varbits.
* @param T Must be a type bit<W>
* @param M Must be a type bit<W>
*/
@pure
extern void hash<O, T, D, M>(out O result, in HashAlgorithm algo, in T base, in D data, in M max);
action set_ecmp_select(bit<16> ecmp_base, bit<32> ecmp_count) {
hash(meta.ecmp_select,
HashAlgorithm.crc16,
ecmp_base,
{ hdr.ipv4.srcAddr,
hdr.ipv4.dstAddr,
hdr.ipv4.protocol,
hdr.tcp.srcPort,
hdr.tcp.dstPort },
ecmp_count);
}
5-tuple과 ecmp_base, ecmp_count값을 기반으로 값을 계산하여 meta.ecmp_select에 넣어주는 것으로 보입니다. ecmp_base, ecmp_count 값은 각 s{num}-runtime.json 마다 정의가 되어있습니다. s1에서는 ecmp_count가 2, 나머지는 1입니다.
5. Egress control
/*************************************************************************
**************** E G R E S S P R O C E S S I N G *******************
*************************************************************************/
control MyEgress(inout headers hdr,
inout metadata meta,
inout standard_metadata_t standard_metadata) {
action rewrite_mac(bit<48> smac) {
hdr.ethernet.srcAddr = smac;
}
action drop() {
mark_to_drop(standard_metadata);
}
table send_frame {
key = {
standard_metadata.egress_port: exact;
}
actions = {
rewrite_mac;
drop;
}
size = 256;
}
apply {
send_frame.apply();
}
}
egress_control은 결정된 포트에 맞추어 MAC 주소를 source mac address를 변경하는 작업을 수행합니다.
Run
Test run때와 동일하게 실행합니다. 이번에는 send.py를 몇 번 실행하다 보면 h2와 h3에 packet이 모두 잘 도착하는 것을 확인할 수 있습니다.
'프로그래밍 (Programming) > P4' 카테고리의 다른 글
10. P4 - multicast (0) | 2024.07.06 |
---|---|
9. P4 - QoS (0) | 2024.07.06 |
7. P4 - source routing (0) | 2024.07.04 |
6. P4 - mri (0) | 2024.06.29 |
5. P4 - ecn (0) | 2024.06.29 |