From 7b3ea01fc27a3839a9f23d0c5ea5055c7011dc54 Mon Sep 17 00:00:00 2001 From: xuzhenbao Date: Tue, 27 Feb 2024 15:02:08 +0800 Subject: [PATCH] Add document for libdfi and dynamic ip mechanism --- bundles/remote_services/README.md | 16 +++++++ .../diagrams/dynamic_ip_filling_seq.png | Bin 0 -> 61463 bytes .../diagrams/dynamic_ip_filling_seq.puml | 43 ++++++++++++++++++ .../discovery_zeroconf/README.md | 16 +++---- .../remote_service_admin_dfi/README.md | 1 + libs/dfi/README.md | 25 ++++++---- 6 files changed, 85 insertions(+), 16 deletions(-) create mode 100644 bundles/remote_services/diagrams/dynamic_ip_filling_seq.png create mode 100644 bundles/remote_services/diagrams/dynamic_ip_filling_seq.puml diff --git a/bundles/remote_services/README.md b/bundles/remote_services/README.md index cec575889..bc090a9c7 100644 --- a/bundles/remote_services/README.md +++ b/bundles/remote_services/README.md @@ -87,6 +87,22 @@ Provides a service discovery using Bonjour. |--|----------------------------| | **Configuration** | See [Zeroconf Discovery](discovery_zeroconf/README.md) | +## Dynamic IP Mechanism For Remote Service Admin + +In order to make remote services work without configuring the IP of the RSA, we have designed the following dynamic IP mechanism. + + - The remote service admin service adds the property "celix.rsa.dynamic.ip.support". If RSA sets this property to true, the RSA will support dynamic IP address. + - If the RSA supports dynamic IP addresses, it should bind the network service address to any address(0.0.0.0/::), and set the property "celix.rsa.port" (which indicates the network port number of the remote service) for the exported remote service endpoint. + - The endpoint listener service of discovery adds the property "celix.rsa.discovery.interface.specific.endpoints.support". If this property is set to true, it means that the discovery support dynamic IP address filling. + - Add the configuration property "CELIX_RSA_INTERFACES_OF_PORT_", which indicates which network interfaces is used to expose the specified port service. + - When the topology manager exports remote services, it should detect whether the "celix.rsa.dynamic.ip.support" property of the remote service admin service is true. If so, the topology manager should create multiple endpoints that support dynamic IP address for a single export registration base on CELIX_RSA_INTERFACES_OF_PORT_. These endpoints are then forwarded to the discovery endpoint listener services that support dynamic IP address filling. + - The endpoint that supports dynamic IP address adds the property "celix.rsa.ifname", which indicates which network interface is used for exported endpoint exposure. This property is set by the topology manager based on CELIX_RSA_INTERFACES_OF_PORT_. + - The endpoint that supports dynamic IP address adds the property "celix.rsa.ip.addresses", which indicates the list of IP addresses corresponding to the endpoint. When the topology manager creates the endpoint description that supports dynamic IP address, the value of this property should be set to null, and the discovery that support dynamic IP address filling will replace the value(Discovery will decide whether to fill in the dynamic IP addresses based on whether the "celix.rsa.ip.addresses" key exists or not). + +The sequence diagram of the dynamic IP mechanism is as follows: +![dynamic_ip_filling](diagrams/dynamic_ip_filling_seq.png) + + The example of dynamic IP mechanism see `remote-services-zeroconf-server` and `remote-services-zeroconf-client`. ## Usage diff --git a/bundles/remote_services/diagrams/dynamic_ip_filling_seq.png b/bundles/remote_services/diagrams/dynamic_ip_filling_seq.png new file mode 100644 index 0000000000000000000000000000000000000000..a5a46f007b444d6d977bbbec3f4de5f2f7a1a236 GIT binary patch literal 61463 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

