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)
return datum->datum + datum->keylen;
}
extern int flood_port;
extern int flood_socket;
extern int server_port;
extern int server_socket;
extern struct datum **data;
extern int numdata, maxdata;
extern struct timespec flood_time;
struct unacked {
int count;
unsigned char *key;
......@@ -38,24 +36,23 @@ struct buffered {
int acked;
};
#define MAXBUFFERED 100
struct buffer {
unsigned char *buf;
int len, cap;
};
struct neighbour {
struct sockaddr_in6 addr;
struct in6_pktinfo *pktinfo;
int permanent;
time_t time;
time_t send_time;
struct unacked *unacked;
int numunacked, maxunacked;
struct buffered *buffered;
int numbuffered;
int dump_request_count;
int dump_done;
int fd;
int handshake_received;
int dump_sent;
struct sockaddr_in6 *sin6;
struct buffer in, out;
};
extern struct neighbour *neighbours;
extern int numneighbours, maxneighbours;
extern struct neighbour *neighs;
extern int numneighs, maxneighs;
extern struct timespec expire_neighs_time;
struct datum *find_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);
int extend_datum(struct datum *datum, time_t extend);
int flood_setup(void (*callback)(struct datum *, int));
void flood_cleanup(void);
int flood_listen(void);
struct neighbour *
find_neighbour(struct sockaddr_in6 *sin6, int create, int update, int permanent);
void flood(struct datum *datum, struct neighbour *neigh, int ack, int doit);
void periodic_flood(void);
int flush_updates(struct neighbour *neigh, int all);
int flood_accept(void);
int flood_connect(const struct sockaddr_in6* sin6);
int flood_read(struct neighbour *neigh);
int flood_write(struct neighbour *neigh);
void flood(struct datum *datum, struct neighbour *except);
void expire_neighs(void);
......@@ -119,7 +119,7 @@ update_lease(const unsigned char *mac, int ipv6,
doit = extend_datum(datum, time);
if(doit_return)
*doit_return = doit;
flood(datum, NULL, 0, 1);
flood(datum, NULL);
return datum;
}
......@@ -136,7 +136,7 @@ update_lease(const unsigned char *mac, int ipv6,
if(doit_return)
*doit_return = doit;
update_client_routes(mac, lease_address(datum, ipv6), ipv6);
flood(datum, NULL, 0, 1);
flood(datum, NULL);
return datum;
}
......@@ -199,7 +199,7 @@ update_association(struct interface *interface, const unsigned char *mac,
if(datum->vallen == 8 &&
memcmp(datum_val(datum), myid, 8) == 0) {
extend_datum(datum, time);
flood(datum, NULL, 0, 1);
flood(datum, NULL);
return client;
} else {
seqno = datum->seqno + 1;
......@@ -207,7 +207,7 @@ update_association(struct interface *interface, const unsigned char *mac,
}
datum = update_datum(key, 7, seqno, myid, 8, time, NULL, NULL);
flood(datum, NULL, 0, 1);
flood(datum, NULL);
return client;
}
......@@ -230,5 +230,5 @@ flush_association(const unsigned char *mac, int time)
seqno = datum->seqno + 1;
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)
p = strtol(optarg, &end, 0);
if(*end != '\0' || p <= 0 || p > 0xFFFF)
goto usage;
flood_port = p;
server_port = p;
}
break;
case 'P': {
......@@ -270,7 +270,7 @@ main(int argc, char **argv)
} else
goto usage;
sin6.sin6_port = htons(port);
find_neighbour(&sin6, 1, 0, 1);
flood_connect(&sin6);
} else {
goto usage;
}
......@@ -339,47 +339,50 @@ main(int argc, char **argv)
}
while(1) {
fd_set readfds;
fd_set readfds, writefds;
int nls = netlink_socket();
int maxfd;
struct timespec deadline;
struct timespec now, deadline;
FD_ZERO(&readfds);
FD_ZERO(&writefds);
FD_SET(nls, &readfds);
maxfd = nls;
if(numinterfaces > 0) {
FD_SET(ra_socket, &readfds);
maxfd = max(maxfd, ra_socket);
FD_SET(dhcpv4_socket, &readfds);
maxfd = max(maxfd, dhcpv4_socket);
}
FD_SET(flood_socket, &readfds);
maxfd = max(nls, flood_socket);
if(numinterfaces > 0)
maxfd = max(maxfd, max(ra_socket, dhcpv4_socket));
if(flood_time.tv_sec > 0) {
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
ts_minus(&deadline, &flood_time, &now);
if(deadline.tv_sec < 0) {
deadline.tv_sec = 0;
deadline.tv_nsec = 0;
FD_SET(server_socket, &readfds);
maxfd = max(maxfd, server_socket);
for(int i = 0; i < numneighs; i++) {
if(neighs[i].fd >= 0) {
if(neighs[i].out.len > 0)
FD_SET(neighs[i].fd, &writefds);
FD_SET(neighs[i].fd, &readfds);
maxfd = max(maxfd, neighs[i].fd);
}
}
rc = pselect(maxfd + 1, &readfds, NULL, NULL,
flood_time.tv_sec > 0 ? &deadline : NULL, NULL);
clock_gettime(CLOCK_MONOTONIC, &now);
ts_minus(&deadline, &expire_neighs_time, &now);
rc = pselect(maxfd + 1, &readfds, &writefds, NULL, &deadline, NULL);
if(rc < 0 && errno != EINTR) {
perror("pselect");
sleep(1);
}
clock_gettime(CLOCK_MONOTONIC, &now);
if(exiting)
break;
if(dumping) {
static const char zeroes[8] = {0};
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
printf("Interfaces");
for(int i = 0; i < numinterfaces; i++)
printf(" %s", interfaces[i].ifname);
......@@ -462,15 +465,8 @@ main(int argc, char **argv)
printf(".\n");
}
printf("\n");
for(int i = 0; i < numneighbours; i++) {
char buf[INET6_ADDRSTRLEN];
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)" : "");
for(int i = 0; i < numneighs; i++) {
printf("Neighbour %d.\n", neighs[i].fd);
}
fflush(stdout);
......@@ -478,33 +474,35 @@ main(int argc, char **argv)
dumping = 0;
}
if(flood_time.tv_sec > 0) {
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
if(ts_compare(&flood_time, &now) <= 0) {
periodic_flood();
if(rc >= 0) {
if(FD_ISSET(nls, &readfds)) {
rc = netlink_listen();
if(rc < 0)
nl_perror(rc, "netlink_listen");
}
}
if(rc <= 0)
continue;
if(FD_ISSET(nls, &readfds)) {
rc = netlink_listen();
if(rc < 0)
nl_perror(rc, "netlink_listen");
}
if(FD_ISSET(server_socket, &readfds))
flood_accept();
if(FD_ISSET(flood_socket, &readfds))
flood_listen();
if(numinterfaces > 0) {
if(FD_ISSET(ra_socket, &readfds))
receive_rs();
for(int i = 0; i < numneighs; i++) {
if(neighs[i].fd >= 0) {
if(FD_ISSET(neighs[i].fd, &readfds))
flood_read(&neighs[i]);
if(FD_ISSET(neighs[i].fd, &writefds))
flood_write(&neighs[i]);
}
}
if(numinterfaces > 0) {
if(FD_ISSET(ra_socket, &readfds))
receive_rs();
if(FD_ISSET(dhcpv4_socket, &readfds))
dhcpv4_receive();
if(FD_ISSET(dhcpv4_socket, &readfds))
dhcpv4_receive();
}
}
if(ts_compare(&now, &expire_neighs_time) >= 0)
expire_neighs();
}
client_cleanup();
......
......@@ -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.
.TP
.BI \-f " port"
Set the local UDP port used by the flooding protocol. If this is not set,
flooding is disabled.
Set the server TCP port used by the flooding protocol. If this is not
set, we don't act as a server.
.TP
.BI \-F " address:port"
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