I have been tasked at the company I work for to make changes to a company generated MIB. That is it lives under the private sub tree.
The MIB has a table with a couple of object defined in the table.
They want the name of one of the object renamed.
Example:
TableEntry ::= SEQUENCE {
yada, yada
OldName Integer32
}
Can I just edit the MIB document to use the new name or do I need to deprecate the OldName and add a new entry and object for the new name?
TableEntry ::= SEQUENCE {
yada, yada
OldName Integer32,
NewName Integer32
}
Seems like this would be harder on an NMS to as a GET on the OldName would return no such object for this table.
The object name is purely for human consumption (or for any tools for human consumption, such as a MIB compiler, or IDE). The SNMP protocol deals only with OIDs.
As such, the worst thing would be to deprecate and add a new entry, since then
you would break all the applications that rely on the old OID.
Your solution is to REPLACE OldName with NewName, not add it to the SEQUENCE.
If you want to be safe, you could add an OBJECT IDENTIFIER clause that makes a
second name equivalence for that OID, in your example, after your definition of
NewName, eg.
NewName OBJECT-TYPE
...
::= { tableentry N }
-- N is a decimal number
you could add
OldName OBJECT IDENTIFIER ::= { tableentry N }
Related
We have a software suite that gathers health information from it's modules (services).
We deal internally with this health info, but we also want to use SNMP to let the outside world know what the status of the modules is.
Instead of using a MIB file and having to implement SNMP in every module, we want to use SNMP in one centralized service, with one MIB file.
This has its advantages, but the accompanying MIB file is getting huge because of the fact that every module may contain a complete copy of its peer modules.
This looks like this, and this just a very simple example.
The question is:
Is there a way to construct sub sections in a mib-tree in order to make the MIB-file more maintainable?
It would be so nice to create a sort of template for a module with all its child objects and just create objects from this template.
Is this possible somehow?
Below is the MIB-file for this example mib tree:
MYCOMP-MYAPP-MIB DEFINITIONS ::= BEGIN
IMPORTS
MODULE-IDENTITY, OBJECT-TYPE, NOTIFICATION-TYPE, enterprises
FROM SNMPv2-SMI
TEXTUAL-CONVENTION
FROM SNMPv2-TC;
mycomp OBJECT IDENTIFIER ::= {enterprises 12345}
myapp MODULE-IDENTITY
LAST-UPDATED "201810220000Z"
ORGANIZATION "MyCompany"
CONTACT-INFO ""
DESCRIPTION ""
::= { mycomp 40 }
systemInfoGroup OBJECT IDENTIFIER ::= {myapp 2}
ErrorStatus ::= TEXTUAL-CONVENTION
STATUS current
DESCRIPTION
"Status"
SYNTAX INTEGER {
normal(0),
error(1),
}
sysManagerGroup OBJECT IDENTIFIER
::= {systemInfoGroup 1}
sysManagerModule1 OBJECT IDENTIFIER
::= {sysManagerGroup 1}
sysManagerModule1Version OBJECT-TYPE
SYNTAX OCTET STRING (SIZE (1..100))
ACCESS read-only
STATUS current
DESCRIPTION
"Contains the version string of the software module."
::= { sysManagerModule1 1 }
sysManagerModule1Uptime OBJECT-TYPE
SYNTAX OCTET STRING (SIZE (1..100))
ACCESS read-only
STATUS current
DESCRIPTION
"Up time."
::= { sysManagerModule1 2 }
sysManagerModule1ErrorA OBJECT-TYPE
SYNTAX ErrorStatus
ACCESS read-only
STATUS current
::= { sysManagerModule1 4 }
sysManagerModule1ErrorB OBJECT-TYPE
SYNTAX ErrorStatus
ACCESS read-only
STATUS current
::= { sysManagerModule1 5 }
sysManagerModule1ErrorC OBJECT-TYPE
SYNTAX ErrorStatus
ACCESS read-only
STATUS current
::= { sysManagerModule1 6 }
sysManagerModule2 OBJECT IDENTIFIER
::= {sysManagerGroup 2}
sysManagerModule2Version OBJECT-TYPE
SYNTAX OCTET STRING (SIZE (1..100))
ACCESS read-only
STATUS current
DESCRIPTION
"Contains the version string of the software module."
::= { sysManagerModule2 1 }
sysManagerModule2Uptime OBJECT-TYPE
SYNTAX OCTET STRING (SIZE (1..100))
ACCESS read-only
STATUS current
DESCRIPTION
"Up time."
::= { sysManagerModule2 2 }
sysManagerModule2ErrorA OBJECT-TYPE
SYNTAX ErrorStatus
ACCESS read-only
STATUS current
::= { sysManagerModule2 4 }
sysManagerModule2ErrorB OBJECT-TYPE
SYNTAX ErrorStatus
ACCESS read-only
STATUS current
::= { sysManagerModule2 5 }
sysManagerModule2ErrorC OBJECT-TYPE
SYNTAX ErrorStatus
ACCESS read-only
STATUS current
::= { sysManagerModule2 6 }
END
I don't fully grok your use case (I'm not completely getting the "every module may contain a complete copy of its peer modules" part, particularly since your modules themselves actually "have" nothing if you're centralising the information in one place), but this seems like a perfect opportunity for tables. This is analogous to an array of structs, in C-like languages.
Instead of having Version, Uptime, ErrorA, ErrorB and ErrorC repeated (both in the MIB and in the actual logical tree) a million times, you have a table that contains five columns, and populate it with as many rows as you need. The syntax/form of each column need only be specified once.
You'd have an additional column (put it first) for the "index" of each row, i.e. module number.
My SMI is rusty, but the definitions would look something like this:
sysManagerGroup OBJECT IDENTIFIER
::= { systemInfoGroup 1 }
sysManagerModuleTable OBJECT-TYPE
SYNTAX SEQUENCE OF SysManagerModuleEntry
MAX-ACCESS not-accessible
STATUS current
DESCRIPTION "Table of modules being monitored"
::= { sysManagerGroup 1 }
sysManagerModuleEntry OBJECT-TYPE
SYNTAX SysManagerModuleEntry
MAX-ACCESS not-accessible
STATUS current
DESCRIPTION "A row in the table of modules being monitored"
INDEX { sysManagerModuleId }
::= { sysManagerModuleTable 1 }
SysManagerModuleEntry ::= { SEQUENCE
sysManagerModuleId Integer32,
sysManagerModuleVersion OCTET STRING,
sysManagerModuleUptime OCTET STRING,
sysManagerModuleErrorA ErrorStatus,
sysManagerModuleErrorB ErrorStatus,
sysManagerModuleErrorC ErrorStatus,
}
sysManagerModuleId OBJECT-TYPE
SYNTAX Integer32,
MAX-ACCESS not-accessible
STATUS current
DESCRIPTION "Numeric ID of the module"
::= { sysManagerModuleEntry 1 }
sysManagerModuleVersion OBJECT-TYPE
SYNTAX OCTET STRING (SIZE (1..100))
MAX-ACCESS read-only
STATUS current
DESCRIPTION
"Contains the version string of the software module."
::= { sysManagerModuleEntry 2 }
sysManagerModuleUptime OBJECT-TYPE
SYNTAX OCTET STRING (SIZE (1..100))
MAX-ACCESS read-only
STATUS current
DESCRIPTION
"Up time."
::= { sysManagerModuleEntry 3 }
sysManagerModuleErrorA OBJECT-TYPE
SYNTAX ErrorStatus
MAX-ACCESS read-only
STATUS current
::= { sysManagerModuleEntry 4 }
sysManagerModuleErrorB OBJECT-TYPE
SYNTAX ErrorStatus
MAX-ACCESS read-only
STATUS current
::= { sysManagerModuleEntry 5 }
sysManagerModuleErrorC OBJECT-TYPE
SYNTAX ErrorStatus
MAX-ACCESS read-only
STATUS current
::= { sysManagerModuleEntry 6 }
And that's it — no repeated definitions required. At runtime, add as many rows as you need/want.
Individual entries will be directly accessible as follows:
4.1.12345.40.2.1.1.1.<ID>.<FIELD>
e.g. module 2's ErrorB is
4.1.12345.40.2.1.1.1.2.5
and module 48,570's Uptime is
4.1.12345.40.2.1.1.1.48570.3
Of course, your remote Manager won't know the number of rows ahead of time, but that's fine: Managers will use a "walk" or variant — some combination of GetNext or GetBulk requests — to discover the contents of the table.
Plug these SMIv2 definitions into your MIB and feed the MIB to your SNMP Manager, and you should see how it improves the layout. How to actually populate the table will depend on your Agent software.
Note that the "table" and "entry" objects are actually kind of pseudo-objects, and thus must have not-accessible access level; the entry's index is a real value but should be not-accessible because its value is logically part of the OID for each entry, rather than a distinct object that you can poll.
By the way, enterprise number 12345 has been assigned to VWB Group; unless you're them, you will need to get your own.
Just out of curiosity, why does the golang place the type specifier after the variable name like below. Have to? Or happen to?
type person struct {
name string
age int
}
Why not just like this? It's more natural IMHO, and it saves the type keyword.
struct person {
string name
int age
}
I think the Go programming language follows these principles:
declarations start with a keyword, so that the parser can be implemented with a single token look-ahead (like in Pascal)
the rest of the declaration follows the English grammar, with every redundant word left out (also like in Pascal, but with fewer keywords)
Examples:
The type Frequency is a map indexed by string, mapping to int
type Frequency map[string]int
The type Point is a struct with two fields, x and y of type int
type Point struct { x, y int }
The above sentences focus more on the names than on the types, which makes sense since the names convey more meaning.
If I had to explain to novice programmers how to write declarations in Go, I would let them first describe it in plain English and then remove every word that might even seem redundant.
Up to now, I didn't find any contradictions to these rules.
I have a following F# enum
type DataType = AUCTION|TRANSACTION
I would like to use DataType as a parameter to a function, so that the values of the parameter is restricted to string AUCTION and TRANSACTION,
is that possible to convert the items in this enum to string, or is there a better way to contraint the value of a parameter to a set of string?
First of all, as several people have mentioned in the comments, the type you have defined is not an Enumeration, it's a Discriminated Union.
Enumerations are effectively just a label given to an integer and, in F#, are declared using this syntax:
type DataType =
|Auction = 1
|Transaction = 2
Using this syntax, you've got a relationship between the value and the associated integer, you can use the integer to get the value of an Enumeration, e.g.
let transaction = enum<DataType>(2) // Transaction
Note that there is nothing stopping you from saying enum<DataType>(3537), even though we haven't defined that case.
For more details on Enumerations, see: https://msdn.microsoft.com/en-us/library/dd233216.aspx
Discriminated Unions are much more flexible than Enumerations. Let's take a look at yours:
type DataType =
|Auction
|Transaction
This version is now actually a Standard .NET class with two case identifiers: Auction and Transaction. You can think of Auction and Transaction as two type constructors for DataType.
Discriminated Unions are not restricted to just simple cases, you could store additional data, e.g.
type DataType =
/// An auction with a list of bids
|Auction of Bid list
/// A transaction with some price in GBP
|Transaction of decimal<GBP>
With Disciminated Unions, there is no implicit relationships with integers, if we want to construct a particular case, we have to use the appropriate case identifier.
e.g. let auction = Auction (bidlist)
For more details on Discriminated Unions, see: https://msdn.microsoft.com/en-us/library/dd233226.aspx
In both cases, converting to a specific string for each case can be achieved using pattern matching.
For the Discriminated Union:
let datatypeToString datatype =
match datatype with
|Auction -> "AUCTION"
|Transaction -> "TRANSACTION"
And for the Enumeration:
let datatypeToString datatype =
match datatype with
|DataType.Auction -> "AUCTION"
|DataType.Transaction -> "TRANSACTION"
Notice that when you use Enumerations, F# will give you a compiler warning telling you that pattern matches cases aren't complete. This is because Enumerations are just ints and there are many ints besides just 1 and 2, this means that the match cases aren't exhaustive.
I therefore recommend you stick to Discriminated Unions and keep your exhaustive pattern matching.
P.S. If you want to go in the other direction, from string to DataType, I recommend using a tryCreateDataType function which would look something like this:
let tryCreateDataType str =
match str with
|"AUCTION" -> Some Auction
|"TRANSACTION" -> Some Transaction
|_ -> None
This returns an Option, so it will allow you to safely match against the function being successful or it failing due to an invalid string.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
storing 1 million phone numbers
How to design a data structure for a phone address book with 3 fields
name, phone number , address
one must be able to search this phone book on any of the 3 fields
Hash table wouldn't work because all the three fields should hash to the same value which is i think impossible. I thought about trie and other data structures too but couldn't think of a proper answer.
You Should use TRIE data Structure for Implementing Phonebook. TRIE is an ordered tree data structure that uses strings as keys. Unlike Binary Trees, TRIE does not store keys associated with the node.
Good example
You could accomplish this with a single hash table or other type of associative array (if you wanted to). For each person, just have three keys in the table (name, address, phone) all pointing to the same record.
I think a combination of a trie (each phone book entry is one leaf) and two skip lists (one for each name and address) could turn out to be effective.
Just assign each node one set of pointers to move along the name axis, and one set of pointers to move along the address axis (that is, to traverse the skip lists).
You can't exactly sort something in three ways at the same time. Nor can you feasibly build a single hash table which allows lookup with only a third of the key.
What you probably want to do is basically what databases do:
Store one (possibly unsorted) master list of all your records.
For each column you want to be able to search on, build some kind of lookup structure which returns a pointer/index into the master list.
So, for example, you build a flat array of {name, phone, address} structs in whatever order you want, and then for each row, put a (phone -> row#) mapping into a hash table. Non-unique columns could hash to a list of row numbers, or you could put them in a binary tree where duplicate keys aren't an issue.
As far as space requirements, you basically end up storing every element twice, so your space requirement will at least double. On top of this you've got the overhead from the data structures themselves; keeping three hash tables loaded at ~70% capacity, your storage requirements increase by at least 2.4 times.
You can do away with one of these auxiliary lookup structures by keeping your main table sorted on one of the columns, so you can search on it directly in O(logN). However, this makes inserting/deleting rows very expensive (O(N)), but if your data is fairly static, this isn't much of an issue. And if this is the case, sorted arrays would be the most space-efficient choice for your auxiliary lookups as well.
in a phone book, the telephone number should be unique, address is unique, but the name could be duplicated.
so perhaps you can use hash table combine with linked list to approach this.
you can use any one or combination of the 'name, address, phone number' as hash key, if you simply use name as hash key, then linked list is needed to store the duplicated entries.
in this approach, search based on the hash key is O(1) efficiency, but search based on the other two will be O(n).
C or C++ or C#?
Use a list of classes
public class PhoneBook
{
public string name;
public string phoneNumber;
public string address;
}
place this in a list and you have a phone book
In C, I think a struct is the best option.
typedef struct _Contact Contact;
struct _Contact
{
char* name;
char* number;
char* address;
};
Contact* add_new_contact( char* name, char* number, char* address )
{
Contact* c = (Contact*) malloc( sizeof( Contact ) );
c->name = name;
c->number = number;
c->address = address;
return c;
}
Contact* phone_book [ 20 ]; /* An array of Contacts */
Use the standard string functions ( <string.h> or if using a C++ compiler, <cstring> ) or something like the glib for searching the names, numbers etc.
Here's a simple example:
Contact* search_for_number( Contact* phone_book[], const char* number )
{
register int i;
for( i = 0; i < sizeof( phone_book ); i++)
{
if ( strcmp( phone_book[i]->number, number ) == 0 ) return phone_book[i];
}
return NULL;
}
There is also a good, helpful code example over here.
Alternatively
You may be able to use linked lists, but since C or the C standard library doesn't provide linked-lists, you either need to implement it yourself, or to use a third-party library.
I suggest using the g_linked_list in the glib.
I'm implementing an SNMP agent and am not sure if my understanding is correct on how values for the "t11ZsZoneMemberIndex" object (see below) are chosen, and who enforces value uniqueness.
My understanding is that an SNMP manager would chose the value for the "t11ZsZoneMemberIndex" object and use it in the "name" field of the VarBind in a SET operation. The SNMP agent would enforce the uniqueness of the "t11ZsZoneMemberIndex" value when it receives the SET. Is this correct? If not, why?
The MIB table is SMIv2, with a RowStatus object. I understand where the values for the other indexes are derived.
t11ZsZoneMemberTable OBJECT-TYPE
SYNTAX SEQUENCE OF T11ZsZoneMemberEntry
MAX-ACCESS not-accessible
::= { t11ZsConfiguration 6 }
t11ZsZoneMemberEntry OBJECT-TYPE
SYNTAX T11ZsZoneMemberEntry
MAX-ACCESS not-accessible
INDEX { fcmInstanceIndex, fcmSwitchIndex,
t11ZsServerFabricIndex, t11ZsZoneMemberParentType,
t11ZsZoneMemberParentIndex, t11ZsZoneMemberIndex }
::= { t11ZsZoneMemberTable 1 }
T11ZsZoneMemberEntry ::= SEQUENCE {
t11ZsZoneMemberParentType INTEGER,
t11ZsZoneMemberParentIndex Unsigned32,
t11ZsZoneMemberIndex Unsigned32,
t11ZsZoneMemberFormat T11ZsZoneMemberType,
t11ZsZoneMemberID OCTET STRING,
t11ZsZoneMemberRowStatus RowStatus
}
t11ZsZoneMemberParentType OBJECT-TYPE
SYNTAX INTEGER {
zone(1), -- member belongs to a Zone
alias(2) -- member belongs to a Zone Alias
}
MAX-ACCESS not-accessible
::= { t11ZsZoneMemberEntry 1 }
t11ZsZoneMemberParentIndex OBJECT-TYPE
SYNTAX Unsigned32 (1..4294967295)
MAX-ACCESS not-accessible
::= { t11ZsZoneMemberEntry 2 }
t11ZsZoneMemberIndex OBJECT-TYPE
SYNTAX Unsigned32 (1..4294967295)
MAX-ACCESS not-accessible
DESCRIPTION
"An index value that uniquely identifies this Zone
Member amongst all Zone Members in the Zone Set
database of a particular Fabric on a particular switch."
::= { t11ZsZoneMemberEntry 3 }
t11ZsZoneMemberFormat OBJECT-TYPE
SYNTAX T11ZsZoneMemberType
MAX-ACCESS read-create
::= { t11ZsZoneMemberEntry 4 }
t11ZsZoneMemberID OBJECT-TYPE
SYNTAX OCTET STRING (SIZE (1..255))
MAX-ACCESS read-create
::= { t11ZsZoneMemberEntry 5 }
t11ZsZoneMemberRowStatus OBJECT-TYPE
SYNTAX RowStatus
MAX-ACCESS read-create
::= { t11ZsZoneMemberEntry 6 }
You have it right, yes. But it's slightly more complex: the SNMP requirements are that the entire set of MIB indexes must be unique when put together. Thus, the above MIB has 6 indexes so each row in the table can have a single row for every combination of those 6 values. Which means that technically the value for t11ZsZoneMemberIndex may be duplicated as long as another index value is different.
If there is a requirement that t11ZsZoneMemberIndex be unique in itself, then the MIB really should have been defined that way and made it the single and only object in the MIB INDEX list. There is no need to add multiple unique indexes to the index itself (and is a waste of bandwidth).
But if there are multiple unique instances, and they can concflict when a manager performs the SET, then yes... It's up to the manager to reject the SET request and return an error when the data being sent isn't compatible with the internal notion of what is acceptable.