...
코드 블럭 | ||
---|---|---|
| ||
/* -*- P4_16 -*- */ #include <core.p4> #include <v1model.p4> const bit<16> TYPE_IPV4 = 0x800; /************************************************************************* *********************** H E A D E R S *********************************** *************************************************************************/ typedef bit<9> egressSpec_t; typedef bit<48> macAddr_t; typedef bit<32> ip4Addr_t; //ethernet의 기본 헤더 header ethernet_t { macAddr_t dstAddr; macAddr_t srcAddr; bit<16> etherType; } //IPv4의 기본 헤더 header ipv4_t { bit<4> version; bit<4> ihl; bit<8> diffserv; 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 { /* empty */ } struct headers { ethernet_t ethernet; ipv4_t ipv4; } /************************************************************************* *********************** P A R S E R *********************************** *************************************************************************/ //패킷에서 헤더를 분리 //packet_in packet은 스위치에 들어오는 패킷 //out headers hdr은 패킷에서 분리된 헤더들이 각각 저장될 변수같은것 //start 상태로 시작해서 모든 헤더 분리가 정상적으로 끝난다면 accept 상태로 이동해서 정상종료, 아니라면 ignore 상태로 이동 parser MyParser(packet_in packet, out headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { //패킷을 처음으로 전달받아서 시작된 상태 state start { //parse_ethernet으로 상태 이동 transition parse_ethernet; } state parse_ethernet { //패킷에서 ethernet헤더에 맞게 분리/추출 packet.extract(hdr.ethernet); //패킷에서 분리된 ethernet 헤더에서 etherType 값이 위에서 정의된 TYPE_IPV4 0x800라면 parse_ipv4 상태로 이동, 0x800이 아닌 상태(default)라면 accept상태로 이동 -> 즉 c언어의 switch 같은 문법 transition select(hdr.ethernet.etherType) { TYPE_IPV4: parse_ipv4; default: accept; } } state parse_ipv4 { //패킷에서 추가적으로 ipv4 헤더 분리/추출 packet.extract(hdr.ipv4); //패킷에서 추출 후에 accept 상태로 이동 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 ******************* *************************************************************************/ //table을 참조하면서 패킷이 다음으로 이동할 경로 설정 control MyIngress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { //table에 match되는 ipv4의 dstAddr이 없다면 패킷을 삭제한다. action drop() { mark_to_drop(standard_metadata); } //table에 match되는 ipv4의 dstAddr이 있다면 실행되는 action으로 알맞은 dstAddr와 port를 인수로 전달받는다. action ipv4_forward(macAddr_t dstAddr, egressSpec_t port) { //해당 스위치/호스트에서 송신할때 쓰는 포트를 설정 //standard_metadata는 v1model 아키텍처에 의해 전달받은 구조체이며 패킷의 다양한 정보가 들어있다. 특히 standard_metadata.egress_spec는 패킷이 이동할 출력포트를 지정한다. standard_metadata.egress_spec = port; //이더넷의 헤더안의 srtAddr과 dstAddr을 알맞게 설정한다. hdr.ethernet.srcAddr = hdr.ethernet.dstAddr; hdr.ethernet.dstAddr = dstAddr; //패킷이 이동할 때마다 ipv4의 ttl을 1씩 줄어들게한다. hdr.ipv4.ttl = hdr.ipv4.ttl - 1; } //테이블을 정의한다. table ipv4_lpm { //테이블의 key와 match되는 방식을 설정한다. key = { hdr.ipv4.dstAddr: lpm; } //테이블의 모든 액션을 정의한다. actions = { ipv4_forward; drop; NoAction; } size = 1024; //기본 액션을 정의한다. default_action = drop(); } //컨트롤 실행 apply { //ipv4가 유효하다면 테이블 매칭을 실행한다. if (hdr.ipv4.isValid()) { ipv4_lpm.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 ************** *************************************************************************/ //ipv4 헤더의 내용이 변경되었으므로 체크섬 값도 그에 맞게 변경 control MyComputeChecksum(inout headers hdr, inout metadata meta) { apply { update_checksum( hdr.ipv4.isValid(), { hdr.ipv4.version, hdr.ipv4.ihl, hdr.ipv4.diffserv, 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); } } /************************************************************************* *********************** D E P A R S E R ******************************* *************************************************************************/ //새롭게 변경된 헤더들을 패킷으로 다시 묶음 control MyDeparser(packet_out packet, in headers hdr) { apply { packet.emit(hdr.ethernet); packet.emit(hdr.ipv4); } } /************************************************************************* *********************** S W I T C H ******************************* *************************************************************************/ //v1model의 기본적인 switch 아키텍처 V1Switch( MyParser(), MyVerifyChecksum(), MyIngress(), MyEgress(), MyComputeChecksum(), MyDeparser() ) main; |
...
코드 블럭 |
---|
/* -*- P4_16 -*- */ #include <core.p4> #include <v1model.p4> //새로운 사용자 설정 이더넷 타입 추가 const bit<16> TYPE_MYTUNNEL = 0x1212; const bit<16> TYPE_IPV4 = 0x800; /************************************************************************* *********************** 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 myTunnel_t { bit<16> proto_id; bit<16> dst_id; } header ipv4_t { bit<4> version; bit<4> ihl; bit<8> diffserv; 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 { /* empty */ } //패킷의 헤더 구조체에 터널링 헤더 추가 struct headers { ethernet_t ethernet; myTunnel_t myTunnel; ipv4_t ipv4; } /************************************************************************* *********************** 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) { //이더넷타입이 새로 만든 타입이라면 parse_myTunnel로 헤더 분리 이더넷타입에 따른 파서를 수행한다. TYPE_MYTUNNEL: parse_myTunnel; TYPE_IPV4: parse_ipv4; default: accept; } } state parse_myTunnel { //터널링 헤더 분리 packet.extract(hdr.myTunnel); //이후에 터널링 헤더 안의 proto_id가 ipv4라면 ipv4 헤더도 분리 transition select(hdr.myTunnel.proto_id) { TYPE_IPV4: parse_ipv4; default: accept; } } state parse_ipv4 { packet.extract(hdr.ipv4); 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 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; } table ipv4_lpm { key = { hdr.ipv4.dstAddr: lpm; } actions = { ipv4_forward; drop; NoAction; } size = 1024; default_action = drop(); } //터널링에 사용되는 action, 터널의 다음 터널이 존재하는목적지 포트를 인수로 받는다 action myTunnel_forward(egressSpec_t port) { //나가는 포트를 설정 standard_metadata.egress_spec = port; } //새로운 테이블 설정 table myTunnel_exact { key = { //터널링 헤더의 dst_id를 key로 설정하고 구별 방법을 exact로 설정 hdr.myTunnel.dst_id: exact; } actions = { //알맞는 action 설정 myTunnel_forward; drop; } size = 1024; default_action = drop(); } apply { //ipv4헤더가 유효하고 터널링 헤더가 유효하지 않다면 ipv4테이블로 포워딩을 진행한다. if (hdr.ipv4.isValid() && !hdr.myTunnel.isValid()) { // Process only non-tunneled IPv4 packets ipv4_lpm.apply(); } //터널링헤더가 유효하다면 터널링 테이블로 포워딩 if (hdr.myTunnel.isValid()) { // process tunneled packets myTunnel_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 { update_checksum( hdr.ipv4.isValid(), { hdr.ipv4.version, hdr.ipv4.ihl, hdr.ipv4.diffserv, 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); } } /************************************************************************* *********************** D E P A R S E R ******************************* *************************************************************************/ control MyDeparser(packet_out packet, in headers hdr) { apply { packet.emit(hdr.ethernet); //터널링 헤드도 같이 디파서 한다. packet.emit(hdr.myTunnel); packet.emit(hdr.ipv4); } } /************************************************************************* *********************** S W I T C H ******************************* *************************************************************************/ V1Switch( MyParser(), MyVerifyChecksum(), MyIngress(), MyEgress(), MyComputeChecksum(), MyDeparser() ) main; |
...