2 # Copyright 2016 Cisco Systems, Inc. All rights reserved.
4 # Licensed under the Apache License, Version 2.0 (the "License"); you may
5 # not use this file except in compliance with the License. You may obtain
6 # a copy of the License at
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 # License for the specific language governing permissions and limitations
19 from network import Network
20 from packet_analyzer import PacketAnalyzer
21 from specs import ChainType
22 from stats_collector import IntervalCollector
25 class StageManager(object):
26 """A class to stage resources in the systenm under test."""
28 def __init__(self, config, cred, factory):
31 # conditions due to EXT chain special cases
32 if (config.vlan_tagging and not config.vlans) or not config.no_int_config:
33 VM_CLASS = factory.get_stage_class(config.service_chain)
34 self.client = VM_CLASS(config, cred)
38 return self.client.get_vlans() if self.client else []
40 def get_host_ips(self):
41 return self.client.get_host_ips()
43 def get_networks_uuids(self):
44 return self.client.get_networks_uuids()
46 def disable_port_security(self):
47 self.client.disable_port_security()
50 return self.client.vms
53 return self.client.nets
56 return self.client.ports
58 def get_compute_nodes(self):
59 return self.client.compute_nodes if self.client else {}
61 def set_vm_macs(self):
62 if self.client and self.config.service_chain != ChainType.EXT:
63 self.config.generator_config.set_vm_mac_list(self.client.get_end_port_macs())
66 if not self.config.no_cleanup and self.client:
70 class PVPStatsManager(object):
71 """A class to generate traffic and extract results for PVP chains."""
73 def __init__(self, config, clients, specs, factory, vlans, notifier=None):
75 self.clients = clients
77 self.notifier = notifier
78 self.interval_collector = None
80 self.factory = factory
83 def set_vlan_tag(self, device, vlan):
85 self.worker.set_vlan_tag(device, vlan)
87 device.set_vlan_tag(vlan)
90 WORKER_CLASS = self.factory.get_chain_worker(self.specs.openstack.encaps,
91 self.config.service_chain)
92 self.worker = WORKER_CLASS(self.config, self.clients, self.specs)
94 self.worker.set_vlans(self.vlans)
95 self._config_interfaces()
97 # since the wrorker is up and running, we need to close it
98 # in case of exception
103 return self.worker.get_data() if self.worker else {}
105 def _get_network(self, traffic_port, stats, reverse=False):
106 """Get the Network object corresponding to a given TG port.
108 :param traffic_port: must be either 0 or 1
109 :param stats: TG stats for given traffic port
110 :param reverse: specifies if the interface list for this network
111 should go from TG to loopback point (reverse=false) or
112 from loopback point to TG (reverse=true)
114 # build the interface list in fwd direction (TG To loopback point)
115 interfaces = [self.clients['traffic'].get_interface(traffic_port, stats)]
118 # interfaces for workers must be aligned on the TG port number
119 interfaces.extend(self.worker.get_network_interfaces(traffic_port))
120 # let Network reverse the interface order if needed
121 return Network(interfaces, reverse)
123 def _config_interfaces(self):
124 if self.config.service_chain != ChainType.EXT:
125 self.clients['vm'].disable_port_security()
127 self.worker.config_interfaces()
129 def _generate_traffic(self):
130 if self.config.no_traffic:
133 self.interval_collector = IntervalCollector(time.time())
134 self.interval_collector.attach_notifier(self.notifier)
135 LOG.info('Starting to generate traffic...')
137 for stats in self.clients['traffic'].run_traffic():
138 self.interval_collector.add(stats)
140 LOG.info('...traffic generating ended.')
144 return self.interval_collector.get() if self.interval_collector else []
146 def get_version(self):
147 return self.worker.get_version() if self.worker else {}
150 """Run analysis in both direction and return the analysis."""
154 stats = self._generate_traffic()
156 'raw_data': self._get_data(),
157 'packet_analysis': {},
161 # fetch latest stats from traffic gen
162 stats = self.clients['traffic'].get_stats()
163 LOG.info('Requesting packet analysis on the forward direction...')
164 result['packet_analysis']['direction-forward'] = \
165 self.get_analysis([self._get_network(0, stats),
166 self._get_network(1, stats, reverse=True)])
167 LOG.info('Packet analysis on the forward direction completed')
169 LOG.info('Requesting packet analysis on the reverse direction...')
170 result['packet_analysis']['direction-reverse'] = \
171 self.get_analysis([self._get_network(1, stats),
172 self._get_network(0, stats, reverse=True)])
174 LOG.info('Packet analysis on the reverse direction completed')
177 def get_compute_nodes_bios(self):
178 return self.worker.get_compute_nodes_bios() if self.worker else {}
181 def get_analysis(nets):
182 LOG.info('Starting traffic analysis...')
184 packet_analyzer = PacketAnalyzer()
185 # Traffic types are assumed to always alternate in every chain. Add a no stats interface in
186 # between if that is not the case.
189 for interface in network.get_interfaces():
190 packet_analyzer.record(interface, 'tx' if tx else 'rx')
193 LOG.info('...traffic analysis completed')
194 return packet_analyzer.get_analysis()
201 class PVVPStatsManager(PVPStatsManager):
202 """A Class to generate traffic and extract results for PVVP chains."""
204 def __init__(self, config, clients, specs, factory, vlans, notifier=None):
205 PVPStatsManager.__init__(self, config, clients, specs, factory, vlans, notifier)
208 """Run analysis in both direction and return the analysis."""
209 fwd_v2v_net, rev_v2v_net = self.worker.run()
211 stats = self._generate_traffic()
213 'raw_data': self._get_data(),
214 'packet_analysis': {},
217 # fetch latest stats from traffic gen
218 stats = self.clients['traffic'].get_stats()
219 fwd_nets = [self._get_network(0, stats)]
221 fwd_nets.append(fwd_v2v_net)
222 fwd_nets.append(self._get_network(1, stats, reverse=True))
224 rev_nets = [self._get_network(1, stats)]
226 rev_nets.append(rev_v2v_net)
227 rev_nets.append(self._get_network(0, stats, reverse=True))
229 LOG.info('Requesting packet analysis on the forward direction...')
230 result['packet_analysis']['direction-forward'] = self.get_analysis(fwd_nets)
231 LOG.info('Packet analysis on the forward direction completed')
233 LOG.info('Requesting packet analysis on the reverse direction...')
234 result['packet_analysis']['direction-reverse'] = self.get_analysis(rev_nets)
236 LOG.info('Packet analysis on the reverse direction completed')
240 class EXTStatsManager(PVPStatsManager):
241 """A Class to generate traffic and extract results for EXT chains."""
243 def __init__(self, config, clients, specs, factory, vlans, notifier=None):
244 PVPStatsManager.__init__(self, config, clients, specs, factory, vlans, notifier)
247 if self.specs.openstack:
248 WORKER_CLASS = self.factory.get_chain_worker(self.specs.openstack.encaps,
249 self.config.service_chain)
250 self.worker = WORKER_CLASS(self.config, self.clients, self.specs)
251 self.worker.set_vlans(self.vlans)
253 if not self.config.no_int_config:
254 self._config_interfaces()