Skip to content

NMS-16237: add support for RFC2348 "TFTP blksize" to the tftp implementation#8184

Closed
dino2gnt wants to merge 8 commits intorelease-35.xfrom
dcy/nms-16237
Closed

NMS-16237: add support for RFC2348 "TFTP blksize" to the tftp implementation#8184
dino2gnt wants to merge 8 commits intorelease-35.xfrom
dcy/nms-16237

Conversation

@dino2gnt
Copy link
Copy Markdown
Contributor

@dino2gnt dino2gnt commented Dec 6, 2025

This also:

  • Adds additional debug logging to aid in troubleshooting DCB issues (failing silently sucks) <1>
  • Adds quality-of-life improvements for how ${filenameSuffix} is checked (endwith() / contains())
  • Bumps commons.net to 3.12.0

Happy to re-target to a different branch if y'all think this is simple enough to go back into other Meridians, otherwise i think this will get it into Horizon 35 and Meridian 2026 ?

Pretty limited blast radius either way.

1>

2025-12-06T15:39:58,798 | DEBUG | pool-19-thread-4 | RetrieverImpl                    | 339 - org.opennms.features.device-config.retrieval - 34.0.1 | retrieve config: /192.168.69.74:22
2025-12-06T15:39:58,799 | INFO  | pool-19-thread-4 | TftpServerImpl                   | 345 - org.opennms.features.device-config.tftp - 34.0.1 | Starting TFTP Server on port 69
2025-12-06T15:39:58,803 | INFO  | pool-19-thread-4 | TftpServerImpl                   | 345 - org.opennms.features.device-config.tftp - 34.0.1 | Registered new TFTP receiver, current receiver count 1
2025-12-06T15:39:58,804 | DEBUG | pool-19-thread-4 | DeviceConfigMonitor              | 337 - org.opennms.features.device-config.monitor - 34.0.1 | Starting retrieval, waiting at most 60000 milliseconds
2025-12-06T15:39:59,552 | DEBUG | Thread-236       | SshScriptingServiceImpl          | 344 - org.opennms.features.device-config.ssh-scripting - 34.0.1 | ssh connection successful, executing script: await: ]$\nsend: echo "HELLO!"\nsend: /usr/bin/atftp --trace --option "blksize 1024" --put -l hosts -r hosts-${filenameSuffix}.cfg ${tftpServerIp} ${tftpServerPort}\nawait: ]$\nsend: exit\n
2025-12-06T15:39:59,552 | DEBUG | Thread-236       | SshScriptingServiceImpl          | 344 - org.opennms.features.device-config.ssh-scripting - 34.0.1 | ssh scripting service executing - await: ]$
2025-12-06T15:40:00,553 | DEBUG | Thread-236       | SshScriptingServiceImpl          | 344 - org.opennms.features.device-config.ssh-scripting - 34.0.1 | ssh scripting service executing - send: echo "HELLO!"
2025-12-06T15:40:00,554 | DEBUG | Thread-236       | SshScriptingServiceImpl          | 344 - org.opennms.features.device-config.ssh-scripting - 34.0.1 | ssh scripting service executing - send: /usr/bin/atftp --trace --option "blksize 1024" --put -l hosts -r hosts-3gDzvpsoSpmNzsa9r_r0-Q-monitor.cfg 192.168.69.121 69
2025-12-06T15:40:00,554 | DEBUG | Thread-236       | SshScriptingServiceImpl          | 344 - org.opennms.features.device-config.ssh-scripting - 34.0.1 | ssh scripting service executing - await: ]$
2025-12-06T15:40:00,561 | DEBUG | Thread-238       | TftpServerImpl                   | 345 - org.opennms.features.device-config.tftp - 34.0.1 | Received write request from client '/192.168.69.74'
2025-12-06T15:40:00,561 | DEBUG | Thread-238       | TftpServerImpl                   | 345 - org.opennms.features.device-config.tftp - 34.0.1 | Received blksize option from client '/192.168.69.74', attempting negotiation
2025-12-06T15:40:00,561 | DEBUG | Thread-238       | TftpServerImpl                   | 345 - org.opennms.features.device-config.tftp - 34.0.1 | Negotiating tftp blksize '1024' with client '/192.168.69.74'
2025-12-06T15:40:00,562 | DEBUG | Thread-238       | TftpServerImpl                   | 345 - org.opennms.features.device-config.tftp - 34.0.1 | Successfully negotiated blksize '1024' with client '/192.168.69.74'
2025-12-06T15:40:00,563 | DEBUG | Thread-238       | TftpServerImpl                   | 345 - org.opennms.features.device-config.tftp - 34.0.1 | Processing block 1 from client '/192.168.69.74'
2025-12-06T15:40:00,563 | DEBUG | Thread-238       | TftpServerImpl                   | 345 - org.opennms.features.device-config.tftp - 34.0.1 | Sending Ack for block 1 from client '/192.168.69.74'
2025-12-06T15:40:00,563 | DEBUG | Thread-238       | TftpServerImpl                   | 345 - org.opennms.features.device-config.tftp - 34.0.1 | Processing block 2 from client '/192.168.69.74'
2025-12-06T15:40:00,564 | DEBUG | Thread-238       | TftpServerImpl                   | 345 - org.opennms.features.device-config.tftp - 34.0.1 | Sending Ack for block 2 from client '/192.168.69.74'
2025-12-06T15:40:00,566 | DEBUG | Thread-238       | TftpServerImpl                   | 345 - org.opennms.features.device-config.tftp - 34.0.1 | Processing block 3 from client '/192.168.69.74'
2025-12-06T15:40:00,566 | DEBUG | Thread-238       | TftpServerImpl                   | 345 - org.opennms.features.device-config.tftp - 34.0.1 | Sending Ack for block 3 from client '/192.168.69.74'
2025-12-06T15:40:00,569 | DEBUG | Thread-238       | TftpServerImpl                   | 345 - org.opennms.features.device-config.tftp - 34.0.1 | Processing block 4 from client '/192.168.69.74'
2025-12-06T15:40:00,569 | DEBUG | Thread-238       | TftpServerImpl                   | 345 - org.opennms.features.device-config.tftp - 34.0.1 | Sending Ack for block 4 from client '/192.168.69.74'
2025-12-06T15:40:00,574 | DEBUG | Thread-238       | TftpServerImpl                   | 345 - org.opennms.features.device-config.tftp - 34.0.1 | Processing block 5 from client '/192.168.69.74'
2025-12-06T15:40:00,576 | DEBUG | Thread-238       | TftpServerImpl                   | 345 - org.opennms.features.device-config.tftp - 34.0.1 | Sending Ack for block 5 from client '/192.168.69.74'
2025-12-06T15:40:00,578 | DEBUG | Thread-238       | RetrieverImpl                    | 339 - org.opennms.features.device-config.retrieval - 34.0.1 | received config - target: /192.168.69.74:22; address: 192.168.69.74
2025-12-06T15:40:01,555 | DEBUG | Thread-236       | SshScriptingServiceImpl          | 344 - org.opennms.features.device-config.ssh-scripting - 34.0.1 | ssh scripting service executing - send: exit
2025-12-06T15:40:01,561 | INFO  | Thread-238       | TftpServerImpl                   | 345 - org.opennms.features.device-config.tftp - 34.0.1 | Unregistered TFTP receiver, current receiver count 0
2025-12-06T15:40:01,562 | INFO  | Thread-238       | TftpServerImpl                   | 345 - org.opennms.features.device-config.tftp - 34.0.1 | No receivers exist currently, closing the tftp server
2025-12-06T15:40:01,562 | DEBUG | Thread-238       | DeviceConfigMonitor              | 337 - org.opennms.features.device-config.monitor - 34.0.1 | Retrieved device configuration - target: /192.168.69.74:22

Accessing the socket via reflection and the blksize test were written with Claude's assistance.

External References

@marshallmassengill
Copy link
Copy Markdown
Contributor

I've tested this in my lab and things seem to be working as expected. I think I would target this at 2025 or maybe even 2024? It's a pretty minimal change but it's a good quality of life improvement for the feature.

I would suggest we tweak the docs for this a bit too explaining that suffix variable a bit if nothing else and mentioning the support for RFC2348.

Copy link
Copy Markdown
Contributor

@marshallmassengill marshallmassengill left a comment

Choose a reason for hiding this comment

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

Code changes look good. See my comments for other notes.

@dino2gnt
Copy link
Copy Markdown
Contributor Author

dino2gnt commented Dec 8, 2025

I would suggest we tweak the docs for this a bit too explaining that suffix variable a bit

I changed the behavior, now no matter how the user interprets the ${filenameSuffix} requirement (end of the full filename, end of the filename but before the file extension, something else), it'll be accepted. Docs can remain unclear 😆

@Override
public void onFileReceived(InetAddress address, String fileName, byte[] content) {
if (fileName.endsWith(fileNameSuffix)) {
if (fileName.endsWith(fileNameSuffix) || fileName.contains(fileNameSuffix)) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

why is this necessary ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Anecdotally, multiple users in multiple instances have been confused by "filenameSuffix" and what "suffix" actually means when relating to "filename" (this tripped up Marshall while were testing this, in fact). Enforcing where the matching string lives in the string is completely arbitrary and confusing to the end user. It could absolutely be simplified to:

if (fileName.contains(fileNameSuffix)) {

if you prefer.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Then it is incomplete. Current code only removes the fileNameSuffix at the end of the fileName

future.complete(Either.right(new Success(content, fileName.substring(0, fileName.length() - fileNameSuffix.length()), scriptOutput)));

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Wasn't aware we removed it at all :D I'll take a closer look.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

    private static String uniqueFilenameSuffix() {
        // the term "monitor" is required to not consume it from the sink module, see class DeviceConfigDispatcher
        return BASE64_URL_ENCODER.encodeToString(uuidToBytes(UUID.randomUUID())) + "-monitor";
    }

This is what fileNameSuffix actually adds for each retrieval , this is added to keep track of each retrieval. It doesn't want to receive any random TFTP upload. It wants to retrieve exactly what is sent from the script.

If there is anything not clear from this, we can update docs.

…/deviceconfig/tftp/impl/TftpServerImpl.java


no fun :/

Co-authored-by: Chandra Gorantla <chandra@opennms.com>
Copy link
Copy Markdown
Contributor

@marshallmassengill marshallmassengill left a comment

Choose a reason for hiding this comment

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

LGTM. I would like to target this at M2025 though.

@dino2gnt
Copy link
Copy Markdown
Contributor Author

dino2gnt commented Apr 7, 2026

LGTM. I would like to target this at M2025 though.

I don't think we should introduce support for a new protocol feature in the middle of a Meridian lifecycle. I'd prefer this goes into whatever Horizon and later M2026.

@marshallmassengill
Copy link
Copy Markdown
Contributor

Fair point... ship it. We're not that far off from 2026 anyway.

Copy link
Copy Markdown
Contributor

@cgorantla cgorantla left a comment

Choose a reason for hiding this comment

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

Don't think we need any change in Retrieverimpl. fileNameSuffix is designed to be at the end after the suffix like send: put juniper.conf.gz juniper.conf.gz${filenameSuffix}.

fileNameSuffix is used to keep track of what was requested and doesn't want to just retrieve any random upload.

@Override
public void onFileReceived(InetAddress address, String fileName, byte[] content) {
if (fileName.endsWith(fileNameSuffix)) {
if (fileName.endsWith(fileNameSuffix) || fileName.contains(fileNameSuffix)) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

    private static String uniqueFilenameSuffix() {
        // the term "monitor" is required to not consume it from the sink module, see class DeviceConfigDispatcher
        return BASE64_URL_ENCODER.encodeToString(uuidToBytes(UUID.randomUUID())) + "-monitor";
    }

This is what fileNameSuffix actually adds for each retrieval , this is added to keep track of each retrieval. It doesn't want to receive any random TFTP upload. It wants to retrieve exactly what is sent from the script.

If there is anything not clear from this, we can update docs.

Copy link
Copy Markdown
Contributor

@cgorantla cgorantla left a comment

Choose a reason for hiding this comment

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

Also we might want to re-target this to release-36.x or to foundation-2025

@dino2gnt dino2gnt changed the base branch from release-35.x to foundation-2025 April 27, 2026 19:26
@dino2gnt dino2gnt changed the base branch from foundation-2025 to release-35.x April 27, 2026 19:27
@dino2gnt dino2gnt closed this Apr 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants