第314篇:OpenConfig 与 IETF 标准模型

关键词:OpenConfig、IETF YANG、标准模型、接口模型、路由模型、多厂商兼容、模型映射


一、引言

前几篇介绍了 NETCONF 和 RESTCONF 这两种协议如何将 YANG 模型作为操作蓝本。然而,YANG 模型本身需要有人来编写——谁来定义这些模型?不同厂商对同一个网络功能(如接口、路由、VLAN)的模型定义是否一致?

这就是 OpenConfig 和 IETF YANG 模型存在的意义:它们提供跨厂商的统一数据模型,使得同一份配置脚本可以在不同品牌的设备上运行。

二、核心概念

2.1 IETF YANG 模型体系

IETF(互联网工程任务组)通过多个工作组定义了覆盖网络核心功能的 YANG 模型:

IETF YANG 模型体系 - 图示

IETF 模型 RFC 覆盖范围
ietf-interfaces RFC 8343 接口基本属性(名称、描述、启用状态、类型)
ietf-ip RFC 8344 IP 地址配置(IPv4/IPv6 地址、前缀、主机路由)
ietf-routing RFC 8294 路由协议实例管理
ietf-bgp RFC 8349 BGP 配置、会话状态、地址族
ietf-ospf 草案阶段 OSPF 配置与状态
ietf-yang-types RFC 6021 公共 YANG 类型(mac-address、dotted-quad 等)
ietf-inet-types RFC 6991 网络类型(ip-address、ipv4-prefix、domain-name 等)

2.2 OpenConfig 项目概述

OpenConfig 是一个开源的 YANG 模型项目,最初由 Google、Facebook 等互联网企业发起,后由开放网络基金会(ONF)维护。其核心设计理念是:

  1. 多厂商兼容:模型基于多家设备厂商的共同能力定义,而非单一厂商特性
  2. 功能优先:以网络功能为组织维度(如 interfaces、routing、platform),而非 CLI 命令层次
  3. 配置与状态分离:明确区分可写配置数据和只读状态数据
  4. 向后兼容:模型演进时保持向后兼容,已有自动化脚本无需修改

OpenConfig 项目概述 - 图示

2.3 OpenConfig 与 IETF 模型对比

维度 OpenConfig IETF
发起方 Google/Facebook 等互联网企业 IETF 标准工作组
设计目标 多厂商通用、功能覆盖全面 标准化、RFC 发布
命名风格 openconfig-interfaces ietf-interfaces
接口标识 支持别名(alias)、名称、索引 仅支持名称
子接口支持 原生支持子接口 通过 if-index + sub-interface 扩展
路由模型 统一路由模型(含 BGP/OSPF/IS-IS/Static) 分散为多个独立模型
平台信息 详细的硬件平台模型(槽位、线卡、端口) 较简略
成熟度 广泛部署,实际驱动 标准发布,渐进式采纳
许可证 Apache 2.0 IETF Trust

2.4 模型的层次关系

模型的层次关系 - 图示

三、技术细节

3.1 ietf-interfaces 模型详解

ietf-interfaces(RFC 8343)是最基础的接口模型:

module ietf-interfaces {
    namespace "urn:ietf:params:xml:ns:yang:ietf-interfaces";
    prefix "if";

    import ietf-yang-types { prefix "yang"; }
    import ietf-inet-types { prefix "inet"; }

    organization "IETF NETMOD (Network Modeling) Working Group";
    contact "IETF NETMOD Working Group";
    description "Interface management model";
    revision 2018-02-22 {
        description "RFC 8343";
    }

