Почему SNMP это не очень просто?

в 10:02, , рубрики: Без рубрики

Меньше месяца назад, на Хабре была опубликована статья, рассказывающая о том, как использовать популярную библиотеку, для работы с SNMP из Java-приложения. Поддерживая, в целом, начинание автора, я хочу остановиться на тех сложностях, которые могут возникнуть в реальном проекте, использующем SNMP.

Читаем документацию

Для начала я хотел бы остановиться на том, что мне не совсем понятно, почему из всего многообразия SNMP-запросов автор остановился на TRAP-ах? Посмотрим, что пишет по этому поводу RFC 1157:

The strategy implicit in the SNMP is that the monitoring of network state at any significant level of detail is accomplished primarily by polling for appropriate information on the part of the monitoring center(s). A limited number of unsolicited messages (traps) guide the timing and focus of the polling. Limiting the number of unsolicited messages is consistent with the goal of simplicity and
minimizing the amount of traffic generated by the network management function.

Для тех, у кого сложности с английским языком, имеется русский перевод:

Стратегия SNMP заключается в том, что мониторинг состояния сети с любым значимым уровнем детализации выполняется главным образом путем опроса из центра мониторинга. Ограниченное число незапрашиваемых сообщений (trap — прерывание) обеспечивает синхронизацию и активизирует опросы. Ограничение числа незапрашиваемых сообщений согласуется с задачами обеспечения простоты и минимизации трафика, создаваемого системой сетевого управления.

Из этих цитат, вполне понятно, что запросы с типами TRAP и INFORM это не наиболее часто используемая часть SNMP. Статью для начинающих было бы более уместно иллюстрировать примерами использования гораздо более ходовых GET-запросов.

Вообще я настоятельно рекомендую ознакомиться со всеми RFC, связанными с SNMP перед началом работы. Некоторые аспекты SNMP не очевидны и имеет смысл получить о них представление из первоисточника. Начать ознакомление с материалом можно с wiki.

Первые шаги

Помимо обязательного ознакомления с документацией, важно понимать, для чего мы все это делаем. В практике телекома, наиболее часто встречаются следующие задачи:

  1. Опрос оборудования по SNMP (аккаунтинг, мониторинг)
  2. Управление оборудованием по SNMP (активация)

Задачи, связанные с опросом оборудования сводятся к формированию GET (и как будет показано далее GETNEXT) запросов. Управление оборудованием сводится к отсылке SET-запросов, изменяющих состояние соответствующих переменных на оборудовании (например, таким образом, можно отключить какой либо интерфейс).

Задача SNMP-мониторинга выделяется на общем фоне требованием того, что опрашиваемого оборудования много или очень много. Предположим, что именно эту задачу нам и предстоит решать.

Начнем писать код. В тестовом примере мы обратимся по SNMP к собственному хосту и прочитаем значение переменной, заданной OID-ом 1.3.6.1.2.1.1.3.0 и содержащей значение uptime-а хоста:

Одиночный GET-запрос

package com.amfitel.m2000.ae.tests.snmp;

import java.io.IOException;

import org.snmp4j.CommunityTarget;
import org.snmp4j.PDU;
import org.snmp4j.Snmp;
import org.snmp4j.Target;
import org.snmp4j.TransportMapping;
import org.snmp4j.event.ResponseEvent;
import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.smi.Address;
import org.snmp4j.smi.GenericAddress;
import org.snmp4j.smi.OID;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.VariableBinding;
import org.snmp4j.transport.DefaultUdpTransportMapping;

public class Test {
	
	private final static String SNMP_COMMUNITY = "public";
	private final static int    SNMP_RETRIES   = 3;
	private final static long   SNMP_TIMEOUT   = 1000L;
	
	private Snmp snmp = null;
	private TransportMapping transport = null;
	
	private void test() throws IOException {
		Target t = getTarget("udp:127.0.0.1/161");
		String r = send(t, "1.3.6.1.2.1.1.3.0");
		System.out.println(r);
	}
	
	private String send(Target target, String oid) throws IOException {
		PDU pdu = new PDU();
		pdu.add(new VariableBinding(new OID(oid)));
		pdu.setType(PDU.GET);
		ResponseEvent event = snmp.send(pdu, target, null);
		if (event != null) {
			return event.getResponse().get(0).toString();
		} else {
			return "Timeout exceeded";
		}
	}
	
	private Target getTarget(String address) {
		Address targetAddress = GenericAddress.parse(address);
		CommunityTarget target = new CommunityTarget();
		target.setCommunity(new OctetString(SNMP_COMMUNITY));
		target.setAddress(targetAddress);
		target.setRetries(SNMP_RETRIES);
		target.setTimeout(SNMP_TIMEOUT);
		target.setVersion(SnmpConstants.version1);
		return target;
	}
	
