diff --git a/test_suites/networkconfig/config_expectations/config_expectations.proto b/test_suites/networkconfig/config_expectations/config_expectations.proto index 6d32092..3ac92b8 100644 --- a/test_suites/networkconfig/config_expectations/config_expectations.proto +++ b/test_suites/networkconfig/config_expectations/config_expectations.proto @@ -25,6 +25,16 @@ message ConfigExpectations { repeated SystemConfig config_expectations = 1; } +message GuestOsSelector { + // The minimum kernel version (inclusive) required for this expectation to + // apply, e.g. "6.8.0" or "6.8". + string min_kernel_version = 1; + + // The maximum kernel version (inclusive) required for this expectation to + // apply, e.g. "6.8.0" or "6.8". + string max_kernel_version = 2; +} + // Configuration for a particular variant of a machine. // Keyed on machine type and NIC types. message SystemConfig { @@ -35,6 +45,9 @@ message SystemConfig { // The GCE machine type e.g. "n2d-standard-2". string machine_type = 2; + // Criteria for matching properties of the VM's guest OS. + GuestOsSelector guest_os_selector = 3; + // NICs in the VM. This includes any device expected to be created by the // GCE stack, but not any created by the user (e.g. not `lo` or `docker0`). repeated NicExpectation nics = 4; diff --git a/test_suites/networkconfig/config_expectations/config_expectations.textproto b/test_suites/networkconfig/config_expectations/config_expectations.textproto index 1f2f23d..8c31747 100644 --- a/test_suites/networkconfig/config_expectations/config_expectations.textproto +++ b/test_suites/networkconfig/config_expectations/config_expectations.textproto @@ -630,8 +630,53 @@ config_expectations: { } } config_expectations: { - description: "n2-32 with single GVNIC" + description: "n2-32 with single GVNIC (with GVE NUMA locality awareness)" machine_type: "n2-highcpu-32" + guest_os_selector: { + min_kernel_version: "6.17" + } + nics: { + type: "GVNIC" + tx_queues: { index: 0 irq_cpulist: "0" xps_cpulist: "0" } + tx_queues: { index: 1 irq_cpulist: "1" xps_cpulist: "1" } + tx_queues: { index: 2 irq_cpulist: "2" xps_cpulist: "2" } + tx_queues: { index: 3 irq_cpulist: "3" xps_cpulist: "3" } + tx_queues: { index: 4 irq_cpulist: "4" xps_cpulist: "4" } + tx_queues: { index: 5 irq_cpulist: "5" xps_cpulist: "5" } + tx_queues: { index: 6 irq_cpulist: "6" xps_cpulist: "6" } + tx_queues: { index: 7 irq_cpulist: "7" xps_cpulist: "7" } + tx_queues: { index: 8 irq_cpulist: "16" xps_cpulist: "8" } + tx_queues: { index: 9 irq_cpulist: "17" xps_cpulist: "9" } + tx_queues: { index: 10 irq_cpulist: "18" xps_cpulist: "10" } + tx_queues: { index: 11 irq_cpulist: "19" xps_cpulist: "11" } + tx_queues: { index: 12 irq_cpulist: "20" xps_cpulist: "12" } + tx_queues: { index: 13 irq_cpulist: "21" xps_cpulist: "13" } + tx_queues: { index: 14 irq_cpulist: "22" xps_cpulist: "14" } + tx_queues: { index: 15 irq_cpulist: "23" xps_cpulist: "15" } + rx_queues: { index: 0 irq_cpulist: "0" } + rx_queues: { index: 1 irq_cpulist: "1" } + rx_queues: { index: 2 irq_cpulist: "2" } + rx_queues: { index: 3 irq_cpulist: "3" } + rx_queues: { index: 4 irq_cpulist: "4" } + rx_queues: { index: 5 irq_cpulist: "5" } + rx_queues: { index: 6 irq_cpulist: "6" } + rx_queues: { index: 7 irq_cpulist: "7" } + rx_queues: { index: 8 irq_cpulist: "16" } + rx_queues: { index: 9 irq_cpulist: "17" } + rx_queues: { index: 10 irq_cpulist: "18" } + rx_queues: { index: 11 irq_cpulist: "19" } + rx_queues: { index: 12 irq_cpulist: "20" } + rx_queues: { index: 13 irq_cpulist: "21" } + rx_queues: { index: 14 irq_cpulist: "22" } + rx_queues: { index: 15 irq_cpulist: "23" } + } +} +config_expectations: { + description: "n2-32 with single GVNIC (without GVE NUMA locality awareness)" + machine_type: "n2-highcpu-32" + guest_os_selector: { + max_kernel_version: "6.16.999" + } nics: { type: "GVNIC" tx_queues: { index: 0 irq_cpulist: "0" xps_cpulist: "0" } diff --git a/test_suites/networkconfig/config_expectations/config_expectations_test.go b/test_suites/networkconfig/config_expectations/config_expectations_test.go index 09dd53f..d934083 100644 --- a/test_suites/networkconfig/config_expectations/config_expectations_test.go +++ b/test_suites/networkconfig/config_expectations/config_expectations_test.go @@ -146,3 +146,28 @@ func TestRingSizes(t *testing.T) { }) } } + +func TestKernelVersionFormat(t *testing.T) { + c := proto() + for _, config := range c.GetConfigExpectations() { + t.Run(config.GetDescription(), func(t *testing.T) { + minVer := config.GetGuestOsSelector().GetMinKernelVersion() + if minVer != "" { + if len(networkutils.ParseKernelVersion(minVer)) == 0 { + t.Errorf("Empty or invalid min_kernel_version string: %q", minVer) + } + } + maxVer := config.GetGuestOsSelector().GetMaxKernelVersion() + if maxVer != "" { + if len(networkutils.ParseKernelVersion(maxVer)) == 0 { + t.Errorf("Empty or invalid max_kernel_version string: %q", maxVer) + } + } + if minVer != "" && maxVer != "" { + if networkutils.CompareKernelVersion(minVer, maxVer) > 0 { + t.Errorf("min_kernel_version (%q) is greater than max_kernel_version (%q)", minVer, maxVer) + } + } + }) + } +} diff --git a/test_suites/networkconfig/config_expectations_proto/config_expectations.pb.go b/test_suites/networkconfig/config_expectations_proto/config_expectations.pb.go index ddff17a..41df616 100644 --- a/test_suites/networkconfig/config_expectations_proto/config_expectations.pb.go +++ b/test_suites/networkconfig/config_expectations_proto/config_expectations.pb.go @@ -93,22 +93,138 @@ func (b0 ConfigExpectations_builder) Build() *ConfigExpectations { return m0 } +type GuestOsSelector struct { + state protoimpl.MessageState `protogen:"opaque.v1"` + xxx_hidden_MinKernelVersion *string `protobuf:"bytes,1,opt,name=min_kernel_version,json=minKernelVersion"` + xxx_hidden_MaxKernelVersion *string `protobuf:"bytes,2,opt,name=max_kernel_version,json=maxKernelVersion"` + XXX_raceDetectHookData protoimpl.RaceDetectHookData + XXX_presence [1]uint32 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GuestOsSelector) Reset() { + *x = GuestOsSelector{} + mi := &file_test_suites_networkconfig_config_expectations_config_expectations_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GuestOsSelector) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GuestOsSelector) ProtoMessage() {} + +func (x *GuestOsSelector) ProtoReflect() protoreflect.Message { + mi := &file_test_suites_networkconfig_config_expectations_config_expectations_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +func (x *GuestOsSelector) GetMinKernelVersion() string { + if x != nil { + if x.xxx_hidden_MinKernelVersion != nil { + return *x.xxx_hidden_MinKernelVersion + } + return "" + } + return "" +} + +func (x *GuestOsSelector) GetMaxKernelVersion() string { + if x != nil { + if x.xxx_hidden_MaxKernelVersion != nil { + return *x.xxx_hidden_MaxKernelVersion + } + return "" + } + return "" +} + +func (x *GuestOsSelector) SetMinKernelVersion(v string) { + x.xxx_hidden_MinKernelVersion = &v + protoimpl.X.SetPresent(&(x.XXX_presence[0]), 0, 2) +} + +func (x *GuestOsSelector) SetMaxKernelVersion(v string) { + x.xxx_hidden_MaxKernelVersion = &v + protoimpl.X.SetPresent(&(x.XXX_presence[0]), 1, 2) +} + +func (x *GuestOsSelector) HasMinKernelVersion() bool { + if x == nil { + return false + } + return protoimpl.X.Present(&(x.XXX_presence[0]), 0) +} + +func (x *GuestOsSelector) HasMaxKernelVersion() bool { + if x == nil { + return false + } + return protoimpl.X.Present(&(x.XXX_presence[0]), 1) +} + +func (x *GuestOsSelector) ClearMinKernelVersion() { + protoimpl.X.ClearPresent(&(x.XXX_presence[0]), 0) + x.xxx_hidden_MinKernelVersion = nil +} + +func (x *GuestOsSelector) ClearMaxKernelVersion() { + protoimpl.X.ClearPresent(&(x.XXX_presence[0]), 1) + x.xxx_hidden_MaxKernelVersion = nil +} + +type GuestOsSelector_builder struct { + _ [0]func() // Prevents comparability and use of unkeyed literals for the builder. + + // The minimum kernel version (inclusive) required for this expectation to + // apply, e.g. "6.8.0" or "6.8". + MinKernelVersion *string + // The maximum kernel version (inclusive) required for this expectation to + // apply, e.g. "6.8.0" or "6.8". + MaxKernelVersion *string +} + +func (b0 GuestOsSelector_builder) Build() *GuestOsSelector { + m0 := &GuestOsSelector{} + b, x := &b0, m0 + _, _ = b, x + if b.MinKernelVersion != nil { + protoimpl.X.SetPresentNonAtomic(&(x.XXX_presence[0]), 0, 2) + x.xxx_hidden_MinKernelVersion = b.MinKernelVersion + } + if b.MaxKernelVersion != nil { + protoimpl.X.SetPresentNonAtomic(&(x.XXX_presence[0]), 1, 2) + x.xxx_hidden_MaxKernelVersion = b.MaxKernelVersion + } + return m0 +} + // Configuration for a particular variant of a machine. // Keyed on machine type and NIC types. type SystemConfig struct { - state protoimpl.MessageState `protogen:"opaque.v1"` - xxx_hidden_Description *string `protobuf:"bytes,1,opt,name=description"` - xxx_hidden_MachineType *string `protobuf:"bytes,2,opt,name=machine_type,json=machineType"` - xxx_hidden_Nics *[]*NicExpectation `protobuf:"bytes,4,rep,name=nics"` - XXX_raceDetectHookData protoimpl.RaceDetectHookData - XXX_presence [1]uint32 - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"opaque.v1"` + xxx_hidden_Description *string `protobuf:"bytes,1,opt,name=description"` + xxx_hidden_MachineType *string `protobuf:"bytes,2,opt,name=machine_type,json=machineType"` + xxx_hidden_GuestOsSelector *GuestOsSelector `protobuf:"bytes,3,opt,name=guest_os_selector,json=guestOsSelector"` + xxx_hidden_Nics *[]*NicExpectation `protobuf:"bytes,4,rep,name=nics"` + XXX_raceDetectHookData protoimpl.RaceDetectHookData + XXX_presence [1]uint32 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SystemConfig) Reset() { *x = SystemConfig{} - mi := &file_test_suites_networkconfig_config_expectations_config_expectations_proto_msgTypes[1] + mi := &file_test_suites_networkconfig_config_expectations_config_expectations_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -120,7 +236,7 @@ func (x *SystemConfig) String() string { func (*SystemConfig) ProtoMessage() {} func (x *SystemConfig) ProtoReflect() protoreflect.Message { - mi := &file_test_suites_networkconfig_config_expectations_config_expectations_proto_msgTypes[1] + mi := &file_test_suites_networkconfig_config_expectations_config_expectations_proto_msgTypes[2] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -151,6 +267,13 @@ func (x *SystemConfig) GetMachineType() string { return "" } +func (x *SystemConfig) GetGuestOsSelector() *GuestOsSelector { + if x != nil { + return x.xxx_hidden_GuestOsSelector + } + return nil +} + func (x *SystemConfig) GetNics() []*NicExpectation { if x != nil { if x.xxx_hidden_Nics != nil { @@ -162,12 +285,16 @@ func (x *SystemConfig) GetNics() []*NicExpectation { func (x *SystemConfig) SetDescription(v string) { x.xxx_hidden_Description = &v - protoimpl.X.SetPresent(&(x.XXX_presence[0]), 0, 3) + protoimpl.X.SetPresent(&(x.XXX_presence[0]), 0, 4) } func (x *SystemConfig) SetMachineType(v string) { x.xxx_hidden_MachineType = &v - protoimpl.X.SetPresent(&(x.XXX_presence[0]), 1, 3) + protoimpl.X.SetPresent(&(x.XXX_presence[0]), 1, 4) +} + +func (x *SystemConfig) SetGuestOsSelector(v *GuestOsSelector) { + x.xxx_hidden_GuestOsSelector = v } func (x *SystemConfig) SetNics(v []*NicExpectation) { @@ -188,6 +315,13 @@ func (x *SystemConfig) HasMachineType() bool { return protoimpl.X.Present(&(x.XXX_presence[0]), 1) } +func (x *SystemConfig) HasGuestOsSelector() bool { + if x == nil { + return false + } + return x.xxx_hidden_GuestOsSelector != nil +} + func (x *SystemConfig) ClearDescription() { protoimpl.X.ClearPresent(&(x.XXX_presence[0]), 0) x.xxx_hidden_Description = nil @@ -198,6 +332,10 @@ func (x *SystemConfig) ClearMachineType() { x.xxx_hidden_MachineType = nil } +func (x *SystemConfig) ClearGuestOsSelector() { + x.xxx_hidden_GuestOsSelector = nil +} + type SystemConfig_builder struct { _ [0]func() // Prevents comparability and use of unkeyed literals for the builder. @@ -206,6 +344,8 @@ type SystemConfig_builder struct { Description *string // The GCE machine type e.g. "n2d-standard-2". MachineType *string + // Criteria for matching properties of the VM's guest OS. + GuestOsSelector *GuestOsSelector // NICs in the VM. This includes any device expected to be created by the // GCE stack, but not any created by the user (e.g. not `lo` or `docker0`). Nics []*NicExpectation @@ -216,13 +356,14 @@ func (b0 SystemConfig_builder) Build() *SystemConfig { b, x := &b0, m0 _, _ = b, x if b.Description != nil { - protoimpl.X.SetPresentNonAtomic(&(x.XXX_presence[0]), 0, 3) + protoimpl.X.SetPresentNonAtomic(&(x.XXX_presence[0]), 0, 4) x.xxx_hidden_Description = b.Description } if b.MachineType != nil { - protoimpl.X.SetPresentNonAtomic(&(x.XXX_presence[0]), 1, 3) + protoimpl.X.SetPresentNonAtomic(&(x.XXX_presence[0]), 1, 4) x.xxx_hidden_MachineType = b.MachineType } + x.xxx_hidden_GuestOsSelector = b.GuestOsSelector x.xxx_hidden_Nics = &b.Nics return m0 } @@ -242,7 +383,7 @@ type NicExpectation struct { func (x *NicExpectation) Reset() { *x = NicExpectation{} - mi := &file_test_suites_networkconfig_config_expectations_config_expectations_proto_msgTypes[2] + mi := &file_test_suites_networkconfig_config_expectations_config_expectations_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -254,7 +395,7 @@ func (x *NicExpectation) String() string { func (*NicExpectation) ProtoMessage() {} func (x *NicExpectation) ProtoReflect() protoreflect.Message { - mi := &file_test_suites_networkconfig_config_expectations_config_expectations_proto_msgTypes[2] + mi := &file_test_suites_networkconfig_config_expectations_config_expectations_proto_msgTypes[3] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -414,7 +555,7 @@ type RxQueue struct { func (x *RxQueue) Reset() { *x = RxQueue{} - mi := &file_test_suites_networkconfig_config_expectations_config_expectations_proto_msgTypes[3] + mi := &file_test_suites_networkconfig_config_expectations_config_expectations_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -426,7 +567,7 @@ func (x *RxQueue) String() string { func (*RxQueue) ProtoMessage() {} func (x *RxQueue) ProtoReflect() protoreflect.Message { - mi := &file_test_suites_networkconfig_config_expectations_config_expectations_proto_msgTypes[3] + mi := &file_test_suites_networkconfig_config_expectations_config_expectations_proto_msgTypes[4] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -526,7 +667,7 @@ type TxQueue struct { func (x *TxQueue) Reset() { *x = TxQueue{} - mi := &file_test_suites_networkconfig_config_expectations_config_expectations_proto_msgTypes[4] + mi := &file_test_suites_networkconfig_config_expectations_config_expectations_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -538,7 +679,7 @@ func (x *TxQueue) String() string { func (*TxQueue) ProtoMessage() {} func (x *TxQueue) ProtoReflect() protoreflect.Message { - mi := &file_test_suites_networkconfig_config_expectations_config_expectations_proto_msgTypes[4] + mi := &file_test_suites_networkconfig_config_expectations_config_expectations_proto_msgTypes[5] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -665,10 +806,14 @@ const file_test_suites_networkconfig_config_expectations_config_expectations_pro "\n" + "Gtest_suites/networkconfig/config_expectations/config_expectations.proto\x12Jgithub_com.googlecloudplatform.cloud_image_tests.test_suites.networkconfig\"\xa0\x01\n" + "\x12ConfigExpectations\x12\x89\x01\n" + - "\x13config_expectations\x18\x01 \x03(\v2X.github_com.googlecloudplatform.cloud_image_tests.test_suites.networkconfig.SystemConfigR\x12configExpectations\"\xc3\x01\n" + + "\x13config_expectations\x18\x01 \x03(\v2X.github_com.googlecloudplatform.cloud_image_tests.test_suites.networkconfig.SystemConfigR\x12configExpectations\"m\n" + + "\x0fGuestOsSelector\x12,\n" + + "\x12min_kernel_version\x18\x01 \x01(\tR\x10minKernelVersion\x12,\n" + + "\x12max_kernel_version\x18\x02 \x01(\tR\x10maxKernelVersion\"\xcd\x02\n" + "\fSystemConfig\x12 \n" + "\vdescription\x18\x01 \x01(\tR\vdescription\x12!\n" + - "\fmachine_type\x18\x02 \x01(\tR\vmachineType\x12n\n" + + "\fmachine_type\x18\x02 \x01(\tR\vmachineType\x12\x87\x01\n" + + "\x11guest_os_selector\x18\x03 \x01(\v2[.github_com.googlecloudplatform.cloud_image_tests.test_suites.networkconfig.GuestOsSelectorR\x0fguestOsSelector\x12n\n" + "\x04nics\x18\x04 \x03(\v2Z.github_com.googlecloudplatform.cloud_image_tests.test_suites.networkconfig.NicExpectationR\x04nics\"\xcc\x02\n" + "\x0eNicExpectation\x12\x12\n" + "\x04type\x18\x01 \x01(\tR\x04type\x12p\n" + @@ -689,24 +834,26 @@ const file_test_suites_networkconfig_config_expectations_config_expectations_pro "\vxps_cpulist\x18\x03 \x01(\tR\n" + "xpsCpulistB7Z5./test_suites/networkconfig/config_expectations_protob\beditionsp\xe9\a" -var file_test_suites_networkconfig_config_expectations_config_expectations_proto_msgTypes = make([]protoimpl.MessageInfo, 5) +var file_test_suites_networkconfig_config_expectations_config_expectations_proto_msgTypes = make([]protoimpl.MessageInfo, 6) var file_test_suites_networkconfig_config_expectations_config_expectations_proto_goTypes = []any{ (*ConfigExpectations)(nil), // 0: github_com.googlecloudplatform.cloud_image_tests.test_suites.networkconfig.ConfigExpectations - (*SystemConfig)(nil), // 1: github_com.googlecloudplatform.cloud_image_tests.test_suites.networkconfig.SystemConfig - (*NicExpectation)(nil), // 2: github_com.googlecloudplatform.cloud_image_tests.test_suites.networkconfig.NicExpectation - (*RxQueue)(nil), // 3: github_com.googlecloudplatform.cloud_image_tests.test_suites.networkconfig.RxQueue - (*TxQueue)(nil), // 4: github_com.googlecloudplatform.cloud_image_tests.test_suites.networkconfig.TxQueue + (*GuestOsSelector)(nil), // 1: github_com.googlecloudplatform.cloud_image_tests.test_suites.networkconfig.GuestOsSelector + (*SystemConfig)(nil), // 2: github_com.googlecloudplatform.cloud_image_tests.test_suites.networkconfig.SystemConfig + (*NicExpectation)(nil), // 3: github_com.googlecloudplatform.cloud_image_tests.test_suites.networkconfig.NicExpectation + (*RxQueue)(nil), // 4: github_com.googlecloudplatform.cloud_image_tests.test_suites.networkconfig.RxQueue + (*TxQueue)(nil), // 5: github_com.googlecloudplatform.cloud_image_tests.test_suites.networkconfig.TxQueue } var file_test_suites_networkconfig_config_expectations_config_expectations_proto_depIdxs = []int32{ - 1, // 0: github_com.googlecloudplatform.cloud_image_tests.test_suites.networkconfig.ConfigExpectations.config_expectations:type_name -> github_com.googlecloudplatform.cloud_image_tests.test_suites.networkconfig.SystemConfig - 2, // 1: github_com.googlecloudplatform.cloud_image_tests.test_suites.networkconfig.SystemConfig.nics:type_name -> github_com.googlecloudplatform.cloud_image_tests.test_suites.networkconfig.NicExpectation - 4, // 2: github_com.googlecloudplatform.cloud_image_tests.test_suites.networkconfig.NicExpectation.tx_queues:type_name -> github_com.googlecloudplatform.cloud_image_tests.test_suites.networkconfig.TxQueue - 3, // 3: github_com.googlecloudplatform.cloud_image_tests.test_suites.networkconfig.NicExpectation.rx_queues:type_name -> github_com.googlecloudplatform.cloud_image_tests.test_suites.networkconfig.RxQueue - 4, // [4:4] is the sub-list for method output_type - 4, // [4:4] is the sub-list for method input_type - 4, // [4:4] is the sub-list for extension type_name - 4, // [4:4] is the sub-list for extension extendee - 0, // [0:4] is the sub-list for field type_name + 2, // 0: github_com.googlecloudplatform.cloud_image_tests.test_suites.networkconfig.ConfigExpectations.config_expectations:type_name -> github_com.googlecloudplatform.cloud_image_tests.test_suites.networkconfig.SystemConfig + 1, // 1: github_com.googlecloudplatform.cloud_image_tests.test_suites.networkconfig.SystemConfig.guest_os_selector:type_name -> github_com.googlecloudplatform.cloud_image_tests.test_suites.networkconfig.GuestOsSelector + 3, // 2: github_com.googlecloudplatform.cloud_image_tests.test_suites.networkconfig.SystemConfig.nics:type_name -> github_com.googlecloudplatform.cloud_image_tests.test_suites.networkconfig.NicExpectation + 5, // 3: github_com.googlecloudplatform.cloud_image_tests.test_suites.networkconfig.NicExpectation.tx_queues:type_name -> github_com.googlecloudplatform.cloud_image_tests.test_suites.networkconfig.TxQueue + 4, // 4: github_com.googlecloudplatform.cloud_image_tests.test_suites.networkconfig.NicExpectation.rx_queues:type_name -> github_com.googlecloudplatform.cloud_image_tests.test_suites.networkconfig.RxQueue + 5, // [5:5] is the sub-list for method output_type + 5, // [5:5] is the sub-list for method input_type + 5, // [5:5] is the sub-list for extension type_name + 5, // [5:5] is the sub-list for extension extendee + 0, // [0:5] is the sub-list for field type_name } func init() { file_test_suites_networkconfig_config_expectations_config_expectations_proto_init() } @@ -720,7 +867,7 @@ func file_test_suites_networkconfig_config_expectations_config_expectations_prot GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_test_suites_networkconfig_config_expectations_config_expectations_proto_rawDesc), len(file_test_suites_networkconfig_config_expectations_config_expectations_proto_rawDesc)), NumEnums: 0, - NumMessages: 5, + NumMessages: 6, NumExtensions: 0, NumServices: 0, }, diff --git a/test_suites/networkconfig/deviceconfig_test.go b/test_suites/networkconfig/deviceconfig_test.go index 7cccbb2..91b4cf1 100644 --- a/test_suites/networkconfig/deviceconfig_test.go +++ b/test_suites/networkconfig/deviceconfig_test.go @@ -25,6 +25,7 @@ import ( "regexp" "slices" "strconv" + "strings" "testing" "time" @@ -72,7 +73,7 @@ func matchKey(a, b *systemKey) bool { return slices.Equal(a.nicTypes, b.nicTypes) } -func expectedConfigForMachine(configExpectations *pb.ConfigExpectations, machineType string, nicTypes []string) (*pb.SystemConfig, error) { +func expectedConfigForMachine(configExpectations *pb.ConfigExpectations, machineType string, nicTypes []string, kernelVersion string) (*pb.SystemConfig, error) { thisSystemKey := &systemKey{machineType: machineType, nicTypes: nicTypes} for _, config := range configExpectations.GetConfigExpectations() { var configNicTypes []string @@ -84,10 +85,16 @@ func expectedConfigForMachine(configExpectations *pb.ConfigExpectations, machine nicTypes: configNicTypes, } if matchKey(configSystemKey, thisSystemKey) { + if minVer := config.GetGuestOsSelector().GetMinKernelVersion(); minVer != "" && networkutils.CompareKernelVersion(kernelVersion, minVer) < 0 { + continue + } + if maxVer := config.GetGuestOsSelector().GetMaxKernelVersion(); maxVer != "" && networkutils.CompareKernelVersion(kernelVersion, maxVer) > 0 { + continue + } return config, nil } } - return nil, fmt.Errorf("no config expectation found for machine type %q and nic types %v", machineType, nicTypes) + return nil, fmt.Errorf("no config expectation found for machine type %q, nic types %v, and kernel version %q", machineType, nicTypes, kernelVersion) } func deviceIRQs(ifaceName string) ([]int, error) { @@ -594,9 +601,16 @@ func TestDeviceConfig(t *testing.T) { nicTypes = append(nicTypes, mdsIface.NICType) } - wantSystemConfig, err := expectedConfigForMachine(&configExpectations, machineType, nicTypes) + kernelVersionCmd := exec.CommandContext(ctx, "uname", "-r") + kernelVersionOut, err := kernelVersionCmd.CombinedOutput() + if err != nil { + t.Fatalf("error getting kernel version: %v", err) + } + kernelVersion := strings.TrimSpace(string(kernelVersionOut)) + + wantSystemConfig, err := expectedConfigForMachine(&configExpectations, machineType, nicTypes, kernelVersion) if err != nil { - t.Fatalf("expectedConfigForMachine(&configExpectations, %q, %v) = err: %v, want nil", machineType, nicTypes, err) + t.Fatalf("expectedConfigForMachine(&configExpectations, %q, %v, %q) = err: %v, want nil", machineType, nicTypes, kernelVersion, err) } gotSystemConfig, err := thisSystemConfig(mdsIfaces) @@ -622,7 +636,7 @@ func TestDeviceConfig(t *testing.T) { protocmp.Transform(), protocmp.SortRepeatedFields(&pb.NicExpectation{}, "tx_queues"), protocmp.SortRepeatedFields(&pb.NicExpectation{}, "rx_queues"), - protocmp.IgnoreFields(&pb.SystemConfig{}, "description", "machine_type"), + protocmp.IgnoreFields(&pb.SystemConfig{}, "description", "machine_type", "guest_os_selector"), ); diff != "" { t.Errorf("SystemConfig mismatch (-want +got):\n%s", diff) } diff --git a/utils/networkutils/networkutils.go b/utils/networkutils/networkutils.go index a6d0b90..8d35add 100644 --- a/utils/networkutils/networkutils.go +++ b/utils/networkutils/networkutils.go @@ -606,3 +606,45 @@ func ParseEthtoolGOutput(output string) (*EthtoolRingSizes, error) { CurrentTX: currentTX, }, nil } + +// ParseKernelVersion parses a kernel version string (e.g. "6.8.0-1006-gcp" or "6.8") +// into a slice of integers representing the version components. +func ParseKernelVersion(v string) []int { + var nums []int + for _, part := range strings.FieldsFunc(v, func(r rune) bool { + return r < '0' || r > '9' + }) { + n, err := strconv.Atoi(part) + if err == nil { + nums = append(nums, n) + } + } + return nums +} + +// CompareKernelVersion compares two kernel version strings (e.g. "6.8.0-1006-gcp" and "6.8.0"). +// Returns -1 if v1 < v2, 0 if v1 == v2, and 1 if v1 > v2. +func CompareKernelVersion(v1 string, v2 string) int { + n1 := ParseKernelVersion(v1) + n2 := ParseKernelVersion(v2) + maxLen := len(n1) + if len(n2) > maxLen { + maxLen = len(n2) + } + for i := 0; i < maxLen; i++ { + var x1, x2 int + if i < len(n1) { + x1 = n1[i] + } + if i < len(n2) { + x2 = n2[i] + } + if x1 < x2 { + return -1 + } + if x1 > x2 { + return 1 + } + } + return 0 +} diff --git a/utils/networkutils/networkutils_test.go b/utils/networkutils/networkutils_test.go index db17eb7..662bebb 100644 --- a/utils/networkutils/networkutils_test.go +++ b/utils/networkutils/networkutils_test.go @@ -755,3 +755,47 @@ TCP data split: on`, }) } } + +func TestParseKernelVersion(t *testing.T) { + tests := []struct { + input string + want []int + }{ + {"6.8.0", []int{6, 8, 0}}, + {"6.8.0-1006-gcp", []int{6, 8, 0, 1006}}, + {"6.8", []int{6, 8}}, + {"5.15.0-1040-gcp", []int{5, 15, 0, 1040}}, + {"", nil}, + {"abc", nil}, + } + for _, tc := range tests { + got := ParseKernelVersion(tc.input) + if diff := cmp.Diff(got, tc.want); diff != "" { + t.Errorf("ParseKernelVersion(%q) mismatch (-got +want):\n%s", tc.input, diff) + } + } +} + +func TestCompareKernelVersion(t *testing.T) { + tests := []struct { + v1 string + v2 string + want int + }{ + {"6.8", "6.8.0", 0}, + {"6.8.0-1006-gcp", "6.8", 1}, + {"6.8.0-1006-gcp", "6.8.0", 1}, + {"6.6.0-1001-gcp", "6.8.0", -1}, + {"6.8", "6.6.0-1001-gcp", 1}, + {"6.7.999", "6.8", -1}, + {"6.8", "6.8.1", -1}, + {"6.8.0", "6.8.0.1", -1}, + {"6.8.0.1", "6.8", 1}, + } + for _, tc := range tests { + got := CompareKernelVersion(tc.v1, tc.v2) + if got != tc.want { + t.Errorf("CompareKernelVersion(%q, %q) = %d, want %d", tc.v1, tc.v2, got, tc.want) + } + } +}