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

Circuit Relay integration #4091

Merged
merged 16 commits into from
Aug 16, 2017
Merged

Circuit Relay integration #4091

merged 16 commits into from
Aug 16, 2017

Conversation

vyzo
Copy link
Contributor

@vyzo vyzo commented Jul 26, 2017

#4090 Integrates circuit relay as a transport, enabled by default.

Notes:

Adds the following options to swarm configuration options:

  • DisableRelay (default: false) -- set to disable circuit relay transport
  • EnableRelayHop (default: false) -- set to enable the node to act as a Hop relay.

@daviddias daviddias added the status/in-progress In progress label Jul 26, 2017
@vyzo
Copy link
Contributor Author

vyzo commented Jul 26, 2017

summning @whyrusleeping @Stebalien

@vyzo vyzo changed the title Circuit Relay integration [WIP] Circuit Relay integration Jul 26, 2017
@vyzo
Copy link
Contributor Author

vyzo commented Jul 26, 2017

iptb testing scenario:

$ iptb start --args --routing=none
Started daemon ..., pid = 21741
Started daemon ..., pid = 21755
Started daemon ..., pid = 21768

$ iptb shell 1
$ ipfs config Swarm.EnableRelayHop
true

$ iptb shell 2
$ ipfs id
{
	"ID": "QmbCdQcF3f2oPGE2Ch7wdmjfGjD227TBWCZNUMxjXqTZJ7",
	"PublicKey": "CAASogEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMs+WIfPPtXG66PPIasxnzNtas9yz3Eo4ahMB9lvOJv9QR197z68RnM4aNRQsiLv0NufxNVdkJi+7dD8Kj2HrX8hklZgrnAQISmHD/nNhamUyYRR+qYFG5nZgshV0yOMreFL9WwQgVau2W0KO/80PmOVe7evsbx/wy4A9XzPUDnVAgMBAAE=",
	"Addresses": [
		"/ip4/127.0.0.1/tcp/50527/ipfs/QmbCdQcF3f2oPGE2Ch7wdmjfGjD227TBWCZNUMxjXqTZJ7",
		"/ip4/10.0.1.30/tcp/50527/ipfs/QmbCdQcF3f2oPGE2Ch7wdmjfGjD227TBWCZNUMxjXqTZJ7"
	],
	"AgentVersion": "go-ipfs/0.4.11-dev/159fa52c",
	"ProtocolVersion": "ipfs/0.1.0"
}

$ iptb connect 0 1
connecting QmcsnBupwKXW8XsTxLMtvgKUVsocyunv6FydY2GJNsg5Qo -> QmUzUq7Bf6vBkSdvatRAokZLjPh1kjNNpQLiYZmduXpxSi
Addresses:  [/ip4/127.0.0.1/tcp/38266/ipfs/QmUzUq7Bf6vBkSdvatRAokZLjPh1kjNNpQLiYZmduXpxSi /ip4/10.0.1.30/tcp/38266/ipfs/QmUzUq7Bf6vBkSdvatRAokZLjPh1kjNNpQLiYZmduXpxSi]
trying ipfs swarm connect /ip4/127.0.0.1/tcp/38266/ipfs/QmUzUq7Bf6vBkSdvatRAokZLjPh1kjNNpQLiYZmduXpxSi
$ iptb connect 1 2
connecting QmUzUq7Bf6vBkSdvatRAokZLjPh1kjNNpQLiYZmduXpxSi -> QmbCdQcF3f2oPGE2Ch7wdmjfGjD227TBWCZNUMxjXqTZJ7
Addresses:  [/ip4/127.0.0.1/tcp/50527/ipfs/QmbCdQcF3f2oPGE2Ch7wdmjfGjD227TBWCZNUMxjXqTZJ7 /ip4/10.0.1.30/tcp/50527/ipfs/QmbCdQcF3f2oPGE2Ch7wdmjfGjD227TBWCZNUMxjXqTZJ7]
trying ipfs swarm connect /ip4/127.0.0.1/tcp/50527/ipfs/QmbCdQcF3f2oPGE2Ch7wdmjfGjD227TBWCZNUMxjXqTZJ7
connection success!