	private void start() throws IOException {
		transport = new DefaultUdpTransportMapping();
		snmp = new Snmp(transport);
		transport.listen();
	}
	
	private void stop() throws IOException {
		try {
			if (transport != null) {
				transport.close();
				transport = null;
			}
		} finally {
			if (snmp != null) {
				snmp.close();
				snmp = null;
			}
		}
	}
	
	public static void main(String[] args) {
		Test t = new Test();
		try {
			try {
				t.start();
				t.test();
			} finally {
				t.stop();
			}
		} catch (IOException e) {
			System.out.println(e.toString());
		}
	}
}

Предварительно убедившись, что служба SNMP на нашем хосте работает и запустив код на выполнение, получим искомое значение uptime-а (времени безостановочной работы хоста с момента последней загрузки):

1.3.6.1.2.1.1.3.0 = 2:28:55.06

Используя это значение, можно осуществлять мониторинг. Если мы обнаруживаем, что значением уменьшилось — значит хост успел перезагрузиться с момента очередного опроса. Если хост не ответил в течение заданного таймаута (после нескольких автоматически сделанных попыток) это, скорее всего, означает, что хост не работает. Все просто?

Подсчитали — прослезились

Не совсем. Вспоминаем о том, что нам предстоит выполнять много запросов. Давайте промеряем, сколько запросов мы можем выполнить в секунду? Внесем небольшое исправление в код:

	private void test() throws IOException {
		Target t = getTarget("udp:127.0.0.1/161");
		Long timestamp = System.currentTimeMillis();
		for (int i = 0; i < 1000; i++) {
			send(t, "1.3.6.1.2.1.1.3.0");
		}
		System.out.println(1000000L /(System.currentTimeMillis() - timestamp));
	}

И запустим его на выполнение:

2463

Почти две с половиной тысячи запросов в секунду! Неплохо?

Не будем торопиться. Мы отправляем запросы на Loopback интерфейс, а он работает несколько быстрее локальной сети. Посмотрим, сколько запросов в секунду мы успеем выполнить к другому хосту в нашей сети:

182

Не дотягиваем даже до двухсот. Вообще говоря, возможно, этого будет достаточно. Все зависит от задачи. Но мы проводили измерения при условии, что опрашиваемый хост доступен. Что будет если хост не ответит?

Будет несколько попыток доступа (в нашем коде мы задали 3) разделенных таймаутом (1000 мсек). Это означает, что за секунду мы не успеем выполнить ни одного запроса. Поскольку не отвечающий хост является не такой уж большой редкостью, это может стать большой проблемой в реальном проекте.

Идем на рекорд

Что с этим можно сделать? Если бы мы имели дело с каким либо синхронным протоколом (например telnet), особого выбора бы у нас не было. Для того, чтобы увеличить производительность, нам пришлось бы одновременно выполнять много потоков. Но SNMP асинхронен по своей природе! Не надо насильственно втискивать его в синхронные рамки.

Как перейти к асинхронному варианту? В нашем случае, довольно просто:

Асинхронные запросы

package com.amfitel.m2000.ae.tests.snmp;

import java.io.IOException;

import org.snmp4j.CommunityTarget;
import org.snmp4j.PDU;
import org.snmp4j.Snmp;
import org.snmp4j.Target;
import org.snmp4j.TransportMapping;
import org.snmp4j.event.ResponseEvent;
import org.snmp4j.event.ResponseListener;
import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.smi.Address;
import org.snmp4j.smi.GenericAddress;
import org.snmp4j.smi.OID;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.VariableBinding;
import org.snmp4j.transport.DefaultUdpTransportMapping;

public class Test implements ResponseListener {
	
	private final static String SNMP_COMMUNITY = "public";
	private final static int    SNMP_RETRIES   = 3;
	private final static long   SNMP_TIMEOUT   = 1000L;
	
	private Snmp snmp = null;
	private TransportMapping transport = null;
	
	public void onResponse(ResponseEvent event) {
		PDU response = event.getResponse();
		if (response != null) {
			System.out.println(response.get(0).toString());
			return;
		}
	}
	
	private void test() throws IOException {
		Target t = getTarget("udp:192.168.131.253/161");
		Long timestamp = System.currentTimeMillis();
		for (int i = 0; i < 1000; i++) {
			send(t, "1.3.6.1.2.1.1.3.0");
		}
		System.out.println(1000000L /(System.currentTimeMillis() - timestamp));
	}
	
