SONiC+P4实践——P4Runtime下发ACL表项

2023-05-16

转载请表明出处

 

注:SONiC系统为vs版本

Part1:实现外部宿主机与SONiC的网络连通

步骤 1:打开一个ubuntu系统安装kvm及其依赖

(1)查看CPU是否支持虚拟化


egrep -c '(vmx|svm)' /proc/cpuinfo  

返回结果不为0则说明支持虚拟化

(2)安装"cpu-checker",查询能否使用kvm

  • 安装"cpu-checker"


sudo apt install cpu-checker  
  • 查询能否使用kvm虚拟机


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。

  • 创建一个br0网桥


brctl addbr br0  
  • 将网卡eth0和网桥进行绑定


brctl addif br0 eth0  
  • 查看网桥:


brctl show br0  

可以看到br0网桥已经与eth0网卡进行了绑定。

  • 启用生成树协议并为网桥分配IP:


brctl stp br0 on  

brctl show br0  


ifconfig eth0 0 up  

ifconfig br0 up  

为网桥分配IP:


dhclient br0  
  • 执行ifconfig eth0ifconfig 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-serversudo snap install redis-desktop-manager

登陆账号

可以看到db0-db6有相应的内容

对应关系如下:

图片来源|在SONiC中运用 redis多实例

下发的表项可以在db14中查看,db14是P4rt专属的数据库,如下图所示。

PS:更多SONiC相关内容可访问微信公众号查看

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SONiC+P4实践——P4Runtime下发ACL表项 的相关文章

  • 2021-02-07 SONiC SAI结构2 1D Bridge

    SONiC SAI结构2 1D Bridge 以太网交换流水线结构 SONiC SAI对交换机 路由器的报文处理流程建立了标准化的行为模型 即使不同的交换芯片内部实现报文处理的方式各不相同 xff0c 由于行为模型是报文处理过程的抽象描述
  • 2021-04-26 SONiC: 转发和管理平面接口SAI模型

    2021 04 26 SONiC 转发和管理平面接口SAI模型 SAI模型中转发平面和管理平面接口 转发平面和管理平面之间的接口是控制报文从转发平面传递到控制平面CPU处理的接口 对于各种类型的交换机而言 xff0c 大量不同种类的控制报文
  • SONiC vs testbed搭建

    准备工作 一台安装Ubuntu18 04的系统 xff0c 内存建议不少于16G 需要支持kvm虚拟化安装ssh server sudo apt update y sudo apt openssh server y 设置sudo免密 sud
  • 蓝牙物理链路类型:SCO和ACL链路与A2DP

    转载于https blog csdn net wenzongliang article details 84689377 蓝牙链路分两种同步链路 SCO 和异步链路 xff08 ACL xff09 A2DP xff08 Advanced A
  • 卡夫卡主题_授权_失败

    我实际上正在努力使用 SASL 纯文本设置简单的 Kafka 身份验证并添加 ACL 授权 但当我尝试使用数据时遇到问题 main INFO org apache kafka common utils AppInfoParser Kafka
  • Symfony2 - 仅限匿名用户而非用户访问登录和注册页面

    我有一个带有登录表单的网站 成功登录后 我被重定向到索引 但是当我单击后退按钮时 它仍然让我查看登录表单 这不太好 我希望只有匿名查看者才能访问登录表单 而已经登录的用户则无法访问 在 symfony2 中有一个简单的方法可以做到这一点吗
  • 通过访问路由名称参数来自动化委托权限并检查用户的权限

    我已经为 ACL 层实现了委托角色 现在 我计划自动对每个请求进行权限检查 这样每次我就不必为用户角色编写权限 例如 我有公司资源 用户角色为 管理员 他只能查看公司 另一个用户角色为 超级 可以管理公司 在数据库中 我为他们提供了适当的权
  • 哪些源代码控制系统具有文件级权限?

    我可能会建议放弃 VSS 因为它无法在文件级别授予和拒绝权限 问题是什么源代码控制系统允许这样做 Update我将 SVN 答案标记为 正确 答案 因为它收到了最多的反馈 然而 没有正确的答案 我将根据您的所有反馈向管理层提出建议 subv
  • 如何在我的 Web MVC 应用程序中实现访问控制列表?

    第一个问题 请您解释一下如何在 MVC 中实现最简单的 ACL 这是在 Controller 中使用 Acl 的第一种方法
  • AD 计算机对象上的设置 ACL

    我正在尝试Set Acl在 AD 中的计算机对象上 首先我使用以下方法获取 ACL acl Get Acl AD CN Tester1 OU Ou1 OU OU2 OU OU3 DC Contoso DC com Access 这给了我该计
  • 如何检查Windows文件是否可读/可写?

    首先 我知道这对于实际检查我是否可以写作并不可靠 我正在编写一个文件传输客户端 并且希望 远程 和 本地 文件浏览器窗格之间具有相同的功能 我完全理解 无论如何 我都必须处理执行的任何操作的任何与权限相关的异常 这不是编程检查 只是显示给用
  • ACL 2024投递指南

    诸神缄默不语 个人CSDN博文目录 显然写这篇博客是因为我要投ACL了 TL DR ACL 2024是ARR提交制 workshop归workshop 最晚提交时间是2024年2月15号 在此之前可以随时撤回 4月15号出结果 4月20号确
  • 限制某些用户而不是其他用户对 Cloudfront(S3) 文件的访问的简单示例

    我刚刚开始了解 AWS S3 和 Cloudfront 的权限 所以请放心 两个主要问题 我想允许某些用户访问 例如 已登录的用户 但是not其他的 我假设我需要使用 ACL 而不是存储桶策略 因为前者更具可定制性 您可以使用查询参数识别
  • 如何从大量文件夹中删除单个用户 ACL?

    我有一个非常大的文件夹列表 我需要从每个文件夹中删除一个 ACL 我没有手动执行此操作 而是尝试编写一个脚本来在很短的时间内完成此操作 但我遇到了一些麻烦 这是我到目前为止所拥有的 filepath C ALCTEST user domai
  • 我的 C# 应用程序如何测试用户是否具有对网络共享的“读取”访问权限?

    我正在开发一个胖客户端应用程序 该应用程序经常遇到访问网络共享的 问题 在对服务器进行任何 IO 之前 我的应用程序会测试共享 通常采用 server share 形式 是否存在 这对于检测客户端与服务器失去连接的情况非常有效 但仍然存在一
  • macOS 钥匙串 ACL 如何确定哪些应用程序具有访问权限?

    当应用程序将项目保存到钥匙串时 macOS 会将该应用程序添加到访问控制列表中 以便您的应用程序稍后可以访问它 如果您尝试从其他应用程序访问该项目 macOS 将显示系统提示 询问用户是否允许访问 这是有记录的here https deve
  • 如何在 CreateEvent 的 SDDL 字符串中添加同步权

    我的 Windows 服务使用 CreateEvent 创建 2 个事件 以便与用户应用程序进行通信 该服务和用户应用程序不在同一用户帐户下运行 用户应用程序打开事件并将其设置为有信号 不会出现错误 但该服务从未收到该事件 另一个事件的作用
  • 在.Net 下为低完整性进程添加写访问权限

    我正在创建一个用于文件创建的 FileSecurity 该文件对于低完整性进程也应该具有写入访问权限 FileSecurity fileAcl new FileSecurity add everyone IdentityReference
  • 如何使用 CodeIgniter ACL 库?

    如何实现 ACL 库 对用户角色使用 ACL 的最佳方法是什么 在标准 PHP 中 我会编写如下代码 if userTypeId Admin hello Admin else if userTypeId Member hello membe
  • Dockerfile 中的 setfacl 没有效果

    我想在使用 setfacl 构建 docker 映像时为某些文件夹设置默认 acl 但它没有效果 默认 acl 不变 我的目标是在 opt 中创建的每个文件都必须对任何用户都具有 rwX 权限 因为该映像稍后将使用任意 uid 运行 并且需