$ iptb shell 0
$ ipfs swarm peers
/ip4/127.0.0.1/tcp/38266/ipfs/QmUzUq7Bf6vBkSdvatRAokZLjPh1kjNNpQLiYZmduXpxSi
$ ipfs swarm connect /p2p-circuit/ipfs/QmbCdQcF3f2oPGE2Ch7wdmjfGjD227TBWCZNUMxjXqTZJ7
connect QmbCdQcF3f2oPGE2Ch7wdmjfGjD227TBWCZNUMxjXqTZJ7 success
$ ipfs swarm peers
/ip4/127.0.0.1/tcp/38266/ipfs/QmUzUq7Bf6vBkSdvatRAokZLjPh1kjNNpQLiYZmduXpxSi
/ipfs/QmUzUq7Bf6vBkSdvatRAokZLjPh1kjNNpQLiYZmduXpxSi/p2p-circuit/ipfs/QmbCdQcF3f2oPGE2Ch7wdmjfGjD227TBWCZNUMxjXqTZJ7

$ iptb shell 1
$ ipfs swarm peers
/ip4/127.0.0.1/tcp/44524/ipfs/QmcsnBupwKXW8XsTxLMtvgKUVsocyunv6FydY2GJNsg5Qo
/ip4/127.0.0.1/tcp/50527/ipfs/QmbCdQcF3f2oPGE2Ch7wdmjfGjD227TBWCZNUMxjXqTZJ7

$ iptb shell 2
$ ipfs swarm peers
/ip4/127.0.0.1/tcp/40106/ipfs/QmUzUq7Bf6vBkSdvatRAokZLjPh1kjNNpQLiYZmduXpxSi
/ipfs/QmUzUq7Bf6vBkSdvatRAokZLjPh1kjNNpQLiYZmduXpxSi/p2p-circuit/ipfs/QmcsnBupwKXW8XsTxLMtvgKUVsocyunv6FydY2GJNsg5Qo

@vyzo vyzo mentioned this pull request Jul 27, 2017
@vyzo vyzo added the status/blocked Unable to be worked further until needs are met label Jul 27, 2017
@vyzo
Copy link
Contributor Author

vyzo commented Jul 27, 2017

Rebased on #4094.

@vyzo
Copy link
Contributor Author

vyzo commented Jul 28, 2017

Added a test/sharness script that implements the iptb scenario described above.

@vyzo
Copy link
Contributor Author

vyzo commented Jul 28, 2017

More iptb interaction: verify the connection works:

$ iptb shell 0
$ echo "hello world" | ipfs add
added QmT78zSuBmuS4z925WZfrqQ1qHaJ56DQaTfyMUF7F8ff5o QmT78zSuBmuS4z925WZfrqQ1qHaJ56DQaTfyMUF7F8ff5o

$ iptb shell 2
$ ipfs cat QmT78zSuBmuS4z925WZfrqQ1qHaJ56DQaTfyMUF7F8ff5o
hello world

I will extend the sharness test to verify the connection.

@vyzo vyzo changed the title [WIP] Circuit Relay integration Circuit Relay integration Jul 28, 2017
@vyzo
Copy link
Contributor Author

vyzo commented Jul 28, 2017

I think it's ready for review.
pinging @Stebalien @whyrusleeping @lgierth

