File: [local] / src / usr.sbin / ldpd / ldpe.c (download)
Revision 1.82, Thu Dec 14 11:10:19 2023 UTC (5 months, 3 weeks ago) by claudio
Branch: MAIN
CVS Tags: OPENBSD_7_5_BASE, OPENBSD_7_5, HEAD Changes since 1.81: +5 -5 lines
Use imsg_get_fd() to access the file descriptor passed in the imsg.
OK tb@
|
/* $OpenBSD: ldpe.c,v 1.82 2023/12/14 11:10:19 claudio Exp $ */
/*
* Copyright (c) 2013, 2016 Renato Westphal <renato@openbsd.org>
* Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
* Copyright (c) 2004, 2008 Esben Norby <norby@openbsd.org>
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <pwd.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <errno.h>
#include "ldpd.h"
#include "ldpe.h"
#include "lde.h"
#include "control.h"
#include "log.h"
static void ldpe_sig_handler(int, short, void *);
static __dead void ldpe_shutdown(void);
static void ldpe_dispatch_main(int, short, void *);
static void ldpe_dispatch_lde(int, short, void *);
static void ldpe_dispatch_pfkey(int, short, void *);
static void ldpe_setup_sockets(int, int, int, int);
static void ldpe_close_sockets(int);
static void ldpe_iface_af_ctl(struct ctl_conn *, int, unsigned int);
struct ldpd_conf *leconf;
struct ldpd_sysdep sysdep;
static struct imsgev *iev_main;
static struct imsgev *iev_lde;
static struct event pfkey_ev;
static void
ldpe_sig_handler(int sig, short event, void *bula)
{
switch (sig) {
case SIGINT:
case SIGTERM:
ldpe_shutdown();
/* NOTREACHED */
default:
fatalx("unexpected signal");
}
}
/* label distribution protocol engine */
void
ldpe(int debug, int verbose, char *sockname)
{
struct passwd *pw;
struct event ev_sigint, ev_sigterm;
leconf = config_new_empty();
log_init(debug);
log_verbose(verbose);
setproctitle("ldp engine");
ldpd_process = PROC_LDP_ENGINE;
log_procname = "ldpe";
/* create ldpd control socket outside chroot */
global.csock = sockname;
if (control_init(global.csock) == -1)
fatalx("control socket setup failed");
LIST_INIT(&global.addr_list);
LIST_INIT(&global.adj_list);
TAILQ_INIT(&global.pending_conns);
if (inet_pton(AF_INET, AllRouters_v4, &global.mcast_addr_v4) != 1)
fatal("inet_pton");
if (inet_pton(AF_INET6, AllRouters_v6, &global.mcast_addr_v6) != 1)
fatal("inet_pton");
global.pfkeysock = pfkey_init();
if ((pw = getpwnam(LDPD_USER)) == NULL)
fatal("getpwnam");
if (chroot(pw->pw_dir) == -1)
fatal("chroot");
if (chdir("/") == -1)
fatal("chdir(\"/\")");
if (setgroups(1, &pw->pw_gid) ||
setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
fatal("can't drop privileges");
if (pledge("stdio inet mcast recvfd", NULL) == -1)
fatal("pledge");
event_init();
accept_init();
/* setup signal handler */
signal_set(&ev_sigint, SIGINT, ldpe_sig_handler, NULL);
signal_set(&ev_sigterm, SIGTERM, ldpe_sig_handler, NULL);
signal_add(&ev_sigint, NULL);
signal_add(&ev_sigterm, NULL);
signal(SIGPIPE, SIG_IGN);
signal(SIGHUP, SIG_IGN);
/* setup pipe and event handler to the parent process */
if ((iev_main = malloc(sizeof(struct imsgev))) == NULL)
fatal(NULL);
imsg_init(&iev_main->ibuf, 3);
iev_main->handler = ldpe_dispatch_main;
iev_main->events = EV_READ;
event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events,
iev_main->handler, iev_main);
event_add(&iev_main->ev, NULL);
if (sysdep.no_pfkey == 0) {
event_set(&pfkey_ev, global.pfkeysock, EV_READ | EV_PERSIST,
ldpe_dispatch_pfkey, NULL);
event_add(&pfkey_ev, NULL);
}
/* mark sockets as closed */
global.ipv4.ldp_disc_socket = -1;
global.ipv4.ldp_edisc_socket = -1;
global.ipv4.ldp_session_socket = -1;
global.ipv6.ldp_disc_socket = -1;
global.ipv6.ldp_edisc_socket = -1;
global.ipv6.ldp_session_socket = -1;
/* listen on ldpd control socket */
control_listen();
event_dispatch();
ldpe_shutdown();
}
static __dead void
ldpe_shutdown(void)
{
struct if_addr *if_addr;
struct adj *adj;
/* close pipes */
msgbuf_write(&iev_lde->ibuf.w);
msgbuf_clear(&iev_lde->ibuf.w);
close(iev_lde->ibuf.fd);
msgbuf_write(&iev_main->ibuf.w);
msgbuf_clear(&iev_main->ibuf.w);
close(iev_main->ibuf.fd);
control_cleanup();
config_clear(leconf);
if (sysdep.no_pfkey == 0) {
event_del(&pfkey_ev);
close(global.pfkeysock);
}
ldpe_close_sockets(AF_INET);
ldpe_close_sockets(AF_INET6);
/* remove addresses from global list */
while ((if_addr = LIST_FIRST(&global.addr_list)) != NULL) {
LIST_REMOVE(if_addr, entry);
free(if_addr);
}
while ((adj = LIST_FIRST(&global.adj_list)) != NULL)
adj_del(adj, S_SHUTDOWN);
/* clean up */
free(iev_lde);
free(iev_main);
log_info("ldp engine exiting");
exit(0);
}
/* imesg */
int
ldpe_imsg_compose_parent(int type, pid_t pid, void *data, uint16_t datalen)
{
return (imsg_compose_event(iev_main, type, 0, pid, -1, data, datalen));
}
int
ldpe_imsg_compose_lde(int type, uint32_t peerid, pid_t pid, void *data,
uint16_t datalen)
{
return (imsg_compose_event(iev_lde, type, peerid, pid, -1,
data, datalen));
}
static void
ldpe_dispatch_main(int fd, short event, void *bula)
{
static struct ldpd_conf *nconf;
struct iface *niface;
struct tnbr *ntnbr;
struct nbr_params *nnbrp;
static struct l2vpn *l2vpn, *nl2vpn;
struct l2vpn_if *lif = NULL, *nlif;
struct l2vpn_pw *npw;
struct imsg imsg;
struct imsgev *iev = bula;
struct imsgbuf *ibuf = &iev->ibuf;
struct iface *iface = NULL;
struct kif *kif;
int af;
enum socket_type *socket_type;
static int disc_socket = -1;
static int edisc_socket = -1;
static int session_socket = -1;
struct nbr *nbr;
int n, shut = 0;
if (event & EV_READ) {
if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
fatal("imsg_read error");
if (n == 0) /* connection closed */
shut = 1;
}
if (event & EV_WRITE) {
if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
fatal("ldpe_dispatch_main: msgbuf_write");
if (n == 0)
shut = 1;
}
for (;;) {
if ((n = imsg_get(ibuf, &imsg)) == -1)
fatal("ldpe_dispatch_main: imsg_get error");
if (n == 0)
break;
switch (imsg.hdr.type) {
case IMSG_IFSTATUS:
if (imsg.hdr.len != IMSG_HEADER_SIZE +
sizeof(struct kif))
fatalx("IFSTATUS imsg with wrong len");
kif = imsg.data;
iface = if_lookup(leconf, kif->ifindex);
if (iface) {
iface->flags = kif->flags;
iface->linkstate = kif->link_state;
if_update(iface, AF_UNSPEC);
break;
}
LIST_FOREACH(l2vpn, &leconf->l2vpn_list, entry) {
lif = l2vpn_if_find(l2vpn, kif->ifindex);
if (lif) {
lif->flags = kif->flags;
lif->linkstate = kif->link_state;
memcpy(lif->mac, kif->mac,
sizeof(lif->mac));
l2vpn_if_update(lif);
break;
}
}
break;
case IMSG_NEWADDR:
if (imsg.hdr.len != IMSG_HEADER_SIZE +
sizeof(struct kaddr))
fatalx("NEWADDR imsg with wrong len");
if_addr_add(imsg.data);
break;
case IMSG_DELADDR:
if (imsg.hdr.len != IMSG_HEADER_SIZE +
sizeof(struct kaddr))
fatalx("DELADDR imsg with wrong len");
if_addr_del(imsg.data);
break;
case IMSG_SOCKET_IPC:
if (iev_lde) {
log_warnx("%s: received unexpected imsg fd "
"to lde", __func__);
break;
}
if ((fd = imsg_get_fd(&imsg)) == -1) {
log_warnx("%s: expected to receive imsg fd to "
"lde but didn't receive any", __func__);
break;
}
if ((iev_lde = malloc(sizeof(struct imsgev))) == NULL)
fatal(NULL);
imsg_init(&iev_lde->ibuf, fd);
iev_lde->handler = ldpe_dispatch_lde;
iev_lde->events = EV_READ;
event_set(&iev_lde->ev, iev_lde->ibuf.fd,
iev_lde->events, iev_lde->handler, iev_lde);
event_add(&iev_lde->ev, NULL);
break;
case IMSG_CLOSE_SOCKETS:
af = imsg.hdr.peerid;
RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) {
if (nbr->af != af)
continue;
session_shutdown(nbr, S_SHUTDOWN, 0, 0);
pfkey_remove(nbr);
}
ldpe_close_sockets(af);
if_update_all(af);
tnbr_update_all(af);
disc_socket = -1;
edisc_socket = -1;
session_socket = -1;
if ((ldp_af_conf_get(leconf, af))->flags &
F_LDPD_AF_ENABLED)
ldpe_imsg_compose_parent(IMSG_REQUEST_SOCKETS,
af, NULL, 0);
break;
case IMSG_SOCKET_NET:
if (imsg.hdr.len != IMSG_HEADER_SIZE +
sizeof(enum socket_type))
fatalx("SOCKET_NET imsg with wrong len");
socket_type = imsg.data;
switch (*socket_type) {
case LDP_SOCKET_DISC:
disc_socket = imsg_get_fd(&imsg);
break;
case LDP_SOCKET_EDISC:
edisc_socket = imsg_get_fd(&imsg);
break;
case LDP_SOCKET_SESSION:
session_socket = imsg_get_fd(&imsg);
break;
}
break;
case IMSG_SETUP_SOCKETS:
af = imsg.hdr.peerid;
if (disc_socket == -1 || edisc_socket == -1 ||
session_socket == -1) {
if (disc_socket != -1)
close(disc_socket);
if (edisc_socket != -1)
close(edisc_socket);
if (session_socket != -1)
close(session_socket);
break;
}
ldpe_setup_sockets(af, disc_socket, edisc_socket,
session_socket);
if_update_all(af);
tnbr_update_all(af);
RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) {
if (nbr->af != af)
continue;
nbr->laddr = (ldp_af_conf_get(leconf,
af))->trans_addr;
if (pfkey_establish(nconf, nbr) == -1)
fatalx("pfkey setup failed");
if (nbr_session_active_role(nbr))
nbr_establish_connection(nbr);
}
break;
case IMSG_RECONF_CONF:
if ((nconf = malloc(sizeof(struct ldpd_conf))) ==
NULL)
fatal(NULL);
memcpy(nconf, imsg.data, sizeof(struct ldpd_conf));
LIST_INIT(&nconf->iface_list);
LIST_INIT(&nconf->tnbr_list);
LIST_INIT(&nconf->nbrp_list);
LIST_INIT(&nconf->l2vpn_list);
LIST_INIT(&nconf->auth_list);
break;
case IMSG_RECONF_IFACE:
if ((niface = malloc(sizeof(struct iface))) == NULL)
fatal(NULL);
memcpy(niface, imsg.data, sizeof(struct iface));
LIST_INIT(&niface->addr_list);
LIST_INIT(&niface->ipv4.adj_list);
LIST_INIT(&niface->ipv6.adj_list);
niface->ipv4.iface = niface;
niface->ipv6.iface = niface;
LIST_INSERT_HEAD(&nconf->iface_list, niface, entry);
break;
case IMSG_RECONF_TNBR:
if ((ntnbr = malloc(sizeof(struct tnbr))) == NULL)
fatal(NULL);
memcpy(ntnbr, imsg.data, sizeof(struct tnbr));
LIST_INSERT_HEAD(&nconf->tnbr_list, ntnbr, entry);
break;
case IMSG_RECONF_NBRP:
if ((nnbrp = malloc(sizeof(struct nbr_params))) == NULL)
fatal(NULL);
memcpy(nnbrp, imsg.data, sizeof(struct nbr_params));
LIST_INSERT_HEAD(&nconf->nbrp_list, nnbrp, entry);
break;
case IMSG_RECONF_L2VPN:
if ((nl2vpn = malloc(sizeof(struct l2vpn))) == NULL)
fatal(NULL);
memcpy(nl2vpn, imsg.data, sizeof(struct l2vpn));
LIST_INIT(&nl2vpn->if_list);
LIST_INIT(&nl2vpn->pw_list);
LIST_INSERT_HEAD(&nconf->l2vpn_list, nl2vpn, entry);
break;
case IMSG_RECONF_L2VPN_IF:
if ((nlif = malloc(sizeof(struct l2vpn_if))) == NULL)
fatal(NULL);
memcpy(nlif, imsg.data, sizeof(struct l2vpn_if));
nlif->l2vpn = nl2vpn;
LIST_INSERT_HEAD(&nl2vpn->if_list, nlif, entry);
break;
case IMSG_RECONF_L2VPN_PW:
if ((npw = malloc(sizeof(struct l2vpn_pw))) == NULL)
fatal(NULL);
memcpy(npw, imsg.data, sizeof(struct l2vpn_pw));
npw->l2vpn = nl2vpn;
LIST_INSERT_HEAD(&nl2vpn->pw_list, npw, entry);
break;
case IMSG_RECONF_CONF_AUTH: {
struct ldp_auth *auth;
auth = malloc(sizeof(*auth));
if (auth == NULL)
fatal(NULL);
memcpy(auth, imsg.data, sizeof(*auth));
LIST_INSERT_HEAD(&nconf->auth_list, auth, entry);
break;
}
case IMSG_RECONF_END:
merge_config(leconf, nconf);
nconf = NULL;
global.conf_seqnum++;
break;
case IMSG_CTL_KROUTE:
case IMSG_CTL_KROUTE_ADDR:
case IMSG_CTL_IFINFO:
case IMSG_CTL_END:
control_imsg_relay(&imsg);
break;
default:
log_debug("ldpe_dispatch_main: error handling imsg %d",
imsg.hdr.type);
break;
}
imsg_free(&imsg);
}
if (!shut)
imsg_event_add(iev);
else {
/* this pipe is dead, so remove the event handler */
event_del(&iev->ev);
event_loopexit(NULL);
}
}
static void
ldpe_dispatch_lde(int fd, short event, void *bula)
{
struct imsgev *iev = bula;
struct imsgbuf *ibuf = &iev->ibuf;
struct imsg imsg;
struct map map;
struct notify_msg nm;
int n, shut = 0;
struct nbr *nbr = NULL;
if (event & EV_READ) {
if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
fatal("imsg_read error");
if (n == 0) /* connection closed */
shut = 1;
}
if (event & EV_WRITE) {
if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
fatal("ldpe_dispatch_lde: msgbuf_write");
if (n == 0)
shut = 1;
}
for (;;) {
if ((n = imsg_get(ibuf, &imsg)) == -1)
fatal("ldpe_dispatch_lde: imsg_get error");
if (n == 0)
break;
switch (imsg.hdr.type) {
case IMSG_MAPPING_ADD:
case IMSG_RELEASE_ADD:
case IMSG_REQUEST_ADD:
case IMSG_WITHDRAW_ADD:
if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(map))
fatalx("invalid size of map request");
memcpy(&map, imsg.data, sizeof(map));
nbr = nbr_find_peerid(imsg.hdr.peerid);
if (nbr == NULL) {
log_debug("ldpe_dispatch_lde: cannot find "
"neighbor");
break;
}
if (nbr->state != NBR_STA_OPER)
break;
switch (imsg.hdr.type) {
case IMSG_MAPPING_ADD:
mapping_list_add(&nbr->mapping_list, &map);
break;
case IMSG_RELEASE_ADD:
mapping_list_add(&nbr->release_list, &map);
break;
case IMSG_REQUEST_ADD:
mapping_list_add(&nbr->request_list, &map);
break;
case IMSG_WITHDRAW_ADD:
mapping_list_add(&nbr->withdraw_list, &map);
break;
}
break;
case IMSG_MAPPING_ADD_END:
case IMSG_RELEASE_ADD_END:
case IMSG_REQUEST_ADD_END:
case IMSG_WITHDRAW_ADD_END:
nbr = nbr_find_peerid(imsg.hdr.peerid);
if (nbr == NULL) {
log_debug("ldpe_dispatch_lde: cannot find "
"neighbor");
break;
}
if (nbr->state != NBR_STA_OPER)
break;
switch (imsg.hdr.type) {
case IMSG_MAPPING_ADD_END:
send_labelmessage(nbr, MSG_TYPE_LABELMAPPING,
&nbr->mapping_list);
break;
case IMSG_RELEASE_ADD_END:
send_labelmessage(nbr, MSG_TYPE_LABELRELEASE,
&nbr->release_list);
break;
case IMSG_REQUEST_ADD_END:
send_labelmessage(nbr, MSG_TYPE_LABELREQUEST,
&nbr->request_list);
break;
case IMSG_WITHDRAW_ADD_END:
send_labelmessage(nbr, MSG_TYPE_LABELWITHDRAW,
&nbr->withdraw_list);
break;
}
break;
case IMSG_NOTIFICATION_SEND:
if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(nm))
fatalx("invalid size of OE request");
memcpy(&nm, imsg.data, sizeof(nm));
nbr = nbr_find_peerid(imsg.hdr.peerid);
if (nbr == NULL) {
log_debug("ldpe_dispatch_lde: cannot find "
"neighbor");
break;
}
if (nbr->state != NBR_STA_OPER)
break;
send_notification_full(nbr->tcp, &nm);
break;
case IMSG_CTL_END:
case IMSG_CTL_SHOW_LIB:
case IMSG_CTL_SHOW_L2VPN_PW:
case IMSG_CTL_SHOW_L2VPN_BINDING:
control_imsg_relay(&imsg);
break;
default:
log_debug("ldpe_dispatch_lde: error handling imsg %d",
imsg.hdr.type);
break;
}
imsg_free(&imsg);
}
if (!shut)
imsg_event_add(iev);
else {
/* this pipe is dead, so remove the event handler */
event_del(&iev->ev);
event_loopexit(NULL);
}
}
static void
ldpe_dispatch_pfkey(int fd, short event, void *bula)
{
if (event & EV_READ) {
if (pfkey_read(fd, NULL) == -1) {
fatal("pfkey_read failed, exiting...");
}
}
}
static void
ldpe_setup_sockets(int af, int disc_socket, int edisc_socket,
int session_socket)
{
struct ldpd_af_global *af_global;
af_global = ldp_af_global_get(&global, af);
/* discovery socket */
af_global->ldp_disc_socket = disc_socket;
event_set(&af_global->disc_ev, af_global->ldp_disc_socket,
EV_READ|EV_PERSIST, disc_recv_packet, NULL);
event_add(&af_global->disc_ev, NULL);
/* extended discovery socket */
af_global->ldp_edisc_socket = edisc_socket;
event_set(&af_global->edisc_ev, af_global->ldp_edisc_socket,
EV_READ|EV_PERSIST, disc_recv_packet, NULL);
event_add(&af_global->edisc_ev, NULL);
/* session socket */
af_global->ldp_session_socket = session_socket;
accept_add(af_global->ldp_session_socket, session_accept, NULL);
}
static void
ldpe_close_sockets(int af)
{
struct ldpd_af_global *af_global;
af_global = ldp_af_global_get(&global, af);
/* discovery socket */
if (event_initialized(&af_global->disc_ev))
event_del(&af_global->disc_ev);
if (af_global->ldp_disc_socket != -1) {
close(af_global->ldp_disc_socket);
af_global->ldp_disc_socket = -1;
}
/* extended discovery socket */
if (event_initialized(&af_global->edisc_ev))
event_del(&af_global->edisc_ev);
if (af_global->ldp_edisc_socket != -1) {
close(af_global->ldp_edisc_socket);
af_global->ldp_edisc_socket = -1;
}
/* session socket */
if (af_global->ldp_session_socket != -1) {
accept_del(af_global->ldp_session_socket);
close(af_global->ldp_session_socket);
af_global->ldp_session_socket = -1;
}
}
void
ldpe_reset_nbrs(int af)
{
struct nbr *nbr;
RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) {
if (nbr->af == af)
session_shutdown(nbr, S_SHUTDOWN, 0, 0);
}
}
void
ldpe_reset_ds_nbrs(void)
{
struct nbr *nbr;
RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) {
if (nbr->ds_tlv)
session_shutdown(nbr, S_SHUTDOWN, 0, 0);
}
}
void
ldpe_remove_dynamic_tnbrs(int af)
{
struct tnbr *tnbr, *safe;
LIST_FOREACH_SAFE(tnbr, &leconf->tnbr_list, entry, safe) {
if (tnbr->af != af)
continue;
tnbr->flags &= ~F_TNBR_DYNAMIC;
tnbr_check(tnbr);
}
}
void
ldpe_stop_init_backoff(int af)
{
struct nbr *nbr;
RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) {
if (nbr->af == af && nbr_pending_idtimer(nbr)) {
nbr_stop_idtimer(nbr);
nbr_establish_connection(nbr);
}
}
}
static void
ldpe_iface_af_ctl(struct ctl_conn *c, int af, unsigned int idx)
{
struct iface *iface;
struct iface_af *ia;
struct ctl_iface *ictl;
LIST_FOREACH(iface, &leconf->iface_list, entry) {
if (idx == 0 || idx == iface->ifindex) {
ia = iface_af_get(iface, af);
if (!ia->enabled)
continue;
ictl = if_to_ctl(ia);
imsg_compose_event(&c->iev, IMSG_CTL_SHOW_INTERFACE,
0, 0, -1, ictl, sizeof(struct ctl_iface));
}
}
}
void
ldpe_iface_ctl(struct ctl_conn *c, unsigned int idx)
{
ldpe_iface_af_ctl(c, AF_INET, idx);
ldpe_iface_af_ctl(c, AF_INET6, idx);
}
void
ldpe_adj_ctl(struct ctl_conn *c)
{
struct nbr *nbr;
struct adj *adj;
struct ctl_adj *actl;
RB_FOREACH(nbr, nbr_addr_head, &nbrs_by_addr) {
LIST_FOREACH(adj, &nbr->adj_list, nbr_entry) {
actl = adj_to_ctl(adj);
imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISCOVERY,
0, 0, -1, actl, sizeof(struct ctl_adj));
}
}
/* show adjacencies not associated with any neighbor */
LIST_FOREACH(adj, &global.adj_list, global_entry) {
if (adj->nbr != NULL)
continue;
actl = adj_to_ctl(adj);
imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISCOVERY, 0, 0,
-1, actl, sizeof(struct ctl_adj));
}
imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0);
}
void
ldpe_nbr_ctl(struct ctl_conn *c)
{
struct nbr *nbr;
struct ctl_nbr *nctl;
RB_FOREACH(nbr, nbr_addr_head, &nbrs_by_addr) {
nctl = nbr_to_ctl(nbr);
imsg_compose_event(&c->iev, IMSG_CTL_SHOW_NBR, 0, 0, -1, nctl,
sizeof(struct ctl_nbr));
}
imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0);
}
void
mapping_list_add(struct mapping_head *mh, struct map *map)
{
struct mapping_entry *me;
me = calloc(1, sizeof(*me));
if (me == NULL)
fatal(__func__);
me->map = *map;
TAILQ_INSERT_TAIL(mh, me, entry);
}
void
mapping_list_clr(struct mapping_head *mh)
{
struct mapping_entry *me;
while ((me = TAILQ_FIRST(mh)) != NULL) {
TAILQ_REMOVE(mh, me, entry);
free(me);
}
}