diff --git a/api/go/gosdn/device/device.pb.go b/api/go/gosdn/device/device.pb.go
new file mode 100644
index 0000000000000000000000000000000000000000..c15f557a8c5cb9491fcf6d861353c4c4bf82be08
--- /dev/null
+++ b/api/go/gosdn/device/device.pb.go
@@ -0,0 +1,1157 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.27.1
+// 	protoc        (unknown)
+// source: gosdn/device/device.proto
+
+package device
+
+import (
+	_ "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/pnd"
+	southbound "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/southbound"
+	transport "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/transport"
+	_ "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options"
+	_ "github.com/openconfig/gnmi/proto/gnmi"
+	_ "google.golang.org/genproto/googleapis/api/annotations"
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	_ "google.golang.org/protobuf/types/descriptorpb"
+	reflect "reflect"
+	sync "sync"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type Status int32
+
+const (
+	Status_STATUS_UNSPECIFIED Status = 0
+	Status_STATUS_OK          Status = 1
+	Status_STATUS_ERROR       Status = 2
+)
+
+// Enum value maps for Status.
+var (
+	Status_name = map[int32]string{
+		0: "STATUS_UNSPECIFIED",
+		1: "STATUS_OK",
+		2: "STATUS_ERROR",
+	}
+	Status_value = map[string]int32{
+		"STATUS_UNSPECIFIED": 0,
+		"STATUS_OK":          1,
+		"STATUS_ERROR":       2,
+	}
+)
+
+func (x Status) Enum() *Status {
+	p := new(Status)
+	*p = x
+	return p
+}
+
+func (x Status) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (Status) Descriptor() protoreflect.EnumDescriptor {
+	return file_gosdn_device_device_proto_enumTypes[0].Descriptor()
+}
+
+func (Status) Type() protoreflect.EnumType {
+	return &file_gosdn_device_device_proto_enumTypes[0]
+}
+
+func (x Status) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use Status.Descriptor instead.
+func (Status) EnumDescriptor() ([]byte, []int) {
+	return file_gosdn_device_device_proto_rawDescGZIP(), []int{0}
+}
+
+type Device struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Id    string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
+	Name  string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
+	Model string `protobuf:"bytes,3,opt,name=model,proto3" json:"model,omitempty"`
+}
+
+func (x *Device) Reset() {
+	*x = Device{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_gosdn_device_device_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Device) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Device) ProtoMessage() {}
+
+func (x *Device) ProtoReflect() protoreflect.Message {
+	mi := &file_gosdn_device_device_proto_msgTypes[0]
+	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 Device.ProtoReflect.Descriptor instead.
+func (*Device) Descriptor() ([]byte, []int) {
+	return file_gosdn_device_device_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *Device) GetId() string {
+	if x != nil {
+		return x.Id
+	}
+	return ""
+}
+
+func (x *Device) GetName() string {
+	if x != nil {
+		return x.Name
+	}
+	return ""
+}
+
+func (x *Device) GetModel() string {
+	if x != nil {
+		return x.Model
+	}
+	return ""
+}
+
+type AddDeviceConfiguration struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Address         string                          `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
+	Sbi             *southbound.SouthboundInterface `protobuf:"bytes,2,opt,name=sbi,proto3" json:"sbi,omitempty"`
+	DeviceName      string                          `protobuf:"bytes,3,opt,name=device_name,json=deviceName,proto3" json:"device_name,omitempty"`
+	TransportOption *transport.TransportOption      `protobuf:"bytes,4,opt,name=transport_option,json=transportOption,proto3" json:"transport_option,omitempty"`
+}
+
+func (x *AddDeviceConfiguration) Reset() {
+	*x = AddDeviceConfiguration{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_gosdn_device_device_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *AddDeviceConfiguration) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AddDeviceConfiguration) ProtoMessage() {}
+
+func (x *AddDeviceConfiguration) ProtoReflect() protoreflect.Message {
+	mi := &file_gosdn_device_device_proto_msgTypes[1]
+	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 AddDeviceConfiguration.ProtoReflect.Descriptor instead.
+func (*AddDeviceConfiguration) Descriptor() ([]byte, []int) {
+	return file_gosdn_device_device_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *AddDeviceConfiguration) GetAddress() string {
+	if x != nil {
+		return x.Address
+	}
+	return ""
+}
+
+func (x *AddDeviceConfiguration) GetSbi() *southbound.SouthboundInterface {
+	if x != nil {
+		return x.Sbi
+	}
+	return nil
+}
+
+func (x *AddDeviceConfiguration) GetDeviceName() string {
+	if x != nil {
+		return x.DeviceName
+	}
+	return ""
+}
+
+func (x *AddDeviceConfiguration) GetTransportOption() *transport.TransportOption {
+	if x != nil {
+		return x.TransportOption
+	}
+	return nil
+}
+
+type AddDeviceRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Timestamp int64                   `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
+	Device    *AddDeviceConfiguration `protobuf:"bytes,2,opt,name=device,proto3" json:"device,omitempty"`
+	Pid       string                  `protobuf:"bytes,3,opt,name=pid,proto3" json:"pid,omitempty"`
+}
+
+func (x *AddDeviceRequest) Reset() {
+	*x = AddDeviceRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_gosdn_device_device_proto_msgTypes[2]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *AddDeviceRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AddDeviceRequest) ProtoMessage() {}
+
+func (x *AddDeviceRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_gosdn_device_device_proto_msgTypes[2]
+	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 AddDeviceRequest.ProtoReflect.Descriptor instead.
+func (*AddDeviceRequest) Descriptor() ([]byte, []int) {
+	return file_gosdn_device_device_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *AddDeviceRequest) GetTimestamp() int64 {
+	if x != nil {
+		return x.Timestamp
+	}
+	return 0
+}
+
+func (x *AddDeviceRequest) GetDevice() *AddDeviceConfiguration {
+	if x != nil {
+		return x.Device
+	}
+	return nil
+}
+
+func (x *AddDeviceRequest) GetPid() string {
+	if x != nil {
+		return x.Pid
+	}
+	return ""
+}
+
+type AddDeviceResponse struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Timestamp int64  `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
+	Status    Status `protobuf:"varint,2,opt,name=status,proto3,enum=gosdn.device.Status" json:"status,omitempty"`
+	DeviceId  string `protobuf:"bytes,3,opt,name=deviceId,proto3" json:"deviceId,omitempty"`
+}
+
+func (x *AddDeviceResponse) Reset() {
+	*x = AddDeviceResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_gosdn_device_device_proto_msgTypes[3]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *AddDeviceResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AddDeviceResponse) ProtoMessage() {}
+
+func (x *AddDeviceResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_gosdn_device_device_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 AddDeviceResponse.ProtoReflect.Descriptor instead.
+func (*AddDeviceResponse) Descriptor() ([]byte, []int) {
+	return file_gosdn_device_device_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *AddDeviceResponse) GetTimestamp() int64 {
+	if x != nil {
+		return x.Timestamp
+	}
+	return 0
+}
+
+func (x *AddDeviceResponse) GetStatus() Status {
+	if x != nil {
+		return x.Status
+	}
+	return Status_STATUS_UNSPECIFIED
+}
+
+func (x *AddDeviceResponse) GetDeviceId() string {
+	if x != nil {
+		return x.DeviceId
+	}
+	return ""
+}
+
+type GetDeviceRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Timestamp int64  `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
+	DeviceID  string `protobuf:"bytes,2,opt,name=deviceID,proto3" json:"deviceID,omitempty"`
+}
+
+func (x *GetDeviceRequest) Reset() {
+	*x = GetDeviceRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_gosdn_device_device_proto_msgTypes[4]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *GetDeviceRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetDeviceRequest) ProtoMessage() {}
+
+func (x *GetDeviceRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_gosdn_device_device_proto_msgTypes[4]
+	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 GetDeviceRequest.ProtoReflect.Descriptor instead.
+func (*GetDeviceRequest) Descriptor() ([]byte, []int) {
+	return file_gosdn_device_device_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *GetDeviceRequest) GetTimestamp() int64 {
+	if x != nil {
+		return x.Timestamp
+	}
+	return 0
+}
+
+func (x *GetDeviceRequest) GetDeviceID() string {
+	if x != nil {
+		return x.DeviceID
+	}
+	return ""
+}
+
+type GetDeviceResponse struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Timestamp int64   `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
+	Status    Status  `protobuf:"varint,2,opt,name=status,proto3,enum=gosdn.device.Status" json:"status,omitempty"`
+	Device    *Device `protobuf:"bytes,3,opt,name=device,proto3" json:"device,omitempty"`
+}
+
+func (x *GetDeviceResponse) Reset() {
+	*x = GetDeviceResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_gosdn_device_device_proto_msgTypes[5]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *GetDeviceResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetDeviceResponse) ProtoMessage() {}
+
+func (x *GetDeviceResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_gosdn_device_device_proto_msgTypes[5]
+	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 GetDeviceResponse.ProtoReflect.Descriptor instead.
+func (*GetDeviceResponse) Descriptor() ([]byte, []int) {
+	return file_gosdn_device_device_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *GetDeviceResponse) GetTimestamp() int64 {
+	if x != nil {
+		return x.Timestamp
+	}
+	return 0
+}
+
+func (x *GetDeviceResponse) GetStatus() Status {
+	if x != nil {
+		return x.Status
+	}
+	return Status_STATUS_UNSPECIFIED
+}
+
+func (x *GetDeviceResponse) GetDevice() *Device {
+	if x != nil {
+		return x.Device
+	}
+	return nil
+}
+
+type GetAllDeviceRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Timestamp int64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
+}
+
+func (x *GetAllDeviceRequest) Reset() {
+	*x = GetAllDeviceRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_gosdn_device_device_proto_msgTypes[6]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *GetAllDeviceRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetAllDeviceRequest) ProtoMessage() {}
+
+func (x *GetAllDeviceRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_gosdn_device_device_proto_msgTypes[6]
+	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 GetAllDeviceRequest.ProtoReflect.Descriptor instead.
+func (*GetAllDeviceRequest) Descriptor() ([]byte, []int) {
+	return file_gosdn_device_device_proto_rawDescGZIP(), []int{6}
+}
+
+func (x *GetAllDeviceRequest) GetTimestamp() int64 {
+	if x != nil {
+		return x.Timestamp
+	}
+	return 0
+}
+
+type GetAllDeviceResponse struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Timestamp int64     `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
+	Status    Status    `protobuf:"varint,2,opt,name=status,proto3,enum=gosdn.device.Status" json:"status,omitempty"`
+	Device    []*Device `protobuf:"bytes,3,rep,name=device,proto3" json:"device,omitempty"`
+}
+
+func (x *GetAllDeviceResponse) Reset() {
+	*x = GetAllDeviceResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_gosdn_device_device_proto_msgTypes[7]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *GetAllDeviceResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetAllDeviceResponse) ProtoMessage() {}
+
+func (x *GetAllDeviceResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_gosdn_device_device_proto_msgTypes[7]
+	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 GetAllDeviceResponse.ProtoReflect.Descriptor instead.
+func (*GetAllDeviceResponse) Descriptor() ([]byte, []int) {
+	return file_gosdn_device_device_proto_rawDescGZIP(), []int{7}
+}
+
+func (x *GetAllDeviceResponse) GetTimestamp() int64 {
+	if x != nil {
+		return x.Timestamp
+	}
+	return 0
+}
+
+func (x *GetAllDeviceResponse) GetStatus() Status {
+	if x != nil {
+		return x.Status
+	}
+	return Status_STATUS_UNSPECIFIED
+}
+
+func (x *GetAllDeviceResponse) GetDevice() []*Device {
+	if x != nil {
+		return x.Device
+	}
+	return nil
+}
+
+type UpdateDeviceRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Timestamp int64   `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
+	Device    *Device `protobuf:"bytes,2,opt,name=device,proto3" json:"device,omitempty"`
+}
+
+func (x *UpdateDeviceRequest) Reset() {
+	*x = UpdateDeviceRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_gosdn_device_device_proto_msgTypes[8]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *UpdateDeviceRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UpdateDeviceRequest) ProtoMessage() {}
+
+func (x *UpdateDeviceRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_gosdn_device_device_proto_msgTypes[8]
+	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 UpdateDeviceRequest.ProtoReflect.Descriptor instead.
+func (*UpdateDeviceRequest) Descriptor() ([]byte, []int) {
+	return file_gosdn_device_device_proto_rawDescGZIP(), []int{8}
+}
+
+func (x *UpdateDeviceRequest) GetTimestamp() int64 {
+	if x != nil {
+		return x.Timestamp
+	}
+	return 0
+}
+
+func (x *UpdateDeviceRequest) GetDevice() *Device {
+	if x != nil {
+		return x.Device
+	}
+	return nil
+}
+
+type UpdateDeviceResponse struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Timestamp int64  `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
+	Status    Status `protobuf:"varint,2,opt,name=status,proto3,enum=gosdn.device.Status" json:"status,omitempty"`
+}
+
+func (x *UpdateDeviceResponse) Reset() {
+	*x = UpdateDeviceResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_gosdn_device_device_proto_msgTypes[9]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *UpdateDeviceResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UpdateDeviceResponse) ProtoMessage() {}
+
+func (x *UpdateDeviceResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_gosdn_device_device_proto_msgTypes[9]
+	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 UpdateDeviceResponse.ProtoReflect.Descriptor instead.
+func (*UpdateDeviceResponse) Descriptor() ([]byte, []int) {
+	return file_gosdn_device_device_proto_rawDescGZIP(), []int{9}
+}
+
+func (x *UpdateDeviceResponse) GetTimestamp() int64 {
+	if x != nil {
+		return x.Timestamp
+	}
+	return 0
+}
+
+func (x *UpdateDeviceResponse) GetStatus() Status {
+	if x != nil {
+		return x.Status
+	}
+	return Status_STATUS_UNSPECIFIED
+}
+
+type DeleteDeviceRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Timestamp int64  `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
+	DeviceID  string `protobuf:"bytes,2,opt,name=deviceID,proto3" json:"deviceID,omitempty"`
+}
+
+func (x *DeleteDeviceRequest) Reset() {
+	*x = DeleteDeviceRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_gosdn_device_device_proto_msgTypes[10]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *DeleteDeviceRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DeleteDeviceRequest) ProtoMessage() {}
+
+func (x *DeleteDeviceRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_gosdn_device_device_proto_msgTypes[10]
+	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 DeleteDeviceRequest.ProtoReflect.Descriptor instead.
+func (*DeleteDeviceRequest) Descriptor() ([]byte, []int) {
+	return file_gosdn_device_device_proto_rawDescGZIP(), []int{10}
+}
+
+func (x *DeleteDeviceRequest) GetTimestamp() int64 {
+	if x != nil {
+		return x.Timestamp
+	}
+	return 0
+}
+
+func (x *DeleteDeviceRequest) GetDeviceID() string {
+	if x != nil {
+		return x.DeviceID
+	}
+	return ""
+}
+
+type DeleteDeviceResponse struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Timestamp int64  `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
+	Status    Status `protobuf:"varint,2,opt,name=status,proto3,enum=gosdn.device.Status" json:"status,omitempty"`
+}
+
+func (x *DeleteDeviceResponse) Reset() {
+	*x = DeleteDeviceResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_gosdn_device_device_proto_msgTypes[11]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *DeleteDeviceResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DeleteDeviceResponse) ProtoMessage() {}
+
+func (x *DeleteDeviceResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_gosdn_device_device_proto_msgTypes[11]
+	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 DeleteDeviceResponse.ProtoReflect.Descriptor instead.
+func (*DeleteDeviceResponse) Descriptor() ([]byte, []int) {
+	return file_gosdn_device_device_proto_rawDescGZIP(), []int{11}
+}
+
+func (x *DeleteDeviceResponse) GetTimestamp() int64 {
+	if x != nil {
+		return x.Timestamp
+	}
+	return 0
+}
+
+func (x *DeleteDeviceResponse) GetStatus() Status {
+	if x != nil {
+		return x.Status
+	}
+	return Status_STATUS_UNSPECIFIED
+}
+
+var File_gosdn_device_device_proto protoreflect.FileDescriptor
+
+var file_gosdn_device_device_proto_rawDesc = []byte{
+	0x0a, 0x19, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x2f, 0x64,
+	0x65, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0c, 0x67, 0x6f, 0x73,
+	0x64, 0x6e, 0x2e, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
+	0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+	0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70,
+	0x74, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2f,
+	0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69,
+	0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x30, 0x67, 0x69, 0x74, 0x68, 0x75,
+	0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
+	0x2f, 0x67, 0x6e, 0x6d, 0x69, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6e, 0x6d, 0x69,
+	0x2f, 0x67, 0x6e, 0x6d, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x13, 0x67, 0x6f, 0x73,
+	0x64, 0x6e, 0x2f, 0x70, 0x6e, 0x64, 0x2f, 0x70, 0x6e, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x1a, 0x1f, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72,
+	0x74, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x1a, 0x21, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2f, 0x73, 0x6f, 0x75, 0x74, 0x68, 0x62, 0x6f,
+	0x75, 0x6e, 0x64, 0x2f, 0x73, 0x6f, 0x75, 0x74, 0x68, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x2e, 0x70,
+	0x72, 0x6f, 0x74, 0x6f, 0x22, 0x42, 0x0a, 0x06, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x0e,
+	0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12,
+	0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61,
+	0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x22, 0xd9, 0x01, 0x0a, 0x16, 0x41, 0x64, 0x64,
+	0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74,
+	0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x37, 0x0a,
+	0x03, 0x73, 0x62, 0x69, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x67, 0x6f, 0x73,
+	0x64, 0x6e, 0x2e, 0x73, 0x6f, 0x75, 0x74, 0x68, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x2e, 0x53, 0x6f,
+	0x75, 0x74, 0x68, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63,
+	0x65, 0x52, 0x03, 0x73, 0x62, 0x69, 0x12, 0x1f, 0x0a, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65,
+	0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x65, 0x76,
+	0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x4b, 0x0a, 0x10, 0x74, 0x72, 0x61, 0x6e, 0x73,
+	0x70, 0x6f, 0x72, 0x74, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28,
+	0x0b, 0x32, 0x20, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70,
+	0x6f, 0x72, 0x74, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x4f, 0x70, 0x74,
+	0x69, 0x6f, 0x6e, 0x52, 0x0f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x4f, 0x70,
+	0x74, 0x69, 0x6f, 0x6e, 0x22, 0x80, 0x01, 0x0a, 0x10, 0x41, 0x64, 0x64, 0x44, 0x65, 0x76, 0x69,
+	0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d,
+	0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69,
+	0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x3c, 0x0a, 0x06, 0x64, 0x65, 0x76, 0x69, 0x63,
+	0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e,
+	0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65,
+	0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x06, 0x64,
+	0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x03, 0x70, 0x69, 0x64, 0x22, 0x7b, 0x0a, 0x11, 0x41, 0x64, 0x64, 0x44, 0x65,
+	0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09,
+	0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52,
+	0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2c, 0x0a, 0x06, 0x73, 0x74,
+	0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x73,
+	0x64, 0x6e, 0x2e, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
+	0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x65, 0x76, 0x69,
+	0x63, 0x65, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69,
+	0x63, 0x65, 0x49, 0x64, 0x22, 0x4c, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63,
+	0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65,
+	0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d,
+	0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65,
+	0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65,
+	0x49, 0x44, 0x22, 0x8d, 0x01, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65,
+	0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65,
+	0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d,
+	0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2c, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73,
+	0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x64,
+	0x65, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74,
+	0x61, 0x74, 0x75, 0x73, 0x12, 0x2c, 0x0a, 0x06, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x18, 0x03,
+	0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x64, 0x65, 0x76,
+	0x69, 0x63, 0x65, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x06, 0x64, 0x65, 0x76, 0x69,
+	0x63, 0x65, 0x22, 0x33, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x44, 0x65, 0x76, 0x69,
+	0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d,
+	0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69,
+	0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x90, 0x01, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x41,
+	0x6c, 0x6c, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+	0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20,
+	0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2c,
+	0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x14,
+	0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x74,
+	0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x2c, 0x0a, 0x06,
+	0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67,
+	0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, 0x65, 0x76, 0x69,
+	0x63, 0x65, 0x52, 0x06, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x22, 0x61, 0x0a, 0x13, 0x55, 0x70,
+	0x64, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+	0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12,
+	0x2c, 0x0a, 0x06, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
+	0x14, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44,
+	0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x06, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x22, 0x62, 0x0a,
+	0x14, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73,
+	0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
+	0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74,
+	0x61, 0x6d, 0x70, 0x12, 0x2c, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20,
+	0x01, 0x28, 0x0e, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x64, 0x65, 0x76, 0x69,
+	0x63, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75,
+	0x73, 0x22, 0x4f, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63,
+	0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65,
+	0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d,
+	0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65,
+	0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65,
+	0x49, 0x44, 0x22, 0x62, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69,
+	0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69,
+	0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74,
+	0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2c, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74,
+	0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e,
+	0x2e, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06,
+	0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2a, 0x41, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
+	0x12, 0x16, 0x0a, 0x12, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45,
+	0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x53, 0x54, 0x41, 0x54,
+	0x55, 0x53, 0x5f, 0x4f, 0x4b, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x53, 0x54, 0x41, 0x54, 0x55,
+	0x53, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x32, 0x9d, 0x03, 0x0a, 0x0d, 0x44, 0x65,
+	0x76, 0x69, 0x63, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x61, 0x0a, 0x03, 0x41,
+	0x64, 0x64, 0x12, 0x1e, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x64, 0x65, 0x76, 0x69, 0x63,
+	0x65, 0x2e, 0x41, 0x64, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
+	0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x64, 0x65, 0x76, 0x69, 0x63,
+	0x65, 0x2e, 0x41, 0x64, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f,
+	0x6e, 0x73, 0x65, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x3a, 0x01, 0x2a, 0x22, 0x0e,
+	0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x2f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x57,
+	0x0a, 0x03, 0x47, 0x65, 0x74, 0x12, 0x1e, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x64, 0x65,
+	0x76, 0x69, 0x63, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65,
+	0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x64, 0x65,
+	0x76, 0x69, 0x63, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65,
+	0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x0f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x09, 0x12, 0x07,
+	0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x64, 0x0a, 0x06, 0x47, 0x65, 0x74, 0x41, 0x6c,
+	0x6c, 0x12, 0x21, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65,
+	0x2e, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71,
+	0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x64, 0x65, 0x76,
+	0x69, 0x63, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65,
+	0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x13, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0d,
+	0x12, 0x0b, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x2f, 0x61, 0x6c, 0x6c, 0x12, 0x6a, 0x0a,
+	0x06, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x21, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e,
+	0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76,
+	0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x67, 0x6f, 0x73,
+	0x64, 0x6e, 0x2e, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65,
+	0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x19,
+	0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x3a, 0x01, 0x2a, 0x22, 0x0e, 0x2f, 0x64, 0x65, 0x76, 0x69,
+	0x63, 0x65, 0x2f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x42, 0x32, 0x5a, 0x30, 0x63, 0x6f, 0x64,
+	0x65, 0x2e, 0x66, 0x62, 0x69, 0x2e, 0x68, 0x2d, 0x64, 0x61, 0x2e, 0x64, 0x65, 0x2f, 0x64, 0x61,
+	0x6e, 0x65, 0x74, 0x2f, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x6f,
+	0x2f, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x62, 0x06, 0x70,
+	0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+	file_gosdn_device_device_proto_rawDescOnce sync.Once
+	file_gosdn_device_device_proto_rawDescData = file_gosdn_device_device_proto_rawDesc
+)
+
+func file_gosdn_device_device_proto_rawDescGZIP() []byte {
+	file_gosdn_device_device_proto_rawDescOnce.Do(func() {
+		file_gosdn_device_device_proto_rawDescData = protoimpl.X.CompressGZIP(file_gosdn_device_device_proto_rawDescData)
+	})
+	return file_gosdn_device_device_proto_rawDescData
+}
+
+var file_gosdn_device_device_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
+var file_gosdn_device_device_proto_msgTypes = make([]protoimpl.MessageInfo, 12)
+var file_gosdn_device_device_proto_goTypes = []interface{}{
+	(Status)(0),                            // 0: gosdn.device.Status
+	(*Device)(nil),                         // 1: gosdn.device.Device
+	(*AddDeviceConfiguration)(nil),         // 2: gosdn.device.AddDeviceConfiguration
+	(*AddDeviceRequest)(nil),               // 3: gosdn.device.AddDeviceRequest
+	(*AddDeviceResponse)(nil),              // 4: gosdn.device.AddDeviceResponse
+	(*GetDeviceRequest)(nil),               // 5: gosdn.device.GetDeviceRequest
+	(*GetDeviceResponse)(nil),              // 6: gosdn.device.GetDeviceResponse
+	(*GetAllDeviceRequest)(nil),            // 7: gosdn.device.GetAllDeviceRequest
+	(*GetAllDeviceResponse)(nil),           // 8: gosdn.device.GetAllDeviceResponse
+	(*UpdateDeviceRequest)(nil),            // 9: gosdn.device.UpdateDeviceRequest
+	(*UpdateDeviceResponse)(nil),           // 10: gosdn.device.UpdateDeviceResponse
+	(*DeleteDeviceRequest)(nil),            // 11: gosdn.device.DeleteDeviceRequest
+	(*DeleteDeviceResponse)(nil),           // 12: gosdn.device.DeleteDeviceResponse
+	(*southbound.SouthboundInterface)(nil), // 13: gosdn.southbound.SouthboundInterface
+	(*transport.TransportOption)(nil),      // 14: gosdn.transport.TransportOption
+}
+var file_gosdn_device_device_proto_depIdxs = []int32{
+	13, // 0: gosdn.device.AddDeviceConfiguration.sbi:type_name -> gosdn.southbound.SouthboundInterface
+	14, // 1: gosdn.device.AddDeviceConfiguration.transport_option:type_name -> gosdn.transport.TransportOption
+	2,  // 2: gosdn.device.AddDeviceRequest.device:type_name -> gosdn.device.AddDeviceConfiguration
+	0,  // 3: gosdn.device.AddDeviceResponse.status:type_name -> gosdn.device.Status
+	0,  // 4: gosdn.device.GetDeviceResponse.status:type_name -> gosdn.device.Status
+	1,  // 5: gosdn.device.GetDeviceResponse.device:type_name -> gosdn.device.Device
+	0,  // 6: gosdn.device.GetAllDeviceResponse.status:type_name -> gosdn.device.Status
+	1,  // 7: gosdn.device.GetAllDeviceResponse.device:type_name -> gosdn.device.Device
+	1,  // 8: gosdn.device.UpdateDeviceRequest.device:type_name -> gosdn.device.Device
+	0,  // 9: gosdn.device.UpdateDeviceResponse.status:type_name -> gosdn.device.Status
+	0,  // 10: gosdn.device.DeleteDeviceResponse.status:type_name -> gosdn.device.Status
+	3,  // 11: gosdn.device.DeviceService.Add:input_type -> gosdn.device.AddDeviceRequest
+	5,  // 12: gosdn.device.DeviceService.Get:input_type -> gosdn.device.GetDeviceRequest
+	7,  // 13: gosdn.device.DeviceService.GetAll:input_type -> gosdn.device.GetAllDeviceRequest
+	9,  // 14: gosdn.device.DeviceService.Update:input_type -> gosdn.device.UpdateDeviceRequest
+	4,  // 15: gosdn.device.DeviceService.Add:output_type -> gosdn.device.AddDeviceResponse
+	6,  // 16: gosdn.device.DeviceService.Get:output_type -> gosdn.device.GetDeviceResponse
+	8,  // 17: gosdn.device.DeviceService.GetAll:output_type -> gosdn.device.GetAllDeviceResponse
+	10, // 18: gosdn.device.DeviceService.Update:output_type -> gosdn.device.UpdateDeviceResponse
+	15, // [15:19] is the sub-list for method output_type
+	11, // [11:15] 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
+}
+
+func init() { file_gosdn_device_device_proto_init() }
+func file_gosdn_device_device_proto_init() {
+	if File_gosdn_device_device_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_gosdn_device_device_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Device); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_gosdn_device_device_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*AddDeviceConfiguration); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_gosdn_device_device_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*AddDeviceRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_gosdn_device_device_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*AddDeviceResponse); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_gosdn_device_device_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*GetDeviceRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_gosdn_device_device_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*GetDeviceResponse); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_gosdn_device_device_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*GetAllDeviceRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_gosdn_device_device_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*GetAllDeviceResponse); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_gosdn_device_device_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*UpdateDeviceRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_gosdn_device_device_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*UpdateDeviceResponse); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_gosdn_device_device_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*DeleteDeviceRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_gosdn_device_device_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*DeleteDeviceResponse); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_gosdn_device_device_proto_rawDesc,
+			NumEnums:      1,
+			NumMessages:   12,
+			NumExtensions: 0,
+			NumServices:   1,
+		},
+		GoTypes:           file_gosdn_device_device_proto_goTypes,
+		DependencyIndexes: file_gosdn_device_device_proto_depIdxs,
+		EnumInfos:         file_gosdn_device_device_proto_enumTypes,
+		MessageInfos:      file_gosdn_device_device_proto_msgTypes,
+	}.Build()
+	File_gosdn_device_device_proto = out.File
+	file_gosdn_device_device_proto_rawDesc = nil
+	file_gosdn_device_device_proto_goTypes = nil
+	file_gosdn_device_device_proto_depIdxs = nil
+}
diff --git a/api/go/gosdn/device/device.pb.gw.go b/api/go/gosdn/device/device.pb.gw.go
new file mode 100644
index 0000000000000000000000000000000000000000..64ca57255f446d0de326e6fa388a479d7416c998
--- /dev/null
+++ b/api/go/gosdn/device/device.pb.gw.go
@@ -0,0 +1,414 @@
+// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
+// source: gosdn/device/device.proto
+
+/*
+Package device is a reverse proxy.
+
+It translates gRPC into RESTful JSON APIs.
+*/
+package device
+
+import (
+	"context"
+	"io"
+	"net/http"
+
+	"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
+	"github.com/grpc-ecosystem/grpc-gateway/v2/utilities"
+	"google.golang.org/grpc"
+	"google.golang.org/grpc/codes"
+	"google.golang.org/grpc/grpclog"
+	"google.golang.org/grpc/metadata"
+	"google.golang.org/grpc/status"
+	"google.golang.org/protobuf/proto"
+)
+
+// Suppress "imported and not used" errors
+var _ codes.Code
+var _ io.Reader
+var _ status.Status
+var _ = runtime.String
+var _ = utilities.NewDoubleArray
+var _ = metadata.Join
+
+func request_DeviceService_Add_0(ctx context.Context, marshaler runtime.Marshaler, client DeviceServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+	var protoReq AddDeviceRequest
+	var metadata runtime.ServerMetadata
+
+	newReader, berr := utilities.IOReaderFactory(req.Body)
+	if berr != nil {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
+	}
+	if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
+	}
+
+	msg, err := client.Add(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
+	return msg, metadata, err
+
+}
+
+func local_request_DeviceService_Add_0(ctx context.Context, marshaler runtime.Marshaler, server DeviceServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+	var protoReq AddDeviceRequest
+	var metadata runtime.ServerMetadata
+
+	newReader, berr := utilities.IOReaderFactory(req.Body)
+	if berr != nil {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
+	}
+	if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
+	}
+
+	msg, err := server.Add(ctx, &protoReq)
+	return msg, metadata, err
+
+}
+
+var (
+	filter_DeviceService_Get_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
+)
+
+func request_DeviceService_Get_0(ctx context.Context, marshaler runtime.Marshaler, client DeviceServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+	var protoReq GetDeviceRequest
+	var metadata runtime.ServerMetadata
+
+	if err := req.ParseForm(); err != nil {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
+	}
+	if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_DeviceService_Get_0); err != nil {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
+	}
+
+	msg, err := client.Get(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
+	return msg, metadata, err
+
+}
+
+func local_request_DeviceService_Get_0(ctx context.Context, marshaler runtime.Marshaler, server DeviceServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+	var protoReq GetDeviceRequest
+	var metadata runtime.ServerMetadata
+
+	if err := req.ParseForm(); err != nil {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
+	}
+	if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_DeviceService_Get_0); err != nil {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
+	}
+
+	msg, err := server.Get(ctx, &protoReq)
+	return msg, metadata, err
+
+}
+
+var (
+	filter_DeviceService_GetAll_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
+)
+
+func request_DeviceService_GetAll_0(ctx context.Context, marshaler runtime.Marshaler, client DeviceServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+	var protoReq GetAllDeviceRequest
+	var metadata runtime.ServerMetadata
+
+	if err := req.ParseForm(); err != nil {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
+	}
+	if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_DeviceService_GetAll_0); err != nil {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
+	}
+
+	msg, err := client.GetAll(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
+	return msg, metadata, err
+
+}
+
+func local_request_DeviceService_GetAll_0(ctx context.Context, marshaler runtime.Marshaler, server DeviceServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+	var protoReq GetAllDeviceRequest
+	var metadata runtime.ServerMetadata
+
+	if err := req.ParseForm(); err != nil {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
+	}
+	if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_DeviceService_GetAll_0); err != nil {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
+	}
+
+	msg, err := server.GetAll(ctx, &protoReq)
+	return msg, metadata, err
+
+}
+
+func request_DeviceService_Update_0(ctx context.Context, marshaler runtime.Marshaler, client DeviceServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+	var protoReq UpdateDeviceRequest
+	var metadata runtime.ServerMetadata
+
+	newReader, berr := utilities.IOReaderFactory(req.Body)
+	if berr != nil {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
+	}
+	if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
+	}
+
+	msg, err := client.Update(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
+	return msg, metadata, err
+
+}
+
+func local_request_DeviceService_Update_0(ctx context.Context, marshaler runtime.Marshaler, server DeviceServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+	var protoReq UpdateDeviceRequest
+	var metadata runtime.ServerMetadata
+
+	newReader, berr := utilities.IOReaderFactory(req.Body)
+	if berr != nil {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
+	}
+	if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
+	}
+
+	msg, err := server.Update(ctx, &protoReq)
+	return msg, metadata, err
+
+}
+
+// RegisterDeviceServiceHandlerServer registers the http handlers for service DeviceService to "mux".
+// UnaryRPC     :call DeviceServiceServer directly.
+// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
+// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterDeviceServiceHandlerFromEndpoint instead.
+func RegisterDeviceServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server DeviceServiceServer) error {
+
+	mux.Handle("POST", pattern_DeviceService_Add_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+		ctx, cancel := context.WithCancel(req.Context())
+		defer cancel()
+		var stream runtime.ServerTransportStream
+		ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
+		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/gosdn.device.DeviceService/Add", runtime.WithHTTPPathPattern("/device/create"))
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+		resp, md, err := local_request_DeviceService_Add_0(rctx, inboundMarshaler, server, req, pathParams)
+		md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
+		ctx = runtime.NewServerMetadataContext(ctx, md)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+
+		forward_DeviceService_Add_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+	})
+
+	mux.Handle("GET", pattern_DeviceService_Get_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+		ctx, cancel := context.WithCancel(req.Context())
+		defer cancel()
+		var stream runtime.ServerTransportStream
+		ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
+		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/gosdn.device.DeviceService/Get", runtime.WithHTTPPathPattern("/device"))
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+		resp, md, err := local_request_DeviceService_Get_0(rctx, inboundMarshaler, server, req, pathParams)
+		md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
+		ctx = runtime.NewServerMetadataContext(ctx, md)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+
+		forward_DeviceService_Get_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+	})
+
+	mux.Handle("GET", pattern_DeviceService_GetAll_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+		ctx, cancel := context.WithCancel(req.Context())
+		defer cancel()
+		var stream runtime.ServerTransportStream
+		ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
+		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/gosdn.device.DeviceService/GetAll", runtime.WithHTTPPathPattern("/device/all"))
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+		resp, md, err := local_request_DeviceService_GetAll_0(rctx, inboundMarshaler, server, req, pathParams)
+		md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
+		ctx = runtime.NewServerMetadataContext(ctx, md)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+
+		forward_DeviceService_GetAll_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+	})
+
+	mux.Handle("POST", pattern_DeviceService_Update_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+		ctx, cancel := context.WithCancel(req.Context())
+		defer cancel()
+		var stream runtime.ServerTransportStream
+		ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
+		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/gosdn.device.DeviceService/Update", runtime.WithHTTPPathPattern("/device/update"))
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+		resp, md, err := local_request_DeviceService_Update_0(rctx, inboundMarshaler, server, req, pathParams)
+		md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
+		ctx = runtime.NewServerMetadataContext(ctx, md)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+
+		forward_DeviceService_Update_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+	})
+
+	return nil
+}
+
+// RegisterDeviceServiceHandlerFromEndpoint is same as RegisterDeviceServiceHandler but
+// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
+func RegisterDeviceServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
+	conn, err := grpc.Dial(endpoint, opts...)
+	if err != nil {
+		return err
+	}
+	defer func() {
+		if err != nil {
+			if cerr := conn.Close(); cerr != nil {
+				grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
+			}
+			return
+		}
+		go func() {
+			<-ctx.Done()
+			if cerr := conn.Close(); cerr != nil {
+				grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
+			}
+		}()
+	}()
+
+	return RegisterDeviceServiceHandler(ctx, mux, conn)
+}
+
+// RegisterDeviceServiceHandler registers the http handlers for service DeviceService to "mux".
+// The handlers forward requests to the grpc endpoint over "conn".
+func RegisterDeviceServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
+	return RegisterDeviceServiceHandlerClient(ctx, mux, NewDeviceServiceClient(conn))
+}
+
+// RegisterDeviceServiceHandlerClient registers the http handlers for service DeviceService
+// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "DeviceServiceClient".
+// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "DeviceServiceClient"
+// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
+// "DeviceServiceClient" to call the correct interceptors.
+func RegisterDeviceServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client DeviceServiceClient) error {
+
+	mux.Handle("POST", pattern_DeviceService_Add_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+		ctx, cancel := context.WithCancel(req.Context())
+		defer cancel()
+		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/gosdn.device.DeviceService/Add", runtime.WithHTTPPathPattern("/device/create"))
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+		resp, md, err := request_DeviceService_Add_0(rctx, inboundMarshaler, client, req, pathParams)
+		ctx = runtime.NewServerMetadataContext(ctx, md)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+
+		forward_DeviceService_Add_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+	})
+
+	mux.Handle("GET", pattern_DeviceService_Get_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+		ctx, cancel := context.WithCancel(req.Context())
+		defer cancel()
+		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/gosdn.device.DeviceService/Get", runtime.WithHTTPPathPattern("/device"))
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+		resp, md, err := request_DeviceService_Get_0(rctx, inboundMarshaler, client, req, pathParams)
+		ctx = runtime.NewServerMetadataContext(ctx, md)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+
+		forward_DeviceService_Get_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+	})
+
+	mux.Handle("GET", pattern_DeviceService_GetAll_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+		ctx, cancel := context.WithCancel(req.Context())
+		defer cancel()
+		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/gosdn.device.DeviceService/GetAll", runtime.WithHTTPPathPattern("/device/all"))
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+		resp, md, err := request_DeviceService_GetAll_0(rctx, inboundMarshaler, client, req, pathParams)
+		ctx = runtime.NewServerMetadataContext(ctx, md)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+
+		forward_DeviceService_GetAll_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+	})
+
+	mux.Handle("POST", pattern_DeviceService_Update_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+		ctx, cancel := context.WithCancel(req.Context())
+		defer cancel()
+		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/gosdn.device.DeviceService/Update", runtime.WithHTTPPathPattern("/device/update"))
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+		resp, md, err := request_DeviceService_Update_0(rctx, inboundMarshaler, client, req, pathParams)
+		ctx = runtime.NewServerMetadataContext(ctx, md)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+
+		forward_DeviceService_Update_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+	})
+
+	return nil
+}
+
+var (
+	pattern_DeviceService_Add_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"device", "create"}, ""))
+
+	pattern_DeviceService_Get_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"device"}, ""))
+
+	pattern_DeviceService_GetAll_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"device", "all"}, ""))
+
+	pattern_DeviceService_Update_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"device", "update"}, ""))
+)
+
+var (
+	forward_DeviceService_Add_0 = runtime.ForwardResponseMessage
+
+	forward_DeviceService_Get_0 = runtime.ForwardResponseMessage
+
+	forward_DeviceService_GetAll_0 = runtime.ForwardResponseMessage
+
+	forward_DeviceService_Update_0 = runtime.ForwardResponseMessage
+)
diff --git a/api/go/gosdn/device/device_grpc.pb.go b/api/go/gosdn/device/device_grpc.pb.go
new file mode 100644
index 0000000000000000000000000000000000000000..c3ac5549182b86db55db544ed5a19e6b3f9ac5e1
--- /dev/null
+++ b/api/go/gosdn/device/device_grpc.pb.go
@@ -0,0 +1,209 @@
+// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
+
+package device
+
+import (
+	context "context"
+	grpc "google.golang.org/grpc"
+	codes "google.golang.org/grpc/codes"
+	status "google.golang.org/grpc/status"
+)
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+// Requires gRPC-Go v1.32.0 or later.
+const _ = grpc.SupportPackageIsVersion7
+
+// DeviceServiceClient is the client API for DeviceService 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 DeviceServiceClient interface {
+	Add(ctx context.Context, in *AddDeviceRequest, opts ...grpc.CallOption) (*AddDeviceResponse, error)
+	Get(ctx context.Context, in *GetDeviceRequest, opts ...grpc.CallOption) (*GetDeviceResponse, error)
+	GetAll(ctx context.Context, in *GetAllDeviceRequest, opts ...grpc.CallOption) (*GetAllDeviceResponse, error)
+	Update(ctx context.Context, in *UpdateDeviceRequest, opts ...grpc.CallOption) (*UpdateDeviceResponse, error)
+}
+
+type deviceServiceClient struct {
+	cc grpc.ClientConnInterface
+}
+
+func NewDeviceServiceClient(cc grpc.ClientConnInterface) DeviceServiceClient {
+	return &deviceServiceClient{cc}
+}
+
+func (c *deviceServiceClient) Add(ctx context.Context, in *AddDeviceRequest, opts ...grpc.CallOption) (*AddDeviceResponse, error) {
+	out := new(AddDeviceResponse)
+	err := c.cc.Invoke(ctx, "/gosdn.device.DeviceService/Add", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *deviceServiceClient) Get(ctx context.Context, in *GetDeviceRequest, opts ...grpc.CallOption) (*GetDeviceResponse, error) {
+	out := new(GetDeviceResponse)
+	err := c.cc.Invoke(ctx, "/gosdn.device.DeviceService/Get", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *deviceServiceClient) GetAll(ctx context.Context, in *GetAllDeviceRequest, opts ...grpc.CallOption) (*GetAllDeviceResponse, error) {
+	out := new(GetAllDeviceResponse)
+	err := c.cc.Invoke(ctx, "/gosdn.device.DeviceService/GetAll", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *deviceServiceClient) Update(ctx context.Context, in *UpdateDeviceRequest, opts ...grpc.CallOption) (*UpdateDeviceResponse, error) {
+	out := new(UpdateDeviceResponse)
+	err := c.cc.Invoke(ctx, "/gosdn.device.DeviceService/Update", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+// DeviceServiceServer is the server API for DeviceService service.
+// All implementations must embed UnimplementedDeviceServiceServer
+// for forward compatibility
+type DeviceServiceServer interface {
+	Add(context.Context, *AddDeviceRequest) (*AddDeviceResponse, error)
+	Get(context.Context, *GetDeviceRequest) (*GetDeviceResponse, error)
+	GetAll(context.Context, *GetAllDeviceRequest) (*GetAllDeviceResponse, error)
+	Update(context.Context, *UpdateDeviceRequest) (*UpdateDeviceResponse, error)
+	mustEmbedUnimplementedDeviceServiceServer()
+}
+
+// UnimplementedDeviceServiceServer must be embedded to have forward compatible implementations.
+type UnimplementedDeviceServiceServer struct {
+}
+
+func (UnimplementedDeviceServiceServer) Add(context.Context, *AddDeviceRequest) (*AddDeviceResponse, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method Add not implemented")
+}
+func (UnimplementedDeviceServiceServer) Get(context.Context, *GetDeviceRequest) (*GetDeviceResponse, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method Get not implemented")
+}
+func (UnimplementedDeviceServiceServer) GetAll(context.Context, *GetAllDeviceRequest) (*GetAllDeviceResponse, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method GetAll not implemented")
+}
+func (UnimplementedDeviceServiceServer) Update(context.Context, *UpdateDeviceRequest) (*UpdateDeviceResponse, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method Update not implemented")
+}
+func (UnimplementedDeviceServiceServer) mustEmbedUnimplementedDeviceServiceServer() {}
+
+// UnsafeDeviceServiceServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to DeviceServiceServer will
+// result in compilation errors.
+type UnsafeDeviceServiceServer interface {
+	mustEmbedUnimplementedDeviceServiceServer()
+}
+
+func RegisterDeviceServiceServer(s grpc.ServiceRegistrar, srv DeviceServiceServer) {
+	s.RegisterService(&DeviceService_ServiceDesc, srv)
+}
+
+func _DeviceService_Add_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(AddDeviceRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(DeviceServiceServer).Add(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/gosdn.device.DeviceService/Add",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(DeviceServiceServer).Add(ctx, req.(*AddDeviceRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _DeviceService_Get_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(GetDeviceRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(DeviceServiceServer).Get(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/gosdn.device.DeviceService/Get",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(DeviceServiceServer).Get(ctx, req.(*GetDeviceRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _DeviceService_GetAll_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(GetAllDeviceRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(DeviceServiceServer).GetAll(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/gosdn.device.DeviceService/GetAll",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(DeviceServiceServer).GetAll(ctx, req.(*GetAllDeviceRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _DeviceService_Update_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(UpdateDeviceRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(DeviceServiceServer).Update(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/gosdn.device.DeviceService/Update",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(DeviceServiceServer).Update(ctx, req.(*UpdateDeviceRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+// DeviceService_ServiceDesc is the grpc.ServiceDesc for DeviceService service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var DeviceService_ServiceDesc = grpc.ServiceDesc{
+	ServiceName: "gosdn.device.DeviceService",
+	HandlerType: (*DeviceServiceServer)(nil),
+	Methods: []grpc.MethodDesc{
+		{
+			MethodName: "Add",
+			Handler:    _DeviceService_Add_Handler,
+		},
+		{
+			MethodName: "Get",
+			Handler:    _DeviceService_Get_Handler,
+		},
+		{
+			MethodName: "GetAll",
+			Handler:    _DeviceService_GetAll_Handler,
+		},
+		{
+			MethodName: "Update",
+			Handler:    _DeviceService_Update_Handler,
+		},
+	},
+	Streams:  []grpc.StreamDesc{},
+	Metadata: "gosdn/device/device.proto",
+}
diff --git a/api/openapiv2/gosdn_northbound.swagger.json b/api/openapiv2/gosdn_northbound.swagger.json
index b9ded2cc7a626857f7fd65de11bd4274aa5c5c01..af22a6a6698f1af5938dafe014840b2d62e12995 100644
--- a/api/openapiv2/gosdn_northbound.swagger.json
+++ b/api/openapiv2/gosdn_northbound.swagger.json
@@ -35,6 +35,9 @@
     {
       "name": "CsbiService"
     },
+    {
+      "name": "DeviceService"
+    },
     {
       "name": "AuthService"
     },
@@ -55,6 +58,138 @@
     "application/json"
   ],
   "paths": {
+    "/device": {
+      "get": {
+        "operationId": "DeviceService_Get",
+        "responses": {
+          "200": {
+            "description": "A successful response.",
+            "schema": {
+              "$ref": "#/definitions/deviceGetDeviceResponse"
+            }
+          },
+          "default": {
+            "description": "An unexpected error response.",
+            "schema": {
+              "$ref": "#/definitions/googlerpcStatus"
+            }
+          }
+        },
+        "parameters": [
+          {
+            "name": "timestamp",
+            "in": "query",
+            "required": false,
+            "type": "string",
+            "format": "int64"
+          },
+          {
+            "name": "deviceID",
+            "in": "query",
+            "required": false,
+            "type": "string"
+          }
+        ],
+        "tags": [
+          "DeviceService"
+        ]
+      }
+    },
+    "/device/all": {
+      "get": {
+        "operationId": "DeviceService_GetAll",
+        "responses": {
+          "200": {
+            "description": "A successful response.",
+            "schema": {
+              "$ref": "#/definitions/deviceGetAllDeviceResponse"
+            }
+          },
+          "default": {
+            "description": "An unexpected error response.",
+            "schema": {
+              "$ref": "#/definitions/googlerpcStatus"
+            }
+          }
+        },
+        "parameters": [
+          {
+            "name": "timestamp",
+            "in": "query",
+            "required": false,
+            "type": "string",
+            "format": "int64"
+          }
+        ],
+        "tags": [
+          "DeviceService"
+        ]
+      }
+    },
+    "/device/create": {
+      "post": {
+        "operationId": "DeviceService_Add",
+        "responses": {
+          "200": {
+            "description": "A successful response.",
+            "schema": {
+              "$ref": "#/definitions/deviceAddDeviceResponse"
+            }
+          },
+          "default": {
+            "description": "An unexpected error response.",
+            "schema": {
+              "$ref": "#/definitions/googlerpcStatus"
+            }
+          }
+        },
+        "parameters": [
+          {
+            "name": "body",
+            "in": "body",
+            "required": true,
+            "schema": {
+              "$ref": "#/definitions/deviceAddDeviceRequest"
+            }
+          }
+        ],
+        "tags": [
+          "DeviceService"
+        ]
+      }
+    },
+    "/device/update": {
+      "post": {
+        "operationId": "DeviceService_Update",
+        "responses": {
+          "200": {
+            "description": "A successful response.",
+            "schema": {
+              "$ref": "#/definitions/deviceUpdateDeviceResponse"
+            }
+          },
+          "default": {
+            "description": "An unexpected error response.",
+            "schema": {
+              "$ref": "#/definitions/googlerpcStatus"
+            }
+          }
+        },
+        "parameters": [
+          {
+            "name": "body",
+            "in": "body",
+            "required": true,
+            "schema": {
+              "$ref": "#/definitions/deviceUpdateDeviceRequest"
+            }
+          }
+        ],
+        "tags": [
+          "DeviceService"
+        ]
+      }
+    },
     "/login": {
       "post": {
         "summary": "Allows a user to login creating a session for further actions.",
@@ -1531,6 +1666,124 @@
         }
       }
     },
+    "deviceAddDeviceConfiguration": {
+      "type": "object",
+      "properties": {
+        "address": {
+          "type": "string"
+        },
+        "sbi": {
+          "$ref": "#/definitions/southboundSouthboundInterface"
+        },
+        "deviceName": {
+          "type": "string"
+        },
+        "transportOption": {
+          "$ref": "#/definitions/transportTransportOption"
+        }
+      }
+    },
+    "deviceAddDeviceRequest": {
+      "type": "object",
+      "properties": {
+        "timestamp": {
+          "type": "string",
+          "format": "int64"
+        },
+        "device": {
+          "$ref": "#/definitions/deviceAddDeviceConfiguration"
+        },
+        "pid": {
+          "type": "string"
+        }
+      }
+    },
+    "deviceAddDeviceResponse": {
+      "type": "object",
+      "properties": {
+        "timestamp": {
+          "type": "string",
+          "format": "int64"
+        },
+        "status": {
+          "$ref": "#/definitions/gosdndeviceStatus"
+        },
+        "deviceId": {
+          "type": "string"
+        }
+      }
+    },
+    "deviceDevice": {
+      "type": "object",
+      "properties": {
+        "id": {
+          "type": "string"
+        },
+        "name": {
+          "type": "string"
+        },
+        "model": {
+          "type": "string"
+        }
+      }
+    },
+    "deviceGetAllDeviceResponse": {
+      "type": "object",
+      "properties": {
+        "timestamp": {
+          "type": "string",
+          "format": "int64"
+        },
+        "status": {
+          "$ref": "#/definitions/gosdndeviceStatus"
+        },
+        "device": {
+          "type": "array",
+          "items": {
+            "$ref": "#/definitions/deviceDevice"
+          }
+        }
+      }
+    },
+    "deviceGetDeviceResponse": {
+      "type": "object",
+      "properties": {
+        "timestamp": {
+          "type": "string",
+          "format": "int64"
+        },
+        "status": {
+          "$ref": "#/definitions/gosdndeviceStatus"
+        },
+        "device": {
+          "$ref": "#/definitions/deviceDevice"
+        }
+      }
+    },
+    "deviceUpdateDeviceRequest": {
+      "type": "object",
+      "properties": {
+        "timestamp": {
+          "type": "string",
+          "format": "int64"
+        },
+        "device": {
+          "$ref": "#/definitions/deviceDevice"
+        }
+      }
+    },
+    "deviceUpdateDeviceResponse": {
+      "type": "object",
+      "properties": {
+        "timestamp": {
+          "type": "string",
+          "format": "int64"
+        },
+        "status": {
+          "$ref": "#/definitions/gosdndeviceStatus"
+        }
+      }
+    },
     "fakeBoolList": {
       "type": "object",
       "properties": {
@@ -2596,6 +2849,15 @@
       ],
       "default": "STATE_UNSPECIFIED"
     },
+    "gosdndeviceStatus": {
+      "type": "string",
+      "enum": [
+        "STATUS_UNSPECIFIED",
+        "STATUS_OK",
+        "STATUS_ERROR"
+      ],
+      "default": "STATUS_UNSPECIFIED"
+    },
     "gosdnpndOperation": {
       "type": "string",
       "enum": [
diff --git a/api/proto/gosdn/device/device.proto b/api/proto/gosdn/device/device.proto
new file mode 100644
index 0000000000000000000000000000000000000000..8dddb500cfe56938802eab713fbf570c6f8df022
--- /dev/null
+++ b/api/proto/gosdn/device/device.proto
@@ -0,0 +1,121 @@
+syntax = "proto3";
+
+package gosdn.device;
+
+import "google/api/annotations.proto";
+import "google/protobuf/descriptor.proto";
+import "protoc-gen-openapiv2/options/annotations.proto";
+import "github.com/openconfig/gnmi/proto/gnmi/gnmi.proto";
+
+import "gosdn/pnd/pnd.proto";
+import "gosdn/transport/transport.proto";
+import "gosdn/southbound/southbound.proto";
+
+option go_package = "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/device";
+
+service DeviceService {
+    rpc Add(AddDeviceRequest) returns (AddDeviceResponse) {
+        option (google.api.http) = {
+            post: "/device/create"
+            body: "*"
+        };
+    }
+
+    rpc Get(GetDeviceRequest) returns (GetDeviceResponse) {
+        option (google.api.http) = {
+            get: "/device"
+        };
+    }
+
+    rpc GetAll(GetAllDeviceRequest) returns (GetAllDeviceResponse) {
+        option (google.api.http) = {
+            get: "/device/all"
+        };
+    }
+
+    rpc Update(UpdateDeviceRequest) returns (UpdateDeviceResponse) {
+        option (google.api.http) = {
+            post: "/device/update"
+            body: "*"
+        };
+    }
+
+    // TODO: not implemented yet!
+    // rpc Delete(DeleteDeviceRequest) returns (DeleteDeviceRequest) {
+    //     option (google.api.http) = {
+    //         delete: "/device"
+    //     };
+    // }
+}
+
+enum Status {
+    STATUS_UNSPECIFIED = 0;
+    STATUS_OK = 1;
+    STATUS_ERROR = 2;
+}
+
+message Device {
+    string id = 1;
+    string name = 2;
+    string model = 3;
+}
+
+message AddDeviceConfiguration {
+    string address = 1;
+    .gosdn.southbound.SouthboundInterface sbi = 2;
+    string device_name = 3;
+    .gosdn.transport.TransportOption transport_option = 4;
+}
+
+message AddDeviceRequest {
+    int64 timestamp = 1;
+    AddDeviceConfiguration device = 2;
+    string pid = 3;
+}
+
+message AddDeviceResponse {
+    int64 timestamp = 1;
+    Status status = 2;
+    string deviceId = 3;
+}
+
+message GetDeviceRequest {
+    int64 timestamp = 1;
+    string deviceID = 2;
+}
+
+message GetDeviceResponse {
+    int64 timestamp = 1;
+    Status status = 2;
+    Device device = 3;
+}
+
+message GetAllDeviceRequest {
+    int64 timestamp = 1;
+}
+
+message GetAllDeviceResponse {
+    int64 timestamp = 1;
+    Status status = 2;
+    repeated Device device = 3;
+}
+
+message UpdateDeviceRequest {
+    int64 timestamp = 1;
+    Device device = 2;
+}
+
+message UpdateDeviceResponse {
+    int64 timestamp = 1;
+    Status status = 2;
+}
+
+message DeleteDeviceRequest {
+    int64 timestamp = 1;
+    string deviceID = 2;
+}
+
+message DeleteDeviceResponse {
+    int64 timestamp = 1;
+    Status status = 2;
+}
diff --git a/controller/api/initialise_test.go b/controller/api/initialise_test.go
index 8c0dfabb393604ea5d2ed3f167710dd5f45a38b6..a2df244b30185ec7d0c74a37b63cfaaf4412ba42 100644
--- a/controller/api/initialise_test.go
+++ b/controller/api/initialise_test.go
@@ -167,6 +167,7 @@ func bootstrapUnitTest() {
 		topologyService,
 		nodeService,
 		portService,
+		&mockPnd,
 	)
 
 	cpb.RegisterCoreServiceServer(s, northbound.Core)
diff --git a/controller/controller.go b/controller/controller.go
index 387bae4769b833b126c8a386fbf9eb067c0cf1ce..923ded438b508ecbede74717f0df556b82f5ad55 100644
--- a/controller/controller.go
+++ b/controller/controller.go
@@ -21,6 +21,7 @@ import (
 
 	pb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/core"
 	cpb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/csbi"
+	dpb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/device"
 	ppb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/pnd"
 	apb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/rbac"
 	spb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/southbound"
@@ -99,14 +100,6 @@ func initialize() error {
 	// Setting up signal capturing
 	signal.Notify(c.stopChan, os.Interrupt, syscall.SIGTERM)
 
-	if err := startGrpc(); err != nil {
-		return err
-	}
-
-	coreLock.Lock()
-	startHttpServer()
-	coreLock.Unlock()
-
 	err = createPrincipalNetworkDomain()
 	if err != nil {
 		return err
@@ -122,6 +115,14 @@ func initialize() error {
 		return err
 	}
 
+	if err := startGrpc(); err != nil {
+		return err
+	}
+
+	coreLock.Lock()
+	startHttpServer()
+	coreLock.Unlock()
+
 	return nil
 }
 
@@ -136,6 +137,11 @@ func startGrpc() error {
 	jwtManager := rbacImpl.NewJWTManager(config.JWTSecret, config.JWTDuration)
 	setupGRPCServerWithCorrectSecurityLevel(jwtManager, c.userService, c.roleService)
 
+	basePnd, err := c.pndStore.Get(store.Query{ID: config.BasePndUUID})
+	if err != nil {
+		panic(err)
+	}
+
 	c.nbi = nbi.NewNBI(
 		c.pndStore,
 		c.userService,
@@ -144,6 +150,7 @@ func startGrpc() error {
 		c.topologyService,
 		c.nodeService,
 		c.portService,
+		basePnd,
 	)
 
 	pb.RegisterCoreServiceServer(c.grpcServer, c.nbi.Core)
@@ -154,6 +161,7 @@ func startGrpc() error {
 	apb.RegisterUserServiceServer(c.grpcServer, c.nbi.User)
 	apb.RegisterRoleServiceServer(c.grpcServer, c.nbi.Role)
 	tpb.RegisterTopologyServiceServer(c.grpcServer, c.nbi.Topology)
+	dpb.RegisterDeviceServiceServer(c.grpcServer, c.nbi.Device)
 
 	go func() {
 		if err := c.grpcServer.Serve(lislisten); err != nil {
diff --git a/controller/http.go b/controller/http.go
index f0a04a9b69452a61a18f45037657d68c382cd849..0a204a27de50b0a5be952f50e6d5b6ff82693188 100644
--- a/controller/http.go
+++ b/controller/http.go
@@ -16,6 +16,7 @@ import (
 	"google.golang.org/grpc/status"
 
 	cgw "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/core"
+	dgw "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/device"
 	pgw "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/pnd"
 	agw "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/rbac"
 	tgw "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/topology"
@@ -81,6 +82,11 @@ func run() error {
 		return err
 	}
 
+	err = dgw.RegisterDeviceServiceHandlerFromEndpoint(ctx, mux, *grpcServerEndpoint, opts)
+	if err != nil {
+		return err
+	}
+
 	// Set the HTTP server of core to the new server
 	c.httpServer = &http.Server{Addr: ":8080", Handler: mux}
 	// Start HTTP server (and proxy calls to gRPC server endpoint)
diff --git a/controller/interfaces/device/device.go b/controller/interfaces/device/device.go
index 09287c1d52482a995acafc8c62361080cebc3c83..fa424fd5599677945503e3d4d5244b2767b1147b 100644
--- a/controller/interfaces/device/device.go
+++ b/controller/interfaces/device/device.go
@@ -21,6 +21,7 @@ type Device interface {
 	SBI() southbound.SouthboundInterface
 	ProcessResponse(proto.Message) error
 	IsTransportValid() bool
+	GetModelAsString() (string, error)
 }
 
 // Details contains details of a device used by the cSBI mechanism
diff --git a/controller/interfaces/device/deviceService.go b/controller/interfaces/device/deviceService.go
index 23417157302cedcb024cc94d68bbefb37e271d15..c82ad96e57d0ed7d46aec52435d8053baf799c34 100644
--- a/controller/interfaces/device/deviceService.go
+++ b/controller/interfaces/device/deviceService.go
@@ -8,6 +8,7 @@ import (
 type Service interface {
 	Add(Device) error
 	Update(Device) error
+	UpdateModel(Device, string) error
 	Delete(Device) error
 	Get(store.Query) (Device, error)
 	GetAll() ([]Device, error)
diff --git a/controller/interfaces/networkdomain/pnd.go b/controller/interfaces/networkdomain/pnd.go
index fc9dec411c54ec8a1877445401bb801f37aec274..ed2c7f1079605f0327e84b530deee5a37e443349 100644
--- a/controller/interfaces/networkdomain/pnd.go
+++ b/controller/interfaces/networkdomain/pnd.go
@@ -19,6 +19,7 @@ type NetworkDomain interface {
 	AddDevice(name string, opts *tpb.TransportOption, sid uuid.UUID) (uuid.UUID, error)
 	GetDevice(identifier string) (device.Device, error)
 	RemoveDevice(uuid.UUID) error
+	UpdateDevice(device.Device, string) error
 	Devices() []device.Device
 	ChangeOND(uuid uuid.UUID, operation ppb.ApiOperation, path string, value ...string) (uuid.UUID, error)
 	Request(uuid.UUID, string) (proto.Message, error)
diff --git a/controller/interfaces/transport/transport.go b/controller/interfaces/transport/transport.go
index 9d732c370599062776d9151c52fa4395df7c3d6f..8e32f357fff138ccc8c8248625951779efa41e5a 100644
--- a/controller/interfaces/transport/transport.go
+++ b/controller/interfaces/transport/transport.go
@@ -5,6 +5,7 @@ import (
 
 	"code.fbi.h-da.de/danet/gosdn/controller/interfaces/change"
 
+	gpb "github.com/openconfig/gnmi/proto/gnmi"
 	"github.com/openconfig/ygot/ytypes"
 )
 
@@ -13,6 +14,7 @@ import (
 type Transport interface {
 	Get(ctx context.Context, params ...string) (interface{}, error)
 	Set(ctx context.Context, payload change.Payload, path string, schema *ytypes.Schema) error
+	CustomSet(ctx context.Context, req *gpb.SetRequest) (*gpb.SetResponse, error)
 	Subscribe(ctx context.Context, params ...string) error
 	Type() string
 	ProcessResponse(resp interface{}, root interface{}, models *ytypes.Schema) error
diff --git a/controller/mocks/Device.go b/controller/mocks/Device.go
index a9158c0cd3424399ffb29ee564b07162b6b75ac3..5cac8a61ddbd4ee56e24f840fa5ae5f825dc6249 100644
--- a/controller/mocks/Device.go
+++ b/controller/mocks/Device.go
@@ -58,6 +58,27 @@ func (_m *Device) GetModel() ygot.GoStruct {
 	return r0
 }
 
+// GetModelAsString provides a mock function with given fields:
+func (_m *Device) GetModelAsString() (string, error) {
+	ret := _m.Called()
+
+	var r0 string
+	if rf, ok := ret.Get(0).(func() string); ok {
+		r0 = rf()
+	} else {
+		r0 = ret.Get(0).(string)
+	}
+
+	var r1 error
+	if rf, ok := ret.Get(1).(func() error); ok {
+		r1 = rf()
+	} else {
+		r1 = ret.Error(1)
+	}
+
+	return r0, r1
+}
+
 // ID provides a mock function with given fields:
 func (_m *Device) ID() uuid.UUID {
 	ret := _m.Called()
diff --git a/controller/mocks/NetworkDomain.go b/controller/mocks/NetworkDomain.go
index 746eafaf7f812c4bdedee6d1118b6ec61ae8ef14..2455cbb107a8c16361a9d004ddd51b845062d193 100644
--- a/controller/mocks/NetworkDomain.go
+++ b/controller/mocks/NetworkDomain.go
@@ -403,6 +403,20 @@ func (_m *NetworkDomain) RequestAll(_a0 string) error {
 	return r0
 }
 
+// UpdateDevice provides a mock function with given fields: _a0, _a1
+func (_m *NetworkDomain) UpdateDevice(_a0 device.Device, _a1 string) error {
+	ret := _m.Called(_a0, _a1)
+
+	var r0 error
+	if rf, ok := ret.Get(0).(func(device.Device, string) error); ok {
+		r0 = rf(_a0, _a1)
+	} else {
+		r0 = ret.Error(0)
+	}
+
+	return r0
+}
+
 type mockConstructorTestingTNewNetworkDomain interface {
 	mock.TestingT
 	Cleanup(func())
diff --git a/controller/mocks/Service.go b/controller/mocks/Service.go
index 7d0768e06c7066aa64347f06e37445198e6d967f..188cd0c9c1e94bec7b2a665f26387dbd0085a7fa 100644
--- a/controller/mocks/Service.go
+++ b/controller/mocks/Service.go
@@ -102,6 +102,20 @@ func (_m *Service) Update(_a0 device.Device) error {
 	return r0
 }
 
+// UpdateModel provides a mock function with given fields: _a0, _a1
+func (_m *Service) UpdateModel(_a0 device.Device, _a1 string) error {
+	ret := _m.Called(_a0, _a1)
+
+	var r0 error
+	if rf, ok := ret.Get(0).(func(device.Device, string) error); ok {
+		r0 = rf(_a0, _a1)
+	} else {
+		r0 = ret.Error(0)
+	}
+
+	return r0
+}
+
 type mockConstructorTestingTNewService interface {
 	mock.TestingT
 	Cleanup(func())
diff --git a/controller/mocks/Transport.go b/controller/mocks/Transport.go
index fffcb59cf84901e7452f9a6e4cd2396b75c98dd7..6062bf4c5a646c79782bfb0d0a16feca25ebfa3e 100644
--- a/controller/mocks/Transport.go
+++ b/controller/mocks/Transport.go
@@ -7,6 +7,8 @@ import (
 
 	change "code.fbi.h-da.de/danet/gosdn/controller/interfaces/change"
 
+	gnmi "github.com/openconfig/gnmi/proto/gnmi"
+
 	mock "github.com/stretchr/testify/mock"
 
 	ytypes "github.com/openconfig/ygot/ytypes"
@@ -17,6 +19,29 @@ type Transport struct {
 	mock.Mock
 }
 
+// CustomSet provides a mock function with given fields: ctx, req
+func (_m *Transport) CustomSet(ctx context.Context, req *gnmi.SetRequest) (*gnmi.SetResponse, error) {
+	ret := _m.Called(ctx, req)
+
+	var r0 *gnmi.SetResponse
+	if rf, ok := ret.Get(0).(func(context.Context, *gnmi.SetRequest) *gnmi.SetResponse); ok {
+		r0 = rf(ctx, req)
+	} else {
+		if ret.Get(0) != nil {
+			r0 = ret.Get(0).(*gnmi.SetResponse)
+		}
+	}
+
+	var r1 error
+	if rf, ok := ret.Get(1).(func(context.Context, *gnmi.SetRequest) error); ok {
+		r1 = rf(ctx, req)
+	} else {
+		r1 = ret.Error(1)
+	}
+
+	return r0, r1
+}
+
 // Get provides a mock function with given fields: ctx, params
 func (_m *Transport) Get(ctx context.Context, params ...string) (interface{}, error) {
 	_va := make([]interface{}, len(params))
diff --git a/controller/northbound/server/device.go b/controller/northbound/server/device.go
new file mode 100644
index 0000000000000000000000000000000000000000..e034192fd4d391a26e11e9d438edbbea7d6a183a
--- /dev/null
+++ b/controller/northbound/server/device.go
@@ -0,0 +1,132 @@
+package server
+
+import (
+	"context"
+	"time"
+
+	dpb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/device"
+	"code.fbi.h-da.de/danet/gosdn/controller/interfaces/networkdomain"
+	"github.com/google/uuid"
+	log "github.com/sirupsen/logrus"
+	"google.golang.org/grpc/codes"
+	"google.golang.org/grpc/status"
+)
+
+// DeviceServer represents a deviceServer.
+type DeviceServer struct {
+	dpb.UnimplementedDeviceServiceServer
+	networkDomain networkdomain.NetworkDomain
+}
+
+// NewDeviceServer returns a new DeviceServer.
+func NewDeviceServer(networkDomain networkdomain.NetworkDomain) *DeviceServer {
+	return &DeviceServer{
+		networkDomain: networkDomain,
+	}
+}
+
+// Add adds a new device.
+func (d *DeviceServer) Add(ctx context.Context, request *dpb.AddDeviceRequest) (*dpb.AddDeviceResponse, error) {
+	sbiID, err := uuid.Parse(request.Device.Sbi.Id)
+	if err != nil {
+		return nil, status.Errorf(codes.Aborted, "%v", err)
+	}
+
+	id, err := d.networkDomain.AddDevice(
+		request.Device.DeviceName,
+		request.Device.TransportOption,
+		sbiID,
+	)
+	if err != nil {
+		return nil, status.Errorf(codes.Aborted, "%v", err)
+	}
+
+	return &dpb.AddDeviceResponse{
+		Timestamp: time.Now().UnixNano(),
+		Status:    dpb.Status_STATUS_OK,
+		DeviceId:  id.String(),
+	}, nil
+}
+
+// GetAll returns all stored devices.
+func (d *DeviceServer) GetAll(ctx context.Context, request *dpb.GetAllDeviceRequest) (*dpb.GetAllDeviceResponse, error) {
+	devices := d.networkDomain.Devices()
+
+	onds := []*dpb.Device{}
+	for _, device := range devices {
+		ygotStructAsJSON, err := device.GetModelAsString()
+		if err != nil {
+			log.Error(err)
+			return nil, status.Errorf(codes.Aborted, "%v", err)
+		}
+
+		onds = append(onds, &dpb.Device{
+			Id:    device.ID().String(),
+			Name:  device.Name(),
+			Model: ygotStructAsJSON,
+		})
+	}
+
+	return &dpb.GetAllDeviceResponse{
+		Timestamp: time.Now().UnixNano(),
+		Status:    dpb.Status_STATUS_OK,
+		Device:    onds,
+	}, nil
+}
+
+// Get returns a device.
+func (d *DeviceServer) Get(ctx context.Context, request *dpb.GetDeviceRequest) (*dpb.GetDeviceResponse, error) {
+	device, err := d.networkDomain.GetDevice(request.DeviceID)
+	if err != nil {
+		return nil, status.Errorf(codes.Aborted, "%v", err)
+	}
+
+	ygotStructAsJSON, err := device.GetModelAsString()
+	if err != nil {
+		log.Error(err)
+		return nil, status.Errorf(codes.Aborted, "%v", err)
+	}
+
+	ond := &dpb.Device{
+		Id:    device.ID().String(),
+		Name:  device.Name(),
+		Model: ygotStructAsJSON,
+	}
+
+	return &dpb.GetDeviceResponse{
+		Timestamp: time.Now().UnixNano(),
+		Status:    dpb.Status_STATUS_OK,
+		Device:    ond,
+	}, nil
+}
+
+// Update updates a device.
+func (d *DeviceServer) Update(ctx context.Context, request *dpb.UpdateDeviceRequest) (*dpb.UpdateDeviceResponse, error) {
+	deviceID, err := uuid.Parse(request.Device.Id)
+	if err != nil {
+		return &dpb.UpdateDeviceResponse{
+			Timestamp: time.Now().UnixNano(),
+			Status:    dpb.Status_STATUS_OK,
+		}, err
+	}
+	device, err := d.networkDomain.GetDevice(deviceID.String())
+	if err != nil {
+		return &dpb.UpdateDeviceResponse{
+			Timestamp: time.Now().UnixNano(),
+			Status:    dpb.Status_STATUS_OK,
+		}, err
+	}
+
+	err = d.networkDomain.UpdateDevice(device, request.Device.Model)
+	if err != nil {
+		return &dpb.UpdateDeviceResponse{
+			Timestamp: time.Now().UnixNano(),
+			Status:    dpb.Status_STATUS_OK,
+		}, err
+	}
+
+	return &dpb.UpdateDeviceResponse{
+		Timestamp: time.Now().UnixNano(),
+		Status:    dpb.Status_STATUS_OK,
+	}, nil
+}
diff --git a/controller/northbound/server/nbi.go b/controller/northbound/server/nbi.go
index 75efc8af288e4cd9bf252ba3e4f4976a9c9a0259..e174165920a7cca18c15f3709d631f92b71c97a3 100644
--- a/controller/northbound/server/nbi.go
+++ b/controller/northbound/server/nbi.go
@@ -26,6 +26,7 @@ type NorthboundInterface struct {
 	User     *UserServer
 	Role     *RoleServer
 	Topology *TopologyServer
+	Device   *DeviceServer
 }
 
 // NewNBI receives a PndStore and returns a new gRPC *NorthboundInterface
@@ -37,6 +38,7 @@ func NewNBI(
 	topologyService topology.Service,
 	nodeService nodes.Service,
 	portService ports.Service,
+	networkDomain networkdomain.NetworkDomain,
 
 ) *NorthboundInterface {
 	return &NorthboundInterface{
@@ -48,6 +50,7 @@ func NewNBI(
 		User:     NewUserServer(&jwt, users),
 		Role:     NewRoleServer(&jwt, roles),
 		Topology: NewTopologyServer(topologyService, nodeService, portService),
+		Device:   NewDeviceServer(networkDomain),
 	}
 }
 
diff --git a/controller/northbound/server/topology.go b/controller/northbound/server/topology.go
index 6c74306b80ed97c9df5a8fdade2785bb80c7198f..e833576bc1dba36ac6b0d02127c0c50c2413dfcd 100644
--- a/controller/northbound/server/topology.go
+++ b/controller/northbound/server/topology.go
@@ -11,7 +11,6 @@ import (
 	"code.fbi.h-da.de/danet/gosdn/controller/topology/nodes"
 	"code.fbi.h-da.de/danet/gosdn/controller/topology/ports"
 	"code.fbi.h-da.de/danet/gosdn/controller/topology/ports/configuration"
-
 	"github.com/google/uuid"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
diff --git a/controller/nucleus/device.go b/controller/nucleus/device.go
index 225ea492e0382adab309272003d6b4c7851f6ec8..bd3795d783305f17aa1920c228110e7332d1fb11 100644
--- a/controller/nucleus/device.go
+++ b/controller/nucleus/device.go
@@ -332,6 +332,16 @@ func (d *CommonDevice) MarshalBSON() ([]byte, error) {
 	})
 }
 
+// GetModelAsString returns the YANG model of a device as string
+func (d *CommonDevice) GetModelAsString() (string, error) {
+	modelAsString, err := ygot.EmitJSON(d.Model, d.getYgotEmitJSONConfig())
+	if err != nil {
+		return "", err
+	}
+
+	return modelAsString, nil
+}
+
 func (d *CommonDevice) getYgotEmitJSONConfig() *ygot.EmitJSONConfig {
 	return &ygot.EmitJSONConfig{
 		Format:         ygot.RFC7951,
diff --git a/controller/nucleus/deviceService.go b/controller/nucleus/deviceService.go
index 618963bd7fff2988f169498975e029ffc03ec402..86458a9f184ca60b31a99cfc58c13f208167d71a 100644
--- a/controller/nucleus/deviceService.go
+++ b/controller/nucleus/deviceService.go
@@ -89,6 +89,35 @@ func (s *DeviceService) Add(deviceToAdd device.Device) error {
 	return nil
 }
 
+// UpdateModel updates a existing device with a new model provided as string.
+func (s *DeviceService) UpdateModel(deviceToUpdate device.Device, modelAsString string) error {
+	exisitingDevice, err := s.Get(store.Query{ID: deviceToUpdate.ID()})
+	if err != nil {
+		return err
+	}
+
+	// Create 'root' path to be able to load the whole model from the store.
+	path, err := ygot.StringToPath("/", ygot.StructuredPath)
+	if err != nil {
+		return err
+	}
+
+	// Use unmarshall from the devices SBI to unmarshall ygot json in go struct.
+	err = exisitingDevice.SBI().Unmarshal([]byte(modelAsString), path, exisitingDevice.GetModel())
+	if err != nil {
+		return err
+	}
+
+	err = s.deviceStore.Update(exisitingDevice)
+	if err != nil {
+		return err
+	}
+
+	s.eventService.PublishEvent(DeviceEventTopic, event.NewUpdateEvent(deviceToUpdate.ID()))
+
+	return nil
+}
+
 // Update updates a existing device.
 func (s *DeviceService) Update(deviceToUpdate device.Device) error {
 	err := s.deviceStore.Update(deviceToUpdate)
diff --git a/controller/nucleus/deviceServiceMock.go b/controller/nucleus/deviceServiceMock.go
new file mode 100644
index 0000000000000000000000000000000000000000..8d3646b9e527416198c86a2941f7ea7b6f38dee2
--- /dev/null
+++ b/controller/nucleus/deviceServiceMock.go
@@ -0,0 +1,100 @@
+package nucleus
+
+import (
+	"code.fbi.h-da.de/danet/gosdn/controller/interfaces/device"
+	"code.fbi.h-da.de/danet/gosdn/controller/store"
+	"github.com/google/uuid"
+)
+
+// DeviceServiceMock provides a in-memory implementation for multiple stores.
+type DeviceServiceMock struct {
+	Store           map[uuid.UUID]device.Device
+	nameLookupTable map[string]uuid.UUID
+}
+
+// NewDeviceServiceMock returns a specific in-memory store for device service.
+func NewDeviceServiceMock() device.Service {
+	return &DeviceServiceMock{
+		Store:           make(map[uuid.UUID]device.Device),
+		nameLookupTable: make(map[string]uuid.UUID),
+	}
+}
+
+// Add adds a item device.Device
+func (t *DeviceServiceMock) Add(item device.Device) error {
+	_, ok := t.Store[item.ID()]
+	if ok {
+		return nil
+	}
+
+	t.Store[item.ID()] = item
+	t.nameLookupTable[item.Name()] = item.ID()
+
+	return nil
+}
+
+// Update updates a item device.Device
+func (t *DeviceServiceMock) Update(item device.Device) error {
+	_, ok := t.Store[item.ID()]
+	if ok {
+		return nil
+	}
+
+	t.Store[item.ID()] = item
+	t.nameLookupTable[item.Name()] = item.ID()
+
+	return nil
+}
+
+// UpdateModel updates a item device.Device
+func (t *DeviceServiceMock) UpdateModel(item device.Device, model string) error {
+	_, ok := t.Store[item.ID()]
+	if ok {
+		return nil
+	}
+
+	t.Store[item.ID()] = item
+	t.nameLookupTable[item.Name()] = item.ID()
+
+	return nil
+}
+
+// Delete deletes a item device.Device
+func (t *DeviceServiceMock) Delete(item device.Device) error {
+	delete(t.Store, item.ID())
+
+	return nil
+}
+
+// Get gets a item device.Device
+func (t *DeviceServiceMock) Get(query store.Query) (device.Device, error) {
+	// First search for direct hit on UUID.
+	item, ok := t.Store[query.ID]
+	if !ok {
+		// Second search for name
+		id, ok := t.nameLookupTable[query.Name]
+		if !ok {
+			return nil, nil
+		}
+
+		item, ok := t.Store[id]
+		if !ok {
+			return nil, nil
+		}
+
+		return item, nil
+	}
+
+	return item, nil
+}
+
+// GetAll gets all items
+func (t *DeviceServiceMock) GetAll() ([]device.Device, error) {
+	var allItems []device.Device
+
+	for _, item := range t.Store {
+		allItems = append(allItems, item)
+	}
+
+	return allItems, nil
+}
diff --git a/controller/nucleus/gnmi_transport.go b/controller/nucleus/gnmi_transport.go
index 84b9e3b3d7e06d755de9cb45d733b512b11846d0..5e5b94a990ad974fe36ce74dd9d1768bc004359e 100644
--- a/controller/nucleus/gnmi_transport.go
+++ b/controller/nucleus/gnmi_transport.go
@@ -49,6 +49,7 @@ func newGnmiTransport(opts *tpb.TransportOption, sbi southbound.SouthboundInterf
 			Param: "'opts.TransportOption' can not be nil",
 		}
 	}
+
 	gnmiConfig := &gnmi.Config{
 		Addr:        opts.Address,
 		Password:    opts.Password,
@@ -61,10 +62,12 @@ func newGnmiTransport(opts *tpb.TransportOption, sbi southbound.SouthboundInterf
 	if err != nil {
 		return nil, err
 	}
+
 	log.WithFields(log.Fields{
 		"target": opts.Address,
 		"tls":    opts.Tls,
 	}).Info("building new gNMI transport")
+
 	return &Gnmi{
 		SetNode:   sbi.SetNode,
 		RespChan:  make(chan *gpb.SubscribeResponse),
@@ -332,6 +335,13 @@ func (g *Gnmi) Close() error {
 	return nil
 }
 
+// CustomSet allows to build a custom set request.
+func (g *Gnmi) CustomSet(ctx context.Context, req *gpb.SetRequest) (*gpb.SetResponse, error) {
+	ctx = gnmi.NewContext(ctx, g.config)
+
+	return g.client.Set(ctx, req)
+}
+
 // SetPassthrough allows to pass an existing SetRequest. Used for cSBI
 func (g *Gnmi) SetPassthrough(ctx context.Context, req *gpb.SetRequest) (*gpb.SetResponse, error) {
 	return g.client.Set(ctx, req)
diff --git a/controller/nucleus/principalNetworkDomain.go b/controller/nucleus/principalNetworkDomain.go
index 7a376e357454fcd502851e09995d9c66099d261d..46e6aa1be776f51f308b778ca43cdc1302167966 100644
--- a/controller/nucleus/principalNetworkDomain.go
+++ b/controller/nucleus/principalNetworkDomain.go
@@ -35,6 +35,7 @@ import (
 	"code.fbi.h-da.de/danet/gosdn/controller/store"
 
 	"github.com/google/uuid"
+	gpb "github.com/openconfig/gnmi/proto/gnmi"
 	"github.com/openconfig/ygot/ygot"
 	"github.com/openconfig/ygot/ytypes"
 	"github.com/prometheus/client_golang/prometheus"
@@ -292,6 +293,21 @@ func (pnd *pndImplementation) RemoveDevice(uuid uuid.UUID) error {
 	return pnd.removeDevice(uuid)
 }
 
+// UpdateDeviceModel updates a device from the PND
+func (pnd *pndImplementation) UpdateDevice(device device.Device, modelAsString string) error {
+	err := pnd.deviceService.UpdateModel(device, modelAsString)
+	if err != nil {
+		return err
+	}
+
+	err = pnd.ensureIntendedConfigurationIsAppliedOnDevice(device.ID())
+	if err != nil {
+		return err
+	}
+
+	return err
+}
+
 // Actual implementation, bind to struct if neccessary
 func destroy() error {
 	return nil
@@ -325,7 +341,6 @@ func (pnd *pndImplementation) addDevice(device device.Device) (uuid.UUID, error)
 	if device.IsTransportValid() {
 		_, err = pnd.Request(device.ID(), "/interfaces")
 		if err != nil {
-			fmt.Printf("ERROR: %s\n", err)
 			return uuid.Nil, err
 		}
 	}
@@ -436,6 +451,41 @@ func (pnd *pndImplementation) RequestAll(path string) error {
 	return nil
 }
 
+func (pnd *pndImplementation) ensureIntendedConfigurationIsAppliedOnDevice(deviceID uuid.UUID) error {
+	device, err := pnd.deviceService.Get(store.Query{
+		ID: deviceID,
+	})
+	if err != nil {
+		return err
+	}
+
+	model, err := device.GetModelAsString()
+	if err != nil {
+		return err
+	}
+
+	req := &gpb.SetRequest{}
+	path, err := ygot.StringToStructuredPath("/")
+	if err != nil {
+		return err
+	}
+
+	req.Update = []*gpb.Update{{
+		Path: path,
+		Val: &gpb.TypedValue{
+			Value: &gpb.TypedValue_JsonIetfVal{JsonIetfVal: []byte(model)},
+		},
+	}}
+
+	response, err := device.Transport().CustomSet(context.Background(), req)
+	if err != nil {
+		log.Errorf("Failed to apply model of device err=%+v, response=%+v", err, response)
+		return err
+	}
+
+	return nil
+}
+
 //nolint:gocyclo
 // ChangeOND creates a change from the provided Operation, path and value.
 // The Change is Pending and times out after the specified timeout period
diff --git a/controller/nucleus/principalNetworkDomain_test.go b/controller/nucleus/principalNetworkDomain_test.go
index 27587e387e5e41bb4658988e0f1a69e37c0d1e43..73043dd766cdda55397112f4ec22039d1efa86de 100644
--- a/controller/nucleus/principalNetworkDomain_test.go
+++ b/controller/nucleus/principalNetworkDomain_test.go
@@ -544,13 +544,13 @@ func Test_pndImplementation_Request(t *testing.T) {
 		t.Run(tt.name, func(t *testing.T) {
 			t.Parallel()
 			sbiService := NewGenericService[southbound.SouthboundInterface]()
-			deviceService := NewGenericService[device.Device]()
+			deviceService := NewDeviceServiceMock()
 
 			pnd := pndImplementation{
 				Name:              "default",
 				Description:       "default test pnd",
 				southboundService: &sbiService,
-				deviceService:     &deviceService,
+				deviceService:     deviceService,
 				changes:           store.NewChangeStore(),
 				Id:                defaultPndID,
 			}
@@ -630,13 +630,13 @@ func Test_pndImplementation_RequestAll(t *testing.T) {
 		t.Run(tt.name, func(t *testing.T) {
 			t.Parallel()
 			sbiService := NewGenericService[southbound.SouthboundInterface]()
-			deviceService := NewGenericService[device.Device]()
+			deviceService := NewDeviceServiceMock()
 
 			pnd := pndImplementation{
 				Name:              "default",
 				Description:       "default test pnd",
 				southboundService: &sbiService,
-				deviceService:     &deviceService,
+				deviceService:     deviceService,
 				changes:           store.NewChangeStore(),
 				Id:                defaultPndID,
 			}
@@ -966,13 +966,13 @@ func Test_pndImplementation_Confirm(t *testing.T) {
 		t.Run(tt.name, func(t *testing.T) {
 			t.Parallel()
 			sbiService := NewGenericService[southbound.SouthboundInterface]()
-			deviceService := NewGenericService[device.Device]()
+			deviceService := NewDeviceServiceMock()
 
 			pnd := pndImplementation{
 				Name:              "default",
 				Description:       "default test pnd",
 				southboundService: &sbiService,
-				deviceService:     &deviceService,
+				deviceService:     deviceService,
 				changes:           store.NewChangeStore(),
 				Id:                defaultPndID,
 			}