随机推荐

  • STM32单片机蜂鸣器实验

    蜂鸣器可以分为两种 xff1a 有源蜂鸣器与无源蜂鸣器 xff0c 这里的 源 指的是有没有自带震荡电路 xff0c 有源的蜂鸣器自带有震荡电路 xff0c 通电的瞬间就会发出声音 xff1b 而无源的蜂鸣器 xff0c 需要提供一个2 5
  • JVM虚拟机

    JVM 1 JVM 概述 x1f6b4 x1f6b4 x1f6b2 x1f6b4 虚拟机 xff08 Virtual Machine xff09 是一台虚拟的计算机 VMware属于系统虚拟机 xff0c 是对物理计算机的仿真 Java虚拟
  • 树莓派桌面WIFI图标消失,树莓派黑屏can‘t currently show the desktop

    方法一 xff1a 重装镜像 方法二 xff1a 找个树莓派显示器终端输入这行代码 sudo apt install wpasupplicant wpagui libengine pkcs11 openssl 转载B站视频 xff1a 完美
  • cuda10.1+cudnn10.1+tensorflow2.2.0+pytorch1.7.1下载安装及配置

    一 cuda及cudnn下载 1 查看自己电脑是否支持GPU 方法 xff1a 鼠标移动到此电脑 xff0c 点击鼠标右键 xff0c 依次选择属性 设备管理器 显示适配器有以下图标 xff08 NVIDIA xff09 即可安装GPU x
  • C语言:strtok()函数简单用法

    strtok函数 切割字符串 第一个参数指定一个字符串 xff0c 它包含了0个或者多个由第二个参数 xff08 字符串 xff09 中的一个或多个分隔符分割的标记 strtok函数找到第一个参数中的下一个标记 xff0c 并将其用 39
  • ESP32之FreeRTOS--任务的创建和运行

    文章目录 前言一 创建任务和删除函数1 xTaskCreate 2 xTaskCreateStatic 3 xTaskCreateRestricted 4 vTaskDelete 二 任务函数和任务控制块TCB1 任务函数模板2 TCB 三
  • 如何将本地项目上传到gitee

    如何将本地项目上传到gitee 第一步 xff1a 首先你要有一个gitee仓库 新建仓库 填写仓库信息 xff1a 如图 第二步 xff1a 将创建好的仓库 xff0c pull xff08 拉取 xff09 到本地 通过git 命令 把
  • go语言操作es

    目录 go语言操作es解决golang使用elastic连接elasticsearch时自动转换连接地址初始化数据创建结构体方式字符串方式 xff1a 查找修改删除查找 集群搭建配置文件修改 go语言操作es go get github c
  • Context介绍

    目录 Context设计原理默认上下文取消信号传值方法小结 Context 上下文 context Context Go 语言中用来设置截止日期 同步信号 xff0c 传递请求相关值的结构体 上下文与 Goroutine 有比较密切的关系
  • 将视频转成ROS的bag包

    执行转化命令 python2 mp4 2 bag py lane video3 mp4 out camera bag 循环播放图片 xff0c 并重命名成自己需要的话题名 rosbag play l out camera bag camer
  • beego介绍(一)

    目录 beego 的 MVC 架构介绍参数配置默认配置解析不同级别的配置多个配置文件支持环境变量配置系统默认参数基础配置App 配置Web配置监听配置Session配置Log配置 路由设置基础路由基本 GET 路由基本 POST 路由注册一
  • TCP如何保证可靠性?

    TCP如何保证可靠性 xff1f TCP协议保证数据传输可靠性的方式主要有 xff1a 校验和 序列号 确认应答 超时重传 连接管理 流量控制 拥塞控制 1 校验和 计算方式 xff1a 在数据传输的过程中 xff0c 将发送的数据段都当做
  • 仿照java的jdk动态代理实现go语言动态代理

    仿照java的jdk动态代理实现go语言动态代理 通过学习java的jdk动态代理和Cglib动态代理 xff0c 仿照jdk动态代理用go实现了一个简单的动态代理 结构型模式 代理模式 代理模式中分为静态代理和动态代理 静态代理需要在编译
  • golang设计模式——装饰器模式

    装饰器模式 装饰器模式 xff1a 动态地给一个对象添加一些额外的职责 xff0c 就增加功能来说 xff0c 装饰模式比生成子类更为灵活 UML类图 xff1a 分析 首先我们需要理解 xff0c 为什么组合优于继承 xff1f 继承有诸
  • GoLang之unsafe分析

    GoLang之unsafe 目录 GoLang之unsafe1 前言2 指针类型转换3 指针运算4 获取大小和偏移5 关于string 1 前言 开发中 xff0c byte类型和string类型需要互相转换的场景并不少见 xff0c 直接
  • Go实现分布式锁

    Go分布式锁 目录 Go分布式锁进程内加锁trylock基于 redis 的 setnx基于 zk基于 etcdredlock如何选择 在单机程序并发或并行修改全局变量时 xff0c 需要对修改行为加锁以创造临界区 为什么需要加锁呢 xff
  • Golang实习蓝湖二面

    蓝湖二面 自我介绍 问题 casbin的策略 ACL RBAB ABAC 他们的区别和应用 JWT的实现 JWT和传统的token有什么区别 三次握手和四次挥手 time wait 为什么需要等待2MSL 什么是完全二叉树 完全二叉树有什么
  • export、import、commit、save、load的区别

    目录 1 docker export 和 docker import2 docker commit3 docker save 和 docker load 1 docker export 和 docker import docker expo
  • docker搭建redis集群模式

    目录 docker 安装redis1 创建redis conf开启redis验证 开启密码 允许redis外地连接后台启动开启redis持久化 2 启动redis容器3 进入容器 redis集群3主3从1 新建6个redis容器2 构建主从
  • SONiC+P4实践——P4Runtime下发ACL表项

    转载请表明出处 注 xff1a SONiC系统为vs版本 Part1 xff1a 实现外部宿主机与SONiC的网络连通 步骤 1 xff1a 打开一个ubuntu系统安装kvm及其依赖 xff08 1 xff09 查看CPU是否支持虚拟化