버전 비교

  • 이 줄이 추가되었습니다.
  • 이 줄이 삭제되었습니다.
  • 서식이 변경되었습니다.

...

  • Fact : P4로 단순한 계산기를 구현해보고 실행해봤지만 생각대로 동작하지 않았다. 성과취합 추가분을 완성했다.
  • Feelings : 보던거랑 실제로 생각해서 구현하는 거랑 난이도가 너무 달랐다.
  • Finding : 아직 P4에 대해 1%도 알지 못한다는 것을 알았다.
  • Future Action Plan : P4로 만든 단순한 계산기를 생각대로 동작되도록 수정
  • Feedbacks :

23/02/23

  • Fact : 
  • Feelings : 
  • Finding : 
  • Future Action Plan : 
  • Feedbacks :

Memo

23/02/20

...

출처

내용

배운 점 및 기억해야할 점

비고

과학데이터교육 인공지능충북대 현장실습 직무교육
휴리스틱 탐색법과 최적,최고 우선 탐색, 탐욕적 탐색과 A*탐색, 적대적 탐색, 게임트리의 탐색, 지식 표현과 추론

23/02/23

출처

내용

배운 점 및 기억해야할 점

비고

과학데이터교육 인공지능충북대 현장실습 직무교육
휴리스틱 탐색법과 최적,최고 우선 탐색, 탐욕적 탐색과 A*탐색, 적대적 탐색, 게임트리의 탐색, 지식 표현과 추론

배운 것 및 기억해야할 것

P4 튜토리얼 Explicit Congestion Notification(ECN)의 이해

...

코드 블럭
/* -*- P4_16 -*- */
#include <core.p4>
#include <v1model.p4>

//새로운 헤더의 임시 타입넘버
const bit<16> TYPE_CALC = 0x1213;

/*************************************************************************
*********************** 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 calc_t{
    bit<2> operator;
    bit<7> operand1;
    bit<7> operand2;
    bit<7> result;
    bit<1> padding;
}
struct metadata {
    /* empty */
}

struct headers {
    ethernet_t   ethernet;
    calc_t       calc; 
}

/*************************************************************************
*********************** 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_CALC:parse_calc;
            default:accept;
        }
    }

    state parse_calc{
        packet.extract(hdr.calc);
        transition accept;
    }

}

/*************************************************************************
************   C H E C K S U M    V E R I F I C A T I O N   *************
*************************************************************************/

control MyVerifyChecksum(inout headers hdr, inout metadata meta) {
    apply {  }
}


/*************************************************************************
**************  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 calc_operand(macAddr_t dstAddr,egressSpec_t port, bit<2> operator) {
        if (operator==0){
             hdr.calc.result=hdr.calc.operand1+hdr.calc.operand2;
         }
         else if (operator==1){
             hdr.calc.result=hdr.calc.operand1-hdr.calc.operand2;
         }
         else if (operator==2){
             hdr.calc.result=hdr.calc.operand1*hdr.calc.operand2;
         }
        standard_metadata.egress_spec = port;
        hdr.ethernet.srcAddr = hdr.ethernet.dstAddr;
        hdr.ethernet.dstAddr = dstAddr;
    }

    table operator_exact {
        key = {
            hdr.calc.operator: exact;
        }
        actions = {
            calc_operand;
            drop;
            NoAction;
        }
        size = 1024;
        default_action = drop();
    }

    apply {
        if (hdr.calc.isValid()) {
            operator_exact.apply();
        }
    }
}

/*************************************************************************
****************  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) {
    apply {  }
}

/*************************************************************************
*************   C H E C K S U M    C O M P U T A T I O N   **************
*************************************************************************/

control MyComputeChecksum(inout headers  hdr, inout metadata meta) {
     apply {  }
}

/*************************************************************************
***********************  D E P A R S E R  *******************************
*************************************************************************/

control MyDeparser(packet_out packet, in headers hdr) {
    apply {
        packet.emit(hdr.ethernet);
        packet.emit(hdr.calc);
    }
}

/*************************************************************************
***********************  S W I T C H  *******************************
*************************************************************************/

V1Switch(
MyParser(),
MyVerifyChecksum(),
MyIngress(),
MyEgress(),
MyComputeChecksum(),
MyDeparser()
) main;

1차 실행결과

h1에서 h2로 패킷을 보내도 h2에서 받은 패킷의 헤더를 파싱해보면 result에 초기값이 들어있다. 

패킷을 보내는 과정을 제대로 손봐야 할것 같다.

코드 수정

simple_calc.p4 
코드 블럭
titlesimple_calc.p4
/* -*- P4_16 -*- */
#include <core.p4>
#include <v1model.p4>

const bit<16> TYPE_CALC = 0x1213;

/*************************************************************************
*********************** 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 calc_t{//각 필드의 비트값을 1byte로 수정
    bit<8> operator;
    bit<8> operand1;
    bit<8> operand2;
    bit<8> result;
}
struct metadata {
    /* empty */
}

struct headers {
    ethernet_t   ethernet;
    calc_t       calc; 
}

...동일

