> Hello, > > It works, thanks! > > However, when both TCP FIN & retransmission packets sent from switch were > lost, the socket for the older connection remains open on controller host. > (old connections remain ESTABLISHED in netstat.) We can wait for its > timeout, but when I tried to call self.dps[dp.id].socket.close() before > older dp being replaced and made further request to the same dpid, it > raised runtime error as below: > > Traceback (most recent call last): > File "/usr/lib/python2.7/dist-packages/eventlet/greenpool.py", line 80, > in _spawn_n_impl > func(*args, **kwargs) > File "/usr/lib/python2.7/dist-packages/eventlet/wsgi.py", line 575, in > process_request > proto = self.protocol(socket, address, self) > File "/usr/lib/python2.7/SocketServer.py", line 638, in __init__ > self.handle() > File "/usr/lib/python2.7/BaseHTTPServer.py", line 342, in handle > self.handle_one_request() > File "/usr/lib/python2.7/dist-packages/eventlet/wsgi.py", line 225, in > handle_one_request > self.raw_requestline = self.rfile.readline(self.server.url_length_limit) > File "/usr/lib/python2.7/socket.py", line 476, in readline > data = self._sock.recv(self._rbufsize) > File "/usr/lib/python2.7/dist-packages/eventlet/greenio.py", line 249, in > recv > timeout_exc=socket.timeout("timed out")) > File "/usr/lib/python2.7/dist-packages/eventlet/hubs/__init__.py", line > 117, in trampoline > listener = hub.add(hub.READ, fileno, current.switch) > File "/usr/lib/python2.7/dist-packages/eventlet/hubs/epolls.py", line 48, > in add > listener = BaseHub.add(self, evtype, fileno, cb) > File "/usr/lib/python2.7/dist-packages/eventlet/hubs/hub.py", line 126, > in add > evtype, fileno, evtype)) > RuntimeError: Second simultaneous read on fileno 6 detected. Unless you > really know what you're doing, make sure that only one greenthread can read > any particular socket. Consider using a pools.Pool. If you do know what > you're doing and want to disable this error, call > eventlet.debug.hub_multiple_reader_prevention(False) > > Any comment on more graceful way to cleanup the old dp?
i'm not sure how it could happen but probably closing a openflow socket from other thread confused the underlying socket/eventlet/etc? i guess it's better to make the datapath thread do a keepalive (using openflow echo request) and close the socket by itself. YAMAMOTO Takashi > > Thanks. > > Sincerely, > Wei-Li Tang > > 2013/11/14 YAMAMOTO Takashi <yamam...@valinux.co.jp> > >> this should fix the following crash recently reported >> by wataru yamamoto on ryu-devel. >> >> hub: uncaught exception: Traceback (most recent call last): >> File "/usr/local/lib/python2.7/dist-packages/ryu/lib/hub.py", line 48, >> in _launch >> func(*args, **kwargs) >> File "/usr/local/lib/python2.7/dist-packages/ryu/base/app_manager.py", >> line 110, in _event_loop >> handler(ev) >> File "/usr/local/lib/python2.7/dist-packages/ryu/controller/dpset.py", >> line 157, in dispacher_change >> self.register(datapath) >> File "/usr/local/lib/python2.7/dist-packages/ryu/controller/dpset.py", >> line 100, in register >> assert dp.id not in self.dps >> AssertionError >> >> Signed-off-by: YAMAMOTO Takashi <yamam...@valinux.co.jp> >> --- >> ryu/controller/dpset.py | 40 ++++++++++++++++++++++++++++------------ >> 1 file changed, 28 insertions(+), 12 deletions(-) >> >> diff --git a/ryu/controller/dpset.py b/ryu/controller/dpset.py >> index 1a4de33..54c9b5a 100644 >> --- a/ryu/controller/dpset.py >> +++ b/ryu/controller/dpset.py >> @@ -96,18 +96,37 @@ class DPSet(app_manager.RyuApp): >> self.port_state = {} # datapath_id => ports >> >> def _register(self, dp): >> + LOG.debug('DPSET: register datapath %s', dp) >> assert dp.id is not None >> - assert dp.id not in self.dps >> >> + # while dpid should be unique, we need to handle duplicates here >> + # because it's entirely possible for a switch to reconnect us >> + # before we notice the drop of the previous connection. >> + # in that case, >> + # - forget the older connection as it likely will disappear soon >> + # - do not send EventDP leave/enter events >> + # - keep the PortState for the dpid >> + if dp.id in self.dps: >> + self.logger.warning('DPSET: Multiple connections from %s', >> + dpid_to_str(dp.id)) >> + self.logger.debug('DPSET: Forgetting datapath %s', self.dps[ >> dp.id]) >> + self.logger.debug('DPSET: New datapath %s', dp) >> self.dps[dp.id] = dp >> - self.port_state[dp.id] = PortState() >> - ev = EventDP(dp, True) >> - for port in dp.ports.values(): >> - self._port_added(dp, port) >> - ev.ports.append(port) >> - self.send_event_to_observers(ev) >> + if not dp.id in self.port_state: >> + self.port_state[dp.id] = PortState() >> + ev = EventDP(dp, True) >> + for port in dp.ports.values(): >> + self._port_added(dp, port) >> + ev.ports.append(port) >> + self.send_event_to_observers(ev) >> >> def _unregister(self, dp): >> + # see the comment in _register(). >> + if not dp in self.dps.values(): >> + return >> + LOG.debug('DPSET: unregister datapath %s', dp) >> + assert self.dps[dp.id] == dp >> + >> # Now datapath is already dead, so port status change event >> doesn't >> # interfere us. >> ev = EventDP(dp, False) >> @@ -117,9 +136,8 @@ class DPSet(app_manager.RyuApp): >> >> self.send_event_to_observers(ev) >> >> - if dp.id in self.dps: >> - del self.dps[dp.id] >> - del self.port_state[dp.id] >> + del self.dps[dp.id] >> + del self.port_state[dp.id] >> >> def get(self, dp_id): >> """ >> @@ -153,10 +171,8 @@ class DPSet(app_manager.RyuApp): >> datapath = ev.datapath >> assert datapath is not None >> if ev.state == handler.MAIN_DISPATCHER: >> - LOG.debug('DPSET: register datapath %s', datapath) >> self._register(datapath) >> elif ev.state == handler.DEAD_DISPATCHER: >> - LOG.debug('DPSET: unregister datapath %s', datapath) >> self._unregister(datapath) >> >> @set_ev_cls(ofp_event.EventOFPSwitchFeatures, >> handler.CONFIG_DISPATCHER) >> -- >> 1.8.3.1 >> >> >> >> ------------------------------------------------------------------------------ >> DreamFactory - Open Source REST & JSON Services for HTML5 & Native Apps >> OAuth, Users, Roles, SQL, NoSQL, BLOB Storage and External API Access >> Free app hosting. Or install the open source package on any LAMP server. >> Sign up and see examples for AngularJS, jQuery, Sencha Touch and Native! >> http://pubads.g.doubleclick.net/gampad/clk?id=63469471&iu=/4140/ostg.clktrk >> _______________________________________________ >> Ryu-devel mailing list >> Ryu-devel@lists.sourceforge.net >> https://lists.sourceforge.net/lists/listinfo/ryu-devel ------------------------------------------------------------------------------ DreamFactory - Open Source REST & JSON Services for HTML5 & Native Apps OAuth, Users, Roles, SQL, NoSQL, BLOB Storage and External API Access Free app hosting. Or install the open source package on any LAMP server. Sign up and see examples for AngularJS, jQuery, Sencha Touch and Native! http://pubads.g.doubleclick.net/gampad/clk?id=63469471&iu=/4140/ostg.clktrk _______________________________________________ Ryu-devel mailing list Ryu-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/ryu-devel