| Expanding JFFNMS |
While JFFNMS comes with many interface types, the sad fact is that the world is filled with a large variety of things you can monitor, graph and alarm. This chapter describes how you can expand JFFNMS so it is able to monitor something new.
If you are happy with your creation and think others could benefit, it would be a nice idea to contribute to JFFNMS by sending in your patches and SQL statements.
Before starting to create your new Interface Type, you should do some planning. Quite often even experienced developers have had to re-work the descriptions so some care and time now is a good idea.
The next sections describe points you should consider before starting to write any code.
What is the least intrusive way of finding these sorts of interfaces? A large majority of interfaces are found by doing an SNMP query to a specific OID. If the OID returns a value, then there could be an interface.
Be careful with assumptions. You may discover half-configured or useless interfaces. The Cisco SAA interface type scans a SNMP table for its interfaces, however only some types of interfaces return useful information. Possibly polling another SNMP table to check for type and suppressing known "bad" types would give a cleaner result.
Design the discovery plug-in to determine with the least amount of prodding and time that an interface of its type doesn't exist on the Host. Is there one SNMP query, for instance, that if it returns nothing means there are no interfaces of this type? If it returns nothing then stop right there; there is no need to continue.
Does it make sense for this type of interface to be manually added by the Administrator. The TCP port interface type does some probing for know TCP ports but does not do an exhaustive check of all 65,535 TCP ports so it does make sense for this interface to have a manual add feature.
Try to avoid using this feature as a work-around for a badly written discovery plugin. If it is not too intrusive the plugin should find all valid interfaces of this type.
Examine the data that you can get about the interface. Look for something that could be used as a short-cut to say "this interface". If your interfaces are part of a well-formed SNMP table, there is most likely to be an index column (probably the first OID in the table).
The index is used as a key to access information about the interface. It should rarely change and if it does, there should be a poller that detects and optionally corrects for this. The ifDescr to ifIndex poller which changes the index field to match a fixed description field is an example of this corrective poller. The TCP port number for the TCP port interfaces is the best sort of index field because the index completely describes the interface; you cannot have TCP port 53 moving to TCP port 80.
Usually there can be some fallback index which is the order that the discovery plugin detects them. This is definitely not recommended, especially for interfaces that can be dynamically added and removed, but sometimes it is the only index you have. All interface types require an index.
The interface name goes by the confusing variable of interfaces.interface. This field is used to match events to interfaces by the event consolidator to create alarms. If you are receiving syslog messages and what to create alarms for interfaces from those messages then part of the syslog message needs to be extracted into the event "interface" field and that field should match the interfaces "Interface Name".
Description fields are interface values that better help describe the interface. They are used to give the operators a prompting about what this interface is used for. A good description will be short and to the point, a brief look at it will give most of the information you require.
While a PID (process ID) makes a good index, it doesn't seem to convey any real meaning. Knowing that PID 1234 is still alive is good, but knowing that the Apache process is running is even better.
Most interface types use one or more descriptions in this way. They can either be directly obtained from the device, such as Interface descriptions for physical interfaces or found elsewhere, such as the protocol name for TCP ports which is found locally and changes TCP port 25 into SMTP.
An important point about description fields is they must not confuse or misinterpret their information. A serious problem could occur where for some reason important interface `A' gets unimportant interface `B' description.
To make it clearer, an Interface Name is usually the name given to the interface or port by the device itself, while the name is something the Administrator does. For a physical interface on a Cisco router, the Name "FastEthernet0/1" is defined by the router's software, while the description "webserver 1" comes from the configuration set by the administrator.
Are there any values or metrics that you would like to collect about this interface type? Traffic or load counters, response times, temperature and errors are things that are typically good to be collecting and displaying.
JFFNMS doesn't really have any limit on what you collect. If it produces a number that makes some sort of sense then it can be graphed. Of course only you can decide if it is worth-while collecting that information.
Values should only be collected if they are to be graphed and/or examined with the RRD analyzer for SLA alarms. If neither of these things will happen then there is no point collecting the information.
Most of the time you will need to know what units the values are being collected in and the sort of value. The value might be a counter, which means it is counting things and increments each time. Alternatively it may be a gauge which is like a level that can go up or down, such as a CPU load.
If you are collecting some data (see previous subsection) you need to know what sort of data it is. There are three types of RRD files: the counter, gauge and absolute.
A counter is the most common type of RRDfile. This is a continuously increasing value and it means you want to measure a rate of something. Other than wrap-around, where the number is so big it goes back to zero again, every time you measure this value it is either the same or bigger than last time. The byte and packet counters of an interface are the most common example of this sort of file.
Next most likely is the gauge. This is a level and is not expressed as a rate. The load on the system, free memory or percent battery charge are examples of a gauge.
Finally there is the absolute type. This is also a counter like the first one but the counter is reset when read. It means an absolute type is something of a mixture of the other two.
Quite often it is easy to get these wrong. The absolute one is, in the authors experience, quite rare so unless it is something very strange you are measuring then it won't be this one.
If you are using a counter type and the values are going negative and they shouldn't be (eg packets per second) then this item is a gauge. Alternatively if your gauge item is steadily increasing and you think it should be approximately level then you probably should be using a counter.
There is generally two types of states for all interfaces: administrative or operational. However there is no real limit on this, it just means if you have other types of states then you need to work out how to interpret or display this information.
Administrative state is due to actions by an Administrator. These states usually only change when someone makes them change. An interface that is shutdown, deconfigured, enabled or taken out of service would have an administrative state change. Administrative state really has only two states: up or down. Half-configured or enabled interfaces are either ready for some service (up) or their not (down).
Administratively down interfaces are marked on the map as gray with a colored square denoting the operational state. Generally administrative state trumps operational; you cannot have an administratively down but operationally up interface.
Operational state is used to determine if an interface is working and can be used. Ethernet interfaces that are enabled, but not plugged in are administratively up but operationally down. If the interface is not usable because something is wrong and it not due to its configuration, then its operational state is down.
For a new device, you will need to determine how, if possible, to detect the administrative and operational state of an interface. There may also be syslog messages or SNMP traps that will change the state of the interface.
Administrative state pollers generally use a backend based on the DB (database) backend plugin to directly change the show field. There is generally no event or alarm created for this change in state. The pollers return a number and the backend equates the number to changing the field or not.
Operational state pollers in contrast return a string, such as "up" or "down". To work correctly the string must be one from the Description field of the Alarm States. The backend is based on the alarm plugin.
Events are something that happens to the Interface. If you have an operational state poller then its corresponding backend should be based on an alarm plugin and reference an Event. The event consolidator will then pick up this event and use it to change the alarm (color in map) state of the interface.
Besides the state poller events, you may also like to consider what syslog messages or SNMP traps are worthy of their own event for this interface. Information that you think would be useful to someone administering the device is a good candidate for an Event.
Events come in two types, those that create alarms and those that don't. The alarming events need to have something in them, for instance the syslog message, that can be put into the `interface' field by the consolidator and then can be used to marry up to the interface name by the event consolidator.
Of the various plugins, the most difficult to make generic is the Discovery ones. This is because there usually has to be specific careful checks to determine if an interface of a particular type.
However there are a few Discovery Plugins that could be reused. For interface types of a certain family there is benefits in using the same discovery plugin.
This discovery plugin is really a SNMP system OID checking plugin. It is given a comma-separated list of matches and compares each match with the system OID. If there is a match it returns a single interface called a CPU.
This discovery plugin is useful for discovering a type or family of the same systems. For example, you may have a new brand of Ethernet switch. You could discover and match against this model's system OID and if it matches create a CPU interface.
By JFFNMS convention, a "CPU interface" is one describing the host itself. It usually has graphs showing CPU load, memory usage and the TCP MIB pollers. Generally the CPU load and memory statistics are host type-specific while the TCP MIB is a generic SNMP MIB.
There are a quite a few Poller Items that could be reused. It is a good idea to check through this list first to see if you can avoid re-writing a poller plugin and use the existing ones instead.
There is a difference between a Poller Plugin and a Poller Item. A plugin is a code fragment that is placed in the engine/pollers directory. Poller Items are instances of pollers that use the plugins and give them parameters. The name given put in the "Poller Command (file)" column of the Poller Item table tells JFFNMS that this Poller Item uses the (file) as its poller backend.
The snmp_counter poller plugin is one of the most used plugins in JFFNMS. It takes only one parameter, which is the SNMP OID the poller should get. The item returns a single value and puts it into the field that matches the Name column.
If you need to get a number out of a device via SNMP, this is probably the plugin to use. Generally you would couple this with the Temporal Buffer backend.
This plugin is like the snmp_counter one, except that it is used for obtaining status via SNMP. It takes two parameters that are separated by a comma. The first one is the SNMP OID to poll. The second is a pipe-separated list of match and value pairs. The pairs are written in match=value format.
For example, to poll OID 123 and return `yes' if the SNMP reply is 1 and `no' if the SNMP reply is 2 the parameter would be "123,1=yes|2=no". If SNMP returns any other number, the plugin returns `down'.
The db name is a mis-nomer because this plugin extracts values out of fields that appear in the poller array (see table * , some of which are derived from database values.
The plugin can take one or two parameters. The first parameter is the key so the poller knows which field you want. The second optional parameter, separated by a comma, is "to_bytes". If this parameter is present the value obtained from the table is divided by 8.
The buffer plugin can yank values out of the buffer that have been previously put there by Poller Items that have used the Buffer or Multibuffer backend. This is especially useful when you have a single poller that obtains multiple values in one hit and now you want to extract a subset of those values. It is important that the Poller Item that puts the values in the buffer happens earlier (Has a lower sequence number) in the poller group.
The plugin takes a comma separated list of buffer keys. These keys would refer to previous buffer names. If there are multiple keys then the values are returned separated by the pipe symbol |. Do not confuse this poller plugin with the Buffer backend plugin. The poller gets values out of the buffer while the backend puts values into the buffer.
The TCP MIB is a generic MIB, or one that is not usually dependent on the particular SNMP agent. Most devices that have SNMP will have this MIB. It's purpose is to measure the number of current established TCP connections, pending passive (incoming) TCP connections and pending active (outgoing) TCP connections.
The set of 3 TCP MIB pollers use the SNMP counter to obtain their information. They are usually used in poller groups for interfaces found using the Host Information discovery plugin.
The comment that you should look at Poller plugins before writing your own is even more important when looking at the backends. Almost every Interface Type uses the same set of backend pollers. The difference is quite clear with JFFNMS shipping approximately 40 poller plugins but only 7 backend plugins.
In fact the backend plugins are so generic you can often use the existing backend definitions. This is mainly due to the fact that a lot of backend obtain their information from the Poller Item name and therefore the same backend can examine or update different fields.
The Alarm backend plugin doesn't directly create an alarm. What it does do is create an event and then that event may create an alarm when the event consolidator runs next.
The plugin requires the Event ID of the event to generate and, optionally, two other parameters. The first optional parameter is what level event to generate if the input from the poller is empty. If this parameter is set to `nothing' then no event is generated. The second optional parameter is number of seconds to wait before adding a event in case the interface is flapping. The default wait time is 60 seconds.
The parameters are separated by commas and are in the order of event id, empty event level, wait time. If you want to default empty event level (which is down) then put two commas between the event id and wait time.
The backend expects from the poller an alarm level or the alarm level and optional description. A pipe character separates the level from the description. The level must match one of the Descriptions in the Alarm States table. If the level is not found in that table, the alarm backend will not work and returns "Invalid Result".
The optional description from the poller is fed into the alarm under the Other Info field. It is then up to the event definition to decide how to present that information.
This backend takes the value from the poller and stores it into a buffer for later use by other pollers or backends in the same Poller Group. It is important to remember that this buffer is destroyed at the end of the Poller Group run.
There are two ways that the buffer is named. If the Backend table has a parameter, then this parameter is the buffer name. A far more common use is that the buffer name comes from the Name column of the Poller Item definition.
There is only one table that can be changed with the db backend and that is the interface table. The backend takes three parameters. The first being the database table field to be changed. Next is a list of key value pair that match the poller result. Finally there is a skip value.
The list of matches are separated by the pipe character and are in the format of match=value. This means if the poller output is match, then the database field will be changed to value. If there are no matches defined, then the database field is changed to the poller output value.
The skip value is used to suppress changes to the database. If the old value of the database field is equal to the skip value, then no changes are made.
To illustrate how it all works we will use the Admin Status Change View backend which is used by Physical interfaces. It has the Parameters of "show_rootmap ,down=2|up=1,0". This will mean that if the field show_rootmap is not already 0 and the poller output is "down" then show_rootmap is changed to 2. Similarly if the value is not already 0 but the poller output is "up" then show_rootmap is set to 1. Finally if the show_rootmap value is 0 or the poller output is not "down" or "up" then the field is unchanged.
The backend returns 1 if there is a database change and -1 if there was none.
The multibuffer is very similar to the standard buffer plugin except that it can take multiple values. The names of the values comes from the Name column of the Poller and are separated by commas.
The backend expects its values from the poller separated by the pipe character. The order of the parameters and poller output is important as the first output variable is put into the first named buffer and so on.
The multibuffer will only set buffers that previously have no value. On other words if a previous poller/backend pair set the buffer of the same name then this backend will not update or modify that buffer.
The backend returns the size of the buffer.
This is by far the simplest backend plugin. It does absolutely nothing except return 0. This backend is generally used when the poller is doing direct operations on certain tables. However the use of this backend generally means you have combined your poller and backend into one.
The RRD backend is used to insert values into the RRD files. It can either have a parameter of "*" or no parameter.
With the parameter of * the backend takes a look at all interface buffers and tries to match the buffers to RRD files by using the buffer name and the RRD interface field Internal Name. This is why it is important your poller items name match the RRD Interface Type value name.
No parameter means that the backend will attempt to update a RRD file by finding an interface field that has the Internal Name that matches the pollers name.
The backend returns a string showing all DS that are changed in the format ds name: value.
The name for this plugin comes from its original purpose which was to check that the interface number was still the same. This backend now has far more flexibility and is used to check that the interface index is still correct.
The poller that feeds this backend needs to independently determine the "correct" value for this interface. For example with physical interfaces the poller could examine the description (ifDescr) table to find the correct index. The point is that the poller has to be sure that the index value is correct and do this without using the index value (because the value will always agree with itself.
The backend takes the correct index value from the poller, compares this value to the current value and then changes it if they are different. For this backend to work, there can be one, and only one, interface type field that is of Index type, see Interface Type Fields.
If you need to get information from some other source that is not available using the standard pollers, then you will need to write your own. The program has to be written in PHP and is put into engine/poller/<command_name>.php
Inside the file, a single function called poller_<command_name> is created. This function is called by the main poller and has a single argument which is an array. The array contains many fields, the first lot are taken directly from the database and describe the interface being checked. They get their values mainly from the Interfaces table.
|
Field | Description |
| host_id | The Host ID from the Hosts Table |
| host_ip | IP Address of the host. |
| rw_community | SNMP Read/Write Community from Host. |
| ro_community | SNMP Read-Only Community from host. |
| interface_id | Internal sequence number in database for this interface. |
| interface_number | IfNum column. |
| interface_description | Description column. |
| address | IP Address of the interface. |
| peer | Peer IP address (for BGP interfaces). |
| bandwidth_in | Incoming (downloading) bandwidth. |
| bandwidth_out | Outgoing (uploading) bandwidth. |
| poller_name | Name of poller from Pollers Table. |
| poller_parameters | Parameters column from Pollers table. |
| random | Random number between 10 and 99. |
| time_start | Start time of poller, from time(). |
| noerrors | Has the No Poll Errors been selected. (deprecated) |
The parameter can be described in any way, because is supplied to the poller in the poller_parameters variable of the options array and the poller has to parse it.
The poller function returns a value which is then directly sent to the backend which also gets the same parameters described above. Useful values to return depend on the backend. For the alarm backend "up" and "down" are generally used. For most others a number of the measurement is used.
JFFNMS can display information collected in its RRD files. The purpose of the graph plugin is to describe to the RRD graphing engine the graph. Items such as what sort of graph, which RRD files to use and graph attributes such as titles, units and colors as defined by the plugin.
The plugin has a file in engine/graphs/graphname .inc.php and has a single function graph_graphname . This function has one parameter which is an array. The array contains standard interface parameters for the specific interface that is going to be graphed, see Table Interface Parameters.
rrdgraph parameters can be broken up into three types. Data definitions, graph descriptions and other parameters. The data definitions and graph descriptions are required for all graphs, the other parameters are useful, but not essential.
To make sense of the graph, plugins you really need to read the rrdgraph manual pages. The function returns an array of two items. The first item is the other parameters and the second are the combined data definitions and graph descriptions.
Data definitions are usually found by using the rrdtool_get_def() function. The first parameter of the function is the same parameter of the plugin function. The second parameter is a an array. The array is either a standard array that lists which interface variables (that are RRDTool type) you will use. In this format the rrdgraph binary will use the same name as the RRDTool interface value.
The second way that the array is used is with an associative array, in the form of "alias" => "name". The "alias" is the name that will be used in the other RRD parameters. The "name" is used to link to the interface values.
The graph description is used to create the virtual data definitions (lines that start with CDEF) and the graphs themselves, using the usual rrdgraph parameters such as LINE1, LINE2, AREA and STACK. Axillary items such as GPRINT, HRULE and COMMENT are also defined at this point.
The other parameters are for any of the command line arguments that you can send to rrdgraph. Most common parameter used is for the vertical label, which is defined by "-vertical-label='Bits per Second' ".
The discovery plugins are found in engine/discovery directory. To make a new discovery plugin, create a file in there called pluginname.inc.php
The file contains one public function, called discovery_pluginname which has 4 parameters: The host IP address, the SNMP read-only community, the hostid and the param field from the discovery table.
The function returns a single array of array. The outer array uses a index number that starts at 1. The inner array contains information for each interface found. The inner array has the following keys:
Starting in 0.7.1 you can return any field from the Interfaces table in the inner array, this allows better control (you can make your discovery script select an specific SLA or Poller)
There should be at least one field that is an index and you should fill in something in the other 3 common fields. If you do not, then JFFNMS might act strangely.
To debug the plugin, use the following steps:
Easily the most common request on the JFFNMS email list is someone has some SNMP-capable device along with the MIB and they want to monitor some value out of the MIB. In JFFNMS this would mean the device will become a host with the value being an interface.
This section deals with how to create a simple interface type that will poll for one counter only. It is probably the most common type of interface you will need for starters at least.
You first need to do your prework, so review the section on the Prework required first and make sure you have considered each point. Good interface design takes some time, but gives you a much better result in the end.
It is easier to use an example to illustrate how to do this work then make it all theoretical. The example I'll use is a "Real Server" from an Alteon Load Balancer. The basic idea is web browsers connect to a Virtual Server on the Load Balancer which then forwards the request to a Real Server (eg something running Apache). The benefit is that you can have many real servers for the one website.
For the Alteons I grabbed the MIBS and ran the following commands:
$ snmpwalk -v 1 -c public -m all -M.:/usr/share/snmp/mibs 10.1.2.3 private $>$ snmpwalk1.txt $ snmpwalk -v 1 -c public -On 10.1.2.3 private $>$ snmpwalk2.txt
Both commands run a snmpwalk on the device. The first loads all MIBs in the current directory (where the Alteon MIB files are) and the common MIB directory. The second command shows the same information but the OID is now numeric with the -On flag.
The hard slog is to work out what OIDS are useful and what are not. Quite often SNMP items are in tables, and we find that the Real Servers are in two tables, so lets start documenting the information we will require. I have only used the shortened SNMP information here.
We have a nice set of OIDs to work with, coming from the configuration, information and stat tables of the real server. There is an explicit index field, but what should be the "Interface Name"?
The name should mean "this interface", a unique property that sets it apart from all the other interfaces of this type. A real server is defined by its number and IP address, however it would be nice to correlate the syslog messages into events and alarms. The messages look like
The syslog messages reference the server by its IP address, so this should be its name.
Refer to the previous chapter about how to create an auto-discovery plugin. The plugin has to check to see if the host returns values for the OID and if so show that interface in the discovery page.
The easiest way to check if the device understands your OID is to query for it and see if it returns something. If it does, you add that interface into an array.
For our real servers, we first query the Index row. If we receive nothing then return FALSE right away. A common mistake is to query all columns first then check to see if valid information is returned.
The plugin then does some more SNMP walks to get the IP address hostname, Admin and Oper state. For each row in the Real Server index table, a row is created in an array which is a row itself. The fields and values are described in Table *.
|
Field | Value |
| real_server | Index number from index row |
| interface | IP address of real server |
| admin | Administrative state of server |
| Oper | Operational state of server |
| hostname | Real Server name |
Next you need to create a new interface type. This interface type will use the poller just created. See the section Creating New Interface Type for details. The interface, admin and Oper fields do not need to be defined as they are there for all interface types.
The fields will also need two RRD types for collecting the Sessions and Octets. These fields will be RRD counters and will look like table *
|
Description | Internal Name | Type and Value |
| Sessions | sessions | RRDTool DS Type: Counter |
| Octets | octets | RRDTool DS Type: Counter |
There is already a poller plugin for getting SNMP values. All you need to do is create enough Poller Items for each value you are tracking for the interface and then create a Poller Group that holds the Items.
The poller command is snmp_counter and the Parameters are the SNMP OID you want to collect. The Name comes from the Internal Name that you put in the Interface Type fields for your new interface for the RRD fields. The OID also needs the instance or the row of the table's column, put ".<index>" at the end of the OID to get the right instance. Table * has the poller items, notice the Name column is the same as the Internal Name column in Table *.
| Description | Name (Match RRD Struct DS) | Poller Command (file) | Parameters |
| Alteon RealServer Octets | octets | snmp_counter | .1.3.6.1.4 ...7.<index> |
| Alteon RealServer Sessions | sessions | snmp_counter | .1.3.6.1.4 ...8.<index> |
| bottomrule |
The Admin poller uses the snmp_counter to return a number that corresponds to the Administrative status. This is fed into a specific DB backend that changes the show interface field if the number matches the value for Administratively down.
The Oper poller uses the snmp_status poller. This poller takes an OID and a list of value=return string pairs. As it returns 'down' on no match, only put the values for up in the poller parameters. This poller feeds the string 'up' or 'down' to a newly created alarm backend. The backend creates an Alteon Real Server specific alarm if the string fed to it is 'down'.
For the interface I always create the group in this order:
The following table displays the poller items
| Poller | Backend | |
| 10 | Alteon RealServer Admin | Alteon Admin Status View |
| 15 | Alteon RealServer Oper | Alarm Verify Operational |
| 20 | Alteon RealServer Sessions | Temporal Buffer |
| 25 | Alteon RealServer Octets | Temporal Buffer |
| 90 | No Poller | RRDTool AllDSs |
Actions are things that JFFNMS can do to respond to an Alarm or an Event. Typical actions are sending messages via email or pagers, but an action could be anything you want it to be, it is just a matter of writing the script and setting up the action in JFFNMS.
Action scripts are found in the directory jffnms/engine/actions/ and have the filename action_name.inc.php In this example, we will call our action "testaction" which means the file will be called jffnms/engine/actions/testaction.inc.php
The file must have one function called "action_
tt action_name", in
our case it would be action_ testaction . The function takes one
parameter which is an array.
The array consists on the following items:
SLA stands for a Service Level Agreement. JFFNMS can continuously monitor network interfaces and check you are within a SLA. The setting of a NMS SLA does not necessarily have to be linked with a contractual SLA with your customers; you may want to use slightly tougher settings within a NMS or just use some design goals.
A SLA is for a certain interface type and consists of several SLA conditions, each of which is checked individually. The information comes from the RRDTool files, these files are updated by the poller.php every 5 minutes.
The steps on creating a SLA are as follows:
The individual SLA conditions are the low-level checks that can be performed on the available data. Variables are written between greater and less than signs like <variablename> and normal mathematical symbols are used.
JFFNMS ships with a set of individual conditions that may do everything you need. It is a good idea to check the list of existing conditions first.
To create a new individual condition, go to the Administration menu Internal Configuration => SLA Definitions => Individual Definitions. You will get a list of the existing conditions. The table for individual conditions has the following columns.
The three Show parameters are used to create the event. For example, if Show Info is "IN > 90%", Show Expression is "(<in> / 1024)" and Show Unit is "kbps" and assuming the value for in is 1024000 and the SLA triggers, the resulting message will look like "IN > 90%: 1000 kbps".
There is already a SLA event type. For most uses this event will do what you need. However if you require a different SLA event type then this is the time to do it. The method for doing this is exactly the same as making any other event type, see Event Types for details on how to create a new event type.
Once the SLA individual conditions and SLA event type are ready, it is time to create a new SLA. This is found in the Administration menu item Internal Configuration => SLA Definitions => Condition Groups. That will bring up the SLA group table, each SLA has the following parameters:
One a new SLA Group is created, it needs to have conditions bound to it so that JFFNMS can check if an interface is within its SLA or not. Clicking on the View link from the SLA group table creates another table underneath it which is used to apply the conditions.
The logic used for the SLA Grouping is RPN. The group is evaluated in order of the Position column and each item is placed onto the stack. If the item is an operator then some items may be removed from the stack and replaced with the result. The only operators allowed are AND and OR.
For example, the "Customer Satellite Link" has the following logic Alarm if (((Drops > 1% ) OR (Packet Loss > 10% ) OR (RTT > 700ms )) AND (Input Traffic < 95% ) AND (Output Traffic < 95% )) OR (Input Error Rate > 10% ). In other words alarm if both input and output traffic are below 95% at the same time there are large drops, packet loss or RTT. Alternatively alarm if the input error rate is more than 10% .
The result would be like table *. The lines are evaluated from the lowest ID to the highest. When the SLA parser finds a Boolean Operator, it takes the last 2 values from the stack and apply the function, the result is put back on the top of the stack.
All Individual Conditions return only TRUE or FALSE. (if their conditions are met or not)
|
Position | Condition |
| 10 | Input Error Rate > 10% |
| 20 | Output Traffic < 95% |
| 30 | Input Traffic < 95% |
| 40 | RoundTrip Time > 700ms |
| 50 | Packet Loss > 10% |
| 60 | Drops > 1% |
| 70 | OR |
| 72 | OR |
| 73 | AND |
| 74 | AND |
| 75 | OR |
JFFNMS is capable of transferring the configuration off a host and storing it locally for later analysis. To do this there are Host Config plugins. JFFNMS is able to transfer configuration from Cisco routers and switches, however if you have another device type you may be able to create a new Host Config Command.
The first thing to do is to determine how the configuration transfer will work. The general method of the transfer is to create a globally writable temporary file in the TFTP directory, issue some SNMP set commands to the host, wait (possibly checking for some SNMP value) and then examine the resulting configuration file in the TFTP directory.
You should try to do the transfer using a shell script first to determine that it is going to work. That way any problems will be due to something within JFFNMS and not because, for example, you are using the wrong SNMP OID.
Each configuration transfer type is stored in JFFNMS/engine/configs/
directory and the file-name is "<transfer_command>.inc.php". The
file has two functions: "config_<transfer_command>_get" and
"config_<transfer_command>_wait".
The get function takes 4 parameters: IP address of the host, Read/Write Community, IP address of the TFTP server, file-name that the configuration will be stored on TFTP server. This function is used by JFFNMS to tell the host to send the configuration to the specified file on the TFTP server. If the transfer initiation was successful return true, otherwise false.
The wait function is used by JFFNMS to determine if the transfer is complete. The function should only return if the transfer completed or if a certain amount of time has expired. Like the get function, it should return true on success and false on failure or timeout.
Once the file is created, you can add a new Host Config Commands type. You will then find the new type in the Host Table.
A lot of the plugins are able get a series of parameters about various items such as users, hosts and interfaces. This section describes what sort of parameters are available and what they can be used for.
|
Parameter | Type | Description |
| interface | number | The name of the interface |
| host_name | text | Name of the host the interface is on |
| host_ip | text | IP address of the host the interface is on |
| client_name | text | Long name of the customer of the interface |
| client_shortname | text | short name of the customer of the interface |
| sla_description | text | Name of the SLA on the interface |
| sla_threshold | number | FIXME |
| poller_group_description | text | Name of the poller group used to poll interface |
| type_description | text | Name of the Interface Type of the interface |
| zone_name | text | Name of the zone the interface is in |
| zone_image | text | file-name of the small icon for the zone the interface is in |
| description | text | Description of the interface |
| address | text | IP address of the interface |
| mask | text | IP network mask of the interface |
| peer | text | IP address of the peer for the interface |
| bandwidthin | number | Incoming/Input Bandwidth of the interface |
| bandwidtout | number | Outgoing/Output Bandwidth of the interface |
| interfacenumber | number | FIXME |
| flipinout | boolean | Flip In/Out on graphs? |
| show_rootmap | boolean | Is the Interface visible in the root map? |
| check_status | boolean | Is status checking of the interface enabled? |
| make_sound | boolean | Will JFFNMS make a sound if the interface state changes? |
| host_show | boolean | Is the host visible? |
| creation_date | timestamp | The time the interface was created in JFFNMS |
| modification_date | timestamp | The time the interface parameters were changed in JFFNMS |
| last_poll_date | timestamp | The time the poller was last run on the interface |
| id | ID | This interface ID |
| host | ID | The host the interface is on |
| type | ID | The interface type |
| sla | ID | The SLA applied to the interface |
| client | ID | The Customer that owns the interface |
| poll | ID | The poller group used on the interface |
| zone | ID | The zone the interface is in |
| rrd_mode | number | How RRD data is stored, new interfaces use 2 |
| poll_interval | number | FIXME |
| aux_table_index | number | FIXME |
The event object may have one or two fields depending if it is an Up event or a Down one. A down event only has a "start" field while an Up event has "start" and "stop" fields. Within each field there is a number of values.
The interface parameters refer to the interface that has had the event on it. The host will refer to the host of that interface. Some of the names of the fields differ between the alarm table and the interface table, but see Interface Parameters for details about those parameters.
|
Parameter | Type Description | |
| id | ID | Event ID |
| date | text | Date of the event change in the format YYYY-MM-DD hh:mm:ss |
| severity | text | String representation of the event severity |
| severity_level | number | Level of severity of the event |
| fgcolor | text | Hex triple for foreground color of event as displayed in viewer |
| bgcolor | text | Hex triple for background color of event as displayed in viewer |
| user | text | Username field for event |
| state | text | State field for event |
| info | text | Extra Info field for event |
| text | text | Event message as displayed in viewer |
| ack | number | Has event been acknowledged? 1=No 1=Yes |
| interface_id | ID | See interface field in Interface Parameters Table |
| interface_customer | text | See client_name field in Interface Parameters Table |
| type_id | text | See type field in Interface Parameters Table |
| client | ID | See client field in Interface Parameters Table |
| host_id | text | See host field in Interface Parameters Table |
| host_ip | text | See host_ip field in Interface Parameters Table |
| host_name | text | See host_name field in Interface Parameters Table |
| show_host | number | See host_show field in Interface Parameters Table |
| zone | text | Short Name of the Zone the host is located in |
| zone_id | ID | See zone field in Interface Parameters Table |
| zone_image | text | See zone_image field in Interface Parameters Table |
| zone_name | ID | See zone_name field in Interface Parameters Table |
...more ...
JFFNMS Manual, last changed March 29, 2008
| Expanding JFFNMS |