frenetic-lang / ocaml-openflow Goto Github PK
View Code? Open in Web Editor NEWSerialization library for OpenFlow
License: Other
Serialization library for OpenFlow
License: Other
While different version of OpenFlow use different sized int
s to represent ports, the standard only uses a certain range of values within those int
s to represent physical ports. When mapping OutputPort n
from the abstraction layer each concrete version implementation should check that the port is with in the valid physical range.
The same holds for Enqueue(pport_id, queue_id)
actions, when supported.
SDN_Types
currently only allows sending packets to physical locations. Add support for sending to the controller while specifying number of bytes that should be sent.
The upper bits of ofp_port_state
represent an enumeration, but the code currently represents it as a collection of flags. Make it an enumeration.
With the introduction of async and core as dependencies, the travis-ci build went from taking several minutes to somewhere around half an hour. Find a way to get this time back down to single-digit minutes.
There is a lot of crap that makes it hard to use.
Currently these function only produce a human-readable message type. They should expose more information about the message.
Related to #72.
when an OpenFlow 1.0 switch disconnects, no event is propagated up to any users of OpenFlow0x01_Platform. this is in stark contrast to the SwitchDisconnected
exception thrown by OpenFlow0x04_Platform.
without such an event/exception, OpenFlow 1.0 controllers (e.g., NetCore) cannot release any resources for a disconnected switch, or otherwise determine that a switch is no longer there.
Not to sound pushy, but can someone review and merge in the outstanding pull requests now that the PLDI rush is over? Some of them have been sitting around for almost two weeks.
It seems as though the port_no
in PortDescriptions
received from switches are always set to 512
, which indicates some sort of parsing error.
This is happening in the reactive branch of this repository, conjunction with the reactive branch in the frenetic repository.
Compiling this local policy:
filter port = 0; (vlanId := 65535; port := 1) |
filter port = 1; (vlanId := 65535; port := 0)
generates this flowtable:
[{pattern={InPort=0,action=SetField(Vlan,65535); OutputPort(1),
cookie=0,idle_timeout=Permanent,hard_timeout=Permanent}
{pattern={InPort=1,action=SetField(Vlan,65535); OutputPort(0),
cookie=0,idle_timeout=Permanent,hard_timeout=Permanent}]
And causes this error:
Fatal error: exception Invalid_argument("unrealizable modification")
Raised at file "lib/ModComposition.ml", line 52, characters 29-73
Called from file "lib/ModComposition.ml", line 59, characters 10-38
Called from file "lib/HighLevelSwitch_common.ml", line 49, characters 6-24
Called from file "lib/HighLevelSwitch_common.ml", line 54, characters 19-38
Called from file "lib/HighLevelSwitch0x04.ml", line 160, characters 43-78
Called from file "lib/HighLevelSwitch0x04.ml", line 243, characters 19-58
Called from file "list.ml", line 57, characters 20-23
Called from file "lib/HighLevelSwitch0x04.ml", line 247, characters 18-42
Called from file "lib/Controller.ml", line 21, characters 11-50
I just did an opam update
, in the process pulling in async
versino 111.13.00, and building ocaml-openflow now fails with:
ocaml setup.ml -build -j 4
Finished, 0 targets (0 cached) in 00:00:00.
+ ocamlfind ocamlc -c -g -I lib -syntax camlp4o -thread -package cstruct.syntax -package cstruct -package str -package sexplib.syntax -package cstruct.async -package packet -package async -package core -package threads -I async -I lib -o async/Async_OpenFlow_Platform.cmo async/Async_OpenFlow_Platform.ml
File "async/Async_OpenFlow_Platform.ml", line 97, characters 48-61:
Error: This expression has type
([> `Allow ] as 'a) Async_kernel.Deferred.t =
'a Async_kernel.Ivar.Deferred.t
but an expression was expected of type
Impl.Client_id.t ->
[ `Allow | `Deny of string option ] Async_extra.Import.Deferred.t
Command exited with code 2.
Compilation unsuccessful after building 82 targets (80 cached) in 00:00:00.
E: Failure("Command ''/home/basus/.opam/4.01.0/bin/ocamlbuild' lib/openflow.cma lib/openflow.cmxa lib/openflow.a lib/openflow.cmxs async/async.cma async/async.cmxa async/async.a async/async.cmxs examples/Learning_Switch.byte -use-ocamlfind -tag debug -j 4' terminated with error code 10")
make: *** [build] Error 1
I'm building the current HEAD of master and the build succeeds on a a different machine with async
version 109.53.02.
I'm trying to use ocaml-openflow with some hardware switches running openvswitch and OpenFlow 1.3. The switches connect properly but it seems like the SDN.setup_flow_table
function does not correctly send out flow mods. I've looked at the links with Wireshark and I can see regular Echo Request and Reply messages, but no flow mods. It also seems like the setup_flow_table
function does not return.
Running on mininet with 80 switches crashes with the following backtrace:
("unhandled exception"
((lib/monitor.ml.Error_
((exn (Unix.Unix_error "Too many open files" accept "((fd 4))"))
(backtrace
("Raised at file \"lib/core_unix.ml\", line 48, characters 11-42"
"Called from file \"lib/core_unix.ml\", line 2125, characters 17-40"
"Called from file \"lib/raw_fd.ml\", line 268, characters 11-25"
"Re-raised at file \"lib/unix_syscalls.ml\", line 786, characters 28-31"
"Called from file \"lib/deferred.ml\", line 119, characters 6-13"
"Called from file \"lib/raw_deferred.ml\", line 48, characters 2-10"
"Called from file \"lib/unix_syscalls.ml\", line 790, characters 4-57"
"Called from file \"lib/monitor.ml\", line 169, characters 25-32"
"Called from file \"lib/jobs.ml\", line 213, characters 10-13" ""))
(monitor
(((name try_with) (here ()) (id 24421) (has_seen_error true)
(someone_is_listening true) (kill_index 0))))))
(Pid 94636)))
libgcc_s.so.1 must be installed for pthread_cancel to work
Aborted
The release shouldn't go out with this feature still in. More carefully consider the consequences of removing it as well as solutions to any problematic consequences.
Related to #90
The flag which indicates "more replies coming" is not parsed properly.
hey all,
I noticed that OpenFlow 0x04 and OpenFlow 0x01 have divergent and overlapping coverage for switch capabilities.
for example, 0x01 has SwitchFeatures.Capabilities while 0x04 has both Capabilities and uses types for OpenFlow0x04_Core (flow_stats, table_stats, etc.)
basically, the work to migrate 0x04 to the 0x01-style SwitchFeatures
was not completed for the Capabilities elements.
cheers,
Andrew
Clearly define what information about the network should be stored, and how that information should be queried.
please provide better error handling for async than "Ignore": https://github.com/frenetic-lang/ocaml-openflow/blob/master/async/Async_OpenFlow_ClientServer.ml#L65
original commit: 0b5eb36
thank you,
Andrew
The VInt
module assumes that the int
type is at most 32 bits. On 64-bit architectures this is not the case, and leads to runtime errors.
Each module that implements a message or a part of a message should export the type the module uses to represent it as t
.
the only downside to this new handshake design in #34 is that I am seeing a much higher rate of handshakes stalling. it appears there is not enough asynchrony / light-weight threading in the new design.
I can reproduce handshake stalls regularly (although not consistently) with a mininet configuration like the following:
$ sudo mn --controller=remote --topo=tree,depth4=2,fanout=2 --mac --arp --switch=user
the userspace switch is better at triggering this than Open vSwitch.
this problem is related to @arjunguha's comment: https://github.com/frenetic-lang/ocaml-openflow/blob/master/lib/OpenFlow0x01_Platform.ml#L82
in my testing, the hanshake stalls manifest as uncaught exceptions when the controller then proceeds to write to a socket has been closed by the switch after timing-out.
Can someone who is an expert in LWT & Ocaml pseudo-threads examine and resolve this please?
thank you,
Andrew
Currently the PseudoPort
data type contains a variant for the special controller port. That constructor takes an integer which is the maximum number of bytes of the packet that should be sent to the controller. The only place where the controller PseudoPort
should be used is in an Output
action, and that's also the only place that handles the length parameter properly. That's mentioned in the code here, and is also clear from the OpenFlow standard, § A.2.5 Action Structures, as the max_length
is part of the ofp_action_output
struct, not the port representation.
PseudoPort
should not include the Controller
variant. That should be removed, and a new data type OutputPort
should be introduced which is either a PseudoPort
or a controller with an int parameter. That should only be used in the Output
action.
The comment in fa51a3f is relevant to this issue.
In order for the abstraction layer to support stats queries, it must be able to transform an OpenFlow 1.0 individualStats
response into an abstraction layer flowStats
response. The code to perform the transformation should be included in the SDN_OpenFlow0x01.ml
and should have the following type signature:
val to_flowStats : OpenFlow0x01_Stats.individualStats -> SDN_Types.flowStats
As noted in the comments of SDN_OpenFlow0x04.mli
, manipulating VLAN tags requires additional bookkeeping in order to properly implement its push/pop semantics. Extend this bookkeeping to the OpenFlow 1.0 implementation and rework the API to these operations as appropriate.
This may be related to frenetic-lang/frenetic#329 and would perhaps be better implemented at the frenetic layer.
Trying to build openflow, I get the following error:
File "lib/OpenFlow0x01.ml", line 788, characters 18-23:
Error: This expression has type Core.Std.bytes
but an expression was expected of type Cstruct.t
Ideas?
As we require a FEATURE_REPLY
from the switch upon handshake, we should drop the connection if the replay does not come within X seconds.
Related to #90.
hi all,
while doing some throughput testing, I noticed that LWT lacks fairness between competing light weight threads. because OCaml lacks support for hardware parallelism, this situation can easily lead to starvation.
the scenario is as follows:
this is the design of a basic ARP cache.
in OpenFlow0x01_Switch.ml, we have two light weight threads: recv_thread
and send_thread
which should be responsible for parts 1 and 2 above. each is implemented as an infinite recursion.
the problem is that LWT appears by default to only yield to a different thread when a system call doesn't return right away. therefore, because there is always something in the receive buffer, recv_thread
hogs the sole OCaml hardware thread, and send_thread
starves.
it would be a big improvement if recv_thread
and send_thread
were interleaved to prevent starvation in such scenarios. of course, this only solves the problem for a single switch, and for as many light-weight threads as the authors see fit to interleave -- the proper solution is to have a language with hardware parallelism. :-(
thank you,
Andrew
PS -- to see / reproduce this, I have two xterms on the same host in mininet. in the first xterm, I do arping -c 200 -w 500000 h2
while in the second, I have tcpdump -i h1-eth0
... from the tcpdump, we can clearly see that all 200 arp requests are received before the 200 replies are sent (even though our my logging emits an arp reply for every arp request incrementally). hence, arping reports that 100% of the arp queries are unanswered (since they arrive after the 200 requests have all been sent).
hey Freneticians,
I got a crash in NetCore when a switch disconnected, apparently during a write.
while OpenFlow0x04_Platform.ml seems to have a fix for this (ie, send_to_switch_fd
has error handling), OpenFlow0x01_Platform.ml does not (and neither of the _Switch.ml versions)
on the other hand, the stacktrace below does not list OpenFlow0x01_Platform.ml, so I'm not sure whether the error handling should be in OpenFlow0x01_Switch.ml directly? (or is that just how LWT hides the root cause?)
thanks!
Andrew
Fatal error: exception Unix.Unix_error(Unix.EBADF, "check_descriptor", "")
Raised at file "src/unix/lwt_unix.ml", line 361, characters 15-67
Called from file "src/unix/lwt_unix.ml", line 552, characters 2-21
Called from file "lib/OpenFlow0x01_Switch.ml", line 42, characters 13-50
Called from file "lib/OpenFlow0x01_Switch.ml", line 126, characters 12-47
Called from file "src/core/lwt.ml", line 646, characters 66-69
Ocaml exiting~
LWT exiting~
Delete all flows on empty OVS causes an error message. I think it is safe to simply ignore it. It sounds safer to always try sending the delete all flows at start time.
This request ...
Openflow Protocol
Header
Version: 0x04
Type: Flow mod (CSM) - OFPT_FLOW_MOD (14)
Length: 56
Transaction ID: 0
Flow Mod
Cookie: 0x0000000000000000
Cookie Mask: 0x0000000000000000
Table ID: 0
Command: Delete all matching flows - OFPFC_DELETE (0x03)
Idle Timeout: 0
Hard Timeout: 0
Priority: 0
Buffer ID: 0xffffffff
Output Port: 0
Output Group: 0
Flags: 0x0000
0000 0000 0000 0... = Reserved: Not set
.... .... .... ...0 = Send flow removed message when flow expires or is deleted: Not set
.... .... .... ..0. = Check for overlapping entries first: Not set
.... .... .... .0.. = Reset flow packet and byte counts: Not set
Padding
Match
Type: OpenFlow Extensible Match - OFPMT_OXM (0x0001)
Length: 4
Padding
Triggers this error:
Openflow Protocol
Header
Version: 0x04
Type: Error (SM) - OFPT_ERROR (1)
Length: 68
Transaction ID: 0
Error
Type: Problem modifying flow entry - OFPET_FLOW_MOD_FAILED (5)
Code: Unspecified error - OFPFMFC_UNKNOWN (0x0000)
Data: 040e00380000000000000000000000000000000000000000...
In order to implement host discovery, it is necessary that the hacker hegemon reappropriate the ARP protocol. An example of such an application can be found here.
copy-pasta from Andrew's issue on frenetic:
hi all,
I recently realized that NetCore silently ignores OpenFlow error messages (ie, ErrorMsg from ocaml-openflow) received from the switch. it appears that NetKat is the same.
at the very least, please log these messages, and honestly, during development, I would prefer to see the controller abort due to many types of errors (eg, OFPFMFC_ALL_TABLES_FULL or OFPFMFC_BAD_COMMAND) rather than silently pretending that the policy had been installed correctly.
handling the OpenFlow error messages sensibly greatly simplifies the task of debugging a policy which is not functioning correctly because of switch limitations.
thank you,
Andrew
Log seems to be removed. opam pin async_extra 111.21.00
does the trick. Report and resolution by @nimishgupta
Support for overlapping record labels in type inference is essential for us.
In order for the abstraction layer to support stats queries, it must be able to transform an OpenFlow 1.3 flowRequest
response into an abstraction layer flowStats
response. The code to perform the transformation should be included in the SDN_OpenFlow0x04.ml
and should have the following type signature:
val to_flowStats : OpenFlow0x04_Core.flowStats -> SDN_Types.flowStats
LLDP exists for this purpose, and has OCaml implementations here, here, and here.
Alternatively, use a controller-specific protocol. Every time a new port comes up on a switch, send the switchId
and portId
in an ethernet packet through that port. If a host is on the other side, it may drop it. If a switch is on the other side, it'll send the packet to the controller as a PACKET_IN
with receivingswitchId
and portId
information, as well as the payload.
in send_to_switch_fd
-- https://github.com/frenetic-lang/ocaml-openflow/blob/master/lib/OpenFlow0x01_Switch.ml#L39 -- we see the following code:
let msg_len = String.length msg_buf in
lwt sent = Lwt_unix.write sock msg_buf 0 msg_len in
Lwt.return (sent = msg_len)
hence, it returns false
if sent < msg_len
which can occur if the socket's receiver is simply slower than the controller. in this case, ocaml-openflow should retry the send from where it left off, not disconnect the switch (!!) when it gets false
back from this function: https://github.com/frenetic-lang/ocaml-openflow/blob/master/lib/OpenFlow0x01_Switch.ml#L129 ... as described in the manpage, http://linux.die.net/man/2/write, -1
indicates an actual error occurred (which LWT might turn into an exception? I'm just guessing here)
this is similar to the need to call recv
multiple times if you get less than you expect from the buffer. that particular case is handled correctly for OpenFlow 1.3 switches only (unfortunately) via the SafeSocket wrapper: https://github.com/frenetic-lang/ocaml-openflow/blob/master/lib/OpenFlow0x04_Misc.ml#L107
you can reproduce this easily by sending a policy with O(1000) rules to a hardware switch. one band-aid for this problem is to turn off Nagle's algorithm by setting TCP_NODELAY to true on the switch socket. this, at least, will OpenFlow messages to the switch with less delay, giving it a better chance of keeping up with the controller. hence, enabling TCP_NODELAY may be worth doing in general (so far, it is helping my use case)
thanks,
Andrew
Is missing. But there should be one, because there are options, like --enable-tests...
Hi there! Great project! :)
I was wondering whether there are any plans to add support for the Open vSwitch extensions from Nicira (NXM), such as additional matches with masks, multiple tables, and the "learn" action?
when an OpenFlow 1.0 switch disconnects abruptly, we eventually see OpenFlow0x01_Switch.ml's disconnect
function called as send_thread
received "false" from swend_to"_switch_fd
.
the disconnect
function throws an error from the Lwt_unix.close
call. unfortunately, I can't figure out how to use try_lwt to catch the error. it would be great if someone with better Ocaml-foo than me could prevent this exception from crashing the controller.
the backtrace I get is just:
lwt_unix.ml 361: raise (Unix.Unix_error (Unix.EBADF, "check_descriptor", ""))
lwt_unix.ml 493: check_descriptor ch;
if it's helpful, here are some steps to reproduce via Flowlog: tnelson/FlowLog#29
I'm trying to generate rules that match Input Port and IP Src and IP DST. I noticed that the rules weren't getting correctly installed on our Pronto switch, in particular only the in_port was installed as a match. Poking at the stream with Wireshark it looks like the FlowMods are being malformed. Wireshark tells me "Error/Malformed: Trying to fetch an IPv6 address with length 4".
If I print the flowtable prior to invoking SDN.setup_flow_table it shows me the correct match, which leads to believe there might a bug in Ocaml-OpenFlow. This is for OpenFlow 0x01. Help?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.