diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..26ad8e2 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,19 @@ +{ + "yaml.format.enable": true, + "yaml.completion": true, + "yaml.validate": true, + "yaml.hover": true, + "yaml.schemas": { + "./docs/schemas/polad_config.json": [ + "polad*.yaml", + "polad*.yml" + ], + "./cmd/pola/docs/schemas/policy.json": [ + "*POLICY*.yaml", + "*POLICY*.yml", + "*policy*.yaml", + "*policy*.yml" + ], + }, + "files.insertFinalNewline": true, +} diff --git a/README.md b/README.md index df58e47..9496834 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Pola PCE is an implementation of the Path Computation Element (PCE) and a PCEP Library in Go. ## Features -* Support for SRv6 and SR-MPLS +* Support for SRv6(full-SID/uSID) and SR-MPLS * Implementation of active stateful PCE functionality (PCInitiate, PCUpdate, etc.) * Dynamic and explicit SR policy definition using YAML * Dynamic path: Utilizes CSPF with GoBGP BGP-LS TED @@ -25,9 +25,12 @@ Pola PCE is an implementation of the Path Computation Element (PCE) and a PCEP L * Junos * FRRouting -### SRv6 +### SRv6 (full-SID) * Junos +### SRv6 (uSID) +* IOS-XR + ## Installation & Use * [Getting Started](docs/sources/getting-started.md) * Examples (powered by [Containerlab](https://containerlab.dev/)/[Tinet](https://github.com/tinynetwork/tinet)) diff --git a/api/grpc/pola.pb.go b/api/grpc/pola.pb.go index 92c95d4..060773f 100644 --- a/api/grpc/pola.pb.go +++ b/api/grpc/pola.pb.go @@ -5,16 +5,16 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.28.1 -// protoc v3.21.12 +// protoc-gen-go v1.34.1 +// protoc v3.12.4 // source: pola.proto package grpc import ( + empty "github.com/golang/protobuf/ptypes/empty" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" - emptypb "google.golang.org/protobuf/types/known/emptypb" reflect "reflect" sync "sync" ) @@ -72,6 +72,52 @@ func (SRPolicyType) EnumDescriptor() ([]byte, []int) { return file_pola_proto_rawDescGZIP(), []int{0} } +type SessionState int32 + +const ( + SessionState_DOWN SessionState = 0 + SessionState_UP SessionState = 1 +) + +// Enum value maps for SessionState. +var ( + SessionState_name = map[int32]string{ + 0: "DOWN", + 1: "UP", + } + SessionState_value = map[string]int32{ + "DOWN": 0, + "UP": 1, + } +) + +func (x SessionState) Enum() *SessionState { + p := new(SessionState) + *p = x + return p +} + +func (x SessionState) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (SessionState) Descriptor() protoreflect.EnumDescriptor { + return file_pola_proto_enumTypes[1].Descriptor() +} + +func (SessionState) Type() protoreflect.EnumType { + return &file_pola_proto_enumTypes[1] +} + +func (x SessionState) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use SessionState.Descriptor instead. +func (SessionState) EnumDescriptor() ([]byte, []int) { + return file_pola_proto_rawDescGZIP(), []int{1} +} + type MetricType int32 const ( @@ -108,11 +154,11 @@ func (x MetricType) String() string { } func (MetricType) Descriptor() protoreflect.EnumDescriptor { - return file_pola_proto_enumTypes[1].Descriptor() + return file_pola_proto_enumTypes[2].Descriptor() } func (MetricType) Type() protoreflect.EnumType { - return &file_pola_proto_enumTypes[1] + return &file_pola_proto_enumTypes[2] } func (x MetricType) Number() protoreflect.EnumNumber { @@ -121,7 +167,7 @@ func (x MetricType) Number() protoreflect.EnumNumber { // Deprecated: Use MetricType.Descriptor instead. func (MetricType) EnumDescriptor() ([]byte, []int) { - return file_pola_proto_rawDescGZIP(), []int{1} + return file_pola_proto_rawDescGZIP(), []int{2} } type Segment struct { @@ -129,7 +175,10 @@ type Segment struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Sid string `protobuf:"bytes,1,opt,name=sid,proto3" json:"sid,omitempty"` + Sid string `protobuf:"bytes,1,opt,name=sid,proto3" json:"sid,omitempty"` + SidStructure string `protobuf:"bytes,2,opt,name=sidStructure,proto3" json:"sidStructure,omitempty"` + LocalAddr string `protobuf:"bytes,3,opt,name=localAddr,proto3" json:"localAddr,omitempty"` + RemoteAddr string `protobuf:"bytes,4,opt,name=remoteAddr,proto3" json:"remoteAddr,omitempty"` } func (x *Segment) Reset() { @@ -171,6 +220,27 @@ func (x *Segment) GetSid() string { return "" } +func (x *Segment) GetSidStructure() string { + if x != nil { + return x.SidStructure + } + return "" +} + +func (x *Segment) GetLocalAddr() string { + if x != nil { + return x.LocalAddr + } + return "" +} + +func (x *Segment) GetRemoteAddr() string { + if x != nil { + return x.RemoteAddr + } + return "" +} + type SRPolicy struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -353,6 +423,61 @@ func (x *CreateSRPolicyInput) GetAsn() uint32 { return 0 } +type DeleteSRPolicyInput struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SRPolicy *SRPolicy `protobuf:"bytes,1,opt,name=SRPolicy,proto3" json:"SRPolicy,omitempty"` + Asn uint32 `protobuf:"varint,2,opt,name=asn,proto3" json:"asn,omitempty"` +} + +func (x *DeleteSRPolicyInput) Reset() { + *x = DeleteSRPolicyInput{} + if protoimpl.UnsafeEnabled { + mi := &file_pola_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteSRPolicyInput) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteSRPolicyInput) ProtoMessage() {} + +func (x *DeleteSRPolicyInput) ProtoReflect() protoreflect.Message { + mi := &file_pola_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteSRPolicyInput.ProtoReflect.Descriptor instead. +func (*DeleteSRPolicyInput) Descriptor() ([]byte, []int) { + return file_pola_proto_rawDescGZIP(), []int{3} +} + +func (x *DeleteSRPolicyInput) GetSRPolicy() *SRPolicy { + if x != nil { + return x.SRPolicy + } + return nil +} + +func (x *DeleteSRPolicyInput) GetAsn() uint32 { + if x != nil { + return x.Asn + } + return 0 +} + type RequestStatus struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -364,7 +489,7 @@ type RequestStatus struct { func (x *RequestStatus) Reset() { *x = RequestStatus{} if protoimpl.UnsafeEnabled { - mi := &file_pola_proto_msgTypes[3] + mi := &file_pola_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -377,7 +502,7 @@ func (x *RequestStatus) String() string { func (*RequestStatus) ProtoMessage() {} func (x *RequestStatus) ProtoReflect() protoreflect.Message { - mi := &file_pola_proto_msgTypes[3] + mi := &file_pola_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -390,7 +515,7 @@ func (x *RequestStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use RequestStatus.ProtoReflect.Descriptor instead. func (*RequestStatus) Descriptor() ([]byte, []int) { - return file_pola_proto_rawDescGZIP(), []int{3} + return file_pola_proto_rawDescGZIP(), []int{4} } func (x *RequestStatus) GetIsSuccess() bool { @@ -405,13 +530,16 @@ type Session struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Addr []byte `protobuf:"bytes,1,opt,name=Addr,proto3" json:"Addr,omitempty"` + Addr []byte `protobuf:"bytes,1,opt,name=Addr,proto3" json:"Addr,omitempty"` + State SessionState `protobuf:"varint,2,opt,name=State,proto3,enum=pb.SessionState" json:"State,omitempty"` + Caps []string `protobuf:"bytes,3,rep,name=Caps,proto3" json:"Caps,omitempty"` + IsSynced bool `protobuf:"varint,4,opt,name=IsSynced,proto3" json:"IsSynced,omitempty"` } func (x *Session) Reset() { *x = Session{} if protoimpl.UnsafeEnabled { - mi := &file_pola_proto_msgTypes[4] + mi := &file_pola_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -424,7 +552,7 @@ func (x *Session) String() string { func (*Session) ProtoMessage() {} func (x *Session) ProtoReflect() protoreflect.Message { - mi := &file_pola_proto_msgTypes[4] + mi := &file_pola_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -437,7 +565,7 @@ func (x *Session) ProtoReflect() protoreflect.Message { // Deprecated: Use Session.ProtoReflect.Descriptor instead. func (*Session) Descriptor() ([]byte, []int) { - return file_pola_proto_rawDescGZIP(), []int{4} + return file_pola_proto_rawDescGZIP(), []int{5} } func (x *Session) GetAddr() []byte { @@ -447,6 +575,27 @@ func (x *Session) GetAddr() []byte { return nil } +func (x *Session) GetState() SessionState { + if x != nil { + return x.State + } + return SessionState_DOWN +} + +func (x *Session) GetCaps() []string { + if x != nil { + return x.Caps + } + return nil +} + +func (x *Session) GetIsSynced() bool { + if x != nil { + return x.IsSynced + } + return false +} + type SessionList struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -458,7 +607,7 @@ type SessionList struct { func (x *SessionList) Reset() { *x = SessionList{} if protoimpl.UnsafeEnabled { - mi := &file_pola_proto_msgTypes[5] + mi := &file_pola_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -471,7 +620,7 @@ func (x *SessionList) String() string { func (*SessionList) ProtoMessage() {} func (x *SessionList) ProtoReflect() protoreflect.Message { - mi := &file_pola_proto_msgTypes[5] + mi := &file_pola_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -484,7 +633,7 @@ func (x *SessionList) ProtoReflect() protoreflect.Message { // Deprecated: Use SessionList.ProtoReflect.Descriptor instead. func (*SessionList) Descriptor() ([]byte, []int) { - return file_pola_proto_rawDescGZIP(), []int{5} + return file_pola_proto_rawDescGZIP(), []int{6} } func (x *SessionList) GetSessions() []*Session { @@ -505,7 +654,7 @@ type SRPolicyList struct { func (x *SRPolicyList) Reset() { *x = SRPolicyList{} if protoimpl.UnsafeEnabled { - mi := &file_pola_proto_msgTypes[6] + mi := &file_pola_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -518,7 +667,7 @@ func (x *SRPolicyList) String() string { func (*SRPolicyList) ProtoMessage() {} func (x *SRPolicyList) ProtoReflect() protoreflect.Message { - mi := &file_pola_proto_msgTypes[6] + mi := &file_pola_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -531,7 +680,7 @@ func (x *SRPolicyList) ProtoReflect() protoreflect.Message { // Deprecated: Use SRPolicyList.ProtoReflect.Descriptor instead. func (*SRPolicyList) Descriptor() ([]byte, []int) { - return file_pola_proto_rawDescGZIP(), []int{6} + return file_pola_proto_rawDescGZIP(), []int{7} } func (x *SRPolicyList) GetSRPolicies() []*SRPolicy { @@ -553,7 +702,7 @@ type LsPrefix struct { func (x *LsPrefix) Reset() { *x = LsPrefix{} if protoimpl.UnsafeEnabled { - mi := &file_pola_proto_msgTypes[7] + mi := &file_pola_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -566,7 +715,7 @@ func (x *LsPrefix) String() string { func (*LsPrefix) ProtoMessage() {} func (x *LsPrefix) ProtoReflect() protoreflect.Message { - mi := &file_pola_proto_msgTypes[7] + mi := &file_pola_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -579,7 +728,7 @@ func (x *LsPrefix) ProtoReflect() protoreflect.Message { // Deprecated: Use LsPrefix.ProtoReflect.Descriptor instead. func (*LsPrefix) Descriptor() ([]byte, []int) { - return file_pola_proto_rawDescGZIP(), []int{7} + return file_pola_proto_rawDescGZIP(), []int{8} } func (x *LsPrefix) GetPrefix() string { @@ -608,7 +757,7 @@ type Metric struct { func (x *Metric) Reset() { *x = Metric{} if protoimpl.UnsafeEnabled { - mi := &file_pola_proto_msgTypes[8] + mi := &file_pola_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -621,7 +770,7 @@ func (x *Metric) String() string { func (*Metric) ProtoMessage() {} func (x *Metric) ProtoReflect() protoreflect.Message { - mi := &file_pola_proto_msgTypes[8] + mi := &file_pola_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -634,7 +783,7 @@ func (x *Metric) ProtoReflect() protoreflect.Message { // Deprecated: Use Metric.ProtoReflect.Descriptor instead. func (*Metric) Descriptor() ([]byte, []int) { - return file_pola_proto_rawDescGZIP(), []int{8} + return file_pola_proto_rawDescGZIP(), []int{9} } func (x *Metric) GetType() MetricType { @@ -669,7 +818,7 @@ type LsLink struct { func (x *LsLink) Reset() { *x = LsLink{} if protoimpl.UnsafeEnabled { - mi := &file_pola_proto_msgTypes[9] + mi := &file_pola_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -682,7 +831,7 @@ func (x *LsLink) String() string { func (*LsLink) ProtoMessage() {} func (x *LsLink) ProtoReflect() protoreflect.Message { - mi := &file_pola_proto_msgTypes[9] + mi := &file_pola_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -695,7 +844,7 @@ func (x *LsLink) ProtoReflect() protoreflect.Message { // Deprecated: Use LsLink.ProtoReflect.Descriptor instead. func (*LsLink) Descriptor() ([]byte, []int) { - return file_pola_proto_rawDescGZIP(), []int{9} + return file_pola_proto_rawDescGZIP(), []int{10} } func (x *LsLink) GetLocalRouterID() string { @@ -772,7 +921,7 @@ type LsNode struct { func (x *LsNode) Reset() { *x = LsNode{} if protoimpl.UnsafeEnabled { - mi := &file_pola_proto_msgTypes[10] + mi := &file_pola_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -785,7 +934,7 @@ func (x *LsNode) String() string { func (*LsNode) ProtoMessage() {} func (x *LsNode) ProtoReflect() protoreflect.Message { - mi := &file_pola_proto_msgTypes[10] + mi := &file_pola_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -798,7 +947,7 @@ func (x *LsNode) ProtoReflect() protoreflect.Message { // Deprecated: Use LsNode.ProtoReflect.Descriptor instead. func (*LsNode) Descriptor() ([]byte, []int) { - return file_pola_proto_rawDescGZIP(), []int{10} + return file_pola_proto_rawDescGZIP(), []int{11} } func (x *LsNode) GetAsn() uint32 { @@ -869,7 +1018,7 @@ type Ted struct { func (x *Ted) Reset() { *x = Ted{} if protoimpl.UnsafeEnabled { - mi := &file_pola_proto_msgTypes[11] + mi := &file_pola_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -882,7 +1031,7 @@ func (x *Ted) String() string { func (*Ted) ProtoMessage() {} func (x *Ted) ProtoReflect() protoreflect.Message { - mi := &file_pola_proto_msgTypes[11] + mi := &file_pola_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -895,7 +1044,7 @@ func (x *Ted) ProtoReflect() protoreflect.Message { // Deprecated: Use Ted.ProtoReflect.Descriptor instead. func (*Ted) Descriptor() ([]byte, []int) { - return file_pola_proto_rawDescGZIP(), []int{11} + return file_pola_proto_rawDescGZIP(), []int{12} } func (x *Ted) GetEnable() bool { @@ -917,128 +1066,156 @@ var File_pola_proto protoreflect.FileDescriptor var file_pola_proto_rawDesc = []byte{ 0x0a, 0x0a, 0x70, 0x6f, 0x6c, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x70, 0x62, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x1b, 0x0a, + 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x7d, 0x0a, 0x07, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x73, 0x69, 0x64, 0x22, 0xff, 0x02, 0x0a, 0x08, 0x53, - 0x52, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x70, 0x63, 0x65, 0x70, 0x53, - 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x0f, 0x70, 0x63, 0x65, 0x70, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x41, 0x64, 0x64, - 0x72, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x72, 0x63, 0x41, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x07, 0x73, 0x72, 0x63, 0x41, 0x64, 0x64, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x64, - 0x73, 0x74, 0x41, 0x64, 0x64, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x64, 0x73, - 0x74, 0x41, 0x64, 0x64, 0x72, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x72, 0x63, 0x52, 0x6f, 0x75, 0x74, - 0x65, 0x72, 0x49, 0x44, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x72, 0x63, 0x52, - 0x6f, 0x75, 0x74, 0x65, 0x72, 0x49, 0x44, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x73, 0x74, 0x52, 0x6f, - 0x75, 0x74, 0x65, 0x72, 0x49, 0x44, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x73, - 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x49, 0x44, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x6c, - 0x6f, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x12, - 0x1e, 0x0a, 0x0a, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x07, 0x20, - 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x12, - 0x1e, 0x0a, 0x0a, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x08, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, - 0x24, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x10, 0x2e, - 0x70, 0x62, 0x2e, 0x53, 0x52, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x54, 0x79, 0x70, 0x65, 0x52, - 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x2d, 0x0a, 0x0b, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, - 0x4c, 0x69, 0x73, 0x74, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x70, 0x62, 0x2e, - 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x0b, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, - 0x4c, 0x69, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x18, 0x0b, - 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0e, 0x2e, 0x70, 0x62, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, - 0x54, 0x79, 0x70, 0x65, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x22, 0x51, 0x0a, 0x13, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x52, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x49, 0x6e, - 0x70, 0x75, 0x74, 0x12, 0x28, 0x0a, 0x08, 0x53, 0x52, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x52, 0x50, 0x6f, 0x6c, - 0x69, 0x63, 0x79, 0x52, 0x08, 0x53, 0x52, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x10, 0x0a, - 0x03, 0x61, 0x73, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x61, 0x73, 0x6e, 0x22, - 0x2d, 0x0a, 0x0d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x73, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x73, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x1d, - 0x0a, 0x07, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x41, 0x64, 0x64, - 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x41, 0x64, 0x64, 0x72, 0x22, 0x36, 0x0a, - 0x0b, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x08, - 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0b, - 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x53, 0x65, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x3c, 0x0a, 0x0c, 0x53, 0x52, 0x50, 0x6f, 0x6c, 0x69, 0x63, - 0x79, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x2c, 0x0a, 0x0a, 0x53, 0x52, 0x50, 0x6f, 0x6c, 0x69, 0x63, - 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x70, 0x62, 0x2e, 0x53, - 0x52, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x0a, 0x53, 0x52, 0x50, 0x6f, 0x6c, 0x69, 0x63, - 0x69, 0x65, 0x73, 0x22, 0x3e, 0x0a, 0x08, 0x4c, 0x73, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x12, - 0x16, 0x0a, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x69, 0x64, 0x49, 0x6e, - 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x73, 0x69, 0x64, 0x49, 0x6e, - 0x64, 0x65, 0x78, 0x22, 0x42, 0x0a, 0x06, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x12, 0x22, 0x0a, - 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0e, 0x2e, 0x70, 0x62, - 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, - 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x84, 0x02, 0x0a, 0x06, 0x4c, 0x73, 0x4c, 0x69, - 0x6e, 0x6b, 0x12, 0x24, 0x0a, 0x0d, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x52, 0x6f, 0x75, 0x74, 0x65, - 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6c, 0x6f, 0x63, 0x61, 0x6c, - 0x52, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, - 0x6c, 0x41, 0x73, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, - 0x6c, 0x41, 0x73, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x50, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x50, 0x12, 0x26, - 0x0a, 0x0e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x49, 0x44, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x52, 0x6f, - 0x75, 0x74, 0x65, 0x72, 0x49, 0x44, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, - 0x41, 0x73, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x72, 0x65, 0x6d, 0x6f, 0x74, - 0x65, 0x41, 0x73, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x49, 0x50, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x49, 0x50, - 0x12, 0x24, 0x0a, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x0a, 0x2e, 0x70, 0x62, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x52, 0x07, 0x6d, - 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x64, 0x6a, 0x53, 0x69, 0x64, - 0x18, 0x08, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x61, 0x64, 0x6a, 0x53, 0x69, 0x64, 0x22, 0xfe, - 0x01, 0x0a, 0x06, 0x4c, 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x73, 0x6e, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x61, 0x73, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x72, - 0x6f, 0x75, 0x74, 0x65, 0x72, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, - 0x6f, 0x75, 0x74, 0x65, 0x72, 0x49, 0x44, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x69, 0x73, 0x41, - 0x72, 0x65, 0x61, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x73, 0x69, - 0x73, 0x41, 0x72, 0x65, 0x61, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, - 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, - 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x72, 0x67, 0x62, 0x42, 0x65, 0x67, 0x69, 0x6e, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x73, 0x72, 0x67, 0x62, 0x42, 0x65, 0x67, 0x69, - 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x72, 0x67, 0x62, 0x45, 0x6e, 0x64, 0x18, 0x06, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x07, 0x73, 0x72, 0x67, 0x62, 0x45, 0x6e, 0x64, 0x12, 0x24, 0x0a, 0x07, 0x6c, - 0x73, 0x4c, 0x69, 0x6e, 0x6b, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x70, - 0x62, 0x2e, 0x4c, 0x73, 0x4c, 0x69, 0x6e, 0x6b, 0x52, 0x07, 0x6c, 0x73, 0x4c, 0x69, 0x6e, 0x6b, - 0x73, 0x12, 0x2c, 0x0a, 0x0a, 0x6c, 0x73, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x65, 0x73, 0x18, - 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x70, 0x62, 0x2e, 0x4c, 0x73, 0x50, 0x72, 0x65, - 0x66, 0x69, 0x78, 0x52, 0x0a, 0x6c, 0x73, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x65, 0x73, 0x22, - 0x43, 0x0a, 0x03, 0x54, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x24, - 0x0a, 0x07, 0x6c, 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x0a, 0x2e, 0x70, 0x62, 0x2e, 0x4c, 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x07, 0x6c, 0x73, 0x4e, - 0x6f, 0x64, 0x65, 0x73, 0x2a, 0x29, 0x0a, 0x0c, 0x53, 0x52, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, - 0x54, 0x79, 0x70, 0x65, 0x12, 0x0c, 0x0a, 0x08, 0x45, 0x58, 0x50, 0x4c, 0x49, 0x43, 0x49, 0x54, - 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x59, 0x4e, 0x41, 0x4d, 0x49, 0x43, 0x10, 0x01, 0x2a, - 0x36, 0x0a, 0x0a, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x54, 0x79, 0x70, 0x65, 0x12, 0x07, 0x0a, - 0x03, 0x49, 0x47, 0x50, 0x10, 0x00, 0x12, 0x06, 0x0a, 0x02, 0x54, 0x45, 0x10, 0x01, 0x12, 0x09, - 0x0a, 0x05, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x10, 0x02, 0x12, 0x0c, 0x0a, 0x08, 0x48, 0x4f, 0x50, - 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x10, 0x03, 0x32, 0xf8, 0x02, 0x0a, 0x0a, 0x50, 0x63, 0x65, 0x53, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x3e, 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x53, 0x52, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x17, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x53, 0x52, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x49, 0x6e, 0x70, 0x75, - 0x74, 0x1a, 0x11, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x22, 0x00, 0x12, 0x4e, 0x0a, 0x1e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x53, 0x52, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x57, 0x69, 0x74, 0x68, 0x6f, 0x75, 0x74, 0x4c, - 0x69, 0x6e, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x17, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x53, 0x52, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x49, 0x6e, 0x70, 0x75, - 0x74, 0x1a, 0x11, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x22, 0x00, 0x12, 0x3b, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, - 0x1a, 0x0f, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, - 0x74, 0x22, 0x00, 0x12, 0x3d, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x53, 0x52, 0x50, 0x6f, 0x6c, 0x69, - 0x63, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x10, - 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x52, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x4c, 0x69, 0x73, 0x74, - 0x22, 0x00, 0x12, 0x2b, 0x0a, 0x06, 0x47, 0x65, 0x74, 0x54, 0x65, 0x64, 0x12, 0x16, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, - 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x07, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x65, 0x64, 0x22, 0x00, 0x12, - 0x31, 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, - 0x12, 0x0b, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x1a, 0x11, 0x2e, - 0x70, 0x62, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x22, 0x00, 0x42, 0x21, 0x5a, 0x1f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, - 0x2f, 0x6e, 0x74, 0x74, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x6f, 0x6c, 0x61, 0x2f, 0x61, 0x70, 0x69, - 0x2f, 0x67, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x73, 0x69, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x69, + 0x64, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0c, 0x73, 0x69, 0x64, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x12, 0x1c, + 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x12, 0x1e, 0x0a, 0x0a, + 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x41, 0x64, 0x64, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0a, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x41, 0x64, 0x64, 0x72, 0x22, 0xff, 0x02, 0x0a, + 0x08, 0x53, 0x52, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x70, 0x63, 0x65, + 0x70, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x0f, 0x70, 0x63, 0x65, 0x70, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x41, + 0x64, 0x64, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x72, 0x63, 0x41, 0x64, 0x64, 0x72, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x73, 0x72, 0x63, 0x41, 0x64, 0x64, 0x72, 0x12, 0x18, 0x0a, + 0x07, 0x64, 0x73, 0x74, 0x41, 0x64, 0x64, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, + 0x64, 0x73, 0x74, 0x41, 0x64, 0x64, 0x72, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x72, 0x63, 0x52, 0x6f, + 0x75, 0x74, 0x65, 0x72, 0x49, 0x44, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x72, + 0x63, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x49, 0x44, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x73, 0x74, + 0x52, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x49, 0x44, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, + 0x64, 0x73, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x49, 0x44, 0x12, 0x14, 0x0a, 0x05, 0x63, + 0x6f, 0x6c, 0x6f, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x63, 0x6f, 0x6c, 0x6f, + 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, + 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x18, + 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x4e, 0x61, 0x6d, + 0x65, 0x12, 0x24, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x10, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x52, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x54, 0x79, 0x70, + 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x2d, 0x0a, 0x0b, 0x73, 0x65, 0x67, 0x6d, 0x65, + 0x6e, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x70, + 0x62, 0x2e, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x0b, 0x73, 0x65, 0x67, 0x6d, 0x65, + 0x6e, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, + 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0e, 0x2e, 0x70, 0x62, 0x2e, 0x4d, 0x65, 0x74, 0x72, + 0x69, 0x63, 0x54, 0x79, 0x70, 0x65, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x22, 0x51, + 0x0a, 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x52, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, + 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x28, 0x0a, 0x08, 0x53, 0x52, 0x50, 0x6f, 0x6c, 0x69, 0x63, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x52, 0x50, + 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x08, 0x53, 0x52, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, + 0x10, 0x0a, 0x03, 0x61, 0x73, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x61, 0x73, + 0x6e, 0x22, 0x51, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x52, 0x50, 0x6f, 0x6c, + 0x69, 0x63, 0x79, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x28, 0x0a, 0x08, 0x53, 0x52, 0x50, 0x6f, + 0x6c, 0x69, 0x63, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x70, 0x62, 0x2e, + 0x53, 0x52, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x08, 0x53, 0x52, 0x50, 0x6f, 0x6c, 0x69, + 0x63, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x73, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x03, 0x61, 0x73, 0x6e, 0x22, 0x2d, 0x0a, 0x0d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x73, 0x53, 0x75, 0x63, 0x63, 0x65, + 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x73, 0x53, 0x75, 0x63, 0x63, + 0x65, 0x73, 0x73, 0x22, 0x75, 0x0a, 0x07, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, + 0x0a, 0x04, 0x41, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x41, 0x64, + 0x64, 0x72, 0x12, 0x26, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x10, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x74, + 0x61, 0x74, 0x65, 0x52, 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x43, 0x61, + 0x70, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x43, 0x61, 0x70, 0x73, 0x12, 0x1a, + 0x0a, 0x08, 0x49, 0x73, 0x53, 0x79, 0x6e, 0x63, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x08, 0x49, 0x73, 0x53, 0x79, 0x6e, 0x63, 0x65, 0x64, 0x22, 0x36, 0x0a, 0x0b, 0x53, 0x65, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x08, 0x53, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x70, 0x62, + 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x73, 0x22, 0x3c, 0x0a, 0x0c, 0x53, 0x52, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x4c, 0x69, + 0x73, 0x74, 0x12, 0x2c, 0x0a, 0x0a, 0x53, 0x52, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x52, 0x50, 0x6f, + 0x6c, 0x69, 0x63, 0x79, 0x52, 0x0a, 0x53, 0x52, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, + 0x22, 0x3e, 0x0a, 0x08, 0x4c, 0x73, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x12, 0x16, 0x0a, 0x06, + 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x72, + 0x65, 0x66, 0x69, 0x78, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x69, 0x64, 0x49, 0x6e, 0x64, 0x65, 0x78, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x73, 0x69, 0x64, 0x49, 0x6e, 0x64, 0x65, 0x78, + 0x22, 0x42, 0x0a, 0x06, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x12, 0x22, 0x0a, 0x04, 0x74, 0x79, + 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0e, 0x2e, 0x70, 0x62, 0x2e, 0x4d, 0x65, + 0x74, 0x72, 0x69, 0x63, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, + 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x22, 0x84, 0x02, 0x0a, 0x06, 0x4c, 0x73, 0x4c, 0x69, 0x6e, 0x6b, 0x12, + 0x24, 0x0a, 0x0d, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x49, 0x44, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x52, 0x6f, 0x75, + 0x74, 0x65, 0x72, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x41, 0x73, + 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x41, 0x73, + 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x50, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x50, 0x12, 0x26, 0x0a, 0x0e, 0x72, + 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x49, 0x44, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, + 0x72, 0x49, 0x44, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x41, 0x73, 0x6e, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x41, 0x73, + 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x49, 0x50, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x49, 0x50, 0x12, 0x24, 0x0a, + 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0a, + 0x2e, 0x70, 0x62, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x52, 0x07, 0x6d, 0x65, 0x74, 0x72, + 0x69, 0x63, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x64, 0x6a, 0x53, 0x69, 0x64, 0x18, 0x08, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x06, 0x61, 0x64, 0x6a, 0x53, 0x69, 0x64, 0x22, 0xfe, 0x01, 0x0a, 0x06, + 0x4c, 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x73, 0x6e, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x03, 0x61, 0x73, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x6f, 0x75, 0x74, + 0x65, 0x72, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x6f, 0x75, 0x74, + 0x65, 0x72, 0x49, 0x44, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x69, 0x73, 0x41, 0x72, 0x65, 0x61, + 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x73, 0x69, 0x73, 0x41, 0x72, + 0x65, 0x61, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, + 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x72, 0x67, 0x62, 0x42, 0x65, 0x67, 0x69, 0x6e, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x09, 0x73, 0x72, 0x67, 0x62, 0x42, 0x65, 0x67, 0x69, 0x6e, 0x12, 0x18, + 0x0a, 0x07, 0x73, 0x72, 0x67, 0x62, 0x45, 0x6e, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x07, 0x73, 0x72, 0x67, 0x62, 0x45, 0x6e, 0x64, 0x12, 0x24, 0x0a, 0x07, 0x6c, 0x73, 0x4c, 0x69, + 0x6e, 0x6b, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x70, 0x62, 0x2e, 0x4c, + 0x73, 0x4c, 0x69, 0x6e, 0x6b, 0x52, 0x07, 0x6c, 0x73, 0x4c, 0x69, 0x6e, 0x6b, 0x73, 0x12, 0x2c, + 0x0a, 0x0a, 0x6c, 0x73, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x65, 0x73, 0x18, 0x08, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x70, 0x62, 0x2e, 0x4c, 0x73, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, + 0x52, 0x0a, 0x6c, 0x73, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x65, 0x73, 0x22, 0x43, 0x0a, 0x03, + 0x54, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x06, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x24, 0x0a, 0x07, 0x6c, + 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x70, + 0x62, 0x2e, 0x4c, 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x07, 0x6c, 0x73, 0x4e, 0x6f, 0x64, 0x65, + 0x73, 0x2a, 0x29, 0x0a, 0x0c, 0x53, 0x52, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x54, 0x79, 0x70, + 0x65, 0x12, 0x0c, 0x0a, 0x08, 0x45, 0x58, 0x50, 0x4c, 0x49, 0x43, 0x49, 0x54, 0x10, 0x00, 0x12, + 0x0b, 0x0a, 0x07, 0x44, 0x59, 0x4e, 0x41, 0x4d, 0x49, 0x43, 0x10, 0x01, 0x2a, 0x20, 0x0a, 0x0c, + 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x08, 0x0a, 0x04, + 0x44, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x06, 0x0a, 0x02, 0x55, 0x50, 0x10, 0x01, 0x2a, 0x36, + 0x0a, 0x0a, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x54, 0x79, 0x70, 0x65, 0x12, 0x07, 0x0a, 0x03, + 0x49, 0x47, 0x50, 0x10, 0x00, 0x12, 0x06, 0x0a, 0x02, 0x54, 0x45, 0x10, 0x01, 0x12, 0x09, 0x0a, + 0x05, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x10, 0x02, 0x12, 0x0c, 0x0a, 0x08, 0x48, 0x4f, 0x50, 0x43, + 0x4f, 0x55, 0x4e, 0x54, 0x10, 0x03, 0x32, 0x88, 0x04, 0x0a, 0x0a, 0x50, 0x63, 0x65, 0x53, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x3e, 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, + 0x52, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x17, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x53, 0x52, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x49, 0x6e, 0x70, 0x75, 0x74, + 0x1a, 0x11, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x22, 0x00, 0x12, 0x4e, 0x0a, 0x1e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, + 0x52, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x57, 0x69, 0x74, 0x68, 0x6f, 0x75, 0x74, 0x4c, 0x69, + 0x6e, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x17, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x53, 0x52, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x49, 0x6e, 0x70, 0x75, 0x74, + 0x1a, 0x11, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x22, 0x00, 0x12, 0x3e, 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, + 0x52, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x17, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x53, 0x52, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x49, 0x6e, 0x70, 0x75, 0x74, + 0x1a, 0x11, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x22, 0x00, 0x12, 0x4e, 0x0a, 0x1e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, + 0x52, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x57, 0x69, 0x74, 0x68, 0x6f, 0x75, 0x74, 0x4c, 0x69, + 0x6e, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x17, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x53, 0x52, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x49, 0x6e, 0x70, 0x75, 0x74, + 0x1a, 0x11, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x22, 0x00, 0x12, 0x3b, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, + 0x0f, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, + 0x22, 0x00, 0x12, 0x3d, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x53, 0x52, 0x50, 0x6f, 0x6c, 0x69, 0x63, + 0x79, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x10, 0x2e, + 0x70, 0x62, 0x2e, 0x53, 0x52, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x22, + 0x00, 0x12, 0x2b, 0x0a, 0x06, 0x47, 0x65, 0x74, 0x54, 0x65, 0x64, 0x12, 0x16, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, + 0x70, 0x74, 0x79, 0x1a, 0x07, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x65, 0x64, 0x22, 0x00, 0x12, 0x31, + 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, + 0x0b, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x1a, 0x11, 0x2e, 0x70, + 0x62, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, + 0x00, 0x42, 0x21, 0x5a, 0x1f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x6e, 0x74, 0x74, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x6f, 0x6c, 0x61, 0x2f, 0x61, 0x70, 0x69, 0x2f, + 0x67, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1053,54 +1230,62 @@ func file_pola_proto_rawDescGZIP() []byte { return file_pola_proto_rawDescData } -var file_pola_proto_enumTypes = make([]protoimpl.EnumInfo, 2) -var file_pola_proto_msgTypes = make([]protoimpl.MessageInfo, 12) +var file_pola_proto_enumTypes = make([]protoimpl.EnumInfo, 3) +var file_pola_proto_msgTypes = make([]protoimpl.MessageInfo, 13) var file_pola_proto_goTypes = []interface{}{ (SRPolicyType)(0), // 0: pb.SRPolicyType - (MetricType)(0), // 1: pb.MetricType - (*Segment)(nil), // 2: pb.Segment - (*SRPolicy)(nil), // 3: pb.SRPolicy - (*CreateSRPolicyInput)(nil), // 4: pb.CreateSRPolicyInput - (*RequestStatus)(nil), // 5: pb.RequestStatus - (*Session)(nil), // 6: pb.Session - (*SessionList)(nil), // 7: pb.SessionList - (*SRPolicyList)(nil), // 8: pb.SRPolicyList - (*LsPrefix)(nil), // 9: pb.LsPrefix - (*Metric)(nil), // 10: pb.Metric - (*LsLink)(nil), // 11: pb.LsLink - (*LsNode)(nil), // 12: pb.LsNode - (*Ted)(nil), // 13: pb.Ted - (*emptypb.Empty)(nil), // 14: google.protobuf.Empty + (SessionState)(0), // 1: pb.SessionState + (MetricType)(0), // 2: pb.MetricType + (*Segment)(nil), // 3: pb.Segment + (*SRPolicy)(nil), // 4: pb.SRPolicy + (*CreateSRPolicyInput)(nil), // 5: pb.CreateSRPolicyInput + (*DeleteSRPolicyInput)(nil), // 6: pb.DeleteSRPolicyInput + (*RequestStatus)(nil), // 7: pb.RequestStatus + (*Session)(nil), // 8: pb.Session + (*SessionList)(nil), // 9: pb.SessionList + (*SRPolicyList)(nil), // 10: pb.SRPolicyList + (*LsPrefix)(nil), // 11: pb.LsPrefix + (*Metric)(nil), // 12: pb.Metric + (*LsLink)(nil), // 13: pb.LsLink + (*LsNode)(nil), // 14: pb.LsNode + (*Ted)(nil), // 15: pb.Ted + (*empty.Empty)(nil), // 16: google.protobuf.Empty } var file_pola_proto_depIdxs = []int32{ 0, // 0: pb.SRPolicy.type:type_name -> pb.SRPolicyType - 2, // 1: pb.SRPolicy.segmentList:type_name -> pb.Segment - 1, // 2: pb.SRPolicy.metric:type_name -> pb.MetricType - 3, // 3: pb.CreateSRPolicyInput.SRPolicy:type_name -> pb.SRPolicy - 6, // 4: pb.SessionList.Sessions:type_name -> pb.Session - 3, // 5: pb.SRPolicyList.SRPolicies:type_name -> pb.SRPolicy - 1, // 6: pb.Metric.type:type_name -> pb.MetricType - 10, // 7: pb.LsLink.metrics:type_name -> pb.Metric - 11, // 8: pb.LsNode.lsLinks:type_name -> pb.LsLink - 9, // 9: pb.LsNode.lsPrefixes:type_name -> pb.LsPrefix - 12, // 10: pb.Ted.lsNodes:type_name -> pb.LsNode - 4, // 11: pb.PceService.CreateSRPolicy:input_type -> pb.CreateSRPolicyInput - 4, // 12: pb.PceService.CreateSRPolicyWithoutLinkState:input_type -> pb.CreateSRPolicyInput - 14, // 13: pb.PceService.GetSessionList:input_type -> google.protobuf.Empty - 14, // 14: pb.PceService.GetSRPolicyList:input_type -> google.protobuf.Empty - 14, // 15: pb.PceService.GetTed:input_type -> google.protobuf.Empty - 6, // 16: pb.PceService.DeleteSession:input_type -> pb.Session - 5, // 17: pb.PceService.CreateSRPolicy:output_type -> pb.RequestStatus - 5, // 18: pb.PceService.CreateSRPolicyWithoutLinkState:output_type -> pb.RequestStatus - 7, // 19: pb.PceService.GetSessionList:output_type -> pb.SessionList - 8, // 20: pb.PceService.GetSRPolicyList:output_type -> pb.SRPolicyList - 13, // 21: pb.PceService.GetTed:output_type -> pb.Ted - 5, // 22: pb.PceService.DeleteSession:output_type -> pb.RequestStatus - 17, // [17:23] is the sub-list for method output_type - 11, // [11:17] is the sub-list for method input_type - 11, // [11:11] is the sub-list for extension type_name - 11, // [11:11] is the sub-list for extension extendee - 0, // [0:11] is the sub-list for field type_name + 3, // 1: pb.SRPolicy.segmentList:type_name -> pb.Segment + 2, // 2: pb.SRPolicy.metric:type_name -> pb.MetricType + 4, // 3: pb.CreateSRPolicyInput.SRPolicy:type_name -> pb.SRPolicy + 4, // 4: pb.DeleteSRPolicyInput.SRPolicy:type_name -> pb.SRPolicy + 1, // 5: pb.Session.State:type_name -> pb.SessionState + 8, // 6: pb.SessionList.Sessions:type_name -> pb.Session + 4, // 7: pb.SRPolicyList.SRPolicies:type_name -> pb.SRPolicy + 2, // 8: pb.Metric.type:type_name -> pb.MetricType + 12, // 9: pb.LsLink.metrics:type_name -> pb.Metric + 13, // 10: pb.LsNode.lsLinks:type_name -> pb.LsLink + 11, // 11: pb.LsNode.lsPrefixes:type_name -> pb.LsPrefix + 14, // 12: pb.Ted.lsNodes:type_name -> pb.LsNode + 5, // 13: pb.PceService.CreateSRPolicy:input_type -> pb.CreateSRPolicyInput + 5, // 14: pb.PceService.CreateSRPolicyWithoutLinkState:input_type -> pb.CreateSRPolicyInput + 6, // 15: pb.PceService.DeleteSRPolicy:input_type -> pb.DeleteSRPolicyInput + 6, // 16: pb.PceService.DeleteSRPolicyWithoutLinkState:input_type -> pb.DeleteSRPolicyInput + 16, // 17: pb.PceService.GetSessionList:input_type -> google.protobuf.Empty + 16, // 18: pb.PceService.GetSRPolicyList:input_type -> google.protobuf.Empty + 16, // 19: pb.PceService.GetTed:input_type -> google.protobuf.Empty + 8, // 20: pb.PceService.DeleteSession:input_type -> pb.Session + 7, // 21: pb.PceService.CreateSRPolicy:output_type -> pb.RequestStatus + 7, // 22: pb.PceService.CreateSRPolicyWithoutLinkState:output_type -> pb.RequestStatus + 7, // 23: pb.PceService.DeleteSRPolicy:output_type -> pb.RequestStatus + 7, // 24: pb.PceService.DeleteSRPolicyWithoutLinkState:output_type -> pb.RequestStatus + 9, // 25: pb.PceService.GetSessionList:output_type -> pb.SessionList + 10, // 26: pb.PceService.GetSRPolicyList:output_type -> pb.SRPolicyList + 15, // 27: pb.PceService.GetTed:output_type -> pb.Ted + 7, // 28: pb.PceService.DeleteSession:output_type -> pb.RequestStatus + 21, // [21:29] is the sub-list for method output_type + 13, // [13:21] is the sub-list for method input_type + 13, // [13:13] is the sub-list for extension type_name + 13, // [13:13] is the sub-list for extension extendee + 0, // [0:13] is the sub-list for field type_name } func init() { file_pola_proto_init() } @@ -1146,7 +1331,7 @@ func file_pola_proto_init() { } } file_pola_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RequestStatus); i { + switch v := v.(*DeleteSRPolicyInput); i { case 0: return &v.state case 1: @@ -1158,7 +1343,7 @@ func file_pola_proto_init() { } } file_pola_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Session); i { + switch v := v.(*RequestStatus); i { case 0: return &v.state case 1: @@ -1170,7 +1355,7 @@ func file_pola_proto_init() { } } file_pola_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SessionList); i { + switch v := v.(*Session); i { case 0: return &v.state case 1: @@ -1182,7 +1367,7 @@ func file_pola_proto_init() { } } file_pola_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SRPolicyList); i { + switch v := v.(*SessionList); i { case 0: return &v.state case 1: @@ -1194,7 +1379,7 @@ func file_pola_proto_init() { } } file_pola_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*LsPrefix); i { + switch v := v.(*SRPolicyList); i { case 0: return &v.state case 1: @@ -1206,7 +1391,7 @@ func file_pola_proto_init() { } } file_pola_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Metric); i { + switch v := v.(*LsPrefix); i { case 0: return &v.state case 1: @@ -1218,7 +1403,7 @@ func file_pola_proto_init() { } } file_pola_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*LsLink); i { + switch v := v.(*Metric); i { case 0: return &v.state case 1: @@ -1230,7 +1415,7 @@ func file_pola_proto_init() { } } file_pola_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*LsNode); i { + switch v := v.(*LsLink); i { case 0: return &v.state case 1: @@ -1242,6 +1427,18 @@ func file_pola_proto_init() { } } file_pola_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LsNode); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_pola_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Ted); i { case 0: return &v.state @@ -1259,8 +1456,8 @@ func file_pola_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_pola_proto_rawDesc, - NumEnums: 2, - NumMessages: 12, + NumEnums: 3, + NumMessages: 13, NumExtensions: 0, NumServices: 1, }, diff --git a/api/grpc/pola.proto b/api/grpc/pola.proto index 634ad52..3b91ed9 100644 --- a/api/grpc/pola.proto +++ b/api/grpc/pola.proto @@ -16,6 +16,10 @@ service PceService { rpc CreateSRPolicyWithoutLinkState (CreateSRPolicyInput) returns (RequestStatus) {}; + rpc DeleteSRPolicy (DeleteSRPolicyInput) returns (RequestStatus) {}; + + rpc DeleteSRPolicyWithoutLinkState (DeleteSRPolicyInput) returns (RequestStatus) {}; + rpc GetSessionList (google.protobuf.Empty) returns (SessionList) {}; rpc GetSRPolicyList (google.protobuf.Empty) returns (SRPolicyList) {}; @@ -27,6 +31,9 @@ service PceService { message Segment { string sid = 1; + string sidStructure = 2; + string localAddr = 3; + string remoteAddr = 4; } enum SRPolicyType { @@ -51,14 +58,27 @@ message SRPolicy { message CreateSRPolicyInput { SRPolicy SRPolicy = 1; uint32 asn = 2; -} +} + +message DeleteSRPolicyInput { + SRPolicy SRPolicy = 1; + uint32 asn = 2; +} message RequestStatus { bool isSuccess = 1; } +enum SessionState { + DOWN = 0; + UP = 1; +} + message Session { bytes Addr = 1; + SessionState State = 2; + repeated string Caps = 3; + bool IsSynced = 4; } message SessionList { diff --git a/api/grpc/pola_grpc.pb.go b/api/grpc/pola_grpc.pb.go index 3dd6446..8523689 100644 --- a/api/grpc/pola_grpc.pb.go +++ b/api/grpc/pola_grpc.pb.go @@ -1,13 +1,22 @@ +// Copyright (c) 2022 NTT Communications Corporation +// +// This software is released under the MIT License. +// see https://github.com/nttcom/pola/blob/main/LICENSE + // Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.3.0 +// - protoc v3.12.4 +// source: pola.proto package grpc import ( context "context" + empty "github.com/golang/protobuf/ptypes/empty" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" - emptypb "google.golang.org/protobuf/types/known/emptypb" ) // This is a compile-time assertion to ensure that this generated file @@ -15,15 +24,28 @@ import ( // Requires gRPC-Go v1.32.0 or later. const _ = grpc.SupportPackageIsVersion7 +const ( + PceService_CreateSRPolicy_FullMethodName = "/pb.PceService/CreateSRPolicy" + PceService_CreateSRPolicyWithoutLinkState_FullMethodName = "/pb.PceService/CreateSRPolicyWithoutLinkState" + PceService_DeleteSRPolicy_FullMethodName = "/pb.PceService/DeleteSRPolicy" + PceService_DeleteSRPolicyWithoutLinkState_FullMethodName = "/pb.PceService/DeleteSRPolicyWithoutLinkState" + PceService_GetSessionList_FullMethodName = "/pb.PceService/GetSessionList" + PceService_GetSRPolicyList_FullMethodName = "/pb.PceService/GetSRPolicyList" + PceService_GetTed_FullMethodName = "/pb.PceService/GetTed" + PceService_DeleteSession_FullMethodName = "/pb.PceService/DeleteSession" +) + // PceServiceClient is the client API for PceService service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. type PceServiceClient interface { CreateSRPolicy(ctx context.Context, in *CreateSRPolicyInput, opts ...grpc.CallOption) (*RequestStatus, error) CreateSRPolicyWithoutLinkState(ctx context.Context, in *CreateSRPolicyInput, opts ...grpc.CallOption) (*RequestStatus, error) - GetSessionList(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*SessionList, error) - GetSRPolicyList(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*SRPolicyList, error) - GetTed(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*Ted, error) + DeleteSRPolicy(ctx context.Context, in *DeleteSRPolicyInput, opts ...grpc.CallOption) (*RequestStatus, error) + DeleteSRPolicyWithoutLinkState(ctx context.Context, in *DeleteSRPolicyInput, opts ...grpc.CallOption) (*RequestStatus, error) + GetSessionList(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*SessionList, error) + GetSRPolicyList(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*SRPolicyList, error) + GetTed(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*Ted, error) DeleteSession(ctx context.Context, in *Session, opts ...grpc.CallOption) (*RequestStatus, error) } @@ -37,7 +59,7 @@ func NewPceServiceClient(cc grpc.ClientConnInterface) PceServiceClient { func (c *pceServiceClient) CreateSRPolicy(ctx context.Context, in *CreateSRPolicyInput, opts ...grpc.CallOption) (*RequestStatus, error) { out := new(RequestStatus) - err := c.cc.Invoke(ctx, "/pb.PceService/CreateSRPolicy", in, out, opts...) + err := c.cc.Invoke(ctx, PceService_CreateSRPolicy_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -46,34 +68,52 @@ func (c *pceServiceClient) CreateSRPolicy(ctx context.Context, in *CreateSRPolic func (c *pceServiceClient) CreateSRPolicyWithoutLinkState(ctx context.Context, in *CreateSRPolicyInput, opts ...grpc.CallOption) (*RequestStatus, error) { out := new(RequestStatus) - err := c.cc.Invoke(ctx, "/pb.PceService/CreateSRPolicyWithoutLinkState", in, out, opts...) + err := c.cc.Invoke(ctx, PceService_CreateSRPolicyWithoutLinkState_FullMethodName, in, out, opts...) if err != nil { return nil, err } return out, nil } -func (c *pceServiceClient) GetSessionList(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*SessionList, error) { +func (c *pceServiceClient) DeleteSRPolicy(ctx context.Context, in *DeleteSRPolicyInput, opts ...grpc.CallOption) (*RequestStatus, error) { + out := new(RequestStatus) + err := c.cc.Invoke(ctx, PceService_DeleteSRPolicy_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *pceServiceClient) DeleteSRPolicyWithoutLinkState(ctx context.Context, in *DeleteSRPolicyInput, opts ...grpc.CallOption) (*RequestStatus, error) { + out := new(RequestStatus) + err := c.cc.Invoke(ctx, PceService_DeleteSRPolicyWithoutLinkState_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *pceServiceClient) GetSessionList(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*SessionList, error) { out := new(SessionList) - err := c.cc.Invoke(ctx, "/pb.PceService/GetSessionList", in, out, opts...) + err := c.cc.Invoke(ctx, PceService_GetSessionList_FullMethodName, in, out, opts...) if err != nil { return nil, err } return out, nil } -func (c *pceServiceClient) GetSRPolicyList(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*SRPolicyList, error) { +func (c *pceServiceClient) GetSRPolicyList(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*SRPolicyList, error) { out := new(SRPolicyList) - err := c.cc.Invoke(ctx, "/pb.PceService/GetSRPolicyList", in, out, opts...) + err := c.cc.Invoke(ctx, PceService_GetSRPolicyList_FullMethodName, in, out, opts...) if err != nil { return nil, err } return out, nil } -func (c *pceServiceClient) GetTed(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*Ted, error) { +func (c *pceServiceClient) GetTed(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*Ted, error) { out := new(Ted) - err := c.cc.Invoke(ctx, "/pb.PceService/GetTed", in, out, opts...) + err := c.cc.Invoke(ctx, PceService_GetTed_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -82,7 +122,7 @@ func (c *pceServiceClient) GetTed(ctx context.Context, in *emptypb.Empty, opts . func (c *pceServiceClient) DeleteSession(ctx context.Context, in *Session, opts ...grpc.CallOption) (*RequestStatus, error) { out := new(RequestStatus) - err := c.cc.Invoke(ctx, "/pb.PceService/DeleteSession", in, out, opts...) + err := c.cc.Invoke(ctx, PceService_DeleteSession_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -95,9 +135,11 @@ func (c *pceServiceClient) DeleteSession(ctx context.Context, in *Session, opts type PceServiceServer interface { CreateSRPolicy(context.Context, *CreateSRPolicyInput) (*RequestStatus, error) CreateSRPolicyWithoutLinkState(context.Context, *CreateSRPolicyInput) (*RequestStatus, error) - GetSessionList(context.Context, *emptypb.Empty) (*SessionList, error) - GetSRPolicyList(context.Context, *emptypb.Empty) (*SRPolicyList, error) - GetTed(context.Context, *emptypb.Empty) (*Ted, error) + DeleteSRPolicy(context.Context, *DeleteSRPolicyInput) (*RequestStatus, error) + DeleteSRPolicyWithoutLinkState(context.Context, *DeleteSRPolicyInput) (*RequestStatus, error) + GetSessionList(context.Context, *empty.Empty) (*SessionList, error) + GetSRPolicyList(context.Context, *empty.Empty) (*SRPolicyList, error) + GetTed(context.Context, *empty.Empty) (*Ted, error) DeleteSession(context.Context, *Session) (*RequestStatus, error) mustEmbedUnimplementedPceServiceServer() } @@ -112,13 +154,19 @@ func (UnimplementedPceServiceServer) CreateSRPolicy(context.Context, *CreateSRPo func (UnimplementedPceServiceServer) CreateSRPolicyWithoutLinkState(context.Context, *CreateSRPolicyInput) (*RequestStatus, error) { return nil, status.Errorf(codes.Unimplemented, "method CreateSRPolicyWithoutLinkState not implemented") } -func (UnimplementedPceServiceServer) GetSessionList(context.Context, *emptypb.Empty) (*SessionList, error) { +func (UnimplementedPceServiceServer) DeleteSRPolicy(context.Context, *DeleteSRPolicyInput) (*RequestStatus, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteSRPolicy not implemented") +} +func (UnimplementedPceServiceServer) DeleteSRPolicyWithoutLinkState(context.Context, *DeleteSRPolicyInput) (*RequestStatus, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteSRPolicyWithoutLinkState not implemented") +} +func (UnimplementedPceServiceServer) GetSessionList(context.Context, *empty.Empty) (*SessionList, error) { return nil, status.Errorf(codes.Unimplemented, "method GetSessionList not implemented") } -func (UnimplementedPceServiceServer) GetSRPolicyList(context.Context, *emptypb.Empty) (*SRPolicyList, error) { +func (UnimplementedPceServiceServer) GetSRPolicyList(context.Context, *empty.Empty) (*SRPolicyList, error) { return nil, status.Errorf(codes.Unimplemented, "method GetSRPolicyList not implemented") } -func (UnimplementedPceServiceServer) GetTed(context.Context, *emptypb.Empty) (*Ted, error) { +func (UnimplementedPceServiceServer) GetTed(context.Context, *empty.Empty) (*Ted, error) { return nil, status.Errorf(codes.Unimplemented, "method GetTed not implemented") } func (UnimplementedPceServiceServer) DeleteSession(context.Context, *Session) (*RequestStatus, error) { @@ -147,7 +195,7 @@ func _PceService_CreateSRPolicy_Handler(srv interface{}, ctx context.Context, de } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/pb.PceService/CreateSRPolicy", + FullMethod: PceService_CreateSRPolicy_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(PceServiceServer).CreateSRPolicy(ctx, req.(*CreateSRPolicyInput)) @@ -165,7 +213,7 @@ func _PceService_CreateSRPolicyWithoutLinkState_Handler(srv interface{}, ctx con } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/pb.PceService/CreateSRPolicyWithoutLinkState", + FullMethod: PceService_CreateSRPolicyWithoutLinkState_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(PceServiceServer).CreateSRPolicyWithoutLinkState(ctx, req.(*CreateSRPolicyInput)) @@ -173,8 +221,44 @@ func _PceService_CreateSRPolicyWithoutLinkState_Handler(srv interface{}, ctx con return interceptor(ctx, in, info, handler) } +func _PceService_DeleteSRPolicy_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteSRPolicyInput) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(PceServiceServer).DeleteSRPolicy(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: PceService_DeleteSRPolicy_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(PceServiceServer).DeleteSRPolicy(ctx, req.(*DeleteSRPolicyInput)) + } + return interceptor(ctx, in, info, handler) +} + +func _PceService_DeleteSRPolicyWithoutLinkState_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteSRPolicyInput) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(PceServiceServer).DeleteSRPolicyWithoutLinkState(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: PceService_DeleteSRPolicyWithoutLinkState_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(PceServiceServer).DeleteSRPolicyWithoutLinkState(ctx, req.(*DeleteSRPolicyInput)) + } + return interceptor(ctx, in, info, handler) +} + func _PceService_GetSessionList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(emptypb.Empty) + in := new(empty.Empty) if err := dec(in); err != nil { return nil, err } @@ -183,16 +267,16 @@ func _PceService_GetSessionList_Handler(srv interface{}, ctx context.Context, de } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/pb.PceService/GetSessionList", + FullMethod: PceService_GetSessionList_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(PceServiceServer).GetSessionList(ctx, req.(*emptypb.Empty)) + return srv.(PceServiceServer).GetSessionList(ctx, req.(*empty.Empty)) } return interceptor(ctx, in, info, handler) } func _PceService_GetSRPolicyList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(emptypb.Empty) + in := new(empty.Empty) if err := dec(in); err != nil { return nil, err } @@ -201,16 +285,16 @@ func _PceService_GetSRPolicyList_Handler(srv interface{}, ctx context.Context, d } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/pb.PceService/GetSRPolicyList", + FullMethod: PceService_GetSRPolicyList_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(PceServiceServer).GetSRPolicyList(ctx, req.(*emptypb.Empty)) + return srv.(PceServiceServer).GetSRPolicyList(ctx, req.(*empty.Empty)) } return interceptor(ctx, in, info, handler) } func _PceService_GetTed_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(emptypb.Empty) + in := new(empty.Empty) if err := dec(in); err != nil { return nil, err } @@ -219,10 +303,10 @@ func _PceService_GetTed_Handler(srv interface{}, ctx context.Context, dec func(i } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/pb.PceService/GetTed", + FullMethod: PceService_GetTed_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(PceServiceServer).GetTed(ctx, req.(*emptypb.Empty)) + return srv.(PceServiceServer).GetTed(ctx, req.(*empty.Empty)) } return interceptor(ctx, in, info, handler) } @@ -237,7 +321,7 @@ func _PceService_DeleteSession_Handler(srv interface{}, ctx context.Context, dec } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/pb.PceService/DeleteSession", + FullMethod: PceService_DeleteSession_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(PceServiceServer).DeleteSession(ctx, req.(*Session)) @@ -260,6 +344,14 @@ var PceService_ServiceDesc = grpc.ServiceDesc{ MethodName: "CreateSRPolicyWithoutLinkState", Handler: _PceService_CreateSRPolicyWithoutLinkState_Handler, }, + { + MethodName: "DeleteSRPolicy", + Handler: _PceService_DeleteSRPolicy_Handler, + }, + { + MethodName: "DeleteSRPolicyWithoutLinkState", + Handler: _PceService_DeleteSRPolicyWithoutLinkState_Handler, + }, { MethodName: "GetSessionList", Handler: _PceService_GetSessionList_Handler, diff --git a/cmd/pola/README.md b/cmd/pola/README.md index 390fcba..5db54f4 100644 --- a/cmd/pola/README.md +++ b/cmd/pola/README.md @@ -1,5 +1,31 @@ # Pola CLI Tool +## Instllation + +### From Go Package + +```bash +$ go install github.com/nttcom/pola/cmd/pola@latest +``` + +### From Source + +**Getting the Source** + +```bash +$ git clone https://github.com/nttcom/pola.git +``` + +**Build & install** + +```bash +$ cd pola +$ go install ./cmd/pola + +# or, install with daemon +$ go install ./... +``` + ## Command Reference ### pola session \[-j\] @@ -7,18 +33,29 @@ Displays the peer addresses of the active session. JSON formatted response ```json -{ - "sessions": [ - { - "address": "192.0.2.1", - "status": "active", - }, - { - "address": "192.0.2.2", - "status": "active", - }, +[ + { + "Addr": "192.0.2.1", + "State": "UP", + "Caps": [ + "Stateful", + "Update", + "Initiate", + "SR-TE", ] -} + }, + { + "Addr": "192.0.2.2", + "State": "UP", + "Caps": [ + "Stateful", + "Update", + "Initiate", + "SR-TE", + "SRv6-TE" + ] + } +] ``` ### pola session del *Address* \[-j\] @@ -123,7 +160,7 @@ JSON formatted response ### pola sr-policy add -f _filepath_ -Create a new SR Policy using TED +Create a new SR Policy **using TED** #### Case: Dynamic Path calculate @@ -174,21 +211,33 @@ JSON formatted response ### pola sr-policy add -f _filepath_ --no-link-state -Create a new SR Policy without using TED +Create a new SR Policy **without using TED** + +Should write the `localAddress` (and `remoteAddr` if Adj-SID) of each sid for creation of Nai + +See [JSON shema](schemas/polad_config.json) for input details. YAML input format ```yaml srPolicy: - pcepSessionAddr: 192.0.2.1 - srcAddr: 192.0.2.1 - dstAddr: 192.0.2.2 - name: name + pcepSessionAddr: "2001:0db8::1" + srcAddr: "2001:0db8::1" + dstAddr: "2001:0db8::2" + name: "policy-name" color: 100 segmentList: - - sid: 16003 - nai: 192.0.2.3 - - sid: 16002 - nai: 192.0.2.2 + - sid: "2001:0db8:1005::" + localAddr: "2001:0db8::5" + sidStructure: "32,16,0,80" + - sid: "2001:0db8:1006::" + localAddr: "2001:0db8::6" + sidStructure: "32,16,0,80" + - sid: "2001:0db8:1005::" + localAddr: "2001:0db8::5" + sidStructure: "32,16,0,80" + - sid: "2001:0db8:1006::" + localAddr: "2001:0db8::6" + sidStructure: "32,16,0,80" ``` json formatted response diff --git a/cmd/pola/docs/schemas/policy.json b/cmd/pola/docs/schemas/policy.json new file mode 100644 index 0000000..17114a4 --- /dev/null +++ b/cmd/pola/docs/schemas/policy.json @@ -0,0 +1,68 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "srPolicy": { + "type": "object", + "properties": { + "pcepSessionAddr": { + "type": "string", + "oneOf": [ + { + "format": "ipv4" + }, + { + "format": "ipv6" + } + ] + }, + "srcAddr": { + "type": "string", + "oneOf": [ + { + "format": "ipv4" + }, + { + "format": "ipv6" + } + ] + }, + "dstAddr": { + "type": "string", + "oneOf": [ + { + "format": "ipv4" + }, + { + "format": "ipv6" + } + ] + }, + "name": { + "type": "string" + }, + "color": { + "type": "integer" + }, + "segmentList": { + "type": "array", + "items": { + "$ref": "segment.json" + } + } + }, + "required": [ + "pcepSessionAddr", + "srcAddr", + "dstAddr", + "name", + "color", + "segmentList" + ] + } + }, + "required": [ + "srPolicy" + ], + "additionalProperties": false +} diff --git a/cmd/pola/docs/schemas/segment.json b/cmd/pola/docs/schemas/segment.json new file mode 100644 index 0000000..0caebf9 --- /dev/null +++ b/cmd/pola/docs/schemas/segment.json @@ -0,0 +1,56 @@ +{ + "type": "object", + "properties": { + "sid": { + "oneOf": [ + { + "type": "string", + "oneOf": [ + { + "format": "ipv4" + }, + { + "format": "ipv6" + } + ], + "$comment": "SRv6 format" + }, + { + "type": "integer", + "$comment": "SR-MPLS format" + } + ] + }, + "localAddr": { + "type": "string", + "oneOf": [ + { + "format": "ipv4" + }, + { + "format": "ipv6" + } + ] + }, + "remoteAddr": { + "type": "string", + "oneOf": [ + { + "format": "ipv4" + }, + { + "format": "ipv6" + } + ] + }, + "sidStructure": { + "type": "string", + "pattern": "^[0-9]+,[0-9]+,[0-9]+,[0-9]+$", + "$comment": ",,," + } + }, + "required": [ + "sid" + ], + "additionalProperties": false +} diff --git a/cmd/pola/grpc_client.go b/cmd/pola/grpc/grpc_client.go similarity index 83% rename from cmd/pola/grpc_client.go rename to cmd/pola/grpc/grpc_client.go index 8e5a3bd..ebd115f 100644 --- a/cmd/pola/grpc_client.go +++ b/cmd/pola/grpc/grpc_client.go @@ -3,7 +3,7 @@ // This software is released under the MIT License. // see https://github.com/nttcom/pola/blob/main/LICENSE -package main +package grpc import ( "context" @@ -20,7 +20,14 @@ func withTimeout() (context.Context, context.CancelFunc) { return context.WithTimeout(context.Background(), time.Second) } -func getSessionAddrList(client pb.PceServiceClient) ([]netip.Addr, error) { +type Session struct { + Addr netip.Addr + State string + Caps []string + IsSynced bool +} + +func GetSessions(client pb.PceServiceClient) ([]Session, error) { ctx, cancel := withTimeout() defer cancel() @@ -29,16 +36,23 @@ func getSessionAddrList(client pb.PceServiceClient) ([]netip.Addr, error) { return nil, err } - var addrs []netip.Addr - for _, ss := range ret.GetSessions() { - addr, _ := netip.AddrFromSlice(ss.GetAddr()) - addrs = append(addrs, addr) + var sessions []Session + for _, pbss := range ret.GetSessions() { + addr, _ := netip.AddrFromSlice(pbss.GetAddr()) + ss := Session{ + Addr: addr, + State: pbss.State.String(), + Caps: []string{}, + IsSynced: pbss.GetIsSynced(), + } + ss.Caps = append(ss.Caps, pbss.GetCaps()...) + sessions = append(sessions, ss) } - return addrs, nil + return sessions, nil } -func deleteSession(client pb.PceServiceClient, session *pb.Session) error { +func DeleteSession(client pb.PceServiceClient, session *pb.Session) error { ctx, cancel := withTimeout() defer cancel() _, err := client.DeleteSession(ctx, session) @@ -48,7 +62,7 @@ func deleteSession(client pb.PceServiceClient, session *pb.Session) error { return nil } -func getSRPolicyList(client pb.PceServiceClient) (map[netip.Addr][]table.SRPolicy, error) { +func GetSRPolicyList(client pb.PceServiceClient) (map[netip.Addr][]table.SRPolicy, error) { ctx, cancel := withTimeout() defer cancel() @@ -85,7 +99,7 @@ func getSRPolicyList(client pb.PceServiceClient) (map[netip.Addr][]table.SRPolic return policies, nil } -func createSRPolicy(client pb.PceServiceClient, input *pb.CreateSRPolicyInput) error { +func CreateSRPolicy(client pb.PceServiceClient, input *pb.CreateSRPolicyInput) error { ctx, cancel := withTimeout() defer cancel() @@ -93,7 +107,7 @@ func createSRPolicy(client pb.PceServiceClient, input *pb.CreateSRPolicyInput) e return err } -func createSRPolicyWithoutLinkState(client pb.PceServiceClient, input *pb.CreateSRPolicyInput) error { +func CreateSRPolicyWithoutLinkState(client pb.PceServiceClient, input *pb.CreateSRPolicyInput) error { ctx, cancel := withTimeout() defer cancel() @@ -101,7 +115,15 @@ func createSRPolicyWithoutLinkState(client pb.PceServiceClient, input *pb.Create return err } -func getTed(client pb.PceServiceClient) (*table.LsTed, error) { +func DeleteSRPolicy(client pb.PceServiceClient, input *pb.DeleteSRPolicyInput) error { + ctx, cancel := withTimeout() + defer cancel() + + _, err := client.DeleteSRPolicy(ctx, input) + return err +} + +func GetTed(client pb.PceServiceClient) (*table.LsTed, error) { ctx, cancel := withTimeout() defer cancel() diff --git a/cmd/pola/session.go b/cmd/pola/session.go index e7adcff..9e43707 100644 --- a/cmd/pola/session.go +++ b/cmd/pola/session.go @@ -9,6 +9,7 @@ import ( "encoding/json" "fmt" + "github.com/nttcom/pola/cmd/pola/grpc" "github.com/spf13/cobra" ) @@ -28,32 +29,26 @@ func newSessionCmd() *cobra.Command { } func showSession(jsonFlag bool) error { - sessionAddrList, err := getSessionAddrList(client) + sessions, err := grpc.GetSessions(client) + if err != nil { return err } if jsonFlag { // Output JSON format - peerAddrs := make([]map[string]string, 0, len(sessionAddrList)) - for _, peerAddr := range sessionAddrList { - peerAddrs = append(peerAddrs, map[string]string{ - "address": peerAddr.String(), - "status": "active", - }) - } - outputMap := map[string]interface{}{ - "sessions": peerAddrs, - } - outputJSON, err := json.Marshal(outputMap) + outputJSON, err := json.Marshal(sessions) if err != nil { return err } fmt.Println(string(outputJSON)) } else { // Output user-friendly format - for i, peerAddr := range sessionAddrList { - fmt.Printf("sessionAddr(%d): %s\n", i, peerAddr.String()) + for i, ss := range sessions { + fmt.Printf("sessionAddr(%d): %s\n", i, ss.Addr.String()) + fmt.Printf(" State: %s\n", ss.State) + fmt.Printf(" Capabilities: %s\n", ss.Caps) + fmt.Printf(" IsSynced: %t\n", ss.IsSynced) } } return nil diff --git a/cmd/pola/session_del.go b/cmd/pola/session_del.go index 94acd18..357a03a 100644 --- a/cmd/pola/session_del.go +++ b/cmd/pola/session_del.go @@ -10,6 +10,7 @@ import ( "net/netip" pb "github.com/nttcom/pola/api/grpc" + "github.com/nttcom/pola/cmd/pola/grpc" "github.com/spf13/cobra" ) @@ -37,7 +38,7 @@ func delSession(session netip.Addr, jsonFlag bool) error { ss := &pb.Session{ Addr: session.AsSlice(), } - err := deleteSession(client, ss) + err := grpc.DeleteSession(client, ss) if err != nil { return err } diff --git a/cmd/pola/sr_policy.go b/cmd/pola/sr_policy.go index 02fb387..5fa69c7 100644 --- a/cmd/pola/sr_policy.go +++ b/cmd/pola/sr_policy.go @@ -17,6 +17,6 @@ func newSRPolicyCmd() *cobra.Command { }, Args: cobra.NoArgs, } - cmd.AddCommand(newSRPolicyListCmd(), newSRPolicyAddCmd()) + cmd.AddCommand(newSRPolicyListCmd(), newSRPolicyAddCmd(), newSRPolicyDeleteCmd()) return cmd } diff --git a/cmd/pola/sr_policy_add.go b/cmd/pola/sr_policy_add.go index 364f039..2aa34c8 100644 --- a/cmd/pola/sr_policy_add.go +++ b/cmd/pola/sr_policy_add.go @@ -11,9 +11,11 @@ import ( "net/netip" "os" - pb "github.com/nttcom/pola/api/grpc" "github.com/spf13/cobra" yaml "gopkg.in/yaml.v2" + + pb "github.com/nttcom/pola/api/grpc" + "github.com/nttcom/pola/cmd/pola/grpc" ) func newSRPolicyAddCmd() *cobra.Command { @@ -42,7 +44,7 @@ func newSRPolicyAddCmd() *cobra.Command { defer f.Close() InputData := InputFormat{} if err := yaml.NewDecoder(f).Decode(&InputData); err != nil { - return fmt.Errorf("file \"%s\" can't open", filepath) + return fmt.Errorf("file \"%s\" decode error: %v", filepath, err) } if err := addSRPolicy(InputData, jsonFmt, noLinkStateFlag); err != nil { @@ -61,7 +63,10 @@ func newSRPolicyAddCmd() *cobra.Command { // Unify with table.Segment type Segment struct { - Sid string `yaml:"sid"` + Sid string `yaml:"sid"` + LocalAddr string `yaml:"localAddr"` + RemoteAddr string `yaml:"remoteAddr"` + SidStructure string `yaml:"sidStructure"` } // Unify with table.SRPolciy @@ -115,14 +120,20 @@ func addSRPolicyNoLinkState(input InputFormat) error { " - sid: 16002\n\n" errMsg := "invalid input\n" + - "input examplse is below\n\n" + + "input example is below\n\n" + sampleInput return errors.New(errMsg) } segmentList := []*pb.Segment{} for _, seg := range input.SRPolicy.SegmentList { - segmentList = append(segmentList, &pb.Segment{Sid: seg.Sid}) + pbSeg := &pb.Segment{ + Sid: seg.Sid, + LocalAddr: seg.LocalAddr, + RemoteAddr: seg.RemoteAddr, + SidStructure: seg.SidStructure, + } + segmentList = append(segmentList, pbSeg) } srPolicy := &pb.SRPolicy{ PcepSessionAddr: input.SRPolicy.PcepSessionAddr.AsSlice(), @@ -136,7 +147,7 @@ func addSRPolicyNoLinkState(input InputFormat) error { inputData := &pb.CreateSRPolicyInput{ SRPolicy: srPolicy, } - if err := createSRPolicyWithoutLinkState(client, inputData); err != nil { + if err := grpc.CreateSRPolicyWithoutLinkState(client, inputData); err != nil { return err } @@ -228,7 +239,7 @@ func addSRPolicyLinkState(input InputFormat) error { SRPolicy: srPolicy, Asn: input.Asn, } - if err := createSRPolicy(client, inputData); err != nil { + if err := grpc.CreateSRPolicy(client, inputData); err != nil { return fmt.Errorf("gRPC Server Error: %s", err.Error()) } diff --git a/cmd/pola/sr_policy_delete.go b/cmd/pola/sr_policy_delete.go new file mode 100644 index 0000000..ab070b9 --- /dev/null +++ b/cmd/pola/sr_policy_delete.go @@ -0,0 +1,90 @@ +// Copyright (c) 2022 NTT Communications Corporation +// +// This software is released under the MIT License. +// see https://github.com/nttcom/pola/blob/main/LICENSE + +package main + +import ( + "errors" + "fmt" + "os" + + pb "github.com/nttcom/pola/api/grpc" + "github.com/spf13/cobra" + yaml "gopkg.in/yaml.v2" + + "github.com/nttcom/pola/cmd/pola/grpc" +) + +func newSRPolicyDeleteCmd() *cobra.Command { + srPolicyDeleteCmd := &cobra.Command{ + Use: "delete", + RunE: func(cmd *cobra.Command, args []string) error { + + filepath, err := cmd.Flags().GetString("file") + if err != nil { + return err + } + if filepath == "" { + return fmt.Errorf("file path option \"-f filepath\" is mandatory") + + } + f, openErr := os.Open(filepath) + if openErr != nil { + return fmt.Errorf("file \"%s\" can't open", filepath) + } + defer f.Close() + InputData := InputFormat{} + if err := yaml.NewDecoder(f).Decode(&InputData); err != nil { + return fmt.Errorf("file \"%s\" can't open", filepath) + } + if err := deleteSRPolicy(InputData, jsonFmt); err != nil { + return err + } + return nil + }, + } + + srPolicyDeleteCmd.Flags().StringP("file", "f", "", "[mandatory] path to yaml formatted LSP information file") + + return srPolicyDeleteCmd + +} + +func deleteSRPolicy(input InputFormat, jsonFlag bool) error { + if !input.SRPolicy.PcepSessionAddr.IsValid() || input.SRPolicy.Color == 0 || !input.SRPolicy.DstAddr.IsValid() || input.SRPolicy.Name == "" { + sampleInput := "srPolicy:\n" + + " pcepSessionAddr: 192.0.2.1\n" + + " dstAddr: 192.0.2.2\n" + + " color: 100\n" + + " name: name\n" + errMsg := "invalid input\n" + + "input example is below\n\n" + + sampleInput + + return errors.New(errMsg) + } + + srPolicy := &pb.SRPolicy{ + PcepSessionAddr: input.SRPolicy.PcepSessionAddr.AsSlice(), + DstAddr: input.SRPolicy.DstAddr.AsSlice(), + Color: input.SRPolicy.Color, + PolicyName: input.SRPolicy.Name, + } + inputData := &pb.DeleteSRPolicyInput{ + SRPolicy: srPolicy, + Asn: input.Asn, + } + if err := grpc.DeleteSRPolicy(client, inputData); err != nil { + return fmt.Errorf("gRPC Server Error: %s", err.Error()) + } + + if jsonFlag { + fmt.Printf("{\"status\": \"success\"}\n") + } else { + fmt.Printf("success!\n") + } + + return nil +} diff --git a/cmd/pola/sr_policy_list.go b/cmd/pola/sr_policy_list.go index 19f42c5..7a511f0 100644 --- a/cmd/pola/sr_policy_list.go +++ b/cmd/pola/sr_policy_list.go @@ -10,6 +10,8 @@ import ( "fmt" "github.com/spf13/cobra" + + "github.com/nttcom/pola/cmd/pola/grpc" ) func newSRPolicyListCmd() *cobra.Command { @@ -25,7 +27,7 @@ func showSRPolicyList(cmd *cobra.Command, args []string) error { return err } - srPolicies, err := getSRPolicyList(client) + srPolicies, err := grpc.GetSRPolicyList(client) if err != nil { return err } diff --git a/cmd/pola/ted.go b/cmd/pola/ted.go index 2effa6c..d8a4c4c 100644 --- a/cmd/pola/ted.go +++ b/cmd/pola/ted.go @@ -9,6 +9,7 @@ import ( "encoding/json" "fmt" + "github.com/nttcom/pola/cmd/pola/grpc" "github.com/spf13/cobra" ) @@ -25,7 +26,7 @@ func newTedCmd() *cobra.Command { } func print(jsonFlag bool) error { - ted, err := getTed(client) + ted, err := grpc.GetTed(client) if err != nil { return err } diff --git a/cmd/polad/main.go b/cmd/polad/main.go index 047292f..ff2811c 100644 --- a/cmd/polad/main.go +++ b/cmd/polad/main.go @@ -59,14 +59,14 @@ func main() { defer fp.Close() // Initialize logger - logger := logger.LogInit(fp) + logger := logger.LogInit(fp, c.Global.Log.Debug) defer func() { err := logger.Sync() if err != nil { logger.Panic("Failed to logger Sync", zap.Error(err)) + log.Panic(err) } }() - zap.ReplaceGlobals(logger) // Prepare TED update tools var tedElemsChan chan []table.TedElem @@ -76,6 +76,7 @@ func main() { tedElemsChan = startGobgpUpdate(&c, logger) default: logger.Panic("Specified TED source is not defined") + log.Panic() } } @@ -86,9 +87,11 @@ func main() { GrpcAddr: c.Global.GrpcServer.Address, GrpcPort: c.Global.GrpcServer.Port, TedEnable: c.Global.Ted.Enable, + USidMode: c.Global.USidMode, } if serverErr := server.NewPce(o, logger, tedElemsChan); serverErr.Error != nil { logger.Panic("Failed to start new server", zap.String("server", serverErr.Server), zap.Error(serverErr.Error)) + log.Panic() } } @@ -98,9 +101,9 @@ func startGobgpUpdate(c *config.Config, logger *zap.Logger) chan []table.TedElem go func() { for { tedElems, err := gobgp.GetBgplsNlris(c.Global.Gobgp.GrpcClient.Address, c.Global.Gobgp.GrpcClient.Port) - logger.Info("Request TED update", zap.String("source", "GoBGP"), zap.String("session", c.Global.Gobgp.GrpcClient.Address+":"+c.Global.Gobgp.GrpcClient.Port)) + logger.Debug("Request TED update", zap.String("source", "GoBGP"), zap.String("session", c.Global.Gobgp.GrpcClient.Address+":"+c.Global.Gobgp.GrpcClient.Port)) if err != nil { - logger.Info("Failed session with GoBGP", zap.Error(err)) + logger.Error("Failed session with GoBGP", zap.Error(err)) } else { tedElemsChan <- tedElems } diff --git a/configs/polad.yaml.sample b/configs/polad.yaml.sample index 36eb28a..66fa3d7 100644 --- a/configs/polad.yaml.sample +++ b/configs/polad.yaml.sample @@ -15,3 +15,4 @@ global: grpc-client: address: "127.0.0.1" port: 50051 + usid-mode: true diff --git a/docs/schemas/polad_config.json b/docs/schemas/polad_config.json new file mode 100644 index 0000000..a499bb2 --- /dev/null +++ b/docs/schemas/polad_config.json @@ -0,0 +1,137 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "global": { + "type": "object", + "properties": { + "pcep": { + "type": "object", + "properties": { + "address": { + "type": "string", + "oneOf": [ + { + "format": "ipv4" + }, + { + "format": "ipv6" + } + ] + }, + "port": { + "type": "integer" + } + }, + "required": [ + "address", + "port" + ] + }, + "grpc-server": { + "type": "object", + "properties": { + "address": { + "type": "string", + "oneOf": [ + { + "format": "ipv4" + }, + { + "format": "ipv6" + } + ] + }, + "port": { + "type": "integer" + } + }, + "required": [ + "address", + "port" + ] + }, + "log": { + "type": "object", + "properties": { + "path": { + "type": "string" + }, + "name": { + "type": "string" + }, + "debug": { + "type": "boolean" + } + }, + "required": [ + "path", + "name" + ] + }, + "ted": { + "type": "object", + "properties": { + "enable": { + "type": "boolean" + }, + "source": { + "type": "string", + "enum": [ + "gobgp" + ] + } + }, + "required": [ + "enable" + ] + }, + "gobgp": { + "type": "object", + "properties": { + "grpc-client": { + "type": "object", + "properties": { + "address": { + "type": "string", + "oneOf": [ + { + "format": "ipv4" + }, + { + "format": "ipv6" + } + ] + }, + "port": { + "type": "integer" + } + }, + "required": [ + "address", + "port" + ] + } + }, + "required": [ + "grpc-client" + ] + }, + "usid-mode": { + "type": "boolean", + "default": false + } + }, + "required": [ + "pcep", + "grpc-server", + "log", + "ted" + ] + } + }, + "required": [ + "global" + ], + "additionalProperties": false +} diff --git a/docs/sources/getting-started.md b/docs/sources/getting-started.md index a8d02eb..8b691e5 100644 --- a/docs/sources/getting-started.md +++ b/docs/sources/getting-started.md @@ -4,13 +4,38 @@ This page explains how to use Pola PCE. ## Instllation +### From Go Package + ```bash $ go install github.com/nttcom/pola/cmd/polad@latest ``` +### From Source + +**Getting the Source** + +```bash +$ git clone https://github.com/nttcom/pola.git +``` + +**Build & install** + +```bash +$ cd pola +$ go install ./cmd/polad + +# or, install with cli command +$ go install ./... +``` + +### From Container Image + +See the [Docker page](../../build/package/README.md). + ## Configuration Specify the IP address and port number for each PCEP and gRPC. +See [JSON shema](../schemas/polad_config.json) for config details. ### case: TED disable @@ -19,16 +44,17 @@ To manage SR Policy without using TED. ```yaml global: pcep: - address: ** + address: "2001:0db8::254" port: 4189 grpc-server: address: "127.0.0.1" - port: 50052 + port: 50051 log: path: "/var/log/pola/" name: "polad.log" ted: enable: false + usid-mode: false ``` ### case: TED enable @@ -39,10 +65,12 @@ Enabling TED allows dynamic path calculation. A specific tool for updating TED is required to use this feature. Currently, only GoBGP is supported. +**Not currently available for IPv6 underlay(IPv6 SR-MPLS / SRv6).** + ```yaml global: pcep: - address: ** + address: "192.0.2.254" port: 4189 grpc-server: address: "127.0.0.1" @@ -85,6 +113,7 @@ Start polad. Specify the created configuration file with the -f option. ```bash $ sudo polad -f polad.yaml 2022-06-05T22:57:59.823Z info gRPC listen {"listenInfo": "127.0.0.1:50052", "server": "grpc"} -2022-06-05T22:57:59.823Z info PCEP listen {"listenInfo": "10.255.0.254:4189"} +2022-06-05T22:57:59.823Z info PCEP listen {"listenInfo": "192.0.2.254:4189"} ``` +After Polad is running, use [pola cmd](../../cmd/pola/README.md) or the [gRCP client](../../api/grpc/) for daemon operations diff --git a/internal/config/config.go b/internal/config/config.go index 97586d3..8a2c01d 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -27,8 +27,9 @@ type GrpcClient struct { } type Log struct { - Path string `yaml:"path"` - Name string `yaml:"name"` + Path string `yaml:"path"` + Name string `yaml:"name"` + Debug bool `yaml:"debug"` } type Gobgp struct { @@ -46,6 +47,7 @@ type Global struct { Log Log `yaml:"log"` Ted Ted `yaml:"ted"` Gobgp Gobgp `yaml:"gobgp"` + USidMode bool `yaml:"usid-mode"` } type Config struct { diff --git a/internal/pkg/table/sr_policy.go b/internal/pkg/table/sr_policy.go index 402be72..dd02a3c 100644 --- a/internal/pkg/table/sr_policy.go +++ b/internal/pkg/table/sr_policy.go @@ -11,6 +11,16 @@ import ( "strconv" ) +// sr-policy state +type PolicyState string + +const ( + POLICY_DOWN = PolicyState("down") + POLICY_UP = PolicyState("up") + POLICY_ACTIVE = PolicyState("active") + POLICY_UNKNOWN = PolicyState("unknown") +) + type SRPolicy struct { PlspID uint32 Name string @@ -19,8 +29,65 @@ type SRPolicy struct { DstAddr netip.Addr Color uint32 Preference uint32 + LspID uint16 + State PolicyState +} + +func NewSRPolicy( + plspId uint32, + name string, + segmentList []Segment, + srcAddr netip.Addr, + dstAddr netip.Addr, + color uint32, + preference uint32, + lspID uint16, + state PolicyState, +) *SRPolicy { + p := &SRPolicy{ + PlspID: plspId, + Name: name, + SegmentList: segmentList, + SrcAddr: srcAddr, + DstAddr: dstAddr, + Color: color, + Preference: preference, + LspID: lspID, + State: state, + } + + return p +} + +// SR Policy parameter that can be changed +type PolicyDiff struct { + Name *string + Color *uint32 + Preference *uint32 + SegmentList []Segment + LspID uint16 + State PolicyState +} + +func (p *SRPolicy) Update(df PolicyDiff) { + p.State = df.State + p.LspID = df.LspID + if df.Name != nil { + p.Name = *df.Name + } + if df.Color != nil { + p.Color = *df.Color + } + if df.Preference != nil { + p.Preference = *df.Preference + } + if df.SegmentList != nil { + p.SegmentList = df.SegmentList + } } +const SRV6_SID_BIT_LENGTH = 128 + type Segment interface { SidString() string } @@ -39,14 +106,46 @@ func NewSegment(sid string) (Segment, error) { return nil, errors.New("invalid SID") } +const ( + BEHAVIOR_RESERVED uint16 = 0x0000 + BEHAVIOR_END uint16 = 0x0001 + BEHAVIOR_END_X uint16 = 0x0005 + BEHAVIOR_UN uint16 = 0x0030 + BEHAVIOR_UA uint16 = 0x0039 +) + type SegmentSRv6 struct { - Sid netip.Addr + Sid netip.Addr + LocalAddr netip.Addr + RemoteAddr netip.Addr + Structure []uint8 + USid bool } func (seg SegmentSRv6) SidString() string { return seg.Sid.String() } +func (seg SegmentSRv6) Behavior() uint16 { + if seg.LocalAddr.IsValid() { + if seg.USid { + if seg.RemoteAddr.IsValid() { + return BEHAVIOR_UA + } else { + return BEHAVIOR_UN + } + } else { + if seg.RemoteAddr.IsValid() { + return BEHAVIOR_END_X + } else { + return BEHAVIOR_END + } + } + } else { + return BEHAVIOR_RESERVED + } +} + func NewSegmentSRv6(sid netip.Addr) SegmentSRv6 { return SegmentSRv6{ Sid: sid, diff --git a/internal/pkg/version/version.go b/internal/pkg/version/version.go index 6c837a5..4cf922e 100644 --- a/internal/pkg/version/version.go +++ b/internal/pkg/version/version.go @@ -8,8 +8,8 @@ package version import "fmt" const MAJOR uint = 1 -const MINOR uint = 2 -const PATCH uint = 1 +const MINOR uint = 3 +const PATCH uint = 0 func Version() string { return fmt.Sprintf("%d.%d.%d", MAJOR, MINOR, PATCH) diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go index f4c2085..5649f85 100644 --- a/pkg/logger/logger.go +++ b/pkg/logger/logger.go @@ -12,12 +12,17 @@ import ( "go.uber.org/zap/zapcore" ) -func LogInit(fp *os.File) *zap.Logger { +func LogInit(fp *os.File, dbg bool) *zap.Logger { pe := zap.NewProductionEncoderConfig() fileEncoder := zapcore.NewJSONEncoder(pe) pe.EncodeTime = zapcore.ISO8601TimeEncoder consoleEncoder := zapcore.NewConsoleEncoder(pe) - level := zap.InfoLevel + var level zapcore.Level + if dbg { + level = zap.DebugLevel + } else { + level = zap.InfoLevel + } core := zapcore.NewTee( zapcore.NewCore(fileEncoder, zapcore.AddSync(fp), level), zapcore.NewCore(consoleEncoder, zapcore.AddSync(os.Stdout), level), diff --git a/pkg/packet/pcep/capability.go b/pkg/packet/pcep/capability.go index 882ef5f..381152a 100644 --- a/pkg/packet/pcep/capability.go +++ b/pkg/packet/pcep/capability.go @@ -7,35 +7,28 @@ package pcep type CapabilityInterface interface { TLVInterface + CapStrings() []string } -func PolaCapability() []CapabilityInterface { - return []CapabilityInterface{ - &StatefulPceCapability{ - LspUpdateCapability: true, - IncludeDBVersion: false, - LspInstantiationCapability: true, - TriggeredResync: false, - DeltaLspSyncCapability: false, - TriggeredInitialSync: false, - }, - &PathSetupTypeCapability{ - PathSetupTypes: Psts{PST_RSVP_TE, PST_SR_TE, PST_SRV6_TE}, - SubTLVs: []TLVInterface{ - &SRPceCapability{ - UnlimitedMSD: false, - SupportNAI: false, - MaximumSidDepth: uint8(16), - }, - }, - }, - &SRPceCapability{ - UnlimitedMSD: false, - SupportNAI: false, - MaximumSidDepth: uint8(16), - }, - &AssocTypeList{ - AssocTypes: []AssocType{AT_PATH_PROTECTION_ASSOCIATION, AT_SR_POLICY_ASSOCIATION}, - }, +func PolaCapability(caps []CapabilityInterface) []CapabilityInterface { + polaCaps := []CapabilityInterface{} + for _, cap := range caps { + switch tlv := cap.(type) { + case *StatefulPceCapability: + tlv = &StatefulPceCapability{ + LspUpdateCapability: true, + IncludeDBVersion: false, + LspInstantiationCapability: true, + TriggeredResync: false, + DeltaLspSyncCapability: false, + TriggeredInitialSync: false, + } + polaCaps = append(polaCaps, tlv) + case *LSPDBVersion: + continue + default: + polaCaps = append(polaCaps, tlv) + } } + return polaCaps } diff --git a/pkg/packet/pcep/message.go b/pkg/packet/pcep/message.go index b0ef187..e6dc1ba 100644 --- a/pkg/packet/pcep/message.go +++ b/pkg/packet/pcep/message.go @@ -287,27 +287,6 @@ func (r *StateReport) decodeVendorInformationObject(objectType uint8, objectBody return r.VendorInformationObject.DecodeFromBytes(objectType, objectBody) } -func (r *StateReport) ToSRPolicy(pcc PccType) table.SRPolicy { - srPolicy := table.SRPolicy{ - PlspID: r.LspObject.PlspID, - Name: r.LspObject.Name, - SegmentList: []table.Segment{}, - SrcAddr: r.LspObject.SrcAddr, - DstAddr: r.LspObject.DstAddr, - } - if pcc == CISCO_LEGACY { - srPolicy.Color = r.VendorInformationObject.Color() - srPolicy.Preference = r.VendorInformationObject.Preference() - } else { - srPolicy.Color = r.AssociationObject.Color() - srPolicy.Preference = r.AssociationObject.Preference() - } - - srPolicy.SegmentList = r.EroObject.ToSegmentList() - - return srPolicy -} - // PCRpt Message type PCRptMessage struct { StateReports []*StateReport @@ -379,13 +358,21 @@ type PCInitiateMessage struct { } func (m *PCInitiateMessage) Serialize() ([]uint8, error) { - eroObjectLength, err := m.EroObject.Len() - if err != nil { - return nil, err + var eroObjectLength uint16 + var err error + if m.EroObject != nil { + eroObjectLength, err = m.EroObject.Len() + if err != nil { + return nil, err + } } - endpointsObjectLength, err := m.EndpointsObject.Len() - if err != nil { - return nil, err + + var endpointsObjectLength uint16 + if m.EndpointsObject != nil { + endpointsObjectLength, err = m.EndpointsObject.Len() + if err != nil { + return nil, err + } } pcinitiateMessageLength := COMMON_HEADER_LENGTH + m.SrpObject.Len() + @@ -395,13 +382,20 @@ func (m *PCInitiateMessage) Serialize() ([]uint8, error) { byteSrpObject := m.SrpObject.Serialize() byteLspObject := m.LspObject.Serialize() - byteEndpointsObject, err := m.EndpointsObject.Serialize() - if err != nil { - return nil, err + + byteEndpointsObject := []uint8{} + if m.EndpointsObject != nil { + byteEndpointsObject, err = m.EndpointsObject.Serialize() + if err != nil { + return nil, err + } } - byteEroObject, err := m.EroObject.Serialize() - if err != nil { - return nil, err + byteEroObject := []uint8{} + if m.EroObject != nil { + byteEroObject, err = m.EroObject.Serialize() + if err != nil { + return nil, err + } } byteVendorInformationObject := []uint8{} @@ -431,7 +425,7 @@ func (m *PCInitiateMessage) Serialize() ([]uint8, error) { return bytePCInitiateMessage, nil } -func NewPCInitiateMessage(srpID uint32, lspName string, segmentList []table.Segment, color uint32, preference uint32, srcAddr netip.Addr, dstAddr netip.Addr, opt ...Opt) (*PCInitiateMessage, error) { +func NewPCInitiateMessage(srpID uint32, lspName string, lspDelete bool, plspID uint32, segmentList []table.Segment, color uint32, preference uint32, srcAddr netip.Addr, dstAddr netip.Addr, opt ...Opt) (*PCInitiateMessage, error) { opts := optParams{ pccType: RFC_COMPLIANT, } @@ -442,11 +436,19 @@ func NewPCInitiateMessage(srpID uint32, lspName string, segmentList []table.Segm m := &PCInitiateMessage{} var err error - if m.SrpObject, err = NewSrpObject(segmentList, srpID, false); err != nil { + if m.SrpObject, err = NewSrpObject(segmentList, srpID, lspDelete); err != nil { return nil, err } - if m.LspObject, err = NewLspObject(lspName, 0); err != nil { // PLSP-ID = 0 - return nil, err + + if lspDelete { + if m.LspObject, err = NewLspObject(lspName, plspID); err != nil { + return nil, err + } + return m, nil + } else { + if m.LspObject, err = NewLspObject(lspName, 0); err != nil { + return nil, err + } } if m.EndpointsObject, err = NewEndpointsObject(dstAddr, srcAddr); err != nil { return nil, err diff --git a/pkg/packet/pcep/object.go b/pkg/packet/pcep/object.go index c4ca1db..52bcc16 100644 --- a/pkg/packet/pcep/object.go +++ b/pkg/packet/pcep/object.go @@ -8,6 +8,7 @@ package pcep import ( "encoding/binary" "errors" + "math" "net/netip" "github.com/nttcom/pola/internal/pkg/table" @@ -257,6 +258,9 @@ func (o *MetricObject) DecodeFromBytes(typ uint8, objectBody []uint8) error { } func (o *MetricObject) Serialize() []uint8 { + metricObjectHeader := NewCommonObjectHeader(OC_METRIC, o.ObjectType, o.Len()) + byteMetricObjectHeader := metricObjectHeader.Serialize() + buf := make([]uint8, 8) if o.CFlag { buf[2] = buf[2] | 0x02 @@ -265,8 +269,24 @@ func (o *MetricObject) Serialize() []uint8 { buf[2] = buf[2] | 0x01 } buf[3] = o.MetricType - binary.BigEndian.PutUint32(buf[4:8], o.MetricValue) - return buf + tmpMetVal := math.Float32bits(float32(o.MetricValue)) + binary.BigEndian.PutUint32(buf[4:8], tmpMetVal) + byteMetricObject := AppendByteSlices(byteMetricObjectHeader, buf) + return byteMetricObject +} + +func (o *MetricObject) Len() uint16 { + // CommonObjectHeader(4byte) + Flags, SRP-ID(8byte) + return COMMON_OBJECT_HEADER_LENGTH + 8 +} + +func NewMetricObject() (*MetricObject, error) { + o := &MetricObject{ + ObjectType: uint8(1), + MetricType: uint8(2), + MetricValue: uint32(30), + } + return o, nil } // LSPA Object (RFC5440 7.11) @@ -292,6 +312,9 @@ func (o *LspaObject) DecodeFromBytes(typ uint8, objectBody []uint8) error { } func (o *LspaObject) Serialize() []uint8 { + lspaObjectHeader := NewCommonObjectHeader(OC_LSPA, o.ObjectType, o.Len()) + byteLspaObjectHeader := lspaObjectHeader.Serialize() + buf := make([]uint8, 16) binary.BigEndian.PutUint32(buf[0:4], o.ExcludeAny) binary.BigEndian.PutUint32(buf[4:8], o.IncludeAny) @@ -301,7 +324,24 @@ func (o *LspaObject) Serialize() []uint8 { if o.LFlag { buf[14] = buf[14] | 0x01 } - return buf + + byteLspaObject := AppendByteSlices(byteLspaObjectHeader, buf) + return byteLspaObject +} + +func (o *LspaObject) Len() uint16 { + // CommonObjectHeader(4byte) + Flags, SRP-ID(8byte) + return COMMON_OBJECT_HEADER_LENGTH + 16 +} + +func NewLspaObject() (*LspaObject, error) { + o := &LspaObject{ + ObjectType: uint8(1), + SetupPriority: uint8(7), + HoldingPriority: uint8(7), + LFlag: true, + } + return o, nil } // PCEP Error Object (RFC5440 7.15) @@ -461,6 +501,9 @@ func NewSrpObject(segs []table.Segment, srpID uint32, isRemove bool) (*SrpObject SrpID: srpID, TLVs: []TLVInterface{}, } + if len(segs) == 0 { + return o, nil + } if _, ok := segs[0].(table.SegmentSRMPLS); ok { o.TLVs = append(o.TLVs, &PathSetupType{PathSetupType: PST_SR_TE}) } else if _, ok := segs[0].(table.SegmentSRv6); ok { @@ -482,6 +525,8 @@ type LspObject struct { SrcAddr netip.Addr DstAddr netip.Addr PlspID uint32 + LspID uint16 + CFlag bool OFlag uint8 AFlag bool RFlag bool @@ -513,10 +558,12 @@ func (o *LspObject) DecodeFromBytes(typ uint8, objectBody []uint8) error { if t, ok := tlv.(*IPv4LspIdentifiers); ok { o.SrcAddr = t.IPv4TunnelSenderAddress o.DstAddr = t.IPv4TunnelEndpointAddress + o.LspID = t.LspID } if t, ok := tlv.(*IPv6LspIdentifiers); ok { o.SrcAddr = t.IPv6TunnelSenderAddress o.DstAddr = t.IPv6TunnelEndpointAddress + o.LspID = t.LspID } } } @@ -529,6 +576,9 @@ func (o *LspObject) Serialize() []uint8 { buf := make([]uint8, 4) binary.BigEndian.PutUint32(buf, uint32(o.PlspID<<12)+uint32(o.OFlag<<4)) + if o.CFlag { + buf[3] = buf[3] | 0x80 + } if o.AFlag { buf[3] = buf[3] | 0x08 } @@ -543,7 +593,7 @@ func (o *LspObject) Serialize() []uint8 { } byteTLVs := []uint8{} for _, tlv := range o.TLVs { - byteTLVs = tlv.Serialize() + byteTLVs = AppendByteSlices(byteTLVs, tlv.Serialize()) } byteLspObject := AppendByteSlices(byteLspObjectHeader, buf, byteTLVs) @@ -566,6 +616,7 @@ func NewLspObject(lspName string, plspID uint32) (*LspObject, error) { ObjectType: OT_LSP_LSP, Name: lspName, PlspID: plspID, + CFlag: true, // (RFC8281 5.3.1) OFlag: uint8(1), // UP (RFC8231 7.3) AFlag: true, // desired operational state is active (RFC8231 7.3) RFlag: false, // TODO: Allow setting from function arguments @@ -835,9 +886,7 @@ type SRv6EroSubobject struct { TFlag bool FFlag bool SFlag bool - Behavior uint16 Segment table.SegmentSRv6 - Nai netip.Addr } func (o *SRv6EroSubobject) DecodeFromBytes(subObj []uint8) error { @@ -849,12 +898,15 @@ func (o *SRv6EroSubobject) DecodeFromBytes(subObj []uint8) error { o.TFlag = (subObj[3] & 0x04) != 0 o.FFlag = (subObj[3] & 0x02) != 0 o.SFlag = (subObj[3] & 0x01) != 0 - o.Behavior = binary.BigEndian.Uint16(subObj[6:8]) sid, _ := netip.AddrFromSlice(subObj[8:24]) o.Segment = table.NewSegmentSRv6(sid) - if o.NaiType == 2 { - o.Nai, _ = netip.AddrFromSlice(subObj[24:40]) + if o.NaiType == NT_SRV6_NODE { + o.Segment.LocalAddr, _ = netip.AddrFromSlice(subObj[24:40]) + } + if o.NaiType == NT_SRV6_ADJACENCY_GLOBAL { + o.Segment.LocalAddr, _ = netip.AddrFromSlice(subObj[24:40]) + o.Segment.RemoteAddr, _ = netip.AddrFromSlice(subObj[40:56]) } return nil } @@ -881,38 +933,87 @@ func (o *SRv6EroSubobject) Serialize() []uint8 { } reserved := make([]uint8, 2) behavior := make([]uint8, 2) - binary.BigEndian.PutUint16(behavior, o.Behavior) + binary.BigEndian.PutUint16(behavior, o.Segment.Behavior()) byteSid := o.Segment.Sid.AsSlice() - byteSRv6EroSubobject := AppendByteSlices(buf, reserved, behavior, byteSid) + + byteNai := []uint8{} + if o.Segment.LocalAddr.IsValid() { + byteNai = append(byteNai, o.Segment.LocalAddr.AsSlice()...) + if o.Segment.RemoteAddr.IsValid() { + byteNai = append(byteNai, o.Segment.RemoteAddr.AsSlice()...) + } + } + + byteSidStructure := []uint8{} + if o.Segment.Structure != nil { + byteSidStructure = append(byteSidStructure, o.Segment.Structure...) + byteSidStructure = append(byteSidStructure, make([]uint8, 4)...) + } + + byteSRv6EroSubobject := AppendByteSlices(buf, reserved, behavior, byteSid, byteNai, byteSidStructure) return byteSRv6EroSubobject } func (o *SRv6EroSubobject) Len() (uint16, error) { // The Length MUST be at least 24, and MUST be a multiple of 4. // An SRv6-ERO subobject MUST contain at least one of a SRv6-SID or an NAI. - if o.NaiType == NT_MUST_NOT_BE_INCLUDED { - // Type, Length, Flags (4byte) + Reserved(2byte) + Behavior(2byte) + SID (16byte) - return uint16(24), nil - } else if o.NaiType == NT_IPV6_NODE { - // Type, Length, Flags (4byte) + Reserved(2byte) + Behavior(2byte) + SID (16byte) + Nai (16byte) - return uint16(40), nil - } else { - return uint16(0), errors.New("unsupported naitype") + + // Type, Length, Flags (4byte) + Reserved(2byte) + Behavior(2byte) + length := uint16(8) + // SRv6-SID value in the subobject body is NOT absent + if !o.SFlag { + length += 16 + } + // NAI value in the subobject body is NOT absent + if !o.FFlag { + switch o.NaiType { + case NT_IPV6_NODE: + length += 16 + case NT_SRV6_ADJACENCY_GLOBAL: + length += 32 + case NT_SRV6_ADJACENCY_LINKLOCAL: + length += 40 + case NT_MUST_NOT_BE_INCLUDED: + return uint16(0), errors.New("when naitype is 0 then FFlag must be 1") + default: + return uint16(0), errors.New("unsupported naitype") + } + } + if o.TFlag { + length += 8 } + return length, nil } func NewSRv6EroSubObject(seg table.SegmentSRv6) (*SRv6EroSubobject, error) { subo := &SRv6EroSubobject{ LFlag: false, SubobjectType: ERO_SUBOBJECT_SRV6, - NaiType: NT_MUST_NOT_BE_INCLUDED, VFlag: false, - TFlag: false, - FFlag: true, - SFlag: false, - Behavior: uint16(1), + SFlag: false, // SID is absent Segment: seg, } + + if seg.Structure != nil { + subo.TFlag = true // the SID Structure value in the subobject body is present + } else { + subo.TFlag = false + } + if seg.LocalAddr.IsValid() { + subo.FFlag = false // Nai is present + + if seg.RemoteAddr.IsValid() { + // End.X or uA + subo.NaiType = NT_SRV6_ADJACENCY_GLOBAL + } else { + // End or uN + subo.NaiType = NT_SRV6_NODE + } + } else { + subo.FFlag = true // SID is absent + subo.NaiType = NT_MUST_NOT_BE_INCLUDED + } + length, err := subo.Len() if err != nil { return subo, err @@ -1140,59 +1241,17 @@ func NewAssociationObject(srcAddr netip.Addr, dstAddr netip.Addr, color uint32, } else { o.AssocID = 1 // (I.D. pce-segment-routing-policy-cp-07 5.1) o.AssocType = ASSOC_TYPE_SR_POLICY_ASSOCIATION // (I.D. pce-segment-routing-policy-cp-07 5.1) - var associationObjectTLVs []TLVInterface - if srcAddr.Is4() { - associationObjectTLVs = []TLVInterface{ - &UndefinedTLV{ - Typ: TLV_EXTENDED_ASSOCIATION_ID, - Length: TLV_EXTENDED_ASSOCIATION_ID_IPV4_LENGTH, - Value: AppendByteSlices( - Uint32ToByteSlice(color), dstAddr.AsSlice(), - ), - }, - &UndefinedTLV{ - Typ: TLV_SRPOLICY_CPATH_ID, - Length: TLV_SRPOLICY_CPATH_ID_LENGTH, - Value: []uint8{ - 0x00, // protocol origin - 0x00, 0x00, 0x00, // mbz - 0x00, 0x00, 0x00, 0x00, // Originator ASN - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Originator Address - 0x00, 0x00, 0x00, 0x00, //discriminator - }, - }, - &UndefinedTLV{ - Typ: TLV_SRPOLICY_CPATH_PREFERENCE, - Length: TLV_SRPOLICY_CPATH_PREFERENCE_LENGTH, - Value: Uint32ToByteSlice(preference), - }, - } - } else if srcAddr.Is6() { - associationObjectTLVs = []TLVInterface{ - &UndefinedTLV{ - Typ: TLV_EXTENDED_ASSOCIATION_ID, - Length: TLV_EXTENDED_ASSOCIATION_ID_IPV6_LENGTH, - Value: AppendByteSlices( - Uint32ToByteSlice(color), dstAddr.AsSlice(), - ), - }, - &UndefinedTLV{ - Typ: TLV_SRPOLICY_CPATH_ID, - Length: TLV_SRPOLICY_CPATH_ID_LENGTH, - Value: []uint8{ - 0x00, // protocol origin - 0x00, 0x00, 0x00, // mbz - 0x00, 0x00, 0x00, 0x00, // Originator ASN - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Originator Address - 0x00, 0x00, 0x00, 0x00, //discriminator - }, - }, - &UndefinedTLV{ - Typ: TLV_SRPOLICY_CPATH_PREFERENCE, - Length: TLV_SRPOLICY_CPATH_PREFERENCE_LENGTH, - Value: Uint32ToByteSlice(preference), - }, - } + associationObjectTLVs := []TLVInterface{ + &ExtendedAssociationID{ + Color: color, + Endpoint: dstAddr, + }, + &SRPolicyCandidatePathIdentifier{ + OriginatorAddr: dstAddr, + }, + &SRPolicyCandidatePathPreference{ + Preference: preference, + }, } o.TLVs = append(o.TLVs, associationObjectTLVs...) } @@ -1204,12 +1263,13 @@ func NewAssociationObject(srcAddr netip.Addr, dstAddr netip.Addr, color uint32, func (o *AssociationObject) Color() uint32 { for _, tlv := range o.TLVs { if t, ok := tlv.(*UndefinedTLV); ok { - if t.Type() == TLV_EXTENDED_ASSOCIATION_ID { - return uint32(binary.BigEndian.Uint32(t.Value[:4])) - } else if t.Type() == JUNIPER_SPEC_TLV_EXTENDED_ASSOCIATION_ID { + if t.Type() == JUNIPER_SPEC_TLV_EXTENDED_ASSOCIATION_ID { return uint32(binary.BigEndian.Uint32(t.Value[:4])) } + } else if t, ok := tlv.(*ExtendedAssociationID); ok { + return t.Color } + } return 0 } @@ -1218,16 +1278,25 @@ func (o *AssociationObject) Color() uint32 { func (o *AssociationObject) Preference() uint32 { for _, tlv := range o.TLVs { if t, ok := tlv.(*UndefinedTLV); ok { - if t.Type() == TLV_SRPOLICY_CPATH_PREFERENCE { - return uint32(binary.BigEndian.Uint32(t.Value)) - } else if t.Type() == JUNIPER_SPEC_TLV_SRPOLICY_CPATH_PREFERENCE { + if t.Type() == JUNIPER_SPEC_TLV_SRPOLICY_CPATH_PREFERENCE { return uint32(binary.BigEndian.Uint32(t.Value)) } + } else if t, ok := tlv.(*SRPolicyCandidatePathPreference); ok { + return t.Preference } } return 0 } +func (o *AssociationObject) Endpoint() netip.Addr { + for _, tlv := range o.TLVs { + if t, ok := tlv.(*ExtendedAssociationID); ok { + return t.Endpoint + } + } + return netip.Addr{} +} + // VENDOR-INFORMATION Object (RFC7470 4) const ( OT_VENDOR_SPECIFIC_CONSTRAINTS uint8 = 1 diff --git a/pkg/packet/pcep/tlv.go b/pkg/packet/pcep/tlv.go index 59e6af0..d2d7fe5 100644 --- a/pkg/packet/pcep/tlv.go +++ b/pkg/packet/pcep/tlv.go @@ -10,6 +10,8 @@ import ( "errors" "fmt" "net/netip" + "slices" + "strconv" "strings" "go.uber.org/zap/zapcore" @@ -76,6 +78,7 @@ const ( // PCEP TLV const ( TLV_STATEFUL_PCE_CAPABILITY_LENGTH uint16 = 4 + TLV_LSP_DB_VERSION_LENGTH uint16 = 8 TLV_SR_PCE_CAPABILITY_LENGTH uint16 = 4 TLV_PATH_SETUP_TYPE_LENGTH uint16 = 4 TLV_EXTENDED_ASSOCIATION_ID_IPV4_LENGTH uint16 = 8 @@ -163,6 +166,30 @@ func (tlv *StatefulPceCapability) Len() uint16 { return TL_LENGTH + TLV_STATEFUL_PCE_CAPABILITY_LENGTH } +func (tlv *StatefulPceCapability) CapStrings() []string { + ret := []string{} + ret = append(ret, "Stateful") + if tlv.LspUpdateCapability { + ret = append(ret, "Update") + } + if tlv.IncludeDBVersion { + ret = append(ret, "Include-DB-Ver") + } + if tlv.LspInstantiationCapability { + ret = append(ret, "Initiate") + } + if tlv.TriggeredResync { + ret = append(ret, "Triggerd-Resync") + } + if tlv.DeltaLspSyncCapability { + ret = append(ret, "Delta-LSP-Sync") + } + if tlv.TriggeredInitialSync { + ret = append(ret, "Triggerd-init-sync") + } + return ret +} + type SymbolicPathName struct { Name string } @@ -214,6 +241,8 @@ func (tlv *SymbolicPathName) Len() uint16 { type IPv4LspIdentifiers struct { IPv4TunnelSenderAddress netip.Addr IPv4TunnelEndpointAddress netip.Addr + LspID uint16 + TunnelID uint16 } func (tlv *IPv4LspIdentifiers) DecodeFromBytes(data []uint8) error { @@ -221,6 +250,8 @@ func (tlv *IPv4LspIdentifiers) DecodeFromBytes(data []uint8) error { if tlv.IPv4TunnelSenderAddress, ok = netip.AddrFromSlice(data[12:16]); !ok { tlv.IPv4TunnelSenderAddress, _ = netip.AddrFromSlice(data[4:8]) } + tlv.LspID = binary.BigEndian.Uint16(data[8:10]) + tlv.TunnelID = binary.BigEndian.Uint16(data[10:12]) tlv.IPv4TunnelEndpointAddress, _ = netip.AddrFromSlice(data[16:20]) return nil } @@ -244,10 +275,14 @@ func (tlv *IPv4LspIdentifiers) Len() uint16 { type IPv6LspIdentifiers struct { IPv6TunnelSenderAddress netip.Addr IPv6TunnelEndpointAddress netip.Addr + LspID uint16 + TunnelID uint16 } func (tlv *IPv6LspIdentifiers) DecodeFromBytes(data []uint8) error { tlv.IPv6TunnelSenderAddress, _ = netip.AddrFromSlice(data[4:20]) + tlv.LspID = binary.BigEndian.Uint16(data[20:22]) + tlv.TunnelID = binary.BigEndian.Uint16(data[22:24]) tlv.IPv6TunnelEndpointAddress, _ = netip.AddrFromSlice(data[40:56]) return nil } @@ -268,6 +303,49 @@ func (tlv *IPv6LspIdentifiers) Len() uint16 { return TL_LENGTH + TLV_IPV6_LSP_IDENTIFIERS_LENGTH } +type LSPDBVersion struct { + VersionNumber uint64 +} + +func (tlv *LSPDBVersion) DecodeFromBytes(data []uint8) error { + tlv.VersionNumber = binary.BigEndian.Uint64(data[4:12]) + return nil +} + +func (tlv *LSPDBVersion) Serialize() []uint8 { + buf := []uint8{} + + typ := make([]uint8, 2) + binary.BigEndian.PutUint16(typ, tlv.Type()) + buf = append(buf, typ...) + + length := make([]uint8, 2) + binary.BigEndian.PutUint16(length, TLV_LSP_DB_VERSION_LENGTH) + buf = append(buf, length...) + + val := make([]uint8, TLV_LSP_DB_VERSION_LENGTH) + binary.BigEndian.PutUint64(val, tlv.VersionNumber) + + buf = append(buf, val...) + return buf +} + +func (tlv *LSPDBVersion) MarshalLogObject(enc zapcore.ObjectEncoder) error { + return nil +} + +func (tlv *LSPDBVersion) Type() uint16 { + return TLV_LSP_DB_VERSION +} + +func (tlv *LSPDBVersion) Len() uint16 { + return TL_LENGTH + TLV_LSP_DB_VERSION_LENGTH +} + +func (tlv *LSPDBVersion) CapStrings() []string { + return []string{"LSP-DB-VERSION"} +} + type SRPceCapability struct { UnlimitedMSD bool SupportNAI bool @@ -317,6 +395,10 @@ func (tlv *SRPceCapability) Len() uint16 { return TL_LENGTH + TLV_SR_PCE_CAPABILITY_LENGTH } +func (tlv *SRPceCapability) CapStrings() []string { + return []string{"SR-TE"} +} + type Pst uint8 const ( @@ -377,6 +459,67 @@ func (tlv *PathSetupType) Len() uint16 { return TL_LENGTH + TLV_PATH_SETUP_TYPE_LENGTH } +type ExtendedAssociationID struct { + Color uint32 + Endpoint netip.Addr +} + +func (tlv *ExtendedAssociationID) DecodeFromBytes(data []uint8) error { + l := binary.BigEndian.Uint16(data[2:4]) + + tlv.Color = binary.BigEndian.Uint32(data[4:8]) + + switch l { + case TLV_EXTENDED_ASSOCIATION_ID_IPV4_LENGTH: + tlv.Endpoint, _ = netip.AddrFromSlice(data[8:12]) + case TLV_EXTENDED_ASSOCIATION_ID_IPV6_LENGTH: + tlv.Endpoint, _ = netip.AddrFromSlice(data[8:24]) + } + + return nil +} + +func (tlv *ExtendedAssociationID) Serialize() []uint8 { + buf := []uint8{} + + typ := make([]uint8, 2) + binary.BigEndian.PutUint16(typ, tlv.Type()) + buf = append(buf, typ...) + + length := make([]uint8, 2) + if tlv.Endpoint.Is4() { + binary.BigEndian.PutUint16(length, TLV_EXTENDED_ASSOCIATION_ID_IPV4_LENGTH) + } else if tlv.Endpoint.Is6() { + binary.BigEndian.PutUint16(length, TLV_EXTENDED_ASSOCIATION_ID_IPV6_LENGTH) + } + buf = append(buf, length...) + + color := make([]uint8, 4) + binary.BigEndian.PutUint32(color, tlv.Color) + buf = append(buf, color...) + + buf = append(buf, tlv.Endpoint.AsSlice()...) + return buf +} + +func (tlv *ExtendedAssociationID) MarshalLogObject(enc zapcore.ObjectEncoder) error { + return nil +} + +func (tlv *ExtendedAssociationID) Type() uint16 { + return TLV_EXTENDED_ASSOCIATION_ID +} + +func (tlv *ExtendedAssociationID) Len() uint16 { + if tlv.Endpoint.Is4() { + return TL_LENGTH + TLV_EXTENDED_ASSOCIATION_ID_IPV4_LENGTH + } else if tlv.Endpoint.Is6() { + return TL_LENGTH + TLV_EXTENDED_ASSOCIATION_ID_IPV6_LENGTH + } + return 0 + +} + type PathSetupTypeCapability struct { PathSetupTypes Psts SubTLVs []TLVInterface @@ -463,6 +606,17 @@ func (tlv *PathSetupTypeCapability) Len() uint16 { return TL_LENGTH + l } +func (tlv *PathSetupTypeCapability) CapStrings() []string { + ret := []string{} + if slices.Contains(tlv.PathSetupTypes, PST_SR_TE) { + ret = append(ret, "SR-TE") + } + if slices.Contains(tlv.PathSetupTypes, PST_SRV6_TE) { + ret = append(ret, "SRv6-TE") + } + return ret +} + type AssocType uint16 const ( @@ -530,6 +684,96 @@ func (tlv *AssocTypeList) Len() uint16 { return TL_LENGTH + l + padding } +func (tlv *AssocTypeList) CapStrings() []string { + return []string{} +} + +type SRPolicyCandidatePathIdentifier struct { + OriginatorAddr netip.Addr // After DecodeFromBytes, even ipv4 addresses are assigned in ipv6 format +} + +func (tlv *SRPolicyCandidatePathIdentifier) DecodeFromBytes(data []uint8) error { + tlv.OriginatorAddr, _ = netip.AddrFromSlice(data[12:28]) + return nil +} + +func (tlv *SRPolicyCandidatePathIdentifier) Serialize() []uint8 { + buf := []uint8{} + + typ := make([]uint8, 2) + binary.BigEndian.PutUint16(typ, tlv.Type()) + buf = append(buf, typ...) + + length := make([]uint8, 2) + binary.BigEndian.PutUint16(length, TLV_SRPOLICY_CPATH_ID_LENGTH) + buf = append(buf, length...) + + buf = append(buf, 0x0a) // protocol origin, PCEP = 10 + buf = append(buf, 0x00, 0x00, 0x00) // mbz + buf = append(buf, 0x00, 0x00, 0x00, 0x00) // Originator ASN + // Originator Address + if tlv.OriginatorAddr.Is4() { + buf = append(buf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) + buf = append(buf, tlv.OriginatorAddr.AsSlice()...) + } else if tlv.OriginatorAddr.Is6() { + buf = append(buf, tlv.OriginatorAddr.AsSlice()...) + } + buf = append(buf, 0x00, 0x00, 0x00, 0x01) // discriminator + + return buf +} + +func (tlv *SRPolicyCandidatePathIdentifier) MarshalLogObject(enc zapcore.ObjectEncoder) error { + return nil +} + +func (tlv *SRPolicyCandidatePathIdentifier) Type() uint16 { + return TLV_SRPOLICY_CPATH_ID +} + +func (tlv *SRPolicyCandidatePathIdentifier) Len() uint16 { + return TL_LENGTH + TLV_SRPOLICY_CPATH_ID_LENGTH +} + +type SRPolicyCandidatePathPreference struct { + Preference uint32 +} + +func (tlv *SRPolicyCandidatePathPreference) DecodeFromBytes(data []uint8) error { + tlv.Preference = binary.BigEndian.Uint32(data[4:8]) + return nil +} + +func (tlv *SRPolicyCandidatePathPreference) Serialize() []uint8 { + buf := []uint8{} + + typ := make([]uint8, 2) + binary.BigEndian.PutUint16(typ, tlv.Type()) + buf = append(buf, typ...) + + length := make([]uint8, 2) + binary.BigEndian.PutUint16(length, TLV_SRPOLICY_CPATH_PREFERENCE_LENGTH) + buf = append(buf, length...) + + preference := make([]uint8, 4) + binary.BigEndian.PutUint32(preference, tlv.Preference) + buf = append(buf, preference...) + + return buf +} + +func (tlv *SRPolicyCandidatePathPreference) MarshalLogObject(enc zapcore.ObjectEncoder) error { + return nil +} + +func (tlv *SRPolicyCandidatePathPreference) Type() uint16 { + return TLV_SRPOLICY_CPATH_PREFERENCE +} + +func (tlv *SRPolicyCandidatePathPreference) Len() uint16 { + return TL_LENGTH + TLV_SRPOLICY_CPATH_PREFERENCE_LENGTH +} + type UndefinedTLV struct { Typ uint16 Length uint16 @@ -579,6 +823,11 @@ func (tlv *UndefinedTLV) Len() uint16 { return TL_LENGTH + tlv.Length + padding } +func (tlv *UndefinedTLV) CapStrings() []string { + cap := "unknown_type_" + strconv.FormatInt(int64(tlv.Typ), 10) + return []string{cap} +} + func (tlv *UndefinedTLV) SetLength() { tlv.Length = uint16(len(tlv.Value)) } @@ -594,14 +843,21 @@ func DecodeTLV(data []uint8) (TLVInterface, error) { tlv = &IPv4LspIdentifiers{} case TLV_IPV6_LSP_IDENTIFIERS: tlv = &IPv6LspIdentifiers{} + case TLV_LSP_DB_VERSION: + tlv = &LSPDBVersion{} case TLV_SR_PCE_CAPABILITY: tlv = &SRPceCapability{} case TLV_PATH_SETUP_TYPE: tlv = &PathSetupType{} + case TLV_EXTENDED_ASSOCIATION_ID: + tlv = &ExtendedAssociationID{} case TLV_PATH_SETUP_TYPE_CAPABILITY: tlv = &PathSetupTypeCapability{} case TLV_ASSOC_TYPE_LIST: tlv = &AssocTypeList{} + case TLV_SRPOLICY_CPATH_PREFERENCE: + tlv = &SRPolicyCandidatePathPreference{} + default: tlv = &UndefinedTLV{} } diff --git a/pkg/server/grpc_server.go b/pkg/server/grpc_server.go index 59dd0d7..240da85 100644 --- a/pkg/server/grpc_server.go +++ b/pkg/server/grpc_server.go @@ -12,6 +12,9 @@ import ( "fmt" "net" "net/netip" + "slices" + "strconv" + "strings" "github.com/golang/protobuf/ptypes/empty" pb "github.com/nttcom/pola/api/grpc" @@ -25,13 +28,17 @@ import ( type APIServer struct { pce *Server grpcServer *grpc.Server + usidMode bool + logger *zap.Logger pb.UnimplementedPceServiceServer } -func NewAPIServer(pce *Server, grpcServer *grpc.Server) *APIServer { +func NewAPIServer(pce *Server, grpcServer *grpc.Server, usidMode bool, logger *zap.Logger) *APIServer { s := &APIServer{ pce: pce, grpcServer: grpcServer, + usidMode: usidMode, + logger: logger.With(zap.String("server", "grpc")), } pb.RegisterPceServiceServer(grpcServer, s) return s @@ -39,7 +46,7 @@ func NewAPIServer(pce *Server, grpcServer *grpc.Server) *APIServer { func (s *APIServer) Serve(address string, port string) error { listenInfo := net.JoinHostPort(address, port) - s.pce.logger.Info("gRPC listen", zap.String("listenInfo", listenInfo), zap.String("server", "grpc")) + s.logger.Info("Start listening on gRPC port", zap.String("listenInfo", listenInfo)) grpcListener, err := net.Listen("tcp", listenInfo) if err != nil { return fmt.Errorf("failed to listen: %w", err) @@ -55,10 +62,19 @@ func (s *APIServer) CreateSRPolicyWithoutLinkState(ctx context.Context, input *p return s.createSRPolicy(ctx, input, false) } -func (s *APIServer) createSRPolicy(ctx context.Context, input *pb.CreateSRPolicyInput, withLinkState bool) (*pb.RequestStatus, error) { - err := validate(input.GetSRPolicy(), input.GetAsn(), withLinkState) - if err != nil { - return &pb.RequestStatus{IsSuccess: false}, err +func (s *APIServer) createSRPolicy(_ context.Context, input *pb.CreateSRPolicyInput, withLinkState bool) (*pb.RequestStatus, error) { + var err error + + if withLinkState { + err = validate(input.GetSRPolicy(), input.GetAsn(), ValidationAdd) + if err != nil { + return &pb.RequestStatus{IsSuccess: false}, err + } + } else { + err = validate(input.GetSRPolicy(), input.GetAsn(), ValidationAddWithoutLinkState) + if err != nil { + return &pb.RequestStatus{IsSuccess: false}, err + } } inputSRPolicy := input.GetSRPolicy() @@ -89,9 +105,49 @@ func (s *APIServer) createSRPolicy(ctx context.Context, input *pb.CreateSRPolicy dstAddr, _ = netip.AddrFromSlice(inputSRPolicy.GetDstAddr()) for _, segment := range inputSRPolicy.GetSegmentList() { - seg, err := table.NewSegment(segment.GetSid()) - if err != nil { - return &pb.RequestStatus{IsSuccess: false}, err + var seg table.Segment + if addr, err := netip.ParseAddr(segment.GetSid()); err == nil && addr.Is6() { + segSRv6 := table.NewSegmentSRv6(addr) + + // handling of related to Nai + if segment.GetLocalAddr() != "" { + if la, addrErr := netip.ParseAddr(segment.GetLocalAddr()); addrErr == nil { + segSRv6.LocalAddr = la + } else { + return &pb.RequestStatus{IsSuccess: false}, addrErr + } + if segment.GetRemoteAddr() != "" { + if ra, addrErr := netip.ParseAddr(segment.GetRemoteAddr()); addrErr == nil { + segSRv6.RemoteAddr = ra + } else { + return &pb.RequestStatus{IsSuccess: false}, addrErr + } + } + } + + // handling of related to SID Structure + if ss := strings.Split(segment.GetSidStructure(), ","); len(ss) == 4 { + segSRv6.Structure = []uint8{} + for _, strElem := range ss { + elem, err := strconv.Atoi(strElem) + if err != nil { + return &pb.RequestStatus{IsSuccess: false}, errors.New("invalid SidStructure information") + } + if elem <= table.SRV6_SID_BIT_LENGTH { + segSRv6.Structure = append(segSRv6.Structure, uint8(elem)) + } else { + return &pb.RequestStatus{IsSuccess: false}, errors.New("element of each Sid Structure less than bit length of SRv6 SID") + } + } + + } + // usid option + segSRv6.USid = s.usidMode + seg = segSRv6 + } else if i, err := strconv.ParseUint(segment.GetSid(), 10, 32); err == nil { + seg = table.NewSegmentSRMPLS(uint32(i)) + } else { + return &pb.RequestStatus{IsSuccess: false}, errors.New("invalid SID") } segmentList = append(segmentList, seg) } @@ -101,9 +157,10 @@ func (s *APIServer) createSRPolicy(ctx context.Context, input *pb.CreateSRPolicy if err != nil { return nil, err } - s.pce.logger.Info("received CreateSRPolicy API request", zap.String("input", string(inputJson)), zap.String("server", "grpc")) + s.logger.Info("Received CreateSRPolicy API request") + s.logger.Debug("Received paramater", zap.String("input", string(inputJson))) - pcepSession, err := getPcepSession(s.pce, inputSRPolicy.GetPcepSessionAddr()) + pcepSession, err := getSyncedPcepSession(s.pce, inputSRPolicy.GetPcepSessionAddr()) if err != nil { return &pb.RequestStatus{IsSuccess: false}, err } @@ -117,9 +174,9 @@ func (s *APIServer) createSRPolicy(ctx context.Context, input *pb.CreateSRPolicy Preference: 100, } - if id, exists := pcepSession.SearchSRPolicyPlspID(inputSRPolicy.GetColor(), dstAddr); exists { + if id, exists := pcepSession.SearchPlspID(inputSRPolicy.GetColor(), dstAddr); exists { // Update SR Policy - s.pce.logger.Info("plspID check", zap.Uint32("plspID", id), zap.String("server", "grpc")) + s.logger.Debug("Request to update SR Policy", zap.Uint32("plspID", id)) srPolicy.PlspID = id if err := pcepSession.SendPCUpdate(srPolicy); err != nil { @@ -127,7 +184,8 @@ func (s *APIServer) createSRPolicy(ctx context.Context, input *pb.CreateSRPolicy } } else { // Initiate SR Policy - if err := pcepSession.SendPCInitiate(srPolicy); err != nil { + s.logger.Debug("Request to create SR Policy") + if err := pcepSession.RequestSRPolicyCreated(srPolicy); err != nil { return &pb.RequestStatus{IsSuccess: false}, err } } @@ -135,42 +193,106 @@ func (s *APIServer) createSRPolicy(ctx context.Context, input *pb.CreateSRPolicy return &pb.RequestStatus{IsSuccess: true}, nil } -func validate(inputSRPolicy *pb.SRPolicy, asn uint32, withLinkState bool) error { - var validator func(policy *pb.SRPolicy, asn uint32) bool +func (s *APIServer) DeleteSRPolicy(ctx context.Context, input *pb.DeleteSRPolicyInput) (*pb.RequestStatus, error) { + err := validate(input.GetSRPolicy(), input.GetAsn(), ValidationDelete) + if err != nil { + return &pb.RequestStatus{IsSuccess: false}, err + } - if withLinkState { - validator = validateInput + inputSRPolicy := input.GetSRPolicy() + var srcAddr, dstAddr netip.Addr + var segmentList []table.Segment + + srcAddr, _ = netip.AddrFromSlice(inputSRPolicy.GetSrcAddr()) + dstAddr, _ = netip.AddrFromSlice(inputSRPolicy.GetDstAddr()) + for _, segment := range inputSRPolicy.GetSegmentList() { + seg, err := table.NewSegment(segment.GetSid()) + if err != nil { + return &pb.RequestStatus{IsSuccess: false}, err + } + segmentList = append(segmentList, seg) + } + + inputJson, err := json.Marshal(input) + if err != nil { + return nil, err + } + s.logger.Info("Received DeleteSRPolicy API request") + s.logger.Debug("Received paramater", zap.String("input", string(inputJson))) + + pcepSession, err := getSyncedPcepSession(s.pce, inputSRPolicy.GetPcepSessionAddr()) + if err != nil { + return &pb.RequestStatus{IsSuccess: false}, err + } + + srPolicy := table.SRPolicy{ + Name: inputSRPolicy.GetPolicyName(), + SegmentList: segmentList, + SrcAddr: srcAddr, + DstAddr: dstAddr, + Color: inputSRPolicy.GetColor(), + Preference: 100, + } + + if id, exists := pcepSession.SearchPlspID(inputSRPolicy.GetColor(), dstAddr); exists { + // Delete SR Policy + s.logger.Debug("Request to delete SR Policy", zap.Uint32("plspID", id)) + srPolicy.PlspID = id + + if err := pcepSession.RequestSRPolicyDeleted(srPolicy); err != nil { + return &pb.RequestStatus{IsSuccess: false}, nil + } } else { - validator = validateInputWithoutLinkState + // Invalid SR Policy + return &pb.RequestStatus{IsSuccess: false}, fmt.Errorf("Requested SR Policy not found") } - if !validator(inputSRPolicy, asn) { - return errors.New("invalid input") + return &pb.RequestStatus{IsSuccess: true}, nil +} + +func validate(inputSRPolicy *pb.SRPolicy, asn uint32, validationKind ValidationKind) error { + if !validator[validationKind](inputSRPolicy, asn) { + return errors.New("validate error, invalid input") } return nil } -func validateInput(policy *pb.SRPolicy, asn uint32) bool { - return asn != 0 && - policy.PcepSessionAddr != nil && - policy.Color != 0 && - policy.SrcRouterID != "" && - policy.DstRouterID != "" -} +type ValidationKind string -func validateInputWithoutLinkState(policy *pb.SRPolicy, asn uint32) bool { - return policy.PcepSessionAddr != nil && - len(policy.SrcAddr) > 0 && - len(policy.DstAddr) > 0 && - len(policy.SegmentList) > 0 +const ( + ValidationAdd ValidationKind = "Add" + ValidationAddWithoutLinkState ValidationKind = "AddWithoutLinkState" + ValidationDelete ValidationKind = "Delete" +) + +var validator = map[ValidationKind]func(policy *pb.SRPolicy, asn uint32) bool{ + ValidationKind("Add"): func(policy *pb.SRPolicy, asn uint32) bool { + return asn != 0 && + policy.PcepSessionAddr != nil && + policy.Color != 0 && + policy.SrcRouterID != "" && + policy.DstRouterID != "" + }, + ValidationKind("AddWithoutLinkState"): func(policy *pb.SRPolicy, asn uint32) bool { + return policy.PcepSessionAddr != nil && + len(policy.SrcAddr) > 0 && + len(policy.DstAddr) > 0 && + len(policy.SegmentList) > 0 + }, + ValidationKind("Delete"): func(policy *pb.SRPolicy, asn uint32) bool { + return policy.PcepSessionAddr != nil && + policy.Color != 0 && + len(policy.DstAddr) > 0 && + policy.PolicyName != "" + }, } -func getPcepSession(pce *Server, addr []byte) (*Session, error) { +func getSyncedPcepSession(pce *Server, addr []byte) (*Session, error) { pcepSessionAddr, _ := netip.AddrFromSlice(addr) - pcepSession := pce.SearchSession(pcepSessionAddr) + pcepSession := pce.SearchSession(pcepSessionAddr, true) if pcepSession == nil { - return nil, fmt.Errorf("no session with %s", pcepSessionAddr) + return nil, fmt.Errorf("no synced session with %s", pcepSessionAddr) } return pcepSession, nil } @@ -230,22 +352,29 @@ func getMetricType(metricType pb.MetricType) (table.MetricType, error) { } func (s *APIServer) GetSessionList(context.Context, *empty.Empty) (*pb.SessionList, error) { - s.pce.logger.Info("Receive GetPeerAddrList API request", zap.String("server", "grpc")) + s.logger.Info("Received GetSessionList API request") var ret pb.SessionList for _, pcepSession := range s.pce.sessionList { ss := &pb.Session{ - Addr: pcepSession.peerAddr.AsSlice(), + Addr: pcepSession.peerAddr.AsSlice(), + State: pb.SessionState_UP, // Only the UP state in the current specification + Caps: []string{}, + IsSynced: pcepSession.isSynced, + } + for _, cap := range pcepSession.pccCapabilities { + ss.Caps = append(ss.Caps, cap.CapStrings()...) } + ss.Caps = slices.Compact(ss.Caps) ret.Sessions = append(ret.Sessions, ss) } - s.pce.logger.Info("Send GetPeerAddrList API reply", zap.String("server", "grpc")) + s.logger.Debug("Send GetPeerAddrList API reply") return &ret, nil } func (s *APIServer) GetSRPolicyList(context.Context, *empty.Empty) (*pb.SRPolicyList, error) { - s.pce.logger.Info("Receive GetSRPolicyList API request", zap.String("server", "grpc")) + s.logger.Info("Received GetSRPolicyList API request") var ret pb.SRPolicyList for ssAddr, pols := range s.pce.SRPolicies() { @@ -270,12 +399,12 @@ func (s *APIServer) GetSRPolicyList(context.Context, *empty.Empty) (*pb.SRPolicy } } - s.pce.logger.Info("Send SRPolicyList API reply", zap.String("server", "grpc")) + s.logger.Debug("Send SRPolicyList API reply") return &ret, nil } func (s *APIServer) GetTed(context.Context, *empty.Empty) (*pb.Ted, error) { - s.pce.logger.Info("Receive GetTed API request", zap.String("server", "grpc")) + s.logger.Info("Received GetTed API request") ret := &pb.Ted{ Enable: true, @@ -344,7 +473,7 @@ func (s *APIServer) GetTed(context.Context, *empty.Empty) (*pb.Ted, error) { } } - s.pce.logger.Info("Send GetTed API reply", zap.String("server", "grpc")) + s.logger.Debug("Send GetTed API reply") return ret, nil } @@ -352,7 +481,10 @@ func (c *APIServer) DeleteSession(ctx context.Context, input *pb.Session) (*pb.R ssAddr, _ := netip.AddrFromSlice(input.GetAddr()) s := c.pce - ss := s.SearchSession(ssAddr) + var ss *Session + if ss = s.SearchSession(ssAddr, false); ss == nil { + return nil, fmt.Errorf("no session with %s", ssAddr) + } if err := ss.SendClose(pcep.R_NO_EXPLANATION_PROVIDED); err != nil { return &pb.RequestStatus{IsSuccess: false}, err } diff --git a/pkg/server/server.go b/pkg/server/server.go index c0bf2b5..cfde793 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -6,8 +6,11 @@ package server import ( + "errors" + "math" "net" "net/netip" + "strconv" "go.uber.org/zap" grpc "google.golang.org/grpc" @@ -27,6 +30,7 @@ type PceOptions struct { GrpcAddr string GrpcPort string TedEnable bool + USidMode bool } func NewPce(o *PceOptions, logger *zap.Logger, tedElemsChan chan []table.TedElem) ServerError { @@ -47,14 +51,14 @@ func NewPce(o *PceOptions, logger *zap.Logger, tedElemsChan chan []table.TedElem } ted.Update(tedElems) s.ted = ted - logger.Info("Update TED") + logger.Debug("Update TED") } }() } errChan := make(chan ServerError) go func() { - if err := s.Serve(o.PcepAddr, o.PcepPort); err != nil { + if err := s.Serve(o.PcepAddr, o.PcepPort, o.USidMode); err != nil { errChan <- ServerError{ Server: "pcep", Error: err, @@ -64,7 +68,7 @@ func NewPce(o *PceOptions, logger *zap.Logger, tedElemsChan chan []table.TedElem go func() { grpcServer := grpc.NewServer() - apiServer := NewAPIServer(s, grpcServer) + apiServer := NewAPIServer(s, grpcServer, o.USidMode, logger) if err := apiServer.Serve(o.GrpcAddr, o.GrpcPort); err != nil { errChan <- ServerError{ Server: "grpc", @@ -72,16 +76,26 @@ func NewPce(o *PceOptions, logger *zap.Logger, tedElemsChan chan []table.TedElem } } }() + serverError := <-errChan return serverError } -func (s *Server) Serve(address string, port string) error { - localAddr, err := netip.ParseAddrPort(address + ":" + port) +func (s *Server) Serve(address string, port string, usidMode bool) error { + a, err := netip.ParseAddr(address) + if err != nil { + return err + } + p, err := strconv.Atoi(port) if err != nil { return err } - s.logger.Info("PCEP listen", zap.String("listenInfo", localAddr.String())) + if p > math.MaxUint16 { + return errors.New("invalid PCEP listen port") + } + localAddr := netip.AddrPortFrom(a, uint16(p)) + + s.logger.Info("Start listening on PCEP port", zap.String("address", localAddr.String())) l, err := net.ListenTCP("tcp", net.TCPAddrFromAddrPort(localAddr)) if err != nil { return err @@ -90,21 +104,22 @@ func (s *Server) Serve(address string, port string) error { sessionID := uint8(1) for { - ss := NewSession(sessionID, s.logger) - ss.tcpConn, err = l.AcceptTCP() + tcpConn, err := l.AcceptTCP() if err != nil { return err } - peerAddrPort, err := netip.ParseAddrPort(ss.tcpConn.RemoteAddr().String()) + peerAddrPort, err := netip.ParseAddrPort(tcpConn.RemoteAddr().String()) if err != nil { return err } - ss.peerAddr = peerAddrPort.Addr() + ss := NewSession(sessionID, peerAddrPort.Addr(), tcpConn, s.logger) + ss.logger.Info("Start PCEP session") + s.sessionList = append(s.sessionList, ss) go func() { ss.Established() s.closeSession(ss) - s.logger.Info("Close PCEP session", zap.String("session", ss.peerAddr.String())) + ss.logger.Info("Close PCEP session") }() sessionID++ } @@ -123,18 +138,22 @@ func (s *Server) closeSession(session *Session) { } } -func (s *Server) SearchSession(peerAddr netip.Addr) *Session { +// SearchSession returns a struct pointer of (Synced) session. +// if not exist, return nil +func (s *Server) SearchSession(peerAddr netip.Addr, onlySynced bool) *Session { for _, pcepSession := range s.sessionList { - if pcepSession.peerAddr == peerAddr && pcepSession.isSynced { - return pcepSession + if pcepSession.peerAddr == peerAddr { + if !(onlySynced) || pcepSession.isSynced { + return pcepSession + } } } return nil } // SRPolicies returns a map of registered SR Policy with key sessionAddr -func (s *Server) SRPolicies() map[netip.Addr][]table.SRPolicy { - srPolicies := make(map[netip.Addr][]table.SRPolicy) +func (s *Server) SRPolicies() map[netip.Addr][]*table.SRPolicy { + srPolicies := make(map[netip.Addr][]*table.SRPolicy) for _, ss := range s.sessionList { if ss.isSynced { srPolicies[ss.peerAddr] = ss.srPolicies diff --git a/pkg/server/session.go b/pkg/server/session.go index 102d226..2d54534 100644 --- a/pkg/server/session.go +++ b/pkg/server/session.go @@ -23,34 +23,35 @@ type Session struct { tcpConn *net.TCPConn isSynced bool srpIDHead uint32 // 0x00000000 and 0xFFFFFFFF are reserved. - srPolicies []table.SRPolicy + srPolicies []*table.SRPolicy logger *zap.Logger keepAlive uint8 pccType pcep.PccType pccCapabilities []pcep.CapabilityInterface } -func NewSession(sessionID uint8, logger *zap.Logger) *Session { +func NewSession(sessionID uint8, peerAddr netip.Addr, tcpConn *net.TCPConn, logger *zap.Logger) *Session { return &Session{ sessionID: sessionID, isSynced: false, srpIDHead: uint32(1), - logger: logger, + logger: logger.With(zap.String("server", "pcep"), zap.String("session", peerAddr.String())), pccType: pcep.RFC_COMPLIANT, + peerAddr: peerAddr, + tcpConn: tcpConn, } } func (ss *Session) Established() { if err := ss.Open(); err != nil { - ss.logger.Info("PCEP OPEN error", zap.String("session", ss.peerAddr.String()), zap.Error(err)) + ss.logger.Debug("ERROR! PCEP OPEN", zap.Error(err)) return } - - ss.logger.Info("PCEP session established") + ss.logger.Debug("PCEP session established") // Send the initial keepalive message if err := ss.SendKeepalive(); err != nil { - ss.logger.Info("Keepalive send error", zap.String("session", ss.peerAddr.String()), zap.Error(err)) + ss.logger.Debug("ERROR! Send Keepalive Message", zap.Error(err)) return } @@ -60,7 +61,7 @@ func (ss *Session) Established() { // Receive PCEP messages in a separate goroutine go func() { if err := ss.ReceivePcepMessage(); err != nil { - ss.logger.Info("Receive PCEP Message error", zap.String("session", ss.peerAddr.String()), zap.Error(err)) + ss.logger.Debug("ERROR! Receive PCEP Message", zap.Error(err)) } done <- struct{}{} }() @@ -74,21 +75,19 @@ func (ss *Session) Established() { return case <-ticker.C: if err := ss.SendKeepalive(); err != nil { - ss.logger.Info("Keepalive send error", zap.String("session", ss.peerAddr.String()), zap.Error(err)) + ss.logger.Debug("ERROR! Send Keepalive Message", zap.Error(err)) + done <- struct{}{} } } } } -func (ss *Session) sendPcepMessage(message pcep.Message, logMessage string) error { +func (ss *Session) sendPcepMessage(message pcep.Message) error { byteMessage, err := message.Serialize() if err != nil { return err } - - ss.logger.Info(logMessage, zap.String("session", ss.peerAddr.String())) if _, err = ss.tcpConn.Write(byteMessage); err != nil { - ss.logger.Info(logMessage+" send error", zap.String("session", ss.peerAddr.String()), zap.Error(err)) return err } return nil @@ -133,27 +132,21 @@ func (ss *Session) parseOpenMessage() (*pcep.OpenMessage, error) { return &openMessage, nil } -func (ss *Session) SendOpen() error { - openMessage, err := pcep.NewOpenMessage(ss.sessionID, ss.keepAlive, ss.pccCapabilities) - if err != nil { - return err - } - - return ss.sendPcepMessage(openMessage, "Send Open") -} - func (ss *Session) ReceiveOpen() error { + ss.logger.Debug("Receive Open Message") openMessage, err := ss.parseOpenMessage() if err != nil { return err } - ss.pccCapabilities = append(ss.pccCapabilities, openMessage.OpenObject.Caps...) + + ss.pccCapabilities = pcep.PolaCapability(openMessage.OpenObject.Caps) // pccType detection // * FRRouting cannot be detected from the open message, so it is treated as an RFC compliant ss.pccType = pcep.DeterminePccType(ss.pccCapabilities) + ss.logger.Debug("Determine PCC Type", zap.Int("pcc-type", int(ss.pccType))) ss.keepAlive = openMessage.OpenObject.Keepalive - ss.logger.Info("Receive Open", zap.String("session", ss.peerAddr.String())) + return nil } @@ -162,7 +155,8 @@ func (ss *Session) SendKeepalive() error { if err != nil { return err } - return ss.sendPcepMessage(keepaliveMessage, "Send Keepalive") + ss.logger.Debug("Send Keepalive Message") + return ss.sendPcepMessage(keepaliveMessage) } func (ss *Session) SendClose(reason uint8) error { @@ -172,8 +166,7 @@ func (ss *Session) SendClose(reason uint8) error { } byteCloseMessage := closeMessage.Serialize() - ss.logger.Info("Send Close", - zap.String("session", ss.peerAddr.String()), + ss.logger.Debug("Send Close Message", zap.Uint8("reason", closeMessage.CloseObject.Reason), zap.String("detail", "See https://www.iana.org/assignments/pcep/pcep.xhtml#close-object-reason-field")) if _, err := ss.tcpConn.Write(byteCloseMessage); err != nil { @@ -188,10 +181,12 @@ func (ss *Session) ReceivePcepMessage() error { if err != nil { return err } + // wait TCP reassembly packet + time.Sleep(10 * time.Millisecond) switch commonHeader.MessageType { case pcep.MT_KEEPALIVE: - ss.logger.Info("Received Keepalive", zap.String("session", ss.peerAddr.String())) + ss.logger.Debug("Received Keepalive") case pcep.MT_REPORT: err = ss.handlePCRpt(commonHeader.MessageLength) if err != nil { @@ -207,8 +202,7 @@ func (ss *Session) ReceivePcepMessage() error { return err } - ss.logger.Info("Received PCErr", - zap.String("session", ss.peerAddr.String()), + ss.logger.Debug("Received PCErr", zap.Uint8("error-Type", pcerrMessage.PcepErrorObject.ErrorType), zap.Uint8("error-value", pcerrMessage.PcepErrorObject.ErrorValue), zap.String("detail", "See https://www.iana.org/assignments/pcep/pcep.xhtml#pcep-error-object")) @@ -221,15 +215,13 @@ func (ss *Session) ReceivePcepMessage() error { if err := closeMessage.DecodeFromBytes(byteCloseMessageBody); err != nil { return err } - ss.logger.Info("Received Close", - zap.String("session", ss.peerAddr.String()), + ss.logger.Debug("Received Close", zap.Uint8("reason", closeMessage.CloseObject.Reason), zap.String("detail", "See https://www.iana.org/assignments/pcep/pcep.xhtml#close-object-reason-field")) // Close session if get Close Message return nil default: - ss.logger.Info("Received unsupported MessageType", - zap.String("session", ss.peerAddr.String()), + ss.logger.Debug("Received unsupported MessageType", zap.Uint8("MessageType", commonHeader.MessageType)) } } @@ -250,7 +242,7 @@ func (ss *Session) readCommonHeader() (*pcep.CommonHeader, error) { } func (ss *Session) handlePCRpt(length uint16) error { - ss.logger.Info("Received PCRpt", zap.String("session", ss.peerAddr.String())) + ss.logger.Debug("Received PCRpt Message") messageBodyBytes := make([]uint8, length-pcep.COMMON_HEADER_LENGTH) if _, err := ss.tcpConn.Read(messageBodyBytes); err != nil { @@ -263,34 +255,66 @@ func (ss *Session) handlePCRpt(length uint16) error { } for _, sr := range message.StateReports { + // synchronization if sr.LspObject.SFlag { - srPolicy := sr.ToSRPolicy(ss.pccType) - ss.logger.Info("Synchronize SR Policy information", zap.String("session", ss.peerAddr.String()), zap.Any("SRPolicy", srPolicy), zap.Any("Message", message)) - go ss.RegisterSRPolicy(srPolicy) + ss.logger.Debug("Synchronize SR Policy information", zap.Any("Message", message)) + ss.RegisterSRPolicy(*sr) } else if !sr.LspObject.SFlag { switch { + // finish synchronization case sr.LspObject.PlspID == 0: - ss.logger.Info("Finish PCRpt state synchronization", zap.String("session", ss.peerAddr.String())) + ss.logger.Debug("Finish PCRpt state synchronization") ss.isSynced = true + // response to request from PCE case sr.SrpObject.SrpID != 0: - srPolicy := sr.ToSRPolicy(ss.pccType) - ss.logger.Info("Finish Stateful PCE request", zap.String("session", ss.peerAddr.String()), zap.Uint32("srpID", sr.SrpObject.SrpID)) - go ss.RegisterSRPolicy(srPolicy) + ss.logger.Debug("Finish Stateful PCE request", zap.Uint32("srpID", sr.SrpObject.SrpID)) + if sr.LspObject.RFlag { + ss.DeleteSRPolicy(*sr) + } else { + ss.RegisterSRPolicy(*sr) + } + default: - // TODO: Need to implementation of PCUpdate for Passive stateful PCE + if sr.LspObject.RFlag { + ss.DeleteSRPolicy(*sr) + } else { + ss.RegisterSRPolicy(*sr) + } } } } - return nil } -func (ss *Session) SendPCInitiate(srPolicy table.SRPolicy) error { - pcinitiateMessage, err := pcep.NewPCInitiateMessage(ss.srpIDHead, srPolicy.Name, srPolicy.SegmentList, srPolicy.Color, srPolicy.Preference, srPolicy.SrcAddr, srPolicy.DstAddr, pcep.VendorSpecific(ss.pccType)) +func (ss *Session) RequestAllSRPolicyDeleted() error { + var srPolicy table.SRPolicy + return ss.SendPCInitiate(srPolicy, true) +} + +func (ss *Session) RequestSRPolicyDeleted(srPolicy table.SRPolicy) error { + return ss.SendPCInitiate(srPolicy, true) +} + +func (ss *Session) RequestSRPolicyCreated(srPolicy table.SRPolicy) error { + return ss.SendPCInitiate(srPolicy, false) +} + +func (ss *Session) SendOpen() error { + openMessage, err := pcep.NewOpenMessage(ss.sessionID, ss.keepAlive, ss.pccCapabilities) if err != nil { return err } - err = ss.sendPcepMessage(pcinitiateMessage, "Send PCInitiate") + ss.logger.Debug("Send Open Message") + return ss.sendPcepMessage(openMessage) +} + +func (ss *Session) SendPCInitiate(srPolicy table.SRPolicy, lspDelete bool) error { + pcinitiateMessage, err := pcep.NewPCInitiateMessage(ss.srpIDHead, srPolicy.Name, lspDelete, srPolicy.PlspID, srPolicy.SegmentList, srPolicy.Color, srPolicy.Preference, srPolicy.SrcAddr, srPolicy.DstAddr, pcep.VendorSpecific(ss.pccType)) + if err != nil { + return err + } + ss.logger.Debug("Send PCInitiate Message") + err = ss.sendPcepMessage(pcinitiateMessage) if err == nil { ss.srpIDHead++ } @@ -302,21 +326,83 @@ func (ss *Session) SendPCUpdate(srPolicy table.SRPolicy) error { if err != nil { return err } - err = ss.sendPcepMessage(pcupdateMessage, "Send PCUpdate") + ss.logger.Debug("Send Update Message") + err = ss.sendPcepMessage(pcupdateMessage) if err == nil { ss.srpIDHead++ } return err } -func (ss *Session) RegisterSRPolicy(srPolicy table.SRPolicy) { - ss.DeleteSRPolicy(srPolicy.PlspID) - ss.srPolicies = append(ss.srPolicies, srPolicy) +func (ss *Session) RegisterSRPolicy(sr pcep.StateReport) { + var color, preference uint32 + + if ss.pccType == pcep.CISCO_LEGACY { + color = sr.VendorInformationObject.Color() + preference = sr.VendorInformationObject.Preference() + } else { + color = sr.AssociationObject.Color() + preference = sr.AssociationObject.Preference() + } + + lspID := sr.LspObject.LspID + + var state table.PolicyState + switch sr.LspObject.OFlag { + case uint8(0x00): + state = table.POLICY_DOWN + case uint8(0x01): + state = table.POLICY_UP + case uint8(0x02): + state = table.POLICY_ACTIVE + default: + state = table.POLICY_UNKNOWN + } + + if p, ok := ss.SearchSRPolicy(sr.LspObject.PlspID); ok { + // update + // If the LSP ID is old, it is not the latest data update. + if p.LspID <= lspID { + p.Update( + table.PolicyDiff{ + Name: &sr.LspObject.Name, + Color: &color, + Preference: &preference, + SegmentList: sr.EroObject.ToSegmentList(), + LspID: lspID, + State: state, + }, + ) + } + } else { + // create + var src, dst netip.Addr + if src = sr.LspObject.SrcAddr; !src.IsValid() { + src = sr.AssociationObject.AssocSrc + } + if dst = sr.LspObject.DstAddr; !dst.IsValid() { + dst = sr.AssociationObject.Endpoint() + } + p := table.NewSRPolicy( + sr.LspObject.PlspID, + sr.LspObject.Name, + sr.EroObject.ToSegmentList(), + src, + dst, + color, + preference, + lspID, + state, + ) + ss.srPolicies = append(ss.srPolicies, p) + } } -func (ss *Session) DeleteSRPolicy(plspID uint32) { +func (ss *Session) DeleteSRPolicy(sr pcep.StateReport) { + lspID := sr.LspObject.LspID for i, v := range ss.srPolicies { - if v.PlspID == plspID { + // If the LSP ID is old, it is not the latest data update. + if v.PlspID == sr.LspObject.PlspID && v.LspID <= lspID { ss.srPolicies[i] = ss.srPolicies[len(ss.srPolicies)-1] ss.srPolicies = ss.srPolicies[:len(ss.srPolicies)-1] break @@ -324,8 +410,17 @@ func (ss *Session) DeleteSRPolicy(plspID uint32) { } } -// SearchSRPolicyPlspID returns the PLSP-ID of a registered SR Policy, along with a boolean value indicating if it was found. -func (ss *Session) SearchSRPolicyPlspID(color uint32, endpoint netip.Addr) (uint32, bool) { +func (ss *Session) SearchSRPolicy(plspID uint32) (*table.SRPolicy, bool) { + for _, v := range ss.srPolicies { + if v.PlspID == plspID { + return v, true + } + } + return nil, false +} + +// SearchPlspID returns the PLSP-ID of a registered SR Policy, along with a boolean value indicating if it was found. +func (ss *Session) SearchPlspID(color uint32, endpoint netip.Addr) (uint32, bool) { for _, v := range ss.srPolicies { if v.Color == color && v.DstAddr == endpoint { return v.PlspID, true