PowerSNMP for .NET
Table Basics



Table Basics

An SNMP table is a collection of objects consisting of zero or more rows, with rows conceptualized by a table's column objects at a specific row index. Most SNMP objects are scalar, having only one instance, specified by an IID of the object's OID appended with a ".0". Tables on the other hand contain table column objects with multiple instances, specified by an IID of the table column's OID appended with a row indexer typically starting at ".1". Other row indexers are possible, such as an IP address (".192.168.0.1") or the numerical ASCII representation of a string.

Working with Tables

To easily retrieve an entire table from an Agent, use SnmpSocket.GetTable(). For more granular control over the requests, call SnmpSocket.GetResponse() with a GetNextMessage (SNMPv1+) or GetBulkMessage (SNMPv2+) and populate the message's Variables property with a Variable lexicographically before the IID(s) desired, usually a table object or table column object for the initial request. When using GetNextMessage or GetBulkMessage, tables are returned lexicographically, so values of one column will be returned before the values of a subsequent column, therefore not by the conceptual row. Also note that variables lexicographically beyond the table can be returned within responses to GetNextMessage and GetBulkMessage, so the values returned should be checked for that and handled as needed. For even greater granularity, such as to request individual table cells, call GetResponse() with a GetMessage, populating Variables with a Variable for each IID desired.

To populate a table on an Agent from a Manager, send one or more SetMessage requests to the Agent with GetResponse(), populating the request's Variables with a Variable for each table cell to set. This is demonstrated in the last snippet below.

On the Agent, tables are constructed by populating Agent.Variables with a Variable for each table cell. For a table defined in a loaded MIB, use the Variable(MibNode, String, String) constructor; for a table defined in an unloaded MIB but the column OIDs and value types are known, use Variable(String, SimpleTaggedType). PowerSNMP for .NET supports sparse tables, so it is not required for every cell in a row to be populated.

EntryStatus (SMIv1) and RowStatus (SMIv2) are used to define the status of a row. As its specific implementation is dependent upon the application's requirements, it is left up to the developer to implement it as needed within their application: updating the value of the row's EntryStatus/RowStatus column as needed beyond Manager sets, and superseding the default response to requests when the EntryStatus/RowStatus indicates that the row is unavailable for use.

The following example demonstrates adding rows to a pre-defined table in Agent.Variables.

C#
Copy Code
/// <summary>
/// Adds/sets a row to/in atTable in the agent's variables collection.
/// </summary>
/// <param name="rowIndex">The 1-based index to set/add the row at</param>
private void setRow(string rowIndex, string physAddress, string netAddress)
{
    //Create the row: create a variable for each column defined for the table
    Variable indexVar = new Variable(agent1.Mib.GetByNodeName(NodeName.atIfIndex), rowIndex, rowIndex);
    Variable physAddressVar = new Variable(agent1.Mib.GetByNodeName(NodeName.atPhysAddress), physAddress, rowIndex);
    Variable netAddressVar = new Variable(agent1.Mib.GetByNodeName(NodeName.atNetAddress), netAddress, rowIndex);

    //Set the row within Agent.Variables. If initializing, Agent.Variables.Add() may be used instead.
    agent1.Variables[indexVar.Id] = indexVar;
    agent1.Variables[physAddressVar.Id] = physAddressVar;
    agent1.Variables[netAddressVar.Id] = netAddressVar;
}
Visual Basic
Copy Code
''' <summary>
''' Adds/sets a row to/in atTable in the agent's variables collection.
''' </summary>
''' <param name="rowIndex">The 1-based index to set/add the row at</param>
Private Sub setRow(ByVal rowIndex As String, ByVal physAddress As String, ByVal netAddress As String)
    'Create the row: create a variable for each column defined for the table
    Dim indexVar As New Variable(agent1.Mib.GetByNodeName(NodeName.atIfIndex), rowIndex, rowIndex)
    Dim physAddressVar As New Variable(agent1.Mib.GetByNodeName(NodeName.atPhysAddress), physAddress, rowIndex)
    Dim netAddressVar As New Variable(agent1.Mib.GetByNodeName(NodeName.atNetAddress), netAddress, rowIndex)

    'Set the row within Agent.Variables. If initializing, Agent.Variables.Add() may be used instead.
    agent1.Variables(indexVar.Id) = indexVar
    agent1.Variables(physAddressVar.Id) = physAddressVar
    agent1.Variables(netAddressVar.Id) = netAddressVar
