/*	$OpenBSD: bgpd.h,v 1.529 2025/12/29 07:48:31 claudio Exp $ */

/*
 * 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.
 */
#ifndef __BGPD_H__
#define	__BGPD_H__

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/queue.h>
#include <sys/tree.h>
#include <netinet/in.h>
#include <net/if.h>
#include <netinet/if_ether.h>

#include <stdint.h>
#include <imsg.h>

#include "monotime.h"

#define	BGP_VERSION			4
#define	RTR_MAX_VERSION			2
#define	RTR_DEFAULT_VERSION		1
#define	BGP_PORT			179
#define	RTR_PORT			323
#define	PEER_DESCR_LEN			64
#define	REASON_LEN			256	/* includes NUL terminator */
#define	PFTABLE_LEN			32
#define	ROUTELABEL_LEN			32
#define	TCP_MD5_KEY_LEN			80
#define	IPSEC_ENC_KEY_LEN		32
#define	IPSEC_AUTH_KEY_LEN		20
#define	SET_NAME_LEN			128

#define	MAX_PKTSIZE			4096
#define	MAX_EXT_PKTSIZE			65535
#define	MAX_BGPD_IMSGSIZE		(128 * 1024)
#define	MAX_SOCK_BUF			(4 * IBUF_READ_SIZE)
#define	RT_BUF_SIZE			16384
#define	MAX_RTSOCK_BUF			(2 * 1024 * 1024)
#define	MAX_COMM_MATCH			3
#define	MAX_ASPA_SPAS_COUNT		10000
#define	MIN_HOLDTIME			3

#define	BGPD_OPT_VERBOSE		0x0001
#define	BGPD_OPT_VERBOSE2		0x0002
#define	BGPD_OPT_NOACTION		0x0004
#define	BGPD_OPT_FORCE_DEMOTE		0x0008

#define	BGPD_FLAG_REFLECTOR		0x0004
#define	BGPD_FLAG_NEXTHOP_BGP		0x0010
#define	BGPD_FLAG_NEXTHOP_DEFAULT	0x0020
#define	BGPD_FLAG_DECISION_MASK		0x0f00
#define	BGPD_FLAG_DECISION_ROUTEAGE	0x0100
#define	BGPD_FLAG_DECISION_TRANS_AS	0x0200
#define	BGPD_FLAG_DECISION_MED_ALWAYS	0x0400
#define	BGPD_FLAG_DECISION_ALL_PATHS	0x0800
#define	BGPD_FLAG_PERMIT_AS_SET		0x1000

#define	BGPD_LOG_UPDATES		0x0001

#ifndef	BGPD_USER
#define	BGPD_USER			"_bgpd"
#endif

#ifndef	SYSCONFDIR
#define	SYSCONFDIR			"/etc"
#endif
#define	CONFFILE			SYSCONFDIR "/bgpd.conf"

#ifndef	RUNSTATEDIR
#define	RUNSTATEDIR			"/var/run"
#endif
#define	SOCKET_NAME			RUNSTATEDIR "/bgpd.sock"

#define	F_BGPD			0x0001
#define	F_BGPD_INSERTED		0x0002
#define	F_CONNECTED		0x0004
#define	F_STATIC		0x0008
#define	F_NEXTHOP		0x0010
#define	F_REJECT		0x0020
#define	F_BLACKHOLE		0x0040
#define	F_MPLS			0x0080
#define	F_LONGER		0x0200
#define	F_SHORTER		0x0400
#define	F_CTL_DETAIL		0x1000		/* only set on requests */
#define	F_CTL_ADJ_IN		0x2000		/* only set on requests */
#define	F_CTL_ADJ_OUT		0x4000		/* only set on requests */
#define	F_CTL_BEST		0x8000
#define	F_CTL_INELIGIBLE	0x10000		/* only set on requests */
#define	F_CTL_LEAKED		0x20000		/* only set on requests */
#define	F_CTL_INVALID		0x40000		/* only set on requests */
#define	F_CTL_OVS_VALID		0x80000
#define	F_CTL_OVS_INVALID	0x100000
#define	F_CTL_OVS_NOTFOUND	0x200000
#define	F_CTL_NEIGHBORS		0x400000	 /* only used by bgpctl */
#define	F_CTL_HAS_PATHID	0x800000	 /* only set on requests */
#define	F_CTL_AVS_VALID		0x1000000
#define	F_CTL_AVS_INVALID	0x2000000
#define	F_CTL_AVS_UNKNOWN	0x4000000
#define	F_CTL_FILTERED		0x8000000	/* only set on requests */
#define	F_CTL_SSV		0x80000000	/* only used by bgpctl */

#define CTASSERT(x)	extern char  _ctassert[(x) ? 1 : -1 ] \
			    __attribute__((__unused__))

#ifndef nitems
#define nitems(_a)	(sizeof((_a)) / sizeof((_a)[0]))
#endif

/*
 * Note that these numeric assignments differ from the numbers commonly
 * used in route origin validation context.
 */
#define	ROA_NOTFOUND		0x0	/* default */
#define	ROA_INVALID		0x1
#define	ROA_VALID		0x2
#define	ROA_MASK		0x3

#define	ASPA_UNKNOWN		0x00	/* default */
#define	ASPA_INVALID		0x01
#define	ASPA_VALID		0x02
#define	ASPA_MASK		0x03
#define	ASPA_NEVER_KNOWN	0x08	/* unknown and check never needed */

/*
 * Limit the number of messages queued in the session engine.
 * The SE will send an IMSG_XOFF messages to the RDE if the high water mark
 * is reached. The RDE should then throttle this peer or control connection.
 * Once the message queue in the SE drops below the low water mark an
 * IMSG_XON message will be sent and the RDE will produce more messages again.
 */
#define RDE_RUNNER_ROUNDS	100
#define RDE_REAPER_ROUNDS	5000
#define SESS_MSG_HIGH_MARK	2000
#define SESS_MSG_LOW_MARK	500
#define CTL_MSG_HIGH_MARK	500
#define CTL_MSG_LOW_MARK	100

enum bgpd_process {
	PROC_MAIN,
	PROC_SE,
	PROC_RDE,
	PROC_RTR,
};

enum reconf_action {
	RECONF_NONE,
	RECONF_KEEP,
	RECONF_REINIT,
	RECONF_RELOAD,
	RECONF_DELETE
};

/* Address Family Numbers as per RFC 1700 */
#define	AFI_UNSPEC	0
#define	AFI_IPv4	1
#define	AFI_IPv6	2
#define	AFI_L2VPN	25

/* Subsequent Address Family Identifier as per RFC 4760 */
#define	SAFI_NONE		0
#define	SAFI_UNICAST		1
#define	SAFI_MULTICAST		2
#define	SAFI_MPLS		4
#define	SAFI_EVPN		70	/* RFC 7432 */
#define	SAFI_MPLSVPN		128
#define	SAFI_FLOWSPEC		133
#define	SAFI_VPNFLOWSPEC	134

struct aid {
	uint16_t	 afi;
	sa_family_t	 af;
	uint8_t		 safi;
	const char	*name;
};

extern const struct aid aid_vals[];

#define	AID_UNSPEC	0
#define	AID_INET	1
#define	AID_INET6	2
#define	AID_VPN_IPv4	3
#define	AID_VPN_IPv6	4
#define	AID_FLOWSPECv4	5
#define	AID_FLOWSPECv6	6
#define	AID_EVPN	7
#define	AID_MAX		8
#define	AID_MIN		1	/* skip AID_UNSPEC since that is a dummy */

#define AID_VALS	{					\
	/* afi, af, safii, name */				\
	{ AFI_UNSPEC, AF_UNSPEC, SAFI_NONE, "unspec"},		\
	{ AFI_IPv4, AF_INET, SAFI_UNICAST, "IPv4 unicast" },	\
	{ AFI_IPv6, AF_INET6, SAFI_UNICAST, "IPv6 unicast" },	\
	{ AFI_IPv4, AF_INET, SAFI_MPLSVPN, "IPv4 vpn" },	\
	{ AFI_IPv6, AF_INET6, SAFI_MPLSVPN, "IPv6 vpn" },	\
	{ AFI_IPv4, AF_INET, SAFI_FLOWSPEC, "IPv4 flowspec" },	\
	{ AFI_IPv6, AF_INET6, SAFI_FLOWSPEC, "IPv6 flowspec" },	\
	{ AFI_L2VPN, AF_UNSPEC, SAFI_EVPN, "EVPN" },		\
}

#define BGP_MPLS_BOS	0x01
#define ESI_ADDR_LEN	10

#define EVPN_ROUTE_TYPE_2	0x02
#define EVPN_ROUTE_TYPE_3	0x03
#define EVPN_ROUTE_TYPE_5	0x05

