sflow

28 阅读42分钟

sFlow 版本 5

作者:Peter Phaal(InMon 公司)、Marc Lavine(Foundry Networks 公司)
日期:2004年7月
版权声明:版权所有 (C) sFlow.org(2004年)。保留所有权利。

摘要

本备忘录定义了 sFlow.org 的 sFlow 系统。sFlow 是一种用于监控包含交换机和路由器的数据包网络流量的技术。具体而言,它规定了 sFlow 代理(sFlow Agent)中实现的流量采样机制、用于配置 sFlow 代理的 sFlow MIB(管理信息库),以及将流量测量数据从 sFlow 代理传输到 sFlow 收集器(sFlow Collector)的 sFlow 数据报格式。

目录

  1. 概述 ...................................................... 2
  2. 术语与架构 .................................. 2
    2.1 术语 ............................................... 2
    2.2 sFlow 参考模型 ..................................... 4
  3. 采样机制 ........................................... 6
    3.1 数据包流采样 ...................................... 6
    3.2 计数器采样 .......................................... 7
  4. sFlow MIB ..................................................... 8
    4.1 SNMP 管理框架 ............................. 8
    4.2 sFlow MIB 模块结构 ......................... 9
    4.2.1 接收者组 .................................. 9
    4.2.2 流采样组 ............................. 9
    4.2.3 计数器轮询组 ........................... 10
    4.3 定义 ............................................... 11
  5. sFlow 数据报格式 ......................................... 23
  6. 安全考量 ....................................... 43
    6.1 配置 ............................................. 44
    6.2 传输 ................................................. 44
    6.3 保密性 ........................................... 44
  7. 参考文献 .................................................... 45
  8. 作者联系方式 ............................................ 47
    附录 A:sFlow 版本 4 与版本 5 的差异 ........ 49
    附录 B:随机数生成 .......................... 50

1. 概述

sFlow 是一种用于监控包含交换机和路由器的数据包网络流量的技术。

sFlow 监控系统由 sFlow 代理(嵌入在交换机、路由器或独立探针中)和中央 sFlow 收集器组成。sFlow 监控系统采用的架构和采样技术,旨在为高速交换和路由网络提供全网(乃至企业级)的持续流量监控。该设计专门解决以下相关问题:

  • 准确监控千兆及以上速率的网络流量。
  • 支持从单个 sFlow 收集器监控数万个代理。
  • sFlow 代理实现成本极低。

sFlow 代理采用采样技术从其监控的设备中捕获流量统计信息,通过 sFlow 数据报将采样的流量统计信息立即转发到 sFlow 收集器进行分析。

本文档描述了 sFlow 代理使用的采样机制、sFlow 收集器用于控制 sFlow 代理的 sFlow MIB,以及 sFlow 代理用于向 sFlow 收集器发送流量数据的 sFlow 数据报格式。

本备忘录描述 sFlow 版本 5,替代 RFC 3176 [1] 中描述的 sFlow 版本 4。sFlow 版本 4 与版本 5 的差异详见附录 A。


2. 术语与架构

本节定义 sFlow 系统的组成要素。

2.1 术语

以下定义 sFlow 架构相关术语,供参考:

  • 网络设备(Network Device):一种网络设备,如交换机或路由器,用于转发数据包。
  • 数据源(Data Source):指网络设备中可进行流量测量的位置。可能的数据源包括接口、设备内部的物理实体(如背板)和 VLAN 等。每个数据源可访问流经设备的部分流量。完全监控一台设备所需的数据源类型和数量取决于该设备的内部架构;通常,设备的每个物理接口都会定义一个数据源,以确保流经设备的每个数据包都能被观测到。
  • 数据包流(Packet Flow):指数据包穿过网络设备的路径(即数据包从一个接口接收,经过交换/路由决策后,从另一个接口发送的路径)。对于单臂路由器,源接口和目的接口可能相同;对于广播或多播数据包,可能存在多个目的接口。
  • 数据包流采样(Packet Flow Sampling):从数据源观测到的数据包流中随机选择一部分进行采样。
  • 采样率(Sampling Rate):指定数据源观测到的数据包与生成的样本之间的比例(例如,采样率为 100 表示平均每观测 100 个数据包生成 1 个样本)。
  • 数据包流记录(Packet Flow Record):描述数据包流的属性,包含两类信息:
    1. 数据包本身的信息,通常包括数据包头、数据包长度和数据包封装格式。
    2. 数据包穿过设备的路径信息,包括与转发路径选择相关的信息。
  • 计数器采样(Counter Sampling):对与数据源相关联的计数器进行周期性采样或轮询。
  • 采样间隔(Sampling Interval):连续两次计数器采样之间的时间间隔。
  • 计数器记录(Counter Record):包含采样间隔结束时与数据源相关联的计数器值的记录。
  • sFlow 实例(sFlow Instance):指与数据源相关联的测量过程。单个数据源可能关联一个或多个 sFlow 实例,每个实例独立运行(例如,数据包流采样实例各自有自己的采样率,计数器采样实例各自有自己的采样间隔)。
  • sFlow 代理(sFlow Agent):提供配置设备内 sFlow 实例的接口(支持命令行和/或基于 SNMP 的配置),负责维护与 sFlow 收集器的测量会话,将数据封装为 sFlow 数据报发送给 sFlow 收集器,并在会话过期时释放资源。
  • sFlow 子代理(sFlow Sub-Agent):在分布式设备架构上实现 sFlow 时,用于分布式部署 sFlow 代理功能,每个子代理负责特定的数据源子集。
  • sFlow 收集器(sFlow Collector):接收来自一个或多个 sFlow 代理的 sFlow 数据报,也可通过 sFlow 代理提供的配置机制配置 sFlow 实例。
  • sFlow 数据报(sFlow Datagram):一种 UDP 数据报,包含测量数据以及测量源和测量过程的相关信息,其格式在本文档中定义。

2.2 sFlow 参考模型

下图展示了 sFlow 系统中不同实体之间的关系:

+--------------------------------------+
|            网络设备(Network Device)            |
|                                      |
|  +--------------------------------+  |
|  |              代理(Agent)             |  |
|  |                                |  |
|  |  +--------------------------+  |  |             +-------------+
|  |  |         子代理(Sub-agent)        |  |  |    SNMP     |             |
|  |  |                          |  +<-+------------>+             |
|  |  |  +--------------------+  |  |  |             |  收集器(Collector)  |
|  |  |  |     数据源(Data Source)    |  |  |  数据报(Datagram)   |             |
|  |  |  |                    |  |  +--+------------>+             |
|  |  |  |   +-------------+  |  |  |  |             |             |
|  |  |  |   |  实例(Instance)   |  |  |  |             +-------------+
|  |  |  |   +-------------+  |  |  |  |                    .
|  |  |  |          .         |  |  |  |                    .
|  |  |  |          .         |  |  |  |             +-------------+
|  |  |  |   +-------------+  |  |  |  |      SNMP   |             |
|  |  |  |   |  实例(Instance)   |  |  +<-+--+--------->+             |
|  |  |  |   +-------------+  |  |  |  |  |          |  收集器(Collector)  |
|  |  |  +--------------------+  |  |  |  | 数据报(Datagram) |             |
|  |  |             .            |  +--+--+--+------>+             |
|  |  |             .            |  |  |  |  |       |             |
|  |  |  +--------------------+  |  |  |  |  |       +-------------+
|  |  |  |     数据源(Data Source)    |  |  |  |  |
|  |  |  +--------------------+  |  |  |  |  |
|  |  +--------------------------+  |  |  |  |
|  |                .               |  |  |  |
|  |                .               |  |  |  |
|  |  +--------------------------+  |  |  |  |
|  |  |         子代理(Sub-agent)        |  |  |  |
|  |  +--------------------------+  |  |  |  |
|  +--------------------------------+  |  |  |
+--------------------------------------+  |  |
                       .                     |  |
                       .                     |  |
