Ignore:
Timestamp:
Apr 1, 2020, 12:43:07 AM (4 years ago)
Author:
chronos
Message:
  • Added: New SpeedLimit table to support network speed limit groups.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Modules/NetworkConfigRouterOS/Generators/Queue.php

    r831 r869  
    11<?php
     2
     3class SpeedLimit
     4{
     5  var $Min;
     6  var $Max;
     7  var $PacketMark;
     8
     9  function __construct(int $Min, int $Max, int $PacketMark = null)
     10  {
     11    $this->Min = $Min;
     12    $this->Max = $Max;
     13    $this->PacketMark = $PacketMark;
     14  }
     15
     16  function Print()
     17  {
     18    $Output = '(Min: '.$this->Min.' Max: '.$this->Max;
     19    if ($this->PacketMark != null) $Output .= ' PacketMark: '.$this->PacketMark;
     20    $Output .= ')';
     21    return $Output;
     22  }
     23}
     24
     25class SpeedLimitItem
     26{
     27  var $Name;
     28  var $Parent;
     29  var $LimitIn;
     30  var $LimitOut;
     31  var $SubItems;
     32
     33  function __construct(string $Name, SpeedLimitItem $Parent = null)
     34  {
     35    $this->Name = $Name;
     36    $this->Parent = $Parent;
     37    if ($Parent != null) $Parent->SubItems->Add($this);
     38    $this->SubItems = new SpeedLimitItems();
     39  }
     40
     41  function Print(int $Indent = 0): string
     42  {
     43    $Output = str_repeat(' ', $Indent * 2).$this->Name.' In:'.$this->LimitIn->Print().' Out:'.$this->LimitOut->Print()."\n";
     44    $Output .= $this->SubItems->Print($Indent + 1);
     45    return $Output;
     46  }
     47
     48  function CheckName($Name, &$UsedNames)
     49  {
     50    if(in_array($Name, $UsedNames)) die("\n".'Duplicate name: '.$Name);
     51      else $UsedNames[] = $Name;
     52  }
     53
     54  function GetCommands(&$UsedNames = null)
     55  {
     56    if ($UsedNames == null) $UsedNames = array();
     57
     58    $this->CheckName($this->Name.'-out', $UsedNames);
     59    $Item = array('name' => $this->Name.'-out', 'limit-at' => $this->LimitOut->Min, 'max-limit' => $this->LimitOut->Max,
     60      'parent' => $this->GetParentName('-out'), 'packet-mark' => $this->LimitOut->PacketMark);
     61    if ($this->LimitOut->PacketMark != null) $Item['packet-mark'] = $this->LimitOut->PacketMark;
     62    $Output[] = $Item;
     63
     64    $this->CheckName($this->Name.'-in', $UsedNames);
     65    $Item = array('name' => $this->Name.'-in', 'limit-at' => $this->LimitIn->Min, 'max-limit' => $this->LimitIn->Max,
     66      'parent' => $this->GetParentName('-in'));
     67    if ($this->LimitIn->PacketMark != null) $Item['packet-mark'] = $this->LimitIn->PacketMark;
     68    $Output[] = $Item;
     69
     70    $Output = array_merge($Output, $this->SubItems->GetCommands($UsedNames));
     71    return $Output;
     72  }
     73
     74  function GetParentName(string $Suffix)
     75  {
     76    if ($this->Parent != null) return $this->Parent->Name.$Suffix;
     77    return 'global';
     78  }
     79
     80  function UpdateMinSpeeds()
     81  {
     82    if (($this->LimitIn->Min == 0) or ($this->LimitOut->Min == 0))
     83    {
     84      $SpeedMinOut = 0;
     85      $SpeedMinIn = 0;
     86      foreach ($this->SubItems->Items as $Index => $Item)
     87      {
     88        $this->SubItems->Items[$Index]->UpdateMinSpeeds();
     89        $SpeedMinOut += $this->SubItems->Items[$Index]->LimitOut->Min;
     90        $SpeedMinIn += $this->SubItems->Items[$Index]->LimitIn->Min;
     91      }
     92      if ($SpeedMinOut > $this->LimitOut->Max) $SpeedMinOut = $this->LimitOut->Max;
     93      if ($SpeedMinIn > $this->LimitIn->Max) $SpeedMinIn = $this->LimitIn->Max;
     94      $this->LimitOut->Min = $SpeedMinOut;
     95      $this->LimitIn->Min = $SpeedMinIn;
     96    }
     97  }
     98}
     99
     100class SpeedLimitItems extends GenericList
     101{
     102  function AddNew(string $Name, SpeedLimitItem $Parent = null)
     103  {
     104    $Item = new SpeedLimitItem($Name, $Parent);
     105    $Item->LimitIn = new SpeedLimit();
     106    $Item->LimitOut = new SpeedLimit();
     107    $this->Items[] = $Item;
     108    return $Item;
     109  }
     110
     111  function Print(int $Indent = 0): string
     112  {
     113    $Output = '';
     114    foreach ($this->Items as $SubItem)
     115    {
     116      $Output .= $SubItem->Print($Indent);
     117    }
     118    return $Output;
     119  }
     120
     121  function GetCommands(&$UsedNames)
     122  {
     123    $Output = array();
     124    foreach ($this->Items as $SubItem)
     125    {
     126      $Output = array_merge($Output, $SubItem->GetCommands($UsedNames));
     127    }
     128    return $Output;
     129  }
     130}
    2131
    3132class ConfigRouterOSQueue extends NetworkConfigItem
     
    6135  var $Devices;
    7136  var $QueueItems;
    8 
    9   function CheckName($Name)
    10   {
    11     if(in_array($Name, $this->UsedNames)) die("\n".'Duplicate name: '.$Name);
    12       else $this->UsedNames[] = $Name;
    13   }
     137  var $SpeedLimits;
    14138
    15139  function Run()
     
    29153
    30154    // Generate traffic shaping rules
    31     //$TotalMaxSpeedIn = 4048; //$RealMaxSpeed; //1536;
    32     //TotalMaxSpeedOut = 3048; //$RealMaxSpeed; //1536;
    33     //$UsersMaxSpeedIn = 1900; //$MaxSpeed;
    34     //$UsersMaxSpeedOut = 1900; //$MaxSpeed;
    35 
    36155    $InDivider = 1;
    37156    $OutDivider = 1;
     
    49168
    50169    $DbResult = $this->Database->select('Service', '*', '(`ChangeAction` IS NULL) AND (`Id`='.TARIFF_FREE.')');
    51     if($DbResult->num_rows == 1)
     170    if ($DbResult->num_rows == 1)
    52171    {
    53172      $Service = $DbResult->fetch_array();
     
    55174    } else $FreeInetSpeed = 0;
    56175
    57     $ItemsQueue = array();
    58 
    59176    // Root of tree and main limit
    60     $ItemsQueue[] = array('name' => 'main-out', 'limit-at' => $UsersMaxSpeedIn, 'max-limit' => $UsersMaxSpeedIn, 'parent' => 'global');
    61     $ItemsQueue[] = array('name' => 'main-in', 'limit-at' => $UsersMaxSpeedOut, 'max-limit' => $UsersMaxSpeedOut, 'parent' => 'global');
     177    $Main = new SpeedLimitItem('main');
     178    $Main->LimitIn = new SpeedLimit(0, $UsersMaxSpeedIn);
     179    $Main->LimitOut = new SpeedLimit(0, $UsersMaxSpeedOut);
     180
     181    $this->LoadSpeedLimits($Main);
    62182
    63183    // Slow free internet
    64     $PacketMark = GetMarkByComment('free-out');
    65     $ItemsQueue[] = array('name' => 'free-out', 'limit-at' => $FreeInetSpeed, 'max-limit' => $FreeInetSpeed, 'parent' => 'main-out', 'packet-mark' => $PacketMark);
    66     $PacketMark = GetMarkByComment('free-in');
    67     $ItemsQueue[] = array('name' => 'free-in', 'limit-at' => $FreeInetSpeed, 'max-limit' => $FreeInetSpeed, 'parent' => 'main-in', 'packet-mark' => $PacketMark);
     184    $Free = new SpeedLimitItem('free', $Main);
     185    $Free->LimitIn = new SpeedLimit($FreeInetSpeed, $FreeInetSpeed, GetMarkByComment('free-in'));
     186    $Free->LimitOut = new SpeedLimit($FreeInetSpeed, $FreeInetSpeed, GetMarkByComment('free-out'));
    68187
    69188    // Process users
     
    74193      $ServiceIndex = 1;
    75194      echo('Zákazník '.$Member['Name']."\n");
    76       $DbResult4 = $this->Database->query('SELECT `Service`.*, `ServiceCustomerRel`.`Id` AS `RelId` FROM `ServiceCustomerRel` '.
     195      $DbResult4 = $this->Database->query('SELECT `Service`.*, `ServiceCustomerRel`.`Id` AS `RelId`, '.
     196        '`ServiceCustomerRel`.`SpeedLimit` AS `SpeedLimit` FROM `ServiceCustomerRel` '.
    77197        'JOIN `Service` ON `Service`.`Id` = `ServiceCustomerRel`.`Service` '.
    78198        'WHERE (`ServiceCustomerRel`.`Customer` = '.$Member['Id'].') AND (`ServiceCustomerRel`.`ChangeAction` IS NULL) '.
     
    86206        $UserMaxSpeedIn = round($Service['InternetSpeedMax'] / $InDivider);
    87207        $UserMaxSpeedOut = round($Service['InternetSpeedMax'] / $OutDivider);
    88         $ItemsQueue[] = array('name' => $MemberName.'-out', 'limit-at' => $SpeedIn, 'max-limit' => $UserMaxSpeedIn, 'parent' => 'main-out');
    89         $ItemsQueue[] = array('name' => $MemberName.'-in', 'limit-at' => $SpeedOut, 'max-limit' => $UserMaxSpeedOut, 'parent' => 'main-in');
    90         $this->CheckName($MemberName.'-out');
    91         $this->CheckName($MemberName.'-in');
     208
     209        // Reduce max speed by speed limits
     210        $SpeedLimitItem = $Main;
     211        if ($Service['SpeedLimit'] != null)
     212        {
     213          $SpeedLimit = $this->SpeedLimits[$Service['SpeedLimit']];
     214          $SpeedLimitItem = $SpeedLimit['SpeedLimitItem'];
     215          if ($UserMaxSpeedIn > $SpeedLimit['SpeedMaxIn']) $UserMaxSpeedIn = $SpeedLimit['SpeedMaxIn'];
     216          if ($UserMaxSpeedOut > $SpeedLimit['SpeedMaxOut']) $UserMaxSpeedOut = $SpeedLimit['SpeedMaxOut'];
     217          while ($SpeedLimit['Parent'] != null)
     218          {
     219            $SpeedLimit = $this->SpeedLimits[$SpeedLimit['Parent']];
     220            if ($UserMaxSpeedIn > $SpeedLimit['SpeedMaxIn']) $UserMaxSpeedIn = $SpeedLimit['SpeedMaxIn'];
     221            if ($UserMaxSpeedOut > $SpeedLimit['SpeedMaxOut']) $UserMaxSpeedOut = $SpeedLimit['SpeedMaxOut'];
     222          }
     223        }
     224
     225        $LimitMember = new SpeedLimitItem($MemberName, $SpeedLimitItem);
     226        $LimitMember->LimitIn = new SpeedLimit($SpeedIn, $UserMaxSpeedIn);
     227        $LimitMember->LimitOut = new SpeedLimit($SpeedOut, $UserMaxSpeedOut);
    92228
    93229        $Filter = '(`Used` = 1) AND (`Service` = '.$Service['RelId'].')';
     
    111247          while($Interface = $DbResult3->fetch_assoc())
    112248          {
    113             $Name = $Device['Name'];
    114             if($Interface['Name'] != '') $Name .= '-'.$Interface['Name'];
    115             $Name = RouterOSIdent($Name);
    116             echo($Name.', ');
    117             $PacketMark = GetMarkByComment($Name.'-out');
    118             $ItemsQueue[] = array('name' => $Name.'-out', 'limit-at' => $HostSpeedIn, 'max-limit' => $UserMaxSpeedIn, 'parent' => $MemberName.'-out', 'packet-mark' => $PacketMark);
    119             $PacketMark = GetMarkByComment($Name.'-in');
    120             $ItemsQueue[] = array('name' => $Name.'-in', 'limit-at' => $HostSpeedOut, 'max-limit' => $UserMaxSpeedOut, 'parent' => $MemberName.'-in', 'packet-mark' => $PacketMark);
    121             $this->CheckName($Name.'-out');
    122             $this->CheckName($Name.'-in');
     249            $DeviceName = $Device['Name'];
     250            if($Interface['Name'] != '') $DeviceName .= '-'.$Interface['Name'];
     251            $DeviceName = RouterOSIdent($DeviceName);
     252            echo($DeviceName.', ');
     253            $LimitDevice = new SpeedLimitItem($DeviceName, $LimitMember);
     254            $LimitDevice->LimitIn = new SpeedLimit($HostSpeedIn, $UserMaxSpeedIn, GetMarkByComment($DeviceName.'-in'));
     255            $LimitDevice->LimitOut = new SpeedLimit($HostSpeedOut, $UserMaxSpeedOut, GetMarkByComment($DeviceName.'-out'));
    123256          }
    124257        }
     
    127260        while($Subnet = $DbResult2->fetch_assoc())
    128261        {
    129           $Subnet['Name'] = RouterOSIdent('subnet-'.$Subnet['Name']);
    130           echo($Subnet['Name'].', ');
    131           $PacketMark = GetMarkByComment($Subnet['Name'].'-out');
    132           $ItemsQueue[] = array('name' => $Subnet['Name'].'-out', 'limit-at' => $HostSpeedIn, 'max-limit' => $UserMaxSpeedIn, 'parent' => $MemberName.'-out', 'packet-mark' => $PacketMark);
    133           $PacketMark = GetMarkByComment($Subnet['Name'].'-in');
    134           $ItemsQueue[] = array('name' => $Subnet['Name'].'-in', 'limit-at' => $HostSpeedOut, 'max-limit' => $UserMaxSpeedOut, 'parent' => $MemberName.'-in', 'packet-mark' => $PacketMark);
    135           $this->CheckName($Subnet['Name'].'-out');
    136           $this->CheckName($Subnet['Name'].'-in');
     262          $SubnetName = RouterOSIdent('subnet-'.$Subnet['Name']);
     263          echo($SubnetName.', ');
     264          $LimitSubnet = new SpeedLimitItem($SubnetName, $LimitMember);
     265          $LimitSubnet->LimitIn = new SpeedLimit($HostSpeedIn, $UserMaxSpeedIn, GetMarkByComment($SubnetName.'-in'));
     266          $LimitSubnet->LimitOut = new SpeedLimit($HostSpeedOut, $UserMaxSpeedOut, GetMarkByComment($SubnetName.'-out'));
    137267        }
    138268        echo("\n");
     
    140270      }
    141271    }
     272    $Main->UpdateMinSpeeds();
     273    echo($Main->Print());
     274    $ItemsQueue = $Main->GetCommands();
     275    //print_r($ItemsQueue);
     276    //die();
    142277
    143278    //print_r($ItemsQueue);
    144279    $Routerboard->ListUpdate($PathQueue, array('name', 'limit-at', 'max-limit', 'parent', 'packet-mark'), $ItemsQueue, array(), true);
     280  }
     281
     282  function BuildSpeedLimit(&$SpeedLimit, $TopSpeedLimitItem)
     283  {
     284    $SpeedLimitName = $SpeedLimit['Name'].'-grp';
     285    $SpeedLimitName = RouterOSIdent($SpeedLimitName);
     286    echo($SpeedLimitName.', ');
     287
     288    $SpeedLimitItem = new SpeedLimitItem($SpeedLimitName, $TopSpeedLimitItem);
     289    $SpeedLimitItem->LimitIn = new SpeedLimit(0, $SpeedLimit['SpeedMaxIn']);
     290    $SpeedLimitItem->LimitOut = new SpeedLimit(0, $SpeedLimit['SpeedMaxOut']);
     291    $SpeedLimit['SpeedLimitItem'] = $SpeedLimitItem;
     292
     293    foreach ($SpeedLimit['Childs'] as $ChildId)
     294    {
     295      $this->BuildSpeedLimit($this->SpeedLimits[$ChildId], $SpeedLimitItem);
     296    }
     297  }
     298
     299  function LoadSpeedLimits($SpeedLimitItem)
     300  {
     301    echo('Limit groups: ');
     302    // Load all speed limits
     303    $this->SpeedLimits = array();
     304    $DbResult = $this->Database->query('SELECT * FROM `NetworkSpeedLimit`');
     305    while ($SpeedLimit = $DbResult->fetch_array())
     306    {
     307      $SpeedLimit['Childs'] = array();
     308      $this->SpeedLimits[$SpeedLimit['Id']] = $SpeedLimit;
     309    }
     310
     311    // Calculate childs from parent
     312    foreach ($this->SpeedLimits as $Index => $SpeedLimit)
     313    {
     314      if ($SpeedLimit['Parent'] != null) $this->SpeedLimits[$SpeedLimit['Parent']]['Childs'][] = $Index;
     315    }
     316
     317    // Build speed limits from top
     318    foreach ($this->SpeedLimits as $Index => $SpeedLimit)
     319    {
     320      if ($SpeedLimit['Parent'] == null)
     321      {
     322        $this->BuildSpeedLimit($this->SpeedLimits[$Index], $SpeedLimitItem);
     323      }
     324    }
     325    echo("\n");
    145326  }
    146327
     
    257438  }
    258439
    259   function BuildQueueItems($DeviceId)
     440  function BuildQueueItems($DeviceId, $SpeedLimitParent)
    260441  {
    261442    $Device = $this->Devices[$DeviceId];
    262443
    263444    // Device
    264     if($Device['Parent'] != 0)
    265       $ParentQueueName = $this->Devices[$Device['Parent']]['QueueName'];
    266       else $ParentQueueName = 'main';
    267     $Name = $Device['Name'];
    268     $Name = RouterOSIdent($Name);
    269     $DeviceName = $Name;
    270     $this->Devices[$DeviceId]['QueueName'] = $Name;
    271     echo($Name.', ');
    272     $PacketMark = GetMarkByComment($Name.'-out');
    273     $this->ItemsQueue[] = array('name' => $Name.'-out', 'limit-at' => $Device['MinSpeed'],
    274       'max-limit' => $Device['MaxSpeed'], 'parent' => $ParentQueueName.'-out',
    275       'packet-mark' => $PacketMark);
    276     $PacketMark = GetMarkByComment($Name.'-in');
    277     $this->ItemsQueue[] = array('name' => $Name.'-in', 'limit-at' => $Device['MinSpeed'],
    278       'max-limit' => $Device['MaxSpeed'], 'parent' => $ParentQueueName.'-in',
    279       'packet-mark' => $PacketMark);
    280     $this->CheckName($Name.'-out');
    281     $this->CheckName($Name.'-in');
     445    $DeviceName = $Device['Name'];
     446    $DeviceName = RouterOSIdent($DeviceName);
     447    $this->Devices[$DeviceId]['QueueName'] = $DeviceName;
     448    echo($DeviceName.', ');
     449
     450    $LimitDevice = new SpeedLimitItem($DeviceName, $SpeedLimitParent);
     451    $LimitDevice->LimitIn = new SpeedLimit($Device['MinSpeed'], $Device['MaxSpeed'], GetMarkByComment($DeviceName.'-in'));
     452    $LimitDevice->LimitOut = new SpeedLimit($Device['MinSpeed'], $Device['MaxSpeed'], GetMarkByComment($DeviceName.'-out'));
    282453
    283454    // Interfaces
     
    286457    while($Interface = $DbResult3->fetch_assoc())
    287458    {
    288       $Name = $Device['Name'];
    289       if($Interface['Name'] != '') $Name .= '-'.$Interface['Name'];
    290         else $Name .= '-';
    291       $Name = RouterOSIdent($Name);
    292       echo($Name.', ');
    293       $PacketMark = GetMarkByComment($Name.'-out');
    294       $this->ItemsQueue[] = array('name' => $Name.'-out', 'limit-at' => round($Device['MinSpeed'] / $IntCount),
    295         'max-limit' => $Device['MaxSpeed'], 'parent' => $DeviceName.'-out',
    296         'packet-mark' => $PacketMark);
    297       $PacketMark = GetMarkByComment($Name.'-in');
    298       $this->ItemsQueue[] = array('name' => $Name.'-in', 'limit-at' => round($Device['MinSpeed'] / $IntCount),
    299         'max-limit' => $Device['MaxSpeed'], 'parent' => $DeviceName.'-in',
    300         'packet-mark' => $PacketMark);
    301       $this->CheckName($Name.'-out');
    302       $this->CheckName($Name.'-in');
     459      $InterfaceName = $Device['Name'];
     460      if($Interface['Name'] != '') $InterfaceName .= '-'.$Interface['Name'];
     461        else $InterfaceName .= '-';
     462      $InterfaceName = RouterOSIdent($InterfaceName);
     463      echo($InterfaceName.', ');
     464
     465      $LimitInterface = new SpeedLimitItem($InterfaceName, $LimitDevice);
     466      $LimitInterface->LimitIn = new SpeedLimit(round($Device['MinSpeed'] / $IntCount), $Device['MaxSpeed'], GetMarkByComment($InterfaceName.'-in'));
     467      $LimitInterface->LimitOut = new SpeedLimit(round($Device['MinSpeed'] / $IntCount), $Device['MaxSpeed'], GetMarkByComment($InterfaceName.'-out'));
    303468    }
    304469
     
    306471    foreach($Device['Childs'] as $DeviceChild)
    307472    {
    308       $this->BuildQueueItems($DeviceChild);
     473      $this->BuildQueueItems($DeviceChild, $LimitDevice);
    309474    }
    310475  }
     
    349514
    350515    // Root of tree and main limit
    351     $this->ItemsQueue[] = array('name' => 'main-out', 'limit-at' => $UsersMaxSpeedIn, 'max-limit' => $UsersMaxSpeedIn, 'parent' => 'global');
    352     $this->ItemsQueue[] = array('name' => 'main-in', 'limit-at' => $UsersMaxSpeedOut, 'max-limit' => $UsersMaxSpeedOut, 'parent' => 'global');
     516    $Main = new SpeedLimitItem('main');
     517    $Main->LimitIn = new SpeedLimit($UsersMaxSpeedIn, $UsersMaxSpeedIn);
     518    $Main->LimitOut = new SpeedLimit($UsersMaxSpeedOut, $UsersMaxSpeedOut);
    353519
    354520    // Slow free internet
    355     $PacketMark = GetMarkByComment('free-out');
    356     $this->ItemsQueue[] = array('name' => 'free-out', 'limit-at' => $FreeInetSpeed, 'max-limit' => $FreeInetSpeed, 'parent' => 'main-out', 'packet-mark' => $PacketMark);
    357     $PacketMark = GetMarkByComment('free-in');
    358     $this->ItemsQueue[] = array('name' => 'free-in', 'limit-at' => $FreeInetSpeed, 'max-limit' => $FreeInetSpeed, 'parent' => 'main-in', 'packet-mark' => $PacketMark);
    359 
    360     $this->BuildTree($this->System->Config['MainRouter']['DeviceId'], 140 * 1000 * 1000);
    361 
    362     $this->BuildQueueItems($this->System->Config['MainRouter']['DeviceId']);
    363 
    364     //print_r($this->ItemsQueue);
    365     $Routerboard->ListUpdate($PathQueue, array('name', 'limit-at', 'max-limit',
    366       'parent', 'packet-mark'), $this->ItemsQueue, array(), true);
     521    $Free = new SpeedLimitItem('free', $Main);
     522    $Free->LimitIn = new SpeedLimit($FreeInetSpeed, $FreeInetSpeed, GetMarkByComment('free-in'));
     523    $Free->LimitOut = new SpeedLimit($FreeInetSpeed, $FreeInetSpeed, GetMarkByComment('free-out'));
     524
     525    $this->BuildTree($this->System->Config['MainRouter']['DeviceId'], $UsersMaxSpeedIn);
     526    $this->BuildQueueItems($this->System->Config['MainRouter']['DeviceId'], $Main);
     527
     528    echo($Main->Print());
     529    //print_r($Main->GetCommands());
     530    die();
     531
     532    print_r($this->ItemsQueue);
     533    //$Routerboard->ListUpdate($PathQueue, array('name', 'limit-at', 'max-limit',
     534    //  'parent', 'packet-mark'), $this->ItemsQueue, array(), true);
    367535  }
    368536}
Note: See TracChangeset for help on using the changeset viewer.