BMC SNMP 开发三(源码分析)

1.说明

1.1 介绍

这一篇是继两篇文章:

之后的第三篇文章。主要是做基本的代码分析。

1.2 资源回顾

写这篇文章的时候,发现之前写的2篇文章,大致内容已经有人写过了:

2.SNMP代码分析基本流程

2.1 基于代码版本

当前基于snmpd版本5.10,基于linux平台做分析:

$ sudo snmpd -v      

NET-SNMP version:  5.10
Web:               http://www.net-snmp.org/
Email:             net-snmp-coders@lists.sourceforge.net

2.2 基本大框架主要流程

分析:agent\snmpd.c,基本的大的程序流程如下:

main()
---> netsnmp_close_fds(2); //关闭大于2的所有描述符
---> snmp_log_syslogname(app_name); //设置syslog名字为snmpd
---> netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,NETSNMP_DS_LIB_APPTYPE, app_name);//设置为snmpd
---> snmpd_parse_options(&opts, argc, argv)//解析参数
---> snmp_enable_filelog()
---> init_agent(app_name)
---> init_mib_modules()
---> init_snmp(app_name)
---> init_master_agent()
---> netsnmp_daemonize()
---> snmp_store(app_name)
---> send_easy_trap(0, 0)
---> netsnmp_addrcache_initialise()
---> receive()
---> SnmpTrapNodeDown()

其中,init_agent()流程如下:

int init_agent(const char *app)
---> netsnmp_set_agent_starttime(NULL); //设置gettimeofday(&starttime, NULL);和netsnmp_get_monotonic_clock(&starttimeM);
---> setup_tree();
---> init_agent_read_config(app);
	---> register_app_config_handler()
	---> register_app_config_handler()
	---> register_app_config_handler()
	---> ...
	---> netsnmp_ds_register_config()
	---> netsnmp_ds_register_config()
	---> netsnmp_ds_register_config()
	---> ...
	---> netsnmp_init_handler_conf()
		---> snmpd_register_config_handler() 
		---> snmp_register_callback()
		---> se_add_pair_to_slist()
---> _init_agent_callback_transport()
---> netsnmp_init_helpers()
	---> netsnmp_init_debug_helper()
	---> netsnmp_init_serialize()
	---> netsnmp_init_read_only_helper()
	---> netsnmp_init_bulk_to_next_helper()
	---> netsnmp_init_table_dataset()
		---> register_app_config_handler"table", netsnmp_config_parse_table_set, NULL,"tableoid");
		---> register_app_config_handler("add_row", netsnmp_config_parse_add_row, NULL, "table_name indexes... values...");
	---> netsnmp_init_row_merge()
	---> netsnmp_init_stash_cache_helper()
---> init_traps()
---> netsnmp_container_init_list()
---> init_agent_sysORTable()
---> agentx_config_init()
	---> netsnmp_register_default_domain("agentx", "unix tcp");
	---> netsnmp_register_default_target("agentx", "unix", NETSNMP_AGENTX_SOCKET);  //"/var/agentx/master"
	---> netsnmp_register_default_target("agentx", "tcp", "localhost:" val(AGENTX_PORT)); // 705
	
---> netsnmp_udp_agent_config_tokens_register()
---> netsnmp_udp6_agent_config_tokens_register()
---> netsnmp_unix_agent_config_tokens_register()
---> init_perl()
---> netsnmp_certs_agent_init()

这里面有一个函数setup_tree(),调用关系如下:

void setup_tree(void)
---> oid ccitt[1]           = { 0 };
---> oid iso[1]             = { 1 };
---> oid joint_ccitt_iso[1] = { 2 };
---> netsnmp_register_null(snmp_duplicate_objid(ccitt, 1), 1);
	---> netsnmp_register_null_context(loc, loc_len, NULL);
		---> reginfo = SNMP_MALLOC_TYPEDEF(netsnmp_handler_registration);
		---> reginfo->handlerName = strdup("");
		---> reginfo->rootoid = loc;
		---> reginfo->rootoid_len = loc_len;
		---> reginfo->modes = HANDLER_CAN_DEFAULT | HANDLER_CAN_GETBULK;
		---> netsnmp_register_handler(reginfo);
		   ---> netsnmp_register_mib( ... )
		   		---> ...
		   		---> netsnmp_subtree_replace_first()
		   			---> add_subtree(new_tree, context_name);
		   		---> ...
