00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 import sys
00027 import platform
00028 pvt = platform.python_version_tuple()
00029 if (int(pvt[0]) == 2) and (int(pvt[1]) < 6):
00030 print "This program requires Python 2.6 or later."
00031 sys.exit(1)
00032 del pvt
00033
00034
00035 import exceptions
00036 import json
00037 import httplib
00038 import os
00039 import types
00040 import urllib
00041
00042 class MiniMaxClientException(exceptions.Exception):
00043 pass
00044
00045
00046
00047
00048 def GetMM2ConfigInJson(mm2name):
00049 """
00050 Read the configuration information from a named Mini Maxwell.
00051 Return a structure
00052
00053 The parts of the structure are these:
00054 jdata[0] - Data Version
00055 jdata[1] - Timestamp
00056 jdata[2] - Full Configuration dictionary
00057
00058 The parts of the full configuration dictionary are:
00059 full_config["general"]
00060 full_config["upstream_impairments"]
00061 full_config["downstream_impairments"]
00062 full_config["upstream-filters"]
00063 full_config["downstream-filters"]
00064 full_config["filters"]
00065 """
00066 conn = httplib.HTTPConnection(mm2name)
00067 conn.request("GET", "/mm2/mpc/mm2.py/get_config_json")
00068 resp = conn.getresponse()
00069
00070 if (resp.status/100) != 2:
00071 raise Exception,resp.reason
00072 jdata = resp.read()
00073 conn.close()
00074 return jdata
00075
00076
00077
00078
00079 def GetMM2Config(mm2name):
00080 return json.loads(GetMM2ConfigInJson(mm2name))
00081
00082
00083
00084
00085 class BandSettings(object):
00086
00087 MM_MAXRATE = 100000000
00088
00089 MM_DELAY_DISTRIBUTIONS = ("none", "normal", "pareto", "paretonormal",
00090 "experimental")
00091
00092 PCNTFMT = "2.5f"
00093
00094 SetProcs = {
00095 "delay_amount": "SetDelayAmount",
00096 "delay_variation": "SetDelayVariation",
00097 "delay_distribution": "SetDelayDistribution",
00098 "delay_correlation": "SetDelayCorrelation",
00099 "delay_reorder": "SetDelayReorder",
00100 "drop_amount": "SetDropAmount",
00101 "drop_correlation": "SetDropCorrelation",
00102 "duplication_amount": "SetDupAmount",
00103 "duplication_correlation": "SetDupCorrelation",
00104 "reorder_gap": "SetReorderGap",
00105 "reorder_correlation": "SetReorderCorrelation",
00106 "reorder_amount": "SetReorderAmount",
00107 "bitrate_limit": "SetRateLimit",
00108 "corruption_amount": "SetCorruptionAmount",
00109 "corruption_correlation": "SetCorruptionCorrelation"
00110 }
00111
00112 def __init__(self, bandnumber, leftflag):
00113 """
00114 @param bandnumber: Band number, an integer in range 1..5
00115 @type bandnumber: int or long
00116 @param leftflag: True if LAN-A to LAN-B, false if LAN-B to LAN-A
00117 @type leftflag: bool
00118 """
00119 if (not isinstance(bandnumber, (types.IntType, types.LongType))) or \
00120 (bandnumber < 1) or (bandnumber > 5):
00121 raise MiniMaxClientException, "Band number not integer in range 1..5"
00122
00123 if not isinstance(leftflag, types.BooleanType):
00124 raise MiniMaxClientException, "Left/right flag not a boolean"
00125
00126 self.__BandNumber = bandnumber
00127 self.__LeftFlag = leftflag
00128
00129 self.SetDefaults()
00130
00131
00132
00133
00134 @property
00135 def BandNumber(self):
00136 return self.__BandNumber
00137
00138 @property
00139 def LeftFlag(self):
00140 return self.__LeftFlag
00141
00142 @property
00143 def DelayAmount(self):
00144 return self.__DelayAmount
00145
00146 @property
00147 def DelayVariation(self):
00148 return self.__DelayVariation
00149
00150 @property
00151 def DelayCorrelation(self):
00152 return self.__DelayCorrelation
00153
00154 @property
00155 def DelayDistribution(self):
00156 return self.__DelayDistribution
00157
00158 @property
00159 def DelayReorder(self):
00160 return self.__DelayReorder
00161
00162 @property
00163 def DropAmount(self):
00164 return self.__DropAmount
00165
00166 @property
00167 def DropCorrelation(self):
00168 return self.__DropCorrelation
00169
00170 @property
00171 def DupAmount(self):
00172 return self.__DupAmount
00173
00174 @property
00175 def DupCorrelation(self):
00176 return self.__DupCorrelation
00177
00178 @property
00179 def ReorderGap(self):
00180 return self.__ReorderGap
00181
00182 @property
00183 def ReorderAmount(self):
00184 return self.__ReorderAmount
00185
00186 @property
00187 def ReorderCorrelation(self):
00188 return self.__ReorderCorrelation
00189
00190 @property
00191 def CorruptionAmount(self):
00192 return self.__CorruptionAmount
00193
00194 @property
00195 def CorruptionCorrelation(self):
00196 return self.__CorruptionCorrelation
00197
00198 @property
00199 def RateLimit(self):
00200 return self.__RateLimit
00201
00202
00203
00204
00205 def Validate(self):
00206 if (self.__DelayVariation < 0) or (self.__DelayVariation > self.__DelayAmount):
00207 raise MiniMaxClientException, "Delay Variation not in range 0 .. Delay Amount"
00208 return True
00209
00210
00211
00212
00213 def SetDefaults(self):
00214
00215 self.__DelayAmount = 0
00216 self.__DelayVariation = 0
00217 self.__DelayCorrelation = 0
00218 self.__DelayDistribution = "none"
00219 self.__DelayReorder = False
00220 self.__DropAmount = 0
00221 self.__DropCorrelation = 0
00222 self.__DupAmount = 0
00223 self.__DupCorrelation = 0
00224 self.__ReorderGap = 0
00225 self.__ReorderAmount = 0
00226 self.__ReorderCorrelation = 0
00227 self.__CorruptionAmount = 0
00228 self.__CorruptionCorrelation = 0
00229 self.__RateLimit = self.__class__.MM_MAXRATE
00230
00231 def SetDelayAmount(self, val):
00232 if (val < 0) or (val > 60000):
00233 raise MiniMaxClientException, "Delay Amount not in range 0 .. 60000"
00234 self.__DelayAmount = val
00235
00236 def SetDelayVariation(self, val):
00237 if (val < 0) or (val > 60000):
00238 raise MiniMaxClientException, "Delay Amount not in range 0 .. 60000"
00239 self.__DelayVariation = val
00240
00241 def SetDelayCorrelation(self, val):
00242 if (val < 0.0) or (val > 100.0):
00243 raise MiniMaxClientException, "Delay Correlation not in range 0 .. 100"
00244 self.__DelayCorrelation = val
00245
00246 def SetDelayDistribution(self, val):
00247 lcval = val.lower()
00248 if val not in self.__class__.MM_DELAY_DISTRIBUTIONS:
00249 raise MiniMaxClientException, "Delay distribution must be one of %s" % \
00250 str(self.__class__.MM_DELAY_DISTRIBUTIONS)
00251 self.__DelayDistribution = val
00252
00253 def SetDelayReorder(self, val):
00254 self.__DelayReorder = bool(val)
00255
00256 def SetDropAmount(self, val):
00257 if (val < 0.0) or (val > 100.0):
00258 raise MiniMaxClientException, "Drop Amount not in range 0 .. 100"
00259 self.__DropAmount = val
00260
00261 def SetDropCorrelation(self, val):
00262 if (val < 0.0) or (val > 100.0):
00263 raise MiniMaxClientException, "Drop Correlation not in range 0 .. 100"
00264 self.__DropCorrelation = val
00265
00266 def SetDupAmount(self, val):
00267 if (val < 0.0) or (val > 100.0):
00268 raise MiniMaxClientException, "Duplication Amount not in range 0 .. 100"
00269 self.__DupAmount = val
00270
00271 def SetDupCorrelation(self, val):
00272 if (val < 0.0) or (val > 100.0):
00273 raise MiniMaxClientException, "Duplication Correlation not in range 0 .. 100"
00274 self.__DupCorrelation = val
00275
00276 def SetReorderGap(self, val):
00277 if (val < 0) or (val > 1024):
00278 raise MiniMaxClientException, "Reorder Gap not in range 0 .. 1024"
00279 self.__ReorderGap = val
00280
00281 def SetReorderAmount(self, val):
00282 if (val < 0.0) or (val > 100.0):
00283 raise MiniMaxClientException, "Reorder Amount not in range 0 .. 100"
00284 self.__ReorderAmount = val
00285
00286 def SetReorderCorrelation(self, val):
00287 if (val < 0.0) or (val > 100.0):
00288 raise MiniMaxClientException, "Reorder Correlation not in range 0 .. 100"
00289 self.__ReorderCorrelation = val
00290
00291 def SetCorruptionAmount(self, val):
00292 if (val < 0.0) or (val > 100.0):
00293 raise MiniMaxClientException, "Corruption Amount not in range 0 .. 100"
00294 self.__CorruptionAmount = val
00295
00296 def SetCorruptionCorrelation(self, val):
00297 if (val < 0.0) or (val > 100.0):
00298 raise MiniMaxClientException, "Corruption Correlation not in range 0 .. 100"
00299 self.__CorruptionCorrelation = val
00300
00301 def SetRateLimit(self, val):
00302 if (val < 128) or (val > self.__class__.MM_MAXRATE):
00303 raise MiniMaxClientException, "Rate Limit not in range 128 .. %u" % \
00304 self.__class__.MM_MAXRATE
00305 self.__RateLimit = val
00306
00307 def SetByCnfigName(self, name, val):
00308 """
00309 Set an item using the name used in the Mini Maxwell configuration file.
00310 """
00311 try:
00312 (self.__class__.__dict__[self.__class__.SetProcs[name]])(self, val)
00313 except:
00314 pass
00315
00316 def AsDict(self):
00317 if self.__LeftFlag:
00318 snum = (2 * self.__BandNumber) - 1
00319 else:
00320 snum = 2 * self.__BandNumber
00321 snumstr = str(snum)
00322 tdict = { \
00323 "DELAY_AMOUNT_" + snumstr: str(self.__DelayAmount),
00324 "DELAY_VAR_" + snumstr: str(self.__DelayVariation),
00325 "DELAY_CORR_" + snumstr: format(self.__DelayCorrelation, self.__class__.PCNTFMT),
00326 "DELAY_CURVE_" + snumstr: self.__DelayDistribution.lower(),
00327 "GAP_" + snumstr: self.__ReorderGap,
00328 "REORDER_AMOUNT_" + snumstr: format(self.__ReorderAmount, self.__class__.PCNTFMT),
00329 "REORDER_CORR_" + snumstr: format(self.__ReorderCorrelation, self.__class__.PCNTFMT),
00330 "DROP_AMOUNT_" + snumstr: format(self.__DropAmount, self.__class__.PCNTFMT),
00331 "DROP_CORR_" + snumstr: format(self.__DropCorrelation, self.__class__.PCNTFMT),
00332 "DUP_AMOUNT_" + snumstr: format(self.__DupAmount, self.__class__.PCNTFMT),
00333 "DUP_CORR_" + snumstr: format(self.__DupCorrelation, self.__class__.PCNTFMT),
00334 "CORRUPTION_AMOUNT_" + snumstr: format(self.__CorruptionAmount, self.__class__.PCNTFMT),
00335 "CORRUPTION_CORR_" + snumstr: format(self.__CorruptionCorrelation, self.__class__.PCNTFMT),
00336 "RATE_LIMIT_" + snumstr: str(self.__RateLimit)
00337 }
00338
00339 if self.__DelayReorder:
00340 tdict["DELAY_REORDER_" + snumstr] = str(self.__DelayReorder)
00341 return tdict
00342
00343
00344
00345
00346 class Bands(object):
00347 def __init__(self):
00348 self.__LeftBands = (
00349 BandSettings(1, True), BandSettings(2, True), BandSettings(3, True),
00350 BandSettings(4, True), BandSettings(5, True))
00351
00352 self.__RightBands = (
00353 BandSettings(1, False), BandSettings(2, False), BandSettings(3, False),
00354 BandSettings(4, False), BandSettings(5, False))
00355
00356 def GetLeftBand(self, bnum):
00357 if (bnum < 1) or (bnum > 5):
00358 raise MiniMaxClientException, "Band number must be in in range 1..5"
00359 return self.__LeftBands[bnum-1]
00360
00361 def GetRightBand(self, bnum):
00362 if (bnum < 1) or (bnum > 5):
00363 raise MiniMaxClientException, "Band number must be in in range 1..5"
00364 return self.__RightBands[bnum-1]
00365
00366 def GetBand(self, bnum, leftflag):
00367 if (bnum < 1) or (bnum > 5):
00368 raise MiniMaxClientException, "Band number must be in in range 1..5"
00369 if leftflag:
00370 return self.__LeftBands[bnum-1]
00371 return self.__RightBands[bnum-1]
00372
00373 def Validate(self):
00374 for bnd in self.__LeftBands:
00375 if not bnd.Validate():
00376 return False
00377 for bnd in self.__RightBands:
00378 if not bnd.Validate():
00379 return False
00380 return True
00381
00382 def SetDefaults(self):
00383 for bnd in self.__LeftBands:
00384 bnd.SetDefaults()
00385 for bnd in self.__RightBands:
00386 bnd.SetDefaults()
00387
00388 def SetBandToDefaults(self, bnum, leftflag):
00389 self.GetBand(bnum, leftflag).SetDefaults()
00390
00391 def SetDelayAmount(self, bnum, leftflag, val):
00392 self.GetBand(bnum, leftflag).SetDelayAmount(val)
00393
00394 def SetDelayVariation(self, bnum, leftflag, val):
00395 self.GetBand(bnum, leftflag).SetDelayVariation(val)
00396
00397 def SetDelayCorrelation(self, bnum, leftflag, val):
00398 self.GetBand(bnum, leftflag).SetDelayCorrelation(val)
00399
00400 def SetDelayDistribution(self, bnum, leftflag, val):
00401 self.GetBand(bnum, leftflag).SetDelayDistribution(val)
00402
00403 def SetDelayReorder(self, bnum, leftflag, val):
00404 self.GetBand(bnum, leftflag).SetDelayReorder(val)
00405
00406 def SetDropAmount(self, bnum, leftflag, val):
00407 self.GetBand(bnum, leftflag).SetDropAmount(val)
00408
00409 def SetDropCorrelation(self, bnum, leftflag, val):
00410 self.GetBand(bnum, leftflag).SetDropCorrelation(val)
00411
00412 def SetDupAmount(self, bnum, leftflag, val):
00413 self.GetBand(bnum, leftflag).SetDupAmount(val)
00414
00415 def SetDupCorrelation(self, bnum, leftflag, val):
00416 self.GetBand(bnum, leftflag).SetDupCorrelation(val)
00417
00418 def SetReorderGap(self, bnum, leftflag, val):
00419 self.GetBand(bnum, leftflag).SetReorderGap(val)
00420
00421 def SetReorderAmount(self, bnum, leftflag, val):
00422 self.GetBand(bnum, leftflag).SetReorderAmount(val)
00423
00424 def SetReorderCorrelation(self, bnum, leftflag, val):
00425 self.GetBand(bnum, leftflag).SetReorderCorrelation(val)
00426
00427 def SetCorruptionAmount(self, bnum, leftflag, val):
00428 self.GetBand(bnum, leftflag).SetCorruptionAmount(val)
00429
00430 def SetCorruptionCorrelation(self, bnum, leftflag, val):
00431 self.GetBand(bnum, leftflag).SetCorruptionCorrelation(val)
00432
00433 def SetRateLimit(self, bnum, leftflag, val):
00434 self.GetBand(bnum, leftflag).SetRateLimit(val)
00435
00436 def AsDict(self):
00437 rdict = {}
00438 for ndx in range(5):
00439 rdict.update(self.__LeftBands[ndx].AsDict())
00440 rdict.update(self.__RightBands[ndx].AsDict())
00441 return rdict
00442
00443
00444
00445
00446 def GetCurrentBands(mm2name):
00447 """
00448 Construct a Bands object using the current configuration on
00449 a named Mini Maxwell
00450 """
00451 bnds = Bands()
00452
00453 current = GetMM2Config(mm2name)
00454 full_config = current[2]
00455
00456 downstream_impairs = full_config["downstream_impairments"]
00457
00458 upstream_impairs = full_config["upstream_impairments"]
00459
00460 bnum = 1
00461 for itm in downstream_impairs:
00462 bnd = bnds.GetLeftBand(bnum)
00463 for imp in itm.items():
00464 bnd.SetByCnfigName(imp[0], imp[1])
00465 bnum += 1
00466
00467 bnum = 1
00468 for itm in upstream_impairs:
00469 bnd = bnds.GetRightBand(bnum)
00470 for imp in itm.items():
00471 bnd.SetByCnfigName(imp[0], imp[1])
00472 bnum += 1
00473
00474 return bnds
00475
00476
00477
00478
00479 def ChangeBandsOnMM(bandsobj, mm2host):
00480 """
00481 @param bandsobj: A Bands object containing the desired impairment settings.
00482 @type bandsobj: Bands
00483 @param mm2host: The hostname or IP address of the Mini Maxwell.
00484 @type mm2host: string
00485 """
00486
00487 bandsobj.Validate()
00488
00489 conn = httplib.HTTPConnection(mm2host)
00490 bdict = bandsobj.AsDict()
00491 bdict["SUBMIT_FLOWIMPAIR_BUTTON"] = "Submit"
00492 params = urllib.urlencode(bdict)
00493 headers = {"Content-type": "application/x-www-form-urlencoded",
00494 "Accept": "text/plain"}
00495 conn.request("POST", "/mm2/mpc/mm2.py/process_flows", params, headers)
00496 resp = conn.getresponse()
00497
00498 if (resp.status/100) != 2:
00499 raise Exception,resp.reason
00500 data = resp.read()
00501 conn.close()
00502 return
00503
00504
00505
00506
00507 if __name__ == "__main__":
00508
00509 if len(sys.argv) != 2:
00510 print "Usage: %s <minimaxwell-hostname-or-ip-address>" % sys.argv[0]
00511 print "Aborting"
00512 sys.exit(1)
00513
00514 mm2name = sys.argv[1]
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539 MM_REV = 12
00540
00541 if MM_REV >= 12:
00542
00543 try:
00544 bnds = GetCurrentBands(mm2name)
00545 except:
00546 bnds = Bands()
00547
00548 else:
00549
00550
00551
00552
00553
00554
00555 bnds = Bands()
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601 bnds.SetDelayAmount(5, True, 100)
00602 bnds.SetDelayVariation(5, True, 10)
00603 bnds.SetDelayReorder(5, True, True)
00604 bnds.SetDelayReorder(5, False, False)
00605
00606
00607
00608
00609 ChangeBandsOnMM(bnds, mm2name)