You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by hu...@apache.org on 2022/09/08 18:50:15 UTC
[plc4x] branch profinet updated: fix(plc4j(profinet): Started to add the LLDP broadcast
This is an automated email from the ASF dual-hosted git repository.
hutcheb pushed a commit to branch profinet
in repository https://gitbox.apache.org/repos/asf/plc4x.git
The following commit(s) were added to refs/heads/profinet by this push:
new eeb55696c fix(plc4j(profinet): Started to add the LLDP broadcast
eeb55696c is described below
commit eeb55696c681d18ac3591084bdf93e533404c1d6
Author: Ben Hutcheson <be...@gmail.com>
AuthorDate: Thu Sep 8 12:49:59 2022 -0600
fix(plc4j(profinet): Started to add the LLDP broadcast
---
.../profinet/discovery/ProfinetPlcDiscoverer.java | 102 +++++++++++++++++++++
.../resources/protocols/profinet/profinet.mspec | 22 +++++
2 files changed, 124 insertions(+)
diff --git a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/discovery/ProfinetPlcDiscoverer.java b/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/discovery/ProfinetPlcDiscoverer.java
index 5eb899bcc..96b2dba67 100644
--- a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/discovery/ProfinetPlcDiscoverer.java
+++ b/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/discovery/ProfinetPlcDiscoverer.java
@@ -51,6 +51,7 @@ import java.util.concurrent.Executors;
public class ProfinetPlcDiscoverer implements PlcDiscoverer {
private static final EtherType PN_EtherType = EtherType.getInstance((short) 0x8892);
+ private static final EtherType LLDP_EtherType = EtherType.getInstance((short) 0x88cc);
// The constants for the different block names and their actual meaning.
private static final String DEVICE_TYPE_NAME = "DEVICE_PROPERTIES_OPTION-1";
@@ -279,6 +280,107 @@ public class ProfinetPlcDiscoverer implements PlcDiscoverer {
return future;
}
+ public void lldpProbe() {
+ Set<PcapHandle> openHandles = new HashSet<>();
+ try {
+ for (PcapNetworkInterface dev : Pcaps.findAllDevs()) {
+ // It turned out on some MAC network devices without any ip addresses
+ // the compiling of the filter expression was causing errors. As
+ // currently there was no other way to detect this, this check seems
+ // to be sufficient.
+ if(dev.getAddresses().size() == 0) {
+ continue;
+ }
+ if (!dev.isLoopBack()) {
+ for (LinkLayerAddress linkLayerAddress : dev.getLinkLayerAddresses()) {
+ org.pcap4j.util.MacAddress macAddress = (org.pcap4j.util.MacAddress) linkLayerAddress;
+ PcapHandle handle = dev.openLive(65536, PcapNetworkInterface.PromiscuousMode.PROMISCUOUS, 10);
+ openHandles.add(handle);
+
+ ExecutorService pool = Executors.newSingleThreadExecutor();
+
+ // Only react on PROFINET DCP packets targeted at our current MAC address.
+ handle.setFilter(
+ "(ether proto 0x88cc)",
+ BpfProgram.BpfCompileMode.OPTIMIZE);
+
+ PacketListener listener =
+ packet -> {
+ // EthernetPacket is the highest level of abstraction we can be expecting.
+ // Everything inside this we will have to decode ourselves.
+ if (packet instanceof EthernetPacket) {
+ EthernetPacket ethernetPacket = (EthernetPacket) packet;
+ boolean isLldpPacket = false;
+ // I have observed sometimes the ethernet packets being wrapped inside a VLAN
+ // Packet, in this case we simply unpack the content.
+ if (ethernetPacket.getPayload() instanceof Dot1qVlanTagPacket) {
+ Dot1qVlanTagPacket vlanPacket = (Dot1qVlanTagPacket) ethernetPacket.getPayload();
+ if (LLDP_EtherType.equals(vlanPacket.getHeader().getType())) {
+ isLldpPacket = true;
+ }
+ } else if (LLDP_EtherType.equals(ethernetPacket.getHeader().getType())) {
+ isLldpPacket = true;
+ }
+
+ // It's a LLDP packet.
+ if (isLldpPacket) {
+ ReadBuffer reader = new ReadBufferByteBased(ethernetPacket.getRawData());
+ try {
+ Ethernet_Frame ethernetFrame = Ethernet_Frame.staticParse(reader);
+ PnDcp_Pdu pdu;
+ // Access the pdu data (either directly or by
+ // unpacking the content of the VLAN packet.
+ if (ethernetFrame.getPayload() instanceof Ethernet_FramePayload_VirtualLan) {
+ Ethernet_FramePayload_VirtualLan vlefpl = (Ethernet_FramePayload_VirtualLan) ethernetFrame.getPayload();
+ pdu = ((Ethernet_FramePayload_PnDcp) vlefpl.getPayload()).getPdu();
+ } else {
+ pdu = ((Ethernet_FramePayload_PnDcp) ethernetFrame.getPayload()).getPdu();
+ }
+ // Inspect the PDU itself
+ // (in this case we only process identify response packets)
+
+
+ logger.debug("Found new device: '{}' using LLDP '{}'",
+ "Not Sure", "Not Sure");
+ } catch (ParseException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+ }
+ };
+ Task t = new Task(handle, listener);
+ pool.execute(t);
+
+ // Construct and send the LLDP Probe
+
+ Ethernet_Frame identificationRequest = new Ethernet_Frame(
+ // Pre-Defined PROFINET discovery MAC address
+ new MacAddress(new byte[]{0x01, 0x0E, (byte) 0xCF, 0x00, 0x00, 0x00}),
+ toPlc4xMacAddress(macAddress),
+ new Ethernet_FramePayload_VirtualLan(VirtualLanPriority.BEST_EFFORT, false, 0,
+ new Ethernet_FramePayload_PnDcp(
+ new PnDcp_Pdu_IdentifyReq(PnDcp_FrameId.DCP_Identify_ReqPDU.getValue(),
+ 1,
+ 256,
+ Collections.singletonList(
+ new PnDcp_Block_ALLSelector()
+ )))));
+ WriteBufferByteBased buffer = new WriteBufferByteBased(34);
+ identificationRequest.serialize(buffer);
+ Packet packet = EthernetPacket.newPacket(buffer.getData(), 0, 34);
+ handle.sendPacket(packet);
+ }
+ }
+ }
+ } catch (IllegalRawDataException | NotOpenException | PcapNativeException | SerializationException e) {
+ logger.error("Got an exception while processing raw socket data", e);
+
+ for (PcapHandle openHandle : openHandles) {
+ openHandle.close();
+ }
+ }
+ }
+
private static MacAddress toPlc4xMacAddress(org.pcap4j.util.MacAddress pcap4jMacAddress) {
byte[] address = pcap4jMacAddress.getAddress();
return new MacAddress(new byte[]{address[0], address[1], address[2], address[3], address[4], address[5]});
diff --git a/protocols/profinet/src/main/resources/protocols/profinet/profinet.mspec b/protocols/profinet/src/main/resources/protocols/profinet/profinet.mspec
index 09bfea4a5..b3c0d9ca0 100644
--- a/protocols/profinet/src/main/resources/protocols/profinet/profinet.mspec
+++ b/protocols/profinet/src/main/resources/protocols/profinet/profinet.mspec
@@ -82,9 +82,31 @@
['0x8892' Ethernet_FramePayload_PnDcp
[simple PnDcp_Pdu pdu ]
]
+ ['0x88cc' Ethernet_FramePayload_LLDP
+ [simple Lldp_Pdu pdu ]
+ ]
]
]
+[type Lldp_Pdu
+ [simple TlvType_Pdu tlvChassisId]
+ [simple TlvType_Pdu tlvPortId]
+ [simple TlvTimeToLive tlvTimeToLive]
+]
+
+[type TlvType_Pdu
+ [simple uint 7 tlvId ]
+ [implicit uint 9 tlvIdLength 'lengthInBytes' ]
+ [simple typeSubType idSubType ]
+ [simple vstring '(tlvIdLength * 8) + 1' Id ]
+]
+
+[type TlvTimeToLive
+ [simple uint 7 tlvId ]
+ [implicit uint 9 tlvIdLength 'lengthInBytes' ]
+ [simple uint 16 tlvTimeToLive]
+]
+
// 4.10.3.2
// A lot of the fields are set to constant values, which would
// usually be dynamic. However are we trying to limit the number of