diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..df748dc --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "python-envs.defaultEnvManager": "ms-python.python:system", + "python-envs.pythonProjects": [] +} \ No newline at end of file diff --git a/COPIED/openconfig.proto b/COPIED/openconfig.proto new file mode 100644 index 0000000..270dc33 --- /dev/null +++ b/COPIED/openconfig.proto @@ -0,0 +1,1740 @@ +// openconfig is generated by proto_generator as a protobuf +// representation of a YANG schema. +// +// Input schema modules: +// - openconfig/interfaces/openconfig-interfaces.yang +// - openconfig/interfaces/openconfig-if-ip.yang +// - openconfig/lacp/openconfig-lacp.yang +// - openconfig/platform/openconfig-platform-linecard.yang +// - openconfig/platform/openconfig-platform-port.yang +// - openconfig/platform/openconfig-platform-transceiver.yang +// - openconfig/platform/openconfig-platform.yang +// - openconfig/system/openconfig-system.yang +// - openconfig/vlan/openconfig-vlan.yang +// - hercules/openconfig-hercules-interfaces.yang +// - hercules/openconfig-hercules-platform-chassis.yang +// - hercules/openconfig-hercules-platform-linecard.yang +// - hercules/openconfig-hercules-platform-node.yang +// - hercules/openconfig-hercules-platform-port.yang +// - hercules/openconfig-hercules-platform.yang +// - hercules/openconfig-hercules-qos.yang +// - hercules/openconfig-hercules.yang +// Include paths: +// - ietf/... +// - openconfig/... +// - hercules/... +syntax = "proto3"; + +package openconfig; + +import "github.com/openconfig/ygot/proto/ywrapper/ywrapper.proto"; +import "github.com/openconfig/ygot/proto/yext/yext.proto"; +import "openconfig/enums/enums.proto"; + +message Device { + message ComponentKey { + string name = 1 [(yext.schemapath) = "/components/component/config/name|/components/component/name"]; + Component component = 2; + } + message InterfaceKey { + string name = 1 [(yext.schemapath) = "/interfaces/interface/config/name|/interfaces/interface/name"]; + Interface interface = 2; + } + repeated ComponentKey component = 51431701 [(yext.schemapath) = "/components/component"]; + Hercules hercules = 458390141 [(yext.schemapath) = "/hercules"]; + repeated InterfaceKey interface = 422482938 [(yext.schemapath) = "/interfaces/interface"]; + Lacp lacp = 421806598 [(yext.schemapath) = "/lacp"]; + Messages messages = 120656914 [(yext.schemapath) = "/messages"]; + Qos qos = 11016188 [(yext.schemapath) = "/qos"]; + System system = 468934236 [(yext.schemapath) = "/system"]; +} + +message Hercules { +} + +message Interface { + message Aggregation { + message SwitchedVlan { + message TrunkVlansUnion { + string trunk_vlans_string = 312059958; + uint64 trunk_vlans_uint64 = 177367799; + } + ywrapper.UintValue access_vlan = 90805781 [(yext.schemapath) = "/interfaces/interface/aggregation/switched-vlan/config/access-vlan"]; + openconfig.enums.OpenconfigVlanVlanModeType interface_mode = 281531048 [(yext.schemapath) = "/interfaces/interface/aggregation/switched-vlan/config/interface-mode"]; + ywrapper.UintValue native_vlan = 44429228 [(yext.schemapath) = "/interfaces/interface/aggregation/switched-vlan/config/native-vlan"]; + repeated TrunkVlansUnion trunk_vlans = 175319366 [(yext.schemapath) = "/interfaces/interface/aggregation/switched-vlan/config/trunk-vlans"]; + } + ywrapper.UintValue lag_speed = 408400324 [(yext.schemapath) = "/interfaces/interface/aggregation/state/lag-speed"]; + openconfig.enums.OpenconfigIfAggregateAggregationType lag_type = 172452860 [(yext.schemapath) = "/interfaces/interface/aggregation/config/lag-type"]; + repeated ywrapper.StringValue member = 432243688 [(yext.schemapath) = "/interfaces/interface/aggregation/state/member"]; + ywrapper.UintValue min_links = 391773051 [(yext.schemapath) = "/interfaces/interface/aggregation/config/min-links"]; + SwitchedVlan switched_vlan = 178357519 [(yext.schemapath) = "/interfaces/interface/aggregation/switched-vlan"]; + } + message Counters { + ywrapper.UintValue carrier_transitions = 270803130 [(yext.schemapath) = "/interfaces/interface/state/counters/carrier-transitions"]; + ywrapper.UintValue in_broadcast_pkts = 280201989 [(yext.schemapath) = "/interfaces/interface/state/counters/in-broadcast-pkts"]; + ywrapper.UintValue in_discards = 11979514 [(yext.schemapath) = "/interfaces/interface/state/counters/in-discards"]; + ywrapper.UintValue in_errors = 456697578 [(yext.schemapath) = "/interfaces/interface/state/counters/in-errors"]; + ywrapper.UintValue in_fcs_errors = 501559027 [(yext.schemapath) = "/interfaces/interface/state/counters/in-fcs-errors"]; + ywrapper.UintValue in_multicast_pkts = 113269128 [(yext.schemapath) = "/interfaces/interface/state/counters/in-multicast-pkts"]; + ywrapper.UintValue in_octets = 333138891 [(yext.schemapath) = "/interfaces/interface/state/counters/in-octets"]; + ywrapper.UintValue in_pkts = 412843491 [(yext.schemapath) = "/interfaces/interface/state/counters/in-pkts"]; + ywrapper.UintValue in_unicast_pkts = 272792307 [(yext.schemapath) = "/interfaces/interface/state/counters/in-unicast-pkts"]; + ywrapper.UintValue in_unknown_protos = 241475497 [(yext.schemapath) = "/interfaces/interface/state/counters/in-unknown-protos"]; + ywrapper.UintValue last_clear = 186014919 [(yext.schemapath) = "/interfaces/interface/state/counters/last-clear"]; + ywrapper.UintValue out_broadcast_pkts = 338589668 [(yext.schemapath) = "/interfaces/interface/state/counters/out-broadcast-pkts"]; + ywrapper.UintValue out_discards = 254055111 [(yext.schemapath) = "/interfaces/interface/state/counters/out-discards"]; + ywrapper.UintValue out_errors = 471103047 [(yext.schemapath) = "/interfaces/interface/state/counters/out-errors"]; + ywrapper.UintValue out_multicast_pkts = 457840757 [(yext.schemapath) = "/interfaces/interface/state/counters/out-multicast-pkts"]; + ywrapper.UintValue out_octets = 201005514 [(yext.schemapath) = "/interfaces/interface/state/counters/out-octets"]; + ywrapper.UintValue out_pkts = 437582090 [(yext.schemapath) = "/interfaces/interface/state/counters/out-pkts"]; + ywrapper.UintValue out_unicast_pkts = 36542246 [(yext.schemapath) = "/interfaces/interface/state/counters/out-unicast-pkts"]; + } + message Ethernet { + message Counters { + ywrapper.UintValue in_8021q_frames = 529738026 [(yext.schemapath) = "/interfaces/interface/ethernet/state/counters/in-8021q-frames"]; + ywrapper.UintValue in_block_errors = 141122900 [(yext.schemapath) = "/interfaces/interface/ethernet/state/counters/in-block-errors"]; + ywrapper.UintValue in_crc_errors = 77292495 [(yext.schemapath) = "/interfaces/interface/ethernet/state/counters/in-crc-errors"]; + ywrapper.UintValue in_fragment_frames = 377378436 [(yext.schemapath) = "/interfaces/interface/ethernet/state/counters/in-fragment-frames"]; + ywrapper.UintValue in_jabber_frames = 428398234 [(yext.schemapath) = "/interfaces/interface/ethernet/state/counters/in-jabber-frames"]; + ywrapper.UintValue in_mac_control_frames = 90181121 [(yext.schemapath) = "/interfaces/interface/ethernet/state/counters/in-mac-control-frames"]; + ywrapper.UintValue in_mac_pause_frames = 373764182 [(yext.schemapath) = "/interfaces/interface/ethernet/state/counters/in-mac-pause-frames"]; + ywrapper.UintValue in_oversize_frames = 12762219 [(yext.schemapath) = "/interfaces/interface/ethernet/state/counters/in-oversize-frames"]; + ywrapper.UintValue in_undersize_frames = 373754277 [(yext.schemapath) = "/interfaces/interface/ethernet/state/counters/in-undersize-frames"]; + ywrapper.UintValue out_8021q_frames = 61726883 [(yext.schemapath) = "/interfaces/interface/ethernet/state/counters/out-8021q-frames"]; + ywrapper.UintValue out_mac_control_frames = 23867076 [(yext.schemapath) = "/interfaces/interface/ethernet/state/counters/out-mac-control-frames"]; + ywrapper.UintValue out_mac_pause_frames = 37153563 [(yext.schemapath) = "/interfaces/interface/ethernet/state/counters/out-mac-pause-frames"]; + } + message SwitchedVlan { + message TrunkVlansUnion { + string trunk_vlans_string = 325293279; + uint64 trunk_vlans_uint64 = 461732658; + } + ywrapper.UintValue access_vlan = 297473650 [(yext.schemapath) = "/interfaces/interface/ethernet/switched-vlan/config/access-vlan"]; + openconfig.enums.OpenconfigVlanVlanModeType interface_mode = 374657465 [(yext.schemapath) = "/interfaces/interface/ethernet/switched-vlan/config/interface-mode"]; + ywrapper.UintValue native_vlan = 16702907 [(yext.schemapath) = "/interfaces/interface/ethernet/switched-vlan/config/native-vlan"]; + repeated TrunkVlansUnion trunk_vlans = 528974489 [(yext.schemapath) = "/interfaces/interface/ethernet/switched-vlan/config/trunk-vlans"]; + } + enum DuplexMode { + DUPLEXMODE_UNSET = 0; + DUPLEXMODE_FULL = 1 [(yext.yang_name) = "FULL"]; + DUPLEXMODE_HALF = 2 [(yext.yang_name) = "HALF"]; + } + enum NegotiatedDuplexMode { + NEGOTIATEDDUPLEXMODE_UNSET = 0; + NEGOTIATEDDUPLEXMODE_FULL = 1 [(yext.yang_name) = "FULL"]; + NEGOTIATEDDUPLEXMODE_HALF = 2 [(yext.yang_name) = "HALF"]; + } + ywrapper.StringValue aggregate_id = 208679153 [(yext.schemapath) = "/interfaces/interface/ethernet/config/aggregate-id"]; + ywrapper.BoolValue auto_negotiate = 362931914 [(yext.schemapath) = "/interfaces/interface/ethernet/config/auto-negotiate"]; + Counters counters = 452454018 [(yext.schemapath) = "/interfaces/interface/ethernet/state/counters"]; + DuplexMode duplex_mode = 281836250 [(yext.schemapath) = "/interfaces/interface/ethernet/config/duplex-mode"]; + ywrapper.BoolValue enable_flow_control = 41554070 [(yext.schemapath) = "/interfaces/interface/ethernet/config/enable-flow-control"]; + ywrapper.BoolValue forwarding_viable = 363724845 [(yext.schemapath) = "/interfaces/interface/ethernet/config/forwarding-viable"]; + ywrapper.StringValue hw_mac_address = 296258675 [(yext.schemapath) = "/interfaces/interface/ethernet/state/hw-mac-address"]; + ywrapper.StringValue mac_address = 1149482 [(yext.schemapath) = "/interfaces/interface/ethernet/config/mac-address"]; + NegotiatedDuplexMode negotiated_duplex_mode = 6853804 [(yext.schemapath) = "/interfaces/interface/ethernet/state/negotiated-duplex-mode"]; + openconfig.enums.OpenconfigIfEthernetETHERNETSPEED negotiated_port_speed = 316416089 [(yext.schemapath) = "/interfaces/interface/ethernet/state/negotiated-port-speed"]; + openconfig.enums.OpenconfigIfEthernetETHERNETSPEED port_speed = 272501003 [(yext.schemapath) = "/interfaces/interface/ethernet/config/port-speed"]; + SwitchedVlan switched_vlan = 268814182 [(yext.schemapath) = "/interfaces/interface/ethernet/switched-vlan"]; + } + message HoldTime { + ywrapper.UintValue down = 171181656 [(yext.schemapath) = "/interfaces/interface/hold-time/config/down"]; + ywrapper.UintValue up = 62026235 [(yext.schemapath) = "/interfaces/interface/hold-time/config/up"]; + } + message RoutedVlan { + message Ipv4 { + message Address { + message VrrpGroup { + message InterfaceTracking { + ywrapper.UintValue priority_decrement = 269461494 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv4/addresses/address/vrrp/vrrp-group/interface-tracking/config/priority-decrement"]; + repeated ywrapper.StringValue track_interface = 109384073 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv4/addresses/address/vrrp/vrrp-group/interface-tracking/config/track-interface"]; + } + ywrapper.BoolValue accept_mode = 14046336 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv4/addresses/address/vrrp/vrrp-group/config/accept-mode"]; + ywrapper.UintValue advertisement_interval = 355068623 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv4/addresses/address/vrrp/vrrp-group/config/advertisement-interval"]; + ywrapper.UintValue current_priority = 415387713 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv4/addresses/address/vrrp/vrrp-group/state/current-priority"]; + InterfaceTracking interface_tracking = 27491390 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv4/addresses/address/vrrp/vrrp-group/interface-tracking"]; + ywrapper.BoolValue preempt = 56784621 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv4/addresses/address/vrrp/vrrp-group/config/preempt"]; + ywrapper.UintValue preempt_delay = 404202907 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv4/addresses/address/vrrp/vrrp-group/config/preempt-delay"]; + ywrapper.UintValue priority = 475345840 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv4/addresses/address/vrrp/vrrp-group/config/priority"]; + repeated ywrapper.StringValue virtual_address = 495492198 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv4/addresses/address/vrrp/vrrp-group/config/virtual-address"]; + } + message VrrpGroupKey { + uint64 virtual_router_id = 1 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv4/addresses/address/vrrp/vrrp-group/config/virtual-router-id|/interfaces/interface/routed-vlan/ipv4/addresses/address/vrrp/vrrp-group/virtual-router-id"]; + VrrpGroup vrrp_group = 2; + } + openconfig.enums.OpenconfigIfIpIpAddressOrigin origin = 474065239 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv4/addresses/address/state/origin"]; + ywrapper.UintValue prefix_length = 319746417 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv4/addresses/address/config/prefix-length"]; + repeated VrrpGroupKey vrrp_group = 517951704 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv4/addresses/address/vrrp/vrrp-group"]; + } + message AddressKey { + string ip = 1 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv4/addresses/address/config/ip|/interfaces/interface/routed-vlan/ipv4/addresses/address/ip"]; + Address address = 2; + } + message Counters { + ywrapper.UintValue in_discarded_pkts = 458022187 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv4/state/counters/in-discarded-pkts"]; + ywrapper.UintValue in_error_pkts = 83701670 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv4/state/counters/in-error-pkts"]; + ywrapper.UintValue in_forwarded_octets = 8098512 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv4/state/counters/in-forwarded-octets"]; + ywrapper.UintValue in_forwarded_pkts = 516706228 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv4/state/counters/in-forwarded-pkts"]; + ywrapper.UintValue in_octets = 114257965 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv4/state/counters/in-octets"]; + ywrapper.UintValue in_pkts = 436478457 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv4/state/counters/in-pkts"]; + ywrapper.UintValue out_discarded_pkts = 240977330 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv4/state/counters/out-discarded-pkts"]; + ywrapper.UintValue out_error_pkts = 221729199 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv4/state/counters/out-error-pkts"]; + ywrapper.UintValue out_forwarded_octets = 60697281 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv4/state/counters/out-forwarded-octets"]; + ywrapper.UintValue out_forwarded_pkts = 313944229 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv4/state/counters/out-forwarded-pkts"]; + ywrapper.UintValue out_octets = 429728576 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv4/state/counters/out-octets"]; + ywrapper.UintValue out_pkts = 66045220 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv4/state/counters/out-pkts"]; + } + message Neighbor { + ywrapper.StringValue link_layer_address = 122384166 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv4/neighbors/neighbor/config/link-layer-address"]; + openconfig.enums.OpenconfigIfIpNeighborOrigin origin = 457574488 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv4/neighbors/neighbor/state/origin"]; + } + message NeighborKey { + string ip = 1 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv4/neighbors/neighbor/config/ip|/interfaces/interface/routed-vlan/ipv4/neighbors/neighbor/ip"]; + Neighbor neighbor = 2; + } + message ProxyArp { + enum Mode { + MODE_DISABLE = 0 [(yext.yang_name) = "DISABLE"]; + MODE_REMOTE_ONLY = 2 [(yext.yang_name) = "REMOTE_ONLY"]; + MODE_ALL = 3 [(yext.yang_name) = "ALL"]; + } + Mode mode = 373366860 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv4/proxy-arp/config/mode"]; + } + message Unnumbered { + message InterfaceRef { + ywrapper.StringValue interface = 88393539 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv4/unnumbered/interface-ref/config/interface"]; + ywrapper.UintValue subinterface = 527598737 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv4/unnumbered/interface-ref/config/subinterface"]; + } + ywrapper.BoolValue enabled = 414259321 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv4/unnumbered/config/enabled"]; + InterfaceRef interface_ref = 433795586 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv4/unnumbered/interface-ref"]; + } + repeated AddressKey address = 491252712 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv4/addresses/address"]; + Counters counters = 108922474 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv4/state/counters"]; + ywrapper.BoolValue dhcp_client = 66717571 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv4/config/dhcp-client"]; + ywrapper.BoolValue enabled = 421586295 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv4/config/enabled"]; + ywrapper.UintValue mtu = 241730120 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv4/config/mtu"]; + repeated NeighborKey neighbor = 49515461 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv4/neighbors/neighbor"]; + ProxyArp proxy_arp = 30863325 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv4/proxy-arp"]; + Unnumbered unnumbered = 494263654 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv4/unnumbered"]; + } + message Ipv6 { + message Address { + message VrrpGroup { + message InterfaceTracking { + ywrapper.UintValue priority_decrement = 24311112 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/addresses/address/vrrp/vrrp-group/interface-tracking/config/priority-decrement"]; + repeated ywrapper.StringValue track_interface = 462890491 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/addresses/address/vrrp/vrrp-group/interface-tracking/config/track-interface"]; + } + ywrapper.BoolValue accept_mode = 473970174 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/addresses/address/vrrp/vrrp-group/config/accept-mode"]; + ywrapper.UintValue advertisement_interval = 35447257 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/addresses/address/vrrp/vrrp-group/config/advertisement-interval"]; + ywrapper.UintValue current_priority = 512020007 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/addresses/address/vrrp/vrrp-group/state/current-priority"]; + InterfaceTracking interface_tracking = 329957492 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/addresses/address/vrrp/vrrp-group/interface-tracking"]; + ywrapper.BoolValue preempt = 111055611 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/addresses/address/vrrp/vrrp-group/config/preempt"]; + ywrapper.UintValue preempt_delay = 458956129 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/addresses/address/vrrp/vrrp-group/config/preempt-delay"]; + ywrapper.UintValue priority = 332652754 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/addresses/address/vrrp/vrrp-group/config/priority"]; + repeated ywrapper.StringValue virtual_address = 28701956 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/addresses/address/vrrp/vrrp-group/config/virtual-address"]; + ywrapper.StringValue virtual_link_local = 224033014 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/addresses/address/vrrp/vrrp-group/config/virtual-link-local"]; + } + message VrrpGroupKey { + uint64 virtual_router_id = 1 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/addresses/address/vrrp/vrrp-group/config/virtual-router-id|/interfaces/interface/routed-vlan/ipv6/addresses/address/vrrp/vrrp-group/virtual-router-id"]; + VrrpGroup vrrp_group = 2; + } + enum Status { + STATUS_UNSET = 0; + STATUS_PREFERRED = 1 [(yext.yang_name) = "PREFERRED"]; + STATUS_DEPRECATED = 2 [(yext.yang_name) = "DEPRECATED"]; + STATUS_INVALID = 3 [(yext.yang_name) = "INVALID"]; + STATUS_INACCESSIBLE = 4 [(yext.yang_name) = "INACCESSIBLE"]; + STATUS_UNKNOWN = 5 [(yext.yang_name) = "UNKNOWN"]; + STATUS_TENTATIVE = 6 [(yext.yang_name) = "TENTATIVE"]; + STATUS_DUPLICATE = 7 [(yext.yang_name) = "DUPLICATE"]; + STATUS_OPTIMISTIC = 8 [(yext.yang_name) = "OPTIMISTIC"]; + } + openconfig.enums.OpenconfigIfIpIpAddressOrigin origin = 70383429 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/addresses/address/state/origin"]; + ywrapper.UintValue prefix_length = 420005967 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/addresses/address/config/prefix-length"]; + Status status = 436927845 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/addresses/address/state/status"]; + repeated VrrpGroupKey vrrp_group = 131881570 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/addresses/address/vrrp/vrrp-group"]; + } + message AddressKey { + string ip = 1 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/addresses/address/config/ip|/interfaces/interface/routed-vlan/ipv6/addresses/address/ip"]; + Address address = 2; + } + message Counters { + ywrapper.UintValue in_discarded_pkts = 239614269 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/state/counters/in-discarded-pkts"]; + ywrapper.UintValue in_error_pkts = 187753516 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/state/counters/in-error-pkts"]; + ywrapper.UintValue in_forwarded_octets = 355825230 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/state/counters/in-forwarded-octets"]; + ywrapper.UintValue in_forwarded_pkts = 71610230 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/state/counters/in-forwarded-pkts"]; + ywrapper.UintValue in_octets = 221620847 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/state/counters/in-octets"]; + ywrapper.UintValue in_pkts = 54277935 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/state/counters/in-pkts"]; + ywrapper.UintValue out_discarded_pkts = 499638688 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/state/counters/out-discarded-pkts"]; + ywrapper.UintValue out_error_pkts = 524876409 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/state/counters/out-error-pkts"]; + ywrapper.UintValue out_forwarded_octets = 229097699 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/state/counters/out-forwarded-octets"]; + ywrapper.UintValue out_forwarded_pkts = 237143003 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/state/counters/out-forwarded-pkts"]; + ywrapper.UintValue out_octets = 19140950 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/state/counters/out-octets"]; + ywrapper.UintValue out_pkts = 334393886 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/state/counters/out-pkts"]; + } + message Neighbor { + enum NeighborState { + NEIGHBORSTATE_UNSET = 0; + NEIGHBORSTATE_INCOMPLETE = 1 [(yext.yang_name) = "INCOMPLETE"]; + NEIGHBORSTATE_REACHABLE = 2 [(yext.yang_name) = "REACHABLE"]; + NEIGHBORSTATE_STALE = 3 [(yext.yang_name) = "STALE"]; + NEIGHBORSTATE_DELAY = 4 [(yext.yang_name) = "DELAY"]; + NEIGHBORSTATE_PROBE = 5 [(yext.yang_name) = "PROBE"]; + } + ywrapper.BoolValue is_router = 444254730 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/neighbors/neighbor/state/is-router"]; + ywrapper.StringValue link_layer_address = 357623180 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/neighbors/neighbor/config/link-layer-address"]; + NeighborState neighbor_state = 125627606 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/neighbors/neighbor/state/neighbor-state"]; + openconfig.enums.OpenconfigIfIpNeighborOrigin origin = 95623922 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/neighbors/neighbor/state/origin"]; + } + message NeighborKey { + string ip = 1 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/neighbors/neighbor/config/ip|/interfaces/interface/routed-vlan/ipv6/neighbors/neighbor/ip"]; + Neighbor neighbor = 2; + } + message RouterAdvertisement { + ywrapper.UintValue interval = 98870893 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/router-advertisement/config/interval"]; + ywrapper.UintValue lifetime = 87992571 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/router-advertisement/config/lifetime"]; + ywrapper.BoolValue suppress = 5991079 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/router-advertisement/config/suppress"]; + } + message Unnumbered { + message InterfaceRef { + ywrapper.StringValue interface = 21523641 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/unnumbered/interface-ref/config/interface"]; + ywrapper.UintValue subinterface = 448921723 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/unnumbered/interface-ref/config/subinterface"]; + } + ywrapper.BoolValue enabled = 172326403 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/unnumbered/config/enabled"]; + InterfaceRef interface_ref = 468223976 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/unnumbered/interface-ref"]; + } + repeated AddressKey address = 512779414 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/addresses/address"]; + Counters counters = 453666504 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/state/counters"]; + ywrapper.BoolValue dhcp_client = 167177313 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/config/dhcp-client"]; + ywrapper.UintValue dup_addr_detect_transmits = 124019213 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/config/dup-addr-detect-transmits"]; + ywrapper.BoolValue enabled = 235203553 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/config/enabled"]; + ywrapper.UintValue mtu = 498820810 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/config/mtu"]; + repeated NeighborKey neighbor = 275473167 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/neighbors/neighbor"]; + RouterAdvertisement router_advertisement = 75504594 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/router-advertisement"]; + Unnumbered unnumbered = 530580104 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6/unnumbered"]; + } + Ipv4 ipv4 = 499852620 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv4"]; + Ipv6 ipv6 = 499852622 [(yext.schemapath) = "/interfaces/interface/routed-vlan/ipv6"]; + oneof vlan { + string vlan_string = 459932191; + uint64 vlan_uint64 = 59552370; + } + } + message Subinterface { + message Counters { + ywrapper.UintValue carrier_transitions = 141120277 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/state/counters/carrier-transitions"]; + ywrapper.UintValue in_broadcast_pkts = 120244022 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/state/counters/in-broadcast-pkts"]; + ywrapper.UintValue in_discards = 307490461 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/state/counters/in-discards"]; + ywrapper.UintValue in_errors = 319720873 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/state/counters/in-errors"]; + ywrapper.UintValue in_fcs_errors = 169858424 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/state/counters/in-fcs-errors"]; + ywrapper.UintValue in_multicast_pkts = 320618859 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/state/counters/in-multicast-pkts"]; + ywrapper.UintValue in_octets = 530205868 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/state/counters/in-octets"]; + ywrapper.UintValue in_pkts = 441153352 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/state/counters/in-pkts"]; + ywrapper.UintValue in_unicast_pkts = 177838880 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/state/counters/in-unicast-pkts"]; + ywrapper.UintValue in_unknown_protos = 146059814 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/state/counters/in-unknown-protos"]; + ywrapper.UintValue last_clear = 518046966 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/state/counters/last-clear"]; + ywrapper.UintValue out_broadcast_pkts = 501221245 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/state/counters/out-broadcast-pkts"]; + ywrapper.UintValue out_discards = 159539762 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/state/counters/out-discards"]; + ywrapper.UintValue out_errors = 466636898 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/state/counters/out-errors"]; + ywrapper.UintValue out_multicast_pkts = 326155776 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/state/counters/out-multicast-pkts"]; + ywrapper.UintValue out_octets = 50579235 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/state/counters/out-octets"]; + ywrapper.UintValue out_pkts = 29497115 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/state/counters/out-pkts"]; + ywrapper.UintValue out_unicast_pkts = 297910971 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/state/counters/out-unicast-pkts"]; + } + message Ipv4 { + message Address { + message VrrpGroup { + message InterfaceTracking { + ywrapper.UintValue priority_decrement = 412949359 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv4/addresses/address/vrrp/vrrp-group/interface-tracking/config/priority-decrement"]; + repeated ywrapper.StringValue track_interface = 225882622 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv4/addresses/address/vrrp/vrrp-group/interface-tracking/config/track-interface"]; + } + ywrapper.BoolValue accept_mode = 241791545 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv4/addresses/address/vrrp/vrrp-group/config/accept-mode"]; + ywrapper.UintValue advertisement_interval = 62480072 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv4/addresses/address/vrrp/vrrp-group/config/advertisement-interval"]; + ywrapper.UintValue current_priority = 410673536 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv4/addresses/address/vrrp/vrrp-group/state/current-priority"]; + InterfaceTracking interface_tracking = 65916063 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv4/addresses/address/vrrp/vrrp-group/interface-tracking"]; + ywrapper.BoolValue preempt = 34241868 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv4/addresses/address/vrrp/vrrp-group/config/preempt"]; + ywrapper.UintValue preempt_delay = 165057134 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv4/addresses/address/vrrp/vrrp-group/config/preempt-delay"]; + ywrapper.UintValue priority = 462156599 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv4/addresses/address/vrrp/vrrp-group/config/priority"]; + repeated ywrapper.StringValue virtual_address = 386503383 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv4/addresses/address/vrrp/vrrp-group/config/virtual-address"]; + } + message VrrpGroupKey { + uint64 virtual_router_id = 1 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv4/addresses/address/vrrp/vrrp-group/config/virtual-router-id|/interfaces/interface/subinterfaces/subinterface/ipv4/addresses/address/vrrp/vrrp-group/virtual-router-id"]; + VrrpGroup vrrp_group = 2; + } + openconfig.enums.OpenconfigIfIpIpAddressOrigin origin = 86633258 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv4/addresses/address/state/origin"]; + ywrapper.UintValue prefix_length = 250130256 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv4/addresses/address/config/prefix-length"]; + repeated VrrpGroupKey vrrp_group = 304427675 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv4/addresses/address/vrrp/vrrp-group"]; + } + message AddressKey { + string ip = 1 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv4/addresses/address/config/ip|/interfaces/interface/subinterfaces/subinterface/ipv4/addresses/address/ip"]; + Address address = 2; + } + message Counters { + ywrapper.UintValue in_discarded_pkts = 23305318 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv4/state/counters/in-discarded-pkts"]; + ywrapper.UintValue in_error_pkts = 125054547 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv4/state/counters/in-error-pkts"]; + ywrapper.UintValue in_forwarded_octets = 210644557 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv4/state/counters/in-forwarded-octets"]; + ywrapper.UintValue in_forwarded_pkts = 257970457 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv4/state/counters/in-forwarded-pkts"]; + ywrapper.UintValue in_octets = 6166740 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv4/state/counters/in-octets"]; + ywrapper.UintValue in_pkts = 55520496 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv4/state/counters/in-pkts"]; + ywrapper.UintValue out_discarded_pkts = 196519817 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv4/state/counters/out-discarded-pkts"]; + ywrapper.UintValue out_error_pkts = 212089176 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv4/state/counters/out-error-pkts"]; + ywrapper.UintValue out_forwarded_octets = 299444306 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv4/state/counters/out-forwarded-octets"]; + ywrapper.UintValue out_forwarded_pkts = 175600114 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv4/state/counters/out-forwarded-pkts"]; + ywrapper.UintValue out_octets = 75882059 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv4/state/counters/out-octets"]; + ywrapper.UintValue out_pkts = 197536867 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv4/state/counters/out-pkts"]; + } + message Neighbor { + ywrapper.StringValue link_layer_address = 11872487 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv4/neighbors/neighbor/config/link-layer-address"]; + openconfig.enums.OpenconfigIfIpNeighborOrigin origin = 454675095 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv4/neighbors/neighbor/state/origin"]; + } + message NeighborKey { + string ip = 1 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv4/neighbors/neighbor/config/ip|/interfaces/interface/subinterfaces/subinterface/ipv4/neighbors/neighbor/ip"]; + Neighbor neighbor = 2; + } + message ProxyArp { + enum Mode { + MODE_DISABLE = 0 [(yext.yang_name) = "DISABLE"]; + MODE_REMOTE_ONLY = 2 [(yext.yang_name) = "REMOTE_ONLY"]; + MODE_ALL = 3 [(yext.yang_name) = "ALL"]; + } + Mode mode = 56040263 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv4/proxy-arp/config/mode"]; + } + message Unnumbered { + message InterfaceRef { + ywrapper.StringValue interface = 462989376 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv4/unnumbered/interface-ref/config/interface"]; + ywrapper.UintValue subinterface = 347895728 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv4/unnumbered/interface-ref/config/subinterface"]; + } + ywrapper.BoolValue enabled = 527961066 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv4/unnumbered/config/enabled"]; + InterfaceRef interface_ref = 235981495 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv4/unnumbered/interface-ref"]; + } + repeated AddressKey address = 92268151 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv4/addresses/address"]; + Counters counters = 437070007 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv4/state/counters"]; + ywrapper.BoolValue dhcp_client = 161639310 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv4/config/dhcp-client"]; + ywrapper.BoolValue enabled = 2746286 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv4/config/enabled"]; + ywrapper.UintValue mtu = 20062117 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv4/config/mtu"]; + repeated NeighborKey neighbor = 188476968 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv4/neighbors/neighbor"]; + ProxyArp proxy_arp = 197757350 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv4/proxy-arp"]; + Unnumbered unnumbered = 488271015 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv4/unnumbered"]; + } + message Ipv6 { + message Address { + message VrrpGroup { + message InterfaceTracking { + ywrapper.UintValue priority_decrement = 246785741 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/addresses/address/vrrp/vrrp-group/interface-tracking/config/priority-decrement"]; + repeated ywrapper.StringValue track_interface = 245530804 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/addresses/address/vrrp/vrrp-group/interface-tracking/config/track-interface"]; + } + ywrapper.BoolValue accept_mode = 474973235 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/addresses/address/vrrp/vrrp-group/config/accept-mode"]; + ywrapper.UintValue advertisement_interval = 206648014 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/addresses/address/vrrp/vrrp-group/config/advertisement-interval"]; + ywrapper.UintValue current_priority = 522580458 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/addresses/address/vrrp/vrrp-group/state/current-priority"]; + InterfaceTracking interface_tracking = 373418769 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/addresses/address/vrrp/vrrp-group/interface-tracking"]; + ywrapper.BoolValue preempt = 473677782 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/addresses/address/vrrp/vrrp-group/config/preempt"]; + ywrapper.UintValue preempt_delay = 322094336 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/addresses/address/vrrp/vrrp-group/config/preempt-delay"]; + ywrapper.UintValue priority = 441053125 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/addresses/address/vrrp/vrrp-group/config/priority"]; + repeated ywrapper.StringValue virtual_address = 50990313 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/addresses/address/vrrp/vrrp-group/config/virtual-address"]; + ywrapper.StringValue virtual_link_local = 432847301 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/addresses/address/vrrp/vrrp-group/config/virtual-link-local"]; + } + message VrrpGroupKey { + uint64 virtual_router_id = 1 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/addresses/address/vrrp/vrrp-group/config/virtual-router-id|/interfaces/interface/subinterfaces/subinterface/ipv6/addresses/address/vrrp/vrrp-group/virtual-router-id"]; + VrrpGroup vrrp_group = 2; + } + enum Status { + STATUS_UNSET = 0; + STATUS_PREFERRED = 1 [(yext.yang_name) = "PREFERRED"]; + STATUS_DEPRECATED = 2 [(yext.yang_name) = "DEPRECATED"]; + STATUS_INVALID = 3 [(yext.yang_name) = "INVALID"]; + STATUS_INACCESSIBLE = 4 [(yext.yang_name) = "INACCESSIBLE"]; + STATUS_UNKNOWN = 5 [(yext.yang_name) = "UNKNOWN"]; + STATUS_TENTATIVE = 6 [(yext.yang_name) = "TENTATIVE"]; + STATUS_DUPLICATE = 7 [(yext.yang_name) = "DUPLICATE"]; + STATUS_OPTIMISTIC = 8 [(yext.yang_name) = "OPTIMISTIC"]; + } + openconfig.enums.OpenconfigIfIpIpAddressOrigin origin = 265403532 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/addresses/address/state/origin"]; + ywrapper.UintValue prefix_length = 23797826 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/addresses/address/config/prefix-length"]; + Status status = 330441988 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/addresses/address/state/status"]; + repeated VrrpGroupKey vrrp_group = 164916337 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/addresses/address/vrrp/vrrp-group"]; + } + message AddressKey { + string ip = 1 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/addresses/address/config/ip|/interfaces/interface/subinterfaces/subinterface/ipv6/addresses/address/ip"]; + Address address = 2; + } + message Counters { + ywrapper.UintValue in_discarded_pkts = 434884732 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/state/counters/in-discarded-pkts"]; + ywrapper.UintValue in_error_pkts = 172406437 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/state/counters/in-error-pkts"]; + ywrapper.UintValue in_forwarded_octets = 379953975 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/state/counters/in-forwarded-octets"]; + ywrapper.UintValue in_forwarded_pkts = 182415255 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/state/counters/in-forwarded-pkts"]; + ywrapper.UintValue in_octets = 109755954 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/state/counters/in-octets"]; + ywrapper.UintValue in_pkts = 276237266 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/state/counters/in-pkts"]; + ywrapper.UintValue out_discarded_pkts = 255300923 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/state/counters/out-discarded-pkts"]; + ywrapper.UintValue out_error_pkts = 183019222 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/state/counters/out-error-pkts"]; + ywrapper.UintValue out_forwarded_octets = 38309568 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/state/counters/out-forwarded-octets"]; + ywrapper.UintValue out_forwarded_pkts = 54486180 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/state/counters/out-forwarded-pkts"]; + ywrapper.UintValue out_octets = 116847869 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/state/counters/out-octets"]; + ywrapper.UintValue out_pkts = 56040841 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/state/counters/out-pkts"]; + } + message Neighbor { + enum NeighborState { + NEIGHBORSTATE_UNSET = 0; + NEIGHBORSTATE_INCOMPLETE = 1 [(yext.yang_name) = "INCOMPLETE"]; + NEIGHBORSTATE_REACHABLE = 2 [(yext.yang_name) = "REACHABLE"]; + NEIGHBORSTATE_STALE = 3 [(yext.yang_name) = "STALE"]; + NEIGHBORSTATE_DELAY = 4 [(yext.yang_name) = "DELAY"]; + NEIGHBORSTATE_PROBE = 5 [(yext.yang_name) = "PROBE"]; + } + ywrapper.BoolValue is_router = 444173615 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/neighbors/neighbor/state/is-router"]; + ywrapper.StringValue link_layer_address = 233623417 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/neighbors/neighbor/config/link-layer-address"]; + NeighborState neighbor_state = 89361925 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/neighbors/neighbor/state/neighbor-state"]; + openconfig.enums.OpenconfigIfIpNeighborOrigin origin = 158224829 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/neighbors/neighbor/state/origin"]; + } + message NeighborKey { + string ip = 1 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/neighbors/neighbor/config/ip|/interfaces/interface/subinterfaces/subinterface/ipv6/neighbors/neighbor/ip"]; + Neighbor neighbor = 2; + } + message RouterAdvertisement { + ywrapper.UintValue interval = 238405632 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/router-advertisement/config/interval"]; + ywrapper.UintValue lifetime = 524948482 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/router-advertisement/config/lifetime"]; + ywrapper.BoolValue suppress = 336253082 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/router-advertisement/config/suppress"]; + } + message Unnumbered { + message InterfaceRef { + ywrapper.StringValue interface = 337892034 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/unnumbered/interface-ref/config/interface"]; + ywrapper.UintValue subinterface = 81083550 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/unnumbered/interface-ref/config/subinterface"]; + } + ywrapper.BoolValue enabled = 80018040 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/unnumbered/config/enabled"]; + InterfaceRef interface_ref = 451937841 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/unnumbered/interface-ref"]; + } + repeated AddressKey address = 332836913 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/addresses/address"]; + Counters counters = 211415865 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/state/counters"]; + ywrapper.BoolValue dhcp_client = 67735920 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/config/dhcp-client"]; + ywrapper.UintValue dup_addr_detect_transmits = 205454088 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/config/dup-addr-detect-transmits"]; + ywrapper.BoolValue enabled = 253027964 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/config/enabled"]; + ywrapper.UintValue mtu = 255734467 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/config/mtu"]; + repeated NeighborKey neighbor = 66223230 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/neighbors/neighbor"]; + RouterAdvertisement router_advertisement = 219367423 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/router-advertisement"]; + Unnumbered unnumbered = 8515701 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6/unnumbered"]; + } + message Vlan { + message EgressMapping { + openconfig.enums.OpenconfigVlanTypesTPIDTYPES tpid = 5974643 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/vlan/egress-mapping/config/tpid"]; + ywrapper.UintValue vlan_id = 115904943 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/vlan/egress-mapping/config/vlan-id"]; + openconfig.enums.OpenconfigVlanVlanStackAction vlan_stack_action = 73085815 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/vlan/egress-mapping/config/vlan-stack-action"]; + } + message IngressMapping { + openconfig.enums.OpenconfigVlanTypesTPIDTYPES tpid = 396796195 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/vlan/ingress-mapping/config/tpid"]; + ywrapper.UintValue vlan_id = 28136351 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/vlan/ingress-mapping/config/vlan-id"]; + openconfig.enums.OpenconfigVlanVlanStackAction vlan_stack_action = 294702087 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/vlan/ingress-mapping/config/vlan-stack-action"]; + } + message Match { + message DoubleTagged { + ywrapper.UintValue inner_vlan_id = 487156134 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/vlan/match/double-tagged/config/inner-vlan-id"]; + ywrapper.UintValue outer_vlan_id = 239275239 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/vlan/match/double-tagged/config/outer-vlan-id"]; + } + message DoubleTaggedInnerList { + repeated ywrapper.UintValue inner_vlan_ids = 241185761 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/vlan/match/double-tagged-inner-list/config/inner-vlan-ids"]; + ywrapper.UintValue outer_vlan_id = 178462631 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/vlan/match/double-tagged-inner-list/config/outer-vlan-id"]; + } + message DoubleTaggedInnerOuterRange { + ywrapper.UintValue inner_high_vlan_id = 199617942 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/vlan/match/double-tagged-inner-outer-range/config/inner-high-vlan-id"]; + ywrapper.UintValue inner_low_vlan_id = 338513248 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/vlan/match/double-tagged-inner-outer-range/config/inner-low-vlan-id"]; + ywrapper.UintValue outer_high_vlan_id = 421546437 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/vlan/match/double-tagged-inner-outer-range/config/outer-high-vlan-id"]; + ywrapper.UintValue outer_low_vlan_id = 423694417 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/vlan/match/double-tagged-inner-outer-range/config/outer-low-vlan-id"]; + } + message DoubleTaggedInnerRange { + ywrapper.UintValue inner_high_vlan_id = 517943948 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/vlan/match/double-tagged-inner-range/config/inner-high-vlan-id"]; + ywrapper.UintValue inner_low_vlan_id = 415647886 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/vlan/match/double-tagged-inner-range/config/inner-low-vlan-id"]; + repeated ywrapper.UintValue outer_vlan_id = 518550994 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/vlan/match/double-tagged-inner-range/config/outer-vlan-id"]; + } + message DoubleTaggedOuterList { + ywrapper.UintValue inner_vlan_id = 254260451 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/vlan/match/double-tagged-outer-list/config/inner-vlan-id"]; + repeated ywrapper.UintValue outer_vlan_ids = 334803485 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/vlan/match/double-tagged-outer-list/config/outer-vlan-ids"]; + } + message DoubleTaggedOuterRange { + ywrapper.UintValue inner_vlan_id = 232967292 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/vlan/match/double-tagged-outer-range/config/inner-vlan-id"]; + ywrapper.UintValue outer_high_vlan_id = 169135066 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/vlan/match/double-tagged-outer-range/config/outer-high-vlan-id"]; + ywrapper.UintValue outer_low_vlan_id = 535310924 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/vlan/match/double-tagged-outer-range/config/outer-low-vlan-id"]; + } + message SingleTagged { + ywrapper.UintValue vlan_id = 305668962 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/vlan/match/single-tagged/config/vlan-id"]; + } + message SingleTaggedList { + repeated ywrapper.UintValue vlan_ids = 80041414 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/vlan/match/single-tagged-list/config/vlan-ids"]; + } + message SingleTaggedRange { + ywrapper.UintValue high_vlan_id = 77488575 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/vlan/match/single-tagged-range/config/high-vlan-id"]; + ywrapper.UintValue low_vlan_id = 158022331 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/vlan/match/single-tagged-range/config/low-vlan-id"]; + } + DoubleTagged double_tagged = 403737974 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/vlan/match/double-tagged"]; + DoubleTaggedInnerList double_tagged_inner_list = 522240822 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/vlan/match/double-tagged-inner-list"]; + DoubleTaggedInnerOuterRange double_tagged_inner_outer_range = 233858807 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/vlan/match/double-tagged-inner-outer-range"]; + DoubleTaggedInnerRange double_tagged_inner_range = 356922801 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/vlan/match/double-tagged-inner-range"]; + DoubleTaggedOuterList double_tagged_outer_list = 17738489 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/vlan/match/double-tagged-outer-list"]; + DoubleTaggedOuterRange double_tagged_outer_range = 470735512 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/vlan/match/double-tagged-outer-range"]; + SingleTagged single_tagged = 498022799 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/vlan/match/single-tagged"]; + SingleTaggedList single_tagged_list = 465169032 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/vlan/match/single-tagged-list"]; + SingleTaggedRange single_tagged_range = 121279207 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/vlan/match/single-tagged-range"]; + } + EgressMapping egress_mapping = 230644992 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/vlan/egress-mapping"]; + IngressMapping ingress_mapping = 179212592 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/vlan/ingress-mapping"]; + Match match = 89345155 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/vlan/match"]; + oneof vlan_id { + string vlan_id_string = 70496816; + uint64 vlan_id_uint64 = 218877865; + } + } + enum AdminStatus { + ADMINSTATUS_UNSET = 0; + ADMINSTATUS_UP = 1 [(yext.yang_name) = "UP"]; + ADMINSTATUS_DOWN = 2 [(yext.yang_name) = "DOWN"]; + ADMINSTATUS_TESTING = 3 [(yext.yang_name) = "TESTING"]; + } + enum OperStatus { + OPERSTATUS_UNSET = 0; + OPERSTATUS_UP = 2 [(yext.yang_name) = "UP"]; + OPERSTATUS_DOWN = 3 [(yext.yang_name) = "DOWN"]; + OPERSTATUS_TESTING = 4 [(yext.yang_name) = "TESTING"]; + OPERSTATUS_UNKNOWN = 5 [(yext.yang_name) = "UNKNOWN"]; + OPERSTATUS_DORMANT = 6 [(yext.yang_name) = "DORMANT"]; + OPERSTATUS_NOT_PRESENT = 7 [(yext.yang_name) = "NOT_PRESENT"]; + OPERSTATUS_LOWER_LAYER_DOWN = 8 [(yext.yang_name) = "LOWER_LAYER_DOWN"]; + } + AdminStatus admin_status = 250658952 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/state/admin-status"]; + Counters counters = 483442783 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/state/counters"]; + ywrapper.StringValue description = 280671199 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/config/description"]; + ywrapper.BoolValue enabled = 297236390 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/config/enabled"]; + ywrapper.UintValue ifindex = 511987815 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/state/ifindex"]; + Ipv4 ipv4 = 222971947 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv4"]; + Ipv6 ipv6 = 222971945 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/ipv6"]; + ywrapper.UintValue last_change = 29904521 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/state/last-change"]; + ywrapper.BoolValue logical = 294124401 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/state/logical"]; + ywrapper.StringValue name = 279346681 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/state/name"]; + OperStatus oper_status = 401969247 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/state/oper-status"]; + Vlan vlan = 164705069 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/vlan"]; + } + message SubinterfaceKey { + uint64 index = 1 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface/config/index|/interfaces/interface/subinterfaces/subinterface/index"]; + Subinterface subinterface = 2; + } + enum AdminStatus { + ADMINSTATUS_UNSET = 0; + ADMINSTATUS_UP = 1 [(yext.yang_name) = "UP"]; + ADMINSTATUS_DOWN = 2 [(yext.yang_name) = "DOWN"]; + ADMINSTATUS_TESTING = 3 [(yext.yang_name) = "TESTING"]; + } + enum HealthIndicator { + HEALTHINDICATOR_UNSET = 0; + HEALTHINDICATOR_GOOD = 1 [(yext.yang_name) = "GOOD"]; + HEALTHINDICATOR_BAD = 2 [(yext.yang_name) = "BAD"]; + } + enum OperStatus { + OPERSTATUS_UNSET = 0; + OPERSTATUS_UP = 2 [(yext.yang_name) = "UP"]; + OPERSTATUS_DOWN = 3 [(yext.yang_name) = "DOWN"]; + OPERSTATUS_TESTING = 4 [(yext.yang_name) = "TESTING"]; + OPERSTATUS_UNKNOWN = 5 [(yext.yang_name) = "UNKNOWN"]; + OPERSTATUS_DORMANT = 6 [(yext.yang_name) = "DORMANT"]; + OPERSTATUS_NOT_PRESENT = 7 [(yext.yang_name) = "NOT_PRESENT"]; + OPERSTATUS_LOWER_LAYER_DOWN = 8 [(yext.yang_name) = "LOWER_LAYER_DOWN"]; + } + AdminStatus admin_status = 474494763 [(yext.schemapath) = "/interfaces/interface/state/admin-status"]; + Aggregation aggregation = 264856597 [(yext.schemapath) = "/interfaces/interface/aggregation"]; + Counters counters = 83645964 [(yext.schemapath) = "/interfaces/interface/state/counters"]; + ywrapper.StringValue description = 418535860 [(yext.schemapath) = "/interfaces/interface/config/description"]; + ywrapper.BoolValue enabled = 37224301 [(yext.schemapath) = "/interfaces/interface/config/enabled"]; + Ethernet ethernet = 79652980 [(yext.schemapath) = "/interfaces/interface/ethernet"]; + ywrapper.StringValue hardware_port = 119177817 [(yext.schemapath) = "/interfaces/interface/state/hardware-port"]; + HealthIndicator health_indicator = 48855692 [(yext.schemapath) = "/interfaces/interface/config/health-indicator"]; + HoldTime hold_time = 175931092 [(yext.schemapath) = "/interfaces/interface/hold-time"]; + ywrapper.UintValue id = 105633293 [(yext.schemapath) = "/interfaces/interface/config/id"]; + ywrapper.UintValue ifindex = 116108202 [(yext.schemapath) = "/interfaces/interface/state/ifindex"]; + ywrapper.UintValue last_change = 127348880 [(yext.schemapath) = "/interfaces/interface/state/last-change"]; + ywrapper.BoolValue logical = 440460216 [(yext.schemapath) = "/interfaces/interface/state/logical"]; + ywrapper.BoolValue loopback_mode = 253516347 [(yext.schemapath) = "/interfaces/interface/config/loopback-mode"]; + ywrapper.UintValue mtu = 376210342 [(yext.schemapath) = "/interfaces/interface/config/mtu"]; + OperStatus oper_status = 470394226 [(yext.schemapath) = "/interfaces/interface/state/oper-status"]; + repeated ywrapper.UintValue physical_channel = 46213654 [(yext.schemapath) = "/interfaces/interface/state/physical-channel"]; + RoutedVlan routed_vlan = 65530678 [(yext.schemapath) = "/interfaces/interface/routed-vlan"]; + repeated SubinterfaceKey subinterface = 464802819 [(yext.schemapath) = "/interfaces/interface/subinterfaces/subinterface"]; + openconfig.enums.OpenconfigVlanTypesTPIDTYPES tpid = 464491713 [(yext.schemapath) = "/interfaces/interface/config/tpid"]; + ywrapper.StringValue transceiver = 84602875 [(yext.schemapath) = "/interfaces/interface/state/transceiver"]; + openconfig.enums.IETFInterfacesInterfaceType type = 144596894 [(yext.schemapath) = "/interfaces/interface/config/type"]; +} + +message Lacp { + message Interface { + message Member { + message Counters { + ywrapper.UintValue lacp_errors = 432819317 [(yext.schemapath) = "/lacp/interfaces/interface/members/member/state/counters/lacp-errors"]; + ywrapper.UintValue lacp_in_pkts = 133444718 [(yext.schemapath) = "/lacp/interfaces/interface/members/member/state/counters/lacp-in-pkts"]; + ywrapper.UintValue lacp_out_pkts = 391388365 [(yext.schemapath) = "/lacp/interfaces/interface/members/member/state/counters/lacp-out-pkts"]; + ywrapper.UintValue lacp_rx_errors = 124474434 [(yext.schemapath) = "/lacp/interfaces/interface/members/member/state/counters/lacp-rx-errors"]; + ywrapper.UintValue lacp_tx_errors = 98014728 [(yext.schemapath) = "/lacp/interfaces/interface/members/member/state/counters/lacp-tx-errors"]; + ywrapper.UintValue lacp_unknown_errors = 33984050 [(yext.schemapath) = "/lacp/interfaces/interface/members/member/state/counters/lacp-unknown-errors"]; + } + openconfig.enums.OpenconfigLacpLacpActivityType activity = 344383748 [(yext.schemapath) = "/lacp/interfaces/interface/members/member/state/activity"]; + ywrapper.BoolValue aggregatable = 490059983 [(yext.schemapath) = "/lacp/interfaces/interface/members/member/state/aggregatable"]; + ywrapper.BoolValue collecting = 431241365 [(yext.schemapath) = "/lacp/interfaces/interface/members/member/state/collecting"]; + Counters counters = 159126128 [(yext.schemapath) = "/lacp/interfaces/interface/members/member/state/counters"]; + ywrapper.BoolValue distributing = 325869523 [(yext.schemapath) = "/lacp/interfaces/interface/members/member/state/distributing"]; + ywrapper.UintValue oper_key = 503255861 [(yext.schemapath) = "/lacp/interfaces/interface/members/member/state/oper-key"]; + ywrapper.StringValue partner_id = 342233611 [(yext.schemapath) = "/lacp/interfaces/interface/members/member/state/partner-id"]; + ywrapper.UintValue partner_key = 313821353 [(yext.schemapath) = "/lacp/interfaces/interface/members/member/state/partner-key"]; + ywrapper.UintValue partner_port_num = 11089282 [(yext.schemapath) = "/lacp/interfaces/interface/members/member/state/partner-port-num"]; + ywrapper.UintValue port_num = 55409541 [(yext.schemapath) = "/lacp/interfaces/interface/members/member/state/port-num"]; + openconfig.enums.OpenconfigLacpLacpSynchronizationType synchronization = 179070617 [(yext.schemapath) = "/lacp/interfaces/interface/members/member/state/synchronization"]; + ywrapper.StringValue system_id = 207537082 [(yext.schemapath) = "/lacp/interfaces/interface/members/member/state/system-id"]; + openconfig.enums.OpenconfigLacpLacpTimeoutType timeout = 834808 [(yext.schemapath) = "/lacp/interfaces/interface/members/member/state/timeout"]; + } + message MemberKey { + string interface = 1 [(yext.schemapath) = "/lacp/interfaces/interface/members/member/state/interface|/lacp/interfaces/interface/members/member/interface"]; + Member member = 2; + } + openconfig.enums.OpenconfigLacpLacpPeriodType interval = 463085042 [(yext.schemapath) = "/lacp/interfaces/interface/config/interval"]; + openconfig.enums.OpenconfigLacpLacpActivityType lacp_mode = 43173203 [(yext.schemapath) = "/lacp/interfaces/interface/config/lacp-mode"]; + repeated MemberKey member = 107372070 [(yext.schemapath) = "/lacp/interfaces/interface/members/member"]; + ywrapper.StringValue system_id_mac = 461403306 [(yext.schemapath) = "/lacp/interfaces/interface/config/system-id-mac"]; + ywrapper.UintValue system_priority = 131529879 [(yext.schemapath) = "/lacp/interfaces/interface/config/system-priority"]; + } + message InterfaceKey { + string name = 1 [(yext.schemapath) = "/lacp/interfaces/interface/config/name|/lacp/interfaces/interface/name"]; + Interface interface = 2; + } + repeated InterfaceKey interface = 212110241 [(yext.schemapath) = "/lacp/interfaces/interface"]; + ywrapper.UintValue system_priority = 71542334 [(yext.schemapath) = "/lacp/config/system-priority"]; +} + +message Messages { + message DebugService { + ywrapper.BoolValue enabled = 199740246 [(yext.schemapath) = "/messages/debug-entries/debug-service/config/enabled"]; + } + message DebugServiceKey { + openconfig.enums.OpenconfigMessagesDEBUGSERVICE service = 1 [(yext.schemapath) = "/messages/debug-entries/debug-service/config/service|/messages/debug-entries/debug-service/service"]; + DebugService debug_service = 2; + } + message Message { + ywrapper.StringValue app_name = 304771296 [(yext.schemapath) = "/messages/state/message/app-name"]; + ywrapper.StringValue msg = 279618974 [(yext.schemapath) = "/messages/state/message/msg"]; + ywrapper.StringValue msgid = 19358029 [(yext.schemapath) = "/messages/state/message/msgid"]; + ywrapper.UintValue priority = 79965083 [(yext.schemapath) = "/messages/state/message/priority"]; + ywrapper.StringValue procid = 40506564 [(yext.schemapath) = "/messages/state/message/procid"]; + } + repeated DebugServiceKey debug_service = 496947347 [(yext.schemapath) = "/messages/debug-entries/debug-service"]; + Message message = 263846912 [(yext.schemapath) = "/messages/state/message"]; + openconfig.enums.OpenconfigMessagesSyslogSeverity severity = 369122415 [(yext.schemapath) = "/messages/config/severity"]; +} + +message Component { + message Backplane { + } + message Chassis { + message Alarms { + message CriticalState { + ywrapper.StringValue info = 342401342 [(yext.schemapath) = "/components/component/chassis/alarms/critical-state/info"]; + openconfig.enums.OpenconfigAlarmTypesOPENCONFIGALARMSEVERITY severity = 397236191 [(yext.schemapath) = "/components/component/chassis/alarms/critical-state/severity"]; + ywrapper.BoolValue status = 41151748 [(yext.schemapath) = "/components/component/chassis/alarms/critical-state/status"]; + ywrapper.UintValue time_created = 477885306 [(yext.schemapath) = "/components/component/chassis/alarms/critical-state/time-created"]; + } + CriticalState critical_state = 432588419 [(yext.schemapath) = "/components/component/chassis/alarms/critical-state"]; + } + Alarms alarms = 408595637 [(yext.schemapath) = "/components/component/chassis/alarms"]; + openconfig.enums.OpenconfigHerculesPlatformPLATFORMTYPE platform = 282254533 [(yext.schemapath) = "/components/component/chassis/config/platform"]; + } + message Cpu { + } + message Fabric { + } + message Fan { + } + message IntegratedCircuit { + message VendorData { + } + ywrapper.UintValue node_id = 182157625 [(yext.schemapath) = "/components/component/integrated-circuit/config/node-id"]; + VendorData vendor_data = 515723575 [(yext.schemapath) = "/components/component/integrated-circuit/vendor-data"]; + } + message Linecard { + openconfig.enums.OpenconfigPlatformLinecardComponentPowerType power_admin_state = 460899237 [(yext.schemapath) = "/components/component/linecard/config/power-admin-state"]; + ywrapper.StringValue slot_id = 262632666 [(yext.schemapath) = "/components/component/linecard/config/slot-id"]; + } + message Memory { + ywrapper.UintValue available = 322322459 [(yext.schemapath) = "/components/component/state/memory/available"]; + ywrapper.UintValue utilized = 235118644 [(yext.schemapath) = "/components/component/state/memory/utilized"]; + } + message Port { + message BreakoutMode { + openconfig.enums.OpenconfigIfEthernetETHERNETSPEED channel_speed = 133662836 [(yext.schemapath) = "/components/component/port/breakout-mode/config/channel-speed"]; + ywrapper.UintValue num_channels = 207420976 [(yext.schemapath) = "/components/component/port/breakout-mode/config/num-channels"]; + } + BreakoutMode breakout_mode = 508830081 [(yext.schemapath) = "/components/component/port/breakout-mode"]; + ywrapper.UintValue port_id = 75743878 [(yext.schemapath) = "/components/component/port/config/port-id"]; + } + message PowerSupply { + } + message Property { + ywrapper.BoolValue configurable = 264996693 [(yext.schemapath) = "/components/component/properties/property/state/configurable"]; + oneof value { + bool value_bool = 320942043; + sint64 value_sint64 = 532815527; + string value_string = 259657076; + uint64 value_uint64 = 1206141; + ywrapper.Decimal64Value value_decimal64value = 342547513; + } + } + message PropertyKey { + string name = 1 [(yext.schemapath) = "/components/component/properties/property/config/name|/components/component/properties/property/name"]; + Property property = 2; + } + message Storage { + } + message Subcomponent { + } + message SubcomponentKey { + string name = 1 [(yext.schemapath) = "/components/component/subcomponents/subcomponent/config/name|/components/component/subcomponents/subcomponent/name"]; + Subcomponent subcomponent = 2; + } + message Temperature { + openconfig.enums.OpenconfigAlarmTypesOPENCONFIGALARMSEVERITY alarm_severity = 296397186 [(yext.schemapath) = "/components/component/state/temperature/alarm-severity"]; + ywrapper.BoolValue alarm_status = 176894761 [(yext.schemapath) = "/components/component/state/temperature/alarm-status"]; + ywrapper.UintValue alarm_threshold = 231489284 [(yext.schemapath) = "/components/component/state/temperature/alarm-threshold"]; + ywrapper.Decimal64Value avg = 100651349 [(yext.schemapath) = "/components/component/state/temperature/avg"]; + ywrapper.Decimal64Value instant = 206000082 [(yext.schemapath) = "/components/component/state/temperature/instant"]; + ywrapper.UintValue interval = 407404980 [(yext.schemapath) = "/components/component/state/temperature/interval"]; + ywrapper.Decimal64Value max = 421397591 [(yext.schemapath) = "/components/component/state/temperature/max"]; + ywrapper.UintValue max_time = 415076571 [(yext.schemapath) = "/components/component/state/temperature/max-time"]; + ywrapper.Decimal64Value min = 18747561 [(yext.schemapath) = "/components/component/state/temperature/min"]; + ywrapper.UintValue min_time = 177135617 [(yext.schemapath) = "/components/component/state/temperature/min-time"]; + } + message Transceiver { + message Channel { + message InputPower { + ywrapper.Decimal64Value avg = 425608185 [(yext.schemapath) = "/components/component/transceiver/physical-channels/channel/state/input-power/avg"]; + ywrapper.Decimal64Value instant = 59663094 [(yext.schemapath) = "/components/component/transceiver/physical-channels/channel/state/input-power/instant"]; + ywrapper.UintValue interval = 54371640 [(yext.schemapath) = "/components/component/transceiver/physical-channels/channel/state/input-power/interval"]; + ywrapper.Decimal64Value max = 73969555 [(yext.schemapath) = "/components/component/transceiver/physical-channels/channel/state/input-power/max"]; + ywrapper.UintValue max_time = 306475071 [(yext.schemapath) = "/components/component/transceiver/physical-channels/channel/state/input-power/max-time"]; + ywrapper.Decimal64Value min = 476619581 [(yext.schemapath) = "/components/component/transceiver/physical-channels/channel/state/input-power/min"]; + ywrapper.UintValue min_time = 250548621 [(yext.schemapath) = "/components/component/transceiver/physical-channels/channel/state/input-power/min-time"]; + } + message LaserBiasCurrent { + ywrapper.Decimal64Value avg = 230643524 [(yext.schemapath) = "/components/component/transceiver/physical-channels/channel/state/laser-bias-current/avg"]; + ywrapper.Decimal64Value instant = 325376671 [(yext.schemapath) = "/components/component/transceiver/physical-channels/channel/state/laser-bias-current/instant"]; + ywrapper.UintValue interval = 384153695 [(yext.schemapath) = "/components/component/transceiver/physical-channels/channel/state/laser-bias-current/interval"]; + ywrapper.Decimal64Value max = 446768222 [(yext.schemapath) = "/components/component/transceiver/physical-channels/channel/state/laser-bias-current/max"]; + ywrapper.UintValue max_time = 277917244 [(yext.schemapath) = "/components/component/transceiver/physical-channels/channel/state/laser-bias-current/max-time"]; + ywrapper.Decimal64Value min = 44118224 [(yext.schemapath) = "/components/component/transceiver/physical-channels/channel/state/laser-bias-current/min"]; + ywrapper.UintValue min_time = 201511538 [(yext.schemapath) = "/components/component/transceiver/physical-channels/channel/state/laser-bias-current/min-time"]; + } + message OutputPower { + ywrapper.Decimal64Value avg = 470907710 [(yext.schemapath) = "/components/component/transceiver/physical-channels/channel/state/output-power/avg"]; + ywrapper.Decimal64Value instant = 110986605 [(yext.schemapath) = "/components/component/transceiver/physical-channels/channel/state/output-power/instant"]; + ywrapper.UintValue interval = 332288817 [(yext.schemapath) = "/components/component/transceiver/physical-channels/channel/state/output-power/interval"]; + ywrapper.Decimal64Value max = 85611000 [(yext.schemapath) = "/components/component/transceiver/physical-channels/channel/state/output-power/max"]; + ywrapper.UintValue max_time = 354684250 [(yext.schemapath) = "/components/component/transceiver/physical-channels/channel/state/output-power/max-time"]; + ywrapper.Decimal64Value min = 219831926 [(yext.schemapath) = "/components/component/transceiver/physical-channels/channel/state/output-power/min"]; + ywrapper.UintValue min_time = 114700532 [(yext.schemapath) = "/components/component/transceiver/physical-channels/channel/state/output-power/min-time"]; + } + ywrapper.StringValue description = 314562795 [(yext.schemapath) = "/components/component/transceiver/physical-channels/channel/config/description"]; + InputPower input_power = 303986504 [(yext.schemapath) = "/components/component/transceiver/physical-channels/channel/state/input-power"]; + LaserBiasCurrent laser_bias_current = 482909465 [(yext.schemapath) = "/components/component/transceiver/physical-channels/channel/state/laser-bias-current"]; + ywrapper.UintValue output_frequency = 226348966 [(yext.schemapath) = "/components/component/transceiver/physical-channels/channel/state/output-frequency"]; + OutputPower output_power = 436080879 [(yext.schemapath) = "/components/component/transceiver/physical-channels/channel/state/output-power"]; + ywrapper.Decimal64Value target_output_power = 128341554 [(yext.schemapath) = "/components/component/transceiver/physical-channels/channel/config/target-output-power"]; + ywrapper.BoolValue tx_laser = 133868429 [(yext.schemapath) = "/components/component/transceiver/physical-channels/channel/config/tx-laser"]; + } + message ChannelKey { + uint64 index = 1 [(yext.schemapath) = "/components/component/transceiver/physical-channels/channel/config/index|/components/component/transceiver/physical-channels/channel/index"]; + Channel channel = 2; + } + message InputPower { + ywrapper.Decimal64Value avg = 424783144 [(yext.schemapath) = "/components/component/transceiver/state/input-power/avg"]; + ywrapper.Decimal64Value instant = 29798419 [(yext.schemapath) = "/components/component/transceiver/state/input-power/instant"]; + ywrapper.UintValue interval = 192286739 [(yext.schemapath) = "/components/component/transceiver/state/input-power/interval"]; + ywrapper.Decimal64Value max = 242200938 [(yext.schemapath) = "/components/component/transceiver/state/input-power/max"]; + ywrapper.UintValue max_time = 207250528 [(yext.schemapath) = "/components/component/transceiver/state/input-power/max-time"]; + ywrapper.Decimal64Value min = 376421828 [(yext.schemapath) = "/components/component/transceiver/state/input-power/min"]; + ywrapper.UintValue min_time = 300437550 [(yext.schemapath) = "/components/component/transceiver/state/input-power/min-time"]; + } + message LaserBiasCurrent { + ywrapper.Decimal64Value avg = 44193839 [(yext.schemapath) = "/components/component/transceiver/state/laser-bias-current/avg"]; + ywrapper.Decimal64Value instant = 400153624 [(yext.schemapath) = "/components/component/transceiver/state/laser-bias-current/instant"]; + ywrapper.UintValue interval = 482176166 [(yext.schemapath) = "/components/component/transceiver/state/laser-bias-current/interval"]; + ywrapper.Decimal64Value max = 26814849 [(yext.schemapath) = "/components/component/transceiver/state/laser-bias-current/max"]; + ywrapper.UintValue max_time = 397616537 [(yext.schemapath) = "/components/component/transceiver/state/laser-bias-current/max-time"]; + ywrapper.Decimal64Value min = 161036031 [(yext.schemapath) = "/components/component/transceiver/state/laser-bias-current/min"]; + ywrapper.UintValue min_time = 106286659 [(yext.schemapath) = "/components/component/transceiver/state/laser-bias-current/min-time"]; + } + message OutputPower { + ywrapper.Decimal64Value avg = 103469393 [(yext.schemapath) = "/components/component/transceiver/state/output-power/avg"]; + ywrapper.Decimal64Value instant = 45091486 [(yext.schemapath) = "/components/component/transceiver/state/output-power/instant"]; + ywrapper.UintValue interval = 140247632 [(yext.schemapath) = "/components/component/transceiver/state/output-power/interval"]; + ywrapper.Decimal64Value max = 286038891 [(yext.schemapath) = "/components/component/transceiver/state/output-power/max"]; + ywrapper.UintValue max_time = 372050135 [(yext.schemapath) = "/components/component/transceiver/state/output-power/max-time"]; + ywrapper.Decimal64Value min = 420259781 [(yext.schemapath) = "/components/component/transceiver/state/output-power/min"]; + ywrapper.UintValue min_time = 351300789 [(yext.schemapath) = "/components/component/transceiver/state/output-power/min-time"]; + } + message PostFecBer { + ywrapper.Decimal64Value avg = 101143861 [(yext.schemapath) = "/components/component/transceiver/state/post-fec-ber/avg"]; + ywrapper.Decimal64Value instant = 488914354 [(yext.schemapath) = "/components/component/transceiver/state/post-fec-ber/instant"]; + ywrapper.UintValue interval = 358186772 [(yext.schemapath) = "/components/component/transceiver/state/post-fec-ber/interval"]; + ywrapper.Decimal64Value max = 421890103 [(yext.schemapath) = "/components/component/transceiver/state/post-fec-ber/max"]; + ywrapper.UintValue max_time = 200255931 [(yext.schemapath) = "/components/component/transceiver/state/post-fec-ber/max-time"]; + ywrapper.Decimal64Value min = 19240073 [(yext.schemapath) = "/components/component/transceiver/state/post-fec-ber/min"]; + ywrapper.UintValue min_time = 128020833 [(yext.schemapath) = "/components/component/transceiver/state/post-fec-ber/min-time"]; + } + message PreFecBer { + ywrapper.Decimal64Value avg = 473442514 [(yext.schemapath) = "/components/component/transceiver/state/pre-fec-ber/avg"]; + ywrapper.Decimal64Value instant = 345533569 [(yext.schemapath) = "/components/component/transceiver/state/pre-fec-ber/instant"]; + ywrapper.UintValue interval = 3876757 [(yext.schemapath) = "/components/component/transceiver/state/pre-fec-ber/interval"]; + ywrapper.Decimal64Value max = 221202788 [(yext.schemapath) = "/components/component/transceiver/state/pre-fec-ber/max"]; + ywrapper.UintValue max_time = 128523470 [(yext.schemapath) = "/components/component/transceiver/state/pre-fec-ber/max-time"]; + ywrapper.Decimal64Value min = 355423706 [(yext.schemapath) = "/components/component/transceiver/state/pre-fec-ber/min"]; + ywrapper.UintValue min_time = 453726032 [(yext.schemapath) = "/components/component/transceiver/state/pre-fec-ber/min-time"]; + } + enum Present { + PRESENT_UNSET = 0; + PRESENT_PRESENT = 1 [(yext.yang_name) = "PRESENT"]; + PRESENT_NOT_PRESENT = 2 [(yext.yang_name) = "NOT_PRESENT"]; + } + repeated ChannelKey channel = 359124959 [(yext.schemapath) = "/components/component/transceiver/physical-channels/channel"]; + openconfig.enums.OpenconfigTransportTypesFIBERCONNECTORTYPE connector_type = 252758609 [(yext.schemapath) = "/components/component/transceiver/state/connector-type"]; + ywrapper.StringValue date_code = 323636967 [(yext.schemapath) = "/components/component/transceiver/state/date-code"]; + ywrapper.BoolValue enabled = 202927581 [(yext.schemapath) = "/components/component/transceiver/config/enabled"]; + openconfig.enums.OpenconfigTransportTypesETHERNETPMDTYPE ethernet_pmd = 416980802 [(yext.schemapath) = "/components/component/transceiver/state/ethernet-pmd"]; + openconfig.enums.OpenconfigTransportTypesETHERNETPMDTYPE ethernet_pmd_preconf = 338246677 [(yext.schemapath) = "/components/component/transceiver/config/ethernet-pmd-preconf"]; + ywrapper.BoolValue fault_condition = 66972341 [(yext.schemapath) = "/components/component/transceiver/state/fault-condition"]; + ywrapper.UintValue fec_corrected_bits = 272535390 [(yext.schemapath) = "/components/component/transceiver/state/fec-corrected-bits"]; + ywrapper.UintValue fec_corrected_bytes = 133775387 [(yext.schemapath) = "/components/component/transceiver/state/fec-corrected-bytes"]; + openconfig.enums.OpenconfigPlatformTypesFECMODETYPE fec_mode = 277265248 [(yext.schemapath) = "/components/component/transceiver/config/fec-mode"]; + openconfig.enums.OpenconfigPlatformTypesFECSTATUSTYPE fec_status = 41358082 [(yext.schemapath) = "/components/component/transceiver/state/fec-status"]; + ywrapper.UintValue fec_uncorrectable_blocks = 497424056 [(yext.schemapath) = "/components/component/transceiver/state/fec-uncorrectable-blocks"]; + ywrapper.UintValue fec_uncorrectable_words = 133578617 [(yext.schemapath) = "/components/component/transceiver/state/fec-uncorrectable-words"]; + openconfig.enums.OpenconfigTransportTypesTRANSCEIVERFORMFACTORTYPE form_factor = 11627927 [(yext.schemapath) = "/components/component/transceiver/state/form-factor"]; + openconfig.enums.OpenconfigTransportTypesTRANSCEIVERFORMFACTORTYPE form_factor_preconf = 471604670 [(yext.schemapath) = "/components/component/transceiver/config/form-factor-preconf"]; + InputPower input_power = 41561605 [(yext.schemapath) = "/components/component/transceiver/state/input-power"]; + LaserBiasCurrent laser_bias_current = 422928146 [(yext.schemapath) = "/components/component/transceiver/state/laser-bias-current"]; + openconfig.enums.OpenconfigTransportTypesOTNAPPLICATIONCODE otn_compliance_code = 302597810 [(yext.schemapath) = "/components/component/transceiver/state/otn-compliance-code"]; + OutputPower output_power = 242740240 [(yext.schemapath) = "/components/component/transceiver/state/output-power"]; + PostFecBer post_fec_ber = 125122572 [(yext.schemapath) = "/components/component/transceiver/state/post-fec-ber"]; + PreFecBer pre_fec_ber = 264885771 [(yext.schemapath) = "/components/component/transceiver/state/pre-fec-ber"]; + Present present = 171782640 [(yext.schemapath) = "/components/component/transceiver/state/present"]; + ywrapper.StringValue serial_no = 48331837 [(yext.schemapath) = "/components/component/transceiver/state/serial-no"]; + openconfig.enums.OpenconfigTransportTypesSONETAPPLICATIONCODE sonet_sdh_compliance_code = 354799300 [(yext.schemapath) = "/components/component/transceiver/state/sonet-sdh-compliance-code"]; + ywrapper.StringValue vendor = 186283901 [(yext.schemapath) = "/components/component/transceiver/state/vendor"]; + ywrapper.StringValue vendor_part = 246872941 [(yext.schemapath) = "/components/component/transceiver/state/vendor-part"]; + ywrapper.StringValue vendor_rev = 62133637 [(yext.schemapath) = "/components/component/transceiver/state/vendor-rev"]; + } + ywrapper.UintValue allocated_power = 382835825 [(yext.schemapath) = "/components/component/state/allocated-power"]; + Backplane backplane = 23572881 [(yext.schemapath) = "/components/component/backplane"]; + Chassis chassis = 153681076 [(yext.schemapath) = "/components/component/chassis"]; + Cpu cpu = 60886558 [(yext.schemapath) = "/components/component/cpu"]; + ywrapper.StringValue description = 167549616 [(yext.schemapath) = "/components/component/state/description"]; + ywrapper.BoolValue empty = 433362321 [(yext.schemapath) = "/components/component/state/empty"]; + ywrapper.BoolValue equipment_failure = 471038183 [(yext.schemapath) = "/components/component/state/equipment-failure"]; + ywrapper.BoolValue equipment_mismatch = 311608903 [(yext.schemapath) = "/components/component/state/equipment-mismatch"]; + Fabric fabric = 101006771 [(yext.schemapath) = "/components/component/fabric"]; + Fan fan = 111660679 [(yext.schemapath) = "/components/component/fan"]; + ywrapper.StringValue firmware_version = 244667518 [(yext.schemapath) = "/components/component/state/firmware-version"]; + ywrapper.StringValue hardware_version = 49616205 [(yext.schemapath) = "/components/component/state/hardware-version"]; + ywrapper.StringValue id = 246882465 [(yext.schemapath) = "/components/component/state/id"]; + IntegratedCircuit integrated_circuit = 195631273 [(yext.schemapath) = "/components/component/integrated-circuit"]; + Linecard linecard = 18894832 [(yext.schemapath) = "/components/component/linecard"]; + ywrapper.StringValue location = 326611111 [(yext.schemapath) = "/components/component/state/location"]; + Memory memory = 443182963 [(yext.schemapath) = "/components/component/state/memory"]; + ywrapper.StringValue mfg_date = 499974311 [(yext.schemapath) = "/components/component/state/mfg-date"]; + ywrapper.StringValue mfg_name = 80033814 [(yext.schemapath) = "/components/component/state/mfg-name"]; + openconfig.enums.OpenconfigPlatformTypesCOMPONENTOPERSTATUS oper_status = 378023501 [(yext.schemapath) = "/components/component/state/oper-status"]; + ywrapper.StringValue parent = 291733930 [(yext.schemapath) = "/components/component/state/parent"]; + ywrapper.StringValue part_no = 173082367 [(yext.schemapath) = "/components/component/state/part-no"]; + Port port = 529421081 [(yext.schemapath) = "/components/component/port"]; + PowerSupply power_supply = 438616709 [(yext.schemapath) = "/components/component/power-supply"]; + repeated PropertyKey property = 502076969 [(yext.schemapath) = "/components/component/properties/property"]; + ywrapper.BoolValue removable = 351010765 [(yext.schemapath) = "/components/component/state/removable"]; + ywrapper.StringValue serial_no = 490029750 [(yext.schemapath) = "/components/component/state/serial-no"]; + ywrapper.StringValue software_version = 220526526 [(yext.schemapath) = "/components/component/state/software-version"]; + Storage storage = 403943259 [(yext.schemapath) = "/components/component/storage"]; + repeated SubcomponentKey subcomponent = 282821422 [(yext.schemapath) = "/components/component/subcomponents/subcomponent"]; + Temperature temperature = 169040172 [(yext.schemapath) = "/components/component/state/temperature"]; + Transceiver transceiver = 40802250 [(yext.schemapath) = "/components/component/transceiver"]; + oneof type { + openconfig.enums.OpenconfigPlatformTypesOPENCONFIGHARDWARECOMPONENT type_openconfigplatformtypesopenconfighardwarecomponent = 149343237; + openconfig.enums.OpenconfigPlatformTypesOPENCONFIGSOFTWARECOMPONENT type_openconfigplatformtypesopenconfigsoftwarecomponent = 205426072; + } + ywrapper.UintValue used_power = 259754309 [(yext.schemapath) = "/components/component/state/used-power"]; +} + +message Qos { + message Classifier { + message Term { + message Actions { + message Remark { + ywrapper.UintValue set_dot1p = 129420902 [(yext.schemapath) = "/qos/classifiers/classifier/terms/term/actions/remark/config/set-dot1p"]; + ywrapper.UintValue set_dscp = 184950326 [(yext.schemapath) = "/qos/classifiers/classifier/terms/term/actions/remark/config/set-dscp"]; + ywrapper.UintValue set_mpls_tc = 115576782 [(yext.schemapath) = "/qos/classifiers/classifier/terms/term/actions/remark/config/set-mpls-tc"]; + } + Remark remark = 45738605 [(yext.schemapath) = "/qos/classifiers/classifier/terms/term/actions/remark"]; + ywrapper.StringValue target_group = 263567595 [(yext.schemapath) = "/qos/classifiers/classifier/terms/term/actions/config/target-group"]; + } + message Conditions { + message Ipv4 { + ywrapper.StringValue destination_address = 527978798 [(yext.schemapath) = "/qos/classifiers/classifier/terms/term/conditions/ipv4/config/destination-address"]; + ywrapper.UintValue dscp = 459218869 [(yext.schemapath) = "/qos/classifiers/classifier/terms/term/conditions/ipv4/config/dscp"]; + ywrapper.UintValue hop_limit = 164634146 [(yext.schemapath) = "/qos/classifiers/classifier/terms/term/conditions/ipv4/config/hop-limit"]; + oneof protocol { + openconfig.enums.OpenconfigPacketMatchTypesIPPROTOCOL protocol_openconfigpacketmatchtypesipprotocol = 371958053; + uint64 protocol_uint64 = 488250108; + } + ywrapper.StringValue source_address = 389228459 [(yext.schemapath) = "/qos/classifiers/classifier/terms/term/conditions/ipv4/config/source-address"]; + } + message Ipv6 { + ywrapper.StringValue destination_address = 139860024 [(yext.schemapath) = "/qos/classifiers/classifier/terms/term/conditions/ipv6/config/destination-address"]; + ywrapper.UintValue destination_flow_label = 26892661 [(yext.schemapath) = "/qos/classifiers/classifier/terms/term/conditions/ipv6/config/destination-flow-label"]; + ywrapper.UintValue dscp = 482221487 [(yext.schemapath) = "/qos/classifiers/classifier/terms/term/conditions/ipv6/config/dscp"]; + ywrapper.UintValue hop_limit = 233120028 [(yext.schemapath) = "/qos/classifiers/classifier/terms/term/conditions/ipv6/config/hop-limit"]; + oneof protocol { + openconfig.enums.OpenconfigPacketMatchTypesIPPROTOCOL protocol_openconfigpacketmatchtypesipprotocol = 483684219; + uint64 protocol_uint64 = 50630658; + } + ywrapper.StringValue source_address = 498643489 [(yext.schemapath) = "/qos/classifiers/classifier/terms/term/conditions/ipv6/config/source-address"]; + ywrapper.UintValue source_flow_label = 158748530 [(yext.schemapath) = "/qos/classifiers/classifier/terms/term/conditions/ipv6/config/source-flow-label"]; + } + message L2 { + ywrapper.StringValue destination_mac = 515610502 [(yext.schemapath) = "/qos/classifiers/classifier/terms/term/conditions/l2/config/destination-mac"]; + ywrapper.StringValue destination_mac_mask = 287932171 [(yext.schemapath) = "/qos/classifiers/classifier/terms/term/conditions/l2/config/destination-mac-mask"]; + oneof ethertype { + openconfig.enums.OpenconfigPacketMatchTypesETHERTYPE ethertype_openconfigpacketmatchtypesethertype = 245699045; + uint64 ethertype_uint64 = 132607809; + } + ywrapper.StringValue source_mac = 658529 [(yext.schemapath) = "/qos/classifiers/classifier/terms/term/conditions/l2/config/source-mac"]; + ywrapper.StringValue source_mac_mask = 49113846 [(yext.schemapath) = "/qos/classifiers/classifier/terms/term/conditions/l2/config/source-mac-mask"]; + } + message Mpls { + ywrapper.UintValue traffic_class = 292059538 [(yext.schemapath) = "/qos/classifiers/classifier/terms/term/conditions/mpls/config/traffic-class"]; + } + message Transport { + enum DestinationPort { + DESTINATIONPORT_UNSET = 0; + DESTINATIONPORT_ANY = 1 [(yext.yang_name) = "ANY"]; + } + enum SourcePort { + SOURCEPORT_UNSET = 0; + SOURCEPORT_ANY = 1 [(yext.yang_name) = "ANY"]; + } + oneof destination_port { + DestinationPort destination_port_destinationport = 61984185; + string destination_port_string = 43341491; + uint64 destination_port_uint64 = 296926614; + } + oneof source_port { + SourcePort source_port_sourceport = 169477687; + string source_port_string = 342703790; + uint64 source_port_uint64 = 278063023; + } + repeated openconfig.enums.OpenconfigPacketMatchTypesTCPFLAGS tcp_flags = 82538752 [(yext.schemapath) = "/qos/classifiers/classifier/terms/term/conditions/transport/config/tcp-flags"]; + } + Ipv4 ipv4 = 10035435 [(yext.schemapath) = "/qos/classifiers/classifier/terms/term/conditions/ipv4"]; + Ipv6 ipv6 = 10035433 [(yext.schemapath) = "/qos/classifiers/classifier/terms/term/conditions/ipv6"]; + L2 l2 = 363202488 [(yext.schemapath) = "/qos/classifiers/classifier/terms/term/conditions/l2"]; + Mpls mpls = 259157330 [(yext.schemapath) = "/qos/classifiers/classifier/terms/term/conditions/mpls"]; + Transport transport = 396236957 [(yext.schemapath) = "/qos/classifiers/classifier/terms/term/conditions/transport"]; + } + Actions actions = 288444670 [(yext.schemapath) = "/qos/classifiers/classifier/terms/term/actions"]; + Conditions conditions = 14705347 [(yext.schemapath) = "/qos/classifiers/classifier/terms/term/conditions"]; + } + message TermKey { + string id = 1 [(yext.schemapath) = "/qos/classifiers/classifier/terms/term/config/id|/qos/classifiers/classifier/terms/term/id"]; + Term term = 2; + } + enum Type { + TYPE_UNSET = 0; + TYPE_IPV4 = 1 [(yext.yang_name) = "IPV4"]; + TYPE_IPV6 = 2 [(yext.yang_name) = "IPV6"]; + TYPE_MPLS = 3 [(yext.yang_name) = "MPLS"]; + TYPE_ETHERNET = 4 [(yext.yang_name) = "ETHERNET"]; + } + repeated TermKey term = 74659894 [(yext.schemapath) = "/qos/classifiers/classifier/terms/term"]; + Type type = 422459117 [(yext.schemapath) = "/qos/classifiers/classifier/config/type"]; + } + message ClassifierKey { + string name = 1 [(yext.schemapath) = "/qos/classifiers/classifier/config/name|/qos/classifiers/classifier/name"]; + Classifier classifier = 2; + } + message ForwardingGroup { + ywrapper.UintValue fabric_priority = 199494503 [(yext.schemapath) = "/qos/forwarding-groups/forwarding-group/config/fabric-priority"]; + ywrapper.StringValue output_queue = 22359152 [(yext.schemapath) = "/qos/forwarding-groups/forwarding-group/config/output-queue"]; + } + message ForwardingGroupKey { + string name = 1 [(yext.schemapath) = "/qos/forwarding-groups/forwarding-group/config/name|/qos/forwarding-groups/forwarding-group/name"]; + ForwardingGroup forwarding_group = 2; + } + message Interface { + message Input { + message Classifier { + message Term { + ywrapper.UintValue matched_octets = 188335353 [(yext.schemapath) = "/qos/interfaces/interface/input/classifers/classifier/terms/term/state/matched-octets"]; + ywrapper.UintValue matched_packets = 437259876 [(yext.schemapath) = "/qos/interfaces/interface/input/classifers/classifier/terms/term/state/matched-packets"]; + } + message TermKey { + string id = 1 [(yext.schemapath) = "/qos/interfaces/interface/input/classifers/classifier/terms/term/config/id|/qos/interfaces/interface/input/classifers/classifier/terms/term/id"]; + Term term = 2; + } + ywrapper.StringValue name = 147745567 [(yext.schemapath) = "/qos/interfaces/interface/input/classifers/classifier/config/name"]; + repeated TermKey term = 256315543 [(yext.schemapath) = "/qos/interfaces/interface/input/classifers/classifier/terms/term"]; + } + message ClassifierKey { + enum Type { + TYPE_UNSET = 0; + TYPE_IPV4 = 5 [(yext.yang_name) = "IPV4"]; + TYPE_IPV6 = 7 [(yext.yang_name) = "IPV6"]; + TYPE_MPLS = 8 [(yext.yang_name) = "MPLS"]; + } + Type type = 1 [(yext.schemapath) = "/qos/interfaces/interface/input/classifers/classifier/config/type|/qos/interfaces/interface/input/classifers/classifier/type"]; + Classifier classifier = 2; + } + message Queue { + ywrapper.UintValue avg_queue_len = 357067202 [(yext.schemapath) = "/qos/interfaces/interface/input/queues/queue/state/avg-queue-len"]; + ywrapper.UintValue dropped_pkts = 530366041 [(yext.schemapath) = "/qos/interfaces/interface/input/queues/queue/state/dropped-pkts"]; + ywrapper.UintValue id = 215343265 [(yext.schemapath) = "/qos/interfaces/interface/input/queues/queue/state/id"]; + ywrapper.UintValue max_queue_len = 535584496 [(yext.schemapath) = "/qos/interfaces/interface/input/queues/queue/state/max-queue-len"]; + ywrapper.UintValue transmit_octets = 237910979 [(yext.schemapath) = "/qos/interfaces/interface/input/queues/queue/state/transmit-octets"]; + ywrapper.UintValue transmit_pkts = 368710075 [(yext.schemapath) = "/qos/interfaces/interface/input/queues/queue/state/transmit-pkts"]; + } + message QueueKey { + string name = 1 [(yext.schemapath) = "/qos/interfaces/interface/input/queues/queue/config/name|/qos/interfaces/interface/input/queues/queue/name"]; + Queue queue = 2; + } + message SchedulerPolicy { + message Scheduler { + ywrapper.UintValue conforming_octets = 204398478 [(yext.schemapath) = "/qos/interfaces/interface/input/scheduler-policy/schedulers/scheduler/state/conforming-octets"]; + ywrapper.UintValue conforming_pkts = 395467958 [(yext.schemapath) = "/qos/interfaces/interface/input/scheduler-policy/schedulers/scheduler/state/conforming-pkts"]; + ywrapper.UintValue exceeding_octets = 22590706 [(yext.schemapath) = "/qos/interfaces/interface/input/scheduler-policy/schedulers/scheduler/state/exceeding-octets"]; + ywrapper.UintValue exceeding_pkts = 80265874 [(yext.schemapath) = "/qos/interfaces/interface/input/scheduler-policy/schedulers/scheduler/state/exceeding-pkts"]; + ywrapper.UintValue violating_octets = 419767763 [(yext.schemapath) = "/qos/interfaces/interface/input/scheduler-policy/schedulers/scheduler/state/violating-octets"]; + ywrapper.UintValue violating_pkts = 174860491 [(yext.schemapath) = "/qos/interfaces/interface/input/scheduler-policy/schedulers/scheduler/state/violating-pkts"]; + } + message SchedulerKey { + uint64 sequence = 1 [(yext.schemapath) = "/qos/interfaces/interface/input/scheduler-policy/schedulers/scheduler/state/sequence|/qos/interfaces/interface/input/scheduler-policy/schedulers/scheduler/sequence"]; + Scheduler scheduler = 2; + } + ywrapper.StringValue name = 5527674 [(yext.schemapath) = "/qos/interfaces/interface/input/scheduler-policy/config/name"]; + repeated SchedulerKey scheduler = 306639558 [(yext.schemapath) = "/qos/interfaces/interface/input/scheduler-policy/schedulers/scheduler"]; + } + message VoqInterface { + message Queue { + ywrapper.UintValue avg_queue_len = 370597120 [(yext.schemapath) = "/qos/interfaces/interface/input/virtual-output-queues/voq-interface/queues/queue/state/avg-queue-len"]; + ywrapper.UintValue dropped_pkts = 300610831 [(yext.schemapath) = "/qos/interfaces/interface/input/virtual-output-queues/voq-interface/queues/queue/state/dropped-pkts"]; + ywrapper.UintValue max_queue_len = 489510182 [(yext.schemapath) = "/qos/interfaces/interface/input/virtual-output-queues/voq-interface/queues/queue/state/max-queue-len"]; + ywrapper.UintValue transmit_octets = 19609109 [(yext.schemapath) = "/qos/interfaces/interface/input/virtual-output-queues/voq-interface/queues/queue/state/transmit-octets"]; + ywrapper.UintValue transmit_pkts = 265927841 [(yext.schemapath) = "/qos/interfaces/interface/input/virtual-output-queues/voq-interface/queues/queue/state/transmit-pkts"]; + } + message QueueKey { + string name = 1 [(yext.schemapath) = "/qos/interfaces/interface/input/virtual-output-queues/voq-interface/queues/queue/config/name|/qos/interfaces/interface/input/virtual-output-queues/voq-interface/queues/queue/name"]; + Queue queue = 2; + } + repeated QueueKey queue = 80000787 [(yext.schemapath) = "/qos/interfaces/interface/input/virtual-output-queues/voq-interface/queues/queue"]; + } + message VoqInterfaceKey { + string name = 1 [(yext.schemapath) = "/qos/interfaces/interface/input/virtual-output-queues/voq-interface/config/name|/qos/interfaces/interface/input/virtual-output-queues/voq-interface/name"]; + VoqInterface voq_interface = 2; + } + repeated ClassifierKey classifier = 140629686 [(yext.schemapath) = "/qos/interfaces/interface/input/classifers/classifier"]; + repeated QueueKey queue = 103221525 [(yext.schemapath) = "/qos/interfaces/interface/input/queues/queue"]; + SchedulerPolicy scheduler_policy = 391585903 [(yext.schemapath) = "/qos/interfaces/interface/input/scheduler-policy"]; + repeated VoqInterfaceKey voq_interface = 134149572 [(yext.schemapath) = "/qos/interfaces/interface/input/virtual-output-queues/voq-interface"]; + } + message InterfaceRef { + ywrapper.StringValue interface = 31011128 [(yext.schemapath) = "/qos/interfaces/interface/interface-ref/config/interface"]; + ywrapper.UintValue subinterface = 407353336 [(yext.schemapath) = "/qos/interfaces/interface/interface-ref/config/subinterface"]; + } + message Output { + message Classifier { + message Term { + ywrapper.UintValue matched_octets = 525483634 [(yext.schemapath) = "/qos/interfaces/interface/output/classifers/classifier/terms/term/state/matched-octets"]; + ywrapper.UintValue matched_packets = 507671601 [(yext.schemapath) = "/qos/interfaces/interface/output/classifers/classifier/terms/term/state/matched-packets"]; + } + message TermKey { + string id = 1 [(yext.schemapath) = "/qos/interfaces/interface/output/classifers/classifier/terms/term/config/id|/qos/interfaces/interface/output/classifers/classifier/terms/term/id"]; + Term term = 2; + } + ywrapper.StringValue name = 273984944 [(yext.schemapath) = "/qos/interfaces/interface/output/classifers/classifier/config/name"]; + repeated TermKey term = 132412642 [(yext.schemapath) = "/qos/interfaces/interface/output/classifers/classifier/terms/term"]; + } + message ClassifierKey { + enum Type { + TYPE_UNSET = 0; + TYPE_IPV4 = 5 [(yext.yang_name) = "IPV4"]; + TYPE_IPV6 = 7 [(yext.yang_name) = "IPV6"]; + TYPE_MPLS = 8 [(yext.yang_name) = "MPLS"]; + } + Type type = 1 [(yext.schemapath) = "/qos/interfaces/interface/output/classifers/classifier/config/type|/qos/interfaces/interface/output/classifers/classifier/type"]; + Classifier classifier = 2; + } + message InterfaceRef { + ywrapper.StringValue interface = 351351714 [(yext.schemapath) = "/qos/interfaces/interface/output/interface-ref/config/interface"]; + ywrapper.UintValue subinterface = 18610174 [(yext.schemapath) = "/qos/interfaces/interface/output/interface-ref/config/subinterface"]; + } + message Queue { + ywrapper.UintValue avg_queue_len = 497534235 [(yext.schemapath) = "/qos/interfaces/interface/output/queues/queue/state/avg-queue-len"]; + ywrapper.UintValue dropped_pkts = 358084770 [(yext.schemapath) = "/qos/interfaces/interface/output/queues/queue/state/dropped-pkts"]; + ywrapper.UintValue id = 441116470 [(yext.schemapath) = "/qos/interfaces/interface/output/queues/queue/state/id"]; + ywrapper.UintValue max_queue_len = 509845137 [(yext.schemapath) = "/qos/interfaces/interface/output/queues/queue/state/max-queue-len"]; + ywrapper.UintValue transmit_octets = 117378910 [(yext.schemapath) = "/qos/interfaces/interface/output/queues/queue/state/transmit-octets"]; + ywrapper.UintValue transmit_pkts = 20090310 [(yext.schemapath) = "/qos/interfaces/interface/output/queues/queue/state/transmit-pkts"]; + } + message QueueKey { + string name = 1 [(yext.schemapath) = "/qos/interfaces/interface/output/queues/queue/config/name|/qos/interfaces/interface/output/queues/queue/name"]; + Queue queue = 2; + } + message SchedulerPolicy { + message Scheduler { + ywrapper.UintValue conforming_octets = 190363557 [(yext.schemapath) = "/qos/interfaces/interface/output/scheduler-policy/schedulers/scheduler/state/conforming-octets"]; + ywrapper.UintValue conforming_pkts = 384889393 [(yext.schemapath) = "/qos/interfaces/interface/output/scheduler-policy/schedulers/scheduler/state/conforming-pkts"]; + ywrapper.UintValue exceeding_octets = 127842319 [(yext.schemapath) = "/qos/interfaces/interface/output/scheduler-policy/schedulers/scheduler/state/exceeding-octets"]; + ywrapper.UintValue exceeding_pkts = 174504655 [(yext.schemapath) = "/qos/interfaces/interface/output/scheduler-policy/schedulers/scheduler/state/exceeding-pkts"]; + ywrapper.UintValue violating_octets = 334250126 [(yext.schemapath) = "/qos/interfaces/interface/output/scheduler-policy/schedulers/scheduler/state/violating-octets"]; + ywrapper.UintValue violating_pkts = 380540342 [(yext.schemapath) = "/qos/interfaces/interface/output/scheduler-policy/schedulers/scheduler/state/violating-pkts"]; + } + message SchedulerKey { + uint64 sequence = 1 [(yext.schemapath) = "/qos/interfaces/interface/output/scheduler-policy/schedulers/scheduler/state/sequence|/qos/interfaces/interface/output/scheduler-policy/schedulers/scheduler/sequence"]; + Scheduler scheduler = 2; + } + ywrapper.StringValue name = 32047975 [(yext.schemapath) = "/qos/interfaces/interface/output/scheduler-policy/config/name"]; + repeated SchedulerKey scheduler = 208885833 [(yext.schemapath) = "/qos/interfaces/interface/output/scheduler-policy/schedulers/scheduler"]; + } + repeated ClassifierKey classifier = 531213741 [(yext.schemapath) = "/qos/interfaces/interface/output/classifers/classifier"]; + InterfaceRef interface_ref = 13944721 [(yext.schemapath) = "/qos/interfaces/interface/output/interface-ref"]; + repeated QueueKey queue = 316768612 [(yext.schemapath) = "/qos/interfaces/interface/output/queues/queue"]; + SchedulerPolicy scheduler_policy = 345632622 [(yext.schemapath) = "/qos/interfaces/interface/output/scheduler-policy"]; + } + Input input = 185281278 [(yext.schemapath) = "/qos/interfaces/interface/input"]; + InterfaceRef interface_ref = 340560111 [(yext.schemapath) = "/qos/interfaces/interface/interface-ref"]; + Output output = 494792021 [(yext.schemapath) = "/qos/interfaces/interface/output"]; + } + message InterfaceKey { + string interface_id = 1 [(yext.schemapath) = "/qos/interfaces/interface/config/interface-id|/qos/interfaces/interface/interface-id"]; + Interface interface = 2; + } + message Queue { + message Red { + ywrapper.UintValue maxth = 77750307 [(yext.schemapath) = "/qos/queues/queue/red/config/maxth"]; + ywrapper.UintValue minth = 301751197 [(yext.schemapath) = "/qos/queues/queue/red/config/minth"]; + } + message Wred { + } + ywrapper.UintValue id = 332418476 [(yext.schemapath) = "/qos/queues/queue/config/id"]; + openconfig.enums.OpenconfigQosTypesQOSQUEUETYPE queue_type = 351938521 [(yext.schemapath) = "/qos/queues/queue/config/queue-type"]; + Red red = 36543379 [(yext.schemapath) = "/qos/queues/queue/red"]; + Wred wred = 285364058 [(yext.schemapath) = "/qos/queues/queue/wred"]; + } + message QueueKey { + string name = 1 [(yext.schemapath) = "/qos/queues/queue/config/name|/qos/queues/queue/name"]; + Queue queue = 2; + } + message SchedulerPolicy { + message Scheduler { + message Input { + enum InputType { + INPUTTYPE_UNSET = 0; + INPUTTYPE_QUEUE = 1 [(yext.yang_name) = "QUEUE"]; + INPUTTYPE_IN_PROFILE = 2 [(yext.yang_name) = "IN_PROFILE"]; + INPUTTYPE_OUT_PROFILE = 3 [(yext.yang_name) = "OUT_PROFILE"]; + } + InputType input_type = 323155511 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/config/input-type"]; + ywrapper.StringValue queue = 442686099 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/config/queue"]; + ywrapper.UintValue weight = 396218658 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/config/weight"]; + } + message InputKey { + string id = 1 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/config/id|/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input/id"]; + Input input = 2; + } + message OneRateTwoColor { + message ConformAction { + ywrapper.UintValue set_dot1p = 347963663 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/one-rate-two-color/conform-action/config/set-dot1p"]; + ywrapper.UintValue set_dscp = 274036909 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/one-rate-two-color/conform-action/config/set-dscp"]; + ywrapper.UintValue set_mpls_tc = 407069875 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/one-rate-two-color/conform-action/config/set-mpls-tc"]; + } + message ExceedAction { + ywrapper.BoolValue drop = 131419485 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/one-rate-two-color/exceed-action/config/drop"]; + ywrapper.UintValue set_dot1p = 431798715 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/one-rate-two-color/exceed-action/config/set-dot1p"]; + ywrapper.UintValue set_dscp = 70544401 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/one-rate-two-color/exceed-action/config/set-dscp"]; + ywrapper.UintValue set_mpls_tc = 156774487 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/one-rate-two-color/exceed-action/config/set-mpls-tc"]; + } + ywrapper.UintValue bc = 100183769 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/one-rate-two-color/config/bc"]; + ywrapper.UintValue cir = 494749918 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/one-rate-two-color/config/cir"]; + ywrapper.UintValue cir_pct = 315109376 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/one-rate-two-color/config/cir-pct"]; + ywrapper.UintValue cir_pct_remaining = 206933707 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/one-rate-two-color/config/cir-pct-remaining"]; + ConformAction conform_action = 29149902 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/one-rate-two-color/conform-action"]; + ExceedAction exceed_action = 297338034 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/one-rate-two-color/exceed-action"]; + ywrapper.UintValue max_queue_depth_bytes = 279197854 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/one-rate-two-color/config/max-queue-depth-bytes"]; + ywrapper.UintValue max_queue_depth_packets = 38247640 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/one-rate-two-color/config/max-queue-depth-packets"]; + ywrapper.UintValue max_queue_depth_percent = 466868204 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/one-rate-two-color/config/max-queue-depth-percent"]; + openconfig.enums.OpenconfigQosQueueBehavior queuing_behavior = 78239583 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/one-rate-two-color/config/queuing-behavior"]; + } + message Output { + enum OutputType { + OUTPUTTYPE_UNSET = 0; + OUTPUTTYPE_SCHEDULER = 1 [(yext.yang_name) = "SCHEDULER"]; + OUTPUTTYPE_FWD_GROUP = 2 [(yext.yang_name) = "FWD_GROUP"]; + OUTPUTTYPE_INTERFACE = 3 [(yext.yang_name) = "INTERFACE"]; + } + ywrapper.StringValue child_scheduler = 101554311 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/output/config/child-scheduler"]; + ywrapper.StringValue output_fwd_group = 283910326 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/output/config/output-fwd-group"]; + OutputType output_type = 485674633 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/output/config/output-type"]; + } + message TwoRateThreeColor { + message ConformAction { + ywrapper.UintValue set_dot1p = 106933487 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/two-rate-three-color/conform-action/config/set-dot1p"]; + ywrapper.UintValue set_dscp = 410653965 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/two-rate-three-color/conform-action/config/set-dscp"]; + ywrapper.UintValue set_mpls_tc = 301290899 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/two-rate-three-color/conform-action/config/set-mpls-tc"]; + } + message ExceedAction { + ywrapper.BoolValue drop = 299899453 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/two-rate-three-color/exceed-action/config/drop"]; + ywrapper.UintValue set_dot1p = 143535771 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/two-rate-three-color/exceed-action/config/set-dot1p"]; + ywrapper.UintValue set_dscp = 530765681 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/two-rate-three-color/exceed-action/config/set-dscp"]; + ywrapper.UintValue set_mpls_tc = 435204023 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/two-rate-three-color/exceed-action/config/set-mpls-tc"]; + } + message ViolateAction { + ywrapper.BoolValue drop = 230160201 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/two-rate-three-color/violate-action/config/drop"]; + ywrapper.UintValue set_dot1p = 433219903 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/two-rate-three-color/violate-action/config/set-dot1p"]; + ywrapper.UintValue set_dscp = 77658205 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/two-rate-three-color/violate-action/config/set-dscp"]; + ywrapper.UintValue set_mpls_tc = 446571619 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/two-rate-three-color/violate-action/config/set-mpls-tc"]; + } + ywrapper.UintValue bc = 488133689 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/two-rate-three-color/config/bc"]; + ywrapper.UintValue be = 488133695 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/two-rate-three-color/config/be"]; + ywrapper.UintValue cir = 72261310 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/two-rate-three-color/config/cir"]; + ywrapper.UintValue cir_pct = 148455776 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/two-rate-three-color/config/cir-pct"]; + ywrapper.UintValue cir_pct_remaining = 426598443 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/two-rate-three-color/config/cir-pct-remaining"]; + ConformAction conform_action = 482658734 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/two-rate-three-color/conform-action"]; + ExceedAction exceed_action = 447571730 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/two-rate-three-color/exceed-action"]; + ywrapper.UintValue pir = 69260261 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/two-rate-three-color/config/pir"]; + ywrapper.UintValue pir_pct = 115916567 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/two-rate-three-color/config/pir-pct"]; + ywrapper.UintValue pir_pct_remaining = 517108460 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/two-rate-three-color/config/pir-pct-remaining"]; + ViolateAction violate_action = 110529342 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/two-rate-three-color/violate-action"]; + } + enum Priority { + PRIORITY_UNSET = 0; + PRIORITY_STRICT = 1 [(yext.yang_name) = "STRICT"]; + } + repeated InputKey input = 224691974 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/inputs/input"]; + OneRateTwoColor one_rate_two_color = 502240564 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/one-rate-two-color"]; + Output output = 46224159 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/output"]; + Priority priority = 116027193 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/config/priority"]; + TwoRateThreeColor two_rate_three_color = 10046740 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/two-rate-three-color"]; + openconfig.enums.OpenconfigQosTypesQOSSCHEDULERTYPE type = 125973545 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/config/type"]; + } + message SchedulerKey { + uint64 sequence = 1 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/config/sequence|/qos/scheduler-policies/scheduler-policy/schedulers/scheduler/sequence"]; + Scheduler scheduler = 2; + } + repeated SchedulerKey scheduler = 494699541 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/schedulers/scheduler"]; + } + message SchedulerPolicyKey { + string name = 1 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy/config/name|/qos/scheduler-policies/scheduler-policy/name"]; + SchedulerPolicy scheduler_policy = 2; + } + repeated ClassifierKey classifier = 281713417 [(yext.schemapath) = "/qos/classifiers/classifier"]; + repeated ForwardingGroupKey forwarding_group = 454859993 [(yext.schemapath) = "/qos/forwarding-groups/forwarding-group"]; + repeated InterfaceKey interface = 178908543 [(yext.schemapath) = "/qos/interfaces/interface"]; + repeated QueueKey queue = 108026875 [(yext.schemapath) = "/qos/queues/queue"]; + repeated SchedulerPolicyKey scheduler_policy = 422526610 [(yext.schemapath) = "/qos/scheduler-policies/scheduler-policy"]; +} + +message System { + message Aaa { + message Accounting { + message AccountingMethodUnion { + openconfig.enums.OpenconfigAaaTypesAAAMETHODTYPE accounting_method_openconfigaaatypesaaamethodtype = 520228688; + string accounting_method_string = 308208143; + } + message Event { + enum Record { + RECORD_UNSET = 0; + RECORD_START_STOP = 1 [(yext.yang_name) = "START_STOP"]; + RECORD_STOP = 2 [(yext.yang_name) = "STOP"]; + } + Record record = 140048324 [(yext.schemapath) = "/system/aaa/accounting/events/event/config/record"]; + } + message EventKey { + openconfig.enums.OpenconfigAaaTypesAAAACCOUNTINGEVENTTYPE event_type = 1 [(yext.schemapath) = "/system/aaa/accounting/events/event/config/event-type|/system/aaa/accounting/events/event/event-type"]; + Event event = 2; + } + repeated AccountingMethodUnion accounting_method = 29748713 [(yext.schemapath) = "/system/aaa/accounting/config/accounting-method"]; + repeated EventKey event = 76913831 [(yext.schemapath) = "/system/aaa/accounting/events/event"]; + } + message Authentication { + message AdminUser { + ywrapper.StringValue admin_password = 17433386 [(yext.schemapath) = "/system/aaa/authentication/admin-user/config/admin-password"]; + ywrapper.StringValue admin_password_hashed = 471791444 [(yext.schemapath) = "/system/aaa/authentication/admin-user/config/admin-password-hashed"]; + ywrapper.StringValue admin_username = 58771374 [(yext.schemapath) = "/system/aaa/authentication/admin-user/state/admin-username"]; + } + message AuthenticationMethodUnion { + openconfig.enums.OpenconfigAaaTypesAAAMETHODTYPE authentication_method_openconfigaaatypesaaamethodtype = 512247800; + string authentication_method_string = 438459495; + } + message User { + ywrapper.StringValue password = 140193929 [(yext.schemapath) = "/system/aaa/authentication/users/user/config/password"]; + ywrapper.StringValue password_hashed = 439845341 [(yext.schemapath) = "/system/aaa/authentication/users/user/config/password-hashed"]; + oneof role { + openconfig.enums.OpenconfigAaaTypesSYSTEMDEFINEDROLES role_openconfigaaatypessystemdefinedroles = 398783100; + string role_string = 284966162; + } + ywrapper.StringValue ssh_key = 372550502 [(yext.schemapath) = "/system/aaa/authentication/users/user/config/ssh-key"]; + } + message UserKey { + string username = 1 [(yext.schemapath) = "/system/aaa/authentication/users/user/config/username|/system/aaa/authentication/users/user/username"]; + User user = 2; + } + AdminUser admin_user = 322829291 [(yext.schemapath) = "/system/aaa/authentication/admin-user"]; + repeated AuthenticationMethodUnion authentication_method = 38969025 [(yext.schemapath) = "/system/aaa/authentication/config/authentication-method"]; + repeated UserKey user = 344997694 [(yext.schemapath) = "/system/aaa/authentication/users/user"]; + } + message Authorization { + message AuthorizationMethodUnion { + openconfig.enums.OpenconfigAaaTypesAAAMETHODTYPE authorization_method_openconfigaaatypesaaamethodtype = 261320746; + string authorization_method_string = 508375681; + } + message Event { + } + message EventKey { + openconfig.enums.OpenconfigAaaTypesAAAAUTHORIZATIONEVENTTYPE event_type = 1 [(yext.schemapath) = "/system/aaa/authorization/events/event/config/event-type|/system/aaa/authorization/events/event/event-type"]; + Event event = 2; + } + repeated AuthorizationMethodUnion authorization_method = 399020027 [(yext.schemapath) = "/system/aaa/authorization/config/authorization-method"]; + repeated EventKey event = 517393149 [(yext.schemapath) = "/system/aaa/authorization/events/event"]; + } + message ServerGroup { + message Server { + message Radius { + message Counters { + ywrapper.UintValue access_accepts = 215193910 [(yext.schemapath) = "/system/aaa/server-groups/server-group/servers/server/radius/state/counters/access-accepts"]; + ywrapper.UintValue access_rejects = 25892249 [(yext.schemapath) = "/system/aaa/server-groups/server-group/servers/server/radius/state/counters/access-rejects"]; + ywrapper.UintValue retried_access_requests = 400682451 [(yext.schemapath) = "/system/aaa/server-groups/server-group/servers/server/radius/state/counters/retried-access-requests"]; + ywrapper.UintValue timeout_access_requests = 24602675 [(yext.schemapath) = "/system/aaa/server-groups/server-group/servers/server/radius/state/counters/timeout-access-requests"]; + } + ywrapper.UintValue acct_port = 289040892 [(yext.schemapath) = "/system/aaa/server-groups/server-group/servers/server/radius/config/acct-port"]; + ywrapper.UintValue auth_port = 298939869 [(yext.schemapath) = "/system/aaa/server-groups/server-group/servers/server/radius/config/auth-port"]; + Counters counters = 38611033 [(yext.schemapath) = "/system/aaa/server-groups/server-group/servers/server/radius/state/counters"]; + ywrapper.UintValue retransmit_attempts = 418545541 [(yext.schemapath) = "/system/aaa/server-groups/server-group/servers/server/radius/config/retransmit-attempts"]; + ywrapper.StringValue secret_key = 91269351 [(yext.schemapath) = "/system/aaa/server-groups/server-group/servers/server/radius/config/secret-key"]; + ywrapper.StringValue source_address = 529894017 [(yext.schemapath) = "/system/aaa/server-groups/server-group/servers/server/radius/config/source-address"]; + } + message Tacacs { + ywrapper.UintValue port = 52133369 [(yext.schemapath) = "/system/aaa/server-groups/server-group/servers/server/tacacs/config/port"]; + ywrapper.StringValue secret_key = 390882862 [(yext.schemapath) = "/system/aaa/server-groups/server-group/servers/server/tacacs/config/secret-key"]; + ywrapper.StringValue source_address = 165060088 [(yext.schemapath) = "/system/aaa/server-groups/server-group/servers/server/tacacs/config/source-address"]; + } + ywrapper.UintValue connection_aborts = 125162735 [(yext.schemapath) = "/system/aaa/server-groups/server-group/servers/server/state/connection-aborts"]; + ywrapper.UintValue connection_closes = 161631333 [(yext.schemapath) = "/system/aaa/server-groups/server-group/servers/server/state/connection-closes"]; + ywrapper.UintValue connection_failures = 113553227 [(yext.schemapath) = "/system/aaa/server-groups/server-group/servers/server/state/connection-failures"]; + ywrapper.UintValue connection_opens = 74843905 [(yext.schemapath) = "/system/aaa/server-groups/server-group/servers/server/state/connection-opens"]; + ywrapper.UintValue connection_timeouts = 408747310 [(yext.schemapath) = "/system/aaa/server-groups/server-group/servers/server/state/connection-timeouts"]; + ywrapper.UintValue errors_received = 531130208 [(yext.schemapath) = "/system/aaa/server-groups/server-group/servers/server/state/errors-received"]; + ywrapper.UintValue messages_received = 183175971 [(yext.schemapath) = "/system/aaa/server-groups/server-group/servers/server/state/messages-received"]; + ywrapper.UintValue messages_sent = 461917808 [(yext.schemapath) = "/system/aaa/server-groups/server-group/servers/server/state/messages-sent"]; + ywrapper.StringValue name = 197201537 [(yext.schemapath) = "/system/aaa/server-groups/server-group/servers/server/config/name"]; + Radius radius = 184878025 [(yext.schemapath) = "/system/aaa/server-groups/server-group/servers/server/radius"]; + Tacacs tacacs = 273909248 [(yext.schemapath) = "/system/aaa/server-groups/server-group/servers/server/tacacs"]; + ywrapper.UintValue timeout = 308122545 [(yext.schemapath) = "/system/aaa/server-groups/server-group/servers/server/config/timeout"]; + } + message ServerKey { + string address = 1 [(yext.schemapath) = "/system/aaa/server-groups/server-group/servers/server/config/address|/system/aaa/server-groups/server-group/servers/server/address"]; + Server server = 2; + } + repeated ServerKey server = 253859376 [(yext.schemapath) = "/system/aaa/server-groups/server-group/servers/server"]; + openconfig.enums.OpenconfigAaaTypesAAASERVERTYPE type = 70733999 [(yext.schemapath) = "/system/aaa/server-groups/server-group/config/type"]; + } + message ServerGroupKey { + string name = 1 [(yext.schemapath) = "/system/aaa/server-groups/server-group/config/name|/system/aaa/server-groups/server-group/name"]; + ServerGroup server_group = 2; + } + Accounting accounting = 175231094 [(yext.schemapath) = "/system/aaa/accounting"]; + Authentication authentication = 520430581 [(yext.schemapath) = "/system/aaa/authentication"]; + Authorization authorization = 92979796 [(yext.schemapath) = "/system/aaa/authorization"]; + repeated ServerGroupKey server_group = 249960919 [(yext.schemapath) = "/system/aaa/server-groups/server-group"]; + } + message Alarm { + ywrapper.StringValue resource = 290470824 [(yext.schemapath) = "/system/alarms/alarm/state/resource"]; + openconfig.enums.OpenconfigAlarmTypesOPENCONFIGALARMSEVERITY severity = 464665929 [(yext.schemapath) = "/system/alarms/alarm/state/severity"]; + ywrapper.StringValue text = 19701185 [(yext.schemapath) = "/system/alarms/alarm/state/text"]; + ywrapper.UintValue time_created = 258054456 [(yext.schemapath) = "/system/alarms/alarm/state/time-created"]; + oneof type_id { + openconfig.enums.OpenconfigAlarmTypesOPENCONFIGALARMTYPEID type_id_openconfigalarmtypesopenconfigalarmtypeid = 375918181; + string type_id_string = 387256722; + } + } + message AlarmKey { + string id = 1 [(yext.schemapath) = "/system/alarms/alarm/state/id|/system/alarms/alarm/id"]; + Alarm alarm = 2; + } + message Clock { + ywrapper.StringValue timezone_name = 100228070 [(yext.schemapath) = "/system/clock/config/timezone-name"]; + } + message Cpu { + message HardwareInterrupt { + ywrapper.UintValue avg = 422453613 [(yext.schemapath) = "/system/cpus/cpu/state/hardware-interrupt/avg"]; + ywrapper.UintValue instant = 196083674 [(yext.schemapath) = "/system/cpus/cpu/state/hardware-interrupt/instant"]; + ywrapper.UintValue interval = 343471148 [(yext.schemapath) = "/system/cpus/cpu/state/hardware-interrupt/interval"]; + ywrapper.UintValue max = 203756111 [(yext.schemapath) = "/system/cpus/cpu/state/hardware-interrupt/max"]; + ywrapper.UintValue max_time = 12201747 [(yext.schemapath) = "/system/cpus/cpu/state/hardware-interrupt/max-time"]; + ywrapper.UintValue min = 69535217 [(yext.schemapath) = "/system/cpus/cpu/state/hardware-interrupt/min"]; + ywrapper.UintValue min_time = 511436553 [(yext.schemapath) = "/system/cpus/cpu/state/hardware-interrupt/min-time"]; + } + message Idle { + ywrapper.UintValue avg = 124715605 [(yext.schemapath) = "/system/cpus/cpu/state/idle/avg"]; + ywrapper.UintValue instant = 230199506 [(yext.schemapath) = "/system/cpus/cpu/state/idle/instant"]; + ywrapper.UintValue interval = 496096436 [(yext.schemapath) = "/system/cpus/cpu/state/idle/interval"]; + ywrapper.UintValue max = 445461847 [(yext.schemapath) = "/system/cpus/cpu/state/idle/max"]; + ywrapper.UintValue max_time = 503768027 [(yext.schemapath) = "/system/cpus/cpu/state/idle/max-time"]; + ywrapper.UintValue min = 42811817 [(yext.schemapath) = "/system/cpus/cpu/state/idle/min"]; + ywrapper.UintValue min_time = 265827073 [(yext.schemapath) = "/system/cpus/cpu/state/idle/min-time"]; + } + message Kernel { + ywrapper.UintValue avg = 253885460 [(yext.schemapath) = "/system/cpus/cpu/state/kernel/avg"]; + ywrapper.UintValue instant = 168068719 [(yext.schemapath) = "/system/cpus/cpu/state/kernel/instant"]; + ywrapper.UintValue interval = 444985103 [(yext.schemapath) = "/system/cpus/cpu/state/kernel/interval"]; + ywrapper.UintValue max = 470023086 [(yext.schemapath) = "/system/cpus/cpu/state/kernel/max"]; + ywrapper.UintValue max_time = 329601932 [(yext.schemapath) = "/system/cpus/cpu/state/kernel/max-time"]; + ywrapper.UintValue min = 67373056 [(yext.schemapath) = "/system/cpus/cpu/state/kernel/min"]; + ywrapper.UintValue min_time = 235683554 [(yext.schemapath) = "/system/cpus/cpu/state/kernel/min-time"]; + } + message Nice { + ywrapper.UintValue avg = 329385588 [(yext.schemapath) = "/system/cpus/cpu/state/nice/avg"]; + ywrapper.UintValue instant = 453505999 [(yext.schemapath) = "/system/cpus/cpu/state/nice/instant"]; + ywrapper.UintValue interval = 48963055 [(yext.schemapath) = "/system/cpus/cpu/state/nice/interval"]; + ywrapper.UintValue max = 8755214 [(yext.schemapath) = "/system/cpus/cpu/state/nice/max"]; + ywrapper.UintValue max_time = 136550124 [(yext.schemapath) = "/system/cpus/cpu/state/nice/max-time"]; + ywrapper.UintValue min = 142976352 [(yext.schemapath) = "/system/cpus/cpu/state/nice/min"]; + ywrapper.UintValue min_time = 330377410 [(yext.schemapath) = "/system/cpus/cpu/state/nice/min-time"]; + } + message SoftwareInterrupt { + ywrapper.UintValue avg = 458756582 [(yext.schemapath) = "/system/cpus/cpu/state/software-interrupt/avg"]; + ywrapper.UintValue instant = 162043877 [(yext.schemapath) = "/system/cpus/cpu/state/software-interrupt/instant"]; + ywrapper.UintValue interval = 336602009 [(yext.schemapath) = "/system/cpus/cpu/state/software-interrupt/interval"]; + ywrapper.UintValue max = 71002944 [(yext.schemapath) = "/system/cpus/cpu/state/software-interrupt/max"]; + ywrapper.UintValue max_time = 94425762 [(yext.schemapath) = "/system/cpus/cpu/state/software-interrupt/max-time"]; + ywrapper.UintValue min = 473652942 [(yext.schemapath) = "/system/cpus/cpu/state/software-interrupt/min"]; + ywrapper.UintValue min_time = 160385836 [(yext.schemapath) = "/system/cpus/cpu/state/software-interrupt/min-time"]; + } + message Total { + ywrapper.UintValue avg = 132944461 [(yext.schemapath) = "/system/cpus/cpu/state/total/avg"]; + ywrapper.UintValue instant = 386144186 [(yext.schemapath) = "/system/cpus/cpu/state/total/instant"]; + ywrapper.UintValue interval = 496728204 [(yext.schemapath) = "/system/cpus/cpu/state/total/interval"]; + ywrapper.UintValue max = 451014703 [(yext.schemapath) = "/system/cpus/cpu/state/total/max"]; + ywrapper.UintValue max_time = 333757299 [(yext.schemapath) = "/system/cpus/cpu/state/total/max-time"]; + ywrapper.UintValue min = 316793809 [(yext.schemapath) = "/system/cpus/cpu/state/total/min"]; + ywrapper.UintValue min_time = 130415593 [(yext.schemapath) = "/system/cpus/cpu/state/total/min-time"]; + } + message User { + ywrapper.UintValue avg = 360451894 [(yext.schemapath) = "/system/cpus/cpu/state/user/avg"]; + ywrapper.UintValue instant = 3525685 [(yext.schemapath) = "/system/cpus/cpu/state/user/instant"]; + ywrapper.UintValue interval = 14529097 [(yext.schemapath) = "/system/cpus/cpu/state/user/interval"]; + ywrapper.UintValue max = 509582096 [(yext.schemapath) = "/system/cpus/cpu/state/user/max"]; + ywrapper.UintValue max_time = 31166770 [(yext.schemapath) = "/system/cpus/cpu/state/user/max-time"]; + ywrapper.UintValue min = 375361214 [(yext.schemapath) = "/system/cpus/cpu/state/user/min"]; + ywrapper.UintValue min_time = 506696348 [(yext.schemapath) = "/system/cpus/cpu/state/user/min-time"]; + } + message Wait { + ywrapper.UintValue avg = 461699088 [(yext.schemapath) = "/system/cpus/cpu/state/wait/avg"]; + ywrapper.UintValue instant = 14128043 [(yext.schemapath) = "/system/cpus/cpu/state/wait/instant"]; + ywrapper.UintValue interval = 227652571 [(yext.schemapath) = "/system/cpus/cpu/state/wait/interval"]; + ywrapper.UintValue max = 276556978 [(yext.schemapath) = "/system/cpus/cpu/state/wait/max"]; + ywrapper.UintValue max_time = 71337832 [(yext.schemapath) = "/system/cpus/cpu/state/wait/max-time"]; + ywrapper.UintValue min = 142336092 [(yext.schemapath) = "/system/cpus/cpu/state/wait/min"]; + ywrapper.UintValue min_time = 42140422 [(yext.schemapath) = "/system/cpus/cpu/state/wait/min-time"]; + } + HardwareInterrupt hardware_interrupt = 81518708 [(yext.schemapath) = "/system/cpus/cpu/state/hardware-interrupt"]; + Idle idle = 511801900 [(yext.schemapath) = "/system/cpus/cpu/state/idle"]; + Kernel kernel = 23883017 [(yext.schemapath) = "/system/cpus/cpu/state/kernel"]; + Nice nice = 74777833 [(yext.schemapath) = "/system/cpus/cpu/state/nice"]; + SoftwareInterrupt software_interrupt = 350532999 [(yext.schemapath) = "/system/cpus/cpu/state/software-interrupt"]; + Total total = 497504852 [(yext.schemapath) = "/system/cpus/cpu/state/total"]; + User user = 329002807 [(yext.schemapath) = "/system/cpus/cpu/state/user"]; + Wait wait = 517899549 [(yext.schemapath) = "/system/cpus/cpu/state/wait"]; + } + message CpuKey { + enum Index { + INDEX_UNSET = 0; + INDEX_ALL = 1 [(yext.yang_name) = "ALL"]; + } + oneof index { + Index index_index = 408896491; + uint64 index_uint64 = 247396011; + } + Cpu cpu = 2; + } + message Dns { + message HostEntry { + repeated ywrapper.StringValue alias = 202464928 [(yext.schemapath) = "/system/dns/host-entries/host-entry/config/alias"]; + repeated ywrapper.StringValue ipv4_address = 47682642 [(yext.schemapath) = "/system/dns/host-entries/host-entry/config/ipv4-address"]; + repeated ywrapper.StringValue ipv6_address = 89261280 [(yext.schemapath) = "/system/dns/host-entries/host-entry/config/ipv6-address"]; + } + message HostEntryKey { + string hostname = 1 [(yext.schemapath) = "/system/dns/host-entries/host-entry/config/hostname|/system/dns/host-entries/host-entry/hostname"]; + HostEntry host_entry = 2; + } + message Server { + ywrapper.UintValue port = 441306980 [(yext.schemapath) = "/system/dns/servers/server/config/port"]; + } + message ServerKey { + string address = 1 [(yext.schemapath) = "/system/dns/servers/server/config/address|/system/dns/servers/server/address"]; + Server server = 2; + } + repeated HostEntryKey host_entry = 297400348 [(yext.schemapath) = "/system/dns/host-entries/host-entry"]; + repeated ywrapper.StringValue search = 529094948 [(yext.schemapath) = "/system/dns/config/search"]; + repeated ServerKey server = 234465781 [(yext.schemapath) = "/system/dns/servers/server"]; + } + message GrpcServer { + message ListenAddressesUnion { + ListenAddresses listen_addresses_listenaddresses = 443616413; + string listen_addresses_string = 442696493; + } + enum ListenAddresses { + LISTENADDRESSES_UNSET = 0; + LISTENADDRESSES_ANY = 1 [(yext.yang_name) = "ANY"]; + } + ywrapper.StringValue certificate_id = 441121224 [(yext.schemapath) = "/system/grpc-server/config/certificate-id"]; + ywrapper.BoolValue enable = 25007668 [(yext.schemapath) = "/system/grpc-server/config/enable"]; + repeated ListenAddressesUnion listen_addresses = 269758191 [(yext.schemapath) = "/system/grpc-server/config/listen-addresses"]; + ywrapper.BoolValue metadata_authentication = 459595831 [(yext.schemapath) = "/system/grpc-server/config/metadata-authentication"]; + ywrapper.UintValue port = 118468388 [(yext.schemapath) = "/system/grpc-server/config/port"]; + ywrapper.BoolValue transport_security = 161056339 [(yext.schemapath) = "/system/grpc-server/config/transport-security"]; + } + message Logging { + message Console { + message Selector { + } + message SelectorKey { + openconfig.enums.OpenconfigSystemLoggingSYSLOGFACILITY facility = 1 [(yext.schemapath) = "/system/logging/console/selectors/selector/config/facility|/system/logging/console/selectors/selector/facility"]; + openconfig.enums.OpenconfigSystemLoggingSyslogSeverity severity = 2 [(yext.schemapath) = "/system/logging/console/selectors/selector/config/severity|/system/logging/console/selectors/selector/severity"]; + Selector selector = 3; + } + repeated SelectorKey selector = 442447029 [(yext.schemapath) = "/system/logging/console/selectors/selector"]; + } + message RemoteServer { + message Selector { + } + message SelectorKey { + openconfig.enums.OpenconfigSystemLoggingSYSLOGFACILITY facility = 1 [(yext.schemapath) = "/system/logging/remote-servers/remote-server/selectors/selector/config/facility|/system/logging/remote-servers/remote-server/selectors/selector/facility"]; + openconfig.enums.OpenconfigSystemLoggingSyslogSeverity severity = 2 [(yext.schemapath) = "/system/logging/remote-servers/remote-server/selectors/selector/config/severity|/system/logging/remote-servers/remote-server/selectors/selector/severity"]; + Selector selector = 3; + } + ywrapper.UintValue remote_port = 22145415 [(yext.schemapath) = "/system/logging/remote-servers/remote-server/config/remote-port"]; + repeated SelectorKey selector = 300442996 [(yext.schemapath) = "/system/logging/remote-servers/remote-server/selectors/selector"]; + ywrapper.StringValue source_address = 4922255 [(yext.schemapath) = "/system/logging/remote-servers/remote-server/config/source-address"]; + } + message RemoteServerKey { + string host = 1 [(yext.schemapath) = "/system/logging/remote-servers/remote-server/config/host|/system/logging/remote-servers/remote-server/host"]; + RemoteServer remote_server = 2; + } + Console console = 197921220 [(yext.schemapath) = "/system/logging/console"]; + repeated RemoteServerKey remote_server = 157599479 [(yext.schemapath) = "/system/logging/remote-servers/remote-server"]; + } + message Memory { + ywrapper.UintValue physical = 108400520 [(yext.schemapath) = "/system/memory/state/physical"]; + ywrapper.UintValue reserved = 140759447 [(yext.schemapath) = "/system/memory/state/reserved"]; + } + message Messages { + message DebugService { + ywrapper.BoolValue enabled = 255266609 [(yext.schemapath) = "/system/messages/debug-entries/debug-service/config/enabled"]; + } + message DebugServiceKey { + openconfig.enums.OpenconfigMessagesDEBUGSERVICE service = 1 [(yext.schemapath) = "/system/messages/debug-entries/debug-service/config/service|/system/messages/debug-entries/debug-service/service"]; + DebugService debug_service = 2; + } + message Message { + ywrapper.StringValue app_name = 209460747 [(yext.schemapath) = "/system/messages/state/message/app-name"]; + ywrapper.StringValue msg = 224593699 [(yext.schemapath) = "/system/messages/state/message/msg"]; + ywrapper.StringValue msgid = 105587764 [(yext.schemapath) = "/system/messages/state/message/msgid"]; + ywrapper.UintValue priority = 157172736 [(yext.schemapath) = "/system/messages/state/message/priority"]; + ywrapper.StringValue procid = 92046335 [(yext.schemapath) = "/system/messages/state/message/procid"]; + } + repeated DebugServiceKey debug_service = 396463998 [(yext.schemapath) = "/system/messages/debug-entries/debug-service"]; + Message message = 16499629 [(yext.schemapath) = "/system/messages/state/message"]; + openconfig.enums.OpenconfigMessagesSyslogSeverity severity = 77893034 [(yext.schemapath) = "/system/messages/config/severity"]; + } + message Ntp { + message NtpKey { + openconfig.enums.OpenconfigSystemNTPAUTHTYPE key_type = 68795202 [(yext.schemapath) = "/system/ntp/ntp-keys/ntp-key/config/key-type"]; + ywrapper.StringValue key_value = 491993133 [(yext.schemapath) = "/system/ntp/ntp-keys/ntp-key/config/key-value"]; + } + message NtpKeyKey { + uint64 key_id = 1 [(yext.schemapath) = "/system/ntp/ntp-keys/ntp-key/config/key-id|/system/ntp/ntp-keys/ntp-key/key-id"]; + NtpKey ntp_key = 2; + } + message Server { + enum AssociationType { + ASSOCIATIONTYPE_SERVER = 0 [(yext.yang_name) = "SERVER"]; + ASSOCIATIONTYPE_PEER = 2 [(yext.yang_name) = "PEER"]; + ASSOCIATIONTYPE_POOL = 3 [(yext.yang_name) = "POOL"]; + } + AssociationType association_type = 403743446 [(yext.schemapath) = "/system/ntp/servers/server/config/association-type"]; + ywrapper.BoolValue iburst = 520002257 [(yext.schemapath) = "/system/ntp/servers/server/config/iburst"]; + ywrapper.UintValue offset = 2287252 [(yext.schemapath) = "/system/ntp/servers/server/state/offset"]; + ywrapper.UintValue poll_interval = 394021196 [(yext.schemapath) = "/system/ntp/servers/server/state/poll-interval"]; + ywrapper.UintValue port = 23953045 [(yext.schemapath) = "/system/ntp/servers/server/config/port"]; + ywrapper.BoolValue prefer = 63587710 [(yext.schemapath) = "/system/ntp/servers/server/config/prefer"]; + ywrapper.UintValue root_delay = 363692935 [(yext.schemapath) = "/system/ntp/servers/server/state/root-delay"]; + ywrapper.UintValue root_dispersion = 81112484 [(yext.schemapath) = "/system/ntp/servers/server/state/root-dispersion"]; + ywrapper.UintValue stratum = 297803783 [(yext.schemapath) = "/system/ntp/servers/server/state/stratum"]; + ywrapper.UintValue version = 385126824 [(yext.schemapath) = "/system/ntp/servers/server/config/version"]; + } + message ServerKey { + string address = 1 [(yext.schemapath) = "/system/ntp/servers/server/config/address|/system/ntp/servers/server/address"]; + Server server = 2; + } + ywrapper.UintValue auth_mismatch = 264062383 [(yext.schemapath) = "/system/ntp/state/auth-mismatch"]; + ywrapper.BoolValue enable_ntp_auth = 345800954 [(yext.schemapath) = "/system/ntp/config/enable-ntp-auth"]; + ywrapper.BoolValue enabled = 520946078 [(yext.schemapath) = "/system/ntp/config/enabled"]; + repeated NtpKeyKey ntp_key = 265614496 [(yext.schemapath) = "/system/ntp/ntp-keys/ntp-key"]; + ywrapper.StringValue ntp_source_address = 418322460 [(yext.schemapath) = "/system/ntp/config/ntp-source-address"]; + repeated ServerKey server = 453498492 [(yext.schemapath) = "/system/ntp/servers/server"]; + } + message Process { + repeated ywrapper.StringValue args = 136113714 [(yext.schemapath) = "/system/processes/process/state/args"]; + ywrapper.UintValue cpu_usage_system = 221645263 [(yext.schemapath) = "/system/processes/process/state/cpu-usage-system"]; + ywrapper.UintValue cpu_usage_user = 6624253 [(yext.schemapath) = "/system/processes/process/state/cpu-usage-user"]; + ywrapper.UintValue cpu_utilization = 346097790 [(yext.schemapath) = "/system/processes/process/state/cpu-utilization"]; + ywrapper.UintValue memory_usage = 70248886 [(yext.schemapath) = "/system/processes/process/state/memory-usage"]; + ywrapper.UintValue memory_utilization = 283685455 [(yext.schemapath) = "/system/processes/process/state/memory-utilization"]; + ywrapper.StringValue name = 245651384 [(yext.schemapath) = "/system/processes/process/state/name"]; + ywrapper.UintValue start_time = 320727543 [(yext.schemapath) = "/system/processes/process/state/start-time"]; + } + message ProcessKey { + uint64 pid = 1 [(yext.schemapath) = "/system/processes/process/state/pid|/system/processes/process/pid"]; + Process process = 2; + } + message SshServer { + enum ProtocolVersion { + PROTOCOLVERSION_V2 = 0 [(yext.yang_name) = "V2"]; + PROTOCOLVERSION_V1 = 2 [(yext.yang_name) = "V1"]; + PROTOCOLVERSION_V1_V2 = 3 [(yext.yang_name) = "V1_V2"]; + } + ywrapper.BoolValue enable = 475045872 [(yext.schemapath) = "/system/ssh-server/config/enable"]; + ProtocolVersion protocol_version = 334522130 [(yext.schemapath) = "/system/ssh-server/config/protocol-version"]; + ywrapper.UintValue rate_limit = 194633841 [(yext.schemapath) = "/system/ssh-server/config/rate-limit"]; + ywrapper.UintValue session_limit = 401851517 [(yext.schemapath) = "/system/ssh-server/config/session-limit"]; + ywrapper.UintValue timeout = 447813214 [(yext.schemapath) = "/system/ssh-server/config/timeout"]; + } + message TelnetServer { + ywrapper.BoolValue enable = 131142084 [(yext.schemapath) = "/system/telnet-server/config/enable"]; + ywrapper.UintValue rate_limit = 174879637 [(yext.schemapath) = "/system/telnet-server/config/rate-limit"]; + ywrapper.UintValue session_limit = 205487953 [(yext.schemapath) = "/system/telnet-server/config/session-limit"]; + ywrapper.UintValue timeout = 360726298 [(yext.schemapath) = "/system/telnet-server/config/timeout"]; + } + Aaa aaa = 128178706 [(yext.schemapath) = "/system/aaa"]; + repeated AlarmKey alarm = 221321319 [(yext.schemapath) = "/system/alarms/alarm"]; + ywrapper.UintValue boot_time = 174811281 [(yext.schemapath) = "/system/state/boot-time"]; + Clock clock = 298112203 [(yext.schemapath) = "/system/clock"]; + repeated CpuKey cpu = 70314881 [(yext.schemapath) = "/system/cpus/cpu"]; + ywrapper.StringValue current_datetime = 14846070 [(yext.schemapath) = "/system/state/current-datetime"]; + Dns dns = 380694544 [(yext.schemapath) = "/system/dns"]; + ywrapper.StringValue domain_name = 514451884 [(yext.schemapath) = "/system/config/domain-name"]; + GrpcServer grpc_server = 115074741 [(yext.schemapath) = "/system/grpc-server"]; + ywrapper.StringValue hostname = 502971767 [(yext.schemapath) = "/system/config/hostname"]; + Logging logging = 147116502 [(yext.schemapath) = "/system/logging"]; + ywrapper.StringValue login_banner = 161971574 [(yext.schemapath) = "/system/config/login-banner"]; + Memory memory = 238855198 [(yext.schemapath) = "/system/memory"]; + Messages messages = 243479275 [(yext.schemapath) = "/system/messages"]; + ywrapper.StringValue motd_banner = 428956479 [(yext.schemapath) = "/system/config/motd-banner"]; + Ntp ntp = 214492667 [(yext.schemapath) = "/system/ntp"]; + repeated ProcessKey process = 8835840 [(yext.schemapath) = "/system/processes/process"]; + SshServer ssh_server = 92111553 [(yext.schemapath) = "/system/ssh-server"]; + TelnetServer telnet_server = 426646341 [(yext.schemapath) = "/system/telnet-server"]; +} diff --git a/COPIED/p4runtime.py b/COPIED/p4runtime.py new file mode 100644 index 0000000..fc5de65 --- /dev/null +++ b/COPIED/p4runtime.py @@ -0,0 +1,350 @@ +# Copyright 2019 Barefoot Networks, Inc. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +from functools import wraps +import google.protobuf.text_format +from google.rpc import status_pb2, code_pb2 +import grpc +import logging +import queue +import sys +import threading +from typing import NamedTuple + +from p4.v1 import p4runtime_pb2 +from p4.v1 import p4runtime_pb2_grpc + + +class P4RuntimeErrorFormatException(Exception): + def __init__(self, message): + super().__init__(message) + + +# Used to iterate over the p4.Error messages in a gRPC error Status object +class P4RuntimeErrorIterator: + def __init__(self, grpc_error): + assert(grpc_error.code() == grpc.StatusCode.UNKNOWN) + self.grpc_error = grpc_error + + error = None + # The gRPC Python package does not have a convenient way to access the + # binary details for the error: they are treated as trailing metadata. + for meta in self.grpc_error.trailing_metadata(): + if meta[0] == "grpc-status-details-bin": + error = status_pb2.Status() + error.ParseFromString(meta[1]) + break + if error is None: + raise P4RuntimeErrorFormatException("No binary details field") + + if len(error.details) == 0: + raise P4RuntimeErrorFormatException( + "Binary details field has empty Any details repeated field") + self.errors = error.details + self.idx = 0 + + def __iter__(self): + return self + + def __next__(self): + while self.idx < len(self.errors): + p4_error = p4runtime_pb2.Error() + one_error_any = self.errors[self.idx] + if not one_error_any.Unpack(p4_error): + raise P4RuntimeErrorFormatException( + "Cannot convert Any message to p4.Error") + if p4_error.canonical_code == code_pb2.OK: + continue + v = self.idx, p4_error + self.idx += 1 + return v + raise StopIteration + + +# P4Runtime uses a 3-level message in case of an error during the processing of +# a write batch. This means that if we do not wrap the grpc.RpcError inside a +# custom exception, we can end-up with a non-helpful exception message in case +# of failure as only the first level will be printed. In this custom exception +# class, we extract the nested error message (one for each operation included in +# the batch) in order to print error code + user-facing message. See P4 Runtime +# documentation for more details on error-reporting. +class P4RuntimeWriteException(Exception): + def __init__(self, grpc_error): + assert(grpc_error.code() == grpc.StatusCode.UNKNOWN) + super().__init__() + self.errors = [] + try: + error_iterator = P4RuntimeErrorIterator(grpc_error) + for error_tuple in error_iterator: + self.errors.append(error_tuple) + except P4RuntimeErrorFormatException: + raise # just propagate exception for now + + def __str__(self): + message = "Error(s) during Write:\n" + for idx, p4_error in self.errors: + code_name = code_pb2._CODE.values_by_number[ + p4_error.canonical_code].name + message += "\t* At index {}: {}, '{}'\n".format( + idx, code_name, p4_error.message) + return message + + +class P4RuntimeException(Exception): + def __init__(self, grpc_error): + super().__init__() + self.grpc_error = grpc_error + + def __str__(self): + message = "P4Runtime RPC error ({}): {}".format( + self.grpc_error.code().name, self.grpc_error.details()) + return message + + +def parse_p4runtime_write_error(f): + @wraps(f) + def handle(*args, **kwargs): + try: + return f(*args, **kwargs) + except grpc.RpcError as e: + if e.code() != grpc.StatusCode.UNKNOWN: + raise e + raise P4RuntimeWriteException(e) from None + return handle + + +def parse_p4runtime_error(f): + @wraps(f) + def handle(*args, **kwargs): + try: + return f(*args, **kwargs) + except grpc.RpcError as e: + raise P4RuntimeException(e) from None + return handle + + +class SSLOptions(NamedTuple): + insecure: bool + cacert: str = None + cert: str = None + key: str = None + + +def read_pem_file(path): + try: + with open(path, 'rb') as f: + return f.read() + except Exception: + logging.critical("Cannot read from PEM file '{}'".format(path)) + sys.exit(1) + + +class P4RuntimeClient: + def __init__(self, device_id, grpc_addr, election_id, role_name=None, ssl_options=None): + self.device_id = device_id + self.election_id = election_id + self.role_name = role_name + if ssl_options is None: + self.ssl_options = SSLOptions(True) + else: + self.ssl_options = ssl_options + logging.debug("Connecting to device {} at {}".format(device_id, grpc_addr)) + if self.ssl_options.insecure: + try: + logging.debug("Using insecure channel") + self.channel = grpc.insecure_channel(grpc_addr) + except Exception: + logging.critical("Failed to connect to P4Runtime server") + sys.exit(1) + else: + # root certificates are retrieved from a default location chosen by gRPC runtime unless + # the user provides custom certificates. + root_certificates = None + if self.ssl_options.cacert is not None: + root_certificates = read_pem_file(self.ssl_options.cacert) + certificate_chain = None + if self.ssl_options.cert is not None: + certificate_chain = read_pem_file(self.ssl_options.cert) + private_key = None + if self.ssl_options.key is not None: + private_key = read_pem_file(self.ssl_options.key) + creds = grpc.ssl_channel_credentials(root_certificates, private_key, certificate_chain) + try: + self.channel = grpc.secure_channel(grpc_addr, creds) + except Exception: + logging.critical("Failed to connect to P4Runtime server") + sys.exit(1) + + self.stub = p4runtime_pb2_grpc.P4RuntimeStub(self.channel) + self.set_up_stream() + + def set_up_stream(self): + self.stream_out_q = queue.Queue() + # queues for different messages + self.stream_in_q = { + "arbitration": queue.Queue(), + "packet": queue.Queue(), + "digest": queue.Queue(), + "idle_timeout_notification": queue.Queue(), + "unknown": queue.Queue(), + } + + def stream_req_iterator(): + while True: + p = self.stream_out_q.get() + if p is None: + break + yield p + + def stream_recv_wrapper(stream): + @parse_p4runtime_error + def stream_recv(): + for p in stream: + if p.HasField("arbitration"): + self.stream_in_q["arbitration"].put(p) + elif p.HasField("packet"): + self.stream_in_q["packet"].put(p) + elif p.HasField("digest"): + self.stream_in_q["digest"].put(p) + elif p.HasField("idle_timeout_notification"): + self.stream_in_q["idle_timeout_notification"].put(p) + else: + self.stream_in_q["unknown"].put(p) + try: + stream_recv() + except P4RuntimeException as e: + logging.critical("StreamChannel error, closing stream") + logging.critical(e) + for k in self.stream_in_q: + self.stream_in_q[k].put(None) + self.stream = self.stub.StreamChannel(stream_req_iterator()) + self.stream_recv_thread = threading.Thread( + target=stream_recv_wrapper, args=(self.stream,)) + self.stream_recv_thread.start() + self.handshake() + + def handshake(self): + req = p4runtime_pb2.StreamMessageRequest() + arbitration = req.arbitration + arbitration.device_id = self.device_id + election_id = arbitration.election_id + election_id.high = self.election_id[0] + election_id.low = self.election_id[1] + if self.role_name is not None: + arbitration.role.name = self.role_name + self.stream_out_q.put(req) + + rep = self.get_stream_packet("arbitration", timeout=2) + if rep is None: + logging.critical("Failed to establish session with server") + sys.exit(1) + is_primary = (rep.arbitration.status.code == code_pb2.OK) + logging.debug("Session established, client is '{}'".format( + 'primary' if is_primary else 'backup')) + if not is_primary: + print("You are not the primary client, you only have read access to the server") + + def get_stream_packet(self, type_, timeout=1): + if type_ not in self.stream_in_q: + print("Unknown stream type '{}'".format(type_)) + return None + try: + msg = self.stream_in_q[type_].get(timeout=timeout) + return msg + except queue.Empty: # timeout expired + return None + + @parse_p4runtime_error + def get_p4info(self): + logging.debug("Retrieving P4Info file") + req = p4runtime_pb2.GetForwardingPipelineConfigRequest() + req.device_id = self.device_id + req.response_type = p4runtime_pb2.GetForwardingPipelineConfigRequest.P4INFO_AND_COOKIE + rep = self.stub.GetForwardingPipelineConfig(req) + return rep.config.p4info + + @parse_p4runtime_error + def set_fwd_pipe_config(self, p4info_path, bin_path): + logging.debug("Setting forwarding pipeline config") + req = p4runtime_pb2.SetForwardingPipelineConfigRequest() + req.device_id = self.device_id + if self.role_name is not None: + req.role = self.role_name + election_id = req.election_id + election_id.high = self.election_id[0] + election_id.low = self.election_id[1] + req.action = p4runtime_pb2.SetForwardingPipelineConfigRequest.VERIFY_AND_COMMIT + with open(p4info_path, 'r') as f1: + with open(bin_path, 'rb') as f2: + try: + google.protobuf.text_format.Merge(f1.read(), req.config.p4info, + allow_unknown_field=True) + except google.protobuf.text_format.ParseError: + logging.error("Error when parsing P4Info") + raise + req.config.p4_device_config = f2.read() + return self.stub.SetForwardingPipelineConfig(req) + + def tear_down(self): + if self.stream_out_q: + logging.debug("Cleaning up stream") + self.stream_out_q.put(None) + if self.stream_in_q: + for k in self.stream_in_q: + self.stream_in_q[k].put(None) + if self.stream_recv_thread: + self.stream_recv_thread.join() + self.channel.close() + del self.channel # avoid a race condition if channel deleted when process terminates + + @parse_p4runtime_write_error + def write(self, req): + req.device_id = self.device_id + if self.role_name is not None: + req.role = self.role_name + election_id = req.election_id + election_id.high = self.election_id[0] + election_id.low = self.election_id[1] + return self.stub.Write(req) + + @parse_p4runtime_write_error + def write_update(self, update): + req = p4runtime_pb2.WriteRequest() + req.device_id = self.device_id + if self.role_name is not None: + req.role = self.role_name + election_id = req.election_id + election_id.high = self.election_id[0] + election_id.low = self.election_id[1] + req.updates.extend([update]) + return self.stub.Write(req) + + # Decorator is useless here: in case of server error, the exception is raised during the + # iteration (when next() is called). + @parse_p4runtime_error + def read_one(self, entity): + req = p4runtime_pb2.ReadRequest() + if self.role_name is not None: + req.role = self.role_name + req.device_id = self.device_id + req.entities.extend([entity]) + return self.stub.Read(req) + + @parse_p4runtime_error + def api_version(self): + req = p4runtime_pb2.CapabilitiesRequest() + rep = self.stub.Capabilities(req) + return rep.p4runtime_api_version diff --git a/COPIED/shell.py b/COPIED/shell.py new file mode 100644 index 0000000..e791743 --- /dev/null +++ b/COPIED/shell.py @@ -0,0 +1,3063 @@ +# Copyright 2019 Barefoot Networks, Inc. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import argparse +import time +from collections import Counter, namedtuple, OrderedDict +import enum +import logging +from threading import Thread +from IPython import start_ipython +from traitlets.config.loader import Config +from IPython.terminal.prompts import Prompts, Token +import os.path +import sys +from p4runtime_sh.p4runtime import (P4RuntimeClient, P4RuntimeException, parse_p4runtime_error, + SSLOptions) +from p4.v1 import p4runtime_pb2 +from p4.config.v1 import p4info_pb2 +from . import bytes_utils +from . global_options import global_options, Options +from .context import P4RuntimeEntity, P4Type, Context +from .utils import UserError, InvalidP4InfoError +import google.protobuf.text_format +from google.protobuf import descriptor +import queue + + +context = Context() +client = None + + +def _print(*args, **kwargs): + if global_options.get_option(Options.verbose): + print(*args, **kwargs) + + +class UserUsageError(UserError): + def __init__(self, usage): + self.usage = usage + + def __str__(self): + return "Usage: " + self.usage + + +class NotSupportedYet(UserError): + def __init__(self, what): + self.what = what + + def __str__(self): + return "{} is not supported yet".format(self.what) + + +class _PrintContext: + def __init__(self): + self.skip_one = False + self.stack = [] + + def find_table(self): + for msg in reversed(self.stack): + if msg.DESCRIPTOR.name == "TableEntry": + try: + return context.get_name_from_id(msg.table_id) + except KeyError: + return None + return None + + def find_action(self): + for msg in reversed(self.stack): + if msg.DESCRIPTOR.name == "Action": + try: + return context.get_name_from_id(msg.action_id) + except KeyError: + return None + return None + + def find_controller_packet_metadata(self): + for msg in reversed(self.stack): + if msg.DESCRIPTOR.name == "PacketIn": + return "packet_in" + if msg.DESCRIPTOR.name == "PacketOut": + return "packet_out" + return None + + +def _sub_object(field, value, pcontext): + id_ = value + try: + return context.get_name_from_id(id_) + except KeyError: + logging.error("Unknown object id {}".format(id_)) + + +def _sub_mf(field, value, pcontext): + id_ = value + table_name = pcontext.find_table() + if table_name is None: + logging.error("Cannot find any table in context") + return + return context.get_mf_name(table_name, id_) + + +def _sub_ap(field, value, pcontext): + id_ = value + action_name = pcontext.find_action() + if action_name is None: + logging.error("Cannot find any action in context") + return + return context.get_param_name(action_name, id_) + + +def _sub_pkt_md(field, value, pcontext): + id_ = value + ctrl_pkt_md_name = pcontext.find_controller_packet_metadata() + return context.get_packet_metadata_name_from_id(ctrl_pkt_md_name, id_) + + +def _gen_pretty_print_proto_field(substitutions, pcontext): + def myPrintField(self, field, value): + self._PrintFieldName(field) + self.out.write(' ') + if field.type == descriptor.FieldDescriptor.TYPE_BYTES: + # TODO(antonin): any kind of checks required? + self.out.write('\"') + self.out.write(''.join('\\\\x{:02x}'.format(b) for b in value)) + self.out.write('\"') + else: + self.PrintFieldValue(field, value) + subs = None + if field.containing_type is not None: + subs = substitutions.get(field.containing_type.name, None) + if subs and field.name in subs and value != 0: + name = subs[field.name](field, value, pcontext) + self.out.write(' ("{}")'.format(name)) + self.out.write(' ' if self.as_one_line else '\n') + + return myPrintField + + +def _repr_pretty_proto(msg, substitutions): + """A custom version of google.protobuf.text_format.MessageToString which represents Protobuf + messages with a more user-friendly string. In particular, P4Runtime ids are supplemented with + the P4 name and binary strings are displayed in hexadecimal format.""" + pcontext = _PrintContext() + + def message_formatter(message, indent, as_one_line): + # For each messages we do 2 passes: the first one updates the _PrintContext instance and + # calls MessageToString again. The second pass returns None immediately (default handling by + # text_format). + if pcontext.skip_one: + pcontext.skip_one = False + return + pcontext.stack.append(message) + pcontext.skip_one = True + s = google.protobuf.text_format.MessageToString( + message, indent=indent, as_one_line=as_one_line, message_formatter=message_formatter) + s = s[indent:-1] + pcontext.stack.pop() + return s + + # We modify the "internals" of the text_format module which is not great as it may break in the + # future, but this enables us to keep the code fairly small. + saved_printer = google.protobuf.text_format._Printer.PrintField + google.protobuf.text_format._Printer.PrintField = _gen_pretty_print_proto_field( + substitutions, pcontext) + + s = google.protobuf.text_format.MessageToString(msg, message_formatter=message_formatter) + + google.protobuf.text_format._Printer.PrintField = saved_printer + + return s + + +def _repr_pretty_p4info(msg): + substitutions = { + "Table": {"const_default_action_id": _sub_object, + "implementation_id": _sub_object, + "direct_resource_ids": _sub_object}, + "ActionRef": {"id": _sub_object}, + "ActionProfile": {"table_ids": _sub_object}, + "DirectCounter": {"direct_table_id": _sub_object}, + "DirectMeter": {"direct_table_id": _sub_object}, + } + return _repr_pretty_proto(msg, substitutions) + + +def _repr_pretty_p4runtime(msg): + substitutions = { + "TableEntry": {"table_id": _sub_object}, + "FieldMatch": {"field_id": _sub_mf}, + "Action": {"action_id": _sub_object}, + "Param": {"param_id": _sub_ap}, + "ActionProfileMember": {"action_profile_id": _sub_object}, + "ActionProfileGroup": {"action_profile_id": _sub_object}, + "MeterEntry": {"meter_id": _sub_object}, + "CounterEntry": {"counter_id": _sub_object}, + "ValueSetEntry": {"value_set_id": _sub_object}, + "RegisterEntry": {"register_id": _sub_object}, + "DigestEntry": {"digest_id": _sub_object}, + "DigestListAck": {"digest_id": _sub_object}, + "DigestList": {"digest_id": _sub_object}, + "PacketMetadata": {"metadata_id": _sub_pkt_md} + } + return _repr_pretty_proto(msg, substitutions) + + +class P4Object: + def __init__(self, obj_type, obj): + self.name = obj.preamble.name + self.id = obj.preamble.id + self._obj_type = obj_type + self._obj = obj + self.__doc__ = """ +A wrapper around the P4Info Protobuf message for {} '{}'. +You can access any field from the message with .. +You can access the name directly with .name. +You can access the id directly with .id. +If you need the underlying Protobuf message, you can access it with msg(). +""".format(obj_type.pretty_name, self.name) + + def __dir__(self): + d = ["info", "msg", "name", "id"] + if self._obj_type == P4Type.table: + d.append("actions") + return d + + def _repr_pretty_(self, p, cycle): + p.text(_repr_pretty_p4info(self._obj)) + + def __str__(self): + return _repr_pretty_p4info(self._obj) + + def __getattr__(self, name): + return getattr(self._obj, name) + + def __settattr__(self, name, value): + return UserError("Operation not supported") + + def msg(self): + """Get Protobuf message object""" + return self._obj + + def info(self): + print(_repr_pretty_p4info(self._obj)) + + def actions(self): + """Print list of actions, only for tables and action profiles.""" + if self._obj_type == P4Type.table: + for action in self._obj.action_refs: + print(context.get_name_from_id(action.id)) + elif self._obj_type == P4Type.action_profile: + t_id = self._obj.table_ids[0] + t_name = context.get_name_from_id(t_id) + t = context.get_table(t_name) + for action in t.action_refs: + print(context.get_name_from_id(action.id)) + else: + raise UserError("'actions' is only available for tables and action profiles") + + +class P4Objects: + def __init__(self, obj_type): + self._obj_type = obj_type + self._names = sorted([name for name, _ in context.get_objs(obj_type)]) + self._iter = None + self.__doc__ = """ +All the {pnames} in the P4 program. +To access a specific {pname}, use {p4info}['']. +You can use this class to iterate over all {pname} instances: +\tfor x in {p4info}: +\t\tprint(x.id) +""".format(pname=obj_type.pretty_name, pnames=obj_type.pretty_names, p4info=obj_type.p4info_name) + + def __call__(self): + for name in self._names: + print(name) + + def _ipython_key_completions_(self): + return self._names + + def __getitem__(self, name): + obj = context.get_obj(self._obj_type, name) + if obj is None: + raise UserError("{} '{}' does not exist".format( + self._obj_type.pretty_name, name)) + return P4Object(self._obj_type, obj) + + def __setitem__(self, name, value): + raise UserError("Operation not allowed") + + def _repr_pretty_(self, p, cycle): + p.text(self.__doc__) + + def __iter__(self): + self._iter = iter(self._names) + return self + + def __next__(self): + name = next(self._iter) + return self[name] + + +class MatchKey: + def __init__(self, table_name, match_fields): + self._table_name = table_name + self._fields = OrderedDict() + self._fields_suffixes = {} + for mf in match_fields: + self._add_field(mf) + self._mk = OrderedDict() + self._set_docstring() + + def _set_docstring(self): + self.__doc__ = "Match key fields for table '{}':\n\n".format(self._table_name) + for name, info in self._fields.items(): + self.__doc__ += str(info) + self.__doc__ += """ +Set a field value with [''] = '...' + * For exact match: [''] = '' + * For ternary match: [''] = '&&&' + * For LPM match: [''] = '/' + * For range match: [''] = '..' + * For optional match: [''] = '' + +If it's inconvenient to use the whole field name, you can use a unique suffix. + +You may also use .set(='') +\t( must not include a '.' in this case, but remember that you can use a unique suffix) +""" + + def _ipython_key_completions_(self): + return self._fields.keys() + + def __dir__(self): + return ["clear"] + + def _full_field_name(self, name): + if name in self._fields: + return name + if name in self._fields_suffixes: + return self._fields_suffixes[name] + raise UserError( + "'{}' is not a valid match field name, nor a valid unique suffix, " + "for table '{}'".format(name, self._table_name)) + + def _get_mf(self, name): + fullname = self._full_field_name(name) + return self._fields[fullname] + + def __setitem__(self, name, value): + fullname = self._full_field_name(name) + field_info = self._get_mf(fullname) + self._mk[fullname] = self._parse_mf(value, field_info) + _print(self._mk[fullname]) + + def __getitem__(self, name): + fullname = self._full_field_name(name) + f = self._mk.get(fullname, None) + if f is None: + _print("Unset") + return f + + def _parse_mf(self, s, field_info): + if type(s) is not str: + raise UserError("Match field value must be a string") + if field_info.match_type == p4info_pb2.MatchField.EXACT: + return self._parse_mf_exact(s, field_info) + elif field_info.match_type == p4info_pb2.MatchField.LPM: + return self._parse_mf_lpm(s, field_info) + elif field_info.match_type == p4info_pb2.MatchField.TERNARY: + return self._parse_mf_ternary(s, field_info) + elif field_info.match_type == p4info_pb2.MatchField.RANGE: + return self._parse_mf_range(s, field_info) + elif field_info.match_type == p4info_pb2.MatchField.OPTIONAL: + return self._parse_mf_optional(s, field_info) + else: + raise UserError("Unsupported match type for field:\n{}".format(field_info)) + + def _parse_mf_exact(self, s, field_info): + v = bytes_utils.parse_value(s.strip(), field_info.bitwidth) + return self._sanitize_and_convert_mf_exact(v, field_info) + + def _sanitize_and_convert_mf_exact(self, value, field_info): + mf = p4runtime_pb2.FieldMatch() + mf.field_id = field_info.id + mf.exact.value = bytes_utils.make_canonical_if_option_set(value) + return mf + + def _parse_mf_optional(self, s, field_info): + v = bytes_utils.parse_value(s.strip(), field_info.bitwidth) + return self._sanitize_and_convert_mf_optional(v, field_info) + + def _sanitize_and_convert_mf_optional(self, value, field_info): + mf = p4runtime_pb2.FieldMatch() + mf.field_id = field_info.id + mf.optional.value = bytes_utils.make_canonical_if_option_set(value) + return mf + + def _parse_mf_lpm(self, s, field_info): + try: + prefix, length = s.split('/') + prefix, length = prefix.strip(), length.strip() + except ValueError: + prefix = s + length = str(field_info.bitwidth) + + prefix = bytes_utils.parse_value(prefix, field_info.bitwidth) + try: + length = int(length) + except ValueError: + raise UserError("'{}' is not a valid prefix length").format(length) + + return self._sanitize_and_convert_mf_lpm(prefix, length, field_info) + + def _sanitize_and_convert_mf_lpm(self, prefix, length, field_info): + if length == 0: + raise UserError( + "Ignoring LPM don't care match (prefix length of 0) as per P4Runtime spec") + + mf = p4runtime_pb2.FieldMatch() + mf.field_id = field_info.id + mf.lpm.prefix_len = length + + first_byte_masked = length // 8 + if first_byte_masked == len(prefix): + mf.lpm.value = prefix + return mf + + barray = bytearray(prefix) + transformed = False + r = length % 8 + byte_mask = 0xff & ((0xff << (8 - r))) + if barray[first_byte_masked] & byte_mask != barray[first_byte_masked]: + transformed = True + barray[first_byte_masked] = barray[first_byte_masked] & byte_mask + + for i in range(first_byte_masked + 1, len(prefix)): + if barray[i] != 0: + transformed = True + barray[i] = 0 + if transformed: + _print("LPM value was transformed to conform to the P4Runtime spec " + "(trailing bits must be unset)") + mf.lpm.value = bytes(bytes_utils.make_canonical_if_option_set(barray)) + return mf + + def _parse_mf_ternary(self, s, field_info): + try: + value, mask = s.split('&&&') + value, mask = value.strip(), mask.strip() + except ValueError: + value = s.strip() + mask = "0b" + ("1" * field_info.bitwidth) + + value = bytes_utils.parse_value(value, field_info.bitwidth) + mask = bytes_utils.parse_value(mask, field_info.bitwidth) + + return self._sanitize_and_convert_mf_ternary(value, mask, field_info) + + def _sanitize_and_convert_mf_ternary(self, value, mask, field_info): + if int.from_bytes(mask, byteorder='big') == 0: + raise UserError("Ignoring ternary don't care match (mask of 0s) as per P4Runtime spec") + + mf = p4runtime_pb2.FieldMatch() + mf.field_id = field_info.id + + barray = bytearray(value) + transformed = False + for i in range(len(value)): + if barray[i] & mask[i] != barray[i]: + transformed = True + barray[i] = barray[i] & mask[i] + if transformed: + _print("Ternary value was transformed to conform to the P4Runtime spec " + "(masked off bits must be unset)") + mf.ternary.value = bytes(bytes_utils.make_canonical_if_option_set(barray)) + mf.ternary.mask = bytes_utils.make_canonical_if_option_set(mask) + return mf + + def _parse_mf_range(self, s, field_info): + try: + start, end = s.split('..') + start, end = start.strip(), end.strip() + except ValueError: + raise UserError("'{}' does not specify a valid range, use '..'").format( + s) + + start = bytes_utils.parse_value(start, field_info.bitwidth) + end = bytes_utils.parse_value(end, field_info.bitwidth) + + return self._sanitize_and_convert_mf_range(start, end, field_info) + + def _sanitize_and_convert_mf_range(self, start, end, field_info): + # It's a bit silly: the fields are converted from str to int to bytes by bytes_utils, then + # converted back to int here... + start_ = int.from_bytes(start, byteorder='big') + end_ = int.from_bytes(end, byteorder='big') + if start_ > end_: + raise UserError("Invalid range match: start is greater than end") + if start_ == 0 and end_ == ((1 << field_info.bitwidth) - 1): + raise UserError( + "Ignoring range don't care match (all possible values) as per P4Runtime spec") + mf = p4runtime_pb2.FieldMatch() + mf.field_id = field_info.id + mf.range.low = bytes_utils.make_canonical_if_option_set(start) + mf.range.high = bytes_utils.make_canonical_if_option_set(end) + return mf + + def _add_field(self, field_info): + self._fields[field_info.name] = field_info + self._recompute_suffixes() + + def _recompute_suffixes(self): + suffixes = {} + suffix_count = Counter() + for fname in self._fields: + suffix = None + for s in reversed(fname.split(".")): + suffix = s if suffix is None else s + "." + suffix + suffixes[suffix] = fname + suffix_count[suffix] += 1 + for suffix, c in suffix_count.items(): + if c > 1: + del suffixes[suffix] + self._fields_suffixes = suffixes + + def __str__(self): + return '\n'.join([str(mf) for name, mf in self._mk.items()]) + + def _repr_pretty_(self, p, cycle): + for name, mf in self._mk.items(): + p.text(str(mf)) + + def set(self, **kwargs): + for name, value in kwargs.items(): + self[name] = value + + def clear(self): + self._mk.clear() + + def _count(self): + return len(self._mk) + + +class Action: + def __init__(self, action_name=None): + self._init = False + if action_name is None: + raise UserError("Please provide name for action") + self.action_name = action_name + action_info = context.get_action(action_name) + if action_info is None: + raise UserError("Unknown action '{}'".format(action_name)) + self._action_id = action_info.preamble.id + self._params = OrderedDict() + for param in action_info.params: + self._params[param.name] = param + self._action_info = action_info + self._param_values = OrderedDict() + self._set_docstring() + self._init = True + + def _set_docstring(self): + self.__doc__ = "Action parameters for action '{}':\n\n".format(self.action_name) + for name, info in self._params.items(): + self.__doc__ += str(info) + self.__doc__ += "\n\n" + self.__doc__ += "Set a param value with [''] = ''\n" + self.__doc__ += "You may also use .set(='')\n" + + def _ipython_key_completions_(self): + return self._params.keys() + + def __dir__(self): + return ["action_name", "msg", "set"] + + def _get_param(self, name): + if name not in self._params: + raise UserError( + "'{}' is not a valid action parameter name for action '{}'".format( + name, self.action_name)) + return self._params[name] + + def __setattr__(self, name, value): + if name[0] == "_" or not self._init: + super().__setattr__(name, value) + return + if name == "action_name": + raise UserError("Cannot change action name") + super().__setattr__(name, value) + + def __setitem__(self, name, value): + param_info = self._get_param(name) + self._param_values[name] = self._parse_param(value, param_info) + _print(self._param_values[name]) + + def __getitem__(self, name): + _ = self._get_param(name) + f = self._param_values.get(name, None) + if f is None: + _print("Unset") + return f + + def _parse_param(self, s, param_info): + if type(s) is not str: + raise UserError("Action parameter value must be a string") + v = bytes_utils.parse_value(s, param_info.bitwidth) + p = p4runtime_pb2.Action.Param() + p.param_id = param_info.id + p.value = bytes_utils.make_canonical_if_option_set(v) + return p + + def msg(self): + msg = p4runtime_pb2.Action() + msg.action_id = self._action_id + msg.params.extend(self._param_values.values()) + return msg + + def _from_msg(self, msg): + assert(self._action_id == msg.action_id) + self._param_values.clear() + for p in msg.params: + p_name = context.get_param_name(self.action_name, p.param_id) + self._param_values[p_name] = p + + def __str__(self): + return str(self.msg()) + + def _repr_pretty_(self, p, cycle): + p.text(str(self.msg())) + + def set(self, **kwargs): + for name, value in kwargs.items(): + self[name] = value + + +class _EntityBase: + def __init__(self, entity_type, p4runtime_cls, modify_only=False): + self._init = False + self._entity_type = entity_type + self._entry = p4runtime_cls() + self._modify_only = modify_only + + def __dir__(self): + d = ["msg", "read"] + if self._modify_only: + d.append("modify") + else: + d.extend(["insert", "modify", "delete"]) + return d + + # to be called before issueing a P4Runtime request + # enforces checks that cannot be performed when setting individual fields + def _validate_msg(self): + return True + + def _update_msg(self): + pass + + def __str__(self): + self._update_msg() + return str(_repr_pretty_p4runtime(self._entry)) + + def _repr_pretty_(self, p, cycle): + self._update_msg() + p.text(_repr_pretty_p4runtime(self._entry)) + + def __getattr__(self, name): + raise AttributeError("'{}' object has no attribute '{}'".format( + self.__class__.__name__, name)) + + def msg(self): + self._update_msg() + return self._entry + + def _write(self, type_): + self._update_msg() + self._validate_msg() + update = p4runtime_pb2.Update() + update.type = type_ + getattr(update.entity, self._entity_type.name).CopyFrom(self._entry) + client.write_update(update) + + def insert(self): + if self._modify_only: + raise NotImplementedError("Insert not supported for {}".format(self._entity_type.name)) + logging.debug("Inserting entry") + self._write(p4runtime_pb2.Update.INSERT) + + def delete(self): + if self._modify_only: + raise NotImplementedError("Delete not supported for {}".format(self._entity_type.name)) + logging.debug("Deleting entry") + self._write(p4runtime_pb2.Update.DELETE) + + def modify(self): + logging.debug("Modifying entry") + self._write(p4runtime_pb2.Update.MODIFY) + + def _from_msg(self, msg): + raise NotImplementedError + + def read(self, function=None): + # Entities should override this method and provide a helpful docstring + self._update_msg() + self._validate_msg() + entity = p4runtime_pb2.Entity() + getattr(entity, self._entity_type.name).CopyFrom(self._entry) + + iterator = client.read_one(entity) + + # Cannot use a (simpler) generator here as we need to decorate __next__ with + # @parse_p4runtime_error. + class _EntryIterator: + def __init__(self, entity, it): + self._entity = entity + self._it = it + self._entities_it = None + + def __iter__(self): + return self + + @parse_p4runtime_error + def __next__(self): + if self._entities_it is None: + rep = next(self._it) + self._entities_it = iter(rep.entities) + try: + entity = next(self._entities_it) + except StopIteration: + self._entities_it = None + return next(self) + + if isinstance(self._entity, _P4EntityBase): + e = type(self._entity)(self._entity.name) # create new instance of same entity + else: + e = type(self._entity)() + msg = getattr(entity, self._entity._entity_type.name) + e._from_msg(msg) + # neither of these should be needed + # e._update_msg() + # e._entry.CopyFrom(msg) + return e + + if function is None: + return _EntryIterator(self, iterator) + else: + for x in _EntryIterator(self, iterator): + function(x) + + +class _P4EntityBase(_EntityBase): + def __init__(self, p4_type, entity_type, p4runtime_cls, name=None, modify_only=False): + super().__init__(entity_type, p4runtime_cls, modify_only) + self._p4_type = p4_type + if name is None: + raise UserError("Please provide name for {}".format(p4_type.pretty_name)) + self.name = name + self._info = P4Objects(p4_type)[name] + self.id = self._info.id + + def __dir__(self): + return super().__dir__() + ["name", "id", "info"] + + def info(self): + """Display P4Info entry for the object""" + return self._info + + +class ActionProfileMember(_P4EntityBase): + def __init__(self, action_profile_name=None): + super().__init__( + P4Type.action_profile, P4RuntimeEntity.action_profile_member, + p4runtime_pb2.ActionProfileMember, action_profile_name) + self.member_id = 0 + self.action = None + self._valid_action_ids = self._get_action_set() + self.__doc__ = """ +An action profile member for '{}' + +Use .info to display the P4Info entry for the action profile. + +Set the member id with .member_id = . + +To set the action specification .action = . +To set the value of action parameters, use .action[''] = . +Type .action? for more details. + + +Typical usage to insert an action profile member: +m = action_profile_member[''](action='', member_id=1) +m.action[''] = ... +... +m.action[''] = ... +# OR m.action.set(p1=..., ..., pM=...) +m.insert + +For information about how to read members, use .read? +""".format(action_profile_name) + self._init = True + + def __dir__(self): + return super().__dir__() + ["member_id", "action"] + + def _get_action_set(self): + t_id = self._info.table_ids[0] + t_name = context.get_name_from_id(t_id) + t = context.get_table(t_name) + return set([action.id for action in t.action_refs]) + + def __call__(self, **kwargs): + for name, value in kwargs.items(): + if name == "action" and type(value) is str: + value = Action(value) + setattr(self, name, value) + return self + + def __setattr__(self, name, value): + if name[0] == "_" or not self._init: + super().__setattr__(name, value) + return + if name == "name": + raise UserError("Cannot change action profile name") + if name == "member_id": + if type(value) is not int: + raise UserError("member_id must be an integer") + if name == "action" and value is not None: + if not isinstance(value, Action): + raise UserError("action must be an instance of Action") + if not self._is_valid_action_id(value._action_id): + raise UserError("action '{}' is not a valid action for this action profile".format( + value.action_name)) + super().__setattr__(name, value) + + def _is_valid_action_id(self, action_id): + return action_id in self._valid_action_ids + + def _update_msg(self): + self._entry.action_profile_id = self.id + self._entry.member_id = self.member_id + if self.action is not None: + self._entry.action.CopyFrom(self.action.msg()) + + def _from_msg(self, msg): + self.member_id = msg.member_id + if msg.HasField('action'): + action = msg.action + action_name = context.get_name_from_id(action.action_id) + self.action = Action(action_name) + self.action._from_msg(action) + + def read(self, function=None): + """Generate a P4Runtime Read RPC. Supports wildcard reads (just leave + the appropriate fields unset). + + If function is None, returns an iterator. Iterate over it to get all the + members (as ActionProfileMember instances) returned by the + server. Otherwise, function is applied to all the members returned + by the server. + """ + return super().read(function) + + +class GroupMember: + """ + A member in an ActionProfileGroup. + Construct with GroupMember(, weight=, watch=, + watch_port=). + You can set / get attributes member_id (required), weight (default 1), watch (default 0), + watch_port (default ""). + """ + def __init__(self, member_id=None, weight=1, watch=0, watch_port=b""): + if member_id is None: + raise UserError("member_id is required") + self._msg = p4runtime_pb2.ActionProfileGroup.Member() + self._msg.member_id = member_id + self._msg.weight = weight + if watch: + self._msg.watch = watch + if watch_port: + self._msg.watch_port = watch_port + + def __dir__(self): + return ["member_id", "weight", "watch", "watch_port"] + + def __setattr__(self, name, value): + if name[0] == "_": + super().__setattr__(name, value) + return + if name == "member_id": + if type(value) is not int: + raise UserError("member_id must be an integer") + self._msg.member_id = value + return + if name == "weight": + if type(value) is not int: + raise UserError("weight must be an integer") + self._msg.weight = value + return + if name == "watch": + if type(value) is not int: + raise UserError("watch must be an integer") + self._msg.watch = value + return + if name == "watch_port": + if type(value) is not bytes: + raise UserError("watch_port must be a byte string") + self._msg.watch_port = value + return + super().__setattr__(name, value) + + def __getattr__(self, name): + if name == "member_id": + return self._msg.member_id + if name == "weight": + return self._msg.weight + if name == "watch": + return self._msg.watch + if name == "watch_port": + return self._msg.watch_port + return super().__getattr__(name) + + def __str__(self): + return str(self._msg) + + def _repr_pretty_(self, p, cycle): + p.text(str(p)) + + +class ActionProfileGroup(_P4EntityBase): + def __init__(self, action_profile_name=None): + super().__init__( + P4Type.action_profile, P4RuntimeEntity.action_profile_group, + p4runtime_pb2.ActionProfileGroup, action_profile_name) + self.group_id = 0 + self.max_size = 0 + self.members = [] + self.__doc__ = """ +An action profile group for '{}' + +Use .info to display the P4Info entry for the action profile. + +Set the group id with .group_id = . Default is 0. +Set the max size with .max_size = . Default is 0. + +Add members to the group with .add(, weight=, watch=, +watch_port=). +weight, watch and watch port are optional (default to 1, 0 and "" respectively). + +Typical usage to insert an action profile group: +g = action_profile_group[''](group_id=1) +g.add() +g.add() +# OR g.add().add() + +For information about how to read groups, use .read? +""".format(action_profile_name) + self._init = True + + def __dir__(self): + return super().__dir__() + ["group_id", "max_size", "members", "add", "clear"] + + def __call__(self, **kwargs): + for name, value in kwargs.items(): + setattr(self, name, value) + return self + + def __setattr__(self, name, value): + if name[0] == "_" or not self._init: + super().__setattr__(name, value) + return + if name == "name": + raise UserError("Cannot change action profile name") + elif name == "group_id": + if type(value) is not int: + raise UserError("group_id must be an integer") + elif name == "members": + if type(value) is not list: + raise UserError("members must be a list of GroupMember objects") + for m in value: + if type(m) is not GroupMember: + raise UserError("members must be a list of GroupMember objects") + super().__setattr__(name, value) + + def add(self, member_id=None, weight=1, watch=0, watch_port=b""): + """Add a member to the members list.""" + self.members.append(GroupMember(member_id, weight, watch, watch_port)) + return self + + def clear(self): + """Empty members list.""" + self.members = [] + + def _update_msg(self): + self._entry.action_profile_id = self.id + self._entry.group_id = self.group_id + self._entry.max_size = self.max_size + del self._entry.members[:] + for member in self.members: + if type(member) is not GroupMember: + raise UserError("members must be a list of GroupMember objects") + m = self._entry.members.add() + m.CopyFrom(member._msg) + + def _from_msg(self, msg): + self.group_id = msg.group_id + self.max_size = msg.max_size + self.members = [] + for member in msg.members: + self.add(member.member_id, member.weight, member.watch, member.watch_port) + + def read(self, function=None): + """Generate a P4Runtime Read RPC. Supports wildcard reads (just leave + the appropriate fields unset). + + If function is None, returns an iterator. Iterate over it to get all the + members (as ActionProfileGroup instances) returned by the + server. Otherwise, function is applied to all the groups returned by the + server. + """ + return super().read(function) + + +def _get_action_profile(table_name): + table = context.get_table(table_name) + implementation_id = table.implementation_id + if implementation_id == 0: + return None + try: + implementation_name = context.get_name_from_id(implementation_id) + except KeyError: + raise InvalidP4InfoError( + "Invalid implementation_id {} for table '{}'".format( + implementation_id, table_name)) + ap = context.get_obj(P4Type.action_profile, implementation_name) + if ap is None: + raise InvalidP4InfoError("Unknown implementation for table '{}'".format(table_name)) + return ap + + +class OneshotAction: + """ + An action in a oneshot action set. + Construct with OneshotAction(, weight=, watch=, + watch_port=). + You can set / get attributes action (required), weight (default 1), watch (default 0), + watch_port (default ""). + """ + def __init__(self, action=None, weight=1, watch=0, watch_port=b""): + if action is None: + raise UserError("action is required") + self.action = action + self.weight = weight + self.watch = watch + self.watch_port = watch_port + + def __dir__(self): + return ["action", "weight", "watch", "watch_port", "msg"] + + def __setattr__(self, name, value): + if name[0] == "_": + super().__setattr__(name, value) + return + if name == "action": + if not isinstance(value, Action): + raise UserError("action must be an instance of Action") + elif name == "weight": + if type(value) is not int: + raise UserError("weight must be an integer") + elif name == "watch": + if type(value) is not int: + raise UserError("watch must be an integer") + elif name == "watch_port": + _print(type(value), value) + if type(value) is not bytes: + raise UserError("watch_port must be a byte string") + super().__setattr__(name, value) + + def msg(self): + msg = p4runtime_pb2.ActionProfileAction() + msg.action.CopyFrom(self.action.msg()) + msg.weight = self.weight + if self.watch: + msg.watch = self.watch + if self.watch_port: + msg.watch_port = self.watch_port + return msg + + def __str__(self): + return str(self.msg()) + + def _repr_pretty_(self, p, cycle): + p.text(str(self.msg())) + + +class Oneshot: + def __init__(self, table_name=None): + self._init = False + if table_name is None: + raise UserError("Please provide table name") + self.table_name = table_name + self.actions = [] + self._table_info = P4Objects(P4Type.table)[table_name] + ap = _get_action_profile(table_name) + if not ap: + raise UserError("Cannot create Oneshot instance for a direct table") + if not ap.with_selector: + raise UserError( + "Cannot create Oneshot instance for a table with an action profile " + "without selector") + self.__doc__ = """ +A "oneshot" action set for table '{}'. + +To add an action to the set, use .add(). +You can also access the set of actions with .actions (which is a Python list). +""".format(self.table_name) + self._init = True + + def __dir__(self): + return ["table_name", "actions", "add", "msg"] + + def __setattr__(self, name, value): + if name[0] == "_" or not self._init: + super().__setattr__(name, value) + return + if name == "table_name": + raise UserError("Cannot change table name") + elif name == "actions": + if type(value) is not list: + raise UserError("actions must be a list of OneshotAction objects") + for m in value: + if type(m) is not OneshotAction: + raise UserError("actions must be a list of OneshotAction objects") + if not self._is_valid_action_id(value.action._action_id): + raise UserError("action '{}' is not a valid action for table {}".format( + value.action.action_name, self.table_name)) + super().__setattr__(name, value) + + def _is_valid_action_id(self, action_id): + for action_ref in self._table_info.action_refs: + if action_id == action_ref.id: + return True + return False + + def add(self, action=None, weight=1, watch=0, watch_port=b""): + """Add an action to the oneshot action set.""" + self.actions.append(OneshotAction(action, weight, watch, watch_port)) + return self + + def msg(self): + msg = p4runtime_pb2.ActionProfileActionSet() + msg.action_profile_actions.extend([action.msg() for action in self.actions]) + return msg + + def _from_msg(self, msg): + for action in msg.action_profile_actions: + action_name = context.get_name_from_id(action.action.action_id) + a = Action(action_name) + a._from_msg(action.action) + self.actions.append(OneshotAction(a, action.weight, action.watch, action.watch_port)) + + def __str__(self): + return str(self.msg()) + + def _repr_pretty_(self, p, cycle): + p.text(str(self.msg())) + + +class _CounterData: + @staticmethod + def attrs_for_counter_type(counter_type): + attrs = [] + if counter_type in {p4info_pb2.CounterSpec.BYTES, p4info_pb2.CounterSpec.BOTH}: + attrs.append("byte_count") + if counter_type in {p4info_pb2.CounterSpec.PACKETS, p4info_pb2.CounterSpec.BOTH}: + attrs.append("packet_count") + return attrs + + def __init__(self, counter_name, counter_type): + self._counter_name = counter_name + self._counter_type = counter_type + self._msg = p4runtime_pb2.CounterData() + self._attrs = _CounterData.attrs_for_counter_type(counter_type) + + def __dir__(self): + return self._attrs + + def __setattr__(self, name, value): + if name[0] == "_": + super().__setattr__(name, value) + return + if name not in self._attrs: + type_name = p4info_pb2._COUNTERSPEC_UNIT.values_by_number[self._counter_type].name + raise UserError("Counter '{}' is of type '{}', you cannot set '{}'".format( + self._counter_name, type_name, name)) + if type(value) is not int: + raise UserError("{} must be an integer".format(name)) + setattr(self._msg, name, value) + + def __getattr__(self, name): + if name == "byte_count" or name == "packet_count": + return getattr(self._msg, name) + raise AttributeError("'{}' object has no attribute '{}'".format( + self.__class__.__name__, name)) + + def msg(self): + return self._msg + + def _from_msg(self, msg): + self._msg.CopyFrom(msg) + + def __str__(self): + return str(self.msg()) + + def _repr_pretty_(self, p, cycle): + p.text(str(self.msg())) + + @classmethod + def set_count(cls, instance, counter_name, counter_type, name, value): + if instance is None: + d = cls(counter_name, counter_type) + else: + d = instance + setattr(d, name, value) + return d + + @classmethod + def get_count(cls, instance, counter_name, counter_type, name): + if instance is None: + d = cls(counter_name, counter_type) + else: + d = instance + r = getattr(d, name) + return d, r + + +class _MeterConfig: + @staticmethod + def attrs(): + return ["cir", "cburst", "pir", "pburst", "eburst"] + + def __init__(self, meter_name, meter_type): + self._meter_name = meter_name + self._meter_type = meter_type + self._msg = p4runtime_pb2.MeterConfig() + self._attrs = _MeterConfig.attrs() + + def __dir__(self): + return self._attrs + + def __setattr__(self, name, value): + if name[0] == "_": + super().__setattr__(name, value) + return + if name in self._attrs: + if type(value) is not int: + raise UserError("{} must be an integer".format(name)) + setattr(self._msg, name, value) + + def __getattr__(self, name): + if name in self._attrs: + return getattr(self._msg, name) + raise AttributeError("'{}' object has no attribute '{}'".format( + self.__class__.__name__, name)) + + def msg(self): + return self._msg + + def _from_msg(self, msg): + self._msg.CopyFrom(msg) + + def __str__(self): + return str(self.msg()) + + def _repr_pretty_(self, p, cycle): + p.text(str(self.msg())) + + @classmethod + def set_param(cls, instance, meter_name, meter_type, name, value): + if instance is None: + d = cls(meter_name, meter_type) + else: + d = instance + setattr(d, name, value) + return d + + @classmethod + def get_param(cls, instance, meter_name, meter_type, name): + if instance is None: + d = cls(meter_name, meter_type) + else: + d = instance + r = getattr(d, name) + return d, r + + +class _IdleTimeout: + @staticmethod + def attrs(): + return ["elapsed_ns"] + + def __init__(self): + self._msg = p4runtime_pb2.TableEntry.IdleTimeout() + self._attrs = _IdleTimeout.attrs() + + def __dir__(self): + return self._attrs + + def __setattr__(self, name, value): + if name[0] == "_": + super().__setattr__(name, value) + return + if name in self._attrs: + if type(value) is not int: + raise UserError("{} must be an integer".format(name)) + setattr(self._msg, name, value) + + def __getattr__(self, name): + if name in self._attrs: + return getattr(self._msg, name) + raise AttributeError("'{}' object has no attribute '{}'".format( + self.__class__.__name__, name)) + + def msg(self): + return self._msg + + def _from_msg(self, msg): + self._msg.CopyFrom(msg) + + def __str__(self): + return str(self.msg()) + + def _repr_pretty_(self, p, cycle): + p.text(str(self.msg())) + + @classmethod + def set_param(cls, instance, name, value): + if instance is None: + d = cls() + else: + d = instance + setattr(d, name, value) + return d + + @classmethod + def get_param(cls, instance, name): + if instance is None: + d = cls() + else: + d = instance + r = getattr(d, name) + return d, r + + +class TableEntry(_P4EntityBase): + @enum.unique + class _ActionSpecType(enum.Enum): + NONE = 0 + DIRECT_ACTION = 1 + MEMBER_ID = 2 + GROUP_ID = 3 + ONESHOT = 4 + + @classmethod + def _action_spec_name_to_type(cls, name): + return { + "action": cls._ActionSpecType.DIRECT_ACTION, + "member_id": cls._ActionSpecType.MEMBER_ID, + "group_id": cls._ActionSpecType.GROUP_ID, + "oneshot": cls._ActionSpecType.ONESHOT, + }.get(name, None) + + def __init__(self, table_name=None): + super().__init__( + P4Type.table, P4RuntimeEntity.table_entry, + p4runtime_pb2.TableEntry, table_name) + self.match = MatchKey(table_name, self._info.match_fields) + self._action_spec_type = self._ActionSpecType.NONE + self._action_spec = None + self.priority = 0 + self.is_default = False + ap = _get_action_profile(table_name) + if ap is None: + self._support_members = False + self._support_groups = False + else: + self._support_members = True + self._support_groups = ap.with_selector + self._direct_counter = None + self._direct_meter = None + for res_id in self._info.direct_resource_ids: + prefix = (res_id & 0xff000000) >> 24 + if prefix == p4info_pb2.P4Ids.DIRECT_COUNTER: + self._direct_counter = context.get_obj_by_id(res_id) + elif prefix == p4info_pb2.P4Ids.DIRECT_METER: + self._direct_meter = context.get_obj_by_id(res_id) + self._counter_data = None + self._meter_config = None + self.idle_timeout_ns = 0 + self._time_since_last_hit = None + self._idle_timeout_behavior = None + table = context.get_table(table_name) + if table.idle_timeout_behavior > 0: + self._idle_timeout_behavior = table.idle_timeout_behavior + self.metadata = b"" + self.__doc__ = """ +An entry for table '{}' + +Use .info to display the P4Info entry for this table. + +To set the match key, use .match[''] = . +Type .match? for more details. +""".format(table_name) + if self._direct_counter is not None: + self.__doc__ += """ +To set the counter spec, use .counter_data.byte_count and/or .counter_data.packet_count. +To unset it, use .counter_data = None or .clear_counter_data(). +""" + if self._direct_meter is not None: + self.__doc__ += """ +To access the meter config, use .meter_config.. +To unset it, use .meter_config = None or .clear_meter_config(). +""" + if ap is None: + self.__doc__ += """ +To set the action specification (this is a direct table): +.action = . +To set the value of action parameters, use .action[''] = . +Type .action? for more details. +""" + if self._support_members: + self.__doc__ += """ +Access the member_id with .member_id. +""" + if self._support_groups: + self.__doc__ += """ +Or access the group_id with .group_id. +""" + if self._idle_timeout_behavior is not None: + self.__doc__ += """ +To access the time this entry was last hit, use .time_since_last_hit.elapsed_ns. +To unset it, use .time_since_last_hit = None or .clear_time_since_last_hit(). +""" + self.__doc__ += """ +To set the priority, use .priority = . + +To mark the entry as default, use .is_default = True. + +To add an idle timeout to the entry, use .idle_timeout_ns = . + +To add metadata to the entry, use .metadata = . +""" + if ap is None: + self.__doc__ += """ +Typical usage to insert a table entry: +t = table_entry[''](action='') +t.match[''] = ... +... +t.match[''] = ... +# OR t.match.set(f1=..., ..., fN=...) +t.action[''] = ... +... +t.action[''] = ... +# OR t.action.set(p1=..., ..., pM=...) +t.insert + +Typical usage to set the default entry: +t = table_entry[''](is_default=True) +t.action[''] = ... +... +t.action[''] = ... +# OR t.action.set(p1=..., ..., pM=...) +t.modify +""" + else: + self.__doc__ += """ +Typical usage to insert a table entry: +t = table_entry[''] +t.match[''] = ... +... +t.match[''] = ... +# OR t.match.set(f1=..., ..., fN=...) +t.member_id = +""" + self.__doc__ += """ +For information about how to read table entries, use .read? +""" + + self._init = True + + def __dir__(self): + d = super().__dir__() + [ + "match", "priority", "is_default", "idle_timeout_ns", "metadata", + "clear_action", "clear_match", "clear_counter_data", "clear_meter_config", + "clear_time_since_last_hit"] + if self._support_groups: + d.extend(["member_id", "group_id", "oneshot"]) + elif self._support_members: + d.append("member_id") + else: + d.append("action") + if self._direct_counter is not None: + d.append("counter_data") + if self._direct_meter is not None: + d.append("meter_config") + if self._idle_timeout_behavior is not None: + d.append("time_since_last_hit") + return d + + def __call__(self, **kwargs): + for name, value in kwargs.items(): + if name == "action" and type(value) is str: + value = Action(value) + setattr(self, name, value) + return self + + def _action_spec_set_member(self, member_id): + if type(member_id) is None: + if self._action_spec_type == self._ActionSpecType.MEMBER_ID: + super().__setattr__("_action_spec_type", self._ActionSpecType.NONE) + super().__setattr__("_action_spec", None) + return + if type(member_id) is not int: + raise UserError("member_id must be an integer") + if not self._support_members: + raise UserError( + "Table does not have an action profile and therefore does not support members") + super().__setattr__("_action_spec_type", self._ActionSpecType.MEMBER_ID) + super().__setattr__("_action_spec", member_id) + + def _action_spec_set_group(self, group_id): + if type(group_id) is None: + if self._action_spec_type == self._ActionSpecType.GROUP_ID: + super().__setattr__("_action_spec_type", self._ActionSpecType.NONE) + super().__setattr__("_action_spec", None) + return + if type(group_id) is not int: + raise UserError("group_id must be an integer") + if not self._support_groups: + raise UserError( + "Table does not have an action profile with selector " + "and therefore does not support groups") + super().__setattr__("_action_spec_type", self._ActionSpecType.GROUP_ID) + super().__setattr__("_action_spec", group_id) + + def _action_spec_set_action(self, action): + if type(action) is None: + if self._action_spec_type == self._ActionSpecType.DIRECT_ACTION: + super().__setattr__("_action_spec_type", self._ActionSpecType.NONE) + super().__setattr__("_action_spec", None) + return + if not isinstance(action, Action): + raise UserError("action must be an instance of Action") + if self._info.implementation_id != 0: + raise UserError( + "Table has an implementation and therefore does not support direct actions " + "(P4Runtime 1.0 doesn't support writing the default action for indirect tables") + if not self._is_valid_action_id(action._action_id): + raise UserError("action '{}' is not a valid action for this table".format( + action.action_name)) + super().__setattr__("_action_spec_type", self._ActionSpecType.DIRECT_ACTION) + super().__setattr__("_action_spec", action) + + def _action_spec_set_oneshot(self, oneshot): + if type(oneshot) is None: + if self._action_spec_type == self._ActionSpecType.ONESHOT: + super().__setattr__("_action_spec_type", self._ActionSpecType.NONE) + super().__setattr__("_action_spec", None) + return + if not isinstance(oneshot, Oneshot): + raise UserError("oneshot must be an instance of Oneshot") + if not self._support_groups: + raise UserError( + "Table does not have an action profile with selector " + "and therefore does not support oneshot programming") + if self.name != oneshot.table_name: + raise UserError("This Oneshot instance was not created for this table") + super().__setattr__("_action_spec_type", self._ActionSpecType.ONESHOT) + super().__setattr__("_action_spec", oneshot) + + def __setattr__(self, name, value): + if name[0] == "_" or not self._init: + super().__setattr__(name, value) + return + elif name == "name": + raise UserError("Cannot change table name") + elif name == "priority": + if type(value) is not int: + raise UserError("priority must be an integer") + elif name == "match" and not isinstance(value, MatchKey): + raise UserError("match must be an instance of MatchKey") + elif name == "is_default": + if type(value) is not bool: + raise UserError("is_default must be a boolean") + # TODO(antonin): should we do a better job and handle other cases (a field is set while + # is_default is set to True)? + if value is True and self.match._count() > 0: + _print("Clearing match key because entry is now default") + self.match.clear() + elif name == "member_id": + self._action_spec_set_member(value) + return + elif name == "group_id": + self._action_spec_set_group(value) + return + elif name == "oneshot": + self._action_spec_set_oneshot(value) + elif name == "action" and value is not None: + self._action_spec_set_action(value) + return + elif name == "counter_data": + if self._direct_counter is None: + raise UserError("Table has no direct counter") + if value is None: + self._counter_data = None + return + raise UserError("Cannot set 'counter_data' directly") + elif name == "meter_config": + if self._direct_meter is None: + raise UserError("Table has no direct meter") + if value is None: + self._meter_config = None + return + raise UserError("Cannot set 'meter_config' directly") + elif name == "idle_timeout_ns": + if type(value) is not int: + raise UserError("idle_timeout_ns must be an integer") + elif name == "time_since_last_hit": + if self._idle_timeout_behavior is None: + raise UserError("Table has no idle timeouts") + if value is None: + self._time_since_last_hit = None + return + raise UserError("Cannot set 'time_since_last_hit' directly") + elif name == "metadata": + if type(value) is not bytes: + raise UserError("metadata must be a byte string") + super().__setattr__(name, value) + + def __getattr__(self, name): + if name == "counter_data": + if self._direct_counter is None: + raise UserError("Table has no direct counter") + if self._counter_data is None: + self._counter_data = _CounterData( + self._direct_counter.preamble.name, self._direct_counter.spec.unit) + return self._counter_data + if name == "meter_config": + if self._direct_meter is None: + raise UserError("Table has no direct meter") + if self._meter_config is None: + self._meter_config = _MeterConfig( + self._direct_meter.preamble.name, self._direct_meter.spec.unit) + return self._meter_config + if name == "time_since_last_hit": + if self._idle_timeout_behavior is None: + raise UserError("Table has no idle timeouts") + if self._time_since_last_hit is None: + self._time_since_last_hit = _IdleTimeout() + return self._time_since_last_hit + + t = self._action_spec_name_to_type(name) + if t is None: + return super().__getattr__(name) + if self._action_spec_type == t: + return self._action_spec + if t == self._ActionSpecType.ONESHOT: + self._action_spec_type = self._ActionSpecType.ONESHOT + self._action_spec = Oneshot(self.name) + return self._action_spec + return None + + def _is_valid_action_id(self, action_id): + for action_ref in self._info.action_refs: + if action_id == action_ref.id: + return True + return False + + def _from_msg(self, msg): + self.priority = msg.priority + self.is_default = msg.is_default_action + self.idle_timeout_ns = msg.idle_timeout_ns + self.metadata = msg.metadata + for mf in msg.match: + mf_name = context.get_mf_name(self.name, mf.field_id) + self.match._mk[mf_name] = mf + if msg.action.HasField('action'): + action = msg.action.action + action_name = context.get_name_from_id(action.action_id) + self.action = Action(action_name) + self.action._from_msg(action) + elif msg.action.HasField('action_profile_member_id'): + self.member_id = msg.action.action_profile_member_id + elif msg.action.HasField('action_profile_group_id'): + self.group_id = msg.action.action_profile_group_id + elif msg.action.HasField('action_profile_action_set'): + self.oneshot = Oneshot(self.name) + self.oneshot._from_msg(msg.action.action_profile_action_set) + if msg.HasField('counter_data'): + self._counter_data = _CounterData( + self._direct_counter.preamble.name, self._direct_counter.spec.unit) + self._counter_data._from_msg(msg.counter_data) + else: + self._counter_data = None + if msg.HasField('meter_config'): + self._meter_config = _MeterConfig( + self._direct_meter.preamble.name, self._direct_meter.spec.unit) + self._meter_config._from_msg(msg.meter_config) + else: + self._meter_config = None + if msg.HasField("time_since_last_hit"): + self._time_since_last_hit = _IdleTimeout() + self._time_since_last_hit._from_msg(msg.time_since_last_hit) + else: + self._time_since_last_hit = None + + def read(self, function=None): + """Generate a P4Runtime Read RPC. Supports wildcard reads (just leave + the appropriate fields unset). + If function is None, returns an iterator. Iterate over it to get all the + table entries (TableEntry instances) returned by the server. Otherwise, + function is applied to all the table entries returned by the server. + + For example: + for te in .read(): + print(te) + The above code is equivalent to the following one-liner: + .read(lambda te: print(te)) + + To delete all the entries from a table, simply use: + table_entry[''].read(function=lambda x: x.delete()) + """ + return super().read(function) + + def _update_msg(self): + entry = p4runtime_pb2.TableEntry() + entry.table_id = self.id + entry.match.extend(self.match._mk.values()) + entry.priority = self.priority + entry.is_default_action = self.is_default + entry.idle_timeout_ns = self.idle_timeout_ns + entry.metadata = self.metadata + if self._action_spec_type == self._ActionSpecType.DIRECT_ACTION: + entry.action.action.CopyFrom(self._action_spec.msg()) + elif self._action_spec_type == self._ActionSpecType.MEMBER_ID: + entry.action.action_profile_member_id = self._action_spec + elif self._action_spec_type == self._ActionSpecType.GROUP_ID: + entry.action.action_profile_group_id = self._action_spec + elif self._action_spec_type == self._ActionSpecType.ONESHOT: + entry.action.action_profile_action_set.CopyFrom(self._action_spec.msg()) + if self._counter_data is None: + entry.ClearField('counter_data') + else: + entry.counter_data.CopyFrom(self._counter_data.msg()) + if self._meter_config is None: + entry.ClearField('meter_config') + else: + entry.meter_config.CopyFrom(self._meter_config.msg()) + if self._time_since_last_hit is None: + entry.ClearField("time_since_last_hit") + else: + entry.time_since_last_hit.CopyFrom(self._time_since_last_hit.msg()) + self._entry = entry + + def _validate_msg(self): + if self.is_default and self.match._count() > 0: + raise UserError( + "Match key must be empty for default entry, use .is_default = False " + "or .match.clear (whichever one is appropriate)") + + def clear_action(self): + """Clears the action spec for the TableEntry.""" + super().__setattr__("_action_spec_type", self._ActionSpecType.NONE) + super().__setattr__("_action_spec", None) + + def clear_match(self): + """Clears the match spec for the TableEntry.""" + self.match.clear() + + def clear_counter_data(self): + """Clear all counter data, same as .counter_data = None""" + self._counter_data = None + + def clear_meter_config(self): + """Clear the meter config, same as .meter_config = None""" + self._meter_config = None + + def clear_time_since_last_hit(self): + """Clear the idle timeout, same as .time_since_last_hit = None""" + self._time_since_last_hit = None + + +class _CounterEntryBase(_P4EntityBase): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._counter_type = self._info.spec.unit + self._data = None + + def __dir__(self): + return super().__dir__() + _CounterData.attrs_for_counter_type(self._counter_type) + [ + "clear_data"] + + def __call__(self, **kwargs): + for name, value in kwargs.items(): + setattr(self, name, value) + return self + + def __setattr__(self, name, value): + if name[0] == "_" or not self._init: + super().__setattr__(name, value) + return + if name == "name": + raise UserError("Cannot change counter name") + if name == "byte_count" or name == "packet_count": + self._data = _CounterData.set_count( + self._data, self.name, self._counter_type, name, value) + return + if name == "data": + if value is None: + self._data = None + return + raise UserError("Cannot set 'data' directly") + super().__setattr__(name, value) + + def __getattr__(self, name): + if name == "byte_count" or name == "packet_count": + self._data, r = _CounterData.get_count( + self._data, self.name, self._counter_type, name) + return r + if name == "data": + if self._data is None: + self._data = _CounterData(self.name, self._counter_type) + return self._data + return super().__getattr__(name) + + def _from_msg(self, msg): + self._entry.CopyFrom(msg) + if msg.HasField('data'): + self._data = _CounterData(self.name, self._counter_type) + self._data._from_msg(msg.data) + else: + self._data = None + + def _update_msg(self): + if self._data is None: + self._entry.ClearField('data') + else: + self._entry.data.CopyFrom(self._data.msg()) + + def clear_data(self): + """Clear all counter data, same as .data = None""" + self._data = None + + +class CounterEntry(_CounterEntryBase): + def __init__(self, counter_name=None): + super().__init__( + P4Type.counter, P4RuntimeEntity.counter_entry, + p4runtime_pb2.CounterEntry, counter_name, + modify_only=True) + self._entry.counter_id = self.id + self.__doc__ = """ +An entry for counter '{}' + +Use .info to display the P4Info entry for this counter. + +Set the index with .index = . +To reset it (e.g. for wildcard read), set it to None. + +Access byte count and packet count with .byte_count / .packet_count. + +To read from the counter, use .read +To write to the counter, use .modify +""".format(counter_name) + self._init = True + + def __dir__(self): + return super().__dir__() + ["index", "data"] + + def __setattr__(self, name, value): + if name == "index": + if value is None: + self._entry.ClearField('index') + return + if type(value) is not int: + raise UserError("index must be an integer") + self._entry.index.index = value + return + super().__setattr__(name, value) + + def __getattr__(self, name): + if name == "index": + return self._entry.index.index + return super().__getattr__(name) + + def read(self, function=None): + """Generate a P4Runtime Read RPC. Supports wildcard reads (just leave + the index unset). + If function is None, returns an iterator. Iterate over it to get all the + counter entries (CounterEntry instances) returned by the + server. Otherwise, function is applied to all the counter entries + returned by the server. + + For example: + for c in .read(): + print(c) + The above code is equivalent to the following one-liner: + .read(lambda c: print(c)) + """ + return super().read(function) + + +class DirectCounterEntry(_CounterEntryBase): + def __init__(self, direct_counter_name=None): + super().__init__( + P4Type.direct_counter, P4RuntimeEntity.direct_counter_entry, + p4runtime_pb2.DirectCounterEntry, direct_counter_name, + modify_only=True) + self._direct_table_id = self._info.direct_table_id + try: + self._direct_table_name = context.get_name_from_id(self._direct_table_id) + except KeyError: + raise InvalidP4InfoError("direct_table_id {} is not a valid table id".format( + self._direct_table_id)) + self._table_entry = TableEntry(self._direct_table_name) + self.__doc__ = """ +An entry for direct counter '{}' + +Use .info to display the P4Info entry for this direct counter. + +Set the table_entry with .table_entry = . +The TableEntry instance must be for the table to which the direct counter is attached. +To reset it (e.g. for wildcard read), set it to None. It is the same as: +.table_entry = TableEntry({}) + +Access byte count and packet count with .byte_count / .packet_count. + +To read from the counter, use .read +To write to the counter, use .modify +""".format(direct_counter_name, self._direct_table_name) + self._init = True + + def __dir__(self): + return super().__dir__() + ["table_entry"] + + def __setattr__(self, name, value): + if name == "index": + raise UserError("Direct counters are not index-based") + if name == "table_entry": + if value is None: + self._table_entry = TableEntry(self._direct_table_name) + return + if not isinstance(value, TableEntry): + raise UserError("table_entry must be an instance of TableEntry") + if value.name != self._direct_table_name: + raise UserError("This DirectCounterEntry is for table '{}'".format( + self._direct_table_name)) + self._table_entry = value + return + super().__setattr__(name, value) + + def __getattr__(self, name): + if name == "index": + raise UserError("Direct counters are not index-based") + if name == "table_entry": + return self._table_entry + return super().__getattr__(name) + + def _update_msg(self): + super()._update_msg() + if self._table_entry is None: + self._entry.ClearField('table_entry') + else: + self._entry.table_entry.CopyFrom(self._table_entry.msg()) + + def _from_msg(self, msg): + super()._from_msg(msg) + if msg.HasField('table_entry'): + self._table_entry._from_msg(msg.table_entry) + else: + self._table_entry = None + + def read(self, function=None): + """Generate a P4Runtime Read RPC. Supports wildcard reads (just leave + the index unset). + If function is None, returns an iterator. Iterate over it to get all the + direct counter entries (DirectCounterEntry instances) returned by the + server. Otherwise, function is applied to all the direct counter entries + returned by the server. + + For example: + for c in .read(): + print(c) + The above code is equivalent to the following one-liner: + .read(lambda c: print(c)) + """ + return super().read(function) + + +class _MeterEntryBase(_P4EntityBase): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._meter_type = self._info.spec.unit + self._config = None + + def __dir__(self): + return super().__dir__() + _MeterConfig.attrs() + ["clear_config"] + + def __call__(self, **kwargs): + for name, value in kwargs.items(): + setattr(self, name, value) + return self + + def __setattr__(self, name, value): + if name[0] == "_" or not self._init: + super().__setattr__(name, value) + return + if name == "name": + raise UserError("Cannot change meter name") + if name in _MeterConfig.attrs(): + self._config = _MeterConfig.set_param( + self._config, self.name, self._meter_type, name, value) + return + if name == "config": + if value is None: + self._config = None + return + raise UserError("Cannot set 'config' directly") + super().__setattr__(name, value) + + def __getattr__(self, name): + if name in _MeterConfig.attrs(): + self._config, r = _MeterConfig.get_param( + self._config, self.name, self._meter_type, name) + return r + if name == "config": + if self._config is None: + self._config = _MeterConfig(self.name, self._meter_type) + return self._config + return super().__getattr__(name) + + def _from_msg(self, msg): + self._entry.CopyFrom(msg) + if msg.HasField('config'): + self._config = _MeterConfig(self.name, self._meter_type) + self._config._from_msg(msg.config) + else: + self._config = None + + def _update_msg(self): + if self._config is None: + self._entry.ClearField('config') + else: + self._entry.config.CopyFrom(self._config.msg()) + + def clear_config(self): + """Clear the meter config, same as .config = None""" + self._config = None + + +class MeterEntry(_MeterEntryBase): + def __init__(self, meter_name=None): + super().__init__( + P4Type.meter, P4RuntimeEntity.meter_entry, + p4runtime_pb2.MeterEntry, meter_name, + modify_only=True) + self._entry.meter_id = self.id + self.__doc__ = """ +An entry for meter '{}' + +Use .info to display the P4Info entry for this meter. + +Set the index with .index = . +To reset it (e.g. for wildcard read), set it to None. + +Access meter rates and burst sizes with: +.cir +.cburst +.pir +.pburst +.eburst + +To read from the meter, use .read +To write to the meter, use .modify +""".format(meter_name) + self._init = True + + def __dir__(self): + return super().__dir__() + ["index", "config"] + + def __setattr__(self, name, value): + if name == "index": + if value is None: + self._entry.ClearField('index') + return + if type(value) is not int: + raise UserError("index must be an integer") + self._entry.index.index = value + return + super().__setattr__(name, value) + + def __getattr__(self, name): + if name == "index": + return self._entry.index.index + return super().__getattr__(name) + + def read(self, function=None): + """Generate a P4Runtime Read RPC. Supports wildcard reads (just leave + the index unset). + If function is None, returns an iterator. Iterate over it to get all the + meter entries (MeterEntry instances) returned by the + server. Otherwise, function is applied to all the meter entries + returned by the server. + + For example: + for c in .read(): + print(c) + The above code is equivalent to the following one-liner: + .read(lambda c: print(c)) + """ + return super().read(function) + + +class DirectMeterEntry(_MeterEntryBase): + def __init__(self, direct_meter_name=None): + super().__init__( + P4Type.direct_meter, P4RuntimeEntity.direct_meter_entry, + p4runtime_pb2.DirectMeterEntry, direct_meter_name, + modify_only=True) + self._direct_table_id = self._info.direct_table_id + try: + self._direct_table_name = context.get_name_from_id(self._direct_table_id) + except KeyError: + raise InvalidP4InfoError("direct_table_id {} is not a valid table id".format( + self._direct_table_id)) + self._table_entry = TableEntry(self._direct_table_name) + self.__doc__ = """ +An entry for direct meter '{}' + +Use .info to display the P4Info entry for this direct meter. + +Set the table_entry with .table_entry = . +The TableEntry instance must be for the table to which the direct meter is attached. +To reset it (e.g. for wildcard read), set it to None. It is the same as: +.table_entry = TableEntry({}) + +Access meter rates and burst sizes with: +.cir +.cburst +.pir +.pburst +.eburst + +To read from the meter, use .read +To write to the meter, use .modify +""".format(direct_meter_name, self._direct_table_name) + self._init = True + + def __dir__(self): + return super().__dir__() + ["table_entry"] + + def __setattr__(self, name, value): + if name == "index": + raise UserError("Direct meters are not index-based") + if name == "table_entry": + if value is None: + self._table_entry = TableEntry(self._direct_table_name) + return + if not isinstance(value, TableEntry): + raise UserError("table_entry must be an instance of TableEntry") + if value.name != self._direct_table_name: + raise UserError("This DirectMeterEntry is for table '{}'".format( + self._direct_table_name)) + self._table_entry = value + return + super().__setattr__(name, value) + + def __getattr__(self, name): + if name == "index": + raise UserError("Direct meters are not index-based") + if name == "table_entry": + return self._table_entry + return super().__getattr__(name) + + def _update_msg(self): + super()._update_msg() + if self._table_entry is None: + self._entry.ClearField('table_entry') + else: + self._entry.table_entry.CopyFrom(self._table_entry.msg()) + + def _from_msg(self, msg): + super()._from_msg(msg) + if msg.HasField('table_entry'): + self._table_entry._from_msg(msg.table_entry) + else: + self._table_entry = None + + def read(self, function=None): + """Generate a P4Runtime Read RPC. Supports wildcard reads (just leave + the index unset). + If function is None, returns an iterator. Iterate over it to get all the + direct meter entries (DirectMeterEntry instances) returned by the + server. Otherwise, function is applied to all the direct meter entries + returned by the server. + + For example: + for c in .read(): + print(c) + The above code is equivalent to the following one-liner: + .read(lambda c: print(c)) + """ + return super().read(function) + + +class P4RuntimeEntityBuilder: + def __init__(self, obj_type, entity_type, entity_cls): + self._obj_type = obj_type + self._names = sorted([name for name, _ in context.get_objs(obj_type)]) + self._entity_type = entity_type + self._entity_cls = entity_cls + self.__doc__ = """Construct a {} entity +Usage: = {}["<{} name>"] +This is equivalent to = {}(<{} name>) +Use command '{}' to see list of {} + """.format(entity_cls.__name__, entity_type.name, obj_type.pretty_name, + entity_cls.__name__, obj_type.pretty_name, + obj_type.p4info_name, obj_type.pretty_names) + + def _ipython_key_completions_(self): + return self._names + + def __getitem__(self, name): + obj = context.get_obj(self._obj_type, name) + if obj is None: + raise UserError("{} '{}' does not exist".format( + self._obj_type.pretty_name, name)) + return self._entity_cls(name) + + def __setitem__(self, name, value): + raise UserError("Operation not allowed") + + def _repr_pretty_(self, p, cycle): + p.text(self.__doc__) + + def __str__(self): + return "Construct a {} entity".format(self.entity_cls.__name__) + + +class Replica: + """ + A port "replica" (port number + instance id) used for multicast and clone session programming. + Construct with Replica(egress_port, instance=). + You can set / get attributes egress_port (required), instance (default 0). + """ + def __init__(self, egress_port=None, instance=0): + if egress_port is None: + raise UserError("egress_port is required") + self._msg = p4runtime_pb2.Replica() + self._msg.egress_port = egress_port + self._msg.instance = instance + + def __dir__(self): + return ["port", "egress_port", "instance"] + + def __setattr__(self, name, value): + if name[0] == "_": + super().__setattr__(name, value) + return + if name == "egress_port" or name == "port": + if type(value) is not int: + raise UserError("egress_port must be an integer") + self._msg.egress_port = value + return + if name == "instance": + if type(value) is not int: + raise UserError("instance must be an integer") + self._msg.instance = value + return + super().__setattr__(name, value) + + def __getattr__(self, name): + if name == "egress_port" or name == "port": + return self._msg.egress_port + if name == "instance": + return self._msg.instance + return super().__getattr__(name) + + def __str__(self): + return str(self._msg) + + def _repr_pretty_(self, p, cycle): + p.text(str(p)) + + +class MulticastGroupEntry(_EntityBase): + def __init__(self, group_id=0): + super().__init__( + P4RuntimeEntity.packet_replication_engine_entry, + p4runtime_pb2.PacketReplicationEngineEntry) + self.group_id = group_id + self.replicas = [] + self.__doc__ = """ +Multicast group entry. +Create an instance with multicast_group_entry(). +Add replicas with .add(, ).add(, )... +""" + self._init = True + + def __dir__(self): + return ["group_id", "replicas"] + + def __setattr__(self, name, value): + if name[0] == "_": + super().__setattr__(name, value) + return + elif name == "group_id": + if type(value) is not int: + raise UserError("group_id must be an integer") + elif name == "replicas": + if type(value) is not list: + raise UserError("replicas must be a list of Replica objects") + for r in value: + if type(r) is not Replica: + raise UserError("replicas must be a list of Replica objects") + super().__setattr__(name, value) + + def _from_msg(self, msg): + self.group_id = msg.multicast_group_entry.multicast_group_id + for r in msg.multicast_group_entry.replicas: + self.add(r.egress_port, r.instance) + + def read(self, function=None): + """Generate a P4Runtime Read RPC. Supports wildcard reads (just leave + the group_id as 0). + If function is None, returns an iterator. Iterate over it to get all the + multicast group entries (MulticastGroupEntry instances) returned by the + server. Otherwise, function is applied to all the multicast group entries + returned by the server. + + For example: + for c in .read(): + print(c) + The above code is equivalent to the following one-liner: + .read(lambda c: print(c)) + """ + return super().read(function) + + def _update_msg(self): + entry = p4runtime_pb2.PacketReplicationEngineEntry() + mcg_entry = entry.multicast_group_entry + mcg_entry.multicast_group_id = self.group_id + for replica in self.replicas: + r = mcg_entry.replicas.add() + r.CopyFrom(replica._msg) + self._entry = entry + + def add(self, egress_port=None, instance=0): + """Add a replica to the multicast group.""" + self.replicas.append(Replica(egress_port, instance)) + return self + + def _write(self, type_): + if self.group_id == 0: + raise UserError("0 is not a valid group_id for MulticastGroupEntry") + super()._write(type_) + + +class CloneSessionEntry(_EntityBase): + def __init__(self, session_id=0): + super().__init__( + P4RuntimeEntity.packet_replication_engine_entry, + p4runtime_pb2.PacketReplicationEngineEntry) + self.session_id = session_id + self.replicas = [] + self.cos = 0 + self.packet_length_bytes = 0 + self.__doc__ = """ +Clone session entry. +Create an instance with clone_session_entry(). +Add replicas with .add(, ).add(, )... +Access class of service with .cos. +Access truncation length with .packet_length_bytes. +""" + self._init = True + + def __dir__(self): + return ["session_id", "replicas", "cos", "packet_length_bytes"] + + def __setattr__(self, name, value): + if name[0] == "_": + super().__setattr__(name, value) + return + elif name == "session_id": + if type(value) is not int: + raise UserError("session_id must be an integer") + elif name == "replicas": + if type(value) is not list: + raise UserError("replicas must be a list of Replica objects") + for r in value: + if type(r) is not Replica: + raise UserError("replicas must be a list of Replica objects") + elif name == "cos": + if type(value) is not int: + raise UserError("cos must be an integer") + elif name == "packet_length_bytes": + if type(value) is not int: + raise UserError("packet_length_bytes must be an integer") + super().__setattr__(name, value) + + def _from_msg(self, msg): + self.session_id = msg.clone_session_entry.session_id + for r in msg.clone_session_entry.replicas: + self.add(r.egress_port, r.instance) + self.cos = msg.clone_session_entry.class_of_service + self.packet_length_bytes = msg.clone_session_entry.packet_length_bytes + + def read(self, function=None): + """Generate a P4Runtime Read RPC. Supports wildcard reads (just leave + the session_id as 0). + If function is None, returns an iterator. Iterate over it to get all the + clone session entries (CloneSessionEntry instances) returned by the + server. Otherwise, function is applied to all the clone session entries + returned by the server. + + For example: + for c in .read(): + print(c) + The above code is equivalent to the following one-liner: + .read(lambda c: print(c)) + """ + return super().read(function) + + def _update_msg(self): + entry = p4runtime_pb2.PacketReplicationEngineEntry() + cs_entry = entry.clone_session_entry + cs_entry.session_id = self.session_id + for replica in self.replicas: + r = cs_entry.replicas.add() + r.CopyFrom(replica._msg) + cs_entry.class_of_service = self.cos + cs_entry.packet_length_bytes = self.packet_length_bytes + self._entry = entry + + def add(self, egress_port=None, instance=0): + """Add a replica to the clone session.""" + self.replicas.append(Replica(egress_port, instance)) + return self + + def _write(self, type_): + if self.session_id == 0: + raise UserError("0 is not a valid group_id for CloneSessionEntry") + super()._write(type_) + + +class DigestEntry(_P4EntityBase): + def __init__(self, digest_name=None): + super().__init__( + P4Type.digest, P4RuntimeEntity.digest_entry, + p4runtime_pb2.DigestEntry, digest_name) + self.max_timeout_ns = 0 + self.max_list_size = 0 + self.ack_timeout_ns = 0 + self.__doc__ = """ +Digest entry for digest '{}'. +Create an instance with digest_entry(). + +Use .info to display the P4Info entry for this digest. +""".format(digest_name) + self._init = True + + def __dir__(self): + return super().__dir__() + [ + "digest_id", "max_timeout_ns", "max_list_size", "ack_timeout_ns"] + + def __setattr__(self, name, value): + if name[0] == "_": + super().__setattr__(name, value) + return + elif name == "digest_id": + if type(value) is not int: + raise UserError("digest_id must be an integer") + elif name == "max_timeout_ns": + if type(value) is not int: + raise UserError("max_timeout_ns must be an integer") + elif name == "max_list_size": + if type(value) is not int: + raise UserError("max_list_size must be an integer") + elif name == "ack_timeout_ns": + if type(value) is not int: + raise UserError("ack_timeout_ns must be an integer") + super().__setattr__(name, value) + + def __getattr__(self, name): + if name == "digest_id": + return self.id + if name == "max_timeout_ns": + return self.max_timeout_ns + if name == "max_list_size": + return self.max_list_size + if name == "ack_timeout_ns": + return self.ack_timeout_ns + return super().__getattr__(name) + + def _from_msg(self, msg): + self.id = msg.digest_id + self.max_timeout_ns = msg.config.max_timeout_ns + self.max_list_size = msg.config.max_list_size + self.ack_timeout_ns = msg.config.ack_timeout_ns + + def __str__(self): + self._update_msg() + return str(_repr_pretty_p4runtime(self._entry)) + + def _repr_pretty_(self, p, cycle): + self._update_msg() + p.text(_repr_pretty_p4runtime(self._entry)) + + def _update_msg(self): + digest_entry = p4runtime_pb2.DigestEntry() + digest_entry.digest_id = self.id + digest_entry.config.max_timeout_ns = self.max_timeout_ns + digest_entry.config.max_list_size = self.max_list_size + digest_entry.config.ack_timeout_ns = self.ack_timeout_ns + self._entry = digest_entry + + def read(self, function=None): + """Generate a P4Runtime Read RPC. Supports wildcard reads (just leave + the digest_id as 0). + If function is None, returns an iterator. Iterate over it to get all the + multicast digest entries (DigestEntry instances) returned by the server. + Otherwise, function is applied to all the digest entries returned by the + server. + + For example: + for c in .read(): + print(c) + The above code is equivalent to the following one-liner: + .read(lambda c: print(c)) + """ + return super().read(function) + + def _write(self, type_): + if self.id == 0: + raise UserError("0 is not a valid digest_id for DigestEntry") + super()._write(type_) + + +class PacketMetadata: + def __init__(self, metadata_info_list): + self._md_info = OrderedDict() + self._md = OrderedDict() + # Initialize every metadata to zero value + for md in metadata_info_list: + self._md_info[md.name] = md + self._md[md.name] = self._parse_md('0', md) + self._set_docstring() + + def _set_docstring(self): + self.__doc__ = "Available metadata:\n\n" + for name, info in self._md_info.items(): + self.__doc__ += str(info) + self.__doc__ += """ +Set a metadata value with .[''] = '...' + +You may also use .set(='') +""" + + def __dir__(self): + return ["clear"] + + def _get_md_info(self, name): + if name in self._md_info: + return self._md_info[name] + raise UserError("'{}' is not a valid metadata name".format(name)) + + def __getitem__(self, name): + _ = self._get_md_info(name) + _print(self._md.get(name, "Unset")) + + def _parse_md(self, value, md_info): + if type(value) is not str: + raise UserError("Metadata value must be a string") + md = p4runtime_pb2.PacketMetadata() + md.metadata_id = md_info.id + md.value = bytes_utils.parse_value(value.strip(), md_info.bitwidth) + return md + + def __setitem__(self, name, value): + md_info = self._get_md_info(name) + self._md[name] = self._parse_md(value, md_info) + + def _ipython_key_completions_(self): + return self._md_info.keys() + + def set(self, **kwargs): + for name, value in kwargs.items(): + self[name] = value + + def clear(self): + self._md.clear() + + def values(self): + return self._md.values() + + +class PacketIn(): + def __init__(self): + ctrl_pkt_md = P4Objects(P4Type.controller_packet_metadata) + self.md_info_list = {} + if "packet_in" in ctrl_pkt_md: + self.p4_info = ctrl_pkt_md["packet_in"] + for md_info in self.p4_info.metadata: + self.md_info_list[md_info.name] = md_info + self.packet_in_queue = queue.Queue() + + def _packet_in_recv_func(packet_in_queue): + while True: + msg = client.get_stream_packet("packet", timeout=None) + if not msg: + break + packet_in_queue.put(msg) + + self.recv_t = Thread(target=_packet_in_recv_func, args=(self.packet_in_queue, )) + self.recv_t.start() + + def sniff(self, function=None, timeout=None): + """ + Return an iterator of packet-in messages. + If the function is provided, we do not return an iterator and instead we apply + the function to every packet-in message. + """ + msgs = [] + + if timeout is not None and timeout < 0: + raise ValueError("Timeout can't be a negative number.") + + if timeout is None: + while True: + try: + msgs.append(self.packet_in_queue.get(block=True)) + except KeyboardInterrupt: + # User sends a Ctrl+C -> breaking + break + + else: # timeout parameter is provided + deadline = time.time() + timeout + remaining_time = timeout + while remaining_time > 0: + try: + msgs.append(self.packet_in_queue.get(block=True, timeout=remaining_time)) + remaining_time = deadline - time.time() + except KeyboardInterrupt: + # User sends an interrupt(e.g., Ctrl+C). + break + except queue.Empty: + # No item available on timeout. Exiting + break + + if function is None: + return iter(msgs) + else: + for msg in msgs: + function(msg) + + +class PacketOut: + def __init__(self, payload=b'', **kwargs): + + self.p4_info = P4Objects(P4Type.controller_packet_metadata)["packet_out"] + self.payload = payload + self.metadata = PacketMetadata(self.p4_info.metadata) + if kwargs: + for key, value in kwargs.items(): + self.metadata[key] = value + + def _update_msg(self): + self._entry = p4runtime_pb2.PacketOut() + self._entry.payload = self.payload + self._entry.metadata.extend(self.metadata.values()) + + def __setattr__(self, name, value): + if name == "payload" and type(value) is not bytes: + raise UserError("payload must be a bytes type") + if name == "metadata" and type(value) is not PacketMetadata: + raise UserError("metadata must be a PacketMetadata type") + return super().__setattr__(name, value) + + def __dir__(self): + return ["metadata", "send", "payload"] + + def __str__(self): + self._update_msg() + return str(_repr_pretty_p4runtime(self._entry)) + + def _repr_pretty_(self, p, cycle): + self._update_msg() + p.text(_repr_pretty_p4runtime(self._entry)) + + def send(self): + self._update_msg() + msg = p4runtime_pb2.StreamMessageRequest() + msg.packet.CopyFrom(self._entry) + client.stream_out_q.put(msg) + + +class IdleTimeoutNotification(): + def __init__(self): + self.notification_queue = queue.Queue() + + def _notification_recv_func(notification_queue): + while True: + msg = client.get_stream_packet("idle_timeout_notification", timeout=None) + if not msg: + break + notification_queue.put(msg) + + self.recv_t = Thread(target=_notification_recv_func, args=(self.notification_queue, )) + self.recv_t.start() + + def sniff(self, function=None, timeout=None): + """ + Return an iterator of notification messages. + If the function is provided, we do not return an iterator and instead we apply + the function to every notification message. + """ + msgs = [] + + if timeout is not None and timeout < 0: + raise ValueError("Timeout can't be a negative number.") + + if timeout is None: + while True: + try: + msgs.append(self.notification_queue.get(block=True)) + except KeyboardInterrupt: + # User sends a Ctrl+C -> breaking + break + + else: # timeout parameter is provided + deadline = time.time() + timeout + remaining_time = timeout + while remaining_time > 0: + try: + msgs.append(self.notification_queue.get(block=True, timeout=remaining_time)) + remaining_time = deadline - time.time() + except KeyboardInterrupt: + # User sends an interrupt(e.g., Ctrl+C). + break + except queue.Empty: + # No item available on timeout. Exiting + break + + if function is None: + return iter(msgs) + else: + for msg in msgs: + function(msg) + + +class DigestList(): + def __init__(self): + self.digest_list_queue = queue.Queue() + + def _notification_recv_func(digest_list_queue): + while True: + msg = client.get_stream_packet("digest", timeout=None) + if not msg: + break + digest_list_queue.put(msg) + # Acknowledge the digest + ack = p4runtime_pb2.StreamMessageRequest() + ack.digest_ack.digest_id = msg.digest.digest_id + ack.digest_ack.list_id = msg.digest.list_id + client.stream_out_q.put(ack) + + self.recv_t = Thread(target=_notification_recv_func, args=(self.digest_list_queue, )) + self.recv_t.start() + + def sniff(self, function=None, timeout=None): + """ + Return an iterator of DigestList messages. + If the function is provided, we do not return an iterator and instead we apply + the function to every notification message. + """ + msgs = [] + + if timeout is not None and timeout < 0: + raise ValueError("Timeout can't be a negative number.") + + if timeout is None: + while True: + try: + msgs.append(self.digest_list_queue.get(block=True)) + except KeyboardInterrupt: + # User sends a Ctrl+C -> breaking + break + + else: # timeout parameter is provided + deadline = time.time() + timeout + remaining_time = timeout + while remaining_time > 0: + try: + msgs.append(self.digest_list_queue.get(block=True, timeout=remaining_time)) + remaining_time = deadline - time.time() + except KeyboardInterrupt: + # User sends an interrupt(e.g., Ctrl+C). + break + except queue.Empty: + # No item available on timeout. Exiting + break + + if function is None: + return iter(msgs) + else: + for msg in msgs: + function(msg) + + +def Write(input_): + """ + Reads a WriteRequest from a file (text format) and sends it to the server. + It rewrites the device id and election id appropriately. + """ + req = p4runtime_pb2.WriteRequest() + if os.path.isfile(input_): + with open(input_, 'r') as f: + google.protobuf.text_format.Merge(f.read(), req) + client.write(req) + else: + raise UserError( + "Write only works with files at the moment and '{}' is not a file".format( + input_)) + + +def APIVersion(): + """ + Returns the version of the P4Runtime API implemented by the server, using + the Capabilities RPC. + """ + return client.api_version() + + +# see https://ipython.readthedocs.io/en/stable/config/details.html +class MyPrompt(Prompts): + def in_prompt_tokens(self, cli=None): + return [(Token.Prompt, 'P4Runtime sh'), + (Token.PrompSeparator, ' >>> ')] + + +FwdPipeConfig = namedtuple('FwdPipeConfig', ['p4info', 'bin']) + + +def get_arg_parser(): + def election_id(arg): + try: + nums = tuple(int(x) for x in arg.split(',')) + if len(nums) != 2: + raise argparse.ArgumentError + return nums + except Exception: + raise argparse.ArgumentError( + "Invalid election id, expected ,") + + def pipe_config(arg): + try: + paths = FwdPipeConfig(*[x for x in arg.split(',')]) + if len(paths) != 2: + raise argparse.ArgumentError + return paths + except Exception: + raise argparse.ArgumentError( + "Invalid pipeline config, expected ,") + + parser = argparse.ArgumentParser(description='P4Runtime shell') + parser.add_argument('--device-id', + help='Device id', + type=int, action='store', default=1) + parser.add_argument('--grpc-addr', + help='P4Runtime gRPC server address', + metavar=':', + type=str, action='store', default='localhost:9559') + parser.add_argument('-v', '--verbose', help='Increase output verbosity', + action='store_true') + parser.add_argument('--election-id', + help='Election id to use', + metavar=',', + type=election_id, action='store', default=(1, 0)) + parser.add_argument('--role-name', + help='Role name of this client', + type=str, action='store') + parser.add_argument('--config', + help='If you want the shell to push a pipeline config to the server first', + metavar=',', + type=pipe_config, action='store', default=None) + parser.add_argument('--ssl', + help='Use secure SSL/TLS gRPC channel to connect to the P4Runtime server', + action='store_true') + parser.add_argument('--no-ssl', + help='Use insecure gRPC channel to connect to the P4Runtime server', + action='store_false') + # Setting the default to False (insecure) for backwards-compatibility. May + # switch it to true in the future. + parser.set_defaults(ssl=False) + parser.add_argument('--cacert', + help='CA certificate to verify peer against, for secure connections', + metavar='', + type=str, action='store', default=None) + parser.add_argument('--cert', + help='Path to client certificate, for mutual authentication', + metavar='', + type=str, action='store', default=None) + parser.add_argument('--private-key', + help='Path to client private key, for mutual authentication', + metavar='', + type=str, action='store', default=None) + + return parser + + +def setup(device_id=1, + grpc_addr='localhost:9559', + election_id=(1, 0), + role_name=None, + config=None, + ssl_options=None, + verbose=True): + global client + logging.debug("Creating P4Runtime client") + client = P4RuntimeClient(device_id, grpc_addr, election_id, role_name, ssl_options) + + if config is not None: + try: + p4info_path = config.p4info + bin_path = config.bin + except Exception: + raise ValueError("Argument 'config' must be a FwdPipeConfig namedtuple") + + try: + client.set_fwd_pipe_config(p4info_path, bin_path) + except FileNotFoundError as e: + logging.critical(e) + client.tear_down() + sys.exit(1) + except P4RuntimeException as e: + logging.critical("Error when setting config") + logging.critical(e) + client.tear_down() + sys.exit(1) + except Exception: + logging.critical("Error when setting config") + client.tear_down() + sys.exit(1) + + try: + p4info = client.get_p4info() + except P4RuntimeException as e: + logging.critical("Error when retrieving P4Info") + logging.critical(e) + client.tear_down() + sys.exit(1) + + logging.debug("Parsing P4Info message") + context.set_p4info(p4info) + global_options["verbose"] = verbose + + +def teardown(): + global client + logging.debug("Tearing down P4Runtime client") + client.tear_down() + client = None + + +def main(): + parser = get_arg_parser() + args = parser.parse_args() + if args.verbose: + logging.basicConfig(level=logging.DEBUG) + if args.cacert and not args.ssl: + logging.error( + "--cacert makes no sense if SSL/TLS is disabled, did you mean to use --ssl?") + if args.cert and not args.ssl: + logging.error( + "--cert makes no sense if SSL/TLS is disabled, did you mean to use --ssl?") + if args.private_key and not args.ssl: + logging.error( + "--private-key makes no sense if SSL/TLS is disabled, did you mean to use --ssl?") + ssl_options = SSLOptions(not args.ssl, args.cacert, args.cert, args.private_key) + setup(args.device_id, args.grpc_addr, args.election_id, args.role_name, args.config, + ssl_options) + + c = Config() + c.TerminalInteractiveShell.banner1 = '*** Welcome to the IPython shell for P4Runtime ***' + c.TerminalInteractiveShell.prompts_class = MyPrompt + c.TerminalInteractiveShell.autocall = 2 + c.TerminalInteractiveShell.show_rewritten_input = False + + user_ns = { + "TableEntry": TableEntry, + "MatchKey": MatchKey, + "Action": Action, + "CounterEntry": CounterEntry, + "DirectCounterEntry": DirectCounterEntry, + "MeterEntry": MeterEntry, + "DirectMeterEntry": DirectMeterEntry, + "ActionProfileMember": ActionProfileMember, + "GroupMember": GroupMember, + "ActionProfileGroup": ActionProfileGroup, + "OneshotAction": OneshotAction, + "Oneshot": Oneshot, + "p4info": context.p4info, + "Write": Write, + "Replica": Replica, + "MulticastGroupEntry": MulticastGroupEntry, + "CloneSessionEntry": CloneSessionEntry, + "DigestEntry": DigestEntry, + "APIVersion": APIVersion, + "global_options": global_options, + } + + for obj_type in P4Type: + user_ns[obj_type.p4info_name] = P4Objects(obj_type) + + supported_entities = [ + (P4RuntimeEntity.table_entry, P4Type.table, TableEntry), + (P4RuntimeEntity.counter_entry, P4Type.counter, CounterEntry), + (P4RuntimeEntity.direct_counter_entry, P4Type.direct_counter, DirectCounterEntry), + (P4RuntimeEntity.meter_entry, P4Type.meter, MeterEntry), + (P4RuntimeEntity.direct_meter_entry, P4Type.direct_meter, DirectMeterEntry), + (P4RuntimeEntity.action_profile_member, P4Type.action_profile, ActionProfileMember), + (P4RuntimeEntity.action_profile_group, P4Type.action_profile, ActionProfileGroup), + (P4RuntimeEntity.digest_entry, P4Type.digest, DigestEntry), + ] + for entity, p4type, cls in supported_entities: + user_ns[entity.name] = P4RuntimeEntityBuilder(p4type, entity, cls) + + user_ns["multicast_group_entry"] = MulticastGroupEntry + user_ns["clone_session_entry"] = CloneSessionEntry + user_ns["packet_in"] = PacketIn() # Singleton packet_in object to handle all packet-in cases + user_ns["packet_out"] = PacketOut + user_ns["idle_timeout_notification"] = IdleTimeoutNotification() # Singleton + user_ns["digest_list"] = DigestList() # Singleton + + start_ipython(user_ns=user_ns, config=c, argv=[]) + + client.tear_down() + + +if __name__ == '__main__': # pragma: no cover + main() diff --git a/EXERCISE-1.md b/EXERCISE-1.md index 2c0e8d7..b18676b 100644 --- a/EXERCISE-1.md +++ b/EXERCISE-1.md @@ -109,16 +109,59 @@ Take a look at this file and try to answer the following questions: 1. What is the fully qualified name of the `l2_exact_table`? What is its numeric ID? + + Answer: name is `IngressPipeImpl.l2_exact_table`; id is 33605373. + 2. To which P4 entity does the ID `16812802` belong to? A table, an action, or something else? What is the corresponding fully qualified name? + + Answer: action `IngressPipeImpl.set_egress_port`. + 3. For the `IngressPipeImpl.set_egress_port` action, how many parameters are defined for this action? What is the bitwidth of the parameter named `port_num`? + Answer: bitwidth = 9 + ``` + params { + id: 1 + name: "port_num" + bitwidth: 9 + } + ``` 4. At the end of the file, look for the definition of the `controller_packet_metadata` message with name `packet_out` at the end of the file. Now look at the definition of `header cpu_out_header_t` in the P4 program. Do you see any relationship between the two? + ```p4 + @controller_header("packet_out") + header cpu_out_header_t { + port_num_t egress_port; + bit<7> _pad; + } + ``` + + ```proto + controller_packet_metadata { + preamble { + id: 67111875 + name: "packet_out" + alias: "packet_out" + annotations: "@controller_header(\"packet_out\")" + } + metadata { + id: 1 + name: "egress_port" + bitwidth: 9 + } + metadata { + id: 2 + name: "_pad" + bitwidth: 7 + } + } + ``` + ## 3. Start Mininet topology It's now time to start an emulated network of `stratum_bmv2` switches. We will @@ -222,6 +265,18 @@ obtained before, use the following command: util/p4rt-sh --grpc-addr localhost:50001 --config p4src/build/p4info.txt,p4src/build/bmv2.json --election-id 0,1 ``` +IN MY CASE: + +```bash +winpty python util/p4rt-sh --grpc-addr localhost:50001 -v --config p4src/build/p4info.txt,p4src/build/bmv2.json --election-id 0,1 +``` + +AND inside p4rt-sh ensure all joined paths do not use backslashes: + +```py +os.path.join(mount_path, fname_p4info).replace("\\", "/") +``` + `util/p4rt-sh` is a simple Python script that invokes the P4Runtime Shell Docker container with the given arguments. For a list of arguments you can type `util/p4rt-sh --help`. @@ -378,6 +433,8 @@ To insert the entry (this will issue a P4Runtime Write RPC to the switch): P4Runtime sh >>> te.insert() ``` +![Entries Inserted](img/ex1_entries_inserted.png) + To read table entries from the switch (this will issue a P4Runtime Read RPC): ``` @@ -399,6 +456,8 @@ PING 2001:1:1::b(2001:1:1::b) 56 data bytes ... ``` +![Ping Working](img/ex1_ping.png) + ## Congratulations! You have completed the first exercise! Leave Mininet running, as you will need it diff --git a/EXERCISE-2.md b/EXERCISE-2.md index e0c2b81..d6b0efb 100644 --- a/EXERCISE-2.md +++ b/EXERCISE-2.md @@ -73,6 +73,11 @@ In the interface model, we can see the path to enable or disable an interface: What is the path to read the number of incoming packets (`in-pkts`) on an interface? +Answer: +``` +/interfaces/interface[name]/state/counters/in-pkts +``` + ------ *Extra Credit:* Take a look at the models in the @@ -83,6 +88,40 @@ Try to find the description of the `enabled` or `in-pkts` leaf nodes. *Hint:* Take a look at the `openconfig-interfaces.yang` file. +``` +leaf in-pkts { + type oc-yang:counter64; + description + "The total number of packets received on the interface, + including all unicast, multicast, broadcast and bad packets + etc."; + reference + "RFC 2819: Remote Network Monitoring Management Information + Base"; +} + +leaf enabled { + type boolean; + default "true"; + description + "This leaf contains the configured, desired state of the + interface. + + Systems that implement the IF-MIB use the value of this + leaf in the 'running' datastore to set + IF-MIB.ifAdminStatus to 'up' or 'down' after an ifEntry + has been initialized, as described in RFC 2863. + + Changes in this leaf in the 'running' datastore are + reflected in ifAdminStatus, but if ifAdminStatus is + changed over SNMP, this leaf is not affected."; + reference + "RFC 2863: The Interfaces Group MIB - ifAdminStatus"; +} + + +``` + ------ ## 2. Understand YANG encoding @@ -192,6 +231,10 @@ get the ingress packets counter in the protobuf messages. *Hint:* Searching by schemapath might help. +```proto + ywrapper.BoolValue enabled = 37224301 [(yext.schemapath) = "/interfaces/interface/config/enabled"]; +``` + ------ `ygot` can also be used to generate Go structs that adhere to the YANG model diff --git a/EXERCISE-4.md b/EXERCISE-4.md index c314562..e714a7d 100644 --- a/EXERCISE-4.md +++ b/EXERCISE-4.md @@ -519,6 +519,8 @@ If you are running the VM on your laptop, open up a browser (e.g. Firefox) to To toggle showing hosts on the topology view, press `H` on your keyboard. +![Hosts](img/ex4_hosts.png) + ## Congratulations! You have completed the fourth exercise! diff --git a/EXERCISE-5.md b/EXERCISE-5.md index 2f3947c..40548bb 100644 --- a/EXERCISE-5.md +++ b/EXERCISE-5.md @@ -230,6 +230,8 @@ tests of the previous exercises as well. If all tests succeed, congratulations! You can move to the next step. +![Success](img/ex5_success.png) + ## 3. Modify ONOS app The last part of the exercise is to update the starter code for the routing @@ -313,6 +315,9 @@ PING 2001:1:2::1(2001:1:2::1) 56 data bytes 64 bytes from 2001:1:2::1: icmp_seq=3 ttl=61 time=2.29 ms 64 bytes from 2001:1:2::1: icmp_seq=4 ttl=61 time=2.71 ms ... + +![Ping works](img/ex5_ping.png) + ``` Pinging between `h3` and `h2` should work now. If ping does NOT work, @@ -381,6 +386,73 @@ and reporting stats every 1 second (`-i1`). Since we are generating UDP traffic, there's no need to start an iperf server on `h3`. +``` +mininet> h2 iperf -c h3 -u -V -P5 -b1M -t600 -i1 +------------------------------------------------------------ +Client connecting to 2001:2:3::1, UDP port 5001 +Sending 1470 byte datagrams, IPG target: 11760.00 us (kalman adjust) +UDP buffer size: 208 KByte (default) +------------------------------------------------------------ +[ 6] local 2001:1:2::1 port 37705 connected with 2001:2:3::1 port 5001 +[ 3] local 2001:1:2::1 port 35488 connected with 2001:2:3::1 port 5001 +[ 5] local 2001:1:2::1 port 50720 connected with 2001:2:3::1 port 5001 +[ 4] local 2001:1:2::1 port 32944 connected with 2001:2:3::1 port 5001 +[ 7] local 2001:1:2::1 port 43098 connected with 2001:2:3::1 port 5001 +[ ID] Interval Transfer Bandwidth +[ 6] 0.0- 1.0 sec 123 KBytes 1.01 Mbits/sec +[ 3] 0.0- 1.0 sec 123 KBytes 1.01 Mbits/sec +[ 5] 0.0- 1.0 sec 123 KBytes 1.01 Mbits/sec +[ 4] 0.0- 1.0 sec 123 KBytes 1.01 Mbits/sec +[ 7] 0.0- 1.0 sec 123 KBytes 1.01 Mbits/sec +[SUM] 0.0- 1.0 sec 617 KBytes 5.06 Mbits/sec +[ 6] 1.0- 2.0 sec 122 KBytes 1000 Kbits/sec +[ 5] 1.0- 2.0 sec 122 KBytes 1000 Kbits/sec +[ 4] 1.0- 2.0 sec 122 KBytes 1000 Kbits/sec +[ 3] 1.0- 2.0 sec 123 KBytes 1.01 Mbits/sec +[ 7] 1.0- 2.0 sec 123 KBytes 1.01 Mbits/sec +[SUM] 1.0- 2.0 sec 613 KBytes 5.02 Mbits/sec +[ 7] 2.0- 3.0 sec 121 KBytes 988 Kbits/sec +[ 6] 2.0- 3.0 sec 123 KBytes 1.01 Mbits/sec +[ 3] 2.0- 3.0 sec 122 KBytes 1000 Kbits/sec +[ 5] 2.0- 3.0 sec 123 KBytes 1.01 Mbits/sec +[ 4] 2.0- 3.0 sec 123 KBytes 1.01 Mbits/sec +[SUM] 2.0- 3.0 sec 613 KBytes 5.02 Mbits/sec +[ 6] 3.0- 4.0 sec 122 KBytes 1000 Kbits/sec +[ 3] 3.0- 4.0 sec 122 KBytes 1000 Kbits/sec +[ 5] 3.0- 4.0 sec 122 KBytes 1000 Kbits/sec +[ 4] 3.0- 4.0 sec 122 KBytes 1000 Kbits/sec +[ 7] 3.0- 4.0 sec 123 KBytes 1.01 Mbits/sec +[SUM] 3.0- 4.0 sec 612 KBytes 5.01 Mbits/sec +[ 6] 4.0- 5.0 sec 122 KBytes 1000 Kbits/sec +[ 3] 4.0- 5.0 sec 122 KBytes 1000 Kbits/sec +[ 5] 4.0- 5.0 sec 122 KBytes 1000 Kbits/sec +[ 4] 4.0- 5.0 sec 122 KBytes 1000 Kbits/sec +[ 7] 4.0- 5.0 sec 122 KBytes 1000 Kbits/sec +[SUM] 4.0- 5.0 sec 610 KBytes 5.00 Mbits/sec +[ 6] 5.0- 6.0 sec 122 KBytes 1000 Kbits/sec +[ 3] 5.0- 6.0 sec 122 KBytes 1000 Kbits/sec +[ 5] 5.0- 6.0 sec 122 KBytes 1000 Kbits/sec +[ 4] 5.0- 6.0 sec 122 KBytes 1000 Kbits/sec +[ 7] 5.0- 6.0 sec 122 KBytes 1000 Kbits/sec +[SUM] 5.0- 6.0 sec 610 KBytes 5.00 Mbits/sec +[ 6] 6.0- 7.0 sec 122 KBytes 1000 Kbits/sec +[ 3] 6.0- 7.0 sec 122 KBytes 1000 Kbits/sec +[ 5] 6.0- 7.0 sec 122 KBytes 1000 Kbits/sec +[ 4] 6.0- 7.0 sec 122 KBytes 1000 Kbits/sec +[ 7] 6.0- 7.0 sec 122 KBytes 1000 Kbits/sec +[SUM] 6.0- 7.0 sec 610 KBytes 5.00 Mbits/sec +[ 6] 7.0- 8.0 sec 122 KBytes 1000 Kbits/sec +[ 3] 7.0- 8.0 sec 122 KBytes 1000 Kbits/sec +[ 5] 7.0- 8.0 sec 122 KBytes 1000 Kbits/sec +[ 4] 7.0- 8.0 sec 122 KBytes 1000 Kbits/sec +[ 7] 7.0- 8.0 sec 122 KBytes 1000 Kbits/sec +[SUM] 7.0- 8.0 sec 610 KBytes 5.00 Mbits/sec +[ 6] 8.0- 9.0 sec 122 KBytes 1000 Kbits/sec +[ 3] 8.0- 9.0 sec 122 KBytes 1000 Kbits/sec +[ 5] 8.0- 9.0 sec 122 KBytes 1000 Kbits/sec +[ 4] 8.0- 9.0 sec 122 KBytes 1000 Kbits/sec +``` + Using the ONF Cloud Tutorial Portal, access the ONOS UI. If you are using the tutorial VM, open up a browser (e.g. Firefox) to . When asked, use the username `onos` and diff --git a/app/src/main/java/org/onosproject/ngsdn/tutorial/Ipv6RoutingComponent.java b/app/src/main/java/org/onosproject/ngsdn/tutorial/Ipv6RoutingComponent.java index 75f40dc..c00f9c1 100644 --- a/app/src/main/java/org/onosproject/ngsdn/tutorial/Ipv6RoutingComponent.java +++ b/app/src/main/java/org/onosproject/ngsdn/tutorial/Ipv6RoutingComponent.java @@ -83,7 +83,7 @@ immediate = true, // *** TODO EXERCISE 5 // set to true when ready - enabled = false + enabled = true ) public class Ipv6RoutingComponent { @@ -192,22 +192,24 @@ private void setUpMyStationTable(DeviceId deviceId) { // Modify P4Runtime entity names to match content of P4Info file (look // for the fully qualified name of tables, match fields, and actions. // ---- START SOLUTION ---- - final String tableId = "MODIFY ME"; + final String tableId = "IngressPipeImpl.ipv6_my_station_table"; final PiCriterion match = PiCriterion.builder() .matchExact( - PiMatchFieldId.of("MODIFY ME"), + PiMatchFieldId.of("hdr.ethernet.dst_addr"), myStationMac.toBytes()) .build(); // Creates an action which do *NoAction* when hit. final PiTableAction action = PiAction.builder() - .withId(PiActionId.of("MODIFY ME")) + .withId(PiActionId.of("NoAction")) .build(); // ---- END SOLUTION ---- final FlowRule myStationRule = Utils.buildFlowRule( deviceId, appId, tableId, match, action); + + log.error("#!#!#!#! INSERTED ipv6_my_station_table ENTRY: deviceId = {}, appId = {}", deviceId, appId); flowRuleService.applyFlowRules(myStationRule); } @@ -237,13 +239,13 @@ private GroupDescription createNextHopGroup(int groupId, // Modify P4Runtime entity names to match content of P4Info file (look // for the fully qualified name of tables, match fields, and actions. // ---- START SOLUTION ---- - final String tableId = "MODIFY ME"; + final String tableId = "IngressPipeImpl.ipv6_routing_table"; for (MacAddress nextHopMac : nextHopMacs) { final PiAction action = PiAction.builder() - .withId(PiActionId.of("MODIFY ME")) + .withId(PiActionId.of("IngressPipeImpl.set_nexthop")) .withParameter(new PiActionParam( // Action param name. - PiActionParamId.of("MODIFY ME"), + PiActionParamId.of("dst_mac"), // Action param value. nextHopMac.toBytes())) .build(); @@ -272,10 +274,10 @@ private FlowRule createRoutingRule(DeviceId deviceId, Ip6Prefix ip6Prefix, // Modify P4Runtime entity names to match content of P4Info file (look // for the fully qualified name of tables, match fields, and actions. // ---- START SOLUTION ---- - final String tableId = "MODIFY ME"; + final String tableId = "IngressPipeImpl.ipv6_routing_table"; final PiCriterion match = PiCriterion.builder() .matchLpm( - PiMatchFieldId.of("MODIFY ME"), + PiMatchFieldId.of("hdr.ipv6.dst_addr"), ip6Prefix.address().toOctets(), ip6Prefix.prefixLength()) .build(); @@ -283,6 +285,8 @@ private FlowRule createRoutingRule(DeviceId deviceId, Ip6Prefix ip6Prefix, final PiTableAction action = PiActionProfileGroupId.of(groupId); // ---- END SOLUTION ---- + log.error("#!#!#!#! INSERTED ipv6_routing_table ENTRY: deviceId = {}, groupId = {}, ip6Prefix = {}", deviceId, groupId, ip6Prefix); + return Utils.buildFlowRule( deviceId, appId, tableId, match, action); } @@ -306,17 +310,17 @@ private FlowRule createL2NextHopRule(DeviceId deviceId, MacAddress nexthopMac, // Modify P4Runtime entity names to match content of P4Info file (look // for the fully qualified name of tables, match fields, and actions. // ---- START SOLUTION ---- - final String tableId = "MODIFY ME"; + final String tableId = "IngressPipeImpl.l2_exact_table"; final PiCriterion match = PiCriterion.builder() - .matchExact(PiMatchFieldId.of("MODIFY ME"), + .matchExact(PiMatchFieldId.of("hdr.ethernet.dst_addr"), nexthopMac.toBytes()) .build(); final PiAction action = PiAction.builder() - .withId(PiActionId.of("MODIFY ME")) + .withId(PiActionId.of("IngressPipeImpl.set_egress_port")) .withParameter(new PiActionParam( - PiActionParamId.of("MODIFY ME"), + PiActionParamId.of("port_num"), outPort.toLong())) .build(); // ---- END SOLUTION ---- diff --git a/app/src/main/java/org/onosproject/ngsdn/tutorial/L2BridgingComponent.java b/app/src/main/java/org/onosproject/ngsdn/tutorial/L2BridgingComponent.java index 6db9985..bfc9402 100644 --- a/app/src/main/java/org/onosproject/ngsdn/tutorial/L2BridgingComponent.java +++ b/app/src/main/java/org/onosproject/ngsdn/tutorial/L2BridgingComponent.java @@ -64,7 +64,7 @@ immediate = true, // *** TODO EXERCISE 4 // Enable component (enabled = true) - enabled = false + enabled = true ) public class L2BridgingComponent { diff --git a/app/src/main/java/org/onosproject/ngsdn/tutorial/NdpReplyComponent.java b/app/src/main/java/org/onosproject/ngsdn/tutorial/NdpReplyComponent.java index bd232bf..c075e59 100644 --- a/app/src/main/java/org/onosproject/ngsdn/tutorial/NdpReplyComponent.java +++ b/app/src/main/java/org/onosproject/ngsdn/tutorial/NdpReplyComponent.java @@ -62,7 +62,7 @@ immediate = true, // *** TODO EXERCISE 5 // Enable component (enabled = true) - enabled = false + enabled = true ) public class NdpReplyComponent { @@ -206,17 +206,20 @@ private FlowRule buildNdpReplyFlowRule(DeviceId deviceId, final PiActionParam targetMacParam = new PiActionParam( PiActionParamId.of("target_mac"), targetMac.toBytes()); final PiAction action = PiAction.builder() - .withId(PiActionId.of("MODIFY ME")) + .withId(PiActionId.of("IngressPipeImpl.ndp_ns_to_na")) .withParameter(targetMacParam) .build(); // Table ID. - final String tableId = "MODIFY ME"; + final String tableId = "IngressPipeImpl.ndp_reply_table"; // ---- END SOLUTION ---- // Build flow rule. final FlowRule rule = Utils.buildFlowRule( deviceId, appId, tableId, match, action); + + log.error("#!#!#!#! INSERTED ndp_ns_to_na ENTRY: deviceId = {}, appId = {}, target_mac = {}", deviceId, appId, targetMac.toBytes()); + return rule; } diff --git a/app/src/main/java/org/onosproject/ngsdn/tutorial/pipeconf/InterpreterImpl.java b/app/src/main/java/org/onosproject/ngsdn/tutorial/pipeconf/InterpreterImpl.java index edf5bfa..2570a3b 100644 --- a/app/src/main/java/org/onosproject/ngsdn/tutorial/pipeconf/InterpreterImpl.java +++ b/app/src/main/java/org/onosproject/ngsdn/tutorial/pipeconf/InterpreterImpl.java @@ -154,7 +154,7 @@ private PiPacketOperation buildPacketOut(ByteBuffer pktData, long portNumber) // Create metadata instance for egress port. // *** TODO EXERCISE 4: modify metadata names to match P4 program // ---- START SOLUTION ---- - final String outPortMetadataName = "ADD HERE METADATA NAME FOR THE EGRESS PORT"; + final String outPortMetadataName = "egress_port"; // ---- END SOLUTION ---- final PiPacketMetadata outPortMetadata = PiPacketMetadata.builder() .withId(PiPacketMetadataId.of(outPortMetadataName)) @@ -186,7 +186,7 @@ public InboundPacket mapInboundPacket(PiPacketOperation packetIn, DeviceId devic // Find the ingress_port metadata. // *** TODO EXERCISE 4: modify metadata names to match P4Info // ---- START SOLUTION ---- - final String inportMetadataName = "ADD HERE METADATA NAME FOR THE INGRESS PORT"; + final String inportMetadataName = "ingress_port"; // ---- END SOLUTION ---- Optional inportMetadata = packetIn.metadatas() .stream() diff --git a/image.png b/image.png new file mode 100644 index 0000000..dcb8e42 Binary files /dev/null and b/image.png differ diff --git a/img/ex1_entries_inserted.png b/img/ex1_entries_inserted.png new file mode 100644 index 0000000..527a207 Binary files /dev/null and b/img/ex1_entries_inserted.png differ diff --git a/img/ex1_pic1.png b/img/ex1_pic1.png new file mode 100644 index 0000000..823fe2a Binary files /dev/null and b/img/ex1_pic1.png differ diff --git a/img/ex1_ping.png b/img/ex1_ping.png new file mode 100644 index 0000000..1ffff83 Binary files /dev/null and b/img/ex1_ping.png differ diff --git a/img/ex4_hosts.png b/img/ex4_hosts.png new file mode 100644 index 0000000..f8338c6 Binary files /dev/null and b/img/ex4_hosts.png differ diff --git a/img/ex5_ping.png b/img/ex5_ping.png new file mode 100644 index 0000000..bd0ac5e Binary files /dev/null and b/img/ex5_ping.png differ diff --git a/img/ex5_success.png b/img/ex5_success.png new file mode 100644 index 0000000..87d9be5 Binary files /dev/null and b/img/ex5_success.png differ diff --git a/img/image.png b/img/image.png new file mode 100644 index 0000000..8e537be Binary files /dev/null and b/img/image.png differ diff --git a/listen.log b/listen.log new file mode 100644 index 0000000..62168b8 --- /dev/null +++ b/listen.log @@ -0,0 +1,14 @@ +h2 tcpdump -i h2-eth0 -w /tmp/attempt1/h2/h2_eth0_fwd.pcap & +h3 tcpdump -i h3-eth0 -w /tmp/attempt1/h3/h3_eth0_fwd.pcap & +leaf1 tcpdump -i leaf1-eth1 -w /tmp/attempt1/leaf1/leaf1_eth1_fwd.pcap & +leaf1 tcpdump -i leaf1-eth2 -w /tmp/attempt1/leaf1/leaf1_eth2_fwd.pcap & +leaf1 tcpdump -i leaf1-eth3 -w /tmp/attempt1/leaf1/leaf1_eth3_fwd.pcap & +leaf1 tcpdump -i leaf1-eth4 -w /tmp/attempt1/leaf1/leaf1_eth4_fwd.pcap & +leaf1 tcpdump -i leaf1-eth5 -w /tmp/attempt1/leaf1/leaf1_eth5_fwd.pcap & +leaf1 tcpdump -i leaf1-eth6 -w /tmp/attempt1/leaf1/leaf1_eth6_fwd.pcap & +leaf2 tcpdump -i leaf2-eth1 -w /tmp/attempt1/leaf2/leaf2_eth1_fwd.pcap & +leaf2 tcpdump -i leaf2-eth2 -w /tmp/attempt1/leaf2/leaf2_eth2_fwd.pcap & +leaf2 tcpdump -i leaf2-eth3 -w /tmp/attempt1/leaf2/leaf2_eth3_fwd.pcap & +leaf2 tcpdump -i leaf2-eth4 -w /tmp/attempt1/leaf2/leaf2_eth4_fwd.pcap & +leaf2 tcpdump -i leaf2-eth5 -w /tmp/attempt1/leaf2/leaf2_eth5_fwd.pcap & +leaf2 tcpdump -i leaf2-eth6 -w /tmp/attempt1/leaf2/leaf2_eth6_fwd.pcap & \ No newline at end of file diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..e69de29 diff --git a/onos.log b/onos.log new file mode 100644 index 0000000..ba161bf --- /dev/null +++ b/onos.log @@ -0,0 +1,19 @@ +deviceId=device:leaf1, flowRuleCount=18 + id=100001e5fba59, state=ADDED, bytes=0, packets=0, duration=2350, liveType=UNKNOWN, priority=40000, tableId=IngressPipeImpl.acl_table, appId=org.onosproject.core, selector=[ETH_TYPE:arp], treatment=DefaultTrafficTreatment{immediate=[IngressPipeImpl.clone_to_cpu()], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=10000217b5edd, state=ADDED, bytes=183520, packets=1480, duration=2350, liveType=UNKNOWN, priority=40000, tableId=IngressPipeImpl.acl_table, appId=org.onosproject.core, selector=[ETH_TYPE:lldp], treatment=DefaultTrafficTreatment{immediate=[IngressPipeImpl.clone_to_cpu()], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=1000039959d4d, state=ADDED, bytes=0, packets=0, duration=2350, liveType=UNKNOWN, priority=40000, tableId=IngressPipeImpl.acl_table, appId=org.onosproject.core, selector=[ETH_TYPE:ipv6, IP_PROTO:58, ICMPV6_TYPE:136], treatment=DefaultTrafficTreatment{immediate=[IngressPipeImpl.clone_to_cpu()], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=1000078c06d68, state=ADDED, bytes=344, packets=4, duration=2350, liveType=UNKNOWN, priority=40000, tableId=IngressPipeImpl.acl_table, appId=org.onosproject.core, selector=[ETH_TYPE:ipv6, IP_PROTO:58, ICMPV6_TYPE:135], treatment=DefaultTrafficTreatment{immediate=[IngressPipeImpl.clone_to_cpu()], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=10000d1887c0b, state=ADDED, bytes=0, packets=0, duration=2350, liveType=UNKNOWN, priority=40000, tableId=IngressPipeImpl.acl_table, appId=org.onosproject.core, selector=[ETH_TYPE:bddp], treatment=DefaultTrafficTreatment{immediate=[IngressPipeImpl.clone_to_cpu()], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=c000007e251531, state=ADDED, bytes=4956, packets=42, duration=2350, liveType=UNKNOWN, priority=10, tableId=IngressPipeImpl.ipv6_my_station_table, appId=org.onosproject.ngsdn-tutorial, selector=[hdr.ethernet.dst_addr=0xaa00000001], treatment=DefaultTrafficTreatment{immediate=[NoAction()], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=c0000028ed981d, state=ADDED, bytes=0, packets=0, duration=2141, liveType=UNKNOWN, priority=10, tableId=IngressPipeImpl.ipv6_routing_table, appId=org.onosproject.ngsdn-tutorial, selector=[hdr.ipv6.dst_addr=0x20010001000200000000000000000001/128], treatment=DefaultTrafficTreatment{immediate=[GROUP:0x20], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=c000005f8a4559, state=ADDED, bytes=0, packets=0, duration=2346, liveType=UNKNOWN, priority=10, tableId=IngressPipeImpl.ipv6_routing_table, appId=org.onosproject.ngsdn-tutorial, selector=[hdr.ipv6.dst_addr=0x20010002000300000000000000000000/64], treatment=DefaultTrafficTreatment{immediate=[GROUP:0xec3b0000], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=c0000076325a77, state=ADDED, bytes=0, packets=0, duration=2346, liveType=UNKNOWN, priority=10, tableId=IngressPipeImpl.ipv6_routing_table, appId=org.onosproject.ngsdn-tutorial, selector=[hdr.ipv6.dst_addr=0x20010002000400000000000000000000/64], treatment=DefaultTrafficTreatment{immediate=[GROUP:0xec3b0000], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=c0000078797bee, state=ADDED, bytes=0, packets=0, duration=2346, liveType=UNKNOWN, priority=10, tableId=IngressPipeImpl.ipv6_routing_table, appId=org.onosproject.ngsdn-tutorial, selector=[hdr.ipv6.dst_addr=0x30201000200000000000000000000/128], treatment=DefaultTrafficTreatment{immediate=[GROUP:0xba], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=c00000a2deb332, state=ADDED, bytes=0, packets=0, duration=2345, liveType=UNKNOWN, priority=10, tableId=IngressPipeImpl.ipv6_routing_table, appId=org.onosproject.ngsdn-tutorial, selector=[hdr.ipv6.dst_addr=0x30202000200000000000000000000/128], treatment=DefaultTrafficTreatment{immediate=[GROUP:0xb9], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=c00000190d48bb, state=ADDED, bytes=1416, packets=12, duration=2141, liveType=UNKNOWN, priority=10, tableId=IngressPipeImpl.l2_exact_table, appId=org.onosproject.ngsdn-tutorial, selector=[hdr.ethernet.dst_addr=0x20], treatment=DefaultTrafficTreatment{immediate=[IngressPipeImpl.set_egress_port(port_num=0x6)], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=c00000abeb8fd1, state=ADDED, bytes=0, packets=0, duration=2345, liveType=UNKNOWN, priority=10, tableId=IngressPipeImpl.l2_exact_table, appId=org.onosproject.ngsdn-tutorial, selector=[hdr.ethernet.dst_addr=0xbb00000001], treatment=DefaultTrafficTreatment{immediate=[IngressPipeImpl.set_egress_port(port_num=0x1)], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=c00000f57b2b7c, state=ADDED, bytes=3540, packets=30, duration=2345, liveType=UNKNOWN, priority=10, tableId=IngressPipeImpl.l2_exact_table, appId=org.onosproject.ngsdn-tutorial, selector=[hdr.ethernet.dst_addr=0xbb00000002], treatment=DefaultTrafficTreatment{immediate=[IngressPipeImpl.set_egress_port(port_num=0x2)], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=c00000a489d650, state=ADDED, bytes=2800, packets=40, duration=2350, liveType=UNKNOWN, priority=10, tableId=IngressPipeImpl.l2_ternary_table, appId=org.onosproject.ngsdn-tutorial, selector=[hdr.ethernet.dst_addr=0x333300000000&&&0xffff00000000], treatment=DefaultTrafficTreatment{immediate=[IngressPipeImpl.set_multicast_group(gid=0xff)], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=c00000c8cf6dac, state=ADDED, bytes=0, packets=0, duration=2350, liveType=UNKNOWN, priority=10, tableId=IngressPipeImpl.l2_ternary_table, appId=org.onosproject.ngsdn-tutorial, selector=[hdr.ethernet.dst_addr=0xffffffffffff&&&0xffffffffffff], treatment=DefaultTrafficTreatment{immediate=[IngressPipeImpl.set_multicast_group(gid=0xff)], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=c0000026ddb735, state=ADDED, bytes=344, packets=4, duration=2350, liveType=UNKNOWN, priority=10, tableId=IngressPipeImpl.ndp_reply_table, appId=org.onosproject.ngsdn-tutorial, selector=[hdr.ndp.target_ipv6_addr=0x200100010002000000000000000000ff], treatment=DefaultTrafficTreatment{immediate=[IngressPipeImpl.ndp_ns_to_na(target_mac=0xaa00000001)], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=c00000e71f7679, state=ADDED, bytes=0, packets=0, duration=2350, liveType=UNKNOWN, priority=10, tableId=IngressPipeImpl.ndp_reply_table, appId=org.onosproject.ngsdn-tutorial, selector=[hdr.ndp.target_ipv6_addr=0x200100010001000000000000000000ff], treatment=DefaultTrafficTreatment{immediate=[IngressPipeImpl.ndp_ns_to_na(target_mac=0xaa00000001)], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} \ No newline at end of file diff --git a/p4src/main.p4 b/p4src/main.p4 index 3bcd2d1..d683ae1 100644 --- a/p4src/main.p4 +++ b/p4src/main.p4 @@ -63,7 +63,6 @@ const bit<32> NDP_FLAG_ROUTER = 0x80000000; const bit<32> NDP_FLAG_SOLICITED = 0x40000000; const bit<32> NDP_FLAG_OVERRIDE = 0x20000000; - //------------------------------------------------------------------------------ // HEADER DEFINITIONS //------------------------------------------------------------------------------ @@ -423,7 +422,6 @@ control IngressPipeImpl (inout parsed_headers_t hdr, counters = direct_counter(CounterType.packets_and_bytes); } - // *** TODO EXERCISE 5 (IPV6 ROUTING) // // 1. Create a table to to handle NDP messages to resolve the MAC address of @@ -446,11 +444,167 @@ control IngressPipeImpl (inout parsed_headers_t hdr, // You can name your tables whatever you like. You will need to fill // the name in elsewhere in this exercise. + action ndp_ns_to_na(mac_addr_t target_mac) { + hdr.ethernet.src_addr = target_mac; + hdr.ethernet.dst_addr = IPV6_MCAST_01; + ipv6_addr_t host_ipv6_tmp = hdr.ipv6.src_addr; + hdr.ipv6.src_addr = hdr.ndp.target_ipv6_addr; + hdr.ipv6.dst_addr = host_ipv6_tmp; + hdr.ipv6.next_hdr = IP_PROTO_ICMPV6; + hdr.icmpv6.type = ICMP6_TYPE_NA; + hdr.ndp.flags = NDP_FLAG_ROUTER | NDP_FLAG_OVERRIDE; + hdr.ndp.type = NDP_OPT_TARGET_LL_ADDR; + hdr.ndp.length = 1; + hdr.ndp.target_mac_addr = target_mac; + standard_metadata.egress_spec = standard_metadata.ingress_port; + } + + table ndp_reply_table { + key = { + hdr.ndp.target_ipv6_addr: exact; + } + actions = { + ndp_ns_to_na; + @defaultonly NoAction; + } + const default_action = NoAction; + @name("ndp_reply_table_counter") + counters = direct_counter(CounterType.packets_and_bytes); + } + + table ipv6_my_station_table { + key = { + hdr.ethernet.dst_addr: exact; + } + actions = { + NoAction; + } + const default_action = NoAction; + @name("ipv6_my_station_table_counter") + counters = direct_counter(CounterType.packets_and_bytes); + } + + // ECMP action selector definition: + action_selector(HashAlgorithm.crc16, 32w1024, 32w16) ecmp_selector; + + action set_nexthop(mac_addr_t dst_mac) { + hdr.ethernet.src_addr = hdr.ethernet.dst_addr; + hdr.ethernet.dst_addr = dst_mac; + hdr.ipv6.hop_limit = hdr.ipv6.hop_limit - 1; + } + + table ipv6_routing_table { + key = { + hdr.ipv6.dst_addr: lpm; + } + actions = { + set_nexthop; + drop; + } + implementation = ecmp_selector; + size = 1024; + } // *** TODO EXERCISE 6 (SRV6) // // Implement tables to provide SRV6 logic. + // --- srv6_my_sid---------------------------------------------------------- + + // Process the packet if the destination IP is the segemnt Id(sid) of this + // device. This table will decrement the "segment left" field from the Srv6 + // header and set destination IP address to next segment. + + action srv6_end() { + hdr.srv6h.segment_left = hdr.srv6h.segment_left - 1; + hdr.ipv6.dst_addr = local_metadata.next_srv6_sid; + } + + direct_counter(CounterType.packets_and_bytes) srv6_my_sid_table_counter; + table srv6_my_sid { + key = { + hdr.ipv6.dst_addr: lpm; + } + actions = { + srv6_end; + } + counters = srv6_my_sid_table_counter; + } + + // --- srv6_transit -------------------------------------------------------- + + // Inserts the SRv6 header to the IPv6 header of the packet based on the + // destination IP address. + + + action insert_srv6h_header(bit<8> num_segments) { + hdr.srv6h.setValid(); + hdr.srv6h.next_hdr = hdr.ipv6.next_hdr; + hdr.srv6h.hdr_ext_len = num_segments * 2; + hdr.srv6h.routing_type = 4; + hdr.srv6h.segment_left = num_segments - 1; + hdr.srv6h.last_entry = num_segments - 1; + hdr.srv6h.flags = 0; + hdr.srv6h.tag = 0; + hdr.ipv6.next_hdr = IP_PROTO_SRV6; + } + + /* + Single segment header doesn't make sense given PSP + i.e. we will pop the SRv6 header when segments_left reaches 0 + */ + + action srv6_t_insert_2(ipv6_addr_t s1, ipv6_addr_t s2) { + hdr.ipv6.dst_addr = s1; + hdr.ipv6.payload_len = hdr.ipv6.payload_len + 40; + insert_srv6h_header(2); + hdr.srv6_list[0].setValid(); + hdr.srv6_list[0].segment_id = s2; + hdr.srv6_list[1].setValid(); + hdr.srv6_list[1].segment_id = s1; + } + + action srv6_t_insert_3(ipv6_addr_t s1, ipv6_addr_t s2, ipv6_addr_t s3) { + hdr.ipv6.dst_addr = s1; + hdr.ipv6.payload_len = hdr.ipv6.payload_len + 56; + insert_srv6h_header(3); + hdr.srv6_list[0].setValid(); + hdr.srv6_list[0].segment_id = s3; + hdr.srv6_list[1].setValid(); + hdr.srv6_list[1].segment_id = s2; + hdr.srv6_list[2].setValid(); + hdr.srv6_list[2].segment_id = s1; + } + + direct_counter(CounterType.packets_and_bytes) srv6_transit_table_counter; + table srv6_transit { + key = { + hdr.ipv6.dst_addr: lpm; + // TODO: what other fields do we want to match? + } + actions = { + srv6_t_insert_2; + srv6_t_insert_3; + // Extra credit: set a metadata field, then push label stack in egress + } + counters = srv6_transit_table_counter; + } + + // Called directly in the apply block. + action srv6_pop() { + hdr.ipv6.next_hdr = hdr.srv6h.next_hdr; + // SRv6 header is 8 bytes + // SRv6 list entry is 16 bytes each + // (((bit<16>)hdr.srv6h.last_entry + 1) * 16) + 8; + bit<16> srv6h_size = (((bit<16>)hdr.srv6h.last_entry + 1) << 4) + 8; + hdr.ipv6.payload_len = hdr.ipv6.payload_len - srv6h_size; + + hdr.srv6h.setInvalid(); + // Need to set MAX_HOPS headers invalid + hdr.srv6_list[0].setInvalid(); + hdr.srv6_list[1].setInvalid(); + hdr.srv6_list[2].setInvalid(); + } // *** ACL // @@ -503,6 +657,10 @@ control IngressPipeImpl (inout parsed_headers_t hdr, // 1. Set the packet egress port to that found in the cpu_out header // 2. Remove (set invalid) the cpu_out header // 3. Exit the pipeline here (no need to go through other tables + + standard_metadata.egress_spec = hdr.cpu_out.egress_port; + hdr.cpu_out.setInvalid(); + return; } bool do_l3_l2 = true; @@ -514,6 +672,10 @@ control IngressPipeImpl (inout parsed_headers_t hdr, // If this is an NDP NS packet, i.e., if a matching entry is found, // unset the "do_l3_l2" flag to skip the L3 and L2 tables, as the // "ndp_ns_to_na" action already set an egress port. + + if (ndp_reply_table.apply().hit) { + do_l3_l2 = false; + } } if (do_l3_l2) { @@ -523,12 +685,36 @@ control IngressPipeImpl (inout parsed_headers_t hdr, // routing table. You should also add a conditional to drop the // packet if the hop_limit reaches 0. + // if (ipv6_my_station_table.apply().hit) { + // if (hdr.ipv6.isValid() && hdr.ipv6.hop_limit == 0) { + // mark_to_drop(standard_metadata); + // } else { + // ipv6_routing_table.apply(); + // } + // } + // *** TODO EXERCISE 6 // Insert logic to match the SRv6 My SID and Transit tables as well // as logic to perform PSP behavior. HINT: This logic belongs // somewhere between checking the switch's my station table and // applying the routing table. + if (hdr.ipv6.isValid() && ipv6_my_station_table.apply().hit) { + if (srv6_my_sid.apply().hit) { + if (hdr.srv6h.isValid() && hdr.srv6h.segment_left == 0) { + srv6_pop(); + } + } else { + srv6_transit.apply(); + } + + ipv6_routing_table.apply(); + + if(hdr.ipv6.hop_limit == 0) { + drop(); + } + } + // L2 bridging logic. Apply the exact table first... if (!l2_exact_table.apply().hit) { // ...if an entry is NOT found, apply the ternary one in case @@ -556,6 +742,9 @@ control EgressPipeImpl (inout parsed_headers_t hdr, // 1. Set cpu_in header as valid // 2. Set the cpu_in.ingress_port field to the original packet's // ingress port (standard_metadata.ingress_port). + + hdr.cpu_in.setValid(); + hdr.cpu_in.ingress_port = standard_metadata.ingress_port; } // If this is a multicast packet (flag set by l2_ternary_table), make diff --git a/ptf/tests/packetio.py b/ptf/tests/packetio.py index 0960bec..846c1d4 100644 --- a/ptf/tests/packetio.py +++ b/ptf/tests/packetio.py @@ -67,7 +67,7 @@ def testPacket(self, pkt): packet_out_msg = self.helper.build_packet_out( payload=str(pkt), metadata={ - "MODIFY ME": outport, + "egress_port": outport, "_pad": 0 }) # ---- END SOLUTION ---- @@ -110,12 +110,12 @@ def testPacket(self, pkt): # clone_to_cpu action. # ---- START SOLUTION ---- self.insert(self.helper.build_table_entry( - table_name="MODIFY ME", + table_name="IngressPipeImpl.acl_table", match_fields={ # Ternary match. - "MODIFY ME": (eth_type, 0xffff) + "hdr.ethernet.ether_type": (eth_type, 0xffff) }, - action_name="MODIFY ME", + action_name="IngressPipeImpl.clone_to_cpu", priority=DEFAULT_PRIORITY )) # ---- END SOLUTION ---- @@ -128,7 +128,146 @@ def testPacket(self, pkt): exp_packet_in_msg = self.helper.build_packet_in( payload=str(pkt), metadata={ - "MODIFY ME": inport, + "ingress_port": inport, + "_pad": 0 + }) + # ---- END SOLUTION ---- + + # Send packet to given switch ingress port and expect P4Runtime + # PacketIn message. + testutils.send_packet(self, inport, str(pkt)) + self.verify_packet_in(exp_packet_in_msg) +# Copyright 2019-present Open Networking Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# ------------------------------------------------------------------------------ +# CONTROLLER PACKET-IN/OUT TESTS +# +# To run all tests in this file: +# make p4-test TEST=packetio +# +# To run a specific test case: +# make p4-test TEST=packetio. +# +# For example: +# make p4-test TEST=packetio.PacketOutTest +# ------------------------------------------------------------------------------ + +# ------------------------------------------------------------------------------ +# Modify everywhere you see TODO +# +# When providing your solution, make sure to use the same names for P4Runtime +# entities as specified in your P4Info file. +# +# Test cases are based on the P4 program design suggested in the exercises +# README. Make sure to modify the test cases accordingly if you decide to +# implement the pipeline differently. +# ------------------------------------------------------------------------------ + +from ptf.testutils import group + +from base_test import * + +CPU_CLONE_SESSION_ID = 99 + + +@group("packetio") +class PacketOutTest(P4RuntimeTest): + """Tests controller packet-out capability by sending PacketOut messages and + expecting a corresponding packet on the output port set in the PacketOut + metadata. + """ + + def runTest(self): + for pkt_type in ["tcp", "udp", "icmp", "arp", "tcpv6", "udpv6", + "icmpv6"]: + print_inline("%s ... " % pkt_type) + pkt = getattr(testutils, "simple_%s_packet" % pkt_type)() + self.testPacket(pkt) + + def testPacket(self, pkt): + for outport in [self.port1, self.port2]: + # Build PacketOut message. + # TODO EXERCISE 4 + # Modify metadata names to match the content of your P4Info file + # ---- START SOLUTION ---- + packet_out_msg = self.helper.build_packet_out( + payload=str(pkt), + metadata={ + "egress_port": outport, + "_pad": 0 + }) + # ---- END SOLUTION ---- + + # Send message and expect packet on the given data plane port. + self.send_packet_out(packet_out_msg) + + testutils.verify_packet(self, pkt, outport) + + # Make sure packet was forwarded only on the specified ports + testutils.verify_no_other_packets(self) + + +@group("packetio") +class PacketInTest(P4RuntimeTest): + """Tests controller packet-in capability my matching on the packet EtherType + and cloning to the CPU port. + """ + + def runTest(self): + for pkt_type in ["tcp", "udp", "icmp", "arp", "tcpv6", "udpv6", + "icmpv6"]: + print_inline("%s ... " % pkt_type) + pkt = getattr(testutils, "simple_%s_packet" % pkt_type)() + self.testPacket(pkt) + + @autocleanup + def testPacket(self, pkt): + + # Insert clone to CPU session + self.insert_pre_clone_session( + session_id=CPU_CLONE_SESSION_ID, + ports=[self.cpu_port]) + + # Insert ACL entry to match on the given eth_type and clone to CPU. + eth_type = pkt[Ether].type + # TODO EXERCISE 4 + # Modify names to match content of P4Info file (look for the fully + # qualified name of the ACL table, EtherType match field, and + # clone_to_cpu action. + # ---- START SOLUTION ---- + self.insert(self.helper.build_table_entry( + table_name="IngressPipeImpl.acl_table", + match_fields={ + # Ternary match. + "hdr.ethernet.ether_type": (eth_type, 0xffff) + }, + action_name="IngressPipeImpl.clone_to_cpu", + priority=DEFAULT_PRIORITY + )) + # ---- END SOLUTION ---- + + for inport in [self.port1, self.port2, self.port3]: + # TODO EXERCISE 4 + # Modify metadata names to match the content of your P4Info file + # ---- START SOLUTION ---- + # Expected P4Runtime PacketIn message. + exp_packet_in_msg = self.helper.build_packet_in( + payload=str(pkt), + metadata={ + "ingress_port": inport, "_pad": 0 }) # ---- END SOLUTION ---- diff --git a/ptf/tests/routing.py b/ptf/tests/routing.py index a3707c2..df0655b 100644 --- a/ptf/tests/routing.py +++ b/ptf/tests/routing.py @@ -64,10 +64,10 @@ def testPacket(self, pkt): # qualified name of tables, match fields, and actions. # ---- START SOLUTION ---- self.insert(self.helper.build_table_entry( - table_name="MODIFY ME", + table_name="IngressPipeImpl.ipv6_my_station_table", match_fields={ # Exact match. - "MODIFY ME": pkt[Ether].dst + "hdr.ethernet.dst_addr": pkt[Ether].dst }, action_name="NoAction" )) @@ -79,11 +79,13 @@ def testPacket(self, pkt): # qualified name of tables, match fields, and actions. # ---- START SOLUTION ---- self.insert(self.helper.build_act_prof_group( - act_prof_name="MODIFY ME", + act_prof_name="IngressPipeImpl.ecmp_selector", group_id=1, actions=[ # List of tuples (action name, action param dict) - ("MODIFY ME", {"MODIFY ME": next_hop_mac}), + ("IngressPipeImpl.set_nexthop", { + "dst_mac": next_hop_mac + }), ] )) # ---- END SOLUTION ---- @@ -94,10 +96,10 @@ def testPacket(self, pkt): # qualified name of tables, match fields, and actions. # ---- START SOLUTION ---- self.insert(self.helper.build_table_entry( - table_name="MODIFY ME", + table_name="IngressPipeImpl.ipv6_routing_table", match_fields={ # LPM match (value, prefix) - "MODIFY ME": (pkt[IPv6].dst, 128) + "hdr.ipv6.dst_addr": (pkt[IPv6].dst, 128) }, group_id=1 )) @@ -109,14 +111,14 @@ def testPacket(self, pkt): # qualified name of tables, match fields, and actions. # ---- START SOLUTION ---- self.insert(self.helper.build_table_entry( - table_name="MODIFY ME", + table_name="IngressPipeImpl.l2_exact_table", match_fields={ # Exact match - "MODIFY ME": next_hop_mac + "hdr.ethernet.dst_addr": next_hop_mac }, - action_name="MODIFY ME", + action_name="IngressPipeImpl.set_egress_port", action_params={ - "MODIFY ME": self.port2 + "port_num": self.port2 } )) # ---- END SOLUTION ---- @@ -149,14 +151,14 @@ def runTest(self): # qualified name of tables, match fields, and actions. # ---- START SOLUTION ---- self.insert(self.helper.build_table_entry( - table_name="MODIFY ME", + table_name="IngressPipeImpl.ndp_reply_table", match_fields={ # Exact match. - "MODIFY ME": switch_ip + "hdr.ndp.target_ipv6_addr": switch_ip }, - action_name="MODIFY ME", + action_name="IngressPipeImpl.ndp_ns_to_na", action_params={ - "MODIFY ME": target_mac + "target_mac": target_mac } )) # ---- END SOLUTION ---- diff --git a/ptf/tests/srv6.py b/ptf/tests/srv6.py index 90e6846..6854aaa 100644 --- a/ptf/tests/srv6.py +++ b/ptf/tests/srv6.py @@ -108,10 +108,10 @@ def testPacket(self, pkt, sid_list, next_hop_mac): # Add entry to "My Station" table. Consider the given pkt's eth dst addr # as myStationMac address. self.insert(self.helper.build_table_entry( - table_name="MODIFY ME", + table_name="IngressPipeImpl.ipv6_my_station_table", match_fields={ # Exact match. - "MODIFY ME": pkt[Ether].dst + "hdr.ethernet.dst_addr": pkt[Ether].dst }, action_name="NoAction" )) @@ -130,10 +130,10 @@ def testPacket(self, pkt, sid_list, next_hop_mac): actions_params = {"s%d" % (x + 1): sid_list[x] for x in range(sid_len)} self.insert(self.helper.build_table_entry( - table_name="MODIFY ME", + table_name="IngressPipeImpl.srv6_transit", match_fields={ # LPM match (value, prefix) - "MODIFY ME": (pkt[IPv6].dst, 128) + "hdr.ipv6.dst_addr": (pkt[IPv6].dst, 128) }, action_name=action_name, action_params=actions_params @@ -141,11 +141,11 @@ def testPacket(self, pkt, sid_list, next_hop_mac): # Insert ECMP group with only one member (next_hop_mac) self.insert(self.helper.build_act_prof_group( - act_prof_name="MODIFY ME", + act_prof_name="IngressPipeImpl.ecmp_selector", group_id=1, actions=[ # List of tuples (action name, {action param: value}) - ("MODIFY ME", {"MODIFY ME": next_hop_mac}), + ("IngressPipeImpl.set_nexthop", {"dst_mac": next_hop_mac}), ] )) @@ -154,7 +154,7 @@ def testPacket(self, pkt, sid_list, next_hop_mac): # Match on L3 routing table. first_sid = sid_list[0] self.insert(self.helper.build_table_entry( - table_name="MODIFY ME", + table_name="IngressPipeImpl.ipv6_routing_table", match_fields={ # LPM match (value, prefix) "hdr.ipv6.dst_addr": (first_sid, 128) @@ -164,14 +164,14 @@ def testPacket(self, pkt, sid_list, next_hop_mac): # Map next_hop_mac to output port self.insert(self.helper.build_table_entry( - table_name="MODIFY ME", + table_name="IngressPipeImpl.l2_exact_table", match_fields={ - # Exact match - "MODIFY ME": next_hop_mac + # Exact match. + "hdr.ethernet.dst_addr": next_hop_mac }, - action_name="MODIFY ME", + action_name="IngressPipeImpl.set_egress_port", action_params={ - "MODIFY ME": self.port2 + "port_num": self.port2 } )) @@ -227,37 +227,37 @@ def testPacket(self, pkt, next_hop_mac, my_sid): # Add entry to "My Station" table. Consider the given pkt's eth dst addr # as myStationMac address. self.insert(self.helper.build_table_entry( - table_name="MODIFY ME", + table_name="IngressPipeImpl.ipv6_my_station_table", match_fields={ # Exact match. - "MODIFY ME": pkt[Ether].dst + "hdr.ethernet.dst_addr": pkt[Ether].dst }, action_name="NoAction" )) # This should be missed, this is plain IPv6 routing. self.insert(self.helper.build_table_entry( - table_name="MODIFY ME", + table_name="IngressPipeImpl.srv6_my_sid", match_fields={ # Longest prefix match (value, prefix length) - "MODIFY ME": (my_sid, 128) + "hdr.ipv6.dst_addr": (my_sid, 128) }, - action_name="MODIFY ME" + action_name="IngressPipeImpl.srv6_end" )) # Insert ECMP group with only one member (next_hop_mac) self.insert(self.helper.build_act_prof_group( - act_prof_name="MODIFY ME", + act_prof_name="IngressPipeImpl.ecmp_selector", group_id=1, actions=[ # List of tuples (action name, {action param: value}) - ("MODIFY ME", {"MODIFY ME": next_hop_mac}), + ("IngressPipeImpl.set_nexthop", {"dst_mac": next_hop_mac}), ] )) # Map pkt's IPv6 dst addr to group self.insert(self.helper.build_table_entry( - table_name="MODIFY ME", + table_name="IngressPipeImpl.ipv6_routing_table", match_fields={ # LPM match (value, prefix) "hdr.ipv6.dst_addr": (pkt[IPv6].dst, 128) @@ -267,14 +267,14 @@ def testPacket(self, pkt, next_hop_mac, my_sid): # Map next_hop_mac to output port self.insert(self.helper.build_table_entry( - table_name="MODIFY ME", + table_name="IngressPipeImpl.l2_exact_table", match_fields={ - # Exact match - "MODIFY ME": next_hop_mac + # Exact match. + "hdr.ethernet.dst_addr": next_hop_mac }, - action_name="MODIFY ME", + action_name="IngressPipeImpl.set_egress_port", action_params={ - "MODIFY ME": self.port2 + "port_num": self.port2 } )) @@ -328,31 +328,31 @@ def testPacket(self, pkt, sid_list, next_hop_mac, my_sid): # Add entry to "My Station" table. Consider the given pkt's eth dst addr # as myStationMac address. self.insert(self.helper.build_table_entry( - table_name="MODIFY ME", + table_name="IngressPipeImpl.ipv6_my_station_table", match_fields={ # Exact match. - "MODIFY ME": pkt[Ether].dst + "hdr.ethernet.dst_addr": pkt[Ether].dst }, action_name="NoAction" )) # This should be matched, we want SRv6 end behavior to be applied. self.insert(self.helper.build_table_entry( - table_name="MODIFY ME", + table_name="IngressPipeImpl.srv6_my_sid", match_fields={ # Longest prefix match (value, prefix length) - "MODIFY ME": (my_sid, 128) + "hdr.ipv6.dst_addr": (my_sid, 128) }, - action_name="MODIFY ME" + action_name="IngressPipeImpl.srv6_end" )) # Insert ECMP group with only one member (next_hop_mac) self.insert(self.helper.build_act_prof_group( - act_prof_name="MODIFY ME", + act_prof_name="IngressPipeImpl.ecmp_selector", group_id=1, actions=[ # List of tuples (action name, {action param: value}) - ("MODIFY ME", {"MODIFY ME": next_hop_mac}), + ("IngressPipeImpl.set_nexthop", {"dst_mac": next_hop_mac}), ] )) @@ -360,7 +360,7 @@ def testPacket(self, pkt, sid_list, next_hop_mac, my_sid): # next SID in the list, we should route based on that. next_sid = sid_list[1] self.insert(self.helper.build_table_entry( - table_name="MODIFY ME", + table_name="IngressPipeImpl.ipv6_routing_table", match_fields={ # LPM match (value, prefix) "hdr.ipv6.dst_addr": (next_sid, 128) @@ -370,14 +370,14 @@ def testPacket(self, pkt, sid_list, next_hop_mac, my_sid): # Map next_hop_mac to output port self.insert(self.helper.build_table_entry( - table_name="MODIFY ME", + table_name="IngressPipeImpl.l2_exact_table", match_fields={ - # Exact match - "MODIFY ME": next_hop_mac + # Exact match. + "hdr.ethernet.dst_addr": next_hop_mac }, - action_name="MODIFY ME", + action_name="IngressPipeImpl.set_egress_port", action_params={ - "MODIFY ME": self.port2 + "port_num": self.port2 } )) @@ -435,38 +435,38 @@ def testPacket(self, pkt, sid_list, next_hop_mac, my_sid): # Add entry to "My Station" table. Consider the given pkt's eth dst addr # as myStationMac address. self.insert(self.helper.build_table_entry( - table_name="MODIFY ME", + table_name="IngressPipeImpl.ipv6_my_station_table", match_fields={ # Exact match. - "MODIFY ME": pkt[Ether].dst + "hdr.ethernet.dst_addr": pkt[Ether].dst }, action_name="NoAction" )) # This should be matched, we want SRv6 end behavior to be applied. self.insert(self.helper.build_table_entry( - table_name="MODIFY ME", + table_name="IngressPipeImpl.srv6_my_sid", match_fields={ # Longest prefix match (value, prefix length) - "MODIFY ME": (my_sid, 128) + "hdr.ipv6.dst_addr": (my_sid, 128) }, - action_name="MODIFY ME" + action_name="IngressPipeImpl.srv6_end" )) # Insert ECMP group with only one member (next_hop_mac) self.insert(self.helper.build_act_prof_group( - act_prof_name="MODIFY ME", + act_prof_name="IngressPipeImpl.ecmp_selector", group_id=1, actions=[ # List of tuples (action name, {action param: value}) - ("MODIFY ME", {"MODIFY ME": next_hop_mac}), + ("IngressPipeImpl.set_nexthop", {"dst_mac": next_hop_mac}), ] )) # Map pkt's IPv6 dst addr to group next_sid = sid_list[1] self.insert(self.helper.build_table_entry( - table_name="MODIFY ME", + table_name="IngressPipeImpl.ipv6_routing_table", match_fields={ # LPM match (value, prefix) "hdr.ipv6.dst_addr": (next_sid, 128) @@ -476,14 +476,14 @@ def testPacket(self, pkt, sid_list, next_hop_mac, my_sid): # Map next_hop_mac to output port self.insert(self.helper.build_table_entry( - table_name="MODIFY ME", + table_name="IngressPipeImpl.l2_exact_table", match_fields={ - # Exact match - "MODIFY ME": next_hop_mac + # Exact match. + "hdr.ethernet.dst_addr": next_hop_mac }, - action_name="MODIFY ME", + action_name="IngressPipeImpl.set_egress_port", action_params={ - "MODIFY ME": self.port2 + "port_num": self.port2 } )) diff --git a/query.log b/query.log new file mode 100644 index 0000000..a053e44 --- /dev/null +++ b/query.log @@ -0,0 +1,1510 @@ +I have the following code: +``` +/* + * Copyright 2019-present Open Networking Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include +#include + +// CPU_PORT specifies the P4 port number associated to controller packet-in and +// packet-out. All packets forwarded via this port will be delivered to the +// controller as P4Runtime PacketIn messages. Similarly, PacketOut messages from +// the controller will be seen by the P4 pipeline as coming from the CPU_PORT. +#define CPU_PORT 255 + +// CPU_CLONE_SESSION_ID specifies the mirroring session for packets to be cloned +// to the CPU port. Packets associated with this session ID will be cloned to +// the CPU_PORT as well as being transmitted via their egress port (set by the +// bridging/routing/acl table). For cloning to work, the P4Runtime controller +// needs first to insert a CloneSessionEntry that maps this session ID to the +// CPU_PORT. +#define CPU_CLONE_SESSION_ID 99 + +// Maximum number of hops supported when using SRv6. +// Required for Exercise 7. +#define SRV6_MAX_HOPS 4 + +typedef bit<9> port_num_t; +typedef bit<48> mac_addr_t; +typedef bit<16> mcast_group_id_t; +typedef bit<32> ipv4_addr_t; +typedef bit<128> ipv6_addr_t; +typedef bit<16> l4_port_t; + +const bit<16> ETHERTYPE_IPV4 = 0x0800; +const bit<16> ETHERTYPE_IPV6 = 0x86dd; + +const bit<8> IP_PROTO_ICMP = 1; +const bit<8> IP_PROTO_TCP = 6; +const bit<8> IP_PROTO_UDP = 17; +const bit<8> IP_PROTO_SRV6 = 43; +const bit<8> IP_PROTO_ICMPV6 = 58; + +const mac_addr_t IPV6_MCAST_01 = 0x33_33_00_00_00_01; + +const bit<8> ICMP6_TYPE_NS = 135; +const bit<8> ICMP6_TYPE_NA = 136; + +const bit<8> NDP_OPT_TARGET_LL_ADDR = 2; + +const bit<32> NDP_FLAG_ROUTER = 0x80000000; +const bit<32> NDP_FLAG_SOLICITED = 0x40000000; +const bit<32> NDP_FLAG_OVERRIDE = 0x20000000; + +//------------------------------------------------------------------------------ +// HEADER DEFINITIONS +//------------------------------------------------------------------------------ + +header ethernet_t { + mac_addr_t dst_addr; + mac_addr_t src_addr; + bit<16> ether_type; +} + +header ipv4_t { + bit<4> version; + bit<4> ihl; + bit<6> dscp; + bit<2> ecn; + bit<16> total_len; + bit<16> identification; + bit<3> flags; + bit<13> frag_offset; + bit<8> ttl; + bit<8> protocol; + bit<16> hdr_checksum; + bit<32> src_addr; + bit<32> dst_addr; +} + +header ipv6_t { + bit<4> version; + bit<8> traffic_class; + bit<20> flow_label; + bit<16> payload_len; + bit<8> next_hdr; + bit<8> hop_limit; + bit<128> src_addr; + bit<128> dst_addr; +} + +header srv6h_t { + bit<8> next_hdr; + bit<8> hdr_ext_len; + bit<8> routing_type; + bit<8> segment_left; + bit<8> last_entry; + bit<8> flags; + bit<16> tag; +} + +header srv6_list_t { + bit<128> segment_id; +} + +header tcp_t { + bit<16> src_port; + bit<16> dst_port; + bit<32> seq_no; + bit<32> ack_no; + bit<4> data_offset; + bit<3> res; + bit<3> ecn; + bit<6> ctrl; + bit<16> window; + bit<16> checksum; + bit<16> urgent_ptr; +} + +header udp_t { + bit<16> src_port; + bit<16> dst_port; + bit<16> len; + bit<16> checksum; +} + +header icmp_t { + bit<8> type; + bit<8> icmp_code; + bit<16> checksum; + bit<16> identifier; + bit<16> sequence_number; + bit<64> timestamp; +} + +header icmpv6_t { + bit<8> type; + bit<8> code; + bit<16> checksum; +} + +header ndp_t { + bit<32> flags; + ipv6_addr_t target_ipv6_addr; + // NDP option. + bit<8> type; + bit<8> length; + bit<48> target_mac_addr; +} + +// Packet-in header. Prepended to packets sent to the CPU_PORT and used by the +// P4Runtime server (Stratum) to populate the PacketIn message metadata fields. +// Here we use it to carry the original ingress port where the packet was +// received. +@controller_header("packet_in") +header cpu_in_header_t { + port_num_t ingress_port; + bit<7> _pad; +} + +// Packet-out header. Prepended to packets received from the CPU_PORT. Fields of +// this header are populated by the P4Runtime server based on the P4Runtime +// PacketOut metadata fields. Here we use it to inform the P4 pipeline on which +// port this packet-out should be transmitted. +@controller_header("packet_out") +header cpu_out_header_t { + port_num_t egress_port; + bit<7> _pad; +} + +struct parsed_headers_t { + cpu_out_header_t cpu_out; + cpu_in_header_t cpu_in; + ethernet_t ethernet; + ipv4_t ipv4; + ipv6_t ipv6; + srv6h_t srv6h; + srv6_list_t[SRV6_MAX_HOPS] srv6_list; + tcp_t tcp; + udp_t udp; + icmp_t icmp; + icmpv6_t icmpv6; + ndp_t ndp; +} + +struct local_metadata_t { + l4_port_t l4_src_port; + l4_port_t l4_dst_port; + bool is_multicast; + ipv6_addr_t next_srv6_sid; + bit<8> ip_proto; + bit<8> icmp_type; +} + + +//------------------------------------------------------------------------------ +// INGRESS PIPELINE +//------------------------------------------------------------------------------ + +parser ParserImpl (packet_in packet, + out parsed_headers_t hdr, + inout local_metadata_t local_metadata, + inout standard_metadata_t standard_metadata) +{ + state start { + transition select(standard_metadata.ingress_port) { + CPU_PORT: parse_packet_out; + default: parse_ethernet; + } + } + + state parse_packet_out { + packet.extract(hdr.cpu_out); + transition parse_ethernet; + } + + state parse_ethernet { + packet.extract(hdr.ethernet); + transition select(hdr.ethernet.ether_type){ + ETHERTYPE_IPV4: parse_ipv4; + ETHERTYPE_IPV6: parse_ipv6; + default: accept; + } + } + + state parse_ipv4 { + packet.extract(hdr.ipv4); + local_metadata.ip_proto = hdr.ipv4.protocol; + transition select(hdr.ipv4.protocol) { + IP_PROTO_TCP: parse_tcp; + IP_PROTO_UDP: parse_udp; + IP_PROTO_ICMP: parse_icmp; + default: accept; + } + } + + state parse_ipv6 { + packet.extract(hdr.ipv6); + local_metadata.ip_proto = hdr.ipv6.next_hdr; + transition select(hdr.ipv6.next_hdr) { + IP_PROTO_TCP: parse_tcp; + IP_PROTO_UDP: parse_udp; + IP_PROTO_ICMPV6: parse_icmpv6; + IP_PROTO_SRV6: parse_srv6; + default: accept; + } + } + + state parse_tcp { + packet.extract(hdr.tcp); + local_metadata.l4_src_port = hdr.tcp.src_port; + local_metadata.l4_dst_port = hdr.tcp.dst_port; + transition accept; + } + + state parse_udp { + packet.extract(hdr.udp); + local_metadata.l4_src_port = hdr.udp.src_port; + local_metadata.l4_dst_port = hdr.udp.dst_port; + transition accept; + } + + state parse_icmp { + packet.extract(hdr.icmp); + local_metadata.icmp_type = hdr.icmp.type; + transition accept; + } + + state parse_icmpv6 { + packet.extract(hdr.icmpv6); + local_metadata.icmp_type = hdr.icmpv6.type; + transition select(hdr.icmpv6.type) { + ICMP6_TYPE_NS: parse_ndp; + ICMP6_TYPE_NA: parse_ndp; + default: accept; + } + } + + state parse_ndp { + packet.extract(hdr.ndp); + transition accept; + } + + state parse_srv6 { + packet.extract(hdr.srv6h); + transition parse_srv6_list; + } + + state parse_srv6_list { + packet.extract(hdr.srv6_list.next); + bool next_segment = (bit<32>)hdr.srv6h.segment_left - 1 == (bit<32>)hdr.srv6_list.lastIndex; + transition select(next_segment) { + true: mark_current_srv6; + default: check_last_srv6; + } + } + + state mark_current_srv6 { + local_metadata.next_srv6_sid = hdr.srv6_list.last.segment_id; + transition check_last_srv6; + } + + state check_last_srv6 { + // working with bit<8> and int<32> which cannot be cast directly; using + // bit<32> as common intermediate type for comparision + bool last_segment = (bit<32>)hdr.srv6h.last_entry == (bit<32>)hdr.srv6_list.lastIndex; + transition select(last_segment) { + true: parse_srv6_next_hdr; + false: parse_srv6_list; + } + } + + state parse_srv6_next_hdr { + transition select(hdr.srv6h.next_hdr) { + IP_PROTO_TCP: parse_tcp; + IP_PROTO_UDP: parse_udp; + IP_PROTO_ICMPV6: parse_icmpv6; + default: accept; + } + } +} + + +control VerifyChecksumImpl(inout parsed_headers_t hdr, + inout local_metadata_t meta) +{ + // Not used here. We assume all packets have valid checksum, if not, we let + // the end hosts detect errors. + apply { /* EMPTY */ } +} + + +control IngressPipeImpl (inout parsed_headers_t hdr, + inout local_metadata_t local_metadata, + inout standard_metadata_t standard_metadata) { + + // Drop action shared by many tables. + action drop() { + mark_to_drop(standard_metadata); + } + + + // *** L2 BRIDGING + // + // Here we define tables to forward packets based on their Ethernet + // destination address. There are two types of L2 entries that we + // need to support: + // + // 1. Unicast entries: which will be filled in by the control plane when the + // location (port) of new hosts is learned. + // 2. Broadcast/multicast entries: used replicate NDP Neighbor Solicitation + // (NS) messages to all host-facing ports; + // + // For (2), unlike ARP messages in IPv4 which are broadcasted to Ethernet + // destination address FF:FF:FF:FF:FF:FF, NDP messages are sent to special + // Ethernet addresses specified by RFC2464. These addresses are prefixed + // with 33:33 and the last four octets are the last four octets of the IPv6 + // destination multicast address. The most straightforward way of matching + // on such IPv6 broadcast/multicast packets, without digging in the details + // of RFC2464, is to use a ternary match on 33:33:**:**:**:**, where * means + // "don't care". + // + // For this reason, our solution defines two tables. One that matches in an + // exact fashion (easier to scale on switch ASIC memory) and one that uses + // ternary matching (which requires more expensive TCAM memories, usually + // much smaller). + + // --- l2_exact_table (for unicast entries) -------------------------------- + + action set_egress_port(port_num_t port_num) { + standard_metadata.egress_spec = port_num; + } + + table l2_exact_table { + key = { + hdr.ethernet.dst_addr: exact; + } + actions = { + set_egress_port; + @defaultonly drop; + } + const default_action = drop; + // The @name annotation is used here to provide a name to this table + // counter, as it will be needed by the compiler to generate the + // corresponding P4Info entity. + @name("l2_exact_table_counter") + counters = direct_counter(CounterType.packets_and_bytes); + } + + // --- l2_ternary_table (for broadcast/multicast entries) ------------------ + + action set_multicast_group(mcast_group_id_t gid) { + // gid will be used by the Packet Replication Engine (PRE) in the + // Traffic Manager--located right after the ingress pipeline, to + // replicate a packet to multiple egress ports, specified by the control + // plane by means of P4Runtime MulticastGroupEntry messages. + standard_metadata.mcast_grp = gid; + local_metadata.is_multicast = true; + } + + table l2_ternary_table { + key = { + hdr.ethernet.dst_addr: ternary; + } + actions = { + set_multicast_group; + @defaultonly drop; + } + const default_action = drop; + @name("l2_ternary_table_counter") + counters = direct_counter(CounterType.packets_and_bytes); + } + + // *** TODO EXERCISE 5 (IPV6 ROUTING) + // + // 1. Create a table to to handle NDP messages to resolve the MAC address of + // switch. This table should: + // - match on hdr.ndp.target_ipv6_addr (exact match) + // - provide action "ndp_ns_to_na" (look in snippets.p4) + // - default_action should be "NoAction" + // + // 2. Create table to handle IPv6 routing. Create a L2 my station table (hit + // when Ethernet destination address is the switch address). This table + // should not do anything to the packet (i.e., NoAction), but the control + // block below should use the result (table.hit) to decide how to process + // the packet. + // + // 3. Create a table for IPv6 routing. An action selector should be use to + // pick a next hop MAC address according to a hash of packet header + // fields (IPv6 source/destination address and the flow label). Look in + // snippets.p4 for an example of an action selector and table using it. + // + // You can name your tables whatever you like. You will need to fill + // the name in elsewhere in this exercise. + + action ndp_ns_to_na(mac_addr_t target_mac) { + hdr.ethernet.src_addr = target_mac; + hdr.ethernet.dst_addr = IPV6_MCAST_01; + ipv6_addr_t host_ipv6_tmp = hdr.ipv6.src_addr; + hdr.ipv6.src_addr = hdr.ndp.target_ipv6_addr; + hdr.ipv6.dst_addr = host_ipv6_tmp; + hdr.ipv6.next_hdr = IP_PROTO_ICMPV6; + hdr.icmpv6.type = ICMP6_TYPE_NA; + hdr.ndp.flags = NDP_FLAG_ROUTER | NDP_FLAG_OVERRIDE; + hdr.ndp.type = NDP_OPT_TARGET_LL_ADDR; + hdr.ndp.length = 1; + hdr.ndp.target_mac_addr = target_mac; + standard_metadata.egress_spec = standard_metadata.ingress_port; + } + + table ndp_reply_table { + key = { + hdr.ndp.target_ipv6_addr: exact; + } + actions = { + ndp_ns_to_na; + @defaultonly NoAction; + } + const default_action = NoAction; + @name("ndp_reply_table_counter") + counters = direct_counter(CounterType.packets_and_bytes); + } + + table ipv6_my_station_table { + key = { + hdr.ethernet.dst_addr: exact; + } + actions = { + NoAction; + } + const default_action = NoAction; + @name("ipv6_my_station_table_counter") + counters = direct_counter(CounterType.packets_and_bytes); + } + + // ECMP action selector definition: + action_selector(HashAlgorithm.crc16, 32w1024, 32w16) ecmp_selector; + + action set_nexthop(mac_addr_t dst_mac) { + hdr.ethernet.src_addr = hdr.ethernet.dst_addr; + hdr.ethernet.dst_addr = dst_mac; + hdr.ipv6.hop_limit = hdr.ipv6.hop_limit - 1; + } + + table ipv6_routing_table { + key = { + hdr.ipv6.dst_addr: lpm; + } + actions = { + set_nexthop; + drop; + } + implementation = ecmp_selector; + size = 1024; + } + + // *** TODO EXERCISE 6 (SRV6) + // + // Implement tables to provide SRV6 logic. + + + // *** ACL + // + // Provides ways to override a previous forwarding decision, for example + // requiring that a packet is cloned/sent to the CPU, or dropped. + // + // We use this table to clone all NDP packets to the control plane, so to + // enable host discovery. When the location of a new host is discovered, the + // controller is expected to update the L2 and L3 tables with the + // corresponding bridging and routing entries. + + action send_to_cpu() { + standard_metadata.egress_spec = CPU_PORT; + } + + action clone_to_cpu() { + // Cloning is achieved by using a v1model-specific primitive. Here we + // set the type of clone operation (ingress-to-egress pipeline), the + // clone session ID (the CPU one), and the metadata fields we want to + // preserve for the cloned packet replica. + clone3(CloneType.I2E, CPU_CLONE_SESSION_ID, { standard_metadata.ingress_port }); + } + + table acl_table { + key = { + standard_metadata.ingress_port: ternary; + hdr.ethernet.dst_addr: ternary; + hdr.ethernet.src_addr: ternary; + hdr.ethernet.ether_type: ternary; + local_metadata.ip_proto: ternary; + local_metadata.icmp_type: ternary; + local_metadata.l4_src_port: ternary; + local_metadata.l4_dst_port: ternary; + } + actions = { + send_to_cpu; + clone_to_cpu; + drop; + } + @name("acl_table_counter") + counters = direct_counter(CounterType.packets_and_bytes); + } + + apply { + + if (hdr.cpu_out.isValid()) { + // *** TODO EXERCISE 4 + // Implement logic such that if this is a packet-out from the + // controller: + // 1. Set the packet egress port to that found in the cpu_out header + // 2. Remove (set invalid) the cpu_out header + // 3. Exit the pipeline here (no need to go through other tables + + standard_metadata.egress_spec = hdr.cpu_out.egress_port; + hdr.cpu_out.setInvalid(); + return; + } + + bool do_l3_l2 = true; + + if (hdr.icmpv6.isValid() && hdr.icmpv6.type == ICMP6_TYPE_NS) { + // *** TODO EXERCISE 5 + // Insert logic to handle NDP messages to resolve the MAC address of the + // switch. You should apply the NDP reply table created before. + // If this is an NDP NS packet, i.e., if a matching entry is found, + // unset the "do_l3_l2" flag to skip the L3 and L2 tables, as the + // "ndp_ns_to_na" action already set an egress port. + + if (ndp_reply_table.apply().hit) { + do_l3_l2 = false; + } + } + + if (do_l3_l2) { + + // *** TODO EXERCISE 5 + // Insert logic to match the My Station table and upon hit, the + // routing table. You should also add a conditional to drop the + // packet if the hop_limit reaches 0. + + if (ipv6_my_station_table.apply().hit) { + if (hdr.ipv6.isValid() && hdr.ipv6.hop_limit == 0) { + mark_to_drop(standard_metadata); + } else { + ipv6_routing_table.apply(); + } + } + + // *** TODO EXERCISE 6 + // Insert logic to match the SRv6 My SID and Transit tables as well + // as logic to perform PSP behavior. HINT: This logic belongs + // somewhere between checking the switch's my station table and + // applying the routing table. + + // L2 bridging logic. Apply the exact table first... + if (!l2_exact_table.apply().hit) { + // ...if an entry is NOT found, apply the ternary one in case + // this is a multicast/broadcast NDP NS packet. + l2_ternary_table.apply(); + } + } + + // Lastly, apply the ACL table. + acl_table.apply(); + } +} + + +control EgressPipeImpl (inout parsed_headers_t hdr, + inout local_metadata_t local_metadata, + inout standard_metadata_t standard_metadata) { + apply { + + if (standard_metadata.egress_port == CPU_PORT) { + // *** TODO EXERCISE 4 + // Implement logic such that if the packet is to be forwarded to the + // CPU port, e.g., if in ingress we matched on the ACL table with + // action send/clone_to_cpu... + // 1. Set cpu_in header as valid + // 2. Set the cpu_in.ingress_port field to the original packet's + // ingress port (standard_metadata.ingress_port). + + hdr.cpu_in.setValid(); + hdr.cpu_in.ingress_port = standard_metadata.ingress_port; + } + + // If this is a multicast packet (flag set by l2_ternary_table), make + // sure we are not replicating the packet on the same port where it was + // received. This is useful to avoid broadcasting NDP requests on the + // ingress port. + if (local_metadata.is_multicast == true && + standard_metadata.ingress_port == standard_metadata.egress_port) { + mark_to_drop(standard_metadata); + } + } +} + + +control ComputeChecksumImpl(inout parsed_headers_t hdr, + inout local_metadata_t local_metadata) +{ + apply { + // The following is used to update the ICMPv6 checksum of NDP + // NA packets generated by the ndp reply table in the ingress pipeline. + // This function is executed only if the NDP header is present. + update_checksum(hdr.ndp.isValid(), + { + hdr.ipv6.src_addr, + hdr.ipv6.dst_addr, + hdr.ipv6.payload_len, + 8w0, + hdr.ipv6.next_hdr, + hdr.icmpv6.type, + hdr.icmpv6.code, + hdr.ndp.flags, + hdr.ndp.target_ipv6_addr, + hdr.ndp.type, + hdr.ndp.length, + hdr.ndp.target_mac_addr + }, + hdr.icmpv6.checksum, + HashAlgorithm.csum16 + ); + } +} + + +control DeparserImpl(packet_out packet, in parsed_headers_t hdr) { + apply { + packet.emit(hdr.cpu_in); + packet.emit(hdr.ethernet); + packet.emit(hdr.ipv4); + packet.emit(hdr.ipv6); + packet.emit(hdr.srv6h); + packet.emit(hdr.srv6_list); + packet.emit(hdr.tcp); + packet.emit(hdr.udp); + packet.emit(hdr.icmp); + packet.emit(hdr.icmpv6); + packet.emit(hdr.ndp); + } +} + + +V1Switch( + ParserImpl(), + VerifyChecksumImpl(), + IngressPipeImpl(), + EgressPipeImpl(), + ComputeChecksumImpl(), + DeparserImpl() +) main; + +``` + +``` +/* + * Copyright 2019-present Open Networking Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onosproject.ngsdn.tutorial; + +/* includes */ + +/** + * App component that configures devices to provide IPv6 routing capabilities + * across the whole fabric. + */ +@Component( + immediate = true, + // *** TODO EXERCISE 5 + // set to true when ready + enabled = true +) +public class Ipv6RoutingComponent { + + private static final Logger log = LoggerFactory.getLogger(Ipv6RoutingComponent.class); + + private static final int DEFAULT_ECMP_GROUP_ID = 0xec3b0000; + private static final long GROUP_INSERT_DELAY_MILLIS = 200; + + private final HostListener hostListener = new InternalHostListener(); + private final LinkListener linkListener = new InternalLinkListener(); + private final DeviceListener deviceListener = new InternalDeviceListener(); + + private ApplicationId appId; + + //-------------------------------------------------------------------------- + // ONOS CORE SERVICE BINDING + // + // These variables are set by the Karaf runtime environment before calling + // the activate() method. + //-------------------------------------------------------------------------- + + /* fields ... */ + + //-------------------------------------------------------------------------- + // COMPONENT ACTIVATION. + // + // When loading/unloading the app the Karaf runtime environment will call + // activate()/deactivate(). + //-------------------------------------------------------------------------- + + @Activate + protected void activate() { + appId = mainComponent.getAppId(); + + hostService.addListener(hostListener); + linkService.addListener(linkListener); + deviceService.addListener(deviceListener); + + // Schedule set up for all devices. + mainComponent.scheduleTask(this::setUpAllDevices, INITIAL_SETUP_DELAY); + + log.info("Started"); + } + + @Deactivate + protected void deactivate() { + hostService.removeListener(hostListener); + linkService.removeListener(linkListener); + deviceService.removeListener(deviceListener); + + log.info("Stopped"); + } + + //-------------------------------------------------------------------------- + // METHODS TO COMPLETE. + // + // Complete the implementation wherever you see TODO. + //-------------------------------------------------------------------------- + + /** + * Sets up the "My Station" table for the given device using the + * myStationMac address found in the config. + *

+ * This method will be called at component activation for each device + * (switch) known by ONOS, and every time a new device-added event is + * captured by the InternalDeviceListener defined below. + * + * @param deviceId the device ID + */ + private void setUpMyStationTable(DeviceId deviceId) { + + log.info("Adding My Station rules to {}...", deviceId); + + final MacAddress myStationMac = getMyStationMac(deviceId); + + // HINT: in our solution, the My Station table matches on the *ethernet + // destination* and there is only one action called *NoAction*, which is + // used as an indication of "table hit" in the control block. + + // *** TODO EXERCISE 5 + // Modify P4Runtime entity names to match content of P4Info file (look + // for the fully qualified name of tables, match fields, and actions. + // ---- START SOLUTION ---- + final String tableId = "IngressPipeImpl.ipv6_my_station_table"; + + final PiCriterion match = PiCriterion.builder() + .matchExact( + PiMatchFieldId.of("hdr.ethernet.dst_addr"), + myStationMac.toBytes()) + .build(); + + // Creates an action which do *NoAction* when hit. + final PiTableAction action = PiAction.builder() + .withId(PiActionId.of("NoAction")) + .build(); + // ---- END SOLUTION ---- + + final FlowRule myStationRule = Utils.buildFlowRule( + deviceId, appId, tableId, match, action); + + log.error("#!#!#!#! INSERTED ipv6_my_station_table ENTRY: deviceId = {}, appId = {}", deviceId, appId); + + flowRuleService.applyFlowRules(myStationRule); + } + + /** + * Creates an ONOS SELECT group for the routing table to provide ECMP + * forwarding for the given collection of next hop MAC addresses. ONOS + * SELECT groups are equivalent to P4Runtime action selector groups. + *

+ * This method will be called by the routing policy methods below to insert + * groups in the L3 table + * + * @param nextHopMacs the collection of mac addresses of next hops + * @param deviceId the device where the group will be installed + * @return a SELECT group + */ + private GroupDescription createNextHopGroup(int groupId, + Collection nextHopMacs, + DeviceId deviceId) { + + String actionProfileId = "IngressPipeImpl.ecmp_selector"; + + final List actions = Lists.newArrayList(); + + // Build one "set next hop" action for each next hop + // *** TODO EXERCISE 5 + // Modify P4Runtime entity names to match content of P4Info file (look + // for the fully qualified name of tables, match fields, and actions. + // ---- START SOLUTION ---- + final String tableId = "IngressPipeImpl.ipv6_routing_table"; + for (MacAddress nextHopMac : nextHopMacs) { + final PiAction action = PiAction.builder() + .withId(PiActionId.of("IngressPipeImpl.set_nexthop")) + .withParameter(new PiActionParam( + // Action param name. + PiActionParamId.of("dst_mac"), + // Action param value. + nextHopMac.toBytes())) + .build(); + + actions.add(action); + } + // ---- END SOLUTION ---- + + return Utils.buildSelectGroup( + deviceId, tableId, actionProfileId, groupId, actions, appId); + } + + /** + * Creates a routing flow rule that matches on the given IPv6 prefix and + * executes the given group ID (created before). + * + * @param deviceId the device where flow rule will be installed + * @param ip6Prefix the IPv6 prefix + * @param groupId the group ID + * @return a flow rule + */ + private FlowRule createRoutingRule(DeviceId deviceId, Ip6Prefix ip6Prefix, + int groupId) { + + // *** TODO EXERCISE 5 + // Modify P4Runtime entity names to match content of P4Info file (look + // for the fully qualified name of tables, match fields, and actions. + // ---- START SOLUTION ---- + final String tableId = "IngressPipeImpl.ipv6_routing_table"; + final PiCriterion match = PiCriterion.builder() + .matchLpm( + PiMatchFieldId.of("hdr.ipv6.dst_addr"), + ip6Prefix.address().toOctets(), + ip6Prefix.prefixLength()) + .build(); + + final PiTableAction action = PiActionProfileGroupId.of(groupId); + // ---- END SOLUTION ---- + + log.error("#!#!#!#! INSERTED ipv6_routing_table ENTRY: deviceId = {}, groupId = {}, ip6Prefix = {}", deviceId, groupId, ip6Prefix); + + return Utils.buildFlowRule( + deviceId, appId, tableId, match, action); + } + + /** + * Creates a flow rule for the L2 table mapping the given next hop MAC to + * the given output port. + *

+ * This is called by the routing policy methods below to establish L2-based + * forwarding inside the fabric, e.g., when deviceId is a leaf switch and + * nextHopMac is the one of a spine switch. + * + * @param deviceId the device + * @param nexthopMac the next hop (destination) mac + * @param outPort the output port + */ + private FlowRule createL2NextHopRule(DeviceId deviceId, MacAddress nexthopMac, + PortNumber outPort) { + + // *** TODO EXERCISE 5 + // Modify P4Runtime entity names to match content of P4Info file (look + // for the fully qualified name of tables, match fields, and actions. + // ---- START SOLUTION ---- + final String tableId = "IngressPipeImpl.l2_exact_table"; + final PiCriterion match = PiCriterion.builder() + .matchExact(PiMatchFieldId.of("hdr.ethernet.dst_addr"), + nexthopMac.toBytes()) + .build(); + + + final PiAction action = PiAction.builder() + .withId(PiActionId.of("IngressPipeImpl.set_egress_port")) + .withParameter(new PiActionParam( + PiActionParamId.of("port_num"), + outPort.toLong())) + .build(); + // ---- END SOLUTION ---- + + return Utils.buildFlowRule( + deviceId, appId, tableId, match, action); + } + + //-------------------------------------------------------------------------- + // EVENT LISTENERS + // + // Events are processed only if isRelevant() returns true. + //-------------------------------------------------------------------------- + + /** + * Listener of host events which triggers configuration of routing rules on + * the device where the host is attached. + */ + class InternalHostListener implements HostListener { + + @Override + public boolean isRelevant(HostEvent event) { + switch (event.type()) { + case HOST_ADDED: + break; + case HOST_REMOVED: + case HOST_UPDATED: + case HOST_MOVED: + default: + // Ignore other events. + // Food for thoughts: + // how to support host moved/removed events? + return false; + } + // Process host event only if this controller instance is the master + // for the device where this host is attached. + final Host host = event.subject(); + final DeviceId deviceId = host.location().deviceId(); + return mastershipService.isLocalMaster(deviceId); + } + + @Override + public void event(HostEvent event) { + Host host = event.subject(); + DeviceId deviceId = host.location().deviceId(); + mainComponent.getExecutorService().execute(() -> { + log.info("{} event! host={}, deviceId={}, port={}", + event.type(), host.id(), deviceId, host.location().port()); + setUpHostRules(deviceId, host); + }); + } + } + + /** + * Listener of link events, which triggers configuration of routing rules to + * forward packets across the fabric, i.e. from leaves to spines and vice + * versa. + *

+ * Reacting to link events instead of device ones, allows us to make sure + * all device are always configured with a topology view that includes all + * links, e.g. modifying an ECMP group as soon as a new link is added. The + * downside is that we might be configuring the same device twice for the + * same set of links/paths. However, the ONOS core treats these cases as a + * no-op when the device is already configured with the desired forwarding + * state (i.e. flows and groups) + */ + class InternalLinkListener implements LinkListener { + + @Override + public boolean isRelevant(LinkEvent event) { + switch (event.type()) { + case LINK_ADDED: + break; + case LINK_UPDATED: + case LINK_REMOVED: + default: + return false; + } + DeviceId srcDev = event.subject().src().deviceId(); + DeviceId dstDev = event.subject().dst().deviceId(); + return mastershipService.isLocalMaster(srcDev) || + mastershipService.isLocalMaster(dstDev); + } + + @Override + public void event(LinkEvent event) { + DeviceId srcDev = event.subject().src().deviceId(); + DeviceId dstDev = event.subject().dst().deviceId(); + + if (mastershipService.isLocalMaster(srcDev)) { + mainComponent.getExecutorService().execute(() -> { + log.info("{} event! Configuring {}... linkSrc={}, linkDst={}", + event.type(), srcDev, srcDev, dstDev); + setUpFabricRoutes(srcDev); + setUpL2NextHopRules(srcDev); + }); + } + if (mastershipService.isLocalMaster(dstDev)) { + mainComponent.getExecutorService().execute(() -> { + log.info("{} event! Configuring {}... linkSrc={}, linkDst={}", + event.type(), dstDev, srcDev, dstDev); + setUpFabricRoutes(dstDev); + setUpL2NextHopRules(dstDev); + }); + } + } + } + + /** + * Listener of device events which triggers configuration of the My Station + * table. + */ + class InternalDeviceListener implements DeviceListener { + + @Override + public boolean isRelevant(DeviceEvent event) { + switch (event.type()) { + case DEVICE_AVAILABILITY_CHANGED: + case DEVICE_ADDED: + break; + default: + return false; + } + // Process device event if this controller instance is the master + // for the device and the device is available. + DeviceId deviceId = event.subject().id(); + return mastershipService.isLocalMaster(deviceId) && + deviceService.isAvailable(event.subject().id()); + } + + @Override + public void event(DeviceEvent event) { + mainComponent.getExecutorService().execute(() -> { + DeviceId deviceId = event.subject().id(); + log.info("{} event! device id={}", event.type(), deviceId); + setUpMyStationTable(deviceId); + }); + } + } + + //-------------------------------------------------------------------------- + // ROUTING POLICY METHODS + // + // Called by event listeners, these methods implement the actual routing + // policy, responsible of computing paths and creating ECMP groups. + //-------------------------------------------------------------------------- + + /** + * Set up L2 nexthop rules of a device to providing forwarding inside the + * fabric, i.e. between leaf and spine switches. + * + * @param deviceId the device ID + */ + private void setUpL2NextHopRules(DeviceId deviceId) { + + Set egressLinks = linkService.getDeviceEgressLinks(deviceId); + + for (Link link : egressLinks) { + // For each other switch directly connected to this. + final DeviceId nextHopDevice = link.dst().deviceId(); + // Get port of this device connecting to next hop. + final PortNumber outPort = link.src().port(); + // Get next hop MAC address. + final MacAddress nextHopMac = getMyStationMac(nextHopDevice); + + final FlowRule nextHopRule = createL2NextHopRule( + deviceId, nextHopMac, outPort); + + flowRuleService.applyFlowRules(nextHopRule); + } + } + + /** + * Sets up the given device with the necessary rules to route packets to the + * given host. + * + * @param deviceId deviceId the device ID + * @param host the host + */ + private void setUpHostRules(DeviceId deviceId, Host host) { + + // Get all IPv6 addresses associated to this host. In this tutorial we + // use hosts with only 1 IPv6 address. + final Collection hostIpv6Addrs = host.ipAddresses().stream() + .filter(IpAddress::isIp6) + .map(IpAddress::getIp6Address) + .collect(Collectors.toSet()); + + if (hostIpv6Addrs.isEmpty()) { + // Ignore. + log.debug("No IPv6 addresses for host {}, ignore", host.id()); + return; + } else { + log.info("Adding routes on {} for host {} [{}]", + deviceId, host.id(), hostIpv6Addrs); + } + + // Create an ECMP group with only one member, where the group ID is + // derived from the host MAC. + final MacAddress hostMac = host.mac(); + int groupId = macToGroupId(hostMac); + + final GroupDescription group = createNextHopGroup( + groupId, Collections.singleton(hostMac), deviceId); + + // Map each host IPV6 address to corresponding /128 prefix and obtain a + // flow rule that points to the group ID. In this tutorial we expect + // only one flow rule per host. + final List flowRules = hostIpv6Addrs.stream() + .map(IpAddress::toIpPrefix) + .filter(IpPrefix::isIp6) + .map(IpPrefix::getIp6Prefix) + .map(prefix -> createRoutingRule(deviceId, prefix, groupId)) + .collect(Collectors.toList()); + + // Helper function to install flows after groups, since here flows + // points to the group and P4Runtime enforces this dependency during + // write operations. + insertInOrder(group, flowRules); + } + + /** + * Set up routes on a given device to forward packets across the fabric, + * making a distinction between spines and leaves. + * + * @param deviceId the device ID. + */ + private void setUpFabricRoutes(DeviceId deviceId) { + if (isSpine(deviceId)) { + setUpSpineRoutes(deviceId); + } else { + setUpLeafRoutes(deviceId); + } + } + + /** + * Insert routing rules on the given spine switch, matching on leaf + * interface subnets and forwarding packets to the corresponding leaf. + * + * @param spineId the spine device ID + */ + private void setUpSpineRoutes(DeviceId spineId) { + + log.info("Adding up spine routes on {}...", spineId); + + for (Device device : deviceService.getDevices()) { + + if (isSpine(device.id())) { + // We only need routes to leaf switches. Ignore spines. + continue; + } + + final DeviceId leafId = device.id(); + final MacAddress leafMac = getMyStationMac(leafId); + final Set subnetsToRoute = getInterfaceIpv6Prefixes(leafId); + + // Since we're here, we also add a route for SRv6 (Exercise 7), to + // forward packets with IPv6 dst the SID of a leaf switch. + final Ip6Address leafSid = getDeviceSid(leafId); + subnetsToRoute.add(Ip6Prefix.valueOf(leafSid, 128)); + + // Create a group with only one member. + int groupId = macToGroupId(leafMac); + + GroupDescription group = createNextHopGroup( + groupId, Collections.singleton(leafMac), spineId); + + List flowRules = subnetsToRoute.stream() + .map(subnet -> createRoutingRule(spineId, subnet, groupId)) + .collect(Collectors.toList()); + + insertInOrder(group, flowRules); + } + } + + /** + * Insert routing rules on the given leaf switch, matching on interface + * subnets associated to other leaves and forwarding packets the spines + * using ECMP. + * + * @param leafId the leaf device ID + */ + private void setUpLeafRoutes(DeviceId leafId) { + log.info("Setting up leaf routes: {}", leafId); + + // Get the set of subnets (interface IPv6 prefixes) associated to other + // leafs but not this one. + Set subnetsToRouteViaSpines = stream(deviceService.getDevices()) + .map(Device::id) + .filter(this::isLeaf) + .filter(deviceId -> !deviceId.equals(leafId)) + .map(this::getInterfaceIpv6Prefixes) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + + // Get myStationMac address of all spines. + Set spineMacs = stream(deviceService.getDevices()) + .map(Device::id) + .filter(this::isSpine) + .map(this::getMyStationMac) + .collect(Collectors.toSet()); + + // Create an ECMP group to distribute traffic across all spines. + final int groupId = DEFAULT_ECMP_GROUP_ID; + final GroupDescription ecmpGroup = createNextHopGroup( + groupId, spineMacs, leafId); + + // Generate a flow rule for each subnet pointing to the ECMP group. + List flowRules = subnetsToRouteViaSpines.stream() + .map(subnet -> createRoutingRule(leafId, subnet, groupId)) + .collect(Collectors.toList()); + + insertInOrder(ecmpGroup, flowRules); + + // Since we're here, we also add a route for SRv6 (Exercise 7), to + // forward packets with IPv6 dst the SID of a spine switch, in this case + // using a single-member group. + stream(deviceService.getDevices()) + .map(Device::id) + .filter(this::isSpine) + .forEach(spineId -> { + MacAddress spineMac = getMyStationMac(spineId); + Ip6Address spineSid = getDeviceSid(spineId); + int spineGroupId = macToGroupId(spineMac); + GroupDescription group = createNextHopGroup( + spineGroupId, Collections.singleton(spineMac), leafId); + FlowRule routingRule = createRoutingRule( + leafId, Ip6Prefix.valueOf(spineSid, 128), + spineGroupId); + insertInOrder(group, Collections.singleton(routingRule)); + }); + } + + //-------------------------------------------------------------------------- + // UTILITY METHODS + //-------------------------------------------------------------------------- + + /** + * Returns true if the given device has isSpine flag set to true in the + * config, false otherwise. + * + * @param deviceId the device ID + * @return true if the device is a spine, false otherwise + */ + private boolean isSpine(DeviceId deviceId) { + return getDeviceConfig(deviceId).map(FabricDeviceConfig::isSpine) + .orElseThrow(() -> new ItemNotFoundException( + "Missing isSpine config for " + deviceId)); + } + + /** + * Returns true if the given device is not configured as spine. + * + * @param deviceId the device ID + * @return true if the device is a leaf, false otherwise + */ + private boolean isLeaf(DeviceId deviceId) { + return !isSpine(deviceId); + } + + /** + * Returns the MAC address configured in the "myStationMac" property of the + * given device config. + * + * @param deviceId the device ID + * @return MyStation MAC address + */ + private MacAddress getMyStationMac(DeviceId deviceId) { + return getDeviceConfig(deviceId) + .map(FabricDeviceConfig::myStationMac) + .orElseThrow(() -> new ItemNotFoundException( + "Missing myStationMac config for " + deviceId)); + } + + /** + * Returns the FabricDeviceConfig config object for the given device. + * + * @param deviceId the device ID + * @return FabricDeviceConfig device config + */ + private Optional getDeviceConfig(DeviceId deviceId) { + FabricDeviceConfig config = networkConfigService.getConfig( + deviceId, FabricDeviceConfig.class); + return Optional.ofNullable(config); + } + + /** + * Returns the set of interface IPv6 subnets (prefixes) configured for the + * given device. + * + * @param deviceId the device ID + * @return set of IPv6 prefixes + */ + private Set getInterfaceIpv6Prefixes(DeviceId deviceId) { + return interfaceService.getInterfaces().stream() + .filter(iface -> iface.connectPoint().deviceId().equals(deviceId)) + .map(Interface::ipAddressesList) + .flatMap(Collection::stream) + .map(InterfaceIpAddress::subnetAddress) + .filter(IpPrefix::isIp6) + .map(IpPrefix::getIp6Prefix) + .collect(Collectors.toSet()); + } + + /** + * Returns a 32 bit bit group ID from the given MAC address. + * + * @param mac the MAC address + * @return an integer + */ + private int macToGroupId(MacAddress mac) { + return mac.hashCode() & 0x7fffffff; + } + + /** + * Inserts the given groups and flow rules in order, groups first, then flow + * rules. In P4Runtime, when operating on an indirect table (i.e. with + * action selectors), groups must be inserted before table entries. + * + * @param group the group + * @param flowRules the flow rules depending on the group + */ + private void insertInOrder(GroupDescription group, Collection flowRules) { + try { + groupService.addGroup(group); + // Wait for groups to be inserted. + Thread.sleep(GROUP_INSERT_DELAY_MILLIS); + flowRules.forEach(flowRuleService::applyFlowRules); + } catch (InterruptedException e) { + log.error("Interrupted!", e); + Thread.currentThread().interrupt(); + } + } + + /** + * Gets Srv6 SID for the given device. + * + * @param deviceId the device ID + * @return SID for the device + */ + private Ip6Address getDeviceSid(DeviceId deviceId) { + return getDeviceConfig(deviceId) + .map(FabricDeviceConfig::mySid) + .orElseThrow(() -> new ItemNotFoundException( + "Missing mySid config for " + deviceId)); + } + + /** + * Sets up IPv6 routing on all devices known by ONOS and for which this ONOS + * node instance is currently master. + */ + private synchronized void setUpAllDevices() { + // Set up host routes + stream(deviceService.getAvailableDevices()) + .map(Device::id) + .filter(mastershipService::isLocalMaster) + .forEach(deviceId -> { + log.info("*** IPV6 ROUTING - Starting initial set up for {}...", deviceId); + setUpMyStationTable(deviceId); + setUpFabricRoutes(deviceId); + setUpL2NextHopRules(deviceId); + hostService.getConnectedHosts(deviceId) + .forEach(host -> setUpHostRules(deviceId, host)); + }); + } +} + +``` + +I do h2 ping h3 (they are in different subnets: h2 is connected to leaf1 switch, h3 is connected to leaf2 switch, leaf2 and leaf1 switches are connected and they are also connected with spine1 and spine2 switches. + +At the begining the tables (especially ipv6_routing_table) are the following: + +``` +capy@pcn-rzymovets-w:/mnt/d/Projects/ngsdn-tutorial$ make onos-cli +*** Connecting to the ONOS CLI... password: rocks +*** Top exit press Ctrl-D +Password authentication +(onos@localhost) Password: +Welcome to Open Network Operating System (ONOS)! + ____ _ ______ ____ + / __ \/ |/ / __ \/ __/ + / /_/ / / /_/ /\ \ + \____/_/|_/\____/___/ + +Documentation: wiki.onosproject.org +Tutorials: tutorials.onosproject.org +Mailing lists: lists.onosproject.org + +Come help out! Find out how at: contribute.onosproject.org + +Hit '' for a list of available commands +and '[cmd] --help' for help on a specific command. +Hit '' or type 'logout' to exit ONOS session. + +f~ onos@root > hosts 07:15:19 +onos@root > flows any device:leaf1 07:15:22 +deviceId=device:leaf1, flowRuleCount=16 + id=100001e5fba59, state=ADDED, bytes=0, packets=0, duration=85, liveType=UNKNOWN, priority=40000, tableId=IngressPipeImpl.acl_table, appId=org.onosproject.core, selector=[ETH_TYPE:arp], treatment=DefaultTrafficTreatment{immediate=[IngressPipeImpl.clone_to_cpu()], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=10000217b5edd, state=ADDED, bytes=6944, packets=56, duration=85, liveType=UNKNOWN, priority=40000, tableId=IngressPipeImpl.acl_table, appId=org.onosproject.core, selector=[ETH_TYPE:lldp], treatment=DefaultTrafficTreatment{immediate=[IngressPipeImpl.clone_to_cpu()], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=1000039959d4d, state=ADDED, bytes=0, packets=0, duration=85, liveType=UNKNOWN, priority=40000, tableId=IngressPipeImpl.acl_table, appId=org.onosproject.core, selector=[ETH_TYPE:ipv6, IP_PROTO:58, ICMPV6_TYPE:136], treatment=DefaultTrafficTreatment{immediate=[IngressPipeImpl.clone_to_cpu()], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=1000078c06d68, state=ADDED, bytes=0, packets=0, duration=85, liveType=UNKNOWN, priority=40000, tableId=IngressPipeImpl.acl_table, appId=org.onosproject.core, selector=[ETH_TYPE:ipv6, IP_PROTO:58, ICMPV6_TYPE:135], treatment=DefaultTrafficTreatment{immediate=[IngressPipeImpl.clone_to_cpu()], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=10000d1887c0b, state=ADDED, bytes=0, packets=0, duration=85, liveType=UNKNOWN, priority=40000, tableId=IngressPipeImpl.acl_table, appId=org.onosproject.core, selector=[ETH_TYPE:bddp], treatment=DefaultTrafficTreatment{immediate=[IngressPipeImpl.clone_to_cpu()], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=c000007e251531, state=ADDED, bytes=0, packets=0, duration=85, liveType=UNKNOWN, priority=10, tableId=IngressPipeImpl.ipv6_my_station_table, appId=org.onosproject.ngsdn-tutorial, selector=[hdr.ethernet.dst_addr=0xaa00000001], treatment=DefaultTrafficTreatment{immediate=[NoAction()], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=c000005f8a4559, state=ADDED, bytes=0, packets=0, duration=83, liveType=UNKNOWN, priority=10, tableId=IngressPipeImpl.ipv6_routing_table, appId=org.onosproject.ngsdn-tutorial, selector=[hdr.ipv6.dst_addr=0x20010002000300000000000000000000/64], treatment=DefaultTrafficTreatment{immediate=[GROUP:0xec3b0000], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=c0000076325a77, state=ADDED, bytes=0, packets=0, duration=83, liveType=UNKNOWN, priority=10, tableId=IngressPipeImpl.ipv6_routing_table, appId=org.onosproject.ngsdn-tutorial, selector=[hdr.ipv6.dst_addr=0x20010002000400000000000000000000/64], treatment=DefaultTrafficTreatment{immediate=[GROUP:0xec3b0000], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=c0000078797bee, state=ADDED, bytes=0, packets=0, duration=83, liveType=UNKNOWN, priority=10, tableId=IngressPipeImpl.ipv6_routing_table, appId=org.onosproject.ngsdn-tutorial, selector=[hdr.ipv6.dst_addr=0x30201000200000000000000000000/128], treatment=DefaultTrafficTreatment{immediate=[GROUP:0xba], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=c00000a2deb332, state=ADDED, bytes=0, packets=0, duration=83, liveType=UNKNOWN, priority=10, tableId=IngressPipeImpl.ipv6_routing_table, appId=org.onosproject.ngsdn-tutorial, selector=[hdr.ipv6.dst_addr=0x30202000200000000000000000000/128], treatment=DefaultTrafficTreatment{immediate=[GROUP:0xb9], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=c00000abeb8fd1, state=ADDED, bytes=0, packets=0, duration=83, liveType=UNKNOWN, priority=10, tableId=IngressPipeImpl.l2_exact_table, appId=org.onosproject.ngsdn-tutorial, selector=[hdr.ethernet.dst_addr=0xbb00000001], treatment=DefaultTrafficTreatment{immediate=[IngressPipeImpl.set_egress_port(port_num=0x1)], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=c00000f57b2b7c, state=ADDED, bytes=0, packets=0, duration=83, liveType=UNKNOWN, priority=10, tableId=IngressPipeImpl.l2_exact_table, appId=org.onosproject.ngsdn-tutorial, selector=[hdr.ethernet.dst_addr=0xbb00000002], treatment=DefaultTrafficTreatment{immediate=[IngressPipeImpl.set_egress_port(port_num=0x2)], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=c00000a489d650, state=ADDED, bytes=560, packets=8, duration=85, liveType=UNKNOWN, priority=10, tableId=IngressPipeImpl.l2_ternary_table, appId=org.onosproject.ngsdn-tutorial, selector=[hdr.ethernet.dst_addr=0x333300000000&&&0xffff00000000], treatment=DefaultTrafficTreatment{immediate=[IngressPipeImpl.set_multicast_group(gid=0xff)], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=c00000c8cf6dac, state=ADDED, bytes=0, packets=0, duration=85, liveType=UNKNOWN, priority=10, tableId=IngressPipeImpl.l2_ternary_table, appId=org.onosproject.ngsdn-tutorial, selector=[hdr.ethernet.dst_addr=0xffffffffffff&&&0xffffffffffff], treatment=DefaultTrafficTreatment{immediate=[IngressPipeImpl.set_multicast_group(gid=0xff)], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=c0000026ddb735, state=ADDED, bytes=0, packets=0, duration=85, liveType=UNKNOWN, priority=10, tableId=IngressPipeImpl.ndp_reply_table, appId=org.onosproject.ngsdn-tutorial, selector=[hdr.ndp.target_ipv6_addr=0x200100010002000000000000000000ff], treatment=DefaultTrafficTreatment{immediate=[IngressPipeImpl.ndp_ns_to_na(target_mac=0xaa00000001)], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=c00000e71f7679, state=ADDED, bytes=0, packets=0, duration=85, liveType=UNKNOWN, priority=10, tableId=IngressPipeImpl.ndp_reply_table, appId=org.onosproject.ngsdn-tutorial, selector=[hdr.ndp.target_ipv6_addr=0x200100010001000000000000000000ff], treatment=DefaultTrafficTreatment{immediate=[IngressPipeImpl.ndp_ns_to_na(target_mac=0xaa00000001)], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} +onos@root > flows any device:leaf2 07:15:32 +deviceId=device:leaf2, flowRuleCount=16 + id=1000009bc6ecf, state=ADDED, bytes=0, packets=0, duration=93, liveType=UNKNOWN, priority=40000, tableId=IngressPipeImpl.acl_table, appId=org.onosproject.core, selector=[ETH_TYPE:ipv6, IP_PROTO:58, ICMPV6_TYPE:136], treatment=DefaultTrafficTreatment{immediate=[IngressPipeImpl.clone_to_cpu()], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=10000106ec5af, state=ADDED, bytes=0, packets=0, duration=93, liveType=UNKNOWN, priority=40000, tableId=IngressPipeImpl.acl_table, appId=org.onosproject.core, selector=[ETH_TYPE:bddp], treatment=DefaultTrafficTreatment{immediate=[IngressPipeImpl.clone_to_cpu()], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=100006be310d5, state=ADDED, bytes=0, packets=0, duration=93, liveType=UNKNOWN, priority=40000, tableId=IngressPipeImpl.acl_table, appId=org.onosproject.core, selector=[ETH_TYPE:ipv6, IP_PROTO:58, ICMPV6_TYPE:135], treatment=DefaultTrafficTreatment{immediate=[IngressPipeImpl.clone_to_cpu()], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=1000084a7d695, state=ADDED, bytes=7688, packets=62, duration=93, liveType=UNKNOWN, priority=40000, tableId=IngressPipeImpl.acl_table, appId=org.onosproject.core, selector=[ETH_TYPE:lldp], treatment=DefaultTrafficTreatment{immediate=[IngressPipeImpl.clone_to_cpu()], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=10000a76b5079, state=ADDED, bytes=0, packets=0, duration=93, liveType=UNKNOWN, priority=40000, tableId=IngressPipeImpl.acl_table, appId=org.onosproject.core, selector=[ETH_TYPE:arp], treatment=DefaultTrafficTreatment{immediate=[IngressPipeImpl.clone_to_cpu()], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=c00000d9aa3be2, state=ADDED, bytes=0, packets=0, duration=93, liveType=UNKNOWN, priority=10, tableId=IngressPipeImpl.ipv6_my_station_table, appId=org.onosproject.ngsdn-tutorial, selector=[hdr.ethernet.dst_addr=0xaa00000002], treatment=DefaultTrafficTreatment{immediate=[NoAction()], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=c00000213ad7e6, state=ADDED, bytes=0, packets=0, duration=88, liveType=UNKNOWN, priority=10, tableId=IngressPipeImpl.ipv6_routing_table, appId=org.onosproject.ngsdn-tutorial, selector=[hdr.ipv6.dst_addr=0x20010001000100000000000000000000/64], treatment=DefaultTrafficTreatment{immediate=[GROUP:0xec3b0000], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=c0000041bda7fc, state=ADDED, bytes=0, packets=0, duration=87, liveType=UNKNOWN, priority=10, tableId=IngressPipeImpl.ipv6_routing_table, appId=org.onosproject.ngsdn-tutorial, selector=[hdr.ipv6.dst_addr=0x30202000200000000000000000000/128], treatment=DefaultTrafficTreatment{immediate=[GROUP:0xb9], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=c00000a3342144, state=ADDED, bytes=0, packets=0, duration=88, liveType=UNKNOWN, priority=10, tableId=IngressPipeImpl.ipv6_routing_table, appId=org.onosproject.ngsdn-tutorial, selector=[hdr.ipv6.dst_addr=0x20010001000200000000000000000000/64], treatment=DefaultTrafficTreatment{immediate=[GROUP:0xec3b0000], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=c00000aacfac11, state=ADDED, bytes=0, packets=0, duration=87, liveType=UNKNOWN, priority=10, tableId=IngressPipeImpl.ipv6_routing_table, appId=org.onosproject.ngsdn-tutorial, selector=[hdr.ipv6.dst_addr=0x30201000200000000000000000000/128], treatment=DefaultTrafficTreatment{immediate=[GROUP:0xba], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=c000000bf6807f, state=ADDED, bytes=0, packets=0, duration=87, liveType=UNKNOWN, priority=10, tableId=IngressPipeImpl.l2_exact_table, appId=org.onosproject.ngsdn-tutorial, selector=[hdr.ethernet.dst_addr=0xbb00000001], treatment=DefaultTrafficTreatment{immediate=[IngressPipeImpl.set_egress_port(port_num=0x1)], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=c000005627c934, state=ADDED, bytes=0, packets=0, duration=87, liveType=UNKNOWN, priority=10, tableId=IngressPipeImpl.l2_exact_table, appId=org.onosproject.ngsdn-tutorial, selector=[hdr.ethernet.dst_addr=0xbb00000002], treatment=DefaultTrafficTreatment{immediate=[IngressPipeImpl.set_egress_port(port_num=0x2)], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=c0000022bfc4bb, state=ADDED, bytes=420, packets=6, duration=93, liveType=UNKNOWN, priority=10, tableId=IngressPipeImpl.l2_ternary_table, appId=org.onosproject.ngsdn-tutorial, selector=[hdr.ethernet.dst_addr=0x333300000000&&&0xffff00000000], treatment=DefaultTrafficTreatment{immediate=[IngressPipeImpl.set_multicast_group(gid=0xff)], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=c0000095e3d42d, state=ADDED, bytes=0, packets=0, duration=93, liveType=UNKNOWN, priority=10, tableId=IngressPipeImpl.l2_ternary_table, appId=org.onosproject.ngsdn-tutorial, selector=[hdr.ethernet.dst_addr=0xffffffffffff&&&0xffffffffffff], treatment=DefaultTrafficTreatment{immediate=[IngressPipeImpl.set_multicast_group(gid=0xff)], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=c000006f559492, state=ADDED, bytes=0, packets=0, duration=93, liveType=UNKNOWN, priority=10, tableId=IngressPipeImpl.ndp_reply_table, appId=org.onosproject.ngsdn-tutorial, selector=[hdr.ndp.target_ipv6_addr=0x200100020004000000000000000000ff], treatment=DefaultTrafficTreatment{immediate=[IngressPipeImpl.ndp_ns_to_na(target_mac=0xaa00000002)], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} + id=c000009f5751b1, state=ADDED, bytes=0, packets=0, duration=93, liveType=UNKNOWN, priority=10, tableId=IngressPipeImpl.ndp_reply_table, appId=org.onosproject.ngsdn-tutorial, selector=[hdr.ndp.target_ipv6_addr=0x200100020003000000000000000000ff], treatment=DefaultTrafficTreatment{immediate=[IngressPipeImpl.ndp_ns_to_na(target_mac=0xaa00000002)], deferred=[], transition=None, meter=[], cleared=false, StatTrigger=null, metadata=null} +``` +Nothing is known about hosts at the begining. +When I do h2 ping h3 from mininet, the ping fails: +``` + mininet> h2 ping h3 +PING 2001:2:3::1(2001:2:3::1) 56 data bytes +^C +--- 2001:2:3::1 ping statistics --- +14 packets transmitted, 0 received, 100% packet loss, time 13253ms +``` + +That triggers Host added event in onos: +``` +onos | 07:15:15.727 INFO [OpenSSHKeyPairProvider] Creating ssh server private key at /root/onos/apache-karaf-4.2.8/etc/host.key +onos | 07:15:15.748 INFO [OpenSSHKeyPairGenerator] generateKeyPair(RSA) generating host key - size=2048 +onos | 07:15:18.192 INFO [ServerUserAuthService] Session onos@/172.19.0.1:50994 authenticated +onos | 07:17:17.084 INFO [Ipv6RoutingComponent] HOST_ADDED event! host=00:00:00:00:00:20/None, deviceId=device:leaf1, port=6 +onos | 07:17:17.090 INFO [Ipv6RoutingComponent] Adding routes on device:leaf1 for host 00:00:00:00:00:20/None [[2001:1:2::1]] +onos | 07:17:17.096 ERROR [Ipv6RoutingComponent] #!#!#!#! INSERTED ipv6_routing_table ENTRY: deviceId = device:leaf1, groupId = 32, ip6Prefix = 2001:1:2::1/128 +onos | 07:17:17.322 INFO [L2BridgingComponent] HOST_ADDED event! host=00:00:00:00:00:20/None, deviceId=device:leaf1, port=6 +onos | 07:17:17.325 INFO [L2BridgingComponent] Adding L2 unicast rule on device:leaf1 for host 00:00:00:00:00:20/None (port 6)... +``` + +So we insert an entry about h2 to ipv6_routing_table + +When I do h3 ping h2, I have the same event and insertion in the table, but the difference is that the ping starts working, as now onos has info about both h2 and h3 and the switch already has entry related to h2 which allows to match h3 -> h2 pings by it. + +How to make it work no matter who pings first. I just want "h2 ping h3" to work at once \ No newline at end of file diff --git a/util/p4rt-sh b/util/p4rt-sh index 884c237..9521eff 100755 --- a/util/p4rt-sh +++ b/util/p4rt-sh @@ -28,12 +28,15 @@ import sys import tempfile import shutil import subprocess +import os DOCKER_IMAGE = 'p4lang/p4runtime-sh' TMP_DIR = os.path.dirname(os.path.abspath(__file__)) + '/.pipe_cfg' def main(): + print("#!#! PWD: ", os.getcwd()) + FwdPipeConfig = namedtuple('FwdPipeConfig', ['p4info', 'bin']) def pipe_config(arg): @@ -86,12 +89,12 @@ def main(): logging.debug( "Created temporary directory '{}', it will be mounted in the docker as '{}'".format( TMP_DIR, mount_path)) - shutil.copy(args.config.p4info, os.path.join(TMP_DIR, fname_p4info)) - shutil.copy(args.config.bin, os.path.join(TMP_DIR, fname_bin)) + shutil.copy(args.config.p4info, os.path.join(TMP_DIR, fname_p4info).replace("\\", "/")) + shutil.copy(args.config.bin, os.path.join(TMP_DIR, fname_bin).replace("\\", "/")) docker_args.extend(["-v", "{}:{}".format(TMP_DIR, mount_path)]) new_args.extend(["--config", "{},{}".format( - os.path.join(mount_path, fname_p4info), os.path.join(mount_path, fname_bin))]) + os.path.join(mount_path, fname_p4info).replace("\\", "/"), os.path.join(mount_path, fname_bin).replace("\\", "/"))]) cmd = ["docker", "run", "-ti", "--network", "host"] cmd.extend(docker_args) diff --git a/util/p4rt_without_onos b/util/p4rt_without_onos new file mode 100644 index 0000000..e2413e7 --- /dev/null +++ b/util/p4rt_without_onos @@ -0,0 +1,5 @@ +#!/bin/bash + +docker stop onos +util/p4rt-sh --grpc-addr localhost:50001 --config p4src/build/p4info.txt,p4src/build/bmv2.json --election-id 0,1 +docker start onos diff --git a/util/restart-all b/util/restart-all new file mode 100644 index 0000000..4200c4c --- /dev/null +++ b/util/restart-all @@ -0,0 +1,12 @@ +#!/bin/bash + +docker rm -f $(docker ps -aq) +make start +sleep 20 + +until make netcfg; do + echo "make netcfg failed, retrying in 2 seconds..." + sleep 2 +done + +make app-build app-reload diff --git a/yang/demo-port.yang b/yang/demo-port.yang index 91edf04..96280df 100644 --- a/yang/demo-port.yang +++ b/yang/demo-port.yang @@ -46,6 +46,10 @@ module demo-port { type boolean; description "Number"; } + leaf capybara { + type boolean; + description "Capybara"; + } } // Top-level model definition