107 lines
3.9 KiB
Python
107 lines
3.9 KiB
Python
# Copyright 2016 Huawei corp.
|
|
# All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
from subprocess import call
|
|
from subprocess import check_call
|
|
|
|
from oslo_log import log as logging
|
|
|
|
import agent_api
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
class TcDriver(agent_api.AgentInterface):
|
|
def __init__(self):
|
|
self.ports = {}
|
|
|
|
def set_ports(self, lan_port, wan_port):
|
|
self.ports['lan_port'] = lan_port
|
|
self.ports['wan_port'] = wan_port
|
|
|
|
def get_ports(self):
|
|
return self.ports
|
|
|
|
def clear_all(self):
|
|
for port in self.ports.values():
|
|
call('sudo tc qdisc del dev %s root' % port, shell=True)
|
|
|
|
def set_root_queue(self, tc_dict):
|
|
check_call('sudo tc qdisc add dev %s handle 1: root htb' %
|
|
self.ports[tc_dict['port_side']], shell=True)
|
|
class_str = 'sudo tc class add dev %s parent 1: classid 1:1 ' \
|
|
'htb rate %s ceil %s'
|
|
check_call(class_str % (self.ports[tc_dict['port_side']],
|
|
str(tc_dict['max_rate']),
|
|
str(tc_dict['max_rate'])), shell=True)
|
|
|
|
def create_traffic_class(self, tc_dict):
|
|
""" Create new traffic class.
|
|
Parameters:
|
|
port_side - lan_port / wan_port
|
|
parent - the parent class
|
|
child - the class id
|
|
min - minimum traffic rate (CIR)
|
|
max - maximum traffic rate. if not provide, the maximum rate will
|
|
be limitted by parent maximum rate.
|
|
"""
|
|
LOG.debug('got request for new class: %s' % tc_dict)
|
|
tc_dict['command'] = 'add'
|
|
self._create_or_update_class(tc_dict)
|
|
LOG.debug('new class created.')
|
|
|
|
def update_traffic_class(self, tc_dict):
|
|
tc_dict['command'] = 'change'
|
|
self._create_or_update_class(tc_dict)
|
|
|
|
def remove_traffic_class(self, tc_dict):
|
|
self._delete_filter(tc_dict)
|
|
cmd = 'sudo tc class del dev %s classid %s:%s' % (
|
|
self.ports[tc_dict['port_side']],
|
|
tc_dict['parent'],
|
|
tc_dict['child']
|
|
)
|
|
check_call(cmd, shell=True)
|
|
|
|
def _create_or_update_class(self, tc_dict):
|
|
cmd = 'sudo tc class %s dev %s parent 1:%s classid 1:%s htb' \
|
|
' rate %s' % (
|
|
tc_dict['command'],
|
|
self.ports[tc_dict['port_side']],
|
|
tc_dict['parent'], tc_dict['child'],
|
|
tc_dict['min']
|
|
)
|
|
if 'max' in tc_dict:
|
|
cmd += ' ceil %s' % tc_dict['max']
|
|
check_call(cmd, shell=True)
|
|
|
|
def create_filter(self, tc_dict):
|
|
cmd = 'sudo tc filter add dev %s parent 1:0' % (
|
|
self.ports[tc_dict['port_side']])
|
|
cmd += ' protocol ip prio 1 u32'
|
|
if tc_dict['protocol'] and tc_dict['protocol'] == 'vxlan':
|
|
cmd += ' match ip protocol 17 0xFF' # UDP
|
|
cmd += ' match u16 0x12B5 0xFFFF at 22' # VxLAN port
|
|
cmd += ' match u32 0x%0.6X00 0xFFFFFF00 at 32' % tc_dict['vni']
|
|
cmd += ' flowid 1:%s' % tc_dict['child']
|
|
LOG.debug('creating filter: %s' % cmd)
|
|
check_call(cmd, shell=True)
|
|
|
|
def _delete_filter(self, tc_dict):
|
|
cmd = 'sudo tc filter del dev %s ' % self.ports[tc_dict['port_side']]
|
|
cmd += ' parent 1:0 protocol ip prio 1 u32'
|
|
cmd += ' flowid %s:%s' % (tc_dict['parent'], tc_dict['child'])
|
|
check_call(cmd, shell=True)
|