From 86a2d39db7e93fbb6211e89276039135ec7c20a5 Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Thu, 18 Jul 2013 16:20:44 -0400 Subject: [PATCH] Change session timer to monotonic when possible Previously the ipmi session was using time.time(). This means that retries and keepalives could be thrown off by things like ntp or manual time corrections. Ideally, we'd use the baked in time.monotonic(), but that doesn't exist aside from python 3.3 Change-Id: Ia00026cef6df214f9463909309de44767c3752b5 --- ipmi/private/session.py | 28 ++++++++++++++++++++++------ ipmictl.py | 16 ++++++++-------- 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/ipmi/private/session.py b/ipmi/private/session.py index de9d6cd8..c2332733 100644 --- a/ipmi/private/session.py +++ b/ipmi/private/session.py @@ -37,6 +37,22 @@ initialtimeout = 0.5 # minimum timeout for first packet to retry in any given # in case of congestion +def _monotonic_time(): + """Provides a monotonic timer + + This code is concerned with relative, not absolute time. + This function facilitates that prior to python 3.3 + """ + # Python does not provide one until 3.3, so we make do + # for most OSes, os.times()[4] works well. + # for microsoft, GetTickCount64 + if (os.name == "posix"): + return os.times()[4] + else: # last resort, non monotonic time + return time.time() + #TODO(jbjohnso): Windows variant + + def _aespad(data): """ipmi demands a certain pad scheme, per table 13-20 AES-CBC encrypted payload fields. @@ -419,8 +435,8 @@ class Session: #advance idle timer since we don't need keepalive while sending packets #out naturally if self in Session.keepalive_sessions: - Session.keepalive_sessions[self]['timeout'] = time.time() + 25 + \ - (random.random() * 4.9) + Session.keepalive_sessions[self]['timeout'] = _monotonic_time() + \ + 25 + (random.random() * 4.9) self._xmit_packet(retry) def _ipmi15authcode(self, payload, checkremotecode=False): @@ -532,8 +548,8 @@ class Session: self.logged = 1 Session.keepalive_sessions[self] = {} Session.keepalive_sessions[self]['ipmisession'] = self - Session.keepalive_sessions[self]['timeout'] = time.time() + 25 + \ - (random.random() * 4.9) + Session.keepalive_sessions[self]['timeout'] = _monotonic_time() + \ + 25 + (random.random() * 4.9) call_with_optional_args( self.onlogon, {'success': True}, self.onlogonargs) @@ -603,7 +619,7 @@ class Session: #Instance C gets to go ahead of Instance A, because #Instance C can get work done, but instance A cannot - curtime = time.time() + curtime = _monotonic_time() # There ar a number of parties that each has their own timeout # The caller can specify a deadline in timeout argument # each session with active outbound payload has callback to @@ -1066,7 +1082,7 @@ class Session: Session.waiting_sessions[self] = {} Session.waiting_sessions[self]['ipmisession'] = self Session.waiting_sessions[self]['timeout'] = self.timeout + \ - time.time() + _monotonic_time() Session.pending += 1 if self.sockaddr: Session.socket.sendto(self.netpacket, self.sockaddr) diff --git a/ipmictl.py b/ipmictl.py index e02ab7b3..8242f625 100755 --- a/ipmictl.py +++ b/ipmictl.py @@ -23,7 +23,7 @@ understand how the ipmi_command class workes. import os import sys -from ipmi.command import Command +from ipmi import command password = os.environ['IPMIPASSWORD'] os.environ['IPMIPASSWORD'] = "" if (len(sys.argv) < 3): @@ -32,23 +32,23 @@ if (len(sys.argv) < 3): sys.exit(1) bmc = sys.argv[1] userid = sys.argv[2] -command = sys.argv[3] +cmmand = sys.argv[3] args = None if len(sys.argv) >= 5: args = sys.argv[4:] -ipmicmd = Command(bmc=bmc, userid=userid, password=password) -if command == 'power': +ipmicmd = command.Command(bmc=bmc, userid=userid, password=password) +if cmmand == 'power': if args: print ipmicmd.set_power(args[0], wait=True) else: print ipmicmd.get_power() -elif command == 'bootdev': +elif cmmand == 'bootdev': if args: print ipmicmd.set_bootdev(args[0]) else: print ipmicmd.get_bootdev() -elif command == 'raw': +elif cmmand == 'raw': netfn = args[0] - command = args[1] + cmmand = args[1] data = args[2:] - print ipmicmd.raw_command(netfn=netfn, command=command, data=data) + print ipmicmd.raw_command(netfn=netfn, command=cmmand, data=data)