Commit b63c15af authored by Juliusz Chroboczek's avatar Juliusz Chroboczek

Make the flooding protocol use TCP.

This simplifies the code a lot, since it gives us the notion of a session
for free.  And congestion control, of course.

This is not quite ready yet: we don't wait for the peer's handshake before
initiating flooding, and we don't perform duplicate suppression.  Doing that
will require a different data structure.
parent d818237e
This diff is collapsed.
...@@ -18,13 +18,11 @@ datum_val(const struct datum *datum) ...@@ -18,13 +18,11 @@ datum_val(const struct datum *datum)
return datum->datum + datum->keylen; return datum->datum + datum->keylen;
} }
extern int flood_port; extern int server_port;
extern int flood_socket; extern int server_socket;
extern struct datum **data; extern struct datum **data;
extern int numdata, maxdata; extern int numdata, maxdata;
extern struct timespec flood_time;
struct unacked { struct unacked {
int count; int count;
unsigned char *key; unsigned char *key;
...@@ -38,24 +36,23 @@ struct buffered { ...@@ -38,24 +36,23 @@ struct buffered {
int acked; int acked;
}; };
#define MAXBUFFERED 100 struct buffer {
unsigned char *buf;
int len, cap;
};
struct neighbour { struct neighbour {
struct sockaddr_in6 addr; int fd;
struct in6_pktinfo *pktinfo; int handshake_received;
int permanent; int dump_sent;
time_t time; struct sockaddr_in6 *sin6;
time_t send_time; struct buffer in, out;
struct unacked *unacked;
int numunacked, maxunacked;
struct buffered *buffered;
int numbuffered;
int dump_request_count;
int dump_done;
}; };
extern struct neighbour *neighbours; extern struct neighbour *neighs;
extern int numneighbours, maxneighbours; extern int numneighs, maxneighs;
extern struct timespec expire_neighs_time;
struct datum *find_datum(const unsigned char *key, int keylen); struct datum *find_datum(const unsigned char *key, int keylen);
struct datum *update_datum(const unsigned char *key, int keylen, struct datum *update_datum(const unsigned char *key, int keylen,
...@@ -67,9 +64,9 @@ time_t datum_remaining(const struct datum *datum); ...@@ -67,9 +64,9 @@ time_t datum_remaining(const struct datum *datum);
int extend_datum(struct datum *datum, time_t extend); int extend_datum(struct datum *datum, time_t extend);
int flood_setup(void (*callback)(struct datum *, int)); int flood_setup(void (*callback)(struct datum *, int));
void flood_cleanup(void); void flood_cleanup(void);
int flood_listen(void); int flood_accept(void);
struct neighbour * int flood_connect(const struct sockaddr_in6* sin6);
find_neighbour(struct sockaddr_in6 *sin6, int create, int update, int permanent); int flood_read(struct neighbour *neigh);
void flood(struct datum *datum, struct neighbour *neigh, int ack, int doit); int flood_write(struct neighbour *neigh);
void periodic_flood(void); void flood(struct datum *datum, struct neighbour *except);
int flush_updates(struct neighbour *neigh, int all); void expire_neighs(void);
...@@ -119,7 +119,7 @@ update_lease(const unsigned char *mac, int ipv6, ...@@ -119,7 +119,7 @@ update_lease(const unsigned char *mac, int ipv6,
doit = extend_datum(datum, time); doit = extend_datum(datum, time);
if(doit_return) if(doit_return)
*doit_return = doit; *doit_return = doit;
flood(datum, NULL, 0, 1); flood(datum, NULL);
return datum; return datum;
} }
...@@ -136,7 +136,7 @@ update_lease(const unsigned char *mac, int ipv6, ...@@ -136,7 +136,7 @@ update_lease(const unsigned char *mac, int ipv6,
if(doit_return) if(doit_return)
*doit_return = doit; *doit_return = doit;
update_client_routes(mac, lease_address(datum, ipv6), ipv6); update_client_routes(mac, lease_address(datum, ipv6), ipv6);
flood(datum, NULL, 0, 1); flood(datum, NULL);
return datum; return datum;
} }
...@@ -199,7 +199,7 @@ update_association(struct interface *interface, const unsigned char *mac, ...@@ -199,7 +199,7 @@ update_association(struct interface *interface, const unsigned char *mac,
if(datum->vallen == 8 && if(datum->vallen == 8 &&
memcmp(datum_val(datum), myid, 8) == 0) { memcmp(datum_val(datum), myid, 8) == 0) {
extend_datum(datum, time); extend_datum(datum, time);
flood(datum, NULL, 0, 1); flood(datum, NULL);
return client; return client;
} else { } else {
seqno = datum->seqno + 1; seqno = datum->seqno + 1;
...@@ -207,7 +207,7 @@ update_association(struct interface *interface, const unsigned char *mac, ...@@ -207,7 +207,7 @@ update_association(struct interface *interface, const unsigned char *mac,
} }
datum = update_datum(key, 7, seqno, myid, 8, time, NULL, NULL); datum = update_datum(key, 7, seqno, myid, 8, time, NULL, NULL);
flood(datum, NULL, 0, 1); flood(datum, NULL);
return client; return client;
} }
...@@ -230,5 +230,5 @@ flush_association(const unsigned char *mac, int time) ...@@ -230,5 +230,5 @@ flush_association(const unsigned char *mac, int time)
seqno = datum->seqno + 1; seqno = datum->seqno + 1;
datum = update_datum(key, 7, seqno, NULL, 0, time, NULL, NULL); datum = update_datum(key, 7, seqno, NULL, 0, time, NULL, NULL);
flood(datum, NULL, 0, 1); flood(datum, NULL);
} }
...@@ -211,7 +211,7 @@ main(int argc, char **argv) ...@@ -211,7 +211,7 @@ main(int argc, char **argv)
p = strtol(optarg, &end, 0); p = strtol(optarg, &end, 0);
if(*end != '\0' || p <= 0 || p > 0xFFFF) if(*end != '\0' || p <= 0 || p > 0xFFFF)
goto usage; goto usage;
flood_port = p; server_port = p;
} }
break; break;
case 'P': { case 'P': {
...@@ -270,7 +270,7 @@ main(int argc, char **argv) ...@@ -270,7 +270,7 @@ main(int argc, char **argv)
} else } else
goto usage; goto usage;
sin6.sin6_port = htons(port); sin6.sin6_port = htons(port);
find_neighbour(&sin6, 1, 0, 1); flood_connect(&sin6);
} else { } else {
goto usage; goto usage;
} }
...@@ -339,47 +339,50 @@ main(int argc, char **argv) ...@@ -339,47 +339,50 @@ main(int argc, char **argv)
} }
while(1) { while(1) {
fd_set readfds; fd_set readfds, writefds;
int nls = netlink_socket(); int nls = netlink_socket();
int maxfd; int maxfd;
struct timespec deadline; struct timespec now, deadline;
FD_ZERO(&readfds); FD_ZERO(&readfds);
FD_ZERO(&writefds);
FD_SET(nls, &readfds); FD_SET(nls, &readfds);
maxfd = nls;
if(numinterfaces > 0) { if(numinterfaces > 0) {
FD_SET(ra_socket, &readfds); FD_SET(ra_socket, &readfds);
maxfd = max(maxfd, ra_socket);
FD_SET(dhcpv4_socket, &readfds); FD_SET(dhcpv4_socket, &readfds);
maxfd = max(maxfd, dhcpv4_socket);
} }
FD_SET(flood_socket, &readfds);
FD_SET(server_socket, &readfds);
maxfd = max(nls, flood_socket); maxfd = max(maxfd, server_socket);
if(numinterfaces > 0)
maxfd = max(maxfd, max(ra_socket, dhcpv4_socket)); for(int i = 0; i < numneighs; i++) {
if(neighs[i].fd >= 0) {
if(flood_time.tv_sec > 0) { if(neighs[i].out.len > 0)
struct timespec now; FD_SET(neighs[i].fd, &writefds);
clock_gettime(CLOCK_MONOTONIC, &now); FD_SET(neighs[i].fd, &readfds);
ts_minus(&deadline, &flood_time, &now); maxfd = max(maxfd, neighs[i].fd);
if(deadline.tv_sec < 0) {
deadline.tv_sec = 0;
deadline.tv_nsec = 0;
} }
} }
rc = pselect(maxfd + 1, &readfds, NULL, NULL, clock_gettime(CLOCK_MONOTONIC, &now);
flood_time.tv_sec > 0 ? &deadline : NULL, NULL); ts_minus(&deadline, &expire_neighs_time, &now);
rc = pselect(maxfd + 1, &readfds, &writefds, NULL, &deadline, NULL);
if(rc < 0 && errno != EINTR) { if(rc < 0 && errno != EINTR) {
perror("pselect"); perror("pselect");
sleep(1); sleep(1);
} }
clock_gettime(CLOCK_MONOTONIC, &now);
if(exiting) if(exiting)
break; break;
if(dumping) { if(dumping) {
static const char zeroes[8] = {0}; static const char zeroes[8] = {0};
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
printf("Interfaces"); printf("Interfaces");
for(int i = 0; i < numinterfaces; i++) for(int i = 0; i < numinterfaces; i++)
printf(" %s", interfaces[i].ifname); printf(" %s", interfaces[i].ifname);
...@@ -462,15 +465,8 @@ main(int argc, char **argv) ...@@ -462,15 +465,8 @@ main(int argc, char **argv)
printf(".\n"); printf(".\n");
} }
printf("\n"); printf("\n");
for(int i = 0; i < numneighbours; i++) { for(int i = 0; i < numneighs; i++) {
char buf[INET6_ADDRSTRLEN]; printf("Neighbour %d.\n", neighs[i].fd);
inet_ntop(AF_INET6, &neighbours[i].addr.sin6_addr,
buf, sizeof(buf));
printf("Neighbour %s:%d %ds %ds%s.\n",
buf, ntohs(neighbours[i].addr.sin6_port),
(int)(now.tv_sec - neighbours[i].time),
(int)(now.tv_sec - neighbours[i].send_time),
neighbours[i].permanent ? " (permanent)" : "");
} }
fflush(stdout); fflush(stdout);
...@@ -478,33 +474,35 @@ main(int argc, char **argv) ...@@ -478,33 +474,35 @@ main(int argc, char **argv)
dumping = 0; dumping = 0;
} }
if(flood_time.tv_sec > 0) { if(rc >= 0) {
struct timespec now; if(FD_ISSET(nls, &readfds)) {
clock_gettime(CLOCK_MONOTONIC, &now); rc = netlink_listen();
if(ts_compare(&flood_time, &now) <= 0) { if(rc < 0)
periodic_flood(); nl_perror(rc, "netlink_listen");
} }
}
if(rc <= 0)
continue;
if(FD_ISSET(nls, &readfds)) { if(FD_ISSET(server_socket, &readfds))
rc = netlink_listen(); flood_accept();
if(rc < 0)
nl_perror(rc, "netlink_listen");
}
if(FD_ISSET(flood_socket, &readfds)) for(int i = 0; i < numneighs; i++) {
flood_listen(); if(neighs[i].fd >= 0) {
if(FD_ISSET(neighs[i].fd, &readfds))
if(numinterfaces > 0) { flood_read(&neighs[i]);
if(FD_ISSET(ra_socket, &readfds)) if(FD_ISSET(neighs[i].fd, &writefds))
receive_rs(); flood_write(&neighs[i]);
}
}
if(numinterfaces > 0) {
if(FD_ISSET(ra_socket, &readfds))
receive_rs();
if(FD_ISSET(dhcpv4_socket, &readfds)) if(FD_ISSET(dhcpv4_socket, &readfds))
dhcpv4_receive(); dhcpv4_receive();
}
} }
if(ts_compare(&now, &expire_neighs_time) >= 0)
expire_neighs();
} }
client_cleanup(); client_cleanup();
......
...@@ -38,8 +38,8 @@ DHCPv4 or IPv6 RA. This option may be specified multiple times, in which ...@@ -38,8 +38,8 @@ DHCPv4 or IPv6 RA. This option may be specified multiple times, in which
case all prefixes will be announced to clients. case all prefixes will be announced to clients.
.TP .TP
.BI \-f " port" .BI \-f " port"
Set the local UDP port used by the flooding protocol. If this is not set, Set the server TCP port used by the flooding protocol. If this is not
flooding is disabled. set, we don't act as a server.
.TP .TP
.BI \-F " address:port" .BI \-F " address:port"
Specify the address of a remote peer for the flooding protocol. There is Specify the address of a remote peer for the flooding protocol. There is
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment