Просмотр исходного кода

Merge pull request #2 from AlexMeuer/master

Add support for delay variance and loss/reorder correlations
Christian Sieber 7 лет назад
Родитель
Сommit
f1dae28017
3 измененных файлов с 77 добавлено и 35 удалено
  1. 15 5
      README.md
  2. 41 22
      main.py
  3. 21 8
      templates/main.html

+ 15 - 5
README.md

@@ -1,20 +1,30 @@
 # tcgui
 
-A lightweight Python-based Web-GUI for Linux traffic control (tc) to set, view and delete traffic shaping rules. The Web-GUI is intended for short-term isolated testbeds or classroom scenarios and does not contain any security mechanisms.
+A lightweight Python-based Web-GUI for Linux traffic control (`tc`) to set, view and delete traffic shaping rules. The Web-GUI is intended for short-term isolated testbeds or classroom scenarios and does not contain any security mechanisms.
 
 No further changes are planned right now, but pull requests are welcome.
 
 ## Requirements
 
-- tested with ubuntu 16.04 LTS
-- netem tools & python3-flask is required
-    - install with `sudo apt-get install iproute python3-flask`
-- more information: https://calomel.org/network_loss_emulation.html
+- Tested with Ubuntu 16.04 LTS & Raspbian 4.14.98-v7+ (stretch, Debian 9.8)
+- `netem` tools & p`ython3-flask` are required
+    - Install with `sudo apt-get install iproute python3-flask`
+- More information:
+    - https://calomel.org/network_loss_emulation.html
+    - https://wiki.linuxfoundation.org/networking/netem
 
 ## Usage
 
 - Execute the main.py file and go to http://localhost:5000:
     
+    ```
     sudo python3 main.py
+    
+    --ip IP               The IP where the server is listening
+    --port PORT           The port where the server is listening
+    --dev [DEV [DEV ...]] The interfaces to restrict to
+    --regex REGEX         A regex to match interfaces
+    --debug               Run Flask in debug mode
+    ```
 
 - The tool will read your interfaces and the current setup every time the site is reloaded

+ 41 - 22
main.py

@@ -30,9 +30,12 @@ def main():
 @app.route('/new_rule/<interface>', methods=['POST'])
 def new_rule(interface):
     delay = request.form['Delay']
+    delay_variance = request.form['DelayVariance']
     loss = request.form['Loss']
+    loss_correlation = request.form['LossCorrelation']
     duplicate = request.form['Duplicate']
     reorder = request.form['Reorder']
+    reorder_correlation = request.form['ReorderCorrelation']
     corrupt = request.form['Corrupt']
     rate = request.form['Rate']
 
@@ -48,12 +51,18 @@ def new_rule(interface):
         command += ' rate %smbit' % rate
     if delay != '':
         command += ' delay %sms' % delay
+        if delay_variance != '':
+            command += ' %sms' % delay_variance
     if loss != '':
         command += ' loss %s%%' % loss
+        if loss_correlation != '':
+            command += ' %s%%' % loss_correlation
     if duplicate != '':
         command += ' duplicate %s%%' % duplicate
     if reorder != '':
         command += ' reorder %s%%' % reorder
+        if reorder_correlation != '':
+            command += ' %s%%' % reorder_correlation
     if corrupt != '':
         command += ' corrupt %s%%' % corrupt
     print(command)
@@ -72,6 +81,7 @@ def remove_rule(interface):
     proc.wait()
     return redirect(url_for('main'))
 
+
 def get_active_rules():
     proc = subprocess.Popen(['tc', 'qdisc'], stdout=subprocess.PIPE)
     output = proc.communicate()[0].decode()
@@ -79,7 +89,7 @@ def get_active_rules():
     rules = []
     dev = set()
     for line in lines:
-        arguments = line.split(' ')
+        arguments = line.split()
         rule = parse_rule(arguments)
         if rule['name'] and rule['name'] not in dev:
             rules.append(rule)
@@ -87,40 +97,49 @@ def get_active_rules():
     return rules
 
 
-def parse_rule(splitted_rule):
-    rule = {'name':      None,
-            'rate':      None,
-            'delay':     None,
-            'loss':      None,
-            'duplicate': None,
-            'reorder':   None,
-            'corrupt':   None}
+def parse_rule(split_rule):
+    rule = {'name':               None,
+            'rate':               None,
+            'delay':              None,
+            'delayVariance':      None,
+            'loss':               None,
+            'lossCorrelation':    None,
+            'duplicate':          None,
+            'reorder':            None,
+            'reorderCorrelation': None,
+            'corrupt':            None}
     i = 0
-    for argument in splitted_rule:
+    for argument in split_rule:
         if argument == 'dev':
             # Both regex pattern and dev name can be given
             # An interface could match the pattern and/or 
             # be in the interface list
             if pattern is None and dev_list is None:
