From 013f5c72353df7293feccd3f39db9543fbf83754 Mon Sep 17 00:00:00 2001 From: Daniel Grau Date: Mon, 14 Aug 2023 17:12:42 +0000 Subject: [PATCH] Support for notifications and other fixes --- dataplane/standalone/apigen/BUILD | 1 + dataplane/standalone/apigen/protogen.go | 590 +++++++++++++++--------- 2 files changed, 384 insertions(+), 207 deletions(-) diff --git a/dataplane/standalone/apigen/BUILD b/dataplane/standalone/apigen/BUILD index 3b6e471a..7f7faec2 100644 --- a/dataplane/standalone/apigen/BUILD +++ b/dataplane/standalone/apigen/BUILD @@ -11,6 +11,7 @@ go_library( importpath = "github.com/openconfig/lemming/dataplane/standalone/apigen", visibility = ["//visibility:private"], deps = [ + "@com_github_golang_glog//:glog", "@com_github_stoewer_go_strcase//:go-strcase", "@org_modernc_cc_v4//:cc", ], diff --git a/dataplane/standalone/apigen/protogen.go b/dataplane/standalone/apigen/protogen.go index 5be81c2e..17716315 100644 --- a/dataplane/standalone/apigen/protogen.go +++ b/dataplane/standalone/apigen/protogen.go @@ -20,6 +20,7 @@ import ( "text/template" "unicode" + log "github.com/golang/glog" strcase "github.com/stoewer/go-strcase" ) @@ -56,8 +57,8 @@ func populateCommonTypes(docInfo *protoGenInfo) (*protoCommonTmplData, error) { common.Enums[protoName] = enum } // Find all the repeated fields that appear in oneof and generate a list wrapper type. - for _, attr := range docInfo.attrs { - for _, f := range attr.setFields { + for n, attr := range docInfo.attrs { + for _, f := range attr.readFields { msgName, isRepeated, err := saiTypeToProtoType(f.SaiType, docInfo, true) if err != nil { return nil, err @@ -79,6 +80,16 @@ func populateCommonTypes(docInfo *protoGenInfo) (*protoCommonTmplData, error) { } common.Lists[msgName] = msg } + attrFields, err := createAttrs(2, docInfo, attr.readFields, true) + if err != nil { + return nil, err + } + common.Lists[n] = &protoTmplMessage{ + Fields: attrFields, + Name: trimSAIName(n, true, false) + "Attribute", + AttrsWrapperStart: "oneof {", + AttrsWrapperEnd: "}", + } } return common, nil } @@ -156,6 +167,11 @@ func populateTmplDataFromFunc(apis map[string]*protoAPITmplData, docInfo *protoG Index: 2, Name: "attr_type", }) + resp.Fields = append(resp.Fields, protoTmplField{ + Index: 1, + Name: "attr", + ProtoType: strcase.UpperCamelCase(typeName + "Attribute"), + }) // attrEnum is the special emun that describes the possible values can be set/get for the API. attrEnum := protoEnum{ @@ -169,14 +185,30 @@ func populateTmplDataFromFunc(apis map[string]*protoAPITmplData, docInfo *protoG Index: i + 1, Name: strings.TrimPrefix(attr.EnumName, "SAI_"), }) + // Handle function pointers as streaming RPCs. + if strings.Contains(attr.SaiType, "sai_pointer_t") { + funcName := strings.Split(attr.SaiType, " ")[1] + name := trimSAIName(strings.TrimSuffix(funcName, "_fn"), true, false) + req := &protoTmplMessage{ + Name: strcase.UpperCamelCase(name + "_request"), + } + resp, ok := funcToStreamResp[funcName] + if !ok { + // TODO: There are 2 function pointers that don't follow this pattern, support them. + log.Warningf("skipping unknown func type %q\n", funcName) + continue + } + apis[apiName].Messages = append(apis[apiName].Messages, *req, resp) + apis[apiName].RPCs = append(apis[apiName].RPCs, protoRPC{ + RequestName: req.Name, + ResponseName: "stream " + resp.Name, + Name: strcase.UpperCamelCase(name), + }) + } } apis[apiName].Enums[attrEnum.Name] = attrEnum - - attrs, err := createAttrs(1, docInfo, docInfo.attrs[typeName].readFields, false) - if err != nil { - return err - } - resp.Attrs = attrs + case "remove": + req.Fields = append(req.Fields, idField) default: return nil } @@ -260,6 +292,8 @@ syntax = "proto3"; package lemming.dataplane.sai; +import "google/protobuf/timestamp.proto"; + option go_package = "github.com/openconfig/lemming/proto/dataplane/sai"; {{ range .Enums }} @@ -335,117 +369,122 @@ type saiTypeInfo struct { MessageDef string } -var saiTypeToProto = map[string]saiTypeInfo{ - "bool": { - ProtoType: "bool", - }, - "char": { - ProtoType: "bytes", - }, - "sai_uint8_t": { - ProtoType: "uint32", - }, - "sai_int8_t": { - ProtoType: "int32", - }, - "sai_uint16_t": { - ProtoType: "uint32", - }, - "sai_int16_t": { - ProtoType: "int32", - }, - "sai_uint32_t": { - ProtoType: "uint32", - }, - "sai_int32_t": { - ProtoType: "uint32", - }, - "sai_uint64_t": { - ProtoType: "uint64", - }, - "sai_int64_t": { - ProtoType: "int64", - }, - "sai_mac_t": { - ProtoType: "bytes", - }, - "sai_ip4_t": { - ProtoType: "bytes", - }, - "sai_ip6_t": { - ProtoType: "bytes", - }, - "sai_s32_list_t": { - Repeated: true, - ProtoType: "int32", - }, - "sai_object_id_t": { - ProtoType: "uint64", - }, - "sai_object_list_t": { - Repeated: true, - ProtoType: "uint64", - }, - "sai_encrypt_key_t": { - ProtoType: "bytes", - }, - "sai_auth_key_t": { - ProtoType: "bytes", - }, - "sai_macsec_sak_t": { - ProtoType: "bytes", - }, - "sai_macsec_auth_key_t": { - ProtoType: "bytes", - }, - "sai_macsec_salt_t": { - ProtoType: "bytes", - }, - "sai_u32_list_t": { - Repeated: true, - ProtoType: "uint32", - }, - "sai_segment_list_t": { - Repeated: true, - ProtoType: "bytes", - }, - "sai_s8_list_t": { - Repeated: true, - ProtoType: "int32", - }, - "sai_u8_list_t": { - Repeated: true, - ProtoType: "uint32", - }, - "sai_port_err_status_list_t": { - Repeated: true, - ProtoType: "PortErrStatus", - }, - "sai_vlan_list_t": { - Repeated: true, - ProtoType: "uint32", - }, // The non-scalar types could be autogenerated, but that aren't that many so create messages by hand. - "sai_u32_range_t": { - ProtoType: "Uint32Range", - MessageDef: `message Uint32Range { +var ( + saiTypeToProto = map[string]saiTypeInfo{ + "bool": { + ProtoType: "bool", + }, + "char": { + ProtoType: "bytes", + }, + "sai_uint8_t": { + ProtoType: "uint32", + }, + "sai_int8_t": { + ProtoType: "int32", + }, + "sai_uint16_t": { + ProtoType: "uint32", + }, + "sai_int16_t": { + ProtoType: "int32", + }, + "sai_uint32_t": { + ProtoType: "uint32", + }, + "sai_int32_t": { + ProtoType: "uint32", + }, + "sai_uint64_t": { + ProtoType: "uint64", + }, + "sai_int64_t": { + ProtoType: "int64", + }, + "sai_mac_t": { + ProtoType: "bytes", + }, + "sai_ip4_t": { + ProtoType: "bytes", + }, + "sai_ip6_t": { + ProtoType: "bytes", + }, + "sai_s32_list_t": { + Repeated: true, + ProtoType: "int32", + }, + "sai_object_id_t": { + ProtoType: "uint64", + }, + "sai_object_list_t": { + Repeated: true, + ProtoType: "uint64", + }, + "sai_encrypt_key_t": { + ProtoType: "bytes", + }, + "sai_auth_key_t": { + ProtoType: "bytes", + }, + "sai_macsec_sak_t": { + ProtoType: "bytes", + }, + "sai_macsec_auth_key_t": { + ProtoType: "bytes", + }, + "sai_macsec_salt_t": { + ProtoType: "bytes", + }, + "sai_u32_list_t": { + Repeated: true, + ProtoType: "uint32", + }, + "sai_segment_list_t": { + Repeated: true, + ProtoType: "bytes", + }, + "sai_s8_list_t": { + Repeated: true, + ProtoType: "int32", + }, + "sai_u8_list_t": { + Repeated: true, + ProtoType: "uint32", + }, + "sai_port_err_status_list_t": { + Repeated: true, + ProtoType: "PortErrStatus", + }, + "sai_vlan_list_t": { + Repeated: true, + ProtoType: "uint32", + }, + "sai_timespec_t": { + ProtoType: "google.protobuf.Timestamp", + }, + // The non-scalar types could be autogenerated, but that aren't that many so create messages by hand. + "sai_u32_range_t": { + ProtoType: "Uint32Range", + MessageDef: `message Uint32Range { uint64 min = 1; uint64 max = 2; }`, - }, - "sai_ip_address_t": { - ProtoType: "bytes", - }, - "sai_map_list_t": { // Wrap the map in a message because maps can't be repeated. - Repeated: true, - ProtoType: "UintMap", - MessageDef: `message UintMap { + }, + "sai_ip_address_t": { + ProtoType: "bytes", + }, + "sai_map_list_t": { // Wrap the map in a message because maps can't be repeated. + Repeated: true, + ProtoType: "UintMap", + MessageDef: `message UintMap { map uintmap = 1; }`, - }, - "sai_tlv_list_t": { - Repeated: true, - ProtoType: "TLVEntry", - MessageDef: `message HMAC { + }, + "sai_tlv_list_t": { + Repeated: true, + ProtoType: "TLVEntry", + MessageDef: `message HMAC { uint32 key_id = 1; repeated uint32 hmac = 2; } @@ -458,11 +497,11 @@ message TLVEntry { HMAC hmac = 4; } }`, - }, - "sai_qos_map_list_t": { - Repeated: true, - ProtoType: "QOSMap", - MessageDef: ` + }, + "sai_qos_map_list_t": { + Repeated: true, + ProtoType: "QOSMap", + MessageDef: ` message QOSMapParams { uint32 tc = 1; uint32 dscp = 2; @@ -479,10 +518,10 @@ message QOSMap { QOSMapParams key = 1; QOSMapParams value = 2; }`, - }, - "sai_system_port_config_t": { - ProtoType: "SystemPortConfig", - MessageDef: `message SystemPortConfig { + }, + "sai_system_port_config_t": { + ProtoType: "SystemPortConfig", + MessageDef: `message SystemPortConfig { uint32 port_id = 1; uint32 attached_switch_id = 2; uint32 attached_core_index = 3; @@ -490,59 +529,59 @@ message QOSMap { uint32 speed = 5; uint32 num_voq = 6; }`, - }, - "sai_system_port_config_list_t": { - Repeated: true, - ProtoType: "SystemPortConfig", - }, - "sai_ip_address_list_t": { - Repeated: true, - ProtoType: "bytes", - }, - "sai_port_eye_values_list_t": { - Repeated: true, - ProtoType: "PortEyeValues", - MessageDef: `message PortEyeValues { + }, + "sai_system_port_config_list_t": { + Repeated: true, + ProtoType: "SystemPortConfig", + }, + "sai_ip_address_list_t": { + Repeated: true, + ProtoType: "bytes", + }, + "sai_port_eye_values_list_t": { + Repeated: true, + ProtoType: "PortEyeValues", + MessageDef: `message PortEyeValues { uint32 lane = 1; int32 left = 2; int32 right = 3; int32 up = 4; int32 down = 5; }`, - }, - "sai_prbs_rx_state_t": { - ProtoType: "PRBS_RXState", - MessageDef: `message PRBS_RXState { + }, + "sai_prbs_rx_state_t": { + ProtoType: "PRBS_RXState", + MessageDef: `message PRBS_RXState { PortPrbsRxStatus rx_status = 1; uint32 error_count = 2; }`, - }, - "sai_fabric_port_reachability_t": { - ProtoType: "FabricPortReachability", - MessageDef: `message FabricPortReachability { + }, + "sai_fabric_port_reachability_t": { + ProtoType: "FabricPortReachability", + MessageDef: `message FabricPortReachability { uint32 switch_id = 1; bool reachable = 2; }`, - }, - "sai_acl_resource_list_t": { - Repeated: true, - ProtoType: "ACLResource", - MessageDef: `message ACLResource { + }, + "sai_acl_resource_list_t": { + Repeated: true, + ProtoType: "ACLResource", + MessageDef: `message ACLResource { AclStage stage = 1; AclBindPointType bind_point = 2; uint32 avail_num = 3; }`, - }, - "sai_acl_capability_t": { - ProtoType: "ACLCapability", - MessageDef: `message ACLCapability { + }, + "sai_acl_capability_t": { + ProtoType: "ACLCapability", + MessageDef: `message ACLCapability { bool is_action_list_mandatory = 1; repeated int32 action_list = 2; }`, - }, - "sai_acl_field_data_t": { - ProtoType: "AclFieldData", - MessageDef: `message AclFieldData { + }, + "sai_acl_field_data_t": { + ProtoType: "AclFieldData", + MessageDef: `message AclFieldData { bool enable = 1; oneof mask { uint64 mask_uint = 2; @@ -560,10 +599,10 @@ message QOSMap { Uint64List data_list = 12; }; }`, - }, - "sai_acl_action_data_t": { - ProtoType: "AclActionData", - MessageDef: `message AclActionData { + }, + "sai_acl_action_data_t": { + ProtoType: "AclActionData", + MessageDef: `message AclActionData { bool enable = 1; oneof parameter { uint64 uint = 2; @@ -575,53 +614,53 @@ message QOSMap { bytes ipaddr = 8; }; }`, - }, - "sai_fdb_entry_t": { - ProtoType: "FdbEntry", - MessageDef: `message FdbEntry { + }, + "sai_fdb_entry_t": { + ProtoType: "FdbEntry", + MessageDef: `message FdbEntry { uint64 switch_id = 1; bytes mac_address = 2; uint64 bv_id = 3; }`, - }, - "sai_ipmc_entry_t": { - ProtoType: "IpmcEntry", - MessageDef: `message IpmcEntry { + }, + "sai_ipmc_entry_t": { + ProtoType: "IpmcEntry", + MessageDef: `message IpmcEntry { uint64 switch_id = 1; uint64 vr_id = 2; IpmcEntryType type = 3; bytes destination = 4; bytes source = 5; }`, - }, - "sai_l2mc_entry_t": { - ProtoType: "L2mcEntry", - MessageDef: `message L2mcEntry { + }, + "sai_l2mc_entry_t": { + ProtoType: "L2mcEntry", + MessageDef: `message L2mcEntry { uint64 switch_id = 1; uint64 bv_id = 2; L2mcEntryType type = 3; bytes destination = 4; bytes source = 5; }`, - }, - "sai_mcast_fdb_entry_t": { - ProtoType: "McastFdbEntry", - MessageDef: `message McastFdbEntry { + }, + "sai_mcast_fdb_entry_t": { + ProtoType: "McastFdbEntry", + MessageDef: `message McastFdbEntry { uint64 switch_id = 1; bytes mac_address = 2; uint64 bv_id = 3; }`, - }, - "sai_inseg_entry_t": { - ProtoType: "InsegEntry", - MessageDef: `message InsegEntry { + }, + "sai_inseg_entry_t": { + ProtoType: "InsegEntry", + MessageDef: `message InsegEntry { uint64 switch_id = 1; uint32 label = 2; }`, - }, - "sai_nat_entry_data_t": { - ProtoType: "NatEntryData", - MessageDef: `message NatEntryData{ + }, + "sai_nat_entry_data_t": { + ProtoType: "NatEntryData", + MessageDef: `message NatEntryData{ oneof key { bytes key_src_ip = 2; bytes key_dst_ip = 3; @@ -637,42 +676,42 @@ message QOSMap { uint32 mask_l4_dst_port = 11; }; }`, - }, - "sai_nat_entry_t": { - ProtoType: "NatEntry", - MessageDef: `message NatEntry { + }, + "sai_nat_entry_t": { + ProtoType: "NatEntry", + MessageDef: `message NatEntry { uint64 switch_id = 1; uint64 vr_id = 2; NatType nat_type = 3; NatEntryData data = 4; }`, - }, - "sai_neighbor_entry_t": { - ProtoType: "NeighborEntry", - MessageDef: `message NeighborEntry { + }, + "sai_neighbor_entry_t": { + ProtoType: "NeighborEntry", + MessageDef: `message NeighborEntry { uint64 switch_id = 1; uint64 rif_id = 2; bytes ip_address = 3; }`, - }, - "sai_ip_prefix_t": { - ProtoType: "IpPrefix", - MessageDef: `message IpPrefix { + }, + "sai_ip_prefix_t": { + ProtoType: "IpPrefix", + MessageDef: `message IpPrefix { bytes addr = 1; bytes mask = 2; }`, - }, - "sai_route_entry_t": { - ProtoType: "RouteEntry", - MessageDef: `message RouteEntry { + }, + "sai_route_entry_t": { + ProtoType: "RouteEntry", + MessageDef: `message RouteEntry { uint64 switch_id = 1; uint64 vr_id = 2; IpPrefix destination = 3; }`, - }, - "sai_my_sid_entry_t": { - ProtoType: "MySidEntry", - MessageDef: `message MySidEntry { + }, + "sai_my_sid_entry_t": { + ProtoType: "MySidEntry", + MessageDef: `message MySidEntry { uint64 switch_id = 1; uint64 vr_id = 2; uint32 locator_block_len = 3; @@ -681,8 +720,143 @@ message QOSMap { uint32 args_len = 6; bytes sid = 7; }`, - }, -} + }, + "sai_fdb_event_notification_data_t": { + ProtoType: "FdbEventNotificationData", + MessageDef: ` +message FdbEventNotificationData { + FdbEvent event_type = 1; + FdbEntry fdb_entry = 2; + repeated FdbEntryAttribute attrs = 3; +}`, + }, + "sai_port_oper_status_notification_t": { + ProtoType: "PortOperStatusNotification", + MessageDef: `message PortOperStatusNotification { + uint64 port_id = 1; + PortOperStatus port_state = 2; +}`, + }, + "sai_queue_deadlock_notification_data_t": { + ProtoType: "QueueDeadlockNotificationData", + MessageDef: `message QueueDeadlockNotificationData { + uint64 queue_id = 1; + QueuePfcDeadlockEventType event= 2; + bool app_managed_recovery = 3; +}`, + }, + "sai_bfd_session_state_notification_t": { + ProtoType: "BfdSessionStateChangeNotificationData", + MessageDef: `message BfdSessionStateChangeNotificationData { + uint64 bfd_session_id = 1; + BfdSessionState session_state = 2; +}`, + }, + "sai_ipsec_sa_status_notification_t": { + ProtoType: "IpsecSaStatusNotificationData", + MessageDef: `message IpsecSaStatusNotificationData { + uint64 ipsec_sa_id = 1; + IpsecSaOctetCountStatus ipsec_sa_octet_count_status = 2; + bool ipsec_egress_sn_at_max_limit = 3; +}`, + }, + } + // The notification function types are implemented as streaming RPCs. + funcToStreamResp = map[string]protoTmplMessage{ + "sai_switch_state_change_notification_fn": { + Name: "SwitchStateChangeNotificationResponse", + Fields: []protoTmplField{{ + Index: 1, + ProtoType: "uint64", + Name: "switch_id", + }, { + Index: 2, + ProtoType: "SwitchOperStatus", + Name: "switch_oper_status", + }}, + }, + "sai_switch_shutdown_request_notification_fn": { + Name: "SwitchShutdownRequestNotificationResponse", + Fields: []protoTmplField{{ + Index: 1, + ProtoType: "uint64", + Name: "switch_id", + }}, + }, + "sai_fdb_event_notification_fn": { + Name: "FdbEventNotificationResponse", + Fields: []protoTmplField{{ + Index: 1, + ProtoType: "repeated FdbEventNotificationData", + Name: "data", + }}, + }, + "sai_port_state_change_notification_fn": { + Name: "PortStateChangeNotificationResponse", + Fields: []protoTmplField{{ + Index: 1, + ProtoType: "repeated PortOperStatusNotification", + Name: "data", + }}, + }, + "sai_packet_event_notification_fn": { + Name: "PacketEventNotificationResponse", + Fields: []protoTmplField{{ + Index: 1, + ProtoType: "uint64", + Name: "switch_id", + }, { + Index: 2, + ProtoType: "bytes", + Name: "buffer", + }, { + Index: 3, + ProtoType: "repeated HostifPacketAttribute", + Name: "attrs", + }}, + }, + "sai_queue_pfc_deadlock_notification_fn": { + Name: "QueuePfcDeadlockNotificationResponse", + Fields: []protoTmplField{{ + Index: 1, + ProtoType: "repeated QueueDeadlockNotificationData", + Name: "data", + }}, + }, + "sai_bfd_session_state_change_notification_fn": { + Name: "BfdSessionStateChangeNotificationResponse", + Fields: []protoTmplField{{ + Index: 1, + ProtoType: "repeated BfdSessionStateChangeNotificationData", + Name: "data", + }}, + }, + "sai_tam_event_notification_fn": { + Name: "TamEventNotificationResponse", + Fields: []protoTmplField{{ + Index: 1, + ProtoType: "uint64", + Name: "tam_event_id", + }, { + Index: 2, + ProtoType: "bytes", + Name: "buffer", + }, { + Index: 3, + ProtoType: "repeated TamEventActionAttribute", + Name: "attrs", + }}, + }, + "sai_ipsec_sa_status_change_notification_fn": { + Name: "IpsecSaStatusNotificationDataResponse", + Fields: []protoTmplField{{ + Index: 1, + ProtoType: "repeated IpsecSaStatusNotificationData", + Name: "data", + }}, + }, + } +) // saiTypeToProtoTypeCompound handles compound sai types (eg list of enums). // The map key contains the base type (eg list) and func accepts the subtype (eg an enum type) @@ -706,6 +880,8 @@ var saiTypeToProtoTypeCompound = map[string]func(subType string, xmlInfo *protoG // saiTypeToProtoType returns the protobuf type string for a SAI type. // example: sai_u8_list_t -> repeated uint32 func saiTypeToProtoType(saiType string, xmlInfo *protoGenInfo, inOneof bool) (string, bool, error) { + saiType = strings.TrimPrefix(saiType, "const ") + if pt, ok := saiTypeToProto[saiType]; ok { if pt.Repeated { if inOneof {