	private void send(Target target, String oid) throws IOException {
		PDU pdu = new PDU();
		pdu.add(new VariableBinding(new OID(oid)));
		pdu.setType(PDU.GET);
		snmp.send(pdu, target, null, this);
	}
	
	private Target getTarget(String address) {
		Address targetAddress = GenericAddress.parse(address);
		CommunityTarget target = new CommunityTarget();
		target.setCommunity(new OctetString(SNMP_COMMUNITY));
		target.setAddress(targetAddress);
		target.setRetries(SNMP_RETRIES);
		target.setTimeout(SNMP_TIMEOUT);
		target.setVersion(SnmpConstants.version1);
		return target;
	}
	
	private void start() throws IOException {
		transport = new DefaultUdpTransportMapping();
		snmp = new Snmp(transport);
		transport.listen();
	}
	
	private void stop() throws IOException {
		try {
			if (transport != null) {
				transport.close();
				transport = null;
			}
		} finally {
			if (snmp != null) {
				snmp.close();
				snmp = null;
			}
		}
	}
	
	public static void main(String[] args) {
		Test t = new Test();
		try {
			try {
				t.start();
				t.test();
			} finally {
				t.stop();
			}
		} catch (IOException e) {
			System.out.println(e.toString());
		}
	}
}

7142

Запросы все равно что проваливаются в бездонную бочку! Разумеется, ответы будут приходить с задержкой, но приходить они будут тоже довольно быстро. Но как мы узнаем, что хост не ответил?

Очень просто, по истечении заданного количества попыток и таймаутов, SNMP4J вернет нам event, response в котором будет равен null:

Исправленный вариант

package com.amfitel.m2000.ae.tests.snmp;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

import org.snmp4j.CommunityTarget;
import org.snmp4j.PDU;
import org.snmp4j.Snmp;
import org.snmp4j.Target;
import org.snmp4j.TransportMapping;
import org.snmp4j.event.ResponseEvent;
import org.snmp4j.event.ResponseListener;
import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.smi.Address;
import org.snmp4j.smi.GenericAddress;
import org.snmp4j.smi.Integer32;
import org.snmp4j.smi.OID;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.VariableBinding;
import org.snmp4j.transport.DefaultUdpTransportMapping;

public class Test implements ResponseListener {
	
	private final static String SNMP_COMMUNITY = "public";
	private final static int    SNMP_RETRIES   = 3;
	private final static long   SNMP_TIMEOUT   = 1000L;
	
	private Snmp snmp = null;
	private TransportMapping transport = null;
	
	private Set<Integer32> requests = new HashSet<Integer32>();
	private Long firstTimestamp = null; 
	private long lastTimestamp; 
	
	public void onResponse(ResponseEvent event) {
		Integer32 requestId = event.getRequest().getRequestID();
		PDU response = event.getResponse();
		if (response != null) {
			lastTimestamp = System.currentTimeMillis();
			if (firstTimestamp == null) {
				firstTimestamp = lastTimestamp;
			}
			return;
		} else {
			synchronized (requests) {
				if (requests.contains(requestId)) {
					System.out.println("Timeout exceeded");
				}
			}
		}
		synchronized (requests) {
			requests.remove(requestId);
		}
	}
	
