From 4934af352aae797b7578023484967cb9066c2f6b Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Tue, 19 Apr 2016 15:25:23 -0700 Subject: [PATCH 01/27] addons: vrf: fix check in vrf map initialization when no running vrfs present Ticket: CM-10178 Review: trivial Testing: tested with failing testcase in the CM This patch fixes a check in vrf map initialization code which did not account for running vrfs correctly. This caused the case where there were no running vrfs but stale map file to fail. Signed-off-by: Roopa Prabhu --- addons/vrf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/vrf.py b/addons/vrf.py index e2279de..7adeb67 100644 --- a/addons/vrf.py +++ b/addons/vrf.py @@ -145,7 +145,7 @@ class vrf(moduleBase): if table: running_vrf_map[int(table)] = v - if running_vrf_map and (running_vrf_map != self.iproute2_vrf_map): + if (not running_vrf_map or (running_vrf_map != self.iproute2_vrf_map)): self.iproute2_vrf_map = running_vrf_map iproute2_vrf_map_force_rewrite = True From 90c6eab5f156a58843a49dd2cba29cd9e41e86da Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Tue, 19 Apr 2016 15:46:09 -0700 Subject: [PATCH 02/27] debian: move /sbin/start-networking to /usr/share/ifupdown2/sbin Signed-off-by: Roopa Prabhu --- debian/ifupdown2.install | 2 +- debian/ifupdown2.networking.service | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/debian/ifupdown2.install b/debian/ifupdown2.install index 8a322db..446b2ac 100644 --- a/debian/ifupdown2.install +++ b/debian/ifupdown2.install @@ -1,3 +1,3 @@ sbin/ifupdown2 /usr/share/ifupdown2/ -sbin/start-networking /sbin +sbin/start-networking /usr/share/ifupdown2/sbin/ debian/networking /etc/default/ diff --git a/debian/ifupdown2.networking.service b/debian/ifupdown2.networking.service index 625630b..ecf5b91 100644 --- a/debian/ifupdown2.networking.service +++ b/debian/ifupdown2.networking.service @@ -7,9 +7,9 @@ Type=oneshot RemainAfterExit=yes SyslogIdentifier=networking TimeoutStopSec=30s -ExecStart=/sbin/start-networking start -ExecStop=/sbin/start-networking stop -ExecReload=/sbin/start-networking reload +ExecStart=/usr/share/ifupdown2/sbin/start-networking start +ExecStop=/usr/share/ifupdown2/sbin/start-networking stop +ExecReload=/usr/share/ifupdown2/sbin/start-networking reload [Install] WantedBy=basic.target network.target From 4c56a7c1a7144e71215d07a75c1e3011caef92db Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Thu, 21 Apr 2016 12:45:22 -0700 Subject: [PATCH 03/27] ifupdown2: fix ifquery --list Ticket: Reviewed By: julien Testing Done: Tested ifquery -l and checked that it is compatible with ifupdown ifquery list lists all matching interfaces. By default that is all auto interfaces: example: {noformat} $cat /etc/network/interfaces auto lo iface lo inet loopback allow-mgmt eth0 iface eth0 inet dhcp vrf mgmt allow-mgmt mgmt iface mgmt address 127.0.0.1/8 vrf-table auto $ifquery -l --allow=mgmt eth0 mgmt $ifquery -a -l lo {noformat} Signed-off-by: Roopa Prabhu --- ifupdown/ifupdownmain.py | 10 +++++++++- sbin/ifupdown2 | 12 +++++++----- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/ifupdown/ifupdownmain.py b/ifupdown/ifupdownmain.py index b3ab306..22e4668 100644 --- a/ifupdown/ifupdownmain.py +++ b/ifupdown/ifupdownmain.py @@ -1206,7 +1206,8 @@ class ifupdownMain(ifupdownBase): if not ifupdownflags.flags.DRYRUN and self.flags.ADDONS_ENABLE: self._save_state() - def query(self, ops, auto=False, allow_classes=None, ifacenames=None, + def query(self, ops, auto=False, format_list=False, allow_classes=None, + ifacenames=None, excludepats=None, printdependency=None, format='native', type=None): """ query an interface """ @@ -1264,6 +1265,9 @@ class ifupdownMain(ifupdownBase): self.print_dependency(filtered_ifacenames, printdependency) return + if format_list and (ops[0] == 'query' or ops[0] == 'query-raw'): + return self.print_ifaceobjs_list(filtered_ifacenames) + if ops[0] == 'query': return self.print_ifaceobjs_pretty(filtered_ifacenames, format) elif ops[0] == 'query-raw': @@ -1594,6 +1598,10 @@ class ifupdownMain(ifupdownBase): self.dependency_graph.keys()) graph.generate_dots(self.dependency_graph, indegrees) + def print_ifaceobjs_list(self, ifacenames): + for i in ifacenames: + print i + def print_ifaceobjs_raw(self, ifacenames): """ prints raw lines for ifaces from config file """ diff --git a/sbin/ifupdown2 b/sbin/ifupdown2 index 9aeaf27..3eee437 100755 --- a/sbin/ifupdown2 +++ b/sbin/ifupdown2 @@ -124,8 +124,10 @@ def run_query(args): interfacesfile=interfacesfilename, interfacesfileiobuf=interfacesfileiobuf, interfacesfileformat=args.interfacesfileformat) - - ifupdown_handle.query([qop], args.all, args.CLASS, iflist, + # list implies all auto interfaces (this is how ifupdown behaves) + if args.list: + args.all = True + ifupdown_handle.query([qop], args.all, args.list, args.CLASS, iflist, excludepats=args.excludepats, printdependency=args.printdependency, format=args.format, type=args.type) @@ -307,8 +309,8 @@ def update_ifquery_argparser(argparser): """ arg parser for ifquery options """ # -l is same as '-a', only here for backward compatibility - argparser.add_argument('-l', '--list', action='store_true', dest='all', - help=argparse.SUPPRESS) + argparser.add_argument('-l', '--list', action='store_true', dest='list', + help='list all matching known interfaces') group = argparser.add_mutually_exclusive_group(required=False) group.add_argument('-r', '--running', dest='running', action='store_true', @@ -425,7 +427,7 @@ def validate_args(op, args): # if args.iflist or args.all: # print 'ignoring interface options ..' # return True - if op == 'query' and args.syntaxhelp: + if op == 'query' and (args.syntaxhelp or args.list): return True if op == 'reload': if not args.all and not args.currentlyup and not args.CLASS: From 6642399fee6e5b4036a0cc10e72ff53a973d70ca Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Thu, 21 Apr 2016 12:58:53 -0700 Subject: [PATCH 04/27] start-networking: ifup mgmt class interfaces if present Ticket: CM-9919 Reviewed By: dsa, daniel Testing Done: Checked that mgmt class interfaces are brought up at boot if present Note that this only indicates that: - 'mgmt' is a reserved class - if any interfaces are tagged as 'mgmt', they will be brought up at boot With this we can put out documentation saying that mgmt devices can be put into its own class for easier management of mgmtvrf. {noformat} $cat /etc/network/interfaces auto lo iface lo inet loopback allow-mgmt eth0 iface eth0 inet dhcp vrf mgmt allow-mgmt mgmt iface mgmt address 127.0.0.1/8 vrf-table auto $ifquery -l --allow=mgmt eth0 mgmt $ifquery -l -a lo $ifreload --allow=mgmt $ifup --allow=mgmt {noformat} Signed-off-by: Roopa Prabhu --- sbin/start-networking | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sbin/start-networking b/sbin/start-networking index 6f1fad4..5b14f48 100755 --- a/sbin/start-networking +++ b/sbin/start-networking @@ -99,6 +99,14 @@ ifup_hotplug () { fi } +ifup_mgmt () { + ifaces=$(ifquery --list --allow=mgmt 2>/dev/null) + if [ -n "$ifaces" ]; then + echo "bringing up mgmt class interfaces" + ifup --allow=mgmt + fi +} + ifupdown_init() { # remove state file at boot [ ! -e ${IFSTATE_LOCKFILE} ] && rm -f ${IFSTATE_FILE} @@ -120,9 +128,9 @@ start) exclusions=$(process_exclusions) perfoptions=$(perf_options) echo ${NAME}':' "Configuring network interfaces" + ifup_mgmt ifup -a $EXTRA_ARGS $exclusions $perfoptions ;; - stop) if [ "$SKIP_DOWN_AT_SYSRESET" = "yes" ]; then SYSRESET=0 From fdf548b091b556fae722df1416adc0338e1ab057 Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Thu, 21 Apr 2016 13:09:33 -0700 Subject: [PATCH 05/27] addons: vrf: remove vrf service code. vrf-helper already handles services Ticket: CM-10533 Reviewed By: dsa Testing Done: Tested sanity Signed-off-by: Roopa Prabhu --- addons/vrf.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/addons/vrf.py b/addons/vrf.py index 7adeb67..8b7708c 100644 --- a/addons/vrf.py +++ b/addons/vrf.py @@ -679,12 +679,6 @@ class vrf(moduleBase): if vrf_table == 'auto': vrf_table = self._get_iproute2_vrf_table(ifaceobj.name) - try: - self.exec_command('/usr/bin/vrf service disable %s' %ifaceobj.name) - except Exception, e: - self.logger.info('%s: %s' %(ifaceobj.name, str(e))) - pass - try: running_slaves = self.ipcmd.link_get_lowers(ifaceobj.name) if running_slaves: From 669b422add399208b953b68f02c4589aae9cbf55 Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Tue, 19 Apr 2016 15:25:23 -0700 Subject: [PATCH 06/27] addons: vrf: fix check in vrf map initialization when no running vrfs present Ticket: CM-10178 Review: trivial Testing: tested with failing testcase in the CM This patch fixes a check in vrf map initialization code which did not account for running vrfs correctly. This caused the case where there were no running vrfs but stale map file to fail. Signed-off-by: Roopa Prabhu addons,ifupdown,sbin: adding ifquery --with-defaults option Ticket: CM-7840 Reviewed By: Roopa Prabhu Testing Done: yes, by installing ifupdown .deb file onto dell-s3000-02 This patch adds a new argument '--with-defaults' to 'ifquery' when 'ifquery --with-defaults' is executed, running states of all interface attributes are compared against respective configured attributes from /etc/network/interfaces file, if configured. Otherwise, compared against default attributes from policy file Signed-off-by: Nikhil --- addons/address.py | 3 ++- addons/bridge.py | 25 ++++++++++++++++--------- addons/ethtool.py | 9 ++++++--- addons/vrf.py | 23 +++++++++++++++++++---- ifupdown/ifupdownmain.py | 10 +++++----- ifupdown/scheduler.py | 40 ++++++++++++++++++++-------------------- sbin/ifupdown2 | 10 +++++++++- 7 files changed, 77 insertions(+), 43 deletions(-) diff --git a/addons/address.py b/addons/address.py index b35206e..812aefe 100644 --- a/addons/address.py +++ b/addons/address.py @@ -500,7 +500,8 @@ class address(moduleBase): if not self.ipcmd: self.ipcmd = iproute2() - def run(self, ifaceobj, operation, query_ifaceobj=None, ifaceobj_getfunc=None): + def run(self, ifaceobj, operation, query_ifaceobj=None, + ifaceobj_getfunc=None, **extra_args): """ run address configuration on the interface object passed as argument Args: diff --git a/addons/bridge.py b/addons/bridge.py index aadee7c..9c184d6 100644 --- a/addons/bridge.py +++ b/addons/bridge.py @@ -1369,8 +1369,7 @@ class bridge(moduleBase): if attrval: ifaceobjcurr.update_config_with_status('bridge-vids', attrval, -1) - def _query_check_bridge(self, ifaceobj, ifaceobjcurr, - ifaceobj_getfunc=None): + def _query_check_bridge(self, ifaceobj, ifaceobjcurr, withdefaults): if not self._is_bridge(ifaceobj): return if not self.brctlcmd.bridge_exists(ifaceobj.name): @@ -1379,6 +1378,9 @@ class bridge(moduleBase): ifaceattrs = self.dict_key_subset(ifaceobj.config, self.get_mod_attrs()) + #Add default attributes if --with-defaults is set + if withdefaults and 'bridge-stp' not in ifaceattrs: + ifaceattrs.append('bridge-stp') if not ifaceattrs: return try: @@ -1396,7 +1398,10 @@ class bridge(moduleBase): # get the corresponding ifaceobj attr v = ifaceobj.get_attr_value_first(k) if not v: - continue + if withdefaults and k == 'bridge-stp': + v = 'on' if self.default_stp_on else 'off' + else: + continue rv = runningattrs.get(k[7:]) if k == 'bridge-mcqv4src': continue @@ -1412,14 +1417,14 @@ class bridge(moduleBase): # special case stp compare because it may # contain more than one valid values stp_on_vals = ['on', 'yes'] - stp_off_vals = ['off'] + stp_off_vals = ['off', 'no'] if ((v in stp_on_vals and rv in stp_on_vals) or (v in stp_off_vals and rv in stp_off_vals)): ifaceobjcurr.update_config_with_status('bridge-stp', - v, 0) + rv, 0) else: ifaceobjcurr.update_config_with_status('bridge-stp', - v, 1) + rv, 1) elif k == 'bridge-ports': # special case ports because it can contain regex or glob running_port_list = rv.keys() if rv else [] @@ -1601,9 +1606,10 @@ class bridge(moduleBase): except Exception, e: self.log_warn('%s: %s' %(ifaceobj.name, str(e))) - def _query_check(self, ifaceobj, ifaceobjcurr, ifaceobj_getfunc=None): + def _query_check(self, ifaceobj, ifaceobjcurr, withdefaults, + ifaceobj_getfunc=None): if self._is_bridge(ifaceobj): - self._query_check_bridge(ifaceobj, ifaceobjcurr) + self._query_check_bridge(ifaceobj, ifaceobjcurr, withdefaults) else: self._query_check_bridge_port(ifaceobj, ifaceobjcurr, ifaceobj_getfunc) @@ -1693,7 +1699,7 @@ class bridge(moduleBase): self.brctlcmd = brctl() def run(self, ifaceobj, operation, query_ifaceobj=None, - ifaceobj_getfunc=None): + ifaceobj_getfunc=None, **extra_args): """ run bridge configuration on the interface object passed as argument. Can create bridge interfaces if they dont exist already @@ -1718,6 +1724,7 @@ class bridge(moduleBase): self._flush_running_vidinfo() if operation == 'query-checkcurr': op_handler(self, ifaceobj, query_ifaceobj, + extra_args['withdefaults'] if 'withdefaults' in extra_args else False, ifaceobj_getfunc=ifaceobj_getfunc) else: op_handler(self, ifaceobj, ifaceobj_getfunc=ifaceobj_getfunc) diff --git a/addons/ethtool.py b/addons/ethtool.py index d1f9a16..32939e4 100644 --- a/addons/ethtool.py +++ b/addons/ethtool.py @@ -123,7 +123,7 @@ class ethtool(moduleBase,utilsBase): def _pre_down(self, ifaceobj): pass #self._post_up(ifaceobj,operation="_pre_down") - def _query_check(self, ifaceobj, ifaceobjcurr): + def _query_check(self, ifaceobj, ifaceobjcurr, withdefaults): """ _query_check() needs to compare the configured (or running) attribute with the running attribute. @@ -133,11 +133,13 @@ class ethtool(moduleBase,utilsBase): This is because a reboot will lose their running attribute (the default will get set). """ + # Add default attributes if --with-defaults is set for attr in ['speed', 'duplex', 'autoneg']: configured = ifaceobj.get_attr_value_first('link-%s'%attr) # if there is nothing configured, do not check if not configured: - continue + if not withdefaults: + continue default = policymanager.policymanager_api.get_iface_default( module_name='ethtool', ifname=ifaceobj.name, @@ -266,6 +268,7 @@ class ethtool(moduleBase,utilsBase): self._init_command_handlers() if operation == 'query-checkcurr': - op_handler(self, ifaceobj, query_ifaceobj) + op_handler(self, ifaceobj, query_ifaceobj, + extra_args['withdefaults'] if 'withdefaults' in extra_args else False) else: op_handler(self, ifaceobj) diff --git a/addons/vrf.py b/addons/vrf.py index 8b7708c..bb2b212 100644 --- a/addons/vrf.py +++ b/addons/vrf.py @@ -744,7 +744,8 @@ class vrf(moduleBase): except Exception, e: self.log_warn(str(e)) - def _query_check_vrf_dev(self, ifaceobj, ifaceobjcurr, vrf_table): + def _query_check_vrf_dev(self, ifaceobj, ifaceobjcurr, vrf_table, + withdefaults): try: if not self.ipcmd.link_exists(ifaceobj.name): self.logger.info('%s: vrf: does not exist' %(ifaceobj.name)) @@ -767,15 +768,28 @@ class vrf(moduleBase): else: ifaceobjcurr.update_config_with_status('vrf-table', running_table, 0) + if not withdefaults: + return + if self.vrf_helper: + ret_vrfhelper = self.exec_command('%s verify %s %s' + %(self.vrf_helper, + ifaceobj.name, vrf_table)) + if 'default routes are installed' not in ret_vrfhelper: + ifaceobjcurr.update_config_with_status('vrf-default-route', + 'no', 1) + else: + ifaceobjcurr.update_config_with_status('vrf-default-route', + 'yes',0) except Exception, e: self.log_warn(str(e)) - def _query_check(self, ifaceobj, ifaceobjcurr): + def _query_check(self, ifaceobj, ifaceobjcurr, withdefaults): try: vrf_table = ifaceobj.get_attr_value_first('vrf-table') if vrf_table: self._iproute2_vrf_map_initialize() - self._query_check_vrf_dev(ifaceobj, ifaceobjcurr, vrf_table) + self._query_check_vrf_dev(ifaceobj, ifaceobjcurr, vrf_table, + withdefaults) else: vrf = ifaceobj.get_attr_value_first('vrf') if vrf: @@ -841,6 +855,7 @@ class vrf(moduleBase): return self._init_command_handlers() if operation == 'query-checkcurr': - op_handler(self, ifaceobj, query_ifaceobj) + op_handler(self, ifaceobj, query_ifaceobj, + extra_args['withdefaults'] if 'withdefaults' in extra_args else False) else: op_handler(self, ifaceobj, ifaceobj_getfunc=ifaceobj_getfunc) diff --git a/ifupdown/ifupdownmain.py b/ifupdown/ifupdownmain.py index 22e4668..b4c3440 100644 --- a/ifupdown/ifupdownmain.py +++ b/ifupdown/ifupdownmain.py @@ -895,13 +895,13 @@ class ifupdownMain(ifupdownBase): # continue reading pass - def _sched_ifaces(self, ifacenames, ops, skipupperifaces=False, - followdependents=True, sort=False): + def _sched_ifaces(self, ifacenames, ops, withdefaults=False, + skipupperifaces=False, followdependents=True, sort=False): self.logger.debug('scheduling \'%s\' for %s' %(str(ops), str(ifacenames))) self._pretty_print_ordered_dict('dependency graph', self.dependency_graph) - ifaceScheduler.sched_ifaces(self, ifacenames, ops, + ifaceScheduler.sched_ifaces(self, ifacenames, ops, withdefaults, dependency_graph=self.dependency_graph, order=ifaceSchedulerFlags.INORDER if 'down' in ops[0] @@ -1209,7 +1209,7 @@ class ifupdownMain(ifupdownBase): def query(self, ops, auto=False, format_list=False, allow_classes=None, ifacenames=None, excludepats=None, printdependency=None, - format='native', type=None): + format='native', type=None, withdefaults=False): """ query an interface """ self.set_type(type) @@ -1273,7 +1273,7 @@ class ifupdownMain(ifupdownBase): elif ops[0] == 'query-raw': return self.print_ifaceobjs_raw(filtered_ifacenames) - ret = self._sched_ifaces(filtered_ifacenames, ops, + ret = self._sched_ifaces(filtered_ifacenames, ops, withdefaults, followdependents=True if self.flags.WITH_DEPENDS else False) diff --git a/ifupdown/scheduler.py b/ifupdown/scheduler.py index 3202f9b..cbcfeb8 100644 --- a/ifupdown/scheduler.py +++ b/ifupdown/scheduler.py @@ -49,7 +49,7 @@ class ifaceScheduler(): cls._SCHED_STATUS = state @classmethod - def run_iface_op(cls, ifupdownobj, ifaceobj, op, cenv=None): + def run_iface_op(cls, ifupdownobj, ifaceobj, op, withdefaults=False, cenv=None): """ Runs sub operation on an interface """ ifacename = ifaceobj.name @@ -80,11 +80,11 @@ class ifaceScheduler(): continue ifupdownobj.logger.debug(msg) m.run(ifaceobj, op, query_ifaceobj, - ifaceobj_getfunc=ifupdownobj.get_ifaceobjs) + ifaceobj_getfunc=ifupdownobj.get_ifaceobjs, withdefaults=withdefaults) else: ifupdownobj.logger.debug(msg) m.run(ifaceobj, op, - ifaceobj_getfunc=ifupdownobj.get_ifaceobjs) + ifaceobj_getfunc=ifupdownobj.get_ifaceobjs, withdefaults=withdefaults) except Exception, e: if not ifupdownobj.ignore_error(str(e)): err = 1 @@ -117,7 +117,7 @@ class ifaceScheduler(): ifupdownobj.log_error(str(e)) @classmethod - def run_iface_list_ops(cls, ifupdownobj, ifaceobjs, ops): + def run_iface_list_ops(cls, ifupdownobj, ifaceobjs, ops, withdefaults=False): """ Runs all operations on a list of interface configurations for the same interface """ @@ -151,7 +151,7 @@ class ifaceScheduler(): %(ifaceobjs[0].name, str(e))) pass for ifaceobj in ifaceobjs: - cls.run_iface_op(ifupdownobj, ifaceobj, op, + cls.run_iface_op(ifupdownobj, ifaceobj, op, withdefaults, cenv=ifupdownobj.generate_running_env(ifaceobj, op) if ifupdownobj.config.get('addon_scripts_support', '0') == '1' else None) @@ -212,8 +212,8 @@ class ifaceScheduler(): return True @classmethod - def run_iface_graph(cls, ifupdownobj, ifacename, ops, parent=None, - order=ifaceSchedulerFlags.POSTORDER, + def run_iface_graph(cls, ifupdownobj, ifacename, ops, withdefaults=False, + parent=None, order=ifaceSchedulerFlags.POSTORDER, followdependents=True): """ runs interface by traversing all nodes rooted at itself """ @@ -235,7 +235,7 @@ class ifaceScheduler(): # If inorder, run the iface first and then its dependents if order == ifaceSchedulerFlags.INORDER: - cls.run_iface_list_ops(ifupdownobj, ifaceobjs, ops) + cls.run_iface_list_ops(ifupdownobj, ifaceobjs, ops, False) for ifaceobj in ifaceobjs: # Run lowerifaces or dependents @@ -254,11 +254,12 @@ class ifaceScheduler(): if ifupdownobj.is_iface_noconfig(d)] if new_dlist: cls.run_iface_list(ifupdownobj, new_dlist, ops, - ifacename, order, followdependents, + withdefaults, ifacename, order, + followdependents, continueonfailure=False) else: cls.run_iface_list(ifupdownobj, dlist, ops, - ifacename, order, + withdefaults, ifacename, order, followdependents, continueonfailure=False) except Exception, e: @@ -270,18 +271,17 @@ class ifaceScheduler(): ifaceStatus.ERROR) raise if order == ifaceSchedulerFlags.POSTORDER: - cls.run_iface_list_ops(ifupdownobj, ifaceobjs, ops) + cls.run_iface_list_ops(ifupdownobj, ifaceobjs, ops, withdefaults) @classmethod - def run_iface_list(cls, ifupdownobj, ifacenames, - ops, parent=None, order=ifaceSchedulerFlags.POSTORDER, + def run_iface_list(cls, ifupdownobj, ifacenames, ops, withdefaults=False, + parent=None, order=ifaceSchedulerFlags.POSTORDER, followdependents=True, continueonfailure=True): """ Runs interface list """ - for ifacename in ifacenames: try: - cls.run_iface_graph(ifupdownobj, ifacename, ops, parent, - order, followdependents) + cls.run_iface_graph(ifupdownobj, ifacename, ops, withdefaults, + parent, order, followdependents) except Exception, e: if continueonfailure: if ifupdownobj.logger.isEnabledFor(logging.DEBUG): @@ -311,7 +311,7 @@ class ifaceScheduler(): if not skip_root: # run the iface first and then its upperifaces - cls.run_iface_list_ops(ifupdownobj, ifaceobjs, ops) + cls.run_iface_list_ops(ifupdownobj, ifaceobjs, ops, False) for ifaceobj in ifaceobjs: # Run upperifaces ulist = ifaceobj.upperifaces @@ -405,7 +405,7 @@ class ifaceScheduler(): ifaceobjs = ifupdownobj.get_ifaceobjs(u) if not ifaceobjs: continue - cls.run_iface_list_ops(ifupdownobj, ifaceobjs, ops) + cls.run_iface_list_ops(ifupdownobj, ifaceobjs, ops, False) except Exception, e: if continueonfailure: self.logger.warn('%s' %str(e)) @@ -434,7 +434,7 @@ class ifaceScheduler(): return ifacenames_sorted @classmethod - def sched_ifaces(cls, ifupdownobj, ifacenames, ops, + def sched_ifaces(cls, ifupdownobj, ifacenames, ops, withdefaults=False, dependency_graph=None, indegrees=None, order=ifaceSchedulerFlags.POSTORDER, followdependents=True, skipupperifaces=False, sort=False): @@ -529,7 +529,7 @@ class ifaceScheduler(): run_queue.reverse() # run interface list - cls.run_iface_list(ifupdownobj, run_queue, ops, + cls.run_iface_list(ifupdownobj, run_queue, ops, withdefaults, parent=None, order=order, followdependents=followdependents) if not cls.get_sched_status(): diff --git a/sbin/ifupdown2 b/sbin/ifupdown2 index 3eee437..289080e 100755 --- a/sbin/ifupdown2 +++ b/sbin/ifupdown2 @@ -107,6 +107,8 @@ def run_query(args): qop = 'query-dependency' elif args.printsavedstate: qop = 'query-savedstate' + elif args.withdefaults: + qop = 'query-withdefaults' else: qop='query' cachearg=(False if (iflist or args.nocache or @@ -130,7 +132,8 @@ def run_query(args): ifupdown_handle.query([qop], args.all, args.list, args.CLASS, iflist, excludepats=args.excludepats, printdependency=args.printdependency, - format=args.format, type=args.type) + format=args.format, type=args.type, + withdefaults=args.withdefaults) except: raise @@ -333,6 +336,11 @@ def update_ifquery_argparser(argparser): argparser.add_argument('-s', '--syntax-help', action='store_true', dest='syntaxhelp', help='print supported interface config syntax') + argparser.add_argument('--with-defaults', action='store_true', + dest='withdefaults', + help='check policy default file contents, ' + + 'for unconfigured attributes, against ' + + 'running state of an interface') def update_ifreload_argparser(argparser): """ parser for ifreload """ From 6e16e5ae90f2fac021db3985415938aefd61d4bf Mon Sep 17 00:00:00 2001 From: Nikhil Date: Wed, 20 Apr 2016 03:02:26 -0700 Subject: [PATCH 07/27] addons,ifupdown,sbin: adding ifquery --with-defaults option Ticket: CM-7840 Reviewed By: Roopa Prabhu Testing Done: yes, by installing ifupdown .deb file onto dell-s3000-02 This patch adds a new argument '--with-defaults' to 'ifquery' when 'ifquery --with-defaults' is executed, running states of all interface attributes are compared against respective configured attributes from /etc/network/interfaces file, if configured. Otherwise, compared against default attributes from policy file This patch also: (1) fixes ifquery check failure for bridge-* stp attributes. (2) removes vrf-default-route and vrf-cgroup attributes from ifupdown2 policy and just have the vrf-helper attribute Signed-off-by: Nikhil --- addons/address.py | 3 +-- addons/bridge.py | 30 +++++++++++---------- addons/ethtool.py | 9 +++---- addons/vrf.py | 50 +++++++++++++++-------------------- ifupdown/ifupdownflags.py | 1 + ifupdown/ifupdownmain.py | 14 +++++----- ifupdown/scheduler.py | 40 ++++++++++++++-------------- ifupdownaddons/bridgeutils.py | 14 +++++++--- sbin/ifupdown2 | 8 +++--- 9 files changed, 84 insertions(+), 85 deletions(-) diff --git a/addons/address.py b/addons/address.py index 812aefe..b35206e 100644 --- a/addons/address.py +++ b/addons/address.py @@ -500,8 +500,7 @@ class address(moduleBase): if not self.ipcmd: self.ipcmd = iproute2() - def run(self, ifaceobj, operation, query_ifaceobj=None, - ifaceobj_getfunc=None, **extra_args): + def run(self, ifaceobj, operation, query_ifaceobj=None, ifaceobj_getfunc=None): """ run address configuration on the interface object passed as argument Args: diff --git a/addons/bridge.py b/addons/bridge.py index 9c184d6..646d3c2 100644 --- a/addons/bridge.py +++ b/addons/bridge.py @@ -1369,7 +1369,8 @@ class bridge(moduleBase): if attrval: ifaceobjcurr.update_config_with_status('bridge-vids', attrval, -1) - def _query_check_bridge(self, ifaceobj, ifaceobjcurr, withdefaults): + def _query_check_bridge(self, ifaceobj, ifaceobjcurr, + ifaceobj_getfunc=None): if not self._is_bridge(ifaceobj): return if not self.brctlcmd.bridge_exists(ifaceobj.name): @@ -1379,7 +1380,7 @@ class bridge(moduleBase): ifaceattrs = self.dict_key_subset(ifaceobj.config, self.get_mod_attrs()) #Add default attributes if --with-defaults is set - if withdefaults and 'bridge-stp' not in ifaceattrs: + if ifupdownflags.flags.WITHDEFAULTS and 'bridge-stp' not in ifaceattrs: ifaceattrs.append('bridge-stp') if not ifaceattrs: return @@ -1398,13 +1399,16 @@ class bridge(moduleBase): # get the corresponding ifaceobj attr v = ifaceobj.get_attr_value_first(k) if not v: - if withdefaults and k == 'bridge-stp': - v = 'on' if self.default_stp_on else 'off' - else: - continue + if ifupdownflags.flags.WITHDEFAULTS and k == 'bridge-stp': + v = 'on' if self.default_stp_on else 'off' + else: + continue rv = runningattrs.get(k[7:]) if k == 'bridge-mcqv4src': continue + if k == 'bridge-maxwait' or k == 'bridge-waitport': + ifaceobjcurr.update_config_with_status(k, v, 0) + continue if k == 'bridge-vlan-aware': rv = self.ipcmd.bridge_is_vlan_aware(ifaceobj.name) if (rv and v == 'yes') or (not rv and v == 'no'): @@ -1424,7 +1428,7 @@ class bridge(moduleBase): rv, 0) else: ifaceobjcurr.update_config_with_status('bridge-stp', - rv, 1) + rv, 1) elif k == 'bridge-ports': # special case ports because it can contain regex or glob running_port_list = rv.keys() if rv else [] @@ -1443,7 +1447,7 @@ class bridge(moduleBase): elif (k == 'bridge-pathcosts' or k == 'bridge-portprios' or k == 'bridge-portmcrouter' or k == 'bridge-portmcfl'): - brctlcmdattrname = k[11:].rstrip('s') + brctlcmdattrname = k[7:].rstrip('s') # for port attributes, the attributes are in a list # = status = 0 @@ -1468,7 +1472,7 @@ class bridge(moduleBase): pass ifaceobjcurr.update_config_with_status(k, currstr, status) elif not rv: - if k == 'bridge-pvid' or k == 'bridge-vids': + if k == 'bridge-pvid' or k == 'bridge-vids' or k == 'bridge-allow-untagged': # bridge-pvid and bridge-vids on a bridge does # not correspond directly to a running config # on the bridge. They correspond to default @@ -1606,10 +1610,9 @@ class bridge(moduleBase): except Exception, e: self.log_warn('%s: %s' %(ifaceobj.name, str(e))) - def _query_check(self, ifaceobj, ifaceobjcurr, withdefaults, - ifaceobj_getfunc=None): + def _query_check(self, ifaceobj, ifaceobjcurr, ifaceobj_getfunc=None): if self._is_bridge(ifaceobj): - self._query_check_bridge(ifaceobj, ifaceobjcurr, withdefaults) + self._query_check_bridge(ifaceobj, ifaceobjcurr) else: self._query_check_bridge_port(ifaceobj, ifaceobjcurr, ifaceobj_getfunc) @@ -1699,7 +1702,7 @@ class bridge(moduleBase): self.brctlcmd = brctl() def run(self, ifaceobj, operation, query_ifaceobj=None, - ifaceobj_getfunc=None, **extra_args): + ifaceobj_getfunc=None): """ run bridge configuration on the interface object passed as argument. Can create bridge interfaces if they dont exist already @@ -1724,7 +1727,6 @@ class bridge(moduleBase): self._flush_running_vidinfo() if operation == 'query-checkcurr': op_handler(self, ifaceobj, query_ifaceobj, - extra_args['withdefaults'] if 'withdefaults' in extra_args else False, ifaceobj_getfunc=ifaceobj_getfunc) else: op_handler(self, ifaceobj, ifaceobj_getfunc=ifaceobj_getfunc) diff --git a/addons/ethtool.py b/addons/ethtool.py index 32939e4..c7a4850 100644 --- a/addons/ethtool.py +++ b/addons/ethtool.py @@ -13,6 +13,7 @@ try: from ifupdownaddons.utilsbase import * from ifupdownaddons.modulebase import moduleBase from ifupdownaddons.iproute2 import iproute2 + import ifupdown.ifupdownflags as ifupdownflags except ImportError, e: raise ImportError (str(e) + "- required module not found") @@ -123,7 +124,7 @@ class ethtool(moduleBase,utilsBase): def _pre_down(self, ifaceobj): pass #self._post_up(ifaceobj,operation="_pre_down") - def _query_check(self, ifaceobj, ifaceobjcurr, withdefaults): + def _query_check(self, ifaceobj, ifaceobjcurr): """ _query_check() needs to compare the configured (or running) attribute with the running attribute. @@ -133,12 +134,11 @@ class ethtool(moduleBase,utilsBase): This is because a reboot will lose their running attribute (the default will get set). """ - # Add default attributes if --with-defaults is set for attr in ['speed', 'duplex', 'autoneg']: configured = ifaceobj.get_attr_value_first('link-%s'%attr) # if there is nothing configured, do not check if not configured: - if not withdefaults: + if not ifupdownflags.flags.WITHDEFAULTS: continue default = policymanager.policymanager_api.get_iface_default( module_name='ethtool', @@ -268,7 +268,6 @@ class ethtool(moduleBase,utilsBase): self._init_command_handlers() if operation == 'query-checkcurr': - op_handler(self, ifaceobj, query_ifaceobj, - extra_args['withdefaults'] if 'withdefaults' in extra_args else False) + op_handler(self, ifaceobj, query_ifaceobj) else: op_handler(self, ifaceobj) diff --git a/addons/vrf.py b/addons/vrf.py index bb2b212..1ff21f3 100644 --- a/addons/vrf.py +++ b/addons/vrf.py @@ -30,10 +30,6 @@ class vrf(moduleBase): {'help' : 'vrf device table id. key to ' + 'creating a vrf device', 'example': ['vrf-table-id 1']}, - 'vrf-default-route': - {'help' : 'vrf device default route ' + - 'to avoid communication outside the vrf device', - 'example': ['vrf-default-route yes/no']}, 'vrf': {'help' : 'vrf the interface is part of.', 'example': ['vrf blue']}}} @@ -97,14 +93,6 @@ class vrf(moduleBase): self.vrf_fix_local_table = True self.vrf_count = 0 - self.vrf_cgroup_create = policymanager.policymanager_api.get_module_globals(module_name=self.__class__.__name__, attr='vrf-cgroup-create') - - if not self.vrf_cgroup_create: - self.vrf_cgroup_create = False - elif self.vrf_cgroup_create == 'yes': - self.vrf_cgroup_create = True - else: - self.vrf_cgroup_create = False self.vrf_mgmt_devname = policymanager.policymanager_api.get_module_globals(module_name=self.__class__.__name__, attr='vrf-mgmt-devname') self.vrf_helper = policymanager.policymanager_api.get_module_globals(module_name=self.__class__.__name__, attr='vrf-helper') @@ -744,8 +732,7 @@ class vrf(moduleBase): except Exception, e: self.log_warn(str(e)) - def _query_check_vrf_dev(self, ifaceobj, ifaceobjcurr, vrf_table, - withdefaults): + def _query_check_vrf_dev(self, ifaceobj, ifaceobjcurr, vrf_table): try: if not self.ipcmd.link_exists(ifaceobj.name): self.logger.info('%s: vrf: does not exist' %(ifaceobj.name)) @@ -768,28 +755,34 @@ class vrf(moduleBase): else: ifaceobjcurr.update_config_with_status('vrf-table', running_table, 0) - if not withdefaults: + if not ifupdownflags.flags.WITHDEFAULTS: return if self.vrf_helper: - ret_vrfhelper = self.exec_command('%s verify %s %s' - %(self.vrf_helper, - ifaceobj.name, vrf_table)) - if 'default routes are installed' not in ret_vrfhelper: - ifaceobjcurr.update_config_with_status('vrf-default-route', - 'no', 1) - else: - ifaceobjcurr.update_config_with_status('vrf-default-route', - 'yes',0) + try: + self.exec_command('%s verify %s %s' + %(self.vrf_helper, + ifaceobj.name, config_table)) + ifaceobjcurr.update_config_with_status('vrf-helper', + '%s create %s %s' + %(self.vrf_helper, + ifaceobj.name, + config_table), 0) + except Exception, e: + ifaceobjcurr.update_config_with_status('vrf-helper', + '%s create %s %s' + %(self.vrf_helper, + ifaceobj.name, + config_table), 1) + pass except Exception, e: self.log_warn(str(e)) - def _query_check(self, ifaceobj, ifaceobjcurr, withdefaults): + def _query_check(self, ifaceobj, ifaceobjcurr): try: vrf_table = ifaceobj.get_attr_value_first('vrf-table') if vrf_table: self._iproute2_vrf_map_initialize() - self._query_check_vrf_dev(ifaceobj, ifaceobjcurr, vrf_table, - withdefaults) + self._query_check_vrf_dev(ifaceobj, ifaceobjcurr, vrf_table) else: vrf = ifaceobj.get_attr_value_first('vrf') if vrf: @@ -855,7 +848,6 @@ class vrf(moduleBase): return self._init_command_handlers() if operation == 'query-checkcurr': - op_handler(self, ifaceobj, query_ifaceobj, - extra_args['withdefaults'] if 'withdefaults' in extra_args else False) + op_handler(self, ifaceobj, query_ifaceobj) else: op_handler(self, ifaceobj, ifaceobj_getfunc=ifaceobj_getfunc) diff --git a/ifupdown/ifupdownflags.py b/ifupdown/ifupdownflags.py index 5b7c386..08ad3ec 100644 --- a/ifupdown/ifupdownflags.py +++ b/ifupdown/ifupdownflags.py @@ -14,6 +14,7 @@ class ifupdownFlags(): self.NOWAIT = False self.PERFMODE = False self.CACHE = False + self.WITHDEFAULTS = False # Flags self.CACHE_FLAGS = 0x0 diff --git a/ifupdown/ifupdownmain.py b/ifupdown/ifupdownmain.py index b4c3440..de6b28c 100644 --- a/ifupdown/ifupdownmain.py +++ b/ifupdown/ifupdownmain.py @@ -171,7 +171,8 @@ class ifupdownMain(ifupdownBase): cache=False, addons_enable=True, statemanager_enable=True, interfacesfile='/etc/network/interfaces', interfacesfileiobuf=None, - interfacesfileformat='native'): + interfacesfileformat='native', + withdefaults=False): """This member function initializes the ifupdownmain object. Kwargs: @@ -188,6 +189,7 @@ class ifupdownMain(ifupdownBase): self.logger = logging.getLogger('ifupdown') ifupdownflags.flags.FORCE = force ifupdownflags.flags.DRYRUN = dryrun + ifupdownflags.flags.WITHDEFAULTS = withdefaults ifupdownflags.flags.NOWAIT = nowait ifupdownflags.flags.PERFMODE = perfmode ifupdownflags.flags.CACHE = cache @@ -895,13 +897,13 @@ class ifupdownMain(ifupdownBase): # continue reading pass - def _sched_ifaces(self, ifacenames, ops, withdefaults=False, - skipupperifaces=False, followdependents=True, sort=False): + def _sched_ifaces(self, ifacenames, ops, skipupperifaces=False, + followdependents=True, sort=False): self.logger.debug('scheduling \'%s\' for %s' %(str(ops), str(ifacenames))) self._pretty_print_ordered_dict('dependency graph', self.dependency_graph) - ifaceScheduler.sched_ifaces(self, ifacenames, ops, withdefaults, + ifaceScheduler.sched_ifaces(self, ifacenames, ops, dependency_graph=self.dependency_graph, order=ifaceSchedulerFlags.INORDER if 'down' in ops[0] @@ -1209,7 +1211,7 @@ class ifupdownMain(ifupdownBase): def query(self, ops, auto=False, format_list=False, allow_classes=None, ifacenames=None, excludepats=None, printdependency=None, - format='native', type=None, withdefaults=False): + format='native', type=None): """ query an interface """ self.set_type(type) @@ -1273,7 +1275,7 @@ class ifupdownMain(ifupdownBase): elif ops[0] == 'query-raw': return self.print_ifaceobjs_raw(filtered_ifacenames) - ret = self._sched_ifaces(filtered_ifacenames, ops, withdefaults, + ret = self._sched_ifaces(filtered_ifacenames, ops, followdependents=True if self.flags.WITH_DEPENDS else False) diff --git a/ifupdown/scheduler.py b/ifupdown/scheduler.py index cbcfeb8..3202f9b 100644 --- a/ifupdown/scheduler.py +++ b/ifupdown/scheduler.py @@ -49,7 +49,7 @@ class ifaceScheduler(): cls._SCHED_STATUS = state @classmethod - def run_iface_op(cls, ifupdownobj, ifaceobj, op, withdefaults=False, cenv=None): + def run_iface_op(cls, ifupdownobj, ifaceobj, op, cenv=None): """ Runs sub operation on an interface """ ifacename = ifaceobj.name @@ -80,11 +80,11 @@ class ifaceScheduler(): continue ifupdownobj.logger.debug(msg) m.run(ifaceobj, op, query_ifaceobj, - ifaceobj_getfunc=ifupdownobj.get_ifaceobjs, withdefaults=withdefaults) + ifaceobj_getfunc=ifupdownobj.get_ifaceobjs) else: ifupdownobj.logger.debug(msg) m.run(ifaceobj, op, - ifaceobj_getfunc=ifupdownobj.get_ifaceobjs, withdefaults=withdefaults) + ifaceobj_getfunc=ifupdownobj.get_ifaceobjs) except Exception, e: if not ifupdownobj.ignore_error(str(e)): err = 1 @@ -117,7 +117,7 @@ class ifaceScheduler(): ifupdownobj.log_error(str(e)) @classmethod - def run_iface_list_ops(cls, ifupdownobj, ifaceobjs, ops, withdefaults=False): + def run_iface_list_ops(cls, ifupdownobj, ifaceobjs, ops): """ Runs all operations on a list of interface configurations for the same interface """ @@ -151,7 +151,7 @@ class ifaceScheduler(): %(ifaceobjs[0].name, str(e))) pass for ifaceobj in ifaceobjs: - cls.run_iface_op(ifupdownobj, ifaceobj, op, withdefaults, + cls.run_iface_op(ifupdownobj, ifaceobj, op, cenv=ifupdownobj.generate_running_env(ifaceobj, op) if ifupdownobj.config.get('addon_scripts_support', '0') == '1' else None) @@ -212,8 +212,8 @@ class ifaceScheduler(): return True @classmethod - def run_iface_graph(cls, ifupdownobj, ifacename, ops, withdefaults=False, - parent=None, order=ifaceSchedulerFlags.POSTORDER, + def run_iface_graph(cls, ifupdownobj, ifacename, ops, parent=None, + order=ifaceSchedulerFlags.POSTORDER, followdependents=True): """ runs interface by traversing all nodes rooted at itself """ @@ -235,7 +235,7 @@ class ifaceScheduler(): # If inorder, run the iface first and then its dependents if order == ifaceSchedulerFlags.INORDER: - cls.run_iface_list_ops(ifupdownobj, ifaceobjs, ops, False) + cls.run_iface_list_ops(ifupdownobj, ifaceobjs, ops) for ifaceobj in ifaceobjs: # Run lowerifaces or dependents @@ -254,12 +254,11 @@ class ifaceScheduler(): if ifupdownobj.is_iface_noconfig(d)] if new_dlist: cls.run_iface_list(ifupdownobj, new_dlist, ops, - withdefaults, ifacename, order, - followdependents, + ifacename, order, followdependents, continueonfailure=False) else: cls.run_iface_list(ifupdownobj, dlist, ops, - withdefaults, ifacename, order, + ifacename, order, followdependents, continueonfailure=False) except Exception, e: @@ -271,17 +270,18 @@ class ifaceScheduler(): ifaceStatus.ERROR) raise if order == ifaceSchedulerFlags.POSTORDER: - cls.run_iface_list_ops(ifupdownobj, ifaceobjs, ops, withdefaults) + cls.run_iface_list_ops(ifupdownobj, ifaceobjs, ops) @classmethod - def run_iface_list(cls, ifupdownobj, ifacenames, ops, withdefaults=False, - parent=None, order=ifaceSchedulerFlags.POSTORDER, + def run_iface_list(cls, ifupdownobj, ifacenames, + ops, parent=None, order=ifaceSchedulerFlags.POSTORDER, followdependents=True, continueonfailure=True): """ Runs interface list """ + for ifacename in ifacenames: try: - cls.run_iface_graph(ifupdownobj, ifacename, ops, withdefaults, - parent, order, followdependents) + cls.run_iface_graph(ifupdownobj, ifacename, ops, parent, + order, followdependents) except Exception, e: if continueonfailure: if ifupdownobj.logger.isEnabledFor(logging.DEBUG): @@ -311,7 +311,7 @@ class ifaceScheduler(): if not skip_root: # run the iface first and then its upperifaces - cls.run_iface_list_ops(ifupdownobj, ifaceobjs, ops, False) + cls.run_iface_list_ops(ifupdownobj, ifaceobjs, ops) for ifaceobj in ifaceobjs: # Run upperifaces ulist = ifaceobj.upperifaces @@ -405,7 +405,7 @@ class ifaceScheduler(): ifaceobjs = ifupdownobj.get_ifaceobjs(u) if not ifaceobjs: continue - cls.run_iface_list_ops(ifupdownobj, ifaceobjs, ops, False) + cls.run_iface_list_ops(ifupdownobj, ifaceobjs, ops) except Exception, e: if continueonfailure: self.logger.warn('%s' %str(e)) @@ -434,7 +434,7 @@ class ifaceScheduler(): return ifacenames_sorted @classmethod - def sched_ifaces(cls, ifupdownobj, ifacenames, ops, withdefaults=False, + def sched_ifaces(cls, ifupdownobj, ifacenames, ops, dependency_graph=None, indegrees=None, order=ifaceSchedulerFlags.POSTORDER, followdependents=True, skipupperifaces=False, sort=False): @@ -529,7 +529,7 @@ class ifaceScheduler(): run_queue.reverse() # run interface list - cls.run_iface_list(ifupdownobj, run_queue, ops, withdefaults, + cls.run_iface_list(ifupdownobj, run_queue, ops, parent=None, order=order, followdependents=followdependents) if not cls.get_sched_status(): diff --git a/ifupdownaddons/bridgeutils.py b/ifupdownaddons/bridgeutils.py index 962f98d..39640df 100644 --- a/ifupdownaddons/bridgeutils.py +++ b/ifupdownaddons/bridgeutils.py @@ -78,6 +78,12 @@ class brctl(utilsBase): battrs['fd'] = broutlines[6].split( 'bridge forward delay')[1].strip( ).replace('.00', '') + battrs['ageing'] = broutlines[7].split( + 'ageing time')[1].strip().replace('.00', '') + battrs['mcrouter'] = broutlines[12].split( + 'mc router')[1].strip().split('\t\t\t')[0] + battrs['bridgeprio'] = self.read_file_oneline( + '/sys/class/net/%s/bridge/priority' %bridgename) battrs.update(self._bridge_get_mcattrs_from_sysfs(bridgename)) # XXX: comment this out until mc attributes become available @@ -94,7 +100,6 @@ class brctl(utilsBase): pass linkCache.update_attrdict([bridgename, 'linkinfo'], battrs) - for cidx in range(1, len(chunks)): bpout = chunks[cidx].lstrip('\n') if not bpout or bpout[0] == ' ': @@ -107,11 +112,12 @@ class brctl(utilsBase): 'path cost')[1].strip() bportattrs['fdelay'] = bplines[4].split( 'forward delay timer')[1].strip() - bportattrs['mcrouter'] = self.read_file_oneline( + bportattrs['portmcrouter'] = self.read_file_oneline( '/sys/class/net/%s/brport/multicast_router' %pname) - bportattrs['mcfl'] = self.read_file_oneline( + bportattrs['portmcfl'] = self.read_file_oneline( '/sys/class/net/%s/brport/multicast_fast_leave' %pname) - + bportattrs['portprio'] = self.read_file_oneline( + '/sys/class/net/%s/brport/priority' %pname) #bportattrs['mcrouters'] = bplines[6].split('mc router')[1].split()[0].strip() #bportattrs['mc fast leave'] = bplines[6].split('mc fast leave')[1].strip() except Exception, e: diff --git a/sbin/ifupdown2 b/sbin/ifupdown2 index 289080e..140202d 100755 --- a/sbin/ifupdown2 +++ b/sbin/ifupdown2 @@ -107,8 +107,6 @@ def run_query(args): qop = 'query-dependency' elif args.printsavedstate: qop = 'query-savedstate' - elif args.withdefaults: - qop = 'query-withdefaults' else: qop='query' cachearg=(False if (iflist or args.nocache or @@ -125,15 +123,15 @@ def run_query(args): cache=cachearg, interfacesfile=interfacesfilename, interfacesfileiobuf=interfacesfileiobuf, - interfacesfileformat=args.interfacesfileformat) + interfacesfileformat=args.interfacesfileformat, + withdefaults=args.withdefaults) # list implies all auto interfaces (this is how ifupdown behaves) if args.list: args.all = True ifupdown_handle.query([qop], args.all, args.list, args.CLASS, iflist, excludepats=args.excludepats, printdependency=args.printdependency, - format=args.format, type=args.type, - withdefaults=args.withdefaults) + format=args.format, type=args.type) except: raise From c4e05f9f8c8aff6ed84a5cbb2e53e07e6a342e2f Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Sat, 23 Apr 2016 09:12:36 -0700 Subject: [PATCH 08/27] addons: vrf: fix vrf-helper args at boot Ticket: Reviewed By: dsa Testing Done: tested boot with vrf devs and checking vrf-helper args Call it with the 'boot' arg at boot: /usr/lib/vrf/vrf-helper create blue 1002 boot Signed-off-by: Roopa Prabhu --- addons/vrf.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/addons/vrf.py b/addons/vrf.py index 1ff21f3..ff2467b 100644 --- a/addons/vrf.py +++ b/addons/vrf.py @@ -535,9 +535,12 @@ class vrf(moduleBase): return vrf_table def _up_vrf_helper(self, ifaceobj, vrf_table): + mode = "" + if ifupdownflags.flags.PERFMODE: + mode = "boot" if self.vrf_helper: - self.exec_command('%s create %s %s' %(self.vrf_helper, - ifaceobj.name, vrf_table)) + self.exec_command('%s create %s %s %s' %(self.vrf_helper, + ifaceobj.name, vrf_table, mode)) def _up_vrf_dev(self, ifaceobj, vrf_table, add_slaves=True, ifaceobj_getfunc=None): @@ -658,9 +661,12 @@ class vrf(moduleBase): self.log_error(str(e)) def _down_vrf_helper(self, ifaceobj, vrf_table): + mode = "" + if ifupdownflags.flags.PERFMODE: + mode = "boot" if self.vrf_helper: - self.exec_command('%s delete %s %s' %(self.vrf_helper, - ifaceobj.name, vrf_table)) + self.exec_command('%s delete %s %s %s' %(self.vrf_helper, + ifaceobj.name, vrf_table, mode)) def _down_vrf_dev(self, ifaceobj, vrf_table, ifaceobj_getfunc=None): From d770f1d53bb5960a3c408229413de0452daa286f Mon Sep 17 00:00:00 2001 From: slaffer Date: Sat, 23 Apr 2016 20:19:48 -0700 Subject: [PATCH 09/27] addons: vlan: remove reserved VLAN check for builtin interfaces Ticket: CM-10387 Reviewed By: roopa, wkok Testing Done: slaffer addons/vlan.py checks if a builtin interface's VLAN ID is within the switchd reserved VLAN range. This stops a user configuring any port- local VLANs within that range, despite it being a valid configuration in both a hardware and kernel sense. This commit removes the check for builtin interfaces only. The check of the bridge-vids list for a vlan-aware bridge still resides and correctly operates in addons/bridge.py. --- addons/vlan.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/addons/vlan.py b/addons/vlan.py index 85e7b75..866be26 100644 --- a/addons/vlan.py +++ b/addons/vlan.py @@ -128,8 +128,6 @@ class vlan(moduleBase): vlanid = self._get_vlan_id(ifaceobj) if vlanid == -1: raise Exception('could not determine vlanid') - if self._handle_reserved_vlan(vlanid, ifaceobj.name): - return vlanrawdevice = self._get_vlan_raw_device(ifaceobj) if not vlanrawdevice: raise Exception('could not determine vlan raw device') From 77d9d6645a7812523c6955637a34a2da3b1d7166 Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Sat, 23 Apr 2016 22:31:13 -0700 Subject: [PATCH 10/27] ifupdownaddons: modulebase: move port expr message to debug Signed-off-by: Roopa Prabhu --- ifupdownaddons/modulebase.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ifupdownaddons/modulebase.py b/ifupdownaddons/modulebase.py index b6c8d78..7236d35 100644 --- a/ifupdownaddons/modulebase.py +++ b/ifupdownaddons/modulebase.py @@ -231,7 +231,7 @@ class moduleBase(object): if not port_expr: return None exprs = re.split(r'[\s\t]\s*', port_expr) - self.logger.info('%s: evaluating port expr \'%s\'' + self.logger.debug('%s: evaluating port expr \'%s\'' %(ifacename, str(exprs))) for expr in exprs: if expr == 'noregex': From f05e1e6d057db28dcd9703de85c853552c93a603 Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Sat, 23 Apr 2016 22:32:14 -0700 Subject: [PATCH 11/27] addons: bridge: call bridge vlan show only if we have attributes that need them Ticket: CM-10273 Reviewed By: Testing Done: Tested with scale interfaces file in the bug This reduces 250 unnecessary 'bridge -c vlan show' commands Signed-off-by: Roopa Prabhu --- addons/bridge.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/addons/bridge.py b/addons/bridge.py index 646d3c2..e1cbf70 100644 --- a/addons/bridge.py +++ b/addons/bridge.py @@ -512,17 +512,21 @@ class bridge(moduleBase): # Supports old style vlan vid info format # for compatibility # + bridge_port_pvids = ifaceobj.get_attr_value_first('bridge-port-pvids') + bridge_port_vids = ifaceobj.get_attr_value_first('bridge-port-vids') + if not bridge_port_pvids and not bridge_port_vids: + return # Handle bridge vlan attrs running_vidinfo = self._get_running_vidinfo() # Install pvids - attrval = ifaceobj.get_attr_value_first('bridge-port-pvids') - if attrval: - portlist = self.parse_port_list(ifaceobj.name, attrval) + if bridge_port_pvids: + portlist = self.parse_port_list(ifaceobj.name, bridge_port_pvids) if not portlist: self.log_warn('%s: could not parse \'%s %s\'' - %(ifaceobj.name, attrname, attrval)) + %(ifaceobj.name, 'bridge-port-pvids', + bridge_port_pvids)) return for p in portlist: try: @@ -539,12 +543,11 @@ class bridge(moduleBase): %(ifaceobj.name, p, str(e))) # install port vids - attrval = ifaceobj.get_attr_value_first('bridge-port-vids') - if attrval: - portlist = self.parse_port_list(ifaceobj.name, attrval) + if bridge_port_vids: + portlist = self.parse_port_list(ifaceobj.name, bridge_port_vids) if not portlist: - self.log_warn('%s: could not parse \'%s %s\'' - %(ifaceobj.name, attrname, attrval)) + self.log_warn('%s: could not parse \'%s %s\'' %(ifaceobj.name, + 'bridge-port-vids', bridge_port_vids)) return for p in portlist: try: From c8a3b44e94bdfa52a2f58297e2c585d7515c2780 Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Sat, 23 Apr 2016 22:57:41 -0700 Subject: [PATCH 12/27] addons: vrf: fix check for max vrf dev count Ticket: CM-10465 Reviewed By: julien, nikhil Testing Done: Tested creating more than 64 vrf devices example config: {noformat} %for v in range(1, 66): auto vrf${v} iface vrf${v} vrf-table auto %endfor {noformat} also, since vrf module already does a link up on vrf dev, remove link up of vrf dev from ifupdownmain scheduler callback --- addons/vrf.py | 10 ++++++---- ifupdown/ifupdownmain.py | 2 ++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/addons/vrf.py b/addons/vrf.py index ff2467b..2b44ce1 100644 --- a/addons/vrf.py +++ b/addons/vrf.py @@ -158,6 +158,7 @@ class vrf(moduleBase): last_used_vrf_table = t self.last_used_vrf_table = last_used_vrf_table self._iproute2_vrf_map_initialized = True + self.vrf_count = len(self.iproute2_vrf_map) def _iproute2_vrf_map_sync_to_disk(self): if not self.iproute2_vrf_map_sync_to_disk: @@ -248,6 +249,7 @@ class vrf(moduleBase): self.iproute2_vrf_map_fd.write('%s %s\n' %(table_id, vrf_dev_name)) self.iproute2_vrf_map_fd.flush() + self.vrf_count += 1 return if old_vrf_name != vrf_dev_name: @@ -487,6 +489,10 @@ class vrf(moduleBase): def _create_vrf_dev(self, ifaceobj, vrf_table): if not self.ipcmd.link_exists(ifaceobj.name): + if self.vrf_count == self.vrf_max_count: + self.log_error('%s: max vrf count %d hit...not ' + 'creating vrf' %(ifaceobj.name, + self.vrf_count)) if vrf_table == 'auto': vrf_table = self._get_avail_vrf_table_id() if not vrf_table: @@ -637,10 +643,6 @@ class vrf(moduleBase): if vrf_table: self._iproute2_vrf_map_initialize() # This is a vrf device - if self.vrf_count == self.vrf_max_count: - self.log_error('%s: max vrf count %d hit...not ' - 'creating vrf' %(ifaceobj.name, - self.vrf_count)) self._up_vrf_dev(ifaceobj, vrf_table, True, ifaceobj_getfunc) else: vrf = ifaceobj.get_attr_value_first('vrf') diff --git a/ifupdown/ifupdownmain.py b/ifupdown/ifupdownmain.py index de6b28c..555549f 100644 --- a/ifupdown/ifupdownmain.py +++ b/ifupdown/ifupdownmain.py @@ -112,6 +112,8 @@ class ifupdownMain(ifupdownBase): # there is no real interface behind it if ifaceobj.type == ifaceType.BRIDGE_VLAN: return + if ifaceobj.link_kind & ifaceLinkKind.VRF: + return if (ifaceobj.addr_method and ifaceobj.addr_method == 'manual'): return From ea9e3c0f152d48c183e259e00ae620fcfe19d047 Mon Sep 17 00:00:00 2001 From: Julien Fortin Date: Mon, 25 Apr 2016 00:32:59 +0200 Subject: [PATCH 13/27] addons: bridge: disabling ipv6 on bridge if any VXLAN port Ticket: CM-7594 Reviewed By: Roopa Testing Done: Creating a bridge with and without vxlan --- addons/bridge.py | 23 +++++++++++++---------- ifupdown/iface.py | 23 ++++++++++++++--------- ifupdown/ifupdownmain.py | 4 ++++ 3 files changed, 31 insertions(+), 19 deletions(-) diff --git a/addons/bridge.py b/addons/bridge.py index e1cbf70..98c5a00 100644 --- a/addons/bridge.py +++ b/addons/bridge.py @@ -306,14 +306,17 @@ class bridge(moduleBase): self.log_warn('%s: unable to process waitport: %s' %(ifaceobj.name, str(e))) - def _ports_enable_disable_ipv6(self, ports, enable='1'): + def _enable_disable_ipv6(self, port, enable='1'): + try: + self.write_file('/proc/sys/net/ipv6/conf/%s/disable_ipv6' % port, enable) + except Exception, e: + self.logger.info(str(e)) + + def handle_ipv6(self, ports, state, ifaceobj=None): + if ifaceobj and (ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VXLAN): + self._enable_disable_ipv6(ifaceobj.name, state) for p in ports: - try: - self.write_file('/proc/sys/net/ipv6/conf/%s' %p + - '/disable_ipv6', enable) - except Exception, e: - self.logger.info(str(e)) - pass + self._enable_disable_ipv6(p, state) def _pretty_print_add_ports_error(self, errstr, bridgename, bridgeports): """ pretty print bridge port add errors. @@ -395,7 +398,7 @@ class bridge(moduleBase): pass # enable ipv6 for ports that were removed - self._ports_enable_disable_ipv6(removedbridgeports, '0') + self.handle_ipv6(removedbridgeports, '0') if err: self.log_error('bridge configuration failed (missing ports)') @@ -1061,7 +1064,7 @@ class bridge(moduleBase): if not running_ports: return # disable ipv6 for ports that were added to bridge - self._ports_enable_disable_ipv6(running_ports, '1') + self.handle_ipv6(running_ports, '1', ifaceobj=ifaceobj) self._apply_bridge_port_settings_all(ifaceobj, ifaceobj_getfunc=ifaceobj_getfunc) except Exception, e: @@ -1090,7 +1093,7 @@ class bridge(moduleBase): ports = self.brctlcmd.get_bridge_ports(ifaceobj.name) self.brctlcmd.delete_bridge(ifaceobj.name) if ports: - self._ports_enable_disable_ipv6(ports, '0') + self.handle_ipv6(ports, '0', ifaceobj=ifaceobj) if ifaceobj.link_type != ifaceLinkType.LINK_NA: map(lambda p: rtnetlink_api.rtnl_api.link_set(p, "down"), ports) diff --git a/ifupdown/iface.py b/ifupdown/iface.py index cccd39f..69c3ef5 100644 --- a/ifupdown/iface.py +++ b/ifupdown/iface.py @@ -56,11 +56,12 @@ class ifaceLinkKind(): class ifaceLinkPrivFlags(): """ This corresponds to kernel netdev->priv_flags and can be BRIDGE_PORT, BOND_SLAVE etc """ - UNKNOWN = 0x0000 - BRIDGE_PORT = 0x0001 - BOND_SLAVE = 0x0010 - VRF_SLAVE = 0x0100 - BRIDGE_VLAN_AWARE = 0x1000 + UNKNOWN = 0x00000 + BRIDGE_PORT = 0x00001 + BOND_SLAVE = 0x00010 + VRF_SLAVE = 0x00100 + BRIDGE_VLAN_AWARE = 0x01000 + BRIDGE_VXLAN = 0x10000 @classmethod def get_str(cls, flag): @@ -74,18 +75,22 @@ class ifaceLinkPrivFlags(): return 'vrf slave' elif flag == cls.BRIDGE_VLAN_AWARE: return 'vlan aware bridge' + elif flag == cls.BRIDGE_VXLAN: + return 'vxlan bridge' @classmethod def get_all_str(cls, flags): str = '' - if (flags & cls.BRIDGE_PORT): + if flags & cls.BRIDGE_PORT: str += 'bridgeport ' - if (flags == cls.BOND_SLAVE): + if flags & cls.BOND_SLAVE: str += 'bondslave ' - elif flags == cls.VRF_SLAVE: + if flags & cls.VRF_SLAVE: str += 'vrfslave ' - elif flags == cls.BRIDGE_VLAN_AWARE: + if flags & cls.BRIDGE_VLAN_AWARE: str += 'vlanawarebridge ' + if flags & cls.BRIDGE_VXLAN: + str += 'vxlanbridge ' return str class ifaceLinkType(): diff --git a/ifupdown/ifupdownmain.py b/ifupdown/ifupdownmain.py index 555549f..16b25bb 100644 --- a/ifupdown/ifupdownmain.py +++ b/ifupdown/ifupdownmain.py @@ -448,6 +448,10 @@ class ifupdownMain(ifupdownBase): self._set_iface_role(ifaceobj, ifaceRole.SLAVE, upperifaceobj) ifaceobj.link_privflags |= ifaceLinkPrivFlags.BRIDGE_PORT + if (ifaceobj.link_kind & ifaceLinkKind.VXLAN) \ + and (upperifaceobj.link_kind & ifaceLinkKind.BRIDGE): + upperifaceobj.link_privflags |= ifaceLinkPrivFlags.BRIDGE_VXLAN + # vrf masters get processed after slaves, which means # check both link_kind vrf and vrf slave if ((upperifaceobj.link_kind & ifaceLinkKind.VRF) or From 634764bd88d7129e8030f02ab544bf0ad655ce08 Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Sun, 24 Apr 2016 17:24:31 -0700 Subject: [PATCH 14/27] ifquery: support for --with-defaults in the base output Ticket: CM-7840 Reviewed By: julien, nikhil Testing Done: Tested ifquery with and without --with-defaults option commit "6e16e5ae90f2" introduced --with-defaults for ifquery --check output. But the base ifquery --with-defaults should also include the default policy attributes we support. This patch adds infrastructure to query default attributes --with-defaults in base ifquery output. example: {noformat} $ifquery br0 auto br0 iface br0 inet static bridge-ports swp1 swp2 $ifquery br0 --with-defaults auto br0 iface br0 inet static bridge-ports swp1 swp2 bridge-stp yes {noformat} --- addons/bridge.py | 8 +++++++- ifupdown/ifupdownmain.py | 6 ++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/addons/bridge.py b/addons/bridge.py index 98c5a00..c2de180 100644 --- a/addons/bridge.py +++ b/addons/bridge.py @@ -1692,10 +1692,16 @@ class bridge(moduleBase): elif self.brctlcmd.is_bridge_port(ifaceobjrunning.name): self._query_running_bridge_port(ifaceobjrunning, ifaceobj_getfunc) + def _query(self, ifaceobj, **kwargs): + """ add default policy attributes supported by the module """ + if self.default_stp_on: + ifaceobj.update_config('bridge-stp', 'yes') + _run_ops = {'pre-up' : _up, 'post-down' : _down, 'query-checkcurr' : _query_check, - 'query-running' : _query_running} + 'query-running' : _query_running, + 'query' : _query} def get_ops(self): """ returns list of ops supported by this module """ diff --git a/ifupdown/ifupdownmain.py b/ifupdown/ifupdownmain.py index 16b25bb..a3a8da9 100644 --- a/ifupdown/ifupdownmain.py +++ b/ifupdown/ifupdownmain.py @@ -1276,7 +1276,7 @@ class ifupdownMain(ifupdownBase): if format_list and (ops[0] == 'query' or ops[0] == 'query-raw'): return self.print_ifaceobjs_list(filtered_ifacenames) - if ops[0] == 'query': + if ops[0] == 'query' and not ifupdownflags.flags.WITHDEFAULTS: return self.print_ifaceobjs_pretty(filtered_ifacenames, format) elif ops[0] == 'query-raw': return self.print_ifaceobjs_raw(filtered_ifacenames) @@ -1285,7 +1285,9 @@ class ifupdownMain(ifupdownBase): followdependents=True if self.flags.WITH_DEPENDS else False) - if ops[0] == 'query-checkcurr': + if ops[0] == 'query' and ifupdownflags.flags.WITHDEFAULTS: + return self.print_ifaceobjs_pretty(filtered_ifacenames, format) + elif ops[0] == 'query-checkcurr': ret = self.print_ifaceobjscurr_pretty(filtered_ifacenames, format) if ret != 0: # if any of the object has an error, signal that silently From 24e32bfc6b17a975415db6c9f9269f40da5409f3 Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Sun, 24 Apr 2016 17:38:00 -0700 Subject: [PATCH 15/27] addons: bridge: fix 'query' handler to check if the interface is a bridge Ticket: CM-7840 Reviewed By: julien, nikhil Testing Done: Tested ifquery with and without --with-defaults option --- addons/bridge.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/addons/bridge.py b/addons/bridge.py index c2de180..de0770d 100644 --- a/addons/bridge.py +++ b/addons/bridge.py @@ -1694,6 +1694,8 @@ class bridge(moduleBase): def _query(self, ifaceobj, **kwargs): """ add default policy attributes supported by the module """ + if not (ifaceobj.link_kind & ifaceLinkKind.BRIDGE): + return if self.default_stp_on: ifaceobj.update_config('bridge-stp', 'yes') From f466af7a8cf5b0bcfddf913b7818e6de99269966 Mon Sep 17 00:00:00 2001 From: Julien Fortin Date: Mon, 25 Apr 2016 17:39:57 +0200 Subject: [PATCH 16/27] addons: addressvirtual: fixing: duplicate address-virtual lines cause switch to lockup Ticket: CM-10478 Reviewed By: Roopa Testing Done: Tested with the interface file provided in the ticket and a custom one. --- addons/addressvirtual.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/addons/addressvirtual.py b/addons/addressvirtual.py index de07bdb..f95d694 100644 --- a/addons/addressvirtual.py +++ b/addons/addressvirtual.py @@ -261,6 +261,11 @@ class addressvirtual(moduleBase): self._remove_address_config(ifaceobj, address_virtual_list) return + if ifaceobj.upperifaces: + self.log_error('%s: invalid placement of address-virtual lines (must be configured under an interface with no upper interfaces or parent interfaces)' + % (ifaceobj.name), ifaceobj) + return + if not self.ipcmd.link_exists(ifaceobj.name): return self._apply_address_config(ifaceobj, address_virtual_list) From 016e9325b6611972aaeaadb0169d219c24ed906f Mon Sep 17 00:00:00 2001 From: Nikhil Date: Mon, 25 Apr 2016 18:48:01 -0700 Subject: [PATCH 17/27] addons: mgmtvrf with static IP needs to support 'gateway' Ticket: CM-10281 Reviewed By: Roopa Prabhu Testing Done: Tested with the configuration mentioned in the bug id Due to bug CM-10188, defualt route via gateway is not installed in time. It needs 2 sec delay, and fix to CM-10188 shall rectify this issue. Signed-off-by: Nikhil --- addons/address.py | 4 +++- ifupdownaddons/iproute2.py | 14 ++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/addons/address.py b/addons/address.py index b35206e..8f01167 100644 --- a/addons/address.py +++ b/addons/address.py @@ -313,7 +313,8 @@ class address(moduleBase): if addr_method != "dhcp": self.ipcmd.route_add_gateway(ifaceobj.name, - ifaceobj.get_attr_value_first('gateway')) + ifaceobj.get_attr_value_first('gateway'), + ifaceobj.get_attr_value_first('vrf')) def _down(self, ifaceobj, ifaceobj_getfunc=None): try: @@ -323,6 +324,7 @@ class address(moduleBase): if addr_method != "dhcp": self.ipcmd.route_del_gateway(ifaceobj.name, ifaceobj.get_attr_value_first('gateway'), + ifaceobj.get_attr_value_first('vrf'), ifaceobj.get_attr_value_first('metric')) if ifaceobj.get_attr_value_first('address-purge')=='no': addrlist = ifaceobj.get_attr_value('address') diff --git a/ifupdownaddons/iproute2.py b/ifupdownaddons/iproute2.py index 7b1466c..281f7da 100644 --- a/ifupdownaddons/iproute2.py +++ b/ifupdownaddons/iproute2.py @@ -437,21 +437,27 @@ class iproute2(utilsBase): def link_get_status(self, ifacename): return self._cache_get('link', [ifacename, 'ifflag'], refresh=True) - def route_add_gateway(self, ifacename, gateway, metric=None): + def route_add_gateway(self, ifacename, gateway, vrf=None, metric=None): if not gateway: return - cmd = 'ip route add default via %s' %gateway + if not vrf: + cmd = 'ip route add default via %s' %gateway + else: + cmd = 'ip route add table %s default via %s' %(vrf, gateway) # Add metric if metric: cmd += 'metric %s' %metric cmd += ' dev %s' %ifacename self.exec_command(cmd) - def route_del_gateway(self, ifacename, gateway, metric=None): + def route_del_gateway(self, ifacename, gateway, vrf=None, metric=None): # delete default gw if not gateway: return - cmd = 'ip route del default via %s' %gateway + if not vrf: + cmd = 'ip route del default via %s' %gateway + else: + cmd = 'ip route del table %s default via %s' %(vrf, gateway) if metric: cmd += ' metric %s' %metric cmd += ' dev %s' %ifacename From 8a360f1b9832db43614d215ec48e60188859d2f9 Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Mon, 25 Apr 2016 22:27:31 -0700 Subject: [PATCH 18/27] ifreload: enable CACHE flag during up of interfaces Ticket: CM-10273 Reviewed By: julien Testing Done: Tested with scale config in the bug --- ifupdown/ifupdownmain.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ifupdown/ifupdownmain.py b/ifupdown/ifupdownmain.py index a3a8da9..36252c8 100644 --- a/ifupdown/ifupdownmain.py +++ b/ifupdown/ifupdownmain.py @@ -1563,6 +1563,7 @@ class ifupdownMain(ifupdownBase): self.logger.info('reload: scheduling up on interfaces: %s' %str(new_filtered_ifacenames)) + ifupdownflags.flags.CACHE = True try: ret = self._sched_ifaces(new_filtered_ifacenames, upops, followdependents=True From 082b4bf7608d771c83fc1d8ac5188f0de6de6328 Mon Sep 17 00:00:00 2001 From: Julien Fortin Date: Tue, 26 Apr 2016 17:10:09 +0200 Subject: [PATCH 19/27] addons: bridge: fixing: bridge disable_ipv6 is not handle on down anymore. Ticket: CM-7594 Reviewed By: Roopa Testing Done: --- addons/bridge.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/bridge.py b/addons/bridge.py index de0770d..799cfee 100644 --- a/addons/bridge.py +++ b/addons/bridge.py @@ -1093,7 +1093,7 @@ class bridge(moduleBase): ports = self.brctlcmd.get_bridge_ports(ifaceobj.name) self.brctlcmd.delete_bridge(ifaceobj.name) if ports: - self.handle_ipv6(ports, '0', ifaceobj=ifaceobj) + self.handle_ipv6(ports, '0') if ifaceobj.link_type != ifaceLinkType.LINK_NA: map(lambda p: rtnetlink_api.rtnl_api.link_set(p, "down"), ports) From baa909c6d0bdd23a9f82dce4437a6db7ba0406a9 Mon Sep 17 00:00:00 2001 From: Nikhil Date: Tue, 26 Apr 2016 15:00:08 -0700 Subject: [PATCH 20/27] addons: adding '--with-defaults' option for base ifquery Ticket: CM-7840 Reviewed By: Roopa Prabhu Testing Done: yes, with different configurations for physical & logical devices This patch adds 'ifquery --with-defaults' to print the policy default values for unconfigured attributes. Signed-off-by: Nikhil --- addons/bridge.py | 3 ++- addons/ethtool.py | 18 +++++++++++++++++- addons/vrf.py | 10 +++++++++- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/addons/bridge.py b/addons/bridge.py index 799cfee..8caa1e4 100644 --- a/addons/bridge.py +++ b/addons/bridge.py @@ -1694,7 +1694,8 @@ class bridge(moduleBase): def _query(self, ifaceobj, **kwargs): """ add default policy attributes supported by the module """ - if not (ifaceobj.link_kind & ifaceLinkKind.BRIDGE): + if (not (ifaceobj.link_kind & ifaceLinkKind.BRIDGE) or + ifaceobj.get_attr_value_first('bridge-stp')): return if self.default_stp_on: ifaceobj.update_config('bridge-stp', 'yes') diff --git a/addons/ethtool.py b/addons/ethtool.py index c7a4850..2617602 100644 --- a/addons/ethtool.py +++ b/addons/ethtool.py @@ -232,10 +232,26 @@ class ethtool(moduleBase,utilsBase): return + def _query(self, ifaceobj, **kwargs): + """ add default policy attributes supported by the module """ + if ifaceobj.link_kind: + return + for attr in ['speed', 'duplex', 'autoneg']: + if ifaceobj.get_attr_value_first('link-%s'%attr): + continue + default = policymanager.policymanager_api.get_iface_default( + module_name='ethtool', + ifname=ifaceobj.name, + attr='link-%s' %attr) + if not default: + continue + ifaceobj.update_config('link-%s' %attr, default) + _run_ops = {'pre-down' : _pre_down, 'post-up' : _post_up, 'query-checkcurr' : _query_check, - 'query-running' : _query_running } + 'query-running' : _query_running, + 'query' : _query} def get_ops(self): """ returns list of ops supported by this module """ diff --git a/addons/vrf.py b/addons/vrf.py index 2b44ce1..420eaf1 100644 --- a/addons/vrf.py +++ b/addons/vrf.py @@ -816,10 +816,18 @@ class vrf(moduleBase): except Exception, e: self.log_warn(str(e)) + def _query(self, ifaceobj, **kwargs): + if not self.vrf_helper: + return + if (ifaceobj.link_kind & ifaceLinkKind.VRF): + ifaceobj.update_config('vrf-helper', '%s %s' %(self.vrf_helper, + ifaceobj.name)) + _run_ops = {'pre-up' : _up, 'post-down' : _down, 'query-running' : _query_running, - 'query-checkcurr' : _query_check} + 'query-checkcurr' : _query_check, + 'query' : _query} def get_ops(self): """ returns list of ops supported by this module """ From f6466fcb907464676c482082ffc86197063e59e1 Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Wed, 27 Apr 2016 16:05:09 -0700 Subject: [PATCH 21/27] addons: vrf: add a check and error for reserved system table names Ticket: Reviewed By: dsa, nikhil, julien Testing Done: Tested with system reserved table names example: err msg: $ifquery default auto default iface default vrf-table auto error: default: cannot use system reserved ['253', '0', '254', '255'] table names This patch makes all tables in /etc/iproute2/rt_tables reserved $cat /etc/iproute2/rt_tables 255 local 254 main 253 default 0 unspec Signed-off-by: Roopa Prabhu --- addons/vrf.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/addons/vrf.py b/addons/vrf.py index 420eaf1..3e92c34 100644 --- a/addons/vrf.py +++ b/addons/vrf.py @@ -41,6 +41,9 @@ class vrf(moduleBase): VRF_TABLE_START = 1001 VRF_TABLE_END = 5000 + system_reserved_rt_tables = {'255' : 'local', '254' : 'main', + '253' : 'default', '0' : 'unspec'} + def __init__(self, *args, **kargs): ifupdownaddons.modulebase.moduleBase.__init__(self, *args, **kargs) self.ipcmd = None @@ -489,6 +492,9 @@ class vrf(moduleBase): def _create_vrf_dev(self, ifaceobj, vrf_table): if not self.ipcmd.link_exists(ifaceobj.name): + if ifaceobj.name in self.system_reserved_rt_tables.values(): + self.log_error('cannot use system reserved %s vrf names' + %( str(self.system_reserved_rt_tables.values()))) if self.vrf_count == self.vrf_max_count: self.log_error('%s: max vrf count %d hit...not ' 'creating vrf' %(ifaceobj.name, @@ -502,6 +508,9 @@ class vrf(moduleBase): %(ifaceobj.name, vrf_table)) else: self._iproute2_is_vrf_tableid_inuse(ifaceobj.name, vrf_table) + if ifaceobj.name in self.system_reserved_rt_tables.keys(): + self.log_error('cannot use system reserved %s table ids' + %(str(self.system_reserved_rt_tables.keys()))) if not vrf_table.isdigit(): self.log_error('%s: vrf-table must be an integer or \'auto\'' From eb3ce8c871779ce0249620785244ec79fdfa3671 Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Thu, 28 Apr 2016 15:49:46 -0700 Subject: [PATCH 22/27] addons: vrf: do not write vrf map to disk during query operation Ticket: CM-10569 Reviewed By: julien, nikhil Testing Done: Tested ifquery -c as non root user unlike ifup/ifdown/ifreload, ifquery can be called by a non-root user. so make sure we dont write the root owned vrf map file during ifquery Signed-off-by: Roopa Prabhu --- addons/vrf.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/addons/vrf.py b/addons/vrf.py index 3e92c34..31d0f67 100644 --- a/addons/vrf.py +++ b/addons/vrf.py @@ -99,7 +99,7 @@ class vrf(moduleBase): self.vrf_mgmt_devname = policymanager.policymanager_api.get_module_globals(module_name=self.__class__.__name__, attr='vrf-mgmt-devname') self.vrf_helper = policymanager.policymanager_api.get_module_globals(module_name=self.__class__.__name__, attr='vrf-helper') - def _iproute2_vrf_map_initialize(self): + def _iproute2_vrf_map_initialize(self, writetodisk=True): if self._iproute2_vrf_map_initialized: return @@ -141,11 +141,12 @@ class vrf(moduleBase): iproute2_vrf_map_force_rewrite = True self.iproute2_vrf_map_fd = None - if iproute2_vrf_map_force_rewrite: - # reopen the file and rewrite the map - self._iproute2_vrf_map_open(True, False) - else: - self._iproute2_vrf_map_open(False, True) + if writetodisk: + if iproute2_vrf_map_force_rewrite: + # reopen the file and rewrite the map + self._iproute2_vrf_map_open(True, False) + else: + self._iproute2_vrf_map_open(False, True) self.iproute2_vrf_map_sync_to_disk = False atexit.register(self._iproute2_vrf_map_sync_to_disk) @@ -164,7 +165,8 @@ class vrf(moduleBase): self.vrf_count = len(self.iproute2_vrf_map) def _iproute2_vrf_map_sync_to_disk(self): - if not self.iproute2_vrf_map_sync_to_disk: + if (ifupdownflags.flags.DRYRUN or + not self.iproute2_vrf_map_sync_to_disk): return self.logger.info('vrf: syncing table map to %s' %self.iproute2_vrf_filename) @@ -178,6 +180,8 @@ class vrf(moduleBase): def _iproute2_vrf_map_open(self, sync_vrfs=False, append=False): self.logger.info('vrf: syncing table map to %s' %self.iproute2_vrf_filename) + if ifupdownflags.flags.DRYRUN: + return fmode = 'a+' if append else 'w' try: self.iproute2_vrf_map_fd = open(self.iproute2_vrf_filename, @@ -798,12 +802,12 @@ class vrf(moduleBase): try: vrf_table = ifaceobj.get_attr_value_first('vrf-table') if vrf_table: - self._iproute2_vrf_map_initialize() + self._iproute2_vrf_map_initialize(writetodisk=False) self._query_check_vrf_dev(ifaceobj, ifaceobjcurr, vrf_table) else: vrf = ifaceobj.get_attr_value_first('vrf') if vrf: - self._iproute2_vrf_map_initialize() + self._iproute2_vrf_map_initialize(writetodisk=False) self._query_check_vrf_slave(ifaceobj, ifaceobjcurr, vrf) except Exception, e: self.log_warn(str(e)) From 9e0be374dc0a6de73535b85bb1ac5c6904eb8a8c Mon Sep 17 00:00:00 2001 From: Julien Fortin Date: Fri, 29 Apr 2016 21:19:42 +0200 Subject: [PATCH 23/27] new ifupdown2.conf variable to adjust logical devices MTU Ticket: CM-8736 Reviewed By: Roopa Testing Done: Smoke tests + the ones from the ticket By default ifupdown2 will adjust logical devices MTU based on the physical interface they are running on top of. set this flag to 0 to disable this behaviour adjust_logical_dev_mtu=1 --- addons/addressvirtual.py | 15 +++++++++++++++ addons/bridge.py | 2 +- addons/vlan.py | 10 ++++++++-- config/ifupdown2.conf | 4 ++++ ifupdownaddons/bridgeutils.py | 5 ++--- ifupdownaddons/iproute2.py | 21 ++++++++++++++------- 6 files changed, 44 insertions(+), 13 deletions(-) diff --git a/addons/addressvirtual.py b/addons/addressvirtual.py index f95d694..55f01af 100644 --- a/addons/addressvirtual.py +++ b/addons/addressvirtual.py @@ -7,6 +7,8 @@ from ifupdown.iface import * from ifupdownaddons.modulebase import moduleBase from ifupdownaddons.iproute2 import iproute2 + +import ifupdown.ifupdownconfig as ifupdownConfig import ifupdown.statemanager as statemanager import ifupdown.rtnetlink_api as rtnetlink_api import ifupdown.ifupdownflags as ifupdownflags @@ -146,6 +148,11 @@ class addressvirtual(moduleBase): def _apply_address_config(self, ifaceobj, address_virtual_list): purge_existing = False if ifupdownflags.flags.PERFMODE else True + lower_iface_mtu = update_mtu = None + if ifupdownConfig.config.get('adjust_logical_dev_mtu', '1') != '0': + if ifaceobj.lowerifaces and address_virtual_list: + update_mtu = True + hwaddress = [] self.ipcmd.batch_start() av_idx = 0 @@ -177,10 +184,18 @@ class addressvirtual(moduleBase): hwaddress.append(mac) self.ipcmd.addr_add_multiple(macvlan_ifacename, ips, purge_existing) + # If link existed before, flap the link if not link_created: self._fix_connected_route(ifaceobj, macvlan_ifacename, ips[0]) + if update_mtu: + lower_iface_mtu = self.ipcmd.link_get_mtu(ifaceobj.lowerifaces[0], refresh=True) + update_mtu = False + + if lower_iface_mtu and lower_iface_mtu != self.ipcmd.link_get_mtu(macvlan_ifacename): + self.ipcmd.link_set_mtu(macvlan_ifacename, lower_iface_mtu) + av_idx += 1 self.ipcmd.batch_commit() diff --git a/addons/bridge.py b/addons/bridge.py index 8caa1e4..ac8ae67 100644 --- a/addons/bridge.py +++ b/addons/bridge.py @@ -1036,7 +1036,7 @@ class bridge(moduleBase): try: if ifaceobj.get_attr_value_first('bridge-vlan-aware') == 'yes': if (bridge_just_created or - not self.ipcmd.bridge_is_vlan_aware(ifaceobj.name)): + not self.ipcmd.bridge_is_vlan_aware(ifaceobj.name)): self.ipcmd.link_set(ifaceobj.name, 'vlan_filtering', '1', False, "bridge") if not bridge_just_created: diff --git a/addons/vlan.py b/addons/vlan.py index 866be26..e50fa81 100644 --- a/addons/vlan.py +++ b/addons/vlan.py @@ -7,6 +7,8 @@ from ifupdown.iface import * from ifupdownaddons.modulebase import moduleBase from ifupdownaddons.iproute2 import iproute2 +import ifupdown.ifupdownconfig as ifupdownConfig + import ifupdown.rtnetlink_api as rtnetlink_api import ifupdown.ifupdownflags as ifupdownflags import logging @@ -92,7 +94,7 @@ class vlan(moduleBase): if vlan_raw_device: return vlan_raw_device return self._get_vlan_raw_device_from_ifacename(ifaceobj.name) - + def get_dependent_ifacenames(self, ifaceobj, ifaceobjs_all=None): if not self._is_vlan_device(ifaceobj): return None @@ -136,6 +138,10 @@ class vlan(moduleBase): raise Exception('rawdevice %s not present' %vlanrawdevice) if self.ipcmd.link_exists(ifaceobj.name): self._bridge_vid_add_del(ifaceobj, vlanrawdevice, vlanid) + if ifupdownConfig.config.get('adjust_logical_dev_mtu', '1') != '0' and len(ifaceobj.lowerifaces): + lower_iface_mtu = self.ipcmd.link_get_mtu(ifaceobj.lowerifaces[0], refresh=True) + if not lower_iface_mtu == self.ipcmd.link_get_mtu(ifaceobj.name): + self.ipcmd.link_set_mtu(ifaceobj.name, lower_iface_mtu) return rtnetlink_api.rtnl_api.create_vlan(vlanrawdevice, ifaceobj.name, vlanid) @@ -204,7 +210,7 @@ class vlan(moduleBase): def _init_command_handlers(self): if not self.ipcmd: self.ipcmd = iproute2() - + def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args): """ run vlan configuration on the interface object passed as argument diff --git a/config/ifupdown2.conf b/config/ifupdown2.conf index d5b808a..13cbbdc 100644 --- a/config/ifupdown2.conf +++ b/config/ifupdown2.conf @@ -58,3 +58,7 @@ addr_config_squash=0 # ifaces stanzas for an interface ifaceobj_squash=0 +# By default ifupdown2 will adjust logical devices MTU +# based on the physical interface they are running on top of. +# set this flag to 0 to disable this behaviour +adjust_logical_dev_mtu=1 diff --git a/ifupdownaddons/bridgeutils.py b/ifupdownaddons/bridgeutils.py index 39640df..edffa71 100644 --- a/ifupdownaddons/bridgeutils.py +++ b/ifupdownaddons/bridgeutils.py @@ -96,7 +96,7 @@ class brctl(utilsBase): ##battrs['mcsnoop'] = broutlines[12].split('mc snooping')[1].strip() #battrs['mclmt'] = broutlines[13].split('mc last member timer')[1].split()[0].strip() except Exception, e: - self.logger.warn(str(e)) + self.logger.warn('%s: error while processing bridge attributes: %s' % (bridgename, str(e))) pass linkCache.update_attrdict([bridgename, 'linkinfo'], battrs) @@ -121,8 +121,7 @@ class brctl(utilsBase): #bportattrs['mcrouters'] = bplines[6].split('mc router')[1].split()[0].strip() #bportattrs['mc fast leave'] = bplines[6].split('mc fast leave')[1].strip() except Exception, e: - self.logger.warn(str(e)) - pass + self.logger.warn('%s: error while processing bridge attributes: %s' % (bridgename, str(e))) bports[pname] = bportattrs linkCache.update_attrdict([bridgename, 'linkinfo', 'ports'], bports) diff --git a/ifupdownaddons/iproute2.py b/ifupdownaddons/iproute2.py index 281f7da..cf15046 100644 --- a/ifupdownaddons/iproute2.py +++ b/ifupdownaddons/iproute2.py @@ -39,7 +39,7 @@ class iproute2(utilsBase): iproute2._cache_fill_done = True return True return False - + def _link_fill(self, ifacename=None, refresh=False): """ fills cache with link information @@ -141,7 +141,7 @@ class iproute2(utilsBase): try: # Check if ifacename is already full, in which case, return if ifacename and not refresh: - linkCache.get_attr([ifacename, 'addrs']) + linkCache.get_attr([ifacename, 'addrs']) return except: pass @@ -418,6 +418,13 @@ class iproute2(utilsBase): self.link_up(ifacename) self._cache_update([ifacename, 'hwaddress'], hwaddress) + def link_set_mtu(self, ifacename, mtu): + if not mtu or not ifacename: return + + with open('/sys/class/net/%s/mtu' % ifacename, 'w') as f: + f.write(mtu) + self._cache_update([ifacename, 'mtu'], mtu) + def link_set_alias(self, ifacename, alias): self.exec_commandl(['ip', 'link', 'set', 'dev', ifacename, 'alias', alias]) @@ -487,7 +494,7 @@ class iproute2(utilsBase): v = vlan_device_name.split('.') if len(v) != 2: self.logger.warn('invalid vlan device name %s' %vlan_device_name) - return + return self.link_create_vlan(vlan_device_name, v[0], v[1]) def link_create_macvlan(self, name, linkdev, mode='private'): @@ -622,8 +629,8 @@ class iproute2(utilsBase): def link_get_linkinfo_attrs(self, ifacename): return self._cache_get('link', [ifacename, 'linkinfo']) - def link_get_mtu(self, ifacename): - return self._cache_get('link', [ifacename, 'mtu']) + def link_get_mtu(self, ifacename, refresh=False): + return self._cache_get('link', [ifacename, 'mtu'], refresh=refresh) def link_get_kind(self, ifacename): return self._cache_get('link', [ifacename, 'kind']) @@ -767,7 +774,7 @@ class iproute2(utilsBase): vlan_str = '' if vlan: vlan_str = 'vlan %s ' % vlan - + dst_str = '' if remote: dst_str = 'dst %s ' % remote @@ -834,7 +841,7 @@ class iproute2(utilsBase): iflags = int(flags, 16) if (iflags & 0x0001): ret = True - except: + except: ret = False pass return ret From b47ce90d95d7135b5e4817495d29fd18899cb570 Mon Sep 17 00:00:00 2001 From: Julien Fortin Date: Fri, 29 Apr 2016 21:21:45 +0200 Subject: [PATCH 24/27] mstp: performances: now globaly caching "mstpctl showportdetail json" calls Ticket: CM-10273 Reviewed By: Roopa Testing Done: Smoke + test from the ticket --- addons/mstpctl.py | 8 ---- ifupdownaddons/cache.py | 23 +++++++++- ifupdownaddons/mstpctlutil.py | 80 ++++++++++++++++------------------- 3 files changed, 58 insertions(+), 53 deletions(-) diff --git a/addons/mstpctl.py b/addons/mstpctl.py index 26b628f..522befe 100644 --- a/addons/mstpctl.py +++ b/addons/mstpctl.py @@ -425,10 +425,6 @@ class mstpctl(moduleBase): if bridgename: mstpd_running = self.mstpd_running stp_running_on = self._is_running_userspace_stp_state_on(bridgename) - # initialize all the mstpctl attributes cache with - # the command mstpctl showportdetail bridge json - # since we are about to loop over all the ports below - self.mstpctlcmd.cache_bridgeport_attrs(bridgename) applied = self._apply_bridge_port_settings(ifaceobj, bridgename, None, stp_running_on, mstpd_running) @@ -474,10 +470,6 @@ class mstpctl(moduleBase): stp = self.brctlcmd.get_stp(ifaceobj.name) if (self.mstpd_running and (stp == 'yes' or stp == 'on')): - # initialize all the mstpctl attributes cache with - # the command mstpctl showportdetail bridge json - # since we are about to loop over all the ports below - self.mstpctlcmd.cache_bridgeport_attrs(ifaceobj.name) self._apply_bridge_settings(ifaceobj) self._apply_bridge_port_settings_all(ifaceobj, ifaceobj_getfunc=ifaceobj_getfunc) diff --git a/ifupdownaddons/cache.py b/ifupdownaddons/cache.py index 311082e..35da9f6 100644 --- a/ifupdownaddons/cache.py +++ b/ifupdownaddons/cache.py @@ -5,7 +5,26 @@ # import pprint -from collections import OrderedDict + + +class MSTPAttrsCache(): + bridges = {} + + @classmethod + def get(cls, bridgename, default=None): + if bridgename in MSTPAttrsCache.bridges: + return MSTPAttrsCache.bridges[bridgename] + else: + return default + + @classmethod + def set(cls, bridgename, attrs): + MSTPAttrsCache.bridges[bridgename] = attrs + + @classmethod + def invalidate(cls): + MSTPAttrsCache.bridges = {} + class linkCache(): """ This class contains methods and instance variables to cache @@ -87,6 +106,6 @@ class linkCache(): @classmethod def dump_link(cls, linkname): - print 'Dumping link %s' %linkname + print 'Dumping link %s' % linkname pp = pprint.PrettyPrinter(indent=4) pp.pprint(cls.links.get(linkname)) diff --git a/ifupdownaddons/mstpctlutil.py b/ifupdownaddons/mstpctlutil.py index 1096cdb..0cc812c 100644 --- a/ifupdownaddons/mstpctlutil.py +++ b/ifupdownaddons/mstpctlutil.py @@ -4,6 +4,7 @@ # Author: Roopa Prabhu, roopa@cumulusnetworks.com # +from cache import MSTPAttrsCache from utilsbase import * from ifupdown.iface import * from cache import * @@ -66,50 +67,43 @@ class mstpctlutil(utilsBase): pass return bridgeattrs - def cache_bridgeport_attrs(self,bridgename): - ''' - This method grab output of a mstpctl showportdetail json and caches - it this should save on the overhead of checking each attribute - for every port in the bridge. - ''' - self.mstpctl_bridgeport_attrs_dict = {} - self.mstpctl_bridgeport_attrs_dict[bridgename] = {} - try: - showall_output = self.subprocess_check_output(['/sbin/mstpctl', - 'showportdetail', bridgename, 'json']) - except Exception as e: - self.logger.info(str(e)) - return - if not showall_output or showall_output == '': - return - showall_output = showall_output.strip('\n') - mstpctl_bridge_cache = json.loads(showall_output) - for portname in mstpctl_bridge_cache.keys(): - # we will ignore the portid for now and just index - # by bridgename, portname, and json attribute - for portid in mstpctl_bridge_cache[portname].keys(): - self.mstpctl_bridgeport_attrs_dict[bridgename][portname] = {} - for jsonAttr in mstpctl_bridge_cache[portname][portid].keys(): - jsonVal = mstpctl_bridge_cache[portname][portid][jsonAttr] - self.mstpctl_bridgeport_attrs_dict[bridgename][portname]\ - [jsonAttr] = str(jsonVal) + def _get_mstpctl_bridgeport_attr_from_cache(self, bridgename): + attrs = MSTPAttrsCache.get(bridgename) + if not attrs: + try: + cmd = ['/sbin/mstpctl', 'showportdetail', bridgename, 'json'] + output = self.subprocess_check_output(cmd) + if not output: + return None + except Exception as e: + self.logger.info(str(e)) + return None + mstpctl_bridgeport_attrs_dict = {} + try: + mstpctl_bridge_cache = json.loads(output.strip('\n')) + for portname in mstpctl_bridge_cache.keys(): + # we will ignore the portid for now and just index + # by bridgename, portname, and json attribute + for portid in mstpctl_bridge_cache[portname].keys(): + mstpctl_bridgeport_attrs_dict[portname] = {} + for jsonAttr in mstpctl_bridge_cache[portname][portid].keys(): + jsonVal = mstpctl_bridge_cache[portname][portid][jsonAttr] + mstpctl_bridgeport_attrs_dict[portname][jsonAttr] = str(jsonVal) + MSTPAttrsCache.set(bridgename, mstpctl_bridgeport_attrs_dict) + return mstpctl_bridgeport_attrs_dict + except Exception as e: + self.logger.info('%s: cannot fetch mstpctl bridge port attributes: %s', str(e)) + return attrs - def get_mstpctl_bridgeport_attr(self,bridgename=None, portname=None, - jsonAttr=None): - ''' - Just return the JSON attribute we cached earlier making - sure to convert integers to strings for later comparison. - ''' - if not bridgename or not portname or not jsonAttr: - return - # just return the value or None if there is no JSON attr defined the - # output will not show anything if the value is no so we default to no - val = self.mstpctl_bridgeport_attrs_dict.get(bridgename,{}).get(portname,{}).\ - get(jsonAttr,'no') - if val == 'True': - val = 'yes' - # some values are integers so we need to return only strings - return str(val) + def get_mstpctl_bridgeport_attr(self, bridgename, portname, attr): + attrs = self._get_mstpctl_bridgeport_attr_from_cache(bridgename) + if not attrs: + return 'no' + else: + val = attrs.get(portname,{}).get(attr, 'no') + if val == 'True': + val = 'yes' + return str(val) def set_bridgeport_attrs(self, bridgename, bridgeportname, attrdict, check=True): From 24aa45e5a3cce9ecd64aeb72f76992be64d3003b Mon Sep 17 00:00:00 2001 From: Julien Fortin Date: Fri, 29 Apr 2016 21:22:52 +0200 Subject: [PATCH 25/27] bridge: display warning when (in vlan unware bridge) an untagged bridge is not configured Ticket: CM-8173 Reviewed By: Roopa Testing Done: smoke + vlan aware and non-aware bridges with untagged bridge without untagged bridge. --- addons/bridge.py | 23 +++++++++++++++++------ ifupdown/ifupdownmain.py | 3 ++- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/addons/bridge.py b/addons/bridge.py index ac8ae67..c68cbd3 100644 --- a/addons/bridge.py +++ b/addons/bridge.py @@ -220,6 +220,12 @@ class bridge(moduleBase): else: self.default_stp_on = False + should_warn = policymanager.policymanager_api.\ + get_module_globals(module_name=self.__class__.__name__, + attr='warn_on_untagged_bridge_absence') + self.warn_on_untagged_bridge_absence = should_warn == 'yes' + + def _is_bridge(self, ifaceobj): if ifaceobj.get_attr_value_first('bridge-ports'): return True @@ -915,12 +921,7 @@ class bridge(moduleBase): def _apply_bridge_port_settings_all(self, ifaceobj, ifaceobj_getfunc=None): err = False - bridge_vlan_aware = ifaceobj.get_attr_value_first( - 'bridge-vlan-aware') - if bridge_vlan_aware and bridge_vlan_aware == 'yes': - bridge_vlan_aware = True - else: - bridge_vlan_aware = False + bridge_vlan_aware = ifaceobj.get_attr_value_first('bridge-vlan-aware') == 'yes' if (ifaceobj.get_attr_value_first('bridge-port-vids') and ifaceobj.get_attr_value_first('bridge-port-pvids')): @@ -978,6 +979,8 @@ class bridge(moduleBase): bportifaceobj, bridge_vids, bridge_pvid) self._apply_bridge_port_settings(bportifaceobj, bridgeifaceobj=ifaceobj) + elif self.warn_on_untagged_bridge_absence: + self._check_untagged_bridge(ifaceobj.name, bportifaceobj, ifaceobj_getfunc) except Exception, e: err = True self.logger.warn('%s: %s' %(ifaceobj.name, str(e))) @@ -985,6 +988,14 @@ class bridge(moduleBase): if err: raise Exception('%s: errors applying port settings' %ifaceobj.name) + def _check_untagged_bridge(self, bridgename, bridgeportifaceobj, ifaceobj_getfunc): + if bridgeportifaceobj.link_kind & ifaceLinkKind.VLAN: + lower_ifaceobj_list = ifaceobj_getfunc(bridgeportifaceobj.lowerifaces[0]) + if lower_ifaceobj_list and lower_ifaceobj_list[0] and \ + not lower_ifaceobj_list[0].link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT: + self.logger.warn('%s: untagged bridge not found. Please configure a bridge with untagged bridge ports to avoid Spanning Tree Interoperability issue.' % bridgename) + self.warn_on_untagged_bridge_absence = False + def _get_bridgename(self, ifaceobj): for u in ifaceobj.upperifaces: if self.ipcmd.is_bridge(u): diff --git a/ifupdown/ifupdownmain.py b/ifupdown/ifupdownmain.py index 36252c8..08558aa 100644 --- a/ifupdown/ifupdownmain.py +++ b/ifupdown/ifupdownmain.py @@ -1137,6 +1137,7 @@ class ifupdownMain(ifupdownBase): raise Exception() return + ret = None try: ret = self._sched_ifaces(filtered_ifacenames, ops, skipupperifaces=skipupperifaces, @@ -1569,8 +1570,8 @@ class ifupdownMain(ifupdownBase): followdependents=True if self.flags.WITH_DEPENDS else False) except Exception, e: + ret = None self.logger.error(str(e)) - pass finally: self._process_delay_admin_state_queue('up') if ifupdownflags.flags.DRYRUN: From 4bdf2d1cde1936d5908f317a9b9b19647224b516 Mon Sep 17 00:00:00 2001 From: Julien Fortin Date: Tue, 3 May 2016 17:40:30 +0200 Subject: [PATCH 26/27] Deprecating `mstpctl-stp` attribute Ticket: CM-10476 Reviewed By: Roopa Testing Done: Using mstpctl-stp attribute in a stanza will display a warning --- addons/mstpctl.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/addons/mstpctl.py b/addons/mstpctl.py index 522befe..fa18ab3 100644 --- a/addons/mstpctl.py +++ b/addons/mstpctl.py @@ -28,7 +28,9 @@ class mstpctl(moduleBase): 'mstpctl-stp' : {'help': 'bridge stp yes/no', 'compat' : True, - 'default' : 'no'}, + 'default' : 'no', + 'deprecated': True, + 'new-attribute': 'bridge-stp'}, 'mstpctl-treeprio' : {'help': 'tree priority', 'default' : '32768', From 612aadeac959475e7a1080b50eaea3cd1fef55fb Mon Sep 17 00:00:00 2001 From: Julien Fortin Date: Wed, 4 May 2016 20:17:17 +0200 Subject: [PATCH 27/27] debian: changelog: update for new release: 1.1-cl3u2 Signed-off-by: Julien Fortin --- debian/changelog | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/debian/changelog b/debian/changelog index 1ebd4f5..4098364 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,11 +1,20 @@ -ifupdown2 (1.1-cl3u2) UNRELEASED; urgency=medium +ifupdown2 (1.1-cl3u2) RELEASED; urgency=medium - * Dry-run upgrade test, will be replaced with proper text at the release time. + * Closes: CM-10478. checks for invalid address-virtual attributes + * New. Deprecated: `mstpctl-stp` attribute + * New. Deprecated: lacp parameters: bond-ad-sys-priority, bond-ad-sys-mac-addr + * New. Enabled: addon module for configuring vrf + * New. Enabled: bridge: display warning when (in vlan unware bridge) an untagged bridge is not configured + * New. Enabled: adjusting MTU for vlan devices depending on lower device mtu + * New. Enabled: introduce checks for reserved vrf table names + * New. Enabled: ifquery: new option '--with-defaults' to include default attributes + * New. Enabled: bridge: disabling ipv6 on bridge if any VXLAN port + * New. Enabled: vrf awareness in dhcp addon module - -- dev-support Tue, 19 Apr 2016 14:35:52 -0700 + -- dev-support Tue, 3 May 2016 14:42:42 -0700 ifupdown2 (1.1-cl3u1) unstable; urgency=low * Initial release. - -- Roopa Prabhu Thu, 20 Aug 2015 06:14:24 -0700 + -- dev-support Thu, 20 Aug 2015 06:14:24 -0700