1 # Copyright (c) 2019 Viosoft 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.
21 from yardstick.network_services.vnf_generic.vnf import sample_vnf
22 from yardstick.common import exceptions
25 LOG = logging.getLogger(__name__)
28 class PktgenHelper(object):
34 def __init__(self, host, port=23000):
37 self.connected = False
40 self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
43 self._sock.settimeout(self.CONNECT_TIMEOUT)
44 self._sock.connect((self.host, self.port))
45 except (socket.gaierror, socket.error, socket.timeout):
54 LOG.info("Connecting to pktgen instance at %s...", self.host)
55 for idx in range(self.RETRY_COUNT):
56 self.connected = self._connect()
59 LOG.debug("Connection attempt %d: Unable to connect to %s, " \
60 "retrying in %d seconds",
61 idx, self.host, self.RETRY_SECONDS)
62 time.sleep(self.RETRY_SECONDS)
64 LOG.error("Unable to connect to pktgen instance on %s !",
69 def send_command(self, command):
70 if not self.connected:
71 LOG.error("Pktgen socket is not connected")
75 self._sock.sendall((command + "\n").encode())
77 except (socket.timeout, socket.error):
78 LOG.error("Error sending command '%s'", command)
84 class VcmtsPktgenSetupEnvHelper(sample_vnf.SetupEnvHelper):
86 BASE_PARAMETERS = "export LUA_PATH=/vcmts/Pktgen.lua;"\
87 + "export CMK_PROC_FS=/host/proc;"
91 def generate_pcap_filename(self, port_cfg):
92 return port_cfg['traffic_type'] + "_" + port_cfg['num_subs'] \
93 + "cms_" + port_cfg['num_ofdm'] + "ofdm.pcap"
95 def find_port_cfg(self, ports_cfg, port_name):
96 for port_cfg in ports_cfg:
97 if port_name in port_cfg:
101 def build_pktgen_parameters(self, pod_cfg):
102 ports_cfg = pod_cfg['ports']
105 for i in range(self.PORTS_COUNT):
106 port_cfg.append(self.find_port_cfg(ports_cfg, 'port_' + str(i)))
108 pktgen_parameters = self.BASE_PARAMETERS + " " \
109 + " /pktgen-config/setup.sh " + pod_cfg['pktgen_id'] \
110 + " " + pod_cfg['num_ports']
112 for i in range(self.PORTS_COUNT):
113 pktgen_parameters += " " + port_cfg[i]['net_pktgen']
115 for i in range(self.PORTS_COUNT):
116 pktgen_parameters += " " + self.generate_pcap_filename(port_cfg[i])
118 return pktgen_parameters
120 def start_pktgen(self, pod_cfg):
121 self.ssh_helper.drop_connection()
122 cmd = self.build_pktgen_parameters(pod_cfg)
123 LOG.debug("Executing: '%s'", cmd)
124 self.ssh_helper.send_command(cmd)
125 LOG.info("Pktgen executed")
127 def setup_vnf_environment(self):
131 class VcmtsPktgen(sample_vnf.SampleVNFTrafficGen):
133 TG_NAME = 'VcmtsPktgen'
134 APP_NAME = 'VcmtsPktgen'
138 PKTGEN_BASE_PORT = 23000
140 def __init__(self, name, vnfd, setup_env_helper_type=None,
141 resource_helper_type=None):
142 if setup_env_helper_type is None:
143 setup_env_helper_type = VcmtsPktgenSetupEnvHelper
144 super(VcmtsPktgen, self).__init__(
145 name, vnfd, setup_env_helper_type, resource_helper_type)
147 self.pktgen_address = vnfd['mgmt-interface']['ip']
148 LOG.info("Pktgen container '%s', IP: %s", name, self.pktgen_address)
150 def extract_pod_cfg(self, pktgen_pods_cfg, pktgen_id):
151 for pod_cfg in pktgen_pods_cfg:
152 if pod_cfg['pktgen_id'] == pktgen_id:
156 def instantiate(self, scenario_cfg, context_cfg):
157 super(VcmtsPktgen, self).instantiate(scenario_cfg, context_cfg)
159 options = scenario_cfg.get('options', {})
160 self.pktgen_rate = options.get('pktgen_rate', self.DEFAULT_RATE)
163 pktgen_values_filepath = options['pktgen_values']
165 raise KeyError("Missing pktgen_values key in scenario options" \
166 "section of the task definition file")
168 if not os.path.isfile(pktgen_values_filepath):
169 raise RuntimeError("The pktgen_values file path provided " \
172 # The yaml_loader.py (SafeLoader) underlying regex has an issue
173 # with reading PCI addresses (processed as double). so the
174 # BaseLoader is used here.
175 with open(pktgen_values_filepath) as stream:
176 pktgen_values = yaml.load(stream, Loader=yaml.BaseLoader)
178 if pktgen_values == None:
179 raise RuntimeError("Error reading pktgen_values file provided (" +
180 pktgen_values_filepath + ")")
182 self.pktgen_id = int(options[self.name]['pktgen_id'])
183 self.resource_helper.pktgen_id = self.pktgen_id
185 self.pktgen_helper = PktgenHelper(self.pktgen_address,
186 self.PKTGEN_BASE_PORT + self.pktgen_id)
188 pktgen_pods_cfg = pktgen_values['topology']['pktgen_pods']
190 self.pod_cfg = self.extract_pod_cfg(pktgen_pods_cfg,
193 if self.pod_cfg == None:
194 raise KeyError("Pktgen with id " + str(self.pktgen_id) + \
197 self.setup_helper.start_pktgen(self.pod_cfg)
199 def run_traffic(self, traffic_profile):
200 if not self.pktgen_helper.connect():
201 raise exceptions.PktgenActionError(command="connect")
202 LOG.info("Connected to pktgen instance at %s", self.pktgen_address)
205 for i in range(self.setup_helper.PORTS_COUNT):
206 commands.append('pktgen.set("' + str(i) + '", "rate", ' +
207 "%0.1f" % self.pktgen_rate + ');')
209 commands.append('pktgen.start("all");')
211 for command in commands:
212 if self.pktgen_helper.send_command(command):
213 LOG.debug("Command '%s' sent to pktgen", command)
214 LOG.info("Traffic started on %s...", self.name)