	private void test() throws IOException {
		Target t = getTarget("udp:192.168.131.253/161");
		Long timestamp = System.currentTimeMillis();
		for (int i = 0; i < 1000; i++) {
			send(t, "1.3.6.1.2.1.1.3.0");
		}
		System.out.println(1000000L /(System.currentTimeMillis() - timestamp));
		while (!requests.isEmpty()) {
			try {
				Thread.sleep(1000L);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		if (firstTimestamp != null) {
			System.out.println(1000000L /(lastTimestamp - firstTimestamp));
		}
	}
	
	private void send(Target target, String oid) throws IOException {
		PDU pdu = new PDU();
		pdu.add(new VariableBinding(new OID(oid)));
		pdu.setType(PDU.GET);
		snmp.send(pdu, target, null, this);
		synchronized (requests) {
			requests.add(pdu.getRequestID());
		}
	}
	
	private Target getTarget(String address) {
		Address targetAddress = GenericAddress.parse(address);
		CommunityTarget target = new CommunityTarget();
		target.setCommunity(new OctetString(SNMP_COMMUNITY));
		target.setAddress(targetAddress);
		target.setRetries(SNMP_RETRIES);
		target.setTimeout(SNMP_TIMEOUT);
		target.setVersion(SnmpConstants.version1);
		return target;
	}
	
	private void start() throws IOException {
		transport = new DefaultUdpTransportMapping();
		snmp = new Snmp(transport);
		transport.listen();
	}
	
	private void stop() throws IOException {
		try {
			if (transport != null) {
				transport.close();
				transport = null;
			}
		} finally {
			if (snmp != null) {
				snmp.close();
				snmp = null;
			}
		}
	}
	
	public static void main(String[] args) {
		Test t = new Test();
		try {
			try {
				t.start();
				t.test();
			} finally {
				t.stop();
			}
		} catch (IOException e) {
			System.out.println(e.toString());
		}
	}
}

Проанализируем результат выполнения:

9174
283

Мы успеваем сформировать 9174 запросов в секунду, а опрашиваемое устройство успевает обрабатывать запросы со скоростью 283 запроса в секунду. На большую часть запросов оно ответить не успевает (соответственно в логе остаются сообщения «Timeout exceeded»). Разумеется, это не будет проблемой когда мы начнем опрашивать большое количество устройств с разумным интервалом между запросами.

Идем далее

Мы научились получать по SNMP значения скалярных переменных. Но, помимо них, в SNMP есть еще и таблицы (например таблица интерфейсов на устройстве). Как они устроены? Посмотрим MIB-browser:

image

В OID mgmt.interfaces (1.3.6.1.2.1.2) мы видим скалярную переменную ifNumber (1.3.6.1.2.1.2.1), содержащую количество интерфейсов в таблице, а также набор столбцов. Каждый из столбцов имеет собственный OID. Например столбец содержащий числовой индекс ifIndex интерфейса имеет OID = 1.3.6.1.2.1.2.2.1.1.

Для того, чтобы получить значение этой переменной, необходимо добавить к OID-у индекс интерфейса (например для интерфейса с индексом 123 OID = 1.3.6.1.2.1.2.2.1.1.123). Но как нам получить индексы интерфейсов? Они совсем не обязательно идут по порядку! Например, на моей машине, таблица интерфейсов выглядит так:

image

Именно для этой цели был придуман запрос GETNEXT. Передавая в этот запрос префикс OID-а, мы получаем OID и значение следующей (в лексикографическом порядке) за этим префиксом переменной. Это означает, что передав префиксы OID-ов столбцов таблицы, мы получим OID-ы и значения первой ее строки. Чтобы получить следующую строку, надо выполнить еще один запрос, передав в него OID-ы, полученные предыдущим запросом. И так до тех пор, пока мы не просмотрим всю таблицу.

Разумеется, с учетом всего сказанного выше, нам следует минимизировать количество запросов (это также необходимо с учетом того, что в рамках одного запроса, согласно RFC, предоставляются консистентные данные, если мы запросим индекс и имя интерфейса двумя последовательными запросами, они возможно не будут соответствовать друг-другу). В рамках 1-ой версии SNMP, мы должны читать всю строку таблицы одним запросом.

Следует заметить, что довольно удобно то, что OID-ы скалярных переменных также представляют собой префиксы. Например, для переменной sysUpTime OID, на самом деле равен 1.3.6.1.2.1.1.3. Мы можем передать его в GETNEXT запрос и получить OID = 1.3.6.1.2.1.1.3.0 вместе с соответствующим значением. Это дает возможность запрашивать скалярные значения вместе с значениями столбцов таблиц, в одном запросе.

Просмотр первой строки таблицы

package com.amfitel.m2000.ae.tests.snmp;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

import org.snmp4j.CommunityTarget;
import org.snmp4j.PDU;
import org.snmp4j.Snmp;
import org.snmp4j.Target;
import org.snmp4j.TransportMapping;
import org.snmp4j.event.ResponseEvent;
import org.snmp4j.event.ResponseListener;
import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.smi.Address;
import org.snmp4j.smi.GenericAddress;
import org.snmp4j.smi.Integer32;
import org.snmp4j.smi.OID;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.VariableBinding;
import org.snmp4j.transport.DefaultUdpTransportMapping;

public class Test implements ResponseListener {
	
	private final static String SNMP_COMMUNITY = "public";
	private final static int    SNMP_RETRIES   = 3;
	private final static long   SNMP_TIMEOUT   = 1000L;
	
	private Snmp snmp = null;
	private TransportMapping transport = null;
	
	private Set<Integer32> requests = new HashSet<Integer32>();
	
	public void onResponse(ResponseEvent event) {
		Integer32 requestId = event.getRequest().getRequestID();
		PDU response = event.getResponse();
		if (response != null) {
			System.out.println(response.toString());
			return;
		} else {
			synchronized (requests) {
				if (requests.contains(requestId)) {
					System.out.println("Timeout exceeded");
				}
			}
		}
		synchronized (requests) {
			requests.remove(requestId);
		}
	}
	
	private void test() throws IOException {
		Target t = getTarget("udp:127.0.0.1/161");
		send(t, new String[] {"1.3.6.1.2.1.1.3", "1.3.6.1.2.1.2.2.1.1", "1.3.6.1.2.1.2.2.1.2"});
	}
	
	private void send(Target target, String[] oids) throws IOException {
		PDU pdu = new PDU();
		for (String oid: oids) {
			pdu.add(new VariableBinding(new OID(oid)));
		}
		pdu.setType(PDU.GETNEXT);
		ResponseEvent event = snmp.send(pdu, target, null);
		synchronized (requests) {
			requests.add(pdu.getRequestID());
		}
		onResponse(event);
	}
	
	private Target getTarget(String address) {
		Address targetAddress = GenericAddress.parse(address);
		CommunityTarget target = new CommunityTarget();
		target.setCommunity(new OctetString(SNMP_COMMUNITY));
		target.setAddress(targetAddress);
		target.setRetries(SNMP_RETRIES);
		target.setTimeout(SNMP_TIMEOUT);
		target.setVersion(SnmpConstants.version1);
		return target;
	}
	
	private void start() throws IOException {
		transport = new DefaultUdpTransportMapping();
		snmp = new Snmp(transport);
		transport.listen();
	}
	
	private void stop() throws IOException {
		try {
			if (transport != null) {
				transport.close();
				transport = null;
			}
		} finally {
			if (snmp != null) {
				snmp.close();
				snmp = null;
			}
		}
	}
	
	public static void main(String[] args) {
		Test t = new Test();
		try {
			try {
				t.start();
				t.test();
			} finally {
				t.stop();
			}
		} catch (IOException e) {
			System.out.println(e.toString());
		}
	}
}

Запустив этот код на выполнение, мы получим следующий response:

RESPONSE[requestID=1170688508, errorStatus=Success(0), errorIndex=0, VBS[1.3.6.1.2.1.1.3.0 = 4:50:53.72; 1.3.6.1.2.1.2.2.1.1.1 = 1; 1.3.6.1.2.1.2.2.1.2.1 = 4d:53:20:54:43:50:20:4c:6f:6f:70:62:61:63:6b:20:69:6e:74:65:72:66:61:63:65:00]]

Мы получили значение uptime-а, индекс первого интерфейса и его имя, закодированное строкой октетов в шестнадцатеричном представлении. Чтобы получить следующие строки, мы должны выполнять последовательные запросы, передавая ранее полученные OID-ы.

С учетом необходимости поддержки возможности асинхронной обработки, это может стать нетривиальной (но вполне решаемой) задачей. К счастью, во 2-ой версии SNMP были добавлены bulk-запросы, автоматизирующие получение табличных данных и минимизирующие количество отсылаемых при этом запросов. Внесем необходимые изменения в код:

BULK-запрос

package com.amfitel.m2000.ae.tests.snmp;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

import org.snmp4j.CommunityTarget;
import org.snmp4j.PDU;
import org.snmp4j.Snmp;
import org.snmp4j.Target;
import org.snmp4j.TransportMapping;
import org.snmp4j.event.ResponseEvent;
import org.snmp4j.event.ResponseListener;
import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.smi.Address;
import org.snmp4j.smi.GenericAddress;
import org.snmp4j.smi.Integer32;
import org.snmp4j.smi.OID;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.VariableBinding;
import org.snmp4j.transport.DefaultUdpTransportMapping;

public class Test implements ResponseListener {
	
	private final static String SNMP_COMMUNITY = "public";
	private final static int    SNMP_RETRIES   = 3;
	private final static long   SNMP_TIMEOUT   = 1000L;
	private final static int    BULK_SIZE      = 50;
	
	private Snmp snmp = null;
	private TransportMapping transport = null;
	
	private Set<Integer32> requests = new HashSet<Integer32>();
	
	public void onResponse(ResponseEvent event) {
		Integer32 requestId = event.getRequest().getRequestID();
		PDU response = event.getResponse();
		if (response != null) {
			System.out.println(response.toString());
			return;
		} else {
			synchronized (requests) {
				if (requests.contains(requestId)) {
					System.out.println("Timeout exceeded");
				}
			}
		}
		synchronized (requests) {
			requests.remove(requestId);
		}
	}
	
	private void test() throws IOException {
		Target t = getTarget("udp:127.0.0.1/161");
		send(t, new String[] {"1.3.6.1.2.1.1.3", "1.3.6.1.2.1.2.2.1.1", "1.3.6.1.2.1.2.2.1.2"});
	}
	
	private void send(Target target, String[] oids) throws IOException {
		PDU pdu = new PDU();
		for (String oid: oids) {
			pdu.add(new VariableBinding(new OID(oid)));
		}
		pdu.setType(PDU.GETBULK);
		pdu.setMaxRepetitions(BULK_SIZE);
		pdu.setNonRepeaters(1);
		ResponseEvent event = snmp.send(pdu, target, null);
		synchronized (requests) {
			requests.add(pdu.getRequestID());
		}
		onResponse(event);
	}
	
	private Target getTarget(String address) {
		Address targetAddress = GenericAddress.parse(address);
		CommunityTarget target = new CommunityTarget();
		target.setCommunity(new OctetString(SNMP_COMMUNITY));
		target.setAddress(targetAddress);
		target.setRetries(SNMP_RETRIES);
		target.setTimeout(SNMP_TIMEOUT);
		target.setVersion(SnmpConstants.version2c);
		return target;
	}
	
	private void start() throws IOException {
		transport = new DefaultUdpTransportMapping();
		snmp = new Snmp(transport);
		transport.listen();
	}
	
	private void stop() throws IOException {
		try {
			if (transport != null) {
				transport.close();
				transport = null;
			}
		} finally {
			if (snmp != null) {
				snmp.close();
				snmp = null;
			}
		}
	}
	
	public static void main(String[] args) {
		Test t = new Test();
		try {
			try {
				t.start();
				t.test();
			} finally {
				t.stop();
			}
		} catch (IOException e) {
			System.out.println(e.toString());
		}
	}
}

Выполнив этот запрос, мы получаем все строки таблицы одним запросом:

Много данных

RESPONSE[requestID=1801703572, errorStatus=Success(0), errorIndex=0, VBS[1.3.6.1.2.1.1.3.0 = 4:58:44.56; 1.3.6.1.2.1.2.2.1.1.1 = 1; 1.3.6.1.2.1.2.2.1.2.1 = 4d:53:20:54:43:50:20:4c:6f:6f:70:62:61:63:6b:20:69:6e:74:65:72:66:61:63:65:00; 1.3.6.1.2.1.2.2.1.1.2 = 2; 1.3.6.1.2.1.2.2.1.2.2 = 56:4d:77:61:72:65:20:56:69:72:74:75:61:6c:20:45:74:68:65:72:6e:65:74:20:41:64:61:70:74:65:72:20:66:6f:72:20:56:4d:6e:65:74:38:00; 1.3.6.1.2.1.2.2.1.1.3 = 3; 1.3.6.1.2.1.2.2.1.2.3 = 56:4d:77:61:72:65:20:56:69:72:74:75:61:6c:20:45:74:68:65:72:6e:65:74:20:41:64:61:70:74:65:72:20:66:6f:72:20:56:4d:6e:65:74:31:00; 1.3.6.1.2.1.2.2.1.1.65541 = 65541; 1.3.6.1.2.1.2.2.1.2.65541 = 52:65:61:6c:74:65:6b:20:52:54:4c:38:31:36:38:2f:38:31:31:31:20:50:43:49:2d:45:20:47:69:67:61:62:69:74:20:45:74:68:65:72:6e:65:74:20:4e:49:43:20:2d:20:44:65:74:65:72:6d:69:6e:69:73:74:69:63:20:4e:65:74:77:6f:72:6b:20:45:6e:68:61:6e:63:65:72:20:4d:69:6e:69:70:6f:72:74:00; 1.3.6.1.2.1.2.2.1.1.65542 = 65542; 1.3.6.1.2.1.2.2.1.2.65542 = 4e:6f:72:74:65:6c:20:49:50:53:45:43:53:48:4d:20:41:64:61:70:74:65:72:20:2d:20:44:65:74:65:72:6d:69:6e:69:73:74:69:63:20:4e:65:74:77:6f:72:6b:20:45:6e:68:61:6e:63:65:72:20:4d:69:6e:69:70:6f:72:74:00; 1.3.6.1.2.1.2.2.1.1.65543 = 65543; 1.3.6.1.2.1.2.2.1.2.65543 = 4e:6f:72:74:65:6c:20:56:50:4e:20:41:64:61:70:74:65:72:20:2d:20:44:65:74:65:72:6d:69:6e:69:73:74:69:63:20:4e:65:74:77:6f:72:6b:20:45:6e:68:61:6e:63:65:72:20:4d:69:6e:69:70:6f:72:74:00; 1.3.6.1.2.1.2.2.1.2.1 = 4d:53:20:54:43:50:20:4c:6f:6f:70:62:61:63:6b:20:69:6e:74:65:72:66:61:63:65:00; 1.3.6.1.2.1.2.2.1.3.1 = 24; 1.3.6.1.2.1.2.2.1.2.2 = 56:4d:77:61:72:65:20:56:69:72:74:75:61:6c:20:45:74:68:65:72:6e:65:74:20:41:64:61:70:74:65:72:20:66:6f:72:20:56:4d:6e:65:74:38:00; 1.3.6.1.2.1.2.2.1.3.2 = 6; 1.3.6.1.2.1.2.2.1.2.3 = 56:4d:77:61:72:65:20:56:69:72:74:75:61:6c:20:45:74:68:65:72:6e:65:74:20:41:64:61:70:74:65:72:20:66:6f:72:20:56:4d:6e:65:74:31:00; 1.3.6.1.2.1.2.2.1.3.3 = 6; 1.3.6.1.2.1.2.2.1.2.65541 = 52:65:61:6c:74:65:6b:20:52:54:4c:38:31:36:38:2f:38:31:31:31:20:50:43:49:2d:45:20:47:69:67:61:62:69:74:20:45:74:68:65:72:6e:65:74:20:4e:49:43:20:2d:20:44:65:74:65:72:6d:69:6e:69:73:74:69:63:20:4e:65:74:77:6f:72:6b:20:45:6e:68:61:6e:63:65:72:20:4d:69:6e:69:70:6f:72:74:00; 1.3.6.1.2.1.2.2.1.3.65541 = 6; 1.3.6.1.2.1.2.2.1.2.65542 = 4e:6f:72:74:65:6c:20:49:50:53:45:43:53:48:4d:20:41:64:61:70:74:65:72:20:2d:20:44:65:74:65:72:6d:69:6e:69:73:74:69:63:20:4e:65:74:77:6f:72:6b:20:45:6e:68:61:6e:63:65:72:20:4d:69:6e:69:70:6f:72:74:00; 1.3.6.1.2.1.2.2.1.3.65542 = 6; 1.3.6.1.2.1.2.2.1.2.65543 = 4e:6f:72:74:65:6c:20:56:50:4e:20:41:64:61:70:74:65:72:20:2d:20:44:65:74:65:72:6d:69:6e:69:73:74:69:63:20:4e:65:74:77:6f:72:6b:20:45:6e:68:61:6e:63:65:72:20:4d:69:6e:69:70:6f:72:74:00; 1.3.6.1.2.1.2.2.1.3.65543 = 6; 1.3.6.1.2.1.2.2.1.3.1 = 24; 1.3.6.1.2.1.2.2.1.4.1 = 1520; 1.3.6.1.2.1.2.2.1.3.2 = 6; 1.3.6.1.2.1.2.2.1.4.2 = 1500; 1.3.6.1.2.1.2.2.1.3.3 = 6; 1.3.6.1.2.1.2.2.1.4.3 = 1500; 1.3.6.1.2.1.2.2.1.3.65541 = 6; 1.3.6.1.2.1.2.2.1.4.65541 = 1500; 1.3.6.1.2.1.2.2.1.3.65542 = 6; 1.3.6.1.2.1.2.2.1.4.65542 = 1402; 1.3.6.1.2.1.2.2.1.3.65543 = 6; 1.3.6.1.2.1.2.2.1.4.65543 = 1376; 1.3.6.1.2.1.2.2.1.4.1 = 1520; 1.3.6.1.2.1.2.2.1.5.1 = 10000000; 1.3.6.1.2.1.2.2.1.4.2 = 1500; 1.3.6.1.2.1.2.2.1.5.2 = 100000000; 1.3.6.1.2.1.2.2.1.4.3 = 1500; 1.3.6.1.2.1.2.2.1.5.3 = 100000000; 1.3.6.1.2.1.2.2.1.4.65541 = 1500; 1.3.6.1.2.1.2.2.1.5.65541 = 100000000; 1.3.6.1.2.1.2.2.1.4.65542 = 1402; 1.3.6.1.2.1.2.2.1.5.65542 = 10000000; 1.3.6.1.2.1.2.2.1.4.65543 = 1376; 1.3.6.1.2.1.2.2.1.5.65543 = 10000000; 1.3.6.1.2.1.2.2.1.5.1 = 10000000; 1.3.6.1.2.1.2.2.1.6.1 = ; 1.3.6.1.2.1.2.2.1.5.2 = 100000000; 1.3.6.1.2.1.2.2.1.6.2 = 00:50:56:c0:00:08; 1.3.6.1.2.1.2.2.1.5.3 = 100000000; 1.3.6.1.2.1.2.2.1.6.3 = 00:50:56:c0:00:01; 1.3.6.1.2.1.2.2.1.5.65541 = 100000000; 1.3.6.1.2.1.2.2.1.6.65541 = 00:18:f3:08:06:13; 1.3.6.1.2.1.2.2.1.5.65542 = 10000000; 1.3.6.1.2.1.2.2.1.6.65542 = 44:45:53:54:42:00; 1.3.6.1.2.1.2.2.1.5.65543 = 10000000; 1.3.6.1.2.1.2.2.1.6.65543 = 00:ff:97:65:06:be; 1.3.6.1.2.1.2.2.1.6.1 = ; 1.3.6.1.2.1.2.2.1.7.1 = 1; 1.3.6.1.2.1.2.2.1.6.2 = 00:50:56:c0:00:08; 1.3.6.1.2.1.2.2.1.7.2 = 1; 1.3.6.1.2.1.2.2.1.6.3 = 00:50:56:c0:00:01; 1.3.6.1.2.1.2.2.1.7.3 = 1; 1.3.6.1.2.1.2.2.1.6.65541 = 00:18:f3:08:06:13; 1.3.6.1.2.1.2.2.1.7.65541 = 1; 1.3.6.1.2.1.2.2.1.6.65542 = 44:45:53:54:42:00; 1.3.6.1.2.1.2.2.1.7.65542 = 1; 1.3.6.1.2.1.2.2.1.6.65543 = 00:ff:97:65:06:be; 1.3.6.1.2.1.2.2.1.7.65543 = 1; 1.3.6.1.2.1.2.2.1.7.1 = 1; 1.3.6.1.2.1.2.2.1.8.1 = 1; 1.3.6.1.2.1.2.2.1.7.2 = 1; 1.3.6.1.2.1.2.2.1.8.2 = 1; 1.3.6.1.2.1.2.2.1.7.3 = 1; 1.3.6.1.2.1.2.2.1.8.3 = 1; 1.3.6.1.2.1.2.2.1.7.65541 = 1; 1.3.6.1.2.1.2.2.1.8.65541 = 1; 1.3.6.1.2.1.2.2.1.7.65542 = 1; 1.3.6.1.2.1.2.2.1.8.65542 = 1; 1.3.6.1.2.1.2.2.1.7.65543 = 1; 1.3.6.1.2.1.2.2.1.8.65543 = 2; 1.3.6.1.2.1.2.2.1.8.1 = 1; 1.3.6.1.2.1.2.2.1.9.1 = 0:00:00.00; 1.3.6.1.2.1.2.2.1.8.2 = 1; 1.3.6.1.2.1.2.2.1.9.2 = 0:00:00.00; 1.3.6.1.2.1.2.2.1.8.3 = 1; 1.3.6.1.2.1.2.2.1.9.3 = 0:00:00.00; 1.3.6.1.2.1.2.2.1.8.65541 = 1; 1.3.6.1.2.1.2.2.1.9.65541 = 0:00:00.00; 1.3.6.1.2.1.2.2.1.8.65542 = 1; 1.3.6.1.2.1.2.2.1.9.65542 = 0:00:00.00; 1.3.6.1.2.1.2.2.1.8.65543 = 2; 1.3.6.1.2.1.2.2.1.9.65543 = 0:00:00.00; 1.3.6.1.2.1.2.2.1.9.1 = 0:00:00.00; 1.3.6.1.2.1.2.2.1.10.1 = 3542209; 1.3.6.1.2.1.2.2.1.9.2 = 0:00:00.00; 1.3.6.1.2.1.2.2.1.10.2 = 40700]]

Разумеется, если таблица содержит более затребованных 50-ти строк, вновь (как и для 1-ой версии SNMP) потребуется формировать запросы для получения последующих строк, передавая в них OID-ыполученные для последней строки.

О чем я не рассказал?

В этой статье я не рассказал о многом. Я не рассказал о том, как изменять значения некоторых (не всех) переменных SET-запросами. Я не рассказал о том, что такое TRAP-ы и для чего они нужны. Я ни сказал ни слова о том, как разрабатывать SNMP-агенты. И я ни одним словом не обмолвился о 3-ей версии SNMP и привнесенных ей изменениях.

Но даже того о чем я сказал вполне достаточно, чтобы понять, что SNMP — это не просто.

При серьезном подходе к вопросу.

Автор: GlukKazan

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js