-
Notifications
You must be signed in to change notification settings - Fork 184
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
feat(iroh-net): Upnp port mapping #1117
feat(iroh-net): Upnp port mapping #1117
Conversation
We use |
This is how we define metrics:
for a detailed walkthrough, ping @Arqu our metrics guy :D |
I would start with the metrics that tailscale collects, other than that my general approach is to collect
|
Yes, maybe we could add some functionality to the |
Dig mostly covered the bare basics of metrics. To have metrics collected run with As for what metrics, there is no hard rule, metrics are there to serve us, the important ones will be surfaced more in grafana but most of them are useful. I usually go by add more as you need. Typically you want to cover major events, and output counters along with instrumenting main loops and interesting branches/error cases. |
Sounds good, though should probably check for what it is actually used where and if we need it. |
This is purely because of the structure of |
This sounds good to me in general, but I think it would be good to check with @flub how to best integrate this with his refactor plans for netcheck. |
iroh-net/src/hp/portmapper.rs
Outdated
tracing::debug!( | ||
"upnp gateway changed from {old_gateway_addr} to {gateway_addr}" | ||
); | ||
// TODO(@divagant-martian): tailscale does not invalidate the mappings here. Why? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we've searched for the router and the router has changed, maybe this implies that we don't have access to the old one anymore, so release
-ing the mapping is maybe not possible, or just not our responsibility?
If our local address has changed, but our router is the same, I understand we want to release the mapping because we want them to not direct the traffic to the old local address.
Anyways, I think it's fine to not invalidate the mappings in this case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you are right about releasing the mappings, sorry for the lack of precision: I mean they don't clear the mappings. So we still have self.current_mapping
as Some
even if, as you pointed, the router is not there anymore
iroh-net/src/hp/netcheck.rs
Outdated
/// Updates the portmap related values based on a [`portmapper::ProbeResult`]. | ||
pub fn update_portmap_probe(&mut self, probe_result: Option<portmapper::ProbeOutput>) { | ||
match probe_result { | ||
Some(portmapper::ProbeOutput { upnp, pmp, pcp }) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion, lest just just store the ProbeOutput
instead of these three individual fields.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done in 0846437
iroh/src/commands/doctor.rs
Outdated
PortMap { | ||
/// Local port to get a mapping. | ||
local_port: NonZeroU16, | ||
/// How long to wait for an external port to be ready. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: in seconds
or sth like that is missing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done in 552e1c7
fn poll(&mut self, cx: &mut std::task::Context<'_>) -> Poll<Event> { | ||
// grab the waker if needed | ||
if let Some(waker) = &self.waker { | ||
if waker.will_wake(cx.waker()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what exactly does this check do?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
an optimization to prevent switching wakers when the task has not moved threads
Not sure what you mean, in your screenshot there is both the log and the error. Can you elaborate? |
@dignifiedquire ok I see. This is somewhat intentional and I see both approaches making sense. Right now I report whether there is an external address and if it changed on the watcher. In the doctor command, a failure would get a If you think it makes sense, I could change this option to a result and propagate it up. The only place where this would make a difference tho is in the doctor command |
I see, that makes sense. Given that we can get the errors via logs, I think we can leave it. |
This should be ready in any case, since I moved to using the same dep as #1157 for the local ip. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lets go :)
changes have been addressed and pr has been approved
* add igd * add log, use types for readability * request mapping * fix code placement + comments * filling in the gaps * some cleanup and refactor * debugging * debug cleanning * merge cleanup * easy doctor appointment * debug cleanning * use non zero to ensure port to map is positive * spelling * follow iroh code style * log when probe fails * update comment * more logs, use localhost * add portmap metrics to iroh-metrics * use portmap metrics * add client * wip: closing for the day * wip * more wip * connecting stuff * coding with the heart lol * fixes * customize timeout of portmapping doctor command * on_change for portmap * improve docs and logs * add mapping struct that handles maintenance * add waker * improve debug logs * connect with mapping thing * partially connect current mapping stream * simplify mapping handling and add a sanity test * remove hardcoded mapping half life * remove unused field * ensure external port is non zero * simplify test types, reduce test timeout * add external addr fn to mapping * rework getting a new upnp mapping to reuse a known gateway and or known external port * connect expiry and renew events * split client functions * update doctor command * add service channel capacity * remove unnecesary change * leverage derive_more and the utils mod * remove yet one more unnecesary clone * Revert "remove yet one more unnecesary clone" might be controversial since technically the probe starts before the report This reverts commit f558246. * misc spelling * misc docs * cleanup * more cleanup * simplify logic updating a probe * appease clippy * expand comment * expand metrics * self review * improve doctor docs * unflatten portmap probe * get interfaces * get interfaces using dep already here
This is the skateboard version of upnp mappings, which I think should cover a wide range of use cases to begin with.
Random notes on this (that depending on process will end up in one/several issues)
Tailscale differences (behaviour)
ssdp:all
request (simple service discovery) this seems unnecessary to me since the type of device we want is anigd
one. Anssdp:all
request will be answered from many different devices, let's say for example speakers connected to the local network. I don't see this as useful since afterwards, the responses are filtered to gather theigd
devices anyway. We don't do that, and instead send theigd
request only.igd
request, which is technically sent to a multicast address, ts sends also a unicast request to the likely router address. This is to deal with firewalls that reject the response to the multicast address since it's coming to the unicast address. Including this sounds something that we should do, but would mean to contribute or forkigd
or move the code to our codebase. Theigd
code is fairly simple so I don't think any of these options is out of scope.await
ing) instead of "spawning a task" (goroutine)on_change
when the mapping changes.Other notes
This so far follows the og template but I'd like us to consider a couple points:
on_change
callback. We probably can instead add atokio::sync::watch
to keep track of the last changed value.These are all changes that make sense to me, but it would be good to have the opinion of someone with better understanding of how port mapping fits within the code as a whole, in concept.
Further notes