+--------------------------------------+  |  |
|             网络设备(Network Device)           |  |  |
|  +--------------------------------+  |  |  |
|  |                                +<-+--+  |
|  |               代理(Agent)            |  |     |
|  |                                +--+-----+
|  +--------------------------------+  |
+--------------------------------------+

sFlow 收集器利用 SNMP 与 sFlow 代理通信,以配置网络设备上的 sFlow 监控。sFlow MIB 描述了配置 sFlow 代理所需的被管理对象。数据包流采样和计数器采样由 sFlow 代理内与各个数据源相关联的 sFlow 实例执行:

  • 为执行数据包流采样,sFlow 实例需配置采样率,采样过程会生成数据包流记录;
  • 为执行计数器采样,sFlow 实例需配置采样间隔,采样过程会生成计数器记录。

sFlow 代理收集计数器记录和数据包流记录,并以 sFlow 数据报的形式发送给 sFlow 收集器。


3. 采样机制

sFlow 代理采用两种采样形式:基于统计的交换或路由数据包流采样,以及基于时间的计数器采样。

3.1 数据包流采样

每个 sFlow 实例执行的数据包流采样机制必须确保,数据源观测到的任何数据包都有相同的采样概率,与数据包所属的数据流无关。

数据包流采样的实现方式如下:

  1. 当数据包到达接口时,网络设备先进行过滤决策,判断是否丢弃该数据包;若未被过滤,则通过交换/路由功能分配目的接口。
  2. 此时决定是否对该数据包进行采样:通过一个计数器,每个数据包到来时计数器递减,当计数器减至零时进行采样。无论是否采样,计数器 Total_Packets(所有可能被采样的数据包总数)都会递增。
  3. 采样过程包括复制数据包头或提取数据包特征(样本的具体形式详见“sFlow 数据报格式”部分)。每次采样时,计数器 Total_Samples(生成的样本总数)递增,样本由 sFlow 实例发送给 sFlow 代理进行处理。
  4. 样本包含数据包信息以及 Total_Packets 和 Total_Samples 的值,sFlow 代理可通过样本获取数据包穿过设备的轨迹相关附加信息(如源接口、目的接口、VLAN、下一跳子网等),具体取决于设备的转发功能。

每次采样后,需重置“下次采样前需跳过的数据包数量”计数器,该计数器的值应设置为随机整数,且长期来看,随机整数序列需满足:
(1) Total_Packets / Total_Samples = 采样率

数据包流采样的另一种策略是:为每个数据包生成一个随机数,将其与预设阈值比较,当随机数小于阈值时进行采样。阈值的合理计算取决于随机数生成器的特性,但最终生成的样本流仍需满足上述公式 (1)。附录 B 进一步讨论了随机数生成器的要求。

3.2 计数器采样

计数器采样的主要目标是高效、周期性地导出与数据源相关联的计数器数据。

通常,设备上每个可作为数据包流入站或出站接口的接口都会关联一个数据源,这些接口数据源用于导出与接口相关的计数器数据。每个与接口数据源相关联的 sFlow 实例都会分配一个最大采样间隔,但 sFlow 代理可自由调度轮询时间,以最大化内部效率。

数据包流采样和计数器采样设计为集成系统的一部分,两种类型的样本均整合在 sFlow 数据报中。由于数据包流采样会产生稳定且随机的 sFlow 数据报流发送至 sFlow 收集器,计数器样本可伺机填充到这些数据报中,具体策略如下:

  1. sFlow 代理维护一个待采样的计数器源列表;
  2. 当生成数据包流样本时,sFlow 代理检查该列表,按“最近最少采样”原则将计数器数据添加到样本数据报中(仅当计数器源距离未满足要求的采样间隔仅剩短时间,例如 5 秒时才添加);
  3. 每当计数器源的统计信息被添加到样本数据报时,更新该计数器源的最后采样时间,并将其移至列表末尾;
  4. 定期(例如每秒)检查计数器源列表,发送所有需满足采样间隔要求的计数器数据。

若 sFlow 代理选择定期调度计数器采样,应给每个计数器源分配不同的起始时间(最好是随机的),以避免代理内部或代理之间的计数器采样同步。


4. sFlow MIB

sFlow MIB 提供了一种远程控制和配置 sFlow 代理的标准机制。

4.1 SNMP 管理框架

SNMP 管理框架目前包含五个主要组件:

  1. 总体架构,详见 RFC 2571 [2]。
  2. 用于描述和命名管理对象及事件的机制:第一版管理信息结构(SMI)称为 SMIv1,详见 STD 16、RFC 1155 [3]、STD 16、RFC 1212 [4] 和 RFC 1215 [5];第二版称为 SMIv2,详见 STD 58、RFC 2578 [6]、STD 58、RFC 2579 [7] 和 STD 58、RFC 2580 [8]。
  3. 用于传输管理信息的消息协议:第一版 SNMP 消息协议称为 SNMPv1,详见 STD 15、RFC 1157 [9];第二版(非互联网标准跟踪协议)称为 SNMPv2c,详见 RFC 1901 [10] 和 RFC 1906 [11];第三版称为 SNMPv3,详见 RFC 1906 [11]、RFC 2572 [12] 和 RFC 2574 [13]。
  4. 用于访问管理信息的协议操作:第一组协议操作及相关 PDU 格式详见 STD 15、RFC 1157 [9];第二组详见 RFC 1905 [14]。
  5. 一组基础应用(详见 RFC 2573 [15])和基于视图的访问控制机制(详见 RFC 2575 [16])。

关于当前 SNMP 管理框架的更详细介绍,可参考 RFC 2570 [17]。

被管理对象通过虚拟信息存储库(称为管理信息库或 MIB)进行访问,MIB 中的对象通过 SMI 定义的机制进行定义。本备忘录指定的 MIB 模块符合 SMIv2 标准,可通过适当转换生成符合 SMIv1 的 MIB(转换后的 MIB 必须在语义上等效,但不包括因无法转换而省略的对象或事件,如使用 Counter64 类型的对象)。

4.2 sFlow MIB 模块结构

该 MIB 包含三组对象:接收者组、流采样组和计数器轮询组。

4.2.1 接收者组(Receiver Group)

接收者组定义了用于维护 sFlow 代理与 sFlow 收集器之间会话的一组对象:

  1. 配置更改前,sFlow 收集器需在接收者表中找到空闲行,通过写入所有者字符串和预留时间占用该行列;会话需定期刷新,否则会自动超时并释放资源。
  2. 接收者组表中的条目无法直接添加或删除,sFlow 代理实现者应限制条目数量,确保并发 sFlow 会话数不超过设备容量。
  3. 占用接收者表中的一行后,sFlow 收集器需指定用于接收 sFlow 数据报的地址和端口,可配置 sFlow 数据报的最大大小以避免分片。
4.2.2 流采样组(Flow Sampling Group)

流采样组定义了设备中能够进行数据包流采样的一组位置(即数据源),数据源可能对应于接口、VLAN 或设备内的其他实体(具体取决于设备架构):

  1. 每个数据源可能支持多个独立的采样过程(即多个 sFlow 实例),每个实例可拥有自己独立的采样率。
  2. 即使数据源硬件仅能生成单个数据包样本流,sFlow 代理也可通过二次采样为该数据源创建多个 sFlow 实例(例如,硬件采样率设为 512,通过软件二次采样率 2 实现 1024 的采样率)。
  3. 流采样实例可能有最小允许采样率,代理可实现采样率的自动单向退避机制:当每秒生成的样本数过多时,将采样率加倍,直至达到可持续水平(采样率不会自动恢复为原始配置值,仅可手动更改)。
4.2.3 计数器轮询组(Counter Polling Group)

计数器轮询组定义了设备中能够提供计数器信息的一组位置(即数据源),通常对应于设备上的接口:

  1. 每个数据源可能支持多个独立的轮询过程(即多个计数器轮询实例),每个实例可拥有自己独立的轮询间隔。

4.3 定义

SFLOW-MIB DEFINITIONS ::= BEGIN
IMPORTS
      MODULE-IDENTITY, OBJECT-TYPE, Integer32, enterprises
              FROM SNMPv2-SMI
      TEXTUAL-CONVENTION
              FROM SNMPv2-TC
      SnmpAdminString
              FROM SNMP-FRAMEWORK-MIB
      OwnerString
              FROM RMON-MIB
      InetAddressType, InetAddress
              FROM INET-ADDRESS-MIB
      MODULE-COMPLIANCE, OBJECT-GROUP
              FROM SNMPv2-CONF;

      sFlowMIB  MODULE-IDENTITY
        LAST-UPDATED "200309240000Z"   -- 2003年9月24日
        ORGANIZATION "sFlow.org"
        CONTACT-INFO
               "Peter Phaal
                sFlow.org
                http://www.sflow.org/
                电话:  +1-415-283-3260
                邮箱: peter.phaal@sflow.org"
        DESCRIPTION
                "用于管理 sFlow 数据记录生成和传输的 MIB 模块。"
        --
        -- 修订历史
        --
        REVISION    "200310180000Z"     -- 2003年11月18日
        DESCRIPTION
                "版本 1.3(草案 5)
                 允许在不改变值的情况下设置 SFlowReceiver。"
        REVISION    "200309240000Z"     -- 2003年9月24日
        DESCRIPTION
                "版本 1.3(草案 4)
                 sFlowRcvrAddress 的默认值应为 '00000000'(十六进制)。
                 sFlowCpReceiver 的默认值应为 0。"
        REVISION    "200304080000Z"     -- 2003年4月8日
        DESCRIPTION
                "版本 1.3(草案 3)
                 明确计数器轮询间隔(sFlowCpInterval)的语义。"
        REVISION    "200209170000Z"     -- 2002年9月17日
        DESCRIPTION
                "版本 1.3(草案 2)
                 支持每个 sFlowDataSource 关联多个 sFlow 采样器。
                 迁移至 sflow.org 企业编号。
                 将流采样、计数器轮询和接收者配置拆分为独立表格。"
        REVISION    "200107310000Z"     -- 2001年7月31日
        DESCRIPTION
                "版本 1.2
                 使 MIB 符合 SMI v2 标准。"
        REVISION    "200105010000Z"      -- 2001年5月1日
        DESCRIPTION
                 "版本 1.1
                  添加 sfDatagramVersion。"
        ::= { enterprises sflow(14706) 1 }

      sFlowAgent OBJECT IDENTIFIER ::= { sFlowMIB 1 }

      SFlowDataSource ::= TEXTUAL-CONVENTION
              STATUS      current
              DESCRIPTION
                "标识 sFlow 数据源。
                目前定义的数据源类型如下:
                - ifIndex.<I>
                此类传统形式的 SFlowDataSources 称为'基于端口的'数据源。理想情况下,采样实体将对源自或发往指定接口的所有流进行采样。
                但如果交换机架构仅支持入站或出站采样,则采样代理允许仅对入站流或出站流进行采样。
                无论数据包将被转发到多少个端口,每个数据包仅需被考虑采样一次。
                注:端口 0 表示设备上的所有端口由单个数据源代表。
                      - sFlowFsPacketSamplingRate 适用于设备上所有能够进行数据包采样的端口。
                - smonVlanDataSource.<V>
                此类形式的 SFlowDataSource 指'基于数据包的 VLAN',称为'基于 VLAN 的'数据源。
                <V> 是符合 IEEE 802.1Q 标准的 VLAN ID,取值范围为 1 至 4094(含),代表特定桥接域内全局有效的 802.1Q VLAN-ID。
                采样将对所有属于指定 VLAN 的接收数据包执行(无论其到达哪个端口)。
                无论数据包将被转发到多少个端口,每个数据包仅需被考虑采样一次。
                - entPhysicalEntry.<N>
                此类形式的 SFlowDataSource 指代理内的物理实体(例如 entPhysicalClass = backplane(4)),称为'基于实体的'数据源。
                采样将对所有进入该资源的数据包执行(例如,若对背板进行采样,则所有传输到背板的数据包都将被视为单个采样候选,无论其最终到达多少个端口)。
                注:由于每个 SFlowDataSource 独立运行,一个穿过多个数据源的数据包可能会生成多个流记录。"
              SYNTAX      OBJECT IDENTIFIER

      SFlowInstance ::= TEXTUAL-CONVENTION
              STATUS      current
              DESCRIPTION
                "如果某个 SFlowDataSource 有多个 sFlow 采样器可用,则通过 SFlowInstance 变量区分各个采样器。
                 SFlowInstance 的取值范围为 1..n,其中 n 是与该 SFlowDataSource 关联的采样器数量。
                 注:每个 sFlow 采样器实例必须独立于其他所有实例运行。
                       设置一个采样器的属性不得改变其他采样器实例的行为和设置。"
              SYNTAX      Integer32 (1..65535)

      SFlowReceiver ::= TEXTUAL-CONVENTION
              STATUS       current
              DESCRIPTION
                "标识与该资源关联的 sFlow 接收者。
                 值为 0 表示该资源可用。
                 非零值必须对应有效的、活跃的 sFlowRcvrIndex。
                 若当前值为 0,可将其设置为 sFlowRcvrTable 中的任何活跃条目;若当前值非零,将其设置为非零且非当前值将导致 SNMP 错误(无效值)。
                 设置为 0 会释放该资源,并将此条目中的所有值恢复为默认值。
                 若 sFlowRcvrTable 中的某个条目过期(无论是因为 sFlowRcvrOwner 被设置为空字符串,还是 sFlowRcvrTimeout 减至 0),
                 则代理必须将所有关联资源标记为可用(通过将关联的 SFlowReceiver 条目设置为 0),并将这些记录中的所有值恢复为默认值。
                 此机制不提供强制约束,依赖管理实体的协作以确保公平解决资源竞争。
                 管理实体在修改某个资源前,必须先通过成功将其 sFlowRcvrIndex 值写入该资源的 SFlowReceiver 来获取该资源的使用权。"
              SYNTAX       Integer32

      sFlowVersion OBJECT-TYPE
              SYNTAX      SnmpAdminString
              MAX-ACCESS  read-only
              STATUS      current
              DESCRIPTION
                "唯一标识此 MIB 的版本和实现。
                 版本字符串必须具有以下结构:
                    <MIB 版本>;<组织>;<软件修订版本>
                 其中:
                    <MIB 版本> 必须为 '1.3'(此 MIB 的版本)。
                    <组织> 负责代理实现的组织名称。
                    <修订版本> 此代理的具体软件构建版本。
                 例如,字符串 '1.3;InMon Corp.;2.1.1' 表示该代理实现了 SFLOW MIB 的 '1.3' 版本,
                 由 'InMon Corp.' 开发,软件构建版本为 '2.1.1'。
                 每当 SFLOW MIB 修订时,MIB 版本将随之更改。
                 管理实体必须检查 MIB 版本,不得尝试管理 MIB 版本高于其设计支持版本的代理。
                 注:sFlow 数据报格式有独立的版本号,可能与 <MIB 版本> 独立更改。
                       <MIB 版本> 仅适用于 SFLOW MIB 的结构和语义。"
              DEFVAL { "1.3;;" }
              ::= { sFlowAgent 1 }

      sFlowAgentAddressType OBJECT-TYPE
              SYNTAX      InetAddressType
              MAX-ACCESS  read-only
              STATUS      current
              DESCRIPTION
                "与该代理关联的地址类型。
                 仅支持 ipv4 和 ipv6 类型。"
              ::= { sFlowAgent 2 }

      sFlowAgentAddress OBJECT-TYPE
              SYNTAX      InetAddress
              MAX-ACCESS  read-only
              STATUS      current
              DESCRIPTION
                "与该代理关联的 IP 地址。对于多宿主代理,应为代理的环回地址。
                 sFlowAgent 地址必须支持对代理的 SNMP 连接,且应是一个不变量,不会因接口重新配置、启用、禁用、添加或删除而改变。
                 管理器应能够将 sFlowAgentAddress 用作唯一键,长期标识该代理,以便维护历史记录。"
             ::= { sFlowAgent 3 }

      --
      -- 接收者表(Receiver Table)
      --
      sFlowRcvrTable OBJECT-TYPE
              SYNTAX      SEQUENCE OF SFlowRcvrEntry
              MAX-ACCESS  not-accessible
              STATUS      current
              DESCRIPTION
                "sFlow 信息接收者表格。"
              ::= { sFlowAgent 4 }

      sFlowRcvrEntry OBJECT-TYPE
              SYNTAX      SFlowRcvrEntry
              MAX-ACCESS  not-accessible
              STATUS      current
              DESCRIPTION
                "sFlow 接收者的属性。"
              INDEX { sFlowRcvrIndex }
              ::= { sFlowRcvrTable 1 }

      SFlowRcvrEntry ::= SEQUENCE {
              sFlowRcvrIndex                    Integer32,
              sFlowRcvrOwner                    OwnerString,
              sFlowRcvrTimeout                  Integer32,
              sFlowRcvrMaximumDatagramSize      Integer32,
              sFlowRcvrAddressType              InetAddressType,
              sFlowRcvrAddress                  InetAddress,
              sFlowRcvrPort                     Integer32,
              sFlowRcvrDatagramVersion          Integer32
      }

      sFlowRcvrIndex OBJECT-TYPE
              SYNTAX      Integer32 (1..65535)
              MAX-ACCESS  not-accessible
              STATUS      current
              DESCRIPTION
                "sFlowReceiverTable 的索引。"
              ::= { sFlowRcvrEntry 1 }

      sFlowRcvrOwner OBJECT-TYPE
              SYNTAX      OwnerString
              MAX-ACCESS  read-write
              STATUS      current
              DESCRIPTION
                "使用此 sFlowRcvrTable 条目的实体。空字符串表示该条目当前未被占用。
                 希望占用 sFlowRcvrTable 条目的实体必须先确认该条目未被占用,然后通过设置所有者字符串来占用它。
                 必须先占用该条目,才能修改其他采样器对象。
                 为避免竞争条件,控制采样器的实体必须在同一个 SNMP 设置请求中同时设置所有者和 sFlowRcvrTimeout 的值。
                 当管理实体不再使用该采样器时,应将 sFlowRcvrOwner 的值恢复为未占用状态。
                 当所有者被设置为未占用状态时,代理必须将此行中的所有其他实体恢复为默认值,并释放与此 sFlowRcvrTable 条目关联的所有其他资源。
                 此机制不提供强制约束,依赖管理实体的协作以确保公平解决接收者条目竞争。"
              DEFVAL { "" }
              ::= { sFlowRcvrEntry 2 }

      sFlowRcvrTimeout OBJECT-TYPE
              SYNTAX      Integer32
              MAX-ACCESS  read-write
              STATUS      current
              DESCRIPTION
                "采样器释放并停止采样前的剩余时间(以秒为单位)。
                 设置时,所有者获得指定时间段的控制权;读取时,返回该时间段的剩余时间。
                 希望维持对采样器控制权的管理实体,必须在旧值过期前设置新值。
                 当该时间段过期时,代理负责将此行中的所有其他实体恢复为默认值,并释放与此 sFlowRcvrTable 条目关联的所有其他资源。"
              DEFVAL { 0 }
              ::= { sFlowRcvrEntry 3 }

      sFlowRcvrMaximumDatagramSize OBJECT-TYPE
              SYNTAX      Integer32
              MAX-ACCESS  read-write
              STATUS      current
              DESCRIPTION
                 "单个样本数据报中可发送的数据字节最大数。
                  管理器应设置此值以避免 sFlow 数据报分片。"
              DEFVAL { 1400 }
              ::= { sFlowRcvrEntry 4 }

      sFlowRcvrAddressType OBJECT-TYPE
              SYNTAX      InetAddressType
              MAX-ACCESS  read-write
              STATUS      current
              DESCRIPTION
                "sFlowRcvrCollectorAddress 的类型。"
              DEFVAL { ipv4 }
              ::= { sFlowRcvrEntry 5 }

      sFlowRcvrAddress OBJECT-TYPE
              SYNTAX      InetAddress
              MAX-ACCESS  read-write
              STATUS      current
              DESCRIPTION
                "sFlow 收集器的 IP 地址。
                 若设置为 0.0.0.0,则不发送任何 sFlow 数据报。"
              DEFVAL { '00000000'h }  -- 0.0.0.0
              ::= { sFlowRcvrEntry 6 }

      sFlowRcvrPort OBJECT-TYPE
              SYNTAX      Integer32
              MAX-ACCESS  read-write
              STATUS      current
              DESCRIPTION
                "sFlow 数据报的目的端口。"
              DEFVAL { 6343 }
              ::= { sFlowRcvrEntry 7 }

      sFlowRcvrDatagramVersion OBJECT-TYPE
              SYNTAX      Integer32
              MAX-ACCESS  read-write
              STATUS      current
              DESCRIPTION
                "应发送的 sFlow 数据报版本。
                 当设置为代理不支持的值时,代理应将该值调整为支持的最大版本(小于请求值);
                 若不存在此类值,则返回 SNMP 无效值错误。"
              DEFVAL { 5 }
              ::= { sFlowRcvrEntry 8 }

      --
      -- 流采样表(Flow Sampling Table)
      --
      sFlowFsTable OBJECT-TYPE
              SYNTAX      SEQUENCE OF SFlowFsEntry
              MAX-ACCESS  not-accessible
              STATUS      current
              DESCRIPTION
                "设备内的流采样器表格。"
              ::= { sFlowAgent 5 }

      sFlowFsEntry OBJECT-TYPE
              SYNTAX      SFlowFsEntry
              MAX-ACCESS  not-accessible
              STATUS      current
              DESCRIPTION
                "流采样器的属性。"
              INDEX { sFlowFsDataSource, sFlowFsInstance }
              ::= { sFlowFsTable 1 }

      SFlowFsEntry ::= SEQUENCE {
              sFlowFsDataSource               SFlowDataSource,
              sFlowFsInstance                 SFlowInstance,
              sFlowFsReceiver                 SFlowReceiver,
              sFlowFsPacketSamplingRate       Integer32,
              sFlowFsMaximumHeaderSize        Integer32
      }

      sFlowFsDataSource OBJECT-TYPE
              SYNTAX      SFlowDataSource
              MAX-ACCESS  not-accessible
              STATUS      current
              DESCRIPTION
                "此流采样器的 sFlowDataSource。"
              ::= { sFlowFsEntry 1 }

      sFlowFsInstance OBJECT-TYPE
              SYNTAX      SFlowInstance
              MAX-ACCESS  not-accessible
              STATUS      current
              DESCRIPTION
                "此流采样器的 sFlow 实例。"
              ::= { sFlowFsEntry 2 }

      sFlowFsReceiver OBJECT-TYPE
              SYNTAX      SFlowReceiver
              MAX-ACCESS  read-write
              STATUS      current
              DESCRIPTION
                "此流采样器的 SFlowReceiver。"
              DEFVAL { 0 }
              ::= { sFlowFsEntry 3 }

      sFlowFsPacketSamplingRate OBJECT-TYPE
              SYNTAX      Integer32
              MAX-ACCESS  read-write
              STATUS      current
              DESCRIPTION
                "来自该数据源的数据包采样统计采样率。
                 设置为 N 表示对监控流中的 1/N 个数据包进行采样。
                 代理应选择自己的算法为采样引入随机性,以避免恰好每 N 个数据包被计数一次。
                 采样率为 1 表示对所有数据包进行采样;采样率为 0 表示禁用采样。
                 代理允许对采样率设置最小和最大允许值:最小速率可让代理设计者设置采样相关开销的上限,
                 最大速率可能受硬件限制(如计数器大小)影响。此外,由于实现考虑,最大和最小速率之间的所有值可能并非都可实现。
                 当设置采样率时,代理可自由调整该值,使其位于最大和最小允许值之间,并取最接近的可实现值。
                 读取时,代理必须返回其实际使用的采样率(经过上述调整后)。
                 采样算法必须收敛,确保长期来看,采样的数据包数量接近监控流中总数据包数的 1/N。"
              DEFVAL { 0 }
              ::= { sFlowFsEntry 4 }

      sFlowFsMaximumHeaderSize OBJECT-TYPE
              SYNTAX      Integer32
              MAX-ACCESS  read-write
              STATUS      current
              DESCRIPTION
                "应从采样数据包中复制的最大字节数。
                 代理可能对允许的大小有内部的最大和最小值限制。
                 若尝试设置的值超出允许范围,代理应将该值调整为最接近的允许值。"
              DEFVAL { 128 }
              ::= { sFlowFsEntry 5 }

      --
      -- 计数器轮询表(Counter Polling Table)
      --
      sFlowCpTable OBJECT-TYPE
              SYNTAX      SEQUENCE OF SFlowCpEntry
              MAX-ACCESS  not-accessible
              STATUS      current
              DESCRIPTION
                "设备内的计数器轮询器表格。"
              ::= { sFlowAgent 6 }

      sFlowCpEntry OBJECT-TYPE
              SYNTAX      SFlowCpEntry
              MAX-ACCESS  not-accessible
              STATUS      current
              DESCRIPTION
                "计数器轮询器的属性。"
              INDEX { sFlowCpDataSource, sFlowCpInstance }
              ::= { sFlowCpTable 1 }

      SFlowCpEntry ::= SEQUENCE {
              sFlowCpDataSource               SFlowDataSource,
              sFlowCpInstance                 SFlowInstance,
              sFlowCpReceiver                 SFlowReceiver,
              sFlowCpInterval                 Integer32
      }

      sFlowCpDataSource OBJECT-TYPE
              SYNTAX      SFlowDataSource
              MAX-ACCESS  not-accessible
              STATUS      current
              DESCRIPTION
                "标识此计数器轮询器的数据源。"
              ::= { sFlowCpEntry 1 }

      sFlowCpInstance OBJECT-TYPE
              SYNTAX      SFlowInstance
              MAX-ACCESS  not-accessible
              STATUS      current
              DESCRIPTION
                "此计数器轮询器的 sFlowInstance。"
              ::= { sFlowCpEntry 2 }

      sFlowCpReceiver OBJECT-TYPE
              SYNTAX      SFlowReceiver
              MAX-ACCESS  read-write
              STATUS      current
              DESCRIPTION
                "与此计数器轮询器关联的 SFlowReciever。"
              DEFVAL { 0 }
              ::= { sFlowCpEntry 3 }

      sFlowCpInterval OBJECT-TYPE
              SYNTAX      Integer32
              MAX-ACCESS  read-write
              STATUS      current
              DESCRIPTION
                "与该数据源关联的计数器连续两次采样之间的最大秒数。
                 采样间隔为 0 表示禁用计数器采样。
                 代理允许对计数器轮询间隔设置最小和最大允许值:最小间隔可让代理设计者设置轮询相关开销的上限,
                 最大间隔可能受实现限制(如计数器大小)影响。此外,由于实现考虑,最大和最小间隔之间的所有值可能并非都可实现。
                 当设置采样率时,代理可自由调整该值,使其位于最大和最小允许值之间,并取最接近的可实现值。
                 读取时,代理必须返回其实际使用的采样间隔(经过上述调整后)。
                 采样算法必须收敛,确保长期来看,采样的数据包数量接近监控流中总数据包数的 1/N。"
              DEFVAL { 0 }
              ::= { sFlowCpEntry 4 }

       --
       -- 合规性声明(Compliance Statements)
       --
      sFlowMIBConformance OBJECT IDENTIFIER ::= { sFlowMIB 2 }
      sFlowMIBGroups      OBJECT IDENTIFIER ::= { sFlowMIBConformance 1 }
      sFlowMIBCompliances OBJECT IDENTIFIER ::= { sFlowMIBConformance 2 }

      sFlowCompliance MODULE-COMPLIANCE
              STATUS      current
              DESCRIPTION
                "sFlow 代理的合规性声明。"
              MODULE -- 本模块
                  MANDATORY-GROUPS { sFlowAgentGroup }
                  OBJECT     sFlowAgentAddressType
                  SYNTAX     InetAddressType { ipv4(1) }
                  DESCRIPTION
                    "代理仅需支持 ipv4。"
                  OBJECT sFlowRcvrAddressType
                  SYNTAX InetAddressType { ipv4(1) }
                  DESCRIPTION
                    "代理仅需支持 ipv4。"
              ::= { sFlowMIBCompliances 1 }

      sFlowAgentGroup OBJECT-GROUP
              OBJECTS { sFlowVersion, sFlowAgentAddressType, sFlowAgentAddress,
                        sFlowRcvrOwner, sFlowRcvrTimeout,
                        sFlowRcvrMaximumDatagramSize, sFlowRcvrAddressType,
                        sFlowRcvrAddress, sFlowRcvrPort,
                        sFlowRcvrDatagramVersion, sFlowFsReceiver,
                        sFlowFsPacketSamplingRate, sFlowFsMaximumHeaderSize,
                        sFlowCpReceiver, sFlowCpInterval }
               STATUS current
               DESCRIPTION
                 "用于管理 sFlow 数据记录生成和传输的对象集合。"
                ::= { sFlowMIBGroups 1 }
END

sFlow MIB 引用了多个现有 RFC [18]、[19]、[20] 和 [21] 中的定义。


5. sFlow 数据报格式

sFlow 数据报格式规定了 sFlow 代理向远程 sFlow 收集器发送采样数据的标准格式。

5.1 基础规范

  • 编码标准:采用 XDR 标准 [32] 定义,比 ASN.1 更紧凑,且 sFlow 代理编码和 sFlow 收集器解码更简单。
  • 传输协议:样本以 UDP 数据包的形式发送,默认端口为 6343(SFLOW MIB 中指定的分配端口)。
  • 可靠性说明:UDP 传输的不可靠性不会显著影响测量准确性——计数器样本丢失可通过下次轮询补充,数据包流样本丢失仅会略微降低有效采样率。
  • 发送策略:sFlow 代理不得等待缓冲区填满样本后再发送数据报,最多可延迟 1 秒发送;可将计数器样本附加到数据包流采样产生的数据报中,若需满足最大采样间隔则单独发送计数器数据报。

5.2 XDR 描述

/* 提议的 sFlow 数据报版本 5(草案 10)*/
/* 修订历史
   - 版本 5 新增支持:
         扩展 flow_sample 和 counter_sample 的编码格式
         新增未知地址类型;
         新增子代理支持。
         新增数据包丢弃信息。
         新增厂商特定扩展支持。
         为数据字段添加长度信息。
         为样本类型添加长度信息。
         定义 flow_sample、counter_sample 序列号的重置语义。
         将 sFlow 数据报定义与流/计数器数据定义分离。
            注:sFlow 数据定义的修订历史现在属于数据定义文档的一部分。*/