struct evpn_addr {
	union {
		struct in_addr	v4;
		struct in6_addr	v6;
	};
	uint32_t	ethtag;
	uint8_t		mac[ETHER_ADDR_LEN];
	uint8_t		esi[ESI_ADDR_LEN];
	uint8_t		aid;
	uint8_t		type;
};

struct bgpd_addr {
	union {
		struct in_addr		v4;
		struct in6_addr		v6;
		struct evpn_addr	evpn;
		/* maximum size for a prefix is 256 bits */
	};		    /* 128-bit address */
	uint64_t	rd;		/* route distinguisher for VPN addrs */
	uint32_t	scope_id;	/* iface scope id for v6 */
	uint8_t		aid;
	uint8_t		labellen;	/* size of the labelstack */
	uint8_t		labelstack[18];	/* max that makes sense */
};

#define	DEFAULT_LISTENER	0x01
#define	LISTENER_LISTENING	0x02

struct listen_addr {
	TAILQ_ENTRY(listen_addr)	entry;
	struct sockaddr_storage		sa;
	int				fd;
	enum reconf_action		reconf;
	socklen_t			sa_len;
	uint8_t				flags;
};

TAILQ_HEAD(timer_head, timer);

TAILQ_HEAD(listen_addrs, listen_addr);
TAILQ_HEAD(filter_set_head, filter_set);

struct bitmap {
	uint64_t	data[2];
};

struct peer;
RB_HEAD(peer_head, peer);

struct l3vpn;
SIMPLEQ_HEAD(l3vpn_head, l3vpn);

struct network;
TAILQ_HEAD(network_head, network);

struct flowspec_config;
RB_HEAD(flowspec_tree, flowspec_config);

struct prefixset;
SIMPLEQ_HEAD(prefixset_head, prefixset);
struct prefixset_item;
RB_HEAD(prefixset_tree, prefixset_item);

struct tentry_v4;
struct tentry_v6;
struct trie_head {
	struct tentry_v4	*root_v4;
	struct tentry_v6	*root_v6;
	int			 match_default_v4;
	int			 match_default_v6;
	size_t			 v4_cnt;
	size_t			 v6_cnt;
};

struct rde_prefixset {
	char				name[SET_NAME_LEN];
	struct trie_head		th;
	SIMPLEQ_ENTRY(rde_prefixset)	entry;
	monotime_t			lastchange;
	int				dirty;
};
SIMPLEQ_HEAD(rde_prefixset_head, rde_prefixset);

struct roa {
	RB_ENTRY(roa)	entry;
	uint8_t		aid;
	uint8_t		prefixlen;
	uint8_t		maxlen;
	uint8_t		pad;
	uint32_t	asnum;
	time_t		expires;
	union {
		struct in_addr	inet;
		struct in6_addr	inet6;
	}		prefix;
};

RB_HEAD(roa_tree, roa);
struct aspa_set;
RB_HEAD(aspa_tree, aspa_set);

struct set_table;
struct as_set;
SIMPLEQ_HEAD(as_set_head, as_set);

struct filter_rule;
TAILQ_HEAD(filter_head, filter_rule);

struct rtr_config;
SIMPLEQ_HEAD(rtr_config_head, rtr_config);

struct bgpd_config {
	struct peer_head			 peers;
	struct l3vpn_head			 l3vpns;
	struct network_head			 networks;
	struct flowspec_tree			 flowspecs;
	struct filter_head			*filters;
	struct listen_addrs			*listen_addrs;
	struct mrt_head				*mrt;
	struct prefixset_head			 prefixsets;
	struct prefixset_head			 originsets;
	struct roa_tree				 roa;
	struct aspa_tree			 aspa;
	struct rde_prefixset_head		 rde_prefixsets;
	struct rde_prefixset_head		 rde_originsets;
	struct as_set_head			 as_sets;
	struct rtr_config_head			 rtrs;
	char					*csock;
	char					*rcsock;
	int					 flags;
	int					 log;
	u_int					 default_tableid;
	uint32_t				 bgpid;
	uint32_t				 clusterid;
	uint32_t				 as;
	uint16_t				 short_as;
	uint16_t				 holdtime;
	uint16_t				 min_holdtime;
	uint16_t				 connectretry;
	uint16_t				 staletime;
	uint8_t					 fib_priority;
	uint8_t					 filtered_in_locrib;
};

extern int cmd_opts;

enum addpath_mode {
	ADDPATH_EVAL_NONE,
	ADDPATH_EVAL_BEST,
	ADDPATH_EVAL_ECMP,
	ADDPATH_EVAL_AS_WIDE,
	ADDPATH_EVAL_ALL,
};

struct addpath_eval {
	enum addpath_mode	mode;
	int			extrapaths;
	int			maxpaths;
};

enum export_type {
	EXPORT_UNSET,
	EXPORT_NONE,
	EXPORT_DEFAULT_ROUTE
};

enum enforce_as {
	ENFORCE_AS_UNDEF,
	ENFORCE_AS_OFF,
	ENFORCE_AS_ON
};

enum role {
	ROLE_NONE,
	ROLE_CUSTOMER,
	ROLE_PROVIDER,
	ROLE_RS,
	ROLE_RS_CLIENT,
	ROLE_PEER,
};

enum auth_method {
	AUTH_NONE,
	AUTH_MD5SIG,
	AUTH_IPSEC_MANUAL_ESP,
	AUTH_IPSEC_MANUAL_AH,
	AUTH_IPSEC_IKE_ESP,
	AUTH_IPSEC_IKE_AH
};

enum auth_alg {
	AUTH_AALG_NONE,
	AUTH_AALG_SHA1HMAC,
	AUTH_AALG_MD5HMAC,
};

enum auth_enc_alg {
	AUTH_EALG_NONE,
	AUTH_EALG_3DESCBC,
	AUTH_EALG_AES,
};

struct auth_config {
	char			md5key[TCP_MD5_KEY_LEN];
	char			auth_key_in[IPSEC_AUTH_KEY_LEN];
	char			auth_key_out[IPSEC_AUTH_KEY_LEN];
	char			enc_key_in[IPSEC_ENC_KEY_LEN];
	char			enc_key_out[IPSEC_ENC_KEY_LEN];
	uint32_t		spi_in;
	uint32_t		spi_out;
	enum auth_method	method;
	enum auth_alg		auth_alg_in;
	enum auth_alg		auth_alg_out;
	enum auth_enc_alg	enc_alg_in;
	enum auth_enc_alg	enc_alg_out;
	uint8_t			md5key_len;
	uint8_t			auth_keylen_in;
	uint8_t			auth_keylen_out;
	uint8_t			enc_keylen_in;
	uint8_t			enc_keylen_out;
};

struct capabilities {
	struct {
		int16_t	timeout;	/* graceful restart timeout */
		int8_t	flags[AID_MAX];	/* graceful restart per AID flags */
		int8_t	restart;	/* graceful restart, RFC 4724 */
		int8_t	grnotification;	/* graceful notification, RFC 8538 */
	}	grestart;
	int8_t	mp[AID_MAX];		/* multiprotocol extensions, RFC 4760 */
	int8_t	add_path[AID_MAX];	/* ADD_PATH, RFC 7911 */
	int8_t	ext_nh[AID_MAX];	/* Ext Nexthop Encoding, RFC 8950 */
	int8_t	refresh;		/* route refresh, RFC 2918 */
	int8_t	as4byte;		/* 4-byte ASnum, RFC 4893 */
	int8_t	enhanced_rr;		/* enhanced route refresh, RFC 7313 */
	int8_t	policy;			/* Open Policy, RFC 9234, 2 = enforce */
	int8_t	ext_msg;		/* Extended Msg, RFC 8654 */
};

enum capa_codes {
	CAPA_NONE = 0,
	CAPA_MP = 1,
	CAPA_REFRESH = 2,
	CAPA_EXT_NEXTHOP = 5,
	CAPA_EXT_MSG = 6,
	CAPA_ROLE = 9,
	CAPA_RESTART = 64,
	CAPA_AS4BYTE = 65,
	CAPA_ADD_PATH = 69,
	CAPA_ENHANCED_RR = 70,
};

/* flags for RFC 4724 - graceful restart */
#define	CAPA_GR_PRESENT		0x01
#define	CAPA_GR_RESTART		0x02
#define	CAPA_GR_FORWARD		0x04
#define	CAPA_GR_RESTARTING	0x08
#define	CAPA_GR_TIMEMASK	0x0fff
#define	CAPA_GR_R_FLAG		0x8000
#define	CAPA_GR_N_FLAG		0x4000
#define	CAPA_GR_F_FLAG		0x80

