понедельник, 13 октября 2014 г.

Чтение информации о VLAN по SNMP

Информацию о VLAN'ах коммутатора можно почерпнуть из раздела Dot1qVlanStaticEntry, который находится по адресу 1.3.6.1.2.1.17.7.1.4.3.1 .

Выполним команду (должен быть установлен пакет net-snmp):

snmpwalk -v2c -c public -On 10.90.90.90 .1.3.6.1.2.1.17.7.1.4.3.1

.1.3.6.1.2.1.17.7.1.4.3.1.1.1 = STRING: "default"
.1.3.6.1.2.1.17.7.1.4.3.1.1.3 = STRING: "3"
.1.3.6.1.2.1.17.7.1.4.3.1.1.3130 = STRING: "my_vlan"
.1.3.6.1.2.1.17.7.1.4.3.1.2.1 = Hex-STRING: 00 00 00 00 00 00 00 00
.1.3.6.1.2.1.17.7.1.4.3.1.2.3 = Hex-STRING: 00 00 00 F0 00 00 00 00
.1.3.6.1.2.1.17.7.1.4.3.1.2.3130 = Hex-STRING: FF FF FF E0 00 00 00 00
.1.3.6.1.2.1.17.7.1.4.3.1.3.1 = Hex-STRING: 00 00 00 00 00 00 00 00
.1.3.6.1.2.1.17.7.1.4.3.1.3.3 = Hex-STRING: 00 00 00 00 00 00 00 00
.1.3.6.1.2.1.17.7.1.4.3.1.3.3130 = Hex-STRING: 00 00 00 00 00 00 00 00
.1.3.6.1.2.1.17.7.1.4.3.1.4.1 = Hex-STRING: 00 00 00 00 00 00 00 00
.1.3.6.1.2.1.17.7.1.4.3.1.4.3 = Hex-STRING: 00 00 00 00 00 00 00 00
.1.3.6.1.2.1.17.7.1.4.3.1.4.3130 = Hex-STRING: FF FF FF 60 00 00 00 00
.1.3.6.1.2.1.17.7.1.4.3.1.5.1 = INTEGER: 1
.1.3.6.1.2.1.17.7.1.4.3.1.5.3 = INTEGER: 1
.1.3.6.1.2.1.17.7.1.4.3.1.5.3130 = INTEGER: 1



Внутри раздела Dot1qVlanStaticEntry есть следующие ключи (в примере выделены жирным шрифтом):
dot1qVlanStaticName (1) - Имя VLAN
dot1qVlanStaticEgressPorts (2) - Порты, входящие в VLAN (member ports)
dot1qVlanForbiddenEgressPorts (3) - Порты, исключенные из VLAN (forbidden ports)
dot1qVlanStaticUntaggedPorts (4) - Порты, настроенные как untagged
dot1qVlanStaticRowStatus (5) - Статус записи

Следом идет идентификатор VLAN (VID) (в примере выделен курсивом).

Рассмотрим отдельно VLAN с VID=3130:
.1.3.6.1.2.1.17.7.1.4.3.1.1.3130 = STRING: "my_vlan"
.1.3.6.1.2.1.17.7.1.4.3.1.2.3130 = Hex-STRING: FF FF FF E0 00 00 00 00
.1.3.6.1.2.1.17.7.1.4.3.1.3.3130 = Hex-STRING: 00 00 00 00 00 00 00 00
.1.3.6.1.2.1.17.7.1.4.3.1.4.3130 = Hex-STRING: FF FF FF 60 00 00 00 00
.1.3.6.1.2.1.17.7.1.4.3.1.5.3130 = INTEGER: 1

В этом примере ключи имеют следующие значения:
VLAN name: my_vlan
Member ports: FF FF FF E0 00 00 00 00
Forbidden ports: 00 00 00 00 00 00 00 00
Untagged ports: FF FF FF 60 00 00 00 00
Status: Active (1)

Осталось разобраться как интерпретировать значения вроде FF FF FF E0 00 00 00 00. На самом деле тут все просто - это побитовое перечисление портов, представленное в шестнадцатеричном виде. Последние 4 байта не используются, поэтому нас интересуют только первые 4.
0xFFFFFFE0 это 0b11111111111111111111111111100000 (member ports)
0xFFFFFF60 это 0b11111111111111111111111101100000 (untagged ports)

