4 ## Copyright (c) 2020 Intel Corporation
6 ## Licensed under the Apache License, Version 2.0 (the "License");
7 ## you may not use this file except in compliance with the License.
8 ## You may obtain a copy of the License at
10 ## http://www.apache.org/licenses/LICENSE-2.0
12 ## Unless required by applicable law or agreed to in writing, software
13 ## distributed under the License is distributed on an "AS IS" BASIS,
14 ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 ## See the License for the specific language governing permissions and
16 ## limitations under the License.
19 from rapid_log import RapidLog
20 from prox_ctrl import prox_ctrl
21 from rapid_machine import RapidMachine
22 from math import ceil, log2
25 class RandomPortBits(object):
27 Class to generate PROX bitmaps for random bit generation
28 in source & dst UPD ports to emulate mutiple flows
31 def get_bitmap(flow_number):
32 number_of_random_bits = ceil(log2(flow_number))
33 if number_of_random_bits > 30:
34 raise Exception("Not able to support that many flows")
35 # throw exeption since we need the first bit to be 1
36 # Otherwise, the randomization could results in all 0's
37 # and that might be an invalid UDP port and result in
38 # packets being discarded
39 src_number_of_random_bits = number_of_random_bits // 2
40 dst_number_of_random_bits = (number_of_random_bits -
41 src_number_of_random_bits)
42 src_port_bitmap = '1000000000000000'.replace ('0','X',
43 src_number_of_random_bits)
44 dst_port_bitmap = '1000000000000000'.replace ('0','X',
45 dst_number_of_random_bits)
46 return [src_port_bitmap, dst_port_bitmap, 1 << number_of_random_bits]
48 class RapidGeneratorMachine(RapidMachine):
50 Class to deal with a generator PROX instance (VM, bare metal, container)
52 def __init__(self, key, user, vim, rundir, resultsdir, machine_params,
59 self.ip_length_offset = 18
60 # In IPV6, the IP size is the size of the IP content
61 self.frame_size_minus_ip_size = (2 * mac_address_size +
62 ethertype_size + ip_header_size + FCS_size)
65 self.ip_length_offset = 16
66 # In IPV4, the IP size is the size of the IP header + IP content
67 self.frame_size_minus_ip_size = (2 * mac_address_size +
68 ethertype_size + FCS_size)
69 self.frame_size_minus_udp_header_and_content = (2 * mac_address_size +
70 ethertype_size + ip_header_size + FCS_size )
71 udp_header_start_offset = (2 * mac_address_size + ethertype_size +
73 self.udp_source_port_offset = udp_header_start_offset
74 self.udp_dest_port_offset = udp_header_start_offset + 2
75 self.udp_length_offset = udp_header_start_offset + 4
77 if 'bucket_size_exp' in machine_params.keys():
78 self.bucket_size_exp = machine_params['bucket_size_exp']
80 self.bucket_size_exp = 11
81 super().__init__(key, user, vim, rundir, resultsdir, machine_params,
85 return (self.machine_params['gencores'] +
86 self.machine_params['latcores'])
88 def remap_all_cpus(self):
89 """Convert relative cpu ids for different parameters (gencores, latcores)
91 super().remap_all_cpus()
93 if self.cpu_mapping is None:
96 if 'gencores' in self.machine_params.keys():
97 cpus_remapped = super().remap_cpus(self.machine_params['gencores'])
98 RapidLog.debug('{} ({}): gencores {} remapped to {}'.format(self.name, self.ip, self.machine_params['gencores'], cpus_remapped))
99 self.machine_params['gencores'] = cpus_remapped
101 if 'latcores' in self.machine_params.keys():
102 cpus_remapped = super().remap_cpus(self.machine_params['latcores'])
103 RapidLog.debug('{} ({}): latcores {} remapped to {}'.format(self.name, self.ip, self.machine_params['latcores'], cpus_remapped))
104 self.machine_params['latcores'] = cpus_remapped
106 def generate_lua(self):
107 appendix = 'gencores="%s"\n'% ','.join(map(str,
108 self.machine_params['gencores']))
109 appendix = appendix + 'latcores="%s"\n'% ','.join(map(str,
110 self.machine_params['latcores']))
111 if 'gw_vm' in self.machine_params.keys():
112 for index, gw_ip in enumerate(self.machine_params['gw_ips'],
114 appendix = appendix + 'gw_ip{}="{}"\n'.format(index, gw_ip)
115 appendix = (appendix + 'gw_hex_ip{}=convertIPToHex(gw_ip{})\n'.
116 format(index, index))
117 appendix = (appendix +
118 'bucket_size_exp="{}"\n'.format(self.bucket_size_exp))
119 if 'heartbeat' in self.machine_params.keys():
120 appendix = (appendix +
121 'heartbeat="%s"\n'% self.machine_params['heartbeat'])
123 appendix = appendix + 'heartbeat="60"\n'
124 super().generate_lua(appendix)
126 def start_prox(self):
127 # Start the generator with the -e option so that the cores don't
128 # start automatically
129 super().start_prox('-e')
130 if self.vim in ['kubernetes']:
131 self.remap_all_cpus()
133 def set_generator_speed(self, speed):
134 # The assumption is that we only use task 0 for generating
135 # We should check the gen.cfg file to make sure there is only task=0
136 speed_per_gen_core = speed / len(self.machine_params['gencores'])
137 self.socket.speed(speed_per_gen_core, self.machine_params['gencores'])
139 def set_udp_packet_size(self, imix_frame_sizes):
140 # We should check the gen.cfg to make sure we only send UDP packets
141 # If only 1 packet size, still using the 'old' way of setting the
142 # packet sizes in PROX. Otherwise, using the 'new' way which
143 # automatically sets IP and UDP sizes. We should switch to the new way
144 # eventually for all cases.
145 if len(imix_frame_sizes) == 1:
146 # Frame size = PROX pkt size + 4 bytes CRC
147 # The set_size function takes the PROX packet size as a parameter
148 self.socket.set_size(self.machine_params['gencores'], 0,
149 imix_frame_sizes[0] - 4)
150 # Writing length in the ip header
151 self.socket.set_value(self.machine_params['gencores'], 0,
152 self.ip_length_offset, imix_frame_sizes[0] -
153 self.frame_size_minus_ip_size, 2)
154 # Writing length in the udp header
155 self.socket.set_value(self.machine_params['gencores'], 0,
156 self.udp_length_offset, imix_frame_sizes[0] -
157 self.frame_size_minus_udp_header_and_content, 2)
160 RapidLog.critical('IMIX not supported for IPV6')
161 prox_sizes = [frame_size - 4 for frame_size in imix_frame_sizes]
162 self.socket.set_imix(self.machine_params['gencores'], 0,
165 def set_flows(self, number_of_flows):
166 source_port, destination_port, actualflows = RandomPortBits.get_bitmap(
168 self.socket.set_random(self.machine_params['gencores'],0,
169 self.udp_source_port_offset, source_port,2)
170 self.socket.set_random(self.machine_params['gencores'],0,
171 self.udp_dest_port_offset, destination_port,2)
174 def start_gen_cores(self):
175 self.socket.start(self.machine_params['gencores'])
177 def stop_gen_cores(self):
178 self.socket.stop(self.machine_params['gencores'])
180 def start_latency_cores(self):
181 self.socket.start(self.machine_params['latcores'])
183 def stop_latency_cores(self):
184 self.socket.stop(self.machine_params['latcores'])
187 # Checking all tasks in the cfg file. In this way, we can have more
188 # latency tasks on the same core
189 return (self.socket.lat_stats(self.machine_params['latcores'],
190 self.all_tasks_for_this_cfg))