object save optimization - object properties divided into groups and anly modified...
[public/netxms.git] / src / server / core / interface.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003-2017 Victor Kirhenshtein
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 **
19 ** File: interface.cpp
20 **
21 **/
22
23 #include "nxcore.h"
24 #include <ieee8021x.h>
25
26 /**
27 * Default constructor for Interface object
28 */
29 Interface::Interface() : NetObj()
30 {
31 m_parentInterfaceId = 0;
32 nx_strncpy(m_description, m_name, MAX_DB_STRING);
33 m_alias[0] = 0;
34 m_index = 0;
35 m_type = IFTYPE_OTHER;
36 m_mtu = 0;
37 m_speed = 0;
38 m_bridgePortNumber = 0;
39 m_slotNumber = 0;
40 m_portNumber = 0;
41 m_peerNodeId = 0;
42 m_peerInterfaceId = 0;
43 m_peerDiscoveryProtocol = LL_PROTO_UNKNOWN;
44 m_adminState = IF_ADMIN_STATE_UNKNOWN;
45 m_operState = IF_OPER_STATE_UNKNOWN;
46 m_pendingOperState = IF_OPER_STATE_UNKNOWN;
47 m_confirmedOperState = IF_OPER_STATE_UNKNOWN;
48 m_dot1xPaeAuthState = PAE_STATE_UNKNOWN;
49 m_dot1xBackendAuthState = BACKEND_STATE_UNKNOWN;
50 memset(m_macAddr, 0, MAC_ADDR_LENGTH);
51 m_lastDownEventId = 0;
52 m_pendingStatus = -1;
53 m_statusPollCount = 0;
54 m_operStatePollCount = 0;
55 m_requiredPollCount = 0; // Use system default
56 m_zoneUIN = 0;
57 m_pingTime = PING_TIME_TIMEOUT;
58 m_pingLastTimeStamp = 0;
59 m_ifTableSuffixLen = 0;
60 m_ifTableSuffix = NULL;
61 }
62
63 /**
64 * Constructor for "fake" interface object
65 */
66 Interface::Interface(const InetAddressList& addrList, UINT32 zoneUIN, bool bSyntheticMask) : NetObj()
67 {
68 m_parentInterfaceId = 0;
69 m_flags = bSyntheticMask ? IF_SYNTHETIC_MASK : 0;
70 if (addrList.isLoopbackOnly())
71 m_flags |= IF_LOOPBACK;
72
73 _tcscpy(m_name, _T("unknown"));
74 _tcscpy(m_description, _T("unknown"));
75 m_alias[0] = 0;
76 m_ipAddressList.add(addrList);
77 m_index = 1;
78 m_type = IFTYPE_OTHER;
79 m_mtu = 0;
80 m_speed = 0;
81 m_bridgePortNumber = 0;
82 m_slotNumber = 0;
83 m_portNumber = 0;
84 m_peerNodeId = 0;
85 m_peerInterfaceId = 0;
86 m_peerDiscoveryProtocol = LL_PROTO_UNKNOWN;
87 m_adminState = IF_ADMIN_STATE_UNKNOWN;
88 m_operState = IF_OPER_STATE_UNKNOWN;
89 m_pendingOperState = IF_OPER_STATE_UNKNOWN;
90 m_confirmedOperState = IF_OPER_STATE_UNKNOWN;
91 m_dot1xPaeAuthState = PAE_STATE_UNKNOWN;
92 m_dot1xBackendAuthState = BACKEND_STATE_UNKNOWN;
93 memset(m_macAddr, 0, MAC_ADDR_LENGTH);
94 m_lastDownEventId = 0;
95 m_pendingStatus = -1;
96 m_statusPollCount = 0;
97 m_operStatePollCount = 0;
98 m_requiredPollCount = 0; // Use system default
99 m_zoneUIN = zoneUIN;
100 m_isHidden = true;
101 m_pingTime = PING_TIME_TIMEOUT;
102 m_pingLastTimeStamp = 0;
103 m_ifTableSuffixLen = 0;
104 m_ifTableSuffix = NULL;
105 }
106
107 /**
108 * Constructor for normal interface object
109 */
110 Interface::Interface(const TCHAR *name, const TCHAR *descr, UINT32 index, const InetAddressList& addrList, UINT32 ifType, UINT32 zoneUIN)
111 : NetObj()
112 {
113 if ((ifType == IFTYPE_SOFTWARE_LOOPBACK) || addrList.isLoopbackOnly())
114 m_flags = IF_LOOPBACK;
115 else
116 m_flags = 0;
117
118 m_parentInterfaceId = 0;
119 nx_strncpy(m_name, name, MAX_OBJECT_NAME);
120 nx_strncpy(m_description, descr, MAX_DB_STRING);
121 m_alias[0] = 0;
122 m_index = index;
123 m_type = ifType;
124 m_mtu = 0;
125 m_speed = 0;
126 m_ipAddressList.add(addrList);
127 m_bridgePortNumber = 0;
128 m_slotNumber = 0;
129 m_portNumber = 0;
130 m_peerNodeId = 0;
131 m_peerInterfaceId = 0;
132 m_adminState = IF_ADMIN_STATE_UNKNOWN;
133 m_operState = IF_OPER_STATE_UNKNOWN;
134 m_pendingOperState = IF_OPER_STATE_UNKNOWN;
135 m_confirmedOperState = IF_OPER_STATE_UNKNOWN;
136 m_peerDiscoveryProtocol = LL_PROTO_UNKNOWN;
137 m_dot1xPaeAuthState = PAE_STATE_UNKNOWN;
138 m_dot1xBackendAuthState = BACKEND_STATE_UNKNOWN;
139 memset(m_macAddr, 0, MAC_ADDR_LENGTH);
140 m_lastDownEventId = 0;
141 m_pendingStatus = -1;
142 m_statusPollCount = 0;
143 m_operStatePollCount = 0;
144 m_requiredPollCount = 0; // Use system default
145 m_zoneUIN = zoneUIN;
146 m_isHidden = true;
147 m_pingTime = PING_TIME_TIMEOUT;
148 m_pingLastTimeStamp = 0;
149 m_ifTableSuffixLen = 0;
150 m_ifTableSuffix = NULL;
151 }
152
153 /**
154 * Interface class destructor
155 */
156 Interface::~Interface()
157 {
158 free(m_ifTableSuffix);
159 }
160
161 /**
162 * Returns last ping time
163 */
164 UINT32 Interface::getPingTime()
165 {
166 if ((time(NULL) - m_pingLastTimeStamp) > g_dwStatusPollingInterval)
167 {
168 updatePingData();
169 nxlog_debug(7, _T("Interface::getPingTime: update ping time is required! Last ping time %d."), m_pingLastTimeStamp);
170 }
171 return m_pingTime;
172 }
173
174 /**
175 * Create object from database record
176 */
177 bool Interface::loadFromDatabase(DB_HANDLE hdb, UINT32 dwId)
178 {
179 bool bResult = false;
180
181 m_id = dwId;
182
183 if (!loadCommonProperties(hdb))
184 return false;
185
186 DB_STATEMENT hStmt = DBPrepare(hdb,
187 _T("SELECT if_type,if_index,node_id,")
188 _T("mac_addr,required_polls,bridge_port,phy_slot,")
189 _T("phy_port,peer_node_id,peer_if_id,description,")
190 _T("dot1x_pae_state,dot1x_backend_state,admin_state,")
191 _T("oper_state,peer_proto,alias,mtu,speed,parent_iface,")
192 _T("iftable_suffix FROM interfaces WHERE id=?"));
193 if (hStmt == NULL)
194 return false;
195 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
196
197 DB_RESULT hResult = DBSelectPrepared(hStmt);
198 if (hResult == NULL)
199 {
200 DBFreeStatement(hStmt);
201 return false; // Query failed
202 }
203
204 if (DBGetNumRows(hResult) != 0)
205 {
206 m_type = DBGetFieldULong(hResult, 0, 0);
207 m_index = DBGetFieldULong(hResult, 0, 1);
208 UINT32 nodeId = DBGetFieldULong(hResult, 0, 2);
209 DBGetFieldByteArray2(hResult, 0, 3, m_macAddr, MAC_ADDR_LENGTH, 0);
210 m_requiredPollCount = DBGetFieldLong(hResult, 0, 4);
211 m_bridgePortNumber = DBGetFieldULong(hResult, 0, 5);
212 m_slotNumber = DBGetFieldULong(hResult, 0, 6);
213 m_portNumber = DBGetFieldULong(hResult, 0, 7);
214 m_peerNodeId = DBGetFieldULong(hResult, 0, 8);
215 m_peerInterfaceId = DBGetFieldULong(hResult, 0, 9);
216 DBGetField(hResult, 0, 10, m_description, MAX_DB_STRING);
217 m_dot1xPaeAuthState = (WORD)DBGetFieldLong(hResult, 0, 11);
218 m_dot1xBackendAuthState = (WORD)DBGetFieldLong(hResult, 0, 12);
219 m_adminState = (WORD)DBGetFieldLong(hResult, 0, 13);
220 m_operState = (WORD)DBGetFieldLong(hResult, 0, 14);
221 m_confirmedOperState = m_operState;
222 m_peerDiscoveryProtocol = (LinkLayerProtocol)DBGetFieldLong(hResult, 0, 15);
223 DBGetField(hResult, 0, 16, m_alias, MAX_DB_STRING);
224 m_mtu = DBGetFieldULong(hResult, 0, 17);
225 m_speed = DBGetFieldUInt64(hResult, 0, 18);
226 m_parentInterfaceId = DBGetFieldULong(hResult, 0, 19);
227
228 TCHAR suffixText[128];
229 DBGetField(hResult, 0, 20, suffixText, 128);
230 StrStrip(suffixText);
231 if (suffixText[0] == 0)
232 {
233 UINT32 suffix[16];
234 size_t l = SNMPParseOID(suffixText, suffix, 16);
235 if (l > 0)
236 {
237 m_ifTableSuffixLen = (int)l;
238 m_ifTableSuffix = (UINT32 *)nx_memdup(suffix, l * sizeof(UINT32));
239 }
240 }
241
242 m_pingTime = PING_TIME_TIMEOUT;
243 m_pingLastTimeStamp = 0;
244
245 // Link interface to node
246 if (!m_isDeleted)
247 {
248 NetObj *object = FindObjectById(nodeId);
249 if (object == NULL)
250 {
251 nxlog_write(MSG_INVALID_NODE_ID, EVENTLOG_ERROR_TYPE, "dd", dwId, nodeId);
252 }
253 else if (object->getObjectClass() != OBJECT_NODE)
254 {
255 nxlog_write(MSG_NODE_NOT_NODE, EVENTLOG_ERROR_TYPE, "dd", dwId, nodeId);
256 }
257 else
258 {
259 object->addChild(this);
260 addParent(object);
261 m_zoneUIN = ((Node *)object)->getZoneUIN();
262 bResult = true;
263 }
264 }
265 else
266 {
267 bResult = true;
268 }
269 }
270
271 DBFreeResult(hResult);
272 DBFreeStatement(hStmt);
273
274 // Read IP addresses
275 hStmt = DBPrepare(hdb, _T("SELECT ip_addr,ip_netmask FROM interface_address_list WHERE iface_id = ?"));
276 if (hStmt != NULL)
277 {
278 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
279 hResult = DBSelectPrepared(hStmt);
280 if (hResult != NULL)
281 {
282 int count = DBGetNumRows(hResult);
283 for(int i = 0; i < count; i++)
284 {
285 InetAddress addr = DBGetFieldInetAddr(hResult, i, 0);
286 addr.setMaskBits(DBGetFieldLong(hResult, i, 1));
287 if (addr.isValid())
288 m_ipAddressList.add(addr);
289 }
290 DBFreeResult(hResult);
291 }
292 DBFreeStatement(hStmt);
293 }
294
295 // Load access list
296 loadACLFromDB(hdb);
297
298 // Validate loopback flag
299 if (m_type == IFTYPE_SOFTWARE_LOOPBACK)
300 {
301 m_flags |= IF_LOOPBACK;
302 }
303 else
304 {
305 const ObjectArray<InetAddress> *list = m_ipAddressList.getList();
306 int count = 0;
307 for(int i = 0; i < list->size(); i++)
308 {
309 if (list->get(i)->isLoopback())
310 count++;
311 }
312 if ((count > 0) && (count == list->size())) // all loopback addresses
313 m_flags |= IF_LOOPBACK;
314 else
315 m_flags &= ~IF_LOOPBACK;
316 }
317
318 return bResult;
319 }
320
321 /**
322 * Save interface object to database
323 */
324 bool Interface::saveToDatabase(DB_HANDLE hdb)
325 {
326 TCHAR szMacStr[16];
327 UINT32 dwNodeId;
328
329 lockProperties();
330
331 if (!saveCommonProperties(hdb))
332 {
333 unlockProperties();
334 return false;
335 }
336
337 // Determine owning node's ID
338 bool success;
339 if (m_modified & MODIFY_INTERFACE_PROPERTIES)
340 {
341 Node *pNode = getParentNode();
342 if (pNode != NULL)
343 dwNodeId = pNode->getId();
344 else
345 dwNodeId = 0;
346
347 // Form and execute INSERT or UPDATE query
348 DB_STATEMENT hStmt;
349 if (IsDatabaseRecordExist(hdb, _T("interfaces"), _T("id"), m_id))
350 {
351 hStmt = DBPrepare(hdb,
352 _T("UPDATE interfaces SET node_id=?,if_type=?,if_index=?,mac_addr=?,")
353 _T("required_polls=?,bridge_port=?,phy_slot=?,phy_port=?,")
354 _T("peer_node_id=?,peer_if_id=?,description=?,admin_state=?,")
355 _T("oper_state=?,dot1x_pae_state=?,dot1x_backend_state=?,")
356 _T("peer_proto=?,alias=?,mtu=?,speed=?,parent_iface=?,")
357 _T("iftable_suffix=? WHERE id=?"));
358 }
359 else
360 {
361 hStmt = DBPrepare(hdb,
362 _T("INSERT INTO interfaces (node_id,if_type,if_index,mac_addr,")
363 _T("required_polls,bridge_port,phy_slot,phy_port,peer_node_id,peer_if_id,description,")
364 _T("admin_state,oper_state,dot1x_pae_state,dot1x_backend_state,peer_proto,alias,mtu,speed,")
365 _T("parent_iface,iftable_suffix,id) ")
366 _T("VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"));
367 }
368 if (hStmt == NULL)
369 {
370 unlockProperties();
371 return FALSE;
372 }
373
374 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, dwNodeId);
375 DBBind(hStmt, 2, DB_SQLTYPE_INTEGER, m_type);
376 DBBind(hStmt, 3, DB_SQLTYPE_INTEGER, m_index);
377 DBBind(hStmt, 4, DB_SQLTYPE_VARCHAR, BinToStr(m_macAddr, MAC_ADDR_LENGTH, szMacStr), DB_BIND_STATIC);
378 DBBind(hStmt, 5, DB_SQLTYPE_INTEGER, (LONG)m_requiredPollCount);
379 DBBind(hStmt, 6, DB_SQLTYPE_INTEGER, m_bridgePortNumber);
380 DBBind(hStmt, 7, DB_SQLTYPE_INTEGER, m_slotNumber);
381 DBBind(hStmt, 8, DB_SQLTYPE_INTEGER, m_portNumber);
382 DBBind(hStmt, 9, DB_SQLTYPE_INTEGER, m_peerNodeId);
383 DBBind(hStmt, 10, DB_SQLTYPE_INTEGER, m_peerInterfaceId);
384 DBBind(hStmt, 11, DB_SQLTYPE_VARCHAR, m_description, DB_BIND_STATIC);
385 DBBind(hStmt, 12, DB_SQLTYPE_INTEGER, (UINT32)m_adminState);
386 DBBind(hStmt, 13, DB_SQLTYPE_INTEGER, (UINT32)m_operState);
387 DBBind(hStmt, 14, DB_SQLTYPE_INTEGER, (UINT32)m_dot1xPaeAuthState);
388 DBBind(hStmt, 15, DB_SQLTYPE_INTEGER, (UINT32)m_dot1xBackendAuthState);
389 DBBind(hStmt, 16, DB_SQLTYPE_INTEGER, (INT32)m_peerDiscoveryProtocol);
390 DBBind(hStmt, 17, DB_SQLTYPE_VARCHAR, m_alias, DB_BIND_STATIC);
391 DBBind(hStmt, 18, DB_SQLTYPE_INTEGER, m_mtu);
392 DBBind(hStmt, 19, DB_SQLTYPE_BIGINT, m_speed);
393 DBBind(hStmt, 20, DB_SQLTYPE_INTEGER, m_parentInterfaceId);
394 if (m_ifTableSuffixLen > 0)
395 {
396 TCHAR buffer[128];
397 DBBind(hStmt, 21, DB_SQLTYPE_VARCHAR, SNMPConvertOIDToText(m_ifTableSuffixLen, m_ifTableSuffix, buffer, 128), DB_BIND_TRANSIENT);
398 }
399 else
400 {
401 DBBind(hStmt, 21, DB_SQLTYPE_VARCHAR, NULL, DB_BIND_STATIC);
402 }
403 DBBind(hStmt, 22, DB_SQLTYPE_INTEGER, m_id);
404
405 success = DBExecute(hStmt);
406 DBFreeStatement(hStmt);
407
408 // Save IP addresses
409 if (success)
410 {
411 success = false;
412
413 hStmt = DBPrepare(hdb, _T("DELETE FROM interface_address_list WHERE iface_id = ?"));
414 if (hStmt != NULL)
415 {
416 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
417 success = DBExecute(hStmt);
418 DBFreeStatement(hStmt);
419 }
420 }
421
422 if (success && (m_ipAddressList.size() > 0))
423 {
424 hStmt = DBPrepare(hdb, _T("INSERT INTO interface_address_list (iface_id,ip_addr,ip_netmask) VALUES (?,?,?)"));
425 if (hStmt != NULL)
426 {
427 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
428 const ObjectArray<InetAddress> *list = m_ipAddressList.getList();
429 for(int i = 0; (i < list->size()) && success; i++)
430 {
431 InetAddress *a = list->get(i);
432 TCHAR buffer[64];
433 DBBind(hStmt, 2, DB_SQLTYPE_VARCHAR, a->toString(buffer), DB_BIND_STATIC);
434 DBBind(hStmt, 3, DB_SQLTYPE_INTEGER, a->getMaskBits());
435 success = DBExecute(hStmt);
436 }
437 DBFreeStatement(hStmt);
438 }
439 else
440 {
441 success = false;
442 }
443 }
444 }
445 else
446 {
447 success = true;
448 }
449
450 // Save access list
451 if (success)
452 success = saveACLToDB(hdb);
453
454 // Clear modifications flag and unlock object
455 if (success)
456 m_modified = 0;
457 unlockProperties();
458
459 return success;
460 }
461
462 /**
463 * Delete interface object from database
464 */
465 bool Interface::deleteFromDatabase(DB_HANDLE hdb)
466 {
467 bool success = NetObj::deleteFromDatabase(hdb);
468 if (success)
469 success = executeQueryOnObject(hdb, _T("DELETE FROM interfaces WHERE id=?"));
470 if (success)
471 success = executeQueryOnObject(hdb, _T("DELETE FROM interface_address_list WHERE iface_id=?"));
472 return success;
473 }
474
475 /**
476 * Perform status poll on interface
477 */
478 void Interface::statusPoll(ClientSession *session, UINT32 rqId, Queue *eventQueue, Cluster *cluster, SNMP_Transport *snmpTransport, UINT32 nodeIcmpProxy)
479 {
480 if (IsShutdownInProgress())
481 return;
482
483 m_pollRequestor = session;
484 Node *pNode = getParentNode();
485 if (pNode == NULL)
486 {
487 m_status = STATUS_UNKNOWN;
488 return; // Cannot find parent node, which is VERY strange
489 }
490
491 sendPollerMsg(rqId, _T(" Starting status poll on interface %s\r\n"), m_name);
492 sendPollerMsg(rqId, _T(" Current interface status is %s\r\n"), GetStatusAsText(m_status, true));
493
494 InterfaceAdminState adminState = IF_ADMIN_STATE_UNKNOWN;
495 InterfaceOperState operState = IF_OPER_STATE_UNKNOWN;
496 BOOL bNeedPoll = TRUE;
497
498 // Poll interface using different methods
499 if ((pNode->getCapabilities() & NC_IS_NATIVE_AGENT) &&
500 (!(pNode->getFlags() & NF_DISABLE_NXCP)) && (!(pNode->getState() & NSF_AGENT_UNREACHABLE)))
501 {
502 sendPollerMsg(rqId, _T(" Retrieving interface status from NetXMS agent\r\n"));
503 pNode->getInterfaceStatusFromAgent(m_index, &adminState, &operState);
504 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): new state from NetXMS agent: adinState=%d operState=%d"), m_id, m_name, adminState, operState);
505 if ((adminState != IF_ADMIN_STATE_UNKNOWN) && (operState != IF_OPER_STATE_UNKNOWN))
506 {
507 sendPollerMsg(rqId, POLLER_INFO _T(" Interface status retrieved from NetXMS agent\r\n"));
508 bNeedPoll = FALSE;
509 }
510 else
511 {
512 sendPollerMsg(rqId, POLLER_WARNING _T(" Unable to retrieve interface status from NetXMS agent\r\n"));
513 }
514 }
515
516 if (bNeedPoll && (pNode->getCapabilities() & NC_IS_SNMP) &&
517 (!(pNode->getFlags() & NF_DISABLE_SNMP)) && (!(pNode->getState() & NSF_SNMP_UNREACHABLE)) &&
518 (snmpTransport != NULL))
519 {
520 sendPollerMsg(rqId, _T(" Retrieving interface status from SNMP agent\r\n"));
521 pNode->getInterfaceStatusFromSNMP(snmpTransport, m_index, m_ifTableSuffixLen, m_ifTableSuffix, &adminState, &operState);
522 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): new state from SNMP: adminState=%d operState=%d"), m_id, m_name, adminState, operState);
523 if ((adminState != IF_ADMIN_STATE_UNKNOWN) && (operState != IF_OPER_STATE_UNKNOWN))
524 {
525 sendPollerMsg(rqId, POLLER_INFO _T(" Interface status retrieved from SNMP agent\r\n"));
526 bNeedPoll = FALSE;
527 }
528 else
529 {
530 sendPollerMsg(rqId, POLLER_WARNING _T(" Unable to retrieve interface status from SNMP agent\r\n"));
531 }
532 }
533
534 if (bNeedPoll)
535 {
536 // Ping cannot be used for cluster sync interfaces
537 if ((pNode->getFlags() & NF_DISABLE_ICMP) || isLoopback() || !m_ipAddressList.hasValidUnicastAddress())
538 {
539 // Interface doesn't have an IP address, so we can't ping it
540 sendPollerMsg(rqId, POLLER_WARNING _T(" Interface status cannot be determined\r\n"));
541 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): cannot use ping for status check"), m_id, m_name);
542 }
543 else
544 {
545 icmpStatusPoll(rqId, nodeIcmpProxy, cluster, &adminState, &operState);
546 }
547 }
548
549 // Calculate interface object status based on admin state, oper state, and expected state
550 int oldStatus = m_status;
551 int newStatus;
552 int expectedState = (m_flags & IF_EXPECTED_STATE_MASK) >> 28;
553 switch(adminState)
554 {
555 case IF_ADMIN_STATE_UP:
556 case IF_ADMIN_STATE_UNKNOWN:
557 switch(operState)
558 {
559 case IF_OPER_STATE_UP:
560 if (expectedState == IF_EXPECTED_STATE_AUTO)
561 {
562 DbgPrintf(5, _T("Interface::StatusPoll(%d,%s): auto expected state changed to UP"), m_id, m_name);
563 expectedState = IF_EXPECTED_STATE_UP;
564 setExpectedState(expectedState);
565 }
566 newStatus = ((expectedState == IF_EXPECTED_STATE_DOWN) ? STATUS_CRITICAL : STATUS_NORMAL);
567 break;
568 case IF_OPER_STATE_DOWN:
569 if (expectedState == IF_EXPECTED_STATE_AUTO)
570 {
571 DbgPrintf(5, _T("Interface::StatusPoll(%d,%s): auto expected state changed to DOWN"), m_id, m_name);
572 expectedState = IF_EXPECTED_STATE_DOWN;
573 setExpectedState(expectedState);
574 }
575 newStatus = (expectedState == IF_EXPECTED_STATE_UP) ? STATUS_CRITICAL : STATUS_NORMAL;
576 break;
577 case IF_OPER_STATE_TESTING:
578 newStatus = STATUS_TESTING;
579 break;
580 case IF_OPER_STATE_DORMANT:
581 newStatus = (expectedState == IF_EXPECTED_STATE_UP) ? STATUS_MINOR : STATUS_NORMAL;
582 break;
583 case IF_OPER_STATE_NOT_PRESENT:
584 newStatus = STATUS_DISABLED;
585 break;
586 default:
587 newStatus = STATUS_UNKNOWN;
588 break;
589 }
590 break;
591 case IF_ADMIN_STATE_DOWN:
592 if (expectedState == IF_EXPECTED_STATE_AUTO)
593 {
594 DbgPrintf(5, _T("Interface::StatusPoll(%d,%s): auto expected state changed to DOWN"), m_id, m_name);
595 expectedState = IF_EXPECTED_STATE_DOWN;
596 setExpectedState(expectedState);
597 }
598 newStatus = STATUS_DISABLED;
599 break;
600 case IF_ADMIN_STATE_TESTING:
601 newStatus = STATUS_TESTING;
602 break;
603 default:
604 newStatus = STATUS_UNKNOWN;
605 break;
606 }
607
608 // Check 802.1x state
609 if ((pNode->getCapabilities() & NC_IS_8021X) && isPhysicalPort() && (snmpTransport != NULL))
610 {
611 DbgPrintf(5, _T("StatusPoll(%s): Checking 802.1x state for interface %s"), pNode->getName(), m_name);
612 paeStatusPoll(rqId, snmpTransport, pNode);
613 if ((m_dot1xPaeAuthState == PAE_STATE_FORCE_UNAUTH) && (newStatus < STATUS_MAJOR))
614 newStatus = STATUS_MAJOR;
615 }
616
617 // Reset status to unknown if node has known network connectivity problems
618 if ((newStatus == STATUS_CRITICAL) && (pNode->getState() & DCSF_NETWORK_PATH_PROBLEM))
619 {
620 newStatus = STATUS_UNKNOWN;
621 DbgPrintf(6, _T("StatusPoll(%s): Status for interface %s reset to UNKNOWN"), pNode->getName(), m_name);
622 }
623
624 if (newStatus == m_pendingStatus)
625 {
626 m_statusPollCount++;
627 }
628 else
629 {
630 m_pendingStatus = newStatus;
631 m_statusPollCount = 1;
632 }
633
634 if (operState == m_pendingOperState)
635 {
636 m_operStatePollCount++;
637 }
638 else
639 {
640 m_pendingOperState = operState;
641 m_operStatePollCount = 1;
642 }
643
644 int requiredPolls = (m_requiredPollCount > 0) ? m_requiredPollCount :
645 ((getParentNode()->getRequiredPolls() > 0) ? getParentNode()->getRequiredPolls() : g_requiredPolls);
646 sendPollerMsg(rqId, _T(" Interface is %s for %d poll%s (%d poll%s required for status change)\r\n"),
647 GetStatusAsText(newStatus, true), m_statusPollCount, (m_statusPollCount == 1) ? _T("") : _T("s"),
648 requiredPolls, (requiredPolls == 1) ? _T("") : _T("s"));
649 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): newStatus=%d oldStatus=%d pollCount=%d requiredPolls=%d"),
650 m_id, m_name, newStatus, oldStatus, m_statusPollCount, requiredPolls);
651
652 if ((operState != m_confirmedOperState) && (m_operStatePollCount >= requiredPolls))
653 {
654 DbgPrintf(6, _T("Interface::StatusPoll(%d,%s): confirmedOperState=%d pollCount=%d requiredPolls=%d"),
655 m_id, m_name, (int)operState, m_operStatePollCount, requiredPolls);
656 m_confirmedOperState = operState;
657 }
658
659 if ((newStatus != oldStatus) && (m_statusPollCount >= requiredPolls) && (expectedState != IF_EXPECTED_STATE_IGNORE))
660 {
661 static UINT32 statusToEvent[] =
662 {
663 EVENT_INTERFACE_UP, // Normal
664 EVENT_INTERFACE_UP, // Warning
665 EVENT_INTERFACE_UP, // Minor
666 EVENT_INTERFACE_DOWN, // Major
667 EVENT_INTERFACE_DOWN, // Critical
668 EVENT_INTERFACE_UNKNOWN, // Unknown
669 EVENT_INTERFACE_UNKNOWN, // Unmanaged
670 EVENT_INTERFACE_DISABLED, // Disabled
671 EVENT_INTERFACE_TESTING // Testing
672 };
673 static UINT32 statusToEventInverted[] =
674 {
675 EVENT_INTERFACE_EXPECTED_DOWN, // Normal
676 EVENT_INTERFACE_EXPECTED_DOWN, // Warning
677 EVENT_INTERFACE_EXPECTED_DOWN, // Minor
678 EVENT_INTERFACE_UNEXPECTED_UP, // Major
679 EVENT_INTERFACE_UNEXPECTED_UP, // Critical
680 EVENT_INTERFACE_UNKNOWN, // Unknown
681 EVENT_INTERFACE_UNKNOWN, // Unmanaged
682 EVENT_INTERFACE_DISABLED, // Disabled
683 EVENT_INTERFACE_TESTING // Testing
684 };
685
686 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): status changed from %d to %d"), m_id, m_name, m_status, newStatus);
687 m_status = newStatus;
688 m_pendingStatus = -1; // Invalidate pending status
689 if (!m_isSystem)
690 {
691 sendPollerMsg(rqId, _T(" Interface status changed to %s\r\n"), GetStatusAsText(m_status, true));
692 const InetAddress& addr = m_ipAddressList.getFirstUnicastAddress();
693 PostEventEx(eventQueue,
694 (expectedState == IF_EXPECTED_STATE_DOWN) ? statusToEventInverted[m_status] : statusToEvent[m_status],
695 pNode->getId(), "dsAdd", m_id, m_name, &addr, addr.getMaskBits(), m_index);
696 }
697 }
698 else if (expectedState == IF_EXPECTED_STATE_IGNORE)
699 {
700 m_status = (newStatus <= STATUS_CRITICAL) ? STATUS_NORMAL : newStatus;
701 if (m_status != oldStatus)
702 m_pendingStatus = -1; // Invalidate pending status
703 }
704
705 lockProperties();
706 if ((m_status != oldStatus) || (adminState != (int)m_adminState) || (operState != (int)m_operState))
707 {
708 m_adminState = (WORD)adminState;
709 m_operState = (WORD)operState;
710 setModified(MODIFY_INTERFACE_PROPERTIES);
711 }
712 unlockProperties();
713
714 sendPollerMsg(rqId, _T(" Interface status after poll is %s\r\n"), GetStatusAsText(m_status, true));
715 sendPollerMsg(rqId, _T(" Finished status poll on interface %s\r\n"), m_name);
716 }
717
718 /**
719 * Updates last ping time and ping time
720 */
721 void Interface::updatePingData()
722 {
723 Node *pNode = getParentNode();
724 if (pNode == NULL)
725 {
726 nxlog_debug(7, _T("Interface::updatePingData: Can't find parent node"));
727 return;
728 }
729 UINT32 icmpProxy = pNode->getIcmpProxy();
730
731 if (IsZoningEnabled() && (m_zoneUIN != 0) && (icmpProxy == 0))
732 {
733 Zone *zone = FindZoneByUIN(m_zoneUIN);
734 if (zone != NULL)
735 {
736 icmpProxy = zone->getProxyNodeId();
737 }
738 }
739
740 if (icmpProxy != 0)
741 {
742 nxlog_debug(7, _T("Interface::updatePingData: ping via proxy [%u]"), icmpProxy);
743 Node *proxyNode = (Node *)g_idxNodeById.get(icmpProxy);
744 if ((proxyNode != NULL) && proxyNode->isNativeAgent() && !proxyNode->isDown())
745 {
746 nxlog_debug(7, _T("Interface::updatePingData: proxy node found: %s"), proxyNode->getName());
747 AgentConnection *conn = proxyNode->createAgentConnection();
748 if (conn != NULL)
749 {
750 TCHAR parameter[128], buffer[64];
751 const ObjectArray<InetAddress> *list = m_ipAddressList.getList();
752 long value = -1;
753 for(int i = 0; (i < list->size()) && ((value == 10000) || (value == -1)); i++)
754 {
755 const InetAddress *a = list->get(i);
756 _sntprintf(parameter, 128, _T("Icmp.Ping(%s)"), a->toString(buffer));
757 if (conn->getParameter(parameter, 64, buffer) == ERR_SUCCESS)
758 {
759 nxlog_debug(7, _T("Interface::updatePingData: proxy response: \"%s\""), buffer);
760 TCHAR *eptr;
761 value = _tcstol(buffer, &eptr, 10);
762 if (*eptr != 0)
763 {
764 value = -1;
765 }
766 }
767 }
768
769 if (value >= 0)
770 {
771 m_pingTime = value;
772 }
773 else
774 {
775 m_pingTime = PING_TIME_TIMEOUT;
776 nxlog_debug(7, _T("Interface::updatePingData: incorrect value or error while parsing"));
777 }
778 m_pingLastTimeStamp = time(NULL);
779 conn->decRefCount();
780 }
781 else
782 {
783 nxlog_debug(7, _T("Interface::updatePingData: cannot connect to agent on proxy node [%u]"), icmpProxy);
784 m_pingTime = PING_TIME_TIMEOUT;
785 }
786 }
787 else
788 {
789 nxlog_debug(7, _T("Interface::updatePingData: proxy node not available [%u]"), icmpProxy);
790 m_pingTime = PING_TIME_TIMEOUT;
791 }
792 }
793 else // not using ICMP proxy
794 {
795 const ObjectArray<InetAddress> *list = m_ipAddressList.getList();
796 UINT32 dwPingStatus = ICMP_TIMEOUT;
797 for(int i = 0; (i < list->size()) && (dwPingStatus != ICMP_SUCCESS); i++)
798 {
799 const InetAddress *a = list->get(i);
800 nxlog_debug(7, _T("Interface::StatusPoll(%d,%s): calling IcmpPing(%s,3,%d,%d,%d)"),
801 m_id, m_name, (const TCHAR *)a->toString(), g_icmpPingTimeout, m_pingTime, g_icmpPingSize);
802 dwPingStatus = IcmpPing(*a, 3, g_icmpPingTimeout, &m_pingTime, g_icmpPingSize);
803 }
804 if (dwPingStatus != ICMP_SUCCESS)
805 {
806 nxlog_debug(7, _T("Interface::updatePingData: error: %d"), dwPingStatus);
807 m_pingTime = PING_TIME_TIMEOUT;
808 }
809 m_pingLastTimeStamp = time(NULL);
810 }
811 }
812
813 /**
814 * Do ICMP part of status poll
815 */
816 void Interface::icmpStatusPoll(UINT32 rqId, UINT32 nodeIcmpProxy, Cluster *cluster, InterfaceAdminState *adminState, InterfaceOperState *operState)
817 {
818 // Use ICMP ping as a last option
819 UINT32 icmpProxy = nodeIcmpProxy;
820
821 if (IsZoningEnabled() && (m_zoneUIN != 0) && (icmpProxy == 0))
822 {
823 Zone *zone = FindZoneByUIN(m_zoneUIN);
824 if (zone != NULL)
825 {
826 icmpProxy = zone->getProxyNodeId();
827 }
828 }
829
830 if (icmpProxy != 0)
831 {
832 sendPollerMsg(rqId, _T(" Starting ICMP ping via proxy\r\n"));
833 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): ping via proxy [%u]"), m_id, m_name, icmpProxy);
834 Node *proxyNode = (Node *)g_idxNodeById.get(icmpProxy);
835 if ((proxyNode != NULL) && proxyNode->isNativeAgent() && !proxyNode->isDown())
836 {
837 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): proxy node found: %s"), m_id, m_name, proxyNode->getName());
838 AgentConnection *conn = proxyNode->createAgentConnection();
839 if (conn != NULL)
840 {
841 TCHAR parameter[128], buffer[64];
842 const ObjectArray<InetAddress> *list = m_ipAddressList.getList();
843 long value = -1;
844 for(int i = 0; (i < list->size()) && ((value == 10000) || (value == -1)); i++)
845 {
846 const InetAddress *a = list->get(i);
847 if (a->isValidUnicast() && ((cluster == NULL) || !cluster->isSyncAddr(*a)))
848 {
849 _sntprintf(parameter, 128, _T("Icmp.Ping(%s)"), a->toString(buffer));
850 if (conn->getParameter(parameter, 64, buffer) == ERR_SUCCESS)
851 {
852 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): proxy response: \"%s\""), m_id, m_name, buffer);
853 TCHAR *eptr;
854 value = _tcstol(buffer, &eptr, 10);
855 if (*eptr != 0)
856 {
857 value = -1;
858 }
859 }
860 }
861 }
862
863 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): response time %d"), m_id, m_name, (int)value);
864 if (value >= 0)
865 {
866 m_pingTime = (UINT32)value;
867 if (value < 10000)
868 {
869 *adminState = IF_ADMIN_STATE_UP;
870 *operState = IF_OPER_STATE_UP;
871 }
872 else
873 {
874 *adminState = IF_ADMIN_STATE_UNKNOWN;
875 *operState = IF_OPER_STATE_DOWN;
876 }
877 }
878 m_pingLastTimeStamp = time(NULL);
879 conn->decRefCount();
880 }
881 else
882 {
883 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): cannot connect to agent on proxy node"), m_id, m_name);
884 sendPollerMsg(rqId, POLLER_ERROR _T(" Unable to establish connection with proxy node\r\n"));
885 }
886 }
887 else
888 {
889 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): proxy node not available"), m_id, m_name);
890 sendPollerMsg(rqId, POLLER_ERROR _T(" ICMP proxy not available\r\n"));
891 }
892 }
893 else // not using ICMP proxy
894 {
895 sendPollerMsg(rqId, _T(" Starting ICMP ping\r\n"));
896 const ObjectArray<InetAddress> *list = m_ipAddressList.getList();
897 UINT32 dwPingStatus = ICMP_TIMEOUT;
898 for(int i = 0; (i < list->size()) && (dwPingStatus != ICMP_SUCCESS); i++)
899 {
900 const InetAddress *a = list->get(i);
901 if (a->isValidUnicast() && ((cluster == NULL) || !cluster->isSyncAddr(*a)))
902 {
903 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): calling IcmpPing(%s,3,%d,%d,%d)"),
904 m_id, m_name, (const TCHAR *)a->toString(), g_icmpPingTimeout, m_pingTime, g_icmpPingSize);
905 dwPingStatus = IcmpPing(*a, 3, g_icmpPingTimeout, &m_pingTime, g_icmpPingSize);
906 }
907 }
908 m_pingLastTimeStamp = time(NULL);
909 if (dwPingStatus == ICMP_SUCCESS)
910 {
911 *adminState = IF_ADMIN_STATE_UP;
912 *operState = IF_OPER_STATE_UP;
913 }
914 else
915 {
916 m_pingTime = PING_TIME_TIMEOUT;
917 *adminState = IF_ADMIN_STATE_UNKNOWN;
918 *operState = IF_OPER_STATE_DOWN;
919 }
920 DbgPrintf(7, _T("Interface::StatusPoll(%d,%s): ping result %d, adminState=%d, operState=%d"), m_id, m_name, dwPingStatus, *adminState, *operState);
921 }
922 }
923
924 /**
925 * PAE (802.1x) status poll
926 */
927 void Interface::paeStatusPoll(UINT32 rqId, SNMP_Transport *pTransport, Node *node)
928 {
929 static const TCHAR *paeStateText[] =
930 {
931 _T("UNKNOWN"),
932 _T("INITIALIZE"),
933 _T("DISCONNECTED"),
934 _T("CONNECTING"),
935 _T("AUTHENTICATING"),
936 _T("AUTHENTICATED"),
937 _T("ABORTING"),
938 _T("HELD"),
939 _T("FORCE AUTH"),
940 _T("FORCE UNAUTH"),
941 _T("RESTART")
942 };
943 static const TCHAR *backendStateText[] =
944 {
945 _T("UNKNOWN"),
946 _T("REQUEST"),
947 _T("RESPONSE"),
948 _T("SUCCESS"),
949 _T("FAIL"),
950 _T("TIMEOUT"),
951 _T("IDLE"),
952 _T("INITIALIZE"),
953 _T("IGNORE")
954 };
955 #define PAE_STATE_TEXT(x) ((((int)(x) <= PAE_STATE_RESTART) && ((int)(x) >= 0)) ? paeStateText[(int)(x)] : paeStateText[0])
956 #define BACKEND_STATE_TEXT(x) ((((int)(x) <= BACKEND_STATE_IGNORE) && ((int)(x) >= 0)) ? backendStateText[(int)(x)] : backendStateText[0])
957
958 sendPollerMsg(rqId, _T(" Checking port 802.1x status...\r\n"));
959
960 TCHAR oid[256];
961 INT32 paeState = PAE_STATE_UNKNOWN, backendState = BACKEND_STATE_UNKNOWN;
962 bool modified = false;
963
964 _sntprintf(oid, 256, _T(".1.0.8802.1.1.1.1.2.1.1.1.%d"), m_index);
965 SnmpGet(pTransport->getSnmpVersion(), pTransport, oid, NULL, 0, &paeState, sizeof(INT32), 0);
966
967 _sntprintf(oid, 256, _T(".1.0.8802.1.1.1.1.2.1.1.2.%d"), m_index);
968 SnmpGet(pTransport->getSnmpVersion(), pTransport, oid, NULL, 0, &backendState, sizeof(INT32), 0);
969
970 if (m_dot1xPaeAuthState != (WORD)paeState)
971 {
972 sendPollerMsg(rqId, _T(" Port PAE state changed to %s\r\n"), PAE_STATE_TEXT(paeState));
973 modified = true;
974 if (!m_isSystem)
975 {
976 PostEvent(EVENT_8021X_PAE_STATE_CHANGED, node->getId(), "dsdsds", paeState, PAE_STATE_TEXT(paeState),
977 (UINT32)m_dot1xPaeAuthState, PAE_STATE_TEXT(m_dot1xPaeAuthState), m_id, m_name);
978
979 if (paeState == PAE_STATE_FORCE_UNAUTH)
980 {
981 PostEvent(EVENT_8021X_PAE_FORCE_UNAUTH, node->getId(), "ds", m_id, m_name);
982 }
983 }
984 }
985
986 if (m_dot1xBackendAuthState != (WORD)backendState)
987 {
988 sendPollerMsg(rqId, _T(" Port backend state changed to %s\r\n"), BACKEND_STATE_TEXT(backendState));
989 modified = true;
990 if (!m_isSystem)
991 {
992 PostEvent(EVENT_8021X_BACKEND_STATE_CHANGED, node->getId(), "dsdsds", backendState, BACKEND_STATE_TEXT(backendState),
993 (UINT32)m_dot1xBackendAuthState, BACKEND_STATE_TEXT(m_dot1xBackendAuthState), m_id, m_name);
994
995 if (backendState == BACKEND_STATE_FAIL)
996 {
997 PostEvent(EVENT_8021X_AUTH_FAILED, node->getId(), "ds", m_id, m_name);
998 }
999 else if (backendState == BACKEND_STATE_TIMEOUT)
1000 {
1001 PostEvent(EVENT_8021X_AUTH_TIMEOUT, node->getId(), "ds", m_id, m_name);
1002 }
1003 }
1004 }
1005
1006 if (modified)
1007 {
1008 lockProperties();
1009 m_dot1xPaeAuthState = (WORD)paeState;
1010 m_dot1xBackendAuthState = (WORD)backendState;
1011 setModified(MODIFY_INTERFACE_PROPERTIES);
1012 unlockProperties();
1013 }
1014 }
1015
1016 /**
1017 * Create NXCP message with object's data
1018 */
1019 void Interface::fillMessageInternal(NXCPMessage *pMsg)
1020 {
1021 NetObj::fillMessageInternal(pMsg);
1022
1023 m_ipAddressList.fillMessage(pMsg, VID_IP_ADDRESS_COUNT, VID_IP_ADDRESS_LIST_BASE);
1024 pMsg->setField(VID_IF_INDEX, m_index);
1025 pMsg->setField(VID_IF_TYPE, m_type);
1026 pMsg->setField(VID_MTU, m_mtu);
1027 pMsg->setField(VID_SPEED, m_speed);
1028 pMsg->setField(VID_IF_SLOT, m_slotNumber);
1029 pMsg->setField(VID_IF_PORT, m_portNumber);
1030 pMsg->setField(VID_MAC_ADDR, m_macAddr, MAC_ADDR_LENGTH);
1031 pMsg->setField(VID_REQUIRED_POLLS, (WORD)m_requiredPollCount);
1032 pMsg->setField(VID_PEER_NODE_ID, m_peerNodeId);
1033 pMsg->setField(VID_PEER_INTERFACE_ID, m_peerInterfaceId);
1034 pMsg->setField(VID_PEER_PROTOCOL, (INT16)m_peerDiscoveryProtocol);
1035 pMsg->setField(VID_DESCRIPTION, m_description);
1036 pMsg->setField(VID_ALIAS, m_alias);
1037 pMsg->setField(VID_ADMIN_STATE, m_adminState);
1038 pMsg->setField(VID_OPER_STATE, m_operState);
1039 pMsg->setField(VID_DOT1X_PAE_STATE, m_dot1xPaeAuthState);
1040 pMsg->setField(VID_DOT1X_BACKEND_STATE, m_dot1xBackendAuthState);
1041 pMsg->setField(VID_ZONE_UIN, m_zoneUIN);
1042 pMsg->setFieldFromInt32Array(VID_IFTABLE_SUFFIX, m_ifTableSuffixLen, m_ifTableSuffix);
1043 pMsg->setField(VID_PARENT_INTERFACE, m_parentInterfaceId);
1044 }
1045
1046 /**
1047 * Modify object from message
1048 */
1049 UINT32 Interface::modifyFromMessageInternal(NXCPMessage *pRequest)
1050 {
1051 // Flags
1052 if (pRequest->isFieldExist(VID_FLAGS))
1053 {
1054 UINT32 mask = pRequest->isFieldExist(VID_FLAGS_MASK) ? (pRequest->getFieldAsUInt32(VID_FLAGS_MASK) & IF_USER_FLAGS_MASK) : IF_USER_FLAGS_MASK;
1055 m_flags &= ~mask;
1056 m_flags |= pRequest->getFieldAsUInt32(VID_FLAGS) & mask;
1057 }
1058
1059 // Number of required polls
1060 if (pRequest->isFieldExist(VID_REQUIRED_POLLS))
1061 m_requiredPollCount = (int)pRequest->getFieldAsUInt16(VID_REQUIRED_POLLS);
1062
1063 // Expected interface state
1064 if (pRequest->isFieldExist(VID_EXPECTED_STATE))
1065 {
1066 setExpectedStateInternal(pRequest->getFieldAsInt16(VID_EXPECTED_STATE));
1067 }
1068
1069 return NetObj::modifyFromMessageInternal(pRequest);
1070 }
1071
1072 /**
1073 * Set expected state for interface
1074 */
1075 void Interface::setExpectedStateInternal(int state)
1076 {
1077 static UINT32 eventCode[] = { EVENT_IF_EXPECTED_STATE_UP, EVENT_IF_EXPECTED_STATE_DOWN, EVENT_IF_EXPECTED_STATE_IGNORE };
1078
1079 int curr = (m_flags & IF_EXPECTED_STATE_MASK) >> 28;
1080 if (curr != state)
1081 {
1082 m_flags &= ~IF_EXPECTED_STATE_MASK;
1083 m_flags |= (UINT32)state << 28;
1084 setModified(MODIFY_COMMON_PROPERTIES);
1085 if (state != IF_EXPECTED_STATE_AUTO)
1086 PostEvent(eventCode[state], getParentNodeId(), "ds", m_index, m_name);
1087 }
1088 }
1089
1090 /**
1091 * Set "exclude from topology" flag
1092 */
1093 void Interface::setExcludeFromTopology(bool excluded)
1094 {
1095 lockProperties();
1096 if (excluded)
1097 m_flags |= IF_EXCLUDE_FROM_TOPOLOGY;
1098 else
1099 m_flags &= ~IF_EXCLUDE_FROM_TOPOLOGY;
1100 setModified(MODIFY_COMMON_PROPERTIES);
1101 unlockProperties();
1102 }
1103
1104 /**
1105 * Wake up node bound to this interface by sending magic packet
1106 */
1107 UINT32 Interface::wakeUp()
1108 {
1109 UINT32 rcc = RCC_NO_MAC_ADDRESS;
1110
1111 if (memcmp(m_macAddr, "\x00\x00\x00\x00\x00\x00", 6))
1112 {
1113 const InetAddress addr = m_ipAddressList.getFirstUnicastAddressV4();
1114 if (addr.isValid())
1115 {
1116 UINT32 destAddr = htonl(addr.getAddressV4() | ~(0xFFFFFFFF << (32 - addr.getMaskBits())));
1117 if (SendMagicPacket(destAddr, m_macAddr, 5))
1118 rcc = RCC_SUCCESS;
1119 else
1120 rcc = RCC_COMM_FAILURE;
1121 }
1122 }
1123 return rcc;
1124 }
1125
1126 /**
1127 * Get interface's parent node
1128 */
1129 Node *Interface::getParentNode()
1130 {
1131 Node *pNode = NULL;
1132
1133 lockParentList(false);
1134 for(int i = 0; i < m_parentList->size(); i++)
1135 if (m_parentList->get(i)->getObjectClass() == OBJECT_NODE)
1136 {
1137 pNode = (Node *)m_parentList->get(i);
1138 break;
1139 }
1140 unlockParentList();
1141 return pNode;
1142 }
1143
1144 /**
1145 * Get ID of parent node object
1146 */
1147 UINT32 Interface::getParentNodeId()
1148 {
1149 Node *node = getParentNode();
1150 return (node != NULL) ? node->getId() : 0;
1151 }
1152
1153 /**
1154 * Update zone ID. New zone ID taken from parent node.
1155 */
1156 void Interface::updateZoneUIN()
1157 {
1158 Node *node = getParentNode();
1159 if (node != NULL)
1160 {
1161 // Unregister from old zone
1162 Zone *zone = FindZoneByUIN(m_zoneUIN);
1163 if (zone != NULL)
1164 zone->removeFromIndex(this);
1165
1166 lockProperties();
1167 m_zoneUIN = node->getZoneUIN();
1168 setModified(MODIFY_INTERFACE_PROPERTIES);
1169 unlockProperties();
1170
1171 // Register in new zone
1172 zone = FindZoneByUIN(m_zoneUIN);
1173 if (zone != NULL)
1174 zone->addToIndex(this);
1175 }
1176 }
1177
1178 /**
1179 * Handler for object deletion notification
1180 */
1181 void Interface::onObjectDelete(UINT32 dwObjectId)
1182 {
1183 if ((m_peerNodeId == dwObjectId) || (m_peerInterfaceId == dwObjectId))
1184 {
1185 lockProperties();
1186 m_peerNodeId = 0;
1187 m_peerInterfaceId = 0;
1188 setModified(MODIFY_INTERFACE_PROPERTIES);
1189 unlockProperties();
1190 }
1191 NetObj::onObjectDelete(dwObjectId);
1192 }
1193
1194 /**
1195 * Set peer information
1196 */
1197 void Interface::setPeer(Node *node, Interface *iface, LinkLayerProtocol protocol, bool reflection)
1198 {
1199 if ((m_peerNodeId == node->getId()) && (m_peerInterfaceId == iface->getId()) && (m_peerDiscoveryProtocol == protocol))
1200 {
1201 if ((m_flags & IF_PEER_REFLECTION) && !reflection)
1202 {
1203 // set peer information as confirmed
1204 m_flags &= ~IF_PEER_REFLECTION;
1205 setModified(MODIFY_COMMON_PROPERTIES);
1206 }
1207 return;
1208 }
1209
1210 m_peerNodeId = node->getId();
1211 m_peerInterfaceId = iface->getId();
1212 m_peerDiscoveryProtocol = protocol;
1213 if (reflection)
1214 m_flags |= IF_PEER_REFLECTION;
1215 else
1216 m_flags &= ~IF_PEER_REFLECTION;
1217 setModified(MODIFY_INTERFACE_PROPERTIES | MODIFY_COMMON_PROPERTIES);
1218 if (!m_isSystem)
1219 {
1220 static const TCHAR *names[] = { _T("localIfId"), _T("localIfIndex"), _T("localIfName"),
1221 _T("localIfIP"), _T("localIfMAC"), _T("remoteNodeId"), _T("remoteNodeName"),
1222 _T("remoteIfId"), _T("remoteIfIndex"), _T("remoteIfName"), _T("remoteIfIP"),
1223 _T("remoteIfMAC"), _T("protocol") };
1224 PostEventWithNames(EVENT_IF_PEER_CHANGED, getParentNodeId(), "ddsAhdsddsAhd", names,
1225 m_id, m_index, m_name, &m_ipAddressList.getFirstUnicastAddress(), m_macAddr,
1226 node->getId(), node->getName(), iface->getId(), iface->getIfIndex(), iface->getName(),
1227 &iface->getIpAddressList()->getFirstUnicastAddress(), iface->getMacAddr(), protocol);
1228 }
1229 }
1230
1231 /**
1232 * Set MAC address for interface
1233 */
1234 void Interface::setMacAddr(const BYTE *macAddr, bool updateMacDB)
1235 {
1236 lockProperties();
1237 if (updateMacDB)
1238 MacDbRemove(m_macAddr);
1239 memcpy(m_macAddr, macAddr, MAC_ADDR_LENGTH);
1240 if (updateMacDB)
1241 MacDbAddInterface(this);
1242 setModified(MODIFY_INTERFACE_PROPERTIES);
1243 unlockProperties();
1244 }
1245
1246 /**
1247 * Set IP address (should be used only for fake interfaces with single IP)
1248 */
1249 void Interface::setIpAddress(const InetAddress& addr)
1250 {
1251 lockProperties();
1252 if (m_ipAddressList.size() == 1)
1253 {
1254 UpdateInterfaceIndex(m_ipAddressList.get(0), addr, this);
1255 m_ipAddressList.clear();
1256 m_ipAddressList.add(addr);
1257 setModified(MODIFY_INTERFACE_PROPERTIES);
1258 }
1259 unlockProperties();
1260 }
1261
1262 /**
1263 * Get first usable IP address
1264 */
1265 const InetAddress& Interface::getFirstIpAddress()
1266 {
1267 const InetAddress& a = m_ipAddressList.getFirstUnicastAddress();
1268 return a.isValid() ? a : m_ipAddressList.get(0);
1269 }
1270
1271 /**
1272 * Add IP address
1273 */
1274 void Interface::addIpAddress(const InetAddress& addr)
1275 {
1276 lockProperties();
1277 m_ipAddressList.add(addr);
1278 setModified(MODIFY_INTERFACE_PROPERTIES);
1279 unlockProperties();
1280 if (!isExcludedFromTopology())
1281 {
1282 if (IsZoningEnabled())
1283 {
1284 Zone *zone = FindZoneByUIN(m_zoneUIN);
1285 if (zone != NULL)
1286 {
1287 zone->addToIndex(addr, this);
1288 }
1289 else
1290 {
1291 DbgPrintf(2, _T("Cannot find zone object with GUID=%d for interface object %s [%d]"), (int)m_zoneUIN, m_name, (int)m_id);
1292 }
1293 }
1294 else
1295 {
1296 g_idxInterfaceByAddr.put(addr, this);
1297 }
1298 }
1299 }
1300
1301 /**
1302 * Delete IP address
1303 */
1304 void Interface::deleteIpAddress(InetAddress addr)
1305 {
1306 lockProperties();
1307 m_ipAddressList.remove(addr);
1308 setModified(MODIFY_INTERFACE_PROPERTIES);
1309 unlockProperties();
1310 if (!isExcludedFromTopology())
1311 {
1312 if (IsZoningEnabled())
1313 {
1314 Zone *zone = FindZoneByUIN(m_zoneUIN);
1315 if (zone != NULL)
1316 {
1317 zone->removeFromInterfaceIndex(addr);
1318 }
1319 else
1320 {
1321 DbgPrintf(2, _T("Cannot find zone object with GUID=%d for interface object %s [%d]"), (int)m_zoneUIN, m_name, (int)m_id);
1322 }
1323 }
1324 else
1325 {
1326 g_idxInterfaceByAddr.remove(addr);
1327 }
1328 }
1329 }
1330
1331 /**
1332 * Change network mask for IP address
1333 */
1334 void Interface::setNetMask(const InetAddress& addr)
1335 {
1336 lockProperties();
1337 m_ipAddressList.replace(addr);
1338 setModified(MODIFY_INTERFACE_PROPERTIES);
1339 unlockProperties();
1340 }
1341
1342 /**
1343 * Create NXSL object for this object
1344 */
1345 NXSL_Value *Interface::createNXSLObject()
1346 {
1347 return new NXSL_Value(new NXSL_Object(&g_nxslInterfaceClass, this));
1348 }
1349
1350 /**
1351 * Serialize object to JSON
1352 */
1353 json_t *Interface::toJson()
1354 {
1355 json_t *root = NetObj::toJson();
1356 json_object_set_new(root, "index", json_integer(m_index));
1357 char macAddrText[64];
1358 json_object_set_new(root, "macAddr", json_string(BinToStrA(m_macAddr, MAC_ADDR_LENGTH, macAddrText)));
1359 json_object_set_new(root, "ipAddressList", m_ipAddressList.toJson());
1360 json_object_set_new(root, "flags", json_integer(m_flags));
1361 json_object_set_new(root, "description", json_string_t(m_description));
1362 json_object_set_new(root, "alias", json_string_t(m_alias));
1363 json_object_set_new(root, "type", json_integer(m_type));
1364 json_object_set_new(root, "mtu", json_integer(m_mtu));
1365 json_object_set_new(root, "speed", json_integer(m_speed));
1366 json_object_set_new(root, "bridgePortNumber", json_integer(m_bridgePortNumber));
1367 json_object_set_new(root, "slotNumber", json_integer(m_slotNumber));
1368 json_object_set_new(root, "portNumber", json_integer(m_portNumber));
1369 json_object_set_new(root, "peerNodeId", json_integer(m_peerNodeId));
1370 json_object_set_new(root, "peerInterfaceId", json_integer(m_peerInterfaceId));
1371 json_object_set_new(root, "peerDiscoveryProtocol", json_integer(m_peerDiscoveryProtocol));
1372 json_object_set_new(root, "adminState", json_integer(m_adminState));
1373 json_object_set_new(root, "operState", json_integer(m_operState));
1374 json_object_set_new(root, "pendingOperState", json_integer(m_pendingOperState));
1375 json_object_set_new(root, "confirmedOperState", json_integer(m_confirmedOperState));
1376 json_object_set_new(root, "dot1xPaeAuthState", json_integer(m_dot1xPaeAuthState));
1377 json_object_set_new(root, "dot1xBackendAuthState", json_integer(m_dot1xBackendAuthState));
1378 json_object_set_new(root, "lastDownEventId", json_integer(m_lastDownEventId));
1379 json_object_set_new(root, "pendingStatus", json_integer(m_pendingStatus));
1380 json_object_set_new(root, "statusPollCount", json_integer(m_statusPollCount));
1381 json_object_set_new(root, "operStatePollCount", json_integer(m_operStatePollCount));
1382 json_object_set_new(root, "requiredPollCount", json_integer(m_requiredPollCount));
1383 json_object_set_new(root, "zoneUIN", json_integer(m_zoneUIN));
1384 json_object_set_new(root, "pingTime", json_integer(m_pingTime));
1385 json_object_set_new(root, "pingLastTimeStamp", json_integer(m_pingLastTimeStamp));
1386 json_object_set_new(root, "ifTableSuffixLen", json_integer(m_ifTableSuffixLen));
1387 json_object_set_new(root, "ifTableSuffix", json_integer_array(m_ifTableSuffix, m_ifTableSuffixLen));
1388 return root;
1389 }