+static int netlink_compare_route_specificity(const void *ap, const void *bp)
+{
+ const struct netlink_route *a=ap;
+ const struct netlink_route *b=bp;
+
+ if (a->net.len==b->net.len) return 0;
+ if (a->net.len<b->net.len) return 1;
+ return -1;
+}
+
+static void netlink_phase_hook(void *sst, uint32_t new_phase)
+{
+ struct netlink *st=sst;
+ struct netlink_client *c;
+ uint32_t i,j;
+
+ /* All the networks serviced by the various tunnels should now
+ * have been registered. We build a routing table by sorting the
+ * routes into most-specific-first order. */
+ st->routes=safe_malloc(st->n_routes*sizeof(*st->routes),
+ "netlink_phase_hook");
+ /* Fill the table */
+ i=0;
+ for (c=st->clients; c; c=c->next) {
+ for (j=0; j<c->networks->entries; j++) {
+ st->routes[i].net=c->networks->list[j];
+ st->routes[i].c=c;
+ i++;
+ }
+ }
+ /* ASSERT i==st->n_routes */
+ if (i!=st->n_routes) {
+ fatal("netlink: route count error: expected %d got %d\n",
+ st->n_routes,i);
+ }
+ /* Sort the table in descending order of specificity */
+ qsort(st->routes,st->n_routes,sizeof(*st->routes),
+ netlink_compare_route_specificity);
+ Message(M_INFO,"%s: routing table:\n",st->name);
+ for (i=0; i<st->n_routes; i++) {
+ string_t net;
+ net=subnet_to_string(&st->routes[i].net);
+ Message(M_INFO,"%s -> tunnel %s\n",net,st->routes[i].c->name);
+ free(net);
+ }
+ Message(M_INFO,"%s/32 -> netlink \"%s\"\n",
+ ipaddr_to_string(st->secnet_address),st->name);
+ for (i=0; i<st->networks.entries; i++) {
+ string_t net;
+ net=subnet_to_string(&st->networks.list[i]);
+ Message(M_INFO,"%s -> host\n",net);
+ free(net);
+ }
+}
+