{"action":"created","comment":{"url":"https://api.github.com/repos/shun159/gyges/pulls/comments/87995240","pull_request_review_id":8582296,"id":87995240,"diff_hunk":"@@ -0,0 +1,669 @@\n+%%------------------------------------------------------------------------------\n+%% Copyright 2015 2016 Eishun Kondoh\n+%%\n+%% Licensed under the Apache License, Version 2.0 (the \"License\");\n+%% you may not use this file except in compliance with the License.\n+%% You may obtain a copy of the License at\n+%%\n+%% http://www.apache.org/licenses/LICENSE-2.0\n+%%\n+%% Unless required by applicable law or agreed to in writing, software\n+%% distributed under the License is distributed on an \"AS IS\" BASIS,\n+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+%% See the License for the specific language governing permissions and\n+%% limitations under the License.\n+%%-----------------------------------------------------------------------------\n+%% @author Eishun Kondoh\n+%%\n+%% @doc OpenFlow Packet Library\n+%% This module implements an openflow 1.0 + nicira_ext\n+-module(ofc_dp_conn).\n+\n+-behaviour(gen_fsm).\n+\n+%% API\n+-export([start_link/4]).\n+-export([get_transaction_count/1]).\n+-export([get_features/1]).\n+-export([set_config/2, get_config/1]).\n+-export([role_request/2]).\n+-export([set_async_config/2, get_async_config/1]).\n+-export([set_port_up/3,set_port_down/3, set_port_advertise/4]).\n+-export([get_switch_description/1]).\n+-export([get_flows/2]).\n+-export([get_aggregate/2]).\n+-export([get_table_stats/1]).\n+-export([get_table_features/1]).\n+-export([get_port_stats/2]).\n+-export([get_port_desc/1]).\n+-export([get_queue_stats/3]).\n+-export([get_group_stats/2]).\n+-export([get_group_desc/1]).\n+-export([get_group_features/1]).\n+-export([send_msg/2, send_msgs/2]).\n+-export([ping_timeout/1]).\n+-export([get_meter_stats/2]).\n+-export([get_meter_config/2]).\n+-export([get_meter_features/1]).\n+\n+%% gen_fsm callbacks\n+-export([init/1, init/4, initializing/2, connecting/2, connected/2, disconnected/2, connected/3, handle_event/3,\n+         handle_sync_event/4, handle_info/3, terminate/3, code_change/4]).\n+\n+-include(\"../../include/ofp_v4.hrl\").\n+-include(\"../../include/switch.hrl\").\n+-include(\"../gyges_logger.hrl\").\n+\n+-define(SERVER, ?MODULE).\n+-define(OFC_OK_REPLY(Reply), {ok, Reply}).\n+-define(OFC_ERR_REPLY(Reply), {error, Reply}).\n+-define(CONNECTING_TIMEOUT, 10000).\n+-define(CONNECTED_TIMEOUT,  10000).\n+-define(SYNC_SEND_TIMEOUT,  1000).\n+-define(PING_FAIL_MAX, 5).\n+-define(ON_ACCEPTED, switch_accepted).\n+-define(ON_CONNECTED, switch_connected).\n+-define(ON_DISCONNECTED, switch_disconnected).\n+-define(STATE, ofc_dp_conn_state).\n+\n+-record(?STATE, {socket :: inet:socket(),\n+                 transport :: atom(),\n+                 version :: integer(),\n+                 connection = #connection{} :: connection(),\n+                 pending_message = #{} :: map(),\n+                 buffer = <<>> :: binary(),\n+                 datapath_id = <<0:64>> :: <<_:64>>,\n+                 datapath_mac = \"\" :: string(),\n+                 n_buffers = 0 :: integer(),\n+                 n_tables = 0 :: integer(),\n+                 auxiliary_id = 0 :: integer(),\n+                 sync_send_client = undefined :: reference(),\n+                 is_echo_request = false :: boolean(),\n+                 ping_timer_ref = undefined :: reference(),\n+                 last_receive :: term(),\n+                 ping_xid = 0 :: integer(),\n+                 ping_interval = 0 :: integer(),\n+                 ping_timeout = 0 :: integer(),\n+                 capabilities = [] :: ofp_switch_capability(),\n+                 ping_fail_count = 0 :: integer(),\n+                 process_xids = [] :: list(),\n+                 in_progress = false :: boolean(),\n+                 sync_request_queue = queue:new() :: {[term()], [term()]}}).\n+\n+%%%===================================================================\n+%%% API\n+%%%===================================================================\n+\n+start_link(Ref, Socket, Transport, Opts) ->\n+    proc_lib:start_link(?MODULE, init, [Ref, Socket, Transport, Opts]).\n+\n+%%%===================================================================\n+%%% Synchronous API\n+%%%===================================================================\n+\n+get_transaction_count({Dpid, AuxId}) ->\n+    Pid = gyges_datapath_db:lookup_connection(Dpid, AuxId),\n+    gen_fsm:sync_send_event(Pid, transaction_count).\n+\n+get_features({Dpid, AuxId}) ->\n+    Pid = gyges_datapath_db:lookup_connection(Dpid, AuxId),\n+    gen_fsm:sync_send_event(Pid, {sync_send, get_features}).\n+\n+set_config({Dpid, AuxId}, Options) ->\n+    Pid = gyges_datapath_db:lookup_connection(Dpid, AuxId),\n+    gen_fsm:sync_send_event(Pid, {sync_send, {set_config, Options}}).\n+\n+get_config({Dpid, AuxId}) ->\n+    Pid = gyges_datapath_db:lookup_connection(Dpid, AuxId),\n+    gen_fsm:sync_send_event(Pid, {sync_send, get_config}).\n+\n+role_request({Dpid, AuxId}, Options) ->\n+    Pid = gyges_datapath_db:lookup_connection(Dpid, AuxId),\n+    gen_fsm:sync_send_event(Pid, {sync_send, {role_request, Options}}).\n+\n+set_async_config({Dpid, AuxId}, Options) ->\n+    Pid = gyges_datapath_db:lookup_connection(Dpid, AuxId),\n+    gen_fsm:sync_send_event(Pid, {sync_send, {set_async_config, Options}}).\n+\n+get_async_config({Dpid, AuxId}) ->\n+    Pid = gyges_datapath_db:lookup_connection(Dpid, AuxId),\n+    gen_fsm:sync_send_event(Pid, {sync_send, get_async_config}).\n+\n+set_port_up({Dpid, AuxId}, PortNo, HwAddr) ->\n+    Pid = gyges_datapath_db:lookup_connection(Dpid, AuxId),\n+    gen_fsm:sync_send_event(Pid, {sync_send, {port_up, PortNo, HwAddr}}).\n+\n+set_port_down({Dpid, AuxId}, PortNo, HwAddr) ->\n+    Pid = gyges_datapath_db:lookup_connection(Dpid, AuxId),\n+    gen_fsm:sync_send_event(Pid, {sync_send, {port_down, PortNo, HwAddr}}).\n+\n+set_port_advertise({Dpid, AuxId}, PortNo, HwAddr, Adv) ->\n+    Pid = gyges_datapath_db:lookup_connection(Dpid, AuxId),\n+    gen_fsm:sync_send_event(Pid, {sync_send, {port_advert, PortNo, HwAddr, Adv}}).\n+\n+get_switch_description({Dpid, AuxId}) ->\n+    Pid = gyges_datapath_db:lookup_connection(Dpid, AuxId),\n+    gen_fsm:sync_send_event(Pid, {sync_send, {switch_desc}}).\n+\n+get_flows({Dpid, AuxId}, Options) ->\n+    Pid = gyges_datapath_db:lookup_connection(Dpid, AuxId),\n+    gen_fsm:sync_send_event(Pid, {sync_send, {flow_stats, Options}}).\n+\n+get_aggregate({Dpid, AuxId}, Options) ->\n+    Pid = gyges_datapath_db:lookup_connection(Dpid, AuxId),\n+    gen_fsm:sync_send_event(Pid, {sync_send, {aggregate_stats, Options}}).\n+\n+get_table_stats({Dpid, AuxId}) ->\n+    Pid = gyges_datapath_db:lookup_connection(Dpid, AuxId),\n+    gen_fsm:sync_send_event(Pid, {sync_send, {table_stats}}).\n+\n+get_table_features({Dpid, AuxId}) ->\n+    Pid = gyges_datapath_db:lookup_connection(Dpid, AuxId),\n+    gen_fsm:sync_send_event(Pid, {sync_send, {table_features}}).\n+\n+get_port_stats({Dpid, AuxId}, PortNo) ->\n+    Pid = gyges_datapath_db:lookup_connection(Dpid, AuxId),\n+    gen_fsm:sync_send_event(Pid, {sync_send, {port_stats, PortNo}}).\n+\n+get_port_desc({Dpid, AuxId}) ->\n+    Pid = gyges_datapath_db:lookup_connection(Dpid, AuxId),\n+    gen_fsm:sync_send_event(Pid, {sync_send, {port_desc}}).\n+\n+get_queue_stats({Dpid, AuxId}, PortNo, QueueId) ->\n+    Pid = gyges_datapath_db:lookup_connection(Dpid, AuxId),\n+    gen_fsm:sync_send_event(Pid, {sync_send, {queue_stats, PortNo, QueueId}}).\n+\n+get_group_stats({Dpid, AuxId}, GroupId) ->\n+    Pid = gyges_datapath_db:lookup_connection(Dpid, AuxId),\n+    gen_fsm:sync_send_event(Pid, {sync_send, {group_stats, GroupId}}).\n+\n+get_group_desc({Dpid, AuxId}) ->\n+    Pid = gyges_datapath_db:lookup_connection(Dpid, AuxId),\n+    gen_fsm:sync_send_event(Pid, {sync_send, {group_desc}}).\n+\n+get_group_features({Dpid, AuxId}) ->\n+    Pid = gyges_datapath_db:lookup_connection(Dpid, AuxId),\n+    gen_fsm:sync_send_event(Pid, {sync_send, {group_features}}).\n+\n+get_meter_stats({Dpid, AuxId}, MeterId) ->\n+    Pid = gyges_datapath_db:lookup_connection(Dpid, AuxId),\n+    gen_fsm:sync_send_event(Pid, {sync_send, {meter_stats, MeterId}}).\n+\n+get_meter_config({Dpid, AuxId}, MeterId) ->\n+    Pid = gyges_datapath_db:lookup_connection(Dpid, AuxId),\n+    gen_fsm:sync_send_event(Pid, {sync_send, {meter_config, MeterId}}).\n+\n+get_meter_features({Dpid, AuxId}) ->\n+    Pid = gyges_datapath_db:lookup_connection(Dpid, AuxId),\n+    gen_fsm:sync_send_event(Pid, {sync_send, {meter_features}}).\n+\n+send_msg({Dpid, AuxId}, Msg) ->\n+    Pid = gyges_datapath_db:lookup_connection(Dpid, AuxId),\n+    gen_fsm:send_event(Pid, {send, {user, Msg}}).\n+\n+send_msgs({Dpid, AuxId}, Msgs) when is_list(Msgs) ->\n+    Pid = gyges_datapath_db:lookup_connection(Dpid, AuxId),\n+    gen_fsm:send_event(Pid, {send_seq, {user, Msgs}}).\n+\n+ping_timeout(Pid) ->\n+    gen_fsm:send_event(Pid, ping_timeout).\n+\n+%%%===================================================================\n+%%% Asynchronous API\n+%%%===================================================================\n+\n+%%%===================================================================\n+%%% gen_fsm callbacks\n+%%%===================================================================\n+\n+init([]) -> {ok, undefined}.\n+\n+init(Ref, Socket, Transport, _Opts = []) ->\n+    ok = proc_lib:init_ack({ok, self()}),\n+    ok = ranch:accept_ack(Ref),\n+    ok = Transport:setopts(Socket, [{active, once}]),\n+    process_flag(trap_exit, true),\n+    {ok, {Addr, Port}} = inet:peername(Socket),\n+    ?DEBUG(\"[~p] Connected to Switch on ~s:~p. Connection : ~p ~n\",\n+           [?MODULE, inet_parse:ntoa(Addr), Port, self()]),\n+    ok = gen_fsm:send_event(self(), {send, hello}),\n+    SwitchConn = #connection{address = Addr, port = Port},\n+    ofc_event:dispatch(?ON_ACCEPTED, SwitchConn#connection{message = ?ON_ACCEPTED}),\n+    true = setup_counter(),\n+    gen_fsm:enter_loop(?MODULE, [], initializing,\n+                       #?STATE{socket = Socket, transport = Transport,\n+                               last_receive = erlang:timestamp(),\n+                               ping_interval = 5000, ping_timeout = 10000,\n+                               connection = SwitchConn}).\n+\n+initializing(#ofp_header{body=#ofp_hello{elements = Elem}},  State) ->\n+    case lists:member(?OFP13_VERSION, Elem) of\n+        true ->\n+            ok = gen_fsm:send_event(self(), {send, get_features}),\n+            {next_state, connecting, State, ?CONNECTING_TIMEOUT};\n+        false ->\n+            close_connection(State, failed_version_negotiation)\n+    end;\n+initializing({send, hello}, State) ->\n+    Xid = get_xid_and_incr(),\n+    Packet = gyges_utils:create_hello_packet(?OFP13_VERSION, Xid),\n+    send_message(State, Packet),\n+    {next_state, initializing, State};\n+initializing(tcp_closed, State) ->\n+    ?MODULE:disconnected({tcp_closed, initializing}, State);\n+initializing(_, State) ->\n+    {next_state, initializing, State}.\n+\n+connecting(#ofp_header{body=#ofp_switch_features{datapath_id = Dpid,\n+                                                 n_buffers = NBuffers,\n+                                                 n_tables = NTables,\n+                                                 auxiliary_id = AuxId,\n+                                                 capabilities = Capas}},\n+           State = #?STATE{connection = SwitchConn0}) ->\n+    DpMac = gyges_utils:datapath_id(Dpid),\n+    gyges_datapath_db:insert_connection(DpMac, AuxId, self()),\n+    ?INFO(\"[~p] Connected datapath_id: ~p aux_id: ~p on ~p~n\", [?MODULE, DpMac, AuxId, self()]),\n+    SwitchConn = SwitchConn0#connection{message = ?ON_CONNECTED, datapath_id = DpMac, aux_id = AuxId},\n+    ofc_event:dispatch(?ON_CONNECTED, SwitchConn),\n+    NewState = State#?STATE{datapath_id = Dpid,\n+                            datapath_mac = DpMac,\n+                            n_buffers = NBuffers,\n+                            n_tables = NTables,\n+                            auxiliary_id = AuxId,\n+                            capabilities = Capas,\n+                            connection = SwitchConn},\n+    {next_state, connected, NewState, ?CONNECTED_TIMEOUT};\n+connecting(<<?OFP13_VERSION:8, ?OFPT_ERROR:8, _/bytes>>, State) ->\n+    close_connection(State, failed_version_negotiation);\n+connecting({send, get_features}, State) ->\n+    Xid = get_xid_and_incr(),\n+    Packet = gyges_utils:create_features_request_packet(?OFP13_VERSION, Xid),\n+    send_message(State, Packet),\n+    {next_state, connecting, State};\n+connecting(timeout, State) ->\n+    close_connection(State, {timeout, initializing});\n+connecting(tcp_closed, State) ->\n+    ?MODULE:disconnected({tcp_closed, connecting}, State);\n+connecting(_, State) ->\n+    {next_state, connecting, State}.\n+\n+connected(timeout,State = #?STATE{is_echo_request = false}) ->\n+    ?INFO(\"[~p] No echo request from switch(~p) in ~p sec, switch to ping mode~n\",\n+          [?MODULE,self(),?CONNECTED_TIMEOUT / 1000]),\n+    NewState = send_ping(State),\n+    {next_state, connected, NewState};\n+connected(#ofp_header{xid = Xid, body = #ofp_echo_request{data = Body}},\n+          State = #?STATE{ping_timeout = PingTimeOut, ping_timer_ref = OldTRef}) ->\n+    timer:cancel(OldTRef),\n+    ok = gen_fsm:send_event(self(), {send, {echo_reply, Xid, Body}}),\n+    {ok, TRef} = timer:apply_after(PingTimeOut, ?MODULE, ping_timeout, [self()]),\n+    {next_state, connected, State#?STATE{is_echo_request = true, ping_timer_ref = TRef}};\n+connected(#ofp_header{xid = Xid, type = barrier_reply} = Msg,\n+          State0 = #?STATE{pending_message = PM0, process_xids = PXids0, connection = SwitchConn}) ->\n+    {InProgress, PXids, State1} = case PXids0 -- [Xid] of\n+                                      []     ->\n+                                          TmpState = State0#?STATE{process_xids = [],in_progress = false},\n+                                          {false, [], maybe_send_queue(TmpState)};\n+                                      PXids1 ->\n+                                          {true, PXids1, State0}\n+                                  end,\n+    NewState = case maps:get(Xid, PM0, false) of\n+                   false ->\n+                       case lists:member(Xid, PXids0) of\n+                           false ->\n+                               ?DEBUG(\"[~p] send openflow message(~p) to handlers\", [?MODULE, barrier_reply]),\n+                               ofc_event:dispatch(barrier_reply, SwitchConn#connection{message = Msg});\n+                           true -> ok\n+                       end,\n+                       State1#?STATE{sync_send_client = undefined,\n+                                     in_progress = InProgress,\n+                                     process_xids = PXids};\n+                   {{_Pid, _Tag} = From, Reply} ->\n+                       gen_fsm:reply(From, ?OFC_OK_REPLY(Reply)),\n+                       State1#?STATE{pending_message = maps:remove(Xid, PM0),\n+                                     sync_send_client = undefined,\n+                                     in_progress = InProgress,\n+                                     process_xids = PXids}\n+               end,\n+    {next_state, connected, NewState};\n+connected(#ofp_header{xid = Xid, type = echo_reply}, State = #?STATE{ping_xid = Xid}) ->\n+    NewState = receive_ping(State),\n+    {next_state, connected, NewState};\n+%% special handler for multipart message\n+connected(#ofp_header{type = multipart_reply, xid = Xid, body = Body} = Msg,\n+          State = #?STATE{pending_message = PM0, connection = SwitchConn}) ->\n+    NewState = case element(2, Body) of\n+                   [more] ->\n+                       ?DEBUG(\"[ofc_dp_conn] received multipart message with more flag (xid=~p)~n\", [Xid]),\n+                       From = maps:get(Xid, PM0, async),\n+                       Fn = fun({F, M}) -> {F, ofproto_v4:append_multipart_reply(M, Body)} end,\n+                       State#?STATE{pending_message = maps:update_with(Xid, Fn, {From, Body}, PM0)};\n+                   [] ->\n+                       ?DEBUG(\"[ofc_dp_conn] received multipart message (xid=~p)~n\", [Xid]),\n+                       case maps:get(Xid, PM0, false) of\n+                           false ->\n+                               ?DEBUG(\"[~p] send openflow message(~p) to handlers\", [?MODULE, multipart_reply]),\n+                               ofc_event:dispatch(multipart_reply, SwitchConn#connection{message = Msg}),\n+                               State;\n+                           {From, Reply} ->\n+                               NewMsg = ofproto_v4:append_multipart_reply(Reply, Body),\n+                               case From of\n+                                   async ->\n+                                       ?DEBUG(\"[~p] send openflow message(~p) to handlers\", [?MODULE, multipart_reply]),\n+                                       ofc_event:dispatch(multipart_reply,\n+                                                          SwitchConn#connection{message = Msg#ofp_header{body=NewMsg}}),\n+                                       State#?STATE{pending_message = maps:remove(Xid, PM0)};\n+                                   {_Pid, _Tag} ->\n+                                       State#?STATE{pending_message = maps:update(Xid, {From, NewMsg}, PM0)}\n+                               end\n+                       end\n+               end,\n+    {next_state, connected, NewState};\n+connected(#ofp_header{xid = Xid, type = Type, body = Body} = Msg,\n+          State = #?STATE{pending_message = PM0, datapath_mac = Dpid, auxiliary_id = AuxId, connection = SwitchConn}) ->\n+    case Type of\n+        error ->\n+            ?ALERT(\"[~p] received OFP_ERROR(xid: ~p type: ~p, code: ~p) on dpid: ~p, aux_id: ~p~n\" ,\n+                   [?MODULE, Xid, Body#ofp_error_msg.type, Body#ofp_error_msg.code, Dpid, AuxId]);\n+        _ ->\n+            undefined\n+    end,\n+    NewState =\n+        case maps:get(Xid, PM0, false) of\n+            false ->\n+                ?DEBUG(\"[~p] send openflow message(~p) to handlers\", [?MODULE, Type]),\n+                ofc_event:dispatch(Type, SwitchConn#connection{message = Msg}),\n+                State;\n+            {{_Pid, _Tag} = From, _} ->\n+                State#?STATE{pending_message = maps:update(Xid, {From, Body}, PM0)}\n+        end,\n+    {next_state, connected, NewState};\n+connected(ping_timeout, State = #?STATE{ping_fail_count = ?PING_FAIL_MAX}) ->\n+    ?NOTICE(\"[ofc_dp_conn] switch(~p) reached to ping max fail count, tcp close~n\", [self()]),\n+    close_connection(State, {tcp_closed, ping_timeout});\n+connected(ping_timeout, State = #?STATE{ping_fail_count = FCnt, ping_timeout = PingTimeOut}) ->\n+    {ok, TRef} = timer:apply_after(PingTimeOut, ?MODULE, ping_timeout, [self()]),\n+    ?DEBUG(\"[ofc_dp_conn] switch(~p) ping failed ~p/~p~n\",[self(), FCnt+1, ?PING_FAIL_MAX]),\n+    {next_state, connected, State#?STATE{ping_fail_count = FCnt+1, ping_timer_ref = TRef}};\n+connected({send, {echo_reply, Xid, Body}}, State) ->\n+    Packet = gyges_utils:create_echo_reply_packet(?OFP13_VERSION, Xid, [{data, Body}]),","path":"src/controller/ofc_dp_conn.erl","position":389,"original_position":389,"commit_id":"3ec588af025853eeb26d5a6fc6d880f03d040bc1","original_commit_id":"3ec588af025853eeb26d5a6fc6d880f03d040bc1","user":{"login":"elvisci","id":8136322,"avatar_url":"https://avatars.githubusercontent.com/u/8136322?v=3","gravatar_id":"","url":"https://api.github.com/users/elvisci","html_url":"https://github.com/elvisci","followers_url":"https://api.github.com/users/elvisci/followers","following_url":"https://api.github.com/users/elvisci/following{/other_user}","gists_url":"https://api.github.com/users/elvisci/gists{/gist_id}","starred_url":"https://api.github.com/users/elvisci/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/elvisci/subscriptions","organizations_url":"https://api.github.com/users/elvisci/orgs","repos_url":"https://api.github.com/users/elvisci/repos","events_url":"https://api.github.com/users/elvisci/events{/privacy}","received_events_url":"https://api.github.com/users/elvisci/received_events","type":"User","site_admin":false},"body":"Line 389 is too long:     Packet = gyges_utils:create_echo_reply_packet(?OFP13_VERSION, Xid, [{data, Body}]),.","created_at":"2016-11-15T11:14:10Z","updated_at":"2016-11-15T11:14:10Z","html_url":"https://github.com/shun159/gyges/pull/113#discussion_r87995240","pull_request_url":"https://api.github.com/repos/shun159/gyges/pulls/113","_links":{"self":{"href":"https://api.github.com/repos/shun159/gyges/pulls/comments/87995240"},"html":{"href":"https://github.com/shun159/gyges/pull/113#discussion_r87995240"},"pull_request":{"href":"https://api.github.com/repos/shun159/gyges/pulls/113"}}},"pull_request":{"url":"https://api.github.com/repos/shun159/gyges/pulls/113","id":82501907,"html_url":"https://github.com/shun159/gyges/pull/113","diff_url":"https://github.com/shun159/gyges/pull/113.diff","patch_url":"https://github.com/shun159/gyges/pull/113.patch","issue_url":"https://api.github.com/repos/shun159/gyges/issues/113","number":113,"state":"open","locked":false,"title":"Add support OpenFlow switch specification 1.3.5","user":{"login":"shun159","id":2569175,"avatar_url":"https://avatars.githubusercontent.com/u/2569175?v=3","gravatar_id":"","url":"https://api.github.com/users/shun159","html_url":"https://github.com/shun159","followers_url":"https://api.github.com/users/shun159/followers","following_url":"https://api.github.com/users/shun159/following{/other_user}","gists_url":"https://api.github.com/users/shun159/gists{/gist_id}","starred_url":"https://api.github.com/users/shun159/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/shun159/subscriptions","organizations_url":"https://api.github.com/users/shun159/orgs","repos_url":"https://api.github.com/users/shun159/repos","events_url":"https://api.github.com/users/shun159/events{/privacy}","received_events_url":"https://api.github.com/users/shun159/received_events","type":"User","site_admin":false},"body":"- [x] add support openflow 1.3 protocol parser/generator\r\n  - [OpenFlow Switch Specification 1.3.5](https://www.opennetworking.org/images/stories/downloads/sdn-resources/onf-specifications/openflow/openflow-switch-v1.3.5.pdf)\r\n  - [x] HELLO\r\n  - [x] ERROR\r\n  - [x] ECHO_REQUEST\r\n  - [x] ECHO_REPLY\r\n  - [x] EXPERIMENTER (あとで何を対応させるか決める)\r\n  - [x] FEATURES_REQUEST\r\n  - [x] FEATURES_REPLY\r\n  - [x] GET_CONFIG_REQUEST\r\n  - [x] GET_CONFIG_REPLY\r\n  - [x] SET_CONFIG\r\n  - [x] PACKET_IN\r\n  - [x] FLOW_REMOVED\r\n  - [x] PORT_STATUS\r\n  - [x] PACKET_OUT\r\n  - [x] FLOW_MOD\r\n  - [x] GROUP_MOD\r\n  - [x] PORT_MOD\r\n  - [x] TABLE_MOD\r\n  - [x] MULTIPART_REQUEST\r\n  - [x] MULTIPART_REPLY\r\n  - [x] BARRIER_REQUEST\r\n  - [x] BARRIER_REPLY\r\n  - [x] QUEUE_GET_CONFIG_REQUEST　(あとで)\r\n  - [x] QUEUE_GET_CONFIG_REPLY　(あとで)\r\n  - [x] ROLE_REQUEST\r\n  - [x] ROLE_REPLY\r\n  - [x] GET_ASYNC_REQUEST\r\n  - [x] GET_ASYNC_REPLY\r\n  - [x] SET_ASYNC\r\n  - [x] METER_MOD\r\n- [x] refactor dp-conn modules\r\n- [x] redefine switch handler architecture\r\n  - [ ] テスト（単一ハンドラ・複数ハンドラ)\r\n  - [ ] OOM killer対策\r\n","created_at":"2016-08-24T08:34:35Z","updated_at":"2016-11-15T11:14:10Z","closed_at":null,"merged_at":null,"merge_commit_sha":"e63480cff97cd32300f40be4a2c0e4a7aeb2ec74","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/shun159/gyges/pulls/113/commits","review_comments_url":"https://api.github.com/repos/shun159/gyges/pulls/113/comments","review_comment_url":"https://api.github.com/repos/shun159/gyges/pulls/comments{/number}","comments_url":"https://api.github.com/repos/shun159/gyges/issues/113/comments","statuses_url":"https://api.github.com/repos/shun159/gyges/statuses/3ec588af025853eeb26d5a6fc6d880f03d040bc1","head":{"label":"shun159:feature/ofpv4","ref":"feature/ofpv4","sha":"3ec588af025853eeb26d5a6fc6d880f03d040bc1","user":{"login":"shun159","id":2569175,"avatar_url":"https://avatars.githubusercontent.com/u/2569175?v=3","gravatar_id":"","url":"https://api.github.com/users/shun159","html_url":"https://github.com/shun159","followers_url":"https://api.github.com/users/shun159/followers","following_url":"https://api.github.com/users/shun159/following{/other_user}","gists_url":"https://api.github.com/users/shun159/gists{/gist_id}","starred_url":"https://api.github.com/users/shun159/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/shun159/subscriptions","organizations_url":"https://api.github.com/users/shun159/orgs","repos_url":"https://api.github.com/users/shun159/repos","events_url":"https://api.github.com/users/shun159/events{/privacy}","received_events_url":"https://api.github.com/users/shun159/received_events","type":"User","site_admin":false},"repo":{"id":30000523,"name":"gyges","full_name":"shun159/gyges","owner":{"login":"shun159","id":2569175,"avatar_url":"https://avatars.githubusercontent.com/u/2569175?v=3","gravatar_id":"","url":"https://api.github.com/users/shun159","html_url":"https://github.com/shun159","followers_url":"https://api.github.com/users/shun159/followers","following_url":"https://api.github.com/users/shun159/following{/other_user}","gists_url":"https://api.github.com/users/shun159/gists{/gist_id}","starred_url":"https://api.github.com/users/shun159/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/shun159/subscriptions","organizations_url":"https://api.github.com/users/shun159/orgs","repos_url":"https://api.github.com/users/shun159/repos","events_url":"https://api.github.com/users/shun159/events{/privacy}","received_events_url":"https://api.github.com/users/shun159/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/shun159/gyges","description":null,"fork":false,"url":"https://api.github.com/repos/shun159/gyges","forks_url":"https://api.github.com/repos/shun159/gyges/forks","keys_url":"https://api.github.com/repos/shun159/gyges/keys{/key_id}","collaborators_url":"https://api.github.com/repos/shun159/gyges/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/shun159/gyges/teams","hooks_url":"https://api.github.com/repos/shun159/gyges/hooks","issue_events_url":"https://api.github.com/repos/shun159/gyges/issues/events{/number}","events_url":"https://api.github.com/repos/shun159/gyges/events","assignees_url":"https://api.github.com/repos/shun159/gyges/assignees{/user}","branches_url":"https://api.github.com/repos/shun159/gyges/branches{/branch}","tags_url":"https://api.github.com/repos/shun159/gyges/tags","blobs_url":"https://api.github.com/repos/shun159/gyges/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/shun159/gyges/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/shun159/gyges/git/refs{/sha}","trees_url":"https://api.github.com/repos/shun159/gyges/git/trees{/sha}","statuses_url":"https://api.github.com/repos/shun159/gyges/statuses/{sha}","languages_url":"https://api.github.com/repos/shun159/gyges/languages","stargazers_url":"https://api.github.com/repos/shun159/gyges/stargazers","contributors_url":"https://api.github.com/repos/shun159/gyges/contributors","subscribers_url":"https://api.github.com/repos/shun159/gyges/subscribers","subscription_url":"https://api.github.com/repos/shun159/gyges/subscription","commits_url":"https://api.github.com/repos/shun159/gyges/commits{/sha}","git_commits_url":"https://api.github.com/repos/shun159/gyges/git/commits{/sha}","comments_url":"https://api.github.com/repos/shun159/gyges/comments{/number}","issue_comment_url":"https://api.github.com/repos/shun159/gyges/issues/comments{/number}","contents_url":"https://api.github.com/repos/shun159/gyges/contents/{+path}","compare_url":"https://api.github.com/repos/shun159/gyges/compare/{base}...{head}","merges_url":"https://api.github.com/repos/shun159/gyges/merges","archive_url":"https://api.github.com/repos/shun159/gyges/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/shun159/gyges/downloads","issues_url":"https://api.github.com/repos/shun159/gyges/issues{/number}","pulls_url":"https://api.github.com/repos/shun159/gyges/pulls{/number}","milestones_url":"https://api.github.com/repos/shun159/gyges/milestones{/number}","notifications_url":"https://api.github.com/repos/shun159/gyges/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/shun159/gyges/labels{/name}","releases_url":"https://api.github.com/repos/shun159/gyges/releases{/id}","deployments_url":"https://api.github.com/repos/shun159/gyges/deployments","created_at":"2015-01-29T02:51:51Z","updated_at":"2016-11-15T11:09:15Z","pushed_at":"2016-11-15T11:14:02Z","git_url":"git://github.com/shun159/gyges.git","ssh_url":"git@github.com:shun159/gyges.git","clone_url":"https://github.com/shun159/gyges.git","svn_url":"https://github.com/shun159/gyges","homepage":"","size":27115,"stargazers_count":8,"watchers_count":8,"language":"Erlang","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":true,"forks_count":0,"mirror_url":null,"open_issues_count":3,"forks":0,"open_issues":3,"watchers":8,"default_branch":"feature/ofpv4"}},"base":{"label":"shun159:develop","ref":"develop","sha":"bb529804ce04684ed1466c5ac642dba082247347","user":{"login":"shun159","id":2569175,"avatar_url":"https://avatars.githubusercontent.com/u/2569175?v=3","gravatar_id":"","url":"https://api.github.com/users/shun159","html_url":"https://github.com/shun159","followers_url":"https://api.github.com/users/shun159/followers","following_url":"https://api.github.com/users/shun159/following{/other_user}","gists_url":"https://api.github.com/users/shun159/gists{/gist_id}","starred_url":"https://api.github.com/users/shun159/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/shun159/subscriptions","organizations_url":"https://api.github.com/users/shun159/orgs","repos_url":"https://api.github.com/users/shun159/repos","events_url":"https://api.github.com/users/shun159/events{/privacy}","received_events_url":"https://api.github.com/users/shun159/received_events","type":"User","site_admin":false},"repo":{"id":30000523,"name":"gyges","full_name":"shun159/gyges","owner":{"login":"shun159","id":2569175,"avatar_url":"https://avatars.githubusercontent.com/u/2569175?v=3","gravatar_id":"","url":"https://api.github.com/users/shun159","html_url":"https://github.com/shun159","followers_url":"https://api.github.com/users/shun159/followers","following_url":"https://api.github.com/users/shun159/following{/other_user}","gists_url":"https://api.github.com/users/shun159/gists{/gist_id}","starred_url":"https://api.github.com/users/shun159/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/shun159/subscriptions","organizations_url":"https://api.github.com/users/shun159/orgs","repos_url":"https://api.github.com/users/shun159/repos","events_url":"https://api.github.com/users/shun159/events{/privacy}","received_events_url":"https://api.github.com/users/shun159/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/shun159/gyges","description":null,"fork":false,"url":"https://api.github.com/repos/shun159/gyges","forks_url":"https://api.github.com/repos/shun159/gyges/forks","keys_url":"https://api.github.com/repos/shun159/gyges/keys{/key_id}","collaborators_url":"https://api.github.com/repos/shun159/gyges/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/shun159/gyges/teams","hooks_url":"https://api.github.com/repos/shun159/gyges/hooks","issue_events_url":"https://api.github.com/repos/shun159/gyges/issues/events{/number}","events_url":"https://api.github.com/repos/shun159/gyges/events","assignees_url":"https://api.github.com/repos/shun159/gyges/assignees{/user}","branches_url":"https://api.github.com/repos/shun159/gyges/branches{/branch}","tags_url":"https://api.github.com/repos/shun159/gyges/tags","blobs_url":"https://api.github.com/repos/shun159/gyges/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/shun159/gyges/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/shun159/gyges/git/refs{/sha}","trees_url":"https://api.github.com/repos/shun159/gyges/git/trees{/sha}","statuses_url":"https://api.github.com/repos/shun159/gyges/statuses/{sha}","languages_url":"https://api.github.com/repos/shun159/gyges/languages","stargazers_url":"https://api.github.com/repos/shun159/gyges/stargazers","contributors_url":"https://api.github.com/repos/shun159/gyges/contributors","subscribers_url":"https://api.github.com/repos/shun159/gyges/subscribers","subscription_url":"https://api.github.com/repos/shun159/gyges/subscription","commits_url":"https://api.github.com/repos/shun159/gyges/commits{/sha}","git_commits_url":"https://api.github.com/repos/shun159/gyges/git/commits{/sha}","comments_url":"https://api.github.com/repos/shun159/gyges/comments{/number}","issue_comment_url":"https://api.github.com/repos/shun159/gyges/issues/comments{/number}","contents_url":"https://api.github.com/repos/shun159/gyges/contents/{+path}","compare_url":"https://api.github.com/repos/shun159/gyges/compare/{base}...{head}","merges_url":"https://api.github.com/repos/shun159/gyges/merges","archive_url":"https://api.github.com/repos/shun159/gyges/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/shun159/gyges/downloads","issues_url":"https://api.github.com/repos/shun159/gyges/issues{/number}","pulls_url":"https://api.github.com/repos/shun159/gyges/pulls{/number}","milestones_url":"https://api.github.com/repos/shun159/gyges/milestones{/number}","notifications_url":"https://api.github.com/repos/shun159/gyges/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/shun159/gyges/labels{/name}","releases_url":"https://api.github.com/repos/shun159/gyges/releases{/id}","deployments_url":"https://api.github.com/repos/shun159/gyges/deployments","created_at":"2015-01-29T02:51:51Z","updated_at":"2016-11-15T11:09:15Z","pushed_at":"2016-11-15T11:14:02Z","git_url":"git://github.com/shun159/gyges.git","ssh_url":"git@github.com:shun159/gyges.git","clone_url":"https://github.com/shun159/gyges.git","svn_url":"https://github.com/shun159/gyges","homepage":"","size":27115,"stargazers_count":8,"watchers_count":8,"language":"Erlang","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":true,"forks_count":0,"mirror_url":null,"open_issues_count":3,"forks":0,"open_issues":3,"watchers":8,"default_branch":"feature/ofpv4"}},"_links":{"self":{"href":"https://api.github.com/repos/shun159/gyges/pulls/113"},"html":{"href":"https://github.com/shun159/gyges/pull/113"},"issue":{"href":"https://api.github.com/repos/shun159/gyges/issues/113"},"comments":{"href":"https://api.github.com/repos/shun159/gyges/issues/113/comments"},"review_comments":{"href":"https://api.github.com/repos/shun159/gyges/pulls/113/comments"},"review_comment":{"href":"https://api.github.com/repos/shun159/gyges/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/shun159/gyges/pulls/113/commits"},"statuses":{"href":"https://api.github.com/repos/shun159/gyges/statuses/3ec588af025853eeb26d5a6fc6d880f03d040bc1"}}}}
{"actor":{"display_login":"elvisci"}}