feature: stateless planning

Add a  feature to plan a configuration without reading from the VPP Dataplane.

In this mode, the configuration file is read and validated in the same way as `check` or `plan`,
but then instead of retrieving the running state from the VPP API, a state is re-created using
the physical interfaces specified in the YAML config.

Implement this by creating vppapi:mockconfig() which reads the 'interfaces' scope from the YAML
config file, and creates a VPPMessage() of type sw_interface_details for each interface that is a
PHY (for now, only supporting device-type 'dpdk').

If the flag --novpp is specified in the planner, call mockconfig() instead of readconfig().

Some further details:
- if the MAC is not set in the YAML config, it won't be set in the output exec file.
- for bondethernets, no MAC can be generated unless it's set in the first member.
- the MTU is always set, because it's mocked to 64b and the YAML file will always be higher.

TESTED:
- the unit tests and YAML tests all pass
- the integration tests all pass, but they do not call this new codepath

- Based on an empty VPP on Hippo, I compared the output of these two, side by side:
for i in intest/*yaml; do ./vppcfg.py plan -c $i -o /tmp/$i-vpp.exec; done
for i in intest/*yaml; do ./vppcfg.py plan --novpp -c $i -o /tmp/$i-novpp.exec; done

==> The only changes here are:
* if I cannot determine the bondether MAC in the --novpp case, it is not emitted
* if the MAC address is set in the YAML file, the --novpp case will always emit it
* if VPP has mtu 9000, the --novpp case will end up still emitting interface and packet MTU,
  because it mocks the interface MTU at 64.

In all cases, --novpp emits more configuration statements, and the statements that it emits are
redundant.
This commit is contained in:
Pim van Pelt
2022-12-03 15:57:00 +00:00
parent 490c294014
commit 305a30b1a1
4 changed files with 149 additions and 24 deletions

View File

@ -1015,7 +1015,10 @@ class Reconciler:
)
member_iface = self.vpp.get_interface_by_name(member_ifname)
if not member_iface or member_ifname not in vpp_members:
if len(vpp_members) == 0:
if (
len(vpp_members) == 0
and member_iface.l2_address != "00:00:00:00:00:00"
):
bondmac = member_iface.l2_address
cli = f"bond add {config_bond_ifname} {member_iface.interface_name}"
self.cli["sync"].append(cli)