Golang编程语言知识介绍


  • 首页

  • todo

  • 思考

  • life

  • food

  • OS

  • lua

  • redis

  • Golang

  • C

  • TCP/IP

  • ebpf

  • p4

  • OpenVPN

  • IPSec

  • L2TP

  • DNS

  • distributed

  • web

  • OpenWRT

  • 运维

  • Git

  • 鸟哥的私房菜

  • IT杂谈

  • 投资

  • About Me

  • 友情链接

  • FTP

  • 搜索
close

利用p4实现ipv6转发实验 系列转载 7

时间: 2023-09-12   |   分类: p4     |   阅读: 1140 字 ~3分钟

写在前面

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


p4代码

/p4_16,v1_model/

img

img

 #include<core.p4>
 #include<v1model.p4>
 
 const bit<16> TYPE_IPV6 = 0x08DD;//ipv6在以太网中的id
 
 /*HEADERS*/
 
 typedef bit<9> egressSpec_t;
 typedef bit<48> macAddr_t;
 
 header ethernet_t{
     macAddr_t dstAddr;
     macAddr_t srcAddr;
     bit<16> etherType;
 }
  
 header ipv6_t{
     bit<4> version;
     bit<8> trafficClass;
     bit<20> flowLabel;
     bit<16> payLoadLen;
     bit<8> nextHdr;
     bit<8> hopLimit;
     bit<128> srcAddr;
     bit<128> dstAddr;
 }
 
 struct metadata{
 }
 
 struct headers{
     ethernet_t ethernet;
     ipv6_t ipv6;
 }
 
 /*PARSER*/
 
 parser MyParser(packet_in packet,out headers hdr,inout metadata meta,inout standard_metadata_t standard_metadata){
     state start{
         transition parse_ethernet;//start开始先以底层eth解析
     }
     
     state parse_ethernet{
         packet.extract(hdr.ethernet);
         transition select(hdr.ethernet.etherType){
             TYPE_IPV6:parse_ipv6;//转至ipv6解析
             default:accept;
         }
     }
     
     state parse_ipv6{
         packet.extract(hdr.ipv6);
         transition accept;
     }
 }
 
 /*CHECKSUM VERIFICATION*/
 
control MyVerifyChecksum(inout headers hdr,inout metadata meta){
    apply{}
}
 
 /*INGRESS PROCESSING*/
 
 control MyIngress(inout headers hdr,inout metadata meta,inout standard_metadata_t standard_metadata){
     action drop(){
         mark_to_drop();//将要丢弃的包标记为丢弃
     }
     
     action ipv6_forward(macAddr_t dstAddr,egressSpec_t port){
         standard_metadata.egress_spec = port;
         hdr.ethernet.srcAddr = hdr.ethernet.dstAddr;
         hdr.ethernet.dstAddr = dstAddr;
         hdr.ipv6.hopLimit = hdr.ipv6.hopLimit - 1;//这个类似ipv4中ttl,为0时就超时
     }
     
     table ipv6_lpm{
         key = {
             hdr.ipv6.dstAddr: lpm;//lpm是最长前缀匹配,exact完全匹配,ternary三元匹配
         }
         
         actions = {
             ipv6_forward;//转发
             drop;//丢弃
             NoAction;//空动作
         }
         
         size = 1024;//流表项容量
         
         default_action = drop();//table miss则丢弃
     }
     
     apply{
         if(hdr.ipv6.isValid()){
             ipv6_lpm.apply();
         }
     }
 }
 
 /*EGRESS PROCESSING*/
 
 control MyEgress(inout headers hdr,inout metadata meta,inout standard_metadata_t standard_metadata){
     apply{}
 }
 
 /*CHECKSUM COMPUTATION*/
 
 control MyComputeChecksum(inout headers hdr,inout metadata meta){
     apply{}
 }
 
 /*DEPARSER*/
 
 control MyDeparser(packet_out packet,in headers hdr){
     apply{
         packet.emit(hdr.ethernet);
         packet.emit(hdr.ipv6);
     }
 }
 
 /*SWITCH*/
 
 V1Switch(
 MyParser(),
 MyVerifyChecksum(),
 MyIngress(),
 MyEgress(),
 MyComputeChecksum(),
 MyDeparser()
 )main;

实验拓扑

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

img

{
    "program": "ipv6_forward.p4",
    "language": "p4-16",
    "targets": {
      "multiswitch": {
          "auto-control-plane": true,
          "cli": true,
          "pcap_dump": true,
          "bmv2_log": true,
          "links": [["h1", "s1"], ["h2", "s1"]],
          "hosts": {
            "h1": {
            },
            "h2": {
            }
          },
          "switches": {
              "s1": {
                  "entries": "s1-commands.txt"
              }
        }
    }
    }
}

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

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

将其流表项画出来如下:

img


收发包脚本代码

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

send.py

import argparse
import sys
import socket
import random
import struct

from scapy.all import sendp, send, get_if_list, get_if_hwaddr
from scapy.all import Packet
from scapy.all import Ether, IPv6, UDP

def get_if():
    ifs=get_if_list()[20230912P4语法三.md](20230912P4%D3%EF%B7%A8%C8%FD.md)
    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 main():

    if len(sys.argv)<3:
        print 'pass 3 arguments:<source> <destination> "<message>"'
        exit(1)
    saddr = sys.argv[1]
    addr = sys.argv[2]
    iface = get_if()

    print "sending on interface %s to %s" % (iface, str(addr))
    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]
    pkt.show2()
    sendp(pkt, iface=iface, verbose=False)


if __name__ == '__main__':
    main()

receive.py

import sys
import struct
import os

from scapy.all import sniff, sendp, hexdump, get_if_list, get_if_hwaddr
from scapy.all import Packet, IPOption
from scapy.all import ShortField, IntField, LongField, BitField, FieldListField, FieldLenField
from scapy.all import IPv6, TCP, UDP, Raw
from scapy.layers.inet import _IPOption_HDR

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

class IPOption_MRI(IPOption):
    name = "MRI"
    option = 31
    fields_desc = [ _IPOption_HDR,
                    FieldLenField("length", None, fmt="B",
                                  length_of="swids",
                                  adjust=lambda pkt,l:l+4),
                    ShortField("count", 0),
                    FieldListField("swids",
                                   [],
                                   IntField("", 0),
                                   length_from=lambda pkt:pkt.count*4) ]
def handle_pkt(pkt):
    print "got a packet"
    pkt.show2()
    #hexdump(pkt)
    sys.stdout.flush()


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

if __name__ == '__main__':
    main()

测试

./run.sh
//在mininet cli中
xterm h1 h2
//在h2中
./receive.py
//在h1中
./send.py fe80::1234 fe80::5678 "Hello p4!"

结果如下:

img


牢骚

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

本文转载自本链接

#p4#
P4 Runtime和p4 info 系列转载 8
P4语法(5) Package 系列转载 6
shankusu2017@gmail.com

shankusu2017@gmail.com

日志
分类
标签
GitHub
© 2009 - 2025
粤ICP备2021068940号-1 粤公网安备44011302003059
0%