From f786a00e9ac4b24e8dae7673cb1255eed9df9866 Mon Sep 17 00:00:00 2001 From: Pim van Pelt Date: Sat, 2 Apr 2022 20:16:51 +0000 Subject: [PATCH] Check for the existence of LCP config statements, and if so, require linux-cp or lcpng plugins are enabled in VPP --- vpp/reconciler.py | 7 +++++++ vpp/vppapi.py | 35 +++++++++++++++++++++++++++++------ vppcfg | 41 +++++++++++++++++++++++++++++------------ 3 files changed, 65 insertions(+), 18 deletions(-) diff --git a/vpp/reconciler.py b/vpp/reconciler.py index c97a742..bad1f37 100644 --- a/vpp/reconciler.py +++ b/vpp/reconciler.py @@ -36,6 +36,13 @@ class Reconciler(): def __del__(self): self.vpp.disconnect() + def lcps_exist_with_lcp_enabled(self): + """ Returns False if there are LCPs defined in the configuration, but LinuxCP + functionality is not enabled in VPP. """ + if not lcp.get_lcps(self.cfg): + return True + return self.vpp.lcp_enabled + def phys_exist_in_vpp(self): """ Return True if all PHYs in the config exist as physical interface names in VPP. Return False otherwise.""" diff --git a/vpp/vppapi.py b/vpp/vppapi.py index a6bdb6e..07fc557 100644 --- a/vpp/vppapi.py +++ b/vpp/vppapi.py @@ -20,12 +20,14 @@ class VPPApi(): self.vpp = None self.config = self.clearconfig() self.config_read = False + self.lcp_enabled = False def connect(self): if self.connected: return True vpp_json_dir = '/usr/share/vpp/api/' + ## vpp_json_dir = "/home/pim/src/vpp/build-root/build-vpp_debug-native/vpp/CMakeFiles/" # construct a list of all the json api files jsonfiles = [] @@ -141,12 +143,33 @@ class VPPApi(): return False self.config_read = False - self.logger.debug("Retrieving LCPs") - r = self.vpp.api.lcp_itf_pair_get() - if isinstance(r, tuple) and r[0].retval == 0: - for lcp in r[1]: - self.config['lcps'][lcp.phy_sw_if_index] = lcp - + + ## Workaround LCPng and linux-cp, in order. + self.lcp_enabled = False + if not self.lcp_enabled: + try: + self.logger.debug("Retrieving LCPs (lcpng)") + r = self.vpp.api.lcpng_itf_pair_get() + if isinstance(r, tuple) and r[0].retval == 0: + for lcp in r[1]: + self.config['lcps'][lcp.phy_sw_if_index] = lcp + self.lcp_enabled = True + except: + self.logger.warning("lcpng not found, trying linux-cp") + if not self.lcp_enabled: + try: + self.logger.debug("Retrieving LCPs (linux-cp)") + r = self.vpp.api.lcp_itf_pair_get() + if isinstance(r, tuple) and r[0].retval == 0: + for lcp in r[1]: + self.config['lcps'][lcp.phy_sw_if_index] = lcp + self.lcp_enabled = True + except: + pass + + if not self.lcp_enabled: + self.logger.warning("lcpng nor linux-cp found, will not reconcile Linux Control Plane") + self.logger.debug("Retrieving interfaces") r = self.vpp.api.sw_interface_dump() for iface in r: diff --git a/vppcfg b/vppcfg index 83bd229..c28625a 100755 --- a/vppcfg +++ b/vppcfg @@ -29,14 +29,21 @@ except ImportError: def main(): parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter) - parser.add_argument('-c', '--config', dest='config', required=True, type=str, help="""YAML configuration file for VPP""") parser.add_argument('-s', '--schema', dest='schema', type=str, default='./schema.yaml', help="""YAML schema validation file""") - parser.add_argument('-d', '--debug', dest='debug', action='store_true', help="""Enable debug, default False""") - parser.add_argument('-q', '--quiet', dest='quiet', action='store_true', help="""Be quiet (only log warnings/errors), default False""") + parser.add_argument('-d', '--debug', dest='debug', action='store_true', help="""Enable debug logging, default False""") + parser.add_argument('-q', '--quiet', dest='quiet', action='store_true', help="""Be quiet (only warnings/errors), default False""") parser.add_argument('-f', '--force', dest='force', action='store_true', help="""Force progress despite warnings, default False""") + parser.add_argument('-c', '--config', dest='config', required=True, type=str, help="""YAML configuration file for vppcfg""") + + subparsers = parser.add_subparsers(dest='command') + check_p = subparsers.add_parser('check') + + plan_p = subparsers.add_parser('plan') + plan_p.add_argument('-o', '--output', dest='outfile', required=False, default='-', type=str, help="""Output file for VPP CLI commands, default stdout""") + + apply_p = subparsers.add_parser('apply') args = parser.parse_args() - level = logging.INFO if args.debug: level = logging.DEBUG @@ -57,6 +64,9 @@ def main(): if not v.valid_config(cfg): logging.error("Configuration is not valid, bailing") sys.exit(-2) + logging.info("Configuration is valid") + if args.command=="check": + sys.exit(0) r = Reconciler(cfg) if not r.vpp_readconfig(): @@ -70,33 +80,40 @@ def main(): logging.error("Not all PHYs in VPP exist in the config") sys.exit(-5) + if not r.lcps_exist_with_lcp_enabled(): + logging.error("Linux Control Plane is needed, but neither lcpng nor linux-cp are available") + sys.exit(-6) + failed = False if not r.prune(): if not args.force: - logging.error("Reconciliation prune failure") + logging.error("Planning prune failure") sys.exit(-10) failed = True - logging.warning("Reconciliation prune failure, continuing due to --force") + logging.warning("Planning prune failure, continuing due to --force") if not r.create(): if not args.force: - logging.error("Reconciliation create failure") + logging.error("Planning create failure") sys.exit(-20) failed = True - logging.warning("Reconciliation create failure, continuing due to --force") + logging.warning("Planning create failure, continuing due to --force") if not r.sync(): if not args.force: - logging.error("Reconciliation sync failure") + logging.error("Planning sync failure") sys.exit(-30) failed = True - logging.warning("Reconciliation sync failure, continuing due to --force") + logging.warning("Planning sync failure, continuing due to --force") if failed: - logging.error("Reconciliation failed") + logging.error("Planning failed") sys.exit(-40) - logging.info("Reconciliation succeeded") + logging.info("Planning succeeded") + if args.command=="plan": + sys.exit(0) + sys.exit(0) if __name__ == "__main__": main()