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