看看Github中的P4:P4APP

p4app

说明:翻译自https://github.com/p4lang/p4app,自学使用

p4app是可以构建、运行、调试和测试P4程序的工具。p4app背后的理念是“easy things should be easy”—p4app旨在使小型、简单的P4程序易于编写并易于与他人共享。

安装

  1. 如果尚未安装docker,请安装它。

  2. 如果需要,可以将p4app脚本放在路径中的某个位置。例如:

    cp p4app /usr/local/bin
    

用法

p4app运行p4app软件包。p4app软件包是带有.p4app扩展名的目录—例如,如果您在P4中编写了路由器,则可以将其放在中router.p4app。在目录内,您将放置P4程序,所有支持文件以及一个p4app.json告诉p4app如何运行它的文件。

该存储库附带一个名为simple_router.p4app的示例p4app。用如下命令运行:

p4app run examples/simple_router.p4app

如果运行此命令,则会最终打开Mininet命令提示符。p4app将自动下载包含P4编译器和工具的Docker映像,编译simpler_router.p4,并设置一个带有模拟网络的容器,您可以使用该网络进行实验。除了Mininet本身,您还可以直接使用tsharkscapy以及net-tools和nmap套件。

但是,Mininet不是p4app支持的唯一后端。这是p4app的另一个示例:

p4app run examples/simple_counter.p4app

如果运行此命令,则p4app将自动编译simple_counter.p4,向其提供定义的输入数据包序列simple_counter.stf,并确保输出数据包符合期望。本示例使用“简单测试框架”,该框架可以帮助您测试确保小型P4程序符合您的期望。

一个p4app软件包包含一个程序,但是它可以包含多个“目标”—例如,一个p4app可能包括Mininet的几种不同网络配置,整套STF测试或两者的混合。p4app默认会运行默认目标,但是您可以通过以下方式通过名称指定目标:

p4app run examples/simple_router.p4app mininet

到这里入门就差不多了!不过,还有一个更有用的命令。您不必每次都重新下载p4app在本地缓存P4编译器和工具,但您可能会不时需要更新到最新版本。这时候可以运行:

p4app update

创建一个p4app包

p4app软件包的目录结构如下所示:

  my_program.p4app
    |
    |- p4app.json
    |
    |- my_program.p4
    |
    |- ...other files...

p4app.json文件是一个软件包清单,它告诉p4app如何构建和运行P4程序。看起来和Makefile差不多。这是一个例子:

{
  "program": "my_program.p4",
  "language": "p4-14",
  "targets": {
    "mininet": {
      "num-hosts": 2,
      "switch-config": "my_program.config"
    }
  }
}

该清单告诉p4app它应该运行my_program.p4,它是用p4-14—编写的—这是P4语言的当前版本,尽管您也可以使用p4-16P4-16草案修订版。它定义了一个目标—mininet并提供了一些Mininet配置选项:网络上将有两台主机,并且将使用my_program.config文件配置模拟交换机。当您以p4app.json这种方式引用外部文件时,只需将该文件放入包中,p4app将确保可以找到它。

如果有多个目标,并且用户未按名称指定一个目标,则p4app将运行任意选择的目标之一。您可以使用该default-target选项设置要运行的默认目标。这是一个具有多个目标的示例:

{
  "program": "my_program.p4",
  "language": "p4-14",
  "default-target": "debug",
  "targets": {
    "debug": { "use": "mininet", "num-hosts": 2 },
    "test1": { "use": "stf", "test": "test1.stf" },
    "test2": { "use": "stf", "test": "test2.stf" },
  }
}

这定义了一个Mininet目标“debug”和两个STF目标“test1”和“test2”。该use字段指定目标使用哪个后端。如果不提供,则目标名称也用作后端名称。因此,在前面的示例中,我们不必指定"use":"mininet"—目标的名称是mininet,这足以让p4app知道您的意思。

言尽于此。最后一个提示:如果您想与其他人共享p4app软件包,则可以运行p4app pack my-program.p4app,p4app会将软件包压缩为一个文件。p4app可以透明地运行压缩程序包,因此您发送给它的人甚至不必解压缩它。但是,如果他们想查看其中包含的文件,则可以运行p4app unpack my-program.p4app,p4app会返回软件包目录。

后端

Mininet

这个后端编译一个P4程序,将其加载到一个simple_switch,的BMV2并创建一个Mininet环境,您可以试一下。

支持以下配置值:

"mininet": {
  "num-hosts": 2,
  "switch-config": "file.config"
}

所有字段都是可选的。

Mininet网络将使用星型拓扑,num-hosts字段的每个主机都通过单独的接口连接到交换机。

