Spaces:
Sleeping
Sleeping
| ## Copyright (C) 2015-2018 Rolf Neugebauer. All rights reserved. | |
| ## Copyright (C) 2015 Netronome Systems, Inc. All rights reserved. | |
| ## | |
| ## Licensed under the Apache License, Version 2.0 (the "License"); | |
| ## you may not use this file except in compliance with the License. | |
| ## You may obtain a copy of the License at | |
| ## | |
| ## http://www.apache.org/licenses/LICENSE-2.0 | |
| ## | |
| ## Unless required by applicable law or agreed to in writing, software | |
| ## distributed under the License is distributed on an "AS IS" BASIS, | |
| ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| ## See the License for the specific language governing permissions and | |
| ## limitations under the License. | |
| """Some general function and data to calculate rates for Ethernet""" | |
| # pylint: disable=bad-whitespace | |
| # pylint: disable=invalid-name | |
| # pylint: disable=too-many-instance-attributes | |
| import sys | |
| # Configuration options | |
| Variants = ['400GigE', '200GigE', '100GigE', '50GigE', '40GigE', '25GigE', '10GigE', 'GigE'] | |
| # Various fields on the wire, all in Bytes | |
| Pre = 7 # Preamble | |
| SOF = 1 # Start of Frame indicator | |
| Hdr = 14 # Header | |
| Hdr_VLAN = 18 # Header including 802.18 Tag | |
| MinPayLoad = 46 # Minimum Payload size | |
| MinPayLoad_VLAN = 42 # Minimum Payload size | |
| CRC = 4 # Checksum | |
| IFG = 12 # Interframe Gap | |
| IFG_GigE = 8 # Optionally reduce IFG for 1GigE | |
| IFG_10GigE = 5 # Optionally reduce IFG for 10GigE | |
| IFG_25GigE = 5 # Optionally reduce IFG for 10GigE | |
| IFG_40plusGigE = 1 # Optionally reduce IFG for 40GigE | |
| class Cfg(): | |
| """A class representing an Ethernet link. Allows to get | |
| various metrics based on a specific configuration""" | |
| def __init__(self, variant='40GigE', vlan=True, ifg_min=False): | |
| """Instantiate a Ethernet config. | |
| - variant: One of the Variants | |
| - vlan: Should the frames contain a VLAN tag | |
| - ifg_min: minimum allowed interframe gap or standard | |
| """ | |
| if variant not in Variants: | |
| raise Exception("Unsupported ethernet variant: %s" % variant) | |
| self.variant = variant | |
| self.vlan = vlan | |
| self.ifg_min = ifg_min | |
| if variant == '400GigE': | |
| self.rate = 400 * 1000 * 1000 * 1000 | |
| elif variant == '200GigE': | |
| self.rate = 200 * 1000 * 1000 * 1000 | |
| elif variant == '100GigE': | |
| self.rate = 100 * 1000 * 1000 * 1000 | |
| elif variant == '50GigE': | |
| self.rate = 50 * 1000 * 1000 * 1000 | |
| elif variant == '40GigE': | |
| self.rate = 40 * 1000 * 1000 * 1000 | |
| elif variant == '25GigE': | |
| self.rate = 25 * 1000 * 1000 * 1000 | |
| elif variant == '10GigE': | |
| self.rate = 10 * 1000 * 1000 * 1000 | |
| elif variant == 'GigE': | |
| self.rate = 1000 * 1000 * 1000 | |
| self.pre_sz = Pre + SOF | |
| if vlan: | |
| self.hdr_sz = Hdr_VLAN | |
| self.min_pay = MinPayLoad_VLAN | |
| else: | |
| self.hdr_sz = Hdr | |
| self.min_pay = MinPayLoad | |
| if ifg_min: | |
| if variant == 'GigE': | |
| self.trail_sz = IFG_GigE | |
| elif variant == '10GigE': | |
| self.trail_sz = IFG_10GigE | |
| elif variant == '25GigE': | |
| self.trail_sz = IFG_25GigE | |
| else: | |
| self.trail_sz = IFG_40plusGigE | |
| else: | |
| self.trail_sz = IFG | |
| self.crc_sz = CRC | |
| def pps(self, payload): | |
| """Return the rate of packets for a given payload""" | |
| if payload < self.min_pay: | |
| p_sz = self.min_pay | |
| else: | |
| p_sz = payload | |
| s = self.pre_sz + self.hdr_sz + p_sz + self.crc_sz + self.trail_sz | |
| return self.rate / float(s * 8) | |
| def bps(self, payload): | |
| "Bits per second of payload bits" | |
| p = self.pps(payload) | |
| return p * payload * 8 | |
| def pps_ex(self, frame_sz): | |
| """Return the rate of packets for a given payload. Assume | |
| @frame_sz includes ethernet header and CRC""" | |
| s = frame_sz - self.hdr_sz - self.crc_sz | |
| return self.pps(s) | |
| def bps_ex(self, frame_sz): | |
| """Bits per second of payload bits for a given payload. Assume | |
| @frame_sz includes ethernet header and CRC""" | |
| p = self.pps_ex(frame_sz) | |
| return p * frame_sz * 8 | |
| def us_ex(self, frame_sz): | |
| """Calculate how long (in us) it takes to transmit a frame | |
| of a given size. Assume @frame_sz includes ethernet header and CRC.""" | |
| s = (frame_sz + self.pre_sz + self.trail_sz) | |
| return (float(s * 8)/self.rate) * 1000 * 1000 | |
| if __name__ == '__main__': | |
| variant = '100GigE' | |
| if len(sys.argv) == 2: | |
| variant = sys.argv[1] | |
| # not much of a test | |
| e = Cfg(variant) | |
| print("%4s %9s %11s %s" % ("sz", "pps", "bps", "ns")) | |
| for sz in [64, 128, 256, 512, 1024, 1518, 4096, 9000]: | |
| print("%4d %9d %11d %.2f" % (sz, e.pps_ex(sz), e.bps_ex(sz), 1000.0 * e.us_ex(sz))) | |
| dat = open("eth.dat", "w") | |
| dat.write("\"Frame Size(Bytes)\" " | |
| "\"Packets/s\" " | |
| "\"Bits/s\" " | |
| "\"Gb/s\" " | |
| "\"Time (us)\" " | |
| "\n") | |
| for sz in range(64, 1519): | |
| _pps = e.pps_ex(sz) | |
| bw = e.bps_ex(sz) | |
| gbs = float(bw) / (1000 * 1000 * 1000) | |
| us = e.us_ex(sz) | |
| dat.write("%d %f %f %f %f\n" % (sz, _pps, bw, gbs, us)) | |