if strings.Contains(info.Addr, "/p2p-circuit/") {
fmt.Fprintf(buf, "%s", info.Addr)
} else {
fmt.Fprintf(buf, "%s/ipfs/%s", info.Addr, info.Peer)
Copy link
Member

Choose a reason for hiding this comment

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

Whats the purpose of this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The address already contains the peer id in this case.
It's of the form .../p2p-circuit/ipfs/QmId, so pasting the peer id again would result in the address formatted as .../p2p-circuit/ipfs/QmId/ipfs/QmId

Copy link
Contributor Author

Choose a reason for hiding this comment

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

do you want me to add a comment to that extent?

Copy link
Member

Choose a reason for hiding this comment

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

Hrm... that feels a bit weird. @Kubuxu @lgierth @Stebalien thoughts?

Copy link
Member

Choose a reason for hiding this comment

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

I'd expect RemoteMultiaddr to return just the /ipfs/QmProxy/p2p-circuit part, not the final /ipfs/QmId. As-is, this is inconsistent with TCP/IP addresses. Is there a technical reason not to do it this way?

Copy link
Contributor Author

@vyzo vyzo Jul 29, 2017

Choose a reason for hiding this comment

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

So we actually need it: the address reported by Conn.RemoteMultiaddr should be dialable, and the partial address won't be.

I will add a comment here explaining why we need this.

Copy link
Member

@Stebalien Stebalien Jul 29, 2017

Choose a reason for hiding this comment

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

Basically /ipfs/QmId serves two purposes:

  1. Routing information: An alias for an internet address (stored in the DHT): /ip4/xxx.xxx.xxx.xxx/tcp/1234
  2. Identity information: The key of the target machine.

In the RemoteMultiaddr case, the second ipfs address is routing information.

We'd actually run into the same problem something returned /ipfs/QmId as the entire RemoteMultiaddr (which would actually make sense if you had a lower-level VPN that understood IPFS addresses).


Actually, that brings up a good point. Maybe we should just be checking to see if the last address is an /ipfs/ address (i.e., the multiaddr ends in /ipfs/QmId) and, if it is, assert that the QmIds match instead of appending something. Thoughts @vyzo?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Maybe we should just be checking to see if the last address is an /ipfs/ address (i.e., the multiaddr ends in /ipfs/QmId) and, if it is, assert that the QmIds match instead of appending something.

That's perhaps the generic case to handle routing addresses similar to how circuit reports address.
So instead of checking if it is a p2p-circuit address, check if it ends with the /ipfs/peerId and if so only append if it doesn't match.

Sure, we can do 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 have changed the check to look for the /ipfs/QmPeer suffix in the remote multiaddr.
If the suffix is present, then it doesn't duplicate it, otherwise it appends /ipfs/QmPeer.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not sure we need a comment any more, it's not p2p-circuit specific and the code is self-explaining.

@vyzo
Copy link
Contributor Author

vyzo commented Jul 29, 2017

Rebased on master.

@vyzo vyzo removed the status/blocked Unable to be worked further until needs are met label Jul 29, 2017
@vyzo vyzo force-pushed the feat/circuit-relay branch 2 times, most recently from 1d60f08 to e9fa416 Compare July 29, 2017 07:37
@vyzo
Copy link
Contributor Author

vyzo commented Jul 29, 2017

Blocked on libp2p/go-libp2p-circuit#6

Reverted: libp2p/go-libp2p-circuit#7

@vyzo vyzo added status/blocked Unable to be worked further until needs are met and removed status/blocked Unable to be worked further until needs are met labels Jul 29, 2017
@vyzo
Copy link
Contributor Author

vyzo commented Jul 29, 2017

Upon discussion with @Stebalien on irc we concluded that it is important to keep the invariant that multiaddrs returned by Conn.RemoteMultiaddr are dialiable.
A partial p2p-circuit address will not be, so we need to keep the ipfs part in the address as was the original design.
I have reverted and will add a comment to the code to explain why we need to filter.

core/core.go Outdated
}
return raddrs
}
hostOpts = append(hostOpts, p2pbhost.AddrsFactory(filterRelayAddr))
Copy link
Member

Choose a reason for hiding this comment

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

What happens if we have multiple address factories in the hostOpts?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We would need to compose them.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do you want me to add scaffolding for the composition?

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, Since we're going to be using the address factory pretty soon anyways for limiting which addresses we announce: #3948

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 will need to add the AddrsFactory option to ConstructPeerHostOpts in order to scaffold the composition properly.

Then we have two options for the composition: filter first or announce factory first. It makes some sense to use the filter first, the announce factory might actually want to announce some relay addresses in the future. On the other hand it also makes sense for the announce factory to see the p2p-circuit relay address, so that it knows that relay is activated.

Copy link
Contributor Author

@vyzo vyzo Jul 30, 2017

Choose a reason for hiding this comment

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

Nonetheless, the announce factory can also tell whether relay is in use from the swarm options already, so the latter argument is not all that compelling.

So the filter should be applied before the announce address factory.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added the scaffolding for address factory composition in 231f8e4:

  • added an AddrsFactory option to ConstructPeerHostOpts
  • composed the specified address factory with the relay filter when present

