• 利用p4实现ipv6转发实验


    写在前面

    只是作为一个入门p4的实验尝试,借用了一些即成的运行代码。


    p4代码

    /**p4_16,v1_model**/

      1 #include<core.p4>
      2 #include<v1model.p4>
      3 
      4 const bit<16> TYPE_IPV6 = 0x08DD;//ipv6在以太网中的id
      5 
      6 /*HEADERS*/
      7 
      8 typedef bit<9> egressSpec_t;
      9 typedef bit<48> macAddr_t;
     10 
     11 header ethernet_t{
     12     macAddr_t dstAddr;
     13     macAddr_t srcAddr;
     14     bit<16> etherType;
     15 }
     16  
     17 header ipv6_t{
     18     bit<4> version;
     19     bit<8> trafficClass;
     20     bit<20> flowLabel;
     21     bit<16> payLoadLen;
     22     bit<8> nextHdr;
     23     bit<8> hopLimit;
     24     bit<128> srcAddr;
     25     bit<128> dstAddr;
     26 }
     27 
     28 struct metadata{
     29 }
     30 
     31 struct headers{
     32     ethernet_t ethernet;
     33     ipv6_t ipv6;
     34 }
     35 
     36 /*PARSER*/
     37 
     38 parser MyParser(packet_in packet,out headers hdr,inout metadata meta,inout standard_metadata_t standard_metadata){
     39     state start{
     40         transition parse_ethernet;//start开始先以底层eth解析
     41     }
     42     
     43     state parse_ethernet{
     44         packet.extract(hdr.ethernet);
     45         transition select(hdr.ethernet.etherType){
     46             TYPE_IPV6:parse_ipv6;//转至ipv6解析
     47             default:accept;
     48         }
     49     }
     50     
     51     state parse_ipv6{
     52         packet.extract(hdr.ipv6);
     53         transition accept;
     54     }
     55 }
     56 
     57 /*CHECKSUM VERIFICATION*/
     58 
     59 control MyVerifyChecksum(inout headers hdr,inout metadata meta){
     60     apply{}
     61 }
     62 
     63 /*INGRESS PROCESSING*/
     64 
     65 control MyIngress(inout headers hdr,inout metadata meta,inout standard_metadata_t standard_metadata){
     66     action drop(){
     67         mark_to_drop();//将要丢弃的包标记为丢弃
     68     }
     69     
     70     action ipv6_forward(macAddr_t dstAddr,egressSpec_t port){
     71         standard_metadata.egress_spec = port;
     72         hdr.ethernet.srcAddr = hdr.ethernet.dstAddr;
     73         hdr.ethernet.dstAddr = dstAddr;
     74         hdr.ipv6.hopLimit = hdr.ipv6.hopLimit - 1;//这个类似ipv4中ttl,为0时就超时
     75     }
     76     
     77     table ipv6_lpm{
     78         key = {
     79             hdr.ipv6.dstAddr: lpm;//lpm是最长前缀匹配,exact完全匹配,ternary三元匹配
     80         }
     81         
     82         actions = {
     83             ipv6_forward;//转发
     84             drop;//丢弃
     85             NoAction;//空动作
     86         }
     87         
     88         size = 1024;//流表项容量
     89         
     90         default_action = drop();//table miss则丢弃
     91     }
     92     
     93     apply{
     94         if(hdr.ipv6.isValid()){
     95             ipv6_lpm.apply();
     96         }
     97     }
     98 }
     99 
    100 /*EGRESS PROCESSING*/
    101 
    102 control MyEgress(inout headers hdr,inout metadata meta,inout standard_metadata_t standard_metadata){
    103     apply{}
    104 }
    105 
    106 /*CHECKSUM COMPUTATION*/
    107 
    108 control MyComputeChecksum(inout headers hdr,inout metadata meta){
    109     apply{}
    110 }
    111 
    112 /*DEPARSER*/
    113 
    114 control MyDeparser(packet_out packet,in headers hdr){
    115     apply{
    116         packet.emit(hdr.ethernet);
    117         packet.emit(hdr.ipv6);
    118     }
    119 }
    120 
    121 /*SWITCH*/
    122 
    123 V1Switch(
    124 MyParser(),
    125 MyVerifyChecksum(),
    126 MyIngress(),
    127 MyEgress(),
    128 MyComputeChecksum(),
    129 MyDeparser()
    130 )main;

    实验拓扑

    这里实验的拓扑用来最简单的一个交换机下挂两个主机,交换机是bmv2。其json文件书写如下: 交换机s1的流表项通过s1-commands.txt文件定义。

     1 {
     2     "program": "ipv6_forward.p4",
     3     "language": "p4-16",
     4     "targets": {
     5       "multiswitch": {
     6           "auto-control-plane": true,
     7           "cli": true,
     8           "pcap_dump": true,
     9           "bmv2_log": true,
    10           "links": [["h1", "s1"], ["h2", "s1"]],
    11           "hosts": {
    12             "h1": {
    13             },
    14             "h2": {
    15             }
    16           },
    17           "switches": {
    18               "s1": {
    19                   "entries": "s1-commands.txt"
    20               }
    21         }
    22     }
    23     }
    24 }

    在s1-commans.txt文件中做如下定义:

    1 table_set_default ipv6_lpm drop
    2 table_add ipv6_lpm ipv6_forward fe80::5678/128 => 00:04:00:00:00:02 2
    3 table_add ipv6_lpm ipv6_forward fe80::1234/128 => 00:04:00:00:00:01 1

    将其流表项画出来如下:


    收发包脚本代码

    鉴于对python socket发包代码不是那么了解,所以套用了一部分模板做了修改。

    send.py

     1 import argparse
     2 import sys
     3 import socket
     4 import random
     5 import struct
     6 
     7 from scapy.all import sendp, send, get_if_list, get_if_hwaddr
     8 from scapy.all import Packet
     9 from scapy.all import Ether, IPv6, UDP
    10 
    11 def get_if():
    12     ifs=get_if_list()
    13     iface=None
    14     for i in get_if_list():
    15         if "eth0" in i:
    16             iface=i
    17             break;
    18     if not iface:
    19         print "Cannot find eth0 interface"
    20         exit(1)
    21     return iface
    22 
    23 def main():
    24 
    25     if len(sys.argv)<3:
    26         print 'pass 3 arguments:<source> <destination> "<message>"'
    27         exit(1)
    28     saddr = sys.argv[1]
    29     addr = sys.argv[2]
    30     iface = get_if()
    31 
    32     print "sending on interface %s to %s" % (iface, str(addr))
    33     pkt =  Ether(src=get_if_hwaddr(iface), dst='ff:ff:ff:ff:ff:ff') / IPv6(src=saddr,dst=addr) / UDP(dport=4321, sport=1234) / sys.argv[3]
    34     pkt.show2()
    35     sendp(pkt, iface=iface, verbose=False)
    36 
    37 
    38 if __name__ == '__main__':
    39     main()

    receive.py

     1 import sys
     2 import struct
     3 import os
     4 
     5 from scapy.all import sniff, sendp, hexdump, get_if_list, get_if_hwaddr
     6 from scapy.all import Packet, IPOption
     7 from scapy.all import ShortField, IntField, LongField, BitField, FieldListField, FieldLenField
     8 from scapy.all import IPv6, TCP, UDP, Raw
     9 from scapy.layers.inet import _IPOption_HDR
    10 
    11 def get_if():
    12     ifs=get_if_list()
    13     iface=None
    14     for i in get_if_list():
    15         if "eth0" in i:
    16             iface=i
    17             break;
    18     if not iface:
    19         print "Cannot find eth0 interface"
    20         exit(1)
    21     return iface
    22 
    23 class IPOption_MRI(IPOption):
    24     name = "MRI"
    25     option = 31
    26     fields_desc = [ _IPOption_HDR,
    27                     FieldLenField("length", None, fmt="B",
    28                                   length_of="swids",
    29                                   adjust=lambda pkt,l:l+4),
    30                     ShortField("count", 0),
    31                     FieldListField("swids",
    32                                    [],
    33                                    IntField("", 0),
    34                                    length_from=lambda pkt:pkt.count*4) ]
    35 def handle_pkt(pkt):
    36     print "got a packet"
    37     pkt.show2()
    38     #hexdump(pkt)
    39     sys.stdout.flush()
    40 
    41 
    42 def main():
    43     ifaces = filter(lambda i: 'eth' in i, os.listdir('/sys/class/net/'))
    44     iface = ifaces[0]
    45     print "sniffing on %s" % iface
    46     sys.stdout.flush()
    47     sniff(filter="udp and port 4321",iface = iface,
    48           prn = lambda x: handle_pkt(x))
    49 
    50 if __name__ == '__main__':
    51     main()

    测试

    1 ./run.sh
    2 //在mininet cli中
    3 xterm h1 h2
    4 //在h2中
    5 ./receive.py
    6 //在h1中
    7 ./send.py fe80::1234 fe80::5678 "Hello p4!"

    结果如下:


    牢骚

    第一次尝试构建p4相关的实验,了解了一部分p4的语法,以及一些的工作原理,也发掘出一部分并未了解的知识内容待后续去琢磨学习。过程有很多不完美,结果也有很多不完美,虽然现在也不满足,但是寒假也快结束了。

  • 相关阅读:
    server正式的环境性能测试nginx-php 指着寻求突破的表现
    SICP 锻炼 (1.45)解决摘要
    sdut 3-4 长方形的周长和面积计算
    吉克1111-1114第七周讲座班、家庭作业(动态规划,期限:2014年4月25日本23点-周五晚上,科委飞信通知学生)
    STL源代码分析——STL算法sort排序算法
    伺服驱动器UVW电机电源线相序错误
    1_BLE nRF51822 UART 与 BLE转发
    研制埃博拉疫苗与科学家的奇思秒想
    垂死挣扎还是涅槃重生 -- Delphi XE5 公布会归来感想
    Recover Binary Search Tree -- LeetCode
  • 原文地址:https://www.cnblogs.com/pullself/p/10418743.html
Copyright © 2020-2023  润新知