Skip to content

Commit c4a8236

Browse files
committed
Merge pull request #136 from fugitifduck/LearningSwitch0x04
Learning switch0x04 and Error Message
2 parents 6501b24 + a5164dc commit c4a8236

File tree

8 files changed

+288
-65
lines changed

8 files changed

+288
-65
lines changed

_oasis

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,3 +125,17 @@ Executable learning_switch
125125
cstruct.async,
126126
openflow,
127127
openflow.async
128+
129+
Executable learning_switch0x04
130+
Path: examples
131+
MainIs: Learning_Switch0x04.ml
132+
Build$: flag(async)
133+
Install: false
134+
BuildDepends:
135+
threads,
136+
core,
137+
async,
138+
packet,
139+
cstruct.async,
140+
openflow,
141+
openflow.async

_tags

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# OASIS_START
2-
# DO NOT EDIT (digest: 72ea415a4e801a171896c8a2a1b11c2d)
2+
# DO NOT EDIT (digest: e841dae195b3a4dde01d54b7e83088dd)
33
# Ignore VCS directories, you can use the same kind of rule outside
44
# OASIS_START/STOP if you want to exclude directories that contains
55
# useless stuff for the build process
@@ -124,6 +124,19 @@
124124
"examples/Learning_Switch.byte": package(threads)
125125
"examples/Learning_Switch.byte": use_async
126126
"examples/Learning_Switch.byte": use_openflow
127+
# Executable learning_switch0x04
128+
"examples/Learning_Switch0x04.byte": package(async)
129+
"examples/Learning_Switch0x04.byte": package(core)
130+
"examples/Learning_Switch0x04.byte": package(cstruct)
131+
"examples/Learning_Switch0x04.byte": package(cstruct.async)
132+
"examples/Learning_Switch0x04.byte": package(cstruct.syntax)
133+
"examples/Learning_Switch0x04.byte": package(packet)
134+
"examples/Learning_Switch0x04.byte": package(sexplib)
135+
"examples/Learning_Switch0x04.byte": package(sexplib.syntax)
136+
"examples/Learning_Switch0x04.byte": package(str)
137+
"examples/Learning_Switch0x04.byte": package(threads)
138+
"examples/Learning_Switch0x04.byte": use_async
139+
"examples/Learning_Switch0x04.byte": use_openflow
127140
<examples/*.ml{,i}>: package(async)
128141
<examples/*.ml{,i}>: package(core)
129142
<examples/*.ml{,i}>: package(cstruct)

examples/Learning_Switch0x04.ml

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
open Async.Std
2+
open Core.Std
3+
4+
open OpenFlow0x04
5+
open OpenFlow0x04_Core
6+
open OpenFlow0x04.Message
7+
8+
module OF0x04Controller = Async_OpenFlow0x04.Controller
9+
10+
module SwitchTable = Map.Make(OF0x04Controller.Client_id)
11+
12+
module EthTable = Map.Make(struct
13+
type t = Int64.t sexp_opaque with sexp
14+
let compare = Pervasives.compare
15+
end)
16+
17+
type switchTable = portId EthTable.t SwitchTable.t
18+
19+
let switch
20+
(ctl : OF0x04Controller.t)
21+
(tbl : switchTable)
22+
evt =
23+
let ensure result response =
24+
begin match response with
25+
| `Sent _ -> return result
26+
| `Drop exn -> raise exn
27+
end in
28+
29+
let learn c_id pi =
30+
let pkt = parse_payload pi.pi_payload in
31+
let rec findPort oxmMatch =
32+
match oxmMatch with
33+
| [] -> failwith "no PhysicalPort"
34+
| (OxmInPort t)::q
35+
| (OxmInPhyPort t)::q -> t
36+
| t::q -> findPort q in
37+
let eth, port = pkt.Packet.dlSrc, (findPort pi.pi_ofp_match) in
38+
let tbl', present = match SwitchTable.find tbl c_id with
39+
| None -> (SwitchTable.add tbl c_id (EthTable.singleton eth port), false)
40+
| Some e_tbl ->
41+
match EthTable.find e_tbl eth with
42+
| None -> (SwitchTable.add tbl c_id (EthTable.add e_tbl eth port), false)
43+
| Some port' when port = port' -> (tbl, true)
44+
| _ -> failwith "Inconsistent topology" in (* XXX(seliopou): exn *)
45+
if present then
46+
return (true, tbl')
47+
else
48+
let fwd, buf = match pi.pi_payload with
49+
| Buffered (b_id, _) -> (false, Some b_id)
50+
| NotBuffered _ -> (true, None) in
51+
OF0x04Controller.send ctl c_id
52+
(1l, FlowModMsg (
53+
{ mfCookie = val_to_mask 0L
54+
; mfTable_id = 0
55+
; mfCommand = AddFlow
56+
; mfIdle_timeout = Permanent
57+
; mfHard_timeout = Permanent
58+
; mfPriority = 5
59+
; mfBuffer_id = buf
60+
; mfOut_port = None
61+
; mfOut_group = None
62+
; mfFlags = { fmf_send_flow_rem = false
63+
; fmf_check_overlap = false
64+
; fmf_reset_counts = false
65+
; fmf_no_pkt_counts = false
66+
; fmf_no_byt_counts = false }
67+
; mfOfp_match = ([OxmEthDst {m_value = eth; m_mask = None}])
68+
; mfInstructions = ([ApplyActions [Output(PhysicalPort port)]])
69+
}
70+
))
71+
(* XXX(seliopu): can ensure asynchronously if not buffered, or if the
72+
* buffering is ignored completely.
73+
* *)
74+
>>= ensure (fwd, tbl') in
75+
76+
let forward (tbl : switchTable) c_id t_id pi =
77+
let dst = (parse_payload pi.pi_payload).Packet.dlDst in
78+
let rec findPort oxmMatch =
79+
match oxmMatch with
80+
| [] -> failwith "no PhysicalPort"
81+
| (OxmInPort t)::q
82+
| (OxmInPhyPort t)::q -> t
83+
| t::q -> findPort q in
84+
let port = findPort pi.pi_ofp_match in
85+
let out =
86+
match EthTable.find (SwitchTable.find_exn tbl c_id) dst with
87+
| None -> Flood
88+
| Some(p) -> PhysicalPort(p) in
89+
OF0x04Controller.send ctl c_id
90+
(t_id, PacketOutMsg {
91+
po_payload = pi.pi_payload;
92+
po_port_id = Some(port);
93+
po_actions = [ Output(out) ] }) in
94+
95+
begin match evt with
96+
| `Connect c_id ->
97+
OF0x04Controller.send ctl c_id
98+
(0l, FlowModMsg (add_flow 1
99+
([])
100+
([ApplyActions [Output(Controller 1024)]]))
101+
)
102+
>>= ensure (SwitchTable.add tbl c_id EthTable.empty)
103+
| `Disconnect (c_id, _) ->
104+
return (SwitchTable.remove tbl c_id)
105+
| `Message (c_id, msg) ->
106+
let t_id, msg = msg in
107+
begin match msg with
108+
| PacketInMsg pi ->
109+
learn c_id pi
110+
>>= (function
111+
| (true , tbl') -> forward tbl' c_id t_id pi >>= ensure tbl'
112+
| (false, tbl') -> return tbl')
113+
| Error err -> failwith (Error.to_string err)
114+
| PortStatusMsg ps ->
115+
let open PortStatus in
116+
let port = ps.desc.port_no in
117+
begin match ps.reason with
118+
| PortDelete ->
119+
let tbl' = SwitchTable.change tbl c_id (function
120+
| None -> None
121+
| Some eth_tbl ->
122+
Some(EthTable.filter eth_tbl (fun ~key:_ ~data:v -> v = port))) in
123+
return tbl'
124+
| PortAdd
125+
| PortModify -> return tbl
126+
end
127+
| _ -> failwith "WHAT MESSAGE IS THIS???"
128+
end
129+
end
130+
131+
let main () =
132+
let open OF0x04Controller in
133+
create 6633 ()
134+
>>= fun t ->
135+
Pipe.fold (listen t) ~init:SwitchTable.empty ~f:(switch t)
136+
137+
let _ = main ()
138+
let _ = never_returns (Scheduler.go ())

lib/OpenFlow0x04.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6614,7 +6614,7 @@ module Message = struct
66146614
| GetAsyncRequest -> Header.size
66156615
| GetAsyncReply async -> Header.size + AsyncConfig.sizeof async
66166616
| SetAsync async -> Header.size + AsyncConfig.sizeof async
6617-
| Error _ -> failwith "NYI: sizeof Error"
6617+
| Error err -> Header.size + Error.sizeof err
66186618
| RoleRequest rr -> Header.size + RoleRequest.sizeof rr
66196619
| RoleReply rr -> Header.size + RoleRequest.sizeof rr
66206620

lib/OpenFlow0x04_Core.ml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,17 @@ let delete_all_flows =
380380
; mfOfp_match = match_all
381381
; mfInstructions = [] }
382382

383+
let parse_payload = function
384+
| Buffered (_, b)
385+
| NotBuffered b ->
386+
Packet.parse b
387+
388+
let marshal_payload buffer pkt =
389+
let payload = Packet.marshal pkt in
390+
match buffer with
391+
| Some b -> Buffered (b, payload)
392+
| None -> NotBuffered payload
393+
383394
type packetInReason =
384395
| NoMatch
385396
| ExplicitSend

lib/OpenFlow0x04_Core.mli

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,14 @@ type oxm =
243243

244244
type oxmMatch = oxm list
245245

246+
(** {2 Convenient Functions} *)
247+
248+
val parse_payload : payload -> Packet.packet
249+
250+
(** [marshal_payload buf pkt] serializes pkt, where [buf] is an optional
251+
buffer ID. *)
252+
val marshal_payload : int32 option -> Packet.packet -> payload
253+
246254
val match_all : oxmMatch
247255

248256
(** A pseudo-port, as described by the [ofp_port_no] enumeration in

myocamlbuild.ml

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
(* OASIS_START *)
2-
(* DO NOT EDIT (digest: c0029058a425da68bec61b75cea5a8b3) *)
2+
(* DO NOT EDIT (digest: d504cc72904744d1a686718531d2e7f0) *)
33
module OASISGettext = struct
44
(* # 22 "src/oasis/OASISGettext.ml" *)
55

@@ -39,10 +39,10 @@ module OASISExpr = struct
3939
open OASISGettext
4040

4141

42-
type test = string
42+
type test = string
4343

4444

45-
type flag = string
45+
type flag = string
4646

4747

4848
type t =
@@ -52,10 +52,10 @@ module OASISExpr = struct
5252
| EOr of t * t
5353
| EFlag of flag
5454
| ETest of test * string
55-
5655

5756

58-
type 'a choices = (t * 'a) list
57+
58+
type 'a choices = (t * 'a) list
5959

6060

6161
let eval var_get t =
@@ -430,10 +430,10 @@ module MyOCamlbuildBase = struct
430430
module OC = Ocamlbuild_pack.Ocaml_compiler
431431

432432

433-
type dir = string
434-
type file = string
435-
type name = string
436-
type tag = string
433+
type dir = string
434+
type file = string
435+
type name = string
436+
type tag = string
437437

438438

439439
(* # 62 "src/plugins/ocamlbuild/MyOCamlbuildBase.ml" *)
@@ -448,7 +448,7 @@ module MyOCamlbuildBase = struct
448448
* directory.
449449
*)
450450
includes: (dir * dir list) list;
451-
}
451+
}
452452

453453

454454
let env_filename =

0 commit comments

Comments
 (0)