/* 地址类型 */
typedef opaque ip_v4[4];
typedef opaque ip_v6[16];

enum address_type {
   UNKNOWN  = 0,  // 未知
   IP_V4    = 1,  // IPv4
   IP_V6    = 2   // IPv6
};

union address (address_type type) {
   case UNKNOWN:
     void;
   case IP_V4:
     ip_v4;
   case IP_V6:
     ip_v6;
};

/* 数据格式
     data_format 唯一标识 sFlow 规范中不透明结构的格式。
     data_format 的构造方式如下:
       - 最高 20 位对应负责结构定义的 SMI 私有企业代码,值为 0 表示 sflow.org 定义的标准结构。
       - 最低 12 位是由企业分配的结构格式编号,用于唯一标识结构的格式。
     目前有三种不透明结构使用 data_formats:
       1. sample_data
       2. counter_data
       3. flow_data
     结构格式编号在每个上述上下文中可重复使用。
     例如,(inmon,1) data_format 用于描述 counter_data 时可能标识一组特定计数器,
     而用于描述 flow_data 时可能指向一组流属性。
     sFlow 实现者应尽可能使用标准结构,即使只能部分填充。
     允许使用厂商特定结构,但仅应用于补充现有结构,或承载尚未标准化的信息。
     鼓励厂商以 XDR 格式在 www.sflow.org 上发布结构定义。
     结构描述文档应包含 XDR 结构定义,且定义前需添加注释,列出适用的结构、企业编号和结构编号。
     详见 counter_sample 和 flow_sample 的定义示例。
     注:定义了 sFlow 结构的企业允许在结构末尾扩展结构定义,无需更改结构编号。
           任何会改变或使已发布结构定义中的字段失效的更改,必须使用新的结构编号实现。
           此策略允许在结构中添加附加数据,同时保持向后兼容性。
           接收 sFlow 数据的应用程序在解码 opaque<> 结构时,必须始终使用不透明长度信息,
           以避免遇到扩展结构时出现解码错误。
           注:这些规则同样适用于标准结构。*/
