Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[python/mdns] Add "resolve" command for operational discovery #5025

Merged
merged 5 commits into from
Mar 5, 2021

Conversation

Damian-Nordic
Copy link
Contributor

@Damian-Nordic Damian-Nordic commented Feb 25, 2021

Problem

DiscoveryImplPlatform class contains code for DNS-SD discovery (currently, only Linux provides a backend based on Avahi), but no common interface for the functionality exists.

Summary of Changes

  • Expose the mDNS resolver functionality implemented for Avahi/Linux using a new Resolver interface.
  • Add DeviceAddressUpdater class which updates device addresses in the device controller based on responses from mDNS resolver. A result of an update/resolution request can be passed to an optional DeviceAddressUpdateDelegate, too.
  • Add discover <fabricid> <nodeid> command to the Python controller.
  • Fix improper global object initialization order. On Linux, DiscoveryImplPlatform constructor refers to MdnsAvahi global object which may not yet be initialized. Some refactoring in the code is required to come up with a better solution, but for now make sure that DiscoveryImplPlatform is not initialized prior to MdnsAvahi.

Usage:

  1. Build CHIP with chip_mdns_advertiser="platform" argument.
  2. Start Python CHIP controller.
  3. Pair a CHIP device using connect -ble ... command.
  4. Discover the device using discover <fabricid> <nodeid>.

Note that Thread devices currently don't support the DNS-SD service registration, but one can still test the new command by registering a service manually, e.g. given that the default node ID 12344321 is used run the following commands to register the corresponding service:

    avahi-publish-address host1.local. fd11:22::1 &
    avahi-publish-service -H host1.local. BC5C01-7B _chip._tcp 12345

After that, resolve 123 12344321 should return fd11:22::1:12345.

src/controller/CHIPDeviceController.cpp Outdated Show resolved Hide resolved
src/controller/CHIPDeviceController.cpp Outdated Show resolved Hide resolved
IgnoreUnusedVariable(nodeData);
}

CHIP_ERROR DeviceController::DiscoverDevice(uint64_t fabricId, NodeId nodeId)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am concerned that we make the device controller do too much - this couples the device controller with global state regarding resolution.

How about having discovery be independent of the controller?

For the long term, I imagine we want to cache these resolutions so that we do not require to rediscover nodes on every operation. For that purpose, a separate object whose purpose is to do cached discovery seems desirable. I would also make it easier to follow the 'only one delegate' support in the Resolver.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I wasn't sure what would be the final usage of this method and where to put it. According to the spec we should perform the discovery when the address is unknown or a message dispatch failed (I guess that will be possible to verify once CRMP is used), so I'm not sure if the global cache will be necessary. I put the method here as I believed the controller will know the fabric ID and the method will be needed after commissioning, but I can move it somewhere else. Do you think some singleton class like chip::Controller::DiscoveryManager would be a better place?

Copy link
Contributor

@gjc13 gjc13 Feb 26, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I perfer to have a simple ResolveNode and leave the caching mechanism to the implementation. Avahi and mDNSResponder are shipped with caching and TTL managmement. Another cache in CHIP will be hard on these platforms since they do not expose the TTL to us. On minimal mDNS we may maintain our own cache.

The api we expose to other modules can be a simple ResolveNodeId but I'd also like it to be a separate class other than the DeviceController.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I perfer to have a simple ResolveNode and leave the caching mechanism to the implementation. Avahi and mDNSResponder are shipped with caching and TTL managmement. Another cache in CHIP will be hard on these platforms since they do not expose the TTL to us. On minimal mDNS we may maintain our own cache.

I have to agree. Building caching into the CHIP stack seems like it pulls way more into the sdk than we need to. If we have an mDNS resolver that doesn't cache, it seems like effort would be better expended to fix that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I created a separate DeviceAddressUpdater, but it can't be completely independent from the controller since it must update addresses in device objects owned by the controller. However, it should be a bit more separated now.

@todo
Copy link

todo bot commented Mar 4, 2021

Clean Mdns initialization order

// TODO: Clean Mdns initialization order
// Previously sManager was a global object, but DiscoveryImplPlatform constructor calls
// platform-specific ChipMdnsInit() which for Linux initializes MdnsAvahi global object
// and that may lead to improper initialization, since the order in which global objects'
// constructors are called is undefined.
static DiscoveryImplPlatform sManager;
return sManager;
}
ServiceAdvertiser & chip::Mdns::ServiceAdvertiser::Instance()


This comment was generated by todo based on a TODO comment in 5262630 in #5025. cc @Damian-Nordic.

@CLAassistant
Copy link

CLAassistant commented Mar 4, 2021

CLA assistant check
All committers have signed the CLA.

@Damian-Nordic Damian-Nordic changed the title [python/mdns] Add "discover" command for operational discovery [python/mdns] Add "resolve" command for operational discovery Mar 4, 2021
src/controller/CHIPDevice.cpp Show resolved Hide resolved
src/controller/CHIPDevice.cpp Show resolved Hide resolved
if len(args) == 2:
err = self.devCtrl.ResolveNode(int(args[0]), int(args[1]))
if err == 0:
address = self.devCtrl.GetAddressAndPort(int(args[1]))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the resolution synchronous? I don't find it easy to follow the entire path, however it seems that at least avahi is asyn: you ask for a resolve and will later get a callback of 'node id resolved'.

What guarantees that GetAddressAndPort here is available as soon as ResolveNode completes?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ResolveNode like other long-running commands spawn the asynchronous node id resolution using CallAsync function which basically waits until a completion event is signaled. So the underlying work is done asynchronously and only ResolveNode waits till it completes.

Copy link
Contributor

@andy31415 andy31415 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving since my comments are nitpicks.
Please address them before merging.

Expose the mDNS resolver functionality implemented for
Avahi/Linux using a new Resolver interface.
Add DeviceAddressUpdater class which updates device
addresses in the device controller based on responses from
mDNS resolver. A result of an update/resolution request
can be passed to an optional DeviceAddressUpdateDelegate.

Add "resolve <fabricid> <nodeid>" command to the Python
CHIP controller. Usage:
1. Build CHIP with chip_mdns_advertiser="platform" argument.
2. Start Python CHIP controller.
3. Pair a CHIP device using "connect -ble" command.
4. Resolve the node ID using "resolve <fabricid> <nodeid>".

Note that Thread devices currently don't support the DNS-SD
service registration, but one can still test the new command
by registering the necessary services manually, e.g.

avahi-publish-address test-host.local. fd11:22::1 &
avahi-publish-publish-service -H test-host.local \
    <fabricid-hex>-<nodeid-hex> _chip._tcp 11097
On Linux, DiscoveryImplPlatform constructor refers to
MdnsAvahi global object which may not yet be initialized.
Some refactoring in the code is required to come up with
a better solution, but for now make sure that
DiscoveryImplPlatform is not initialized prior to MdnsAvahi.
Also, fix updating the device address in the device
controller as previously the connection state wasn't
updated.
@github-actions
Copy link

github-actions bot commented Mar 5, 2021

Size increase report for "gn_qpg6100-example-build" from c85120e

File Section File VM
chip-qpg6100-lock-example.out .heap 0 840
chip-qpg6100-lock-example.out .data 4 4
chip-qpg6100-lock-example.out .bss 0 -848
chip-qpg6100-lock-example.out .text -16516 -16516
Full report output
BLOAT REPORT

Files found only in the build output:
    report.csv

Comparing ./master_artifact/chip-qpg6100-lock-example.out and ./pull_artifact/chip-qpg6100-lock-example.out:

sections,vmsize,filesize
[Unmapped],0,16484
.heap,840,0
[ELF Headers],0,32
.data,4,4
.shstrtab,0,-1
.bss,-848,0
.debug_aranges,0,-1136
.debug_frame,0,-3744
.symtab,0,-6208
.strtab,0,-9187
.debug_ranges,0,-11584
.text,-16516,-16516
.debug_abbrev,0,-27559
.debug_str,0,-31995
.debug_line,0,-54644
.debug_loc,0,-57255
.debug_info,0,-287751


@github-actions
Copy link

github-actions bot commented Mar 5, 2021

Size increase report for "nrfconnect-example-build" from c85120e

File Section File VM
chip-lock.elf datas 4 4
chip-lock.elf devices -4 -4
chip-lock.elf shell_root_cmds_sections -8 -8
chip-lock.elf [LOAD #3 [RW]] 0 -23
chip-lock.elf bss 0 -841
chip-lock.elf rodata -1600 -1600
chip-lock.elf text -9752 -9752
chip-lighting.elf shell_root_cmds_sections 8 8
chip-lighting.elf datas 4 4
chip-lighting.elf devices -4 -4
chip-lighting.elf [LOAD #3 [RW]] 0 -31
chip-lighting.elf bss 0 -833
chip-lighting.elf rodata -1600 -1600
chip-lighting.elf text -9752 -9752
Full report output
BLOAT REPORT

Files found only in the build output:
    report.csv

Comparing ./master_artifact/chip-lock.elf and ./pull_artifact/chip-lock.elf:

sections,vmsize,filesize
datas,4,4
.shstrtab,0,-1
devices,-4,-4
shell_root_cmds_sections,-8,-8
[LOAD #3 [RW]],-23,0
bss,-841,0
.debug_aranges,0,-1368
rodata,-1600,-1600
.debug_frame,0,-4344
.symtab,0,-6352
text,-9752,-9752
.strtab,0,-10851
.debug_ranges,0,-13856
.debug_abbrev,0,-29368
.debug_str,0,-31571
.debug_loc,0,-39893
.debug_line,0,-51149
.debug_info,0,-301747

Comparing ./master_artifact/chip-shell.elf and ./pull_artifact/chip-shell.elf:

sections,vmsize,filesize

Comparing ./master_artifact/chip-lighting.elf and ./pull_artifact/chip-lighting.elf:

sections,vmsize,filesize
shell_root_cmds_sections,8,8
datas,4,4
.shstrtab,0,-1
devices,-4,-4
[LOAD #3 [RW]],-31,0
bss,-833,0
.debug_aranges,0,-1368
rodata,-1600,-1600
.debug_frame,0,-4344
.symtab,0,-6352
text,-9752,-9752
.strtab,0,-10851
.debug_ranges,0,-13856
.debug_abbrev,0,-29368
.debug_str,0,-31571
.debug_loc,0,-39897
.debug_line,0,-51177
.debug_info,0,-301819


@andy31415 andy31415 merged commit a578416 into project-chip:master Mar 5, 2021
@todo todo bot mentioned this pull request Mar 5, 2021
@Damian-Nordic Damian-Nordic deleted the python-discover branch March 16, 2021 08:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants