Thanks for your interest! Any questions, please submit an issue.
BMC is powered by google/gopacket
.
It is strongly recommended to read the documentation for this in full before digging into this codebase.
The pkg/ipmi
package essentially just implements IPMI layers.
The root bmc
package ties these together with transport and session establishment logic, and a friendlier API.
Commands are specified in their own file within pkg/ipmi
, named after the lower-cased command, separated with underscores, e.g. get_channel_authentication_capabilities.go
.
This file contains request and/or response structs, named after the unabbreviated command name followed by Req
for requests, and Rsp
for responses.
E.g. GetChannelAuthenticationCapabilitiesReq
and GetChannelAuthenticationCapabilitiesRsp
respectively.
If a command has no request parameters (relying only on NetFn and Cmd), the *Req
struct should be omitted.
Likewise, if the response is empty and the completion code is sufficient, the *Rsp
struct should be omitted.
These structs correspond to layers that can be sent and received respectively.
It is perfectly fine - and even encouraged - for request structs to not be decodable, and response struct to not be serialisable.
Be sure to reference the relevant section(s) of the spec(s) in the struct documentation.
Layers are defined in layer_types.go
and simply returned in LayerType()
. It is generally recommended for these to be exported.
Tests are encouraged, especially for complex responses where there's lots of bit shifting.
For each struct, define a OperationX
variable in operation.go
, where X
is the name of the struct.
Be sure to add response operations to the operationLayerTypes
map in this file, as otherwise the library will not know which layer to use.
If the request or response payload has any enum-style fields, e.g. ChassisControl
, create a new type with constants for its possible values, then implement fmt.Stringer
to make it print nicely.
It is recommended not to embed any fields implementing fmt.Stringer
in a layer, as this means it cannot be printed by gopacket
(there is an issue here).
Session-less commands should be added to the SessionlessCommands
interface, then the appropriate decoders in v(1|2)sessionless.go
.
Commands that must be sent inside a session should be added to the SessionCommands
interface, then the appropriate decoders in v(1|2)session.go
.
Writing appropriate implementations for IPMI v1.5 and v2.0 in v1session(less).go
and v2session(less).go
respectively makes the command easy for users to execute.
- Empty command body: Get Chassis Status
- Empty response body: Chassis Control
- Non-empty command and response bodies: Get Channel Authentication Capabilities