Byeo

9. P4 - QoS 본문

프로그래밍 (Programming)/P4

9. P4 - QoS

BKlee 2024. 7. 6. 20:11
반응형

이번 예제는 IP header에서 DiffServ field를 이용해서 packet의 유형을 분류하고 QoS를 제공하는 실습입니다. Real-world에서는 더 다른 방법으로 다양하게 사용하고 있겠으나, 이 예제에서는 UDP, TCP에 따라서 diffserv field 값을 변경합니다.

 

링크: https://github.com/p4lang/tutorials/tree/master/exercises/qos

 

tutorials/exercises/qos at master · p4lang/tutorials

P4 language tutorials. Contribute to p4lang/tutorials development by creating an account on GitHub.

github.com

 

 

 

 

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

 

Differentiated services - Wikipedia

From Wikipedia, the free encyclopedia Networking architecture for prioritizing traffic Differentiated services or DiffServ is a computer networking architecture that specifies a mechanism for classifying and managing network traffic and providing quality o

en.wikipedia.org

 

 

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
Comments