Удобнее разбить длинную запись 4 группы по 8 бит:
11111111 11111111 11111111 11100000 (member ports)
11111111 11111111 11111111 01100000 (untagged ports) 

Если порт N входит в member ports, то на его месте в такой последовательности стоит 1, иначе - 0. Нумерация в такой записи идет слева направо. Таким образом, в данном случае для VID=3130 member ports будут 1-27, а untagged ports - 1-24,26-27. Порт 25 входит в members, но не входит в диапазон untagged ports. Следовательно 25-й порт настроен как tagged для VID=3130.



8 комментариев:

  1. А есть пример кода на Python или PHP?
    Вот допустим вычитал я с коммуатора OID в котором хранятся порты входящие во VLAN, отрезал лишнее конвертировал в HEX в BIN и... И дальше мне воспринимать строку, как массив/список и, индексы этого массива считать номерами портов, а значения, собственно, показателем того является порт членом вилана или нет? Или есть какой-то более логичный способ?

    ОтветитьУдалить
  2. Забавно, даже вырезать ничего не надо:

    echo base_convert( 'Hex-STRING: 80 00 00 00 00 00 00 00 ' , 16 , 2 );

    ОтветитьУдалить
  3. О как! Буду знать.
    У меня в swtoolz есть функции по вычислению портов, а где то на python была функция вычисления диапазонов как в d-link, т.е. 1-24 и т.п. Правда последняя довольно громоздкая с неочевидным алгоритмом.

    ОтветитьУдалить
    Ответы
    1. Вот и я прикидываю и так и сяк, и все равно получается довольно громоздко, с парой циклов...

      И да тут заметил, что base_convert не совсем правильно отрабатывает если первые порты не являются членами вилана, он просто ведущие нули отбрасывает :( Сделал себе такой кнвертер:

      $hex = array(' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F');
      $bin = array('', '0000', '0001', '0010', '0011', '0100', '0101', '0110', '0111', '1000', '1001', '1010', '1011', '1100', '1101', '1110', '1111');
      str_replace($hex, $bin, str_replace('Hex-STRING: ', '', $member_ports));

      Удалить
    2. Точнее так:
      function member_ports($string)
      {
      $hex = array('Hex-STRING: ',' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F');
      $bin = array('', '', '0000', '0001', '0010', '0011', '0100', '0101', '0110', '0111', '1000', '1001', '1010', '1011', '1100', '1101', '1110', '1111');
      return str_replace($hex, $bin, $string);
      }

      Удалить
  4. Точнее так:
    function member_ports($string)
    {
    $hex = array('Hex-STRING: ',' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F');
    $bin = array('', '', '0000', '0001', '0010', '0011', '0100', '0101', '0110', '0111', '1000', '1001', '1010', '1011', '1100', '1101', '1110', '1111');
    return str_replace($hex, $bin, $string);
    }

    PS
    Прикол какойто. Гугл первый коментраий не публикует, приходится повторно его отправлять :(

    ОтветитьУдалить
  5. последние 4 байта используются в 52-портовых коммутаторах

    кусок перла:

    use Net::SNMP ();

    my %hex_bin = (0,"0000",1,"0001",2,"0010",3,"0011",4,"0100",5,"0101",6,"0110",7,"0111",8,"1000",9,"1001","a","1010","b","1011","c","1100","d","1101","e","1110","f","1111");
    my $oid = "1.3.6.1.2.1.17.7.1.4.3.1.2.$vid";
    my ($session,$error) = Net::SNMP->session(Hostname=>$ip,Community=>$comm, Version=>"2c");

    $result = $session->get_request("$oid");
    $result = substr ($result->{$oid},2);
    chomp($result);
    print "$result\n";
    for ($i = 0;$i <= length($result)-1; $i += 1) {
    $member[$i] = $hex_bin{substr($result,$i,1)};
    print "$member[$i] ";
    }
    print "\n";

    ОтветитьУдалить
  6. на python'e я так делал:

    t = ''.join(['%08d' % int(bin(int('0x%s' % i, 16)).replace('0b', '')) for i in data.aplit(' ')]),

    где data - строка, полученная с коммутатора:
    "FF FF FF E0 00 00 00 00"

    На выходе получаем '1111111111111111111111111110000000000000000000000000000000000000'

    ОтветитьУдалить