转载请表明出处
注:SONiC系统为vs版本
Part1:实现外部宿主机与SONiC的网络连通
步骤 1:打开一个ubuntu系统安装kvm及其依赖
(1)查看CPU是否支持虚拟化
egrep -c '(vmx|svm)' /proc/cpuinfo
返回结果不为0则说明支持虚拟化
(2)安装"cpu-checker",查询能否使用kvm
sudo apt install cpu-checker
sudo kvm-ok
返回内容如图所示说明可以使用kvm
(3)安装kvm依赖
sudo apt install qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils virtinst virt-manager
sudo service libvirtd start
lsmod|grep kvm
步骤2:为SONiC配置桥接模式网络
一、说明
kvm虚拟机为配置来宾网络提供了三种模式:用户模式、专用虚拟网桥模式、公共网桥模式。
①用户模式。来宾虚拟机能够访问主机、Internet、或本地网络上可用的资源,但外部主机无法访问虚拟机内部。
②专用虚拟网桥模式。在 2 个或更多虚拟机之间设置专用网络,其他虚拟机或真实网络中都看不到此专用网桥。
③公共网桥模式。公共网桥模式能够为虚拟机分配IP地址,使得本地网络能够访问内部虚拟机。
由于需要通过宿主机向SONiC下发P4runtime文件,因而在搭建kvm虚拟机时采用公共网桥模式
二、配置步骤
(1)安装bridge-utils软件包,它提供brctl工具来配置网桥
yum install bridge-utils
(2)加载tun和bridge模块
lsmod | grep tun
lsmod | grep bridge
(3)创建网桥bridge
将物理机工作的网口绑定到 brdige 上,将网口 IP 清除,让 bridge 获取 IP。
brctl addbr br0
brctl addif br0 eth0
brctl show br0
可以看到br0网桥已经与eth0网卡进行了绑定。
brctl stp br0 on
brctl show br0
ifconfig eth0 0 up
ifconfig br0 up
为网桥分配IP:
dhclient br0
可以发现:br0网桥的mac地址与eth0网卡的mac相同,此时eth0已成为网桥接口的附庸。
此时的接口逻辑如下:
步骤3:下载镜像文件并执行脚本mk-vm.sh
启动SONiC
(1)下载镜像文件
镜像编译参考https://mp.weixin.qq.com/s/vPEhuXcE6HSQ9i5ikFug4w
下载镜像
(2)执行脚本文件mk-vm.sh,执行命令:./mk-vm.sh onienet
mk-vm.sh脚本文件内容如下:
#!/bin/sh
# Copyright (C) 2014 Curt Brune <curt@cumulusnetworks.com>
#
# SPDX-License-Identifier: GPL-2.0
MEM=4096
DISK="/home/p4/Desktop/sonic/onie-x86-demo.img"
# Path to ONIE installer .iso image
CDROM="/home/p4/Desktop/sonic/onie-recovery-x86_64-kvm_x86_64-r0.iso"
# Path to OVMF firmware for qemu
# Download OVMF from http://www.tianocore.org/ovmf/
OVMF="$HOME/kvm/OVMF.fd"
# VM will listen on telnet port $KVM_PORT
KVM_PORT=9000
# VNC display to use
VNC_PORT=0
# set mode=disk to boot from hard disk
mode=disk
# set mode=cdrom to boot from the CDROM
# mode=cdrom
# set mode=net to boot from network adapters
# mode=net
# set firmware=uefi to boot with UEFI firmware, otherwise the system
# will boot into legacy mode.
firmware=bios
on_exit()
{
rm -f $kvm_log
}
kvm_log=$(mktemp)
trap on_exit EXIT
boot=c
if [ "$mode" = "cdrom" ] ; then
boot="order=cd,once=d"
cdrom="-cdrom $CDROM"
elif [ "$mode" = "net" ] ; then
boot="order=cd,once=n,menu=on"
fi
if [ "$firmware" = "uefi" ] ; then
[ -r "$OVMF" ] || {
echo "ERROR: Cannot find the OVMF firmware for UEFI: $OVMF"
echo "Please make sure to install the OVMF.fd in the expected directory"
exit 1
}
bios="-bios $OVMF"
fi
#!/bin/sh
set -x
switch=br0
if [ -n "$1" ];then
#tunctl -u `onie` -t $1
ip tuntap add $1 mode tap user `onie`
ip link set $1 up
sleep 0.5s
#brctl addif $switch $1
ip link set $1 master $switch
else
echo "Error: no interface specified"
exit 1
fi
macaddress='DE:AD:BE:EF:00:00'
sudo /usr/bin/kvm -m $MEM \
-name "onie" \
$bios \
-boot $boot $cdrom \
-device e1000,netdev=onienet,mac=$macaddress \
-netdev tap,id=onienet \
-vnc 0.0.0.0:$VNC_PORT \
-vga std \
-drive file=$DISK,media=disk,if=virtio,index=0 \
-serial telnet:localhost:$KVM_PORT,server > $kvm_log 2>&1 &
kvm_pid=$!
sleep 1.0
[ -d "/proc/$kvm_pid" ] || {
echo "ERROR: kvm died."
cat $kvm_log
exit 1
}
telnet localhost $KVM_PORT
echo "to kill kvm: sudo kill $kvm_pid"
exit 0
注意:DISK和CDROM的路径需要根据镜像所安放的位置进行更改,否则将会找不到镜像位置。
说明:
switch=br0
if [ -n "$1" ];then
#tunctl -u `onie` -t $1
ip tuntap add $1 mode tap user `onie`
ip link set $1 up
sleep 0.5s
#brctl addif $switch $1
ip link set $1 master $switch
else
echo "Error: no interface specified"
exit 1
fi
这部分代码作用为:kvm虚拟机启动时,kvm的QEMU模块将所创建的tap设备绑定到brige网桥上,使得虚拟机与外部联通。
此时的接口逻辑如下图:
步骤4:外部主机与SONiC内部的配置
(1)由步骤3进入SONiC系统后进行登录
用户名:admin
密码:YourPaSsWoRd
(2)为SONiC安装依赖,用来正常使用P4RT
sudo apt-get update
sudo apt-get install libgmpxx4ldbl
(3)进入SONiC所携带的P4RT容器,拷贝必要文件至外部
docker exec -it p4rt /bin/bash
容器同样需要安装依赖:
sudo apt-get update
sudo apt-get install libgmpxx4ldbl
安装好后,输入命令where is p4rt
,查看P4RT文件位置
查询完后,执行命令exit
退出容器回到SONiC
在SONiC中执行命令docker ps
查看p4rt 容器的容器id,为文件拷贝做准备
接着进行文件拷贝,将容器内部的两个p4rt文件拷贝至外部SONiC的同样位置
sudo docker cp 2953e27fbeb3:/usr/bin/p4rt.sh /usr/bin
sudo docker cp 2953e27fbeb3:/usr/local/bin/p4rt /usr/local/bin
(4)执行p4rt --help
可以发现,此时SONiC已提供9559端口作为P4RT的监听端口
Part2:P4Runtime下发ACL表项
步骤1:下载info文件
在SONiC官网中下载已经编译好的info文件,重命名为p4info.txt,为后续流表下发做好准备。
https://github.com/sonic-net/sonic-pins/blob/main/sai_p4/instantiations/google/middleblock.p4info.pb.txt
步骤2:编写runtime.py文件,实现grpc连接
#!/usr/bin/env python3
import argparse
import grpc
import os
import sys
from time import sleep
sys.path.append(
os.path.join(os.path.dirname(os.path.abspath(__file__)),
'../../utils/'))
import p4runtime_lib.bmv2
from p4runtime_lib.error_utils import printGrpcError
from p4runtime_lib.switch import ShutdownAllSwitchConnections
import p4runtime_lib.helper
SWITCH_TO_HOST_PORT = 1
SWITCH_TO_SWITCH_PORT = 2
def writeTunnelRules(p4info_helper, ingress_sw
):
table_entry = p4info_helper.buildTableEntry(
table_name="ingress.acl_ingress.acl_ingress_table",
match_fields={
"l4_dst_port": (0x0001, 0xffff)
},
action_name="forward",
action_params={
},
priority= 12
)
is_ok = ingress_sw.WriteTableEntry(table_entry)
print("Install transit rule", is_ok)
def main(p4info_file_path, bmv2_file_path):
p4info_helper = p4runtime_lib.helper.P4InfoHelper(p4info_file_path)
try:
s1 = p4runtime_lib.bmv2.Bmv2SwitchConnection(
name='s1',
address='192.168.44.130:9559',
device_id=0,
proto_dump_file='logs/s1-p4runtime-requests.txt')
s1.MasterArbitrationUpdate()
s1.SetForwardingPipelineConfig(p4info=p4info_helper.p4info,
bmv2_json_file_path=bmv2_file_path)
print("Installed P4 Program using SetForwardingPipelineConfig on s1")
writeTunnelRules(p4info_helper, s1)
while(True):
pass
except KeyboardInterrupt:
print(" Shutting down.")
except grpc.RpcError as e:
printGrpcError(e)
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='P4Runtime Controller')
parser.add_argument('--p4info', help='p4info proto in text format from p4c',
type=str, action="store", required=False,
default='./build/p4info.txt')
parser.add_argument('--bmv2-json', help='BMv2 JSON file from p4c',
type=str, action="store", required=False,
default='./build/advanced_tunnel.json')
args = parser.parse_args()
if not os.path.exists(args.p4info):
parser.print_help()
print("\np4info file not found: %s\nHave you run 'make'?" % args.p4info)
parser.exit(1)
if not os.path.exists(args.bmv2_json):
parser.print_help()
print("\nBMv2 JSON file not found: %s\nHave you run 'make'?" % args.bmv2_json)
parser.exit(1)
main(args.p4info, args.bmv2_json)
运行SONiC,通过sudo ifconfig指令获得SONiC的IP地址,p4rt --help指令获得端口号
sudo ifconfig
p4rt --help
根据得到的IP地址和端口号相应的修改s1的相关配置
s1 = p4runtime_lib.bmv2.Bmv2SwitchConnection(
name='s1',
address='192.168.44.130:9559',
device_id=0,
proto_dump_file='logs/s1-p4runtime-requests.txt')
步骤3:根据p4info文件写相应的需要下发的流表项
根据p4info文件,我们选择acl_ingress_table中id为15的match_fields进行匹配和下发
//P4info文件
tables {
preamble {
id: 33554688
name: "ingress.acl_ingress.acl_ingress_table"
alias: "acl_ingress_table"
annotations: "@p4runtime_role(\"sdn_controller\")"
annotations: "@sai_acl(INGRESS)"
...
}
...
match_fields {
id: 15
name: "l4_dst_port"
annotations: "@sai_field(SAI_ACL_TABLE_ATTR_FIELD_L4_DST_PORT)"
bitwidth: 16
match_type: TERNARY
}
...
对应的在runtime.py文件中,用下列代码进行流表下发
//runtime.py文件
table_entry = p4info_helper.buildTableEntry(
table_name="ingress.acl_ingress.acl_ingress_table",
match_fields={
"l4_dst_port": (0x0001, 0xffff)
},
action_name="forward",
action_params={
},
priority= 12
)
步骤4:下发流表
在SONiC中开启p4rt监听,可以看到下发的具体信息
p4rt --logtostderr
在终端下发流表项
sudo ./runtime.py
在SONiC中可以看到:
可以说明,我们已经成功下发流表。为了更加直观的查看下发的流表,我们通过安装Redis数据库,运用可视化工具Redis Desktop Manager来观察。
步骤5:运用Redis数据库查看下发的流表
首先安装Redis和Redis Desktop Manager
sudo apt install redis-server
sudo snap install redis-desktop-manager
登陆账号
可以看到db0-db6有相应的内容
对应关系如下:
图片来源|在SONiC中运用 redis多实例
下发的表项可以在db14中查看,db14是P4rt专属的数据库,如下图所示。
PS:更多SONiC相关内容可访问微信公众号查看
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)