diff --git a/Cargo.lock b/Cargo.lock index c82dd95..d7d2614 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -378,7 +378,7 @@ dependencies = [ [[package]] name = "gateway_config" -version = "0.14.0" +version = "0.15.0" dependencies = [ "async-trait", "bolero", diff --git a/Cargo.toml b/Cargo.toml index a77789f..8b447b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "gateway_config" -version = "0.14.0" +version = "0.15.0" edition = "2024" license = "Apache-2.0" rust-version = "1.87.0" @@ -24,11 +24,17 @@ futures = "0.3" async-trait = "0.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" +thiserror = "2.0.17" [dev-dependencies] tower = "0.5.2" thiserror = { version = "2.0.17", features = ["std"] } tokio-stream = { version = "0.1", features = ["net"] } +bolero = { version = "0.13.4", features = [ + "alloc", + "arbitrary", + "std", +]} [build-dependencies] tonic-build = { version = "0.14", optional = true } diff --git a/build.rs b/build.rs index 45499c5..bb88f22 100644 --- a/build.rs +++ b/build.rs @@ -9,7 +9,7 @@ fn add_type_generators( types.iter().fold(bld, |bld, t| { bld.type_attribute( t, - "#[cfg_attr(feature = \"bolero\", derive(::bolero::TypeGenerator))]", + "#[cfg_attr(any(feature = \"bolero\", test), derive(::bolero::TypeGenerator))]", ) }) } @@ -30,6 +30,7 @@ fn main() { &[ "BgpAddressFamilyL2vpnEvpn", "BgpAF", + "Duration", "IfType", "IfRole", "LogLevel", diff --git a/pkg/dataplane/dataplane.pb.go b/pkg/dataplane/dataplane.pb.go index 0719091..5f444ea 100644 --- a/pkg/dataplane/dataplane.pb.go +++ b/pkg/dataplane/dataplane.pb.go @@ -12,6 +12,7 @@ package dataplane import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + durationpb "google.golang.org/protobuf/types/known/durationpb" reflect "reflect" sync "sync" unsafe "unsafe" @@ -994,18 +995,103 @@ func (*PeeringAs_Cidr) isPeeringAs_Rule() {} func (*PeeringAs_Not) isPeeringAs_Rule() {} +type PeeringStatelessNAT struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PeeringStatelessNAT) Reset() { + *x = PeeringStatelessNAT{} + mi := &file_proto_dataplane_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PeeringStatelessNAT) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PeeringStatelessNAT) ProtoMessage() {} + +func (x *PeeringStatelessNAT) ProtoReflect() protoreflect.Message { + mi := &file_proto_dataplane_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PeeringStatelessNAT.ProtoReflect.Descriptor instead. +func (*PeeringStatelessNAT) Descriptor() ([]byte, []int) { + return file_proto_dataplane_proto_rawDescGZIP(), []int{10} +} + +type PeeringStatefulNAT struct { + state protoimpl.MessageState `protogen:"open.v1"` + IdleTimeout *durationpb.Duration `protobuf:"bytes,1,opt,name=idleTimeout,proto3" json:"idleTimeout,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PeeringStatefulNAT) Reset() { + *x = PeeringStatefulNAT{} + mi := &file_proto_dataplane_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PeeringStatefulNAT) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PeeringStatefulNAT) ProtoMessage() {} + +func (x *PeeringStatefulNAT) ProtoReflect() protoreflect.Message { + mi := &file_proto_dataplane_proto_msgTypes[11] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PeeringStatefulNAT.ProtoReflect.Descriptor instead. +func (*PeeringStatefulNAT) Descriptor() ([]byte, []int) { + return file_proto_dataplane_proto_rawDescGZIP(), []int{11} +} + +func (x *PeeringStatefulNAT) GetIdleTimeout() *durationpb.Duration { + if x != nil { + return x.IdleTimeout + } + return nil +} + // Defines a rule between exposing IP and translated type Expose struct { - state protoimpl.MessageState `protogen:"open.v1"` - Ips []*PeeringIPs `protobuf:"bytes,1,rep,name=ips,proto3" json:"ips,omitempty"` - As []*PeeringAs `protobuf:"bytes,2,rep,name=as,proto3" json:"as,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + Ips []*PeeringIPs `protobuf:"bytes,1,rep,name=ips,proto3" json:"ips,omitempty"` + As []*PeeringAs `protobuf:"bytes,2,rep,name=as,proto3" json:"as,omitempty"` + // Types that are valid to be assigned to Nat: + // + // *Expose_Stateless + // *Expose_Stateful + Nat isExpose_Nat `protobuf_oneof:"nat"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *Expose) Reset() { *x = Expose{} - mi := &file_proto_dataplane_proto_msgTypes[10] + mi := &file_proto_dataplane_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1017,7 +1103,7 @@ func (x *Expose) String() string { func (*Expose) ProtoMessage() {} func (x *Expose) ProtoReflect() protoreflect.Message { - mi := &file_proto_dataplane_proto_msgTypes[10] + mi := &file_proto_dataplane_proto_msgTypes[12] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1030,7 +1116,7 @@ func (x *Expose) ProtoReflect() protoreflect.Message { // Deprecated: Use Expose.ProtoReflect.Descriptor instead. func (*Expose) Descriptor() ([]byte, []int) { - return file_proto_dataplane_proto_rawDescGZIP(), []int{10} + return file_proto_dataplane_proto_rawDescGZIP(), []int{12} } func (x *Expose) GetIps() []*PeeringIPs { @@ -1047,6 +1133,47 @@ func (x *Expose) GetAs() []*PeeringAs { return nil } +func (x *Expose) GetNat() isExpose_Nat { + if x != nil { + return x.Nat + } + return nil +} + +func (x *Expose) GetStateless() *PeeringStatelessNAT { + if x != nil { + if x, ok := x.Nat.(*Expose_Stateless); ok { + return x.Stateless + } + } + return nil +} + +func (x *Expose) GetStateful() *PeeringStatefulNAT { + if x != nil { + if x, ok := x.Nat.(*Expose_Stateful); ok { + return x.Stateful + } + } + return nil +} + +type isExpose_Nat interface { + isExpose_Nat() +} + +type Expose_Stateless struct { + Stateless *PeeringStatelessNAT `protobuf:"bytes,3,opt,name=stateless,proto3,oneof"` +} + +type Expose_Stateful struct { + Stateful *PeeringStatefulNAT `protobuf:"bytes,4,opt,name=stateful,proto3,oneof"` +} + +func (*Expose_Stateless) isExpose_Nat() {} + +func (*Expose_Stateful) isExpose_Nat() {} + // Defines a list of exposures per VPC type PeeringEntryFor struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -1058,7 +1185,7 @@ type PeeringEntryFor struct { func (x *PeeringEntryFor) Reset() { *x = PeeringEntryFor{} - mi := &file_proto_dataplane_proto_msgTypes[11] + mi := &file_proto_dataplane_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1070,7 +1197,7 @@ func (x *PeeringEntryFor) String() string { func (*PeeringEntryFor) ProtoMessage() {} func (x *PeeringEntryFor) ProtoReflect() protoreflect.Message { - mi := &file_proto_dataplane_proto_msgTypes[11] + mi := &file_proto_dataplane_proto_msgTypes[13] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1083,7 +1210,7 @@ func (x *PeeringEntryFor) ProtoReflect() protoreflect.Message { // Deprecated: Use PeeringEntryFor.ProtoReflect.Descriptor instead. func (*PeeringEntryFor) Descriptor() ([]byte, []int) { - return file_proto_dataplane_proto_rawDescGZIP(), []int{11} + return file_proto_dataplane_proto_rawDescGZIP(), []int{13} } func (x *PeeringEntryFor) GetVpc() string { @@ -1111,7 +1238,7 @@ type VpcPeering struct { func (x *VpcPeering) Reset() { *x = VpcPeering{} - mi := &file_proto_dataplane_proto_msgTypes[12] + mi := &file_proto_dataplane_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1123,7 +1250,7 @@ func (x *VpcPeering) String() string { func (*VpcPeering) ProtoMessage() {} func (x *VpcPeering) ProtoReflect() protoreflect.Message { - mi := &file_proto_dataplane_proto_msgTypes[12] + mi := &file_proto_dataplane_proto_msgTypes[14] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1136,7 +1263,7 @@ func (x *VpcPeering) ProtoReflect() protoreflect.Message { // Deprecated: Use VpcPeering.ProtoReflect.Descriptor instead. func (*VpcPeering) Descriptor() ([]byte, []int) { - return file_proto_dataplane_proto_rawDescGZIP(), []int{12} + return file_proto_dataplane_proto_rawDescGZIP(), []int{14} } func (x *VpcPeering) GetName() string { @@ -1165,7 +1292,7 @@ type VPC struct { func (x *VPC) Reset() { *x = VPC{} - mi := &file_proto_dataplane_proto_msgTypes[13] + mi := &file_proto_dataplane_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1177,7 +1304,7 @@ func (x *VPC) String() string { func (*VPC) ProtoMessage() {} func (x *VPC) ProtoReflect() protoreflect.Message { - mi := &file_proto_dataplane_proto_msgTypes[13] + mi := &file_proto_dataplane_proto_msgTypes[15] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1190,7 +1317,7 @@ func (x *VPC) ProtoReflect() protoreflect.Message { // Deprecated: Use VPC.ProtoReflect.Descriptor instead. func (*VPC) Descriptor() ([]byte, []int) { - return file_proto_dataplane_proto_rawDescGZIP(), []int{13} + return file_proto_dataplane_proto_rawDescGZIP(), []int{15} } func (x *VPC) GetId() string { @@ -1232,7 +1359,7 @@ type Overlay struct { func (x *Overlay) Reset() { *x = Overlay{} - mi := &file_proto_dataplane_proto_msgTypes[14] + mi := &file_proto_dataplane_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1244,7 +1371,7 @@ func (x *Overlay) String() string { func (*Overlay) ProtoMessage() {} func (x *Overlay) ProtoReflect() protoreflect.Message { - mi := &file_proto_dataplane_proto_msgTypes[14] + mi := &file_proto_dataplane_proto_msgTypes[16] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1257,7 +1384,7 @@ func (x *Overlay) ProtoReflect() protoreflect.Message { // Deprecated: Use Overlay.ProtoReflect.Descriptor instead. func (*Overlay) Descriptor() ([]byte, []int) { - return file_proto_dataplane_proto_rawDescGZIP(), []int{14} + return file_proto_dataplane_proto_rawDescGZIP(), []int{16} } func (x *Overlay) GetVpcs() []*VPC { @@ -1286,7 +1413,7 @@ type BgpAddressFamilyIPv4 struct { func (x *BgpAddressFamilyIPv4) Reset() { *x = BgpAddressFamilyIPv4{} - mi := &file_proto_dataplane_proto_msgTypes[15] + mi := &file_proto_dataplane_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1298,7 +1425,7 @@ func (x *BgpAddressFamilyIPv4) String() string { func (*BgpAddressFamilyIPv4) ProtoMessage() {} func (x *BgpAddressFamilyIPv4) ProtoReflect() protoreflect.Message { - mi := &file_proto_dataplane_proto_msgTypes[15] + mi := &file_proto_dataplane_proto_msgTypes[17] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1311,7 +1438,7 @@ func (x *BgpAddressFamilyIPv4) ProtoReflect() protoreflect.Message { // Deprecated: Use BgpAddressFamilyIPv4.ProtoReflect.Descriptor instead. func (*BgpAddressFamilyIPv4) Descriptor() ([]byte, []int) { - return file_proto_dataplane_proto_rawDescGZIP(), []int{15} + return file_proto_dataplane_proto_rawDescGZIP(), []int{17} } func (x *BgpAddressFamilyIPv4) GetRedistributeConnected() bool { @@ -1347,7 +1474,7 @@ type BgpAddressFamilyIPv6 struct { func (x *BgpAddressFamilyIPv6) Reset() { *x = BgpAddressFamilyIPv6{} - mi := &file_proto_dataplane_proto_msgTypes[16] + mi := &file_proto_dataplane_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1359,7 +1486,7 @@ func (x *BgpAddressFamilyIPv6) String() string { func (*BgpAddressFamilyIPv6) ProtoMessage() {} func (x *BgpAddressFamilyIPv6) ProtoReflect() protoreflect.Message { - mi := &file_proto_dataplane_proto_msgTypes[16] + mi := &file_proto_dataplane_proto_msgTypes[18] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1372,7 +1499,7 @@ func (x *BgpAddressFamilyIPv6) ProtoReflect() protoreflect.Message { // Deprecated: Use BgpAddressFamilyIPv6.ProtoReflect.Descriptor instead. func (*BgpAddressFamilyIPv6) Descriptor() ([]byte, []int) { - return file_proto_dataplane_proto_rawDescGZIP(), []int{16} + return file_proto_dataplane_proto_rawDescGZIP(), []int{18} } func (x *BgpAddressFamilyIPv6) GetRedistributeConnected() bool { @@ -1406,7 +1533,7 @@ type BgpAddressFamilyL2VpnEvpn struct { func (x *BgpAddressFamilyL2VpnEvpn) Reset() { *x = BgpAddressFamilyL2VpnEvpn{} - mi := &file_proto_dataplane_proto_msgTypes[17] + mi := &file_proto_dataplane_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1418,7 +1545,7 @@ func (x *BgpAddressFamilyL2VpnEvpn) String() string { func (*BgpAddressFamilyL2VpnEvpn) ProtoMessage() {} func (x *BgpAddressFamilyL2VpnEvpn) ProtoReflect() protoreflect.Message { - mi := &file_proto_dataplane_proto_msgTypes[17] + mi := &file_proto_dataplane_proto_msgTypes[19] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1431,7 +1558,7 @@ func (x *BgpAddressFamilyL2VpnEvpn) ProtoReflect() protoreflect.Message { // Deprecated: Use BgpAddressFamilyL2VpnEvpn.ProtoReflect.Descriptor instead. func (*BgpAddressFamilyL2VpnEvpn) Descriptor() ([]byte, []int) { - return file_proto_dataplane_proto_rawDescGZIP(), []int{17} + return file_proto_dataplane_proto_rawDescGZIP(), []int{19} } func (x *BgpAddressFamilyL2VpnEvpn) GetAdvertiseAllVni() bool { @@ -1454,7 +1581,7 @@ type BgpNeighborUpdateSource struct { func (x *BgpNeighborUpdateSource) Reset() { *x = BgpNeighborUpdateSource{} - mi := &file_proto_dataplane_proto_msgTypes[18] + mi := &file_proto_dataplane_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1466,7 +1593,7 @@ func (x *BgpNeighborUpdateSource) String() string { func (*BgpNeighborUpdateSource) ProtoMessage() {} func (x *BgpNeighborUpdateSource) ProtoReflect() protoreflect.Message { - mi := &file_proto_dataplane_proto_msgTypes[18] + mi := &file_proto_dataplane_proto_msgTypes[20] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1479,7 +1606,7 @@ func (x *BgpNeighborUpdateSource) ProtoReflect() protoreflect.Message { // Deprecated: Use BgpNeighborUpdateSource.ProtoReflect.Descriptor instead. func (*BgpNeighborUpdateSource) Descriptor() ([]byte, []int) { - return file_proto_dataplane_proto_rawDescGZIP(), []int{18} + return file_proto_dataplane_proto_rawDescGZIP(), []int{20} } func (x *BgpNeighborUpdateSource) GetSource() isBgpNeighborUpdateSource_Source { @@ -1536,7 +1663,7 @@ type BgpNeighbor struct { func (x *BgpNeighbor) Reset() { *x = BgpNeighbor{} - mi := &file_proto_dataplane_proto_msgTypes[19] + mi := &file_proto_dataplane_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1548,7 +1675,7 @@ func (x *BgpNeighbor) String() string { func (*BgpNeighbor) ProtoMessage() {} func (x *BgpNeighbor) ProtoReflect() protoreflect.Message { - mi := &file_proto_dataplane_proto_msgTypes[19] + mi := &file_proto_dataplane_proto_msgTypes[21] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1561,7 +1688,7 @@ func (x *BgpNeighbor) ProtoReflect() protoreflect.Message { // Deprecated: Use BgpNeighbor.ProtoReflect.Descriptor instead. func (*BgpNeighbor) Descriptor() ([]byte, []int) { - return file_proto_dataplane_proto_rawDescGZIP(), []int{19} + return file_proto_dataplane_proto_rawDescGZIP(), []int{21} } func (x *BgpNeighbor) GetAddress() string { @@ -1605,7 +1732,7 @@ type RouteMap struct { func (x *RouteMap) Reset() { *x = RouteMap{} - mi := &file_proto_dataplane_proto_msgTypes[20] + mi := &file_proto_dataplane_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1617,7 +1744,7 @@ func (x *RouteMap) String() string { func (*RouteMap) ProtoMessage() {} func (x *RouteMap) ProtoReflect() protoreflect.Message { - mi := &file_proto_dataplane_proto_msgTypes[20] + mi := &file_proto_dataplane_proto_msgTypes[22] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1630,7 +1757,7 @@ func (x *RouteMap) ProtoReflect() protoreflect.Message { // Deprecated: Use RouteMap.ProtoReflect.Descriptor instead. func (*RouteMap) Descriptor() ([]byte, []int) { - return file_proto_dataplane_proto_rawDescGZIP(), []int{20} + return file_proto_dataplane_proto_rawDescGZIP(), []int{22} } func (x *RouteMap) GetName() string { @@ -1677,7 +1804,7 @@ type RouterConfig struct { func (x *RouterConfig) Reset() { *x = RouterConfig{} - mi := &file_proto_dataplane_proto_msgTypes[21] + mi := &file_proto_dataplane_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1689,7 +1816,7 @@ func (x *RouterConfig) String() string { func (*RouterConfig) ProtoMessage() {} func (x *RouterConfig) ProtoReflect() protoreflect.Message { - mi := &file_proto_dataplane_proto_msgTypes[21] + mi := &file_proto_dataplane_proto_msgTypes[23] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1702,7 +1829,7 @@ func (x *RouterConfig) ProtoReflect() protoreflect.Message { // Deprecated: Use RouterConfig.ProtoReflect.Descriptor instead. func (*RouterConfig) Descriptor() ([]byte, []int) { - return file_proto_dataplane_proto_rawDescGZIP(), []int{21} + return file_proto_dataplane_proto_rawDescGZIP(), []int{23} } func (x *RouterConfig) GetAsn() string { @@ -1767,7 +1894,7 @@ type VRF struct { func (x *VRF) Reset() { *x = VRF{} - mi := &file_proto_dataplane_proto_msgTypes[22] + mi := &file_proto_dataplane_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1779,7 +1906,7 @@ func (x *VRF) String() string { func (*VRF) ProtoMessage() {} func (x *VRF) ProtoReflect() protoreflect.Message { - mi := &file_proto_dataplane_proto_msgTypes[22] + mi := &file_proto_dataplane_proto_msgTypes[24] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1792,7 +1919,7 @@ func (x *VRF) ProtoReflect() protoreflect.Message { // Deprecated: Use VRF.ProtoReflect.Descriptor instead. func (*VRF) Descriptor() ([]byte, []int) { - return file_proto_dataplane_proto_rawDescGZIP(), []int{22} + return file_proto_dataplane_proto_rawDescGZIP(), []int{24} } func (x *VRF) GetName() string { @@ -1833,7 +1960,7 @@ type Underlay struct { func (x *Underlay) Reset() { *x = Underlay{} - mi := &file_proto_dataplane_proto_msgTypes[23] + mi := &file_proto_dataplane_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1845,7 +1972,7 @@ func (x *Underlay) String() string { func (*Underlay) ProtoMessage() {} func (x *Underlay) ProtoReflect() protoreflect.Message { - mi := &file_proto_dataplane_proto_msgTypes[23] + mi := &file_proto_dataplane_proto_msgTypes[25] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1858,7 +1985,7 @@ func (x *Underlay) ProtoReflect() protoreflect.Message { // Deprecated: Use Underlay.ProtoReflect.Descriptor instead. func (*Underlay) Descriptor() ([]byte, []int) { - return file_proto_dataplane_proto_rawDescGZIP(), []int{23} + return file_proto_dataplane_proto_rawDescGZIP(), []int{25} } func (x *Underlay) GetVrfs() []*VRF { @@ -1879,7 +2006,7 @@ type Ports struct { func (x *Ports) Reset() { *x = Ports{} - mi := &file_proto_dataplane_proto_msgTypes[24] + mi := &file_proto_dataplane_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1891,7 +2018,7 @@ func (x *Ports) String() string { func (*Ports) ProtoMessage() {} func (x *Ports) ProtoReflect() protoreflect.Message { - mi := &file_proto_dataplane_proto_msgTypes[24] + mi := &file_proto_dataplane_proto_msgTypes[26] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1904,7 +2031,7 @@ func (x *Ports) ProtoReflect() protoreflect.Message { // Deprecated: Use Ports.ProtoReflect.Descriptor instead. func (*Ports) Descriptor() ([]byte, []int) { - return file_proto_dataplane_proto_rawDescGZIP(), []int{24} + return file_proto_dataplane_proto_rawDescGZIP(), []int{26} } func (x *Ports) GetName() string { @@ -1930,7 +2057,7 @@ type Eal struct { func (x *Eal) Reset() { *x = Eal{} - mi := &file_proto_dataplane_proto_msgTypes[25] + mi := &file_proto_dataplane_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1942,7 +2069,7 @@ func (x *Eal) String() string { func (*Eal) ProtoMessage() {} func (x *Eal) ProtoReflect() protoreflect.Message { - mi := &file_proto_dataplane_proto_msgTypes[25] + mi := &file_proto_dataplane_proto_msgTypes[27] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1955,7 +2082,7 @@ func (x *Eal) ProtoReflect() protoreflect.Message { // Deprecated: Use Eal.ProtoReflect.Descriptor instead. func (*Eal) Descriptor() ([]byte, []int) { - return file_proto_dataplane_proto_rawDescGZIP(), []int{25} + return file_proto_dataplane_proto_rawDescGZIP(), []int{27} } type TracingConfig struct { @@ -1968,7 +2095,7 @@ type TracingConfig struct { func (x *TracingConfig) Reset() { *x = TracingConfig{} - mi := &file_proto_dataplane_proto_msgTypes[26] + mi := &file_proto_dataplane_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1980,7 +2107,7 @@ func (x *TracingConfig) String() string { func (*TracingConfig) ProtoMessage() {} func (x *TracingConfig) ProtoReflect() protoreflect.Message { - mi := &file_proto_dataplane_proto_msgTypes[26] + mi := &file_proto_dataplane_proto_msgTypes[28] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1993,7 +2120,7 @@ func (x *TracingConfig) ProtoReflect() protoreflect.Message { // Deprecated: Use TracingConfig.ProtoReflect.Descriptor instead. func (*TracingConfig) Descriptor() ([]byte, []int) { - return file_proto_dataplane_proto_rawDescGZIP(), []int{26} + return file_proto_dataplane_proto_rawDescGZIP(), []int{28} } func (x *TracingConfig) GetDefault() LogLevel { @@ -2024,7 +2151,7 @@ type Device struct { func (x *Device) Reset() { *x = Device{} - mi := &file_proto_dataplane_proto_msgTypes[27] + mi := &file_proto_dataplane_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2036,7 +2163,7 @@ func (x *Device) String() string { func (*Device) ProtoMessage() {} func (x *Device) ProtoReflect() protoreflect.Message { - mi := &file_proto_dataplane_proto_msgTypes[27] + mi := &file_proto_dataplane_proto_msgTypes[29] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2049,7 +2176,7 @@ func (x *Device) ProtoReflect() protoreflect.Message { // Deprecated: Use Device.ProtoReflect.Descriptor instead. func (*Device) Descriptor() ([]byte, []int) { - return file_proto_dataplane_proto_rawDescGZIP(), []int{27} + return file_proto_dataplane_proto_rawDescGZIP(), []int{29} } func (x *Device) GetDriver() PacketDriver { @@ -2100,7 +2227,7 @@ type GatewayConfig struct { func (x *GatewayConfig) Reset() { *x = GatewayConfig{} - mi := &file_proto_dataplane_proto_msgTypes[28] + mi := &file_proto_dataplane_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2112,7 +2239,7 @@ func (x *GatewayConfig) String() string { func (*GatewayConfig) ProtoMessage() {} func (x *GatewayConfig) ProtoReflect() protoreflect.Message { - mi := &file_proto_dataplane_proto_msgTypes[28] + mi := &file_proto_dataplane_proto_msgTypes[30] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2125,7 +2252,7 @@ func (x *GatewayConfig) ProtoReflect() protoreflect.Message { // Deprecated: Use GatewayConfig.ProtoReflect.Descriptor instead. func (*GatewayConfig) Descriptor() ([]byte, []int) { - return file_proto_dataplane_proto_rawDescGZIP(), []int{28} + return file_proto_dataplane_proto_rawDescGZIP(), []int{30} } func (x *GatewayConfig) GetGeneration() int64 { @@ -2160,7 +2287,7 @@ var File_proto_dataplane_proto protoreflect.FileDescriptor const file_proto_dataplane_proto_rawDesc = "" + "\n" + - "\x15proto/dataplane.proto\x12\x06config\"\x12\n" + + "\x15proto/dataplane.proto\x12\x06config\x1a\x1egoogle/protobuf/duration.proto\"\x12\n" + "\x10GetConfigRequest\"D\n" + "\x13UpdateConfigRequest\x12-\n" + "\x06config\x18\x01 \x01(\v2\x15.config.GatewayConfigR\x06config\"U\n" + @@ -2209,10 +2336,16 @@ const file_proto_dataplane_proto_rawDesc = "" + "\tPeeringAs\x12\x14\n" + "\x04cidr\x18\x01 \x01(\tH\x00R\x04cidr\x12\x12\n" + "\x03not\x18\x02 \x01(\tH\x00R\x03notB\x06\n" + - "\x04rule\"Q\n" + + "\x04rule\"\x15\n" + + "\x13PeeringStatelessNAT\"Q\n" + + "\x12PeeringStatefulNAT\x12;\n" + + "\vidleTimeout\x18\x01 \x01(\v2\x19.google.protobuf.DurationR\vidleTimeout\"\xcf\x01\n" + "\x06Expose\x12$\n" + "\x03ips\x18\x01 \x03(\v2\x12.config.PeeringIPsR\x03ips\x12!\n" + - "\x02as\x18\x02 \x03(\v2\x11.config.PeeringAsR\x02as\"K\n" + + "\x02as\x18\x02 \x03(\v2\x11.config.PeeringAsR\x02as\x12;\n" + + "\tstateless\x18\x03 \x01(\v2\x1b.config.PeeringStatelessNATH\x00R\tstateless\x128\n" + + "\bstateful\x18\x04 \x01(\v2\x1a.config.PeeringStatefulNATH\x00R\bstatefulB\x05\n" + + "\x03nat\"K\n" + "\x0fPeeringEntryFor\x12\x10\n" + "\x03vpc\x18\x01 \x01(\tR\x03vpc\x12&\n" + "\x06expose\x18\x02 \x03(\v2\x0e.config.ExposeR\x06expose\"K\n" + @@ -2357,7 +2490,7 @@ func file_proto_dataplane_proto_rawDescGZIP() []byte { } var file_proto_dataplane_proto_enumTypes = make([]protoimpl.EnumInfo, 7) -var file_proto_dataplane_proto_msgTypes = make([]protoimpl.MessageInfo, 30) +var file_proto_dataplane_proto_msgTypes = make([]protoimpl.MessageInfo, 32) var file_proto_dataplane_proto_goTypes = []any{ (Error)(0), // 0: config.Error (OspfNetworkType)(0), // 1: config.OspfNetworkType @@ -2376,73 +2509,79 @@ var file_proto_dataplane_proto_goTypes = []any{ (*Interface)(nil), // 14: config.Interface (*PeeringIPs)(nil), // 15: config.PeeringIPs (*PeeringAs)(nil), // 16: config.PeeringAs - (*Expose)(nil), // 17: config.Expose - (*PeeringEntryFor)(nil), // 18: config.PeeringEntryFor - (*VpcPeering)(nil), // 19: config.VpcPeering - (*VPC)(nil), // 20: config.VPC - (*Overlay)(nil), // 21: config.Overlay - (*BgpAddressFamilyIPv4)(nil), // 22: config.BgpAddressFamilyIPv4 - (*BgpAddressFamilyIPv6)(nil), // 23: config.BgpAddressFamilyIPv6 - (*BgpAddressFamilyL2VpnEvpn)(nil), // 24: config.BgpAddressFamilyL2vpnEvpn - (*BgpNeighborUpdateSource)(nil), // 25: config.BgpNeighborUpdateSource - (*BgpNeighbor)(nil), // 26: config.BgpNeighbor - (*RouteMap)(nil), // 27: config.RouteMap - (*RouterConfig)(nil), // 28: config.RouterConfig - (*VRF)(nil), // 29: config.VRF - (*Underlay)(nil), // 30: config.Underlay - (*Ports)(nil), // 31: config.Ports - (*Eal)(nil), // 32: config.Eal - (*TracingConfig)(nil), // 33: config.TracingConfig - (*Device)(nil), // 34: config.Device - (*GatewayConfig)(nil), // 35: config.GatewayConfig - nil, // 36: config.TracingConfig.TaglevelEntry + (*PeeringStatelessNAT)(nil), // 17: config.PeeringStatelessNAT + (*PeeringStatefulNAT)(nil), // 18: config.PeeringStatefulNAT + (*Expose)(nil), // 19: config.Expose + (*PeeringEntryFor)(nil), // 20: config.PeeringEntryFor + (*VpcPeering)(nil), // 21: config.VpcPeering + (*VPC)(nil), // 22: config.VPC + (*Overlay)(nil), // 23: config.Overlay + (*BgpAddressFamilyIPv4)(nil), // 24: config.BgpAddressFamilyIPv4 + (*BgpAddressFamilyIPv6)(nil), // 25: config.BgpAddressFamilyIPv6 + (*BgpAddressFamilyL2VpnEvpn)(nil), // 26: config.BgpAddressFamilyL2vpnEvpn + (*BgpNeighborUpdateSource)(nil), // 27: config.BgpNeighborUpdateSource + (*BgpNeighbor)(nil), // 28: config.BgpNeighbor + (*RouteMap)(nil), // 29: config.RouteMap + (*RouterConfig)(nil), // 30: config.RouterConfig + (*VRF)(nil), // 31: config.VRF + (*Underlay)(nil), // 32: config.Underlay + (*Ports)(nil), // 33: config.Ports + (*Eal)(nil), // 34: config.Eal + (*TracingConfig)(nil), // 35: config.TracingConfig + (*Device)(nil), // 36: config.Device + (*GatewayConfig)(nil), // 37: config.GatewayConfig + nil, // 38: config.TracingConfig.TaglevelEntry + (*durationpb.Duration)(nil), // 39: google.protobuf.Duration } var file_proto_dataplane_proto_depIdxs = []int32{ - 35, // 0: config.UpdateConfigRequest.config:type_name -> config.GatewayConfig + 37, // 0: config.UpdateConfigRequest.config:type_name -> config.GatewayConfig 0, // 1: config.UpdateConfigResponse.error:type_name -> config.Error 1, // 2: config.OspfInterface.network_type:type_name -> config.OspfNetworkType 2, // 3: config.Interface.type:type_name -> config.IfType 3, // 4: config.Interface.role:type_name -> config.IfRole 12, // 5: config.Interface.ospf:type_name -> config.OspfInterface - 15, // 6: config.Expose.ips:type_name -> config.PeeringIPs - 16, // 7: config.Expose.as:type_name -> config.PeeringAs - 17, // 8: config.PeeringEntryFor.expose:type_name -> config.Expose - 18, // 9: config.VpcPeering.for:type_name -> config.PeeringEntryFor - 14, // 10: config.VPC.interfaces:type_name -> config.Interface - 20, // 11: config.Overlay.vpcs:type_name -> config.VPC - 19, // 12: config.Overlay.peerings:type_name -> config.VpcPeering - 4, // 13: config.BgpNeighbor.af_activate:type_name -> config.BgpAF - 25, // 14: config.BgpNeighbor.update_source:type_name -> config.BgpNeighborUpdateSource - 26, // 15: config.RouterConfig.neighbors:type_name -> config.BgpNeighbor - 22, // 16: config.RouterConfig.ipv4_unicast:type_name -> config.BgpAddressFamilyIPv4 - 23, // 17: config.RouterConfig.ipv6_unicast:type_name -> config.BgpAddressFamilyIPv6 - 24, // 18: config.RouterConfig.l2vpn_evpn:type_name -> config.BgpAddressFamilyL2vpnEvpn - 27, // 19: config.RouterConfig.route_maps:type_name -> config.RouteMap - 14, // 20: config.VRF.interfaces:type_name -> config.Interface - 28, // 21: config.VRF.router:type_name -> config.RouterConfig - 13, // 22: config.VRF.ospf:type_name -> config.OspfConfig - 29, // 23: config.Underlay.vrfs:type_name -> config.VRF - 5, // 24: config.TracingConfig.default:type_name -> config.LogLevel - 36, // 25: config.TracingConfig.taglevel:type_name -> config.TracingConfig.TaglevelEntry - 6, // 26: config.Device.driver:type_name -> config.PacketDriver - 32, // 27: config.Device.eal:type_name -> config.Eal - 31, // 28: config.Device.ports:type_name -> config.Ports - 33, // 29: config.Device.tracing:type_name -> config.TracingConfig - 34, // 30: config.GatewayConfig.device:type_name -> config.Device - 30, // 31: config.GatewayConfig.underlay:type_name -> config.Underlay - 21, // 32: config.GatewayConfig.overlay:type_name -> config.Overlay - 5, // 33: config.TracingConfig.TaglevelEntry.value:type_name -> config.LogLevel - 7, // 34: config.ConfigService.GetConfig:input_type -> config.GetConfigRequest - 10, // 35: config.ConfigService.GetConfigGeneration:input_type -> config.GetConfigGenerationRequest - 8, // 36: config.ConfigService.UpdateConfig:input_type -> config.UpdateConfigRequest - 35, // 37: config.ConfigService.GetConfig:output_type -> config.GatewayConfig - 11, // 38: config.ConfigService.GetConfigGeneration:output_type -> config.GetConfigGenerationResponse - 9, // 39: config.ConfigService.UpdateConfig:output_type -> config.UpdateConfigResponse - 37, // [37:40] is the sub-list for method output_type - 34, // [34:37] is the sub-list for method input_type - 34, // [34:34] is the sub-list for extension type_name - 34, // [34:34] is the sub-list for extension extendee - 0, // [0:34] is the sub-list for field type_name + 39, // 6: config.PeeringStatefulNAT.idleTimeout:type_name -> google.protobuf.Duration + 15, // 7: config.Expose.ips:type_name -> config.PeeringIPs + 16, // 8: config.Expose.as:type_name -> config.PeeringAs + 17, // 9: config.Expose.stateless:type_name -> config.PeeringStatelessNAT + 18, // 10: config.Expose.stateful:type_name -> config.PeeringStatefulNAT + 19, // 11: config.PeeringEntryFor.expose:type_name -> config.Expose + 20, // 12: config.VpcPeering.for:type_name -> config.PeeringEntryFor + 14, // 13: config.VPC.interfaces:type_name -> config.Interface + 22, // 14: config.Overlay.vpcs:type_name -> config.VPC + 21, // 15: config.Overlay.peerings:type_name -> config.VpcPeering + 4, // 16: config.BgpNeighbor.af_activate:type_name -> config.BgpAF + 27, // 17: config.BgpNeighbor.update_source:type_name -> config.BgpNeighborUpdateSource + 28, // 18: config.RouterConfig.neighbors:type_name -> config.BgpNeighbor + 24, // 19: config.RouterConfig.ipv4_unicast:type_name -> config.BgpAddressFamilyIPv4 + 25, // 20: config.RouterConfig.ipv6_unicast:type_name -> config.BgpAddressFamilyIPv6 + 26, // 21: config.RouterConfig.l2vpn_evpn:type_name -> config.BgpAddressFamilyL2vpnEvpn + 29, // 22: config.RouterConfig.route_maps:type_name -> config.RouteMap + 14, // 23: config.VRF.interfaces:type_name -> config.Interface + 30, // 24: config.VRF.router:type_name -> config.RouterConfig + 13, // 25: config.VRF.ospf:type_name -> config.OspfConfig + 31, // 26: config.Underlay.vrfs:type_name -> config.VRF + 5, // 27: config.TracingConfig.default:type_name -> config.LogLevel + 38, // 28: config.TracingConfig.taglevel:type_name -> config.TracingConfig.TaglevelEntry + 6, // 29: config.Device.driver:type_name -> config.PacketDriver + 34, // 30: config.Device.eal:type_name -> config.Eal + 33, // 31: config.Device.ports:type_name -> config.Ports + 35, // 32: config.Device.tracing:type_name -> config.TracingConfig + 36, // 33: config.GatewayConfig.device:type_name -> config.Device + 32, // 34: config.GatewayConfig.underlay:type_name -> config.Underlay + 23, // 35: config.GatewayConfig.overlay:type_name -> config.Overlay + 5, // 36: config.TracingConfig.TaglevelEntry.value:type_name -> config.LogLevel + 7, // 37: config.ConfigService.GetConfig:input_type -> config.GetConfigRequest + 10, // 38: config.ConfigService.GetConfigGeneration:input_type -> config.GetConfigGenerationRequest + 8, // 39: config.ConfigService.UpdateConfig:input_type -> config.UpdateConfigRequest + 37, // 40: config.ConfigService.GetConfig:output_type -> config.GatewayConfig + 11, // 41: config.ConfigService.GetConfigGeneration:output_type -> config.GetConfigGenerationResponse + 9, // 42: config.ConfigService.UpdateConfig:output_type -> config.UpdateConfigResponse + 40, // [40:43] is the sub-list for method output_type + 37, // [37:40] is the sub-list for method input_type + 37, // [37:37] is the sub-list for extension type_name + 37, // [37:37] is the sub-list for extension extendee + 0, // [0:37] is the sub-list for field type_name } func init() { file_proto_dataplane_proto_init() } @@ -2461,19 +2600,23 @@ func file_proto_dataplane_proto_init() { (*PeeringAs_Cidr)(nil), (*PeeringAs_Not)(nil), } - file_proto_dataplane_proto_msgTypes[18].OneofWrappers = []any{ + file_proto_dataplane_proto_msgTypes[12].OneofWrappers = []any{ + (*Expose_Stateless)(nil), + (*Expose_Stateful)(nil), + } + file_proto_dataplane_proto_msgTypes[20].OneofWrappers = []any{ (*BgpNeighborUpdateSource_Address)(nil), (*BgpNeighborUpdateSource_Interface)(nil), } - file_proto_dataplane_proto_msgTypes[21].OneofWrappers = []any{} - file_proto_dataplane_proto_msgTypes[22].OneofWrappers = []any{} + file_proto_dataplane_proto_msgTypes[23].OneofWrappers = []any{} + file_proto_dataplane_proto_msgTypes[24].OneofWrappers = []any{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_proto_dataplane_proto_rawDesc), len(file_proto_dataplane_proto_rawDesc)), NumEnums: 7, - NumMessages: 30, + NumMessages: 32, NumExtensions: 0, NumServices: 1, }, diff --git a/proto/dataplane.proto b/proto/dataplane.proto index 31dc9be..b7eb6eb 100644 --- a/proto/dataplane.proto +++ b/proto/dataplane.proto @@ -5,6 +5,8 @@ syntax = "proto3"; package config; +import "google/protobuf/duration.proto"; + option go_package = "pkg/dataplane"; service ConfigService { @@ -116,10 +118,19 @@ message PeeringAs { } } +message PeeringStatelessNAT {} +message PeeringStatefulNAT { + google.protobuf.Duration idleTimeout = 1; +} + /* Defines a rule between exposing IP and translated */ message Expose { repeated PeeringIPs ips = 1; repeated PeeringAs as = 2; + oneof nat { + PeeringStatelessNAT stateless = 3; + PeeringStatefulNAT stateful = 4; + } } /* Defines a list of exposures per VPC */ diff --git a/src/bolero/expose.rs b/src/bolero/expose.rs index 781d08f..515461a 100644 --- a/src/bolero/expose.rs +++ b/src/bolero/expose.rs @@ -5,7 +5,12 @@ use bolero::{Driver, TypeGenerator, ValueGenerator}; use std::ops::Bound; use crate::bolero::support::{UniqueV4CidrGenerator, UniqueV6CidrGenerator}; -use crate::config::{Expose, PeeringAs, PeeringIPs, peering_as, peering_i_ps}; +use crate::config::expose::Nat; +use crate::config::{ + Expose, PeeringAs, PeeringIPs, PeeringStatefulNat, PeeringStatelessNat, peering_as, + peering_i_ps, +}; +use crate::google::protobuf::Duration; struct UniquePeeringAs>> { cidr_producer: T, @@ -75,6 +80,32 @@ where } } +impl TypeGenerator for PeeringStatefulNat { + fn generate(d: &mut D) -> Option { + let seconds = d.gen_i64(Bound::Included(&0), Bound::Included(&i64::MAX))?; + let nanos = d.gen_i32(Bound::Included(&0), Bound::Included(&999_999_999))?; + let idle_timeout = Some(Duration { seconds, nanos }); + Some(PeeringStatefulNat { idle_timeout }) + } +} + +impl TypeGenerator for PeeringStatelessNat { + fn generate(_d: &mut D) -> Option { + Some(PeeringStatelessNat {}) + } +} + +impl TypeGenerator for Nat { + fn generate(d: &mut D) -> Option { + let stateful = d.gen_bool(None)?; + if stateful { + Some(Nat::Stateful(d.produce()?)) + } else { + Some(Nat::Stateless(d.produce()?)) + } + } +} + // FIXME(manishv): We should make sure that the number of peering ips and ases are // consistent. // FIXME(manishv): We should also make sure that the cidrs use not @@ -96,23 +127,25 @@ impl TypeGenerator for Expose { }; let has_as = d.gen_bool(None)?; - let r#as = if has_as { + let (r#as, nat) = if has_as { + let nat = d.produce()?; if v4 { let v4_cidr_producer_as = UniquePeeringAs::new(UniqueV4CidrGenerator::new(len, v4_mask)); - v4_cidr_producer_as.generate(d)? + (v4_cidr_producer_as.generate(d)?, Some(nat)) } else { let v6_cidr_producer_as = UniquePeeringAs::new(UniqueV6CidrGenerator::new(len, v6_mask)); - v6_cidr_producer_as.generate(d)? + (v6_cidr_producer_as.generate(d)?, Some(nat)) } } else { - vec![] + (vec![], None) }; Some(Expose { ips: peering_ips, r#as, + nat, }) } } @@ -122,6 +155,7 @@ mod test { use super::*; use crate::bolero::test_support::parse_cidr; use crate::bolero::test_support::{get_peering_as_ip, get_peering_ip}; + use crate::config::expose; use std::net::IpAddr; enum IpAddrType { @@ -171,6 +205,17 @@ mod test { .collect::>() .as_slice() )); + if !expose.r#as.is_empty() { + let Some(nat) = expose.nat else { + panic!("nat is None"); + }; + match nat { + expose::Nat::Stateless(_s) => {} + expose::Nat::Stateful(s) => { + assert!(s.idle_timeout.is_some()); + } + } + } }); assert!(more_than_one); } diff --git a/src/duration.rs b/src/duration.rs new file mode 100644 index 0000000..0ed95a3 --- /dev/null +++ b/src/duration.rs @@ -0,0 +1,169 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2025 Hedgehog + +use crate::google::protobuf::Duration as ProtoDuration; +use std::time::Duration as StdDuration; + +#[derive(thiserror::Error, Debug)] +pub enum DurationConversionError { + #[error("Duration cannot be negative ({0} seconds, {1} nanoseconds)")] + NegativeDuration(i64, i32), +} + +impl TryFrom<&ProtoDuration> for StdDuration { + type Error = DurationConversionError; + + fn try_from(proto_duration: &ProtoDuration) -> Result { + let seconds = proto_duration.seconds; + let nanos = proto_duration.nanos; + + let nanos_as_seconds = nanos / 1_000_000_000; + let nanos_leftover = nanos - nanos_as_seconds * 1_000_000_000; + let new_seconds = seconds + i64::from(nanos_as_seconds); + + assert!(nanos_leftover.abs() < 1_000_000_000); + + if new_seconds < 0 { + return Err(DurationConversionError::NegativeDuration(seconds, nanos)); + } + + let (seconds_u64, nanos_u32) = if nanos_leftover < 0 { + if new_seconds < 1 { + return Err(DurationConversionError::NegativeDuration(seconds, nanos)); + } + let new_seconds = new_seconds - 1; + let nanos_leftover = nanos_leftover + 1_000_000_000; + + ( + u64::try_from(new_seconds).expect("Failed to convert Proto Duration seconds to std::time::Duration with negative nanos_leftover (should never happen"), + u32::try_from(nanos_leftover).expect("Failed to convert Proto Duration nanos to std::time::Duration with negative nanos_leftover (should never happen"), + ) + } else { + ( + u64::try_from(new_seconds).expect("Failed to convert Proto Duration seconds to std::time::Duration (should never happen)"), + u32::try_from(nanos_leftover).expect("Failed to convert Proto Duration nanos to std::time::Duration (should never happen)"), + ) + }; + + Ok(StdDuration::new(seconds_u64, nanos_u32)) + } +} + +impl TryFrom for StdDuration { + type Error = DurationConversionError; + + fn try_from(proto_duration: ProtoDuration) -> Result { + StdDuration::try_from(&proto_duration) + } +} + +impl TryFrom<&StdDuration> for ProtoDuration { + type Error = std::num::TryFromIntError; + + fn try_from(std_duration: &StdDuration) -> Result { + let seconds = i64::try_from(std_duration.as_secs())?; + let nanos = i32::try_from(std_duration.subsec_nanos())?; + Ok(ProtoDuration { seconds, nanos }) + } +} + +impl TryFrom for ProtoDuration { + type Error = std::num::TryFromIntError; + + fn try_from(std_duration: StdDuration) -> Result { + Self::try_from(&std_duration) + } +} + +#[cfg(test)] +mod tests { + use crate::google::protobuf::Duration as ProtoDuration; + + #[test] + fn test_proto_to_std_duration_conversion_bolero() { + bolero::check!() + .with_type::() + .for_each(|proto_duration| { + let result = std::time::Duration::try_from(proto_duration); + match result { + Ok(duration) => { + // This check is not complete, but easy to check in this case + if proto_duration.seconds > 0 && proto_duration.nanos > 0 { + assert_eq!( + duration, + std::time::Duration::new( + u64::try_from(proto_duration.seconds).unwrap(), + u32::try_from(proto_duration.nanos).unwrap() + ) + ); + } + } + Err(_) => { + // This is not a full check that the error is valid, but one of these must be true for there to be a conversion error + assert!(proto_duration.seconds < 0 || proto_duration.nanos < 0); + } + } + }); + } + + #[test] + fn test_proto_to_std_duration_conversion_negative_nanos() { + let proto_duration = ProtoDuration { + seconds: 10, + nanos: -1, + }; + let result = std::time::Duration::try_from(proto_duration); + assert_eq!(result.unwrap(), std::time::Duration::new(9, 999_999_999)); + + let proto_duration = ProtoDuration { + seconds: 10, + nanos: -1_000_000_001, + }; + let result = std::time::Duration::try_from(proto_duration); + assert_eq!(result.unwrap(), std::time::Duration::new(8, 999_999_999)); + } + + #[test] + fn test_proto_to_std_duration_conversion_negative_seconds() { + let proto_duration = ProtoDuration { + seconds: -1, + nanos: 1_000_000_001, + }; + let result = std::time::Duration::try_from(proto_duration); + assert_eq!(result.unwrap(), std::time::Duration::new(0, 1)); + + let proto_duration = ProtoDuration { + seconds: -1, + nanos: 2_000_000_000, + }; + let result = std::time::Duration::try_from(proto_duration); + assert_eq!(result.unwrap(), std::time::Duration::new(1, 0)); + } + + #[test] + fn test_std_to_proto_duration_conversion_bolero() { + bolero::check!() + .with_type::() + .for_each(|duration| { + let proto_duration_result = ProtoDuration::try_from(duration); + match proto_duration_result { + Err(_) => { + assert!( + i64::try_from(duration.as_secs()).is_err() + || i32::try_from(duration.subsec_nanos()).is_err() + ); + } + Ok(proto_duration) => { + assert_eq!( + u64::try_from(proto_duration.seconds).unwrap(), + duration.as_secs() + ); + assert_eq!( + u32::try_from(proto_duration.nanos).unwrap(), + duration.subsec_nanos() + ); + } + } + }); + } +} diff --git a/src/generated/config.rs b/src/generated/config.rs index 2b0580e..3ce6ae2 100644 --- a/src/generated/config.rs +++ b/src/generated/config.rs @@ -114,6 +114,15 @@ pub mod peering_as { Not(::prost::alloc::string::String), } } +#[derive(::serde::Deserialize, ::serde::Serialize)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] +pub struct PeeringStatelessNat {} +#[derive(::serde::Deserialize, ::serde::Serialize)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] +pub struct PeeringStatefulNat { + #[prost(message, optional, tag = "1")] + pub idle_timeout: ::core::option::Option, +} /// Defines a rule between exposing IP and translated #[derive(::serde::Deserialize, ::serde::Serialize)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -122,6 +131,19 @@ pub struct Expose { pub ips: ::prost::alloc::vec::Vec, #[prost(message, repeated, tag = "2")] pub r#as: ::prost::alloc::vec::Vec, + #[prost(oneof = "expose::Nat", tags = "3, 4")] + pub nat: ::core::option::Option, +} +/// Nested message and enum types in `Expose`. +pub mod expose { + #[derive(::serde::Deserialize, ::serde::Serialize)] + #[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Oneof)] + pub enum Nat { + #[prost(message, tag = "3")] + Stateless(super::PeeringStatelessNat), + #[prost(message, tag = "4")] + Stateful(super::PeeringStatefulNat), + } } /// Defines a list of exposures per VPC #[derive(::serde::Deserialize, ::serde::Serialize)] @@ -189,7 +211,7 @@ pub struct BgpAddressFamilyIPv6 { pub networks: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, } /// BGP options for L2VPN EVPN AFI -#[cfg_attr(feature = "bolero", derive(::bolero::TypeGenerator))] +#[cfg_attr(any(feature = "bolero", test), derive(::bolero::TypeGenerator))] #[derive(::serde::Deserialize, ::serde::Serialize)] #[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct BgpAddressFamilyL2vpnEvpn { @@ -370,7 +392,7 @@ impl Error { } } /// OSPF Network Type -#[cfg_attr(feature = "bolero", derive(::bolero::TypeGenerator))] +#[cfg_attr(any(feature = "bolero", test), derive(::bolero::TypeGenerator))] #[derive(::serde::Deserialize, ::serde::Serialize)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] @@ -405,7 +427,7 @@ impl OspfNetworkType { } } /// Defines interface representation on the Gateway -#[cfg_attr(feature = "bolero", derive(::bolero::TypeGenerator))] +#[cfg_attr(any(feature = "bolero", test), derive(::bolero::TypeGenerator))] #[derive(::serde::Deserialize, ::serde::Serialize)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] @@ -440,7 +462,7 @@ impl IfType { } } /// For physical interface - fabric-facing or external-facing -#[cfg_attr(feature = "bolero", derive(::bolero::TypeGenerator))] +#[cfg_attr(any(feature = "bolero", test), derive(::bolero::TypeGenerator))] #[derive(::serde::Deserialize, ::serde::Serialize)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] @@ -469,7 +491,7 @@ impl IfRole { } } /// AFIs supported for BGP peering -#[cfg_attr(feature = "bolero", derive(::bolero::TypeGenerator))] +#[cfg_attr(any(feature = "bolero", test), derive(::bolero::TypeGenerator))] #[derive(::serde::Deserialize, ::serde::Serialize)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] @@ -501,7 +523,7 @@ impl BgpAf { } } /// Log-level for dataplane and DPDK -#[cfg_attr(feature = "bolero", derive(::bolero::TypeGenerator))] +#[cfg_attr(any(feature = "bolero", test), derive(::bolero::TypeGenerator))] #[derive(::serde::Deserialize, ::serde::Serialize)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] @@ -542,7 +564,7 @@ impl LogLevel { } } /// Backend driver for packet processing -#[cfg_attr(feature = "bolero", derive(::bolero::TypeGenerator))] +#[cfg_attr(any(feature = "bolero", test), derive(::bolero::TypeGenerator))] #[derive(::serde::Deserialize, ::serde::Serialize)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] diff --git a/src/generated/google.protobuf.rs b/src/generated/google.protobuf.rs index ebab9ea..99b733f 100644 --- a/src/generated/google.protobuf.rs +++ b/src/generated/google.protobuf.rs @@ -2,3 +2,85 @@ // SPDX-License-Identifier: Apache-2.0 // This file is @generated by prost-build. +/// A Duration represents a signed, fixed-length span of time represented +/// as a count of seconds and fractions of seconds at nanosecond +/// resolution. It is independent of any calendar and concepts like "day" +/// or "month". It is related to Timestamp in that the difference between +/// two Timestamp values is a Duration and it can be added or subtracted +/// from a Timestamp. Range is approximately +-10,000 years. +/// +/// # Examples +/// +/// Example 1: Compute Duration from two Timestamps in pseudo code. +/// +/// ```text +/// Timestamp start = ...; +/// Timestamp end = ...; +/// Duration duration = ...; +/// +/// duration.seconds = end.seconds - start.seconds; +/// duration.nanos = end.nanos - start.nanos; +/// +/// if (duration.seconds < 0 && duration.nanos > 0) { +/// duration.seconds += 1; +/// duration.nanos -= 1000000000; +/// } else if (duration.seconds > 0 && duration.nanos < 0) { +/// duration.seconds -= 1; +/// duration.nanos += 1000000000; +/// } +/// ``` +/// +/// Example 2: Compute Timestamp from Timestamp + Duration in pseudo code. +/// +/// ```text +/// Timestamp start = ...; +/// Duration duration = ...; +/// Timestamp end = ...; +/// +/// end.seconds = start.seconds + duration.seconds; +/// end.nanos = start.nanos + duration.nanos; +/// +/// if (end.nanos < 0) { +/// end.seconds -= 1; +/// end.nanos += 1000000000; +/// } else if (end.nanos >= 1000000000) { +/// end.seconds += 1; +/// end.nanos -= 1000000000; +/// } +/// ``` +/// +/// Example 3: Compute Duration from datetime.timedelta in Python. +/// +/// ```text +/// td = datetime.timedelta(days=3, minutes=10) +/// duration = Duration() +/// duration.FromTimedelta(td) +/// ``` +/// +/// # JSON Mapping +/// +/// In JSON format, the Duration type is encoded as a string rather than an +/// object, where the string ends in the suffix "s" (indicating seconds) and +/// is preceded by the number of seconds, with nanoseconds expressed as +/// fractional seconds. For example, 3 seconds with 0 nanoseconds should be +/// encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should +/// be expressed in JSON format as "3.000000001s", and 3 seconds and 1 +/// microsecond should be expressed in JSON format as "3.000001s". +#[cfg_attr(any(feature = "bolero", test), derive(::bolero::TypeGenerator))] +#[derive(::serde::Deserialize, ::serde::Serialize)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] +pub struct Duration { + /// Signed seconds of the span of time. Must be from -315,576,000,000 + /// to +315,576,000,000 inclusive. Note: these bounds are computed from: + /// 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years + #[prost(int64, tag = "1")] + pub seconds: i64, + /// Signed fractions of a second at nanosecond resolution of the span + /// of time. Durations less than one second are represented with a 0 + /// `seconds` field and a positive or negative `nanos` field. For durations + /// of one second or more, a non-zero value for the `nanos` field must be + /// of the same sign as the `seconds` field. Must be from -999,999,999 + /// to +999,999,999 inclusive. + #[prost(int32, tag = "2")] + pub nanos: i32, +} diff --git a/src/lib.rs b/src/lib.rs index 3b1f369..effdae2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -75,3 +75,5 @@ pub const VERSION: &str = env!("CARGO_PKG_VERSION"); #[cfg(feature = "bolero")] pub mod bolero; + +mod duration;