---> netsnmp_register_null(snmp_duplicate_objid(iso, 1), 1);
---> netsnmp_register_null(snmp_duplicate_objid(joint_ccitt_iso, 1), 1);

完成添加根节点的subtree.

函数init_mib_modules()流程如下:

void init_mib_modules(void)
---> #  include "mib_module_inits.h"
---> snmp_register_callback( SNMP_CALLBACK_LIBRARY,
                                     SNMP_CALLBACK_SHUTDOWN,
                                     _shutdown_mib_modules,
                                     NULL);

这里面使用了include代码的方式,实际调用的内容为:

/* This file is automatically generated by configure.  Do not modify by hand. */
  if (should_init("snmpEngine")) init_snmpEngine();
  if (should_init("snmpMPDStats")) init_snmpMPDStats();
  if (should_init("usmStats")) init_usmStats();
  if (should_init("usmUser")) init_usmUser();
  if (should_init("system_mib")) init_system_mib();
  if (should_init("sysORTable")) init_sysORTable();
  if (should_init("snmp_mib")) init_snmp_mib();
  if (should_init("vacm_vars")) init_vacm_vars();
  if (should_init("setSerialNo")) init_setSerialNo();
  if (should_init("at")) init_at();
  if (should_init("ip")) init_ip();
  if (should_init("tcp")) init_tcp();
  if (should_init("udp")) init_udp();
  if (should_init("ipv6")) init_ipv6();
  if (should_init("icmp")) init_icmp();
  if (should_init("proc")) init_proc();
  if (should_init("versioninfo")) init_versioninfo();
  if (should_init("pass")) init_pass();
  if (should_init("pass_persist")) init_pass_persist();
  if (should_init("disk_hw")) init_disk_hw();
  if (should_init("loadave")) init_loadave();
  if (should_init("extend")) init_extend();
  if (should_init("errormib")) init_errormib();
  if (should_init("file")) init_file();
  if (should_init("dlmod")) init_dlmod();
  if (should_init("proxy")) init_proxy();
  if (should_init("logmatch")) init_logmatch();
  if (should_init("memory")) init_memory();
  if (should_init("vmstat")) init_vmstat();
  if (should_init("snmpNotifyTable")) init_snmpNotifyTable();
  if (should_init("snmpNotifyFilterProfileTable")) init_snmpNotifyFilterProfileTable();
  if (should_init("notification_log")) init_notification_log();
  if (should_init("snmpTargetAddrEntry")) init_snmpTargetAddrEntry();
  if (should_init("snmpTargetParamsEntry")) init_snmpTargetParamsEntry();
  if (should_init("target_counters")) init_target_counters();
  if (should_init("nsTransactionTable")) init_nsTransactionTable();
  if (should_init("nsModuleTable")) init_nsModuleTable();
  if (should_init("nsDebug")) init_nsDebug();
  if (should_init("nsCache")) init_nsCache();
  if (should_init("nsLogging")) init_nsLogging();
  if (should_init("nsVacmAccessTable")) init_nsVacmAccessTable();
  if (should_init("mteScalars")) init_mteScalars();
  if (should_init("mteTrigger")) init_mteTrigger();
  if (should_init("mteTriggerTable")) init_mteTriggerTable();
  if (should_init("mteTriggerDeltaTable")) init_mteTriggerDeltaTable();
  if (should_init("mteTriggerExistenceTable")) init_mteTriggerExistenceTable();
  if (should_init("mteTriggerBooleanTable")) init_mteTriggerBooleanTable();
  if (should_init("mteTriggerThresholdTable")) init_mteTriggerThresholdTable();
  if (should_init("mteTriggerConf")) init_mteTriggerConf();
  if (should_init("mteEvent")) init_mteEvent();
  if (should_init("mteEventTable")) init_mteEventTable();
  if (should_init("mteEventSetTable")) init_mteEventSetTable();
  if (should_init("mteEventNotificationTable")) init_mteEventNotificationTable();
  if (should_init("mteEventConf")) init_mteEventConf();
  if (should_init("mteObjects")) init_mteObjects();
  if (should_init("mteObjectsTable")) init_mteObjectsTable();
  if (should_init("mteObjectsConf")) init_mteObjectsConf();
  if (should_init("schedCore")) init_schedCore();
  if (should_init("schedConf")) init_schedConf();
  if (should_init("schedTable")) init_schedTable();
  if (should_init("override")) init_override();
  if (should_init("hr_system")) init_hr_system();
  if (should_init("hr_device")) init_hr_device();
  if (should_init("hr_other")) init_hr_other();
  if (should_init("hr_proc")) init_hr_proc();
  if (should_init("hr_network")) init_hr_network();
  if (should_init("hr_print")) init_hr_print();
  if (should_init("hr_disk")) init_hr_disk();
  if (should_init("hr_partition")) init_hr_partition();
  if (should_init("hrh_storage")) init_hrh_storage();
  if (should_init("hrh_filesys")) init_hrh_filesys();
  if (should_init("hrSWInstalledTable")) init_hrSWInstalledTable();
  if (should_init("hrSWRunTable")) init_hrSWRunTable();
  if (should_init("vacm_context")) init_vacm_context();
  if (should_init("var_route")) init_var_route();
  if (should_init("tcpTable")) init_tcpTable();
  if (should_init("udpTable")) init_udpTable();
  if (should_init("ip_scalars")) init_ip_scalars();
  if (should_init("snmpNotifyTable_data")) init_snmpNotifyTable_data();
  if (should_init("snmpNotifyFilterTable_data_storage")) init_snmpNotifyFilterTable_data_storage();
  if (should_init("snmpNotifyFilterTable")) init_snmpNotifyFilterTable();
  if (should_init("snmpNotifyFilterProfileTable_data")) init_snmpNotifyFilterProfileTable_data();
  if (should_init("snmpTargetAddrEntry_data")) init_snmpTargetAddrEntry_data();
  if (should_init("snmpTargetParamsEntry_data")) init_snmpTargetParamsEntry_data();
  if (should_init("swinst")) init_swinst();
  if (should_init("swrun")) init_swrun();
  if (should_init("hrSWRunPerfTable")) init_hrSWRunPerfTable();
  if (should_init("ifTable")) init_ifTable();
  if (should_init("ifXTable")) init_ifXTable();
  if (should_init("ipAddressTable")) init_ipAddressTable();
  if (should_init("ipAddressPrefixTable")) init_ipAddressPrefixTable();
  if (should_init("ipDefaultRouterTable")) init_ipDefaultRouterTable();
  if (should_init("inetNetToMediaTable")) init_inetNetToMediaTable();
  if (should_init("ipSystemStatsTable")) init_ipSystemStatsTable();
  if (should_init("ipv6ScopeZoneIndexTable")) init_ipv6ScopeZoneIndexTable();
  if (should_init("ipIfStatsTable")) init_ipIfStatsTable();
  if (should_init("ipCidrRouteTable")) init_ipCidrRouteTable();
  if (should_init("inetCidrRouteTable")) init_inetCidrRouteTable();
  if (should_init("tcpConnectionTable")) init_tcpConnectionTable();
  if (should_init("tcpListenerTable")) init_tcpListenerTable();
  if (should_init("udpEndpointTable")) init_udpEndpointTable();
  if (should_init("hw_fsys")) init_hw_fsys();
  if (should_init("hw_mem")) init_hw_mem();
  if (should_init("cpu")) init_cpu();
  if (should_init("cpu_linux")) init_cpu_linux();
  if (should_init("interface")) init_interface();

这些函数内容init_xx(),其实在之前的2篇文章中,可以参考它们。这些代码里面也会包含mib文件,可以参考并对照代码学习

函数init_snmp()调用关系如下:

void init_snmp(const char *type)
---> _init_snmp();
	---> netsnmp_init_mib_internals();
	---> netsnmp_tdomain_init();
	---> gettimeofday(&tv, (struct timezone *) 0);
	---> netsnmp_register_default_domain("snmp", "udp udp6");
	---> netsnmp_register_default_domain("snmptrap", "udp udp6");
	---> netsnmp_register_default_target("snmp", "udp", ":161");
	---> netsnmp_register_default_target("snmp", "tcp", ":161");
	---> netsnmp_register_default_target("snmp", "udp6", ":161");
	---> netsnmp_register_default_target("snmp", "tcp6", ":161");
	---> netsnmp_register_default_target("snmptrap", "udp", ":162");
	---> ...
---> setlocale(LC_CTYPE, "");
---> snmp_debug_init(); 
---> netsnmp_container_init_list();
---> init_callbacks()
---> init_snmp_logging();
---> snmp_init_statistics();
---> register_mib_handlers();
	---> register_prenetsnmp_mib_handler("snmp", "mibdirs", ...)
	---> register_prenetsnmp_mib_handler("snmp", "mibs", ...)
	--->  register_config_handler("snmp", "mibfile", handle_mibfile_conf, NULL, "mibfile-to-read");

---> register_default_handlers();
---> init_snmp_transport();
---> init_snmpv3(type);
---> init_snmp_alarm();
---> init_snmp_enum(type);
---> init_vacm();
---> netsnmp_certs_init()
---> read_premib_configs();
	---> read_config_files(PREMIB_CONFIG);
	---> read_configs_optional(optional_config, PREMIB_CONFIG);
	---> netsnmp_config_process_memories_when(PREMIB_CONFIG, 0);
---> netsnmp_init_mib();
	---> netsnmp_init_mib_internals();
	---> netsnmp_fixup_mib_directory();
	---> add_mibdir(entry);
	---> add_mibfile(entry, NULL);
	---> read_all_mibs();
	---> read_mib(entry);
	---> netsnmp_read_module(entry);
---> read_configs();
	---> read_config_files(NORMAL_CONFIG);
		---> free_config();
		---> read_config_files_of_type(when, ctmp)
	---> read_configs_optional(optional_config, NORMAL_CONFIG);
	---> netsnmp_config_process_memories_when(NORMAL_CONFIG, 1);
```'
函数`netsnmp_init_mib_internals()`定义如下:
```c
static void _init_snmp(void)
---> void netsnmp_init_mib_internals(void)
	---> build_translation_table();
	---> static void init_tree_roots(void)
		---> tp = calloc(1, sizeof(struct tree));
		---> lasttp = tp;
		---> tp = calloc(1, sizeof(struct tree));
		---> tp->next_peer = lasttp;
		---> lasttp = tp;
		---> tp = calloc(1, sizeof(struct tree));
		---> tp->next_peer = lasttp;
		---> tree_head = tp;

其中,tree_head()snmp_add_var()调用:

int
snmp_add_var(netsnmp_pdu *pdu,
             const oid * name, size_t name_length, char type, const char *value)
---> tp = get_tree(name, name_length, get_tree_head());
	---> for (; subtree; subtree = subtree->next_peer) {
		---> if (*objid == subtree->subid)
		}

函数:handle_mibfile_conf()如下:

static void handle_mibfile_conf(const char *token, char *line)
---> read_mib(line);
	---> new_module(token, filename);
	---> netsnmp_read_module(token);
		---> status = read_module_internal(name);
			---> netsnmp_init_mib_internals();
				---> module_map_head = module_map;  //重要的mib对应关系名
				---> build_translation_table();
					---> case OBJID:
					---> case OCTETSTR:
					---> case INTEGER:
					---> case NETADDR:
					---> case IPADDR:
					---> case COUNTER:
					---> case GAUGE:
					---> case TIMETICKS:
					---> case INTEGER32:
					---> ...
				---> init_tree_roots();          /* Set up initial roots */
					---> base_modid = which_module("SNMPv2-SMI");
					---> base_modid = which_module("RFC1155-SMI");
					---> base_modid = which_module("RFC1213-MIB");
					---> tp->label = strdup("joint-iso-ccitt"); //joint-iso-ccitt .2
					---> tp->subid = 2;
					---> tp->label = strdup("ccitt");   //ccitt .0
					---> tp->subid = 0;
					---> tp->label = strdup("iso");     //iso .1
					---> tp->subid = 1; 

这里就是前面的mib文件中定义的几个根节点的OID:

ccitt           .0
iso             .1
joint-iso-ccitt .2

函数:init_master_agent()如下:

int init_master_agent(void)			
---> netsnmp_set_lookup_cache_size(-1);
---> netsnmp_agent_listen_on(cptr)		
	---> transport = netsnmp_transport_open_server("snmp", port);
	---> handle = netsnmp_register_agent_nsap(transport);
---> real_init_master();
		---> snmp_sess_init(&sess);	
			---> _init_snmp();
		---> netsnmp_unix_create_path_with_mode(agentx_dir_perm);
		---> netsnmp_unix_dont_create_path();

