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)