- Today
- Total
Byeo
9. P4 - QoS 본문
이번 예제는 IP header에서 DiffServ field를 이용해서 packet의 유형을 분류하고 QoS를 제공하는 실습입니다. Real-world에서는 더 다른 방법으로 다양하게 사용하고 있겠으나, 이 예제에서는 UDP, TCP에 따라서 diffserv field 값을 변경합니다.
링크: https://github.com/p4lang/tutorials/tree/master/exercises/qos
0. topology
1. Test Run
이번에도 바로 시작해봅니다.
make run
mininet> xterm h1 h2
h2> ./receive.py
h1> ./send.py --p=UDP --des=10.0.2.2 --m="P4 is cool" --dur=30
h1> ./send.py --p=TCP --des=10.0.2.2 --m="P4 is cool" --dur=30
위를 실행하면 h2에서는 protocol (UDP, TCP)에 무관하게 항상 tos가 0x1이 찍히는 것을 확인할 수 있습니다. h2에 received packet과 sent packet이 동시에 찍히므로 주의해서 확인해야 합니다.
2. header
이번에도 역시 header부터 확인해봅시다.
const bit<16> TYPE_IPV4 = 0x800;
/* IP protocols */
const bit<8> IP_PROTOCOLS_ICMP = 1;
const bit<8> IP_PROTOCOLS_IGMP = 2;
const bit<8> IP_PROTOCOLS_IPV4 = 4;
const bit<8> IP_PROTOCOLS_TCP = 6;
const bit<8> IP_PROTOCOLS_UDP = 17;
const bit<8> IP_PROTOCOLS_IPV6 = 41;
const bit<8> IP_PROTOCOLS_GRE = 47;
const bit<8> IP_PROTOCOLS_IPSEC_ESP = 50;
const bit<8> IP_PROTOCOLS_IPSEC_AH = 51;
const bit<8> IP_PROTOCOLS_ICMPV6 = 58;
const bit<8> IP_PROTOCOLS_EIGRP = 88;
const bit<8> IP_PROTOCOLS_OSPF = 89;
const bit<8> IP_PROTOCOLS_PIM = 103;
const bit<8> IP_PROTOCOLS_VRRP = 112;
/*************************************************************************
*********************** 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;
}
/*
* TODO: split tos to two fields 6 bit diffserv and 2 bit ecn
*/
header ipv4_t {
bit<4> version;
bit<4> ihl;
bit<8> tos;
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 {
}
struct headers {
ethernet_t ethernet;
ipv4_t ipv4;
}
주석에 적혀있듯, IPv4 field중에서 tos를 6 bits의 diffserv와 2bits의 ecn으로 나누라고 합니다.
바로 나눠줍니다!
header ipv4_t {
bit<4> version;
bit<4> ihl;
bit<6> diffserv;
bit<2> ecn;
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;
}
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) {
TYPE_IPV4: parse_ipv4;
default: accept;
}
}
state parse_ipv4 {
packet.extract(hdr.ipv4);
transition accept;
}
}
parser는 별 특이사항이 없습니다. ethernet의 type을 확인하여 TYPE_IPV4인지 체크하고, 맞다면 ipv4를 parsing합니다.
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 ipv4_forward(macAddr_t dstAddr, egressSpec_t port) {
standard_metadata.egress_spec = port;
hdr.ethernet.srcAddr = hdr.ethernet.dstAddr;
hdr.ethernet.dstAddr = dstAddr;
hdr.ipv4.ttl = hdr.ipv4.ttl - 1;
}
/* TODO: Implement actions for different traffic classes */
table ipv4_lpm {
key = {
hdr.ipv4.dstAddr: lpm;
}
actions = {
ipv4_forward;
drop;
NoAction;
}
size = 1024;
default_action = NoAction();
}
/* TODO: set hdr.ipv4.diffserv on the basis of protocol */
apply {
if (hdr.ipv4.isValid()) {
ipv4_lpm.apply();
}
}
}
ingress control은 몇 가지 작성해야 할 내용이 있습니다. 먼저, apply에서 hdr.ipv4.protocol에 따라 값을 설정하는 action을 작성합니다.
apply {
if (hdr.ipv4.isValid()) {
if (hdr.ipv4.protocol == IP_PROTOCOLS_UDP) {
set_diffserv_udp();
} else if (hdr.ipv4.protocol == IP_PROTOCOLS_TCP) {
set_diffserv_tcp();
}
ipv4_lpm.apply();
}
}
그리고 set_diffserv_udp와 set_diffserv_tcp action을 작성합니다. 값은 설명에 명시된 내용이 없어서 solution을 참고했습니다.
/* TODO: Implement actions for different traffic classes */
action set_diffserv_udp() {
hdr.ipv4.diffserv = 46;
}
action set_diffserv_tcp() {
hdr.ipv4.diffserv = 44;
}
diffserv의 값은 위키를 참조하면 좋을 듯 합니다: https://en.wikipedia.org/wiki/Differentiated_services
5. MyComputeChecksum
field의 항목이 변경됨에 따라 checksum을 재계산하는 곳도 일부 수정되어야 합니다.
control MyComputeChecksum(inout headers hdr, inout metadata meta) {
apply {
/* TODO: replace tos with diffserv and ecn */
update_checksum(
hdr.ipv4.isValid(),
{ hdr.ipv4.version,
hdr.ipv4.ihl,
hdr.ipv4.diffserv,
hdr.ipv4.ecn,
hdr.ipv4.totalLen,
hdr.ipv4.identification,
hdr.ipv4.flags,
hdr.ipv4.fragOffset,
hdr.ipv4.ttl,
hdr.ipv4.protocol,
hdr.ipv4.srcAddr,
hdr.ipv4.dstAddr },
hdr.ipv4.hdrChecksum,
HashAlgorithm.csum16);
}
}
Run
Test Run때와 동일하게 h1, h2를 각각 실행합니다.
UDP
0xb9를 받았음을 확인했습니다.
TCP
0xb1을 받았음을 확인했습니다.
'프로그래밍 (Programming) > P4' 카테고리의 다른 글
10. P4 - multicast (0) | 2024.07.06 |
---|---|
8. P4 - load balancing (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 |