*subj* :-)
Давно було зрозуміло, що без нормального конфігуратора керувати нормальним шейпером «важкувато», але… все ускладнювала одна обставина — я не програміст (тм).
Чим мене не влаштовують наявні інструменти?
По-перше, всі знайдені вирішують трохи інші задачі, простіші; зокрема, я так і не знайшов конфігуратора для «свого шейпера» — шейпера на мості (bridge/linux), з використанням хеш-таблиць. Для великої кількості клієнтів, для великої кількості IP адрес.
Отже, мені треба було написати щось своє.
Я собі спростив задачу:
- Хай його всі сварять — я використовуватиму django.
- Поєднувати в одній схемі «службові» («кістякові») та «клієнтські» класи здалося заважким — вирішив зробити інакше: для генерування «кістяка» шейпера використовуватиметься окремий скрипт, а для конфігурування (генерування відповідного скрипта) клієнтських класів зроблю собі GUI.
Мій шейпер (тм,-) використовує хеш-таблиці; ці таблиці створює вищезгаданий «окремий скрипт», а заповнюються вони вже скриптами, які генеруються автоматично, засобами django, через специфічні представлення даних.
Отже, «схема» містить такі сутності:
«Схема» трохи недоперемудрена, але поки що хай.
По суті, вся робота з конфігурацією базується на «допиляній» стандартній адмінці django; наприклад, отаке вікно з переліком «контрактів» (показано з уже вибраним окремим контрактом):

Для призначення клієнту діапазону адрес використовується трошки специфічних запитів та шматочок AJAX (генерується таблиця ще не виділених — не наявних у базі — діапазонів потрібного розміру). Це також дописаний до стандартної адмінки віджет:

Подібним чином можна «асоціювати» піддіапазон (шматочок із уже виділених клієнту адрес) з підсмугою:

Звісно, все це для того, щоб можна було автоматизувати процес генерування скрипта :-)
Скрипти генеруються за допомогою специфічних тегів у специфічних представленнях.
Наприклад, ось такий шаблон генерує скрипт для певного «підключення»:
| {% load mylib %}
 
<!-- START -->
<div class="script">
<br />
<span class="comment">#<br />
# <span class="contract">Contract {{conn.contract}}</span>,<br />
{% if conn.contract.is_active %}
  # connection {{conn.id}} (0x{{conn.id|to_hex}}).</span><br />
  {% if conn.is_active %}
    {% for DIR in directions %}
      <!-- {{DIR}}put -->
      <span class="comment">#<br />
      # <span class="direction-{{DIR}}">{{DIR}}put</span>:</span><br />
      {% tc_class action conn DIR %}<br />
      {% if conn.subconnection_set.all %}
        {% for sub in conn.subconnection_set.all %}
          <span class="comment"># sub-conn. <b>{{sub.id}}</b>{% if sub.is_default %} (default) {% endif %}:</span><br />
          {% tc_class action sub DIR %}<br />
          {% ifequal action "add" %}
            {% tc_filters sub DIR %}<br />
          {% endifequal %}
        {% endfor %}
      {% else %}
        {% ifequal action "add" %}
          {% tc_filters conn DIR %}<br />
        {% endifequal %}
      {% endif %}
      {% ifequal action "add" %}
        {% if conn.peersrange_set.all %}
          <span class="comment"># own networks:</span><br />
          {% tc_filters_own conn DIR %}<br />
        {% endif %}
      {% endifequal %}
    {% endfor %}
  {% else %}
    <span class="comment"># inactive.</span>
  {% endif %}
{% else %}
  # inactive.</span>
{% endif %}<br />
</div> | 
Ось такий вигляд має вікно зі згенерованим скриптом для створення класів та фільтрів для певного «підключення» (іденифікатор підключення передається у запиті; на запит без ідентифікатора буде згенеровано увесь скрипт, для всіх підключень всіх клієнтів):

Отакий «інтерфейс» доступний непривілейованим користувачам — це вікно перегляду стану клієнта:

Для цього клієнта створено підсмуги, певним підсмугам призначені певні адреси. Бачите, трафіка ще немає :-) Це пов’язано із тим, що конфігурацію щойно створено, клієнт ще «думає». Трафік буде :-)
Крім продемонстрованих можливостей конфігуратор може:
- призначати різні параметри на «день» та «ніч» (і генерувати скрипти, відповідно, для «день» та «ніч», а також скрипти для переходу між станами — tc class change ...)
- перевіряти введені значення (наприклад, сума rate для всіх підсмуг не може перевищувати ceil відповідної смуги тощо)
- фіксувати делегування діапазонів у RIPE
- шукати клієнта за номером контракту, IP адресою, коментарем…
- … напевно, щось іще, але треба сформулювати :-)
Для моніторингу стану шейпера використовується py-htbstat.
