PageRenderTime 60ms CodeModel.GetById 32ms RepoModel.GetById 0ms app.codeStats 0ms

/src/nox/coreapps/pyrt/pycontext.cc

https://github.com/homework/nox
C++ | 455 lines | 362 code | 65 blank | 28 comment | 22 complexity | 55b803a3ec6dc037c84f33892132222b MD5 | raw file
  1. /* Copyright 2008 (C) Nicira, Inc.
  2. *
  3. * This file is part of NOX.
  4. *
  5. * NOX is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * NOX is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with NOX. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include "pycontext.hh"
  19. #ifndef SWIG
  20. #ifndef SWIGPYTHON
  21. #include "swigpyrun.h"
  22. #endif // SWIGPYTHON
  23. #endif // SWIG
  24. #include <iostream>
  25. #include <vector>
  26. #include <cstring>
  27. #include <boost/bind.hpp>
  28. #include <boost/intrusive_ptr.hpp>
  29. #include <boost/shared_array.hpp>
  30. #include<boost/tokenizer.hpp>
  31. #include "netinet++/ethernetaddr.hh"
  32. #include "datapath-join.hh"
  33. #include "datapath-leave.hh"
  34. #include "switch-mgr.hh"
  35. #include "switch-mgr-join.hh"
  36. #include "switch-mgr-leave.hh"
  37. #include "bootstrap-complete.hh"
  38. #include "aggregate-stats-in.hh"
  39. #include "desc-stats-in.hh"
  40. #include "table-stats-in.hh"
  41. #include "port-stats-in.hh"
  42. #include "echo-request.hh"
  43. #include "flow-mod-event.hh"
  44. #include "flow-removed.hh"
  45. #include "packet-in.hh"
  46. #include "port-status.hh"
  47. #include "pycomponent.hh"
  48. #include "pyevent.hh"
  49. #include "pyglue.hh"
  50. #include "pyrt.hh"
  51. #include "port.hh"
  52. #include "shutdown-event.hh"
  53. #include "threads/cooperative.hh"
  54. #include "vlog.hh"
  55. #include "openflow-default.hh"
  56. using namespace std;
  57. using namespace vigil;
  58. using namespace boost;
  59. using namespace vigil::applications;
  60. namespace vigil {
  61. namespace applications {
  62. PyContext::PyContext(const container::Context* ctxt_,
  63. container::Component* c_, Python_event_manager* pyem_)
  64. : ctxt(ctxt_), c(c_), pyem(pyem_) {
  65. }
  66. PyObject*
  67. PyContext::resolve(PyObject* interface)
  68. {
  69. // If component returned a (class) type, translate it to a string.
  70. if (interface && PyClass_Check(interface) && !PyInstance_Check(interface)) {
  71. PyObject* t = interface;
  72. interface = PyObject_Str(t);
  73. Py_DECREF(t);
  74. }
  75. if (!PyString_Check(interface)){
  76. PyErr_SetString(PyExc_TypeError, "resolve expects an interface "
  77. "as a parameter.");
  78. return 0;
  79. }
  80. container::Interface_description i(PyString_AsString(interface));
  81. PyComponent* c = dynamic_cast<PyComponent*>(ctxt->get_by_interface(i));
  82. if (c) {
  83. PyObject *r = c->getPyObject();
  84. Py_INCREF(r);
  85. return r;
  86. } else {
  87. Py_RETURN_NONE;
  88. }
  89. }
  90. Kernel*
  91. PyContext::get_kernel(){
  92. return ctxt->get_kernel();
  93. }
  94. const char*
  95. PyContext::get_version() {
  96. return VERSION;
  97. }
  98. void
  99. PyContext::post(Event* event) {
  100. c->post(event);
  101. }
  102. void
  103. PyContext::register_event(const Event_name& name) {
  104. try {
  105. c->register_event(name);
  106. }
  107. catch (const std::exception& e) {
  108. /* Unable to convert the arguments. */
  109. PyErr_SetString(PyExc_TypeError, e.what());
  110. }
  111. }
  112. static void convert_python_event(const Event& e, PyObject* proxy) {
  113. const pyevent& sfe
  114. = dynamic_cast<const pyevent&>(e);
  115. if(sfe.python_arg){
  116. pyglue_setattr_string(proxy, "pyevent", sfe.python_arg);
  117. Py_INCREF(sfe.python_arg);
  118. }else{
  119. pyglue_setattr_string(proxy, "pyevent", Py_None);
  120. vlog().log(vlog().get_module_val("pyrt"), Vlog::LEVEL_ERR,
  121. "Pyevent without internal python_arg set");
  122. Py_INCREF(Py_None);
  123. }
  124. ((Event*)SWIG_Python_GetSwigThis(proxy)->ptr)->operator=(e);
  125. }
  126. void
  127. PyContext::register_python_event(const Event_name& name)
  128. {
  129. register_event(name);
  130. // For python events, we register the generic pyevent event
  131. // converter
  132. register_event_converter(name,&convert_python_event);
  133. }
  134. void
  135. PyContext::register_event_converter(const Event_name& name,
  136. const Event_converter& converter) {
  137. try {
  138. pyem->register_event_converter(name, converter);
  139. }
  140. catch (const std::exception& e) {
  141. /* Unable to convert the arguments. */
  142. PyErr_SetString(PyExc_TypeError, e.what());
  143. }
  144. }
  145. void
  146. PyContext::register_handler(const Event_name& name,
  147. PyObject* callable)
  148. {
  149. if (!callable || !PyCallable_Check(callable)) {
  150. PyErr_SetString(PyExc_TypeError, "not a callable parameter");
  151. return;
  152. }
  153. // Use intrusive pointer to call INCREF and DECREF for all
  154. // handlers passed to the container.
  155. boost::intrusive_ptr<PyObject> cptr(callable, true);
  156. try {
  157. c->register_handler(name,
  158. boost::bind(&Python_event_manager::
  159. call_python_handler, pyem,
  160. _1, cptr));
  161. }
  162. catch (const std::exception& e) {
  163. /* Unable to convert the arguments. */
  164. PyErr_SetString(PyExc_TypeError, e.what());
  165. }
  166. }
  167. uint32_t
  168. PyContext::register_handler_on_match(PyObject* callable,
  169. uint32_t priority,
  170. const Packet_expr &expr) {
  171. if (!callable || !PyCallable_Check(callable)) {
  172. PyErr_SetString(PyExc_TypeError, "not a callable parameter");
  173. return 0;
  174. }
  175. try {
  176. boost::intrusive_ptr<PyObject> cptr(callable, true);
  177. return c->register_handler_on_match
  178. (priority, expr, boost::bind(&Python_event_manager::
  179. call_python_handler, pyem, _1, cptr));
  180. }
  181. catch (const std::exception& e) {
  182. /* Unable to convert the arguments. */
  183. PyErr_SetString(PyExc_TypeError, e.what());
  184. return 0;
  185. }
  186. }
  187. void
  188. PyContext::send_openflow_packet(uint64_t datapath_id,
  189. const Nonowning_buffer& packet,
  190. uint16_t out_port, uint16_t in_port) {
  191. c->send_openflow_packet(datapathid::from_host(datapath_id), packet,
  192. out_port, in_port, false);
  193. }
  194. void
  195. PyContext::send_openflow_packet(uint64_t datapath_id,
  196. const Nonowning_buffer& packet,
  197. const Nonowning_buffer& actions,
  198. uint16_t in_port) {
  199. c->send_openflow_packet(datapathid::from_host(datapath_id), packet,
  200. (ofp_action_header*)actions.data(), actions.size(),
  201. in_port, false);
  202. }
  203. void
  204. PyContext::send_openflow_buffer(uint64_t datapath_id,
  205. uint32_t buffer_id,
  206. uint16_t out_port, uint16_t in_port) {
  207. c->send_openflow_packet(datapathid::from_host(datapath_id), buffer_id,
  208. out_port, in_port, false);
  209. }
  210. void
  211. PyContext::send_openflow_buffer(uint64_t datapath_id,
  212. uint32_t buffer_id,
  213. const Nonowning_buffer& actions,
  214. uint16_t in_port) {
  215. c->send_openflow_packet(datapathid::from_host(datapath_id), buffer_id,
  216. (ofp_action_header*)actions.data(),
  217. actions.size(), in_port, false);
  218. }
  219. void
  220. PyContext::send_flow_command(uint64_t datapath_id,
  221. ofp_flow_mod_command command,
  222. const ofp_match& match,
  223. uint16_t idle_timeout, uint16_t hard_timeout,
  224. const Nonowning_buffer& actions,
  225. uint32_t buffer_id,
  226. uint16_t priority , uint64_t cookie) {
  227. ofp_flow_mod* ofm = NULL;
  228. size_t size = sizeof *ofm + actions.size();
  229. boost::shared_array<uint8_t> raw_of(new uint8_t[size]);
  230. ofm = (ofp_flow_mod*) raw_of.get();
  231. ofm->header.version = OFP_VERSION;
  232. ofm->header.type = OFPT_FLOW_MOD;
  233. ofm->header.length = htons(size);
  234. ofm->header.xid = htonl(0);
  235. ofm->match = match;
  236. ofm->cookie = cookie;
  237. ofm->command = htons(command);
  238. ofm->idle_timeout = htons(idle_timeout);
  239. ofm->hard_timeout = htons(hard_timeout);
  240. ofm->buffer_id = htonl(buffer_id);
  241. ofm->out_port = htons(OFPP_NONE);
  242. ofm->priority = htons(priority);
  243. ofm->flags = htons(ofd_flow_mod_flags());
  244. if (actions.size() > 0) {
  245. ::memcpy(ofm->actions, actions.data(), actions.size());
  246. }
  247. int error = c->send_openflow_command(datapathid::from_host(datapath_id),
  248. &ofm->header, false);
  249. if (error == EAGAIN) {
  250. vlog().log(vlog().get_module_val("pyrt"), Vlog::LEVEL_ERR,
  251. "unable to send flow setup for dpid: %"PRIx64"\n",
  252. datapath_id);
  253. }
  254. }
  255. int
  256. PyContext::close_openflow_connection(uint64_t datapath_id)
  257. {
  258. return c->close_openflow_connection(datapathid::from_host(datapath_id));
  259. }
  260. int
  261. PyContext::send_switch_command(uint64_t dpid, const std::string command)
  262. {
  263. return send_switch_command(dpid, command, "");
  264. }
  265. int
  266. PyContext::send_switch_command(uint64_t dpid, const std::string
  267. command, const std::string args )
  268. {
  269. vector<string> vargs;
  270. if(args != ""){
  271. tokenizer<> tok(args);
  272. for(tokenizer<>::iterator beg=tok.begin(); beg!=tok.end();++beg){
  273. vargs.push_back(*beg);
  274. }
  275. }
  276. return c->send_switch_command(datapathid::from_host(dpid), command, vargs);
  277. }
  278. int
  279. PyContext::switch_reset(uint64_t dpid)
  280. {
  281. return c->switch_reset(datapathid::from_host(dpid));
  282. }
  283. int
  284. PyContext::switch_update(uint64_t dpid)
  285. {
  286. return c->switch_update(datapathid::from_host(dpid));
  287. }
  288. int PyContext::send_add_snat(uint64_t dpid, uint16_t port,
  289. uint32_t ip_addr_start, uint32_t ip_addr_end,
  290. uint16_t tcp_start, uint16_t tcp_end,
  291. uint16_t udp_start, uint16_t udp_end,
  292. ethernetaddr mac_addr, uint16_t mac_timeout) {
  293. return c->send_add_snat(datapathid::from_host(dpid),
  294. port,ip_addr_start,ip_addr_end,
  295. tcp_start,tcp_end,udp_start,udp_end, mac_addr, mac_timeout);
  296. }
  297. int PyContext::send_del_snat(uint64_t dpid, uint16_t port){
  298. return c->send_del_snat(datapathid::from_host(dpid), port);
  299. }
  300. uint32_t PyContext::get_switch_controller_ip(uint64_t dpid){
  301. return c->get_switch_controller_ip(datapathid::from_host(dpid));
  302. }
  303. uint32_t PyContext::get_switch_ip(uint64_t dpid){
  304. return c->get_switch_ip(datapathid::from_host(dpid));
  305. }
  306. void
  307. PyContext::send_table_stats_request(uint64_t datapath_id)
  308. {
  309. send_stats_request(datapath_id, OFPST_TABLE, 0, 0);
  310. }
  311. void
  312. PyContext::send_port_stats_request(uint64_t datapath_id, uint16_t port)
  313. {
  314. ofp_port_stats_request psr;
  315. psr.port_no = htons(port);
  316. send_stats_request(datapath_id, OFPST_PORT, (const
  317. uint8_t*)&psr, sizeof(struct ofp_port_stats_request));
  318. }
  319. void
  320. PyContext::send_desc_stats_request(uint64_t datapath_id)
  321. {
  322. send_stats_request(datapath_id, OFPST_DESC, 0, 0);
  323. }
  324. void
  325. PyContext::send_aggregate_stats_request(uint64_t datapath_id, const struct ofp_match& match, uint8_t table_id)
  326. {
  327. ofp_aggregate_stats_request asr;
  328. asr.table_id = table_id;
  329. asr.match = match;
  330. asr.out_port = htons(OFPP_NONE);
  331. send_stats_request(datapath_id, OFPST_AGGREGATE, (const
  332. uint8_t*)&asr, sizeof(struct ofp_aggregate_stats_request));
  333. }
  334. void
  335. PyContext::send_stats_request(uint64_t datapath_id, ofp_stats_types type, const uint8_t* data, size_t data_size )
  336. {
  337. ofp_stats_request* osr = NULL;
  338. size_t msize = sizeof(ofp_stats_request) + data_size;
  339. boost::shared_array<uint8_t> raw_sr(new uint8_t[msize]);
  340. // Send OFPT_STATS_REQUEST
  341. osr = (ofp_stats_request*) raw_sr.get();
  342. osr->header.type = OFPT_STATS_REQUEST;
  343. osr->header.version = OFP_VERSION;
  344. osr->header.length = htons(msize);
  345. osr->header.xid = 0;
  346. osr->type = htons(type);
  347. osr->flags = htons(0); /* CURRENTLY NONE DEFINED */
  348. if(data){
  349. ::memcpy(osr->body, data, data_size );
  350. }
  351. int error = c->send_openflow_command(datapathid::from_host(datapath_id),
  352. &osr->header, false);
  353. if (error == EAGAIN) {
  354. vlog().log(vlog().get_module_val("pyrt"), Vlog::LEVEL_ERR,
  355. "unable to send stats request for dpid: %"PRIx64"\n",
  356. datapath_id);
  357. }
  358. }
  359. int
  360. PyContext::send_port_mod(uint64_t datapath_id, uint16_t port_no, ethernetaddr addr, uint32_t mask, uint32_t config )
  361. {
  362. ofp_port_mod* opm = NULL;
  363. size_t msize = sizeof(ofp_port_mod);
  364. boost::shared_array<uint8_t> raw_sr(new uint8_t[msize]);
  365. // Send OFPT_STATS_REQUEST
  366. opm = (ofp_port_mod*) raw_sr.get();
  367. opm->header.type = OFPT_PORT_MOD;
  368. opm->header.version = OFP_VERSION;
  369. opm->header.length = htons(msize);
  370. opm->header.xid = 0;
  371. opm->port_no = htons(port_no);
  372. opm->config = htonl(config);
  373. opm->mask = htonl(mask);
  374. opm->advertise = htonl(0);
  375. memcpy(opm->hw_addr, addr.octet, sizeof(opm->hw_addr));
  376. int error = c->send_openflow_command(datapathid::from_host(datapath_id),
  377. &opm->header, false);
  378. if (error == EAGAIN) {
  379. vlog().log(vlog().get_module_val("pyrt"), Vlog::LEVEL_ERR,
  380. "unable to send port_mod for dpid: %"PRIx64"\n",
  381. datapath_id);
  382. }
  383. return error;
  384. }
  385. bool
  386. PyContext::unregister_handler(uint32_t rule_id) {
  387. return c->unregister_handler(rule_id);
  388. }
  389. } // applications
  390. } // vigil