Instantiating topology
In order to run a topology you need create an instance that describes what parts of the platform you want to run in your virtual environment. The instance also specifies what tests to run, optional ui and jupyter notebooks etc.
To understand how a topology is instantiated you can use
remotive-topology show topology --resolve <filename>
This shows only the parts of the platform that are instantiated and any defaults that have been applied.
See full topology schema for details. Also make sure to setup your editor to use schema validation, see installation instructions.
Platform subset
Given a platform:
schema: remotive-topology-platform:0.6
channels:
DriverCan0:
type: can
database: ../databases/driver_can.dbc
BodyCan0:
type: can
database: ../databases/body_can.dbc
You need to specify both what platform to use and which ECUs to instantiate:
schema: remotive-topology-instance:0.6
platform:
includes:
- ./topology.platform.yaml
ecus:
BCM:
By default all channels that are connected to the ECU are instantiated. This means the resulting topology is:
⚡ Notice how all the other ECUs aren't instantiated!
You can optionally specify a subset of channels. For example this only includes a single channel:
schema: remotive-topology-instance:0.6
platform:
includes:
- ./topology.platform.yaml
ecus:
BCM:
channels:
DriverCan0:
This results in the following topology:
ECU configuration
By default RemotiveTopology instantiates ECUs by using RemotiveBroker as this is the default virtualization in RemotiveTopology. You can using any other virtualization tool as long as it can be containerized, see below.
The RemotiveBroker allows you to communicate as an ECU, for example using the correct IP address on a VLAN or using a CAN device. However, you need to control what behavior the RemotiveBroker should have. RemotiveTopology supports Behavioral models or mocks.
Notice that it's not required to specify a behavior, i.e. you can also control the RemotiveBroker either interactively or from your test case.
Behavioral models
A behavioral model is a way to create a reusable component that emulates the behavior of a real ECU. It can receive and send messages.
To instantiate a behavioral model simply add the model to its ECU. Notice that an ECU can have multiple models, but each model must have a unique name.
ecus:
BCM:
models:
bcm:
type: python
include: ../ecus
main: bcm
When working with the RemotiveTopology framework you refer to namespaces which represents your ECUs view on a channel. Namespaces are named <ECU>-<Channel>
. If you are unsure about what namespaces exists you can start the topology instance and run:
remotive broker signals namespaces --url http://localhost:50051
Mock
An ECU Mock is a simpler alternative to a Behavioral Model. A common use case is providing a restbus that emulates an ECU so you can test a device in a realistic bus environment.
By default a mock is created for all channels that the ECU is connected to:
ecus:
FLCM:
mock: {}
You can also specify what channels you want to mock. This is useful when combining mocks and behavioral models for the same ECU:
ecus:
FLCM:
mock:
channels:
DriverCan0:
Container
Normally an ECU is instantiated using RemotiveBroker, but you can also use a custom container. This allows you to run any code as the ECU. For example to use a vsomeip implementation of an ECU:
ecus:
ecu_a:
container:
build:
dockerfile: ../../vsomeip.dockerfile
volumes:
- ../../config:/config_mapped
working_dir: /vsomeip/build/examples
command: "sh -c ./notify-sample"
environment:
- VSOMEIP_CONFIGURATION=/config_mapped/vsomeip-udp-service-ecu-a.json
- VSOMEIP_APPLICATION_NAME=service-sample
- VSOMEIP_LOGLEVEL=debug
Notice that the container starts correctly connected to all ECU channels according to the platform, e.g. for ethernet channel the container has the correct IP address.
Channel configuration
Channels must be configured when connecting to physical hardware or when connecting to software running outside the containerized environment.
CAN
RemotiveTopology supports two ways of instantiating a CAN network:
- DockerCAN using SocketCAN (default)
- Emulation using UDP (by broadcasting ethernet PDUs)
DockerCAN using SocketCAN is needed to connect to physical hardware and to use standard CAN tooling such as candump
. However, as SocketCAN is only supported on Linux. On Mac and Windows you need to fall back to emulation. Notice that the UDP packets are still encoded in the same way as the real CAN frames, by using ethernet PDUs.
DockerCAN
DockerCAN provides SocketCAN access to docker containers. SocketCAN is only available on Linux. You need to install RemotiveLabs DockerCAN. For each channel you must specify what CAN device to use on the host. In this example to map candevice0
to channel DriverCan0
you need to specify:
channels:
DriverCan0:
type: can
driver:
type: dockercan
device_name: candevice0
While the device on the host is called candevice0
, unfortunately docker appends a 0 to the name, i.e. in this case the device name inside the docker container is candevice00
.
By default the channel is configured to connect to a device with the same name as the channel (but in lowercase), i.e. like this:
channels:
MyChannel:
type: can
driver:
type: dockercan
device_name: mychannel
Remember that inside the docker container the device name has a 0 appended, i.e. in the default case it's called mychannel0
.
If you need a different name inside the docker container than on the host you can specify peer
:
channels:
DriverCan0:
type: can
driver:
type: dockercan
device_name: candevice0
peer: in-docker
Unfortunately as 0 is still appended, the device inside docker is called in-docker0
.
Linux has a max length of the name of a device. If your channel name is too long, then you have to assign a shorter device_name
.
Recommendations:
- Avoid names such as
can0
orcan1
- Rename physical devices to match your target architecture, e.g.
sudo ip link set can0 name drivercan0
- Inside the container try to use a name similar to the channel. This makes it easier to understand in a virtual context.
Emulation using UDP
Emulation using UDP is available on all platform and doesn't require any additional setup. This works by using UDP multicast and encoding frames as ethernet PDUs, i.e. signals are encoded the same ways when using CAN. Simply change this global setting:
settings:
can:
default_driver: udp
Optionally, you can specify this for each instance channel:
channels:
DriverCan0:
type: can
driver:
type: udp
Ethernet
Ethernet doesn't require any configuration by default.
VLAN
To connect physical networks into the topology you need to configure which device should map into what channel. For example this is mapping eth1 device to the ETH
channel:
channels:
ETH:
type: ethernet
driver:
type: macvlan
device_name: eth1
This is using macvlan
network driver.
If the platform has defined a VLAN this tag is added automatically!
Bridge with iptables
docker network create -d bridge \
--subnet=198.0.0.0/24 \
--gateway=198.0.0.252 \
LowSafety
sudo iptables -I DOCKER 1 -d 198.0.0.22/32 -i gre1 -o br-ccea162a699d -c 0 0 -j ACCEPT
sudo iptables -I DOCKER 1 -s 198.0.0.22/32 -i br-ccea162a699d -o gre1 -j ACCEPT
Gateway
Normally a gateway shouldn't be used as all communication typically happens within each subnet. However, if an ECU needs to route packets outside the subnet a gateway is needed.
Docker automatically provides a gateway for each network that handles routing outside the subnet. Also notice that unless a specific network interface is used, the default is the control network that's automatically added by RemotiveTopology.
RemotiveTopology automatically assigns a free i.p address to the gateway, but you can also specify the gateway like this:
channels:
ETH:
type: ethernet
gateway_ip: 10.1.1.192
In general this isn't needed.
TopologyBroker
Every topology includes a central TopologyBroker which coordinates the other brokers and also allows communication with most channels.
RemotiveTopology automatically assign a free IP address to the TopologyBroker, but you can also specify the an IP address like this:
channels:
ETH:
type: ethernet
topology_broker_ip: 10.1.1.199
In general this isn't needed.
Additional containers
RemotiveTopology also provides a way to run arbitrary containers inside the topology. These containers have access to RemotiveBroker and can therefore interact with ECUs in the topology.
A common use case is to run test cases. By using an arbitrary container you can use whatever test framework you want:
containers:
tester:
profiles: [tester]
build:
dockerfile: ../../../python-runner.dockerfile
volumes:
- ../tests:/app
working_dir: /app
command: "pytest --broker_url=http://topology-broker.com:50051 -s -vv"
Profiles
The containers can have one or more profiles. These correspond to profiles in docker compose, i.e. to run the preceding tests you simply start:
docker compose -f build/mytopology/docker-compose.yaml --profile tester up
When running tests it's useful to shut down the topology after the tests have completed using the flag --abort-on-container-exit
:
docker compose -f build/mytopology/docker-compose.yaml --profile tester up --abort-on-container-exit
User interface
RemotiveTopology includes a web app that allows you to interact with the topology and inspect signals. To avoid running this in CI you need to trigger the profile: ui
docker compose -f build/mytopology/docker-compose.yaml --profile ui up
Then open http://localhost:8080 to access the user interface.
Settings
CAN
To emulate CAN using UDP for all CAN channels specify:
settings:
can:
default_driver: udp
This setting is optional, by default DockerCAN is used.
Docker
To instantiate the mocks and behavioral models a container or image configuration is needed. This needs python and RemotiveTopology framework, but you can also add custom dependencies here.
settings:
docker:
mock:
image: remotivelabs/remotivelabs-topology-python:0.9.0
python:
build:
dockerfile: ../python-runner.dockerfile
Specifying mock
and python
is optional. python
since this can be configured as part of the Behavioral model and mock
since the generator defaults to a docker image. A version of the generator always uses the same docker image.
RemotiveBroker
RemotiveBroker can either be configured using instance.yaml
or environment variables.
settings:
remotivebroker:
version: v1.10.1
license_file: ../../../LICENSE_FILE
Corresponding environment variables:
REMOTIVEBROKER_TAG=v1.10.1
REMOTIVEBROKER_LICENSE=/path/to/LICENSE_FILE
Recommendation:
- Version: Use
instance.yaml
to ensure that you have consistent behavior in all environments - License: Use REMOTIVEBROKER_LICENSE to avoid having LICENSE_FILE in your repository
TopologyBroker
The TopologyBroker needs to have access to all frames on all channels. To achieve this RemotiveTopology automatically merges all necessary signaldatabases for use by the TopologyBroker. However, it might be useful to explicitly set which signaldatabase, for example if you want to use ECU extracts for all ECUs but you also have a complete signaldatabase for the channel available.
settings:
topology_broker:
channels:
DriverCan0:
database: ./special.dbc
These settings are optional.
User interface
You can configure details about the ui
web app. It might be useful to specify a different port number. You can also change the profile, for example if you want to use ui
profile for your custom containers.
settings:
ui:
port: 8080
profile: ui
These settings are optional.