    // 接口列表
    list interface {
        key "name";

        leaf name {
            type string;
            description "接口名称,作为唯一标识";
        }

        leaf description {
            type string;
            description "接口描述(管理用途)";
        }

        leaf type {
            type identityref {
                base "iana-if-type:interfaceType";
            }
            mandatory true;
            description "接口类型(如 ethernetCsmacd)";
        }

        leaf enabled {
            type boolean;
            default true;
            description "接口管理状态(true=启用)";
        }

        leaf link-up-down-trap-enable {
            type boolean;
            default true;
        }

        leaf admin-status {
            type enumeration {
                enum up;
                enum down;
                enum testing;
            }
            config false;
            description "管理状态(只读)";
        }

        leaf oper-status {
            type enumeration {
                enum up;
                enum down;
                enum testing;
                enum unknown;
                enum dormant;
                enum not-present;
                enum lower-layer-down;
            }
            config false;
            description "运行状态(只读)";
        }

        leaf if-index {
            type int32 {
                range "1..2147483647";
            }
            config false;
        }

        // 统计计数器
        container statistics {
            config false;

            leaf in-octets {
                type yang:counter32;
            }
            leaf in-unicast-pkts {
                type yang:counter32;
            }
            leaf in-discards {
                type yang:counter32;
            }
            leaf in-errors {
                type yang:counter32;
            }
            leaf out-octets {
                type yang:counter32;
            }
            leaf out-unicast-pkts {
                type yang:counter32;
            }
            leaf out-discards {
                type yang:counter32;
            }
            leaf out-errors {
                type yang:counter32;
            }
        }
    }

    // 接口统计(全局)
    container interfaces-state {
        config false;

        list interface {
            key "name";

            leaf name {
                type string;
            }

            leaf if-index {
                type int32;
            }

            leaf type {
                type identityref {
                    base "iana-if-type:interfaceType";
                }
            }

            leaf oper-status {
                type enumeration {
                    enum up;
                    enum down;
                    enum testing;
                    enum unknown;
                }
            }

            leaf in-octets {
                type yang:counter64;
            }
            leaf out-octets {
                type yang:counter64;
            }

            container statistics {
                leaf in-octets {
                    type yang:counter64;
                }
                leaf out-octets {
                    type yang:counter64;
                }
                leaf in-errors {
                    type yang:counter64;
                }
                leaf out-errors {
                    type yang:counter64;
                }
            }
        }
    }
}

3.2 OpenConfig Interfaces 模型详解

OpenConfig 的接口模型比 IETF 更丰富,支持子接口、MTU、子速率等高级功能:

module openconfig-interfaces {
    namespace "http://openconfig.net/yang/interfaces";
    prefix "oc-if";

    import openconfig-if-aggregate { prefix "oc-ifagg"; }
    import openconfig-if-ethernet { prefix "oc-ifeth"; }
    import openconfig-types { prefix "oc-types"; }
    import ietf-yang-types { prefix "yang"; }
    import ietf-inet-types { prefix "inet"; }

    organization "OpenConfig working group";
    contact "OpenConfig";
    description "Model for interface management";

