Skip to content

Commit aaf635c

Browse files
committed
Draft someip-network-daemon architecture
1 parent 9d30b71 commit aaf635c

4 files changed

Lines changed: 240 additions & 0 deletions

File tree

74.3 KB
Loading
Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
@startuml sequence_provide_someip_service
2+
title "Sequence Provide SOME/IP service"
3+
hide footbox
4+
5+
participant "<u>UpperLayer</u>" as UpperLayer
6+
participant "<u>NetworkDaemonAPI</u>" as NetworkDaemonAPI
7+
participant "<u>vsomeip_v3::application</u>" as Application
8+
9+
activate UpperLayer
10+
UpperLayer -> NetworkDaemonAPI : message CreateSomeIPService
11+
12+
activate Runtime
13+
activate ConfigParser
14+
15+
opt user wants to specify non-default manifest path
16+
Process -> Runtime : Initialize(int argc, char** argv)
17+
activate Process
18+
deactivate OS
19+
20+
group config creation
21+
note over Runtime, ConfigParser: sequence see below
22+
end group
23+
24+
Runtime --> Process : return: void
25+
end opt
26+
27+
Process -> Runtime : getInstance()
28+
29+
opt config creation if singleton instance not yet created
30+
Runtime -> Runtime : Initialize() //with default manifest path
31+
Runtime -> ConfigParser : parse(path, const serviceTypeRegistry*)
32+
create Configuration
33+
ConfigParser -> Configuration : create()
34+
35+
ConfigParser --> Runtime : return: Configuration
36+
deactivate ConfigParser
37+
38+
create RuntimeInstance
39+
Runtime -> RuntimeInstance : create(configuration)
40+
end opt
41+
42+
Runtime --> Process : return: singleton instance
43+
deactivate Runtime
44+
45+
Process -> RuntimeInstance : resolve(InstanceSpecifier)
46+
activate RuntimeInstance
47+
RuntimeInstance -> Configuration : serviceInstances_.find(InstanceSpecifier)
48+
activate Configuration
49+
Configuration --> RuntimeInstance : return: Iter
50+
deactivate Configuration
51+
52+
RuntimeInstance --> Process : return: InstanceIdentifierContainer
53+
deactivate RuntimeInstance
54+
deactivate Process
55+
56+
@enduml
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
# SOME/IP Network Daemon Design Proposal
2+
3+
## Intro
4+
5+
Because of safety considerations we have a specific `SOME/IP network daemon`, which is responsible to handle the SOME/IP
6+
related network communication.
7+
It will be based on the open source SOME/IP implementation `vSomeIP`, which is provided [here](https://github.com/COVESA/vsomeip/blob/master/README.md).
8+
9+
Within S-CORE architecture, there will be different upper layers, which all need to use this network daemon. Currently
10+
under discussion:
11+
- Generic SOME/IP Gateway Daemon
12+
- OEM specific SOME/IP Gateway Daemon
13+
- S-CORE application using `score::mw::com` with a specific SOME/IP binding
14+
15+
The interfacing with the `SOME/IP network daemon` shall be identical for all upper layers.
16+
In this proposal we define a common architecture, which should end up in re-usable building blocks/libs, which are then
17+
used by all upper layers uniformly.
18+
19+
## Basic Architecture
20+
21+
There exist two "channels" between the `SOME/IP network daemon` and an upper layer using/relying on it:
22+
23+
- a DATA channel
24+
- a CONTROL channel
25+
26+
we explicitly separate these two channels as we intend to implement them with different technical mechanisms.
27+
28+
![Channels](./assets/basic_arch_overview.png)
29+
30+
### DATA channel
31+
32+
The DATA channel transports the (SOME/IP) service instance related data. This is:
33+
34+
- Event payloads
35+
- Field payloads
36+
- Method payloads (in-arguments and return values)
37+
38+
We intend to use shared-memory to implement the DATA channel. Mainly because payloads listed above might be large and
39+
using shared-memory as exchange mechanism might save copies in certain cases, which helps with performance.
40+
Additionally: Since there are already existing building blocks for shared-memory communication either in the more high
41+
level form of the `score::mw::com` SHM/LoLa binding or in its underlying `lib/memory/shared`.
42+
43+
Initially we plan implement this by DATA channel via creation of corresponding `score::mw::com` skeletons and proxies
44+
with LoLa/SHM binding. This already provides us with the underlying shared-memory storage!
45+
If we later discover, that using high-level proxy/skeleton abstraction isn't flexible enough (gives too many constraints),
46+
we can refactor in a way to use `lib/memory/shared` directly to build a better tailored shared-memory DATA channel
47+
48+
### CONTROL channel
49+
50+
The CONTROL channel is used to notify events occurring at one layer to the adjacent layer (upper layer to lower layer
51+
and vice versa). These events may be related to:
52+
53+
- DATA updates (notification, that event/field/method data has been updated)
54+
- service-discovery activities (initiating find/search, discovery results)
55+
- subscription activities
56+
57+
The CONTROL channel will be implemented based on `score::message_passing`, which is located [here](https://github.com/eclipse-score/communication/tree/main/score/message_passing).
58+
`score::message_passing` provides:
59+
60+
- unidirectional messaging from client to server
61+
- unidirectional messaging with asynchronous reply from the server side
62+
- synchronous RPC style communication.
63+
- asynchronous notification back from server to client
64+
65+
### `vSomeIP` interface
66+
67+
The main interface being used from `vSomeIP` will be the class `application`
68+
(see [here](https://github.com/COVESA/vsomeip/blob/master/interface/vsomeip/application.hpp)). Thus, the
69+
`Network Daemon API` shown in the picture above, will essentially interface to class `vsomeip_v3::application`!
70+
71+
For resource reasons, there will be only one instance of `vsomeip_v3::application` running within the
72+
`SOME/IP network daemon`.
73+
74+
### Usage of generic proxies and skeletons
75+
76+
As described in [DATA channel](#data-channel), we will use off-the-shelf `score::mw::com` proxies/skeletons to realize
77+
the DATA channel. Since we gain much more flexibility in these gateway biased use cases, when using loosely typed proxies
78+
and skeletons, this proposal relies on `score::mw::com::GenericProxy` (already existing) and
79+
`score::mw::com::GenericSkeleton` (to be developed) instances.
80+
81+
### Service-Discovery usage
82+
83+
From a functional perspective, we could do **without** usage of a service-discovery as the proxies/skeletons are solely
84+
used in a one-to-one relation and the existing CONTROL channel implicitly informs about the existence of the
85+
`score::mw::com::GenericSkeleton` providing the DATA channel.
86+
87+
But since a lot of the proxy side functionality is deeply coupled with service-discovery functionality, bypassing it
88+
seems to generate a lot of effort! Thus, we will use existing `OfferService` (skeleton) and `FindService` (proxy)
89+
functionality.
90+
91+
## Service instance forwarding to SOME/IP network daemon
92+
93+
### SOME/IP service instance identification
94+
95+
When interacting with SOME/IP network daemon (which encapsulates `vsomeip_v3::application`) we introduce the type
96+
`SomeIpServiceInstanceId`, which consists of the tuple of:
97+
98+
- service_t
99+
- instance_t
100+
- major_version_t
101+
- minor_version_t
102+
103+
which come from `vsomeip_v3::application`.
104+
105+
### Steps taken to offer local service instance towards SOME/IP and forward data
106+
107+
These are the steps, to forward a local service instance to the SOME/IP network daemon so that it gets provided as a
108+
SOME/IP service instance on the network:
109+
110+
1. The upper layer creates the DATA channel for the service instance by creating a corresponding
111+
`score::mw::com::GenericSkeleton` with LoLa/SHM binding.
112+
It might be sufficient, that each event/field contained in this skeleton has only one sample slot. This would implicitly
113+
mean, that we will see a data-loss, when the upper layer wants to update an event/field, but the `SOME/IP network daemon`
114+
is still busy/accessing the single slot.
115+
2. Then the upper layer sends a message via `score::message_passing` to the `SOME/IP network daemon`, to create the
116+
SOME/IP service instance. Thus, the message contains a tag/message-id `CreateServiceInstance`. Further payload of this
117+
message:
118+
- `SomeIpServiceInstanceId` describing the service instance
119+
- LoLa service type and instance id, which allows the `SOME/IP network daemon` to create the corresponding proxy instance
120+
to the skeleton created in (1).
121+
3. The `SOME/IP network daemon` receives the message in (2) and creates the proxy from the information contained. I.e. it
122+
issues a `score::mw::com::GenericProxy::FindService` and expects to get instantly a handle back, from which it then
123+
creates the proxy instance.
124+
Afterward, it is capable of accessing the event/field slots: The DATA channel is now set up.
125+
4. The upper layer sends a message via `score::message_passing` to the `SOME/IP network daemon`, to offer the service
126+
instance created in (1). Thus, the message contains a tag/message-id `OfferServiceInstance`. Further payload of
127+
this message:
128+
- `SomeIpServiceInstanceId` describing the service instance
129+
5. The `SOME/IP network daemon`receives the message sent in (4) and then calls `vsomeip_v3::application::offer_event()`
130+
for each event/field the underlying proxy created in (3) contains and then finally calls
131+
`vsomeip_v3::application::offer_service()` with the args taken from `SomeIpServiceInstanceId`.
132+
6. After the upper layer sends/updates an event/field on the `score::mw::com` skeleton, it sends a message via
133+
`score::message_passing` to the `SOME/IP network daemon`, to push the update to the SOME/IP service instance. Thus,
134+
the message contains a tag/message-id `UpdateEvent`. Further payload of this message:
135+
- `SomeIpServiceInstanceId` describing the service instance.
136+
- `EventId` describing which event/field to update
137+
7. The `SOME/IP network daemon`receives the message sent in (6) and then calls `vsomeip_v3::application::send()`
138+
for the event/field identified by `EventId`. The payload to hand over will be created by accessing the corresponding
139+
event/field of the `score::mw::com` proxy via `GetNewSamples()`. I.e. only, when `ProxyEvent::GetNewSamples()`
140+
returns a new `SamplePtr`, a `std::shared_ptr<message>` will be created from it and handed over to the call of
141+
`vsomeip_v3::application::send()`. After the call returned, the `SamplePtr` can be disposed.
142+
143+
### Steps taken to stop-offer service instance
144+
145+
In case the upper layer only wants to forward a "stop-offer" for its local `score::mw::com` skeleton, it sends a message
146+
via `score::message_passing` to the `SOME/IP network daemon`, to stop the service instance offering. The message
147+
contains a tag/message-id `StopOfferServiceInstance`. Further payload of this message:
148+
- `SomeIpServiceInstanceId` describing the service instance
149+
The implementation in `SOME/IP network daemon`receives the message and calls
150+
- `vsomeip_v3::application::stop_offer_service()` with the args taken from `SomeIpServiceInstanceId`.
151+
152+
## Service instance reception from SOME/IP network daemon
153+
154+
### Steps taken to receive a SOME/IP service-instance and provide it locally
155+
156+
1. The upper layer sends a message via `score::message_passing` to the `SOME/IP network daemon`, to trigger the search/
157+
discovery for the service instance on the SOME/IP (network) side. Thus, the message contains a tag/message-id
158+
`DiscoverServiceInstance`. Further payload of this message:
159+
- `SomeIpServiceInstanceId` describing the service instance
160+
- detailed meta-info of all events/fields/methods, which is sufficient, that the `SOME/IP network daemon` can create
161+
a `score::mw::com::GenericSkeleton` from it.
162+
2. The `SOME/IP network daemon` receives the message in (1) and then calls
163+
`vsomeip_v3::application::register_availability_handler`. All arguments but one are filled from
164+
`SomeIpServiceInstanceId`. Last argument is the availability handler (`availability_handler_t`), created by the
165+
`SOME/IP network daemon`.
166+
3. As soon as the availability handler fires and indicates, that on SOME/IP the instance identified via
167+
`SomeIpServiceInstanceId` is available, the `SOME/IP network daemon` creates a `score::mw::com::GenericSkeleton`
168+
based on the arguments received in (1) and sends back a notification to the upper layer via `score::message_passing`
169+
(`IServerConnection::Notify()`). Thus, the message contains a tag/message-id `ServiceInstanceAvailable`. Further
170+
payload of this message:
171+
- `SomeIpServiceInstanceId` describing the service instance
172+
- `InstanceIdentifier`. describing the created `score::mw::com::GenericSkeleton` instance
173+
4. Then the `SOME/IP network daemon` calls `vsomeip_v3::application::register_message_handler` for each event/field of
174+
the service instance to register its handler for SOME/IP message reception.
175+
5. When the upper layer receives the notification sent in (3), it calls `score::mw::com::GenericProxy::FindService()`
176+
with the `InstanceIdentifier` taken from the message and then creates `GenericProxy` instance from the returned
177+
handle. It now has a "connected" proxy to the SOME/IP service instance.
178+
6. When an event/field update happens for the network side SOME/IP service instance identified by `SomeIpServiceInstanceId`,
179+
the `SOME/IP network daemon` gets notified via its handler, which it has registered in (4). In its registered handler
180+
the `SOME/IP network daemon` accesses the received message payload containing event/field data update and calls the
181+
corresponding `GenericSkeletonEvent`/`GenericSkeletonField` `Send`/`Update` method.
182+
7. The upper layer can then &ndash; via the GenericProxy it has created in (5) &ndash; access updated event/field data
183+
with the standard mechanisms: (polling based or event notified) `GetNewSamples()`

0 commit comments

Comments
 (0)