End Sub

The following example demonstrates populating an entire table on a local Agent from a 2d string array.

C#
Copy Code
/// <summary>
/// Adds/sets table values from the specified 2d string array to/in the Agent's variables collection.
/// </summary>
/// <param name="myAgent">Agent instance to add/set the table data to/in.</param>
/// <param name="tableNameOrOid">Name or OID of the table.</param>
/// <param name="tableData">A 2d array [rows, columns] containing the table data to set on the agent.</param>
/// <remarks>
/// This method takes a string tableNameOrOid argument, therefore it is compatible with dynamically loaded MIBs.
/// This method requires the MIB or Mib Code File defining the table to be loaded/imported in myManager.Mib.
/// To sparsely populate the table, or to not update a table cell, specify null/Nothing for the tableData element.
/// </remarks>
private void setLocalTable(Agent myAgent, string tableNameOrOid, string[,] tableData)
{
    //Can also take a MibNode argument
    MibNode[] tableNodes = myAgent.Mib.GetTableColumns(tableNameOrOid);
    int rows = tableData.GetLength(0);
    int columns = tableData.GetLength(1);

    if (columns != tableNodes.Length)
        throw new ArgumentException("The number of columns contained in the table data does not match the table's definition", "tableData");

    for (int rowIndex = 0; rowIndex <= rows - 1; rowIndex++)
    {
        for (int columnIndex = 0; columnIndex <= columns - 1; columnIndex++)
        {
            if (tableData[rowIndex, columnIndex] != null)
            {
                Variable tableCellVariable = new Variable(tableNodes[columnIndex], tableData[rowIndex, columnIndex], (rowIndex + 1).ToString());
                //The below allows updating Variables in and adding Variables to the collection. 
                //If initializing, Agent.Variables.Add() may be used instead.
                myAgent.Variables[tableCellVariable.Id] = tableCellVariable;
            }
        }
    }
}