您可以在启动时使用switch-config来将配置加载到交换机中。文件格式仅仅是一个BMV2的命令序列simple_switch_CLI。

在启动过程中,将显示info,告诉您有关网络配置以及如何访问日志记录和调试功能的信息。BMV2调试器特别方便。您可以在此处阅读如何使用它。

此目标还支持目标的配置值compile-bvm2

多交换机

mininet一样,此目标编译P4程序并在Mininet环境中运行它。此外,该目标允许您使用自定义拓扑运行多个交换机并在主机上执行任意命令。开关与L2和L3规则路由流量的所有主机自动配置的(假定P4程序有ipv4_lpmsend_frameforward表)。例如:

"multiswitch": {
  "links": [
    ["h1", "s1"],
    ["s1", "s2"],
    ["s2", "h2", 50]
  ],
  "hosts": {
    "h1": {
      "cmd": "python echo_server.py $port",
      "startup_sleep": 0.2,
      "wait": false
    },
    "h2": {
      "cmd": "python echo_client.py h1 $port $echo_msg",
      "wait": true
    }
  },
  "parameters": {
    "port": 8000,
    "echo_msg": "foobar"
  }
}

此配置将创建如下拓扑:

h1 <---> s1 <---> s2 <---> h2

s2-h2链路需要具有50ms的人为延迟。可以使用以下选项配置主机:

  • cmd—要在主机上执行的命令。
  • wait—等待命令完成后再继续。通过将其设置为false,可以在后台主机(如守护程序/服务器)上启动进程。
  • startup_sleep—启动命令后应等待的时间(以秒为单位)。
  • latency—此主机与交换机之间的延迟。可以是数字(解释为秒),也可以是带有时间单位的字符串(例如50ms1s)。这将覆盖links对象中设置的延迟。

通过用h1相应的IP地址替换主机名(例如)来格式化命令。目标中指定的参数将作为环境变量(即$后跟变量名)供命令使用。例如,查看多交换机示例应用程序的清单。

局限性

当前,每个主机最多可以连接到一个交换机。

为每个交换机指定条目(命令)

路由表(ipv4_lpmsend_frameforward)将自动填充该目标。此外,您可以指定在每个交换机上运行的自定义命令。您可以自定义文件命令或数组命令。这些自定义命令将在为路由表自动生成命令之前发送。例如:

"multiswitch": {
  "links": [ ... ],
  "hosts": { ... },
  "switches": {
    "s1": {
      "commands": "s1_commands.txt"
    },
    "s2": {
      "commands": [
        "table_add ipv4_lpm set_nhop 10.0.1.10/32 => 10.0.1.10 1",
        "table_add ipv4_lpm set_nhop 10.0.2.10/32 => 10.0.2.10 2"
      ]
    }
  }
}

如果用以上命令给s2下流表与自动生成命令的流表重复(例如,有一个自动输入set_nhop 10.0.1.10/32),则这些自定义命令应该具有不同优先级,并且在填充表时,您将看到有关重复条目的警告。

自定义拓扑类

您可以使用自己的类来代替让该目标创建mininet Topo类。使用topo_module选项指定模块的名称。例如:

"multiswitch": {
  ...
  "topo_module": "mytopo"
  ...
}

这将导入mytopo模块,该模块mytopo.py应与清单文件(p4app.json)位于同一目录中。该模块应实现CustomAppTopo类。它可以扩展默认的topo类apptopo.AppTopo。例如:

# mytopo.py
from apptopo import AppTopo

class CustomAppTopo(AppTopo):
    def __init__(self, *args, **kwargs):
        AppTopo.__init__(self, *args, **kwargs)

        print self.links()

请参阅customtopo.p4app工作示例。

定制控制器

与该topo_module选项类似,您可以使用该controller_module选项指定控制器。这个模块应该实现CustomAppController类。默认控制器类为appcontroller.AppController。您可以扩展此类,如customtopo.p4app示例所示。

自定义主机进程运行器

AppProcRunner类负责在每个mininet主机中执行程序。通过指定controller_module选项,您可以覆盖在主机上启动和终止程序的默认行为。这个模块应该实现CustomAppProcRunner类。默认控制器类为appprocrunner.AppProcRunner。您可以扩展此类,如customtopo.p4app示例所示。

logging

运行此目标时,主机上的临时目录/tmp/p4app_log挂载在客户机上的/tmp/p4app_log。运行p4app之后,此目录中的所有数据都将保留到主机。主机命令的标准输出存储在此位置。如果需要保存命令的输出(例如日志),也可以将其放在此目录中。

