]> git.proxmox.com Git - mirror_ifupdown2.git/blob - addons/dhcp.py
Merge pull request #80 from BarbarossaTM/tunnel-fixes-master
[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 dhclient4_running = self.dhclientcmd.is_running(ifaceobj.name)
42 dhclient6_running = self.dhclientcmd.is_running6(ifaceobj.name)
43
44 # today if we have an interface with both inet and inet6, if we
45 # remove the inet or inet6 or both then execute ifreload, we need
46 # to release/kill the appropriate dhclient(4/6) if they are running
47 self._down_stale_dhcp_config(ifaceobj, 'inet', dhclient4_running)
48 self._down_stale_dhcp_config(ifaceobj, 'inet6', dhclient6_running)
49
50 try:
51 dhclient_cmd_prefix = None
52 dhcp_wait = policymanager.policymanager_api.get_attr_default(
53 module_name=self.__class__.__name__, attr='dhcp-wait')
54 wait = not str(dhcp_wait).lower() == "no"
55 vrf = ifaceobj.get_attr_value_first('vrf')
56 if (vrf and self.vrf_exec_cmd_prefix and
57 self.ipcmd.link_exists(vrf)):
58 dhclient_cmd_prefix = '%s %s' %(self.vrf_exec_cmd_prefix, vrf)
59
60 if 'inet' in ifaceobj.addr_family:
61 if dhclient4_running:
62 self.logger.info('dhclient4 already running on %s. '
63 'Not restarting.' % ifaceobj.name)
64 else:
65 # First release any existing dhclient processes
66 try:
67 if not ifupdownflags.flags.PERFMODE:
68 self.dhclientcmd.stop(ifaceobj.name)
69 except:
70 pass
71 self.dhclientcmd.start(ifaceobj.name, wait=wait,
72 cmd_prefix=dhclient_cmd_prefix)
73 if 'inet6' in ifaceobj.addr_family:
74 if dhclient6_running:
75 self.logger.info('dhclient6 already running on %s. '
76 'Not restarting.' % ifaceobj.name)
77 else:
78 accept_ra = ifaceobj.get_attr_value_first('accept_ra')
79 if accept_ra:
80 # XXX: Validate value
81 self.sysctl_set('net.ipv6.conf.%s' %ifaceobj.name +
82 '.accept_ra', accept_ra)
83 autoconf = ifaceobj.get_attr_value_first('autoconf')
84 if autoconf:
85 # XXX: Validate value
86 self.sysctl_set('net.ipv6.conf.%s' %ifaceobj.name +
87 '.autoconf', autoconf)
88 try:
89 self.dhclientcmd.stop6(ifaceobj.name)
90 except:
91 pass
92 #add delay before starting IPv6 dhclient to
93 #make sure the configured interface/link is up.
94 time.sleep(2)
95 timeout = 10
96 while timeout:
97 timeout -= 2
98 addr_output = utils.exec_command('ip -6 addr show %s'
99 % ifaceobj.name)
100 r = re.search('inet6 .* scope link', addr_output)
101 if r:
102 self.dhclientcmd.start6(ifaceobj.name,
103 wait=wait,
104 cmd_prefix=dhclient_cmd_prefix)
105 return
106 time.sleep(2)
107
108 except Exception, e:
109 self.log_error(str(e), ifaceobj)
110
111 def _down_stale_dhcp_config(self, ifaceobj, family, dhclientX_running):
112 addr_family = ifaceobj.addr_family
113 try:
114 if not family in ifaceobj.addr_family and dhclientX_running:
115 ifaceobj.addr_family = [family]
116 self._dhcp_down(ifaceobj)
117 except:
118 pass
119 finally:
120 ifaceobj.addr_family = addr_family
121
122 def _dhcp_down(self, ifaceobj):
123 dhclient_cmd_prefix = None
124 vrf = ifaceobj.get_attr_value_first('vrf')
125 if (vrf and self.vrf_exec_cmd_prefix and
126 self.ipcmd.link_exists(vrf)):
127 dhclient_cmd_prefix = '%s %s' %(self.vrf_exec_cmd_prefix, vrf)
128 if 'inet6' in ifaceobj.addr_family:
129 self.dhclientcmd.release6(ifaceobj.name, dhclient_cmd_prefix)
130 if 'inet' in ifaceobj.addr_family:
131 self.dhclientcmd.release(ifaceobj.name, dhclient_cmd_prefix)
132
133 def _down(self, ifaceobj):
134 self._dhcp_down(ifaceobj)
135 self.ipcmd.link_down(ifaceobj.name)
136
137 def _query_check(self, ifaceobj, ifaceobjcurr):
138 status = ifaceStatus.SUCCESS
139 dhcp_running = False
140
141 dhcp_v4 = self.dhclientcmd.is_running(ifaceobjcurr.name)
142 dhcp_v6 = self.dhclientcmd.is_running6(ifaceobjcurr.name)
143
144 if dhcp_v4:
145 dhcp_running = True
146 if 'inet' not in ifaceobj.addr_family and not dhcp_v6:
147 status = ifaceStatus.ERROR
148 ifaceobjcurr.addr_method = 'dhcp'
149 if dhcp_v6:
150 dhcp_running = True
151 if 'inet6' not in ifaceobj.addr_family and not dhcp_v4:
152 status = ifaceStatus.ERROR
153 ifaceobjcurr.addr_method = 'dhcp'
154 ifaceobjcurr.addr_family = ifaceobj.addr_family
155 if not dhcp_running:
156 ifaceobjcurr.addr_family = []
157 status = ifaceStatus.ERROR
158 ifaceobjcurr.status = status
159
160 def _query_running(self, ifaceobjrunning):
161 if not self.ipcmd.link_exists(ifaceobjrunning.name):
162 return
163 if self.dhclientcmd.is_running(ifaceobjrunning.name):
164 ifaceobjrunning.addr_family.append('inet')
165 ifaceobjrunning.addr_method = 'dhcp'
166 if self.dhclientcmd.is_running6(ifaceobjrunning.name):
167 ifaceobjrunning.addr_family.append('inet6')
168 ifaceobjrunning.addr_method = 'dhcp6'
169
170 _run_ops = {'up' : _up,
171 'down' : _down,
172 'pre-down' : _down,
173 'query-checkcurr' : _query_check,
174 'query-running' : _query_running }
175
176 def get_ops(self):
177 """ returns list of ops supported by this module """
178 return self._run_ops.keys()
179
180 def _init_command_handlers(self):
181 if not self.ipcmd:
182 self.ipcmd = iproute2()
183
184 def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
185 """ run dhcp configuration on the interface object passed as argument
186
187 Args:
188 **ifaceobj** (object): iface object
189
190 **operation** (str): any of 'up', 'down', 'query-checkcurr',
191 'query-running'
192
193 Kwargs:
194 **query_ifaceobj** (object): query check ifaceobject. This is only
195 valid when op is 'query-checkcurr'. It is an object same as
196 ifaceobj, but contains running attribute values and its config
197 status. The modules can use it to return queried running state
198 of interfaces. status is success if the running state is same
199 as user required state in ifaceobj. error otherwise.
200 """
201 op_handler = self._run_ops.get(operation)
202 if not op_handler:
203 return
204 try:
205 if (operation != 'query-running' and
206 (ifaceobj.addr_method != 'dhcp' and
207 ifaceobj.addr_method != 'dhcp6')):
208 return
209 except:
210 return
211 if not self.is_dhcp_allowed_on(ifaceobj, syntax_check=False):
212 return
213 self._init_command_handlers()
214 if operation == 'query-checkcurr':
215 op_handler(self, ifaceobj, query_ifaceobj)
216 else:
217 op_handler(self, ifaceobj)