instructions.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. // Copyright 2016 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package bpf
  5. import "fmt"
  6. // An Instruction is one instruction executed by the BPF virtual
  7. // machine.
  8. type Instruction interface {
  9. // Assemble assembles the Instruction into a RawInstruction.
  10. Assemble() (RawInstruction, error)
  11. }
  12. // A RawInstruction is a raw BPF virtual machine instruction.
  13. type RawInstruction struct {
  14. // Operation to execute.
  15. Op uint16
  16. // For conditional jump instructions, the number of instructions
  17. // to skip if the condition is true/false.
  18. Jt uint8
  19. Jf uint8
  20. // Constant parameter. The meaning depends on the Op.
  21. K uint32
  22. }
  23. // Assemble implements the Instruction Assemble method.
  24. func (ri RawInstruction) Assemble() (RawInstruction, error) { return ri, nil }
  25. // Disassemble parses ri into an Instruction and returns it. If ri is
  26. // not recognized by this package, ri itself is returned.
  27. func (ri RawInstruction) Disassemble() Instruction {
  28. switch ri.Op {
  29. case opClsLoadA | opLoadWidth4 | opAddrModeImmediate:
  30. return LoadConstant{Dst: RegA, Val: ri.K}
  31. case opClsLoadX | opLoadWidth4 | opAddrModeImmediate:
  32. return LoadConstant{Dst: RegX, Val: ri.K}
  33. case opClsLoadA | opLoadWidth4 | opAddrModeScratch:
  34. if ri.K > 15 {
  35. return ri
  36. }
  37. return LoadScratch{Dst: RegA, N: int(ri.K)}
  38. case opClsLoadX | opLoadWidth4 | opAddrModeScratch:
  39. if ri.K > 15 {
  40. return ri
  41. }
  42. return LoadScratch{Dst: RegX, N: int(ri.K)}
  43. case opClsLoadA | opLoadWidth4 | opAddrModeAbsolute:
  44. ext := Extension(uint32(ri.K) + 0x1000)
  45. switch ext {
  46. case ExtProto, ExtType, ExtPayloadOffset, ExtInterfaceIndex, ExtNetlinkAttr, ExtNetlinkAttrNested, ExtMark, ExtQueue, ExtLinkLayerType, ExtRXHash, ExtCPUID, ExtVLANTag, ExtVLANTagPresent, ExtVLANProto, ExtRand:
  47. return LoadExtension{Num: ext}
  48. default:
  49. return LoadAbsolute{Off: ri.K, Size: 4}
  50. }
  51. case opClsLoadA | opLoadWidth2 | opAddrModeAbsolute:
  52. return LoadAbsolute{Off: ri.K, Size: 2}
  53. case opClsLoadA | opLoadWidth1 | opAddrModeAbsolute:
  54. return LoadAbsolute{Off: ri.K, Size: 1}
  55. case opClsLoadA | opLoadWidth4 | opAddrModeIndirect:
  56. return LoadIndirect{Off: ri.K, Size: 4}
  57. case opClsLoadA | opLoadWidth2 | opAddrModeIndirect:
  58. return LoadIndirect{Off: ri.K, Size: 2}
  59. case opClsLoadA | opLoadWidth1 | opAddrModeIndirect:
  60. return LoadIndirect{Off: ri.K, Size: 1}
  61. case opClsLoadX | opLoadWidth1 | opAddrModeIPv4HeaderLen:
  62. return LoadIPv4HeaderLen{Off: ri.K}
  63. case opClsLoadA | opLoadWidth4 | opAddrModePacketLen:
  64. return LoadExtension{Num: ExtLen}
  65. case opClsStoreA:
  66. if ri.K > 15 {
  67. return ri
  68. }
  69. return StoreScratch{Src: RegA, N: int(ri.K)}
  70. case opClsStoreX:
  71. if ri.K > 15 {
  72. return ri
  73. }
  74. return StoreScratch{Src: RegX, N: int(ri.K)}
  75. case opClsALU | uint16(aluOpNeg):
  76. return NegateA{}
  77. case opClsJump | opJumpAlways:
  78. return Jump{Skip: ri.K}
  79. case opClsJump | opJumpEqual:
  80. return JumpIf{
  81. Cond: JumpEqual,
  82. Val: ri.K,
  83. SkipTrue: ri.Jt,
  84. SkipFalse: ri.Jf,
  85. }
  86. case opClsJump | opJumpGT:
  87. return JumpIf{
  88. Cond: JumpGreaterThan,
  89. Val: ri.K,
  90. SkipTrue: ri.Jt,
  91. SkipFalse: ri.Jf,
  92. }
  93. case opClsJump | opJumpGE:
  94. return JumpIf{
  95. Cond: JumpGreaterOrEqual,
  96. Val: ri.K,
  97. SkipTrue: ri.Jt,
  98. SkipFalse: ri.Jf,
  99. }
  100. case opClsJump | opJumpSet:
  101. return JumpIf{
  102. Cond: JumpBitsSet,
  103. Val: ri.K,
  104. SkipTrue: ri.Jt,
  105. SkipFalse: ri.Jf,
  106. }
  107. case opClsReturn | opRetSrcA:
  108. return RetA{}
  109. case opClsReturn | opRetSrcConstant:
  110. return RetConstant{Val: ri.K}
  111. case opClsMisc | opMiscTXA:
  112. return TXA{}
  113. case opClsMisc | opMiscTAX:
  114. return TAX{}
  115. }
  116. // ALU operations require bitmasking to decode, so are done
  117. // outside the main switch.
  118. if ri.Op&opClsMask != opClsALU {
  119. return ri
  120. }
  121. op := ALUOp(ri.Op & opALUOpMask)
  122. switch op {
  123. case ALUOpAdd, ALUOpSub, ALUOpMul, ALUOpDiv, ALUOpOr, ALUOpAnd, ALUOpShiftLeft, ALUOpShiftRight, ALUOpMod, ALUOpXor:
  124. default:
  125. return ri
  126. }
  127. if ri.Op&opALUSrcMask != 0 {
  128. return ALUOpX{Op: op}
  129. }
  130. return ALUOpConstant{Op: op, Val: ri.K}
  131. }
  132. // LoadConstant loads Val into register Dst.
  133. type LoadConstant struct {
  134. Dst Register
  135. Val uint32
  136. }
  137. // Assemble implements the Instruction Assemble method.
  138. func (a LoadConstant) Assemble() (RawInstruction, error) {
  139. return assembleLoad(a.Dst, 4, opAddrModeImmediate, a.Val)
  140. }
  141. // LoadScratch loads scratch[N] into register Dst.
  142. type LoadScratch struct {
  143. Dst Register
  144. N int // 0-15
  145. }
  146. // Assemble implements the Instruction Assemble method.
  147. func (a LoadScratch) Assemble() (RawInstruction, error) {
  148. if a.N < 0 || a.N > 15 {
  149. return RawInstruction{}, fmt.Errorf("invalid scratch slot %d", a.N)
  150. }
  151. return assembleLoad(a.Dst, 4, opAddrModeScratch, uint32(a.N))
  152. }
  153. // LoadAbsolute loads packet[Off:Off+Size] as an integer value into
  154. // register A.
  155. type LoadAbsolute struct {
  156. Off uint32
  157. Size int // 1, 2 or 4
  158. }
  159. // Assemble implements the Instruction Assemble method.
  160. func (a LoadAbsolute) Assemble() (RawInstruction, error) {
  161. return assembleLoad(RegA, a.Size, opAddrModeAbsolute, a.Off)
  162. }
  163. // LoadIndirect loads packet[X+Off:X+Off+Size] as an integer value
  164. // into register A.
  165. type LoadIndirect struct {
  166. Off uint32
  167. Size int // 1, 2 or 4
  168. }
  169. // Assemble implements the Instruction Assemble method.
  170. func (a LoadIndirect) Assemble() (RawInstruction, error) {
  171. return assembleLoad(RegA, a.Size, opAddrModeIndirect, a.Off)
  172. }
  173. // LoadIPv4HeaderLen loads into register X the length of the IPv4
  174. // header whose first byte is packet[Off].
  175. type LoadIPv4HeaderLen struct {
  176. Off uint32
  177. }
  178. // Assemble implements the Instruction Assemble method.
  179. func (a LoadIPv4HeaderLen) Assemble() (RawInstruction, error) {
  180. return assembleLoad(RegX, 1, opAddrModeIPv4HeaderLen, a.Off)
  181. }
  182. // LoadExtension invokes a linux-specific extension and stores the
  183. // result in register A.
  184. type LoadExtension struct {
  185. Num Extension
  186. }
  187. // Assemble implements the Instruction Assemble method.
  188. func (a LoadExtension) Assemble() (RawInstruction, error) {
  189. if a.Num == ExtLen {
  190. return assembleLoad(RegA, 4, opAddrModePacketLen, 0)
  191. }
  192. return assembleLoad(RegA, 4, opAddrModeAbsolute, uint32(-0x1000+a.Num))
  193. }
  194. // StoreScratch stores register Src into scratch[N].
  195. type StoreScratch struct {
  196. Src Register
  197. N int // 0-15
  198. }
  199. // Assemble implements the Instruction Assemble method.
  200. func (a StoreScratch) Assemble() (RawInstruction, error) {
  201. if a.N < 0 || a.N > 15 {
  202. return RawInstruction{}, fmt.Errorf("invalid scratch slot %d", a.N)
  203. }
  204. var op uint16
  205. switch a.Src {
  206. case RegA:
  207. op = opClsStoreA
  208. case RegX:
  209. op = opClsStoreX
  210. default:
  211. return RawInstruction{}, fmt.Errorf("invalid source register %v", a.Src)
  212. }
  213. return RawInstruction{
  214. Op: op,
  215. K: uint32(a.N),
  216. }, nil
  217. }
  218. // ALUOpConstant executes A = A <Op> Val.
  219. type ALUOpConstant struct {
  220. Op ALUOp
  221. Val uint32
  222. }
  223. // Assemble implements the Instruction Assemble method.
  224. func (a ALUOpConstant) Assemble() (RawInstruction, error) {
  225. return RawInstruction{
  226. Op: opClsALU | opALUSrcConstant | uint16(a.Op),
  227. K: a.Val,
  228. }, nil
  229. }
  230. // ALUOpX executes A = A <Op> X
  231. type ALUOpX struct {
  232. Op ALUOp
  233. }
  234. // Assemble implements the Instruction Assemble method.
  235. func (a ALUOpX) Assemble() (RawInstruction, error) {
  236. return RawInstruction{
  237. Op: opClsALU | opALUSrcX | uint16(a.Op),
  238. }, nil
  239. }
  240. // NegateA executes A = -A.
  241. type NegateA struct{}
  242. // Assemble implements the Instruction Assemble method.
  243. func (a NegateA) Assemble() (RawInstruction, error) {
  244. return RawInstruction{
  245. Op: opClsALU | uint16(aluOpNeg),
  246. }, nil
  247. }
  248. // Jump skips the following Skip instructions in the program.
  249. type Jump struct {
  250. Skip uint32
  251. }
  252. // Assemble implements the Instruction Assemble method.
  253. func (a Jump) Assemble() (RawInstruction, error) {
  254. return RawInstruction{
  255. Op: opClsJump | opJumpAlways,
  256. K: a.Skip,
  257. }, nil
  258. }
  259. // JumpIf skips the following Skip instructions in the program if A
  260. // <Cond> Val is true.
  261. type JumpIf struct {
  262. Cond JumpTest
  263. Val uint32
  264. SkipTrue uint8
  265. SkipFalse uint8
  266. }
  267. // Assemble implements the Instruction Assemble method.
  268. func (a JumpIf) Assemble() (RawInstruction, error) {
  269. var (
  270. cond uint16
  271. flip bool
  272. )
  273. switch a.Cond {
  274. case JumpEqual:
  275. cond = opJumpEqual
  276. case JumpNotEqual:
  277. cond, flip = opJumpEqual, true
  278. case JumpGreaterThan:
  279. cond = opJumpGT
  280. case JumpLessThan:
  281. cond, flip = opJumpGE, true
  282. case JumpGreaterOrEqual:
  283. cond = opJumpGE
  284. case JumpLessOrEqual:
  285. cond, flip = opJumpGT, true
  286. case JumpBitsSet:
  287. cond = opJumpSet
  288. case JumpBitsNotSet:
  289. cond, flip = opJumpSet, true
  290. default:
  291. return RawInstruction{}, fmt.Errorf("unknown JumpTest %v", a.Cond)
  292. }
  293. jt, jf := a.SkipTrue, a.SkipFalse
  294. if flip {
  295. jt, jf = jf, jt
  296. }
  297. return RawInstruction{
  298. Op: opClsJump | cond,
  299. Jt: jt,
  300. Jf: jf,
  301. K: a.Val,
  302. }, nil
  303. }
  304. // RetA exits the BPF program, returning the value of register A.
  305. type RetA struct{}
  306. // Assemble implements the Instruction Assemble method.
  307. func (a RetA) Assemble() (RawInstruction, error) {
  308. return RawInstruction{
  309. Op: opClsReturn | opRetSrcA,
  310. }, nil
  311. }
  312. // RetConstant exits the BPF program, returning a constant value.
  313. type RetConstant struct {
  314. Val uint32
  315. }
  316. // Assemble implements the Instruction Assemble method.
  317. func (a RetConstant) Assemble() (RawInstruction, error) {
  318. return RawInstruction{
  319. Op: opClsReturn | opRetSrcConstant,
  320. K: a.Val,
  321. }, nil
  322. }
  323. // TXA copies the value of register X to register A.
  324. type TXA struct{}
  325. // Assemble implements the Instruction Assemble method.
  326. func (a TXA) Assemble() (RawInstruction, error) {
  327. return RawInstruction{
  328. Op: opClsMisc | opMiscTXA,
  329. }, nil
  330. }
  331. // TAX copies the value of register A to register X.
  332. type TAX struct{}
  333. // Assemble implements the Instruction Assemble method.
  334. func (a TAX) Assemble() (RawInstruction, error) {
  335. return RawInstruction{
  336. Op: opClsMisc | opMiscTAX,
  337. }, nil
  338. }
  339. func assembleLoad(dst Register, loadSize int, mode uint16, k uint32) (RawInstruction, error) {
  340. var (
  341. cls uint16
  342. sz uint16
  343. )
  344. switch dst {
  345. case RegA:
  346. cls = opClsLoadA
  347. case RegX:
  348. cls = opClsLoadX
  349. default:
  350. return RawInstruction{}, fmt.Errorf("invalid target register %v", dst)
  351. }
  352. switch loadSize {
  353. case 1:
  354. sz = opLoadWidth1
  355. case 2:
  356. sz = opLoadWidth2
  357. case 4:
  358. sz = opLoadWidth4
  359. default:
  360. return RawInstruction{}, fmt.Errorf("invalid load byte length %d", sz)
  361. }
  362. return RawInstruction{
  363. Op: cls | sz | mode,
  364. K: k,
  365. }, nil
  366. }