typedef unsigned int data_format;

/* sFlowDataSource 的编码方式如下:
     source_id 的最高字节用于指示 sFlowDataSource 的类型:
        0 = ifIndex
        1 = smonVlanDataSource
        2 = entPhysicalEntry
     低三个字节包含相关的索引值。*/
typedef unsigned int sflow_data_source;

/* 输入/输出端口信息
     编码数据包穿过设备路径所涉及的接口。
     若接口未知,则为 0。
     最高 2 位用于指示 30 位值的格式:
        - 格式 = 0:单个接口
            值为接口的 ifIndex。最大值 0x3FFFFFFF 表示无输入或输出接口(取决于其所在字段)。
            用于描述未经过代理监控设备桥接、路由或其他转发处理,
            而是源自或终止于设备本身的流量。
            在输入字段中,此值表示数据包源自设备本身(例如,设备作为 IP 路由器发送的 RIP 请求数据包);
            在输出字段中,此值表示数据包的目的地是设备本身(例如,设备作为 IP 路由器接收的 RIP 响应数据包(无论是否为单播))。
        - 格式 = 1:数据包被丢弃
            值为原因码。目前定义的原因码如下:
                0 - 255:使用 ICMP 目的地不可达码(详见 www.iana.org 上的权威列表,RFC 1812 第 5.2.7.1 节描述了当前的代码)。
                        注:使用这些代码并不意味着所指数据包是 IP 数据包,
                        也不意味着为此生成了任何类型的 ICMP 消息。
                        当前值如下:
                          0  网络不可达
                          1  主机不可达
                          2  协议不可达
                          3  端口不可达
                          4  需要分片但设置了不分片位
                          5  源路由失败
                          6  目的网络未知
                          7  目的主机未知
                          8  源主机隔离
                          9  与目的网络的通信被管理员禁止
                         10  与目的主机的通信被管理员禁止
                         11  针对特定服务类型的目的网络不可达
                         12  针对特定服务类型的目的主机不可达
                         13  通信被管理员禁止
                         14  主机优先级违规
                         15  优先级阈值生效
                256 = 未知
                257 = TTL 超时
                258 = 访问控制列表(ACL)
                259 = 无缓冲区空间
                260 = 随机早期检测(RED)
                261 = 流量整形/速率限制
                262 = 数据包过大(适用于不支持分片的协议)
             注:后续可能会发布更多原因码。接收 sFlow 数据的应用程序必须准备好接收附加原因码。
                   原因码的权威列表将在 www.sflow.org 上维护。
        - 格式 = 2:多个目的接口
            值为接口数量。值为 0 表示未知数量(大于 1)。
      注:格式 1 和 2 仅适用于输出接口,不适用于输入接口。
            数据包始终通过单个(可能未知)接口接收。
      示例:
         0x00000002  表示 ifIndex = 2
         0x00000000  ifIndex 未知
         0x40000001  数据包因 ACL 被丢弃
         0x80000007  表示数据包发送到 7 个接口
         0x80000000  表示数据包发送到未知数量的接口(大于 1)*/
typedef unsigned int interface;

/* 计数器和流样本格式
   定义了计数器和流样本的紧凑格式和扩展格式。
   代理不得混合使用紧凑/扩展编码。
   若代理的 ifIndex 编号始终 < 2^24,则必须对所有接口使用紧凑编码;
   否则,必须对所有接口使用扩展格式。
   虽然 ifIndex 编号的理论范围是 2^32,但 RFC 2863 建议 ifIndex 编号从 1 开始分配小整数值。
   对于大多数代理实现,紧凑编码支持的 2^24 范围的 ifIndex 已足够,
   且使用紧凑编码可节省带宽。
   提供扩展编码是为了支持 ifIndex 的最大可能值,尽管不鼓励使用大的 ifIndex 值。*/

struct flow_record {
   data_format flow_format;         /* sflow_data 的格式 */
   opaque flow_data<>;              /* 由 flow_format 唯一定义的流数据 */
};

struct counter_record {
   data_format counter_format;     /* counter_data 的格式 */
   opaque counter_data<>;          /* 由 counter_format 唯一定义的计数器块 */
};

/* 紧凑格式的流/计数器样本
      若 ifIndex 编号始终 < 2^24,则必须使用紧凑格式 */

/* 单个流样本的格式 */
/* opaque = sample_data; enterprise = 0; format = 1 */
struct flow_sample {
   unsigned int sequence_number;  /* 由该 source_id 生成的每个流样本递增。
                                     注:若代理重置 sample_pool,则必须同时重置 sequence_number。*/
   sflow_data_source source_id;   /* sFlowDataSource */
   unsigned int sampling_rate;    /* sFlowPacketSamplingRate */
   unsigned int sample_pool;      /* 所有可能被采样的数据包总数(即采样过程跳过的数据包数 + 样本总数) */
   unsigned int drops;            /* sFlow 代理检测到标记为采样的数据包因资源不足而丢弃的次数。
                                     drops 计数器报告自代理上次重置以来检测到的丢弃总数。
                                     高丢弃率表明管理代理无法像硬件生成样本那样快地处理样本。
                                     提高 sampling_rate 可降低丢弃率。
                                     注:无法检测丢弃的代理将始终报告 0。 */
   interface input;               /* 数据包接收接口 */
   interface output;              /* 数据包发送接口 */
   flow_record flow_records<>;    /* 采样数据包的相关信息 */
};

/* 单个计数器样本的格式 */
/* opaque = sample_data; enterprise = 0; format = 2 */
struct counters_sample {
   unsigned int sequence_number;   /* 由该 source_id 生成的每个计数器样本递增。
                                      注:若代理重置任何计数器,则必须同时重置 sequence_number。
                                      对于基于 ifIndex 的 source_id,每当 ifCounterDiscontinuityTime 更改时,必须重置序列号。 */
   sflow_data_source source_id;    /* sFlowDataSource */
   counter_record counters<>;      /* 该数据源的轮询计数器 */
};

/* 扩展格式的流/计数器样本
      若 ifIndex 编号可能 >= 2^24,则必须使用扩展格式 */

struct sflow_data_source_expanded {
   unsigned int source_id_type;   /* sFlowDataSource 类型 */
   unsigned int source_id_index;  /* sFlowDataSource 索引 */
};

struct interface_expanded {
  unsigned int format;            /* 接口格式 */
  unsigned int value;             /* 接口值 */
};

/* 单个扩展流样本的格式 */
/* opaque = sample_data; enterprise = 0; format = 3 */
struct flow_sample_expanded {
   unsigned int sequence_number;  /* 由该 source_id 生成的每个流样本递增。
                                     注:若代理重置 sample_pool,则必须同时重置 sequence_number。*/
   sflow_data_source_expanded source_id; /* sFlowDataSource */
   unsigned int sampling_rate;    /* sFlowPacketSamplingRate */
   unsigned int sample_pool;      /* 所有可能被采样的数据包总数(即采样过程跳过的数据包数 + 样本总数) */
   unsigned int drops;            /* sFlow 代理检测到标记为采样的数据包因资源不足而丢弃的次数。
                                     drops 计数器报告自代理上次重置以来检测到的丢弃总数。
                                     高丢弃率表明管理代理无法像硬件生成样本那样快地处理样本。
                                     提高 sampling_rate 可降低丢弃率。
                                     注:无法检测丢弃的代理将始终报告 0。 */
   interface_expanded input;      /* 数据包接收接口 */
   interface_expanded output;     /* 数据包发送接口 */
   flow_record flow_records<>;    /* 采样数据包的相关信息 */
};

/* 单个扩展计数器样本的格式 */
/* opaque = sample_data; enterprise = 0; format = 4 */
struct counters_sample_expanded {
   unsigned int sequence_number;   /* 由该 source_id 生成的每个计数器样本递增。
                                      注:若代理重置任何计数器,则必须同时重置 sequence_number。
                                      对于基于 ifIndex 的 source_id,每当 ifCounterDiscontinuityTime 更改时,必须重置序列号。 */
   sflow_data_source_expanded source_id; /* sFlowDataSource */
   counter_record counters<>;      /* 该数据源的轮询计数器 */
};

/* 样本数据报的格式 */
struct sample_record {
   data_format sample_type;       /* 指定样本数据的类型 */
   opaque sample_data<>;          /* 与 sample_type 对应的结构 */
};

/* sFlow 版本 5 数据报的头部信息
   子代理字段用于 sFlow 代理在分布式架构上实现的场景,
   此时将样本集中到单个点进行传输不切实际。
   但强烈建议尽可能不使用子代理机制。
   若设备内有多个处理器可用,可将创建流和计数器样本的相关任务分配给不同处理器,
   但代理的架构应确保所有样本都被封装为单个数据报流。
   最终的封装任务几乎不需要处理,但对提高整个 sFlow 系统的可扩展性具有重要意义:
   通过减少 UDP 数据包和数据包流的数量,可显著降低接收端与 sFlow 相关的协议开销。
   每个 sFlowDataSource 必须仅与一个子代理关联,且在整个 sFlow 会话期间,
   sFlowDataSource 与子代理的关联必须保持不变。 */
struct sample_datagram_v5 {
   address agent_address;          /* 采样代理的 IP 地址(sFlowAgentAddress) */
   unsigned int sub_agent_id;     /* 用于区分设备内独立代理子实体的数据流 */
   unsigned int sequence_number;  /* 由代理内的子代理生成的每个样本数据报递增 */
   unsigned int uptime;           /* 当前时间(设备上次启动后的毫秒数)。
                                     应尽可能接近数据报传输时间设置。
                                     注:虽然子代理应尝试跟踪全局 sysUptime 值,
                                           但 sFlow 数据包的接收者不得假设子代理之间的值是同步的。 */
   sample_record samples<>;        /* 样本记录数组 */
};

enum datagram_version {
   VERSION5 = 5
};

union sample_datagram_type (datagram_version version) {
   case VERSION5:
      sample_datagram_v5 datagram;
};

struct sample_datagram {
   sample_datagram_type version;
};

5.3 标准数据集格式

sFlow 数据报包含数据包流记录和计数器记录列表,每个记录的格式由 data_format 值标识(命名空间可扩展)。以下是标准数据集的 XDR 描述:

/* 提议的标准 sFlow 数据格式(草案 14)*/
/* 修订历史
   - 版本 5
         明确未标记端口的 extended_switch 定义
         新增 CPU、内存利用率信息
         新增 MPLS 隧道、虚拟电路和 FEC 信息
         明确 next_hop 定义
         为 sampled_header 添加剥离计数
         新增 POS header_protocol
         新增 BGP 下一跳路由器
         明确数据包长度的定义
         移除数据包头大小限制
         为 URL 扩展添加主机字段,并明确 url_direction
         将 url 定义为 HTTP 请求行
         为用户数据添加字符集信息
         新增 NAT 支持
         新增 MPLS 信息
   - 版本 4 新增 BGP 社区支持
   - 版本 3 新增 extended_url 信息支持 */

/* 企业编号 = 0 指 sFlow 标准结构。
   sFlow 实现者应尽可能使用标准结构,即使只能部分填充。
   允许使用厂商特定结构,但仅应用于补充现有结构,或承载尚未标准化的信息。
   对于未知字段,应使用以下值(除非结构定义中另有说明):
      - 未知整数值:使用 0 表示值未知。
      - 未知计数器:使用最大计数器值表示计数器不可用。
                   在任何给定的 sFlow 会话中,特定计数器必须始终可用或始终不可用。
                   可用计数器在即将溢出到 0 之前,可能暂时显示为最大值,这是允许的。
      - 未知字符串:使用长度为 0 的空字符串。 */

/* 流数据类型
   流样本必须包含数据包头信息。
   报告数据包头信息的首选格式是 sampled_header。
   但如果采样过程无法获取数据包头,则可使用 sampled_ethernet、sampled_ipv4、sampled_ipv6 中的一种或多种。 */

/* 数据包头数据 */
/* header_protocol 枚举可能会随时间扩展。
   接收 sFlow 数据的应用程序必须准备好接收包含未知 sampled_header 值的 sampled_header 结构。
   协议编号的权威列表将在 www.sflow.org 上维护。 */
enum header_protocol {
   ETHERNET_ISO88023    = 1,    // 以太网-ISO88023
   ISO88024_TOKENBUS    = 2,    // ISO88024-令牌总线
   ISO88025_TOKENRING   = 3,    // ISO88025-令牌环
   FDDI                 = 4,    // FDDI
   FRAME_RELAY          = 5,    // 帧中继
   X25                  = 6,    // X25
   PPP                  = 7,    // PPP
   SMDS                 = 8,    // SMDS
   AAL5                 = 9,    // AAL5
   AAL5_IP              = 10,   // AAL5-IP(例如 Cisco AAL5 多路复用器)
   IPv4                 = 11,   // IPv4
   IPv6                 = 12,   // IPv6
   MPLS                 = 13,   // MPLS
   POS                  = 14    // POS(RFC 1662、2615)
};

/* 原始数据包头 */
/* opaque = flow_data; enterprise = 0; format = 1 */
struct sampled_header {
   header_protocol protocol;       /* 采样头部的格式 */
   unsigned int frame_length;      /* 采样前数据包的原始长度。
                                      注:对于二层 header_protocol,长度是网络上接收的数据的总字节数
                                            (不包括成帧位,但包括 FCS 字节)。
                                            硬件限制可能导致无法准确报告底层帧长度,
                                            但代理应尽可能准确。
                                            任何为补偿底层硬件移除的封装而添加到 frame_length 的字节,
                                            也必须添加到 stripped 计数中。 */
   unsigned int stripped;          /* 提取 header<> 字节前从数据包中移除的字节数。
                                      与任何已剥离的前置封装对应的后置封装数据也必须剥离;
                                      采样头部中包含的最外层协议层的后置封装数据必须剥离。
                                      对于非封装的 802.3 数据包,stripped >= 4,
                                      因为除 FCS 外,VLAN 标记信息也可能被剥离。
                                      不明确或不属于标准 header_protocol 的外层封装必须剥离。 */
   opaque header<>;                /* 头部字节 */
};

typedef opaque mac[6];

/* 以太网帧数据 */
/* opaque = flow_data; enterprise = 0; format = 2 */
struct sampled_ethernet {
     unsigned int length;   /* 网络上接收的 MAC 数据包长度,
                               不包括下层封装和成帧位,但包括 FCS 字节 */
     mac src_mac;           /* 源 MAC 地址 */
     mac dst_mac;           /* 目的 MAC 地址 */
     unsigned int type;     /* 以太网数据包类型 */
};

/* IPv4 数据包数据 */
/* opaque = flow_data; enterprise = 0; format = 3 */
struct sampled_ipv4 {
   unsigned int length;     /* IPv4 数据包长度,不包括下层封装 */
   unsigned int protocol;   /* IP 协议类型(例如,TCP = 6,UDP = 17) */
   ip_v4 src_ip;            /* 源 IP 地址 */
   ip_v4 dst_ip;            /* 目的 IP 地址 */
   unsigned int src_port;   /* TCP/UDP 源端口号或等效端口号 */
   unsigned int dst_port;   /* TCP/UDP 目的端口号或等效端口号 */
   unsigned int tcp_flags;  /* TCP 标志位 */
   unsigned int tos;        /* IP 服务类型 */
};

/* IPv6 数据包数据 */
/* opaque = flow_data; enterprise = 0; format = 4 */
struct sampled_ipv6 {
   unsigned int length;     /* IPv6 数据包长度,不包括下层封装 */
   unsigned int protocol;   /* IP 下一层协议(例如,TCP = 6,UDP = 17) */
   ip_v6 src_ip;            /* 源 IP 地址 */
   ip_v6 dst_ip;            /* 目的 IP 地址 */
   unsigned int src_port;   /* TCP/UDP 源端口号或等效端口号 */
   unsigned int dst_port;   /* TCP/UDP 目的端口号或等效端口号 */
   unsigned int tcp_flags;  /* TCP 标志位 */
   unsigned int priority;   /* IP 优先级 */
};

/* 扩展流数据
   扩展数据类型提供采样数据包的补充信息。
   每个流样本应包含所有适用的扩展流记录。 */

/* 扩展交换机数据 */
/* opaque = flow_data; enterprise = 0; format = 1001 */
/* 注:对于未标记的入站端口,src_vlan 和 src_priority 值使用端口的分配 VLAN 和优先级;
         对于未标记的出站端口,dst_vlan 和 dst_priority 值使用
         若出站端口是 VLAN 的标记成员时本应放入 802.Q 标记的值。 */
struct extended_switch {
   unsigned int src_vlan;     /* 入站帧的 802.1Q VLAN ID */
   unsigned int src_priority; /* 入站帧的 802.1p 优先级 */
   unsigned int dst_vlan;     /* 出站帧的 802.1Q VLAN ID */
   unsigned int dst_priority; /* 出站帧的 802.1p 优先级 */
};

/* IP 路由下一跳
   IPv4 路由使用 ipForwardNextHop(RFC 2096);
   IPv6 路由使用 ipv6RouteNextHop(RFC 2465)。 */
typedef next_hop address;

/* 扩展路由器数据 */
/* opaque = flow_data; enterprise = 0; format = 1002 */
struct extended_router {
   next_hop nexthop;            /* 下一跳路由器的 IP 地址 */
   unsigned int src_mask_len;   /* 源地址前缀掩码(以比特数表示) */
   unsigned int dst_mask_len;   /* 目的地址前缀掩码(以比特数表示) */
};

enum as_path_segment_type {
   AS_SET      = 1,            /* 自治系统(AS)的无序集合 */
   AS_SEQUENCE = 2             /* 自治系统(AS)的有序集合 */
};

union as_path_type (as_path_segment_type type) {
   case AS_SET:
      unsigned int as_set<>;
   case AS_SEQUENCE:
      unsigned int as_sequence<>;
};

/* 扩展网关数据 */
/* opaque = flow_data; enterprise = 0; format = 1003 */
struct extended_gateway {
   next_hop nexthop;           /* 目的网络应使用的边界路由器地址 */
   unsigned int as;            /* 路由器的自治系统编号 */
   unsigned int src_as;        /* 源的自治系统编号 */
   unsigned int src_peer_as;   /* 源对等体的自治系统编号 */
   as_path_type dst_as_path<>; /* 到目的网络的自治系统路径 */
   unsigned int communities<>; /* 与此路由关联的社区属性 */
   unsigned int localpref;     /* 与此路由关联的本地优先级(LocalPref) */
};

/* 字符集
     用于编码字符串的字符集的 MIBEnum 值(详见 RFC 2978)。
     尽可能使用 UTF-8 编码(MIBEnum=106)。值为 0 表示未知编码。 */
typedef unsigned int charset;

/* 扩展用户数据 */
/* opaque = flow_data; enterprise = 0; format = 1004 */
struct extended_user {
   charset src_charset;        /* src_user 的字符集 */
   opaque src_user<>;          /* 与数据包源相关联的用户 ID */
   charset dst_charset;        /* dst_user 的字符集 */
   opaque dst_user<>;          /* 与数据包目的相关联的用户 ID */
};

enum url_direction {
   src    = 1,                 /* 源地址是服务器 */
   dst    = 2                  /* 目的地址是服务器 */
};

/* 扩展 URL 数据 */
/* opaque = flow_data; enterprise = 0; format = 1005 */
struct extended_url {
   url_direction direction;    /* 连接方向 */
   string url<>;               /* HTTP 请求行(详见 RFC 2616) */
   string host<>;              /* HTTP 头部中的主机字段 */
};

/* MPLS 标签栈
    - 若值未知,可返回空栈
    - 若仅知道最内层标签,栈可包含单个条目
    - 标签编码详见 RFC 3032
    - 标签按网络顺序排列 */
typedef int label_stack<>;

/* 扩展 MPLS 数据 */
/* opaque = flow_data; enterprise = 0; format = 1006 */
struct extended_mpls {
   next_hop nexthop;           /* 下一跳地址 */
   label_stack in_stack;       /* 接收数据包的标签栈 */
   label_stack out_stack;      /* 传输数据包的标签栈 */
};

/* 扩展 NAT 数据
   数据包头记录报告 sFlowDataSource 处观测到的地址。
   extended_nat 结构报告该数据包的转换后源地址和/或目的地址。
   若地址未转换,则应与头部报告的地址一致。 */
/* opaque = flow_data; enterprise = 0; format = 1007 */
struct extended_nat {
     address src_address;            /* 源地址 */
     address dst_address;            /* 目的地址 */
};

/* 扩展 MPLS 隧道 */
/* opaque = flow_data; enterprise = 0; format = 1008 */
struct extended_mpls_tunnel {
   string tunnel_lsp_name<>;   /* 隧道名称 */
   unsigned int tunnel_id;     /* 隧道 ID */
   unsigned int tunnel_cos;    /* 隧道 COS 值 */
};

/* 扩展 MPLS VC */
/* opaque = flow_data; enterprise = 0; format = 1009 */
struct extended_mpls_vc {
   string vc_instance_name<>;  /* VC 实例名称 */
   unsigned int vll_vc_id;     /* VLL/VC 实例 ID */
   unsigned int vc_label_cos;  /* VC 标签 COS 值 */
};

/* 扩展 MPLS FEC
    - 定义源自 MPLS-FTN-STD-MIB mplsFTNTable */
/* opaque = flow_data; enterprise = 0; format = 1010 */
struct extended_mpls_FTN {
   string mplsFTNDescr<>;
   unsigned int mplsFTNMask;
};

/* 扩展 MPLS LVP FEC
    - 定义源自 MPLS-LDP-STD-MIB mplsFecTable
    注:mplsFecAddrType、mplsFecAddr 信息可从数据包头获取 */
/* opaque = flow_data; enterprise = 0; format = 1011 */
struct extended_mpls_LDP_F



参考: