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