UKX*=Am&5~G%Ljz=3VvF?YS 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 RSA_A: exportService() +note over RSA_A: Exported service endpoint description e.g.:\n{\ncelix.rsa.port: 80"(set by RSA),\n...\n}" +TM_A -> TM_A: Create endpoint descriptions\n that support dynamic ip +note over TM_A: Dynamic ip endpoint description e.g.:\n{\ncelix.rsa.ifname: "eth0"(set by TopologyManager),\ncelix.rsa.port: 80",\ncelix.rsa.ip.addresses:""(set by TopologyManager),\n...\n} +TM_A -> Discovery_A: endpointAdded() + +Discovery_A -> Discovery_B: Announce endpoint \nto other frameworks + +Discovery_B -> Discovery_B: Watch remote endpoints \nand fill in dynamic ip +Discovery_B -> TM_B: endpointAdded() +note over TM_B: Dynamic ip endpoint description e.g.:\n{\ncelix.rsa.port: 80",\ncelix.rsa.ip.addresses:"192.168...1.1, 192.168...1.2"(replaced by Discovery),\n...\n}" +TM_B -> RSA_B: importService() +@enduml \ No newline at end of file diff --git a/bundles/remote_services/discovery_zeroconf/README.md b/bundles/remote_services/discovery_zeroconf/README.md index a17071ef6..9d5eb6bc7 100644 --- a/bundles/remote_services/discovery_zeroconf/README.md +++ b/bundles/remote_services/discovery_zeroconf/README.md @@ -25,14 +25,14 @@ The `Discovery_zeroconf` is implemented based on [Bonjour](https://github.com/ap The mapping between celix and mdns services is as follows: -| **mDNS service** | **celix service** | -|------------------|------------------------------------------------------------------------------------------------------------------------------| -| instance name | service name+pid(process id) | -| service type | "${last word of service configuration type}._sub._celix-rpc._udp" | -| domain name | "local" | -| txt record | service properties | -| host | hostname. | -| port | The property value of "${service configuration type}.port". If it is not network server, it will be set a dummy value(65535) | +| **mDNS service** | **celix service** | +|------------------|-------------------------------| +| instance name | service name+pid(process id) | +| service type | "${last word of service configuration type}._sub._celix-rpc._udp"| +| domain name | "local" | +| txt record | service properties | +| host | hostname of OS(It can be got by gethostname function).| +| port | The property value of "celix.rsa.port". It is set by RSA. If it is not network server, Discovery will set a dummy value(65535) to mDNS daemon.| The domain name value is set to "local" , because for remote discovery the mDNS query will only use link-local multicast. diff --git a/bundles/remote_services/remote_service_admin_dfi/README.md b/bundles/remote_services/remote_service_admin_dfi/README.md index 33b37368c..2dfb6523e 100644 --- a/bundles/remote_services/remote_service_admin_dfi/README.md +++ b/bundles/remote_services/remote_service_admin_dfi/README.md @@ -39,6 +39,7 @@ Libffi is configured using descriptor files in the bundles. Default is false CELIX_RSA_BIND_ON_ALL_INTERFACES If set to true the RSA will bind to all interfaces. Default is true. + CELIX_RSA_DFI_DYNAMIC_IP_SUPPORT If set to true the RSA will support dynamic IP address fill-in for service exports. Default is false. ###### CMake option RSA_REMOTE_SERVICE_ADMIN_DFI=ON diff --git a/libs/dfi/README.md b/libs/dfi/README.md index dd68acce1..8110c42e1 100644 --- a/libs/dfi/README.md +++ b/libs/dfi/README.md @@ -236,13 +236,15 @@ The data types supported by the interface description include: ~~~ In order to represent the properties of function parameters (eg: in, out...), function parameters support the following metadata annotations: - |Meta-info|Description| - |---------|-----------| - |am=handle| void pointer for the handle| - |am=pre | output pointer with memory pre-allocated| - |am=out | output pointer, the caller should use `free` to release the memory| + |Meta-info| Description| + |---------|------------| + |am=handle| void pointer for the handle.| + |am=pre | output pointer with memory pre-allocated, it should be pointer to [trivially copyable type](#notion-definitions).| + |am=out | output pointer, the caller should use `free` to release the memory, and it should be pointer to text(t) or double pointer to [serializable types](#notion-definitions).| |const=true| text argument(t) can use it, Normally a text argument will be handled as char*, meaning that the callee is expected to take of ownership.If a const=true annotation is used the text argument will be handled as a const char*, meaning that the caller keeps ownership of the string.| + If there is no metadata annotation, the default is standard argument(input parameter). And it can be any serializable type. + *Example*: ~~~ add(#am=handle;PDD#am=pre;*D)N @@ -251,9 +253,16 @@ The data types supported by the interface description include: ~~~ int add(void* handle,double a, double b, double *ret); ~~~ - > **Notes**: - > - For RPC interface, the return type of methods must be N, because remote service calls usually return error codes. - > - Currently, the method only supports one output parameter, so the method cannot be defined in a multi-output parameter form. + +##### Notion Definitions + +- **trivially copyable type**: A trivially copyable type is a type that can be copied with a simple memcpy without the usual danger of shallow copying. +- **serializable type**: All types except types involving untyped pointer or double pointer (pointer to pointer) are serializable. For example, complex types consisting of non-pointer fields are serializable while complex type containing a untyped pointer field is not serializable; [I is serializable while [P and [**D are not serializable. + +##### RSA Interface Convention Enforcement: + - For RSA interface, the return type of methods must be N, because remote service calls usually return error codes. + - The first parameter of a method must be `handle`, and`am=handle` can appear exactly once. + - If exists, output parameter (either `am=pre` or `am=out`) is only allowed as the last one. Therefore, there is at most one output parameter. #### Interface Description File