-                rule['name'] = splitted_rule[i+1]
+                rule['name'] = split_rule[i + 1]
             if pattern:
-                if pattern.match(splitted_rule[i+1]) :
-                    rule['name'] = splitted_rule[i+1]
+                if pattern.match(split_rule[i + 1]) :
+                    rule['name'] = split_rule[i + 1]
             if dev_list:
-                if splitted_rule[i+1] in dev_list:
-                    rule['name'] = splitted_rule[i+1]
+                if split_rule[i + 1] in dev_list:
+                    rule['name'] = split_rule[i + 1]
         elif argument == 'rate':
-            rule['rate'] = splitted_rule[i + 1].split('Mbit')[0]
+            rule['rate'] = split_rule[i + 1].split('Mbit')[0]
         elif argument == 'delay':
-            rule['delay'] = splitted_rule[i + 1]
+            rule['delay'] = split_rule[i + 1]
+            if 'ms' in split_rule[i + 2]:
+                rule['delayVariance'] = split_rule[i + 2]
         elif argument == 'loss':
-            rule['loss'] = splitted_rule[i + 1]
+            rule['loss'] = split_rule[i + 1]
+            if '%' in split_rule[i + 2]:
+                rule['lossCorrelation'] = split_rule[i + 2]
         elif argument == 'duplicate':
-            rule['duplicate'] = splitted_rule[i + 1]
+            rule['duplicate'] = split_rule[i + 1]
         elif argument == 'reorder':
-            rule['reorder'] = splitted_rule[i + 1]
+            rule['reorder'] = split_rule[i + 1]
+            if '%' in split_rule[i + 2]:
+                rule['reorderCorrelation'] = split_rule[i + 2]
         elif argument == 'corrupt':
-            rule['corrupt'] = splitted_rule[i + 1]
+            rule['corrupt'] = split_rule[i + 1]
         i += 1
     return rule
 
@@ -133,7 +152,7 @@ if __name__ == "__main__":
         pattern = re.compile(args.regex)
     if args.dev:
         dev_list = args.dev
-    app_args={}
+    app_args = {}
     if args.ip:
         app_args['host'] = args.ip
     if args.port:

+ 21 - 8
templates/main.html

@@ -16,36 +16,44 @@
                         <th>Name</th>
                         <th>Current Value</th>
                         <th>New Value</th>
+                        <th>Variance / Correlation</th>
+                        <th>New Value</th>
                     </tr>
                     <tr>
                         <td>Rate:</td>
-                        <td>{{ rule['rate'] }}</td>
-                        <td><input type="text" name="Rate" size="5"> in Mbit</td>
+			<td>{{ rule['rate'] }}</td>
+                        <td><input type="number" name="Rate" size="5"> Mbit</td>
                     </tr>
                     <tr>
                         <td>Delay:</td>
                         <td>{{ rule['delay'] }}</td>
-                        <td><input type="text" name="Delay" size="5"> in ms</td>
+                        <td><input type="number" name="Delay" size="5"> ms</td>
+                        <td>±{{ rule['delayVariance'] }}</td>
+                        <td>±<input type="number" name="DelayVariance" size="5"> ms</td>
                     </tr>
                     <tr>
                         <td>Loss:</td>
                         <td>{{ rule['loss'] }}</td>
-                        <td><input type="text" name="Loss" size="5"> in %</td>
+                        <td><input type="number" name="Loss" size="5"> %</td>
+                        <td>{{ rule['lossCorrelation'] }}</td>
+                        <td><input type="number" name="LossCorrelation" size="5"> %</td>
                     </tr>
                     <tr>
                         <td>Duplicate:</td>
                         <td>{{ rule['duplicate'] }}</td>
-                        <td><input type="text" name="Duplicate" size="5"> in %</td>
+                        <td><input type="number" name="Duplicate" size="5"> %</td>
                     </tr>
                     <tr>
                         <td>Reorder:</td>
                         <td>{{ rule['reorder'] }}</td>
-                        <td><input type="text" name="Reorder" size="5"> in %</td>
+                        <td><input type="number" name="Reorder" size="5"> %</td>
+                        <td>{{ rule['reorderCorrelation'] }}</td>
+                        <td><input type="number" name="ReorderCorrelation" size="5"> %</td>
                     </tr>
                     <tr>
                         <td>Corrupt</td>
                         <td>{{ rule['corrupt'] }}</td>
-                        <td><input type="text" name="Corrupt" size="5"> in %</td>
+                        <td><input type="number" name="Corrupt" size="5"> %</td>
                     </tr>
                 </table>
                 <input type="submit" value="Apply Rules">
@@ -56,5 +64,10 @@
         </li>
     {% endfor %}
 </ul>
+<style>
+    th,td {
+        text-align: center;
+    }
+</style>
 </body>
-</html>
+</html>