/// <summary>
/// Overload that takes a NodeName parameter.
/// </summary>
/// <param name="myAgent">Agent instance to add/set the table data to/in.</param>
/// <param name="tableNodeName">NodeName of the table. From either Dart.Snmp.NodeName or Mib.NodeName.</param>
/// <param name="tableData">A 2d array [rows, columns] containing the table data to set on the agent.</param>
/// <remarks>
/// This overload takes an Enum tableNodeName argument, therefore it can only be used with built-in NodeNames, or 
/// NodeNames from an imported Mib Code File.
/// </remarks>
private void setLocalTable(Agent myAgent, Enum tableNodeName, string[,] tableData)
{
    setLocalTable(myAgent, tableNodeName.ToString(), tableData);
}
Visual Basic
Copy Code
''' <summary>
''' Adds/sets table values from the specified 2d string array to/in the Agent's variables collection.
''' </summary>
''' <param name="myAgent">Agent instance to add/set the table data to/in.</param>
''' <param name="tableNameOrOid">Name or OID of the table.</param>
''' <param name="tableData">A 2d array [rows, columns] containing the table data to set on the agent.</param>
''' <remarks>
''' This method takes a string tableNameOrOid argument, therefore it is compatible with dynamically loaded MIBs.
''' This method requires the MIB or Mib Code File defining the table to be loaded/imported in myManager.Mib.
''' To sparsely populate the table, or to not update a table cell, specify null/Nothing for the tableData element.
''' </remarks>
Private Sub setLocalTable(ByVal myAgent As Agent, ByVal tableNameOrOid As String, ByVal tableData(,) As String)
    'Can also take a MibNode argument
    Dim tableNodes() As MibNode = myAgent.Mib.GetTableColumns(tableNameOrOid)
    Dim rows As Integer = tableData.GetLength(0)
    Dim columns As Integer = tableData.GetLength(1)

    If columns <> tableNodes.Length Then
        Throw New ArgumentException("The number of columns contained in the table data does not match the table's definition", "tableData")
    End If

    For rowIndex As Integer = 0 To rows - 1
        For columnIndex As Integer = 0 To columns - 1
            If tableData(rowIndex, columnIndex) IsNot Nothing Then
                Dim tableCellVariable As New Variable(tableNodes(columnIndex), tableData(rowIndex, columnIndex), (rowIndex + 1).ToString())
                'The below allows updating Variables in and adding Variables to the collection. 
                'If initializing, Agent.Variables.Add() may be used instead.
                myAgent.Variables(tableCellVariable.Id) = tableCellVariable
            End If
        Next columnIndex
    Next rowIndex
End Sub

''' <summary>
''' Overload that takes a NodeName parameter.
''' </summary>
''' <param name="myAgent">Agent instance to add/set the table data to/in.</param>
''' <param name="tableNodeName">NodeName of the table. From either Dart.Snmp.NodeName or Mib.NodeName.</param>
''' <param name="tableData">A 2d array [rows, columns] containing the table data to set on the agent.</param>
''' <remarks>
''' This overload takes an Enum tableNodeName argument, therefore it can only be used with built-in NodeNames, or 
''' NodeNames from an imported Mib Code File.
''' </remarks>
Private Sub setLocalTable(ByVal myAgent As Agent, ByVal tableNodeName As [Enum], ByVal tableData(,) As String)
    setLocalTable(myAgent, tableNodeName.ToString(), tableData)
End Sub

The following example demonstrates setting a whole table on a remote Agent from a Manager from values in a 2d string array.

C#
Copy Code
/// <summary>
/// Sets table values on a remote agent from the values contained in a 2d string array.
/// </summary>
/// <param name="myManager">Local Manager instance</param>
/// <param name="agentEP">Agent address</param>
/// <param name="tableNameOrOid">Name or OID of the table.</param>
/// <param name="tableData">A 2d array [rows, columns] containing the table data to set on the agent.</param>
/// <remarks>
/// This method takes a string tableNameOrOid argument, therefore it is compatible with dynamically loaded MIBs.
/// This method requires the MIB or Mib Code File defining the table to be loaded/imported in myManager.Mib.
/// To sparsely populate the table, or to not update a table cell, specify null/Nothing for the tableData element.
/// </remarks>
private void setRemoteTable(Manager myManager, IPEndPoint agentEP, string tableNameOrOid, string[,] tableData)
{
    //Can also take a MibNode argument
    MibNode[] tableNodes = myManager.Mib.GetTableColumns(tableNameOrOid);
    int rows = tableData.GetLength(0);
    int columns = tableData.GetLength(1);

    if (columns != tableNodes.Length)
        throw new ArgumentException("The number of columns contained in the table data does not match the table's definition", "tableData");

    SnmpSocket managerSocket = new SnmpSocket(myManager);

    try
    {
        //Set the variables on the agent row by row (instead of trying to set the entire table at once) so that it's unlikely that the set 
        //messages are too large (otherwise the response's ResponseMessage.ErrorStatus is ErrorStatus.TooBig).
        //-If this is the case (can be caused by many columns, or cells that contain a lot of data), break up the Variables across more SetMessages.
        for (int rowIndex = 0; rowIndex <= rows - 1; rowIndex++)
        {
            SetMessage rowSetMessage = new SetMessage();
            for (int columnIndex = 0; columnIndex <= columns - 1; columnIndex++)
                if(tableData[rowIndex, columnIndex] != null)
                    rowSetMessage.Variables.Add(new Variable(tableNodes[columnIndex], tableData[rowIndex, columnIndex], (rowIndex + 1).ToString()));
            ResponseMessage response = managerSocket.GetResponse(rowSetMessage, agentEP, 3);
            //Handle response as desired here...
        }
    }
    finally
    {
        managerSocket.Close();
    }
}

/// <summary>
/// Overload that takes a NodeName parameter.
/// </summary>
/// <param name="myManager">Local Manager instance</param>
/// <param name="agentEP">Agent address</param>
/// <param name="tableNodeName">NodeName of the table. From either Dart.Snmp.NodeName or Mib.NodeName.</param>
/// <param name="tableData">A 2d array [rows, columns] containing the table data to set on the agent.</param>
/// <remarks>
/// This overload takes an Enum tableNodeName argument, therefore it can only be used with built-in NodeNames, or 
/// NodeNames from an imported Mib Code File.
/// </remarks>
private void setRemoteTable(Manager myManager, IPEndPoint agentEP, Enum tableNodeName, string[,] tableData)
{
    setRemoteTable(myManager, agentEP, tableNodeName.ToString(), tableData);
}
Visual Basic
Copy Code
''' <summary>
''' Sets table values on a remote agent from the values contained in a 2d string array.
''' </summary>
''' <param name="myManager">Local Manager instance</param>
''' <param name="agentEP">Agent address</param>
''' <param name="tableNameOrOid">Name or OID of the table.</param>
''' <param name="tableData">A 2d array [rows, columns] containing the table data to set on the agent.</param>
''' <remarks>
''' This method takes a string tableNameOrOid argument, therefore it is compatible with dynamically loaded MIBs.
''' This method requires the MIB or Mib Code File defining the table to be loaded/imported in myManager.Mib.
''' To sparsely populate the table, or to not update a table cell, specify null/Nothing for the tableData element.
''' </remarks>
Private Sub setRemoteTable(ByVal myManager As Manager, ByVal agentEP As IPEndPoint, ByVal tableNameOrOid As String, ByVal tableData(,) As String)
    'Can also take a MibNode argument
    Dim tableNodes() As MibNode = myManager.Mib.GetTableColumns(tableNameOrOid)
    Dim rows As Integer = tableData.GetLength(0)
    Dim columns As Integer = tableData.GetLength(1)

    If columns <> tableNodes.Length Then
        Throw New ArgumentException("The number of columns contained in the table data does not match the table's definition", "tableData")
    End If

    Dim managerSocket As New SnmpSocket(myManager)

    Try
        'Set the variables on the agent row by row (instead of trying to set the entire table at once) so that it's unlikely that the set 
        'messages are too large (otherwise the response's ResponseMessage.ErrorStatus is ErrorStatus.TooBig).
        '-If this is the case (can be caused by many columns, or cells that contain a lot of data), break up the Variables across more SetMessages.
        For rowIndex As Integer = 0 To rows - 1
            Dim rowSetMessage As New SetMessage()
            For columnIndex As Integer = 0 To columns - 1
                If tableData(rowIndex, columnIndex) IsNot Nothing Then
                    rowSetMessage.Variables.Add(New Variable(tableNodes(columnIndex), tableData(rowIndex, columnIndex), (rowIndex + 1).ToString()))
                End If
            Next columnIndex
            Dim response As ResponseMessage = managerSocket.GetResponse(rowSetMessage, agentEP, 3)
            'Handle response as desired here...
        Next rowIndex
    Finally
        managerSocket.Close()
    End Try
End Sub

''' <summary>
''' Overload that takes a NodeName parameter.
''' </summary>
''' <param name="myManager">Local Manager instance</param>
''' <param name="agentEP">Agent address</param>
''' <param name="tableNodeName">NodeName of the table. From either Dart.Snmp.NodeName or Mib.NodeName.</param>
''' <param name="tableData">A 2d array [rows, columns] containing the table data to set on the agent.</param>
''' <remarks>
''' This overload takes an Enum tableNodeName argument, therefore it can only be used with built-in NodeNames, or 
''' NodeNames from an imported Mib Code File.
''' </remarks>
Private Sub setRemoteTable(ByVal myManager As Manager, ByVal agentEP As IPEndPoint, ByVal tableNodeName As [Enum], ByVal tableData(,) As String)
    setRemoteTable(myManager, agentEP, tableNodeName.ToString(), tableData)
End Sub

PowerSNMP for .NET Documentation Version 7.0
© 2023 Dart Communications. All Rights Reserved.
Send comments on this topic