diff --git a/ryu/app/ofctl_rest.py b/ryu/app/ofctl_rest.py index 38301ca5..a3644017 100644 --- a/ryu/app/ofctl_rest.py +++ b/ryu/app/ofctl_rest.py @@ -35,6 +35,13 @@ from ryu.app.wsgi import ControllerBase, WSGIApplication LOG = logging.getLogger('ryu.app.ofctl_rest') +# supported ofctl versions in this restful app +supported_ofctl = { + ofproto_v1_0.OFP_VERSION: ofctl_v1_0, + ofproto_v1_2.OFP_VERSION: ofctl_v1_2, + ofproto_v1_3.OFP_VERSION: ofctl_v1_3, +} + # REST API # @@ -143,16 +150,21 @@ class StatsController(ControllerBase): return Response(content_type='application/json', body=body) def get_desc_stats(self, req, dpid, **_kwargs): + + if type(dpid) == str and not dpid.isdigit(): + LOG.debug('invalid dpid %s', dpid) + return Response(status=400) + dp = self.dpset.get(int(dpid)) + if dp is None: return Response(status=404) + _ofp_version = dp.ofproto.OFP_VERSION + + _ofctl = supported_ofctl.get(_ofp_version, None) + if _ofctl is not None: + desc = _ofctl.get_desc_stats(dp, self.waiters) - if dp.ofproto.OFP_VERSION == ofproto_v1_0.OFP_VERSION: - desc = ofctl_v1_0.get_desc_stats(dp, self.waiters) - elif dp.ofproto.OFP_VERSION == ofproto_v1_2.OFP_VERSION: - desc = ofctl_v1_2.get_desc_stats(dp, self.waiters) - elif dp.ofproto.OFP_VERSION == ofproto_v1_3.OFP_VERSION: - desc = ofctl_v1_3.get_desc_stats(dp, self.waiters) else: LOG.debug('Unsupported OF protocol') return Response(status=501) @@ -161,25 +173,34 @@ class StatsController(ControllerBase): return Response(content_type='application/json', body=body) def get_flow_stats(self, req, dpid, **_kwargs): + if req.body == '': flow = {} + else: + try: flow = ast.literal_eval(req.body) + except SyntaxError: LOG.debug('invalid syntax %s', req.body) return Response(status=400) + if type(dpid) == str and not dpid.isdigit(): + LOG.debug('invalid dpid %s', dpid) + return Response(status=400) + dp = self.dpset.get(int(dpid)) + if dp is None: return Response(status=404) - if dp.ofproto.OFP_VERSION == ofproto_v1_0.OFP_VERSION: - flows = ofctl_v1_0.get_flow_stats(dp, self.waiters, flow) - elif dp.ofproto.OFP_VERSION == ofproto_v1_2.OFP_VERSION: - flows = ofctl_v1_2.get_flow_stats(dp, self.waiters, flow) - elif dp.ofproto.OFP_VERSION == ofproto_v1_3.OFP_VERSION: - flows = ofctl_v1_3.get_flow_stats(dp, self.waiters, flow) + _ofp_version = dp.ofproto.OFP_VERSION + + _ofctl = supported_ofctl.get(_ofp_version, None) + if _ofctl is not None: + flows = _ofctl.get_flow_stats(dp, self.waiters, flow) + else: LOG.debug('Unsupported OF protocol') return Response(status=501) @@ -188,25 +209,33 @@ class StatsController(ControllerBase): return Response(content_type='application/json', body=body) def get_aggregate_flow_stats(self, req, dpid, **_kwargs): + if req.body == '': flow = {} + else: try: flow = ast.literal_eval(req.body) + except SyntaxError: LOG.debug('invalid syntax %s', req.body) return Response(status=400) + if type(dpid) == str and not dpid.isdigit(): + LOG.debug('invalid dpid %s', dpid) + return Response(status=400) + dp = self.dpset.get(int(dpid)) + if dp is None: return Response(status=404) - if dp.ofproto.OFP_VERSION == ofproto_v1_0.OFP_VERSION: - flows = ofctl_v1_0.get_aggregate_flow_stats(dp, self.waiters, flow) - elif dp.ofproto.OFP_VERSION == ofproto_v1_2.OFP_VERSION: - flows = ofctl_v1_2.get_aggregate_flow_stats(dp, self.waiters, flow) - elif dp.ofproto.OFP_VERSION == ofproto_v1_3.OFP_VERSION: - flows = ofctl_v1_3.get_aggregate_flow_stats(dp, self.waiters, flow) + _ofp_version = dp.ofproto.OFP_VERSION + + _ofctl = supported_ofctl.get(_ofp_version, None) + if _ofctl is not None: + flows = _ofctl.get_aggregate_flow_stats(dp, self.waiters, flow) + else: LOG.debug('Unsupported OF protocol') return Response(status=501) @@ -215,16 +244,22 @@ class StatsController(ControllerBase): return Response(content_type='application/json', body=body) def get_port_stats(self, req, dpid, **_kwargs): + + if type(dpid) == str and not dpid.isdigit(): + LOG.debug('invalid dpid %s', dpid) + return Response(status=400) + dp = self.dpset.get(int(dpid)) + if dp is None: return Response(status=404) - if dp.ofproto.OFP_VERSION == ofproto_v1_0.OFP_VERSION: - ports = ofctl_v1_0.get_port_stats(dp, self.waiters) - elif dp.ofproto.OFP_VERSION == ofproto_v1_2.OFP_VERSION: - ports = ofctl_v1_2.get_port_stats(dp, self.waiters) - elif dp.ofproto.OFP_VERSION == ofproto_v1_3.OFP_VERSION: - ports = ofctl_v1_3.get_port_stats(dp, self.waiters) + _ofp_version = dp.ofproto.OFP_VERSION + + _ofctl = supported_ofctl.get(_ofp_version, None) + if _ofctl is not None: + ports = _ofctl.get_port_stats(dp, self.waiters) + else: LOG.debug('Unsupported OF protocol') return Response(status=501) @@ -233,16 +268,22 @@ class StatsController(ControllerBase): return Response(content_type='application/json', body=body) def get_queue_stats(self, req, dpid, **_kwargs): + + if type(dpid) == str and not dpid.isdigit(): + LOG.debug('invalid dpid %s', dpid) + return Response(status=400) + dp = self.dpset.get(int(dpid)) + if dp is None: return Response(status=404) - if dp.ofproto.OFP_VERSION == ofproto_v1_0.OFP_VERSION: - queues = ofctl_v1_0.get_queue_stats(dp, self.waiters) - elif dp.ofproto.OFP_VERSION == ofproto_v1_2.OFP_VERSION: - queues = ofctl_v1_2.get_queue_stats(dp, self.waiters) - elif dp.ofproto.OFP_VERSION == ofproto_v1_3.OFP_VERSION: - queues = ofctl_v1_3.get_queue_stats(dp, self.waiters) + _ofp_version = dp.ofproto.OFP_VERSION + + _ofctl = supported_ofctl.get(_ofp_version, None) + if _ofctl is not None: + queues = _ofctl.get_queue_stats(dp, self.waiters) + else: LOG.debug('Unsupported OF protocol') return Response(status=501) @@ -251,127 +292,172 @@ class StatsController(ControllerBase): return Response(content_type='application/json', body=body) def get_meter_features(self, req, dpid, **_kwargs): + + if type(dpid) == str and not dpid.isdigit(): + LOG.debug('invalid dpid %s', dpid) + return Response(status=400) + dp = self.dpset.get(int(dpid)) + if dp is None: return Response(status=404) - if dp.ofproto.OFP_VERSION == ofproto_v1_3.OFP_VERSION: - meters = ofctl_v1_3.get_meter_features(dp, self.waiters) - elif dp.ofproto.OFP_VERSION == ofproto_v1_0.OFP_VERSION or \ - dp.ofproto.OFP_VERSION == ofproto_v1_2.OFP_VERSION: - LOG.debug('Request not supported in this OF protocol version') - return Response(status=501) + _ofp_version = dp.ofproto.OFP_VERSION + _ofctl = supported_ofctl.get(_ofp_version, None) + + if _ofctl is not None and hasattr(_ofctl, 'get_meter_features'): + meters = _ofctl.get_meter_features(dp, self.waiters) + else: - LOG.debug('Unsupported OF protocol') + LOG.debug('Unsupported OF protocol or \ + request not supported in this OF protocol version') return Response(status=501) body = json.dumps(meters) return Response(content_type='application/json', body=body) def get_meter_config(self, req, dpid, **_kwargs): + + if type(dpid) == str and not dpid.isdigit(): + LOG.debug('invalid dpid %s', dpid) + return Response(status=400) + dp = self.dpset.get(int(dpid)) + if dp is None: return Response(status=404) - if dp.ofproto.OFP_VERSION == ofproto_v1_3.OFP_VERSION: - meters = ofctl_v1_3.get_meter_config(dp, self.waiters) - elif dp.ofproto.OFP_VERSION == ofproto_v1_0.OFP_VERSION or \ - dp.ofproto.OFP_VERSION == ofproto_v1_2.OFP_VERSION: - LOG.debug('Request not supported in this OF protocol version') - return Response(status=501) + _ofp_version = dp.ofproto.OFP_VERSION + _ofctl = supported_ofctl.get(_ofp_version, None) + + if _ofctl is not None and hasattr(_ofctl, 'get_meter_config'): + meters = _ofctl.get_meter_config(dp, self.waiters) + else: - LOG.debug('Unsupported OF protocol') + LOG.debug('Unsupported OF protocol or \ + request not supported in this OF protocol version') return Response(status=501) body = json.dumps(meters) return Response(content_type='application/json', body=body) def get_meter_stats(self, req, dpid, **_kwargs): + + if type(dpid) == str and not dpid.isdigit(): + LOG.debug('invalid dpid %s', dpid) + return Response(status=400) + dp = self.dpset.get(int(dpid)) + if dp is None: return Response(status=404) - if dp.ofproto.OFP_VERSION == ofproto_v1_3.OFP_VERSION: - meters = ofctl_v1_3.get_meter_stats(dp, self.waiters) - elif dp.ofproto.OFP_VERSION == ofproto_v1_0.OFP_VERSION or \ - dp.ofproto.OFP_VERSION == ofproto_v1_2.OFP_VERSION: - LOG.debug('Request not supported in this OF protocol version') - return Response(status=501) + _ofp_version = dp.ofproto.OFP_VERSION + _ofctl = supported_ofctl.get(_ofp_version, None) + + if _ofctl is not None and hasattr(_ofctl, 'get_meter_stats'): + meters = _ofctl.get_meter_stats(dp, self.waiters) + else: - LOG.debug('Unsupported OF protocol') + LOG.debug('Unsupported OF protocol or \ + request not supported in this OF protocol version') return Response(status=501) body = json.dumps(meters) return Response(content_type='application/json', body=body) def get_group_features(self, req, dpid, **_kwargs): + + if type(dpid) == str and not dpid.isdigit(): + LOG.debug('invalid dpid %s', dpid) + return Response(status=400) + dp = self.dpset.get(int(dpid)) + if dp is None: return Response(status=404) - if dp.ofproto.OFP_VERSION == ofproto_v1_2.OFP_VERSION: - groups = ofctl_v1_2.get_group_features(dp, self.waiters) - elif dp.ofproto.OFP_VERSION == ofproto_v1_3.OFP_VERSION: - groups = ofctl_v1_3.get_group_features(dp, self.waiters) - elif dp.ofproto.OFP_VERSION == ofproto_v1_0.OFP_VERSION: - LOG.debug('Request not supported in this OF protocol version') - return Response(status=501) + _ofp_version = dp.ofproto.OFP_VERSION + _ofctl = supported_ofctl.get(_ofp_version, None) + + if _ofctl is not None and hasattr(_ofctl, 'get_group_features'): + groups = _ofctl.get_group_features(dp, self.waiters) + else: - LOG.debug('Unsupported OF protocol') + LOG.debug('Unsupported OF protocol or \ + request not supported in this OF protocol version') return Response(status=501) body = json.dumps(groups) return Response(content_type='application/json', body=body) def get_group_desc(self, req, dpid, **_kwargs): + + if type(dpid) == str and not dpid.isdigit(): + LOG.debug('invalid dpid %s', dpid) + return Response(status=400) + dp = self.dpset.get(int(dpid)) + if dp is None: return Response(status=404) - if dp.ofproto.OFP_VERSION == ofproto_v1_2.OFP_VERSION: - groups = ofctl_v1_2.get_group_desc(dp, self.waiters) - elif dp.ofproto.OFP_VERSION == ofproto_v1_3.OFP_VERSION: - groups = ofctl_v1_3.get_group_desc(dp, self.waiters) - elif dp.ofproto.OFP_VERSION == ofproto_v1_0.OFP_VERSION: - LOG.debug('Request not supported in this OF protocol version') - return Response(status=501) + _ofp_version = dp.ofproto.OFP_VERSION + _ofctl = supported_ofctl.get(_ofp_version, None) + + if _ofctl is not None and hasattr(_ofctl, 'get_group_desc'): + groups = _ofctl.get_group_desc(dp, self.waiters) + else: - LOG.debug('Unsupported OF protocol') + LOG.debug('Unsupported OF protocol or \ + request not supported in this OF protocol version') return Response(status=501) body = json.dumps(groups) return Response(content_type='application/json', body=body) def get_group_stats(self, req, dpid, **_kwargs): + + if type(dpid) == str and not dpid.isdigit(): + LOG.debug('invalid dpid %s', dpid) + return Response(status=400) + dp = self.dpset.get(int(dpid)) + if dp is None: return Response(status=404) - if dp.ofproto.OFP_VERSION == ofproto_v1_2.OFP_VERSION: - groups = ofctl_v1_2.get_group_stats(dp, self.waiters) - elif dp.ofproto.OFP_VERSION == ofproto_v1_3.OFP_VERSION: - groups = ofctl_v1_3.get_group_stats(dp, self.waiters) - elif dp.ofproto.OFP_VERSION == ofproto_v1_0.OFP_VERSION: - LOG.debug('Request not supported in this OF protocol version') - return Response(status=501) + _ofp_version = dp.ofproto.OFP_VERSION + _ofctl = supported_ofctl.get(_ofp_version, None) + + if _ofctl is not None and hasattr(_ofctl, 'get_group_stats'): + groups = _ofctl.get_group_stats(dp, self.waiters) + else: - LOG.debug('Unsupported OF protocol') + LOG.debug('Unsupported OF protocol or \ + request not supported in this OF protocol version') return Response(status=501) body = json.dumps(groups) return Response(content_type='application/json', body=body) def get_port_desc(self, req, dpid, **_kwargs): + + if type(dpid) == str and not dpid.isdigit(): + LOG.debug('invalid dpid %s', dpid) + return Response(status=400) + dp = self.dpset.get(int(dpid)) + if dp is None: return Response(status=404) - if dp.ofproto.OFP_VERSION == ofproto_v1_0.OFP_VERSION: - groups = ofctl_v1_0.get_port_desc(dp, self.waiters) - elif dp.ofproto.OFP_VERSION == ofproto_v1_2.OFP_VERSION: - groups = ofctl_v1_2.get_port_desc(dp, self.waiters) - elif dp.ofproto.OFP_VERSION == ofproto_v1_3.OFP_VERSION: - groups = ofctl_v1_3.get_port_desc(dp, self.waiters) + _ofp_version = dp.ofproto.OFP_VERSION + + _ofctl = supported_ofctl.get(_ofp_version, None) + if _ofctl is not None: + groups = _ofctl.get_port_desc(dp, self.waiters) + else: LOG.debug('Unsupported OF protocol') return Response(status=501) @@ -380,14 +466,22 @@ class StatsController(ControllerBase): return Response(content_type='application/json', body=body) def mod_flow_entry(self, req, cmd, **_kwargs): + try: flow = ast.literal_eval(req.body) + except SyntaxError: LOG.debug('invalid syntax %s', req.body) return Response(status=400) dpid = flow.get('dpid') + + if type(dpid) == str and not dpid.isdigit(): + LOG.debug('invalid dpid %s', dpid) + return Response(status=400) + dp = self.dpset.get(int(dpid)) + if dp is None: return Response(status=404) @@ -404,12 +498,10 @@ class StatsController(ControllerBase): else: return Response(status=404) - if dp.ofproto.OFP_VERSION == ofproto_v1_0.OFP_VERSION: - ofctl_v1_0.mod_flow_entry(dp, flow, cmd) - elif dp.ofproto.OFP_VERSION == ofproto_v1_2.OFP_VERSION: - ofctl_v1_2.mod_flow_entry(dp, flow, cmd) - elif dp.ofproto.OFP_VERSION == ofproto_v1_3.OFP_VERSION: - ofctl_v1_3.mod_flow_entry(dp, flow, cmd) + _ofp_version = dp.ofproto.OFP_VERSION + _ofctl = supported_ofctl.get(_ofp_version, None) + if _ofctl is not None: + _ofctl.mod_flow_entry(dp, flow, cmd) else: LOG.debug('Unsupported OF protocol') return Response(status=501) @@ -417,18 +509,24 @@ class StatsController(ControllerBase): return Response(status=200) def delete_flow_entry(self, req, dpid, **_kwargs): + + if type(dpid) == str and not dpid.isdigit(): + LOG.debug('invalid dpid %s', dpid) + return Response(status=400) + dp = self.dpset.get(int(dpid)) + if dp is None: return Response(status=404) flow = {'table_id': dp.ofproto.OFPTT_ALL} - if dp.ofproto.OFP_VERSION == ofproto_v1_0.OFP_VERSION: - ofctl_v1_0.delete_flow_entry(dp) - elif dp.ofproto.OFP_VERSION == ofproto_v1_2.OFP_VERSION: - ofctl_v1_2.mod_flow_entry(dp, flow, dp.ofproto.OFPFC_DELETE) - elif dp.ofproto.OFP_VERSION == ofproto_v1_3.OFP_VERSION: - ofctl_v1_3.mod_flow_entry(dp, flow, dp.ofproto.OFPFC_DELETE) + _ofp_version = dp.ofproto.OFP_VERSION + + _ofctl = supported_ofctl.get(_ofp_version, None) + if _ofctl is not None: + _ofctl.mod_flow_entry(dp, flow, dp.ofproto.OFPFC_DELETE) + else: LOG.debug('Unsupported OF protocol') return Response(status=501) @@ -436,14 +534,22 @@ class StatsController(ControllerBase): return Response(status=200) def mod_meter_entry(self, req, cmd, **_kwargs): + try: flow = ast.literal_eval(req.body) + except SyntaxError: LOG.debug('invalid syntax %s', req.body) return Response(status=400) dpid = flow.get('dpid') + + if type(dpid) == str and not dpid.isdigit(): + LOG.debug('invalid dpid %s', dpid) + return Response(status=400) + dp = self.dpset.get(int(dpid)) + if dp is None: return Response(status=404) @@ -456,34 +562,39 @@ class StatsController(ControllerBase): else: return Response(status=404) - if dp.ofproto.OFP_VERSION == ofproto_v1_3.OFP_VERSION: - ofctl_v1_3.mod_meter_entry(dp, flow, cmd) - elif dp.ofproto.OFP_VERSION == ofproto_v1_0.OFP_VERSION or \ - dp.ofproto.OFP_VERSION == ofproto_v1_2.OFP_VERSION: - LOG.debug('Request not supported in this OF protocol version') - return Response(status=501) + _ofp_version = dp.ofproto.OFP_VERSION + _ofctl = supported_ofctl.get(_ofp_version, None) + + if _ofctl is not None and hasattr(_ofctl, 'mod_meter_entry'): + _ofctl.mod_meter_entry(dp, flow, cmd) + else: - LOG.debug('Unsupported OF protocol') + LOG.debug('Unsupported OF protocol or \ + request not supported in this OF protocol version') return Response(status=501) return Response(status=200) def mod_group_entry(self, req, cmd, **_kwargs): + try: group = ast.literal_eval(req.body) + except SyntaxError: LOG.debug('invalid syntax %s', req.body) return Response(status=400) dpid = group.get('dpid') + + if type(dpid) == str and not dpid.isdigit(): + LOG.debug('invalid dpid %s', dpid) + return Response(status=400) + dp = self.dpset.get(int(dpid)) + if dp is None: return Response(status=404) - if dp.ofproto.OFP_VERSION == ofproto_v1_0.OFP_VERSION: - LOG.debug('Request not supported in this OF protocol version') - return Response(status=501) - if cmd == 'add': cmd = dp.ofproto.OFPGC_ADD elif cmd == 'modify': @@ -493,27 +604,41 @@ class StatsController(ControllerBase): else: return Response(status=404) - if dp.ofproto.OFP_VERSION == ofproto_v1_2.OFP_VERSION: - ofctl_v1_2.mod_group_entry(dp, group, cmd) - elif dp.ofproto.OFP_VERSION == ofproto_v1_3.OFP_VERSION: - ofctl_v1_3.mod_group_entry(dp, group, cmd) + _ofp_version = dp.ofproto.OFP_VERSION + _ofctl = supported_ofctl.get(_ofp_version, None) + + if _ofctl is not None and hasattr(_ofctl, 'mod_group_entry'): + _ofctl.mod_group_entry(dp, group, cmd) + else: - LOG.debug('Unsupported OF protocol') + LOG.debug('Unsupported OF protocol or \ + request not supported in this OF protocol version') return Response(status=501) return Response(status=200) def mod_port_behavior(self, req, cmd, **_kwargs): + try: port_config = ast.literal_eval(req.body) + except SyntaxError: LOG.debug('invalid syntax %s', req.body) return Response(status=400) dpid = port_config.get('dpid') - port_no = int(port_config.get('port_no', 0)) + if type(dpid) == str and not dpid.isdigit(): + LOG.debug('invalid dpid %s', dpid) + return Response(status=400) + + port_no = port_config.get('port_no', 0) + if type(port_no) == str and not port_no.isdigit(): + LOG.debug('invalid port_no %s', port_no) + return Response(status=400) + port_info = self.dpset.port_state[int(dpid)].get(port_no) + if port_info: port_config.setdefault('hw_addr', port_info.hw_addr) port_config.setdefault('advertise', port_info.advertised) @@ -521,40 +646,49 @@ class StatsController(ControllerBase): return Response(status=404) dp = self.dpset.get(int(dpid)) + if dp is None: return Response(status=404) if cmd != 'modify': return Response(status=404) - if dp.ofproto.OFP_VERSION == ofproto_v1_0.OFP_VERSION: - ofctl_v1_0.mod_port_behavior(dp, port_config) - elif dp.ofproto.OFP_VERSION == ofproto_v1_2.OFP_VERSION: - ofctl_v1_2.mod_port_behavior(dp, port_config) - elif dp.ofproto.OFP_VERSION == ofproto_v1_3.OFP_VERSION: - ofctl_v1_3.mod_port_behavior(dp, port_config) + _ofp_version = dp.ofproto.OFP_VERSION + + _ofctl = supported_ofctl.get(_ofp_version, None) + if _ofctl is not None: + _ofctl.mod_port_behavior(dp, port_config) + else: LOG.debug('Unsupported OF protocol') return Response(status=501) + return Response(status=200) + def send_experimenter(self, req, dpid, **_kwargs): + + if type(dpid) == str and not dpid.isdigit(): + LOG.debug('invalid dpid %s', dpid) + return Response(status=400) + dp = self.dpset.get(int(dpid)) + if dp is None: return Response(status=404) try: exp = ast.literal_eval(req.body) + except SyntaxError: LOG.debug('invalid syntax %s', req.body) return Response(status=400) - if dp.ofproto.OFP_VERSION == ofproto_v1_2.OFP_VERSION: - ofctl_v1_2.send_experimenter(dp, exp) - elif dp.ofproto.OFP_VERSION == ofproto_v1_3.OFP_VERSION: - ofctl_v1_3.send_experimenter(dp, exp) - elif dp.ofproto.OFP_VERSION == ofproto_v1_0.OFP_VERSION: - LOG.debug('Request not supported in this OF protocol version') - return Response(status=501) + _ofp_version = dp.ofproto.OFP_VERSION + _ofctl = supported_ofctl.get(_ofp_version, None) + + if _ofctl is not None and hasattr(_ofctl, 'send_experimenter'): + _ofctl.send_experimenter(dp, exp) + else: LOG.debug('Unsupported OF protocol') return Response(status=501)