]> git.ipfire.org Git - thirdparty/lldpd.git/commitdiff
dot3: as PD device, echo back PSE allocated value feature/echo-pd-pse-allocated 256/head
authorVincent Bernat <vincent@bernat.im>
Sun, 19 Nov 2017 15:38:33 +0000 (16:38 +0100)
committerVincent Bernat <vincent@bernat.im>
Sun, 19 Nov 2017 15:38:33 +0000 (16:38 +0100)
Dot3 power TLV contains an allocated value and a requested value. When
PSE allocates some power and says so in its TLV, PD device is expected
to echo back (within 10 seconds) the received value in its own TLV. We
handle this part automatically.

Fix #243
Fix #249

NEWS
src/daemon/lldpd.c
tests/integration/test_dot3.py

diff --git a/NEWS b/NEWS
index 40635946a1715494c327899a73faa3538ce8df11..b1f9c298503c998dd5b91b12afbc7d44fa225cee 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,7 @@ lldpd (0.9.9)
   * Changes:
     + lldpcli can now display local interfaces with LLDP data sent on
       each of them ("show interfaces").
+    + As Dot3 PD device, echo back allocated value from PSE device.
   * Fix:
     + Don't remove interfaces when they are released from a bridge.
     + Don't use "expect stop" with Upstart. It's buggy.
index 343870083f2657199ceb66428c0a20e30acbf805..35d71174dc81735331a38412cb479f8c26f61631 100644 (file)
@@ -944,6 +944,37 @@ lldpd_hide_all(struct lldpd *cfg)
        }
 }
 
+/* If PD device and PSE allocated power, echo back this change. If we have
+ * several LLDP neighbors, we use the latest updated. */
+static void
+lldpd_dot3_power_pd_pse(struct lldpd_hardware *hardware)
+{
+#ifdef ENABLE_DOT3
+       struct lldpd_port *port, *selected_port = NULL;
+       /* Are we a PD device? */
+       if (hardware->h_lport.p_power.devicetype != LLDP_DOT3_POWER_PD)
+               return;
+       TAILQ_FOREACH(port, &hardware->h_rports, p_entries) {
+               if (port->p_hidden_in)
+                       continue;
+               if (port->p_protocol != LLDPD_MODE_LLDP)
+                       continue;
+               if (port->p_power.devicetype != LLDP_DOT3_POWER_PSE)
+                       continue;
+               if (!selected_port || port->p_lastupdate > selected_port->p_lastupdate)
+                       selected_port = port;
+       }
+       if (selected_port->p_power.allocated != hardware->h_lport.p_power.allocated) {
+               log_info("receive", "for %s, PSE told us allocated is now %d instead of %d",
+                   hardware->h_ifname,
+                   selected_port->p_power.allocated,
+                   hardware->h_lport.p_power.allocated);
+               hardware->h_lport.p_power.allocated = selected_port->p_power.allocated;
+               levent_schedule_pdu(hardware);
+       }
+#endif
+}
+
 void
 lldpd_recv(struct lldpd *cfg, struct lldpd_hardware *hardware, int fd)
 {
@@ -981,6 +1012,7 @@ lldpd_recv(struct lldpd *cfg, struct lldpd_hardware *hardware, int fd)
        TRACE(LLDPD_FRAME_RECEIVED(hardware->h_ifname, buffer, (size_t)n));
        lldpd_decode(cfg, buffer, n, hardware);
        lldpd_hide_all(cfg); /* Immediatly hide */
+       lldpd_dot3_power_pd_pse(hardware);
        lldpd_count_neighbors(cfg);
        free(buffer);
 }
index f24e0372f8a3c5f53ef663392f296d4dfc466ca0..6f311953bc01671f6f09d2fdf849e93d8aff9bc6 100644 (file)
@@ -1,5 +1,4 @@
 import pytest
-import pyroute2
 import shlex
 import time
 
@@ -57,3 +56,46 @@ class TestLldpDot3(object):
                    for k, v in out.items()
                    if k.startswith(pfx)}
             assert out == expected
+
+    def test_autoneg_power(self, links, lldpd, lldpcli, namespaces):
+        links(namespaces(1), namespaces(2))
+        with namespaces(1):
+            lldpd()
+        with namespaces(2):
+            lldpd()
+            result = lldpcli(
+                *shlex.split("configure dot3 power pd "
+                             "supported enabled paircontrol "
+                             "powerpairs spare "
+                             "class class-3 "
+                             "type 1 source both priority low "
+                             "requested 20000 allocated 5000"))
+            assert result.returncode == 0
+            time.sleep(2)
+        with namespaces(1):
+            # Did we receive the request?
+            out = lldpcli("-f", "keyvalue", "show", "neighbors", "details")
+            assert out['lldp.eth0.port.power.requested'] == '20000'
+            assert out['lldp.eth0.port.power.allocated'] == '5000'
+            # Send an answer we agree to give almost that (this part
+            # cannot be automated, lldpd cannot take this decision).
+            result = lldpcli(
+                *shlex.split("configure dot3 power pse "
+                             "supported enabled paircontrol powerpairs "
+                             "spare class class-3 "
+                             "type 1 source primary priority high "
+                             "requested 20000 allocated 19000"))
+            assert result.returncode == 0
+            time.sleep(2)
+        with namespaces(2):
+            # Did we receive that?
+            out = lldpcli("-f", "keyvalue", "show", "neighbors", "details")
+            assert out['lldp.eth1.port.power.requested'] == '20000'
+            assert out['lldp.eth1.port.power.allocated'] == '19000'
+        with namespaces(1):
+            # Did we get an echo back? This part is handled
+            # automatically by lldpd: we confirm we received the
+            # answer "immediately".
+            out = lldpcli("-f", "keyvalue", "show", "neighbors", "details")
+            assert out['lldp.eth0.port.power.requested'] == '20000'
+            assert out['lldp.eth0.port.power.allocated'] == '19000'