forked from ocaml-attic/ocaml-openflow
/
ofpacket.ml
2442 lines (2218 loc) · 86.4 KB
/
ofpacket.ml
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
(*
* Copyright (c) 2011 Richard Mortier <mort@cantab.net>
Charalampos Rotsos <cr409@cl.cam.ac.uk>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*)
open Printf
open Lwt
open Int32
(* open Cstruct *)
let sp = Printf.sprintf
let pp = Printf.printf
let ep = Printf.eprintf
exception Unparsable of string * Cstruct.buf
exception Unparsed of string * Cstruct.buf
exception Unsupported of string
let resolve t = Lwt.on_success t (fun _ -> ())
let (|>) x f = f x (* pipe *)
let (>>) f g x = g (f x) (* functor pipe *)
let (||>) l f = List.map f l (* element-wise pipe *)
let (+++) x y = Int32.add x y
let (&&&) x y = Int32.logand x y
let (|||) x y = Int32.logor x y
let (^^^) x y = Int32.logxor x y
let (<<<) x y = Int32.shift_left x y
let (>>>) x y = Int32.shift_right_logical x y
let join c l = String.concat c l
let stop (x, bits) = x (* drop remainder to stop parsing and demuxing *)
type int16 = int
(* XXX of dubious merit - but we don't do arithmetic so prefer the
documentation benefits for now *)
type uint8 = char
type uint16 = int
type uint32 = int32
type uint64 = int64
let uint8_of_int i = Char.chr i
(* XXX network specific types that should have a proper home *)
type ipv4 = uint32
let ipv4_to_string i =
sp "%ld.%ld.%ld.%ld"
((i &&& 0x0_ff000000_l) >>> 24) ((i &&& 0x0_00ff0000_l) >>> 16)
((i &&& 0x0_0000ff00_l) >>> 8) ((i &&& 0x0_000000ff_l) )
type byte = uint8
let byte (i:int) : byte = Char.chr i
let int_of_byte b = int_of_char b
let int32_of_byte b = b |> int_of_char |> Int32.of_int
let int32_of_int (i:int) = Int32.of_int i
type bytes = string
type eaddr = bytes
let bytes_to_hex_string bs =
bs |> Array.map (fun b -> sp "%02x." (int_of_byte b))
let eaddr_to_string s =
let l = String.length s in
let hp s i = sp "%02x" (int_of_char s.[i]) in
String.concat ":" (Array.init l (fun i -> hp s i) |> Array.to_list)
(* let bitstring_of_eaddr s =
(BITSTRING{s:48:string}) *)
let eaddr_is_broadcast s =
match s with
| "\xFF\xFF\xFF\xFF\xFF\xFF" -> true
| _ -> false
let ipv4_addr_of_bytes bs =
((bs.[0] |> int32_of_byte <<< 24) ||| (bs.[1] |> int32_of_byte <<< 16)
||| (bs.[2] |> int32_of_byte <<< 8) ||| (bs.[3] |> int32_of_byte))
(*********************************************************************** *)
(* for readability *)
type vendor = uint32
type queue_id = uint32
type datapath_id = uint64
let contain_exc l v =
try
Some (v ())
with exn ->
eprintf "ofpacket %s exn: %s\n%!" l (Printexc.to_string exn);
None
(*
* bit manipulation functions for 32-bit integers
* *)
let int_of_bool = function
| true -> 1
| false -> 0
let get_int32_bit f off = (Int32.logand f (Int32.shift_left 1l off)) > 0l
let set_int32_bit f off v =
logor f (Int32.shift_left (Int32.of_int(int_of_bool v)) off)
let get_int32_byte f off =
let ret = Int32.shift_left (f logand (Int32.shift_left 13l off)) off in
char_of_int (0x00ff land (Int32.to_int ret))
let set_int32_byte f off v =
let value = Int32.of_int ((int_of_char v) lsl off) in
logor f value
let get_int32_nw_mask f off =
let ret = Int32.shift_left (logand f (Int32.shift_left 13l off)) off in
char_of_int (0x003f land (Int32.to_int ret))
let set_int32_nw_mask f off v =
let value = Int32.of_int ((0x3f land v) lsl off) in
logor f value
let get_int_bit f off = (f land (1 lsl off)) > 0
let set_int_bit f off v = f lor ((int_of_bool v) lsl off)
let marshal_and_sub fn bits =
let len = fn bits in
Cstruct.sub bits 0 len
let marshal_and_shift fn bits =
let len = fn bits in
(len, (Cstruct.shift bits len))
module Header = struct
cstruct ofp_header {
uint8_t version;
uint8_t typ;
uint16_t length;
uint32_t xid
} as big_endian
cenum msg_code {
HELLO = 0;
ERROR = 1;
ECHO_REQ = 2;
ECHO_RESP = 3;
VENDOR = 4;
FEATURES_REQ = 5;
FEATURES_RESP = 6;
GET_CONFIG_REQ = 7;
GET_CONFIG_RESP = 8;
SET_CONFIG = 9;
PACKET_IN = 10;
FLOW_REMOVED = 11;
PORT_STATUS = 12;
PACKET_OUT = 13;
FLOW_MOD = 14;
PORT_MOD = 15;
STATS_REQ = 16;
STATS_RESP = 17;
BARRIER_REQ = 18;
BARRIER_RESP = 19;
QUEUE_GET_CONFIG_REQ = 20;
QUEUE_GET_CONFIG_RESP = 21
} as uint8_t
type h = {
ver: uint8;
ty: msg_code;
len: uint16;
xid: uint32;
}
let get_len = 8
let parse_header bits =
match ((get_ofp_header_version bits),
(int_to_msg_code (get_ofp_header_typ bits))) with
| (1, Some(ty))
-> let ret =
{ ver=(char_of_int (get_ofp_header_version bits));
ty;
len=(get_ofp_header_length bits);
xid=(get_ofp_header_xid bits); } in
let _ = Cstruct.shift bits sizeof_ofp_header in
ret
| (_, _) -> raise (Unparsable ("parse_h", bits))
let header_to_string h =
sp "ver:%d type:%s len:%d xid:0x%08lx"
(int_of_byte h.ver) (msg_code_to_string h.ty) h.len h.xid
let create ty len xid =
{ ver=byte 1; ty; len; xid }
let marshal_header h bits =
let _ = set_ofp_header_version bits 1 in
let _ = set_ofp_header_typ bits (msg_code_to_int h.ty) in
let _ = set_ofp_header_length bits h.len in
let _ = set_ofp_header_xid bits h.xid in
sizeof_ofp_header
end
module Queue = struct
type h = {
queue_id: queue_id;
}
type t = NONE | MIN_RATE of uint16
end
module Port = struct
type t =
| Max | In_port | Table | Normal | Flood | All
| Controller | Local | No_port
| Port of int16
let port_of_int = function
| 0xff00 -> Max
| 0xfff8 -> In_port
| 0xfff9 -> Table
| 0xfffa -> Normal
| 0xfffb -> Flood
| 0xfffc -> All
| 0xfffd -> Controller
| 0xfffe -> Local
| 0xffff -> No_port
| p -> Port p
and int_of_port = function
| Max -> 0xff00
| In_port -> 0xfff8
| Table -> 0xfff9
| Normal -> 0xfffa
| Flood -> 0xfffb
| All -> 0xfffc
| Controller -> 0xfffd
| Local -> 0xfffe
| No_port -> 0xffff
| Port p -> p
and string_of_port = function
| Max -> sp "MAX"
| In_port -> sp "IN_PORT"
| Table -> sp "TABLE"
| Normal -> sp "NORMAL"
| Flood -> sp "FLOOD"
| All -> sp "ALL"
| Controller -> sp "CONTROLLER"
| Local -> sp "LOCAL"
| No_port -> sp "NO_PORT"
| Port p -> sp "PORT(%d)" p
type config = {
port_down: bool;
no_stp: bool;
no_recv: bool;
no_recv_stp: bool;
no_flood: bool;
no_fwd: bool;
no_packet_in: bool;
}
let parse_config bits =
{ port_down=(get_int32_bit bits 0);
no_stp=(get_int32_bit bits 1);
no_recv=(get_int32_bit bits 2);
no_recv_stp=(get_int32_bit bits 3);
no_flood=(get_int32_bit bits 4);
no_fwd=(get_int32_bit bits 5);
no_packet_in=(get_int32_bit bits 6);}
let marshal_config config =
let ret = 0l in
let ret = set_int32_bit ret 0 config.port_down in
let ret = set_int32_bit ret 1 config.no_stp in
let ret = set_int32_bit ret 2 config.no_recv in
let ret = set_int32_bit ret 3 config.no_recv_stp in
let ret = set_int32_bit ret 4 config.no_flood in
let ret = set_int32_bit ret 5 config.no_fwd in
let ret = set_int32_bit ret 6 config.no_packet_in in
ret
let init_port_config =
{port_down=false; no_stp=false; no_recv=false; no_recv_stp=false;
no_flood=false; no_fwd=false; no_packet_in=false; }
type features = {
pause_asym: bool;
pause: bool;
autoneg: bool;
fiber: bool;
copper: bool;
f_10GB_FD: bool;
f_1GB_FD: bool;
f_1GB_HD: bool;
f_100MB_FD: bool;
f_100MB_HD: bool;
f_10MB_FD: bool;
f_10MB_HD: bool;
}
let parse_features bits =
{ pause_asym=(get_int32_bit bits 11);
pause=(get_int32_bit bits 10);
autoneg=(get_int32_bit bits 9);
fiber=(get_int32_bit bits 8);
copper=(get_int32_bit bits 7);
f_10GB_FD=(get_int32_bit bits 6);
f_1GB_FD=(get_int32_bit bits 5);
f_1GB_HD=(get_int32_bit bits 4);
f_100MB_FD=(get_int32_bit bits 3);
f_100MB_HD=(get_int32_bit bits 2);
f_10MB_FD=(get_int32_bit bits 1);
f_10MB_HD=(get_int32_bit bits 0);}
let init_port_features =
{pause_asym=false; pause=false; autoneg=false;
fiber=false; copper=false; f_10GB_FD=false; f_1GB_FD=false;
f_1GB_HD=false; f_100MB_FD=false; f_100MB_HD=false; f_10MB_FD=false;
f_10MB_HD=false; };
type state = {
link_down: bool;
stp_listen: bool;
stp_learn: bool;
stp_forward: bool;
stp_block: bool;
}
let get_link_down f = (logand f 1l) > 0l
let get_stp_listen f = (logand f (Int32.shift_left 0l 8)) > 0l
let get_stp_learn f = (logand f (Int32.shift_left 1l 8)) > 0l
let get_stp_forward f = (logand f (Int32.shift_left 2l 8)) > 0l
let get_stp_block f = (logand f (Int32.shift_left 3l 8)) > 0l
(*TODO this parsing is incorrect. use get_int32_bit and I think
* set_stp_forward is a byte *)
let set_link_down f v = f logor (Int32.of_int (int_of_bool v))
let set_stp_listen f v =
logor f (shift_left (Int32.of_int (int_of_bool v)) 8)
let set_stp_learn f v =
logor f (shift_left (Int32.of_int (int_of_bool v)) 8)
let set_stp_forward f v =
logor f (shift_left (Int32.of_int (int_of_bool v)) 8)
let set_stp_block f v =
logor f (shift_left (Int32.of_int (int_of_bool v)) 8)
let parse_state bits =
{ link_down=(get_link_down bits);
stp_listen=(get_stp_listen bits);
stp_learn=(get_stp_learn bits);
stp_forward=(get_stp_forward bits);
stp_block=(get_stp_block bits); }
let init_port_state =
{link_down=false; stp_listen=false; stp_learn=false; stp_forward=false;
stp_block=false; }
type phy = {
port_no: uint16;
hw_addr: eaddr;
name: string;
config: config;
state: state;
curr: features;
advertised: features;
supported: features;
peer: features;
}
cstruct ofp_phy_port {
uint16_t port_no;
uint8_t hw_addr[6];
uint8_t name[16];
uint32_t config;
uint32_t state;
uint32_t curr;
uint32_t advertised;
uint32_t supported;
uint32_t peer
} as big_endian
let max_name_len = 16
let phy_len = 48
let parse_phy bits =
let port_no = (get_ofp_phy_port_port_no bits) in
let hw_addr=(Cstruct.to_string (get_ofp_phy_port_hw_addr bits)) in
let name=(Cstruct.to_string (get_ofp_phy_port_name bits)) in
let config = (parse_config (get_ofp_phy_port_config bits)) in
let state = (parse_state (get_ofp_phy_port_state bits)) in
let curr = (parse_features (get_ofp_phy_port_curr bits)) in
let advertised = (parse_features (get_ofp_phy_port_advertised bits)) in
let supported = (parse_features (get_ofp_phy_port_supported bits)) in
let peer = (parse_features (get_ofp_phy_port_peer bits)) in
let _ = Cstruct.shift bits sizeof_ofp_phy_port in
{port_no; hw_addr; name; config; state; curr; advertised;
supported; peer; }
let parse_phys bits =
let rec aux ports bits =
match (Cstruct.len bits) with
| 0 -> ports
| l when (l >= sizeof_ofp_phy_port ) ->
aux ((parse_phy bits) :: ports)
(Cstruct.shift bits sizeof_ofp_phy_port)
| _ -> raise (Unparsable("parse_phys", bits))
in
aux [] bits
let init_port_phy ?(port_no = 0) ?(hw_addr="\x11\x11\x11\x11\x11\x11")
?(name="") () =
{port_no; hw_addr; name; config=init_port_config;
state=init_port_state; curr=init_port_features;
advertised=init_port_features; supported=init_port_features;
peer=init_port_features;}
let marshal_phy phy bits =
let _ = set_ofp_phy_port_port_no bits phy.port_no in
let _ = set_ofp_phy_port_hw_addr phy.hw_addr 0 bits in
let name = String.make 16 (char_of_int 0) in
let _ = String.blit phy.name 0 name 0 (String.length phy.name) in
let _ = set_ofp_phy_port_name name 0 bits in
let _ = set_ofp_phy_port_config bits 0l in
let _ = set_ofp_phy_port_state bits 0l in
let _ = set_ofp_phy_port_curr bits 0l in
let _ = set_ofp_phy_port_advertised bits 0l in
let _ = set_ofp_phy_port_supported bits 0l in
let _ = set_ofp_phy_port_peer bits 0l in
Cstruct.shift bits sizeof_ofp_phy_port
let string_of_phy ph =
(sp "port_no:%d,hw_addr:%s,name:%s"
ph.port_no (eaddr_to_string ph.hw_addr) ph.name)
type stats = {
mutable port_id: uint16;
mutable rx_packets: uint64;
mutable tx_packets: uint64;
mutable rx_bytes: uint64;
mutable tx_bytes: uint64;
mutable rx_dropped: uint64;
mutable tx_dropped: uint64;
mutable rx_errors: uint64;
mutable tx_errors: uint64;
mutable rx_frame_err: uint64;
mutable rx_over_err: uint64;
mutable rx_crc_err: uint64;
mutable collisions: uint64;
}
cstruct ofp_port_stats {
uint16_t port_no;
uint8_t pad[6];
uint64_t rx_packets;
uint64_t tx_packets;
uint64_t rx_bytes;
uint64_t tx_bytes;
uint64_t rx_dropped;
uint64_t tx_dropped;
uint64_t rx_errors;
uint64_t tx_errors;
uint64_t rx_frame_err;
uint64_t rx_over_err;
uint64_t rx_crc_err;
uint64_t collisions
} as big_endian
let rec parse_port_stats_reply bits =
match (Cstruct.len bits) with
| 0 -> []
| _ ->
let record = [{port_id=(get_ofp_port_stats_port_no bits);
rx_packets=(get_ofp_port_stats_rx_packets bits);
tx_packets=(get_ofp_port_stats_tx_packets bits);
rx_bytes=(get_ofp_port_stats_rx_bytes bits);
tx_bytes=(get_ofp_port_stats_tx_bytes bits);
rx_dropped=(get_ofp_port_stats_rx_dropped bits);
tx_dropped=(get_ofp_port_stats_tx_dropped bits);
rx_errors=(get_ofp_port_stats_rx_errors bits);
tx_errors=(get_ofp_port_stats_tx_errors bits);
rx_frame_err=(get_ofp_port_stats_rx_frame_err bits);
rx_over_err=(get_ofp_port_stats_rx_over_err bits);
rx_crc_err=(get_ofp_port_stats_rx_crc_err bits);
collisions=(get_ofp_port_stats_collisions bits);}] in
let _ = Cstruct.shift_left bits sizeof_ofp_port_stats in
record @ (parse_port_stats_reply (bits) )
let rec string_of_port_stats_reply ports =
match ports with
| [] -> ""
| h::q -> (
sp "port_no:%d,rx_packets:%Ld,tx_packets:%Ld,rx_bytes:%Ld,\
tx_bytes:%Ld,rx_dropped:%Ld,tx_dropped:%Ld,rx_errors:%Ld,\
tx_errors:%Ld,rx_frame_err:%Ld,rx_over_err:%Ld,rx_crc_err:%Ld,\
collisions:%Ld\n%s"
h.port_id
h.rx_packets h.tx_packets h.rx_bytes h.tx_bytes
h.rx_dropped h.tx_dropped h.rx_errors h.tx_errors
h.rx_frame_err h.rx_over_err h.rx_crc_err h.collisions
(string_of_port_stats_reply q))
cenum reason {
ADD = 0;
DEL = 1;
MOD = 2
} as uint8_t
(* type reason = ADD | DEL | MOD
let reason_of_int = function
| 0 -> ADD
| 1 -> DEL
| 2 -> MOD
| _ -> invalid_arg "reason_of_int"
and int_of_reason = function
| ADD -> 0
| DEL -> 1
| MOD -> 2
and string_of_reason = function
| ADD -> sp "ADD"
| DEL -> sp "DEL"
| MOD -> sp "MOD"*)
type status = {
reason: reason;
desc: phy;
}
cstruct ofp_port_status {
uint8_t reason;
uint8_t pad[7]
} as big_endian
let string_of_status st =
(sp "Port status,reason:%s,%s" (reason_to_string st.reason)
(string_of_phy st.desc) )
let parse_status bits =
let reason =
match (int_to_reason (get_ofp_port_status_reason bits)) with
| Some(reason) -> reason
| None -> raise(Unparsable("reason_of_int", bits))
in
let _ = Cstruct.shift_left bits sizeof_ofp_port_status in
{reason; desc=(parse_phy bits)}
end
module Switch = struct
type capabilities = {
flow_stats: bool;
table_stats: bool;
port_stats: bool;
stp: bool;
ip_reasm: bool;
queue_stats: bool;
arp_match_ip: bool;
}
let parse_capabilities bits =
{ arp_match_ip=(get_int32_bit bits 7);
queue_stats=(get_int32_bit bits 6);
ip_reasm=(get_int32_bit bits 5);
stp=(get_int32_bit bits 3);
port_stats=(get_int32_bit bits 2);
table_stats=(get_int32_bit bits 1);
flow_stats=(get_int32_bit bits 0);}
let marshal_capabilities c =
let bits = 0l in
let _ = set_int32_bit bits 7 c.arp_match_ip in
let _ = set_int32_bit bits 6 c.queue_stats in
let _ = set_int32_bit bits 5 c.ip_reasm in
let _ = set_int32_bit bits 3 c.stp in
let _ = set_int32_bit bits 2 c.port_stats in
let _ = set_int32_bit bits 1 c.table_stats in
let _ = set_int32_bit bits 0 c.flow_stats in
bits
type actions = {
output: bool;
set_vlan_id: bool;
set_vlan_pcp: bool;
strip_vlan: bool;
set_dl_src: bool;
set_dl_dst: bool;
set_nw_src: bool;
set_nw_dst: bool;
set_nw_tos: bool;
set_tp_src: bool;
set_tp_dst: bool;
enqueue: bool;
vendor: bool;
}
let parse_actions bits =
{ output=(get_int32_bit bits 0);
set_vlan_id=(get_int32_bit bits 1);
set_vlan_pcp=(get_int32_bit bits 2);
strip_vlan=(get_int32_bit bits 3);
set_dl_src=(get_int32_bit bits 4);
set_dl_dst=(get_int32_bit bits 5);
set_nw_src=(get_int32_bit bits 6);
set_nw_dst=(get_int32_bit bits 7);
set_nw_tos=(get_int32_bit bits 8);
set_tp_src=(get_int32_bit bits 9);
set_tp_dst=(get_int32_bit bits 10);
enqueue=(get_int32_bit bits 11);
vendor=(get_int32_bit bits 12);}
let marshal_actions action =
let bits = 0l in
let bits = set_int32_bit bits 0 action.output in
let bits = set_int32_bit bits 1 action.set_vlan_id in
let bits = set_int32_bit bits 2 action.set_vlan_pcp in
let bits = set_int32_bit bits 3 action.strip_vlan in
let bits = set_int32_bit bits 4 action.set_dl_src in
let bits = set_int32_bit bits 5 action.set_dl_dst in
let bits = set_int32_bit bits 6 action.set_nw_src in
let bits = set_int32_bit bits 7 action.set_nw_dst in
let bits = set_int32_bit bits 8 action.set_nw_tos in
let bits = set_int32_bit bits 9 action.set_tp_src in
let bits = set_int32_bit bits 10 action.set_tp_dst in
let bits = set_int32_bit bits 11 action.enqueue in
let bits = set_int32_bit bits 12 action.vendor in
bits
type features = {
datapath_id: datapath_id;
n_buffers: uint32;
n_tables: byte;
capabilities: capabilities;
actions: actions;
mutable ports: Port.phy list;
}
cstruct ofp_switch_features {
uint64_t datapath_id;
uint32_t n_buffers;
uint8_t n_tables;
uint8_t pad[3];
uint32_t capabilities;
uint32_t action
} as big_endian
let rec marshal_phy_ports ports bits =
match ports with
| [] -> bits
| head :: tail ->
let bits = Port.marshal_phy head bits in
marshal_phy_ports tail bits
let marshal_reply_features xid feat bits =
let ports_count = (List.length feat.ports) in
let len = Header.get_len + sizeof_ofp_switch_features +
ports_count*Port.phy_len in
let header = Header.create Header.FEATURES_RESP len xid in
let (_, bits) = marshal_and_shift (Header.marshal_header header) bits in
let _ = set_ofp_switch_features_datapath_id bits feat.datapath_id in
let _ = set_ofp_switch_features_n_buffers bits feat.n_buffers in
let _ = set_ofp_switch_features_n_tables bits
(int_of_char feat.n_tables) in
let _ = set_ofp_switch_features_capabilities bits
(marshal_capabilities feat.capabilities) in
let _ = set_ofp_switch_features_action bits
(marshal_actions feat.actions) in
let bits = Cstruct.shift bits sizeof_ofp_switch_features in
let _ = marshal_phy_ports feat.ports bits in
len
let parse_features bits =
let datapath_id = get_ofp_switch_features_datapath_id bits in
let n_buffers = get_ofp_switch_features_n_buffers bits in
let n_tables = char_of_int (get_ofp_switch_features_n_tables bits) in
let capabilities = parse_capabilities
(get_ofp_switch_features_capabilities bits) in
let actions = parse_actions (get_ofp_switch_features_action bits) in
let bits = Cstruct.shift bits sizeof_ofp_switch_features in
let ports = Port.parse_phys bits in
{datapath_id; n_buffers; n_tables; capabilities; actions; ports;}
type config = {
drop: bool;
reasm: bool;
miss_send_len: uint16;
}
let init_switch_config =
{drop=true; reasm=true;miss_send_len=1000;}
cstruct ofp_switch_config {
uint16_t flags;
uint16_t miss_send_len
} as big_endian
let marshal_switch_config xid config bits =
let header = (Header.create Header.GET_CONFIG_RESP
(Header.get_len + sizeof_ofp_switch_config) xid) in
let (_, bits) = marshal_and_shift (Header.marshal_header header) bits in
let _ = set_ofp_switch_config_flags bits 0 in
let _ = set_ofp_switch_config_miss_send_len bits config.miss_send_len in
(Header.sizeof_ofp_header + sizeof_ofp_switch_config)
end
module Wildcards = struct
type t = {
in_port: bool;
dl_vlan: bool;
dl_src: bool;
dl_dst: bool;
dl_type: bool;
nw_proto: bool;
tp_src: bool;
tp_dst: bool;
nw_src: byte; (* XXX *)
nw_dst: byte; (* XXX *)
dl_vlan_pcp: bool;
nw_tos: bool;
}
let full_wildcard =
{ in_port=true; dl_vlan=true; dl_src=true;
dl_dst=true; dl_type=true; nw_proto=true;
tp_src=true; tp_dst=true; nw_src=(char_of_int 32);
nw_dst=(char_of_int 32); dl_vlan_pcp=true; nw_tos=true;
}
let exact_match =
{ in_port=false; dl_vlan=false; dl_src=false;
dl_dst=false; dl_type=false; nw_proto=false;
tp_src=false; tp_dst=false; nw_src=(char_of_int 0);
nw_dst=(char_of_int 0); dl_vlan_pcp=false; nw_tos=false;
}
let l2_match =
{ in_port=false;dl_vlan=false;dl_src=false;dl_dst=false;
dl_type=false;nw_proto=true;tp_src=true;tp_dst=true;
nw_src=(char_of_int 32);nw_dst=(char_of_int 32);dl_vlan_pcp=false;
nw_tos=true
}
let l3_match =
{ in_port=false;dl_vlan=false;dl_vlan_pcp=false;dl_src=false;
dl_dst=false;dl_type=false;nw_proto=false;nw_tos=false;
nw_src=(char_of_int 0);nw_dst=(char_of_int 0);tp_src=true;tp_dst=true;
}
let arp_match =
{ in_port=false;dl_vlan=false;dl_vlan_pcp=false;dl_src=false;
dl_dst=false;dl_type=false;nw_proto=false;nw_tos=true;
nw_src=(char_of_int 32);nw_dst=(char_of_int 32);tp_src=true;tp_dst=true;
}
let marshal_wildcard m =
let ret = 0l in
let ret = set_int32_bit ret 0 m.in_port in
let ret = set_int32_bit ret 1 m.dl_vlan in
let ret = set_int32_bit ret 2 m.dl_src in
let ret = set_int32_bit ret 3 m.dl_dst in
let ret = set_int32_bit ret 4 m.dl_type in
let ret = set_int32_bit ret 5 m.nw_proto in
let ret = set_int32_bit ret 6 m.tp_src in
let ret = set_int32_bit ret 7 m.tp_dst in
let ret = set_int32_nw_mask ret 8 (int_of_char m.nw_src) in
let ret = set_int32_nw_mask ret 14 (int_of_char m.nw_dst) in
let ret = set_int32_bit ret 20 m.dl_vlan_pcp in
let ret = set_int32_bit ret 21 m.nw_tos in
ret
let wildcard_to_string h =
sp "in_port:%s,dl_vlan:%s,dl_src:%s,dl_dst:%s,dl_type:%s,\
nw_proto:%s,tp_src:%s,tp_dst:%s,nw_src:%d,nw_dst:%d,\
dl_vlan_pcp:%s,nw_tos:%s"
(string_of_bool h.in_port)
(string_of_bool h.dl_vlan) (string_of_bool h.dl_src)
(string_of_bool h.dl_dst) (string_of_bool h.dl_type)
(string_of_bool h.nw_proto) (string_of_bool h.tp_src)
(string_of_bool h.tp_dst) (int_of_char h.nw_src)
(int_of_char h.nw_dst) (string_of_bool h.dl_vlan_pcp)
(string_of_bool h.nw_tos)
let parse_wildcards bits =
{nw_tos=(get_int32_bit bits 21);
dl_vlan_pcp=(get_int32_bit bits 20);
nw_dst=(get_int32_nw_mask bits 14);
nw_src=(get_int32_nw_mask bits 8);
tp_dst=(get_int32_bit bits 7);
tp_src=(get_int32_bit bits 6);
nw_proto=(get_int32_bit bits 5);
dl_type=(get_int32_bit bits 4);
dl_dst=(get_int32_bit bits 3);
dl_src=(get_int32_bit bits 2);
dl_vlan=(get_int32_bit bits 1);
in_port=(get_int32_bit bits 0);}
end
module Match = struct
type t = {
wildcards: Wildcards.t;
in_port: Port.t;
dl_src: eaddr;
dl_dst: eaddr;
dl_vlan: uint16;
dl_vlan_pcp: byte;
dl_type: uint16;
nw_src: uint32;
nw_dst: uint32;
nw_tos: byte;
nw_proto: byte;
tp_src: uint16;
tp_dst: uint16;
}
cstruct ofp_match {
uint32_t wildcards;
uint16_t in_port;
uint8_t dl_src[6];
uint8_t dl_dst[6];
uint16_t dl_vlan;
uint8_t dl_vlan_pcp;
uint8_t pad1[1];
uint16_t dl_type;
uint8_t nw_tos;
uint8_t nw_proto;
uint8_t pad2[2];
uint32_t nw_src;
uint32_t nw_dst;
uint16_t tp_src;
uint16_t tp_dst
} as big_endian
let marshal_match m bits =
let _ = set_ofp_match_wildcards bits
(Wildcards.marshal_wildcard m.wildcards) in
let _ = set_ofp_match_in_port bits (Port.int_of_port m.in_port) in
let _ = set_ofp_match_dl_src m.dl_src 0 bits in
let _ = set_ofp_match_dl_dst m.dl_dst 0 bits in
let _ = set_ofp_match_dl_vlan bits m.dl_vlan in
let _ = set_ofp_match_dl_vlan_pcp bits (int_of_char m.dl_vlan_pcp) in
let _ = set_ofp_match_dl_type bits m.dl_type in
let _ = set_ofp_match_nw_tos bits (int_of_char m.nw_tos) in
let _ = set_ofp_match_nw_proto bits (int_of_char m.nw_proto) in
let _ = set_ofp_match_nw_src bits m.nw_src in
let _ = set_ofp_match_nw_dst bits m.nw_dst in
let _ = set_ofp_match_tp_src bits m.tp_src in
let _ = set_ofp_match_tp_dst bits m.tp_dst in
sizeof_ofp_match
let parse_match bits =
let wildcards = Wildcards.parse_wildcards (get_ofp_match_wildcards bits) in
let in_port = Port.port_of_int (get_ofp_match_in_port bits) in
let dl_src = Cstruct.to_string (get_ofp_match_dl_src bits) in
let dl_dst = Cstruct.to_string (get_ofp_match_dl_dst bits) in
let dl_vlan = get_ofp_match_dl_vlan bits in
let dl_vlan_pcp = char_of_int (get_ofp_match_dl_vlan_pcp bits) in
let dl_type = get_ofp_match_dl_type bits in
let nw_tos = char_of_int (get_ofp_match_nw_tos bits) in
let nw_proto = char_of_int (get_ofp_match_nw_proto bits) in
let nw_src = get_ofp_match_nw_src bits in
let nw_dst = get_ofp_match_nw_dst bits in
let tp_src = get_ofp_match_tp_src bits in
let tp_dst = get_ofp_match_tp_dst bits in
let _ = Cstruct.shift bits sizeof_ofp_match in
{wildcards; in_port; dl_src; dl_dst; dl_vlan; dl_vlan_pcp;
dl_type; nw_tos; nw_proto; nw_src; nw_dst; tp_src; tp_dst;}
(* Check if the flow object is include in flow_def match *)
let null_eaddr = "\x00\x00\x00\x00\x00\x00"
let create_flow_match wildcards
?(in_port = 0) ?(dl_src=null_eaddr) ?(dl_dst=null_eaddr)
?(dl_vlan=0xffff) ?(dl_vlan_pcp=(char_of_int 0)) ?(dl_type=0)
?(nw_tos=(char_of_int 0))
?(nw_proto=(char_of_int 0))
?(nw_src=(Int32.of_int 0)) ?(nw_dst=(Int32.of_int 0))
?(tp_src=0) ?(tp_dst=0)
() =
{ wildcards; in_port=(Port.port_of_int in_port);
dl_src; dl_dst; dl_vlan; dl_vlan_pcp; dl_type;
nw_src; nw_dst; nw_tos; nw_proto; tp_src; tp_dst;
}
cstruct dl_header {
uint8_t dl_dst[6];
uint8_t dl_src[6];
uint16_t dl_type
} as big_endian
cstruct arphdr {
uint16_t ar_hrd;
uint16_t ar_pro;
uint8_t ar_hln;
uint8_t ar_pln;
uint16_t ar_op;
uint8_t ar_sha[6];
uint32_t nw_src;
uint8_t ar_tha[6];
uint32_t nw_dst
} as big_endian
cstruct nw_header {
uint8_t hlen_version;
uint8_t nw_tos;
uint16_t total_len;
uint8_t pad[5];
uint8_t nw_proto;
uint16_t csum;
uint32_t nw_src;
uint32_t nw_dst
} as big_endian
cstruct tp_header {
uint16_t tp_src;
uint16_t tp_dst
} as big_endian
cstruct icmphdr {
uint8_t typ;
uint8_t code;
uint16_t checksum
} as big_endian
let raw_packet_to_match in_port bits =
let dl_dst = Cstruct.to_string (get_dl_header_dl_dst bits) in
let dl_src = Cstruct.to_string (get_dl_header_dl_src bits) in
let dl_type = get_dl_header_dl_type bits in
let bits = Cstruct.shift bits sizeof_dl_header in
match (dl_type) with
| 0x0800 -> begin
let nw_src = get_nw_header_nw_src bits in
let nw_dst = get_nw_header_nw_dst bits in
let nw_proto = get_nw_header_nw_proto bits in
let nw_tos = char_of_int (get_nw_header_nw_tos bits) in
let len = (get_nw_header_hlen_version bits) land 0xf in
let bits = Cstruct.shift bits (len*4) in
match (nw_proto) with
| 17
| 6 ->
{wildcards=Wildcards.exact_match;
in_port; dl_src; dl_dst; dl_vlan=0xffff;
dl_vlan_pcp=(char_of_int 0);dl_type; nw_src;
nw_dst; nw_tos;
nw_proto=(char_of_int nw_proto); tp_src=(get_tp_header_tp_src bits);
tp_dst=(get_tp_header_tp_dst bits);}
| 1 ->
{ wildcards =Wildcards.exact_match;
in_port;dl_src; dl_dst; dl_vlan=0xffff;
dl_vlan_pcp=(char_of_int 0);dl_type;
nw_src; nw_dst; nw_tos;
nw_proto=(char_of_int nw_proto); tp_src=(get_icmphdr_typ bits);
tp_dst=(get_icmphdr_code bits); }
| _ ->
{ wildcards =Wildcards.l3_match;
in_port;dl_src; dl_dst; dl_vlan=0xffff;
dl_vlan_pcp=(char_of_int 0);dl_type;
nw_src; nw_dst; nw_tos;
nw_proto=(char_of_int nw_proto); tp_src=0; tp_dst=0; }
end
| 0x0806 ->
{wildcards=Wildcards.arp_match;
in_port; dl_src; dl_dst; dl_type;
dl_vlan=0xffff; dl_vlan_pcp=(char_of_int 0);
nw_src=(get_arphdr_nw_src bits);
nw_dst=(get_arphdr_nw_dst bits);
nw_proto=( char_of_int (get_arphdr_ar_op bits));
nw_tos=(char_of_int 0); tp_src=0; tp_dst=0}
| _ ->
{wildcards=Wildcards.l2_match;
in_port; dl_src; dl_dst; dl_type;
dl_vlan=0xffff; dl_vlan_pcp=(char_of_int 0);
nw_src=0l; nw_dst=0l;
nw_tos=(char_of_int 0); nw_proto=(char_of_int 0);
tp_src=0; tp_dst=0}
let match_to_string m =
match (m.dl_type, (int_of_char m.nw_proto)) with
| (0x0800, 17)
-> (sp "in_port:%s,dl_src:%s,dl_dst:%s,dl_type:ip,nw_src:%s/%d,nw_dst:%s/%d,\
nw_tos:%d,nw_proto:%d,tp_dst:%d,tp_src:%d"
(Port.string_of_port m.in_port) (eaddr_to_string m.dl_src)
(eaddr_to_string m.dl_dst) (ipv4_to_string m.nw_src) (int_of_char m.wildcards.Wildcards.nw_src)
(ipv4_to_string m.nw_dst) (int_of_char m.wildcards.Wildcards.nw_dst) (Char.code m.nw_tos)
(Char.code m.nw_proto) m.tp_dst m.tp_src
)
| (0x0800, _)
-> (sp "in_port:%s,dl_src:%s,dl_dst:%s,dl_type:ip,nw_src:%s/%d,\
nw_dst:%s/%d,nw_tos:%d,nw_proto:%d"
(Port.string_of_port m.in_port) (eaddr_to_string m.dl_src)
(eaddr_to_string m.dl_dst) (ipv4_to_string m.nw_src) (int_of_char m.wildcards.Wildcards.nw_src)
(ipv4_to_string m.nw_dst) (int_of_char m.wildcards.Wildcards.nw_dst) (Char.code m.nw_tos)
(Char.code m.nw_proto)
)
| (_, _) -> (sp "in_port:%s,dl_src:%s,dl_dst:%s,dl_type:0x%x"
(Port.string_of_port m.in_port) (eaddr_to_string m.dl_src)
(eaddr_to_string m.dl_dst) m.dl_type