/* flags for RFC 7911 - enhanced router refresh */
#define	CAPA_AP_RECV		0x01
#define	CAPA_AP_SEND		0x02
#define	CAPA_AP_BIDIR		0x03
#define	CAPA_AP_MASK		0x0f
#define	CAPA_AP_RECV_ENFORCE	0x10	/* internal only */
#define	CAPA_AP_SEND_ENFORCE	0x20	/* internal only */

/* values for RFC 9234 - BGP Open Policy */
#define CAPA_ROLE_PROVIDER	0x00
#define CAPA_ROLE_RS		0x01
#define CAPA_ROLE_RS_CLIENT	0x02
#define CAPA_ROLE_CUSTOMER	0x03
#define CAPA_ROLE_PEER		0x04

struct peer_config {
	struct bgpd_addr	 remote_addr;
	struct bgpd_addr	 local_addr_v4;
	struct bgpd_addr	 local_addr_v6;
	struct capabilities	 capabilities;
	struct addpath_eval	 eval;
	char			 group[PEER_DESCR_LEN];
	char			 descr[PEER_DESCR_LEN];
	char			 reason[REASON_LEN];
	char			 rib[PEER_DESCR_LEN];
	char			 if_depend[IFNAMSIZ];
	char			 demote_group[IFNAMSIZ];
	uint32_t		 id;
	uint32_t		 groupid;
	uint32_t		 remote_as;
	uint32_t		 local_as;
	uint32_t		 max_prefix;
	uint32_t		 max_out_prefix;
	enum export_type	 export_type;
	enum enforce_as		 enforce_as;
	enum enforce_as		 enforce_local_as;
	enum role		 role;
	uint16_t		 max_prefix_restart;
	uint16_t		 max_out_prefix_restart;
	uint16_t		 holdtime;
	uint16_t		 min_holdtime;
	uint16_t		 connectretry;
	uint16_t		 staletime;
	uint16_t		 local_short_as;
	uint16_t		 remote_port;
	uint8_t			 template;
	uint8_t			 remote_masklen;
	uint8_t			 ebgp;		/* 0 = ibgp else ebgp */
	uint8_t			 distance;	/* 1 = direct, >1 = multihop */
	uint8_t			 passive;
	uint8_t			 down;
	uint8_t			 reflector_client;
	uint8_t			 ttlsec;	/* TTL security hack */
	uint8_t			 flags;
};

#define	PEER_ID_NONE		0
#define	PEER_ID_SELF		1
#define	PEER_ID_STATIC_MIN	2	/* exclude self */
#define	PEER_ID_STATIC_MAX	(UINT_MAX / 2)
#define	PEER_ID_DYN_MAX		UINT_MAX

#define PEERFLAG_TRANS_AS	0x01
#define PEERFLAG_LOG_UPDATES	0x02
#define PEERFLAG_EVALUATE_ALL	0x04
#define PEERFLAG_PERMIT_AS_SET	0x08

struct rde_peer_stats {
	uint64_t			 prefix_rcvd_update;
	uint64_t			 prefix_rcvd_withdraw;
	uint64_t			 prefix_rcvd_eor;
	uint64_t			 prefix_sent_update;
	uint64_t			 prefix_sent_withdraw;
	uint64_t			 prefix_sent_eor;
	uint32_t			 prefix_cnt;
	uint32_t			 prefix_out_cnt;
	uint32_t			 pending_update;
	uint32_t			 pending_withdraw;
};

enum network_type {
	NETWORK_DEFAULT,	/* from network statements */
	NETWORK_STATIC,
	NETWORK_CONNECTED,
	NETWORK_RTLABEL,
	NETWORK_MRTCLONE,
	NETWORK_PRIORITY,
	NETWORK_PREFIXSET,
};

struct network_config {
	struct bgpd_addr	 prefix;
	struct filter_set_head	 attrset;
	char			 psname[SET_NAME_LEN];
	uint64_t		 rd;
	enum network_type	 type;
	uint16_t		 rtlabel;
	uint8_t			 prefixlen;
	uint8_t			 priority;
	uint8_t			 old;	/* used for reloading */
};

struct network {
	struct network_config	net;
	TAILQ_ENTRY(network)	entry;
};

struct flowspec {
	uint16_t		len;
	uint8_t			aid;
	uint8_t			flags;
	uint8_t			data[1];
};
#define FLOWSPEC_SIZE	(offsetof(struct flowspec, data))

struct flowspec_config {
	RB_ENTRY(flowspec_config)	 entry;
	struct filter_set_head		 attrset;
	struct flowspec			*flow;
	enum reconf_action		 reconf_action;
};

enum rtr_error {
	NO_ERROR = -1,
	CORRUPT_DATA = 0,
	INTERNAL_ERROR,
	NO_DATA_AVAILABLE,
	INVALID_REQUEST,
	UNSUPP_PROTOCOL_VERS,
	UNSUPP_PDU_TYPE,
	UNK_REC_WDRAWL,
	DUP_REC_RECV,
	UNEXP_PROTOCOL_VERS,
};

struct rtr_config {
	SIMPLEQ_ENTRY(rtr_config)	entry;
	char				descr[PEER_DESCR_LEN];
	struct auth_config		auth;
	struct bgpd_addr		remote_addr;
	struct bgpd_addr		local_addr;
	uint32_t			id;
	uint16_t			remote_port;
	uint8_t				min_version;
};

struct rtr_config_msg {
	char				descr[PEER_DESCR_LEN];
	uint8_t				min_version;
};

struct ctl_show_rtr {
	char			descr[PEER_DESCR_LEN];
	char			state[PEER_DESCR_LEN];
	char			last_sent_msg[REASON_LEN];
	char			last_recv_msg[REASON_LEN];
	struct bgpd_addr	remote_addr;
	struct bgpd_addr	local_addr;
	uint32_t		serial;
	uint32_t		refresh;
	uint32_t		retry;
	uint32_t		expire;
	int			session_id;
	enum rtr_error		last_sent_error;
	enum rtr_error		last_recv_error;
	uint16_t		remote_port;
	uint8_t			version;
	uint8_t			min_version;
};

enum imsg_type {
	IMSG_NONE,
	IMSG_CTL_END,
	IMSG_CTL_RELOAD,
	IMSG_CTL_FIB_COUPLE,
	IMSG_CTL_FIB_DECOUPLE,
	IMSG_CTL_NEIGHBOR_UP,
	IMSG_CTL_NEIGHBOR_DOWN,
	IMSG_CTL_NEIGHBOR_CLEAR,
	IMSG_CTL_NEIGHBOR_RREFRESH,
	IMSG_CTL_NEIGHBOR_DESTROY,
	IMSG_CTL_KROUTE,
	IMSG_CTL_KROUTE_ADDR,
	IMSG_CTL_RESULT,
	IMSG_CTL_SHOW_NEIGHBOR,
	IMSG_CTL_SHOW_NEXTHOP,
	IMSG_CTL_SHOW_INTERFACE,
	IMSG_CTL_SHOW_RIB,
	IMSG_CTL_SHOW_RIB_PREFIX,
	IMSG_CTL_SHOW_RIB_COMMUNITIES,
	IMSG_CTL_SHOW_RIB_ATTR,
	IMSG_CTL_SHOW_NETWORK,
	IMSG_CTL_SHOW_FLOWSPEC,
	IMSG_CTL_SHOW_RIB_MEM,
	IMSG_CTL_SHOW_TERSE,
	IMSG_CTL_SHOW_TIMER,
	IMSG_CTL_LOG_VERBOSE,
	IMSG_CTL_SHOW_FIB_TABLES,
	IMSG_CTL_SHOW_SET,
	IMSG_CTL_SHOW_RTR,
	IMSG_CTL_TERMINATE,
	IMSG_NETWORK_ADD,
	IMSG_NETWORK_ASPATH,
	IMSG_NETWORK_ATTR,
	IMSG_NETWORK_REMOVE,
	IMSG_NETWORK_FLUSH,
	IMSG_NETWORK_DONE,
	IMSG_FLOWSPEC_ADD,
	IMSG_FLOWSPEC_DONE,
	IMSG_FLOWSPEC_REMOVE,
	IMSG_FLOWSPEC_FLUSH,
	IMSG_FILTER_SET,
	IMSG_SOCKET_CONN,
	IMSG_SOCKET_CONN_CTL,
	IMSG_SOCKET_CONN_RTR,
	IMSG_SOCKET_SETUP,
	IMSG_SOCKET_TEARDOWN,
	IMSG_RECONF_CONF,
	IMSG_RECONF_RIB,
	IMSG_RECONF_PEER,
	IMSG_RECONF_PEER_AUTH,
	IMSG_RECONF_FILTER,
	IMSG_RECONF_LISTENER,
	IMSG_RECONF_CTRL,
	IMSG_RECONF_VPN,
	IMSG_RECONF_VPN_EXPORT,
	IMSG_RECONF_VPN_IMPORT,
	IMSG_RECONF_VPN_DONE,
	IMSG_RECONF_PREFIX_SET,
	IMSG_RECONF_PREFIX_SET_ITEM,
	IMSG_RECONF_AS_SET,
	IMSG_RECONF_AS_SET_ITEMS,
	IMSG_RECONF_AS_SET_DONE,
	IMSG_RECONF_ORIGIN_SET,
	IMSG_RECONF_ROA_SET,
	IMSG_RECONF_ROA_ITEM,
	IMSG_RECONF_ASPA,
	IMSG_RECONF_ASPA_TAS,
	IMSG_RECONF_ASPA_DONE,
	IMSG_RECONF_ASPA_PREP,
	IMSG_RECONF_RTR_CONFIG,
	IMSG_RECONF_DRAIN,
	IMSG_RECONF_DONE,
	IMSG_UPDATE,
	IMSG_UPDATE_ERR,
	IMSG_SESSION_ADD,
	IMSG_SESSION_UP,
	IMSG_SESSION_DOWN,
	IMSG_SESSION_DELETE,
	IMSG_SESSION_STALE,
	IMSG_SESSION_NOGRACE,
	IMSG_SESSION_FLUSH,
	IMSG_SESSION_RESTARTED,
	IMSG_SESSION_DEPENDON,
	IMSG_PFKEY_RELOAD,
	IMSG_MRT_OPEN,
	IMSG_MRT_REOPEN,
	IMSG_MRT_CLOSE,
	IMSG_KROUTE_CHANGE,
	IMSG_KROUTE_DELETE,
	IMSG_KROUTE_FLUSH,
	IMSG_NEXTHOP_ADD,
	IMSG_NEXTHOP_REMOVE,
	IMSG_NEXTHOP_UPDATE,
	IMSG_PFTABLE_ADD,
	IMSG_PFTABLE_REMOVE,
	IMSG_PFTABLE_COMMIT,
	IMSG_REFRESH,
	IMSG_DEMOTE,
	IMSG_XON,
	IMSG_XOFF
};

struct demote_msg {
	char		 demote_group[IFNAMSIZ];
	int		 level;
};

enum ctl_results {
	CTL_RES_OK,
	CTL_RES_NOSUCHPEER,
	CTL_RES_DENIED,
	CTL_RES_NOCAP,
	CTL_RES_PARSE_ERROR,
	CTL_RES_PENDING,
	CTL_RES_NOMEM,
	CTL_RES_BADPEER,
	CTL_RES_BADSTATE,
	CTL_RES_NOSUCHRIB,
	CTL_RES_OPNOTSUPP,
};

/* needed for session.h parse prototype */
LIST_HEAD(mrt_head, mrt);

/* error codes and subcodes needed in SE and RDE */
enum err_codes {
	ERR_HEADER = 1,
	ERR_OPEN,
	ERR_UPDATE,
	ERR_HOLDTIMEREXPIRED,
	ERR_FSM,
	ERR_CEASE,
	ERR_RREFRESH,
	ERR_SENDHOLDTIMEREXPIRED,
};

enum suberr_update {
	ERR_UPD_UNSPECIFIC,
	ERR_UPD_ATTRLIST,
	ERR_UPD_UNKNWN_WK_ATTR,
	ERR_UPD_MISSNG_WK_ATTR,
	ERR_UPD_ATTRFLAGS,
	ERR_UPD_ATTRLEN,
	ERR_UPD_ORIGIN,
	ERR_UPD_LOOP,
	ERR_UPD_NEXTHOP,
	ERR_UPD_OPTATTR,
	ERR_UPD_NETWORK,
	ERR_UPD_ASPATH
};

enum suberr_cease {
	ERR_CEASE_MAX_PREFIX = 1,
	ERR_CEASE_ADMIN_DOWN,
	ERR_CEASE_PEER_UNCONF,
	ERR_CEASE_ADMIN_RESET,
	ERR_CEASE_CONN_REJECT,
	ERR_CEASE_OTHER_CHANGE,
	ERR_CEASE_COLLISION,
	ERR_CEASE_RSRC_EXHAUST,
	ERR_CEASE_HARD_RESET,
	ERR_CEASE_MAX_SENT_PREFIX
};

enum suberr_rrefresh {
	ERR_RR_INV_LEN = 1
};

struct kroute;
struct kroute6;
struct knexthop;
struct kredist_node;
RB_HEAD(kroute_tree, kroute);
RB_HEAD(kroute6_tree, kroute6);
RB_HEAD(knexthop_tree, knexthop);
RB_HEAD(kredist_tree, kredist_node);

struct ktable {
	char			 descr[PEER_DESCR_LEN];
	struct kroute_tree	 krt;
	struct kroute6_tree	 krt6;
	struct knexthop_tree	 knt;
	struct kredist_tree	 kredist;
	struct network_head	 krn;
	u_int			 rtableid;
	u_int			 nhtableid; /* rdomain id for nexthop lookup */
	int			 nhrefcnt;  /* refcnt for nexthop table */
	enum reconf_action	 state;
	uint8_t			 fib_conf;  /* configured FIB sync flag */
	uint8_t			 fib_sync;  /* is FIB synced with kernel? */
};

struct kroute_full {
	struct bgpd_addr	prefix;
	struct bgpd_addr	nexthop;
	char			label[ROUTELABEL_LEN];
	uint32_t		mplslabel;
	uint16_t		flags;
	u_short			ifindex;
	uint8_t			prefixlen;
	uint8_t			priority;
};

struct kroute_nexthop {
	struct bgpd_addr	nexthop;
	struct bgpd_addr	gateway;
	struct bgpd_addr	net;
	uint8_t			netlen;
	uint8_t			valid;
	uint8_t			connected;
};

struct session_dependon {
	char			 ifname[IFNAMSIZ];
	uint8_t			 depend_state;	/* for session depend on */
};

struct session_up {
	struct bgpd_addr	local_v4_addr;
	struct bgpd_addr	local_v6_addr;
	struct bgpd_addr	remote_addr;
	struct capabilities	capa;
	uint32_t		remote_bgpid;
	unsigned int		if_scope;
	uint16_t		short_as;
};

struct route_refresh {
	uint8_t			aid;
	uint8_t			subtype;
};
#define ROUTE_REFRESH_REQUEST	0
#define ROUTE_REFRESH_BEGIN_RR	1
#define ROUTE_REFRESH_END_RR	2

struct pftable_msg {
	struct bgpd_addr	addr;
	char			pftable[PFTABLE_LEN];
	uint8_t			len;
};

struct ctl_show_interface {
	char			 ifname[IFNAMSIZ];
	char			 linkstate[32];
	char			 media[32];
	uint64_t		 baudrate;
	u_int			 rdomain;
	uint8_t			 nh_reachable;
	uint8_t			 is_up;
};

struct ctl_show_nexthop {
	struct bgpd_addr		addr;
	struct ctl_show_interface	iface;
	struct kroute_full		kr;
	uint8_t				valid;
	uint8_t				krvalid;
};

struct ctl_show_set {
	char			name[SET_NAME_LEN];
	monotime_t		lastchange;
	size_t			v4_cnt;
	size_t			v6_cnt;
	size_t			as_cnt;
	enum {
		ASNUM_SET,
		PREFIX_SET,
		ORIGIN_SET,
		ROA_SET,
		ASPA_SET,
	}			type;
};

struct ctl_neighbor {
	struct bgpd_addr	addr;
	char			descr[PEER_DESCR_LEN];
	char			reason[REASON_LEN];
	int			show_timers;
	int			is_group;
};

#define	F_PREF_ELIGIBLE	0x001
#define	F_PREF_BEST	0x002
#define	F_PREF_INTERNAL	0x004
#define	F_PREF_ANNOUNCE	0x008
#define	F_PREF_STALE	0x010
#define	F_PREF_INVALID	0x020
#define	F_PREF_PATH_ID	0x040
#define	F_PREF_OTC_LEAK	0x080
#define	F_PREF_ECMP	0x100
#define	F_PREF_AS_WIDE	0x200
#define	F_PREF_FILTERED	0x400

struct ctl_show_rib {
	struct bgpd_addr	true_nexthop;
	struct bgpd_addr	exit_nexthop;
	struct bgpd_addr	prefix;
	struct bgpd_addr	remote_addr;
	char			descr[PEER_DESCR_LEN];
	monotime_t		lastchange;
	uint32_t		remote_id;
	uint32_t		path_id;
	uint32_t		local_pref;
	uint32_t		med;
	uint32_t		weight;
	uint32_t		flags;
	uint8_t			prefixlen;
	uint8_t			origin;
	uint8_t			roa_validation_state;
	uint8_t			aspa_validation_state;
	int8_t			dmetric;
	/* plus an aspath */
};

enum as_spec {
	AS_UNDEF,
	AS_ALL,
	AS_SOURCE,
	AS_TRANSIT,
	AS_PEER,
	AS_EMPTY
};

enum aslen_spec {
	ASLEN_NONE,
	ASLEN_MAX,
	ASLEN_SEQ
};

#define AS_FLAG_NEIGHBORAS	0x01
#define AS_FLAG_AS_SET_NAME	0x02
#define AS_FLAG_AS_SET		0x04

struct filter_as {
	char		 name[SET_NAME_LEN];
	struct as_set	*aset;
	uint32_t	 as_min;
	uint32_t	 as_max;
	enum as_spec	 type;
	uint8_t		 flags;
	uint8_t		 op;
};

struct filter_aslen {
	u_int		aslen;
	enum aslen_spec	type;
};

#define PREFIXSET_FLAG_FILTER	0x01
#define PREFIXSET_FLAG_DIRTY	0x02	/* prefix-set changed at reload */
#define PREFIXSET_FLAG_OPS	0x04	/* indiv. prefixes have prefixlenops */
#define PREFIXSET_FLAG_LONGER	0x08	/* filter all prefixes with or-longer */

struct filter_prefixset {
	int			 flags;
	char			 name[SET_NAME_LEN];
	struct rde_prefixset	*ps;
};

struct filter_originset {
	char			 name[SET_NAME_LEN];
	struct rde_prefixset	*ps;
};

struct filter_vs {
	uint8_t			 validity;
	uint8_t			 is_set;
};

/*
 * Communities are encoded depending on their type. The low byte of flags
 * is the COMMUNITY_TYPE (BASIC, LARGE, EXT). BASIC encoding is just using
 * data1 and data2, LARGE uses all data fields and EXT is also using all
 * data fields. The 4-byte flags fields consists of up to 3 data flags
 * for e.g. COMMUNITY_ANY and the low byte is the community type.
 * If flags is 0 the community struct is unused. If the upper 24bit of
 * flags is 0 a fast compare can be used.
 * The code uses a type cast to uint8_t to access the type.
 */
struct community {
	uint32_t	flags;
	uint32_t	data1;
	uint32_t	data2;
	uint32_t	data3;
};

struct ctl_show_rib_request {
	char			rib[PEER_DESCR_LEN];
	struct ctl_neighbor	neighbor;
	struct bgpd_addr	prefix;
	struct filter_as	as;
	struct community	community;
	uint32_t		flags;
	uint32_t		path_id;
	pid_t			pid;
	enum imsg_type		type;
	uint8_t			validation_state;
	uint8_t			prefixlen;
	uint8_t			aid;
};

struct ctl_kroute_req {
	int			flags;
	sa_family_t		af;
};

enum filter_actions {
	ACTION_NONE,
	ACTION_ALLOW,
	ACTION_DENY
};

enum directions {
	DIR_IN = 1,
	DIR_OUT
};

enum from_spec {
	FROM_ALL,
	FROM_ADDRESS,
	FROM_DESCR,
	FROM_GROUP
};

enum comp_ops {
	OP_NONE,
	OP_RANGE,
	OP_XRANGE,
	OP_EQ,
	OP_NE,
	OP_LE,
	OP_LT,
	OP_GE,
	OP_GT
};

struct filter_peers {
	uint32_t	peerid;
	uint32_t	groupid;
	uint32_t	remote_as;
	uint16_t	ribid;
	uint8_t		ebgp;
	uint8_t		ibgp;
};

/* special community type, keep in sync with the attribute type */
#define	COMMUNITY_TYPE_NONE		0
#define	COMMUNITY_TYPE_BASIC		8
#define	COMMUNITY_TYPE_EXT		16
#define	COMMUNITY_TYPE_LARGE		32

#define	COMMUNITY_ANY			1
#define	COMMUNITY_NEIGHBOR_AS		2
#define	COMMUNITY_LOCAL_AS		3

/* wellknown community definitions */
#define	COMMUNITY_WELLKNOWN		0xffff
#define	COMMUNITY_GRACEFUL_SHUTDOWN	0x0000  /* RFC 8326 */
#define	COMMUNITY_BLACKHOLE		0x029A	/* RFC 7999 */
#define	COMMUNITY_NO_EXPORT		0xff01
#define	COMMUNITY_NO_ADVERTISE		0xff02
#define	COMMUNITY_NO_EXPSUBCONFED	0xff03
#define	COMMUNITY_NO_PEER		0xff04	/* RFC 3765 */

/* extended community definitions */
#define EXT_COMMUNITY_IANA		0x80
#define EXT_COMMUNITY_NON_TRANSITIVE	0x40
#define EXT_COMMUNITY_VALUE		0x3f
/* extended transitive types */
#define EXT_COMMUNITY_TRANS_TWO_AS	0x00	/* 2 octet AS specific */
#define EXT_COMMUNITY_TRANS_IPV4	0x01	/* IPv4 specific */
#define EXT_COMMUNITY_TRANS_FOUR_AS	0x02	/* 4 octet AS specific */
#define EXT_COMMUNITY_TRANS_OPAQUE	0x03	/* opaque ext community */
#define EXT_COMMUNITY_TRANS_EVPN	0x06	/* EVPN RFC 7432 */
/* extended non-transitive types */
#define EXT_COMMUNITY_NON_TRANS_TWO_AS	0x40	/* 2 octet AS specific */
#define EXT_COMMUNITY_NON_TRANS_IPV4	0x41	/* IPv4 specific */
#define EXT_COMMUNITY_NON_TRANS_FOUR_AS	0x42	/* 4 octet AS specific */
#define EXT_COMMUNITY_NON_TRANS_OPAQUE	0x43	/* opaque ext community */
#define EXT_COMMUNITY_UNKNOWN		-1
/* generic transitive types */
#define EXT_COMMUNITY_GEN_TWO_AS	0x80	/* 2 octet AS specific */
#define EXT_COMMUNITY_GEN_IPV4		0x81	/* IPv4 specific */
#define EXT_COMMUNITY_GEN_FOUR_AS	0x82	/* 4 octet AS specific */

/* BGP Origin Validation State Extended Community RFC 8097 */
#define EXT_COMMUNITY_SUBTYPE_OVS	0
#define EXT_COMMUNITY_OVS_VALID		0
#define EXT_COMMUNITY_OVS_NOTFOUND	1
#define EXT_COMMUNITY_OVS_INVALID	2

/* other handy defines */
#define EXT_COMMUNITY_OPAQUE_MAX	0xffffffffffffULL
#define EXT_COMMUNITY_FLAG_VALID	0x01

struct ext_comm_pairs {
	uint8_t		type;
	uint8_t		subtype;
	const char	*subname;
};

#define IANA_EXT_COMMUNITIES	{				\
	{ EXT_COMMUNITY_TRANS_TWO_AS, 0x02, "rt" },		\
	{ EXT_COMMUNITY_TRANS_TWO_AS, 0x03, "soo" },		\
	{ EXT_COMMUNITY_TRANS_TWO_AS, 0x05, "odi" },		\
	{ EXT_COMMUNITY_TRANS_TWO_AS, 0x08, "bdc" },		\
	{ EXT_COMMUNITY_TRANS_TWO_AS, 0x09, "srcas" },		\
	{ EXT_COMMUNITY_TRANS_TWO_AS, 0x0a, "l2vid" },		\
								\
	{ EXT_COMMUNITY_TRANS_FOUR_AS, 0x02, "rt" },		\
	{ EXT_COMMUNITY_TRANS_FOUR_AS, 0x03, "soo" },		\
	{ EXT_COMMUNITY_TRANS_FOUR_AS, 0x05, "odi" },		\
	{ EXT_COMMUNITY_TRANS_FOUR_AS, 0x08, "bdc" },		\
	{ EXT_COMMUNITY_TRANS_FOUR_AS, 0x09, "srcas" },		\
								\
	{ EXT_COMMUNITY_TRANS_IPV4, 0x02, "rt" },		\
	{ EXT_COMMUNITY_TRANS_IPV4, 0x03, "soo" },		\
	{ EXT_COMMUNITY_TRANS_IPV4, 0x05, "odi" },		\
	{ EXT_COMMUNITY_TRANS_IPV4, 0x07, "ori" },		\
	{ EXT_COMMUNITY_TRANS_IPV4, 0x0a, "l2vid" },		\
	{ EXT_COMMUNITY_TRANS_IPV4, 0x0b, "vrfri" },		\
								\
	{ EXT_COMMUNITY_TRANS_OPAQUE, 0x06, "ort" },		\
	{ EXT_COMMUNITY_TRANS_OPAQUE, 0x0c, "encap" },		\
	{ EXT_COMMUNITY_TRANS_OPAQUE, 0x0d, "defgw" },		\
								\
	{ EXT_COMMUNITY_NON_TRANS_OPAQUE, EXT_COMMUNITY_SUBTYPE_OVS, "ovs" }, \
								\
	{ EXT_COMMUNITY_TRANS_EVPN, 0x00, "mac-mob" },		\
	{ EXT_COMMUNITY_TRANS_EVPN, 0x01, "esi-lab" },		\
	{ EXT_COMMUNITY_TRANS_EVPN, 0x02, "esi-rt" },		\
								\
	{ EXT_COMMUNITY_GEN_TWO_AS, 0x06, "flow-rate" },	\
	{ EXT_COMMUNITY_GEN_TWO_AS, 0x0c, "flow-pps" },		\
	{ EXT_COMMUNITY_GEN_TWO_AS, 0x07, "flow-action" },	\
	{ EXT_COMMUNITY_GEN_TWO_AS, 0x08, "flow-rt-redir" },	\
	{ EXT_COMMUNITY_GEN_IPV4,   0x08, "flow-rt-redir" },	\
	{ EXT_COMMUNITY_GEN_FOUR_AS, 0x08, "flow-rt-redir" },	\
	{ EXT_COMMUNITY_GEN_TWO_AS, 0x09, "flow-dscp" },	\
								\
	{ 0 }							\
}

