diff --git a/pyghmi/ipmi/command.py b/pyghmi/ipmi/command.py index 4775e5d0..3ad9c835 100644 --- a/pyghmi/ipmi/command.py +++ b/pyghmi/ipmi/command.py @@ -110,6 +110,7 @@ class Command(object): self._sdr = None self._oem = None self._netchannel = None + self._ipv6support = None if onlogon is not None: self.ipmi_session = session.Session(bmc=bmc, userid=userid, @@ -962,6 +963,18 @@ class Command(object): rsp = self.xraw_command(netfn=0xc, command=2, data=(channel, 16, 0, 0)) return rsp['data'][1:].partition('\x00')[0] + @property + def _supports_standard_ipv6(self): + # Supports the *standard* ipv6 commands for various things + # used to internally steer some commands to standard or OEM + # handler of commands + lanchan = self.get_network_channel() + if self._ipv6support is None: + rsp = self.raw_command(netfn=0xc, command=0x2, data=(2, lanchan, + 0x32, 0, 0)) + self._ipv6support = rsp['code'] == 0 + return self._ipv6support + def set_alert_destination(self, ip=None, acknowledge_required=None, acknowledge_timeout=None, retries=None, destination=0, channel=None): @@ -991,10 +1004,17 @@ class Command(object): destdata.extend(parsedip) destdata.extend('\x00\x00\x00\x00\x00\x00') except socket.error: - parsedip = socket.inet_pton(socket.AF_INET6, ip) - destdata.append(0b10000000) - destdata.extend(parsedip) - self.xraw_command(netfn=0xc, command=1, data=destdata) + if self._supports_standard_ipv6: + parsedip = socket.inet_pton(socket.AF_INET6, ip) + destdata.append(0b10000000) + destdata.extend(parsedip) + else: + destdata = None + self.oem_init() + self._oem.set_alert_ipv6_destination(ip, destination, + channel) + if destdata: + self.xraw_command(netfn=0xc, command=1, data=destdata) if (acknowledge_required is not None or retries is not None or acknowledge_timeout is not None): currtype = self.xraw_command(netfn=0xc, command=2, data=( diff --git a/pyghmi/ipmi/oem/generic.py b/pyghmi/ipmi/oem/generic.py index c31740ed..082d4513 100644 --- a/pyghmi/ipmi/oem/generic.py +++ b/pyghmi/ipmi/oem/generic.py @@ -229,3 +229,18 @@ class OEMHandler(object): def attach_remote_media(self, imagename, username, password): raise exc.UnsupportedFunctionality() + + def set_alert_ipv6_destination(self, ip, destination, channel): + """Set an IPv6 alert destination + + If and only if an implementation does not support standard + IPv6 but has an OEM implementation, override this to process + the data. + + :param ip: IPv6 address to set + :param destination: Destination number + :param channel: Channel number to apply + + :returns True if standard parameter set should be suppressed + """ + return False diff --git a/pyghmi/ipmi/oem/lenovo/handler.py b/pyghmi/ipmi/oem/lenovo/handler.py index 4c73ba03..1f4b03d3 100755 --- a/pyghmi/ipmi/oem/lenovo/handler.py +++ b/pyghmi/ipmi/oem/lenovo/handler.py @@ -131,6 +131,15 @@ class OEMHandler(generic.OEMHandler): self.ipmicmd = weakref.proxy(ipmicmd) self._has_megarac = None self.oem_inventory_info = None + self._mrethidx = None + + @property + def _megarac_eth_index(self): + if self._mrethidx is None: + chan = self.ipmicmd.get_network_channel() + rsp = self.ipmicmd.xraw_command(0x32, command=0x62, data=(chan,)) + self._mrethidx = rsp['data'][0] + return self._mrethidx def get_video_launchdata(self): if self.has_tsm: @@ -571,6 +580,17 @@ class OEMHandler(generic.OEMHandler): pass # Means that it's not going to be a megarac return self._has_megarac + def set_alert_ipv6_destination(self, ip, destination, channel): + if self.has_megarac: + ethidx = self._megarac_eth_index + reqdata = bytearray([channel, 193, destination, ethidx, 0]) + parsedip = socket.inet_pton(socket.AF_INET6, ip) + reqdata.extend(parsedip) + reqdata.extend('\x00\x00\x00\x00\x00\x00') + self.ipmicmd.xraw_command(netfn=0xc, command=1, data=reqdata) + return True + return False + def _set_short_ris_string(self, selector, value): data = (1, selector, 0) + struct.unpack('{0}B'.format(len(value)), value)