1 # Copyright (c) 2016-2017 Intel Corporation
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
17 NETWORK_KERNEL = 'network_kernel'
18 NETWORK_DPDK = 'network_dpdk'
19 NETWORK_OTHER = 'network_other'
20 CRYPTO_KERNEL = 'crypto_kernel'
21 CRYPTO_DPDK = 'crypto_dpdk'
22 CRYPTO_OTHER = 'crypto_other'
25 class DpdkBindHelperException(Exception):
29 class DpdkBindHelper(object):
30 DPDK_STATUS_CMD = "{dpdk_nic_bind} --status"
31 DPDK_BIND_CMD = "sudo {dpdk_nic_bind} {force} -b {driver} {vpci}"
33 NIC_ROW_RE = re.compile("([^ ]+) '([^']+)' (?:if=([^ ]+) )?drv=([^ ]+) "
34 "unused=([^ ]*)(?: (\*Active\*))?")
35 SKIP_RE = re.compile('(====|<none>|^$)')
36 NIC_ROW_FIELDS = ['vpci', 'dev_type', 'iface', 'driver', 'unused', 'active']
39 (re.compile('^Network.*DPDK.*$'), NETWORK_DPDK),
40 (re.compile('^Network.*kernel.*$'), NETWORK_KERNEL),
41 (re.compile('^Other network.*$'), NETWORK_OTHER),
42 (re.compile('^Crypto.*DPDK.*$'), CRYPTO_DPDK),
43 (re.compile('^Crypto.*kernel$'), CRYPTO_KERNEL),
44 (re.compile('^Other crypto.*$'), CRYPTO_OTHER),
47 def clean_status(self):
57 def __init__(self, ssh_helper):
58 self.dpdk_status = None
59 self.status_nic_row_re = None
60 self._dpdk_nic_bind_attr = None
61 self._status_cmd_attr = None
63 self.ssh_helper = ssh_helper
66 def _dpdk_execute(self, *args, **kwargs):
67 res = self.ssh_helper.execute(*args, **kwargs)
69 raise DpdkBindHelperException('{} command failed with rc={}'.format(
70 self._dpdk_nic_bind, res[0]))
74 def _dpdk_nic_bind(self):
75 if self._dpdk_nic_bind_attr is None:
76 self._dpdk_nic_bind_attr = self.ssh_helper.provision_tool(tool_file="dpdk-devbind.py")
77 return self._dpdk_nic_bind_attr
80 def _status_cmd(self):
81 if self._status_cmd_attr is None:
82 self._status_cmd_attr = self.DPDK_STATUS_CMD.format(dpdk_nic_bind=self._dpdk_nic_bind)
83 return self._status_cmd_attr
85 def _addline(self, active_list, line):
86 if active_list is None:
88 res = self.NIC_ROW_RE.match(line)
91 new_data = {k: v for k, v in zip(self.NIC_ROW_FIELDS, res.groups())}
92 new_data['active'] = bool(new_data['active'])
93 self.dpdk_status[active_list].append(new_data)
96 def _switch_active_dict(cls, a_row, active_dict):
97 for regexp, a_dict in cls.HEADER_DICT_PAIRS:
98 if regexp.match(a_row):
102 def parse_dpdk_status_output(self, input):
105 for a_row in input.splitlines():
106 if self.SKIP_RE.match(a_row):
108 active_dict = self._switch_active_dict(a_row, active_dict)
109 self._addline(active_dict, a_row)
110 return self.dpdk_status
112 def _get_bound_pci_addresses(self, active_dict):
113 return [iface['vpci'] for iface in self.dpdk_status[active_dict]]
116 def dpdk_bound_pci_addresses(self):
117 return self._get_bound_pci_addresses(NETWORK_DPDK)
120 def kernel_bound_pci_addresses(self):
121 return self._get_bound_pci_addresses(NETWORK_KERNEL)
124 def interface_driver_map(self):
125 return {interface['vpci']: interface['driver']
126 for interface in itertools.chain(*self.dpdk_status.values())}
128 def read_status(self):
129 return self.parse_dpdk_status_output(self._dpdk_execute(self._status_cmd)[1])
131 def bind(self, pci, driver, force=True):
132 cmd = self.DPDK_BIND_CMD.format(dpdk_nic_bind=self._dpdk_nic_bind,
134 vpci=' '.join(list(pci)),
135 force='--force' if force else '')
136 self._dpdk_execute(cmd)
137 # update the inner status dict
140 def save_used_drivers(self):
141 self.used_drivers = self.interface_driver_map
143 def rebind_drivers(self, force=True):
144 for vpci, driver in self.used_drivers.items():
145 self.bind(vpci, driver, force)