понедельник, 25 мая 2015 г.

Конференция в jabber

От скуки зарегистрировал конференцию в джаббере - ccna@conference.jabber.ru.

Собираюсь присутствовать там в рабочее время и, иногда, по вечерам. Заходите, пообщаемся, обсудим нюансы сетестроения. :)

p.s. Из новостей - плотно взялся за PCF ACL на коммутаторах DES-3200-xx/C1. Через пару недель поделюсь результатами.

пятница, 3 апреля 2015 г.

Перезагрузка коммутаторов при помощи Briseis

Продолжим использовать Briseis не по назначению. :) В прошлой заметке мы научились массово обновлять прошивку на коммутаторах, а теперь отправим все перепрошитые коммутаторы в перезагрузку. Будем считать, что мы продолжаем работы, описанные в прошлый раз, так что остановлюсь на самом главном.

В любом месте файла userdict.py определяем списки OID для формирования varbind:

reboot3028 = [
    ['.1.3.6.1.4.1.171.11.63.6.2.1.2.1','0','3','INTEGER']
]

reboot3200 = [
    ['.1.3.6.1.4.1.171.11.113.1.3.2.1.2.1','0','3','INTEGER']
]

reboot3200_c1 = [
    ['.1.3.6.1.4.1.171.12.1.2.19','0','2','INTEGER']
]


reboot_01_04 = [
    ['1.3.6.1.4.1.171.12.1.2.32.1.3','1','\x05\x05','OCTETSTR'],
    ['1.3.6.1.4.1.171.12.1.2.32.1.4','1','\x01\x04\x07\xdf','OCTETSTR'],
    ['1.3.6.1.4.1.171.12.1.2.32.1.5','1','1','INTEGER']
]


Первые 3 списка нужны для мгновенной перезагрузки коммутатора, а 4-й позволяет выполнить отложенную перезагрузку коммутаторов DES-3200-28 ревизии C1.

Теперь в файле bconfig.py исправляем 'PassSetSet' на:
PassSetSet  = {1:['reboot']}

А 'oids_set' на:
oids_set={
    'DES-3200-28':{
       'reboot':reboot3200
    },
    'DES-3200-28/C1':{
        'reboot':reboot3200_c1
    },
    'DES-3028':{
       'reboot':reboot3028
    }
}


Для модели DES-3200-28/C1 при желании можем использовать отложенную перезагрузку, заменив значение 'reboot3200_c1' на 'reboot_01_04'. Поскольку 1-е апреля уже прошло, то есть смысл заменить '\x01\x04' на желаемую дату. Кстати, дата в команде дана скорее для примера оформления hex-значений для net-snmp в Python. На самом деле достаточно указывать только время:
delayed reboot = [
    ['1.3.6.1.4.1.171.12.1.2.32.1.3','1','\x05\x05','OCTETSTR'],
    ['1.3.6.1.4.1.171.12.1.2.32.1.5','1','1','INTEGER']
]

Такой набор позволит планировать перезагрузку в любой день без правки словаря. Перезагрузка произойдет когда часы в следующий раз покажут 5:05.

Закончим это небольшое, но весьма полезное отступление и запустим программу:
./briseis.py start

Не забудем и остановить ее через несколько секунд:
./briseis.py stop

Благодаря тому, что мы используем сохранение конфигурации перед перезагрузкой, а также тому, что все команды отправляются практически одновременно, мы можем перезагружать гирлянды коммутаторов за один подход.

вторник, 31 марта 2015 г.

Перепрошивка коммутаторов с помощью Briseis

Briseis - мой проект для сбора метрик с сетевых устройств. Иногда перед чтением метрики требуется предварительно выполнить операцию записи. Такое может понадобиться, например, при диагностики состояния кабельной линии - сначала выполняется инициализация теста, а затем уже сам сбор результатов. Briseis умеет производить операции snmpset и этой возможностью мы воспользуемся для использования программы не совсем по прямому назначению, а именно - для массовой перепрошивки коммутаторов. :) При этом несколько усложним себе задачу и представим, что мы не знаем с какими именно моделями и ревизиями коммутаторов D-Link нам потребуется работать. Будем считать, что нам известен критерий выбора этих устройств из базы MySQL и их write-community.

1. Для начала напишем MySQL-запрос к нашей СУБД для выбора коммутаторов по некоторому критерию. В моей случае это IP-адрес. В вашем случае это может быть что-то другое, поэтому не вижу смысла приводить здесь мой запрос - важен лишь результат. Убедитесь, что имеете доступ к вашему MySQL-серверу с машины, на которой будете запускать Briseis и что сам запрос возвращает табличку вида:
+------+---------------+-------------+
| id   | ip            | wcomm       |
+------+---------------+-------------+
| 6248 | 10.90.90.91   | private     |
| 6249 | 10.90.90.92   | private     |
| 6250 | 10.90.90.93   | private     |
+------+---------------+-------------+


2. Идем далее. Если мы не знаем, какие модели и ревизии коммутаторов присутствуют в этом списке, то мы можем получить эту информацию из статистики Briseis. Создадим на сервере MySQL базу данных с таблицей для размещения статистики и гарантируем пользователю 'briseis' права для работы с этой таблицей.
CREATE DATABASE IF NOT EXISTS `blackhole` /*!40100 DEFAULT CHARACTER SET utf8 */;
USE `blackhole`;

CREATE TABLE IF NOT EXISTS `stats` (
  `device_id` int(4) unsigned NOT NULL,
  `host` char(16) NOT NULL,
  `mname` char(16) NOT NULL,
  `set_timestamp` int(4) unsigned NOT NULL,
  `walk_timestamp` int(4) unsigned NOT NULL,
  `avail` int(4) unsigned NOT NULL,
  `not_avail` int(4) unsigned NOT NULL,
  `errors` int(4) unsigned NOT NULL,
  `time` int(4) unsigned NOT NULL,
  PRIMARY KEY (`device_id`),
  KEY `host` (`host`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

GRANT USAGE ON *.* TO 'briseis'@'%' IDENTIFIED BY 'briseis_pass';
GRANT ALL PRIVILEGES ON `blackhole`.`stats` TO 'briseis'@'%' WITH GRANT OPTION;


Не помешает выполнить проверку и убедиться, что доступ к таблице получен. После этого переходим к настройке программы.

3. Скачиваем Briseis отсюда. При написании этой заметки я проделал этот несложный маневр при помощи простой команды:
wget https://github.com/xcme/briseis/archive/v1.0.2.tar.gz --no-check-certificate

Распаковываем архив и притупаем к правке bconfig.py. Правим настройки для MySQL на нужные нам, т.е. прописываем адреса серверов, логины, пароли и т.п. Исправляем 'useMySQLstat' на 'True' и не забываем вписать в 'mysql_query_p' запрос, который мы разработали на шаге №1. Исправляем 'logfile', указывая желаемый путь для файла журнала.

Меняем 'PassSetSet' и 'PassSetWalk' на словари с одним пустым списком:
PassSetSet = {1:[]}
PassSetWalk = {1:[]}


Задаем 'oids_set' как пустой словарь, а 'oids_walk' как пустой список:
oids_set={}
oids_walk=[]


Значения 'useGraphite' и 'useAttractor' выставляем в 'False'.

При такой настройки Briseis выполнит только проверку устройств на доступность, опросив их по ключу 'oid_ModelName', и запишет результаты в таблицу статистики.

Важно: При написании заметки обнаружил один нюанс. По умолчанию программа использует '/var/run/briseis.pid' в качестве pid-файла. Доступ к этому каталогу для обычного пользователя может быть закрыт. Если вы не хотите запускать программу от root или давать доступ к этому каталогу, исправьте путь в файле 'briseis.py' на нужный вам. В этом случае программа запустится от обычного пользователя.

4. Сохраним настройки и выполним ручной запуск программы:
./briseis.py start
При появлении в логе сообщения об завершении цикла или же просто через несколько секунд останавливаем программу:
./briseis.py stop
При этом в файле журнала мы увидим примерно следующее:
Connection to MySQL Server '*******' established
MySQL Read-Query '*Select devices*' OK. 17 rows found
(+++) Added 17 devices to database
Polling devices from the database. Attempt #1 of 2 completed for 0.6087 sec
Polling devices from the database. Attempt #2 of 2 completed for 0.0000 sec
Sending set-queries for []...
Completed all set-requests. Elapsed time 0.0470 sec. Going to sleep for 3 sec...
Sending get/walk-queries for []...
Completed all walk-requests. Elapsed time 0.0566 sec
Total number of metrics in memory: 0
Connection to MySQL statistics Server '*******' established
Sended 17 entries to statictics server. Elapsed time 0.0632 sec
------- Pass №1 completed for 4.3851 sec -------


Как видим, 17 устройств было добавлено в память программы из базы, все они оказались доступными (нет сообщений о недоступных устройствах) и 17 записей было отправлено в таблицу статистики.

5. Подключимся к нашему серверу с базой статистики и выполним запрос:
SELECT mname,count(mname) FROM blackhole.stats GROUP by mname;

В ответ получаем:
+----------------+--------------+
| mname          | count(mname) |
+----------------+--------------+
| DES-3028       |           13 |
| DES-3200-28    |            1 |
| DES-3200-28/C1 |            3 |
+----------------+--------------+
3 rows in set (0.01 sec)


Прекрасно! Теперь мы знаем с какими устройствами нам предстоит работать.

6. Теперь нам нужно научить Briseis заливать ПО на коммутаторы. Если модели устройств были бы известны нам заранее, этот пункт можно было выполнять сразу после шага №1.

В любом месте файла userdict.py определяем списки OID для формирования varbind:
fw_up3200 = [
    ['1.3.6.1.4.1.171.12.1.2.1.1.3','1','10.90.90.101','IPADDR'],
    ['1.3.6.1.4.1.171.12.1.2.1.1.4','1','2','INTEGER'],
    ['1.3.6.1.4.1.171.12.1.2.1.1.5','1','DES-3200R_1.85.B008.had','OCTETSTR'],
    ['1.3.6.1.4.1.171.12.1.2.1.1.7','1','3','INTEGER'],
    ['1.3.6.1.4.1.171.12.1.2.1.1.8','1','3','INTEGER'],
    ['1.3.6.1.4.1.171.12.1.2.1.1.9','1','2','INTEGER'],
    ['1.3.6.1.4.1.171.12.1.2.1.1.10','1','1','INTEGER'],
]

fw_up3028 = [
    ['1.3.6.1.4.1.171.12.1.2.1.1.3','1','10.90.90.101','IPADDR'],
    ['1.3.6.1.4.1.171.12.1.2.1.1.4','1','2','INTEGER'],
    ['1.3.6.1.4.1.171.12.1.2.1.1.5','1','DES_3028_52_V2.94-B07.had','OCTETSTR'],
    ['1.3.6.1.4.1.171.12.1.2.1.1.7','1','3','INTEGER'],
    ['1.3.6.1.4.1.171.12.1.2.1.1.8','1','3','INTEGER'],
    ['1.3.6.1.4.1.171.12.1.2.1.1.9','1','2','INTEGER'],
    ['1.3.6.1.4.1.171.12.1.2.1.1.10','1','1','INTEGER'],
]

fw_up3200_c1 = [
    ['1.3.6.1.4.1.171.12.1.2.18.1.1.3','1','10.90.90.101','IPADDR'],
    ['1.3.6.1.4.1.171.12.1.2.18.1.1.5','1','DES3200R_4.39.B008.had','OCTETSTR'],
    ['1.3.6.1.4.1.171.12.1.2.18.1.1.8','1','3','INTEGER'],
    ['1.3.6.1.4.1.171.12.1.2.18.1.1.12','1','3','INTEGER'],
]


TFTP-сервером в нашем примере будет '10.90.90.101'. Значения остальных параметров рекомендую посмотреть тут.

Важно: Пакет net-snmp в какой то из версий имеет баг, не позволяющий работать с типом IPADDR в python-модуле. В этом случае при работе Briseis пакет не будет сформирован и ничего не произойдет. Если вы уверены, что делаете все правильно, но при этом результата нет - обновите пакет net-snmp.

Исправляем 'PassSetSet':
PassSetSet  = {1:['FW_upd']}

Исправляем 'oids_set':
oids_set={
    'DES-3200-28':{
        'FW_upd':fw_up3200
    },
    'DES-3200-28/C1':{
        'FW_upd':fw_up3200_c1
    },
    'DES-3028':{
        'FW_upd':fw_up3028
    }
}


Правим 'snmp_Retries':
snmp_Retries  = 0

Это нужно чтобы запрос отправлялся только 1 раз. При получении первого запроса на обновление ПО коммутатор может быть занят выполнением команды и не успеет отправить подтверждение. Когда мы выставляем 0 дополнительных попыток, то спасаем коммутатор от обновления ПО несколько раз - по 1 на каждую попытку.

Запускаем программу:
./briseis.py start
И через 5 секунд останавливаем:
./briseis.py stop
В логе видим:
Sending set-queries for ['FW_upd']...
Completed all set-requests. Elapsed time 0.2973 sec. Going to sleep for 3 sec...


7. Через 3-5 минут проверяем коммутаторы. Видим, что прошивка успешно загрузилась. Теперь в 'oids_set' комментируем строки:
#    'DES-3200-28/C1':{
#        'FW_upd':fw_up3200_c1
#    },

В файле userdict.py в списках 'fw_up3200' и 'fw_up3028' меняем строку
['1.3.6.1.4.1.171.12.1.2.1.1.10','1','1','INTEGER'],
на
['1.3.6.1.4.1.171.12.1.2.1.1.10','1','2','INTEGER'],

После чего снова запускаем и останавливаем программу
./briseis.py start
./briseis.py stop


Этими действиями мы перепрошили второй образ для DES-3200-28 и DES-3028, исключив при этом из обработки модель DES-3200-28/C1.

Все прошивки обновлены, осталось только перезагрузить коммутаторы. Об этом, быть может, в другой раз.

пятница, 27 марта 2015 г.

Attractor - Анализатор метрик, собираемых с сетевых устройств

В прошлом посте упоминал про анализатор метрик. Теперь он доступен тут: https://github.com/xcme/attractor

Attractor - Анализатор метрик, собираемых Briseis.

Программа может работать только в паре в Briseis, где и собираются сами метрики. Документация прилагается в комплекте.

среда, 11 марта 2015 г.

Briseis - демон для FreeBSD для сбора метрик по SNMP с устройств в сети

Как и обещал, выкладываю свой инструмент для сбора метрик с устройств в сети. Взять его можно тут: https://github.com/xcme/briseis


Briseis - мощный, гибкий и быстрый инструмент для сбора метрик с устройств в сети по протоколу SNMPv2. Написанный на Python и представленный в виде Unix-демона, он позволяет собирать большие объемы данных в несколько потоков и передавать их в Graphite и анализатор метрик Attractor. Этот инструмент будет полезен, прежде всего, сетевым администраторам.

Остальные детали можно уточнить, перейдя по ссылке. Через несколько дней выложу анализатор собираемых метрик, который называется Attractor.

понедельник, 9 марта 2015 г.

Мои проекты на GitHub

В конце прошлого года обещал поделиться некоторыми своими наработками, выложив их в открытый доступ. В течении первых двух месяцев этого года я обкатывал в работе и шлифовал сервисы сбора и анализа метрик с коммутаторов D-Link. Теперь, когда они готовы, их надо где-то разместить. Выбор пал на GitHub. Однако, поскольку мой опыт работы с этим сервисом оставляет желать лучшего, я решил сначала потренироваться на "кошках" и сначала разместить свой старый проект SWToolz.

Следующим будет Briseis - многопроцессорный и многопоточный поллер для сбора данных по SNMP, работающий демоном под FreeBSD.

воскресенье, 1 февраля 2015 г.

Ingress Checking и LLDP

После месячного перерыва появилась тема для новой заметки. На этот раз поговорим об LLDP и Ingress Checking. Если кому-то интересна предыстория, с ней можно ознакомиться здесь. Ниже я просто опишу выводы.

На моделях DES-3200-XX A1/B1 согласно информации от D-Link "начиная с прошивки 1.52.B004 Ingress Checking действует также и на BPDU пакетики, поэтому PVID магистральных портов должен быть равен VID реально существующего на них влана либо нужно отключать Ingress Checking."

На практике это означает, что для работы LLDP следует либо выключить Ingress Checking совсем, либо для каждого коммутатора подбирать настройки с учетом имеющихся на нем VLAN'ов.

Что же такое Ingress Checking*? Это "проверка попадания" кадра в набор VID, ассоцирированных с портом. Если функционал Ingress Checking включен, то при поступлении в порт коммутатора кадра производится сравнение VID кадра с набором идентификаторов VID, ассоциированных с портом (включая PVID порта). Если нет, то кадр отбрасывается. Если же функционал Ingress Checking выключен, то никакой проверки не производится.

В моем случае получалось, что VLAN на порту отсутствовал, но фрейм с его ID прилетал на коммутатор, который заносил MAC-адрес в таблицу коммутации. Немного подумав, коммутатор выкидывал этот MAC из таблицы коммутации до истечения fdb aging time. Видимо, он сам чувствовал, что здесь что-то не так! Но через несколько секунд MAC появлялся в таблице снова. В результате коммутатор генерировал большое количество MAC-notify трапов, благодаря чему, собственно, и был найден. После включения Ingress Checking безобразия прекращались, но переставал работать LLDP. Происходило так потому, что магистральные порты не настраивались как untagged, поэтому PVID там был равен 1. А после удаления с портов vlan default фреймы LLDP попадали под проверку функционалом Ingress Checking и отбрасывались.

Решение было найдено следующее: прописывать на магистральных портах PVID равный VID multicast-vlan'a. Удобство здесь в том, что данный VLAN присутствует на всех коммутаторах сети и на каждом имеет один и тот же ID. Это позволяет указывать такой PVID одинаковым для любого коммутатора, независимо от имеющихся на нем VLAN. В результате и настройка одинакова для всех коммутаторов и LLDP работает и некорректные фреймы с абонентских портов блокируются.

*Updated 2017.08.23:
Теперь приведено описание Ingress Checking для более общего случая. Раньше описывался вариант для untagged-порта.