gossipd: Implement gossip_routing_failure for master to report routing failures.

This commit is contained in:
ZmnSCPxj 2018-01-17 23:32:36 +00:00 committed by Rusty Russell
parent 7a651c62fa
commit b255d82ae2
9 changed files with 152 additions and 1 deletions

View File

@ -56,7 +56,8 @@ GOSSIPD_COMMON_OBJS := \
common/wire_error.o \
hsmd/client.o \
hsmd/gen_hsm_client_wire.o \
lightningd/gossip_msg.o
lightningd/gossip_msg.o \
wire/gen_onion_wire.o
$(LIGHTNINGD_GOSSIP_OBJS) $(LIGHTNINGD_GOSSIP_CLIENT_OBJS): $(LIGHTNINGD_HEADERS) $(LIGHTNINGD_GOSSIP_HEADERS)

View File

@ -1883,6 +1883,27 @@ fail:
tal_free(tmpctx);
return daemon_conn_read_next(conn, &daemon->master);
}
static struct io_plan *handle_routing_failure(struct io_conn *conn,
struct daemon *daemon,
const u8 *msg)
{
struct pubkey erring_node;
struct short_channel_id erring_channel;
u16 failcode;
if (!fromwire_gossip_routing_failure(msg, NULL,
&erring_node,
&erring_channel,
&failcode))
master_badmsg(WIRE_GOSSIP_ROUTING_FAILURE, msg);
routing_failure(daemon->rstate,
&erring_node,
&erring_channel,
(enum onion_type) failcode);
return daemon_conn_read_next(conn, &daemon->master);
}
static struct io_plan *recv_req(struct io_conn *conn, struct daemon_conn *master)
{
@ -1932,6 +1953,9 @@ static struct io_plan *recv_req(struct io_conn *conn, struct daemon_conn *master
case WIRE_GOSSIP_DISABLE_CHANNEL:
return handle_disable_channel(conn, daemon, master->msg_in);
case WIRE_GOSSIP_ROUTING_FAILURE:
return handle_routing_failure(conn, daemon, master->msg_in);
/* We send these, we don't receive them */
case WIRE_GOSSIPCTL_RELEASE_PEER_REPLY:
case WIRE_GOSSIPCTL_RELEASE_PEER_REPLYFAIL:

View File

@ -1,5 +1,6 @@
#include <common/cryptomsg.h>
#include <common/wireaddr.h>
#include <wire/gen_onion_wire.h>
# Initialize the gossip daemon.
gossipctl_init,3000
@ -195,3 +196,9 @@ gossip_disable_channel,3019
gossip_disable_channel,,short_channel_id,struct short_channel_id
gossip_disable_channel,,direction,u8
gossip_disable_channel,,active,bool
# master->gossipd a routing failure occurred
gossip_routing_failure,3021
gossip_routing_failure,,erring_node,struct pubkey
gossip_routing_failure,,erring_channel,struct short_channel_id
gossip_routing_failure,,failcode,u16

1 #include <common/cryptomsg.h>
2 #include <common/wireaddr.h>
3 #include <wire/gen_onion_wire.h>
4 # Initialize the gossip daemon.
5 gossipctl_init,3000
6 gossipctl_init,,broadcast_interval,u32
196
197
198
199
200
201
202
203
204

View File

@ -13,6 +13,7 @@
#include <common/type_to_string.h>
#include <common/wireaddr.h>
#include <inttypes.h>
#include <wire/gen_onion_wire.h>
#include <wire/gen_peer_wire.h>
#ifndef SUPERVERBOSE
@ -238,6 +239,12 @@ get_or_make_connection(struct routing_state *rstate,
return nc;
}
static void delete_connection(struct routing_state *rstate,
const struct node_connection *connection)
{
tal_free(connection);
}
struct node_connection *half_add_connection(
struct routing_state *rstate,
const struct pubkey *from,
@ -1007,3 +1014,99 @@ struct route_hop *get_route(tal_t *ctx, struct routing_state *rstate,
/* FIXME: Shadow route! */
return hops;
}
/* Get the struct node_connection matching the short_channel_id,
* which must be an out connection of the given node. */
static struct node_connection *
get_out_node_connection_of(struct routing_state *rstate,
const struct node *node,
const struct short_channel_id *short_channel_id)
{
int i;
for (i = 0; i < tal_count(node->out); ++i) {
if (short_channel_id_eq(&node->out[i]->short_channel_id, short_channel_id))
return node->out[i];
}
return NULL;
}
/**
* routing_failure_on_nc - Handle routing failure on a specific
* node_connection.
*/
static void routing_failure_on_nc(struct routing_state *rstate,
enum onion_type failcode,
struct node_connection *nc)
{
/* BOLT #4:
*
* - if the PERM bit is NOT set:
* - SHOULD restore the channels as it receives new `channel_update`s.
*/
if (failcode & PERM)
nc->active = false;
else
delete_connection(rstate, nc);
}
void routing_failure(struct routing_state *rstate,
const struct pubkey *erring_node_pubkey,
const struct short_channel_id *scid,
enum onion_type failcode)
{
const tal_t *tmpctx = tal_tmpctx(rstate);
struct node *node;
struct node_connection *nc;
int i;
status_trace("Received routing failure 0x%04x (%s), "
"erring node %s, "
"channel %s",
(int) failcode, onion_type_name(failcode),
type_to_string(tmpctx, struct pubkey, erring_node_pubkey),
type_to_string(tmpctx, struct short_channel_id, scid));
node = get_node(rstate, erring_node_pubkey);
if (!node) {
status_trace("UNUSUAL routing_failure: "
"Erring node %s not in map",
type_to_string(tmpctx, struct pubkey,
erring_node_pubkey));
/* No node, so no channel, so any channel_update
* can also be ignored. */
goto out;
}
/* BOLT #4:
*
* - if the NODE bit is set:
* - SHOULD remove all channels connected with the erring node from
* consideration.
*
*/
if (failcode & NODE) {
for (i = 0; i < tal_count(node->in); ++i)
routing_failure_on_nc(rstate, failcode, node->in[i]);
for (i = 0; i < tal_count(node->out); ++i)
routing_failure_on_nc(rstate, failcode, node->out[i]);
} else {
nc = get_out_node_connection_of(rstate, node, scid);
if (nc)
routing_failure_on_nc(rstate, failcode, nc);
else
status_trace("UNUSUAL routing_failure: "
"Channel %s not an out channel "
"of node %s",
type_to_string(tmpctx,
struct short_channel_id,
scid),
type_to_string(tmpctx, struct pubkey,
erring_node_pubkey));
}
/* FIXME: if UPDATE is set, apply the channel update. */
out:
tal_free(tmpctx);
}

View File

@ -4,6 +4,7 @@
#include <bitcoin/pubkey.h>
#include <ccan/htable/htable_type.h>
#include <gossipd/broadcast.h>
#include <wire/gen_onion_wire.h>
#include <wire/wire.h>
#define ROUTING_MAX_HOPS 20
@ -148,6 +149,11 @@ struct route_hop *get_route(tal_t *ctx, struct routing_state *rstate,
const struct pubkey *destination,
const u32 msatoshi, double riskfactor,
u32 final_cltv);
/* Disable channel(s) based on the given routing failure. */
void routing_failure(struct routing_state *rstate,
const struct pubkey *erring_node,
const struct short_channel_id *erring_channel,
enum onion_type failcode);
/* Utility function that, given a source and a destination, gives us
* the direction bit the matching channel should get */

View File

@ -63,6 +63,9 @@ u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
/* Generated stub for fromwire_wireaddr */
bool fromwire_wireaddr(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct wireaddr *addr UNNEEDED)
{ fprintf(stderr, "fromwire_wireaddr called!\n"); abort(); }
/* Generated stub for onion_type_name */
const char *onion_type_name(int e UNNEEDED)
{ fprintf(stderr, "onion_type_name called!\n"); abort(); }
/* Generated stub for queue_broadcast */
bool queue_broadcast(struct broadcast_state *bstate UNNEEDED,
const int type UNNEEDED,

View File

@ -34,6 +34,9 @@ u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
/* Generated stub for fromwire_wireaddr */
bool fromwire_wireaddr(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct wireaddr *addr UNNEEDED)
{ fprintf(stderr, "fromwire_wireaddr called!\n"); abort(); }
/* Generated stub for onion_type_name */
const char *onion_type_name(int e UNNEEDED)
{ fprintf(stderr, "onion_type_name called!\n"); abort(); }
/* Generated stub for queue_broadcast */
bool queue_broadcast(struct broadcast_state *bstate UNNEEDED,
const int type UNNEEDED,

View File

@ -27,6 +27,9 @@ u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
/* Generated stub for fromwire_wireaddr */
bool fromwire_wireaddr(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct wireaddr *addr UNNEEDED)
{ fprintf(stderr, "fromwire_wireaddr called!\n"); abort(); }
/* Generated stub for onion_type_name */
const char *onion_type_name(int e UNNEEDED)
{ fprintf(stderr, "onion_type_name called!\n"); abort(); }
/* Generated stub for queue_broadcast */
bool queue_broadcast(struct broadcast_state *bstate UNNEEDED,
const int type UNNEEDED,

View File

@ -110,6 +110,7 @@ static unsigned gossip_msg(struct subd *gossip, const u8 *msg, const int *fds)
case WIRE_GOSSIP_SEND_GOSSIP:
case WIRE_GOSSIP_GET_TXOUT_REPLY:
case WIRE_GOSSIP_DISABLE_CHANNEL:
case WIRE_GOSSIP_ROUTING_FAILURE:
/* This is a reply, so never gets through to here. */
case WIRE_GOSSIP_GET_UPDATE_REPLY:
case WIRE_GOSSIP_GETNODES_REPLY: