bacpypes icon indicating copy to clipboard operation
bacpypes copied to clipboard

Broadcasted 'IAm' response from BACnet device not registered by bacpypes

Open aakashrav opened this issue 6 years ago • 14 comments

Hey all,

I am running bacpypes version 0.16.4 and am just getting started writing some simple applications using the sample code given in the codebase.

I also have a BACnet server (bacnet-stack-0.8.2) running on a Raspberrry Pi 3 rev B as a testing device to play with different commands.

When I run the 'WhoIsAmI.py' script in the Tutorials folder, I can see using Wireshark that both the 'WhoIs' request from my Mac (macOS Sierra 10.12.6) and the subsequent 'IAm' response from the Pi are sent and registered. However, my 'WhoIsAmI.py' script doesn't seem to register the Pi's response, as it doesn't output the details of any incoming 'IAm' responses.

Both devices are on the same network, and the Pi definitely receives the 'WhoIs' request as it issues an 'IAm response'. The only problem is that this 'IAm' response doesn't seem to be properly processed by bacpypes afterwards.

Has anyone had a similar situation or can provide more information on why this problem might be occurring?

Thank you very much.

aakashrav avatar Oct 30 '17 21:10 aakashrav

Aakash,

Both devices are on the same network, and the Pi definitely receives the 'WhoIs' request as it issues an 'IAm response'. The only problem is that this 'IAm' response doesn't seem to be properly processed by bacpypes afterwards. tl;dr - check the 'address' part of the INI file and make sure you provide both the IP address and network size in CIDR notation. Your application is not listening on the broadcast address. It should be something like 192.168.0.12/24

There are two different UDP broadcast addresses (actually three, but one of them hasn't been used in decades), all F's and all F's in the host portion of the address. Let's say you have 192.168.0.12 on your machine with a subnet mask 255.255.255.0, the two most common broadcast addresses seen in the wild would be 255.255.255.255 and 192.168.0.255.

The 255.255.255.255 broadcast address is the address of the "zero network" or 0.0.0.0 and it reaches all devices, even those that are on different subnets when there is more than one subnet on the same (usually Ethernet) network. Assume that the broadcast is a request, like Who-Is. A device with address 192.168.1.16 would receive the broadcast directly but it could not reply with a unicast response (the I-Am) without going through a router which breaks symmetry.

For BACpypes applications to listen for unicast messages for the IP address and broadcast messages on the subnet broadcast address it opens up two sockets, and if you run 'netstat' or something similar you can see them both. The UDP layer in BACpypes also uses it to translate the generic '*' meaning "local broadcast" into the appropriate broadcast IP address.

If you have the 'netifaces' Python module installed you can also use the name of the interface like 'eth0' or 'en1' and it will gather the IP address and mask from that.

Joel

JoelBender avatar Nov 01 '17 11:11 JoelBender

Has this been resolved? Any updates, or should it be closed?

JoelBender avatar Apr 07 '18 22:04 JoelBender

@JoelBender , I am seeing similar behavior with bacpypes 0.17.6 and 0.17.5

Some details below inet 172.21.34.104/24 brd 172.21.34.255

There should be approximately 98 devices on this subnet.

There are ~ 100 devices on the same subnet, and there are 3-4 other subnets with BBMDs which also propagate the WhoIs.

The WhoIsIam sample only registers IAms from 90 odd devices +-5. However, these are devices across all subnets (which should number in the 400s).

Wireshark traffic shows IAms from 400 devices. WhoIsIam on bacpypes only shows 90 odd.

noenthu avatar Feb 11 '20 22:02 noenthu

I don't think that the Python socket loop can keep up with the traffic volume. The processing overhead for each decoding and dispatching each packet takes too long and the operating system buffer for UDP traffic is getting overrun. It's a downside of using Python. Try increasing the buffer like here or here and see if that makes a difference.

The alternative is to switch to asyncio, which I'm working on, pipeline the traffic into different processes or threads, etc. If you have a chance to run it with PyPy I'd like to at least hear if you have problems, and if you can process packets faster.

JoelBender avatar Feb 12 '20 02:02 JoelBender

I'm wondering if a more gentle whois could help you... in BAC0, I've implemented a discover function that takes one network at a time, but I must admit that I don't face a lot of gigantic networks... But anyway, the idea was to "try not to flood the network with IAms..." and if Python is flooded, it's kinda telling you that it's drowning.

ChristianTremblay avatar Feb 12 '20 03:02 ChristianTremblay

I will give the UDP buffer change recommendation a try and see if that nets anything different. Any eta on the asyncio implementation? :) I'll try to run it under pypy (not familiar with it) and try to get some metrics out for science!

Workaround for now would be to get the list of IPs and discover them individually.

@ChristianTremblay I'll look into the discover functionality and see if that will help us here.

noenthu avatar Feb 12 '20 16:02 noenthu

If there is a pattern to the device identifiers (like ours are the network number x 100 + the MSTP or ARCNET address) then it's easier to isolate groups of devices. You can also use a local broadcast address for just IP things, and remote broadcast addresses for other networks. It's a little more involved, but you can also passively listen for broadcast messages by other devices (like COV notifications and I-Am's), then Who-Is unicast to the address, then read the device-address-binding list to sniffer out more address. You might set off intrusion detection alarms.

Science is cool, thank you for that, and the asyncio stuff grinds along. Sigh.

JoelBender avatar Feb 13 '20 02:02 JoelBender

@JoelBender - I had increased the udp buffer max sysctl -w net.core.rmem_max=26214400 and still did not register all IAms using cpython 3.6. I updated the udp default buffer sysctl -w net.core.rmem_default=26214400 but did not test again with cpython. I then installed pypy (python2.7) and ran the whoisiam and registered all ~390 IAMs Tried with regular python 3.6 and now it registers all 390 IAMs as well.

I am not sure if both rmem_max and rmem_default need to be set for the UDP buffer to increase? Since only the max value did not result in any benefit. Now I am seeing all 390 responses with both pypy and cpython bacpypes

noenthu avatar Feb 14 '20 16:02 noenthu

I have the same issue. Can anyone please help to resolve.

nambiraja avatar Dec 17 '20 17:12 nambiraja

@noenthu Thank you for the update, I know it was a while ago!

@nambiraja Try some of the things that @noenthu did to see if it resolves your problem. In general, as the number of BACnet devices on your networks grows the possibility that there are going to be network collisions and bottlenecks also grows. Try to "divide and conquer" the instance number or address space. For MS/TP and ARCNET field bus networks, also know that the devices will probably be less capable, have smaller buffers, etc.

JoelBender avatar Dec 17 '20 20:12 JoelBender

Thanks for the quick replay. I have only one bacnet device in the network. It was Legrand RCU 048412.

nambiraja avatar Dec 17 '20 22:12 nambiraja

The most common reason for having problems is that the IPv4 network configuration is wrong, followed by a lack of experience with the idiosyncrasies of UDP communications and how BACnet uses them. Your best bet is to run Wireshark and see exactly what is being sent and received on the wire. Set your capture filter to udp and port 47808.

JoelBender avatar Dec 19 '20 20:12 JoelBender

I have seen that the provided whoisiam example app just not displays the expected result. But it is easy to fix. The result of a whois request arrives ok at the def indication(self, apdu): section of the whoisiam app. But there is an isinstance check afterwards which just failes most of the time, and so the example app does not display the result of the incoming iam messages.

pebauer68 avatar Feb 05 '21 07:02 pebauer68

Yes, that is by design, the instance check for a matching Who-Is request is to keep the I-Am traffic being displayed limited. On really busy networks with tens of thousands of devices it can be harder to focus on a specific device or range of devices with the console output streaming along.

JoelBender avatar Feb 05 '21 16:02 JoelBender