From fdf7541a43352dd9b2caa268d444df6827223bb7 Mon Sep 17 00:00:00 2001 From: Tony Przygienda Date: Tue, 2 Jan 2024 09:50:47 +0100 Subject: [PATCH] newest schema before interop (#116) Merge pull request from Tony P.: Upgrade YANG schema. --- requirements-3-10.txt | 10 +- rift/common.thrift | 57 +++-------- rift/common/__init__.py | 1 + rift/common/constants.py | 4 + rift/common/ttypes.py | 21 ++-- rift/encoding.thrift | 112 ++++++++------------ rift/encoding/__init__.py | 3 + rift/encoding/constants.py | 4 +- rift/encoding/ttypes.py | 169 +++++++++++++++++++++++-------- tests/test_packet_common.py | 4 +- topology/yaml_topology_schema.md | 77 +++++++++++--- 11 files changed, 271 insertions(+), 191 deletions(-) diff --git a/requirements-3-10.txt b/requirements-3-10.txt index 2c1ff75e..b2242e4b 100644 --- a/requirements-3-10.txt +++ b/requirements-3-10.txt @@ -3,14 +3,14 @@ appdirs==1.4.4 astroid==2.12.7 atomicwrites==1.4.1 attrs==22.1.0 -awscli==1.25.67 -botocore==1.27.66 +awscli==1.29.62 +botocore==1.31.62 CacheControl==0.12.11 Cerberus==1.3.4 certifi==2022.6.15 chardet==5.0.0 charset-normalizer==2.1.1 -codecov==2.1.12 +codecov==2.1.13 colorama==0.4.4 contextlib2==21.6.0 coverage==6.4.4 @@ -51,12 +51,12 @@ python-dateutil==2.8.2 pytoml==0.1.21 pytoolconfig==1.2.2 pytricia==1.0.2 -PyYAML==5.4.1 +PyYAML==6.0.1 requests==2.28.1 retrying==1.3.3 rope==1.3.0 rsa==4.7.2 -s3transfer==0.6.0 +s3transfer==0.7.0 six==1.16.0 sortedcontainers==2.4.0 thrift==0.16.0 diff --git a/rift/common.thrift b/rift/common.thrift index 460085ef..b368d5d5 100644 --- a/rift/common.thrift +++ b/rift/common.thrift @@ -4,7 +4,6 @@ namespace py common -namespace rs models /** @note MUST be interpreted in implementation as unsigned 64 bits. */ @@ -147,6 +146,14 @@ const MTUSizeType default_mtu_size = 1400 /** default link being BFD capable */ const bool bfd_default = true +/** type used to target nodes with key value */ +typedef i64 KeyValueTargetType + +/** default target for key value are all nodes. */ +const KeyValueTargetType keyvaluetarget_default = 0 +/** value for _all leaves_ addressing. Represented by all bits set. */ +const KeyValueTargetType keyvaluetarget_all_south_leaves = -1 + /** undefined nonce, equivalent to missing nonce */ const NonceType undefined_nonce = 0; /** outer security key id, MUST be interpreted as in implementation @@ -183,13 +190,13 @@ enum AddressFamilyType { struct IPv4PrefixType { 1: required IPv4Address address; 2: required PrefixLenType prefixlen; -} (python.immutable = "") +} /** IPv6 prefix type. */ struct IPv6PrefixType { 1: required IPv6Address address; 2: required PrefixLenType prefixlen; -} (python.immutable = "") +} /** IP address type. */ union IPAddressType { @@ -197,7 +204,7 @@ union IPAddressType { 1: optional IPv4Address ipv4address; /** Content is IPv6 */ 2: optional IPv6Address ipv6address; -} (python.immutable = "") +} /** Prefix advertisement. @@ -210,7 +217,7 @@ union IPAddressType { union IPPrefixType { 1: optional IPv4PrefixType ipv4prefix; 2: optional IPv6PrefixType ipv6prefix; -} (python.immutable = "") +} /** Sequence of a prefix in case of move. */ @@ -272,45 +279,11 @@ enum RouteType { } enum KVTypes { - OUI = 1, - WellKnown = 2, -} - -/** - EVPN Fabric ID */ -typedef i16 FabricIDType - -const FabricIDType undefined_fabric_id = 0 -const FabricIDType default_fabric_id = 1 - -const bool default_acting_auto_evpn_dci_when_tof = false - -enum AutoEVPNModel { - ERB_VLAN_BUNDLE = 0, + Experimental = 1, + WellKnown = 2, + OUI = 3, } -const AutoEVPNModel default_autoevpn_model = AutoEVPNModel.ERB_VLAN_BUNDLE - -/** */ - -/** */ - -enum AutoFRModel { - /** Full Mesh of L1 tunnel shortcuts, only model supported currently with auto FR */ - TunnelMode = 0, - NoTunnelMode = 1, -} - -const AutoFRModel default_autofr_model = AutoFRModel.TunnelMode - -typedef i32 FloodReflectionClusterIDType -/* maybe used in future for special purposes */ -const FloodReflectionClusterIDType IllegalClusterID = 0 -const FloodReflectionClusterIDType DefaultClusterID = 1 -/// preference to become FR, higher is better -typedef i32 FloodReflectionPreferenceType -const FloodReflectionPreferenceType MinFloodReflectionPreference = 0 -/** */ diff --git a/rift/common/__init__.py b/rift/common/__init__.py index aba2c7f4..806d6f91 100644 --- a/rift/common/__init__.py +++ b/rift/common/__init__.py @@ -9,3 +9,4 @@ delattr(getattr(ttypes, _klass),"__setattr__") except (KeyError, AttributeError): pass + diff --git a/rift/common/constants.py b/rift/common/constants.py index 564a28ca..9dd1586f 100644 --- a/rift/common/constants.py +++ b/rift/common/constants.py @@ -41,6 +41,8 @@ default_tie_udp_flood_port = 915 default_mtu_size = 1400 bfd_default = True +keyvaluetarget_default = 0 +keyvaluetarget_all_south_leaves = -1 undefined_nonce = 0 undefined_securitykey_id = 0 maximum_valid_nonce_delta = 5 @@ -49,7 +51,9 @@ default_fabric_id = 1 default_acting_auto_evpn_dci_when_tof = False default_autoevpn_model = 0 +AUTO_EVPN_SUPPORT_DEFAULT = False default_autofr_model = 0 IllegalClusterID = 0 DefaultClusterID = 1 MinFloodReflectionPreference = 0 +AUTO_FLOOD_REFLECTION_SUPPORT = False diff --git a/rift/common/ttypes.py b/rift/common/ttypes.py index 164e725c..27669a14 100644 --- a/rift/common/ttypes.py +++ b/rift/common/ttypes.py @@ -183,17 +183,20 @@ class RouteType(object): class KVTypes(object): - OUI = 1 + Experimental = 1 WellKnown = 2 + OUI = 3 _VALUES_TO_NAMES = { - 1: "OUI", + 1: "Experimental", 2: "WellKnown", + 3: "OUI", } _NAMES_TO_VALUES = { - "OUI": 1, + "Experimental": 1, "WellKnown": 2, + "OUI": 3, } @@ -213,17 +216,17 @@ class AutoFRModel(object): """ """ - TunnelMode = 0 - NoTunnelMode = 1 + NoTunnelMode = 0 + TunnelMode = 1 _VALUES_TO_NAMES = { - 0: "TunnelMode", - 1: "NoTunnelMode", + 0: "NoTunnelMode", + 1: "TunnelMode", } _NAMES_TO_VALUES = { - "TunnelMode": 0, - "NoTunnelMode": 1, + "NoTunnelMode": 0, + "TunnelMode": 1, } diff --git a/rift/encoding.thrift b/rift/encoding.thrift index 39979d2e..502d2413 100644 --- a/rift/encoding.thrift +++ b/rift/encoding.thrift @@ -1,19 +1,16 @@ /** Thrift file for packet encodings for RIFT - Copyright (c) Juniper Networks, Inc., 2016- - All rights reserved. */ include "common.thrift" -namespace rs models namespace py encoding /** Represents protocol encoding schema major version */ -const common.VersionType protocol_major_version = 6 +const common.VersionType protocol_major_version = 8 /** Represents protocol encoding schema minor version */ -const common.MinorVersionType protocol_minor_version = 1 +const common.MinorVersionType protocol_minor_version = 0 /** Common RIFT packet header. */ struct PacketHeader { @@ -39,7 +36,7 @@ struct Community { 1: required i32 top; /** Lower order bits */ 2: required i32 bottom; -} (python.immutable = "") +} /** Neighbor structure. */ struct Neighbor { @@ -47,7 +44,7 @@ struct Neighbor { 1: required common.SystemIDType originator; /** ID of remote side of the link. */ 2: required common.LinkIDType remote_id; -} (python.immutable = "") +} /** Capabilities the node supports. */ struct NodeCapabilities { @@ -62,16 +59,8 @@ struct NodeCapabilities { procedures. */ 3: optional common.HierarchyIndications hierarchy_indications; - /** - indicates whether auto-evpn feature is implemented on this node (but not necessarily enabled). */ - 10: optional bool auto_evpn_support = false; - /** */ - /** - indicates whether auto-flood-reflection feature is implemented on this node (but not necessarily enabled). */ - 20: optional bool auto_flood_reflection_support = false; - /** */ -} (python.immutable = "") +} /** Link capabilities. */ struct LinkCapabilities { @@ -81,7 +70,7 @@ struct LinkCapabilities { /** Indicates whether the interface will support IPv4 forwarding. */ 2: optional bool ipv4_forwarding_capable = true; -} (python.immutable = "") +} /** RIFT LIE Packet. @@ -134,19 +123,10 @@ struct LIEPacket { /** Instance name in case multiple RIFT instances running on same interface. */ 24: optional string instance_name; - /** - provides the optional ID of the configured auto-evpn fabric. */ - 35: optional common.FabricIDType fabric_id; - /** provides optional version of EVPN ZTP as 256 * MAJOR + MINOR */ - 36: optional i16 auto_evpn_version; - /** */ - - /** */ - /** It provides optional version of FR ZTP as 256 * MAJOR + MINOR, indicates support for auto FR */ - 40: optional i16 auto_flood_reflection_version; - - 41: optional common.FloodReflectionClusterIDType auto_flood_reflection_cluster_id; - /** */ + /** It provides the optional ID of the Fabric configured. This MUST match the information advertised + on the node element. */ + 35: optional common.FabricIDType fabric_id = common.default_fabric_id; + } /** LinkID pair describes one of parallel links between two nodes. */ @@ -171,8 +151,8 @@ struct LinkIDPair { /** Optional indication which address families are up on the interface */ 14: optional set - (python.immutable = "") address_families; -} (python.immutable = "") + address_families; +} /** Unique ID of a TIE. */ struct TIEID { @@ -184,7 +164,7 @@ struct TIEID { 3: required common.TIETypeType tietype; /** number of the tie */ 4: required common.TIENrType tie_nr; -} (python.immutable = "") +} /** Header of a TIE. */ struct TIEHeader { @@ -215,13 +195,13 @@ struct TIDEPacket { 2: required TIEID end_range; /** _Sorted_ list of headers. */ 3: required list - (python.immutable = "") headers; + headers; } /** TIRE packet */ struct TIREPacket { 1: required set - (python.immutable = "") headers; + headers; } /** neighbor of a node */ @@ -233,22 +213,18 @@ struct NodeNeighborsTIEElement { = common.default_distance; /** can carry description of multiple parallel links in a TIE */ 4: optional set - (python.immutable = "") link_ids; + link_ids; /** total bandwith to neighbor as sum of all parallel links */ 5: optional common.BandwithInMegaBitsType bandwidth = common.default_bandwidth; -} (python.immutable = "") +} /** Indication flags of the node. */ struct NodeFlags { /** Indicates that node is in overload, do not transit traffic through it. */ 1: optional bool overload = common.overload_default; - /** */ - /** acting as DCI for auto-evpn, necessary for proper RR election where DCIs are preferred */ - 10: optional bool acting_auto_evpn_dci_when_tof = common.default_acting_auto_evpn_dci_when_tof, - /** */ -} (python.immutable = "") +} /** Description of a node. */ struct NodeTIEElement { @@ -270,32 +246,18 @@ struct NodeTIEElement { /** If any local links are miscabled, this indication is flooded. */ 10: optional set - (python.immutable = "") miscabled_links; + miscabled_links; - /** ToFs in the same plane. Only carried by ToF. Multiple node TIEs can carry disjoint sets of ToFs - which can be joined to form a single set. Used in complex multi-plane elections. */ - 12: optional set same_plane_tofs; + /** ToFs in the same plane. Only carried by ToF. Multiple Node TIEs can carry disjoint sets of ToFs + which MUST be joined to form a single set. */ + 12: optional set + same_plane_tofs; - /** */ - /** All Auto EVPN elements MUST be present in at least one node TIE in each direction if auto evpn is running. */ - /** It provides optional version of EVPN ZTP as 256 * MAJOR + MINOR, if set auto EVPN is enabled. */ - 21: optional i16 auto_evpn_version; /** It provides the optional ID of the Fabric configured */ - 22: optional common.FabricIDType fabric_id = common.default_fabric_id; - /** provides optionally the EVPN model supported */ - 25: optional common.AutoEVPNModel auto_evpn_model = common.AutoEVPNModel.ERB_VLAN_BUNDLE, - /** */ - - /** */ - /** All Auto FR elements MUST be present in at least one TIE in each direction if auto FR is running. */ - /** It provides optional version of FR ZTP as 256 * MAJOR + MINOR, if set indicates auto FR is enabled. */ - 30: optional i16 auto_flood_reflection_version; - /** cluster ID of Auto FR */ - 31: optional common.FloodReflectionClusterIDType auto_flood_reflection_cluster_id; - /** preference to become FR, if not set it indicates that the node cannot perform flood reflection role */ - 32: optional common.FloodReflectionPreferenceType auto_flood_reflection_preference; - /** */ -} (python.immutable = "") + 20: optional common.FabricIDType fabric_id = common.default_fabric_id; + + +} /** Attributes of a prefix. */ struct PrefixAttributes { @@ -306,7 +268,7 @@ struct PrefixAttributes { to other protocols or use within the context of real time analytics. */ 3: optional set - (python.immutable = "") tags; + tags; /** Monotonic clock for mobile addresses. */ 4: optional common.PrefixSequenceType monotonic_clock; /** Indicates if the prefix is a node loopback. */ @@ -317,18 +279,24 @@ struct PrefixAttributes { 10: optional common.LinkIDType from_link; /** Optional, per prefix significant label. */ 12: optional common.LabelType label; -} (python.immutable = "") +} /** TIE carrying prefixes */ struct PrefixTIEElement { /** Prefixes with the associated attributes. */ 1: required map prefixes; -} (python.immutable = "") +} + +/** Defines the targeted nodes and the value carried. */ +struct KeyValueTIEElementContent { + 1: optional common.KeyValueTargetType targets = common.keyvaluetarget_default; + 2: optional binary value; +} /** Generic key value pairs. */ struct KeyValueTIEElement { - 1: required map keyvalues; -} (python.immutable = "") + 1: required map keyvalues; +} /** Single element in a TIE. */ union TIEElement { @@ -347,7 +315,7 @@ union TIEElement { positive_external_disaggregation_prefixes; /** Key-Value store elements. */ 9: optional KeyValueTIEElement keyvalues; -} (python.immutable = "") +} /** TIE packet */ struct TIEPacket { @@ -367,4 +335,4 @@ union PacketContent { struct ProtocolPacket { 1: required PacketHeader header; 2: required PacketContent content; -} \ No newline at end of file +} diff --git a/rift/encoding/__init__.py b/rift/encoding/__init__.py index 197bf787..806d6f91 100644 --- a/rift/encoding/__init__.py +++ b/rift/encoding/__init__.py @@ -1,3 +1,5 @@ +#very, very magic code to cleanup the immutable schema to allow old code to modify rift packets + __all__ = ['ttypes', 'constants'] from . import ttypes @@ -7,3 +9,4 @@ delattr(getattr(ttypes, _klass),"__setattr__") except (KeyError, AttributeError): pass + diff --git a/rift/encoding/constants.py b/rift/encoding/constants.py index e6ec875d..358c41c6 100644 --- a/rift/encoding/constants.py +++ b/rift/encoding/constants.py @@ -11,5 +11,5 @@ from thrift.protocol.TProtocol import TProtocolException import sys from .ttypes import * -protocol_major_version = 6 -protocol_minor_version = 1 +protocol_major_version = 8 +protocol_minor_version = 0 diff --git a/rift/encoding/ttypes.py b/rift/encoding/ttypes.py index fc8c4403..aa9b158c 100644 --- a/rift/encoding/ttypes.py +++ b/rift/encoding/ttypes.py @@ -31,18 +31,18 @@ class PacketHeader(object): thrift_spec = ( None, # 0 - (1, TType.BYTE, 'major_version', None, 6, ), # 1 - (2, TType.I16, 'minor_version', None, 1, ), # 2 + (1, TType.BYTE, 'major_version', None, 8, ), # 1 + (2, TType.I16, 'minor_version', None, 0, ), # 2 (3, TType.I64, 'sender', None, None, ), # 3 (4, TType.BYTE, 'level', None, None, ), # 4 ) def __init__(self, major_version=thrift_spec[1][4], minor_version=thrift_spec[2][4], sender=None, level=None,): if major_version is self.thrift_spec[1][4]: - major_version = 6 + major_version = 8 self.major_version = major_version if minor_version is self.thrift_spec[2][4]: - minor_version = 1 + minor_version = 0 self.minor_version = minor_version self.sender = sender self.level = level @@ -327,14 +327,13 @@ class NodeCapabilities(object): leaf only (in ZTP) or support for leaf-2-leaf procedures. - auto_evpn_support: - indicates whether auto-evpn feature is implemented on this node (but not necessarily enabled). - - auto_flood_reflection_support: - indicates whether auto-flood-reflection feature is implemented on this node (but not necessarily enabled). + /** indicates whether auto-evpn feature is implemented on this node (but not necessarily enabled). + - auto_flood_reflection_support: indicates whether auto-flood-reflection feature is implemented on this node (but not necessarily enabled). """ thrift_spec = ( None, # 0 - (1, TType.I16, 'protocol_minor_version', None, 1, ), # 1 + (1, TType.I16, 'protocol_minor_version', None, 0, ), # 1 (2, TType.BOOL, 'flood_reduction', None, True, ), # 2 (3, TType.I32, 'hierarchy_indications', None, None, ), # 3 None, # 4 @@ -358,7 +357,7 @@ class NodeCapabilities(object): def __init__(self, protocol_minor_version=thrift_spec[1][4], flood_reduction=thrift_spec[2][4], hierarchy_indications=None, auto_evpn_support=thrift_spec[10][4], auto_flood_reflection_support=thrift_spec[20][4],): if protocol_minor_version is self.thrift_spec[1][4]: - protocol_minor_version = 1 + protocol_minor_version = 0 super(NodeCapabilities, self).__setattr__('protocol_minor_version', protocol_minor_version) super(NodeCapabilities, self).__setattr__('flood_reduction', flood_reduction) super(NodeCapabilities, self).__setattr__('hierarchy_indications', hierarchy_indications) @@ -589,11 +588,11 @@ class LIEPacket(object): all other TIEs. Ignored when received from southbound neighbor. - instance_name: Instance name in case multiple RIFT instances running on same interface. - - fabric_id: - provides the optional ID of the configured auto-evpn fabric. - - auto_evpn_version: provides optional version of EVPN ZTP as 256 * MAJOR + MINOR - - auto_flood_reflection_version: It provides optional version of FR ZTP as 256 * MAJOR + MINOR, indicates support for auto FR - - auto_flood_reflection_cluster_id + - fabric_id: It provides the optional ID of the Fabric configured. This MUST match the information advertised + on the node element. + - auto_evpn_version: It provides optional version of EVPN ZTP as 256 * MAJOR + MINOR + - auto_flood_reflection_version: It provides optional version of flood-reflection ZTP as 256 * MAJOR + MINOR, indicates support for auto FR. + - auto_flood_reflection_cluster_id: It provides the cluster ID of flood reflection cluster. """ thrift_spec = ( @@ -632,7 +631,7 @@ class LIEPacket(object): None, # 32 None, # 33 None, # 34 - (35, TType.I16, 'fabric_id', None, None, ), # 35 + (35, TType.I16, 'fabric_id', None, 1, ), # 35 (36, TType.I16, 'auto_evpn_version', None, None, ), # 36 None, # 37 None, # 38 @@ -641,7 +640,7 @@ class LIEPacket(object): (41, TType.I32, 'auto_flood_reflection_cluster_id', None, None, ), # 41 ) - def __init__(self, name=None, local_id=None, flood_port=thrift_spec[3][4], link_mtu_size=thrift_spec[4][4], link_bandwidth=thrift_spec[5][4], neighbor=None, pod=thrift_spec[7][4], node_capabilities=None, link_capabilities=None, holdtime=thrift_spec[12][4], label=None, not_a_ztp_offer=thrift_spec[21][4], you_are_flood_repeater=thrift_spec[22][4], you_are_sending_too_quickly=thrift_spec[23][4], instance_name=None, fabric_id=None, auto_evpn_version=None, auto_flood_reflection_version=None, auto_flood_reflection_cluster_id=None,): + def __init__(self, name=None, local_id=None, flood_port=thrift_spec[3][4], link_mtu_size=thrift_spec[4][4], link_bandwidth=thrift_spec[5][4], neighbor=None, pod=thrift_spec[7][4], node_capabilities=None, link_capabilities=None, holdtime=thrift_spec[12][4], label=None, not_a_ztp_offer=thrift_spec[21][4], you_are_flood_repeater=thrift_spec[22][4], you_are_sending_too_quickly=thrift_spec[23][4], instance_name=None, fabric_id=thrift_spec[35][4], auto_evpn_version=None, auto_flood_reflection_version=None, auto_flood_reflection_cluster_id=None,): self.name = name self.local_id = local_id if flood_port is self.thrift_spec[3][4]: @@ -667,6 +666,8 @@ def __init__(self, name=None, local_id=None, flood_port=thrift_spec[3][4], link_ self.you_are_flood_repeater = you_are_flood_repeater self.you_are_sending_too_quickly = you_are_sending_too_quickly self.instance_name = instance_name + if fabric_id is self.thrift_spec[35][4]: + fabric_id = 1 self.fabric_id = fabric_id self.auto_evpn_version = auto_evpn_version self.auto_flood_reflection_version = auto_flood_reflection_version @@ -1835,14 +1836,16 @@ class NodeTIEElement(object): - pod: PoD to which the node belongs. - startup_time: optional startup time of the node - miscabled_links: If any local links are miscabled, this indication is flooded. - - same_plane_tofs: ToFs in the same plane. Only carried by ToF. Multiple node TIEs can carry disjoint sets of ToFs - which can be joined to form a single set. Used in complex multi-plane elections. - - auto_evpn_version: It provides optional version of EVPN ZTP as 256 * MAJOR + MINOR, if set auto EVPN is enabled. + - same_plane_tofs: ToFs in the same plane. Only carried by ToF. Multiple Node TIEs can carry disjoint sets of ToFs + which MUST be joined to form a single set. - fabric_id: It provides the optional ID of the Fabric configured - - auto_evpn_model: provides optionally the EVPN model supported + - auto_evpn_version: All Auto EVPN elements MUST be present in at least one node TIE in each direction if auto-evpn is running. + It provides optional version of EVPN ZTP as 256 * MAJOR + MINOR, if set auto EVPN is enabled. + - auto_evpn_model: provides optionally the auto-evpn EVPN model supported - auto_flood_reflection_version: It provides optional version of FR ZTP as 256 * MAJOR + MINOR, if set indicates auto FR is enabled. - - auto_flood_reflection_cluster_id: cluster ID of Auto FR - - auto_flood_reflection_preference: preference to become FR, if not set it indicates that the node cannot perform flood reflection role + - auto_flood_reflection_cluster_id: cluster ID of auto-flood-reflection + - auto_flood_reflection_preference: preference to become flood reflector in auto-flood-reflection, + if not set it indicates that the node cannot perform flood reflection role. """ thrift_spec = ( @@ -1858,7 +1861,7 @@ class NodeTIEElement(object): None, # 9 (10, TType.SET, 'miscabled_links', (TType.I32, None, True), None, ), # 10 None, # 11 - (12, TType.SET, 'same_plane_tofs', (TType.I64, None, False), None, ), # 12 + (12, TType.SET, 'same_plane_tofs', (TType.I64, None, True), None, ), # 12 None, # 13 None, # 14 None, # 15 @@ -1866,9 +1869,9 @@ class NodeTIEElement(object): None, # 17 None, # 18 None, # 19 - None, # 20 + (20, TType.I16, 'fabric_id', None, 1, ), # 20 (21, TType.I16, 'auto_evpn_version', None, None, ), # 21 - (22, TType.I16, 'fabric_id', None, 1, ), # 22 + None, # 22 None, # 23 None, # 24 (25, TType.I32, 'auto_evpn_model', None, 0, ), # 25 @@ -1881,7 +1884,7 @@ class NodeTIEElement(object): (32, TType.I32, 'auto_flood_reflection_preference', None, None, ), # 32 ) - def __init__(self, level=None, neighbors=None, capabilities=None, flags=None, name=None, pod=None, startup_time=None, miscabled_links=None, same_plane_tofs=None, auto_evpn_version=None, fabric_id=thrift_spec[22][4], auto_evpn_model=thrift_spec[25][4], auto_flood_reflection_version=None, auto_flood_reflection_cluster_id=None, auto_flood_reflection_preference=None,): + def __init__(self, level=None, neighbors=None, capabilities=None, flags=None, name=None, pod=None, startup_time=None, miscabled_links=None, same_plane_tofs=None, fabric_id=thrift_spec[20][4], auto_evpn_version=None, auto_evpn_model=thrift_spec[25][4], auto_flood_reflection_version=None, auto_flood_reflection_cluster_id=None, auto_flood_reflection_preference=None,): super(NodeTIEElement, self).__setattr__('level', level) super(NodeTIEElement, self).__setattr__('neighbors', neighbors) super(NodeTIEElement, self).__setattr__('capabilities', capabilities) @@ -1891,10 +1894,10 @@ def __init__(self, level=None, neighbors=None, capabilities=None, flags=None, na super(NodeTIEElement, self).__setattr__('startup_time', startup_time) super(NodeTIEElement, self).__setattr__('miscabled_links', miscabled_links) super(NodeTIEElement, self).__setattr__('same_plane_tofs', same_plane_tofs) - super(NodeTIEElement, self).__setattr__('auto_evpn_version', auto_evpn_version) - if fabric_id is self.thrift_spec[22][4]: + if fabric_id is self.thrift_spec[20][4]: fabric_id = 1 super(NodeTIEElement, self).__setattr__('fabric_id', fabric_id) + super(NodeTIEElement, self).__setattr__('auto_evpn_version', auto_evpn_version) super(NodeTIEElement, self).__setattr__('auto_evpn_model', auto_evpn_model) super(NodeTIEElement, self).__setattr__('auto_flood_reflection_version', auto_flood_reflection_version) super(NodeTIEElement, self).__setattr__('auto_flood_reflection_cluster_id', auto_flood_reflection_cluster_id) @@ -1907,7 +1910,7 @@ def __delattr__(self, *args): raise TypeError("can't modify immutable instance") def __hash__(self): - return hash(self.__class__) ^ hash((self.level, self.neighbors, self.capabilities, self.flags, self.name, self.pod, self.startup_time, self.miscabled_links, self.same_plane_tofs, self.auto_evpn_version, self.fabric_id, self.auto_evpn_model, self.auto_flood_reflection_version, self.auto_flood_reflection_cluster_id, self.auto_flood_reflection_preference, )) + return hash(self.__class__) ^ hash((self.level, self.neighbors, self.capabilities, self.flags, self.name, self.pod, self.startup_time, self.miscabled_links, self.same_plane_tofs, self.fabric_id, self.auto_evpn_version, self.auto_evpn_model, self.auto_flood_reflection_version, self.auto_flood_reflection_cluster_id, self.auto_flood_reflection_preference, )) @classmethod def read(cls, iprot): @@ -1922,8 +1925,8 @@ def read(cls, iprot): __var_startup_time= None __var_miscabled_links= None __var_same_plane_tofs= None - __var_auto_evpn_version= None __var_fabric_id= None + __var_auto_evpn_version= None __var_auto_evpn_model= None __var_auto_flood_reflection_version= None __var_auto_flood_reflection_cluster_id= None @@ -1993,16 +1996,17 @@ def read(cls, iprot): _elem46 = iprot.readI64() __var_same_plane_tofs.add(_elem46) iprot.readSetEnd() + __var_same_plane_tofs = frozenset(__var_same_plane_tofs) else: iprot.skip(ftype) - elif fid == 21: + elif fid == 20: if ftype == TType.I16: - __var_auto_evpn_version = iprot.readI16() + __var_fabric_id = iprot.readI16() else: iprot.skip(ftype) - elif fid == 22: + elif fid == 21: if ftype == TType.I16: - __var_fabric_id = iprot.readI16() + __var_auto_evpn_version = iprot.readI16() else: iprot.skip(ftype) elif fid == 25: @@ -2039,8 +2043,8 @@ def read(cls, iprot): startup_time=__var_startup_time, miscabled_links=__var_miscabled_links, same_plane_tofs=__var_same_plane_tofs, - auto_evpn_version=__var_auto_evpn_version, fabric_id=__var_fabric_id, + auto_evpn_version=__var_auto_evpn_version, auto_evpn_model=__var_auto_evpn_model, auto_flood_reflection_version=__var_auto_flood_reflection_version, auto_flood_reflection_cluster_id=__var_auto_flood_reflection_cluster_id, @@ -2098,14 +2102,14 @@ def write(self, oprot): oprot.writeI64(iter50) oprot.writeSetEnd() oprot.writeFieldEnd() + if self.fabric_id is not None: + oprot.writeFieldBegin('fabric_id', TType.I16, 20) + oprot.writeI16(self.fabric_id) + oprot.writeFieldEnd() if self.auto_evpn_version is not None: oprot.writeFieldBegin('auto_evpn_version', TType.I16, 21) oprot.writeI16(self.auto_evpn_version) oprot.writeFieldEnd() - if self.fabric_id is not None: - oprot.writeFieldBegin('fabric_id', TType.I16, 22) - oprot.writeI16(self.fabric_id) - oprot.writeFieldEnd() if self.auto_evpn_model is not None: oprot.writeFieldBegin('auto_evpn_model', TType.I32, 25) oprot.writeI32(self.auto_evpn_model) @@ -2413,6 +2417,84 @@ def __ne__(self, other): return not (self == other) +class KeyValueTIEElementContent(object): + """ + Defines the targeted nodes and the value carried. + + Attributes: + - targets + - value + """ + + thrift_spec = ( + None, # 0 + (1, TType.I64, 'targets', None, 0, ), # 1 + (2, TType.STRING, 'value', 'BINARY', None, ), # 2 + ) + + def __init__(self, targets=thrift_spec[1][4], value=None,): + if targets is self.thrift_spec[1][4]: + targets = 0 + self.targets = targets + self.value = value + + def read(self, iprot): + if iprot._fast_decode is not None and isinstance(iprot.trans, TTransport.CReadableTransport) and self.thrift_spec is not None: + iprot._fast_decode(self, iprot, (self.__class__, self.thrift_spec)) + return + self.targets = None + self.value = None + iprot.readStructBegin() + while True: + (fname, ftype, fid) = iprot.readFieldBegin() + if ftype == TType.STOP: + break + if fid == 1: + if ftype == TType.I64: + self.targets = iprot.readI64() + else: + iprot.skip(ftype) + elif fid == 2: + if ftype == TType.STRING: + self.value = iprot.readBinary() + else: + iprot.skip(ftype) + else: + iprot.skip(ftype) + iprot.readFieldEnd() + iprot.readStructEnd() + + def write(self, oprot): + if oprot._fast_encode is not None and self.thrift_spec is not None: + oprot.trans.write(oprot._fast_encode(self, (self.__class__, self.thrift_spec))) + return + oprot.writeStructBegin('KeyValueTIEElementContent') + if self.targets is not None: + oprot.writeFieldBegin('targets', TType.I64, 1) + oprot.writeI64(self.targets) + oprot.writeFieldEnd() + if self.value is not None: + oprot.writeFieldBegin('value', TType.STRING, 2) + oprot.writeBinary(self.value) + oprot.writeFieldEnd() + oprot.writeFieldStop() + oprot.writeStructEnd() + + def validate(self): + return + + def __repr__(self): + L = ['%s=%r' % (key, value) + for key, value in self.__dict__.items()] + return '%s(%s)' % (self.__class__.__name__, ', '.join(L)) + + def __eq__(self, other): + return isinstance(other, self.__class__) and self.__dict__ == other.__dict__ + + def __ne__(self, other): + return not (self == other) + + class KeyValueTIEElement(object): """ Generic key value pairs. @@ -2423,7 +2505,7 @@ class KeyValueTIEElement(object): thrift_spec = ( None, # 0 - (1, TType.MAP, 'keyvalues', (TType.I32, None, TType.STRING, 'BINARY', False), None, ), # 1 + (1, TType.MAP, 'keyvalues', (TType.I32, None, TType.STRUCT, (KeyValueTIEElementContent, KeyValueTIEElementContent.thrift_spec), False), None, ), # 1 ) def __init__(self, keyvalues=None,): @@ -2454,7 +2536,8 @@ def read(cls, iprot): (_ktype68, _vtype69, _size67) = iprot.readMapBegin() for _i71 in range(_size67): _key72 = iprot.readI32() - _val73 = iprot.readBinary() + _val73 = KeyValueTIEElementContent() + _val73.read(iprot) __var_keyvalues[_key72] = _val73 iprot.readMapEnd() else: @@ -2474,10 +2557,10 @@ def write(self, oprot): oprot.writeStructBegin('KeyValueTIEElement') if self.keyvalues is not None: oprot.writeFieldBegin('keyvalues', TType.MAP, 1) - oprot.writeMapBegin(TType.I32, TType.STRING, len(self.keyvalues)) + oprot.writeMapBegin(TType.I32, TType.STRUCT, len(self.keyvalues)) for kiter74, viter75 in self.keyvalues.items(): oprot.writeI32(kiter74) - oprot.writeBinary(viter75) + viter75.write(oprot) oprot.writeMapEnd() oprot.writeFieldEnd() oprot.writeFieldStop() diff --git a/tests/test_packet_common.py b/tests/test_packet_common.py index 34e9c052..6b41a402 100644 --- a/tests/test_packet_common.py +++ b/tests/test_packet_common.py @@ -435,8 +435,8 @@ def test_fix_key_value_tie_packet(): external_prefixes=None, keyvalues=encoding.ttypes.KeyValueTIEElement( keyvalues={ - 1: b"een", - 2: b"twee" + 1: encoding.ttypes.KeyValueTIEElementContent(value=b"een"), + 2: encoding.ttypes.KeyValueTIEElementContent(value=b"twee"), } ) ) diff --git a/topology/yaml_topology_schema.md b/topology/yaml_topology_schema.md index 6fb6ed2d..a1fcf977 100644 --- a/topology/yaml_topology_schema.md +++ b/topology/yaml_topology_schema.md @@ -10,46 +10,59 @@ format below. We use an intuitive, loose format. The multiplicity is presented a # comments {1} const: - {?} keys: {8} + {?} authentication_keys: {8} {+} - id: <24-bit key number> {1} algorithm: [hmac-sha-256] {1} secret: - {?} private-secret: {7} + {?} private-secret: {7} {1} shards: {+} - id: <64-bit integer shard identifier> {1} nodes: - {*} - name: + {*} - name: {?} passive (1) - {1} level: [ | undefined | leaf | leaf-2-leaf | top-of-fabric ] (2) + {1} level: [ | undefined | leaf | leaf-2-leaf | top-of-fabric ] {2} {1} systemid: <64-bit integer> {?} rx_lie_mcast_address: (5) + in dotted notation, e.g. 224.0.0.2> {5} {?} rx_lie_v6_mcast_address: (5) - {1} rx_lie_port: (4) + {1} rx_lie_port: {4} {?}X state_thrift_services_port: {?}X config_thrift_services_port: {?} generate_defaults: - {?} active_key: <24-bit key number> - {?} tie_validation: [none|permissive|loose|strict] (6) + {?} authentication_keys: {9} + {?} tie_origination_authentication_key: <24-bit key number> + {?} tie_authentication_validation: [none|permissive|loose|strict] {6} {1} interfaces: {*} - name: {?} bandwidth: {?} metric: 0, if not given, schema default> {?} tx_lie_port: (3) + unique within the configuration> {3} {?} rx_lie_port: (3) + unique within the configuration> {3} {?} rx_tie_port: (3) + within the configuration> {3} {?} advertise_subnet: - {?} active_key: <8-bit key number> - {?} accept_keys: - {?} link_validation: [none|permissive|loose|strict] (6) + {?} active_authentication_key: <8-bit key number> + {?} accept_authentication_keys: + {?} link_authentication_validation: [none|permissive|loose|strict] {6} + {?} allow_horizontal: + {?} address_families: (11) + {?} bfd: string + {?} failure-probability-per-minute: + {?} maximum-allowed-failures: = 0> + {?} average-secs-remain-in-down: 0> + {?} southbound-key-values: + {?} system-id: {19} + {?} northbound-key-values: + {*} - key: <32 bit number> + {1} value: sequence of bytes {?} v4prefixes: {*} - address: {1} mask: @@ -58,6 +71,13 @@ format below. We use an intuitive, loose format. The multiplicity is presented a {*} - address: {1} mask: {1} metric: 0> + {?} auto-evpn: (13) + {?} fabric-id: (14) + {?} evis: (15) + {?} ignore-leaf-level-neighbors: + {?} act-as-dci-gateway: (16) + {?} auto-flood-reflection: (17) + {?} cluster-id: (18) (1) Passive nodes are not started but just used to match up correct ports and addresses. This is very useful in e.g. interoperability testing where such a node can be started as @@ -83,6 +103,31 @@ format below. We use an intuitive, loose format. The multiplicity is presented a - permissive: accept if key id unknown - loose: check if authentication present, otherwise accept -{7} only necessary if it's a private/public key pair +(7) only necessary if it's a private/public key pair + +(8) those are both TIE and link security keys. Only key ID < 256 can be used for link keys. + +(9) these numbers are IDs of the keys specified in the `authentication_keys` clause. If not defined, + all `authentication_keys` are used on the node. + +(10) the bfd clause enables BFD. Further clauses set failure probability per minute + (BFD will recover after failure within the specified average number of seconds) + and max. number of failures limits how many times the link can fail. + +(11) default for address families is both + +(13) clause starts AUTO EVPN calculations and analytics + +(14) if not present, default fabric ID is assumed + +(15) if not present, default # of EVIs is assumed + +(16) if not present, schema default (false) is assumed + +(17) clause starts AUTO FLOOD REFLECTION calculations and analytics + +(18) if not present, default cluster ID is assumed + +(19) if not present, default is false. Observe that if this overlaps the other + defined southbound key values the behavior is undefined. -{8} \ No newline at end of file