Brian, I think that I am making a mistake in how I am binding my IPv6 multicast sockets on which I expect to hear GRASP DULL messages.
1) I create a socket with an unspecified address, and the GRASP_PORT (7017):
let rsin6 = SocketAddrV6::new(Ipv6Addr::UNSPECIFIED,
grasp::GRASP_PORT as u16, 0, ifindex);
let recv_try = UdpSocket::bind(rsin6).await;
Note that I had originally expected that I should bind it to the IPv6-LL of
the interface, but that meant that the socket does not match the
multicast destinations.
I mark SO_REUSEPORT, and SO_REUSEADDR on this socket.
2) I join the multicast address for that socket:
let grasp_mcast =
"FF02:0:0:0:0:0:0:13".parse::<Ipv6Addr>().unwrap();
recv.join_multicast_v6(&grasp_mcast, ifindex).unwrap();
Note that "ifindex" is the scope of the interface that I want to bind.
3) If that works, then, in order to send, I create a new socket, which I do
not bind to multicast, but I do bind it to the interface:
let ssin6 = SocketAddrV6::new(Ipv6Addr::UNSPECIFIED,
0 as u16, 0, ifindex);
let send = UdpSocket::bind(ssin6).await.unwrap();
maybe I could use the above socket, but I think it is easier to have two
sockets as it simplies threads.
I have been binding a multicast listening socket for each "physical" interface.
In testing with more than one interface I realized two things:
a) I hear myself on the same interface. That is, M_FLOODs about address
fe80::1234, are heard on the multicast socket bound to fe80::1234.
Okay, I think, just filter those out since they come from "me"
b) Oops, I hear myself on the other interfaces.
So, M_FLOODs about fe80::1234 on ifindex 2 are heard on ifindex 3,
(call it "fe80::abcd"). They aren't "me", so I actually have to talk my
list of interfaces and filter out all the "me".
I realized that the originating sockaddr provided in recvfrom() also
has an sin6_scope which is filled in, so the multicasts which loop back
internally can be filtered out by listening on for things which
are on the ifindex I wanted to listen to.
But, I still have to filter for the list of "me", because it could be
that fe80::1234 and fe80::abcd are actually two ports in the same L2 domain.
I actually ran into the last bit when looking at the IPsec policies that were
being created. My IKEv2 daemon gets cross when you ask it to initiate to
a peer which it is convinced it also self.
I may have made some mistakes setting the IP TTL of my packets.
I think they are set to 1.
(The GRASP TTL was incorrectly set to that as well, which I fixed already.)
I have been creating a GraspDaemon thread per interface.
Since this is really just a Rust Async co-routine (a "green thread"), and not
an actual system thread, I feel that the simplicity of just having the
simplest of loops running outweighs the potential scaling issue of having
hundreds of these running. The co-routine mechanism means that this all just
leads down to an event loop and a call to select(2)/poll(2)/epoll(2),
etc. all handled by tokio and the compiler and not me.
But now, I'm thinking that I should have just done a single Grasp(DULL)
daemon receive thread, listening on all interfaces. I can't really remember
why I didn't do that. Maybe because I thought I would need a multicast
socket per physical interface.
On the transmit side, I have multiple loops sending, but that is easily
merged into a single loop, and it would have the advantage that I could more
easily stagger DULL announcements across different interfaces.
I'm not actually sure how often M_FLOODs are supposed to be sent.
I scanned through ACP (section 6.4) and through GRASP-15, and I didn't see
anything.
That is:
loop {
sleep(60s +- rand(10));
send-M_FLOOD-on-next-interface;
}
rather than:
loop {
sleep(60s);
for if in interfaces {
send-M_FLOOD-on(if)
}
}
--
Michael Richardson <[email protected]> . o O ( IPv6 IøT consulting )
Sandelman Software Works Inc, Ottawa and Worldwide
signature.asc
Description: PGP signature
_______________________________________________ Anima mailing list [email protected] https://www.ietf.org/mailman/listinfo/anima
