packetforge: add packetforge for generic flow to extras
[vpp.git] / extras / packetforge / parsegraph / spec.md
1 #### Packet Forger JSON Specification Rev 0.1
2
3 ### 0. Change Logs
4
5 2021-10, initialized by Zhang, Qi
6
7 ### 1. Parse Graph
8
9 A Parse Graph is a unidirectional graph. It is consist of a set of nodes and edges. A node represent a network protocol header, and an edge represent the linkage of two protocol headers which is adjacent in the packet. An example of a parse graph have 5 nodes and 6 edges.
10
11 [![](https://mermaid.ink/img/eyJjb2RlIjoiZ3JhcGggVERcbiAgICBBKChNQUMpKSAtLT4gQigoSVB2NCkpXG4gICAgQSgoTUFDKSkgLS0-IEMoKElQdjYpKVxuICAgIEIgLS0-IEQoKFRDUCkpXG4gICAgQyAtLT4gRCgoVENQKSlcbiAgICBCIC0tPiBFKChVRFApKVxuICAgIEMgLS0-IEUoKFVEUCkpXG4gICAgIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRhcmsifSwidXBkYXRlRWRpdG9yIjpmYWxzZSwiYXV0b1N5bmMiOnRydWUsInVwZGF0ZURpYWdyYW0iOmZhbHNlfQ)](https://mermaid-js.github.io/mermaid-live-editor/edit#eyJjb2RlIjoiZ3JhcGggVERcbiAgICBBKChNQUMpKSAtLT4gQigoSVB2NCkpXG4gICAgQSgoTUFDKSkgLS0-IEMoKElQdjYpKVxuICAgIEIgLS0-IEQoKFRDUCkpXG4gICAgQyAtLT4gRCgoVENQKSlcbiAgICBCIC0tPiBFKChVRFApKVxuICAgIEMgLS0-IEUoKFVEUCkpXG4gICAgIiwibWVybWFpZCI6IntcbiAgXCJ0aGVtZVwiOiBcImRhcmtcIlxufSIsInVwZGF0ZUVkaXRvciI6ZmFsc2UsImF1dG9TeW5jIjp0cnVlLCJ1cGRhdGVEaWFncmFtIjpmYWxzZX0)
12
13 A Node or an Edge is described by a json object. There is no json representation for a parse graph, software should load all json objects of nodes and edges then build the parse graph logic in memory.
14
15 ### 2. Node
16
17 A json object of Node will include below properties:
18
19 * **type**
20
21   This should always be "node".
22
23 * **name**
24
25   This is the name of the protocol.
26
27 * **layout**
28
29   This is an array of fields in the protocol header which also imply the bit order. For example, json object of mac header as below:
30   ```
31   {
32       "type" : "node",
33       "name" : "mac",
34       "layout" : [
35           {
36               "name" : "src",
37               "size" : "48",
38               "format" : "mac",
39           },
40           {
41               "name" : "dst",
42               "size" : "48",
43               "format" : "mac",
44           },
45           {
46               "name" : "ethertype",
47               "size" : "16",
48           }
49       ]
50   }
51   ```
52
53   For each field, there are properties can be defined:
54
55     * **name**
56
57       The name of the field, typically it should be unique to all fields in the same node, except when it is "reserved".
58
59     * **size**
60
61       Size of the field, note, the unit is "bit" but not "byte".
62       Sometime a field's size can be decided by another field's value, for example, a geneve header's "options" field's size is decided by "optlen" field's value, so we have below:
63
64       ```
65       "name" : "geneve",
66       "layout" : [
67
68           ......
69
70           {
71               "name" : "reserved",
72               "size" : "8"
73           },
74           {
75               "name" : "options",
76               "size" : "optlen<<5"
77           }
78       ],
79       ```
80       Since when "optlen" increases 1 which means 4 bytes (32 bits) increase of "options"'s size so the bit value should shift left 5.
81
82     * **format**
83
84       Defined the input string format of the value, all formats are described in the section **Input Format** which also described the default format if it is not explicitly defined.
85
86     * **default**
87
88       Defined the default value of the field when a protocol header instance is created by the node. If not defined, the default value is always 0. The default value can be overwritten when forging a packet with specific value of the field. For example, we defined the default ipv4 address as below:
89
90       ```
91       "name" : "ipv4",
92       "layout" : [
93
94           ......
95
96           {
97               "name" : "src",
98               "size" : "32",
99               "format" : "ipv4",
100               "default" : "1.1.1.1"
101           },
102           {
103               "name" : "dst",
104               "size" : "32",
105               "format" : "ipv4",
106               "default" : "2.2.2.2"
107           }
108       ]
109       ```
110
111     * **readonly**
112
113       Define if a field is read only or not, typically it will be used together with "default". For example, the version of IPv4 header should be 4 and can't be overwritten.
114
115       ```
116       "name" : "ipv4",
117       "layout" : [
118           {
119               "name" : "version",
120               "size" : "4",
121               "default" : "4",
122               "readonly" : "true"
123           },
124           ......
125       ],
126       ```
127       A reserved field implies it is "readonly" and should always be 0.
128
129     * **optional**
130
131       A field could be optional depends on some flag as another field. For example, the GRE header has couple optional fields.
132
133       ```
134       "name" : "gre",
135       "layout" : [
136           {
137               "name" : "c",
138               "size" : "1",
139           },
140           {
141               "name" : "reserved",
142               "size" : "1",
143           },
144           {
145               "name" : "k",
146               "size" : "1",
147           },
148           {
149               "name" : "s",
150               "size" : "1",
151           },
152
153           ......
154
155           {
156               "name" : "checksum",
157               "size" : "16",
158               "optional" : "c=1",
159           },
160           {
161               "name" : "reserved",
162               "size" : "16",
163               "optional" : "c=1",
164           },
165           {
166               "name" : "key",
167               "size" : "32",
168               "optional" : "k=1"
169           },
170           {
171               "name" : "sequencenumber",
172               "size" : "32",
173               "optional" : "s=1"
174           }
175       ]
176       ```
177
178       The expresion of an optional field can use "**&**" or "**|**" combine multiple conditions, for example for gtpu header, we have below optional fields.
179
180       ```
181       "name" : "gtpu",
182       "layout" : [
183
184           ......
185
186           {
187               "name" : "e",
188               "size" : "1"
189           },
190           {
191               "name" : "s",
192               "size" : "1"
193           },
194           {
195               "name" : "pn",
196               "size" : "1"
197           },
198
199           ......
200
201           {
202               "name" : "teid",
203               "size" : "16"
204           },
205           {
206               "name" : "sequencenumber",
207               "size" : "16",
208               "optional" : "e=1|s=1|pn=1",
209           },
210
211           ......
212       ]
213
214       ```
215
216     * **autoincrease**
217
218       Some field's value cover the length of the payload or size of an optional field in the same header, so it should be auto increased during packet forging. For example the "totallength" of ipv4 header is a autoincrease feild.
219
220       ```
221       "name" : "ipv4",
222       "layout" : [
223
224           ......
225
226           {
227               "name" : "totallength",
228               "size" : "16",
229               "default" : "20",
230               "autoincrease" : "true",
231           },
232
233           ......
234
235       ]
236       ```
237
238       A field which is autoincrease also imply its readonly.
239
240     * **increaselength**
241
242       Typically this should only be enabled for an optional field to trigger another field's autoincrease. For example, the gtpc's "messagelength" field cover all the data start from field "teid", so its default size is 4 bytes which cover sequencenumber + 8 reserved bit, and should be increased if "teid" exist or any payload be appended.
243
244       ```
245       "name" : "gtpc",
246       "layout" : [
247
248           ......
249
250           {
251               "name" : "messagelength",
252               "size" : "16",
253               "default" : "4",
254               "autoincrease" : "true",
255           },
256           {
257               "name" : "teid",
258               "size" : "32",
259               "optional" : "t=1",
260               "increaselength" : "true"
261           },
262           {
263               "name" : "sequencenumber",
264               "size" : "24",
265           },
266           {
267               "name" : "reserved",
268               "size" : "8",
269           }
270       ]
271       ```
272
273 * **attributes**
274
275   This defines an array of attributes, the attribute does not define the data belongs to current protocol header, but it impact the behaviour during applying actions of an edge when the protocol header is involved. For example, a geneve node has attribute "udpport" which define the udp tunnel port, so when it is appended after a udp header, the udp header's dst port is expected to be changed to this value.
276
277   ```
278   "name" : "geneve",
279
280   "fields" : [
281
282       ......
283
284   ],
285   "attributes" : [
286       {
287           "name" : "udpport",
288           "size" : "16",
289           "default" : "6081"
290       }
291   ]
292   ```
293
294   An attribute can only have below properties which take same effect when they are in  field.
295
296   * name
297   * size  (must be fixed value)
298   * default
299   * format
300
301 ### 3. Edge
302
303   A json object of Edge will include below properties:
304
305   * **type**
306
307     This should always be "edge".
308
309   * **start**
310
311     This is the start node of the edge.
312
313   * **end**
314
315     This is the end node of the edge.
316
317   * **actions**
318
319     This is an array of actions the should be applied during packet forging.
320     For example, when append a ipv4 headers after a mac header, the "ethertype" field of mac should be set to "0x0800":
321
322     ```
323     {
324         "type" : "edge",
325         "start" : "mac",
326         "end" : "ipv4",
327         "actions" : [
328             {
329                 "dst" : "start.ethertype",
330                 "src" : "0x0800"
331             }
332         ]
333     }
334     ```
335     Each action should have two properties:
336
337     * **dst**
338
339       This describe the target field to set, it is formatted as <node>.<field>
340       node must be "start" or "end".
341
342     * **src**
343
344       This describe the value to set, it could be a const value or same format as dst's.
345       For example when append a vlan header after mac, we will have below actions:
346
347       ```
348       {
349           "type" : "edge",
350           "start" : "mac",
351           "end" : "vlan",
352           "actions" : [
353               {
354                   "dst" : "start.ethertype",
355                   "src" : "end.tpid"
356               },
357               {
358                   "dst" : "end.ethertype",
359                   "src" : "start.ethertype"
360               }
361           ]
362       }
363       ```
364
365
366   To avoid duplication, multiple edges can be aggregate into the one json object if there actions are same. So, multiple node name can be added to **start** or **end** with seperateor "**,**".
367
368   For example, all ipv6 and ipv6 extention header share the same actions when append a udp header
369
370   ```
371   {
372       "type" : "edge",
373       "start" : "ipv6,ipv6srh,ipv6crh16,ipv6crh32",
374       "end" : "udp",
375       "actions" : [
376           {
377               "dst" : "start.nextheader",
378               "src" : "17"
379           }
380       ]
381   }
382   ```
383
384   Another examples is gre and nvgre share the same actions when be appanded after a ipv4 header:
385   ```
386   {
387       "type" : "edge",
388       "start" : "ipv4",
389       "end" : "gre,nvgre",
390       "actions" : [
391           {
392               "dst" : "start.protocol",
393               "src" : "47"
394           }
395       ]
396   }
397   ```
398
399 ### 4. Path
400
401 A path defines a sequence of nodes which is the input parameter for a packet forging, a packet forging should fail if the path can't be recognised as a subgraph of the parser graph.
402
403 A json object of a path should include below properties:
404
405 * **type**
406
407   This should always be "path".
408
409 * **stack**
410
411   This is an array of node configurations which also imply the protocol header sequence of a packet. Below is an example to forge an ipv4 / udp packet with default value.
412
413   ```
414   {
415       "type" : "path",
416       "stack" : [
417           {
418               "header" : "mac"
419           },
420           {
421               "header" : "ipv4"
422           },
423           {
424               "header" : "udp"
425           },
426       ]
427   }
428   ```
429
430   A node configuration can have below properties:
431
432   * **header**
433
434     This is a protocol name (a node name).
435
436   * **fields**
437
438     This is an array of 3 member tuples:
439
440     * **name**
441
442       The name of the field or attribute that belongs to the node, note a readonly field should not be selected.
443
444     * **value**
445
446       The value to set the field or attribute.
447
448     * **mask**
449
450       This is optional, if it is not defined, corresponding bit of the mask should be set to 0, and it should be ignored for an attribute.
451
452 * **actions**
453
454   This is optional. When this json file is the input of flow adding commands, it can be used directly as the flow rule's action.
455
456   An example to forge a ipv4 packet with src ip address 192.168.0.1 and dst ip address 192.168.0.2, also take ip address as mask.
457
458   ```
459   {
460       "type" : "path",
461       "stack" : [
462           {
463               "header" : "mac",
464           },
465           {
466               "header" : "ipv4",
467               "fields" : [
468                   {
469                       "name" : "src",
470                       "value" : "192.168.0.1",
471                       "mask" : "255.255.255.255"
472                   },
473                   {
474                       "name" : "dst",
475                       "value" : "192.168.0.2",
476                       "mask" : "255.255.255.255"
477                   }
478               ]
479           }
480       ],
481       "actions" : "redirect-to-queue 3"
482   }
483   ```
484
485
486 ### 5. Input Format
487
488 Every field or attribute is associated with an **Input Format**, so the software can figure out how to parse default value in the node or a config value in the path.
489
490 Currently we have 8 predefined format and don't support customised format.
491
492 * **u8**
493
494   accept number from 0 to 255 or hex from 0x0 to 0xff.
495
496 * **u16**
497
498   accept number from 0 to 65535 or hex from 0x0 to 0xffff.
499
500 * **u32**
501
502   accept number from 0 to 4294967295 or hex from 0x0 to 0xffffffff
503
504 * **u64**
505
506   accept number from 0 to 2^64 -1 or hex from 0x0 to 0xffffffffffffffff
507
508 * **mac**
509
510   accept xx:xx:xx:xx:xx:xx , x in hex from 0 to f
511
512 * **ipv4**
513
514   accept n.n.n.n , n from 0 to 255
515
516 * **ipv6**
517
518   accept xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx, x in hex from 0 to f
519
520 * **bytearray**
521
522   accept u8,u8,u8.....
523
524 If format is not defined for a field or attribute, the default format will be selected base on size as below, and the MSB should be ignored by software if the value exceeds the limitation.
525
526 | Size          | Default Format |
527 | ------------- | -------------- |
528 | 1 - 8         | u8             |
529 | 9 - 16        | u16            |
530 | 17 - 32       | u32            |
531 | 33 - 64       | u64            |
532 | > 64          | bytearray      |
533 | variable size | bytearray      |