Create a new plugin from scratch by example pt. 4 (LLDP)

Ok, last part, let’s start! What do we have now? A simple page to manage lldpd and what protocols to enable:



But wouldn’t it be nice to have a tab where we can see the output of the neighbors?

Now we’re back at the point that we should be familiar with all plugins, so we know where to look for code and how to achieve our goals.


If you had a look at the Quagga plugin within the Diagnostics, you can see the current running configuration of the daemon in a text box.

In the background just a simple command is executed and the result posted to the UI. So how do we manage this in lldpd?

It’s just a single command: /usr/local/sbin/lldpcli show neighbors


First step is to register a command in the actions file plugins/net-mgmt/lldpd/src/opnsense/service/conf/actions.d/actions_lldpd.conf

command:/usr/local/sbin/lldpcli show neighbors
message:show lldp neighbors


Then we have to create an API call in plugins/net-mgmt/lldpd/src/opnsense/mvc/app/controllers/OPNsense/Lldpd/Api/ServiceController.php

In the ServiceController add:

* show lldpd neighbors
* @return array
public function neighborAction()
$backend = new Backend();
$response = $backend->configdRun(„lldpd neighbor“);
return array(„response“ => $response);

Now we have an API call which can be executed via UI and calls the lldpcli daemon via configd. If you are wondering how I get to these lines, just look at the controller code for Quagga. plugins/net/quagga/src/opnsense/mvc/app/controllers/OPNsense/Quagga/Api/DiagnosticsController.php there at line 63 begins the function. Be aware that Action is a must and is hast to start with an upper case „A“.

Confused? No, it’s easy if you’ve done similar tasks for a couple of times ­čÖé

When we look in our volt in/plugins/blob/lldpd/net-mgmt/lldpd/src/opnsense/mvc/app/views/OPNsense/Lldpd/general.volt there is only a simple div and our content loaded via standard functions. Since we cannot add out API call within it we have to create a new tab with this function.

The tab is

<ul class=“nav nav-tabs“ data-tabs=“tabs“ id=“maintabs“>
<li class=“active“><a data-toggle=“tab“ href=“#general“>{{ lang._(‚General‘) }}</a></li>
<li><a data-toggle=“tab“ href=“#neighbor“>{{ lang._(‚Neighbors‘) }}</a></li>


Following the API call:

ajaxCall(url=“/api/lldpd/service/neighbor“, sendData={}, callback=function(data,status) {


And a simple div loading the values:

<div id=“neighbor“ class=“tab-pane fade in“>
<pre id=“listneighbor“></pre>


Note: Since this is already merged some minutes ago you can view it here:


Now we are finished and can install the package on a test machine:

git clone<user>/plugins
cd plugins
git checkout lldpd (if you use a branch)
cd net-mgmt/lldpd
make package
pkg install work/pkg/os-*.txz


If everything works you can create a pull request and the guys from OPNsense will help to finalize.


Note: If you have question feel free to ask in the forums, if you are nearly complete you can also create a PR and ask the guys via Github to help. I had also no idea how to manage templating via calling the daemon:


And here you can follow my discussion adding this daemon to the source. As you can see it hasn’t to be perfect from the beginning ­čÖé


Have fun!