在一切开始之前,首先介绍一下我们要做什么,做这个要有什么基础,以及实现的环境
我们要在图下图所示的拓扑中,完成在如以下拓扑所示的网络中,配合ONOS实现基本的L2L3转发以及SRv6,项目总体实现功能较为复杂,因此分为多张准备。
本项目要求的基础:Python、Java、P4\P4runtime、ONOS、YANG以及基本的网络协议
首先,给大家看一下完整的代码,有几个重要的角色:
IPv6Host:这是一个支持IPv6的主机,主要实现了一个ip地址更新的功能,并继承了mininet的Host类,config函数主要是完成对它的超类属性的配置和额外属性的配置
TutorialTopo:实验拓扑图,就是如上图所示的那个图,定义了两个叶交换机和两个脊交换机,并增设链路,然后给各个主机赋予配置
主函数:创建一个Mininet网络,开启它的cli
import argparse
from mininet.cli import CLI
from mininet.log import setLogLevel
from mininet.net import Mininet
from mininet.node import Host
from mininet.topo import Topo
from stratum import StratumBmv2Switch
CPU_PORT = 255
class IPv6Host(Host):
"""Host that can be configured with an IPv6 gateway (default route).
"""
def config(self, ipv6, ipv6_gw=None, **params):
super(IPv6Host, self).config(**params)
self.cmd('ip -4 addr flush dev %s' % self.defaultIntf())
self.cmd('ip -6 addr flush dev %s' % self.defaultIntf())
self.cmd('ip -6 addr add %s dev %s' % (ipv6, self.defaultIntf()))
if ipv6_gw:
self.cmd('ip -6 route add default via %s' % ipv6_gw)
# Disable offload
for attr in ["rx", "tx", "sg"]:
cmd = "/sbin/ethtool --offload %s %s off" % (self.defaultIntf(), attr)
self.cmd(cmd)
def updateIP():
return ipv6.split('/')[0]
self.defaultIntf().updateIP = updateIP
def terminate(self):
super(IPv6Host, self).terminate()
class TutorialTopo(Topo):
"""2x2 fabric topology with IPv6 hosts"""
def __init__(self, *args, **kwargs):
Topo.__init__(self, *args, **kwargs)
# Leaves
# gRPC port 50001
leaf1 = self.addSwitch('leaf1', cls=StratumBmv2Switch, cpuport=CPU_PORT)
# gRPC port 50002
leaf2 = self.addSwitch('leaf2', cls=StratumBmv2Switch, cpuport=CPU_PORT)
# Spines
# gRPC port 50003
spine1 = self.addSwitch('spine1', cls=StratumBmv2Switch, cpuport=CPU_PORT)
# gRPC port 50004
spine2 = self.addSwitch('spine2', cls=StratumBmv2Switch, cpuport=CPU_PORT)
# Switch Links
self.addLink(spine1, leaf1)
self.addLink(spine1, leaf2)
self.addLink(spine2, leaf1)
self.addLink(spine2, leaf2)
# IPv6 hosts attached to leaf 1
h1a = self.addHost('h1a', cls=IPv6Host, mac="00:00:00:00:00:1A",
ipv6='2001:1:1::a/64', ipv6_gw='2001:1:1::ff')
h1b = self.addHost('h1b', cls=IPv6Host, mac="00:00:00:00:00:1B",
ipv6='2001:1:1::b/64', ipv6_gw='2001:1:1::ff')
h1c = self.addHost('h1c', cls=IPv6Host, mac="00:00:00:00:00:1C",
ipv6='2001:1:1::c/64', ipv6_gw='2001:1:1::ff')
h2 = self.addHost('h2', cls=IPv6Host, mac="00:00:00:00:00:20",
ipv6='2001:1:2::1/64', ipv6_gw='2001:1:2::ff')
self.addLink(h1a, leaf1) # port 3
self.addLink(h1b, leaf1) # port 4
self.addLink(h1c, leaf1) # port 5
self.addLink(h2, leaf1) # port 6
# IPv6 hosts attached to leaf 2
h3 = self.addHost('h3', cls=IPv6Host, mac="00:00:00:00:00:30",
ipv6='2001:2:3::1/64', ipv6_gw='2001:2:3::ff')
h4 = self.addHost('h4', cls=IPv6Host, mac="00:00:00:00:00:40",
ipv6='2001:2:4::1/64', ipv6_gw='2001:2:4::ff')
self.addLink(h3, leaf2) # port 3
self.addLink(h4, leaf2) # port 4
def main():
net = Mininet(topo=TutorialTopo(), controller=None)
net.start()
CLI(net)
net.stop()
print '#' * 80
print 'ATTENTION: Mininet was stopped! Perhaps accidentally?'
print 'No worries, it will restart automatically in a few seconds...'
print 'To access again the Mininet CLI, use `make mn-cli`'
print 'To detach from the CLI (without stopping), press Ctrl-D'
print 'To permanently quit Mininet, use `make stop`'
print '#' * 80
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description='Mininet topology script for 2x2 fabric with stratum_bmv2 and IPv6 hosts')
args = parser.parse_args()
setLogLevel('info')
main()
其次介绍一下项目的工具,虽然很枯燥,但是一定要看:
M ake command |
Description |
---|---|
make deps |
build 所有需要的依赖 |
make p4-build |
build P4程序 |
make p4-test |
运用p4测试 |
make start |
主角:创建Mininet网络和创建ONOS容器 |
make stop |
关闭所有容器 |
make restart |
重新打开先前创建的容器 |
make onos-cli |
进入ONOS-cli的命令行 |
make onos-log |
显示onos的日志信息 |
make mn-cli |
进入mininet的命令行 |
make mn-log |
显示mininet的日志信息 |
make app-build |
build onos的APP |
make app-reload |
装载APP到onos上 |
make netcfg |
把网络配置文件装载到onos上 |
其中start的打开一看,实际上就是区分不同的拓扑的py脚本,然后在后台创建所有容器。
_start:
$(info *** Starting ONOS and Mininet (${NGSDN_TOPO_PY})... )
@mkdir -p tmp/onos
@NGSDN_TOPO_PY=${NGSDN_TOPO_PY} docker-compose up -d
start: NGSDN_TOPO_PY := topo-v6.py
start: _start
yml文件如下所示:
version: "3"
services:
mininet:
image: opennetworking/ngsdn-tutorial:stratum_bmv2
hostname: mininet
container_name: mininet
privileged: true
tty: true
stdin_open: true
restart: always
volumes:
- ./tmp:/tmp
- ./mininet:/mininet
ports:
- "50001:50001"
- "50002:50002"
- "50003:50003"
- "50004:50004"
# NGSDN_TOPO_PY is a Python-based Mininet script defining the topology. Its
# value is passed to docker-compose as an environment variable, defined in
# the Makefile.
entrypoint: "/mininet/${NGSDN_TOPO_PY}"
onos:
image: onosproject/onos:2.2.2
hostname: onos
container_name: onos
ports:
- "8181:8181" # HTTP
- "8101:8101" # SSH (CLI)
volumes:
- ./tmp/onos:/root/onos/apache-karaf-4.2.8/data/tmp
environment:
- ONOS_APPS=gui2,drivers.bmv2,lldpprovider,hostprovider
links:
- mininet
环境介绍完了,接下来开始第一个实验吧!