mirror of
https://github.com/linux-system-roles/network.git
synced 2026-01-23 02:15:17 +00:00
initscripts: Configure output device in routes
Without an explicit output device, the kernel might use a different output device than intended by the user. Therefore, use the interface name of connections to specify it if it is available. Otherwise, educate the user about this potential problem with a warning. This aligns the behavior with NetworkManager which configures the output device in routes when activating profiles on devices. Fixes: https://bugzilla.redhat.com/2168735 Signed-off-by: Wen Liang <liangwen12year@gmail.com>
This commit is contained in:
parent
e4cc5c138f
commit
7c0579ddfc
5 changed files with 398 additions and 3 deletions
|
|
@ -531,6 +531,19 @@ class IfcfgUtil:
|
|||
line = r["network"] + "/" + str(r["prefix"])
|
||||
if r["gateway"]:
|
||||
line += " via " + r["gateway"]
|
||||
if connection["interface_name"]:
|
||||
line += " dev " + connection["interface_name"]
|
||||
else:
|
||||
warn_fcn(
|
||||
"The connection {0} does not specify an interface name. "
|
||||
"Therefore, the route to {1}/{2} will be configured without "
|
||||
"the output device and the kernel will choose it "
|
||||
"automatically which might result in an unwanted device being "
|
||||
"used. To avoid this, specify `interface_name` in the "
|
||||
"connection appropriately.".format(
|
||||
connection["name"], r["network"], r["prefix"]
|
||||
),
|
||||
)
|
||||
if r["metric"] != -1:
|
||||
line += " metric " + str(r["metric"])
|
||||
|
||||
|
|
|
|||
188
tests/playbooks/tests_route_device.yml
Normal file
188
tests/playbooks/tests_route_device.yml
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- name: Test output device of routes
|
||||
hosts: all
|
||||
vars:
|
||||
type: veth
|
||||
interface0: ethtest0
|
||||
interface1: ethtest1
|
||||
|
||||
tasks:
|
||||
- name: Set type and interface0
|
||||
set_fact:
|
||||
type: "{{ type }}"
|
||||
interface: "{{ interface0 }}"
|
||||
- name: Show interfaces
|
||||
include_tasks: tasks/show_interfaces.yml
|
||||
- name: Manage test interface
|
||||
include_tasks: tasks/manage_test_interface.yml
|
||||
vars:
|
||||
state: present
|
||||
- name: Assert device is present
|
||||
include_tasks: tasks/assert_device_present.yml
|
||||
- name: Set interface1
|
||||
set_fact:
|
||||
interface: "{{ interface1 }}"
|
||||
- name: Show interfaces
|
||||
include_tasks: tasks/show_interfaces.yml
|
||||
- name: Manage test interface
|
||||
include_tasks: tasks/manage_test_interface.yml
|
||||
vars:
|
||||
state: present
|
||||
- name: Assert device is present
|
||||
include_tasks: tasks/assert_device_present.yml
|
||||
- name: Test the route or the warning log when configuring the route with
|
||||
or without the interface name
|
||||
block:
|
||||
- name: Configure the IP addresses and the route with interface name
|
||||
specified
|
||||
import_role:
|
||||
name: linux-system-roles.network
|
||||
vars:
|
||||
network_connections:
|
||||
- name: "{{ interface0 }}"
|
||||
interface_name: "{{ interface0 }}"
|
||||
state: up
|
||||
type: ethernet
|
||||
autoconnect: false
|
||||
ip:
|
||||
address:
|
||||
- 198.51.100.3/24
|
||||
- 2001:db8::2/32
|
||||
route:
|
||||
- network: 198.51.10.64
|
||||
prefix: 26
|
||||
gateway: 198.51.100.6
|
||||
metric: 4
|
||||
- network: 2001:db6::4
|
||||
prefix: 128
|
||||
gateway: 2001:db8::1
|
||||
metric: 2
|
||||
- name: "{{ interface1 }}"
|
||||
interface_name: "{{ interface1 }}"
|
||||
state: up
|
||||
type: ethernet
|
||||
autoconnect: false
|
||||
ip:
|
||||
address:
|
||||
- 198.51.100.6/24
|
||||
- 2001:db8::4/32
|
||||
route:
|
||||
- network: 198.51.12.128
|
||||
prefix: 26
|
||||
gateway: 198.51.100.1
|
||||
metric: 2
|
||||
- name: Get the IPv4 routes from the route table main
|
||||
command: ip -4 route
|
||||
register: route_table_main_ipv4
|
||||
changed_when: false
|
||||
|
||||
- name: Assert that the route table main contains the specified IPv4
|
||||
routes
|
||||
assert:
|
||||
that:
|
||||
# When running with nm provider, the route will be configured
|
||||
# with `proto static`
|
||||
# In RHEL-6.10 managed host, the attribute in the route is not
|
||||
# equally spaced
|
||||
- route_table_main_ipv4.stdout is search("198.51.10.64/26 via
|
||||
198.51.100.6 dev ethtest0\s+(proto static )?metric 4")
|
||||
- route_table_main_ipv4.stdout is search("198.51.12.128/26 via
|
||||
198.51.100.1 dev ethtest1\s+(proto static )?metric 2")
|
||||
msg: "the route table main does not contain the specified IPv4
|
||||
route"
|
||||
|
||||
- name: Get the IPv6 routes from the route table main
|
||||
command: ip -6 route
|
||||
register: route_table_main_ipv6
|
||||
changed_when: false
|
||||
|
||||
- name: Assert that the route table main contains the specified IPv6
|
||||
routes
|
||||
assert:
|
||||
that:
|
||||
- route_table_main_ipv6.stdout is search("2001:db6::4 via
|
||||
2001:db8::1 dev ethtest0\s+(proto static )?metric 2")
|
||||
msg: "the route table main does not contain the specified IPv6
|
||||
route"
|
||||
- name: Get the interface1 MAC address
|
||||
command: cat /sys/class/net/{{ interface1 }}/address
|
||||
register: interface1_mac
|
||||
changed_when: false
|
||||
- name: Configure the IP addresses and the route with only the MAC
|
||||
address specified
|
||||
import_role:
|
||||
name: linux-system-roles.network
|
||||
vars:
|
||||
network_connections:
|
||||
- name: "{{ interface1 }}"
|
||||
mac: "{{ interface1_mac.stdout }}"
|
||||
type: ethernet
|
||||
autoconnect: false
|
||||
ip:
|
||||
address:
|
||||
- 198.51.100.4/24
|
||||
- 2001:db8::6/32
|
||||
route:
|
||||
- network: 198.58.10.64
|
||||
prefix: 26
|
||||
gateway: 198.51.100.102
|
||||
metric: 4
|
||||
|
||||
- name: Assert that the warning about specifying the route without
|
||||
the output device is logged for initscripts provider
|
||||
assert:
|
||||
that:
|
||||
- __network_connections_result.stderr is search("\[003\]
|
||||
<warn> .0, state.None persistent_state.present,
|
||||
'{{ interface1 }}'. The connection {{ interface1 }} does not
|
||||
specify an interface name. Therefore, the route to
|
||||
198.58.10.64/26 will be configured without the output device
|
||||
and the kernel will choose it automatically which might result
|
||||
in an unwanted device being used. To avoid this, specify
|
||||
`interface_name` in the connection appropriately.")
|
||||
msg: The warning about specifying the route without the output
|
||||
device is not logged for initscripts provider
|
||||
when: network_provider == "initscripts"
|
||||
|
||||
- name: Assert that no warning is logged for nm provider
|
||||
assert:
|
||||
that:
|
||||
- __network_connections_result.stderr is not search("<warn>")
|
||||
msg: The warning is logged for nm provider
|
||||
when: network_provider == "nm"
|
||||
always:
|
||||
- name: Remove test configuration
|
||||
block:
|
||||
- name: Bring down test devices and profiles
|
||||
include_role:
|
||||
name: linux-system-roles.network
|
||||
vars:
|
||||
network_connections:
|
||||
- name: "{{ interface0 }}"
|
||||
persistent_state: absent
|
||||
state: down
|
||||
- name: "{{ interface1 }}"
|
||||
persistent_state: absent
|
||||
state: down
|
||||
- name: Delete interface1
|
||||
include_tasks: tasks/delete_interface.yml
|
||||
- name: Assert interface1 is absent
|
||||
include_tasks: tasks/assert_device_absent.yml
|
||||
- name: Set interface0
|
||||
set_fact:
|
||||
interface: "{{ interface0 }}"
|
||||
- name: Delete interface0
|
||||
include_tasks: tasks/delete_interface.yml
|
||||
- name: Assert interface0 is absent
|
||||
include_tasks: tasks/assert_device_absent.yml
|
||||
- name: Assert interface0 profile and interface1 profile are absent
|
||||
include_tasks: tasks/assert_profile_absent.yml
|
||||
vars:
|
||||
profile: "{{ item }}"
|
||||
loop:
|
||||
- "{{ interface0 }}"
|
||||
- "{{ interface1 }}"
|
||||
tags:
|
||||
- "tests::cleanup"
|
||||
...
|
||||
16
tests/tests_route_device_initscripts.yml
Normal file
16
tests/tests_route_device_initscripts.yml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# This file was generated by ensure_provider_tests.py
|
||||
---
|
||||
- hosts: all
|
||||
name: Run playbook 'playbooks/tests_route_device.yml' with initscripts as provider
|
||||
tasks:
|
||||
- include_tasks: tasks/el_repo_setup.yml
|
||||
- name: Set network provider to 'initscripts'
|
||||
set_fact:
|
||||
network_provider: initscripts
|
||||
tags:
|
||||
- always
|
||||
|
||||
- import_playbook: playbooks/tests_route_device.yml
|
||||
when: (ansible_distribution in ['CentOS','RedHat'] and
|
||||
ansible_distribution_major_version | int < 9)
|
||||
20
tests/tests_route_device_nm.yml
Normal file
20
tests/tests_route_device_nm.yml
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# This file was generated by ensure_provider_tests.py
|
||||
---
|
||||
# set network provider and gather facts
|
||||
- hosts: all
|
||||
name: Run playbook 'playbooks/tests_route_device.yml' with nm as provider
|
||||
tasks:
|
||||
- include_tasks: tasks/el_repo_setup.yml
|
||||
- name: Set network provider to 'nm'
|
||||
set_fact:
|
||||
network_provider: nm
|
||||
tags:
|
||||
- always
|
||||
|
||||
|
||||
# The test requires or should run with NetworkManager, therefore it cannot run
|
||||
# on RHEL/CentOS 6
|
||||
- import_playbook: playbooks/tests_route_device.yml
|
||||
when:
|
||||
- ansible_distribution_major_version != '6'
|
||||
|
|
@ -2651,7 +2651,7 @@ class TestValidator(Python26CompatTestCase):
|
|||
"DEVICE": "555",
|
||||
},
|
||||
"keys": None,
|
||||
"route": "192.168.45.0/24 metric 545\n192.168.46.0/30\n",
|
||||
"route": "192.168.45.0/24 dev 555 metric 545\n192.168.46.0/30 dev 555\n",
|
||||
"route6": None,
|
||||
"rule": None,
|
||||
"rule6": None,
|
||||
|
|
@ -2772,7 +2772,7 @@ class TestValidator(Python26CompatTestCase):
|
|||
{
|
||||
"ifcfg": "",
|
||||
"keys": None,
|
||||
"route": "192.168.40.0/24 metric 545\n192.168.46.0/30",
|
||||
"route": "192.168.40.0/24 dev e556 metric 545\n192.168.46.0/30",
|
||||
"route6": "a:b:c:f::/64",
|
||||
"rule": None,
|
||||
"rule6": None,
|
||||
|
|
@ -2792,13 +2792,171 @@ class TestValidator(Python26CompatTestCase):
|
|||
"DEVICE": "e556",
|
||||
},
|
||||
"keys": None,
|
||||
"route": "192.168.40.0/24 metric 545\n192.168.46.0/30\n"
|
||||
"route": "192.168.40.0/24 dev e556 metric 545\n"
|
||||
"192.168.46.0/30\n"
|
||||
"192.168.45.0/24 dev e556 metric 545\n"
|
||||
"192.168.46.0/30 dev e556\n",
|
||||
"route6": "a:b:c:f::/64\na:b:c:d::/64 dev e556\n",
|
||||
"rule": None,
|
||||
"rule6": None,
|
||||
}
|
||||
],
|
||||
)
|
||||
|
||||
def test_route_without_interface_name(self):
|
||||
route_device_warning = (
|
||||
"The connection e556 does not specify an interface name. Therefore, the "
|
||||
"route to {0} will be configured without the output device and the kernel "
|
||||
"will choose it automatically which might result in an unwanted device "
|
||||
"being used. To avoid this, specify `interface_name` in the connection "
|
||||
"appropriately."
|
||||
)
|
||||
self.maxDiff = None
|
||||
self.do_connections_validate(
|
||||
[
|
||||
{
|
||||
"actions": ["present", "up"],
|
||||
"autoconnect": True,
|
||||
"check_iface_exists": True,
|
||||
"ethernet": ETHERNET_DEFAULTS,
|
||||
"ethtool": ETHTOOL_DEFAULTS,
|
||||
"force_state_change": None,
|
||||
"ignore_errors": None,
|
||||
"interface_name": None,
|
||||
"ip": {
|
||||
"gateway6": None,
|
||||
"gateway4": None,
|
||||
"route_metric4": None,
|
||||
"auto6": True,
|
||||
"ipv6_disabled": False,
|
||||
"dhcp4": True,
|
||||
"address": [],
|
||||
"auto_gateway": None,
|
||||
"route_append_only": True,
|
||||
"rule_append_only": False,
|
||||
"route": [
|
||||
{
|
||||
"family": socket.AF_INET,
|
||||
"network": "192.168.45.0",
|
||||
"prefix": 24,
|
||||
"gateway": None,
|
||||
"metric": 545,
|
||||
"table": None,
|
||||
},
|
||||
{
|
||||
"family": socket.AF_INET,
|
||||
"network": "192.168.46.0",
|
||||
"prefix": 30,
|
||||
"gateway": None,
|
||||
"metric": -1,
|
||||
"table": None,
|
||||
},
|
||||
{
|
||||
"family": socket.AF_INET6,
|
||||
"network": "a:b:c:d::",
|
||||
"prefix": 64,
|
||||
"gateway": None,
|
||||
"metric": -1,
|
||||
"table": None,
|
||||
},
|
||||
],
|
||||
"routing_rule": [],
|
||||
"dns": [],
|
||||
"dns_options": [],
|
||||
"dns_priority": 0,
|
||||
"dns_search": ["aa", "bb"],
|
||||
"route_metric6": None,
|
||||
"dhcp4_send_hostname": None,
|
||||
},
|
||||
"mac": "12:23:34:45:56:60",
|
||||
"cloned_mac": "default",
|
||||
"match": {},
|
||||
"controller": None,
|
||||
"ieee802_1x": None,
|
||||
"wireless": None,
|
||||
"mtu": None,
|
||||
"name": "e556",
|
||||
"parent": None,
|
||||
"persistent_state": "present",
|
||||
"port_type": None,
|
||||
"state": "up",
|
||||
"type": "ethernet",
|
||||
"wait": None,
|
||||
"zone": "external",
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"name": "e556",
|
||||
"state": "up",
|
||||
"type": "ethernet",
|
||||
"zone": "external",
|
||||
"mac": "12:23:34:45:56:60",
|
||||
"ip": {
|
||||
"dns_search": ["aa", "bb"],
|
||||
"route_append_only": True,
|
||||
"rule_append_only": False,
|
||||
"route": [
|
||||
{"network": "192.168.45.0", "metric": 545},
|
||||
{"network": "192.168.46.0", "prefix": 30},
|
||||
{"network": "a:b:c:d::"},
|
||||
],
|
||||
},
|
||||
}
|
||||
],
|
||||
nm_route_list_current=[
|
||||
[
|
||||
{"network": "192.168.40.0", "prefix": 24, "metric": 545},
|
||||
{"network": "192.168.46.0", "prefix": 30},
|
||||
{"network": "a:b:c:f::"},
|
||||
]
|
||||
],
|
||||
nm_route_list_expected=[
|
||||
[
|
||||
{"network": "192.168.40.0", "prefix": 24, "metric": 545},
|
||||
{"network": "192.168.46.0", "prefix": 30},
|
||||
{"network": "192.168.45.0", "prefix": 24, "metric": 545},
|
||||
{"network": "a:b:c:f::"},
|
||||
{"network": "a:b:c:d::"},
|
||||
]
|
||||
],
|
||||
initscripts_content_current=[
|
||||
{
|
||||
"ifcfg": "",
|
||||
"keys": None,
|
||||
"route": "192.168.40.0/24 metric 545\n192.168.46.0/30",
|
||||
"route6": "a:b:c:f::/64",
|
||||
"rule": None,
|
||||
"rule6": None,
|
||||
}
|
||||
],
|
||||
initscripts_dict_expected=[
|
||||
{
|
||||
"ifcfg": {
|
||||
"BOOTPROTO": "dhcp",
|
||||
"DOMAIN": "aa bb",
|
||||
"HWADDR": "12:23:34:45:56:60",
|
||||
"IPV6INIT": "yes",
|
||||
"IPV6_AUTOCONF": "yes",
|
||||
"NM_CONTROLLED": "no",
|
||||
"ONBOOT": "yes",
|
||||
"TYPE": "Ethernet",
|
||||
"ZONE": "external",
|
||||
},
|
||||
"keys": None,
|
||||
"route": "192.168.40.0/24 metric 545\n"
|
||||
"192.168.46.0/30\n"
|
||||
"192.168.45.0/24 metric 545\n",
|
||||
"route6": "a:b:c:f::/64\na:b:c:d::/64\n",
|
||||
"rule": None,
|
||||
"rule6": None,
|
||||
}
|
||||
],
|
||||
initscripts_expected_warnings=[
|
||||
route_device_warning.format("192.168.45.0/24"),
|
||||
route_device_warning.format("192.168.46.0/30"),
|
||||
route_device_warning.format("a:b:c:d::/64"),
|
||||
],
|
||||
)
|
||||
|
||||
def test_802_1x_1(self):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue