When configuring monitoring and using templates in Zabbix you often see low-level discovery (LLD) used for finding out the monitored components or features of a host. In this post, I will explain how user macros and regular expressions are used in LLD for filtering the discovery results.

I’m using the Network Generic Device by SNMP template as an example. (Note that by using the dropdown menu in the top of that linked page you can select the Zabbix version you are using. It defaults to Master, which means the latest Zabbix version that is being developed, currently 6.4.)

Let’s see the Network interfaces discovery rule and specifically the Filters tab:

Discovery rule filters

All these filters use regular expressions to match (or not match) the LLD macro value. For example:

{#IFNAME} matches {$NET.IF.IFNAME.MATCHES}

These are the macros defined in the template:

Macros defined in the template

There we see that {$NET.IF.IFNAME.MATCHES} is defined with a value: ^.*$

That is a regular expression (often called regexp or regex). I won’t try to make this post a full regular expression tutorial, but there is:

  • ^ = match the beginning of the string
  • . = match any single character
  • * = match zero or more occurrences of the previous element (which is any character in this case)
  • $ = match the end of the string

Basically, that means: “match any kind of string, empty or not”

(In this case a shorter .* would mean the exact same thing, but that’s how the template was configured when I downloaded it.)

When the discovery runs, it finds all network interfaces and assigns values to all of the LLD macros (like the interface name to {#IFNAME}), and then the filters are tested.

In the LLD filters Type of calculation is usually set to “And” (see the first screenshot), so that all filters need to be true for the interface to be discovered (in other words, if any of the filters is false, then no item is created for that interface).

If you want to change the filtering by modifying the macros, here is the thing:

  • You don’t modify the macros in the template.
  • You should modify the macros in the host that is using the template.

When you go to the Macros tab on your host, there is the Inherited and host macros button. After clicking it, you will also see all macros that are defined in the templates that the host is using:

Inherited and host macros for a host

You can click the Change link for any of the macros to enter a new value for that macro, and that value will then be used for everything for this host. The value in the template will thus act as a default value that is used whenever there is no other value set at the host level.

If you for example want to discover only interfaces that start with “wan”, “lan” or “vlan”, you can use this regexp in {$NET.IF.IFNAME.MATCHES} macro (again, change it in the host macros, not in the template): ^(wan|lan|vlan)

It means:

  • match “wan”, “lan” or “vlan”
  • but only if they are in the beginning of the string.

This is the same, just grouped differently: (^wan|^lan|^vlan)

If you at the same time want to exclude interface “vlan999”, you can use {$NET.IF.IFNAME.NOT_MATCHES} macro for that (note the “does not match” selection in the LLD filters list). The default value for that macro is:

(^Software Loopback Interface|^NULL[0-9.]*$|^[Ll]o[0-9.]*$|^[Ss]ystem$|^Nu[0-9.]*$|^veth[0-9a-z]+$|docker[0-9]+|br-[a-z0-9]{12})

Quite a mouthful, but it is basically a long list of “or” patterns separated by the vertical bar (|). You can add your own exclusion there inside the parenthesis, separated by |, or if you know that’s the only thing you want to exclude in that particular host, you can just replace the whole string with ^vlan999$ to exclude only vlan999 (and not for example lan999 or vlan9999). Note the use of ^ and $ to make sure it only matches the full interface name, not any partial names.

A common “not matches” macro value for me is something like this: ^(Nu|Tunnel|Loopback|VoIP)

It will exclude all those Null0, Loopback0 and other virtual interfaces that may exist on the device by default but won’t usually be useful in Zabbix statistics. I will always exclude these kinds of interfaces to reduce polling intensity and save database capacity.

It should also be said that all these regular expressions are case-sensitive, so use upper case or lower case as appropriate in your particular device, or expand the regexp to include various syntaxes as needed.

To conclude: When you want to reconfigure the discovery for a host:

  • See the filters that are used in the discovery rule
  • Check which macros are used in the filters
  • In the host you are configuring, change the macro values to achieve the desired filtering results.

This post was originally published on the author’s blog.

Subscribe
Notify of
2 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Aigars Kadiķis
Editor
19 days ago

I appreciate the mono space characters used in this blog post. Looks beautiful.
My two cents – if screen space is an issue (you prefer less pixels on screen), we can use context macro:
{$SERVICES:white.list}
{$SERVICES:black.list}

It magically works on all Zabbix versions 🙂

Also, this topic correlates with section from my publication:
https://blog.zabbix.com/generating-zabbix-health-csv-reports-with-custom-frontend-module/24369/#3_Identify_exceptions
Under “Connection characteristics and custom trigger thresholds” title, there is a DB query available to identify if you have installed an user macro override at a host level.

Last edited 19 days ago by Aigars Kadiķis
Matthew Steeves
Matthew Steeves
8 days ago

Only thing I would add re: case-sensitive is that, to cut down on the noise/effort of handling all possible case variations, you could also make the reg-ex case insensitive via the in-line option modifer: (?i)
e.g.
(?i)^(Nu|Tunnel|Loopback|VoIP)

I’ve used this before and really like it.

Ref: https://www.pcre.org/original/doc/html/pcresyntax.html#SEC16

2
0
Would love your thoughts, please comment.x
()
x