forked from Mirror/frr
ospf6d: support unicast hellos on PtP/PtMP
Some lower layers still don't handle multicast correctly (or efficiently.) Add option to send unicast hellos on explicitly configured neighbors for PtP/PtMP. Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
This commit is contained in:
parent
3d1482a945
commit
0c58d83688
|
@ -543,6 +543,9 @@ static int ospf6_interface_state_change(uint8_t next_state,
|
||||||
OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB(oi->area);
|
OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB(oi->area);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (next_state == OSPF6_INTERFACE_POINTTOPOINT)
|
||||||
|
ospf6_if_p2xp_up(oi);
|
||||||
|
|
||||||
hook_call(ospf6_interface_change, oi, next_state, prev_state);
|
hook_call(ospf6_interface_change, oi, next_state, prev_state);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2777,6 +2780,7 @@ static int config_write_ospf6_interface(struct vty *vty, struct vrf *vrf)
|
||||||
vty_out(vty,
|
vty_out(vty,
|
||||||
" ipv6 ospf6 p2p-p2mp disable-multicast-hello\n");
|
" ipv6 ospf6 p2p-p2mp disable-multicast-hello\n");
|
||||||
|
|
||||||
|
config_write_ospf6_p2xp_neighbor(vty, oi);
|
||||||
ospf6_bfd_write_config(vty, oi);
|
ospf6_bfd_write_config(vty, oi);
|
||||||
|
|
||||||
ospf6_auth_write_config(vty, &oi->at_data);
|
ospf6_auth_write_config(vty, &oi->at_data);
|
||||||
|
|
|
@ -268,6 +268,18 @@ static struct ospf6_packet *ospf6_packet_new(size_t size)
|
||||||
return new;
|
return new;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct ospf6_packet *ospf6_packet_dup(struct ospf6_packet *old)
|
||||||
|
{
|
||||||
|
struct ospf6_packet *new;
|
||||||
|
|
||||||
|
new = XCALLOC(MTYPE_OSPF6_PACKET, sizeof(struct ospf6_packet));
|
||||||
|
new->s = stream_dup(old->s);
|
||||||
|
new->dst = old->dst;
|
||||||
|
new->length = old->length;
|
||||||
|
|
||||||
|
return new;
|
||||||
|
}
|
||||||
|
|
||||||
static void ospf6_packet_free(struct ospf6_packet *op)
|
static void ospf6_packet_free(struct ospf6_packet *op)
|
||||||
{
|
{
|
||||||
if (op->s)
|
if (op->s)
|
||||||
|
@ -2257,8 +2269,6 @@ static void ospf6_write(struct event *thread)
|
||||||
void ospf6_hello_send(struct event *thread)
|
void ospf6_hello_send(struct event *thread)
|
||||||
{
|
{
|
||||||
struct ospf6_interface *oi;
|
struct ospf6_interface *oi;
|
||||||
struct ospf6_packet *op;
|
|
||||||
uint16_t length = OSPF6_HEADER_SIZE;
|
|
||||||
|
|
||||||
oi = (struct ospf6_interface *)EVENT_ARG(thread);
|
oi = (struct ospf6_interface *)EVENT_ARG(thread);
|
||||||
|
|
||||||
|
@ -2287,9 +2297,16 @@ void ospf6_hello_send(struct event *thread)
|
||||||
event_add_timer(master, ospf6_hello_send, oi, oi->hello_interval,
|
event_add_timer(master, ospf6_hello_send, oi, oi->hello_interval,
|
||||||
&oi->thread_send_hello);
|
&oi->thread_send_hello);
|
||||||
|
|
||||||
if (oi->state == OSPF6_INTERFACE_POINTTOPOINT
|
ospf6_hello_send_addr(oi, NULL);
|
||||||
&& oi->p2xp_no_multicast_hello)
|
}
|
||||||
return 0;
|
|
||||||
|
/* used to send polls for PtP/PtMP too */
|
||||||
|
void ospf6_hello_send_addr(struct ospf6_interface *oi,
|
||||||
|
const struct in6_addr *addr)
|
||||||
|
{
|
||||||
|
struct ospf6_packet *op;
|
||||||
|
uint16_t length = OSPF6_HEADER_SIZE;
|
||||||
|
bool anything = false;
|
||||||
|
|
||||||
op = ospf6_packet_new(oi->ifmtu);
|
op = ospf6_packet_new(oi->ifmtu);
|
||||||
|
|
||||||
|
@ -2309,16 +2326,37 @@ void ospf6_hello_send(struct event *thread)
|
||||||
/* Set packet length. */
|
/* Set packet length. */
|
||||||
op->length = length;
|
op->length = length;
|
||||||
|
|
||||||
op->dst = allspfrouters6;
|
if (!addr && oi->state == OSPF6_INTERFACE_POINTTOPOINT
|
||||||
|
&& oi->p2xp_no_multicast_hello) {
|
||||||
|
struct listnode *node;
|
||||||
|
struct ospf6_neighbor *on;
|
||||||
|
struct ospf6_packet *opdup;
|
||||||
|
|
||||||
ospf6_fill_hdr_checksum(oi, op);
|
for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, node, on)) {
|
||||||
|
if (on->state < OSPF6_NEIGHBOR_INIT)
|
||||||
|
/* poll-interval for these */
|
||||||
|
continue;
|
||||||
|
|
||||||
/* Add packet to the top of the interface output queue, so that they
|
opdup = ospf6_packet_dup(op);
|
||||||
* can't get delayed by things like long queues of LS Update packets
|
opdup->dst = on->linklocal_addr;
|
||||||
*/
|
ospf6_packet_add_top(oi, opdup);
|
||||||
ospf6_packet_add_top(oi, op);
|
anything = true;
|
||||||
|
}
|
||||||
|
|
||||||
OSPF6_MESSAGE_WRITE_ON(oi);
|
ospf6_packet_free(op);
|
||||||
|
} else {
|
||||||
|
op->dst = addr ? *addr : allspfrouters6;
|
||||||
|
|
||||||
|
/* Add packet to the top of the interface output queue, so that
|
||||||
|
* they can't get delayed by things like long queues of LS
|
||||||
|
* Update packets
|
||||||
|
*/
|
||||||
|
ospf6_packet_add_top(oi, op);
|
||||||
|
anything = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (anything)
|
||||||
|
OSPF6_MESSAGE_WRITE_ON(oi);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint16_t ospf6_make_dbdesc(struct ospf6_neighbor *on, struct stream *s)
|
static uint16_t ospf6_make_dbdesc(struct ospf6_neighbor *on, struct stream *s)
|
||||||
|
|
|
@ -50,6 +50,8 @@ extern unsigned char conf_debug_ospf6_message[];
|
||||||
#define OSPF6_MESSAGE_TYPE_ALL 0x6 /* For debug option */
|
#define OSPF6_MESSAGE_TYPE_ALL 0x6 /* For debug option */
|
||||||
#define OSPF6_MESSAGE_TYPE_MAX 0x6 /* same as OSPF6_MESSAGE_TYPE_ALL */
|
#define OSPF6_MESSAGE_TYPE_MAX 0x6 /* same as OSPF6_MESSAGE_TYPE_ALL */
|
||||||
|
|
||||||
|
struct ospf6_interface;
|
||||||
|
|
||||||
struct ospf6_packet {
|
struct ospf6_packet {
|
||||||
struct ospf6_packet *next;
|
struct ospf6_packet *next;
|
||||||
|
|
||||||
|
@ -169,6 +171,9 @@ extern void ospf6_lsupdate_send_neighbor(struct event *thread);
|
||||||
extern void ospf6_lsack_send_interface(struct event *thread);
|
extern void ospf6_lsack_send_interface(struct event *thread);
|
||||||
extern void ospf6_lsack_send_neighbor(struct event *thread);
|
extern void ospf6_lsack_send_neighbor(struct event *thread);
|
||||||
|
|
||||||
|
extern void ospf6_hello_send_addr(struct ospf6_interface *oi,
|
||||||
|
const struct in6_addr *addr);
|
||||||
|
|
||||||
extern int config_write_ospf6_debug_message(struct vty *);
|
extern int config_write_ospf6_debug_message(struct vty *);
|
||||||
extern void install_element_ospf6_debug_message(void);
|
extern void install_element_ospf6_debug_message(void);
|
||||||
extern const char *ospf6_message_type(int type);
|
extern const char *ospf6_message_type(int type);
|
||||||
|
|
|
@ -775,9 +775,7 @@ DEFPY (ipv6_ospf6_p2xp_neigh_cost,
|
||||||
oi = ospf6_interface_create(ifp);
|
oi = ospf6_interface_create(ifp);
|
||||||
}
|
}
|
||||||
|
|
||||||
p2xp_cfg = ospf6_if_p2xp_find(oi, &neighbor);
|
p2xp_cfg = ospf6_if_p2xp_get(oi, &neighbor);
|
||||||
if (!p2xp_cfg)
|
|
||||||
return CMD_SUCCESS;
|
|
||||||
|
|
||||||
uint32_t prev_cost;
|
uint32_t prev_cost;
|
||||||
if (p2xp_cfg->active)
|
if (p2xp_cfg->active)
|
||||||
|
@ -796,6 +794,74 @@ DEFPY (ipv6_ospf6_p2xp_neigh_cost,
|
||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void p2xp_unicast_hello_send(struct event *event);
|
||||||
|
|
||||||
|
static void p2xp_unicast_hello_sched(struct ospf6_if_p2xp_neighcfg *p2xp_cfg)
|
||||||
|
{
|
||||||
|
if (!p2xp_cfg->poll_interval
|
||||||
|
|| p2xp_cfg->ospf6_if->state != OSPF6_INTERFACE_POINTTOPOINT)
|
||||||
|
/* state check covers DOWN state too */
|
||||||
|
EVENT_OFF(p2xp_cfg->t_unicast_hello);
|
||||||
|
else
|
||||||
|
event_add_timer(master, p2xp_unicast_hello_send, p2xp_cfg,
|
||||||
|
p2xp_cfg->poll_interval,
|
||||||
|
&p2xp_cfg->t_unicast_hello);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ospf6_if_p2xp_up(struct ospf6_interface *oi)
|
||||||
|
{
|
||||||
|
struct ospf6_if_p2xp_neighcfg *p2xp_cfg;
|
||||||
|
|
||||||
|
frr_each (ospf6_if_p2xp_neighcfgs, &oi->p2xp_neighs, p2xp_cfg)
|
||||||
|
p2xp_unicast_hello_sched(p2xp_cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void p2xp_unicast_hello_send(struct event *event)
|
||||||
|
{
|
||||||
|
struct ospf6_if_p2xp_neighcfg *p2xp_cfg = EVENT_ARG(event);
|
||||||
|
struct ospf6_interface *oi = p2xp_cfg->ospf6_if;
|
||||||
|
|
||||||
|
if (oi->state != OSPF6_INTERFACE_POINTTOPOINT)
|
||||||
|
return;
|
||||||
|
|
||||||
|
p2xp_unicast_hello_sched(p2xp_cfg);
|
||||||
|
|
||||||
|
if (p2xp_cfg->active && p2xp_cfg->active->state >= OSPF6_NEIGHBOR_INIT)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ospf6_hello_send_addr(oi, &p2xp_cfg->addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFPY (ipv6_ospf6_p2xp_neigh_poll_interval,
|
||||||
|
ipv6_ospf6_p2xp_neigh_poll_interval_cmd,
|
||||||
|
"[no] ipv6 ospf6 neighbor X:X::X:X poll-interval (1-65535)",
|
||||||
|
NO_STR
|
||||||
|
IP6_STR
|
||||||
|
OSPF6_STR
|
||||||
|
"Configure static neighbor\n"
|
||||||
|
"Neighbor link-local address\n"
|
||||||
|
"Send unicast hellos to neighbor when down\n"
|
||||||
|
"Unicast hello interval when down (seconds)\n")
|
||||||
|
{
|
||||||
|
VTY_DECLVAR_CONTEXT(interface, ifp);
|
||||||
|
struct ospf6_interface *oi = ifp->info;
|
||||||
|
struct ospf6_if_p2xp_neighcfg *p2xp_cfg;
|
||||||
|
|
||||||
|
if (!oi) {
|
||||||
|
if (no)
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
oi = ospf6_interface_create(ifp);
|
||||||
|
}
|
||||||
|
if (no)
|
||||||
|
poll_interval = 0;
|
||||||
|
|
||||||
|
p2xp_cfg = ospf6_if_p2xp_get(oi, &neighbor);
|
||||||
|
p2xp_cfg->poll_interval = poll_interval;
|
||||||
|
|
||||||
|
p2xp_unicast_hello_sched(p2xp_cfg);
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
/* show neighbor structure */
|
/* show neighbor structure */
|
||||||
static void ospf6_neighbor_show(struct vty *vty, struct ospf6_neighbor *on,
|
static void ospf6_neighbor_show(struct vty *vty, struct ospf6_neighbor *on,
|
||||||
json_object *json_array, bool use_json)
|
json_object *json_array, bool use_json)
|
||||||
|
@ -1404,6 +1470,8 @@ void ospf6_neighbor_init(void)
|
||||||
|
|
||||||
install_element(INTERFACE_NODE, &ipv6_ospf6_p2xp_neigh_cmd);
|
install_element(INTERFACE_NODE, &ipv6_ospf6_p2xp_neigh_cmd);
|
||||||
install_element(INTERFACE_NODE, &ipv6_ospf6_p2xp_neigh_cost_cmd);
|
install_element(INTERFACE_NODE, &ipv6_ospf6_p2xp_neigh_cost_cmd);
|
||||||
|
install_element(INTERFACE_NODE,
|
||||||
|
&ipv6_ospf6_p2xp_neigh_poll_interval_cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFUN (debug_ospf6_neighbor,
|
DEFUN (debug_ospf6_neighbor,
|
||||||
|
@ -1514,6 +1582,11 @@ int config_write_ospf6_p2xp_neighbor(struct vty *vty,
|
||||||
frr_each (ospf6_if_p2xp_neighcfgs, &oi->p2xp_neighs, p2xp_cfg) {
|
frr_each (ospf6_if_p2xp_neighcfgs, &oi->p2xp_neighs, p2xp_cfg) {
|
||||||
vty_out(vty, " ipv6 ospf6 neighbor %pI6\n", &p2xp_cfg->addr);
|
vty_out(vty, " ipv6 ospf6 neighbor %pI6\n", &p2xp_cfg->addr);
|
||||||
|
|
||||||
|
if (p2xp_cfg->poll_interval)
|
||||||
|
vty_out(vty,
|
||||||
|
" ipv6 ospf6 neighbor %pI6 poll-interval %u\n",
|
||||||
|
&p2xp_cfg->addr, p2xp_cfg->poll_interval);
|
||||||
|
|
||||||
if (p2xp_cfg->cfg_cost)
|
if (p2xp_cfg->cfg_cost)
|
||||||
vty_out(vty, " ipv6 ospf6 neighbor %pI6 cost %u\n",
|
vty_out(vty, " ipv6 ospf6 neighbor %pI6 cost %u\n",
|
||||||
&p2xp_cfg->addr, p2xp_cfg->cost);
|
&p2xp_cfg->addr, p2xp_cfg->cost);
|
||||||
|
|
|
@ -161,9 +161,12 @@ struct ospf6_if_p2xp_neighcfg {
|
||||||
bool cfg_cost : 1;
|
bool cfg_cost : 1;
|
||||||
|
|
||||||
uint32_t cost;
|
uint32_t cost;
|
||||||
|
uint16_t poll_interval;
|
||||||
|
|
||||||
/* NULL if down */
|
/* NULL if down */
|
||||||
struct ospf6_neighbor *active;
|
struct ospf6_neighbor *active;
|
||||||
|
|
||||||
|
struct event *t_unicast_hello;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Neighbor state */
|
/* Neighbor state */
|
||||||
|
@ -220,6 +223,7 @@ void ospf6_neighbor_lladdr_set(struct ospf6_neighbor *on,
|
||||||
const struct in6_addr *addr);
|
const struct in6_addr *addr);
|
||||||
struct ospf6_if_p2xp_neighcfg *ospf6_if_p2xp_find(struct ospf6_interface *oi,
|
struct ospf6_if_p2xp_neighcfg *ospf6_if_p2xp_find(struct ospf6_interface *oi,
|
||||||
const struct in6_addr *addr);
|
const struct in6_addr *addr);
|
||||||
|
void ospf6_if_p2xp_up(struct ospf6_interface *oi);
|
||||||
|
|
||||||
uint32_t ospf6_neighbor_cost(struct ospf6_neighbor *on);
|
uint32_t ospf6_neighbor_cost(struct ospf6_neighbor *on);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue