• P4基础


    basic实验

    步骤 1:运行(不完整的)初学者代码

    h1 ping h2 失败

    图片1.png

    pingall 失败

    图片2.png

    步骤 2:实现 L3 转发

    Parser解析数据包

    从start状态开始,每一个状态便解析一种协议,然后根据低层协议的类型字段,选择解析高一层协议的状态,然后transition到该状态解析上层协议,最后transition到accept。

    parser MyParser(packet_in packet,
                    out headers hdr,	//out相当于输出的数据,type是headers
                    inout metadata meta,	//inout同时作为输入和输出值,类似c++里面的引用
                    inout standard_metadata_t standard_metadata) {
    
        state start {//①
            transition parse_ethernet;      //转移到parse_ethernet状态(解析以太网包头)
        }
    
        state parse_ethernet {
            packet.extract(hdr.ethernet);   //提取以太网包头
            transition select(hdr.ethernet.etherType) { //根据etherType的值(协议类型)选择下一个状态
                //类似switch...case
                TYPE_IPV4: parse_ipv4;      //转换到parse_ipv4状态(解析ip包头)
                default: accept;            //默认是接受,进入下一步处理
            }  
        }
    
        state parse_ipv4 {
            packet.extract(hdr.ipv4);       //提取ip包头
            transition accept;              //接受,进入下一步处理
        }
    
    }
    

    Ingress输入处理

    定义一个用于转发的流表,定义匹配域和动作。

    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;               //递减生存时间TTL
        }
    
        table ipv4_lpm {
            key = {                        //匹配域
                hdr.ipv4.dstAddr: lpm;     //匹配字段是数据包头部字段中的ipv4头部的目标地址
                                           //lpm是最长前缀匹配 
            }
            actions = {                    //动作类型集合
                ipv4_forward;              //自定义的转发动作
                drop;                      //丢弃动作
                NoAction;                  //空动作
            }
            size = 1024;                   //流表可以容纳多少流表项
            default_action = drop();       //默认是丢弃
        }
    
        apply {//③
            if (hdr.ipv4.isValid()) { 
                ipv4_lpm.apply();          //仅当解析成功时,应用ipv4_lpm
            }
        }
    
    }
    
    

    Deparser逆解析器

    control MyDeparser(packet_out packet, in headers hdr) {
        apply {//④
            packet.emit(hdr.ethernet);      //按顺序,发射
            packet.emit(hdr.ipv4);
        }
    }
    

    步骤 3:运行解决方案

    h1 ping h2 成功

    图片3.png

    pingall 成功

    图片4.png

    basic_tunnel实验

    步骤 1:实现基本隧道

    Parser解析数据包

    parser MyParser(packet_in packet,
                    out headers hdr,	//out相当于输出的数据,type是headers
                    inout metadata meta,	//inout同时作为输入和输出值,类似c++里面的引用
                    inout standard_metadata_t standard_metadata) {
    
        state start {
            transition parse_ethernet;      //转移到parse_ethernet状态(解析以太网包头)
        }
    
        state parse_ethernet {
            packet.extract(hdr.ethernet);   //提取以太网包头
            transition select(hdr.ethernet.etherType) { //根据etherType的值(协议类型)选择下一个状态
                //类似switch
                TYPE_MYTUNNEL: parse_myTunnel; //转移到parse_myTunnel状态(隧道)
                TYPE_IPV4: parse_ipv4;      //转换到parse_ipv4状态(解析ip包头)
                default: accept;            //默认是接受,进入下一步处理
            }  
        }
    
        state parse_myTunnel {//①
            packet.extract(hdr.myTunnel);
            transition select(hdr.myTunnel.proto_id) {
                TYPE_IPV4: parse_ipv4;
                default: accept;
            }
        }
    
        state parse_ipv4 {
            packet.extract(hdr.ipv4);       //提取ip包头
            transition accept;              //接受,进入下一步处理
        }
    
    }
    
    

    Ingress输入处理

    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;               //递减生存时间TTL
        }
    
        table ipv4_lpm {
            key = {                        //匹配域
                hdr.ipv4.dstAddr: lpm;     //匹配字段是数据包头部字段中的ipv4头部的目标地址
                                           //lpm是最长前缀匹配 
            }
            actions = {                    //动作类型集合
                ipv4_forward;              //自定义的转发动作
                drop;                      //丢弃动作
                NoAction;                  //空动作
            }
            size = 1024;                   //流表可以容纳多少流表项
            default_action = drop();       //默认是丢弃
        }
    
        //②将出口端口号设置为控制平面提供的端口号
        action myTunnel_forward(egressSpec_t port) {
            standard_metadata.egress_spec = port;
        }
    
        //③如果表中myTunnel_forward存在匹配项,则该表应调用该drop动作,否则应调用该动作。
        table myTunnel_exact {
            key = {
                hdr.myTunnel.dst_id: exact;//要匹配的动作和模式,exact是精准匹配
            }
            actions = {                    //可选动作
                myTunnel_forward;
                drop;
            }
            size = 1024;
            default_action = drop();       //默认是丢弃
        }
    
        apply {//④
            if (hdr.myTunnel.isValid()) {   //隧道包
                myTunnel_exact.apply();
            }
            else if (hdr.ipv4.isValid()) {  //ipv4包
                ipv4_lpm.apply();
            }
        }
    
    }
    

    Deparser逆解析器

    control MyDeparser(packet_out packet, in headers hdr) {//⑤
        apply {
            packet.emit(hdr.ethernet);      //按顺序,发射
            packet.emit(hdr.myTunnel);      //加上隧道包
            packet.emit(hdr.ipv4);
        }
    }
    

    步骤 2:运行解决方案

    (1)h1运行 ./send.py 10.0.2.2 "P4 is cool" ,只设置IPv4转发,h2成功接收,并且含有ip头;

    (2)h1运行 ./send.py 10.0.2.2 "P4 is cool" --dst_id 2 ,同时设置IPv4转发和隧道转发,目标都是h2,h2成功接收,并且包头解析到隧道信息;

    (3)h1运行 ./send.py 10.0.3.3 "P4 is cool" ,同时设置IPv4转发给h3和隧道转发给h2,验证转发优先级,结果h2成功接收,并且包头解析到隧道信息,而h3不会接收;

    思考

    1.如果将basic和basic_tunnel项目文件移出tutorials/exercise目录,能否继续运行?如果不能运行,怎样才能运行。

    5.png

    不能。因为 basic 和 basic_tunnel 项目文件的 Makefile 中使用了include ../../utils/Makefile,include 关键字的含义是把别的 Makefile 文件包含进来,而将 basic 和 basic_tunnel 项目文件移出 tutorials/exercise目录,此处引用的 Makefile 的路径出现错误。根据路径进一步查看 tutorials/utils/Makefile 文件,由于 basic 项目中的 Makefile 文件已有 TOPO 的另行定义,因此会覆盖此处 TOPO=topology.json 的定义。而 RUN_SCRIPT 涉及 run_exercise.py ,需要将该 python 代码运行所需的相关包文件全部拷贝。

    图片1.png

    图片2.png

    新建一个 p4examples 目录,把 tutorials/exercise/basic/ 整体拷入,将原有拓扑文件整合到新建的 topo 目录,修改 topology.json 文件中每台交换机配置文件的目录,以s1交换机为例,改成 “topo/s1-runtime.json”,新建 script 目录,整合所需要构建的包含P4交换机的网络拓扑的 Python 代码,并修改 Makefile 文件。如此,在 p4examples/basic 目录下即可运行成功。

    2.阅读basic实验提供的send.py和receive.py脚本,分析程序导入的python包scapy,说明各自的实现逻辑是什么样的?

    send.py:

    ①首先使用 gethostbyname() 函数,用域名或主机名获取IP地址;
    ②使用自定义的 get_if() 函数获取源主机的发送端口,作为发送数据的端口;
    ③使用 Ether() 函数设置发送方和接收方的 MAC 地址;
    ④使用 IP() 和 TCP() 构造一个 HTTP 数据包;
    ⑤最后使用 sendp() 函数发送 Ether 数据包。

    receive.py:

    ①使用 os.listdir() 返回 /sys/class/net/ 列表中包含 “eth” 的名称,即物理网卡、子网卡、虚拟VLAN网卡,赋值给ifaces;iface为ifaces中第0个元素;
    ②使用sys.stdout.flush()显示地让缓冲区的内容输出;
    ③sniff(iface = iface,prn = lambda x: handle_pkt(x))对于指定的网络接口进行抓包。同时prn定义回调函数handle_pkt(),当符合filter的流量被捕获时,就会执行回调函数,把收到的包里面的东西立刻打印出来。

    3.同样的拓扑在传统网络中是如何实现IPv4转发的,网关在这当中起到了什么作用,basic实验项目的相关流规则设置是如何应用的?

    pod-topo.png

    IPv4转发的实现:

    主机 ( h1, h2, h3, h4) 发送数据报,交换机 ( s1, s2, s3, s4) 对数据报进行转发。具体过程如下:
    ①主机发送 ARP 广播获取网关 MAC 地址;
    ②交换机形成该主机的 MAC 表项,并用网关 MAC 地址回应该主机的 ARP 请求;
    ③该主机把网关 MAC 地址当作目的主机的 MAC 地址,来访问目的主机;
    ④交换机接收到一个数据报,将这个数据报头部的目的 MAC 信息提取出来,与自身的 MAC 地址表比较:如果找到对应项,则按 MAC 表进行转发;如果没找到对应项,则在除了接收到数据包以外的所有端口进行转发(广播)。

    网关的作用:

    连接相同或不同类型网络,并且能找到网络中数据传输最合适的路径,即路由选择。

    相关流规则设置的应用:

    载入静态流表项时采用 runtime 方法:在 sx-runtime.json 文件中,定义一个个具体的流表项,标明了流表项所处的位置,匹配域,匹配模式,动作名,以及动作参数。而这些字段依赖于 P4 代码中Ingress 输入处理模块所自定义的流表,匹配域和动作。

    图片1.png

  • 相关阅读:
    document.getElementById(“id”)与$("#id")的区别
    sqlserver 无法打开备份文件a.bak
    xnconvert 图片转换工具
    基于jQuery的 h5移动端抽奖页面插件
    nodeJS 简单启动express服务器
    jquery 按钮切换插件
    微信判断手机有没有APP,有则打开,没有则跳到应用商城
    jQuery 文字向上轮播
    Node.js制作爬取简书内容的爬虫
    jquery手机端轮播图,点击放大手动轮播
  • 原文地址:https://www.cnblogs.com/dump16/p/16300803.html
Copyright © 2020-2023  润新知