---> _pdu_stats_init();

2.3 一个scalar例子的流程

按照之前文章中写到的scalar例子中,大致的代码流程为:

scalar:
init_WITYUANModule()
	const oid wityuanNode_oid[] = { 1,3,6,1,4,1,60000,1,1 };
	netsnmp_handler_registration reg;
	reg = netsnmp_create_handler_registration("wityuanNode", handle_wityuanNode,wityuanNode_oid, OID_LENGTH(wityuanNode_oid), HANDLER_CAN_RWRITE)
		---> netsnmp_mib_handler *handler = netsnmp_create_handler(name, handler_access_method);
			---> netsnmp_mib_handler *ret = SNMP_MALLOC_TYPEDEF(netsnmp_mib_handler);
			---> ret->access_method = handler_access_method;
			---> ret->handler_name = strdup(name);
		---> netsnmp_handler_registration_create(name, handler, reg_oid, reg_oid_len, modes);
			---> netsnmp_handler_registration *the_reg;
			---> the_reg->handler = handler;
			---> the_reg->handlerName = strdup(name);
			---> the_reg->rootoid = snmp_duplicate_objid(reg_oid, reg_oid_len);
	netsnmp_register_scalar(reg)
	---> tmp = (oid*)realloc(reginfo->rootoid,
                                    (reginfo->rootoid_len+1) * sizeof(oid) );
    ---> reginfo->rootoid = tmp;
    ---> reginfo->rootoid[ reginfo->rootoid_len ] = 0;
	---> h1 = netsnmp_get_instance_handler();
		---> netsnmp_create_handler("instance",netsnmp_instance_helper_handler);
			---> netsnmp_mib_handler *ret = SNMP_MALLOC_TYPEDEF(netsnmp_mib_handler);
			---> ret->access_method = handler_access_method;
			---> ret->handler_name = strdup(name);
	---> h2 = netsnmp_get_scalar_handler();
		---> netsnmp_create_handler("scalar",netsnmp_scalar_helper_handler);
			---> netsnmp_mib_handler *ret = SNMP_MALLOC_TYPEDEF(netsnmp_mib_handler);
			---> ret->access_method = handler_access_method;
			---> ret->handler_name = strdup(name);
	---> netsnmp_inject_handler(reginfo, h1)
		handler2->next = reginfo->handler;  //h1->next=reginfo->handler;
	---> netsnmp_inject_handler(reginfo, h2)
		handler2->next = reginfo->handler; //h2->next=reginfo->handler; 
	---> netsnmp_register_serialize(reginfo);
		---> netsnmp_mib_handler *handler = netsnmp_get_serialize_handler();
		---> netsnmp_register_handler(reginfo);
			---> netsnmp_register_mib(reginfo->handlerName,....)

大致流图如下所示:

在这里插入图片描述
可以留意到3行代码:

    tmp = (oid*)realloc(reginfo->rootoid,
                                    (reginfo->rootoid_len+1) * sizeof(oid) );
    reginfo->rootoid = tmp;
    reginfo->rootoid[ reginfo->rootoid_len ] = 0;

因此,对于scalar,总体而言访问的话,其最后应该添加一个.0.

2.4 一个table例子的流程,TBD...

流程类似。

3.snmp oid构建方法,TBD...

后面有机会再来补充吧…

4.snmp parser,TBD...

后面有机会再来补充吧…

5.snmp over ssh

snmp over ssh可以参考如下2篇文章:

6.snmptable的实现原理

snmptablenet-snmp提供的一个工具,调用关系如下:

int main(int argc, char *argv[])
---> netsnmp_set_line_buffering(stdout);
---> snmp_parse_oid(argv[optind], root, &rootlen)
---> get_field_names();
---> reverse_fields();
---> ss = snmp_open(&session);
---> if (use_getbulk) getbulk_table_entries(ss);
	---> pdu = snmp_pdu_create(SNMP_MSG_GETBULK); //使用bulk方式获取table数据
---> else get_table_entries(ss);
	---> pdu = snmp_pdu_create(SNMP_MSG_GETNEXT); //使用getnext方式获取table数据

因此,snmptable使用的是getbulk或者getnext方式获取table数据。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wit_yuan

专注模块功能分析与架构

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值