def init(self): LOG.info('%s(): caller(): %s', log_utils.get_fname(1), log_utils.get_fname(2)) """ Validates the given ``ovsdb_addr`` and connects to OVS instance. If failed to connect to OVS instance or the given ``datapath_id`` does not match with the Datapath ID of the connected OVS instance, raises :py:mod:`os_ken.lib.ovs.bridge.OVSBridgeNotFound` exception. """ if not valid_ovsdb_addr(self.ovsdb_addr): raise ValueError('Invalid OVSDB address: %s' % self.ovsdb_addr) if self.br_name is None: self.br_name = self._get_bridge_name()
def get_controller(self): LOG.info('%s(): caller(): %s', log_utils.get_fname(1), log_utils.get_fname(2)) """ Gets the configured OpenFlow controller address. This method is corresponding to the following ovs-vsctl command:: $ ovs-vsctl get-controller <bridge> """ command = ovs_vsctl.VSCtlCommand('get-controller', [self.br_name]) self.run_command([command]) result = command.result return result[0] if len(result) == 1 else result
def add_db_attribute(self, table, record, column, value, key=None): LOG.info('%s(): caller(): %s', log_utils.get_fname(1), log_utils.get_fname(2)) """ Adds ('key'=)'value' into 'column' in 'record' in 'table'. This method is corresponding to the following ovs-vsctl command:: $ ovs-vsctl add TBL REC COL [KEY=]VALUE """ if key is not None: value = '%s=%s' % (key, value) command = ovs_vsctl.VSCtlCommand('add', (table, record, column, value)) self.run_command([command])
def _set_meter(self, rest, waiters): LOG.info('%s(): caller(): %s', log_utils.get_fname(1), log_utils.get_fname(2)) cmd = self.dp.ofproto.OFPMC_ADD try: self.ofctl.mod_meter_entry(self.dp, rest, cmd) except: raise ValueError('Invalid meter parameter.') msg = { 'result': 'success', 'details': 'Meter added. : Meter ID=%s' % rest[REST_METER_ID] } return msg
def set_queue(self, rest, vlan_id): LOG.info('%s(): caller(): %s', log_utils.get_fname(1), log_utils.get_fname(2)) if self.ovs_bridge is None: msg = {'result': 'failure', 'details': 'ovs_bridge is not exists'} return REST_COMMAND_RESULT, msg port_name = rest.get(REST_PORT_NAME, None) vif_ports = self.ovs_bridge.get_port_name_list() if port_name is not None: if port_name not in vif_ports: raise ValueError('%s port is not exists' % port_name) vif_ports = [port_name] queue_list = {} queue_type = rest.get(REST_QUEUE_TYPE, 'linux-htb') parent_max_rate = rest.get(REST_QUEUE_MAX_RATE, None) queues = rest.get(REST_QUEUES, []) queue_id = 0 queue_config = [] for queue in queues: max_rate = queue.get(REST_QUEUE_MAX_RATE, None) min_rate = queue.get(REST_QUEUE_MIN_RATE, None) if max_rate is None and min_rate is None: raise ValueError('Required to specify max_rate or min_rate') config = {} if max_rate is not None: config['max-rate'] = max_rate if min_rate is not None: config['min-rate'] = min_rate if len(config): queue_config.append(config) queue_list[queue_id] = {'config': config} queue_id += 1 for port_name in vif_ports: try: self.ovs_bridge.set_qos(port_name, type=queue_type, max_rate=parent_max_rate, queues=queue_config) except Exception as msg: raise ValueError(msg) self.queue_list[port_name] = queue_list msg = {'result': 'success', 'details': queue_list} return REST_COMMAND_RESULT, msg
def set_qos(self, port_name, type='linux-htb', max_rate=None, queues=None): LOG.info('%s(): caller(): %s', log_utils.get_fname(1), log_utils.get_fname(2)) """ Sets a Qos rule and creates Queues on the given port. """ queues = queues if queues else [] command_qos = ovs_vsctl.VSCtlCommand('set-qos', [port_name, type, max_rate]) command_queue = ovs_vsctl.VSCtlCommand('set-queue', [port_name, queues]) self.run_command([command_qos, command_queue]) if command_qos.result and command_queue.result: return command_qos.result + command_queue.result return None
def set_db_attribute(self, table, record, column, value, key=None): LOG.info('%s(): caller(): %s', log_utils.get_fname(1), log_utils.get_fname(2)) """ Sets 'value' into 'column' in 'record' in 'table'. This method is corresponding to the following ovs-vsctl command:: $ ovs-vsctl set TBL REC COL[:KEY]=VALUE """ if key is not None: column = '%s:%s' % (column, key) command = ovs_vsctl.VSCtlCommand('set', (table, record, '%s=%s' % (column, value))) self.run_command([command])
def list_db_attributes(self, table, record=None): LOG.info('%s(): caller(): %s', log_utils.get_fname(1), log_utils.get_fname(2)) """ Lists 'record' (or all records) in 'table'. This method is corresponding to the following ovs-vsctl command:: $ ovs-vsctl list TBL [REC] """ command = ovs_vsctl.VSCtlCommand('list', (table, record)) self.run_command([command]) if command.result: return command.result return []
def _get_external_port(self, name): LOG.info('%s(): caller(): %s', log_utils.get_fname(1), log_utils.get_fname(2)) # exclude vif ports external_ids = self.db_get_map('Interface', name, 'external_ids') if external_ids: return # exclude tunnel ports options = self.db_get_map('Interface', name, 'options') if 'remote_ip' in options: return ofport = self.get_ofport(name) return VifPort(name, ofport, None, None, self)
def regist_ofs(dp, CONF): LOG.info('%s(): caller(): %s', log_utils.get_fname(1), log_utils.get_fname(2)) if dp.id in QoSController._OFS_LIST: return dpid_str = dpid_lib.dpid_to_str(dp.id) try: f_ofs = QoS(dp, CONF) f_ofs.set_default_flow() except OFPUnknownVersion as message: QoSController._LOGGER.info('dpid=%s: %s', dpid_str, message) return QoSController._OFS_LIST.setdefault(dp.id, f_ofs) QoSController._LOGGER.info('dpid=%s: Join qos switch.', dpid_str)
def __init__(self, *args, **kwargs): LOG.info('%s(): caller(): %s', log_utils.get_fname(1), log_utils.get_fname(2)) super(RestQoSAPI, self).__init__(*args, **kwargs) # logger configure QoSController.set_logger(self.logger) self.cs = kwargs['conf_switch'] self.dpset = kwargs['dpset'] wsgi = kwargs['wsgi'] self.waiters = {} self.data = {} self.data['dpset'] = self.dpset self.data['waiters'] = self.waiters wsgi.registory['QoSController'] = self.data wsgi.register(QoSController, self.data)
def __init__(self, CONF, datapath_id, ovsdb_addr, timeout=None, exception=None): LOG.info('%s(): caller(): %s', log_utils.get_fname(1), log_utils.get_fname(2)) super(OVSBridge, self).__init__() self.datapath_id = datapath_id self.ovsdb_addr = ovsdb_addr self.vsctl = ovs_vsctl.VSCtl(ovsdb_addr) self.timeout = timeout or CONF.ovsdb_timeout self.exception = exception self.br_name = None
def set_default_flow(self): LOG.info('%s(): caller(): %s', log_utils.get_fname(1), log_utils.get_fname(2)) if self.version == ofproto_v1_0.OFP_VERSION: return cookie = 0 priority = DEFAULT_FLOW_PRIORITY actions = [{'type': 'GOTO_TABLE', 'table_id': QOS_TABLE_ID + 1}] flow = self._to_of_flow(cookie=cookie, priority=priority, match={}, actions=actions) cmd = self.dp.ofproto.OFPFC_ADD self.ofctl.mod_flow_entry(self.dp, flow, cmd)
def get_db_attribute(self, table, record, column, key=None): LOG.info('%s(): caller(): %s', log_utils.get_fname(1), log_utils.get_fname(2)) """ Gets values of 'column' in 'record' in 'table'. This method is corresponding to the following ovs-vsctl command:: $ ovs-vsctl get TBL REC COL[:KEY] """ if key is not None: column = '%s:%s' % (column, key) command = ovs_vsctl.VSCtlCommand('get', (table, record, column)) self.run_command([command]) if command.result: return command.result[0] return None
def delete_meter(self, rest, vlan_id, waiters): LOG.info('%s(): caller(): %s', log_utils.get_fname(1), log_utils.get_fname(2)) if (self.version == ofproto_v1_0.OFP_VERSION or self.version == ofproto_v1_2.OFP_VERSION): raise ValueError('delete_meter operation is not supported') cmd = self.dp.ofproto.OFPMC_DELETE try: self.ofctl.mod_meter_entry(self.dp, rest, cmd) except: raise ValueError('Invalid meter parameter.') msg = { 'result': 'success', 'details': 'Meter deleted. : Meter ID=%s' % rest[REST_METER_ID] } return REST_COMMAND_RESULT, msg
def _get_cookie(self, vlan_id): LOG.info('%s(): caller(): %s', log_utils.get_fname(1), log_utils.get_fname(2)) if vlan_id == REST_ALL: vlan_ids = self.vlan_list.keys() else: vlan_ids = [vlan_id] cookie_list = [] for vlan_id in vlan_ids: self.vlan_list.setdefault(vlan_id, 0) self.vlan_list[vlan_id] += 1 self.vlan_list[vlan_id] &= ofproto_v1_3_parser.UINT32_MAX cookie = (vlan_id << COOKIE_SHIFT_VLANID) + \ self.vlan_list[vlan_id] cookie_list.append([cookie, vlan_id]) return cookie_list
def set_ovsdb_addr(self, dpid, ovsdb_addr): LOG.info('%s(): caller(): %s', log_utils.get_fname(1), log_utils.get_fname(2)) old_address = self.ovsdb_addr if old_address == ovsdb_addr: return elif ovsdb_addr is None: # Determine deleting OVSDB address was requested. if self.ovs_bridge: self.ovs_bridge = None return ovs_bridge = bridge.OVSBridge(self.CONF, dpid, ovsdb_addr) try: ovs_bridge.init() except: raise ValueError('ovsdb addr is not available.') self.ovsdb_addr = ovsdb_addr self.ovs_bridge = ovs_bridge
def add_vxlan_port(self, name, remote_ip, local_ip=None, key=None, ofport=None): LOG.info('%s(): caller(): %s', log_utils.get_fname(1), log_utils.get_fname(2)) """ Creates a VxLAN tunnel port. See the description of ``add_tunnel_port()``. """ self.add_tunnel_port(name, 'vxlan', remote_ip, local_ip=local_ip, key=key, ofport=ofport)
def to_rest(flow): LOG.info('%s(): caller(): %s', log_utils.get_fname(1), log_utils.get_fname(2)) if REST_ACTION in flow: actions = [] for act in flow[REST_ACTION]: field_value = re.search(r'SET_FIELD: \{ip_dscp:(\d+)', act) if field_value: actions.append({REST_ACTION_MARK: field_value.group(1)}) meter_value = re.search(r'METER:(\d+)', act) if meter_value: actions.append({REST_ACTION_METER: meter_value.group(1)}) queue_value = re.search(r'SET_QUEUE:(\d+)', act) if queue_value: actions.append({REST_ACTION_QUEUE: queue_value.group(1)}) action = {REST_ACTION: actions} else: action = {REST_ACTION: 'Unknown action type.'} return action
def find_db_attributes(self, table, *conditions): LOG.info('%s(): caller(): %s', log_utils.get_fname(1), log_utils.get_fname(2)) """ Lists records satisfying 'conditions' in 'table'. This method is corresponding to the following ovs-vsctl command:: $ ovs-vsctl find TBL CONDITION... .. Note:: Currently, only '=' condition is supported. To support other condition is TODO. """ args = [table] args.extend(conditions) command = ovs_vsctl.VSCtlCommand('find', args) self.run_command([command]) if command.result: return command.result return []
def get_ofs(self, dp_id): LOG.info('%s(): caller(): %s', log_utils.get_fname(1), log_utils.get_fname(2)) if len(self) == 0: raise ValueError('qos sw is not connected.') dps = {} if dp_id == REST_ALL: dps = self else: try: dpid = dpid_lib.str_to_dpid(dp_id) except: raise ValueError('Invalid switchID.') if dpid in self: dps = {dpid: self[dpid]} else: msg = 'qos sw is not connected. : switchID=%s' % dp_id raise ValueError(msg) return dps
class VifPort(object): LOG.info('%s(): caller(): %s', log_utils.get_fname(1), log_utils.get_fname(2)) def __init__(self, port_name, ofport, vif_id, vif_mac, switch): LOG.info('%s(): caller(): %s', log_utils.get_fname(1), log_utils.get_fname(2)) super(VifPort, self).__init__() self.port_name = port_name self.ofport = ofport self.vif_id = vif_id self.vif_mac = vif_mac self.switch = switch def __str__(self): LOG.info('%s(): caller(): %s', log_utils.get_fname(1), log_utils.get_fname(2)) return ('iface-id=%s, ' 'vif_mac=%s, ' 'port_name=%s, ' 'ofport=%d, ' 'bridge_name=%s' % (self.vif_id, self.vif_mac, self.port_name, self.ofport, self.switch.br_name))
def to_mod_openflow(of_match): LOG.info('%s(): caller(): %s', log_utils.get_fname(1), log_utils.get_fname(2)) mac_dontcare = mac.haddr_to_str(mac.DONTCARE) ip_dontcare = '0.0.0.0' ipv6_dontcare = '::' match = {} for key, value in of_match.items(): if key == REST_SRC_MAC or key == REST_DST_MAC: if value == mac_dontcare: continue elif key == REST_SRC_IP or key == REST_DST_IP: if value == ip_dontcare: continue elif key == REST_SRC_IPV6 or key == REST_DST_IPV6: if value == ipv6_dontcare: continue elif value == 0: continue match.setdefault(key, value) return match
def stats_reply_handler(self, ev): LOG.info('%s(): caller(): %s', log_utils.get_fname(1), log_utils.get_fname(2)) msg = ev.msg dp = msg.datapath if dp.id not in self.waiters: return if msg.xid not in self.waiters[dp.id]: return lock, msgs = self.waiters[dp.id][msg.xid] msgs.append(msg) flags = 0 if dp.ofproto.OFP_VERSION == ofproto_v1_0.OFP_VERSION or \ dp.ofproto.OFP_VERSION == ofproto_v1_2.OFP_VERSION: flags = dp.ofproto.OFPSF_REPLY_MORE elif dp.ofproto.OFP_VERSION == ofproto_v1_3.OFP_VERSION: flags = dp.ofproto.OFPMPF_REPLY_MORE if msg.flags & flags: return del self.waiters[dp.id][msg.xid] lock.set()
def add_tunnel_port(self, name, tunnel_type, remote_ip, local_ip=None, key=None, ofport=None): LOG.info('%s(): caller(): %s', log_utils.get_fname(1), log_utils.get_fname(2)) """ Creates a tunnel port. :param name: Port name to be created :param tunnel_type: Type of tunnel (gre or vxlan) :param remote_ip: Remote IP address of tunnel :param local_ip: Local IP address of tunnel :param key: Key of GRE or VNI of VxLAN :param ofport: Requested OpenFlow port number """ options = 'remote_ip=%(remote_ip)s' % locals() if key: options += ',key=%(key)s' % locals() if local_ip: options += ',local_ip=%(local_ip)s' % locals() args = [ 'Interface', name, 'type=%s' % tunnel_type, 'options:%s' % options ] if ofport: args.append('ofport_request=%(ofport)s' % locals()) command_add = ovs_vsctl.VSCtlCommand('add-port', (self.br_name, name)) command_set = ovs_vsctl.VSCtlCommand('set', args) self.run_command([command_add, command_set])
def add_bond(self, name, ifaces, bond_mode=None, lacp=None): LOG.info('%s(): caller(): %s', log_utils.get_fname(1), log_utils.get_fname(2)) """ Creates a bonded port. :param name: Port name to be created :param ifaces: List of interfaces containing at least 2 interfaces :param bond_mode: Bonding mode (active-backup, balance-tcp or balance-slb) :param lacp: LACP mode (active, passive or off) """ assert len(ifaces) >= 2 options = '' if bond_mode: options += 'bond_mode=%(bond_mode)s' % locals() if lacp: options += 'lacp=%(lacp)s' % locals() command_add = ovs_vsctl.VSCtlCommand('add-bond', (self.br_name, name, ifaces), options) self.run_command([command_add])
def get_tunnel_ports(self, tunnel_type='gre'): LOG.info('%s(): caller(): %s', log_utils.get_fname(1), log_utils.get_fname(2)) get_tunnel_port = functools.partial(self.get_tunnel_port, tunnel_type=tunnel_type) return self._get_ports(get_tunnel_port)
def get_external_ports(self): LOG.info('%s(): caller(): %s', log_utils.get_fname(1), log_utils.get_fname(2)) return self._get_ports(self._get_external_port)
def get_vif_ports(self): LOG.info('%s(): caller(): %s', log_utils.get_fname(1), log_utils.get_fname(2)) """ Returns a VIF object for each VIF port """ return self._get_ports(self._get_vif_port)
def _get_vif_port(self, name): LOG.info('%s(): caller(): %s', log_utils.get_fname(1), log_utils.get_fname(2)) external_ids = self.db_get_map('Interface', name, 'external_ids') if 'iface-id' in external_ids and 'attached-mac' in external_ids: return self._vifport(name, external_ids)