-
Notifications
You must be signed in to change notification settings - Fork 0
/
simple.p4i
1138 lines (985 loc) · 39.9 KB
/
simple.p4i
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# 1 "simple.p4"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "simple.p4"
/* -*- P4_16 -*- */
# 1 "/usr/local/share/p4c/p4include/core.p4" 1
/*
Copyright 2013-present Barefoot Networks, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/* This is the P4-16 core library, which declares some built-in P4 constructs using P4 */
/// Standard error codes. New error codes can be declared by users.
error {
NoError, /// No error.
PacketTooShort, /// Not enough bits in packet for 'extract'.
NoMatch, /// 'select' expression has no matches.
StackOutOfBounds, /// Reference to invalid element of a header stack.
HeaderTooShort, /// Extracting too many bits into a varbit field.
ParserTimeout, /// Parser execution time limit exceeded.
ParserInvalidArgument /// Parser operation was called with a value
/// not supported by the implementation.
}
extern packet_in {
/// Read a header from the packet into a fixed-sized header @hdr and advance the cursor.
/// May trigger error PacketTooShort or StackOutOfBounds.
/// @T must be a fixed-size header type
void extract<T>(out T hdr);
/// Read bits from the packet into a variable-sized header @variableSizeHeader
/// and advance the cursor.
/// @T must be a header containing exactly 1 varbit field.
/// May trigger errors PacketTooShort, StackOutOfBounds, or HeaderTooShort.
void extract<T>(out T variableSizeHeader,
in bit<32> variableFieldSizeInBits);
/// Read bits from the packet without advancing the cursor.
/// @returns: the bits read from the packet.
/// T may be an arbitrary fixed-size type.
T lookahead<T>();
/// Advance the packet cursor by the specified number of bits.
void advance(in bit<32> sizeInBits);
/// @return packet length in bytes. This method may be unavailable on
/// some target architectures.
bit<32> length();
}
extern packet_out {
/// Write @hdr into the output packet, advancing cursor.
/// @T can be a header type, a header stack, a header_union, or a struct
/// containing fields with such types.
void emit<T>(in T hdr);
}
// TODO: remove from this file, convert to built-in
/// Check a predicate @check in the parser; if the predicate is true do nothing,
/// otherwise set the parser error to @toSignal, and transition to the `reject` state.
extern void verify(in bool check, in error toSignal);
/// Built-in action that does nothing.
@noWarn("unused")
action NoAction() {}
/// Standard match kinds for table key fields.
/// Some architectures may not support all these match kinds.
/// Architectures can declare additional match kinds.
match_kind {
/// Match bits exactly.
exact,
/// Ternary match, using a mask.
ternary,
/// Longest-prefix match.
lpm
}
# 3 "simple.p4" 2
# 1 "/usr/local/share/p4c/p4include/v1model.p4" 1
/*
Copyright 2013-present Barefoot Networks, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/* P4-16 declaration of the P4 v1.0 switch model */
/* Note 1: More details about the definition of v1model architecture
* can be found at the location below.
*
* https://github.com/p4lang/behavioral-model/blob/master/docs/simple_switch.md
*
* Note 2: There were several discussions among P4 working group
* members in early 2019 regarding exactly how resubmit, recirculate,
* and clone3 operations can be called anywhere in their respective
* controls, but the values of the fields to be preserved is the value
* they have when that control is finished executing. That is how
* these operations are defined in P4_14. See
* https://github.com/p4lang/behavioral-model/blob/master/docs/simple_switch.md#restrictions-on-recirculate-resubmit-and-clone-operations
* for more details on the current state of affairs.
*
* Note 3: There are at least some P4_14 implementations where
* invoking a generate_digest operation on a field_list will create a
* message to the control plane that contains the values of those
* fields when the ingress control is finished executing, which can be
* different than the values those fields have at the time the
* generate_digest operation is invoked in the program, if those field
* values are changed later in the execution of the P4_14 ingress
* control.
*
* The P4_16 plus v1model implementation should always create digest
* messages that contain the values of the specified fields at the
* time that the digest extern function is called. Thus if a P4_14
* program expecting the behavior described above is compiled using
* p4c, it may behave differently.
*/
# 1 "/usr/local/share/p4c/p4include/core.p4" 1
/*
Copyright 2013-present Barefoot Networks, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/* This is the P4-16 core library, which declares some built-in P4 constructs using P4 */
# 53 "/usr/local/share/p4c/p4include/v1model.p4" 2
match_kind {
range,
// Either an exact match, or a wildcard (matching any value).
optional,
// Used for implementing dynamic_action_selection
selector
}
const bit<32> __v1model_version = 20180101;
@metadata @name("standard_metadata")
struct standard_metadata_t {
bit<9> ingress_port;
bit<9> egress_spec;
bit<9> egress_port;
bit<32> instance_type;
bit<32> packet_length;
//
// @alias is used to generate the field_alias section of the BMV2 JSON.
// Field alias creates a mapping from the metadata name in P4 program to
// the behavioral model's internal metadata name. Here we use it to
// expose all metadata supported by simple switch to the user through
// standard_metadata_t.
//
// flattening fields that exist in bmv2-ss
// queueing metadata
@alias("queueing_metadata.enq_timestamp")
bit<32> enq_timestamp;
@alias("queueing_metadata.enq_qdepth")
bit<19> enq_qdepth;
@alias("queueing_metadata.deq_timedelta")
bit<32> deq_timedelta;
/// queue depth at the packet dequeue time.
@alias("queueing_metadata.deq_qdepth")
bit<19> deq_qdepth;
// intrinsic metadata
@alias("intrinsic_metadata.ingress_global_timestamp")
bit<48> ingress_global_timestamp;
@alias("intrinsic_metadata.egress_global_timestamp")
bit<48> egress_global_timestamp;
/// multicast group id (key for the mcast replication table)
@alias("intrinsic_metadata.mcast_grp")
bit<16> mcast_grp;
/// Replication ID for multicast
@alias("intrinsic_metadata.egress_rid")
bit<16> egress_rid;
/// Indicates that a verify_checksum() method has failed.
/// 1 if a checksum error was found, otherwise 0.
bit<1> checksum_error;
/// Error produced by parsing
error parser_error;
/// set packet priority
@alias("intrinsic_metadata.priority")
bit<3> priority;
}
enum CounterType {
packets,
bytes,
packets_and_bytes
}
enum MeterType {
packets,
bytes
}
extern counter
{
/***
* A counter object is created by calling its constructor. This
* creates an array of counter states, with the number of counter
* states specified by the size parameter. The array indices are
* in the range [0, size-1].
*
* You must provide a choice of whether to maintain only a packet
* count (CounterType.packets), only a byte count
* (CounterType.bytes), or both (CounterType.packets_and_bytes).
*
* Counters can be updated from your P4 program, but can only be
* read from the control plane. If you need something that can be
* both read and written from the P4 program, consider using a
* register.
*/
counter(bit<32> size, CounterType type);
// FIXME -- size arg should be `int` but that breaks typechecking
/***
* count() causes the counter state with the specified index to be
* read, modified, and written back, atomically relative to the
* processing of other packets, updating the packet count, byte
* count, or both, depending upon the CounterType of the counter
* instance used when it was constructed.
*
* @param index The index of the counter state in the array to be
* updated, normally a value in the range [0,
* size-1]. If index >= size, no counter state will be
* updated.
*/
void count(in bit<32> index);
}
extern direct_counter {
/***
* A direct_counter object is created by calling its constructor.
* You must provide a choice of whether to maintain only a packet
* count (CounterType.packets), only a byte count
* (CounterType.bytes), or both (CounterType.packets_and_bytes).
* After constructing the object, you can associate it with at
* most one table, by adding the following table property to the
* definition of that table:
*
* counters = <object_name>;
*
* Counters can be updated from your P4 program, but can only be
* read from the control plane. If you need something that can be
* both read and written from the P4 program, consider using a
* register.
*/
direct_counter(CounterType type);
/***
* The count() method is actually unnecessary in the v1model
* architecture. This is because after a direct_counter object
* has been associated with a table as described in the
* documentation for the direct_counter constructor, every time
* the table is applied and a table entry is matched, the counter
* state associated with the matching entry is read, modified, and
* written back, atomically relative to the processing of other
* packets, regardless of whether the count() method is called in
* the body of that action.
*/
void count();
}
extern meter
{
/***
* A meter object is created by calling its constructor. This
* creates an array of meter states, with the number of meter
* states specified by the size parameter. The array indices are
* in the range [0, size-1]. For example, if in your system you
* have 128 different "flows" numbered from 0 up to 127, and you
* want to meter each of those flows independently of each other,
* you could do so by creating a meter object with size=128.
*
* You must provide a choice of whether to meter based on the
* number of packets, regardless of their size
* (MeterType.packets), or based upon the number of bytes the
* packets contain (MeterType.bytes).
*/
meter(bit<32> size, MeterType type);
// FIXME -- size arg should be `int` but that breaks typechecking
/***
* execute_meter() causes the meter state with the specified index
* to be read, modified, and written back, atomically relative to
* the processing of other packets, and an integer encoding of one
* of the colors green, yellow, or red to be written to the result
* out parameter.
*
* @param index The index of the meter state in the array to be
* updated, normally a value in the range [0,
* size-1]. If index >= size, no meter state will be
* updated.
* @param result Type T must be bit<W> with W >= 2. When index is
* in range, the value of result will be assigned 0
* for color GREEN, 1 for color YELLOW, and 2 for
* color RED (see RFC 2697 and RFC 2698 for the
* meaning of these colors). When index is out of
* range, the final value of result is not specified,
* and should be ignored by the caller.
*/
void execute_meter<T>(in bit<32> index, out T result);
}
extern direct_meter<T> {
/***
* A direct_meter object is created by calling its constructor.
* You must provide a choice of whether to meter based on the
* number of packets, regardless of their size
* (MeterType.packets), or based upon the number of bytes the
* packets contain (MeterType.bytes). After constructing the
* object, you can associate it with at most one table, by adding
* the following table property to the definition of that table:
*
* meters = <object_name>;
*/
direct_meter(MeterType type);
/***
* After a direct_meter object has been associated with a table as
* described in the documentation for the direct_meter
* constructor, every time the table is applied and a table entry
* is matched, the meter state associated with the matching entry
* is read, modified, and written back, atomically relative to the
* processing of other packets, regardless of whether the read()
* method is called in the body of that action.
*
* read() may only be called within an action executed as a result
* of matching a table entry, of a table that has a direct_meter
* associated with it. Calling read() causes an integer encoding
* of one of the colors green, yellow, or red to be written to the
* result out parameter.
*
* @param result Type T must be bit<W> with W >= 2. The value of
* result will be assigned 0 for color GREEN, 1 for
* color YELLOW, and 2 for color RED (see RFC 2697
* and RFC 2698 for the meaning of these colors).
*/
void read(out T result);
}
extern register<T>
{
/***
* A register object is created by calling its constructor. This
* creates an array of 'size' identical elements, each with type
* T. The array indices are in the range [0, size-1]. For
* example, this constructor call:
*
* register<bit<32>>(512) my_reg;
*
* allocates storage for 512 values, each with type bit<32>.
*/
register(bit<32> size); // FIXME -- arg should be `int` but that breaks typechecking
/***
* read() reads the state of the register array stored at the
* specified index, and returns it as the value written to the
* result parameter.
*
* @param index The index of the register array element to be
* read, normally a value in the range [0, size-1].
* @param result Only types T that are bit<W> are currently
* supported. When index is in range, the value of
* result becomes the value read from the register
* array element. When index >= size, the final
* value of result is not specified, and should be
* ignored by the caller.
*/
@noSideEffects
void read(out T result, in bit<32> index);
/***
* write() writes the state of the register array at the specified
* index, with the value provided by the value parameter.
*
* If you wish to perform a read() followed later by a write() to
* the same register array element, and you wish the
* read-modify-write sequence to be atomic relative to other
* processed packets, then there may be parallel implementations
* of the v1model architecture for which you must execute them in
* a P4_16 block annotated with an @atomic annotation. See the
* P4_16 language specification description of the @atomic
* annotation for more details.
*
* @param index The index of the register array element to be
* written, normally a value in the range [0,
* size-1]. If index >= size, no register state will
* be updated.
* @param value Only types T that are bit<W> are currently
* supported. When index is in range, this
* parameter's value is written into the register
* array element specified by index.
*/
void write(in bit<32> index, in T value);
}
// used as table implementation attribute
extern action_profile {
action_profile(bit<32> size);
}
/***
* Generate a random number in the range lo..hi, inclusive, and write
* it to the result parameter. The value written to result is not
* specified if lo > hi.
*
* @param T Must be a type bit<W>
*/
extern void random<T>(out T result, in T lo, in T hi);
/***
* Calling digest causes a message containing the values specified in
* the data parameter to be sent to the control plane software. It is
* similar to sending a clone of the packet to the control plane
* software, except that it can be more efficient because the messages
* are typically smaller than packets, and many such small digest
* messages are typically coalesced together into a larger "batch"
* which the control plane software processes all at once.
*
* The value of the fields that are sent in the message to the control
* plane is the value they have at the time the digest call occurs,
* even if those field values are changed by later ingress control
* code. See Note 3.
*
* Calling digest is only supported in the ingress control. There is
* no way to undo its effects once it has been called.
*
* If the type T is a named struct, the name is used to generate the
* control plane API.
*
* The BMv2 implementation of the v1model architecture ignores the
* value of the receiver parameter.
*/
extern void digest<T>(in bit<32> receiver, in T data);
enum HashAlgorithm {
crc32,
crc32_custom,
crc16,
crc16_custom,
random,
identity,
csum16,
xor16
}
@deprecated("Please use mark_to_drop(standard_metadata) instead.")
extern void mark_to_drop();
/***
* mark_to_drop(standard_metadata) is a primitive action that modifies
* standard_metadata.egress_spec to an implementation-specific special
* value that in some cases causes the packet to be dropped at the end
* of ingress or egress processing. It also assigns 0 to
* standard_metadata.mcast_grp. Either of those metadata fields may
* be changed by executing later P4 code, after calling
* mark_to_drop(), and this can change the resulting behavior of the
* packet to do something other than drop.
*
* See
* https://github.com/p4lang/behavioral-model/blob/master/docs/simple_switch.md
* -- in particular the section "Pseudocode for what happens at the
* end of ingress and egress processing" -- for the relative priority
* of the different possible things that can happen to a packet when
* ingress and egress processing are complete.
*/
@pure
extern void mark_to_drop(inout standard_metadata_t standard_metadata);
/***
* Calculate a hash function of the value specified by the data
* parameter. The value written to the out parameter named result
* will always be in the range [base, base+max-1] inclusive, if max >=
* 1. If max=0, the value written to result will always be base.
*
* Note that the types of all of the parameters may be the same as, or
* different from, each other, and thus their bit widths are allowed
* to be different.
*
* @param O Must be a type bit<W>
* @param D Must be a tuple type where all the fields are bit-fields (type bit<W> or int<W>) or varbits.
* @param T Must be a type bit<W>
* @param M Must be a type bit<W>
*/
@pure
extern void hash<O, T, D, M>(out O result, in HashAlgorithm algo, in T base, in D data, in M max);
extern action_selector {
action_selector(HashAlgorithm algorithm, bit<32> size, bit<32> outputWidth);
}
enum CloneType {
I2E,
E2E
}
@deprecated("Please use verify_checksum/update_checksum instead.")
extern Checksum16 {
Checksum16();
bit<16> get<D>(in D data);
}
/***
* Verifies the checksum of the supplied data. If this method detects
* that a checksum of the data is not correct, then the value of the
* standard_metadata checksum_error field will be equal to 1 when the
* packet begins ingress processing.
*
* Calling verify_checksum is only supported in the VerifyChecksum
* control.
*
* @param T Must be a tuple type where all the tuple elements
* are of type bit<W>, int<W>, or varbit<W>. The
* total length of the fields must be a multiple of
* the output size.
* @param O Checksum type; must be bit<X> type.
* @param condition If 'false' the verification always succeeds.
* @param data Data whose checksum is verified.
* @param checksum Expected checksum of the data; note that it must
* be a left-value.
* @param algo Algorithm to use for checksum (not all algorithms
* may be supported). Must be a compile-time
* constant.
*/
extern void verify_checksum<T, O>(in bool condition, in T data, in O checksum, HashAlgorithm algo);
/***
* Computes the checksum of the supplied data and writes it to the
* checksum parameter.
*
* Calling update_checksum is only supported in the ComputeChecksum
* control.
*
* @param T Must be a tuple type where all the tuple elements
* are of type bit<W>, int<W>, or varbit<W>. The
* total length of the fields must be a multiple of
* the output size.
* @param O Output type; must be bit<X> type.
* @param condition If 'false' the checksum parameter is not changed
* @param data Data whose checksum is computed.
* @param checksum Checksum of the data.
* @param algo Algorithm to use for checksum (not all algorithms
* may be supported). Must be a compile-time
* constant.
*/
@pure
extern void update_checksum<T, O>(in bool condition, in T data, inout O checksum, HashAlgorithm algo);
/***
* verify_checksum_with_payload is identical in all ways to
* verify_checksum, except that it includes the payload of the packet
* in the checksum calculation. The payload is defined as "all bytes
* of the packet which were not parsed by the parser".
*
* Calling verify_checksum_with_payload is only supported in the
* VerifyChecksum control.
*/
extern void verify_checksum_with_payload<T, O>(in bool condition, in T data, in O checksum, HashAlgorithm algo);
/**
* update_checksum_with_payload is identical in all ways to
* update_checksum, except that it includes the payload of the packet
* in the checksum calculation. The payload is defined as "all bytes
* of the packet which were not parsed by the parser".
*
* Calling update_checksum_with_payload is only supported in the
* ComputeChecksum control.
*/
@noSideEffects
extern void update_checksum_with_payload<T, O>(in bool condition, in T data, inout O checksum, HashAlgorithm algo);
/***
* Calling resubmit during execution of the ingress control will,
* under certain documented conditions, cause the packet to be
* resubmitted, i.e. it will begin processing again with the parser,
* with the contents of the packet exactly as they were when it last
* began parsing. The only difference is in the value of the
* standard_metadata instance_type field, and any user-defined
* metadata fields that the resubmit operation causes to be
* preserved.
*
* The value of the user-defined metadata fields that are preserved in
* resubmitted packets is the value they have at the end of ingress
* processing, not their values at the time the resubmit call is made.
* See Note 2 for issues with this.
*
* Calling resubmit is only supported in the ingress control. There
* is no way to undo its effects once it has been called. If resubmit
* is called multiple times during a single execution of the ingress
* control, only one packet is resubmitted, and only the data from the
* last such call is preserved. See the v1model architecture
* documentation (Note 1) for more details.
*/
extern void resubmit<T>(in T data);
/***
* Calling recirculate during execution of the egress control will,
* under certain documented conditions, cause the packet to be
* recirculated, i.e. it will begin processing again with the parser,
* with the contents of the packet as they are created by the
* deparser. Recirculated packets can be distinguished from new
* packets in ingress processing by the value of the standard_metadata
* instance_type field. The caller may request that some user-defined
* metadata fields be preserved with the recirculated packet.
*
* The value of the user-defined metadata fields that are preserved in
* recirculated packets is the value they have at the end of egress
* processing, not their values at the time the recirculate call is
* made. See Note 2 for issues with this.
*
* Calling recirculate is only supported in the egress control. There
* is no way to undo its effects once it has been called. If
* recirculate is called multiple times during a single execution of
* the egress control, only one packet is recirculated, and only the
* data from the last such call is preserved. See the v1model
* architecture documentation (Note 1) for more details.
*/
extern void recirculate<T>(in T data);
/***
* clone is in most ways identical to the clone3 operation, with the
* only difference being that it never preserves any user-defined
* metadata fields with the cloned packet. It is equivalent to
* calling clone3 with the same type and session parameter values,
* with empty data.
*/
extern void clone(in CloneType type, in bit<32> session);
/***
* Calling clone3 during execution of the ingress or egress control
* will cause the packet to be cloned, sometimes also called
* mirroring, i.e. zero or more copies of the packet are made, and
* each will later begin egress processing as an independent packet
* from the original packet. The original packet continues with its
* normal next steps independent of the clone(s).
*
* The session parameter is an integer identifying a clone session id
* (sometimes called a mirror session id). The control plane software
* must configure each session you wish to use, or else no clones will
* be made using that session. Typically this will involve the
* control plane software specifying one output port to which the
* cloned packet should be sent, or a list of (port, egress_rid) pairs
* to which a separate clone should be created for each, similar to
* multicast packets.
*
* Cloned packets can be distinguished from others by the value of the
* standard_metadata instance_type field.
*
* The caller may request that some user-defined metadata field values
* from the original packet should be preserved with the cloned
* packet(s). The value of the user-defined metadata fields that are
* preserved with cloned packets is the value they have at the end of
* ingress or egress processing, not their values at the time the
* clone3 call is made. See Note 2 for issues with this.
*
* If clone3 is called during ingress processing, the first parameter
* must be CloneType.I2E. If clone3 is called during egress
* processing, the first parameter must be CloneType.E2E.
*
* There is no way to undo its effects once it has been called. If
* there are multiple calls to clone3 and/or clone during a single
* execution of the same ingress (or egress) control, only the last
* clone session and data are used. See the v1model architecture
* documentation (Note 1) for more details.
*/
extern void clone3<T>(in CloneType type, in bit<32> session, in T data);
extern void truncate(in bit<32> length);
/***
* Calling assert when the argument is true has no effect, except any
* effect that might occur due to evaluation of the argument (but see
* below). If the argument is false, the precise behavior is
* target-specific, but the intent is to record or log which assert
* statement failed, and optionally other information about the
* failure.
*
* For example, on the simple_switch target, executing an assert
* statement with a false argument causes a log message with the file
* name and line number of the assert statement to be printed, and
* then the simple_switch process exits.
*
* If you provide the --ndebug command line option to p4c when
* compiling, the compiled program behaves as if all assert statements
* were not present in the source code.
*
* We strongly recommend that you avoid using expressions as an
* argument to an assert call that can have side effects, e.g. an
* extern method or function call that has side effects. p4c will
* allow you to do this with no warning given. We recommend this
* because, if you follow this advice, your program will behave the
* same way when assert statements are removed.
*/
extern void assert(in bool check);
/***
* For the purposes of compiling and executing P4 programs on a target
* device, assert and assume are identical, including the use of the
* --ndebug p4c option to elide them. See documentation for assert.
*
* The reason that assume exists as a separate function from assert is
* because they are expected to be used differently by formal
* verification tools. For some formal tools, the goal is to try to
* find example packets and sets of installed table entries that cause
* an assert statement condition to be false.
*
* Suppose you run such a tool on your program, and the example packet
* given is an MPLS packet, i.e. hdr.ethernet.etherType == 0x8847.
* You look at the example, and indeed it does cause an assert
* condition to be false. However, your plan is to deploy your P4
* program in a network in places where no MPLS packets can occur.
* You could add extra conditions to your P4 program to handle the
* processing of such a packet cleanly, without assertions failing,
* but you would prefer to tell the tool "such example packets are not
* applicable in my scenario -- never show them to me". By adding a
* statement:
*
* assume(hdr.ethernet.etherType != 0x8847);
*
* at an appropriate place in your program, the formal tool should
* never show you such examples -- only ones that make all such assume
* conditions true.
*
* The reason that assume statements behave the same as assert
* statements when compiled to a target device is that if the
* condition ever evaluates to false when operating in a network, it
* is likely that your assumption was wrong, and should be reexamined.
*/
extern void assume(in bool check);
/*
* Log user defined messages
* Example: log_msg("User defined message");
* or log_msg("Value1 = {}, Value2 = {}",{value1, value2});
*/
extern void log_msg(string msg);
extern void log_msg<T>(string msg, in T data);
// The name 'standard_metadata' is reserved
/*
* Architecture.
*
* M must be a struct.
*
* H must be a struct where every one if its members is of type
* header, header stack, or header_union.
*/
parser Parser<H, M>(packet_in b,
out H parsedHdr,
inout M meta,
inout standard_metadata_t standard_metadata);
/*
* The only legal statements in the body of the VerifyChecksum control
* are: block statements, calls to the verify_checksum and
* verify_checksum_with_payload methods, and return statements.
*/
control VerifyChecksum<H, M>(inout H hdr,
inout M meta);
@pipeline
control Ingress<H, M>(inout H hdr,
inout M meta,
inout standard_metadata_t standard_metadata);
@pipeline
control Egress<H, M>(inout H hdr,
inout M meta,
inout standard_metadata_t standard_metadata);
/*
* The only legal statements in the body of the ComputeChecksum
* control are: block statements, calls to the update_checksum and
* update_checksum_with_payload methods, and return statements.
*/
control ComputeChecksum<H, M>(inout H hdr,
inout M meta);
/*
* The only legal statements in the body of the Deparser control are:
* calls to the packet_out.emit() method.
*/
@deparser
control Deparser<H>(packet_out b, in H hdr);
package V1Switch<H, M>(Parser<H, M> p,
VerifyChecksum<H, M> vr,
Ingress<H, M> ig,
Egress<H, M> eg,
ComputeChecksum<H, M> ck,
Deparser<H> dep
);
# 4 "simple.p4" 2
const bit<16> TYPE_IPV4 = 0x800;
const bit<8> TYPE_TCP = 6;
const bit<16> TYPE_LLDP_IN = 5;
const bit<16> TYPE_LLDP_OUT = 4;
/*************************************************************************
*********************** H E A D E R S ***********************************
*************************************************************************/
typedef bit<9> egressSpec_t;
typedef bit<48> macAddr_t;
typedef bit<48> ip4Addr_t;
header ethernet_t {
macAddr_t dstAddr;
macAddr_t srcAddr;
bit<16> etherType;
}
header ipv4_t {
bit<4> version;
bit<4> ihl;
bit<8> diffserv;
bit<16> totalLen;
bit<16> identification;
bit<3> flags;
bit<13> fragOffset;
bit<8> ttl;
bit<8> protocol;
bit<16> hdrChecksum;
ip4Addr_t srcAddr;
ip4Addr_t dstAddr;
}
header tcp_t{
bit<16> srcPort;
bit<16> dstPort;
bit<32> seqNo;
bit<32> ackNo;
bit<4> dataOffset;
bit<4> res;
bit<1> cwr;
bit<1> ece;
bit<1> urg;
bit<1> ack;
bit<1> psh;
bit<1> rst;
bit<1> syn;
bit<1> fin;
bit<16> window;
bit<16> checksum;
bit<16> urgentPtr;
}
// packet in
//@controller_header("packet_in")
header packet_in_header_t {
bit<64> zeros;
bit<16> ingress_port;
bit<16> type;
}
// packet out
//@controller_header("packet_out")
//header packet_out_header_t {
//bit<16> egress_port;
//bit<16> TYPE;
//}
struct metadata {
//@metadate
//bit<16> ingress_port;
//@metadata @name("TYPE")
//bit<16> TYPE;
// bit<32> counter;
// bit<8> flow_id;
// bit<16> count;
// bit<8> index;
// bit<1> enabled;
// bit<32> ingress_port;
}
struct headers {
packet_in_header_t packet_in_header;
//packet_out_header_t packet_out_header;
ethernet_t ethernet;
ipv4_t ipv4;
//tcp_t tcp;
}
/*************************************************************************
*********************** P A R S E R ***********************************
*************************************************************************/
parser MyParser(packet_in packet,
out headers hdr,
inout metadata meta,
inout standard_metadata_t standard_metadata) {
state start {
transition select(packet.lookahead<packet_in_header_t>().zeros){
(bit<64>)0 : parse_packet_in_header;
//CPU_PORT: parse_packet_out;
default: parse_ethernet;
}
//packet.extract(hdr.packet_out_header);
//transition parse_ethernet;
}
state parse_packet_in_header {
packet.extract(hdr.packet_in_header);
transition parse_ethernet;
}
state parse_ethernet {
packet.extract(hdr.ethernet);
transition select(hdr.ethernet.etherType) {
TYPE_IPV4: parse_ipv4;
default: accept;
}
}
state parse_ipv4 {
packet.extract(hdr.ipv4);
transition accept;
}