...
- 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
코드 블럭 | ||
---|---|---|
| ||
/* -*- 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로 패킷을 보낼 때 사용하는 파이썬 스크립트
코드 블럭 | ||
---|---|---|
| ||
#!/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헤더의 필드에 맞게 파싱하여 출력할수 있다.
코드 블럭 | ||
---|---|---|
| ||
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
설계한 토폴로지
코드 블럭 | ||
---|---|---|
| ||
{
"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의 포워딩 테이블 정적 정의
코드 블럭 | ||
---|---|---|
| ||
{
"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차 결과
h1에서 h2로 clac헤더의 operator필드에 1, operand1필드에 10 operand2필드에 6을 넣어서 패킷을 보냈을 때 h2에서 받은 패킷의 calc헤더의 result 필드가 16으로 바뀐것을 볼수있다.
operator를 1로 했을 때는 뺴기연산, operator를 2로 했을 때는 곱하기 연산의 결과가 result필드에 들어간것을 볼 수 있다.