PageRenderTime 44ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/tests/of_driver_tests.erl

https://github.com/chinnurtb/of_driver
Erlang | 624 lines | 509 code | 73 blank | 42 comment | 2 complexity | ade680eb0f48230010208f346a96ec0f MD5 | raw file
Possible License(s): Apache-2.0
  1. %%------------------------------------------------------------------------------
  2. %% Copyright 2014 FlowForwarding.org
  3. %%
  4. %% Licensed under the Apache License, Version 2.0 (the "License");
  5. %% you may not use this file except in compliance with the License.
  6. %% You may obtain a copy of the License at
  7. %%
  8. %% http://www.apache.org/licenses/LICENSE-2.0
  9. %%
  10. %% Unless required by applicable law or agreed to in writing, software
  11. %% distributed under the License is distributed on an "AS IS" BASIS,
  12. %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. %% See the License for the specific language governing permissions and
  14. %% limitations under the License.
  15. %%-----------------------------------------------------------------------------
  16. %% @author Erlang Solutions Ltd. <openflow@erlang-solutions.com>
  17. %% @copyright 2014 FlowForwarding.org
  18. -module (of_driver_tests).
  19. -include_lib("eunit/include/eunit.hrl").
  20. -include_lib("of_protocol/include/of_protocol.hrl").
  21. -include_lib("of_protocol/include/ofp_v4.hrl").
  22. -define(LISTEN_PORT, 15578).
  23. -define(DATAPATH_ID, 1).
  24. -define(DATAPATH_UNPARSED,<<8,0,39,150,212,121>>).
  25. -define(DATAPATH_HEX,"00:01:08:00:27:96:D4:79").
  26. -export([trace/0]).
  27. %%------------------------------------------------------------------------------
  28. of_driver_test_() ->
  29. {setup,
  30. fun setup/0,
  31. fun cleanup/1,
  32. fun(S) ->
  33. {foreach, fun test_setup/0,
  34. [{"set_xid", fun set_xid/0},
  35. {"main_connect", fun main_connect/0},
  36. {"main_terminate", fun main_terminate/0},
  37. {"early_message", fun early_message/0},
  38. {"close_connection", fun close_connection/0}|
  39. [{N, fun() -> F(S) end} || {N, F} <-
  40. [{"gen_xid", fun gen_xid/1}
  41. ,{"aux_connect", fun aux_connect/1}
  42. ,{"in_message", fun in_message/1}
  43. ,{"echo_request", fun echo_request/1}
  44. ,{"echo_request with data", fun echo_request2/1}
  45. ,{"send", fun send/1}
  46. ,{"sync_send", fun sync_send/1}
  47. ,{"sync_send_no_reply", fun sync_send_no_reply/1}
  48. ,{"sync_send_non_reply", fun sync_send_non_reply/1}
  49. ,{"sync_send_multipart", fun sync_send_multipart/1}
  50. ,{"send_list", fun send_list/1}
  51. ,{"sync_send_list", fun sync_send_list/1}
  52. ,{"sync_send_list_no_reply", fun sync_send_list_no_reply/1}
  53. ,{"sync_send_list_multipart", fun sync_send_list_multipart/1}
  54. ,{"multiple_sync_send", fun multiple_sync_send/1}
  55. ,{"send_unsupported_version", fun send_unsupported_version/1}
  56. ,{"sync_send_unsupported_version", fun sync_send_unsupported_version/1}
  57. ,{"send_bad_message", fun send_bad_message/1}
  58. ,{"sync_send_bad_message", fun sync_send_bad_message/1}
  59. ,{"send_list_bad_message", fun send_list_bad_message/1}
  60. ,{"sync_send_list_bad_message", fun sync_send_list_bad_message/1}
  61. ]]]} end
  62. }.
  63. setup() ->
  64. ok = meck:new(of_driver_handler_mock, [passthrough]),
  65. ConnTable = ets:new(conn_table, [set, public]),
  66. [application:set_env(of_driver, K, V) || {K, V} <-
  67. [{callback_module, of_driver_handler_mock},
  68. {listen_port, ?LISTEN_PORT},
  69. {init_opt, ConnTable}]],
  70. ok = application:start(eenum),
  71. ok = application:start(of_protocol),
  72. ok = application:start(lager),
  73. ok = application:start(of_driver),
  74. Socket = connect(),
  75. {Socket, ConnTable}.
  76. cleanup({Socket, _ConnTable}) ->
  77. ok = gen_tcp:close(Socket),
  78. % wait for of_driver to exit before unloading mocks
  79. meck:wait(of_driver_handler_mock, terminate, '_', 1000),
  80. meck:unload().
  81. test_setup() ->
  82. meck:reset(of_driver_handler_mock).
  83. trace() ->
  84. dbg:start(),
  85. dbg:tracer(),
  86. dbg:p(all, c)
  87. % ,dbg:tpl(ofp_v4_encode, [])
  88. % ,dbg:tpl(ofp_v4_encode, [{'_', [], [{return_trace}]}])
  89. % ,dbg:tpl(of_driver_utils, [])
  90. % ,dbg:tpl(of_driver_connection, [])
  91. ,dbg:tpl(of_driver_connection, [{'_', [], [{return_trace}]}])
  92. % ,dbg:tpl(of_driver_datapath, [])
  93. % ,dbg:tpl(gen_tcp, [])
  94. % ,dbg:tpl(gen_tcp, [{'_', [], [{return_trace}]}])
  95. % ,dbg:tpl(?MODULE, [])
  96. .
  97. %%------------------------------------------------------------------------------
  98. set_xid() ->
  99. NewXid = 9999,
  100. Msg = of_msg_lib:get_features(4),
  101. ?assertNotEqual(NewXid, Msg#ofp_message.xid),
  102. NewMsg = of_driver:set_xid(Msg, NewXid),
  103. ?assertEqual(NewXid, NewMsg#ofp_message.xid).
  104. main_connect() ->
  105. ExpectedDatapathId = ?DATAPATH_ID,
  106. meck:expect(of_driver_handler_mock, init,
  107. fun(_IpAddr, DatapathId, Features, Version, _Connection, _Opt) ->
  108. ?assertMatch(#ofp_features_reply{
  109. datapath_mac = ?DATAPATH_UNPARSED,
  110. datapath_id = ExpectedDatapathId}, Features),
  111. ?assertEqual(DatapathId,?DATAPATH_HEX),
  112. ?assertEqual(Version, ?VERSION),
  113. {ok, callback_state}
  114. end),
  115. meck:expect(of_driver_handler_mock, terminate, fun(_Reason, callback_state) -> ok end),
  116. Socket = connect(ExpectedDatapathId),
  117. gen_tcp:close(Socket),
  118. ?assert(meck:validate(of_driver_handler_mock)).
  119. main_terminate() ->
  120. ExpectedDatapathId = ?DATAPATH_ID,
  121. ExpectedAuxId = 1,
  122. meck:expect(of_driver_handler_mock, init,
  123. fun(_IpAddr, DatapathId, Features, Version, _Connection, _Opt) ->
  124. ?assertMatch(#ofp_features_reply{
  125. datapath_mac = ?DATAPATH_UNPARSED,
  126. datapath_id = ExpectedDatapathId}, Features),
  127. ?assertEqual(DatapathId,?DATAPATH_HEX),
  128. ?assertEqual(Version, ?VERSION),
  129. {ok, callback_state}
  130. end),
  131. meck:expect(of_driver_handler_mock, terminate, fun(_Reason, callback_state) -> ok end),
  132. meck:expect(of_driver_handler_mock, handle_connect,
  133. fun(_IpAddr, DatapathId, Features, Version, _Connection, AuxId, _Opt) ->
  134. ?assertMatch(#ofp_features_reply{
  135. datapath_mac = ?DATAPATH_UNPARSED,
  136. datapath_id = ExpectedDatapathId}, Features),
  137. ?assertEqual(DatapathId,?DATAPATH_HEX),
  138. ?assertEqual(Version, ?VERSION),
  139. ?assertEqual(AuxId, ExpectedAuxId),
  140. {ok, aux_callback_state}
  141. end),
  142. meck:expect(of_driver_handler_mock, handle_disconnect, fun(_Reason, aux_callback_state) -> ok end),
  143. Socket = connect(ExpectedDatapathId),
  144. _AuxSocket = connect(ExpectedDatapathId, ExpectedAuxId),
  145. gen_tcp:close(Socket),
  146. ?assert(meck:validate(of_driver_handler_mock)).
  147. early_message() ->
  148. ExpectedDatapathId = ?DATAPATH_ID,
  149. meck:expect(of_driver_handler_mock, init,
  150. fun(_IpAddr, DatapathId, Features, Version, _Connection, _Opt) ->
  151. ?assertMatch(#ofp_features_reply{
  152. datapath_mac = ?DATAPATH_UNPARSED,
  153. datapath_id = ExpectedDatapathId}, Features),
  154. ?assertEqual(DatapathId,?DATAPATH_HEX),
  155. ?assertEqual(Version, ?VERSION),
  156. {ok, callback_state}
  157. end),
  158. meck:expect(of_driver_handler_mock, terminate, fun(_Reason, callback_state) -> ok end),
  159. {ok, Socket} = gen_tcp:connect({127,0,0,1}, ?LISTEN_PORT,
  160. [binary, {active, false}], 5000),
  161. send_msg(Socket, packet_in()),
  162. send_msg(Socket, create_hello(?VERSION)),
  163. {#ofp_message{type = hello}, Rest} = receive_msg(Socket, <<>>),
  164. {#ofp_message{type = features_request, xid = FXID}, <<>>} = receive_msg(Socket, Rest),
  165. send_msg(Socket, packet_in()),
  166. send_msg(Socket, features_reply(FXID, ExpectedDatapathId, 0)),
  167. gen_tcp:close(Socket),
  168. ?assert(meck:validate(of_driver_handler_mock)).
  169. close_connection() ->
  170. ExpectedDatapathId = ?DATAPATH_ID,
  171. Me = self(),
  172. meck:expect(of_driver_handler_mock, init,
  173. fun(_IpAddr, _DatapathId, _Features, _Version, Connection, _Opt) ->
  174. Me ! {connection, Connection},
  175. {ok, callback_state}
  176. end),
  177. meck:expect(of_driver_handler_mock, terminate, fun(_Reason, callback_state) -> ok end),
  178. _Socket = connect(ExpectedDatapathId),
  179. Conn = receive
  180. {connection, C} ->
  181. C
  182. end,
  183. of_driver:close_connection(Conn),
  184. ?assert(meck:validate(of_driver_handler_mock)).
  185. gen_xid({_Socket, ConnTable}) ->
  186. Connection = get_connection(ConnTable),
  187. Count = 4,
  188. Set = lists:foldl(
  189. fun(_C, S) ->
  190. sets:add_element(of_driver:gen_xid(Connection), S)
  191. end, sets:new(), lists:seq(1, Count)),
  192. ?debugVal(sets:to_list(Set)),
  193. ?assertEqual(Count, sets:size(Set)).
  194. aux_connect({_Socket, _ConnTable}) ->
  195. ExpectedAuxId = 1,
  196. meck:expect(of_driver_handler_mock, handle_connect,
  197. fun(_IpAddr, DatapathId, Features, Version, _Connection, AuxId, _Opt) ->
  198. % ?assertMatch(#ofp_features_reply{
  199. % datapath_mac = ?DATAPATH_UNPARSED,
  200. % datapath_id = ?DATAPATH_ID }, Features),
  201. ?assertMatch(#ofp_features_reply{
  202. datapath_mac = ?DATAPATH_UNPARSED,
  203. datapath_id = ?DATAPATH_ID }, Features),
  204. ?assertEqual(DatapathId,?DATAPATH_HEX),
  205. ?assertEqual(Version, ?VERSION),
  206. ?assertEqual(AuxId, ExpectedAuxId),
  207. {ok, aux_callback_state}
  208. end),
  209. meck:expect(of_driver_handler_mock, handle_disconnect, fun(_Reason, aux_callback_state) -> ok end),
  210. AuxSocket = connect_aux(?DATAPATH_ID,ExpectedAuxId),
  211. gen_tcp:close(AuxSocket),
  212. ?assertNot(meck:called(of_driver_handler_mock, terminate, '_')),
  213. ?assert(meck:validate(of_driver_handler_mock)).
  214. in_message({Socket, _ConnTable}) ->
  215. meck:expect(of_driver_handler_mock, handle_message,
  216. fun(#ofp_message{type = packet_in}, State) -> {ok, State} end),
  217. send_msg(Socket, packet_in()),
  218. ?assert(meck:validate(of_driver_handler_mock)).
  219. echo_request({Socket, _ConnTable}) ->
  220. Xid = 1234,
  221. Data = <<>>,
  222. send_msg(Socket, echo_request(Xid, Data)),
  223. {#ofp_message{type = echo_reply, xid = Xid, body = Body}, <<>>} = receive_msg(Socket, <<>>),
  224. ?assertMatch(#ofp_echo_reply{data = Data}, Body).
  225. echo_request2({Socket, _ConnTable}) ->
  226. Xid = 1234,
  227. Data = <<"somedata">>,
  228. send_msg(Socket, echo_request(Xid, Data)),
  229. {#ofp_message{type = echo_reply, xid = Xid, body = Body}, <<>>} = receive_msg(Socket, <<>>),
  230. ?assertMatch(#ofp_echo_reply{data = Data}, Body).
  231. send({Socket, ConnTable}) ->
  232. Hello = create_hello(4),
  233. Connection = get_connection(ConnTable),
  234. ok = of_driver:send(Connection, Hello),
  235. {Recv, <<>>} = receive_msg(Socket, <<>>),
  236. ?assertEqual(Hello, Recv),
  237. ?assertNot(meck:called(of_driver_handler_mock, handle_message, '_')).
  238. sync_send({Socket, ConnTable}) ->
  239. Connection = get_connection(ConnTable),
  240. Msg = of_msg_lib:get_features(4),
  241. Future = future(of_driver, sync_send, [Connection, Msg]),
  242. {#ofp_message{type = features_request, xid = RXID}, Rest} = receive_msg(Socket, <<>>),
  243. {#ofp_message{type = barrier_request, xid = BXID}, <<>>} = receive_msg(Socket, Rest),
  244. send_msg(Socket, features_reply(RXID)),
  245. send_msg(Socket, barrier_reply(BXID)),
  246. {ok, Reply} = wait_future(Future),
  247. ?assertMatch(#ofp_message{type = features_reply}, Reply),
  248. ?assertNot(meck:called(of_driver_handler_mock, handle_message, '_')).
  249. sync_send_no_reply({Socket, ConnTable}) ->
  250. Connection = get_connection(ConnTable),
  251. Msg = of_msg_lib:get_features(4),
  252. Future = future(of_driver, sync_send, [Connection, Msg]),
  253. {#ofp_message{type = features_request}, Rest} = receive_msg(Socket, <<>>),
  254. {#ofp_message{type = barrier_request, xid = BXID}, <<>>} = receive_msg(Socket, Rest),
  255. send_msg(Socket, barrier_reply(BXID)),
  256. {ok, Reply} = wait_future(Future),
  257. ?assertEqual(noreply, Reply),
  258. ?assertNot(meck:called(of_driver_handler_mock, handle_message, '_')).
  259. sync_send_non_reply({Socket, ConnTable}) ->
  260. % sync_send and message is received that is not a reply to the request
  261. % (XID doesn't match).
  262. meck:expect(of_driver_handler_mock, handle_message,
  263. fun(#ofp_message{type = features_reply, xid = 9999}, State) ->
  264. {ok, State}
  265. end),
  266. Connection = get_connection(ConnTable),
  267. Msg = of_msg_lib:get_features(4),
  268. Future = future(of_driver, sync_send, [Connection, Msg]),
  269. {#ofp_message{type = features_request}, Rest} = receive_msg(Socket, <<>>),
  270. {#ofp_message{type = barrier_request, xid = BXID}, <<>>} = receive_msg(Socket, Rest),
  271. send_msg(Socket, features_reply(9999)),
  272. send_msg(Socket, barrier_reply(BXID)),
  273. {ok, Reply} = wait_future(Future),
  274. ?assertEqual(noreply, Reply),
  275. ?assertEqual(1, meck:num_calls(of_driver_handler_mock, handle_message, '_')),
  276. ?assert(meck:validate(of_driver_handler_mock)).
  277. sync_send_multipart({Socket, ConnTable}) ->
  278. Connection = get_connection(ConnTable),
  279. Msg = of_msg_lib:get_port_descriptions(4),
  280. Future = future(of_driver, sync_send, [Connection, Msg]),
  281. {#ofp_message{type = multipart_request, xid = RXID}, Rest} = receive_msg(Socket, <<>>),
  282. {#ofp_message{type = barrier_request, xid = BXID}, <<>>} = receive_msg(Socket, Rest),
  283. send_msg(Socket, multipart_reply(ofp_port_desc_reply,RXID,[more])),
  284. send_msg(Socket, multipart_reply(ofp_port_desc_reply,RXID)),
  285. send_msg(Socket, barrier_reply(BXID)),
  286. {ok, Reply} = wait_future(Future),
  287. ?assertMatch(#ofp_message{type = multipart_reply,
  288. xid = RXID,
  289. body = #ofp_port_desc_reply{ body = [#ofp_port{} = _InnerBody1,
  290. #ofp_port{} = _InnerBody2] }
  291. }, Reply),
  292. ?assertNot(meck:called(of_driver_handler_mock, handle_message, '_')).
  293. send_list({Socket, ConnTable}) ->
  294. Connection = get_connection(ConnTable),
  295. Hello = create_hello(4),
  296. Features = of_msg_lib:get_features(4),
  297. ok = of_driver:send_list(Connection, [Hello, Features, Hello]),
  298. {Recv0, Rest0} = receive_msg(Socket, <<>>),
  299. {Recv1, Rest1} = receive_msg(Socket, Rest0),
  300. {Recv2, <<>>} = receive_msg(Socket, Rest1),
  301. ?assertMatch(#ofp_message{type = hello}, Recv0),
  302. ?assertMatch(#ofp_message{type = features_request}, Recv1),
  303. ?assertMatch(#ofp_message{type = hello}, Recv2).
  304. sync_send_list({Socket, ConnTable}) ->
  305. Connection = get_connection(ConnTable),
  306. Msg = of_msg_lib:get_features(4),
  307. Future = future(of_driver, sync_send_list, [Connection, [Msg, Msg, Msg]]),
  308. {#ofp_message{type = features_request, xid = RXID0}, Rest0} = receive_msg(Socket, <<>>),
  309. {#ofp_message{type = features_request, xid = RXID1}, Rest1} = receive_msg(Socket, Rest0),
  310. {#ofp_message{type = features_request, xid = RXID2}, Rest2} = receive_msg(Socket, Rest1),
  311. {#ofp_message{type = barrier_request, xid = BXID}, <<>>} = receive_msg(Socket, Rest2),
  312. send_msg(Socket, features_reply(RXID0)),
  313. send_msg(Socket, features_reply(RXID1)),
  314. send_msg(Socket, features_reply(RXID2)),
  315. send_msg(Socket, barrier_reply(BXID)),
  316. {ok, [Reply0, Reply1, Reply2]} = wait_future(Future),
  317. ?assertMatch({ok, #ofp_message{type = features_reply, xid = RXID0}}, Reply0),
  318. ?assertMatch({ok, #ofp_message{type = features_reply, xid = RXID1}}, Reply1),
  319. ?assertMatch({ok, #ofp_message{type = features_reply, xid = RXID2}}, Reply2),
  320. ?assertNot(meck:called(of_driver_handler_mock, handle_message, '_')).
  321. sync_send_list_no_reply({Socket, ConnTable}) ->
  322. meck:expect(of_driver_handler_mock, handle_message,
  323. fun(#ofp_message{type = features_reply, xid = 9999}, State) ->
  324. {ok, State}
  325. end),
  326. Connection = get_connection(ConnTable),
  327. Msg = of_msg_lib:get_features(4),
  328. Future = future(of_driver, sync_send_list, [Connection, [Msg, Msg, Msg]]),
  329. {#ofp_message{type = features_request, xid = _RXID0}, Rest0} = receive_msg(Socket, <<>>),
  330. {#ofp_message{type = features_request, xid = _RXID1}, Rest1} = receive_msg(Socket, Rest0),
  331. {#ofp_message{type = features_request, xid = RXID2}, Rest2} = receive_msg(Socket, Rest1),
  332. {#ofp_message{type = barrier_request, xid = BXID}, <<>>} = receive_msg(Socket, Rest2),
  333. % no reply to first features request
  334. send_msg(Socket, features_reply(9999)),
  335. send_msg(Socket, features_reply(RXID2)),
  336. send_msg(Socket, barrier_reply(BXID)),
  337. {ok, [Reply0, Reply1, Reply2]} = wait_future(Future),
  338. ?assertMatch({ok, noreply}, Reply0),
  339. ?assertMatch({ok, noreply}, Reply1),
  340. ?assertMatch({ok, #ofp_message{type = features_reply, xid = RXID2}}, Reply2),
  341. ?assert(meck:validate(of_driver_handler_mock)).
  342. sync_send_list_multipart({Socket, ConnTable}) ->
  343. Connection = get_connection(ConnTable),
  344. Msg = of_msg_lib:get_port_descriptions(4),
  345. Msg2 = of_msg_lib:get_queue_statistics(4,any,all),
  346. Future = future(of_driver, sync_send_list, [Connection, [Msg, Msg2]]),
  347. %% {ofp_message,4,multipart_request,20,{ofp_port_desc_request,[]}}
  348. {#ofp_message{type = multipart_request, xid = RXID0}, Rest0} = receive_msg(Socket, <<>>),
  349. {#ofp_message{type = multipart_request, xid = RXID1}, Rest1} = receive_msg(Socket, Rest0),
  350. {#ofp_message{type = barrier_request, xid = BXID}, <<>>} = receive_msg(Socket, Rest1),
  351. send_msg(Socket, multipart_reply(ofp_port_desc_reply,RXID0,[more])),
  352. send_msg(Socket, multipart_reply(ofp_port_desc_reply,RXID0)),
  353. send_msg(Socket, multipart_reply(ofp_queue_stats_reply,RXID1,[more])),
  354. send_msg(Socket, multipart_reply(ofp_queue_stats_reply,RXID1)),
  355. send_msg(Socket, barrier_reply(BXID)),
  356. {ok, [Reply0, Reply1]} = wait_future(Future),
  357. %% io:format("Reply0 ~p\n",[Reply0]),
  358. %% io:format("Reply1 ~p\n",[Reply1]),
  359. ?assertMatch({ok,#ofp_message{type = multipart_reply,
  360. xid = RXID0,
  361. body = #ofp_port_desc_reply{ body = [#ofp_port{} = _InnerBody1,
  362. #ofp_port{} = _InnerBody2] }
  363. }}, Reply0),
  364. ?assertMatch({ok,#ofp_message{type = multipart_reply,
  365. xid = RXID1,
  366. body = #ofp_queue_stats_reply{ body = [#ofp_queue_stats{} = _InnerBody3,
  367. #ofp_queue_stats{} = _InnerBody4] }
  368. }}, Reply1),
  369. ?assertNot(meck:called(of_driver_handler_mock, handle_message, '_')).
  370. multiple_sync_send({Socket, ConnTable}) ->
  371. Connection = get_connection(ConnTable),
  372. Msg = of_msg_lib:get_features(4),
  373. Future1 = future(of_driver, sync_send, [Connection, Msg]),
  374. {#ofp_message{type = features_request, xid = RXID1}, Rest1} = receive_msg(Socket, <<>>),
  375. {#ofp_message{type = barrier_request, xid = BXID1}, <<>>} = receive_msg(Socket, Rest1),
  376. Future2 = future(of_driver, sync_send, [Connection, Msg]),
  377. {#ofp_message{type = features_request, xid = RXID2}, Rest2} = receive_msg(Socket, <<>>),
  378. {#ofp_message{type = barrier_request, xid = BXID2}, <<>>} = receive_msg(Socket, Rest2),
  379. send_msg(Socket, features_reply(RXID2)),
  380. send_msg(Socket, features_reply(RXID1)),
  381. send_msg(Socket, barrier_reply(BXID1)),
  382. send_msg(Socket, barrier_reply(BXID2)),
  383. {ok, Reply1} = wait_future(Future1),
  384. {ok, Reply2} = wait_future(Future2),
  385. ?assertMatch(#ofp_message{type = features_reply, xid = RXID1}, Reply1),
  386. ?assertMatch(#ofp_message{type = features_reply, xid = RXID2}, Reply2),
  387. ?assertNot(meck:called(of_driver_handler_mock, handle_message, '_')).
  388. send_unsupported_version({_Socket, ConnTable}) ->
  389. Connection = get_connection(ConnTable),
  390. BadMsg = (of_msg_lib:get_features(4))#ofp_message{version = -1},
  391. R = of_driver:send(Connection, BadMsg),
  392. ?assertMatch({error, unsupported_version}, R).
  393. sync_send_unsupported_version({Socket, ConnTable}) ->
  394. Connection = get_connection(ConnTable),
  395. BadMsg = (of_msg_lib:get_features(4))#ofp_message{version = -1},
  396. Future = future(of_driver, sync_send, [Connection, BadMsg]),
  397. {#ofp_message{type = barrier_request, xid = BXID}, <<>>} = receive_msg(Socket, <<>>),
  398. send_msg(Socket, barrier_reply(BXID)),
  399. ?assertMatch({error, unsupported_version}, wait_future(Future)).
  400. send_bad_message({_Socket, ConnTable}) ->
  401. Connection = get_connection(ConnTable),
  402. R = of_driver:send(Connection, #ofp_message{type = not_a_valid_message, version = 4}),
  403. ?assertMatch({error, {bad_message, _}}, R).
  404. sync_send_bad_message({Socket, ConnTable}) ->
  405. Connection = get_connection(ConnTable),
  406. Future = future(of_driver, sync_send, [Connection, #ofp_message{type = not_a_valid_message, version = 4}]),
  407. {#ofp_message{type = barrier_request, xid = BXID}, <<>>} = receive_msg(Socket, <<>>),
  408. send_msg(Socket, barrier_reply(BXID)),
  409. ?assertMatch({error, _}, wait_future(Future)).
  410. send_list_bad_message({Socket, ConnTable}) ->
  411. Connection = get_connection(ConnTable),
  412. GoodMsg = of_msg_lib:get_features(4),
  413. BadMsg = #ofp_message{type = not_a_valid_message, version = 4},
  414. R = of_driver:send_list(Connection, [GoodMsg, BadMsg]),
  415. ?assertMatch({error, [ok, {error, {bad_message, _}}]}, R),
  416. {#ofp_message{type = features_request}, <<>>} = receive_msg(Socket, <<>>).
  417. sync_send_list_bad_message({Socket, ConnTable}) ->
  418. Connection = get_connection(ConnTable),
  419. GoodMsg = of_msg_lib:get_features(4),
  420. BadMsg = #ofp_message{type = not_a_valid_message, version = 4},
  421. Future = future(of_driver, sync_send_list, [Connection, [GoodMsg, BadMsg]]),
  422. {#ofp_message{type = features_request}, Rest} = receive_msg(Socket, <<>>),
  423. {#ofp_message{type = barrier_request, xid = BXID}, <<>>} = receive_msg(Socket, Rest),
  424. send_msg(Socket, barrier_reply(BXID)),
  425. Reply = wait_future(Future),
  426. ?assertMatch({error, [{ok, noreply}, {error,{bad_message, _}}]}, Reply).
  427. %%------------------------------------------------------------------------------
  428. get_connection(ConnTable) ->
  429. get_connection(ConnTable, 0).
  430. get_connection(ConnTable, AuxId) ->
  431. [{AuxId, Connection}] = ets:lookup(ConnTable, AuxId),
  432. Connection.
  433. receive_msg(Socket, <<>>) ->
  434. {ok, MsgBin} = gen_tcp:recv(Socket, 0),
  435. {ok, OfpMsg, LeftOvers} = of_protocol:decode(<<MsgBin/binary>>),
  436. % ?debugFmt("~n~nreceive message: ~p~n", [OfpMsg]),
  437. {OfpMsg, LeftOvers};
  438. receive_msg(_Socket, MsgBin) ->
  439. {ok, OfpMsg, LeftOvers} = of_protocol:decode(<<MsgBin/binary>>),
  440. % ?debugFmt("~n~nreceive message: ~p~n", [OfpMsg]),
  441. {OfpMsg, LeftOvers}.
  442. send_msg(Socket, Msg) ->
  443. % ?debugFmt("~n~nsend message: ~p~n", [Msg]),
  444. {ok, Bin} = of_protocol:encode(Msg),
  445. ok = gen_tcp:send(Socket, Bin).
  446. connect_aux(AuxId) ->
  447. connect(0, AuxId).
  448. connect_aux(DatapathID,AuxId) ->
  449. connect(DatapathID,AuxId).
  450. connect() ->
  451. connect(0, 0).
  452. connect(DatapathId) ->
  453. connect(DatapathId, 0).
  454. connect(DatapathId, AuxId) ->
  455. {ok, Socket} = gen_tcp:connect({127,0,0,1}, ?LISTEN_PORT,
  456. [binary, {active, false}], 5000),
  457. send_msg(Socket, create_hello(?VERSION)),
  458. {#ofp_message{type = hello}, Rest} = receive_msg(Socket, <<>>),
  459. {#ofp_message{type = features_request, xid = XID}, <<>>} = receive_msg(Socket, Rest),
  460. send_msg(Socket, features_reply(XID, DatapathId, AuxId)),
  461. Socket.
  462. future(M, F, A) ->
  463. Token = make_ref(),
  464. Parent = self(),
  465. spawn(fun() -> future_call(Parent, Token, M, F, A) end),
  466. Token.
  467. wait_future(Token) ->
  468. receive
  469. {future, Token, R} -> R
  470. end.
  471. future_call(Parent, Token, M, F, A) ->
  472. R = apply(M, F, A),
  473. Parent ! {future, Token, R}.
  474. %%------------------------------------------------------------------------------
  475. create_hello(Version) ->
  476. #ofp_message{version = Version, xid = 0,
  477. type = hello,
  478. body = #ofp_hello{elements = [{versionbitmap, [Version]}]}}.
  479. barrier_reply(XID) ->
  480. #ofp_message{
  481. version = ?VERSION,
  482. type = barrier_reply,
  483. xid = XID,
  484. body = #ofp_barrier_reply{}
  485. }.
  486. features_reply(XID) ->
  487. features_reply(XID, ?DATAPATH_ID, 0).
  488. features_reply(XID, DatapathId, AuxId) ->
  489. #ofp_message{
  490. version = ?VERSION,
  491. type = features_reply,
  492. xid = XID,
  493. body = #ofp_features_reply{
  494. datapath_mac = ?DATAPATH_UNPARSED,
  495. datapath_id = DatapathId,
  496. n_buffers = 0,
  497. n_tables = 255,
  498. auxiliary_id = AuxId,
  499. capabilities = [flow_stats,table_stats,port_stats,group_stats,queue_stats]
  500. }
  501. }.
  502. echo_request(XID, Data) ->
  503. #ofp_message{
  504. version = ?VERSION,
  505. type = echo_request,
  506. xid = XID,
  507. body = #ofp_echo_request{
  508. data = Data
  509. }
  510. }.
  511. packet_in() ->
  512. #ofp_message{
  513. version = ?VERSION,
  514. type = packet_in,
  515. body = #ofp_packet_in{
  516. buffer_id = no_buffer,
  517. reason = action,
  518. table_id = 1,
  519. cookie = <<0:64>>,
  520. match = #ofp_match{fields = []},
  521. data = <<"abcd">>
  522. }
  523. }.
  524. multipart_reply(Type,Xid) ->
  525. multipart_reply(Type,Xid,[]).
  526. multipart_reply(ofp_port_desc_reply,Xid,Flags) ->
  527. #ofp_message{
  528. version = ?VERSION,
  529. type = multipart_reply,
  530. xid = Xid,
  531. body = #ofp_port_desc_reply{ flags = Flags,
  532. body = [{ofp_port,714,
  533. <<14,7,73,8,219,149>>,
  534. <<"Port714">>,[],
  535. [live],
  536. ['100mb_fd',copper,autoneg],
  537. [copper,autoneg],
  538. ['100mb_fd',copper,autoneg],
  539. ['100mb_fd',copper,autoneg],
  540. 5000,5000}]
  541. }
  542. };
  543. multipart_reply(ofp_queue_stats_reply,Xid,_Flags) ->
  544. #ofp_message{
  545. version = ?VERSION,
  546. type = multipart_reply,
  547. xid = Xid,
  548. body = #ofp_queue_stats_reply{flags = [more],
  549. body = [{ofp_queue_stats,1,664,0,0,0,13980,651246000}]
  550. }
  551. }.