| 1 | <?php
|
|---|
| 2 |
|
|---|
| 3 | class SpeedLimit
|
|---|
| 4 | {
|
|---|
| 5 | public int $Min;
|
|---|
| 6 | public int $Max;
|
|---|
| 7 | public ?int $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(): string
|
|---|
| 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 |
|
|---|
| 25 | class SpeedLimitItem
|
|---|
| 26 | {
|
|---|
| 27 | public string $Name;
|
|---|
| 28 | public ?SpeedLimitItem $Parent;
|
|---|
| 29 | public SpeedLimit $LimitIn;
|
|---|
| 30 | public SpeedLimit $LimitOut;
|
|---|
| 31 | public bool $FixedSpeed;
|
|---|
| 32 | public SpeedLimitItems $SubItems;
|
|---|
| 33 |
|
|---|
| 34 | function __construct(string $Name, SpeedLimitItem $Parent = null)
|
|---|
| 35 | {
|
|---|
| 36 | $this->Name = $Name;
|
|---|
| 37 | $this->Parent = $Parent;
|
|---|
| 38 | if ($Parent != null) $Parent->SubItems->Add($this);
|
|---|
| 39 | $this->SubItems = new SpeedLimitItems();
|
|---|
| 40 | $this->FixedSpeed = false;
|
|---|
| 41 | }
|
|---|
| 42 |
|
|---|
| 43 | function Print(int $Indent = 0): string
|
|---|
| 44 | {
|
|---|
| 45 | $Output = str_repeat(' ', $Indent * 2).$this->Name.' In:'.$this->LimitIn->Print().' Out:'.$this->LimitOut->Print()."\n";
|
|---|
| 46 | $Output .= $this->SubItems->Print($Indent + 1);
|
|---|
| 47 | return $Output;
|
|---|
| 48 | }
|
|---|
| 49 |
|
|---|
| 50 | function CheckName($Name, &$UsedNames): void
|
|---|
| 51 | {
|
|---|
| 52 | if (in_array($Name, $UsedNames)) die("\n".'Duplicate name: '.$Name);
|
|---|
| 53 | else $UsedNames[] = $Name;
|
|---|
| 54 | }
|
|---|
| 55 |
|
|---|
| 56 | function GetCommands(&$UsedNames = null): array
|
|---|
| 57 | {
|
|---|
| 58 | if ($UsedNames == null) $UsedNames = array();
|
|---|
| 59 |
|
|---|
| 60 | $this->CheckName($this->Name.'-out', $UsedNames);
|
|---|
| 61 | $Item = array('name' => $this->Name.'-out', 'limit-at' => $this->LimitOut->Min, 'max-limit' => $this->LimitOut->Max,
|
|---|
| 62 | 'parent' => $this->GetParentName('-out'), 'packet-mark' => $this->LimitOut->PacketMark);
|
|---|
| 63 | if ($this->LimitOut->PacketMark != null) $Item['packet-mark'] = $this->LimitOut->PacketMark;
|
|---|
| 64 | $Output[] = $Item;
|
|---|
| 65 |
|
|---|
| 66 | $this->CheckName($this->Name.'-in', $UsedNames);
|
|---|
| 67 | $Item = array('name' => $this->Name.'-in', 'limit-at' => $this->LimitIn->Min, 'max-limit' => $this->LimitIn->Max,
|
|---|
| 68 | 'parent' => $this->GetParentName('-in'));
|
|---|
| 69 | if ($this->LimitIn->PacketMark != null) $Item['packet-mark'] = $this->LimitIn->PacketMark;
|
|---|
| 70 | $Output[] = $Item;
|
|---|
| 71 |
|
|---|
| 72 | $Output = array_merge($Output, $this->SubItems->GetCommands($UsedNames));
|
|---|
| 73 | return $Output;
|
|---|
| 74 | }
|
|---|
| 75 |
|
|---|
| 76 | function GetParentName(string $Suffix): string
|
|---|
| 77 | {
|
|---|
| 78 | if ($this->Parent != null) return $this->Parent->Name.$Suffix;
|
|---|
| 79 | return 'global';
|
|---|
| 80 | }
|
|---|
| 81 |
|
|---|
| 82 | function UpdateMinSpeeds(): void
|
|---|
| 83 | {
|
|---|
| 84 | if (($this->LimitIn->Min == 0) or ($this->LimitOut->Min == 0))
|
|---|
| 85 | {
|
|---|
| 86 | $SpeedMinOut = 0;
|
|---|
| 87 | $SpeedMinIn = 0;
|
|---|
| 88 | foreach ($this->SubItems->Items as $Index => $Item)
|
|---|
| 89 | {
|
|---|
| 90 | $this->SubItems->Items[$Index]->UpdateMinSpeeds();
|
|---|
| 91 | $SpeedMinOut += $this->SubItems->Items[$Index]->LimitOut->Min;
|
|---|
| 92 | $SpeedMinIn += $this->SubItems->Items[$Index]->LimitIn->Min;
|
|---|
| 93 | }
|
|---|
| 94 | if ($SpeedMinOut > $this->LimitOut->Max) $SpeedMinOut = $this->LimitOut->Max;
|
|---|
| 95 | if ($SpeedMinIn > $this->LimitIn->Max) $SpeedMinIn = $this->LimitIn->Max;
|
|---|
| 96 | $this->LimitOut->Min = $SpeedMinOut;
|
|---|
| 97 | $this->LimitIn->Min = $SpeedMinIn;
|
|---|
| 98 | }
|
|---|
| 99 | }
|
|---|
| 100 |
|
|---|
| 101 | function AdjustMinSpeedsToMax(float $MultiplierIn, float $MultiplierOut): void
|
|---|
| 102 | {
|
|---|
| 103 | foreach ($this->SubItems->Items as $Index => $Item)
|
|---|
| 104 | {
|
|---|
| 105 | $this->SubItems->Items[$Index]->AdjustMinSpeedsToMax($MultiplierIn, $MultiplierOut);
|
|---|
| 106 | }
|
|---|
| 107 | if ($this->FixedSpeed == false)
|
|---|
| 108 | {
|
|---|
| 109 | $this->LimitOut->Min = round($this->LimitOut->Min * $MultiplierOut);
|
|---|
| 110 | if ($this->LimitOut->Min > $this->LimitOut->Max)
|
|---|
| 111 | {
|
|---|
| 112 | echo($this->Name.': '.$this->LimitOut->Min.' > '.$this->LimitOut->Max."\n");
|
|---|
| 113 | $this->LimitOut->Min = $this->LimitOut->Max;
|
|---|
| 114 | }
|
|---|
| 115 | $this->LimitIn->Min = round($this->LimitIn->Min * $MultiplierIn);
|
|---|
| 116 | if ($this->LimitIn->Min > $this->LimitIn->Max)
|
|---|
| 117 | {
|
|---|
| 118 | echo($this->Name.': '.$this->LimitIn->Min.' > '.$this->LimitIn->Max."\n");
|
|---|
| 119 | $this->LimitIn->Min = $this->LimitIn->Max;
|
|---|
| 120 | }
|
|---|
| 121 | }
|
|---|
| 122 | }
|
|---|
| 123 | }
|
|---|
| 124 |
|
|---|
| 125 | class SpeedLimitItems extends GenericList
|
|---|
| 126 | {
|
|---|
| 127 | function AddNew(string $Name, SpeedLimitItem $Parent = null): SpeedLimitItem
|
|---|
| 128 | {
|
|---|
| 129 | $Item = new SpeedLimitItem($Name, $Parent);
|
|---|
| 130 | $Item->LimitIn = new SpeedLimit(0, 0);
|
|---|
| 131 | $Item->LimitOut = new SpeedLimit(0, 0);
|
|---|
| 132 | $this->Items[] = $Item;
|
|---|
| 133 | return $Item;
|
|---|
| 134 | }
|
|---|
| 135 |
|
|---|
| 136 | function Print(int $Indent = 0): string
|
|---|
| 137 | {
|
|---|
| 138 | $Output = '';
|
|---|
| 139 | foreach ($this->Items as $SubItem)
|
|---|
| 140 | {
|
|---|
| 141 | $Output .= $SubItem->Print($Indent);
|
|---|
| 142 | }
|
|---|
| 143 | return $Output;
|
|---|
| 144 | }
|
|---|
| 145 |
|
|---|
| 146 | function GetCommands(&$UsedNames): array
|
|---|
| 147 | {
|
|---|
| 148 | $Output = array();
|
|---|
| 149 | foreach ($this->Items as $SubItem)
|
|---|
| 150 | {
|
|---|
| 151 | $Output = array_merge($Output, $SubItem->GetCommands($UsedNames));
|
|---|
| 152 | }
|
|---|
| 153 | return $Output;
|
|---|
| 154 | }
|
|---|
| 155 | }
|
|---|
| 156 |
|
|---|
| 157 | class ConfigRouterOSQueue extends NetworkConfigItem
|
|---|
| 158 | {
|
|---|
| 159 | var $UsedNames;
|
|---|
| 160 | var $Devices;
|
|---|
| 161 | var $QueueItems;
|
|---|
| 162 | var $SpeedLimits;
|
|---|
| 163 |
|
|---|
| 164 | function Run(): void
|
|---|
| 165 | {
|
|---|
| 166 | $PathQueue = array('queue', 'tree');
|
|---|
| 167 |
|
|---|
| 168 | $Routerboard = new Routerboard();
|
|---|
| 169 | $Routerboard->UserName = $this->System->Config['MainRouter']['UserName'];
|
|---|
| 170 | $Routerboard->Timeout = $this->System->Config['MainRouter']['ConnectTimeout'];
|
|---|
| 171 | $Routerboard->HostName = $this->System->Config['MainRouter']['HostName'];
|
|---|
| 172 | $Routerboard->Debug = true;
|
|---|
| 173 |
|
|---|
| 174 | $this->UsedNames = array();
|
|---|
| 175 |
|
|---|
| 176 | $Finance = &ModuleFinance::Cast($this->System->GetModule('Finance'))->Finance;
|
|---|
| 177 | $Finance->LoadMonthParameters(0);
|
|---|
| 178 |
|
|---|
| 179 | // Generate traffic shaping rules
|
|---|
| 180 | $InDivider = 1;
|
|---|
| 181 | $OutDivider = 1;
|
|---|
| 182 | $TotalMaxSpeedIn = round($Finance->RealMaxSpeed / $InDivider) * 1000;
|
|---|
| 183 | $TotalMaxSpeedOut = round($Finance->RealMaxSpeed / $OutDivider) * 1000;
|
|---|
| 184 | $UsersMaxSpeedIn = round($Finance->MaxSpeed / $InDivider) * 1000;
|
|---|
| 185 | $UsersMaxSpeedOut = round($Finance->MaxSpeed / $OutDivider) * 1000;
|
|---|
| 186 | $OutInterface = 'eth1';
|
|---|
| 187 | $InInterface = 'ifb0';
|
|---|
| 188 | $InetInterface = $this->System->Config['MainRouter']['InetInterface'];
|
|---|
| 189 |
|
|---|
| 190 | $DbResult = $this->Database->select('Service', '*', '(`ChangeAction` IS NULL) AND (`Id`='.TARIFF_FREE.')');
|
|---|
| 191 | if ($DbResult->num_rows == 1)
|
|---|
| 192 | {
|
|---|
| 193 | $Service = $DbResult->fetch_array();
|
|---|
| 194 | $FreeInetSpeed = $Service['InternetSpeedMax'];
|
|---|
| 195 | } else $FreeInetSpeed = 0;
|
|---|
| 196 |
|
|---|
| 197 | // Root of tree and main limit
|
|---|
| 198 | $Main = new SpeedLimitItem('main');
|
|---|
| 199 | $Main->LimitIn = new SpeedLimit(0, $UsersMaxSpeedIn);
|
|---|
| 200 | $Main->LimitOut = new SpeedLimit(0, $UsersMaxSpeedOut);
|
|---|
| 201 |
|
|---|
| 202 | $this->LoadSpeedLimits($Main);
|
|---|
| 203 |
|
|---|
| 204 | // Free internet
|
|---|
| 205 | $Free = new SpeedLimitItem('free', $Main);
|
|---|
| 206 | $Free->LimitIn = new SpeedLimit($FreeInetSpeed, $FreeInetSpeed, GetMarkByComment('free-in'));
|
|---|
| 207 | $Free->LimitOut = new SpeedLimit($FreeInetSpeed, $FreeInetSpeed, GetMarkByComment('free-out'));
|
|---|
| 208 | $Free->FixedSpeed = true;
|
|---|
| 209 |
|
|---|
| 210 | // Process users
|
|---|
| 211 | $DbResult = $this->Database->query('SELECT `Member`.*, `Subject`.`Name` FROM `Member` '.
|
|---|
| 212 | 'LEFT JOIN `Subject` ON `Subject`.`Id` = `Member`.`Subject` WHERE `Member`.`Blocked`=0');
|
|---|
| 213 | while ($Member = $DbResult->fetch_assoc())
|
|---|
| 214 | {
|
|---|
| 215 | $ServiceIndex = 1;
|
|---|
| 216 | echo('Zákazník '.$Member['Name']."\n");
|
|---|
| 217 | $DbResult4 = $this->Database->query('SELECT `Service`.*, `ServiceCustomerRel`.`Id` AS `RelId`, '.
|
|---|
| 218 | '`ServiceCustomerRel`.`SpeedLimit` AS `SpeedLimit` FROM `ServiceCustomerRel` '.
|
|---|
| 219 | 'JOIN `Service` ON `Service`.`Id` = `ServiceCustomerRel`.`Service` '.
|
|---|
| 220 | 'WHERE (`ServiceCustomerRel`.`Customer` = '.$Member['Id'].') AND (`ServiceCustomerRel`.`ChangeAction` IS NULL) '.
|
|---|
| 221 | 'AND (`Service`.`InternetSpeedMax` > 0) AND (`Service`.`InternetSpeedMin` > 0)');
|
|---|
| 222 | while ($Service = $DbResult4->fetch_assoc())
|
|---|
| 223 | {
|
|---|
| 224 | $MinSpeed = $Service['InternetSpeedMin'];
|
|---|
| 225 | $MaxSpeed = $Service['InternetSpeedMax'];
|
|---|
| 226 | if ($Service['InternetSpeedBonus'] > $MaxSpeed) $MaxSpeed = $Service['InternetSpeedBonus'];
|
|---|
| 227 |
|
|---|
| 228 | echo('Služba '.$Service['Name'].': ');
|
|---|
| 229 | $MemberName = RouterOSIdent($Member['Name'].'-'.$Member['Id'].'-'.$ServiceIndex);
|
|---|
| 230 | $MinReduction = 100;
|
|---|
| 231 | $SpeedIn = round($MinSpeed / $InDivider / $MinReduction);
|
|---|
| 232 | $SpeedOut = round($MinSpeed / $OutDivider / $MinReduction);
|
|---|
| 233 | $UserMaxSpeedIn = round($MaxSpeed / $InDivider);
|
|---|
| 234 | $UserMaxSpeedOut = round($MaxSpeed / $OutDivider);
|
|---|
| 235 |
|
|---|
| 236 | // Reduce max speed by speed limits
|
|---|
| 237 | $SpeedLimitItem = $Main;
|
|---|
| 238 | if ($Service['SpeedLimit'] != null)
|
|---|
| 239 | {
|
|---|
| 240 | $SpeedLimit = $this->SpeedLimits[$Service['SpeedLimit']];
|
|---|
| 241 | $SpeedLimitItem = $SpeedLimit['SpeedLimitItem'];
|
|---|
| 242 | if ($UserMaxSpeedIn > $SpeedLimit['SpeedMaxIn']) $UserMaxSpeedIn = $SpeedLimit['SpeedMaxIn'];
|
|---|
| 243 | if ($UserMaxSpeedOut > $SpeedLimit['SpeedMaxOut']) $UserMaxSpeedOut = $SpeedLimit['SpeedMaxOut'];
|
|---|
| 244 | while ($SpeedLimit['Parent'] != null)
|
|---|
| 245 | {
|
|---|
| 246 | $SpeedLimit = $this->SpeedLimits[$SpeedLimit['Parent']];
|
|---|
| 247 | if ($UserMaxSpeedIn > $SpeedLimit['SpeedMaxIn']) $UserMaxSpeedIn = $SpeedLimit['SpeedMaxIn'];
|
|---|
| 248 | if ($UserMaxSpeedOut > $SpeedLimit['SpeedMaxOut']) $UserMaxSpeedOut = $SpeedLimit['SpeedMaxOut'];
|
|---|
| 249 | }
|
|---|
| 250 | }
|
|---|
| 251 |
|
|---|
| 252 | $LimitMember = new SpeedLimitItem($MemberName, $SpeedLimitItem);
|
|---|
| 253 | $LimitMember->LimitIn = new SpeedLimit($SpeedIn, $UserMaxSpeedIn);
|
|---|
| 254 | $LimitMember->LimitOut = new SpeedLimit($SpeedOut, $UserMaxSpeedOut);
|
|---|
| 255 |
|
|---|
| 256 | $Filter = '(`Used` = 1) AND (`Service` = '.$Service['RelId'].')';
|
|---|
| 257 | $DbResult2 = $this->Database->select('NetworkDevice', 'COUNT(*)', $Filter);
|
|---|
| 258 | $Row = $DbResult2->fetch_row();
|
|---|
| 259 | $HostCount = $Row[0];
|
|---|
| 260 | if ($HostCount > 0)
|
|---|
| 261 | {
|
|---|
| 262 | $HostSpeedIn = round($SpeedIn / $HostCount);
|
|---|
| 263 | $HostSpeedOut = round($SpeedOut / $HostCount);
|
|---|
| 264 | } else
|
|---|
| 265 | {
|
|---|
| 266 | $HostSpeedIn = $SpeedIn;
|
|---|
| 267 | $HostSpeedOut = $SpeedOut;
|
|---|
| 268 | }
|
|---|
| 269 |
|
|---|
| 270 | $DbResult2 = $this->Database->select('NetworkDevice', '*', $Filter);
|
|---|
| 271 | while ($Device = $DbResult2->fetch_assoc())
|
|---|
| 272 | {
|
|---|
| 273 | $DbResult3 = $this->Database->select('NetworkInterface', '*', '`Device` = '.$Device['Id'].' AND `LocalIP` != ""');
|
|---|
| 274 | while ($Interface = $DbResult3->fetch_assoc())
|
|---|
| 275 | {
|
|---|
| 276 | $DeviceName = $Device['Name'];
|
|---|
| 277 | if ($Interface['Name'] != '') $DeviceName .= '-'.$Interface['Name'];
|
|---|
| 278 | $DeviceName = RouterOSIdent($DeviceName);
|
|---|
| 279 | echo($DeviceName.', ');
|
|---|
| 280 | $LimitDevice = new SpeedLimitItem($DeviceName, $LimitMember);
|
|---|
| 281 | $LimitDevice->LimitIn = new SpeedLimit($HostSpeedIn, $UserMaxSpeedIn, GetMarkByComment($DeviceName.'-in'));
|
|---|
| 282 | $LimitDevice->LimitOut = new SpeedLimit($HostSpeedOut, $UserMaxSpeedOut, GetMarkByComment($DeviceName.'-out'));
|
|---|
| 283 | }
|
|---|
| 284 | }
|
|---|
| 285 |
|
|---|
| 286 | $DbResult2 = $this->Database->select('NetworkSubnet', '*', '`Service`='.$Service['RelId']);
|
|---|
| 287 | while ($Subnet = $DbResult2->fetch_assoc())
|
|---|
| 288 | {
|
|---|
| 289 | $SubnetName = RouterOSIdent('subnet-'.$Subnet['Name']);
|
|---|
| 290 | echo($SubnetName.', ');
|
|---|
| 291 | $LimitSubnet = new SpeedLimitItem($SubnetName, $LimitMember);
|
|---|
| 292 | $LimitSubnet->LimitIn = new SpeedLimit($HostSpeedIn, $UserMaxSpeedIn, GetMarkByComment($SubnetName.'-in'));
|
|---|
| 293 | $LimitSubnet->LimitOut = new SpeedLimit($HostSpeedOut, $UserMaxSpeedOut, GetMarkByComment($SubnetName.'-out'));
|
|---|
| 294 | }
|
|---|
| 295 | echo("\n");
|
|---|
| 296 | $ServiceIndex++;
|
|---|
| 297 | }
|
|---|
| 298 | }
|
|---|
| 299 | $Main->UpdateMinSpeeds();
|
|---|
| 300 | $Main->AdjustMinSpeedsToMax($Main->LimitIn->Max / $Main->LimitIn->Min,
|
|---|
| 301 | $Main->LimitOut->Max / $Main->LimitOut->Min);
|
|---|
| 302 |
|
|---|
| 303 | echo($Main->Print());
|
|---|
| 304 | $ItemsQueue = $Main->GetCommands();
|
|---|
| 305 | $Routerboard->ListUpdate($PathQueue, array('name', 'limit-at', 'max-limit', 'parent', 'packet-mark'), $ItemsQueue, array(), true);
|
|---|
| 306 | }
|
|---|
| 307 |
|
|---|
| 308 | function BuildSpeedLimit(&$SpeedLimit, $TopSpeedLimitItem): void
|
|---|
| 309 | {
|
|---|
| 310 | $SpeedLimitName = $SpeedLimit['Name'].'-grp';
|
|---|
| 311 | $SpeedLimitName = RouterOSIdent($SpeedLimitName);
|
|---|
| 312 | echo($SpeedLimitName.', ');
|
|---|
| 313 |
|
|---|
| 314 | $SpeedLimitItem = new SpeedLimitItem($SpeedLimitName, $TopSpeedLimitItem);
|
|---|
| 315 | $SpeedLimitItem->LimitIn = new SpeedLimit(0, $SpeedLimit['SpeedMaxIn']);
|
|---|
| 316 | $SpeedLimitItem->LimitOut = new SpeedLimit(0, $SpeedLimit['SpeedMaxOut']);
|
|---|
| 317 | $SpeedLimit['SpeedLimitItem'] = $SpeedLimitItem;
|
|---|
| 318 |
|
|---|
| 319 | foreach ($SpeedLimit['Childs'] as $ChildId)
|
|---|
| 320 | {
|
|---|
| 321 | $this->BuildSpeedLimit($this->SpeedLimits[$ChildId], $SpeedLimitItem);
|
|---|
| 322 | }
|
|---|
| 323 | }
|
|---|
| 324 |
|
|---|
| 325 | function LoadSpeedLimits($SpeedLimitItem): void
|
|---|
| 326 | {
|
|---|
| 327 | echo('Limit groups: ');
|
|---|
| 328 | // Load all speed limits
|
|---|
| 329 | $this->SpeedLimits = array();
|
|---|
| 330 | $DbResult = $this->Database->query('SELECT * FROM `NetworkSpeedLimit`');
|
|---|
| 331 | while ($SpeedLimit = $DbResult->fetch_array())
|
|---|
| 332 | {
|
|---|
| 333 | $SpeedLimit['Childs'] = array();
|
|---|
| 334 | $this->SpeedLimits[$SpeedLimit['Id']] = $SpeedLimit;
|
|---|
| 335 | }
|
|---|
| 336 |
|
|---|
| 337 | // Calculate childs from parent
|
|---|
| 338 | foreach ($this->SpeedLimits as $Index => $SpeedLimit)
|
|---|
| 339 | {
|
|---|
| 340 | if ($SpeedLimit['Parent'] != null) $this->SpeedLimits[$SpeedLimit['Parent']]['Childs'][] = $Index;
|
|---|
| 341 | }
|
|---|
| 342 |
|
|---|
| 343 | // Build speed limits from top
|
|---|
| 344 | foreach ($this->SpeedLimits as $Index => $SpeedLimit)
|
|---|
| 345 | {
|
|---|
| 346 | if ($SpeedLimit['Parent'] == null)
|
|---|
| 347 | {
|
|---|
| 348 | $this->BuildSpeedLimit($this->SpeedLimits[$Index], $SpeedLimitItem);
|
|---|
| 349 | }
|
|---|
| 350 | }
|
|---|
| 351 | echo("\n");
|
|---|
| 352 | }
|
|---|
| 353 |
|
|---|
| 354 | function UpdateMinSpeed($DeviceId): void
|
|---|
| 355 | {
|
|---|
| 356 | $MinSpeed = 0;
|
|---|
| 357 | foreach ($this->Devices[$DeviceId]['Childs'] as $DeviceChild)
|
|---|
| 358 | {
|
|---|
| 359 | $this->UpdateMinSpeed($DeviceChild);
|
|---|
| 360 | $MinSpeed += $this->Devices[$DeviceChild]['MinSpeed'];
|
|---|
| 361 | }
|
|---|
| 362 | $this->Devices[$DeviceId]['MinSpeed'] = $MinSpeed;
|
|---|
| 363 | if ($this->Devices[$DeviceId]['DeviceCount'] > 0)
|
|---|
| 364 | $this->Devices[$DeviceId]['MinSpeed'] += round($this->Devices[$DeviceId]['InternetSpeedMin'] / $this->Devices[$DeviceId]['DeviceCount']);
|
|---|
| 365 | }
|
|---|
| 366 |
|
|---|
| 367 | // Calculate maximum real speed available for each network device Start with main router and continue with adjecement nodes.
|
|---|
| 368 | function BuildTree($RootDeviceId, $BaseSpeed): void
|
|---|
| 369 | {
|
|---|
| 370 | // Load network devices
|
|---|
| 371 | $this->Devices = array();
|
|---|
| 372 | $DbResult = $this->Database->query('SELECT `NetworkDevice`.`Name`,`NetworkDevice`.`Id`, '.
|
|---|
| 373 | '`Service`.`InternetSpeedMin`, `Service`.`InternetSpeedMax`, '.
|
|---|
| 374 | '(SELECT COUNT(*) FROM `NetworkDevice` AS `T` WHERE `T`.`Service` = `NetworkDevice`.`Service`) AS `DeviceCount` FROM `NetworkDevice` '.
|
|---|
| 375 | 'LEFT JOIN `ServiceCustomerRel` ON `ServiceCustomerRel`.`Id`=`NetworkDevice`.`Service` '.
|
|---|
| 376 | 'LEFT JOIN `Service` ON `Service`.`Id` = `ServiceCustomerRel`.`Service`');
|
|---|
| 377 | while ($Device = $DbResult->fetch_assoc())
|
|---|
| 378 | {
|
|---|
| 379 | $Device['Interfaces'] = array();
|
|---|
| 380 | $Device['Calculated'] = false;
|
|---|
| 381 | $Device['MaxSpeed'] = 0;
|
|---|
| 382 | $Device['MinSpeed'] = 0;
|
|---|
| 383 | $Device['Childs'] = array();
|
|---|
| 384 | $Device['Parent'] = 0;
|
|---|
| 385 | $Device['QueueName'] = '';
|
|---|
| 386 | $this->Devices[$Device['Id']] = $Device;
|
|---|
| 387 | }
|
|---|
| 388 |
|
|---|
| 389 | // Load network interfaces and assign them to device
|
|---|
| 390 | $Interfaces = array();
|
|---|
| 391 | $DbResult = $this->Database->query('SELECT `Device`,`Name`,`Id` FROM `NetworkInterface`');
|
|---|
| 392 | while ($Interface = $DbResult->fetch_assoc())
|
|---|
| 393 | {
|
|---|
| 394 | $Interface['Links'] = array();
|
|---|
| 395 | $Interfaces[$Interface['Id']] = $Interface;
|
|---|
| 396 | $this->Devices[$Interface['Device']]['Interfaces'][] = $Interface['Id'];
|
|---|
| 397 | }
|
|---|
| 398 |
|
|---|
| 399 | // Load network links and assign them to interfaces
|
|---|
| 400 | $Links = array();
|
|---|
| 401 | $DbResult = $this->Database->query('SELECT `NetworkLink`.`Id`,`NetworkLink`.`Interface1`,'.
|
|---|
| 402 | '`NetworkLink`.`Interface2`,`NetworkLinkType`.`MaxRealSpeed` FROM `NetworkLink` '.
|
|---|
| 403 | 'LEFT JOIN `NetworkLinkType` ON `NetworkLinkType`.`Id`=`NetworkLink`.`Type`');
|
|---|
| 404 | while ($Link = $DbResult->fetch_assoc())
|
|---|
| 405 | {
|
|---|
| 406 | $Links[$Link['Id']] = $Link;
|
|---|
| 407 | $Interfaces[$Link['Interface1']]['Links'][] = $Link['Id'];
|
|---|
| 408 | $Interfaces[$Link['Interface2']]['Links'][] = $Link['Id'];
|
|---|
| 409 | }
|
|---|
| 410 |
|
|---|
| 411 | // Calculate maximum speed for network devices
|
|---|
| 412 | $DevicesToCheck = array($RootDeviceId);
|
|---|
| 413 | $this->Devices[$RootDeviceId]['MaxSpeed'] = $BaseSpeed;
|
|---|
| 414 | $this->Devices[$RootDeviceId]['Calculated'] = true;
|
|---|
| 415 |
|
|---|
| 416 | while (count($DevicesToCheck) > 0)
|
|---|
| 417 | {
|
|---|
| 418 | $NewDevicesToCheck = array();
|
|---|
| 419 | foreach ($DevicesToCheck as $DeviceId)
|
|---|
| 420 | {
|
|---|
| 421 | foreach ($this->Devices[$DeviceId]['Interfaces'] as $InterfaceId)
|
|---|
| 422 | {
|
|---|
| 423 | foreach ($Interfaces[$InterfaceId]['Links'] as $LinkId)
|
|---|
| 424 | {
|
|---|
| 425 | $Link = $Links[$LinkId];
|
|---|
| 426 | $Interface2Id = $Link['Interface1'];
|
|---|
| 427 | if ($Interface2Id == $InterfaceId) $Interface2Id = $Links[$LinkId]['Interface2'];
|
|---|
| 428 |
|
|---|
| 429 | $Device2Id = $Interfaces[$Interface2Id]['Device'];
|
|---|
| 430 | if ($this->Devices[$Device2Id]['Calculated'] == false)
|
|---|
| 431 | {
|
|---|
| 432 | $this->Devices[$Device2Id]['Calculated'] = true;
|
|---|
| 433 | $NewMaxSpeed = $this->Devices[$DeviceId]['MaxSpeed'];
|
|---|
| 434 | if ($NewMaxSpeed > $Link['MaxRealSpeed'])
|
|---|
| 435 | $NewMaxSpeed = $Link['MaxRealSpeed'];
|
|---|
| 436 | $this->Devices[$Device2Id]['MaxSpeed'] = $NewMaxSpeed;
|
|---|
| 437 | // Set nodes tree relation
|
|---|
| 438 | $this->Devices[$Device2Id]['Parent'] = $DeviceId;
|
|---|
| 439 | $this->Devices[$DeviceId]['Childs'][] = $Device2Id;
|
|---|
| 440 | $NewDevicesToCheck[] = $Device2Id;
|
|---|
| 441 | }
|
|---|
| 442 | }
|
|---|
| 443 | }
|
|---|
| 444 | }
|
|---|
| 445 | $DevicesToCheck = $NewDevicesToCheck;
|
|---|
| 446 | }
|
|---|
| 447 |
|
|---|
| 448 | // Calculate maximum speed for network devices
|
|---|
| 449 | $this->UpdateMinSpeed($RootDeviceId);
|
|---|
| 450 |
|
|---|
| 451 | echo('Not linked network devices: ');
|
|---|
| 452 | foreach ($this->Devices as $Device)
|
|---|
| 453 | {
|
|---|
| 454 | if ($Device['MaxSpeed'] == 0) echo($Device['Name'].', ');
|
|---|
| 455 | }
|
|---|
| 456 | echo("\n");
|
|---|
| 457 | }
|
|---|
| 458 |
|
|---|
| 459 | function BuildQueueItems($DeviceId, $SpeedLimitParent): void
|
|---|
| 460 | {
|
|---|
| 461 | $Device = $this->Devices[$DeviceId];
|
|---|
| 462 |
|
|---|
| 463 | // Device
|
|---|
| 464 | $DeviceName = $Device['Name'];
|
|---|
| 465 | $DeviceName = RouterOSIdent($DeviceName);
|
|---|
| 466 | $this->Devices[$DeviceId]['QueueName'] = $DeviceName;
|
|---|
| 467 | echo($DeviceName.', ');
|
|---|
| 468 |
|
|---|
| 469 | $LimitDevice = new SpeedLimitItem($DeviceName, $SpeedLimitParent);
|
|---|
| 470 | $LimitDevice->LimitIn = new SpeedLimit($Device['MinSpeed'], $Device['MaxSpeed'], GetMarkByComment($DeviceName.'-in'));
|
|---|
| 471 | $LimitDevice->LimitOut = new SpeedLimit($Device['MinSpeed'], $Device['MaxSpeed'], GetMarkByComment($DeviceName.'-out'));
|
|---|
| 472 |
|
|---|
| 473 | // Interfaces
|
|---|
| 474 | $DbResult3 = $this->Database->select('NetworkInterface', '*', '`Device` = '.$DeviceId.' AND `LocalIP` != ""');
|
|---|
| 475 | $IntCount = $DbResult3->num_rows;
|
|---|
| 476 | while ($Interface = $DbResult3->fetch_assoc())
|
|---|
| 477 | {
|
|---|
| 478 | $InterfaceName = $Device['Name'];
|
|---|
| 479 | if ($Interface['Name'] != '') $InterfaceName .= '-'.$Interface['Name'];
|
|---|
| 480 | else $InterfaceName .= '-';
|
|---|
| 481 | $InterfaceName = RouterOSIdent($InterfaceName);
|
|---|
| 482 | echo($InterfaceName.', ');
|
|---|
| 483 |
|
|---|
| 484 | $LimitInterface = new SpeedLimitItem($InterfaceName, $LimitDevice);
|
|---|
| 485 | $LimitInterface->LimitIn = new SpeedLimit(round($Device['MinSpeed'] / $IntCount), $Device['MaxSpeed'], GetMarkByComment($InterfaceName.'-in'));
|
|---|
| 486 | $LimitInterface->LimitOut = new SpeedLimit(round($Device['MinSpeed'] / $IntCount), $Device['MaxSpeed'], GetMarkByComment($InterfaceName.'-out'));
|
|---|
| 487 | }
|
|---|
| 488 |
|
|---|
| 489 | // Process childs
|
|---|
| 490 | foreach ($Device['Childs'] as $DeviceChild)
|
|---|
| 491 | {
|
|---|
| 492 | $this->BuildQueueItems($DeviceChild, $LimitDevice);
|
|---|
| 493 | }
|
|---|
| 494 | }
|
|---|
| 495 |
|
|---|
| 496 | function RunTopology(): void
|
|---|
| 497 | {
|
|---|
| 498 | $PathQueue = array('queue', 'tree');
|
|---|
| 499 |
|
|---|
| 500 | $Routerboard = new Routerboard();
|
|---|
| 501 | $Routerboard->UserName = $this->System->Config['MainRouter']['UserName'];
|
|---|
| 502 | $Routerboard->Timeout = $this->System->Config['MainRouter']['ConnectTimeout'];
|
|---|
| 503 | $Routerboard->HostName = $this->System->Config['MainRouter']['HostName'];
|
|---|
| 504 | $Routerboard->Debug = true;
|
|---|
| 505 |
|
|---|
| 506 | $this->UsedNames = array();
|
|---|
| 507 |
|
|---|
| 508 | $Finance = &ModuleFinance::Cast($this->System->GetModule('Finance'))->Finance;
|
|---|
| 509 | $Finance->LoadMonthParameters(0);
|
|---|
| 510 |
|
|---|
| 511 | $InDivider = 1;
|
|---|
| 512 | $OutDivider = 1;
|
|---|
| 513 | $UsersMaxSpeedIn = round($Finance->MaxSpeed / $InDivider) * 1000;
|
|---|
| 514 | $UsersMaxSpeedOut = round($Finance->MaxSpeed / $OutDivider) * 1000;
|
|---|
| 515 |
|
|---|
| 516 | $DbResult = $this->Database->select('Service', '*', '(`ChangeAction` IS NULL) AND (`Id`='.TARIFF_FREE.')');
|
|---|
| 517 | if ($DbResult->num_rows == 1)
|
|---|
| 518 | {
|
|---|
| 519 | $Service = $DbResult->fetch_array();
|
|---|
| 520 | $FreeInetSpeed = $Service['InternetSpeedMax'];
|
|---|
| 521 | } else $FreeInetSpeed = 0;
|
|---|
| 522 |
|
|---|
| 523 | $this->ItemsQueue = array();
|
|---|
| 524 |
|
|---|
| 525 | // Root of tree and main limit
|
|---|
| 526 | $Main = new SpeedLimitItem('main');
|
|---|
| 527 | $Main->LimitIn = new SpeedLimit($UsersMaxSpeedIn, $UsersMaxSpeedIn);
|
|---|
| 528 | $Main->LimitOut = new SpeedLimit($UsersMaxSpeedOut, $UsersMaxSpeedOut);
|
|---|
| 529 |
|
|---|
| 530 | // Slow free internet
|
|---|
| 531 | $Free = new SpeedLimitItem('free', $Main);
|
|---|
| 532 | $Free->LimitIn = new SpeedLimit($FreeInetSpeed, $FreeInetSpeed, GetMarkByComment('free-in'));
|
|---|
| 533 | $Free->LimitOut = new SpeedLimit($FreeInetSpeed, $FreeInetSpeed, GetMarkByComment('free-out'));
|
|---|
| 534 |
|
|---|
| 535 | $this->BuildTree($this->System->Config['MainRouter']['DeviceId'], $UsersMaxSpeedIn);
|
|---|
| 536 | $this->BuildQueueItems($this->System->Config['MainRouter']['DeviceId'], $Main);
|
|---|
| 537 |
|
|---|
| 538 | echo($Main->Print());
|
|---|
| 539 | die();
|
|---|
| 540 |
|
|---|
| 541 | print_r($this->ItemsQueue);
|
|---|
| 542 | //$Routerboard->ListUpdate($PathQueue, array('name', 'limit-at', 'max-limit',
|
|---|
| 543 | // 'parent', 'packet-mark'), $this->ItemsQueue, array(), true);
|
|---|
| 544 | }
|
|---|
| 545 | }
|
|---|