OpenStack Networking (Neutron)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

116 lines
4.7KB

  1. # Copyright (c) 2015 OpenStack Foundation
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License"); you may
  4. # not use this file except in compliance with the License. You may obtain
  5. # a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  11. # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  12. # License for the specific language governing permissions and limitations
  13. # under the License.
  14. from oslo_config import cfg
  15. from oslo_log import log as logging
  16. from neutron.agent.l2.extensions import qos
  17. from neutron.plugins.ml2.drivers.openvswitch.mech_driver import (
  18. mech_openvswitch)
  19. LOG = logging.getLogger(__name__)
  20. class QosOVSAgentDriver(qos.QosAgentDriver):
  21. SUPPORTED_RULES = (
  22. mech_openvswitch.OpenvswitchMechanismDriver.supported_qos_rule_types)
  23. def __init__(self):
  24. super(QosOVSAgentDriver, self).__init__()
  25. self.br_int_name = cfg.CONF.OVS.integration_bridge
  26. self.br_int = None
  27. self.agent_api = None
  28. def consume_api(self, agent_api):
  29. self.agent_api = agent_api
  30. def initialize(self):
  31. self.br_int = self.agent_api.request_int_br()
  32. self.cookie = self.br_int.default_cookie
  33. def create_bandwidth_limit(self, port, rule):
  34. self.update_bandwidth_limit(port, rule)
  35. def update_bandwidth_limit(self, port, rule):
  36. vif_port = port.get('vif_port')
  37. if not vif_port:
  38. port_id = port.get('port_id', None)
  39. LOG.debug("update_bandwidth_limit was received for port %s but "
  40. "vif_port was not found. It seems that port is already "
  41. "deleted", port_id)
  42. return
  43. max_kbps = rule.max_kbps
  44. # NOTE(slaweq): According to ovs docs:
  45. # http://openvswitch.org/support/dist-docs/ovs-vswitchd.conf.db.5.html
  46. # ovs accepts only integer values of burst:
  47. max_burst_kbps = int(self._get_egress_burst_value(rule))
  48. self.br_int.create_egress_bw_limit_for_port(vif_port.port_name,
  49. max_kbps,
  50. max_burst_kbps)
  51. def delete_bandwidth_limit(self, port):
  52. vif_port = port.get('vif_port')
  53. if not vif_port:
  54. port_id = port.get('port_id', None)
  55. LOG.debug("delete_bandwidth_limit was received for port %s but "
  56. "vif_port was not found. It seems that port is already "
  57. "deleted", port_id)
  58. return
  59. self.br_int.delete_egress_bw_limit_for_port(vif_port.port_name)
  60. def create_dscp_marking(self, port, rule):
  61. self.update_dscp_marking(port, rule)
  62. def update_dscp_marking(self, port, rule):
  63. port_name = port['vif_port'].port_name
  64. port = self.br_int.get_port_ofport(port_name)
  65. mark = rule.dscp_mark
  66. #mark needs to be bit shifted 2 left to not overwrite the
  67. #lower 2 bits of type of service packet header.
  68. #source: man ovs-ofctl (/mod_nw_tos)
  69. mark = str(mark << 2)
  70. # reg2 is a metadata field that does not alter packets.
  71. # By loading a value into this field and checking if the value is
  72. # altered it allows the packet to be resubmitted and go through
  73. # the flow table again to be identified by other flows.
  74. flows = self.br_int.dump_flows_for(cookie=self.cookie, table=0,
  75. in_port=port, reg2=0)
  76. if not flows:
  77. actions = ("mod_nw_tos:" + mark + ",load:55->NXM_NX_REG2[0..5]," +
  78. "resubmit(,0)")
  79. self.br_int.add_flow(in_port=port, table=0, priority=65535,
  80. reg2=0, actions=actions)
  81. else:
  82. for flow in flows:
  83. actions = str(flow).partition("actions=")[2]
  84. acts = actions.split(',')
  85. # mod_nw_tos = modify type of service header
  86. # This is the second byte of the IPv4 packet header.
  87. # DSCP makes up the upper 6 bits of this header field.
  88. actions = "mod_nw_tos:" + mark + ","
  89. actions += ','.join([act for act in acts
  90. if "mod_nw_tos:" not in act])
  91. self.br_int.mod_flow(reg2=0, in_port=port, table=0,
  92. actions=actions)
  93. def delete_dscp_marking(self, port):
  94. port_name = port['vif_port'].port_name
  95. port = self.br_int.get_port_ofport(port_name)
  96. self.br_int.delete_flows(in_port=port, table=0, reg2=0)