extern const struct ext_comm_pairs iana_ext_comms[];

/* BGP flowspec defines RFC 8955 and 8956 */
#define FLOWSPEC_LEN_LIMIT	0xf0
#define FLOWSPEC_OP_EOL		0x80
#define FLOWSPEC_OP_AND		0x40
#define FLOWSPEC_OP_LEN_MASK	0x30
#define FLOWSPEC_OP_LEN_SHIFT	4
#define FLOWSPEC_OP_LEN(op)					\
	(1 << (((op) & FLOWSPEC_OP_LEN_MASK) >> FLOWSPEC_OP_LEN_SHIFT))
#define FLOWSPEC_OP_NUM_LT	0x04
#define FLOWSPEC_OP_NUM_GT	0x02
#define FLOWSPEC_OP_NUM_EQ	0x01
#define FLOWSPEC_OP_NUM_LE	(FLOWSPEC_OP_NUM_LT | FLOWSPEC_OP_NUM_EQ)
#define FLOWSPEC_OP_NUM_GE	(FLOWSPEC_OP_NUM_GT | FLOWSPEC_OP_NUM_EQ)
#define FLOWSPEC_OP_NUM_NOT	(FLOWSPEC_OP_NUM_GT | FLOWSPEC_OP_NUM_LT)
#define FLOWSPEC_OP_NUM_MASK	0x07
#define FLOWSPEC_OP_BIT_NOT	0x02
#define FLOWSPEC_OP_BIT_MATCH	0x01
#define FLOWSPEC_OP_BIT_MASK	0x03

#define FLOWSPEC_TYPE_MIN		1
#define FLOWSPEC_TYPE_DEST		1
#define FLOWSPEC_TYPE_SOURCE		2
#define FLOWSPEC_TYPE_PROTO		3
#define FLOWSPEC_TYPE_PORT		4
#define FLOWSPEC_TYPE_DST_PORT		5
#define FLOWSPEC_TYPE_SRC_PORT		6
#define FLOWSPEC_TYPE_ICMP_TYPE		7
#define FLOWSPEC_TYPE_ICMP_CODE		8
#define FLOWSPEC_TYPE_TCP_FLAGS		9
#define FLOWSPEC_TYPE_PKT_LEN		10
#define FLOWSPEC_TYPE_DSCP		11
#define FLOWSPEC_TYPE_FRAG		12
#define FLOWSPEC_TYPE_FLOW		13
#define FLOWSPEC_TYPE_MAX		14

#define FLOWSPEC_TCP_FLAG_STRING	"FSRPAUEW"
#define FLOWSPEC_FRAG_STRING4		"DIFL"
#define FLOWSPEC_FRAG_STRING6		" IFL"

struct filter_prefix {
	struct bgpd_addr	addr;
	uint8_t			op;
	uint8_t			len;
	uint8_t			len_min;
	uint8_t			len_max;
};

struct filter_nexthop {
	struct bgpd_addr	addr;
	uint8_t			flags;
#define FILTER_NEXTHOP_ADDR	1
#define FILTER_NEXTHOP_NEIGHBOR	2
};

struct filter_match {
	struct filter_prefix		prefix;
	struct filter_nexthop		nexthop;
	struct filter_as		as;
	struct filter_aslen		aslen;
	struct community		community[MAX_COMM_MATCH];
	struct filter_prefixset		prefixset;
	struct filter_originset		originset;
	struct filter_vs		ovs;
	struct filter_vs		avs;
	int				maxcomm;
	int				maxextcomm;
	int				maxlargecomm;
};

struct filter_rule {
	TAILQ_ENTRY(filter_rule)	entry;
	char				rib[PEER_DESCR_LEN];
	struct filter_peers		peer;
	struct filter_match		match;
	struct filter_set_head		set;
#define RDE_FILTER_SKIP_PEERID		0
#define RDE_FILTER_SKIP_GROUPID		1
#define RDE_FILTER_SKIP_REMOTE_AS	2
#define RDE_FILTER_SKIP_COUNT		3
	struct filter_rule		*skip[RDE_FILTER_SKIP_COUNT];
	enum filter_actions		action;
	enum directions			dir;
	uint8_t				quick;
};

enum action_types {
	ACTION_SET_LOCALPREF,
	ACTION_SET_RELATIVE_LOCALPREF,
	ACTION_SET_MED,
	ACTION_SET_RELATIVE_MED,
	ACTION_SET_WEIGHT,
	ACTION_SET_RELATIVE_WEIGHT,
	ACTION_SET_PREPEND_SELF,
	ACTION_SET_PREPEND_PEER,
	ACTION_SET_AS_OVERRIDE,
	ACTION_SET_NEXTHOP,
	ACTION_SET_NEXTHOP_REF,
	ACTION_SET_NEXTHOP_REJECT,
	ACTION_SET_NEXTHOP_BLACKHOLE,
	ACTION_SET_NEXTHOP_NOMODIFY,
	ACTION_SET_NEXTHOP_SELF,
	ACTION_DEL_COMMUNITY,
	ACTION_SET_COMMUNITY,
	ACTION_PFTABLE,
	ACTION_PFTABLE_ID,
	ACTION_RTLABEL,
	ACTION_RTLABEL_ID,
	ACTION_SET_ORIGIN
};

struct nexthop;
struct filter_set {
	TAILQ_ENTRY(filter_set)		entry;
	enum action_types		type;
	union {
		uint8_t				 prepend;
		uint8_t				 origin;
		uint16_t			 id;
		uint32_t			 metric;
		int32_t				 relative;
		struct nexthop			*nh_ref;
		struct community		 community;
		struct bgpd_addr		 nexthop;
		char				 pftable[PFTABLE_LEN];
		char				 rtlabel[ROUTELABEL_LEN];
	}				action;
};

struct roa_set {
	uint32_t	as;	/* must be first */
	uint32_t	maxlen;	/* change type for better struct layout */
};

struct prefixset_item {
	struct filter_prefix		p;
	RB_ENTRY(prefixset_item)	entry;
};

struct prefixset {
	int				 sflags;
	char				 name[SET_NAME_LEN];
	struct prefixset_tree		 psitems;
	struct roa_tree			 roaitems;
	SIMPLEQ_ENTRY(prefixset)	 entry;
};

struct as_set {
	char				 name[SET_NAME_LEN];
	SIMPLEQ_ENTRY(as_set)		 entry;
	struct set_table		*set;
	monotime_t			 lastchange;
	int				 dirty;
};

struct aspa_set {
	time_t				 expires;
	uint32_t			 as;
	uint32_t			 num;
	uint32_t			 *tas;
	RB_ENTRY(aspa_set)		 entry;
};

struct aspa_prep {
	size_t				datasize;
	uint32_t			entries;
};

struct l3vpn {
	SIMPLEQ_ENTRY(l3vpn)		entry;
	char				descr[PEER_DESCR_LEN];
	char				ifmpe[IFNAMSIZ];
	struct filter_set_head		import;
	struct filter_set_head		export;
	struct network_head		net_l;
	uint64_t			rd;
	u_int				rtableid;
	u_int				label;
	int				flags;
};

struct rde_rib {
	SIMPLEQ_ENTRY(rde_rib)	entry;
	char			name[PEER_DESCR_LEN];
	u_int			rtableid;
	uint16_t		id;
	uint16_t		flags;
};
SIMPLEQ_HEAD(rib_names, rde_rib);
extern struct rib_names ribnames;

/* rde_rib flags */
#define F_RIB_LOCAL		0x0001
#define F_RIB_NOEVALUATE	0x0002
#define F_RIB_NOFIB		0x0004
#define F_RIB_NOFIBSYNC		0x0008

/* 4-byte magic AS number */
#define AS_TRANS	23456
/* AS_NONE for origin validation */
#define AS_NONE		0

struct rde_memstats {
	long long	path_cnt;
	long long	path_refs;
	long long	prefix_cnt;
	long long	adjout_prefix_cnt;
	long long	adjout_prefix_size;
	long long	pend_prefix_cnt;
	long long	pend_attr_cnt;
	long long	rib_cnt;
	long long	pt_cnt[AID_MAX];
	long long	pt_size[AID_MAX];
	long long	nexthop_cnt;
	long long	aspath_cnt;
	long long	aspath_size;
	long long	comm_cnt;
	long long	comm_nmemb;
	long long	comm_size;
	long long	comm_refs;
	long long	attr_cnt;
	long long	attr_refs;
	long long	attr_data;
	long long	attr_dcnt;
	long long	adjout_attr_cnt;
	long long	adjout_attr_refs;
	long long	aset_cnt;
	long long	aset_size;
	long long	aset_nmemb;
	long long	pset_cnt;
	long long	pset_size;
	long long	rde_event_loop_count;
	long long	rde_event_loop_usec;
	long long	rde_event_io_usec;
	long long	rde_event_peer_usec;
	long long	rde_event_adjout_usec;
	long long	rde_event_ribdump_usec;
	long long	rde_event_nexthop_usec;
	long long	rde_event_update_usec;
};

#define	MRT_FILE_LEN	512
#define	MRT2MC(x)	((struct mrt_config *)(x))

enum mrt_type {
	MRT_NONE,
	MRT_TABLE_DUMP,
	MRT_TABLE_DUMP_MP,
	MRT_TABLE_DUMP_V2,
	MRT_ALL_IN,
	MRT_ALL_OUT,
	MRT_UPDATE_IN,
	MRT_UPDATE_OUT
};

enum mrt_state {
	MRT_STATE_RUNNING,
	MRT_STATE_OPEN,
	MRT_STATE_REOPEN,
	MRT_STATE_REMOVE
};

struct mrt {
	char			rib[PEER_DESCR_LEN];
	LIST_ENTRY(mrt)		entry;
	struct msgbuf		*wbuf;
	uint32_t		peer_id;
	uint32_t		group_id;
	int			fd;
	enum mrt_type		type;
	enum mrt_state		state;
	uint16_t		seqnum;
};

struct mrt_config {
	struct mrt		conf;
	char			name[MRT_FILE_LEN];	/* base file name */
	char			file[MRT_FILE_LEN];	/* actual file name */
	struct timer_head	timer;
	int			ReopenTimerInterval;
};

/* prototypes */
/* bgpd.c */
struct pollfd;
void		 send_nexthop_update(struct kroute_nexthop *);
void		 send_imsg_session(int, pid_t, void *, uint16_t);
int		 send_network(int, struct network_config *,
		    struct filter_set_head *);
int		 bgpd_oknexthop(struct kroute_full *);
int		 bgpd_has_bgpnh(void);
void		 set_pollfd(struct pollfd *, struct imsgbuf *);
int		 handle_pollfd(struct pollfd *, struct imsgbuf *);

/* control.c */
int	control_imsg_relay(struct imsg *, struct peer *);

/* config.c */
struct bgpd_config	*new_config(void);
void		copy_config(struct bgpd_config *, struct bgpd_config *);
void		network_free(struct network *);
struct flowspec_config	*flowspec_alloc(uint8_t, int);
void		flowspec_free(struct flowspec_config *);
void		free_l3vpns(struct l3vpn_head *);
void		free_config(struct bgpd_config *);
void		free_prefixsets(struct prefixset_head *);
void		free_rde_prefixsets(struct rde_prefixset_head *);
void		free_prefixtree(struct prefixset_tree *);
void		free_roatree(struct roa_tree *);
void		free_aspa(struct aspa_set *);
void		free_aspatree(struct aspa_tree *);
void		free_rtrs(struct rtr_config_head *);
void		filterlist_free(struct filter_head *);
int		host(const char *, struct bgpd_addr *, uint8_t *);
uint32_t	get_bgpid(void);
void		expand_networks(struct bgpd_config *, struct network_head *);
RB_PROTOTYPE(prefixset_tree, prefixset_item, entry, prefixset_cmp);
RB_PROTOTYPE(roa_tree, roa, entry, roa_cmp);
RB_PROTOTYPE(aspa_tree, aspa_set, entry, aspa_cmp);
RB_PROTOTYPE(flowspec_tree, flowspec_config, entry, flowspec_config_cmp);

/* kroute.c */
int		 kr_init(int *, uint8_t);
int		 kr_default_prio(void);
int		 kr_check_prio(long long);
int		 ktable_update(u_int, char *, int);
void		 ktable_preload(void);
void		 ktable_postload(void);
int		 ktable_exists(u_int, u_int *);
int		 kr_change(u_int, struct kroute_full *);
int		 kr_delete(u_int, struct kroute_full *);
int		 kr_flush(u_int);
void		 kr_shutdown(void);
void		 kr_fib_couple(u_int);
void		 kr_fib_couple_all(void);
void		 kr_fib_decouple(u_int);
void		 kr_fib_decouple_all(void);
void		 kr_fib_prio_set(uint8_t);
int		 kr_dispatch_msg(void);
int		 kr_nexthop_add(uint32_t, struct bgpd_addr *);
void		 kr_nexthop_delete(uint32_t, struct bgpd_addr *);
void		 kr_show_route(struct imsg *);
void		 kr_ifinfo(char *);
void		 kr_net_reload(u_int, uint64_t, struct network_head *);
int		 kr_reload(void);
int		 get_mpe_config(const char *, u_int *, u_int *);
uint8_t		 mask2prefixlen(sa_family_t, struct sockaddr *);

/* log.c */
void		 log_peer_info(const struct peer_config *, const char *, ...)
			__attribute__((__format__ (printf, 2, 3)));
void		 log_peer_warn(const struct peer_config *, const char *, ...)
			__attribute__((__format__ (printf, 2, 3)));
void		 log_peer_warnx(const struct peer_config *, const char *, ...)
			__attribute__((__format__ (printf, 2, 3)));

/* mrt.c */
void		 mrt_write(struct mrt *);
void		 mrt_clean(struct mrt *);
void		 mrt_init(struct imsgbuf *, struct imsgbuf *);
monotime_t	 mrt_timeout(struct mrt_head *, monotime_t);
void		 mrt_reconfigure(struct mrt_head *);
void		 mrt_handler(struct mrt_head *);
struct mrt	*mrt_get(struct mrt_head *, struct mrt *);
void		 mrt_mergeconfig(struct mrt_head *, struct mrt_head *);

/* name2id.c */
uint16_t	 rtlabel_name2id(const char *);
const char	*rtlabel_id2name(uint16_t);
void		 rtlabel_unref(uint16_t);
uint16_t	 rtlabel_ref(uint16_t);
uint16_t	 pftable_name2id(const char *);
const char	*pftable_id2name(uint16_t);
void		 pftable_unref(uint16_t);
uint16_t	 pftable_ref(uint16_t);

/* parse.y */
int			cmdline_symset(char *);
struct prefixset	*find_prefixset(char *, struct prefixset_head *);
struct bgpd_config	*parse_config(const char *, struct peer_head *,
			    struct rtr_config_head *);

/* pftable.c */
int	pftable_exists(const char *);
int	pftable_add(const char *);
int	pftable_clear_all(void);
int	pftable_addr_add(struct pftable_msg *);
int	pftable_addr_remove(struct pftable_msg *);
int	pftable_commit(void);

/* rde_filter.c */
void	filterset_free(struct filter_set_head *);
int	filterset_cmp(struct filter_set *, struct filter_set *);
void	filterset_move(struct filter_set_head *, struct filter_set_head *);
void	filterset_copy(struct filter_set_head *, struct filter_set_head *);
const char	*filterset_name(enum action_types);
int	filterset_send(struct imsgbuf *, struct filter_set_head *);
void	filterset_recv(struct imsg *, struct filter_set_head *);

/* bitmap.c */
int		 bitmap_set(struct bitmap *, uint32_t);
int		 bitmap_test(struct bitmap *, uint32_t);
void		 bitmap_clear(struct bitmap *, uint32_t);
int		 bitmap_empty(struct bitmap *);

int		 bitmap_id_get(struct bitmap *, uint32_t *);
void		 bitmap_id_put(struct bitmap *, uint32_t);

void		 bitmap_init(struct bitmap *);
void		 bitmap_reset(struct bitmap *);

/* rde_sets.c */
struct as_set	*as_sets_lookup(struct as_set_head *, const char *);
struct as_set	*as_sets_new(struct as_set_head *, const char *, size_t,
		    size_t);
void		 as_sets_free(struct as_set_head *);
void		 as_sets_mark_dirty(struct as_set_head *, struct as_set_head *);
int		 as_set_match(const struct as_set *, uint32_t);

struct set_table	*set_new(size_t, size_t);
void			 set_free(struct set_table *);
int			 set_add(struct set_table *, void *, size_t);
void			*set_get(struct set_table *, size_t *);
void			 set_prep(struct set_table *);
void			*set_match(const struct set_table *, uint32_t);
int			 set_equal(const struct set_table *,
			    const struct set_table *);
size_t			 set_nmemb(const struct set_table *);

/* rde_trie.c */
int	trie_add(struct trie_head *, struct bgpd_addr *, uint8_t, uint8_t,
	    uint8_t);
int	trie_roa_add(struct trie_head *, struct roa *);
void	trie_free(struct trie_head *);
int	trie_match(struct trie_head *, struct bgpd_addr *, uint8_t, int);
int	trie_roa_check(struct trie_head *, struct bgpd_addr *, uint8_t,
	    uint32_t);
void	trie_dump(struct trie_head *);
int	trie_equal(struct trie_head *, struct trie_head *);

/* util.c */
const char	*log_addr(const struct bgpd_addr *);
const char	*log_evpnaddr(const struct bgpd_addr *, struct sockaddr *,
		    socklen_t);
const char	*log_in6addr(const struct in6_addr *);
const char	*log_sockaddr(struct sockaddr *, socklen_t);
const char	*log_as(uint32_t);
const char	*log_rd(uint64_t);
const char	*log_ext_subtype(int, uint8_t);
const char	*log_reason(const char *);
const char	*log_aspath_error(int);
const char	*log_roa(struct roa *);
const char	*log_aspa(struct aspa_set *);
const char	*log_rtr_error(enum rtr_error);
const char	*log_policy(enum role);
const char	*log_capability(uint8_t);
int		 aspath_asprint(char **, struct ibuf *);
uint32_t	 aspath_extract(const void *, int);
int		 aspath_verify(struct ibuf *, int, int);
#define		 AS_ERR_LEN	-1
#define		 AS_ERR_TYPE	-2
#define		 AS_ERR_BAD	-3
#define		 AS_ERR_SOFT	-4
struct ibuf	*aspath_inflate(struct ibuf *);
int		 extract_prefix(const u_char *, int, void *, uint8_t, uint8_t);
int		 nlri_get_prefix(struct ibuf *, struct bgpd_addr *, uint8_t *);
int		 nlri_get_prefix6(struct ibuf *, struct bgpd_addr *, uint8_t *);
int		 nlri_get_vpn4(struct ibuf *, struct bgpd_addr *, uint8_t *,
		    int);
int		 nlri_get_vpn6(struct ibuf *, struct bgpd_addr *, uint8_t *,
		    int);
int		 nlri_get_evpn(struct ibuf *, struct bgpd_addr *, uint8_t *);
int		 prefix_compare(const struct bgpd_addr *,
		    const struct bgpd_addr *, int);
void		 inet4applymask(struct in_addr *, const struct in_addr *, int);
void		 inet6applymask(struct in6_addr *, const struct in6_addr *,
		    int);
void		 applymask(struct bgpd_addr *, const struct bgpd_addr *, int);
const char	*aid2str(uint8_t);
int		 aid2afi(uint8_t, uint16_t *, uint8_t *);
int		 afi2aid(uint16_t, uint8_t, uint8_t *);
sa_family_t	 aid2af(uint8_t);
int		 af2aid(sa_family_t, uint8_t, uint8_t *);
struct sockaddr	*addr2sa(const struct bgpd_addr *, uint16_t, socklen_t *);
void		 sa2addr(struct sockaddr *, struct bgpd_addr *, uint16_t *);
const char	*get_baudrate(unsigned long long, char *);

unsigned int	 bin_of_attrs(unsigned int);
unsigned int	 bin_of_communities(unsigned int);
unsigned int	 bin_of_adjout_prefixes(unsigned int);

/* flowspec.c */
int	flowspec_valid(const uint8_t *, int, int);
int	flowspec_cmp(const uint8_t *, int, const uint8_t *, int, int);
int	flowspec_get_component(const uint8_t *, int, int, int,
	    const uint8_t **, int *);
int	flowspec_get_addr(const uint8_t *, int, int, int, struct bgpd_addr *,
	    uint8_t *, uint8_t *);
const char	*flowspec_fmt_label(int);
const char	*flowspec_fmt_num_op(const uint8_t *, int, int *);
const char	*flowspec_fmt_bin_op(const uint8_t *, int, int *, const char *);

static const char * const log_procnames[] = {
	"parent",
	"SE",
	"RDE",
	"RTR"
};

/* logmsg.c and needed by bgpctl */
static const char * const statenames[] = {
	"None",
	"Idle",
	"Connect",
	"Active",
	"OpenSent",
	"OpenConfirm",
	"Established"
};

static const char * const msgtypenames[] = {
	"NONE",
	"OPEN",
	"UPDATE",
	"NOTIFICATION",
	"KEEPALIVE",
	"RREFRESH"
};

static const char * const eventnames[] = {
	"None",
	"Start",
	"Stop",
	"Connection opened",
	"Connection closed",
	"Connection open failed",
	"Fatal error",
	"ConnectRetryTimer expired",
	"HoldTimer expired",
	"KeepaliveTimer expired",
	"SendHoldTimer expired",
	"OPEN message received",
	"KEEPALIVE message received",
	"UPDATE message received",
	"NOTIFICATION received",
	"graceful NOTIFICATION received",
};

static const char * const errnames[] = {
	"none",
	"Header error",
	"error in OPEN message",
	"error in UPDATE message",
	"HoldTimer expired",
	"Finite State Machine error",
	"Cease",
	"error in ROUTE-REFRESH message"
};

static const char * const suberr_header_names[] = {
	"none",
	"synchronization error",
	"wrong length",
	"unknown message type"
};

static const char * const suberr_open_names[] = {
	"none",
	"version mismatch",
	"AS unacceptable",
	"BGPID invalid",
	"optional parameter error",
	"authentication error",
	"unacceptable holdtime",
	"unsupported capability",
	NULL,
	NULL,
	NULL,
	"role mismatch",
};

static const char * const suberr_fsm_names[] = {
	"unspecified error",
	"received unexpected message in OpenSent",
	"received unexpected message in OpenConfirm",
	"received unexpected message in Established"
};

static const char * const suberr_update_names[] = {
	"none",
	"attribute list error",
	"unknown well-known attribute",
	"well-known attribute missing",
	"attribute flags error",
	"attribute length wrong",
	"origin unacceptable",
	"loop detected",
	"nexthop unacceptable",
	"optional attribute error",
	"network unacceptable",
	"AS-Path unacceptable"
};

static const char * const suberr_cease_names[] = {
	"none",
	"received max-prefix exceeded",
	"administratively down",
	"peer unconfigured",
	"administrative reset",
	"connection rejected",
	"other config change",
	"collision",
	"resource exhaustion",
	"hard reset",
	"sent max-prefix exceeded"
};

static const char * const suberr_rrefresh_names[] = {
	"none",
	"invalid message length"
};

static const char * const ctl_res_strerror[] = {
	"no error",
	"no such neighbor",
	"permission denied",
	"neighbor does not have this capability",
	"config file has errors, reload failed",
	"previous reload still running",
	"out of memory",
	"not a cloned peer",
	"peer still active, down peer first",
	"no such RIB",
	"operation not supported",
};

static const char * const timernames[] = {
	"None",
	"ConnectRetryTimer",
	"KeepaliveTimer",
	"HoldTimer",
	"SendHoldTimer",
	"IdleHoldTimer",
	"IdleHoldResetTimer",
	"CarpUndemoteTimer",
	"RestartTimer",
	"SessionDownTimer",
	"RTR RefreshTimer",
	"RTR RetryTimer",
	"RTR ExpireTimer",
	"RTR ActiveTimer",
	"MRT ReopenTimer",
	""
};

#endif /* __BGPD_H__ */
