]> git.proxmox.com Git - mirror_ifupdown2.git/blob - addons/dhcp.py
addons: dhcp: check if iface has link-local address before starting dhclient6
[mirror_ifupdown2.git] / addons / dhcp.py
1 #!/usr/bin/python
2 #
3 # Copyright 2014 Cumulus Networks, Inc. All rights reserved.
4 # Author: Roopa Prabhu, roopa@cumulusnetworks.com
5 #
6
7 try:
8 import re
9 from ipaddr import IPNetwork
10 from sets import Set
11 from ifupdown.iface import *
12 import ifupdown.policymanager as policymanager
13 from ifupdownaddons.modulebase import moduleBase
14 from ifupdownaddons.dhclient import dhclient
15 from ifupdownaddons.iproute2 import iproute2
16 import ifupdown.ifupdownflags as ifupdownflags
17 from ifupdown.utils import utils
18 import time
19 from ifupdown.netlink import netlink
20 except ImportError, e:
21 raise ImportError (str(e) + "- required module not found")
22
23 class dhcp(moduleBase):
24 """ ifupdown2 addon module to configure dhcp on interface """
25
26 def __init__(self, *args, **kargs):
27 moduleBase.__init__(self, *args, **kargs)
28 self.dhclientcmd = dhclient(**kargs)
29 self.ipcmd = None
30
31 def syntax_check(self, ifaceobj, ifaceobj_getfunc):
32 return self.is_dhcp_allowed_on(ifaceobj, syntax_check=True)
33
34 def is_dhcp_allowed_on(self, ifaceobj, syntax_check):
35 if ifaceobj.addr_method and 'dhcp' in ifaceobj.addr_method:
36 return utils.is_addr_ip_allowed_on(ifaceobj, syntax_check=True)
37 return True
38
39 def _up(self, ifaceobj):
40 # if dhclient is already running do not stop and start it
41 if self.dhclientcmd.is_running(ifaceobj.name) or \
42 self.dhclientcmd.is_running6(ifaceobj.name):
43 self.logger.info('dhclient already running on %s. Not restarting.' % \
44 ifaceobj.name)
45 return
46 try:
47 dhclient_cmd_prefix = None
48 dhcp_wait = policymanager.policymanager_api.get_attr_default(
49 module_name=self.__class__.__name__, attr='dhcp-wait')
50 wait = not str(dhcp_wait).lower() == "no"
51 vrf = ifaceobj.get_attr_value_first('vrf')
52 if (vrf and self.vrf_exec_cmd_prefix and
53 self.ipcmd.link_exists(vrf)):
54 dhclient_cmd_prefix = '%s %s' %(self.vrf_exec_cmd_prefix, vrf)
55
56 if 'inet' in ifaceobj.addr_family:
57 # First release any existing dhclient processes
58 try:
59 if not ifupdownflags.flags.PERFMODE:
60 self.dhclientcmd.stop(ifaceobj.name)
61 except:
62 pass
63 self.dhclientcmd.start(ifaceobj.name, wait=wait,
64 cmd_prefix=dhclient_cmd_prefix)
65 if 'inet6' in ifaceobj.addr_family:
66 accept_ra = ifaceobj.get_attr_value_first('accept_ra')
67 if accept_ra:
68 # XXX: Validate value
69 self.sysctl_set('net.ipv6.conf.%s' %ifaceobj.name +
70 '.accept_ra', accept_ra)
71 autoconf = ifaceobj.get_attr_value_first('autoconf')
72 if autoconf:
73 # XXX: Validate value
74 self.sysctl_set('net.ipv6.conf.%s' %ifaceobj.name +
75 '.autoconf', autoconf)
76 try:
77 self.dhclientcmd.stop6(ifaceobj.name)
78 except:
79 pass
80 #add delay before starting IPv6 dhclient to
81 #make sure the configured interface/link is up.
82 time.sleep(2)
83 timeout = 10
84 while timeout:
85 timeout -= 2
86 addr_output = utils.exec_command('ip -6 addr show %s'
87 % ifaceobj.name)
88 r = re.search('inet6 .* scope link', addr_output)
89 if r:
90 self.dhclientcmd.start6(ifaceobj.name,
91 wait=wait,
92 cmd_prefix=dhclient_cmd_prefix)
93 return
94 time.sleep(2)
95
96
97 except Exception, e:
98 self.log_error(str(e), ifaceobj)
99
100 def _down(self, ifaceobj):
101 dhclient_cmd_prefix = None
102 vrf = ifaceobj.get_attr_value_first('vrf')
103 if (vrf and self.vrf_exec_cmd_prefix and
104 self.ipcmd.link_exists(vrf)):
105 dhclient_cmd_prefix = '%s %s' %(self.vrf_exec_cmd_prefix, vrf)
106 if 'inet6' in ifaceobj.addr_family:
107 self.dhclientcmd.release6(ifaceobj.name, dhclient_cmd_prefix)
108 if 'inet' in ifaceobj.addr_family:
109 self.dhclientcmd.release(ifaceobj.name, dhclient_cmd_prefix)
110 self.ipcmd.link_down(ifaceobj.name)
111
112 def _query_check(self, ifaceobj, ifaceobjcurr):
113 status = ifaceStatus.SUCCESS
114 dhcp_running = False
115
116 dhcp_v4 = self.dhclientcmd.is_running(ifaceobjcurr.name)
117 dhcp_v6 = self.dhclientcmd.is_running6(ifaceobjcurr.name)
118
119 if dhcp_v4:
120 dhcp_running = True
121 if 'inet' not in ifaceobj.addr_family and not dhcp_v6:
122 status = ifaceStatus.ERROR
123 ifaceobjcurr.addr_method = 'dhcp'
124 if dhcp_v6:
125 dhcp_running = True
126 if 'inet6' not in ifaceobj.addr_family and not dhcp_v4:
127 status = ifaceStatus.ERROR
128 ifaceobjcurr.addr_method = 'dhcp'
129 ifaceobjcurr.addr_family = ifaceobj.addr_family
130 if not dhcp_running:
131 ifaceobjcurr.addr_family = []
132 status = ifaceStatus.ERROR
133 ifaceobjcurr.status = status
134
135 def _query_running(self, ifaceobjrunning):
136 if not self.ipcmd.link_exists(ifaceobjrunning.name):
137 return
138 if self.dhclientcmd.is_running(ifaceobjrunning.name):
139 ifaceobjrunning.addr_family.append('inet')
140 ifaceobjrunning.addr_method = 'dhcp'
141 if self.dhclientcmd.is_running6(ifaceobjrunning.name):
142 ifaceobjrunning.addr_family.append('inet6')
143 ifaceobjrunning.addr_method = 'dhcp6'
144
145 _run_ops = {'up' : _up,
146 'down' : _down,
147 'pre-down' : _down,
148 'query-checkcurr' : _query_check,
149 'query-running' : _query_running }
150
151 def get_ops(self):
152 """ returns list of ops supported by this module """
153 return self._run_ops.keys()
154
155 def _init_command_handlers(self):
156 if not self.ipcmd:
157 self.ipcmd = iproute2()
158
159 def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
160 """ run dhcp configuration on the interface object passed as argument
161
162 Args:
163 **ifaceobj** (object): iface object
164
165 **operation** (str): any of 'up', 'down', 'query-checkcurr',
166 'query-running'
167
168 Kwargs:
169 **query_ifaceobj** (object): query check ifaceobject. This is only
170 valid when op is 'query-checkcurr'. It is an object same as
171 ifaceobj, but contains running attribute values and its config
172 status. The modules can use it to return queried running state
173 of interfaces. status is success if the running state is same
174 as user required state in ifaceobj. error otherwise.
175 """
176 op_handler = self._run_ops.get(operation)
177 if not op_handler:
178 return
179 try:
180 if (operation != 'query-running' and
181 (ifaceobj.addr_method != 'dhcp' and
182 ifaceobj.addr_method != 'dhcp6')):
183 return
184 except:
185 return
186 if not self.is_dhcp_allowed_on(ifaceobj, syntax_check=False):
187 return
188 self._init_command_handlers()
189 if operation == 'query-checkcurr':
190 op_handler(self, ifaceobj, query_ifaceobj)
191 else:
192 op_handler(self, ifaceobj)