51学通信论坛2017新版

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 1263|回复: 0
打印 上一主题 下一主题

虚拟网络:OpenFlow,与OpenStack集成,边缘虚拟网络

[复制链接]

 成长值: 15613

  • TA的每日心情
    开心
    2022-7-17 17:50
  • 2444

    主题

    2544

    帖子

    7万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    74104
    跳转到指定楼层
    楼主
    发表于 2017-9-16 21:10:26 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
    2017-07-24 云技术社区翻译组 云技术实践
    第5章 虚拟网络
    本章,我们主要介绍以下内容:
    l 基于OpenFlow 实现网络虚拟化
    l 与OpenStack Neutron集成配置
    l OpenStack和OpenDaylight集成
    l 边缘虚拟网络
    l 服务功能链(SFC)
    简介
    网络虚拟化可以在虚拟环境运行,同时可以把硬件资源跟虚拟网络解耦,提供更高的扩展能力。虚拟化用软件模拟硬件平台,这样用一个硬件就可以支持多个虚拟机,按照自己的需要来管理这些虚拟机。NFV(Network Function Virtulization)就是这种能力在网络方面的对应。
    配合SDN,NFV的交互能力和定制化能力得到显著的提高,为数据中心和云计算提供更细粒度的优化。其中,动态提供和监控、按需提供网络功能带来的基础设施水平扩展能力、对生产拓扑更好管理更好理解以及其他的一些好处正在电信生态中体现。这提供了高效、可扩展和可管理的解决方案。在本章中,我们会介绍使用OpenDaylight做网络虚拟化的用法。
    基于OpenFlow 实现网络虚拟化
    正如公司通常分几个部门,每个部门都有明确的分工。同样,网络系统和硬件驻留在不同的部门。 OpenDaylight的虚拟网络租户项目出于减轻物理网络负荷的考虑,让软件处理它。 在配置完成时VTN会自动映射想要的网络能力,这样用户只要关心自己要创建的网络功能虚拟实体,而不用去考虑物理网络。 这样,您将更好地利用资源并减少重新配置网络服务时间。
    该项目提供两个主要组成部分:
    VTN Manager:它是与其他模块交互的内部OpenDaylight应用程序,实现VTN模型的组件。 使用REST API,用户可以根据需要创建、删除、更新和删除(CRUD)VTN组件。
    此外,VTN管理器实现OpenStack L2网络功能API。
    VTN协调器:作为外部应用程序提供,但是在OpenDaylight发行包发布。它提供REST API来与VTN Manager组件交互,以便定义用户配置。它是服务和编排层的一部分,支持多控制器编排,并使虚拟网络租户功能有效。VTN协调器的目的是提供虚拟层2层网络以便互连。主机用虚拟网桥使用VTN管理器组件。
    预备条件
    此解决方案需要一个虚拟交换机。 如果你没有任何虚拟交换机,你可以使用Mininet-vm与OvS安装。可以从网站下载mininet-vm:
    https: //github. com/mininet/mininet/wiki/Mininet-VM-Images.。
    本章采用OvS 2.3.1的Mininet-VM。你也可以从以下网站得到postman的执行集: https: //www. getpostman.com/collections/d49899eae85985d8e4ba
    操作指南
    1.使用karaf脚本启动OpenDaylight。使用脚本访问karaf CLI:

    $ ./bin/karaf

    2.安装面向用户界面,安装连接OpenFlow交换机所需的依赖项:

    opendaylight-user@root>feature:install odl-vtn-manager-neutron odl-vtn-manager-rest

    可能需要一分钟左右完成安装。
    3.以被动或主动模式将OvS实例连接到OpenDaylight:

    使用用户名和密码登录到mininet-vm。
    用户名:mininet
    密码:mininet
    使用主动模式连接两个OvS。
    $ sudo ovs-vsctl set-manager tcp:${CONTROLLER_IP}:6640
    其中,$ {CONTROLLER_IP}是运行OpenDaylight的主机的IP地址。
    现在,我们的虚拟交换机已连接到OpenDaylight:
    mininet@mininet-vm:~$ sudo ovs-vsctl show
    0b8ed0aa-67ac-4405-af13-70249a7e8a96
    Manager "tcp:192.168.0.115:6640"
    is_connected: true
    ovs_version: "2.3.1"

    4.创建包含三个交换机和四个主机的网络拓扑Mininet-VM。使用此命令:

    $ sudo mn --controller = remote,ip = $ {CONTROLLER_IP} --topo tree,2
    使用以下命令查看拓扑:
    mininet> net

    5.尝试从h3 ping h1,动作结果将显示失败。因为按原理,交换机2不能到达交换机3:

    mininet> h1 ping h3
    mininet> h1 ping h3
    PING 10.0.0.3 (10.0.0.3) 56(84) bytes of data.
    From 10.0.0.1 icmp_seq=1 Destination Host Unreachable
    From 10.0.0.1 icmp_seq=2 Destination Host Unreachable
    From 10.0.0.1 icmp_seq=3 Destination Host Unreachable
    ^C
    --- 10.0.0.3 ping statistics ---
    5 packets transmitted, 0 received, +3 errors, 100% packet
    loss, time 4024ms

    6. 交换机转发数据包到控制器时,如果有table-miss,需要添加要求流量。

    $ sudo ovs-ofctl add-flow s1 priority = 0,actions = output:CONTROLLER
    $ sudo ovs-ofctl add-flow s2 priority = 0,actions = output:CONTROLLER
    $ sudo ovs-ofctl add-flow s3 priority = 0,actions = output:CONTROLLER

    此步骤只有第一个版本或Beryllium版需要做,Beryllium-SR以后的版本会自动增加这些流表。
    7.使用以下请求,创建名为vtn1的虚拟承租人:

    type: POST
    headers: Authorization: Basic YWRtaW46YWRtaW4=
    url: http://localhost:8181/restconf/operations/vtn:update-vtn
    payload:
    {
    "input":{
    "tenant-name":"vtn1"
    }
    }
    你会收到代码200 OK的反馈信息。

    8.在先前创建的租户内创建名为vBr1的虚拟网桥:

    type: POST
    headers: Authorization: Basic YWRtaW46YWRtaW4=
    url: http://localhost:8181/restconf/operations/vtn:update-vtn
    payload:
    {
    "input":{
    "tenant-name":"vtn1",
    "bridge-name":"vbr1"
    }
    }
    你应该会收到代码200 OK的反馈信息。

    9.在虚拟网桥中创建两个接口if1和if2:

    type: POST
    headers: Authorization: Basic YWRtaW46YWRtaW4=
    url:
    http://localhost:8181/restconf/operations/vtn-vinterface:update-vinterface
    payload:
    {
    "input":{
    "tenant-name":"vtn1",
    "bridge-name":"vbr1",
    "interface-name":"if1"
    }
    }
    收到代码200 OK的反馈信息。
    重复此请求以创建第二个接口,但更改接口名称与if2。

    10. 在交换机内,创建之前创建的接口和实际端口之间的映射。目的是在h1和h3内创建一个桥。在OvS中,h1连接到端口s2-eth1,h3连接到端口s3-eth1。
    为了完成映射,我们还需要在OpenDaylight内部的openflow节点与交换机端口建立关联。它可以通过阅读openflow节点信息来获取。
    在我们的例子中,s2-eth1与openflow:2相关联,s3-eth1与openflow:3相关连。

    type: POST
    headers:Authorization: Basic YWRtaW46YWRtaW4=
    url:
    http://localhost:8181/restconf/operations/vtn-port-map:set-port-map
    payload for host 1:
    {
    "input":{
    "tenant-name":"vtn1",
    "bridge-name":"vbr1",
    "interface-name":"if1",
    "node":"openflow:2",
    "port-name":"s2-eth1"
    }
    }

    你应该会收到代码200 OK的响应。
    重复同样的操作,请务必使用主机3的值替换interface-name,node和port-name
    11.主机1现在应该能够使用创建的虚拟网桥ping主机3:

    mininet> h1 ping h3
    PING 10.0.0.3 (10.0.0.3) 56(84) bytes of data.
    64 bytes from 10.0.0.3: icmp_seq=1
    ttl=64 time=47.4 ms
    64 bytes from 10.0.0.3: icmp_seq=2
    ttl=64 time=0.220 ms
    64 bytes from 10.0.0.3: icmp_seq=3
    ttl=64 time=0.055 ms
    64 bytes from 10.0.0.3: icmp_seq=4
    ttl=64 time=0.150 ms
    ^C
    --- 10.0.0.3 ping statistics ---
    4 packets transmitted, 4 received,
    0% packet loss, time
    3002ms
    rtt min/avg/max/mdev =
    0.055/11.968/47.450/20.485 ms

    运转机制
    当把物理端口连接到虚拟接口时,VTN项目将使用端口匹配信息、vlan和mac地址等生成流表并推送到交换机来启用通信。
    请参见每个交换机内的流(仅显示交换机1,但类似的流存在于其他交换机中):匹配VLAN 0x000的报文

    mininet@mininet-vm:~$ sudo ovs-ofctl dump-flows s1 -O OpenFlow13
    OFPST_FLOW reply (OF1.3) (xid=0x2):
    cookie=0x0, duration=123.379s, table=0, n_packets=48, n_bytes=4080,
    priority=0 actions=CONTROLLER:65535
    cookie=0x7f56000000000001, duration=118.249s, table=0, n_packets=4,
    n_bytes=336, send_flow_rem
    priority=10,in_port=2,vlan_tci=0x0000/0x1fff,dl_src=a6:33:4c:dd:fb:9f,
    dl_dst=92:bd:3b:89:75:6b actions=output:1
    cookie=0x7f56000000000002, duration=118.243s, table=0, n_packets=4,
    n_bytes=336, send_flow_rem
    priority=10,in_port=1,vlan_tci=0x0000/0x1fff,dl_src=92:bd:3b:89:75:6b,
    dl_dst=a6:33:4c:dd:fb:9f actions=output:2

    更多信息
    使用以下请求检索完整配置:

    type: GET
    headers:Authorization: Basic YWRtaW46YWRtaW4=
    url:
    http://localhost:8181/restconf/operational/vtn:vtns/
    删除租户的完整配置:
    type: POST
    headers: Authorization: Basic YWRtaW46YWRtaW4=
    url:
    http://localhost:8181/restconf/operations/vtn:remove
    -vtn
    payload:
    {
    "input":{
    "tenant-name":"vtn1"
    }
    }

    与OpenStack neutron集成配置
    Networking-odl是OpenStack组件,在Neutron API和OpenDaylight
    之间建立连接通道。NeutronNorthbound项目,是OpenDaylight项目的一部分,为Neutron中定义的每个API建立了Yang模型。在Beryllium版本,这些模型可以在项目的github镜像https: //github. com/opendaylight/neutron/tree/stable/beryllium/model/src/main/yang中找到。这两个项目的网络框架建立了NFV平台和SDN框架之间的桥梁。
    OpenStack的Mechanical Layer 2驱动程序和OpenDaylight Neutron Northbound需要保持他们两个框架之间相关数据的一致性,保证任何时候数据都能共享。
    NeutronNortbound(NN)项目根本不与数据交互。它提供给他们发生Neutron事件时的数据存储。 Neutron Northbound的消费服务在这些模型上注册监听器,这样就可以基于事件对网络行为进行响应和编程。
    在这一节里,我们将演示如何用dummy provider创建网络、子网和端口,所以创建后并不会发生什么。创建的目的是演示如何使Neutron API集成在OpenDaylight中。
    预备条件
    本方案需要OpenDaylight,而功能文件需要添加dummy-provider,以便在没有任何用户注册的情况下测试Neutron API(下面将会介绍详细操作步骤)。
    注:由于删除了dummy provider,该解决方案无法适用于Boron版本。它只适用Lithium and Beryllium版本。
    操作指南
    1. 使用karaf脚本启动OpenDaylight karaf。访问karaf CLI的脚本程序如下:

    $ ./bin/karaf

    2. 安装面向用户的功能,并安装所有依赖项:

    opendaylight-user@root>feature:
    install feature:install odl-neutron-service
    完成安装可能需要一分钟左右。

    3. 在karaf CLI上使用以下命令验证部署

    $ web:list

    可以看到Web-ContextPath的Web状态部署为/controller/nb/v2/neutron,这意味着OpenDaylight中的Neutron Northbound Web服务器已经被部署为可用。
    4. 添加一个特性库引入虚拟提供者,为了测试API需要下载合适的功能文件,不同的版本下载的链接不一样。

    Beryllium-SR: https: //raw. githubusercontent. com/j goodyear/OpenDayl
    ightCookbook/master/chapter5/chapter5-recipe2/src/main/resources
    /features-neutron-test-0. 6. 0-Beryllium-features. xml
    Beryllium-SR1:
    https: //raw. githubusercontent. com/j goodyear/OpenDaylightCookbook
    /master/chapter5/chapter5-recipe2/src/main/resources/features-ne
    utron-test-0. 6. 1-Beryllium-SR1-features. xml
    Beryllium-SR2:
    https: //raw. githubusercontent. com/j goodyear/OpenDaylightCookbook
    /master/chapter5/chapter5-recipe2/src/main/resources/features-ne
    utron-test-0. 6. 2-Beryllium-SR2-features. xml

    然后使用此命令在运行的实例中添加存储库的OpenDaylight:

    $ feature:repo-add
    https://nexus.opendaylight.org/content/
    repositories/opendaylight.release/org/
    opendaylight/neutron/
    features-neutron-test/0.6.0-Beryllium/
    features-neutron-test-0.6.0-Beryllium-features.xml
    添加后,安装dummy-provider功能:
    $ feature:install odl-neutron-dummyprovider-test

    5.添加网络
    要执行此操作,您需要发送以下请求,以及有效载荷。正如你可以看到的,有效载荷中定义的UUID是其中一个URL,并且必须匹配

    type: POST
    headers: Authorization: Basic YWRtaW46YWRtaW4=
    url:
    http://localhost:8080/controller/nb/v2/neutron/networks/
    payload:
    {
    "networks":[ {
    "status":"ACTIVE",
    "subnets":[],
    "name":"network1",
    "admin_state_up":true,
    "tenant_id:
    "60cd4f6dbc5f499982a284e7b83b5be3",
    "provider:network_type":"local",
    "router:external":false,
    "shared":false,
    "id":"e9330b1f-a2ef-4160-
    a991-169e56ab17f5",
    "provider:segmentation_id":100
    } ]
    }

    使用虚拟提供程序,将发送201 Created请求。
    6. 在网络中,为同一租户添加子网:

    type: POST
    headers: Authorization: Basic YWRtaW46YWRtaW4=
    url:
    http://localhost:8080/controller/nb/v2/neutron/subnets/
    payload:
    {
    "subnet": {
    "name": "",
    "enable_dhcp": true,
    "network_id": "e9330b1f-a2ef-
    4160-a991-169e56ab17f5",
    "tenant_id":
    "4fd44f30292945e481c7b8a0c8908869",
    "dns_nameservers": [],
    "allocation_pools": [ {
    "start": "192.168.199.2",
    "end": "192.168.199.254"
    } ],
    "host_routes": [],
    "ip_version": 4,
    "gateway_ip": "192.168.199.1",
    "cidr": "192.168.199.0/24",
    "id": "3b80198d-4f7b-4f77-9ef5
    -774d54e17126"
    }
    }

    7.在子网中,为同一个租户创建一个端口:

    type: POST
    headers:Authorization: Basic YWRtaW46YWRtaW4=
    url:
    http://localhost:8080/controller/nb/v2/neutron/ports/
    payload:
    {
    "port": {
    "status": "DOWN",
    "binding:host_id": "",
    "name": "port1",
    "allowed_address_pairs": [],
    "admin_state_up": true,
    "network_id": "e9330b1f-a2ef-
    4160-a991-169e56ab17f5",
    "tenant_id": "4fd44f30292945e481c
    7b8a0c8908869",
    "binding:vif_details": {},
    "binding:vnic_type": "normal",
    "binding:vif_type": "unbound",
    "mac_address": "fa:16:3e:c9:cb:f0",
    "binding:profile": {},
    "fixed_ips": [ {
    "subnet_id":
    "3b80198d-4f7b-4f77-
    9ef5774d54e17126",
    "ip_address": "192.168.199.1"
    } ],
    "id": "65c0ee9f-d634-4522-8954-
    51021b570b0d"
    }
    }

    工作原理
    通过本书前面章节提到的定义模型,我们发送的每个请求都等同于OpenDaylight数据存储区中的写入。NeutronNorthbound项目支持比三个基本操作更多的操作,但目的是示范它如何工作、有效载荷,以及如何与OpenStack Neutron API匹配。
    OpenStack与OpenDaylight集成
    OpenDaylight中的各种子项目正在集成OpenStack,例如VTN项目。本章节我们将专注于一个网络虚拟化项目:NetVirt。
    NetVirt是一个使用Open vSwitch DataBase(OVSDB)做南向接口跟Open Vswitch以及硬件VTEP交换机交互的解决方案。 NetVirt项目还支持服务功能链(将在下一章节中讨论)。
    在本小节中,我们将演示OpenStack如何用devstack与OpenDaylight集成使用。
    预备条件
    这个解决方案需要至少两个OpenStack节点,一个控制节点和一个计算节点(您可以有多个计算节点)以及一个OpenDaylight发布。 为了您的
    方便,我们创建了VirtualBox使用的OVA镜像,可以轻松为使用者设置所有部署。包括OpenStack Liberty 和 OpenDaylightBeryllium。下载地址:https: //drive.google.com/file/d/0B8ihDx8wnbwjMU5nUmttUFRJOEU。
    OVA镜像提供三个节点:

    OpenStack control and compute – devstack – OvS – CentOS7
    OpenStack compute – devstack – OvS – CentOS7
    Router for external access – CentOS6.5

    操作指南
    1. 打开VirtualBox
    如果你没有安装VirtualBox,你可以在这里下载:
    https: //www. virtualbox. org/wiki/Downloads
    2.将OVA导入VirtualBox

    File | Import Appliance

    选择下载的设备:

    ovsdbtutorial15_2_liberty_be_external.ova

    几分钟后,在VirtualBox中有三个新节点,名为:

    odl31-control, odl32-compute, router-node

    3.启动前两个虚拟机,通过终端ssh登陆到虚拟机:
    登录控制节点,密码为odl:

    $ ssh odl@192.168.50.31

    登录计算节点,密码为odl:

    $ ssh odl@192.168.50.32

    4.为了有效地启动和配置OpenStack,使用DevStack完成集成:

    http: //docs. openstack. org/developer/devstack/

    它提供了安装OpenStack关键组件的工具源,允许用户选择要使用的服务。
    DevStack的配置文件是local.conf。让我们仔细看看devstack配置文件:
    第一行是设置日志配置,以不同源方向登录输出,从而获得更好的操作效果:

    LOGFILE=/opt/stack/logs/stack.sh.log
    SCREEN_LOGDIR=/opt/stack/logs
    LOG_COLOR=False

    由于VM中提供的映像包含所有需要的源代码和工具,设置以下选项以避免错误更新源代码。

    OFFLINE=True
    RECLONE=no
    VERBOSE=TRUE

    禁用所有服务,以便我们可以明确启用我们需要的:

    disable_all_services

    启用核心服务:glance,keystone,nova,vnc,horizon:

    n-obj
    n-cpu n-cond n-sch n-novnc n-xvnc n-cauth
    enable_service horizon

    将OpenDaylight设置为Neutron后端引擎,而不是OpenStack L2 agent:

    enable_service neutron q-dhcp q-meta q-svc
    odl-compute odl-neutron

    设置主机信息,您将需要运行的主机的IP地址跑DevStack,这里是192.168.254.31,必须定义hostname,这里是odl31:

    HOST_IP=192.168.254.31
    HOST_NAME=odl31
    SERVICE_HOST_NAME=$HOST_NAME
    SERVICE_HOST=$HOST_IP
    Q_HOST=$SERVICE_HOST

    启用networking-odl插件,使用其存储库信息:
    当配置为离线时,DevStack将尝试从/ opt / stack / networking-odl文件夹(这是源代码实际位于的位置)检索network-odl存储库。

    enable_plugin networking-odl
    http://git.openstack.org/openstack/networking-odl

    关于OpenDaylight的几个配置必须在配置文件里设置,最重要的是以下:

    ODL_PORT=8080
    ODL_MGR_IP=192.168.2.11
    ODL_L3=True
    ODL_PROVIDER_MAPPINGS=br-ex:eth2

    您可以指定OpenDaylight IP地址,一个OpenDaylight监听的端口,L3转发是否启用和映射配置,这里设置br_ex在eth2后面。
    如果OpenDaylight在与DevStack(控制节点)相同的主机上运行,将会禁用L3转发,因为两个实体使用L2能够良好通信。但是,如果OpenDaylight在DevStack外部安装,必须在DevStack和OpenDaylight配置中启用L3(参见第6条OpenDaylight配置)。
    local.conf中剩余的配置主要是关于OpenStack内部其他功能。
    有关配置文件的详细信息,请访问:

    http: //docs. openstack. org/developer/devstack/configuration. html#local-conf

    5. 在控制和计算节点上,编辑local.conf以添加IP地址。
    主机运行OpenDaylight:

    $ vi /opt/devstack/local.conf

    更改IP地址ODL_MGR_IP的值运行主机上的ODL。
    6.在OpenDaylight中启用L3转发:

    $ vi etc / custom.properties

    取消注释第83行以启用此功能:

    ovsdb.l3.fwd.enabled = yes

    7.使用karaf脚本启动OpenDaylight karaf。用以下脚本访问karaf CLI。

    $ ./bin/karaf

    8.安装面向用户的功能,包括安装所有依赖项:

    opendaylight-user@root>feature:install odl-ovsdb-openstack

    完成安装可能需要一分钟左右。
    9.在每个节点上,执行以下命令:

    $ cd /opt/devstack
    $ ./stack.sh

    完成后,您应该有以下输出:

    This is your host IP address: 192.168.254.31
    This is your host IPv6 address: ::1
    Horizon is now available at
    http://192.168.254.31/dashboard
    Keystone is serving at
    http://192.168.254.31:5000/
    The default users are: admin and demo
    The password: admin

    注:您应该使用192.168.50.31,而不是使用192.168.254.31作为Horizon IP地址。 原因是因为192.168.254.0子网是一个从主机无法访问的隔离网络,而192.168.50.0子网可从主机到达。
    10.每个节点都有一个OvS实例运行,并配置有两个网桥:内部(br-int)和外部桥(br-ex)。 使用以下命令,查看输出拓扑:

    [odl@odl31 devstack]$ sudo ovs-vsctl show
    6b96af57-f05b-4663-9e1d-180c0c788a5b
    Manager "tcp:192.168.1.164:6640"
    is_connected: true
    Bridge br-ex
    Controller "tcp:192.168.1.164:6653"
    is_connected: true
    fail_mode: secure
    Port br-ex
    Interface br-ex
    type: internal
    Bridge br-int
    Controller "tcp:192.168.1.164:6653"
    is_connected: true
    fail_mode: secure
    Port br-int
    Interface br-int
    type: internal
    ovs_version: "2.4.0"

    11.每个网桥被设置有一组流以便管理服务。这里是每个桥的流量转储:

    [odl@odl32 stack]$ sudo ovs-ofctl dump-flows br-int –O OpenFlow13
    OFPST_FLOW reply (OF1.3) (xid=0x2):
    cookie=0x0, duration=2688.686s, table=0, n_packets=0,
    n_bytes=0, dl_type=0x88cc actions=CONTROLLER:65535
    cookie=0x0, duration=2688.649s, table=0, n_packets=0,
    n_bytes=0, priority=0 actions=goto_table:20
    cookie=0x0, duration=2688.649s, table=20, n_packets=0,
    n_bytes=0, priority=0 actions=goto_table:30
    cookie=0x0, duration=2688.649s, table=30, n_packets=0,
    n_bytes=0, priority=0 actions=goto_table:40
    cookie=0x0, duration=2688.649s, table=40, n_packets=0,
    n_bytes=0, priority=0 actions=goto_table:50
    cookie=0x0, duration=2688.649s, table=50, n_packets=0,
    n_bytes=0, priority=0 actions=goto_table:60
    cookie=0x0, duration=2688.649s, table=60, n_packets=0,
    n_bytes=0, priority=0 actions=goto_table:70
    cookie=0x0, duration=2688.649s, table=70, n_packets=0,
    n_bytes=0, priority=0 actions=goto_table:80
    cookie=0x0, duration=2688.649s, table=80, n_packets=0,
    n_bytes=0, priority=0 actions=goto_table:90
    cookie=0x0, duration=2688.649s, table=90, n_packets=0,
    n_bytes=0, priority=0 actions=goto_table:100
    cookie=0x0, duration=2688.649s, table=100, n_packets=0,
    n_bytes=0, priority=0 actions=goto_table:110
    cookie=0x0, duration=2688.649s, table=110, n_packets=0,
    n_bytes=0, priority=0 actions=drop
    [odl@odl32 stack]$ sudo ovs-ofctl dump-flows br-ex –O OpenFlow13
    OFPST_FLOW reply (OF1.3) (xid=0x2):
    cookie=0x0, duration=2700.054s, table=0, n_packets=0,
    n_bytes=0, dl_type=0x88cc actions=CONTROLLER:65535
    cookie=0x0, duration=2700.054s, table=0, n_packets=0,
    n_bytes=0, priority=0 actions=NORMAL

    内部桥,br-int,设置提供以下流水线:
    12.仔细观察节点的接口配置。 每个节点都共享了相同的内部配置,即:
    eth0:VirtualBox NAT地址,10.0.2.15。管理界面可以使用但需要添加VirtualBox端口转发才能从主机到达。
    eth1:租户流量的内部接口
    eth2:浮动IP外部接口
    eth3:VirtualBox桥接适配器,192.168.50.3 {1,2}。从主机可达管理接口。
    工作原理
    使用OpenDaylight的外部实例,必须启用L3转发,以便两个实体(OpenStack控制节点和OpenDaylight)能够彼此通信。 此外,需要在DevStack配置中设置外部桥接器(eth2)所在的接口。
    配置时,控制和计算节点中包含的OvS实例将连接到OpenDaylight。通过OpenFlowPlugin和OpenFlowJava项目,NetVirt项目能够在这些事件上注册一个监听器,从而通过添加内部网桥(br-int)和外部网桥来做出反应。仅当启用L3转发时才添加外部网桥。
    为了添加这些交换机,NetVirt使用OVSDB南向插件与OVS进行通信。
    最后,在交换机内,基本流表被推送,这样他们就知道如何反应,基于它们的匹配动作向什么地方发送这些报文。
    边缘虚拟网络
    使用OpenStack集成的各种关键特性之一是,OpenDaylight可以在主机之间创建虚拟可扩展LAN(VXLAN)、网络实体、网络、子网和端口配置。 使用安全组和安全规则,可以轻松地定义端口组的规范,无论是入口或出口端口,并且定义组内规则允许行为。
    在本方案中,我们将演示使用vxlan、L3和浮动IP做网络虚拟化。
    预备条件
    该方案需要至少两个OpenStack节点、一个控制节点和一个计算节点
    (您可以有多个计算节点),以及一个OpenDaylight分布。使用VirtualBox的OVA映像可以使用户轻松部署。它包含OpenStack Liberty和OpenDaylightBeryllium。下载地址:
    https: //drive. google. com/file/d/0B8ihDx8wnbwj MU5nUmttUFRJOEU
    OVA图像提供三个节点:
    OpenStack控制和计算 - devstack - OvS - CentOS7
    OpenStack计算 - devstack - OvS - CentOS7
    外部访问路由器 - CentOS6.5
    操作原理
    1.使用先前介绍中完成的设置。如果您还没有完成配置,请阅读前面的章节,完成配置。
    2.设置Neutron环境
    一旦你有准备好的环境,我们就可以开始使用Neutron控制节点,执行以下命令:

    $ source openrc admin admin

    3.设置具有64 MB内存、无磁盘空间和一个VCPU的nano flavor。flavor是对服务器定义的硬件配置。

    $ nova flavor-create m1.nano auto 64 0 1

    以下脚本可用于执行相同的操作:

    /opt/tools/os_addnano.sh。

    4.创建管理密钥对:

    $ nova keypair-add --pub-key ~/.ssh / id_rsa.pub admin_key

    以下脚本可用于执行相同的操作:

    /opt/tools/os_addadminkey.sh。

    5.创建一个外部flat网络和子网,地址池[192.168.56.9 - 192.168.56.14],网关192.168.56.1和网络192.168.56.0/24:

    $ neutron net-create ext-net --router:external
    --provider:physical_network public
    -- provider:network_type flat
    $ neutron subnet-create --name ext-subnet
    --allocation-pool
    start=192.168.56.9,end=192.168.56.14
    --disable-dhcp --gateway 192.168.56.1
    ext-net 192.168.56.0/24

    6.创建一个外部路由器,并添加上面创建的外部网络作为它
    网关:

    $ neutron router-create ext-rtr
    $ neutron router-gateway-set ext-rtr ext-net

    7.创建虚拟可扩展LAN(VXLAN)网络和子网:

    $ neutron net-create vx-net
    --provider:network_type vxlan
    --provider:segmentation_id 1500
    $ neutron subnet-create vx-net 10.100.5.0/24
    --name vx-subnet --dns-nameserver 8.8.8.8

    8.将VXLAN子网添加为步骤5中创建的路由器的接口:

    $ neutron router-interface-add ext-rtr vx-subnet

    以下脚本可用于执行操作5,6和7:

    /opt/tools/os_addextnetrtr.sh.

    9.创建两个虚拟机,并将它们附加到VXLAN:

    $ nova boot --poll --flavor m1.nano --image
    $(nova image-list | grep 'uec\s' |
    awk '{print $2}' | tail -1)
    --nic net-id=$(neutron net-list |
    grep -w vx-net | awk '{print $2}') vmvx1
    --availability_zone=nova:odl31 --key_name admin_key
    $ nova boot --poll --flavor m1.nano --image
    $(nova image-list | grep 'uec\s' |
    awk '{print $2}' | tail -1)
    --nic net-id=$(neutron net-list | grep -w vx-net |
    awk '{print $2}') vmvx2
    --availability_zone=nova:odl32 --key_name admin_key
    $ nova get-vnc-console vmvx1 novnc
    $ nova get-vnc-console vmvx2 novnc

    以下脚本可用于执行相同的操作:

    /opt/tools/os_addvms.sh.

    10.为每个VM创建浮动IP,以便通过外部可访问网络:
    对于vmvx1 vmvx2:

    vm_id=$(nova list | grep $vm | awk '{print
    $2}')
    port_id=$(neutron port-list -c id -c fixed_ips
    --
    --device_id $vm_id | grep subnet_id | awk
    '{print $2}')
    neutron floatingip-create --port_id $port_id
    ext-net
    done;

    以下脚本可用于执行相同的操作:

    /opt/tools/os_addfloatingips.sh.

    您还可以使用此脚本运行所有这些命令:/opt/tools/os_doitall.sh
    这是控制台上运行所有这些命令后的全局输出:
    https://github. com/j goodyear/OpenDaylightCookbook/blob/master/chapter5/cha
    pter5-recipe4/src/main/resources/console-output. Txt
    11.使用Web UI界面查看创建的拓扑。为此,请安装karaf中的以下功能:

    opendaylight-user@root>feature:install odl-ovsdb-ui

    导航到以下网址,请务必更改$ {CONTROLLER_IP}为运行OpenDaylight的主机的IP地址.
    http://${CONTROLLER_IP}:8181/index.html#/ovsdb/index
    用户是admin,密码是admin。
    您将能够看到以下视图。通过点击任何组件的视图,您将被提供有关它的信息。
    在bellow视图中,您可以看到创建的外部和vxlan网络,以及vxlan网络中包含的两个虚拟机。
    您还可以使用OpenStack UI查看类似的拓扑,只需浏览以下地址:
    http://192.168.50.31/dashboard/project/network_topology/
    用户是admin,密码是admin。
    12.查看OpenDaylight数据存储中的数据。
    OVSDB操作数据存储:
    类型:POST
    headers: Authorization: Basic YWRtaW46YWRtaW4=
    网址:
    http://localhost:8080/restconf/operational/network-topology:network-topology/
    Neutron数据存储 (与OpenStack同步):
    网络:
    类型: POST
    headers: Authorization: Basic YWRtaW46YWRtaW4=
    网址:
    http://localhost:8080/controller/nb/v2/neutr
    on/networks/
    子网:
    类型: POST
    headers: Authorization: Basic YWRtaW46YWRtaW4=
    网址:
    http://localhost:8080/controller/nb/v2/neutron/subnets/
    端口:
    类型: POST
    headers: Authorization: Basic YWRtaW46YWRtaW4=
    网址:
    http://localhost:8080/controller/nb/v2/neutron/ports/
    安全组:
    类型: POST
    headers: Authorization: Basic YWRtaW46YWRtaW4=
    网址:
    http://localhost:8080/controller/nb/v2/neutr
    on/security-groups/
    安全规则:
    类型: POST
    headers: Authorization: Basic YWRtaW46YWRtaW4=
    网址:
    http://localhost:8080/controller/nb/v2/neutron/security-group-rules/
    13. 看看OvS拓扑,对于控制和计算,我们可以看到
    vxlan隧道已经建立。
    期望的控制节点:

    https: //github. com/j goodyear/OpenDaylightCookbook/blob/master/chapter5/chapter5-recipe4/src/main/resources/control-node-topo. txt

    期望的计算节点:

    https: //github. com/j goodyear/OpenDaylightCookbook/blob/master/chapter5/chapter5-recipe4/src/main/resources/compute-node-topo. txt

    工作原理
    这个部署涉及OpenStack和OpenDaylight。这其中,networking-odl和NeutronNorthbound项目做连接的工作,NetVirt是Neutron事件的消费者。NetVirt项目有侦听器,当事件发生时,获得回调,回调将触发写入进入OVSDB Southbound插件,更新OvS拓扑。
    服务功能链
    端到端业务通常需要许多业务功能,如网络业务等作为负载平衡器或防火墙,以及特定应用的服务。 为了提供这些功能的动态服务功能链,减少对网络拓扑和物理资源的耦合,OpenDaylight创建了SFC项目。利用VM和(或)容器网络,可以有效地创建需要具有完全模块化和动态的服务链的网络服务。
    在本小节中,我们将用sfc103演示SFC项目。

    https://github.com/opendaylight/sfc/tree/release/beryllium-sr2/sfc-demo/sfc103

    此方案的全局网络拓扑如下:
    注:以下方案使用的是OpenDaylight Beryllium SR2测试版本,不能保证配置会与其他版本完全一致。
    发布。
    预备条件
    本解决方案需要VirtualBox和一台至少有8G RAM的机器。我们将
    使用trusty Ubuntu虚拟机,可以在这里找到:https: //cloud-images. ubuntu. com/vagrant/trusty/current/trusty-server-cloudimg-amd64-vagrant-disk1. box
    操作指南
    1. .克隆SFC,checkouttag为release/beryllium-sr2的stable/beryllium分支:

    $ git clone
    https://git.opendaylight.org/gerrit/sfc
    $ cd sfc
    $ git checkout tabs/release/beryllium-sr2

    2. 开始演示安装(可以全部自动完成,如果想手动完成安装,请跳过此步骤):

    $ cd sfc-demo/sfc103/
    $ ./demo.sh

    完成安装,可能需要5到10分钟。下面的步骤用来解释自动安装做了哪些事情。
    3. 创建OpenDaylight VM:
    资源:4CPU和4GB的RAM
    私有IP:192.168.1.5
    设置并运行SFC项目。

    $ wget

    https://raw.githubusercontent.com/jgoodyear/OpenDaylightCookbook/master/chapter5/chapter5-recipe5/src/main/resources/setup_odl.sh

    $ ./setup_odl.sh

    4. 创建classifier1 VM:
    资源:1CPU和1GB的RAM(默认,无需指定)
    私有IP:192.168.1.10
    安装先决条件

    $ wget

    https://raw.githubusercontent.com/jgoodyear/OpenDaylightCookbook/master/chapter5/chapter5-recipe5/src/main/resources/setup_prerequisites.sh

    $ ./setup_prerequisites.sh

    安装patched为nhs-aware的OpenVSwitch

    $ rmmod openvswitch
    $ find /lib/modules | grep openvswitch.ko| xargs rm -rf
    $ curl https://raw.githubusercontent.com/priteshk/ovs/nsh-v8/third-party/start-ovs-deb.sh | bash

    将OpenDaylight设置为OVS的管理器,并创建初始交换机br-sfc:

    $ sudo ovs-vsctl set-manager tcp:192.168.1.5:6640
    $ sudo ovs-vsctl add-br br-sfc

    创建和配置内部网络命名空间
    1)创建一个名为app的新网络命名空间:

    $ ip netns add app

    2)通过创建虚拟网络接口对将接口分配给网络命名空间veth-app:

    $ ip link add veth-app type veth peer
    name veth-br

    使用命令ip链接列表,你应该看到一对虚拟以太网接口,现在他们属于“默认”
    或“全局”网络命名空间。 为了连接全局veth接口到创建的app命名空间,执行以下操作:

    $ ip link set veth-app netns app

    3)在br-sfc中创建一个名为veth-br的端口

    $ sudo ovs-vsctl add-port br-sfc veth-br

    4)将veth-br端口设置为up

    $ ip link set dev veth-br up

    5)使用以下命令配置我们的app命名空间
    给veth-app接口分配一个IP地址并设置:

    $ ip netns exec app ifconfig veth-app 192.168.2.1/24 up

    6)为veth-app接口的链路层分配一个mac地址:

    $ ip netns exec app ip link set dev veth-app addr 00:00:11:11:11:11

    7)为veth-app创建一个ARP地址映射条目:

    $ ip netns exec app arp -s 192.168.2.200:00:22:22:22:22 -i veth-app

    8)接口veth-app和lo up:

    $ ip netns exec app ip link set dev veth-app up
    $ ip netns exec app ip link set dev lo up

    9)设置接口veth-app的最大传输单元(MTU):

    $ ip netns exec app ifconfig veth-app mtu 1400

    5. 创建classifier2 VM(步骤类似于步骤4)。
    私有IP:192.168.1.10
    在执行以下步骤时修改值:
    1)使用IP地址192.168.2.2/24
    2)使用MAC地址00:00:22:22:22:22
    3)使用此命令创建ARP映射:

    $ ip netns exec app arp -s 192.168.2.100:00:11:11:11:11-i veth-app

    启动一个简单的HTTP服务器,绑定在端口80上面:

    $ ip netns exec app python -m SimpleHTTPServer 80

    一旦完成步骤4和5,我们有两个分类器的架构。
    6.创建服务功能转发器VM1:
    资源:1CPU和1GB RAM(默认,无需指定)
    私有IP:192.168.1.20
    安装先决条件

    $ wget

    https://raw.githubusercontent.com/jgoodyear/OpenDaylightCookbook/master/chapter5/chapter5-recipe5/src/main/resources/setup_prerequisites.sh

    $ ./setup_prerequisites.sh

    安装补丁为nhs-aware的OpenVSwitch

    $ rmmod openvswitch
    $ find /lib/modules | grep openvswitch.ko| xargs rm -rf
    $ curl https://raw.githubusercontent.com/priteshk/ovs/nsh-v8/third-party/start-ovs-deb.sh | bash

    将OpenDaylight设置为OVS管理器并创建初始网桥和br-sfc:

    $ sudo ovs-vsctl set-manager tcp:192.168.1.5:6640

    7. 创建服务功能转发器VM2:
    资源:1CPU和1GB RAM(默认,无需指定)
    私人IP:192.168.1.50
    安装先决条件

    $ wget https://raw.githubusercontent.com/jgoodyear/OpenDaylightCookbook/master/chapter5/chapter5-recipe5/src/main/resources/setup_prerequisites.sh
    $ ./setup_prerequisites.sh

    安装打了nhs-aware补丁的Open Vswitch

    $ rmmod openvswitch
    $ find /lib/modules | grep openvswitch.ko| xargs rm -rf
    $ curl
    https://raw.githubusercontent.com/priteshk/ovs/nsh-v8/third-party/start-ovs-deb.sh | bash

    将OpenDaylight设置为OVS管理器,并创建初始网桥和br-sfc:

    $ sudo ovs-vsctl set-manager tcp:192.168.1.5:6640

    8.创建服务功能VM1和VM2。 一个是深度检查包(DPI),另一个将是防火墙。
    为这两个VM重复以下操作:
    资源:1CPU和1GB的RAM(默认,无需指定)
    私有IP:192.168.1.30
    安装先决条件

    $ wget

    https://raw.githubusercontent.com/jgoodyear/OpenDaylightCookbook/master/chapter5/chapter5-recipe5/src/main/resources/setup_sf.sh

    $ ./setup_sf.sh

    现在我们已经创建和部署了所有拓扑,让我们进行配置OpenDaylight,使用以下9个请求
    9.为以前创建的节点创建服务节点:

    type: PUT
    headers: Authorization: Basic YWRtaW46YWRtaW4=
    url:
    http://192.168.1.5:8181/restconf/config/service-node:se
    rvice-nodes
    payload:
    {
    "service-nodes":{
    "service-node":[
    {
    "name":"node0",
    "service-function":[],
    "ip-mgmt-address":"192.168.1.10"
    },
    {
    "name":"node1",
    "service-function":[],
    "ip-mgmt-address":"192.168.1.20"
    },
    {
    "name":"node2",
    "service-function":["dpi-1"],
    "ip-mgmt-address":"192.168.1.30"
    },
    {
    "name":"node3",
    "service-function":["firewall-1"],
    "ip-mgmt-address":"192.168.1.40"
    },
    {
    "name":"node4",
    "service-function":[],
    "ip-mgmt-address":"192.168.1.50"
    },
    {
    "name":"node5",
    "service-function":[],
    "ip-mgmt-address":"192.168.1.60"
    }]
    }
    }

    10.创建两个服务功能(DPI和FireWall):

    type: PUT
    headers: Authorization: Basic YWRtaW46YWRtaW4=
    url:
    http://192.168.1.5:8181/restconf/config/service-functio
    n:service-functions
    payload:
    {
    "service-functions":{
    "service-function":[
    {
    "name":"dpi-1",
    "ip-mgmt-address":"192.168.1.30",
    "rest-
    uri":"http://192.168.1.30:5000",
    "type":"dpi",
    "nsh-aware":"true",
    "sf-data-plane-locator":[
    {
    "name":"sf1-dpl",
    "port":6633,
    "ip":"192.168.1.30",
    "transport":"service-
    locator:vxlan-gpe",
    "service-function
    forwarder":"SFF1"
    }]
    },
    {
    "name":"firewall-1",
    "ip-mgmt-address":"192.168.1.40",
    "rest-
    uri":"http://192.168.1.40:5000",
    "type":"firewall",
    "nsh-aware":"true",
    "sf-data-plane-locator":[
    {
    "name":"sf2-dpl",
    "port":6633,
    "ip":"192.168.1.40",
    "transport":"service-
    locator:vxlan-gpe",
    "service-function-
    forwarder":"SFF2"
    }]
    }]
    }
    }

    11.创建服务功能转发器:

    type: PUT
    headers: Authorization: Basic YWRtaW46YWRtaW4=
    url:
    http://192.168.1.5:8181/restconf/config/service-functio
    n-forwarder:service-function-forwarders
    payload: https: //raw. githubusercontent. com/j goodyear/OpenDay
    lightCookbook/master/chapter5/chapter5-recipe5/src/main/res
    ources/sff.json

    12.创建服务功能链:

    type: PUT
    headers: Authorization: Basic YWRtaW46YWRtaW4=
    url:
    http://192.168.1.5:8181/restconf/config/service-functio
    n-chain:service-function-chains/
    payload:
    {
    "service-function-chains":{
    "service-function-chain":[
    {
    "name":"SFC1",
    "symmetric":"true",
    "sfc-service-function":[
    {
    "name":"dpi-abstract1",
    "type":"dpi"
    },
    {
    "name":"firewall-abstract1",
    "type":"firewall"
    } ]
    } ]
    }
    }

    13.创建服务功能元数据:

    type: PUT
    headers: Authorization: Basic YWRtaW46YWRtaW4=
    url:
    http://192.168.1.5:8181/restconf/config/service-functio
    n-path-metadata:service-function-metadata/
    payload:
    {
    "service-function-metadata":{
    "context-metadata":[
    {
    "name":"NSH1",
    "context-header1":"1",
    "context-header2":"2",
    "context-header3":"3",
    "context-header4":"4"
    } ]
    }
    }

    14.创建服务功能路径:

    type: PUT
    headers: Authorization: Basic YWRtaW46YWRtaW4=
    url:
    http://192.168.1.5:8181/restconf/config/service-functio
    n-path:service-function-paths/
    payload:
    {
    "service-function-paths":{
    "service-function-path":[
    {
    "name":"SFP1",
    "service-chain-name":"SFC1",
    "classifier":"Classifier1",
    "symmetric-
    classifier":"Classifier2",
    "context-metadata":"NSH1",
    "symmetric":"true"
    } ]
    }
    }

    15.创建服务功能访问控制列表(ACL):

    type: PUT
    headers: Authorization: Basic YWRtaW46YWRtaW4=
    url:
    http://192.168.1.5:8181/restconf/config/ietf-access-con
    trol-list:access-lists/
    payload: https: //raw. githubusercontent. com/j goodyear/OpenDay
    lightCookbook/master/chapter5/chapter5-recipe5/src/main/res
    ources/acl. j son

    16.创建呈现的服务路径:

    type: POST
    headers: Authorization: Basic YWRtaW46YWRtaW4=
    url:
    http://192.168.1.5:8181/restconf/operations/rendered-se
    rvice-path:create-rendered-path/
    payload:
    {
    "input": {
    "name": "RSP1",
    "parent-service-function-path":
    "SFP1",
    "symmetric": "true"
    }
    }

    17.创建服务功能分类器:

    type: PUT
    headers: Authorization: Basic YWRtaW46YWRtaW4=
    url:
    http://192.168.1.5:8181/restconf/config/service-functio
    n-classifier:service-function-classifiers/
    payload:
    {
    "service-function-classifiers": {
    "service-function-classifier": [
    {
    "name": "Classifier1",
    "scl-service-function-forwarder": [
    {
    "name": "SFF0",
    "interface": "veth-br"
    } ],
    "access-list": "ACL1"
    },
    {
    "name": "Classifier2",
    "scl-service-function-forwarder": [
    {
    "name": "SFF3",
    "interface": "veth-br"
    } ],
    "access-list": "ACL2"
    } ]
    }
    }

    18. 验证部署和环境:
    在分类器和服务功能转发器VM中,查看流量:

    $ sudo ovs-ofctl dump-flows -OOpenflow13 br-sfc

    在创建应用程序网络命名空间时,从classifier1,发送一个wget查询到classifier2。因为在classifier2中设置一个简单的HTTP服务器时,它将响应从而创建流量,并在创建的服务功能链内流动。
    使用wireshark,观察数据包。
    19.拆除部署:

    $ vagrant destroy –f

    工作原理
    首先,我们必须使用VirtualBox和linux网络命令创建环境,设置分类器。完成后,需要配置服务节点、函数、函数转发器、链、元数据、路径、访问控制列表、分类器,以及OpenDaylight数据存储中的渲染器服务路径。 为此,我们使用了REST API由OpenDaylight的SFC yang模型。详细资料可以参阅:https://github. com/opendaylight/sfc/tree/release/beryllium-sr2/sfc-model/src/main/yang。
    关于在分类器和服务功能中使用的OpenVSwitch实例转发器,它已被修改为启用网络服务头(NSH),并能够从OpenFlow规则中封装和解封装VXLAN隧道。
    编者按
    《OpenDaylight Coolbook》这本书由云技术社区志愿者翻译组翻译,因为没有出版纸质书的计划,本书的翻译只会翻译重点章节。
    翻译的过程是译者和作者思想沟通的过程,也是一个学习的过程,中间充满艰辛,也充满快乐。
    云技术越来越成熟,但是云计算网络技术目前有好几个流派,OpenDaylight就是其中之一,《OpenDaylight Coolbook》侧重概念及实战,阅读本书可以快读了解OpenDaylight。
    以下社区优秀翻译参加了本书的翻译:
    云技术社区 金牌翻译 韩卫 第一章
    云技术社区 金牌翻译 邓嘉浩 第三章
    云技术社区 金牌翻译 路君 第四章
    云技术社区 金牌翻译 刘志红 第五章
    云技术社区 金牌翻译 罗晶 第六章
    云技术社区 金牌翻译 罗莹 第九章
    云技术社区 金牌翻译 孟驰 第十章
    云技术社区 金牌翻译 文杰 第十一章
    校对
    云技术社区 金牌翻译 陈海 第一,三,四章
    云技术社区 金牌翻译 陈建永 第五,六,九章
    云技术社区 金牌翻译 黄继敏 第十,十一章
    在此感谢他们辛苦而卓越的付出!
    已经发布章节链接:
    《OpenDaylight Cookbook》第一章:OpenDaylight原理(上)
    《OpenDaylight》第一章:OpenDaylight原理(中)
    《OpenDaylight》第一章:OpenDaylight原理(下)
    《OpenDaylight》第三章:虚拟客户边界
    《OpenDaylight》第四章:动态互联(2)
    《OpenDaylight》第四章:动态互联(2)
    《OpenDaylight》第四章:动态互联(3)
    未经允许谢绝转载

    声明:本文转载自网络。版权归原作者所有,如有侵权请联系删除。
    扫描并关注51学通信微信公众号,获取更多精彩通信课程分享。
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    Archiver|手机版|小黑屋|51学通信技术论坛

    GMT+8, 2025-1-31 17:57 , Processed in 0.161910 second(s), 32 queries .

    Powered by Discuz! X3

    © 2001-2013 Comsenz Inc.

    快速回复 返回顶部 返回列表