blob: 34f63e58ab3225704fe89f256333e66fa8909e8b [file] [log] [blame]
Hariharasubramanian Rcd387972016-01-20 07:19:41 -06001#!/usr/bin/env python
2
Hariharasubramanian R308cffc2016-03-03 09:35:16 -06003from subprocess import call, Popen, PIPE
Edward A. James75757c02016-07-15 09:11:18 -05004from IPy import IP
Hariharasubramanian Rcd387972016-01-20 07:19:41 -06005import sys
6import subprocess
7import dbus
8import string
Hariharasubramanian R308cffc2016-03-03 09:35:16 -06009import socket
10import re
Hariharasubramanian Rcd387972016-01-20 07:19:41 -060011import os
12import fcntl
13import glib
14import gobject
15import dbus.service
16import dbus.mainloop.glib
17
18DBUS_NAME = 'org.openbmc.NetworkManager'
19OBJ_NAME = '/org/openbmc/NetworkManager/Interface'
20
21network_providers = {
Adriana Kobylak88c733b2016-02-03 16:46:58 -060022 'networkd' : {
23 'bus_name' : 'org.freedesktop.network1',
24 'ip_object_name' : '/org/freedesktop/network1/network/default',
25 'hw_object_name' : '/org/freedesktop/network1/link/_31',
Hariharasubramanian R3a224e72016-02-10 12:32:08 -060026 'ip_if_name' : 'org.freedesktop.network1.Network',
27 'hw_if_name' : 'org.freedesktop.network1.Link',
Adriana Kobylak88c733b2016-02-03 16:46:58 -060028 'method' : 'org.freedesktop.network1.Network.SetAddr'
29 },
30 'NetworkManager' : {
31 'bus_name' : 'org.freedesktop.NetworkManager',
32 'ip_object_name' : '/org/freedesktop/NetworkManager',
33 'hw_object_name' : '/org/freedesktop/NetworkManager',
Hariharasubramanian R3a224e72016-02-10 12:32:08 -060034 'ip_if_name' : 'org.freedesktop.NetworkManager',
35 'hw_if_name' : 'org.freedesktop.NetworkManager',
Adriana Kobylak88c733b2016-02-03 16:46:58 -060036 'method' : 'org.freedesktop.NetworkManager' # FIXME:
37 },
Hariharasubramanian Rcd387972016-01-20 07:19:41 -060038}
39
40def getPrefixLen(mask):
Adriana Kobylak88c733b2016-02-03 16:46:58 -060041 prefixLen = sum([bin(int(x)).count('1') for x in mask.split('.')])
42 return prefixLen
Hariharasubramanian Rcd387972016-01-20 07:19:41 -060043
44class IfAddr ():
45 def __init__ (self, family, scope, flags, prefixlen, addr, gw):
46 self.family = family
47 self.scope = scope
48 self.flags = flags
49 self.prefixlen = prefixlen
50 self.addr = addr
51 self.gw = gw
52
53class NetMan (dbus.service.Object):
54 def __init__(self, bus, name):
55 self.bus = bus
56 self.name = name
57 dbus.service.Object.__init__(self,bus,name)
58
59 def setNetworkProvider(self, provider):
60 self.provider = provider
61
Hariharasubramanian R308cffc2016-03-03 09:35:16 -060062 def _isvaliddev(self, device):
63 devices = os.listdir ("/sys/class/net")
64 if not device in devices : return False
65 else: return True
Hariharasubramanian Rcd387972016-01-20 07:19:41 -060066
Hariharasubramanian R308cffc2016-03-03 09:35:16 -060067 def _ishwdev (self, device):
68 f = open ("/sys/class/net/"+device+"/type")
69 type = f.read()
70 return False if (int(type) == 772) else True
Hariharasubramanian Rcd387972016-01-20 07:19:41 -060071
Hariharasubramanian R308cffc2016-03-03 09:35:16 -060072 def _isvalidmask (self, mask):
73 for x in mask.split('.'):
74 try:
75 y = int(x)
76 except:
77 return False
78 if y > 255: return False
79 return mask.count('.') == 3
80
81 def _isvalidmac(self, mac):
82 macre = '([a-fA-F0-9]{2}[:|\-]?){6}'
83 if re.compile(macre).search(mac) : return True
84 else: return False
85
Edward A. James75757c02016-07-15 09:11:18 -050086 def _isvalidipv4(self, ipstr, netmask):
87 ip_parts = ipstr.split(".")
88 if len(ip_parts) != 4:
89 return "Malformed"
Hariharasubramanian R308cffc2016-03-03 09:35:16 -060090
Edward A. James75757c02016-07-15 09:11:18 -050091 first, second, third, fourth = [int(part) for part in ip_parts]
92 if first == 0 and second == 0 and third == 0 and fourth == 0:
93 return "Invalid" # "this" network disallowed
94 if first == 169 and second == 254:
95 return "Link Local"
96 if first >= 224:
97 return "Invalid" # class D multicast and class E disallowed
98 if first == 192 and second == 88 and third == 99:
99 return "Invalid" # ipv6 relay
Hariharasubramanian R308cffc2016-03-03 09:35:16 -0600100
Edward A. James75757c02016-07-15 09:11:18 -0500101 # check validity against netmask
102 if netmask != '0':
103 ip_bin = (first << 24) + (second << 16) + (third << 8) + fourth
104 mask_parts = netmask.split(".")
105 if len(mask_parts) == 4: # long form netmask
106 mask_bin = (int(mask_parts[0]) << 24) + (int(mask_parts[1]) << 16) + (int(mask_parts[2]) << 8) + int(mask_parts[3])
107 elif netmask.count(".") == 0: # short form netmask
108 mask_bin = 0xffffffff ^ (1 << 32 - int(netmask)) - 1
109 else:
110 return "Malformed" # bad netmask
Hariharasubramanian R308cffc2016-03-03 09:35:16 -0600111
Edward A. James75757c02016-07-15 09:11:18 -0500112 if ip_bin & ~mask_bin == 0:
113 return "Invalid" # disallowed by this netmask
114 if ip_bin | mask_bin == 0xFFFFFFFF:
115 return "Invalid" # disallowed by this netmask
116
117 return "Valid"
118
119
120 def _isvalidip(self, ipaddr, netmask = '0'):
121 try:
122 ip = IP(ipaddr)
123 except ValueError:
124 return "Malformed"
125
126 ipstr = ip.strNormal(0)
127 ipstr_masked = ip.strNormal(2)
128 if ipstr_masked.count("/") != 0 and netmask == '0':
129 netmask = ipstr_masked.split("/")[1]
130
131 if ip.version() == 4: # additional checks for ipv4
132 return self._isvalidipv4(ipstr, netmask)
133 # TODO: check ipv6 openbmc/openbmc#496
134
135 return "Valid"
Hariharasubramanian Rcd387972016-01-20 07:19:41 -0600136
137 def _getAddr (self, target, device):
138 netprov = network_providers [self.provider]
139 bus_name = netprov ['bus_name']
140
141 if (target == "ip"):
Hariharasubramanian R308cffc2016-03-03 09:35:16 -0600142 ipaddr = ""
143 defgw = ""
144 prefixlen = "0"
145
146 proc = subprocess.Popen(["ip", "addr", "show", "dev", device], stdout=PIPE)
147 procout = proc.communicate()
148 if procout:
149 ipout = procout[0].splitlines()[2].strip()
150 ipaddr,prefixlen = ipout.split ()[1].split("/")
151
152 proc = subprocess.Popen(["ip", "route", "show", "dev", device, "default", "0.0.0.0/0"], stdout=PIPE)
153 procout = proc.communicate()
154 if procout[0]:
155 ipout = procout[0].splitlines()[0].strip()
156 defgw = ipout.split ()[2]
157
158 return 2, int(prefixlen), ipaddr, defgw
Hariharasubramanian Rcd387972016-01-20 07:19:41 -0600159
160 if (target == "mac"):
Hariharasubramanian R308cffc2016-03-03 09:35:16 -0600161 proc = subprocess.Popen(["ip", "link", "show", "dev", device], stdout=PIPE)
162 ipout = proc.communicate()[0].splitlines()[1].strip()
163 mac = ipout.split ()[1]
Hariharasubramanian Rcd387972016-01-20 07:19:41 -0600164 return mac
165
Hariharasubramanian Rcd387972016-01-20 07:19:41 -0600166 @dbus.service.method(DBUS_NAME, "", "")
167 def test(self):
168 print("TEST")
169
Hariharasubramanian R3a224e72016-02-10 12:32:08 -0600170 @dbus.service.method(DBUS_NAME, "s", "x")
171 def EnableDHCP (self, device):
Hariharasubramanian R308cffc2016-03-03 09:35:16 -0600172 if not self._isvaliddev (device) : raise ValueError, "Invalid Device"
173
174 confFile = "/etc/systemd/network/00-bmc-" + device + ".network"
Hariharasubramanian R3a224e72016-02-10 12:32:08 -0600175
176 print("Making .network file...")
Hariharasubramanian R308cffc2016-03-03 09:35:16 -0600177 try:
178 networkconf = open (confFile, "w+")
179 except IOError:
180 raise IOError, "Failed to open " + confFile
181
Hariharasubramanian R3a224e72016-02-10 12:32:08 -0600182 networkconf.write ('[Match]'+ '\n')
183 networkconf.write ('Name=' + (device) + '\n')
184 networkconf.write ('[Network]' + '\n')
185 networkconf.write ('DHCP=yes')
186 networkconf.close ()
187
188 print("Restarting networkd service...")
Hariharasubramanian R308cffc2016-03-03 09:35:16 -0600189 rc = call(["ip", "addr", "flush", device])
190 rc = call(["systemctl", "restart", "systemd-networkd.service"])
191 return rc
Hariharasubramanian R3a224e72016-02-10 12:32:08 -0600192
Hariharasubramanian Rcd387972016-01-20 07:19:41 -0600193 @dbus.service.method(DBUS_NAME, "ssss", "x")
Hariharasubramanian R308cffc2016-03-03 09:35:16 -0600194 def SetAddress4 (self, device, ipaddr, netmask, gateway):
195 if not self._isvaliddev (device) : raise ValueError, "Invalid Device"
Hariharasubramanian R308cffc2016-03-03 09:35:16 -0600196 if not self._isvalidmask (netmask) : raise ValueError, "Invalid Mask"
Hariharasubramanian Rcd387972016-01-20 07:19:41 -0600197 prefixLen = getPrefixLen (netmask)
Hariharasubramanian R308cffc2016-03-03 09:35:16 -0600198 if prefixLen == 0: raise ValueError, "Invalid Mask"
Edward A. James75757c02016-07-15 09:11:18 -0500199 valid = self._isvalidip (ipaddr, netmask)
200 if valid != "Valid": raise ValueError, valid + " IP Address"
201 valid = self._isvalidip (gateway)
202 if valid != "Valid": raise ValueError, valid + " IP Address"
Hariharasubramanian R308cffc2016-03-03 09:35:16 -0600203
204 confFile = "/etc/systemd/network/00-bmc-" + device + ".network"
Hariharasubramanian Rcd387972016-01-20 07:19:41 -0600205
206 print("Making .network file...")
Hariharasubramanian R308cffc2016-03-03 09:35:16 -0600207 try:
208 networkconf = open (confFile, "w+")
209 except IOError:
210 raise IOError, "Failed to open " + confFile
211
Hariharasubramanian Rcd387972016-01-20 07:19:41 -0600212 networkconf.write ('[Match]'+ '\n')
213 networkconf.write ('Name=' + (device) + '\n')
214 networkconf.write ('[Network]' + '\n')
215 networkconf.write ('Address=' + ipaddr + '/' + str(prefixLen) + '\n')
216 networkconf.write ('Gateway=' + gateway + '\n')
Chris Austenb13a3cd2016-02-01 18:18:21 -0600217 networkconf.close()
Hariharasubramanian Rcd387972016-01-20 07:19:41 -0600218
219 print("Restarting networkd service...")
Hariharasubramanian R308cffc2016-03-03 09:35:16 -0600220 rc = call(["ip", "addr", "flush", device])
221 rc = call(["systemctl", "restart", "systemd-networkd.service"])
222 return rc
Hariharasubramanian Rcd387972016-01-20 07:19:41 -0600223
Hariharasubramanian Rcc28a6f2016-04-29 12:25:12 -0500224 @dbus.service.method(DBUS_NAME, "s", "s")
225 def GetAddressType (self, device):
226 if not self._isvaliddev (device) : raise ValueError, "Invalid Device"
227
228 confFile = "/etc/systemd/network/00-bmc-" + device + ".network"
229 if not os.path.exists(confFile):
230 print "Config file (%s) not found !" % confFile
231 netprov = network_providers [self.provider]
232 bus_name = netprov ['bus_name']
233 obj_name = netprov ['ip_object_name']
234 o = self.bus.get_object(bus_name, obj_name, introspect=False)
235 i = dbus.Interface(o, 'org.freedesktop.DBus.Properties')
236 f = i.Get (netprov ['ip_if_name'], "SourcePath")
237 print "Using default networkd config file (%s)" % f
238 confFile = f
239
240 with open(confFile, "r") as f:
241 for line in f:
242 config = line.split ("=")
243 if (len (config) < 2) : continue
244 if config [0].upper() == "DHCP":
245 v = config[1].strip().upper()
246 if (v=="YES" or v=="IPV4" or v=="IPV6"):
247 return "DHCP"
248 return "STATIC"
249
Hariharasubramanian R308cffc2016-03-03 09:35:16 -0600250 #family, prefixlen, ip, defgw
251 @dbus.service.method(DBUS_NAME, "s", "iyss")
Hariharasubramanian Rcd387972016-01-20 07:19:41 -0600252 def GetAddress4 (self, device):
Hariharasubramanian R308cffc2016-03-03 09:35:16 -0600253 if not self._isvaliddev (device) : raise ValueError, "Invalid Device"
Hariharasubramanian Rcd387972016-01-20 07:19:41 -0600254 return self._getAddr ("ip", device)
255
256 @dbus.service.method(DBUS_NAME, "s", "s")
257 def GetHwAddress (self, device):
Hariharasubramanian R308cffc2016-03-03 09:35:16 -0600258 if not self._isvaliddev (device) : raise ValueError, "Invalid Device"
Hariharasubramanian Rcd387972016-01-20 07:19:41 -0600259 return self._getAddr ("mac", device)
260
Hariharasubramanian R308cffc2016-03-03 09:35:16 -0600261 @dbus.service.method(DBUS_NAME, "ss", "i")
262 def SetHwAddress (self, device, mac):
263 if not self._isvaliddev (device) : raise ValueError, "Invalid Device"
264 if not self._ishwdev (device) : raise ValueError, "Not a Hardware Device"
265 if not self._isvalidmac (mac) : raise ValueError, "Malformed MAC address"
266
Adriana Kobylak88c733b2016-02-03 16:46:58 -0600267 rc = subprocess.call(["fw_setenv", "ethaddr", mac])
Hariharasubramanian R308cffc2016-03-03 09:35:16 -0600268
269 print("Restarting networkd service...")
270 rc = call(["ip", "link", "set", "dev", device, "down"])
271 rc = call(["ip", "link", "set", "dev", device, "address", mac])
272 rc = call(["ip", "link", "set", "dev", device, "up"])
273
274 rc = call(["systemctl", "restart", "systemd-networkd.service"])
Adriana Kobylak88c733b2016-02-03 16:46:58 -0600275 return rc
276
vishwa5c912c82016-03-24 07:59:28 -0500277 #string of nameservers
278 @dbus.service.method(DBUS_NAME,"s", "s")
279 def SetNameServers (self, nameservers):
280 dns_entry = nameservers.split()
281 fail_msg = ''
282 dhcp_auto = False
283 file_opened = False
284 if len(dns_entry) > 0:
285 for dns in dns_entry:
Edward A. James75757c02016-07-15 09:11:18 -0500286 valid = self._isvalidip (dns)
287 if valid != "Valid":
vishwa5c912c82016-03-24 07:59:28 -0500288 if dns == "DHCP_AUTO=":
289 #This DNS is supplied by DHCP.
290 dhcp_auto = True
291 else:
Edward A. James75757c02016-07-15 09:11:18 -0500292 print valid + " DNS Address [" + dns + "]"
vishwa5c912c82016-03-24 07:59:28 -0500293 fail_msg = fail_msg + '[' + dns + ']'
294 else:
295 #Only over write on a first valid input
296 if file_opened == False:
297 resolv_conf = open("/etc/resolv.conf",'w')
298 file_opened = True
299 if dhcp_auto == True:
300 resolv_conf.write("### Generated automatically via DHCP ###\n")
301 else:
302 resolv_conf.write("### Generated manually via dbus settings ###\n")
303 dns_ip = 'nameserver ' + dns + '\n'
304 resolv_conf.write(dns_ip)
305 if file_opened == True:
306 resolv_conf.close()
307 else:
308 raise ValueError, "Invalid DNS entry"
309 if len(fail_msg) > 0:
310 return 'Failures encountered processing' + fail_msg
311 else:
312 return "DNS entries updated Successfully"
313
Hariharasubramanian Rcd387972016-01-20 07:19:41 -0600314def main():
315 dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
316 bus = dbus.SystemBus()
317 name = dbus.service.BusName(DBUS_NAME, bus)
318 obj = NetMan (bus, OBJ_NAME)
319 obj.setNetworkProvider ("networkd")
320 mainloop = gobject.MainLoop()
321 print("Started")
322 mainloop.run()
323
324if __name__ == '__main__':
Adriana Kobylake150bfd2016-02-01 21:47:34 -0600325 sys.exit(main())