blob: 881fc5532ef0c4e7788c45b9d44d61156d7d238f [file] [log] [blame]
carlosmscabralf40ecd12013-02-01 18:15:58 -02001From 5c9610ffb88c89b0f36359ad3c7547831482a3ff Mon Sep 17 00:00:00 2001
2From: Bob Lantz <rlantz@cs.stanford.edu>
3Date: Fri, 3 Feb 2012 14:48:58 -0800
4Subject: [PATCH] OpenFlow tutorial port nox-destiny.
5
6---
7 src/nox/coreapps/examples/Makefile.am | 2 +-
8 src/nox/coreapps/examples/tutorial/Makefile.am | 25 ++++
9 src/nox/coreapps/examples/tutorial/meta.json | 12 ++
10 src/nox/coreapps/examples/tutorial/pytutorial.py | 67 +++++++++++
11 src/nox/coreapps/examples/tutorial/tutorial.cc | 134 ++++++++++++++++++++++
12 5 files changed, 239 insertions(+), 1 deletions(-)
13 create mode 100644 src/nox/coreapps/examples/tutorial/Makefile.am
14 create mode 100644 src/nox/coreapps/examples/tutorial/__init__.py
15 create mode 100644 src/nox/coreapps/examples/tutorial/meta.json
16 create mode 100644 src/nox/coreapps/examples/tutorial/pytutorial.py
17 create mode 100644 src/nox/coreapps/examples/tutorial/tutorial.cc
18
19diff --git a/src/nox/coreapps/examples/Makefile.am b/src/nox/coreapps/examples/Makefile.am
20index 126f32e..1a0458c 100644
21--- a/src/nox/coreapps/examples/Makefile.am
22+++ b/src/nox/coreapps/examples/Makefile.am
23@@ -1,6 +1,6 @@
24 include ../../../Make.vars
25
26-SUBDIRS = t
27+SUBDIRS = tutorial t
28
29 EXTRA_DIST =\
30 meta.json\
31diff --git a/src/nox/coreapps/examples/tutorial/Makefile.am b/src/nox/coreapps/examples/tutorial/Makefile.am
32new file mode 100644
33index 0000000..51cf921
34--- /dev/null
35+++ b/src/nox/coreapps/examples/tutorial/Makefile.am
36@@ -0,0 +1,25 @@
37+include ../../../../Make.vars
38+
39+EXTRA_DIST =\
40+ meta.xml \
41+ __init__.py \
42+ pytutorial.py
43+
44+if PY_ENABLED
45+AM_CPPFLAGS += $(PYTHON_CPPFLAGS)
46+endif # PY_ENABLED
47+
48+pkglib_LTLIBRARIES = \
49+ tutorial.la
50+
51+tutorial_la_CPPFLAGS = $(AM_CPPFLAGS) -I $(top_srcdir)/src/nox -I $(top_srcdir)/src/nox/coreapps/
52+tutorial_la_SOURCES = tutorial.cc
53+tutorial_la_LDFLAGS = -module -export-dynamic
54+
55+NOX_RUNTIMEFILES = meta.json \
56+ __init__.py \
57+ pytutorial.py
58+
59+all-local: nox-all-local
60+clean-local: nox-clean-local
61+install-exec-hook: nox-install-local
62diff --git a/src/nox/coreapps/examples/tutorial/__init__.py b/src/nox/coreapps/examples/tutorial/__init__.py
63new file mode 100644
64index 0000000..e69de29
65diff --git a/src/nox/coreapps/examples/tutorial/meta.json b/src/nox/coreapps/examples/tutorial/meta.json
66new file mode 100644
67index 0000000..7a9f227
68--- /dev/null
69+++ b/src/nox/coreapps/examples/tutorial/meta.json
70@@ -0,0 +1,12 @@
71+{
72+ "components": [
73+ {
74+ "name": "tutorial",
75+ "library": "tutorial"
76+ },
77+ {
78+ "name": "pytutorial",
79+ "python": "nox.coreapps.examples.tutorial.pytutorial"
80+ }
81+ ]
82+}
83diff --git a/src/nox/coreapps/examples/tutorial/pytutorial.py b/src/nox/coreapps/examples/tutorial/pytutorial.py
84new file mode 100644
85index 0000000..1e21c0b
86--- /dev/null
87+++ b/src/nox/coreapps/examples/tutorial/pytutorial.py
88@@ -0,0 +1,67 @@
89+# Tutorial Controller
90+# Starts as a hub, and your job is to turn this into a learning switch.
91+
92+import logging
93+
94+from nox.lib.core import *
95+import nox.lib.openflow as openflow
96+from nox.lib.packet.ethernet import ethernet
97+from nox.lib.packet.packet_utils import mac_to_str, mac_to_int
98+
99+log = logging.getLogger('nox.coreapps.tutorial.pytutorial')
100+
101+
102+class pytutorial(Component):
103+
104+ def __init__(self, ctxt):
105+ Component.__init__(self, ctxt)
106+ # Use this table to store MAC addresses in the format of your choice;
107+ # Functions already imported, including mac_to_str, and mac_to_int,
108+ # should prove useful for converting the byte array provided by NOX
109+ # for packet MAC destination fields.
110+ # This table is initialized to empty when your module starts up.
111+ self.mac_to_port = {} # key: MAC addr; value: port
112+
113+ def learn_and_forward(self, dpid, inport, packet, buf, bufid):
114+ """Learn MAC src port mapping, then flood or send unicast."""
115+
116+ # Initial hub behavior: flood packet out everything but input port.
117+ # Comment out the line below when starting the exercise.
118+ self.send_openflow(dpid, bufid, buf, openflow.OFPP_FLOOD, inport)
119+
120+ # Starter psuedocode for learning switch exercise below: you'll need to
121+ # replace each pseudocode line with more specific Python code.
122+
123+ # Learn the port for the source MAC
124+ #self.mac_to_port = <fill in>
125+ #if (destination MAC of the packet is known):
126+ # Send unicast packet to known output port
127+ #self.send_openflow( <fill in params> )
128+ # Later, only after learning controller works:
129+ # push down flow entry and remove the send_openflow command above.
130+ #self.install_datapath_flow( <fill in params> )
131+ #else:
132+ #flood packet out everything but the input port
133+ #self.send_openflow(dpid, bufid, buf, openflow.OFPP_FLOOD, inport)
134+
135+ def packet_in_callback(self, dpid, inport, reason, len, bufid, packet):
136+ """Packet-in handler"""
137+ if not packet.parsed:
138+ log.debug('Ignoring incomplete packet')
139+ else:
140+ self.learn_and_forward(dpid, inport, packet, packet.arr, bufid)
141+
142+ return CONTINUE
143+
144+ def install(self):
145+ self.register_for_packet_in(self.packet_in_callback)
146+
147+ def getInterface(self):
148+ return str(pytutorial)
149+
150+def getFactory():
151+ class Factory:
152+ def instance(self, ctxt):
153+ return pytutorial(ctxt)
154+
155+ return Factory()
156diff --git a/src/nox/coreapps/examples/tutorial/tutorial.cc b/src/nox/coreapps/examples/tutorial/tutorial.cc
157new file mode 100644
158index 0000000..e7240cc
159--- /dev/null
160+++ b/src/nox/coreapps/examples/tutorial/tutorial.cc
161@@ -0,0 +1,134 @@
162+#include "component.hh"
163+#include "config.h"
164+#include "packet-in.hh"
165+#include "flow.hh"
166+#include "assert.hh"
167+#include "netinet++/ethernetaddr.hh"
168+#include "netinet++/ethernet.hh"
169+#include <boost/shared_array.hpp>
170+#include <boost/bind.hpp>
171+#ifdef LOG4CXX_ENABLED
172+#include <boost/format.hpp>
173+#include "log4cxx/logger.h"
174+#else
175+#include "vlog.hh"
176+#endif
177+
178+using namespace std;
179+using namespace vigil;
180+using namespace vigil::container;
181+
182+namespace
183+{
184+ static Vlog_module lg("tutorial");
185+
186+ /** Learning switch.
187+ */
188+ class tutorial
189+ : public Component
190+ {
191+ public:
192+ /** Constructor.
193+ */
194+ tutorial(const Context* c, const json_object* node)
195+ : Component(c)
196+ { }
197+
198+ /** Configuration.
199+ * Add handler for packet-in event.
200+ */
201+ void configure(const Configuration*)
202+ {
203+ register_handler<Packet_in_event>
204+ (boost::bind(&tutorial::handle, this, _1));
205+ }
206+
207+ /** Just simply install.
208+ */
209+ void install()
210+ {
211+ lg.dbg(" Install called ");
212+ }
213+
214+ /** Function to setup flow.
215+ */
216+ void setup_flow(Flow& flow, datapathid datapath_id ,
217+ uint32_t buffer_id, uint16_t out_port)
218+ {
219+ ofp_flow_mod* ofm;
220+ size_t size = sizeof *ofm + sizeof(ofp_action_output);
221+ boost::shared_array<char> raw_of(new char[size]);
222+ ofm = (ofp_flow_mod*) raw_of.get();
223+
224+ ofm->header.version = OFP_VERSION;
225+ ofm->header.type = OFPT_FLOW_MOD;
226+ ofm->header.length = htons(size);
227+ ofm->match.wildcards = htonl(0);
228+ ofm->match.in_port = htons(flow.in_port);
229+ ofm->match.dl_vlan = flow.dl_vlan;
230+ memcpy(ofm->match.dl_src, flow.dl_src.octet, sizeof ofm->match.dl_src);
231+ memcpy(ofm->match.dl_dst, flow.dl_dst.octet, sizeof ofm->match.dl_dst);
232+ ofm->match.dl_type = flow.dl_type;
233+ ofm->match.nw_src = flow.nw_src;
234+ ofm->match.nw_dst = flow.nw_dst;
235+ ofm->match.nw_proto = flow.nw_proto;
236+ ofm->match.tp_src = flow.tp_src;
237+ ofm->match.tp_dst = flow.tp_dst;
238+ ofm->command = htons(OFPFC_ADD);
239+ ofm->buffer_id = htonl(buffer_id);
240+ ofm->idle_timeout = htons(5);
241+ ofm->hard_timeout = htons(OFP_FLOW_PERMANENT);
242+ ofm->priority = htons(OFP_DEFAULT_PRIORITY);
243+ ofp_action_output& action = *((ofp_action_output*)ofm->actions);
244+ memset(&action, 0, sizeof(ofp_action_output));
245+ action.type = htons(OFPAT_OUTPUT);
246+ action.len = htons(sizeof(ofp_action_output));
247+ action.max_len = htons(0);
248+ action.port = htons(out_port);
249+ send_openflow_command(datapath_id, &ofm->header, true);
250+ }
251+
252+ /** Function to handle packets.
253+ * @param datapath_id datapath id of switch
254+ * @param in_port port packet is received
255+ * @param buffer_id buffer id of packet
256+ * @param source source mac address in host order
257+ * @param destination destination mac address in host order
258+ */
259+ void handle_packet(datapathid datapath_id, uint16_t in_port, uint32_t buffer_id,
260+ uint64_t source, uint64_t destination)
261+ {
262+ send_openflow_packet(datapath_id, buffer_id, OFPP_FLOOD,
263+ in_port, true);
264+ }
265+
266+ /** Packet-on handler.
267+ */
268+ Disposition handle(const Event& e)
269+ {
270+ const Packet_in_event& pi = assert_cast<const Packet_in_event&>(e);
271+ uint32_t buffer_id = pi.buffer_id;
272+ Flow flow(pi.in_port, *pi.get_buffer());
273+
274+ // drop LLDP packets
275+ if (flow.dl_type == ethernet::LLDP)
276+ return CONTINUE;
277+
278+ // pass handle of unicast packet, else flood
279+ if (!flow.dl_src.is_multicast())
280+ handle_packet(pi.datapath_id, pi.in_port, buffer_id,
281+ flow.dl_src.hb_long(), flow.dl_dst.hb_long());
282+ else
283+ send_openflow_packet(pi.datapath_id, buffer_id, OFPP_FLOOD,
284+ pi.in_port, true);
285+
286+ return CONTINUE;
287+ }
288+
289+ private:
290+};
291+
292+REGISTER_COMPONENT(container::Simple_component_factory<tutorial>,
293+ tutorial);
294+
295+} // unnamed namespace
296--
2971.7.5.4
298