要从P4开关保存调试日志,请在"bmv2_log": true目标中设置。要从所有交换机捕获PCAP,请设置"pcap_dump": true。这些文件将保存到/tmp/p4app_log。有关用法示例,请参见广播示例应用程序的清单。

清理命令

如果需要在运行目标后(并且Mininet停止之前)在docker容器中执行命令,可以使用afterafter应该包含cmd,可以是命令,也可以是命令列表。例如:

"multiswitch": {
  "links": [ ... ],
  "hosts": { ... },
  "after": {
    "cmd": [
      "echo register_read my_register 1 | simple_switch_CLI --json p4src/my_router.p4.json",
      "echo register_read my_register 2 | simple_switch_CLI --json p4src/my_router.p4.json"
    ]
  }
}

custom

这是编译P4程序以在Mininet环境中运行的第三种方法。该目标允许您指定一个使用Mininet的Python API即program来指定网络拓扑和配置的Python。例如:

{
  "program": "source_routing.p4",
  "language": "p4-14",
  "targets": {
      "custom": {
           "program": "topo.py"
      }
  }
}

该目标将调用python脚本topo.py来启动Mininet。而program会调用下面的参数:

Argument Argument
-behavioral-exe Value将是switch可执行文件
--json Value将是P4编译器的输出
--cli Value将是switch命令行界面程序

调用示例:

PYTHONPATH=$PYTHONPATH:/scripts/mininet/ python2 topo.py \
                        --behavioral-exe simple_switch \
                        --json SOME_FILE \
                        --cli simple_switch_CLI

您可以通过将其他参数包含在program定义里来指定其他参数以传递到自定义拓扑程序:

{
  "program": "source_routing.p4",
  "language": "p4-14",
  "targets": {
      "custom": {
           "program": "topo.py --num-hosts 2 --switch-config simple_router.config"
      }
  }
}

上述program可在HOSTNAME环境变量中找到的docker容器ID,以便它可以复制/粘贴输出有用的命令:

import os
container = os.environ['HOSTNAME']
print 'Run the switch CLI as follows:'
print '  docker exec -t -i %s %s' % (container, args.cli)

stf

该目标编译提供的P4程序并针对为STF测试框架编写的程序运行测试。

以下配置值是必需的:

"stf": {
  "test": "file.stf"
}

您必须test以STF格式编写指定的文件,但很遗憾,当前没有文档说明。(如果您想对它进行逆向工程并提供一些文档,请提交PR!)您可以看一下此仓库中包含的示例p4apps,以了解基础知识。

此目标还支持目标的配置值compile-bvm2

编译bmv2

这是一个简单的后端,仅用于BMV2体系结构编译提供的P4程序。

支持以下可选配置值:

"compile-bmv2": {
  "compiler-flags": ["-v", "-E"],
  "run-before-compile": ["date"],
  "run-after-compile": ["date"]
}

高级功能

如果您要入侵P4工具链或p4app本身,则可能要使用修改后的Docker映像,而不是标准的p4lang映像。这很容易做到;只需将P4APP_IMAGE环境变量设置为您要使用的Docker映像即可。例如:

P4APP_IMAGE=me/my_p4app_image:latest p4app run examples/simple_router.p4app

指定文件清单的名称

默认情况下,p4app将使用p4app.json在应用程序目录中调用的清单文件。如果未调用清单文件,则p4app.json可以使用--manifest选项指定清单的名称。例如:

p4app run myapp.p4app --manifest testing.p4app

指定日志的目录位置

默认情况下,p4app会将/tmp/p4app_logs主机上的/tmp/p4app_logs目录挂载到docker容器客户虚拟机上。bmv2的输出以及程序的所有输出将保存到此目录。(/tmp/p4app_logs)您可以使用$P4APP_LOGDIR环境变量指定另一个目录。例如,运行:

P4APP_LOGDIR=./out p4app run myapp.p4app

所有日志文件都将存储到./out

启动交互执行的命令

要在当前运行的p4app上交互式运行命令,可以使用

p4app exec command arg1 arg2 ...

这将在当前正在运行的p4app实例中运行命令。如果有多个实例在运行,该命令将在最近启动的p4app上执行。

要在Mininet主机上运行命令,可以使用p4app中包含的Mininet的m实用程序脚本。例如,ping在Mininet主机上运行h1

p4app exec m h1 ping 10.0.2.101

您还可以在Mininet主机上运行tcpdump以使用Wireshark实时查看数据包:

p4app exec m h1 tcpdump -Uw - | wireshark -ki -

你可能感兴趣的:(看看Github中的P4:P4APP)