mirror of
https://opendev.org/x/pyghmi
synced 2025-11-10 08:00:37 +00:00
Merge "Rework LUN support"
This commit is contained in:
@@ -430,7 +430,7 @@ class Command(object):
|
||||
return {'bootdev': bootdev}
|
||||
|
||||
def xraw_command(self, netfn, command, bridge_request=(), data=(),
|
||||
delay_xmit=None, retry=True, timeout=None, lun=0):
|
||||
delay_xmit=None, retry=True, timeout=None, rslun=0):
|
||||
"""Send raw ipmi command to BMC, raising exception on error
|
||||
|
||||
This is identical to raw_command, except it raises exceptions
|
||||
@@ -454,7 +454,7 @@ class Command(object):
|
||||
bridge_request=bridge_request,
|
||||
data=data, delay_xmit=delay_xmit,
|
||||
retry=retry, timeout=timeout,
|
||||
lun=lun)
|
||||
rslun=rslun)
|
||||
if 'error' in rsp:
|
||||
raise exc.IpmiException(rsp['error'], rsp['code'])
|
||||
rsp['data'] = buffer(rsp['data'])
|
||||
@@ -479,7 +479,7 @@ class Command(object):
|
||||
return self._oem.get_description()
|
||||
|
||||
def raw_command(self, netfn, command, bridge_request=(), data=(),
|
||||
delay_xmit=None, retry=True, timeout=None, lun=0):
|
||||
delay_xmit=None, retry=True, timeout=None, rslun=0):
|
||||
"""Send raw ipmi command to BMC
|
||||
|
||||
This allows arbitrary IPMI bytes to be issued. This is commonly used
|
||||
@@ -501,7 +501,7 @@ class Command(object):
|
||||
bridge_request=bridge_request,
|
||||
data=data, delay_xmit=delay_xmit,
|
||||
retry=retry, timeout=timeout,
|
||||
lun=lun)
|
||||
rslun=rslun)
|
||||
return rsp
|
||||
|
||||
def get_power(self):
|
||||
@@ -749,7 +749,7 @@ class Command(object):
|
||||
if self._sdr.sensors[sensor].name == sensorname:
|
||||
currsensor = self._sdr.sensors[sensor]
|
||||
rsp = self.raw_command(command=0x2d, netfn=4,
|
||||
lun=currsensor.sensor_lun,
|
||||
rslun=currsensor.sensor_lun,
|
||||
data=(currsensor.sensor_number,))
|
||||
if 'error' in rsp:
|
||||
raise exc.IpmiException(rsp['error'], rsp['code'])
|
||||
@@ -964,7 +964,7 @@ class Command(object):
|
||||
for sensor in self._sdr.get_sensor_numbers():
|
||||
currsensor = self._sdr.sensors[sensor]
|
||||
rsp = self.raw_command(command=0x2d, netfn=4,
|
||||
lun=currsensor.sensor_lun,
|
||||
rslun=currsensor.sensor_lun,
|
||||
data=(currsensor.sensor_number,))
|
||||
if 'error' in rsp:
|
||||
if rsp['code'] == 203: # Sensor does not exist, optional dev
|
||||
|
||||
@@ -113,10 +113,10 @@ class Session(object):
|
||||
retry=True,
|
||||
delay_xmit=None,
|
||||
timeout=None,
|
||||
waitall=False, lun=0):
|
||||
waitall=False, rslun=0):
|
||||
self.addr.channel = CURRCHAN
|
||||
self.addr.addr_type = ADDRTYPE
|
||||
self.addr.lun = lun
|
||||
self.addr.lun = rslun
|
||||
self.req.addr_len = ctypes.sizeof(IpmiSystemInterfaceAddr)
|
||||
self.req.addr = ctypes.pointer(self.addr)
|
||||
self.req.msg.netfn = netfn
|
||||
|
||||
@@ -598,6 +598,7 @@ class Session(object):
|
||||
self.ipmiversion = 1.5
|
||||
self.timeout = initialtimeout + (0.5 * random.random())
|
||||
self.logoutexpiry = _monotonic_time() + self._getmaxtimeout()
|
||||
self.rqlun = 0
|
||||
self.seqlun = 0
|
||||
# NOTE(jbjohnso): per IPMI table 5-4, software ids in the ipmi spec may
|
||||
# be 0x81 through 0x8d. We'll stick with 0x81 for now,
|
||||
@@ -626,12 +627,14 @@ class Session(object):
|
||||
|
||||
part of ipmi payload.
|
||||
"""
|
||||
# NOTE(puwen): need to pay attention for this function because the
|
||||
# structure does not seem to match the specifications.
|
||||
head = bytearray((constants.IPMI_BMC_ADDRESS,
|
||||
constants.netfn_codes['application'] << 2))
|
||||
check_sum = _checksum(*head)
|
||||
# NOTE(fengqian): according IPMI Figure 14-11, rqSWID is set to 81h
|
||||
boday = bytearray((0x81, self.seqlun, constants.IPMI_SEND_MESSAGE_CMD,
|
||||
0x40 | channel))
|
||||
boday = bytearray((0x81, (self.seqlun << 2) | self.rqlun,
|
||||
constants.IPMI_SEND_MESSAGE_CMD, 0x40 | channel))
|
||||
# NOTE(fengqian): Track request
|
||||
self._add_request_entry((constants.netfn_codes['application'] + 1,
|
||||
self.seqlun, constants.IPMI_SEND_MESSAGE_CMD))
|
||||
@@ -654,7 +657,7 @@ class Session(object):
|
||||
self.request_entry.remove(entry)
|
||||
|
||||
def _make_ipmi_payload(self, netfn, command, bridge_request=None, data=(),
|
||||
lun=0):
|
||||
rslun=0):
|
||||
"""This function generates the core ipmi payload that would be
|
||||
|
||||
applicable for any channel (including KCS)
|
||||
@@ -672,8 +675,8 @@ class Session(object):
|
||||
self.tabooseq[(netfn, command, self.seqlun)] and seqincrement):
|
||||
self.tabooseq[(self.expectednetfn, command, self.seqlun)] -= 1
|
||||
# Allow taboo to eventually expire after a few rounds
|
||||
self.seqlun += 4 # the last two bits are lun, so add 4 to add 1
|
||||
self.seqlun &= 0xff # we only have one byte, wrap when exceeded
|
||||
self.seqlun += 1 # the last two bits are lun, so add 4 to add 1
|
||||
self.seqlun &= 0x3f # we only have one byte, wrap when exceeded
|
||||
seqincrement -= 1
|
||||
|
||||
if bridge_request:
|
||||
@@ -692,8 +695,9 @@ class Session(object):
|
||||
# figure 13-4, first two bytes are rsaddr and
|
||||
# netfn, for non-bridge request, rsaddr is always 0x20 since we are
|
||||
# addressing BMC while rsaddr is specified forbridge request
|
||||
header = bytearray((rsaddr, (netfn << 2) | lun))
|
||||
reqbody = bytearray((rqaddr, self.seqlun, command)) + data
|
||||
header = bytearray((rsaddr, (netfn << 2) | rslun))
|
||||
reqbody = bytearray(
|
||||
(rqaddr, (self.seqlun << 2) | self.rqlun, command)) + data
|
||||
headsum = bytearray((_checksum(*header),))
|
||||
bodysum = bytearray((_checksum(*reqbody),))
|
||||
payload = header + headsum + reqbody + bodysum
|
||||
@@ -757,7 +761,7 @@ class Session(object):
|
||||
delay_xmit=None,
|
||||
timeout=None,
|
||||
callback=None,
|
||||
lun=0):
|
||||
rslun=0):
|
||||
if not self.logged:
|
||||
if (self.logoutexpiry is not None and
|
||||
_monotonic_time() > self.logoutexpiry):
|
||||
@@ -775,7 +779,7 @@ class Session(object):
|
||||
self._send_ipmi_net_payload(netfn, command, data,
|
||||
bridge_request=bridge_request,
|
||||
retry=retry, delay_xmit=delay_xmit,
|
||||
timeout=timeout, lun=lun)
|
||||
timeout=timeout, rslun=rslun)
|
||||
|
||||
if retry: # in retry case, let the retry timers indicate wait time
|
||||
timeout = None
|
||||
@@ -802,7 +806,7 @@ class Session(object):
|
||||
def _send_ipmi_net_payload(self, netfn=None, command=None, data=(), code=0,
|
||||
bridge_request=None,
|
||||
retry=None, delay_xmit=None, timeout=None,
|
||||
lun=0):
|
||||
rslun=0):
|
||||
if retry is None:
|
||||
retry = not self.servermode
|
||||
if self.servermode:
|
||||
@@ -814,7 +818,7 @@ class Session(object):
|
||||
else:
|
||||
data = bytearray(data)
|
||||
ipmipayload = self._make_ipmi_payload(netfn, command, bridge_request,
|
||||
data, lun)
|
||||
data, rslun)
|
||||
payload_type = constants.payload_types['ipmi']
|
||||
self.send_payload(payload=ipmipayload, payload_type=payload_type,
|
||||
retry=retry, delay_xmit=delay_xmit, timeout=timeout)
|
||||
@@ -943,7 +947,7 @@ class Session(object):
|
||||
raise exc.IpmiException("Password is too long for ipmi 1.5")
|
||||
password += '\x00' * padneeded
|
||||
if checkremotecode:
|
||||
seqbytes = struct.pack("<I", self.remsequencenumber)
|
||||
seqbytes = struct.pack("<I", self.remseqnumber)
|
||||
else:
|
||||
seqbytes = struct.pack("<I", self.sequencenumber)
|
||||
sessdata = struct.pack("<I", self.sessionid)
|
||||
@@ -1308,9 +1312,9 @@ class Session(object):
|
||||
# things off ignore the second reply since we have one
|
||||
# satisfactory answer
|
||||
if data[4] in (0, 2): # This is an ipmi 1.5 paylod
|
||||
remsequencenumber = struct.unpack('<I', bytes(data[5:9]))[0]
|
||||
remseqnumber = struct.unpack('<I', bytes(data[5:9]))[0]
|
||||
remsessid = struct.unpack("<I", bytes(data[9:13]))[0]
|
||||
if (remsequencenumber == 0 and remsessid == 0 and
|
||||
if (remseqnumber == 0 and remsessid == 0 and
|
||||
qent[2] in Session.bmc_handlers):
|
||||
# So a new ipmi client happens to get a previously seen and
|
||||
# still active UDP source port. Clear ourselves out and punt
|
||||
@@ -1320,10 +1324,10 @@ class Session(object):
|
||||
iserver.pktqueue.append(qent)
|
||||
iserver.process_pktqueue()
|
||||
return
|
||||
if (hasattr(self, 'remsequencenumber') and
|
||||
remsequencenumber < self.remsequencenumber):
|
||||
if (hasattr(self, 'remseqnumber') and
|
||||
remseqnumber < self.remseqnumber):
|
||||
return -5 # remote sequence number is too low, reject it
|
||||
self.remsequencenumber = remsequencenumber
|
||||
self.remseqnumber = remseqnumber
|
||||
if data[4] != self.authtype:
|
||||
# BMC responded with mismatch authtype, for
|
||||
# mutual authentication reject it. If this causes
|
||||
@@ -1619,13 +1623,14 @@ class Session(object):
|
||||
# drop it and carry about our business.
|
||||
return
|
||||
if self.servermode:
|
||||
self.seqlun = payload[4]
|
||||
self.seqlun = payload[4] >> 2
|
||||
self.clientaddr = payload[3]
|
||||
self.clientnetfn = (payload[1] >> 2) + 1
|
||||
self.clientcommand = payload[5]
|
||||
self._parse_payload(payload)
|
||||
return
|
||||
entry = (payload[1] >> 2, payload[4] & 0xfc, payload[5])
|
||||
# payload[4] is rqSeq + rsLUN, we only need the rqSeq
|
||||
entry = (payload[1] >> 2, payload[4] >> 2, payload[5])
|
||||
if self._lookup_request_entry(entry):
|
||||
self._remove_request_entry(entry)
|
||||
|
||||
@@ -1661,8 +1666,8 @@ class Session(object):
|
||||
self.expectednetfn = 0x1ff
|
||||
self.expectedcmd = 0x1ff
|
||||
if not self.servermode:
|
||||
self.seqlun += 4 # prepare seqlun for next transmit
|
||||
self.seqlun &= 0xff # when overflowing, wrap around
|
||||
self.seqlun += 1 # prepare seqlun for next transmit
|
||||
self.seqlun &= 0x3f # when overflowing, wrap around
|
||||
with util.protect(WAITING_SESSIONS):
|
||||
Session.waiting_sessions.pop(self, None)
|
||||
# render retry mechanism utterly incapable of
|
||||
|
||||
@@ -296,6 +296,7 @@ class Session(object):
|
||||
self.ipmiversion = 1.5
|
||||
self.timeout = initialtimeout + (0.5 * random.random())
|
||||
self.logoutexpiry = _monotonic_time() + self._getmaxtimeout()
|
||||
self.rqlun = 0
|
||||
self.seqlun = 0
|
||||
# NOTE(jbjohnso): per IPMI table 5-4, software ids in the ipmi spec may
|
||||
# be 0x81 through 0x8d. We'll stick with 0x81 for now,
|
||||
@@ -328,8 +329,8 @@ class Session(object):
|
||||
constants.netfn_codes['application'] << 2))
|
||||
check_sum = _checksum(*head)
|
||||
# NOTE(fengqian): according IPMI Figure 14-11, rqSWID is set to 81h
|
||||
boday = bytearray((0x81, self.seqlun, constants.IPMI_SEND_MESSAGE_CMD,
|
||||
0x40 | channel))
|
||||
boday = bytearray((0x81, (self.seqlun << 2) | self.rqlun,
|
||||
constants.IPMI_SEND_MESSAGE_CMD, 0x40 | channel))
|
||||
# NOTE(fengqian): Track request
|
||||
self._add_request_entry((constants.netfn_codes['application'] + 1,
|
||||
self.seqlun, constants.IPMI_SEND_MESSAGE_CMD))
|
||||
@@ -352,7 +353,7 @@ class Session(object):
|
||||
self.request_entry.remove(entry)
|
||||
|
||||
def _make_ipmi_payload(self, netfn, command, bridge_request=None, data=(),
|
||||
lun=0):
|
||||
rslun=0):
|
||||
"""This function generates the core ipmi payload that would be
|
||||
|
||||
applicable for any channel (including KCS)
|
||||
@@ -370,8 +371,8 @@ class Session(object):
|
||||
self.tabooseq[(netfn, command, self.seqlun)] and seqincrement):
|
||||
self.tabooseq[(self.expectednetfn, command, self.seqlun)] -= 1
|
||||
# Allow taboo to eventually expire after a few rounds
|
||||
self.seqlun += 4 # the last two bits are lun, so add 4 to add 1
|
||||
self.seqlun &= 0xff # we only have one byte, wrap when exceeded
|
||||
self.seqlun += 1 # the last two bits are lun, so add 4 to add 1
|
||||
self.seqlun &= 0x3f # we only have one byte, wrap when exceeded
|
||||
seqincrement -= 1
|
||||
|
||||
if bridge_request:
|
||||
@@ -390,9 +391,10 @@ class Session(object):
|
||||
# figure 13-4, first two bytes are rsaddr and
|
||||
# netfn, for non-bridge request, rsaddr is always 0x20 since we are
|
||||
# addressing BMC while rsaddr is specified forbridge request
|
||||
header = bytearray((rsaddr, (netfn << 2) | lun))
|
||||
header = bytearray((rsaddr, (netfn << 2) | rslun))
|
||||
|
||||
reqbody = bytearray((rqaddr, self.seqlun, command)) + data
|
||||
reqbody = bytearray((
|
||||
rqaddr, (self.seqlun << 2) | self.rqlun, command)) + data
|
||||
headsum = bytearray((_checksum(*header),))
|
||||
bodysum = bytearray((_checksum(*reqbody),))
|
||||
payload = header + headsum + reqbody + bodysum
|
||||
@@ -451,7 +453,7 @@ class Session(object):
|
||||
delay_xmit=None,
|
||||
timeout=None,
|
||||
callback=None,
|
||||
lun=0):
|
||||
rslun=0):
|
||||
if not self.logged:
|
||||
if (self.logoutexpiry is not None and
|
||||
_monotonic_time() > self.logoutexpiry):
|
||||
@@ -469,7 +471,7 @@ class Session(object):
|
||||
self._send_ipmi_net_payload(netfn, command, data,
|
||||
bridge_request=bridge_request,
|
||||
retry=retry, delay_xmit=delay_xmit,
|
||||
timeout=timeout, lun=lun)
|
||||
timeout=timeout, rslun=rslun)
|
||||
|
||||
if retry: # in retry case, let the retry timers indicate wait time
|
||||
timeout = None
|
||||
@@ -496,7 +498,7 @@ class Session(object):
|
||||
def _send_ipmi_net_payload(self, netfn=None, command=None, data=(), code=0,
|
||||
bridge_request=None,
|
||||
retry=None, delay_xmit=None, timeout=None,
|
||||
lun=0):
|
||||
rslun=0):
|
||||
if retry is None:
|
||||
retry = not self.servermode
|
||||
if self.servermode:
|
||||
@@ -508,7 +510,7 @@ class Session(object):
|
||||
else:
|
||||
data = bytearray(data)
|
||||
ipmipayload = self._make_ipmi_payload(netfn, command, bridge_request,
|
||||
data, lun)
|
||||
data, rslun)
|
||||
payload_type = constants.payload_types['ipmi']
|
||||
self.send_payload(payload=ipmipayload, payload_type=payload_type,
|
||||
retry=retry, delay_xmit=delay_xmit, timeout=timeout)
|
||||
@@ -632,7 +634,7 @@ class Session(object):
|
||||
raise exc.IpmiException("Password is too long for ipmi 1.5")
|
||||
password += '\x00' * padneeded
|
||||
if checkremotecode:
|
||||
seqbytes = struct.pack("<I", self.remsequencenumber)
|
||||
seqbytes = struct.pack("<I", self.remseqnumber)
|
||||
else:
|
||||
seqbytes = struct.pack("<I", self.sequencenumber)
|
||||
sessdata = struct.pack("<I", self.sessionid)
|
||||
@@ -916,12 +918,12 @@ class Session(object):
|
||||
# things off ignore the second reply since we have one
|
||||
# satisfactory answer
|
||||
if data[4] in (0, 2): # This is an ipmi 1.5 paylod
|
||||
remsequencenumber = struct.unpack('<I', bytes(data[5:9]))[0]
|
||||
remseqnumber = struct.unpack('<I', bytes(data[5:9]))[0]
|
||||
remsessid = struct.unpack("<I", bytes(data[9:13]))[0]
|
||||
if (hasattr(self, 'remsequencenumber') and
|
||||
remsequencenumber < self.remsequencenumber):
|
||||
if (hasattr(self, 'remseqnumber') and
|
||||
remseqnumber < self.remseqnumber):
|
||||
return -5 # remote sequence number is too low, reject it
|
||||
self.remsequencenumber = remsequencenumber
|
||||
self.remseqnumber = remseqnumber
|
||||
if data[4] != self.authtype:
|
||||
# BMC responded with mismatch authtype, for
|
||||
# mutual authentication reject it. If this causes
|
||||
@@ -1215,7 +1217,7 @@ class Session(object):
|
||||
# since we can't do anything remotely sane with such a packet,
|
||||
# drop it and carry about our business.
|
||||
return
|
||||
entry = (payload[1] >> 2, payload[4], payload[5])
|
||||
entry = (payload[1] >> 2, payload[4] >> 2, payload[5])
|
||||
if self._lookup_request_entry(entry):
|
||||
self._remove_request_entry(entry)
|
||||
|
||||
@@ -1251,8 +1253,8 @@ class Session(object):
|
||||
self.expectednetfn = 0x1ff
|
||||
self.expectedcmd = 0x1ff
|
||||
if not self.servermode:
|
||||
self.seqlun += 4 # prepare seqlun for next transmit
|
||||
self.seqlun &= 0xff # when overflowing, wrap around
|
||||
self.seqlun += 1 # prepare seqlun for next transmit
|
||||
self.seqlun &= 0x3f # when overflowing, wrap around
|
||||
# render retry mechanism utterly incapable of
|
||||
# doing anything, though it shouldn't matter
|
||||
self.lastpayload = None
|
||||
|
||||
@@ -349,7 +349,7 @@ class SDREntry(object):
|
||||
# event only, compact and full are very similar
|
||||
# this function handles the common aspects of compact and full
|
||||
# offsets from spec, minus 6
|
||||
self.sensor_lun = entry[1]
|
||||
self.sensor_lun = entry[1] & 0x03
|
||||
self.sensor_number = entry[2]
|
||||
self.entity = ipmiconst.entity_ids.get(
|
||||
entry[3], 'Unknown entity {0}'.format(entry[3]))
|
||||
|
||||
Reference in New Issue
Block a user