/*************************************************************************
**************  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 calc_operand(macAddr_t dstAddr,egressSpec_t port, bit<8> operator) {//operator의 bit를 1byte로 수정
        if (operator==0){
            hdr.calc.result=hdr.calc.operand1+hdr.calc.operand2;
        }
        else if (operator==1){
            hdr.calc.result=hdr.calc.operand1-hdr.calc.operand2;
        }
        else if (operator==2){
            hdr.calc.result=hdr.calc.operand1*hdr.calc.operand2;
        }
        else if (operator==3){
            hdr.calc.result=hdr.calc.operand1+hdr.calc.operand2;
        }
        standard_metadata.egress_spec = port;
        hdr.ethernet.srcAddr = hdr.ethernet.dstAddr;
        hdr.ethernet.dstAddr = dstAddr;
    }

 ...동일
send.py

h1에서 h2로 패킷을 보낼 때 사용하는 파이썬 스크립트

코드 블럭
titlesend.py
#!/usr/bin/env python3
import argparse
import random
import socket

from Calc_header import Calc
from scapy.all import *

TYPE_CALC = 0x1213

def get_if():
    ifs=get_if_list()
    iface=None # "h1-eth0"
    for i in get_if_list():
        if "eth0" in i:
            iface=i
            break;
    if not iface:
        print("Cannot find eth0 interface")
        exit(1)
    return iface

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--operator', type=int, help="0:+, 1:-, 2:*, 3:/")
    parser.add_argument('--oper1', type=int, help="operand1")
    parser.add_argument('--oper2', type=int, help='operand2')
    args = parser.parse_args()
    operator = args.operator
    oper1 = args.oper1
    oper2=args.oper2
    iface = get_if()

    pkt =  Ether(src=get_if_hwaddr(iface), dst='ff:ff:ff:ff:ff:ff')
    pkt = pkt / Calc(operator=operator,operand1=oper1,operand2=oper2)

    pkt.show2()
    sendp(pkt, iface=iface, verbose=False)


if __name__ == '__main__':
    main()
receive.py

h2에서 h1의 패킷을 받아서 출력하는 스크립트 파일

코드 블럭
#!/usr/bin/env python3
import os
import sys

from scapy.all import (
    TCP,
    FieldLenField,
    FieldListField,
    IntField,
    IPOption,
    ShortField,
    get_if_list,
    sniff
)
from scapy.layers.inet import _IPOption_HDR
from Calc_header import Calc


def get_if():
    ifs=get_if_list()
    iface=None
    for i in get_if_list():
        if "eth0" in i:
            iface=i
            break;
    if not iface:
        print("Cannot find eth0 interface")
        exit(1)
    return iface

def handle_pkt(pkt):
    print("got a packet")
    pkt.show2()

def main():
    ifaces = [i for i in os.listdir('/sys/class/net/') if 'eth' in i]
    iface = ifaces[0]
    print("sniffing on %s" % iface)
    sys.stdout.flush()
    sniff(iface = iface,
          prn = lambda x: handle_pkt(x))

if __name__ == '__main__':
    main()

calc_header.py

simplecalc.p4에서 구현한대로 만들 헤더, 이를 사용해서 send.py에서는 임의로 만든 calc헤더가 담긴 패킷을 보낼 수 있으며 receive.py에서는 받은 패킷을 clac헤더의 필드에 맞게 파싱하여 출력할수 있다.

코드 블럭
titleCalc_header.py
from scapy.all import *

TYPE_MYTUNNEL = 0x1213

class Calc(Packet):
    name = "Calc"
    fields_desc = [
        ByteField("operator", 0),
        ByteField("operand1", 0),
        ByteField("operand2", 0),
        ByteField("result", 0)
    ]

bind_layers(Ether, Calc, type=TYPE_MYTUNNEL)
topology.json

설계한 토폴로지

코드 블럭
titletopology.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.1.10 dev eth0",
                           "arp -i eth0 -s 10.0.1.10 08:00:00:00:01:00"]}
    },
    "switches": {
        "s1": { "runtime_json" : "pod-topo/s1-runtime.json" }
    },
    "links": [
        ["h1", "s1-p1"], ["h2","s1-p2"]
    ]
}

s1-runtime.json

s1의 포워딩 테이블 정적 정의

코드 블럭
titles1-runtime.json
{
  "target": "bmv2",
  "p4info": "build/basic.p4.p4info.txt",
  "bmv2_json": "build/basic.json",
  "table_entries": [
    {
      "table": "MyIngress.operator_exact",
      "default_action": true,
      "action_name": "MyIngress.drop",
      "action_params": { }
    },
    {
      "table": "MyIngress.operator_exact",
      "match": {
        "hdr.calc.operator": 0
      },
      "action_name": "MyIngress.calc_operand",
      "action_params": {
        "dstAddr": "08:00:00:00:02:22",
        "port": 2,
        "operator":0
      }
    },
    {
      "table": "MyIngress.operator_exact",
      "match": {
        "hdr.calc.operator": 1
      },
      "action_name": "MyIngress.calc_operand",
      "action_params": {
        "dstAddr": "08:00:00:00:02:22",
        "port": 2,
        "operator":1
      }
    },
    {
      "table": "MyIngress.operator_exact",
      "match": {
        "hdr.calc.operator": 2
      },
      "action_name": "MyIngress.calc_operand",
      "action_params": {
        "dstAddr": "08:00:00:00:02:22",
        "port": 2,
        "operator":2
      }
    },
    {
      "table": "MyIngress.operator_exact",
      "match": {
        "hdr.calc.operator": 3
      },
      "action_name": "MyIngress.calc_operand",
      "action_params": {
        "dstAddr": "08:00:00:00:02:22",
        "port": 2,
        "operator":3
      }
    }
  ]
}

2차 결과

Image AddedImage Added

h1에서 h2로 clac헤더의 operator필드에 1, operand1필드에 10 operand2필드에 6을 넣어서 패킷을 보냈을 때 h2에서 받은 패킷의 calc헤더의 result 필드가 16으로 바뀐것을 볼수있다.

operator를 1로 했을 때는 뺴기연산, operator를 2로 했을 때는 곱하기 연산의 결과가 result필드에 들어간것을 볼 수 있다.