    // 主接口容器
    container interfaces {
        list interface {
            key "name";

            leaf name {
                type string;
                description "接口名称";
            }

            leaf config {
                type leafref {
                    path "config/name";
                }
            }

            // 配置数据
            container config {
                leaf name {
                    type string;
                }
                leaf description {
                    type string;
                }
                leaf type {
                    type identityref {
                        base "oc-if-types:IF_TYPE";
                    }
                }
                leaf enabled {
                    type boolean;
                    default true;
                }
                leaf loopback-mode {
                    type boolean;
                }
                leaf mtu {
                    type uint16;
                    description "最大传输单元";
                }
            }

            // 状态数据
            container state {
                leaf name {
                    type string;
                    config false;
                }
                leaf oper-status {
                    type enumeration {
                        enum UP;
                        enum DOWN;
                        enum TESTING;
                        enum UNKNOWN;
                        enum DORMANT;
                    }
                    config false;
                }
                leaf phys-address {
                    type yang:mac-address;
                    config false;
                    description "物理 MAC 地址";
                }
                leaf highest-speed {
                    type oc-types:BPS;
                    config false;
                }
                leaf mtu {
                    type uint16;
                    config false;
                }

                // 子接口列表
                list subinterface {
                    key "index";

                    leaf index {
                        type uint32;
                        description "子接口索引号";
                    }

                    container config {
                        leaf index {
                            type uint32;
                        }
                        leaf description {
                            type string;
                        }
                        leaf enabled {
                            type boolean;
                        }
                    }

                    container state {
                        leaf index {
                            type uint32;
                            config false;
                        }
                        leaf oper-status {
                            type enumeration {
                                enum UP;
                                enum DOWN;
                            }
                            config false;
                        }
                    }

                    // 子接口的以太网配置
                    container ethernet {
                        container config {
                            leaf min-mac-limit {
                                type uint16;
                            }
                            leaf max-mac-limit {
                                type uint16;
                            }
                        }
                    }

                    // 子接口的 IP 配置
                    container ipv4 {
                        list address {
                            key "ip";

                            leaf ip {
                                type inet:ipv4-address;
                            }

                            container config {
                                leaf ip {
                                    type inet:ipv4-address;
                                }
                                leaf prefix-length {
                                    type union {
                                        type inet:ipv4-prefix-length;
                                        type yang:dotted-quad;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

3.3 接口配置:IETF vs OpenConfig JSON 对比

同一接口配置用两种模型表示:

{
  "ietf_comparison": {
    "ietf_interfaces": {
      "ietf-interfaces:interface": {
        "name": "GigabitEthernet1/0/1",
        "description": "Uplink-to-Core",
        "type": "iana-if-type:ethernetCsmacd",
        "enabled": true,
        "ietf-ip:ipv4": {
          "address": [
            {
              "ip": "10.2.2.1",
              "netmask": "/30"
            }
          ]
        }
      }
    },
    "openconfig_interfaces": {
      "openconfig-interfaces:interface": {
        "config": {
          "name": "GigabitEthernet1/0/1",
          "description": "Uplink-to-Core",
          "type": "ETHernetCsmacd",
          "enabled": true,
          "mtu": 9000
        },
        "state": {
          "name": "GigabitEthernet1/0/1",
          "oper-status": "UP",
          "phys-address": "00:11:22:33:44:55"
        },
        "subinterfaces": {
          "subinterface": [
            {
              "index": 0,
              "config": {
                "index": 0,
                "description": "Main-subinterface"
              },
              "ipv4": {
                "addresses": {
                  "address": [
                    {
                      "config": {
                        "ip": "10.2.2.1",
                        "prefix-length": 30
                      }
                    }
                  ]
                }
              }
            }
          ]
        }
      }
    }
  }
}
对比维度 IETF 模型 OpenConfig 模型
配置/状态组织 同一节点内混合,用 config false 区分 明确分离 config 和 state 容器
子接口支持 不支持(需厂商扩展) 原生支持 subinterface 列表
MTU 不在核心模型中 在 config/mtu 中定义
MAC 地址 无 state/phys-address
接口速率 无 state/highest-speed
命名空间 urn:ietf:params:xml:ns:yang:ietf-interfaces http://openconfig.net/yang/interfaces

3.4 OpenConfig Routing 模型

OpenConfig 的路由模型提供了统一的路由协议管理框架:

module openconfig-routing-policy {
    namespace "http://openconfig.net/yang/policy";
    prefix "oc-pol";

    organization "OpenConfig working group";
    description "Routing policy model";

    // 策略定义
    container routing-policy {
        list policy-definition {
            key "name";

            leaf name {
                type string;
                description "策略名称";
            }

            // 策略条目列表
            list policy-statements {
                leaf statement-id {
                    type string;
                }

                // 匹配条件
                container conditions {
                    container match {
                        // 匹配路由协议
                        leaf route-type {
                            type enumeration {
                                enum DIRECT;
                                enum STATIC;
                                enum CONNECTED;
                                enum BGP;
                                enum OSPF;
                                enum ISIS;
                            }
                        }
                        // 匹配前缀
                        container address-prefixes {
                            list address-prefix {
                                key "prefix-length";
                                leaf prefix-length {
                                    type uint8;
                                }
                                leaf prefix {
                                    type string;
                                }
                            }
                        }
                    }
                }

                // 策略动作
                container actions {
                    leaf policy-result {
                        type enumeration {
                            enum ACCEPT_ROUTE;
                            enum REJECT_ROUTE;
                        }
                    }
                    // 设置路由属性
                    container route-modifications {
                        leaf community {
                            type oc-types:COMMUNITY_TYPE;
                        }
                        leaf local-preference {
                            type uint32;
                        }
                        leaf metric {
                            type uint32;
                        }
                    }
                }
            }
        }
    }
}

3.5 模型选择与兼容性策略

模型选择与兼容性策略 - 图示

场景 推荐模型 理由
单一华为设备 华为扩展模型 功能覆盖最全,支持所有华为特性
多厂商设备混合 OpenConfig 多厂商共识模型,功能比 IETF 丰富
最大兼容性要求 IETF 标准模型 所有 NETCONF/RESTCONF 设备均支持
子接口管理 OpenConfig IETF 不支持子接口
硬件平台信息 OpenConfig 提供槽位、线卡、端口详细模型
路由策略 OpenConfig 统一策略模型,比 IETF 完善

四、实战配置/案例分析

4.1 案例一:用 IETF 模型跨厂商管理接口

# scripts/ietf_multi_vendor.py
from ncclient import manager
import xml.etree.ElementTree as ET

# IETF interfaces 模型在所有厂商间通用
IETF_INTERFACE_FILTER = """
<filter type="subtree">
    <interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"/>
</filter>
"""

def collect_interfaces_iETF(device):
    """使用 IETF 标准模型采集接口(跨厂商通用)"""
    with manager.connect(
        host=device["host"],
        port=830,
        username=device["username"],
        password=device["password"],
        hostkey_verify=False,
        device_params={"name": device.get("vendor", "huawei")},
        timeout=30
    ) as m:
        reply = m.get_config(source="running", filter=IETF_INTERFACE_FILTER)
        return ET.tostring(reply.data_element, pretty_print=True).decode()

# 多厂商设备
devices = [
    {"host": "10.1.1.1", "username": "admin", "password": "HuaWei@123", "vendor": "huawei"},
    {"host": "10.1.1.2", "username": "admin", "password": "Juniper1", "vendor": "juniper"},
    {"host": "10.1.1.3", "username": "admin", "password": "Cisco123", "vendor": "cisco"},
]

for device in devices:
    try:
        config = collect_interfaces_iETF(device)
        print(f"✓ {device['host']} ({device['vendor']}): 采集成功, {len(config)} bytes")
    except Exception as e:
        print(f"✗ {device['host']}: {e}")

4.2 案例二:OpenConfig 模型配置子接口

# scripts/openconfig_subinterface.py
import requests
import json

BASE_URL = "https://10.1.1.1:443/restconf/data"
HEADERS = {
    "Accept": "application/yang-data+json",
    "Content-Type": "application/yang-data+json",
}

def configure_openconfig_subinterface(session, interface_name, subindex,
                                       ip_address, prefix_length):
    """使用 OpenConfig 模型配置子接口"""
    encoded = interface_name.replace("/", "%2F")
    url = (f"{BASE_URL}/openconfig-interfaces:interfaces/interface"
           f"={encoded}/subinterfaces/subinterface={subindex}")

    subinterface_config = {
        "openconfig-interfaces:subinterface": {
            "config": {
                "index": subindex,
                "description": f"Subinterface-{subindex}",
                "enabled": True
            },
            "ipv4": {
                "addresses": {
                    "address": [
                        {
                            "config": {
                                "ip": ip_address,
                                "prefix-length": prefix_length
                            }
                        }
                    ]
                }
            }
        }
    }

    resp = session.put(url, headers=HEADERS, json=subinterface_config)
    return resp.status_code in (200, 204)

# 使用示例
subinterfaces = [
    (10, "10.10.10.1", 30),
    (20, "10.20.20.1", 30),
    (30, "10.30.30.1", 30),
]

for subindex, ip, prefix in subinterfaces:
    success = configure_openconfig_subinterface(
        SESSION, "GigabitEthernet1/0/1", subindex, ip, prefix
    )
    print(f"{'✓' if success else '✗'} Subinterface {subindex}: {ip}/{prefix}")

4.3 案例三:模型兼容性问题排查

故障场景:同一份自动化脚本在华为设备上运行正常,在 Juniper 设备上失败。

# scripts/model_compatibility_check.py
from ncclient import manager

def check_model_support(m, module_name):
    """检查设备是否支持特定 YANG 模块"""
    capabilities = m.server_capabilities
    supported = []

    for cap in capabilities:
        # 检查 model  capability
        if "yang:" in cap:
            parts = cap.split(";")
            for part in parts:
                if part.startswith("module="):
                    module = part.split("=")[1]
                    if module_name.lower() in module.lower():
                        supported.append(cap)

    return supported

def test_ietf_vs_openconfig():
    """对比测试 IETF 和 OpenConfig 模型支持"""
    results = {}

    for vendor, host in [("huawei", "10.1.1.1"), ("juniper", "10.1.1.2")]:
        try:
            with manager.connect(
                host=host, port=830,
                username="admin", password="Pass123",
                hostkey_verify=False,
                device_params={"name": vendor}
            ) as m:
                # 检查 IETF interfaces
                ietf_caps = check_model_support(m, "ietf-interfaces")
                # 检查 OpenConfig interfaces
                oc_caps = check_model_support(m, "openconfig-interfaces")

                results[vendor] = {
                    "ietf_interfaces": bool(ietf_caps),
                    "openconfig_interfaces": bool(oc_caps),
                    "ietf_capabilities": ietf_caps,
                    "oc_capabilities": oc_caps,
                }

        except Exception as e:
            results[vendor] = {"error": str(e)}

    return results

compatibility = test_ietf_vs_openconfig()
for vendor, result in compatibility.items():
    print(f"\n{vendor}:")
    if "error" in result:
        print(f"  连接失败: {result['error']}")
    else:
        print(f"  IETF interfaces: {'支持' if result['ietf_interfaces'] else '不支持'}")
        print(f"  OpenConfig interfaces: {'支持' if result['openconfig_interfaces'] else '不支持'}")

故障根因: 1. Juniper 设备可能不支持 OpenConfig 模型,仅支持 IETF 标准模型和厂商自有模型 2. 接口类型标识在不同模型中名称不同(iana-if-type:ethernetCsmacd vs ETHernetCsmacd) 3. 华为设备的 NETCONF 实现可能在某些 IETF 模型上存在差异

解决方案: - 在脚本启动时先探测设备支持的 YANG 模块 - 根据探测结果动态选择使用 IETF 或 OpenConfig 模型 - 为不同模型编写适配层(adapter),将统一配置转换为对应模型的格式

四(续)、高级主题

4.4 OpenConfig 模型版本管理与向后兼容

OpenConfig 模型通过 revision 日期跟踪版本演进:

module openconfig-interfaces {
    yang-version 1.1;
    namespace "http://openconfig.net/yang/interfaces";
    prefix "oc-if";

    organization "OpenConfig working group";
    contact "openconfig@openconfig.net";

    // 每个 revision 代表一次正式发布
    revision 2023-11-02 {
        description "Latest stable release";
        reference "https://github.com/openconfig/public/releases/tag/interfaces-latest";
    }
    revision 2020-01-24 {
        description "Added subinterface support";
    }
    revision 2017-02-20 {
        description "Initial release";
    }
}

版本兼容性策略:

策略 说明 适用场景
最小版本约束 脚本检查设备支持的 revision,低于最低版本则跳过 多版本设备混布
功能探测 尝试访问特定节点,404 表示不支持 渐进式功能升级
适配层抽象 封装不同版本的 API 差异,对外暴露统一接口 跨版本自动化平台
# scripts/model_version_check.py
from ncclient import manager

MIN_REVISIONS = {
    "openconfig-interfaces": "2020-01-24",
    "openconfig-routing-policy": "2019-04-15",
}

def check_model_versions(device):
    """检查设备支持的模型版本"""
    with manager.connect(
        host=device["host"], port=830,
        username=device["username"], password=device["password"],
        hostkey_verify=False,
        device_params={"name": device["vendor"]}
    ) as m:
        results = {}
        for module_name, min_rev in MIN_REVISIONS.items():
            for cap in m.server_capabilities:
                if module_name in str(cap):
                    # 提取 revision 日期
                    rev_match = re.search(r'revision;\s*([\d-]+)', str(cap))
                    if rev_match:
                        actual_rev = rev_match.group(1)
                        supported = actual_rev >= min_rev
                        results[module_name] = {
                            "required": min_rev,
                            "actual": actual_rev,
                            "supported": supported
                        }
        return results

4.5 YANG 模型开发最佳实践

当标准模型不满足需求时,需要自行扩展 YANG 模型:

// 自定义扩展:华为设备光模块详细信息
module huawei-transceiver-ext {
    yang-version 1.1;
    namespace "urn:huawei:params:yang:huawei-transceiver-ext";
    prefix "hw-tx";

    import openconfig-interfaces { prefix oc-if; }
    import ietf-yang-types { prefix yang; }

    // 通过 augment 扩展 OpenConfig 接口模型
    augment "/oc-if:interfaces/oc-if:interface" {
        case openconfig-if-ethernet:
            container huawei-transceiver {
                description "华为设备光模块详细信息";

                leaf serial-number {
                    type string;
                    description "光模块序列号";
                }

                leaf manufacturer {
                    type string;
                    description "光模块厂商";
                }

                leaf part-number {
                    type string;
                    description "光模块料号";
                }

                container diagnostic {
                    leaf tx-power {
                        type decimal64 { fraction-digits 2; }
                        units "dBm";
                        description "发送光功率";
                    }

                    leaf rx-power {
                        type decimal64 { fraction-digits 2; }
                        units "dBm";
                        description "接收光功率";
                    }

                    leaf temperature {
                        type decimal64 { fraction-digits 1; }
                        units "Celsius";
                        description "光模块温度";
                    }

                    leaf voltage {
                        type decimal64 { fraction-digits 2; }
                        units "V";
                        description "供电电压";
                    }

                    leaf bias-current {
                        type decimal64 { fraction-digits 2; }
                        units "mA";
                        description "偏置电流";
                    }
                }
            }
        }
    }
}

4.6 模型驱动配置生成器

# scripts/model_config_generator.py
import json

class ModelDrivenConfigGenerator:
    """基于 YANG 模型的配置生成器"""

    def __init__(self, model="openconfig"):
        self.model = model

    def generate_interface_config(self, interface_name, **kwargs):
        """根据模型类型生成接口配置"""
        if self.model == "openconfig":
            return {
                "openconfig-interfaces:interface": {
                    "config": {
                        "name": interface_name,
                        "description": kwargs.get("description", ""),
                        "type": "iana-if-type:ethernetCsmacd",
                        "enabled": kwargs.get("enabled", True),
                    },
                    "subinterfaces": {
                        "subinterface": [{
                            "config": {
                                "index": kwargs.get("subindex", 0),
                                "description": kwargs.get("sub_desc", ""),
                            },
                            "ipv4": {
                                "addresses": {
                                    "address": [{
                                        "config": {
                                            "ip": kwargs.get("ip", ""),
                                            "prefix-length": kwargs.get("prefix", 24),
                                        }
                                    }]
                                }
                            }
                        }]
                    }
                }
            }
        elif self.model == "ietf":
            return {
                "ietf-interfaces:interface": {
                    "name": interface_name,
                    "description": kwargs.get("description", ""),
                    "type": "iana-if-type:ethernetCsmacd",
                    "enabled": kwargs.get("enabled", True),
                    "ietf-ip:ipv4": {
                        "address": [{
                            "ip": kwargs.get("ip", ""),
                            "netmask": f"/{kwargs.get('prefix', 24)}"
                        }]
                    }
                }
            }

# 使用
gen = ModelDrivenConfigGenerator(model="openconfig")
config = gen.generate_interface_config(
    "GigabitEthernet1/0/1",
    description="To-CoreRtr-Uplink",
    ip="10.1.1.1",
    prefix=30
)
print(json.dumps(config, indent=2))

五、总结

模型体系 适用场景 优势 局限
IETF 标准模型 跨厂商最大兼容性 所有 NETCONF 设备支持,标准权威 功能覆盖有限,缺少子接口/MTU 等
OpenConfig 模型 多厂商功能丰富的场景 功能全面,厂商共识,社区活跃 部分厂商实现不完全,版本差异
厂商扩展模型 单一厂商深度功能 支持所有设备特性 锁定厂商,无法跨设备复用
最佳实践 说明
优先标准模型 新项目优先使用 IETF 或 OpenConfig,避免厂商锁定
能力探测 脚本启动时探测设备支持的 YANG 模块
适配层设计 编写统一 API,内部适配不同模型
模型版本管理 跟踪模型 revision,确保自动化脚本与模型版本匹配
测试验证 在目标设备实际验证模型节点是否可用

思考题

  1. 为什么 OpenConfig 模型将配置数据和状态数据分离到 config 和 state 两个容器,而 IETF 模型混在一起?
  2. 在一个同时运行华为、Juniper、Cisco 的网络中,选择 OpenConfig 还是 IETF 模型?为什么?
  3. YANG 模型中的 identityref 类型有什么作用?为什么接口类型不用 string 而用 identityref?

下篇预告:第315篇:gNMI/gNOI:谷歌开源的网络管理协议