作者对文中所写内容也是才开始了解,参考了不少网络资料。如有错误,会进行修正。
安装VMVare
这一步比较容易,直接去VmWare官网 https://www.vmware.com/cn.html
如果需要注册码,百度搜一下就行。
安装教程:https://blog.csdn.net/qq_43800119/article/details/123375502
安装CentOS8虚拟机
centos镜像下载地址
http://mirrors.aliyun.com/centos/8/isos/x86_64/
选择DVD版本(标准版本),最大的那个。
1. 打开VmWare,新建虚拟机

不断下一步就行(过程图没有保存)
2. 安装成功

3. 配置网络连接(不要忘记这一步)

安装Docker
注:p4编译官方是基于ubuntu的,但是被要求使用centos,按照各个教程都没法配置成功,所以出此下策。
1. 下载Docker
安装教程参考https://blog.csdn.net/qq_39505065/article/details/106986475
2. 检查Docker是否安装成功
docker version

3. 打开docker
service docker start
4. 查看镜像列表
docker images
拉取镜像
1. 拉取镜像
docker pull p4lang/p4c
注:镜像地址 https://registry.hub.docker.com/r/p4lang/p4c
2. 运行p4c镜像
docker run --cap-add NET_ADMIN -it --rm p4c /bin/bash
注: 其中 –cap -addNET_ADMIN是要加上的,后面sudo那部分才不会出错

参考 http://hustcat.github.io/docker-config-capabilities/
● 打开指定版本镜像方法,把p4c改成p4c:tag
3. 查看镜像列表
docker images

实践(Hello world)
参考: https://www.sdnlab.com/24136.html
1. 首先更新vim等工具
apt-get update
apt-get install
sudo apt-get install vim
sudo apt-get install ping
2. 新建文件
vim test.p4
test.p4内容如下
#include <core.p4>
#include <v1model.p4>
typedef bit<48> EthernetAddress;
typedef bit<32> IPv4Address;
header ethernet_t {
EthernetAddress dst_addr;
EthernetAddress src_addr;
bit<16> ether_type;
}
header ipv4_t {
bit<4> version;
bit<4> ihl;
bit<8> diffserv;
bit<16> total_len;
bit<16> identification;
bit<3> flags;
bit<13> frag_offset;
bit<8> ttl;
bit<8> protocol;
bit<16> hdr_checksum;
IPv4Address src_addr;
IPv4Address dst_addr;
}
struct headers_t {
ethernet_t ethernet;
ipv4_t ipv4;
}
struct metadata_t {
}
error {
IPv4IncorrectVersion,
IPv4OptionsNotSupported
}
parser my_parser(packet_in packet,
out headers_t hd,
inout metadata_t meta,
inout standard_metadata_t standard_meta)
{
state start {
packet.extract(hd.ethernet);
transition select(hd.ethernet.ether_type) {
0x0800: parse_ipv4;
default: accept;
}
}
state parse_ipv4 {
packet.extract(hd.ipv4);
verify(hd.ipv4.version == 4w4, error.IPv4IncorrectVersion);
verify(hd.ipv4.ihl == 4w5, error.IPv4OptionsNotSupported);
transition accept;
}
}
control my_deparser(packet_out packet,
in headers_t hdr)
{
apply {
packet.emit(hdr.ethernet);
packet.emit(hdr.ipv4);
}
}
control my_verify_checksum(inout headers_t hdr,
inout metadata_t meta)
{
apply { }
}
control my_compute_checksum(inout headers_t hdr,
inout metadata_t meta)
{
apply { }
}
control my_ingress(inout headers_t hdr,
inout metadata_t meta,
inout standard_metadata_t standard_metadata)
{
bool dropped = false;
action drop_action() {
mark_to_drop(standard_metadata);
dropped = true;
}
action to_port_action(bit<9> port) {
hdr.ipv4.ttl = hdr.ipv4.ttl - 1;
standard_metadata.egress_spec = port;
}
table ipv4_match {
key = {
hdr.ipv4.dst_addr: lpm;
}
actions = {
drop_action;
to_port_action;
}
size = 1024;
default_action = drop_action;
}
apply {
ipv4_match.apply();
if (dropped) return;
}
}
control my_egress(inout headers_t hdr,
inout metadata_t meta,
inout standard_metadata_t standard_metadata)
{
apply { }
}
V1Switch(my_parser(),
my_verify_checksum(),
my_ingress(),
my_egress(),
my_compute_checksum(),
my_deparser()) main;
3. 编译文件
p4c -b bmv2 test.p4 -o test.bmv2
查看目录ls,已经生成test.bmv2

注:
-b:指定 target
-o:指定输出路径
4. 构建网络拓扑

sudo ip link add name veth0 type veth peer name veth1
sudo ip link set dev veth0 up
sudo ip link set dev veth1 up
sudo sysctl net.ipv6.conf.veth0.disable_ipv6=1
sudo sysctl net.ipv6.conf.veth1.disable_ipv6=1
sudo ip link add name veth2 type veth peer name veth3
sudo ip link set dev veth2 up
sudo ip link set dev veth3 up
sudo sysctl net.ipv6.conf.veth2.disable_ipv6=1
sudo sysctl net.ipv6.conf.veth3.disable_ipv6=1
sudo ip link add name veth4 type veth peer name veth5
sudo ip link set dev veth4 up
sudo ip link set dev veth5 up
sudo sysctl net.ipv6.conf.veth4.disable_ipv6=1
sudo sysctl net.ipv6.conf.veth5.disable_ipv6=1
5. 启动switch_simple交换机
sudo simple_switch --interface 0@veth0 --interface 1@veth2 --interface 2@veth4 test.bmv2/test.json &
接下来通过simple_switch_CLI程序来控制该P4软件交换机
6. 向交换机的路由表下发路由
启动交换机
simple_switch_CLI

查看当前所有表
show_tables
查看指定表的信息
table_info ipv4_match

接下来就是控制平面,使用 table_add 命令向交换机添加路由。假设:
port 0(veth 0)连接 10.10.0.0/16 网段
port 1(veth 2)连接 20.20.0.0/16 网段
port 2(veth 4)连接 30.30.0.0/16 网段
输入如下命令
table_add ipv4_match to_port_action 10.10.0.0/16 => 0
table_add ipv4_match to_port_action 20.20.0.0/16 => 1
table_add ipv4_match to_port_action 30.30.0.0/16 => 2

使用命令table_dump确定添加的表项
table_dump ipv4_match

7. 测试交换机的三层转发
首先新建控制台窗口,即同一容器多个界面
docker exec -it fc9942741dca /bin/bash
注:docker exec -it /bin/bash 其中<>里面是容器id
首次使用scapy,请先安装依赖
sudo apt-get install scapy
启动scapy
sudo scapy

开始测试前veth3和veth5抓包情况——都没有包
sudo tcpdump -n -i veth3
sudo tcpdump -n -i veth5

使用 scapy 工具从 veth1 注入目的地为 20.20.0.1 的报文
p = Ether()/IP(dst="20.20.0.1")/UDP()
sendp(p,iface="veth1")

抓包——三个窗口同时运行截图:scapy发送两个包,veth3都收到了,veth5无变化。
sudo tcpdump -n -i veth3
sudo tcpdump -n -i veth5

使用scapy从 veth1 注入目的地为 30.30.0.1 的报文
p = Ether()/IP(dst="30.30.0.1")/UDP()
sendp(p,iface="veth1")

抓包——运行截图,scapy从veth1发送包,veth5收到,veth3没变化。
sudo tcpdump -n -i veth3
sudo tcpdump -n -i veth5

最后!保存容器
这一步真的很重要,要不然一切工具安装与更新都作废!
docker commit 容器id demo:v1.0
demo:v1.0是想存储名字:版本号

991

被折叠的 条评论
为什么被折叠?



