Поднимаем Q-in-Q в Linux Debian + pppoe server + dhcp relay + dhcpd

Вобщем суть такова, что решил я на провайдере начать использовать q-in-q, чтобы оптимизировать работу с большим количеством vlan-ов, в связи с переходом на схему vlan-на-свитч доступа (до этого была схема vlan-на-агрегацию).
прокидывать по трассе кучу вланов до каждого коммутатора доступа, удовольствия мало, добавлять рутину в работу желания нет, а обезопасить лишний раз сетку не помешало бы.
Помимо всего прочего используем мы pppoe-server-а на линухах, поэтому немного почитав и пораскинув мозгами пришел к такой схеме:
На сервере запускаем первичные vlan-ы с id от 100 до 254, а в них упаковывем в каждый еще по 24 vlan-а с id 101..124.
Дальше гоним до агрегации района только первичные вланы, а упакованые в них раскрываем на агрегации в сторону свитчей доступа. 1 порт - vlan101, 2 порт - vlan102 и так далее по 24 порт.
На стороне сервера нам также необходимо запустить pppoe-server на каждый вторичный vlan и повесить на него подсетку.
Подсетки будем вешать тоже в зависимости от VLANID.
Например на интерфейсе vlan150.105 будет подсеть 10.150.105.1/24, на интерфейсе vlan221.114 будет подсеть 10.221.114.1/24 и так далее.
И еще у нас работает на серваке dhcp-relay, необходимо чтобы он подхватывал все новые интерфейсы.
Для того чтобы не запускать это всё ручками как дебилу, решил написать удобный скрипт
/etc/network/if-up.d/qinq

#!/bin/bash
 
case "$1" in
  up)
    LINEA=$IFACE
    for i in `seq 101 124`;
      do
        vconfig set_name_type DEV_PLUS_VID_NO_PAD
        VLANID=`echo $IFACE|sed "s/vlan0*//"`
        vconfig add $IFACE $i
        ifconfig $IFACE.$i 10.$VLANID.$i.1 netmask 255.255.255.0 up
        /usr/sbin/pppoe-server -I $IFACE.$i -L 176.16.0.1 -N 50 -T 300 -k
        LINEA="$LINEA $IFACE.$i"
      done
    sed -i "/INTERFACES=/a $LINEA" /etc/default/isc-dhcp-relay
    echo "isc-dhcp-relay restarting..."
    sleep 1
    /etc/init.d/isc-dhcp-relay restart
    ;;
  down)
    LINEA=$IFACE
    for i in `seq 101 124`;
      do
        PID=`ps aux | grep "pppoe-server -I $IFACE.$i" | grep 'usr' | awk {'print $2'}`
        kill $PID
        vconfig rem $IFACE.$i
        LINEA="$LINEA $IFACE.$i"
      done
    sed -i "/$LINEA/d" /etc/default/isc-dhcp-relay
    echo "isc-dhcp-relay restarting..."
    sleep 1
    /etc/init.d/isc-dhcp-relay restart
    ;;
esac

файл /etc/default/isc-dhcp-relay необходимо привести к такому виду:
(двойную ковычку у интерфейсов переносим на следующую строку)

# Defaults for isc-dhcp-relay initscript
# sourced by /etc/init.d/isc-dhcp-relay
# installed at /etc/default/isc-dhcp-relay by the maintainer scripts
#
# This is a POSIX shell fragment
#
# What servers should the DHCP relay forward requests to?
SERVERS="192.168.201.201"
 
# On what interfaces should the DHCP relay (dhrelay) serve DHCP requests?
INTERFACES="
"
 
# Additional options that are passed to the DHCP relay daemon?
OPTIONS=""

А вот так выглядит вырезка из /etc/network/interfaces

#тест
auto vlan245
iface vlan245 inet static
address 10.245.100.1
netmask 255.255.255.0   
vlan_raw_device eth0
post-up /etc/network/if-up.d/qinq up
pre-down /etc/network/if-up.d/qinq down

Ну и осталось еще удобно добавлять подсетки в dhcp-server.
Суть такова, что интерфейсов с подсетками много и держать всё в одном конфиге неудобно, поэтому я решил делать отдельный конфиг для каждого первичного влана, а внутри конфига уже настройки на 24 вторичных влана. Конфиги, а также шаблон, с которого эти конфиги будут генериться лежат в каталоге /etc/dhcp/qinq.d/ и все эти конфиги мы инклудим в главный конфиг.
Для этого тоже написал отдельный скриптик.

#!/bin/bash
 
# Скрипт создает конфигурационный файл dhcpd, согласно заданному шаблону ($MUESTRA) для интерфейсов q-in-q
# В качестве первой переменной нужно указать ID первичного Vlan
 
CARPETA=/etc/dhcp/qinq.d/
MUESTRA=vlanXXX.conf
CONFIG=/etc/dhcp/dhcpd.conf
 
cat $CARPETA/$MUESTRA | sed "s/XXX/$1/g;" > $CARPETA/vlan$1.conf
sed -i "/#INCLUDES/a include \"/etc/dhcp/qinq.d/vlan$1.conf\";" $CONFIG
 
echo "isc-dhcp-server restarting..."
sleep 1
/etc/init.d/isc-dhcp-server restart

Якорем, после которого вставляем инклуды является #INCLUDES, поэтому в главном конфиге в конце добавляем

shared-network QINQ {
#INCLUDES
}

Шаблон vlanXXX.conf вышел достаточно громосским приведу лишь пример из него на дву подсети

class "vlanXXX.101" {
        match if (binary-to-ascii(10,8, ".", packet(24,4)) = "10.XXX.101.1");
}
class "vlanXXX.102" {
        match if (binary-to-ascii(10,8, ".", packet(24,4)) = "10.XXX.102.1");
}
subnet 10.XXX.101.0 netmask 255.255.255.0 {
  pool {
    allow members of "vlanXXX.101";
    option routers 10.XXX.101.1;
    option broadcast-address 10.XXX.101.255;
    range 10.XXX.101.10 10.XXX.101.250;
  }
}
subnet 10.XXX.102.0 netmask 255.255.255.0 {
  pool {
    allow members of "vlanXXX.102";
    option routers 10.XXX.102.1;
    option broadcast-address 10.XXX.102.255;
    range 10.XXX.102.10 10.XXX.102.250;
  }
}

думаю, что 154 влана (100..254) должно с лихвой хватить, умножаем еще на 24 внутри каждого и получается 3696. Не много не мало, а работы я cебе на будущее убавил вагон и схему при желании можно смаштабировать еще в несколько раз )))