Byeo

10. P4 - multicast 본문

프로그래밍 (Programming)/P4

10. P4 - multicast

BKlee 2024. 7. 6. 22:38
반응형

Multicast는 라우터에 multicast packet이 유입되면 특정 그룹에 속한 host들에게 모두 전달하는 것을 의미합니다. 연결만 되어있다고 전달하는 것은 아니고, 같은 그룹에 속해있음을 host가 사전에 라우터에게 등록해야 합니다.

 

이번 예제에서는 목적지 mac address가 일치하는 호스트가 존재한다면 forwarding을, 그렇지 않다면 mutlciast group에게 전부 packet을 전달하는 코드를 작성합니다.

 

https://github.com/p4lang/tutorials/tree/master/exercises/multicast

 

tutorials/exercises/multicast 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> h1 ping h2
mininet> pingall

 

위 ping에 대해서 모두 실패하는 것을 확인할 수 있습니다.

 

Why?

그런데.. 왜 실패할까요? multicast 요청도 아니고, ping은 그냥 성공해야 하는 것 아닐까요?

 

사실 이 환경에서 문제는 ARP에 있습니다. ARP를 모두 drop하기 때문이죠. 간단히 눈으로 확인하는 방법으로 xterm h1 h2를 입력하여 두 호스트를 열고 tcpdump를 거는 방법이 있겠습니다.

 

 

h1에서 계속 ARP request를 보내는데, 그 응답을 받지 못하는 것이죠. 따라서 h2의 mac address를 알 수 없어서 통신이 불가합니다.

 

ARP response만 받고나면 그 다음부터 ping의 destination mac address는 h2의 mac address가 쓰여질 것이므로 mac_fowarding action이 취해져 통신이 가능해집니다.

 

 

2. Header

/*************************************************************************
*********************** 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;
}


struct metadata {
    /* empty */
}

struct headers {
    ethernet_t   ethernet;
}

 

header는 정말 단순합니다. ethernet만 확인합니다.

 

 

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) {
            default : accept;
        }
    }
}

 

parser도 마찬가지로 ethernet만 hdr에 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);
    }

    // TODO: define `multicast` action to multicast packets to group 1
    // Hint: Check v1model for multicast group

    action mac_forward(egressSpec_t port) {
        standard_metadata.egress_spec = port;
    }

    table mac_lookup {
        key = {
            hdr.ethernet.dstAddr : exact;
        }
        actions = {
            // TODO: add `multicast` action to the list of available actions
            mac_forward;
            drop;
        }
        size = 1024;
        // TODO : replace default drop action by multicast
        default_action = drop;
    }
    apply {
        if (hdr.ethernet.isValid())
            mac_lookup.apply();
    }
}

 

ingress control은 작업해야 할 내용이 있습니다. ethernet header가 valid하다면 mac_lookup table을 적용합니다. 

 

현재 multicast action이 빠져있으므로 추가해줍니다. 

    // TODO: define `multicast` action to multicast packets to group 1
    // Hint: Check v1model for multicast group
    action multicast() {

    }

 

 

그리고 mac이 조회가 되지 않는 경우에는 drop이 아니라 multicast를 해야하므로 mac_lookup table의 default_action도 수정해줍니다.

    table mac_lookup {
        key = {
            hdr.ethernet.dstAddr : exact;
        }
        actions = {
            multicast;
            mac_forward;
            drop;
        }
        size = 1024;
        default_action = multicast;
    }

 

 

4-1. action multicast()

multicast action을 작성해야 합니다.

 

주석에서 알려주는 힌트대로 v1model을 살펴봅니다. ( /usr/local/share/p4c/p4include/v1model.p4)

 

해당 파일을 살펴보면 multicast group과 관련된 내용이 다음과 같이 있습니다.

struct standard_metadata_t {
#if V1MODEL_VERSION >= 20200408
    PortId_t    ingress_port;
    PortId_t    egress_spec;
    PortId_t    egress_port;
#else
    bit<9>      ingress_port;
    bit<9>      egress_spec;
    bit<9>      egress_port;
#endif
    bit<32>     instance_type;
    bit<32>     packet_length;

    ...

    /// multicast group id (key for the mcast replication table)
    @alias("intrinsic_metadata.mcast_grp")
    bit<16> mcast_grp;
    /// Replication ID for multicast
    @alias("intrinsic_metadata.egress_rid")
    
    ...
}

 

 

보면 mcast_grp라는 변수가 standard_metadata에 들어있는 것을 확인할 수 있습니다.

    action multicast() {
        standard_metadata.mcast_grp = 1;
    }

 

단순하게 값을 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 drop() {
        mark_to_drop(standard_metadata);
    }

    apply {
        // Prune multicast packet to ingress port to preventing loop
        if (standard_metadata.egress_port == standard_metadata.ingress_port)
            drop();
    }
}

 

egress control을 확인해보면 standard_metadata.egress_port와 standard_metadata.ingress_port가 같으면 drop()을 하라고 되어있습니다. 이는 multicast packet을 요청한 host에게 다시 되돌아가는 것을 방지하기 위함입니다.

 

 

중간 점검

mininet> pingall
*** Ping: testing ping reachability
h1 -> h2 h3 X
h2 -> h1 h3 X
h3 -> h1 h2 X
h4 -> h1 h2 h3
*** Results: 25% dropped (9/12 received)

이 상태에서 바로 pingall을 실행하면 h4에게만 packet이 도달하지 않는 것을 확인할 수 있습니다.

 

 

6. s1-runtime.json 수정

sig-topo/s1-runtime.json의 맨 하단에 누락되어 있던 egress_port4 관련 json object를 하나 추가해줍니다.

  "multicast_group_entries": [
    {
      "multicast_group_id": 1,
      "replicas": [
        {
          "egress_port": 1,
          "instance": 1
        },
        {
          "egress_port": 2,
          "instance": 1
        },
        {
          "egress_port": 3,
          "instance": 1
        },
        {
          "egress_port": 4,
          "instance": 1
        }
      ]
    }

 

 

Run

mininet> pingall
*** Ping: testing ping reachability
h1 -> h2 h3 h4
h2 -> h1 h3 h4
h3 -> h1 h2 h4
h4 -> h1 h2 h3
*** Results: 0% dropped (12/12 received)

 

바로 pingall이 성공하는 것을 확인할 수 있습니다.

 

 

어느새 P4 tutorial도 2개밖에 안남았습니다. 빠르네요.

반응형

'프로그래밍 (Programming) > P4' 카테고리의 다른 글

9. P4 - QoS  (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