@@ -106,6 +107,13 @@ func ParseMultiaddr(m ma.Multiaddr) (a IPFSAddr, err error) {

func Transport(iaddr IPFSAddr) (maddr ma.Multiaddr) {
maddr = iaddr.Multiaddr()

// /ipfs/QmId is part of the transport address for p2p-circuit
_, err := maddr.ValueForProtocol(circuit.P_CIRCUIT)
Copy link
Member

Choose a reason for hiding this comment

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

Would prefer if we at least put a TODO here to clean this up. We need to rethink (later, not now) how addresses get composed and consumed so that we don't have to have this special case here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure, will add a TODO.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added TODO comment in a11f632

Copy link
Member

Choose a reason for hiding this comment

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

I wonder if we could just stop distinguishing between the transport part and the application part. Multiaddrs don't really have a clear transport/application layer separation (they can have transport -> application -> transport -> transport -> application, etc...).

Instead, we could either:

a. Have dialers recursively dial (dial the parts they understand and then recursively call the "main" dialer to dial the rest).
b. Dial like we resolve through IPLD objects and return an intermediate transport + the rest of the undialed path.

Copy link
Member

@whyrusleeping whyrusleeping left a comment

Choose a reason for hiding this comment

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

This LGTM for the most part, some questions around host construction, and the special casing of relay multiaddrs still weirds me out. But thats probably okay to figure out later.

@whyrusleeping whyrusleeping requested review from a user and Kubuxu July 29, 2017 20:27
Copy link
Member

@Stebalien Stebalien left a comment

Choose a reason for hiding this comment

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

The code looks good to me. Just a question on configuration/documentation.

@@ -221,5 +221,12 @@ improvement, as well as a reduction in memory usage.
- `DisableNatPortMap`
Disable NAT discovery.

- `DisableRelay`
Disables the p2p-circuit relay transport.
Copy link
Member

Choose a reason for hiding this comment

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

Will this disable relays entirely or just disable listening on relayed addresses? There are three cases:

  1. Listen using relays.
  2. Act as a relay.
  3. Connect to nodes through relays.

It would be nice to be able to enable/disable these independently. Can we currently do that?

Copy link
Contributor Author

@vyzo vyzo Aug 16, 2017

Choose a reason for hiding this comment

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

Setting to true will disable the relay transport entirely.

The DislableRelay controls option 1 and 3, so by default we listen for relay connections and we can connect to peers through relay.
In order to act as a hop relay (2), you need to EnableRelayHop, in addition to having the relay transport enabled.

I don't think it makes sense to have more fine-grained independent configuration, as we can't really separate listening from dial (and do we really want to do that?) and we already have an option to control hop relaying.

Copy link
Member

Choose a reason for hiding this comment

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

As discussed on IRC, I misunderstood what these toggles did. DisableRelay disables relaying entirely and we don't yet support advertising relayed addresses; when implemented, that will probably have an additional toggle.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, that's the plan.

vyzo added 15 commits August 16, 2017 09:26
- enabled by default, so that we can dial/receive dials
- /p2p-circuit/QmId address is not announced; filtered at host with AddrsFactory
- use case is manual swarm connect with relay address

License: MIT
Signed-off-by: vyzo <[email protected]>
License: MIT
Signed-off-by: vyzo <[email protected]>
Handles p2p-circuit addresses and any other address that uses a similar
routing scheme.

License: MIT
Signed-off-by: vyzo <[email protected]>
- Adds AddrsFactory to ConstructPeerHostOpts
- Composes the AddrsFactory option with the relay filter

License: MIT
Signed-off-by: vyzo <[email protected]>
License: MIT
Signed-off-by: vyzo <[email protected]>
integrate #3948

License: MIT
Signed-off-by: vyzo <[email protected]>
Necessary for meaningful semantics in the presence of address filtering.

License: MIT
Signed-off-by: vyzo <[email protected]>
License: MIT
Signed-off-by: vyzo <[email protected]>
@vyzo
Copy link
Contributor Author

vyzo commented Aug 16, 2017

Rebased on master and fixed the conflict.

@vyzo
Copy link
Contributor Author

vyzo commented Aug 16, 2017

@whyrusleeping this is ready to merge.

@whyrusleeping whyrusleeping merged commit 22ee73d into master Aug 16, 2017
@whyrusleeping whyrusleeping deleted the feat/circuit-relay branch August 16, 2017 19:46
@whyrusleeping
Copy link
Member

Merged! ipfs has relay support!! Thank you @vyzo!

@whyrusleeping
Copy link
Member

@vyzo do you think you could write up a small doc on how to use the relay feature? That would be immensely helpful to have

@vyzo
Copy link
Contributor Author

vyzo commented Aug 17, 2017

Sure! Where should it live though?

@Kubuxu
Copy link
Member

Kubuxu commented Aug 17, 2017

docs/experimental-features.md

@vyzo
Copy link
Contributor Author

vyzo commented Aug 17, 2017

#4148 adds documentation in docs/experimental-features.md

@magik6k magik6k added this to the Ipfs 0.4.11 milestone Aug 17, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants