Skip to content

Commit 0d4bfdd

Browse files
committed
[radvd] Add radvd role for IPv6 RA management
Creates a new Ansible role to manage radvd (Router Advertisement Daemon) configuration for IPv6 networks. Features: - Manages system radvd.service and /etc/radvd.conf - Configuration fragment assembly from /etc/cifmw-radvd.d/ - Support for SLAAC and DHCPv6 (M-flag, O-flag) - IPv6 prefix, route, and RDNSS advertisement - Dynamic network addition/removal via tasks_from - Molecule test coverage Assisted-By: Claude Code/claude-4.5-sonnet Signed-off-by: Harald Jensås <[email protected]>
1 parent 0cf91bc commit 0d4bfdd

File tree

14 files changed

+749
-0
lines changed

14 files changed

+749
-0
lines changed

roles/radvd/README.md

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
# radvd
2+
3+
Manage radvd (Router Advertisement Daemon) configuration.
4+
5+
This role provides IPv6 Router Advertisements for network interfaces, enabling
6+
Stateless Address Autoconfiguration (SLAAC) and/or DHCPv6.
7+
8+
## Privilege escalation
9+
10+
- Package installation
11+
- Writing in protected locations `/etc/radvd.conf`, `/etc/cifmw-radvd.d`
12+
- Managing system service `radvd.service`
13+
14+
## Common Parameters
15+
16+
* `cifmw_radvd_basedir`: (String) Configuration fragments directory. Defaults to `/etc/cifmw-radvd.d`.
17+
* `cifmw_radvd_networks`: (List) List of networks to configure. Defaults to `[]`.
18+
19+
## Network Configuration
20+
21+
Each network in `cifmw_radvd_networks` supports the following parameters:
22+
23+
* `name`: (String) Network/interface name. **Required**.
24+
* `state`: (String) Network status. Must be either `present` or `absent`. Defaults to `present`.
25+
* `prefixes`: (List[mapping]) List of IPv6 prefixes to advertise. **Required when state is present**.
26+
* `adv_send_advert`: (Bool) Enable/disable router advertisements. Defaults to `true`.
27+
* `adv_managed_flag`: (Bool) Managed address configuration flag (M-flag). Indicates DHCPv6 for addresses.
28+
* `adv_other_config_flag`: (Bool) Other configuration flag (O-flag). Indicates DHCPv6 for other configuration.
29+
* `adv_ra_solicited_unicast`: (Bool) Enable unicast router advertisements.
30+
* `adv_link_mtu`: (Int) Advertised MTU for the link.
31+
* `min_rtr_adv_interval`: (Int) Minimum router advertisement interval in seconds.
32+
* `max_rtr_adv_interval`: (Int) Maximum router advertisement interval in seconds.
33+
* `routes`: (List[mapping]) List of routes to advertise. Optional.
34+
* `rdnss`: (List[mapping]) List of recursive DNS servers to advertise. Optional.
35+
36+
### Prefix mapping
37+
38+
* `network`: (String) IPv6 prefix (e.g., `2001:db8:1::/64`). **Required**.
39+
* `adv_on_link`: (Bool) On-link flag. Defaults to `true`.
40+
* `adv_autonomous`: (Bool) Autonomous address configuration flag (SLAAC). Defaults to `true`.
41+
* `adv_router_addr`: (Bool) Include router address in prefix information.
42+
* `adv_valid_lifetime`: (String/Int) Valid lifetime for the prefix (e.g., `86400`, `infinity`).
43+
* `adv_preferred_lifetime`: (String/Int) Preferred lifetime for the prefix.
44+
45+
### Route mapping
46+
47+
* `network`: (String) IPv6 route prefix. **Required**.
48+
* `adv_route_preference`: (String) Route preference (`low`, `medium`, `high`).
49+
* `adv_route_lifetime`: (Int) Route lifetime in seconds.
50+
51+
### RDNSS mapping
52+
53+
* `servers`: (List[String]) List of IPv6 DNS server addresses. **Required**.
54+
* `adv_rdnss_lifetime`: (Int) RDNSS lifetime in seconds.
55+
56+
## Examples
57+
58+
### Basic network with SLAAC only
59+
60+
```yaml
61+
- name: Configure radvd networks
62+
vars:
63+
cifmw_radvd_networks:
64+
- name: testnet
65+
adv_managed_flag: false
66+
adv_other_config_flag: false
67+
adv_link_mtu: 1500
68+
min_rtr_adv_interval: 30
69+
max_rtr_adv_interval: 100
70+
prefixes:
71+
- network: "2001:db8:1::/64"
72+
adv_on_link: true
73+
adv_autonomous: true
74+
adv_router_addr: true
75+
ansible.builtin.include_role:
76+
name: radvd
77+
```
78+
79+
### Network with DHCPv6 for addresses and other configuration
80+
81+
```yaml
82+
- name: Configure radvd with DHCPv6
83+
vars:
84+
cifmw_radvd_networks:
85+
- name: provisioning
86+
adv_managed_flag: true
87+
adv_other_config_flag: true
88+
adv_ra_solicited_unicast: true
89+
adv_link_mtu: 1500
90+
min_rtr_adv_interval: 30
91+
max_rtr_adv_interval: 100
92+
prefixes:
93+
- network: "2001:db8:2::/64"
94+
adv_on_link: true
95+
adv_autonomous: false
96+
rdnss:
97+
- servers:
98+
- "2001:db8:2::53"
99+
adv_rdnss_lifetime: 300
100+
ansible.builtin.include_role:
101+
name: radvd
102+
```
103+
104+
### Multiple networks
105+
106+
```yaml
107+
- name: Configure multiple networks
108+
vars:
109+
cifmw_radvd_networks:
110+
- name: net1
111+
adv_managed_flag: true
112+
adv_other_config_flag: true
113+
adv_link_mtu: 1500
114+
min_rtr_adv_interval: 30
115+
max_rtr_adv_interval: 100
116+
prefixes:
117+
- network: "2001:db8:1::/64"
118+
adv_on_link: true
119+
adv_autonomous: true
120+
- name: net2
121+
adv_managed_flag: false
122+
adv_other_config_flag: false
123+
prefixes:
124+
- network: "2001:db8:2::/64"
125+
adv_on_link: true
126+
adv_autonomous: true
127+
ansible.builtin.include_role:
128+
name: radvd
129+
```
130+
131+
### Remove a network configuration
132+
133+
```yaml
134+
- name: Remove radvd configuration for a network
135+
vars:
136+
cifmw_radvd_networks:
137+
- name: testnet
138+
state: absent
139+
ansible.builtin.include_role:
140+
name: radvd
141+
```
142+
143+
### Adding a single network dynamically
144+
145+
You can also add a single network using `tasks_from: manage_network.yml`:
146+
147+
```yaml
148+
- name: Add a single network to radvd
149+
vars:
150+
cifmw_radvd_network:
151+
name: testnet
152+
adv_managed_flag: true
153+
adv_other_config_flag: true
154+
adv_link_mtu: 1500
155+
min_rtr_adv_interval: 30
156+
max_rtr_adv_interval: 100
157+
prefixes:
158+
- network: "2001:db8:1::/64"
159+
adv_on_link: true
160+
adv_autonomous: true
161+
adv_router_addr: true
162+
ansible.builtin.include_role:
163+
name: radvd
164+
tasks_from: manage_network.yml
165+
```
166+
167+
### Cleanup entire radvd service
168+
169+
```yaml
170+
- name: Cleanup radvd
171+
ansible.builtin.include_role:
172+
name: radvd
173+
tasks_from: cleanup.yml
174+
```
175+
176+
## Understanding the flags
177+
178+
### Managed Flag (M-flag) - `adv_managed_flag`
179+
180+
When set to `true`, hosts should use DHCPv6 to obtain IPv6 addresses (stateful DHCPv6).
181+
When set to `false`, hosts should use SLAAC (Stateless Address Autoconfiguration) based on the advertised prefix.
182+
183+
### Other Config Flag (O-flag) - `adv_other_config_flag`
184+
185+
When set to `true`, hosts should use DHCPv6 to obtain other configuration information (DNS, NTP, etc.).
186+
187+
### Common configurations
188+
189+
1. **SLAAC only**: `adv_managed_flag: false`, `adv_other_config_flag: false`, `adv_autonomous: true`
190+
2. **SLAAC + DHCPv6 for options**: `adv_managed_flag: false`, `adv_other_config_flag: true`, `adv_autonomous: true`
191+
3. **DHCPv6 for everything**: `adv_managed_flag: true`, `adv_other_config_flag: true`, `adv_autonomous: false`
192+
193+
## Notes
194+
195+
- The interface/bridge specified by the `name` parameter must exist before radvd can advertise on it.
196+
- IPv6 forwarding must be enabled on the host for router advertisements to work properly.
197+
- Multiple prefixes can be advertised on the same interface.
198+
- The role uses the system `radvd.service` from the RPM package.
199+
- Configuration is assembled from fragments in `/etc/cifmw-radvd.d/` into `/etc/radvd.conf`.
200+

roles/radvd/defaults/main.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
---
2+
# Copyright Red Hat, Inc.
3+
# All Rights Reserved.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
6+
# not use this file except in compliance with the License. You may obtain
7+
# a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14+
# License for the specific language governing permissions and limitations
15+
# under the License.
16+
17+
18+
# All variables within this role should have a prefix of "cifmw_radvd"
19+
20+
cifmw_radvd_basedir: "/etc/cifmw-radvd.d"
21+
cifmw_radvd_networks: []
22+

roles/radvd/meta/main.yml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
---
2+
# Copyright Red Hat, Inc.
3+
# All Rights Reserved.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
6+
# not use this file except in compliance with the License. You may obtain
7+
# a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14+
# License for the specific language governing permissions and limitations
15+
# under the License.
16+
17+
18+
galaxy_info:
19+
author: CI Framework
20+
description: CI Framework Role -- radvd
21+
company: Red Hat
22+
license: Apache-2.0
23+
min_ansible_version: "2.14"
24+
namespace: cifmw
25+
galaxy_tags:
26+
- cifmw
27+
28+
# List your role dependencies here, one per line. Be sure to remove the '[]' above,
29+
# if you add dependencies to this list.
30+
dependencies: []
31+
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
---
2+
# Copyright Red Hat, Inc.
3+
# All Rights Reserved.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
6+
# not use this file except in compliance with the License. You may obtain
7+
# a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14+
# License for the specific language governing permissions and limitations
15+
# under the License.
16+
17+
- name: Cleanup
18+
hosts: all
19+
tasks:
20+
- name: Copy generated content in ci-framework-data/artifacts
21+
vars:
22+
dest_dir: >-
23+
{{
24+
(ansible_user_dir,
25+
'ci-framework-data',
26+
'artifacts') | path_join
27+
}}
28+
ansible.posix.synchronize:
29+
src: "{{ item }}"
30+
dest: "{{ dest_dir }}"
31+
loop:
32+
- /etc/radvd.conf
33+
- /etc/cifmw-radvd.d/
34+
35+
- name: Remove testnet3 network configuration
36+
vars:
37+
cifmw_radvd_networks:
38+
- name: testnet3
39+
state: absent
40+
ansible.builtin.include_role:
41+
name: radvd
42+
43+
- name: Verify testnet3 network configuration was removed
44+
become: true
45+
ansible.builtin.stat:
46+
path: /etc/cifmw-radvd.d/testnet3.conf
47+
register: _testnet3_conf
48+
49+
- name: Assert testnet3 configuration is removed
50+
ansible.builtin.assert:
51+
that:
52+
- not _testnet3_conf.stat.exists
53+
54+
- name: Cleanup radvd
55+
ansible.builtin.import_role:
56+
name: "radvd"
57+
tasks_from: "cleanup.yml"
58+
59+
- name: Verify cleanup was successful
60+
become: true
61+
ansible.builtin.stat:
62+
path: "{{ item }}"
63+
register: _cleanup_check
64+
loop:
65+
- /etc/radvd.conf
66+
- /etc/cifmw-radvd.d
67+
failed_when: _cleanup_check.results | map(attribute='stat.exists') | list | max

0 commit comments

Comments
 (0)