P4编程环境安装(ubuntu16.04,p4c+bmv2+mininet+PI+tutorial)
张记仇
编辑于 2020年10月30日 14:59

研究了好几天终于把P4编程环境成功搭建好,特此记录

安装时间:2020-10-29

主要参考P4官网github的安装流程

https://github.com/p4lang/tutorials/blob/master/vm/user-bootstrap.sh

参考神秘网友安装教程

https://www.tqwba.com/x_d/jishu/175044.html

参考jiang1436的博客运行P4案例程序

https://www.cnblogs.com/jiang1436/p/12055436.html

对以上教程进行一些补充

安装过程

编译环境

Ubuntu16.04(内核 4.10.0

Python 2.7.12

pip 8.1.1 from /usr/lib/python2.7/dist-packages (python 2.7)

建议将虚拟机设置为4 8G内存 以及足够多的硬盘空间 这样make命令可以改为make -j4加快速度

注意:一些安装过程中的报错可能是因为网络原因所导致,建议使用良好的网络来配置P4环境,以免出现一些意料之外的错误。

建立工作目录

mkdir ~/P4

cd ~/P4

echo "P4_HOME=$(pwd)" >> ~/.bashrc

source ~/.bashrc

安装依赖项

sudo apt-get update

 

sudo apt-get install automake cmake libjudy-dev libpcap-dev libboost-dev libboost-test-dev libboost-program-options-dev libboost-system-dev libboost-filesystem-dev libboost-thread-dev libevent-dev libtool flex bison pkg-config g++ libssl-dev  -y

 

sudo apt-get install cmake g++ git automake libtool libgc-dev bison flex libfl-dev libgmp-dev libboost-dev libboost-iostreams-dev libboost-graph-dev llvm pkg-config python python-scapy python-ipaddr python-ply tcpdump curl  -y

 

sudo apt-get install libreadline6 libreadline6-dev  python-pip  -y 

 

sudo pip install psutil

sudo pip install crcmod

设置版本信息

版本相当重要,每一步的checkout都十分关键,如果使用新的版本可能会出现各种问题,严格按照教程中使用2019的旧版本

P4_HOME=$HOME/P4

BMV2_COMMIT="b447ac4c0cfd83e5e72a3cc6120251c1e91128ab"  # August 10, 2019

PI_COMMIT="41358da0ff32c94fa13179b9cee0ab597c9ccbcc"    # August 10, 2019

P4C_COMMIT="69e132d0d663e3408d740aaf8ed534ecefc88810"   # August 10, 2019

PROTOBUF_COMMIT="v3.2.0"

GRPC_COMMIT="v1.3.2"

Mininet部分

#--- Mininet ---

git clone git://github.com/mininet/mininet mininet

sudo ./mininet/util/install.sh -nwv

protobuf部分

git clone https://github.com/google/protobuf.git

cd protobuf

git checkout ${PROTOBUF_COMMIT}

./autogen.sh

./configure --prefix=/usr

Make

sudo make install

sudo ldconfig

# Force install python module

cd python

sudo python setup.py install

cd ../..

注意:

1.git checkout后可以使用git branch检查

2.git clone https://github.com/google/protobuf.git 速度太慢可以改为git clone https://gitee.com/tonysw/protobuf.git

gRPC部分

git clone https://github.com/grpc/grpc.git

cd grpc

git checkout ${GRPC_COMMIT}

git submodule update --init —recursive

注意:

1.git clone https://github.com/grpc/grpc.git速度过慢 可以改为 git clone https://gitee.com/tonysw/grpc.git

2.获取子模块时可能会出现关于 third_party/boringssl-with-bazel 链接失败问题,原因是资源网站被墙了无法访问。

解决方法:修改.gitmodules文件 third_party/boringssl-with-bazel url进行修改

新的url 

修改过后使用 git submodule sync 进行更新 ,这样url才会被正确的修改。

继续安装

make 

sudo make install

sudo ldconfig

cd ..

# Install gRPC Python Package

sudo pip install grpcio

bmv2依赖

git clone https://github.com/p4lang/behavioral-model.git

cd behavioral-model

git checkout ${BMV2_COMMIT}

#From bmv2's install_deps.sh, we can skip apt-get install.

#Nanomsg is required by p4runtime, p4runtime is needed by BMv2...

tmpdir=`mktemp -d -p .`

cd ${tmpdir}

bash ../travis/install-thrift.sh

bash ../travis/install-nanomsg.sh

sudo ldconfig

bash ../travis/install-nnpy.sh

cd ..

sudo rm -rf $tmpdir

cd ..

PI部分

git clone https://github.com/p4lang/PI.git

cd PI

git checkout ${PI_COMMIT}

git submodule update --init --recursive

./autogen.sh

./configure --with-proto

make

sudo make install

sudo ldconfig

cd ..

正式安装bmv2

cd behavioral-model

./autogen.sh

./configure --enable-debugger --with-pi

make

sudo make install

sudo ldconfig

# Simple_switch_grpc target

cd targets/simple_switch_grpc

./autogen.sh

./configure --with-thrift

make

sudo make install

sudo ldconfig

cd ../../..

p4c部分

git clone https://github.com/p4lang/p4c

cd p4c

git checkout ${P4C_COMMIT}

git submodule update --init --recursive

mkdir -p build

cd build

cmake ..

make 

sudo make install

sudo ldconfig

cd ../..

安装教程目录

git clone https://github.com/p4lang/tutorials

安装完成!

安装完成之后P4目录如下:

P4

── behavioral-model  ## BMv2 软件交换机

── grpc              ## 作为BMv2的依赖

── mininet           ## mininet 网络仿真

── p4c       ## p4c 编译器

── PI                ## PI P4 runtime

── protobuf          ## 作为依赖

└── tutorials         #### 教程目录,以及以后主要的学习,实验

实现tutorialsbasic示例

进入 P4/tutorials/exercises/basic 目录

basic.p4补充完整

完整代码如下:

/* -*- 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;

header ethernet_t {

    macAddr_t dstAddr;

    macAddr_t srcAddr;

    bit<16>   etherType;

}

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  ***********************************

*************************************************************************/

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) {

            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();

    }

    

    apply {

        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   **************

*************************************************************************/

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  *******************************

*************************************************************************/

V1Switch(

MyParser(),

MyVerifyChecksum(),

MyIngress(),

MyEgress(),

MyComputeChecksum(),

MyDeparser()

) main;

basic.p4文件所在目录下打开终端,输入make run编译运行  

输入如下命令进行连通性测试,连通则补充正确,并查看网络拓扑结构

成功!