From 7e56bfb527863d2a2b763fa5e8451a4c744c9dd3 Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Tue, 18 Dec 2012 17:29:40 +0900 Subject: ofp_handler: Improve hello version negotiation When switch sends version higher than Ryu supports, Ryu fails to negotiate. In this case 4 = OF1.3 from switch 3 = OF1.2 from Ryu datapath.supported_ofp_version = (3 = OF1.2,) In such cases, we should use OF1.2 instead of error. > Connection to controller closed because of {"localhost",6633,0, {unsupported_version,4}} Reported-by: Shivaram Mysore Signed-off-by: Isaku Yamahata Signed-off-by: FUJITA Tomonori --- ryu/controller/ofp_handler.py | 66 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 53 insertions(+), 13 deletions(-) diff --git a/ryu/controller/ofp_handler.py b/ryu/controller/ofp_handler.py index 63f888a6..9c13c20c 100644 --- a/ryu/controller/ofp_handler.py +++ b/ryu/controller/ofp_handler.py @@ -18,7 +18,6 @@ import logging from ryu import utils from ryu.base import app_manager -from ryu.controller import dispatcher from ryu.controller import ofp_event from ryu.controller.handler import set_ev_cls from ryu.controller.handler import HANDSHAKE_DISPATCHER, CONFIG_DISPATCHER,\ @@ -44,6 +43,15 @@ class OFPHandler(app_manager.RyuApp): def __init__(self, *args, **kwargs): super(OFPHandler, self).__init__(*args, **kwargs) + @staticmethod + def hello_failed(datapath, error_desc): + LOG.error(error_desc) + error_msg = datapath.ofproto_parser.OFPErrorMsg(datapath) + error_msg.type = datapath.ofproto.OFPET_HELLO_FAILED + error_msg.code = datapath.ofproto.OFPHFC_INCOMPATIBLE + error_msg.data = error_desc + datapath.send_msg(error_msg) + @set_ev_cls(ofp_event.EventOFPHello, HANDSHAKE_DISPATCHER) def hello_handler(self, ev): LOG.debug('hello ev %s', ev) @@ -52,20 +60,52 @@ class OFPHandler(app_manager.RyuApp): # TODO: check if received version is supported. # pre 1.0 is not supported - if msg.version not in datapath.supported_ofp_version: + # TODO: OFPHET_VERSIONBITMAP + usable_versions = [version for version + in datapath.supported_ofp_version + if version <= msg.version] + if not usable_versions: # send the error - error_msg = datapath.ofproto_parser.OFPErrorMsg(datapath) - error_msg.type = datapath.ofproto.OFPET_HELLO_FAILED - error_msg.code = datapath.ofproto.OFPHFC_INCOMPATIBLE - error_msg.data = 'unsupported version 0x%x' % msg.version - datapath.send_msg(error_msg) + error_desc = 'unsupported version 0x%x. ' + 'If possible, set the switch to use one of the versions %s' % ( + msg.version, datapath.supported_ofp_version.keys()) + self.hello_failed(error_desc) return - - # should we again send HELLO with the version that the switch - # supports? - # msg.version != datapath.ofproto.OFP_VERSION: - - datapath.set_version(msg.version) + version = max(usable_versions) + if version != min(msg.version, datapath.ofproto.OFP_VERSION): + # The version of min(msg.version, datapath.ofproto.OFP_VERSION) + # should be used according to the spec. But we can't. + # So log it and use max(usable_versions) with the hope that + # the switch is able to understand lower version. + # e.g. + # OF 1.1 from switch + # OF 1.2 from Ryu and supported_ofp_version = (1.0, 1.2) + # In this case, 1.1 should be used according to the spec, + # but 1.1 can't be used. + # + # OF1.3.1 6.3.1 + # Upon receipt of this message, the recipient must + # calculate the OpenFlow protocol version to be used. If + # both the Hello message sent and the Hello message + # received contained a OFPHET_VERSIONBITMAP hello element, + # and if those bitmaps have some common bits set, the + # negotiated version must be the highest version set in + # both bitmaps. Otherwise, the negotiated version must be + # the smaller of the version number that was sent and the + # one that was received in the version fields. If the + # negotiated version is supported by the recipient, then + # the connection proceeds. Otherwise, the recipient must + # reply with an OFPT_ERROR message with a type field of + # OFPET_HELLO_FAILED, a code field of OFPHFC_INCOMPATIBLE, + # and optionally an ASCII string explaining the situation + # in data, and then terminate the connection. + error_desc = 'no compatible version found: ' + 'switch 0x%x controller 0x%x, but found usable 0x%x. ' + 'If possible, set the switch to use OF version 0x%x' % ( + msg.version, datapath.ofproto.OFP_VERSION, version, version) + self.hello_failed(error_desc) + return + datapath.set_version(version) # now send feature features_reqeust = datapath.ofproto_parser.OFPFeaturesRequest(datapath) -- cgit v1.2.3