]> git.proxmox.com Git - mirror_ifupdown2.git/blame - sbin/ifupdown
Document ifreload new option + add it into init.d networking script
[mirror_ifupdown2.git] / sbin / ifupdown
CommitLineData
a6f80f0e 1#!/usr/bin/python
904908bc
RP
2#
3# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
4# Author: Roopa Prabhu, roopa@cumulusnetworks.com
5#
6# ifupdown --
7# tool to configure network interfaces
8#
a6f80f0e 9import sys
10import os
e6c9d007 11import argcomplete
a6f80f0e 12import argparse
14dc390d 13import ConfigParser
14import StringIO
a6f80f0e 15import logging
261379f0 16import logging.handlers
61636dcc 17import resource
d40e96ee 18from ifupdown.ifupdownmain import *
19from ifupdown.utils import *
a6f80f0e 20
21lockfile="/run/network/.lock"
14dc390d 22configfile="/etc/network/ifupdown2/ifupdown2.conf"
23configmap_g=None
a6f80f0e 24logger = None
3dcc1d0e 25interfacesfileiobuf=None
03d5166b 26ENVPATH = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
a6f80f0e 27
f802fe3c 28def run_up(args):
a6f80f0e 29 logger.debug('args = %s' %str(args))
30
31 try:
739f665b 32 iflist = args.iflist
33 if len(args.iflist) == 0:
34 iflist = None
a6f80f0e 35 logger.debug('creating ifupdown object ..')
f802fe3c 36 cachearg=(False if (iflist or args.nocache or
d08d5f54 37 args.perfmode or args.noact)
38 else True)
14dc390d 39 ifupdown_handle = ifupdownMain(config=configmap_g,
40 force=args.force,
f802fe3c 41 withdepends=args.withdepends,
42 perfmode=args.perfmode,
f802fe3c 43 dryrun=args.noact,
20dd6242 44 cache=cachearg,
45 addons_enable=not args.noaddons,
14dc390d 46 statemanager_enable=not args.noaddons,
3dcc1d0e 47 interfacesfile=args.interfacesfile,
48 interfacesfileiobuf=interfacesfileiobuf,
49 interfacesfileformat=args.interfacesfileformat)
20dd6242 50 if args.noaddons:
51 ifupdown_handle.up(['up'], args.all, args.CLASS, iflist,
52 excludepats=args.excludepats,
9dce3561 53 printdependency=args.printdependency,
ad25e7bb
RP
54 syntaxcheck=args.syntaxcheck, type=args.type,
55 skipupperifaces=args.skipupperifaces)
20dd6242 56 else:
57 ifupdown_handle.up(['pre-up', 'up', 'post-up'],
d08d5f54 58 args.all, args.CLASS, iflist,
739f665b 59 excludepats=args.excludepats,
9dce3561 60 printdependency=args.printdependency,
ad25e7bb
RP
61 syntaxcheck=args.syntaxcheck, type=args.type,
62 skipupperifaces=args.skipupperifaces)
f802fe3c 63 except:
64 raise
739f665b 65
f802fe3c 66def run_down(args):
67 logger.debug('args = %s' %str(args))
68
69 try:
70 iflist = args.iflist
f802fe3c 71 logger.debug('creating ifupdown object ..')
14dc390d 72 ifupdown_handle = ifupdownMain(config=configmap_g, force=args.force,
f802fe3c 73 withdepends=args.withdepends,
74 perfmode=args.perfmode,
f802fe3c 75 dryrun=args.noact,
20dd6242 76 addons_enable=not args.noaddons,
14dc390d 77 statemanager_enable=not args.noaddons,
3dcc1d0e 78 interfacesfile=args.interfacesfile,
79 interfacesfileiobuf=interfacesfileiobuf,
80 interfacesfileformat=args.interfacesfileformat)
f802fe3c 81
82 ifupdown_handle.down(['pre-down', 'down', 'post-down'],
83 args.all, args.CLASS, iflist,
84 excludepats=args.excludepats,
5c721925 85 printdependency=args.printdependency,
2da58137
RP
86 usecurrentconfig=args.usecurrentconfig,
87 type=args.type)
f802fe3c 88 except:
89 raise
90
91def run_query(args):
92 logger.debug('args = %s' %str(args))
93
94 try:
95 iflist = args.iflist
f802fe3c 96 if args.checkcurr:
97 qop='query-checkcurr'
98 elif args.running:
f802fe3c 99 qop='query-running'
100 elif args.raw:
101 qop='query-raw'
102 elif args.syntaxhelp:
103 qop = 'query-syntax'
104 elif args.printdependency:
105 qop = 'query-dependency'
5c721925 106 elif args.printsavedstate:
107 qop = 'query-savedstate'
f802fe3c 108 else:
109 qop='query'
83c1f241 110 cachearg=(False if (iflist or args.nocache or
111 args.perfmode or args.syntaxhelp or
112 (qop != 'query-checkcurr' and
113 qop != 'query-running')) else True)
c798b0f4 114 if not iflist and qop == 'query-running':
115 iflist = [i for i in os.listdir('/sys/class/net/')
116 if os.path.isdir('/sys/class/net/%s' %i)]
83c1f241 117 logger.debug('creating ifupdown object ..')
14dc390d 118 ifupdown_handle = ifupdownMain(config=configmap_g,
119 withdepends=args.withdepends,
83c1f241 120 perfmode=args.perfmode,
14dc390d 121 cache=cachearg,
3dcc1d0e 122 interfacesfile=args.interfacesfile,
123 interfacesfileiobuf=interfacesfileiobuf,
124 interfacesfileformat=args.interfacesfileformat)
83c1f241 125
f802fe3c 126 ifupdown_handle.query([qop], args.all, args.CLASS, iflist,
127 excludepats=args.excludepats,
128 printdependency=args.printdependency,
2da58137 129 format=args.format, type=args.type)
f802fe3c 130 except:
131 raise
132
f802fe3c 133def run_reload(args):
134 logger.debug('args = %s' %str(args))
135
136 try:
137 logger.debug('creating ifupdown object ..')
14dc390d 138 ifupdown_handle = ifupdownMain(config=configmap_g,
139 withdepends=args.withdepends,
140 perfmode=args.perfmode)
20dd6242 141 ifupdown_handle.reload(['pre-up', 'up', 'post-up'],
142 ['pre-down', 'down', 'post-down'],
97382e88 143 auto=args.all, allow=None, ifacenames=None,
14dc390d 144 excludepats=args.excludepats,
2da58137
RP
145 usecurrentconfig=args.usecurrentconfig,
146 currentlyup=args.currentlyup)
a6f80f0e 147 except:
148 raise
149
a6f80f0e 150def init(args):
151 global logger
3dcc1d0e 152 global interfacesfileiobuf
a6f80f0e 153
154 log_level = logging.WARNING
fe0a57d3 155 if args.verbose:
a6f80f0e 156 log_level = logging.INFO
fe0a57d3 157 if args.debug:
a6f80f0e 158 log_level = logging.DEBUG
159
160 try:
261379f0
RP
161 if hasattr(args, 'syslog') and args.syslog:
162 root_logger = logging.getLogger()
163 syslog_handler = logging.handlers.SysLogHandler(address='/dev/log',
164 facility=logging.handlers.SysLogHandler.LOG_DAEMON)
165 logging.addLevelName(logging.ERROR, 'error')
166 logging.addLevelName(logging.WARNING, 'warning')
167 logging.addLevelName(logging.DEBUG, 'debug')
168 logging.addLevelName(logging.INFO, 'info')
169 root_logger.setLevel(log_level)
170 syslog_handler.setFormatter(logging.Formatter(
171 '%(name)s: %(levelname)s: %(message)s'))
172 root_logger.addHandler(syslog_handler)
173 logger = logging.getLogger('ifupdown')
174 else:
175 logging.basicConfig(level=log_level,
176 format='%(levelname)s: %(message)s')
177 logging.addLevelName(logging.ERROR, 'error')
178 logging.addLevelName(logging.WARNING, 'warning')
179 logging.addLevelName(logging.DEBUG, 'debug')
180 logging.addLevelName(logging.INFO, 'info')
181 logger = logging.getLogger('ifupdown')
a6f80f0e 182 except:
183 raise
184
3dcc1d0e 185 # If interfaces file is stdin, read
186 if hasattr(args, 'interfacesfile') and args.interfacesfile == '-':
187 interfacesfileiobuf = sys.stdin.read()
a6f80f0e 188
189def deinit():
eab25b7c 190 {}
a6f80f0e 191
192def update_argparser(argparser):
cca03c30 193 """ base parser, common to all commands """
37c0543d 194
195 argparser.add_argument('-a', '--all', action='store_true', required=False,
cca03c30 196 help='process all interfaces marked \"auto\"')
a6f80f0e 197 argparser.add_argument('iflist', metavar='IFACE',
f802fe3c 198 nargs='*', help='interface list separated by spaces. ' +
199 'IFACE list is mutually exclusive with -a option.')
a6f80f0e 200 argparser.add_argument('-v', '--verbose', dest='verbose',
201 action='store_true', help='verbose')
202 argparser.add_argument('-d', '--debug', dest='debug',
203 action='store_true',
204 help='output debug info')
205 argparser.add_argument('-q', '--quiet', dest='quiet',
206 action='store_true',
207 help=argparse.SUPPRESS)
eab25b7c 208 argparser.add_argument('--allow', dest='CLASS',
209 help='ignore non-\"allow-CLASS\" interfaces')
14dc390d 210 argparser.add_argument('-w', '--with-depends', dest='withdepends',
f802fe3c 211 action='store_true', help='run with all dependent interfaces.'+
212 ' This option is redundant when \'-a\' is specified. With ' +
213 '\'-a\' interfaces are always executed in dependency order')
3e8ee54f 214 argparser.add_argument('--perfmode', dest='perfmode',
eab25b7c 215 action='store_true', help=argparse.SUPPRESS)
14dc390d 216 #argparser.add_argument('-j', '--jobs', dest='jobs', type=int,
217 # default=-1, choices=range(1,12), help=argparse.SUPPRESS)
739f665b 218 argparser.add_argument('--nocache', dest='nocache', action='store_true',
219 help=argparse.SUPPRESS)
3e8ee54f 220 argparser.add_argument('-X', '--exclude', dest='excludepats',
37c0543d 221 action='append',
222 help='Exclude interfaces from the list of interfaces' +
f802fe3c 223 ' to operate on. Can be specified multiple times.')
14dc390d 224 argparser.add_argument('-i', '--interfaces', dest='interfacesfile',
225 default='/etc/network/interfaces',
226 help='use interfaces file instead of default ' +
227 '/etc/network/interfaces')
3dcc1d0e 228 argparser.add_argument('-t', '--interfaces-format',
229 dest='interfacesfileformat',
230 default='native',
231 choices=['native', 'json'],
232 help='interfaces file format')
2da58137
RP
233 argparser.add_argument('-T', '--type',
234 dest='type',
235 default=None,
236 choices=['iface', 'vlan'],
237 help='type of interface entry (iface or vlan).' +
238 'This option can be used in case of ambiguity between ' +
239 'a vlan interface and an iface interface of the same name')
a6f80f0e 240
241def update_ifupdown_argparser(argparser):
cca03c30 242 """ common arg parser for ifup and ifdown """
a6f80f0e 243 argparser.add_argument('-f', '--force', dest='force',
244 action='store_true',
245 help='force run all operations')
261379f0
RP
246 argparser.add_argument('-l', '--syslog', dest='syslog',
247 action='store_true',
248 help=argparse.SUPPRESS)
5c721925 249 group = argparser.add_mutually_exclusive_group(required=False)
250 group.add_argument('-n', '--no-act', dest='noact',
3e8ee54f 251 action='store_true', help='print out what would happen,' +
252 'but don\'t do it')
14dc390d 253 group.add_argument('-p', '--print-dependency',
cca03c30 254 dest='printdependency', choices=['list', 'dot'],
255 help='print iface dependency')
d40e96ee 256 group.add_argument('--no-scripts', '--admin-state',
20dd6242 257 dest='noaddons', action='store_true',
14dc390d 258 help='dont run any addon modules/scripts. Only bring the ' +
259 'interface administratively up/down')
a6f80f0e 260
261def update_ifup_argparser(argparser):
9dce3561 262 argparser.add_argument('-s', '--syntax-check', dest='syntaxcheck',
263 action='store_true',
264 help='Only run the interfaces file parser')
ad25e7bb
RP
265 argparser.add_argument('-k', '--skip-upperifaces', dest='skipupperifaces',
266 action='store_true',
267 help='ifup by default tries to add newly created interfaces' +
268 ' into its upper/parent interfaces. Eg. if a bridge port is' +
269 ' created as a result of ifup on the port, ifup automatically' +
270 ' adds the port to the bridge. This option can be used to ' +
271 'disable this default behaviour')
a6f80f0e 272 update_ifupdown_argparser(argparser)
273
274def update_ifdown_argparser(argparser):
275 update_ifupdown_argparser(argparser)
522bf8e6 276 argparser.add_argument('-u', '--use-current-config',
5c721925 277 dest='usecurrentconfig', action='store_true',
14dc390d 278 help='By default ifdown looks at the saved state for ' +
279 'interfaces to bring down. This option allows ifdown to ' +
280 'look at the current interfaces file. Useful when your ' +
281 'state file is corrupted or you want down to use the latest '
282 'from the interfaces file')
a6f80f0e 283
284def update_ifquery_argparser(argparser):
cca03c30 285 """ arg parser for ifquery options """
286
37c0543d 287 # -l is same as '-a', only here for backward compatibility
3e8ee54f 288 argparser.add_argument('-l', '--list', action='store_true', dest='all',
cca03c30 289 help=argparse.SUPPRESS)
a6f80f0e 290 group = argparser.add_mutually_exclusive_group(required=False)
360d5f8e 291 group.add_argument('-r', '--running', dest='running',
eab25b7c 292 action='store_true',
293 help='query running state of an interface')
360d5f8e 294 group.add_argument('-c', '--check', dest='checkcurr',
739f665b 295 action='store_true',
360d5f8e 296 help='check interface file contents against ' +
297 'running state of an interface')
51a80991 298 group.add_argument('-x', '--raw', action='store_true', dest='raw',
d08d5f54 299 help='print raw config file entries')
5c721925 300 group.add_argument('--print-savedstate', action='store_true',
301 dest='printsavedstate',
302 help=argparse.SUPPRESS)
522bf8e6 303 argparser.add_argument('-o', '--format', dest='format', default='native',
14dc390d 304 choices=['native', 'json'],
305 help='interface display format')
306 argparser.add_argument('-p', '--print-dependency',
d08d5f54 307 dest='printdependency', choices=['list', 'dot'],
308 help='print interface dependency')
14dc390d 309 argparser.add_argument('-s', '--syntax-help', action='store_true',
d08d5f54 310 dest='syntaxhelp',
311 help='print supported interface config syntax')
37c0543d 312
739f665b 313def update_ifreload_argparser(argparser):
f802fe3c 314 """ parser for ifreload """
2da58137
RP
315 group = argparser.add_mutually_exclusive_group(required=True)
316 group.add_argument('-a', '--all', action='store_true',
f802fe3c 317 help='process all interfaces marked \"auto\"')
2da58137
RP
318 group.add_argument('-c', '--currently-up', dest='currentlyup',
319 action='store_true',
320 help='only reload auto and other interfaces that are ' +
321 'currently up')
f802fe3c 322 argparser.add_argument('iflist', metavar='IFACE',
323 nargs='*', help=argparse.SUPPRESS)
324 argparser.add_argument('-n', '--no-act', dest='noact',
325 action='store_true', help=argparse.SUPPRESS)
326 argparser.add_argument('-v', '--verbose', dest='verbose',
327 action='store_true', help='verbose')
328 argparser.add_argument('-d', '--debug', dest='debug',
37c0543d 329 action='store_true',
f802fe3c 330 help='output debug info')
14dc390d 331 argparser.add_argument('-w', '--with-depends', dest='withdepends',
f802fe3c 332 action='store_true', help=argparse.SUPPRESS)
333 argparser.add_argument('--perfmode', dest='perfmode',
334 action='store_true', help=argparse.SUPPRESS)
335 argparser.add_argument('--nocache', dest='nocache', action='store_true',
336 help=argparse.SUPPRESS)
337 argparser.add_argument('-X', '--exclude', dest='excludepats',
338 action='append',
339 help=argparse.SUPPRESS)
14dc390d 340 #argparser.add_argument('-j', '--jobs', dest='jobs', type=int,
341 # default=-1, choices=range(1,12), help=argparse.SUPPRESS)
3dcc1d0e 342 #argparser.add_argument('-i', '--interfaces', dest='interfacesfile',
343 # default='/etc/network/interfaces',
344 # help='use interfaces file instead of default ' +
345 # '/etc/network/interfaces')
522bf8e6 346 argparser.add_argument('-u', '--use-current-config',
14dc390d 347 dest='usecurrentconfig', action='store_true',
348 help='By default ifreload looks at saved state for ' +
349 'interfaces to bring down. With this option ifreload will'
350 ' only look at the current interfaces file. Useful when your ' +
351 'state file is corrupted or you want down to use the latest '
352 'from the interfaces file')
261379f0
RP
353 argparser.add_argument('-l', '--syslog', dest='syslog',
354 action='store_true',
355 help=argparse.SUPPRESS)
d462f1fa
RP
356 argparser.add_argument('-f', '--force', dest='force',
357 action='store_true',
358 help='force run all operations')
37c0543d 359
a6f80f0e 360def parse_args(argsv, op):
cca03c30 361 if op == 'query':
37c0543d 362 descr = 'query interfaces (all or interface list)'
91067b3d 363 elif op == 'reload':
364 descr = 'reload interface configuration.'
cca03c30 365 else:
366 descr = 'interface management'
a6f80f0e 367 argparser = argparse.ArgumentParser(description=descr)
f802fe3c 368 if op == 'reload':
739f665b 369 update_ifreload_argparser(argparser)
f802fe3c 370 else:
371 update_argparser(argparser)
372 if op == 'up':
373 update_ifup_argparser(argparser)
374 elif op == 'down':
375 update_ifdown_argparser(argparser)
376 elif op == 'query':
377 update_ifquery_argparser(argparser)
378 elif op == 'reload':
379 update_ifreload_argparser(argparser)
e6c9d007 380 argcomplete.autocomplete(argparser)
a6f80f0e 381 return argparser.parse_args(argsv)
382
f802fe3c 383handlers = {'up' : run_up,
384 'down' : run_down,
385 'query' : run_query,
386 'reload' : run_reload }
387
9dce3561 388def validate_args(op, args):
3dcc1d0e 389 #if op == 'up' and args.syntaxcheck:
390 # if args.iflist or args.all:
391 # print 'ignoring interface options ..'
392 # return True
9dce3561 393 if op == 'query' and args.syntaxhelp:
394 return True
fffdae9c 395 if op == 'reload':
2da58137
RP
396 if not args.all and not args.currentlyup:
397 print '\'-a\' or \'-c\' option is required'
fffdae9c
RP
398 return False
399 elif (not args.iflist and
400 not args.all and not args.CLASS):
9dce3561 401 print '\'-a\' option or interface list are required'
402 return False
403 if args.iflist and args.all:
404 print '\'-a\' option and interface list are mutually exclusive'
405 return False
fffdae9c 406 if op != 'reload' and args.CLASS and (args.all or args.iflist):
5ee3e1a8
RP
407 print ('\'--allow\' option is mutually exclusive ' +
408 'with interface list and \'-a\'')
409 return False
9dce3561 410 return True
411
cebe79c9 412def read_config(args):
14dc390d 413 global configmap_g
414
415 config = open(configfile, 'r').read()
416 configStr = '[ifupdown2]\n' + config
417 configFP = StringIO.StringIO(configStr)
418 parser = ConfigParser.RawConfigParser()
419 parser.readfp(configFP)
420 configmap_g = dict(parser.items('ifupdown2'))
421
8e113d63
RP
422 # Preprocess config map
423 configval = configmap_g.get('multiple_vlan_aware_bridge_support', '0')
424 if configval == '0':
425 # if multiple bridges not allowed, set the bridge-vlan-aware
426 # attribute in the 'no_repeats' config, so that the ifupdownmain
427 # module can catch it appropriately
428 configmap_g['no_repeats'] = {'bridge-vlan-aware' : 'yes'}
429
cebe79c9
RP
430
431 configval = configmap_g.get('link_master_slave', '0')
432 if configval == '1':
433 # link_master_slave is only valid when all is set
434 if hasattr(args, 'all') and not args.all:
435 configmap_g['link_master_slave'] = '0'
436
437 configval = configmap_g.get('delay_admin_state_change', '0')
438 if configval == '1':
439 # reset link_master_slave if delay_admin_state_change is on
440 configmap_g['link_master_slave'] = '0'
441
a6f80f0e 442def main(argv):
443 """ main function """
f802fe3c 444 args = None
a6f80f0e 445 try:
446 op = None
fe0a57d3 447 if argv[0].endswith('ifup'):
a6f80f0e 448 op = 'up'
fe0a57d3 449 elif argv[0].endswith('ifdown'):
a6f80f0e 450 op = 'down'
fe0a57d3 451 elif argv[0].endswith('ifquery'):
a6f80f0e 452 op = 'query'
fe0a57d3 453 elif argv[0].endswith('ifreload'):
739f665b 454 op = 'reload'
a6f80f0e 455 else:
456 print ('Unexpected executable.' +
457 ' Should be \'ifup\' or \'ifdown\' or \'ifquery\'')
458 exit(1)
a6f80f0e 459 # Command line arg parser
460 args = parse_args(argv[1:], op)
9dce3561 461 if not validate_args(op, args):
a6f80f0e 462 exit(1)
522bf8e6
RP
463
464 if not sys.argv[0].endswith('ifquery') and not os.geteuid() == 0:
465 print 'error: must be root to run this command'
466 exit(1)
467
468 if not sys.argv[0].endswith('ifquery') and not utils.lockFile(lockfile):
469 print 'Another instance of this program is already running.'
470 exit(0)
471
cebe79c9 472 read_config(args)
a6f80f0e 473 init(args)
f802fe3c 474 handlers.get(op)(args)
a6f80f0e 475 except Exception, e:
fe0a57d3 476 if not str(e):
eab25b7c 477 exit(1)
f802fe3c 478 if args and args.debug:
a6f80f0e 479 raise
480 else:
f802fe3c 481 if logger:
482 logger.error(str(e))
483 else:
484 print str(e)
86fc62e2 485 #if args and not args.debug:
486 # print '\nrerun the command with \'-d\' for a detailed errormsg'
eab25b7c 487 exit(1)
a6f80f0e 488 finally:
489 deinit()
490
a6f80f0e 491if __name__ == "__main__":
492
03d5166b 493 # required during boot
494 os.putenv('PATH', ENVPATH)
61636dcc 495 resource.setrlimit(resource.RLIMIT_CORE, (0,0))
a6f80f0e 496 main(sys.argv)