d62a17aedeb0eebdba98238874bb13d62c48dbf9
c14777c6bfd0a446c85243d3a9835054a259c276
996c93142d3abfab0f6d6c800474e22a8cfbdbc5
+# require semicolon after macro XYZ
+67b0f40c98aeb9bbc95370fe2be29e56a00a8748
+80413c2073a20774b264ab04f7a4ea4515699790
+960b9a53837d1aefa16bd531c7087f800dbe147b
+96244aca23adec551c29b78f26605f8af8eea53e
+8451921b70044a2c1075e7ba391f095fabee2550
+bf8d3d6aca3f20255a621ed1c148fd05b3a8ae5c
/libtool
/libtool.orig
/changelog-auto
+/test-driver
/Makefile
/Makefile.in
include yang/subdir.am
include yang/libyang_plugins/subdir.am
include vrrpd/subdir.am
+include pceplib/subdir.am
+include pceplib/test/subdir.am
include pathd/subdir.am
include vtysh/subdir.am
#include "xroute.h"
#include "babel_errors.h"
-DEFINE_MTYPE_STATIC(BABELD, BABEL_IF, "Babel Interface")
+DEFINE_MTYPE_STATIC(BABELD, BABEL_IF, "Babel Interface");
#define IS_ENABLE(ifp) (babel_enable_if_lookup(ifp->name) >= 0)
.yang_modules = babeld_yang_modules,
.n_yang_modules = array_size(babeld_yang_modules),
- )
+);
int
main(int argc, char **argv)
#include "babel_zebra.h"
#include "babel_errors.h"
-DEFINE_MGROUP(BABELD, "babeld")
-DEFINE_MTYPE_STATIC(BABELD, BABEL, "Babel Structure")
+DEFINE_MGROUP(BABELD, "babeld");
+DEFINE_MTYPE_STATIC(BABELD, BABEL, "Babel Structure");
static int babel_init_routing_process(struct thread *thread);
static void babel_get_myid(void);
#define MAX(x,y) ((x)<=(y)?(y):(x))
#define MIN(x,y) ((x)<=(y)?(x):(y))
-#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
-/* nothing */
-#elif defined(__GNUC__)
-#define inline __inline
-#if (__GNUC__ >= 3)
-#define restrict __restrict
-#else
-#define restrict /**/
-#endif
-#else
-#define inline /**/
-#define restrict /**/
-#endif
-
#if defined(__GNUC__) && (__GNUC__ >= 3)
#define ATTRIBUTE(x) __attribute__ (x)
#define LIKELY(_x) __builtin_expect(!!(_x), 1)
#include "log.h"
#include "memory.h"
-DECLARE_MGROUP(BABELD)
+DECLARE_MGROUP(BABELD);
#if defined(i386) || defined(__mc68020__) || defined(__x86_64__)
#define DO_NTOHS(_d, _s) do{ _d = ntohs(*(const unsigned short*)(_s)); }while(0)
vararg macros are not portable. */
#if defined NO_DEBUG
-#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
#define debugf(...) do {} while(0)
-#elif defined __GNUC__
-#define debugf(_args...) do {} while(0)
-#else
-static inline void debugf(int level, const char *format, ...) { return; }
-#endif
#else /* NO_DEBUG */
#define BABEL_DEBUG_ROUTE (1 << 5)
#define BABEL_DEBUG_ALL (0xFFFF)
-#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
#define debugf(level, ...) \
do { \
if(UNLIKELY(debug & level)) zlog_debug(__VA_ARGS__); \
} while(0)
-#elif defined __GNUC__
-#define debugf(level, _args...) \
-do { \
-if(UNLIKELY(debug & level)) zlog_debug(_args); \
-} while(0)
-#else
-static inline void debugf(int level, const char *format, ...) { return; }
-#endif
#endif /* NO_DEBUG */
#include "bfd.h"
-DEFINE_MTYPE_STATIC(BFDD, BFDD_CONFIG, "long-lived configuration memory")
-DEFINE_MTYPE_STATIC(BFDD, BFDD_PROFILE, "long-lived profile memory")
-DEFINE_MTYPE_STATIC(BFDD, BFDD_SESSION_OBSERVER, "Session observer")
-DEFINE_MTYPE_STATIC(BFDD, BFDD_VRF, "BFD VRF")
+DEFINE_MTYPE_STATIC(BFDD, BFDD_CONFIG, "long-lived configuration memory");
+DEFINE_MTYPE_STATIC(BFDD, BFDD_PROFILE, "long-lived profile memory");
+DEFINE_MTYPE_STATIC(BFDD, BFDD_SESSION_OBSERVER, "Session observer");
+DEFINE_MTYPE_STATIC(BFDD, BFDD_VRF, "BFD VRF");
/*
* Prototypes
bp->echo_mode = false;
bp->passive = false;
bp->minimum_ttl = BFD_DEF_MHOP_TTL;
- bp->min_echo_rx = BFD_DEF_REQ_MIN_ECHO;
+ bp->min_echo_rx = BFD_DEF_REQ_MIN_ECHO_RX;
+ bp->min_echo_tx = BFD_DEF_DES_MIN_ECHO_TX;
bp->min_rx = BFD_DEFREQUIREDMINRX;
bp->min_tx = BFD_DEFDESIREDMINTX;
}
/* We can only apply echo options on single hop sessions. */
if (!CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
- /* Configure remote echo if it was default. */
- if (bs->peer_profile.min_echo_rx == BFD_DEF_REQ_MIN_ECHO)
- bs->timers.required_min_echo = bp->min_echo_rx;
+ /* Configure echo timers if they were default. */
+ if (bs->peer_profile.min_echo_rx == BFD_DEF_REQ_MIN_ECHO_RX)
+ bs->timers.required_min_echo_rx = bp->min_echo_rx;
else
- bs->timers.required_min_echo =
+ bs->timers.required_min_echo_rx =
bs->peer_profile.min_echo_rx;
+ if (bs->peer_profile.min_echo_tx == BFD_DEF_DES_MIN_ECHO_TX)
+ bs->timers.desired_min_echo_tx = bp->min_echo_tx;
+ else
+ bs->timers.desired_min_echo_tx =
+ bs->peer_profile.min_echo_tx;
+
/* Toggle echo if default value. */
if (bs->peer_profile.echo_mode == false)
bfd_set_echo(bs, bp->echo_mode);
void ptm_bfd_echo_start(struct bfd_session *bfd)
{
bfd->echo_detect_TO = (bfd->remote_detect_mult * bfd->echo_xmt_TO);
- if (bfd->echo_detect_TO > 0)
+ if (bfd->echo_detect_TO > 0) {
+ bfd_echo_recvtimer_update(bfd);
ptm_bfd_echo_xmt_TO(bfd);
+ }
}
void ptm_bfd_sess_up(struct bfd_session *bfd)
bs->timers.desired_min_tx = BFD_DEFDESIREDMINTX;
bs->timers.required_min_rx = BFD_DEFREQUIREDMINRX;
- bs->timers.required_min_echo = BFD_DEF_REQ_MIN_ECHO;
+ bs->timers.required_min_echo_rx = BFD_DEF_REQ_MIN_ECHO_RX;
+ bs->timers.desired_min_echo_tx = BFD_DEF_DES_MIN_ECHO_TX;
bs->detect_mult = BFD_DEFDETECTMULT;
bs->mh_ttl = BFD_DEF_MHOP_TTL;
bs->ses_state = PTM_BFD_DOWN;
bs->peer_profile.detection_multiplier = bs->detect_mult;
}
- if (bpc->bpc_has_echointerval) {
- bs->timers.required_min_echo = bpc->bpc_echointerval * 1000;
- bs->peer_profile.min_echo_rx = bs->timers.required_min_echo;
+ if (bpc->bpc_has_echorecvinterval) {
+ bs->timers.required_min_echo_rx = bpc->bpc_echorecvinterval * 1000;
+ bs->peer_profile.min_echo_rx = bs->timers.required_min_echo_rx;
+ }
+
+ if (bpc->bpc_has_echotxinterval) {
+ bs->timers.desired_min_echo_tx = bpc->bpc_echotxinterval * 1000;
+ bs->peer_profile.min_echo_tx = bs->timers.desired_min_echo_tx;
}
if (bpc->bpc_has_label)
* RFC 5880, Section 6.8.9.
*/
old_timer = bs->echo_xmt_TO;
- if (bs->remote_timers.required_min_echo > bs->timers.required_min_echo)
+ if (bs->remote_timers.required_min_echo > bs->timers.desired_min_echo_tx)
bs->echo_xmt_TO = bs->remote_timers.required_min_echo;
else
- bs->echo_xmt_TO = bs->timers.required_min_echo;
+ bs->echo_xmt_TO = bs->timers.desired_min_echo_tx;
if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO_ACTIVE) == 0
|| old_timer != bs->echo_xmt_TO)
#define BFDD_JSON_CONV_OPTIONS (0)
#endif
-DECLARE_MGROUP(BFDD)
-DECLARE_MTYPE(BFDD_CONTROL)
-DECLARE_MTYPE(BFDD_NOTIFICATION)
+DECLARE_MGROUP(BFDD);
+DECLARE_MTYPE(BFDD_CONTROL);
+DECLARE_MTYPE(BFDD_NOTIFICATION);
struct bfd_timers {
uint32_t desired_min_tx;
/** Echo mode (only applies to single hop). */
bool echo_mode;
+ /** Desired echo transmission interval (in microseconds). */
+ uint32_t min_echo_tx;
/** Minimum required echo receive interval (in microseconds). */
uint32_t min_echo_rx;
/* bfd_session shortcut label forwarding. */
struct peer_label;
+struct bfd_config_timers {
+ uint32_t desired_min_tx;
+ uint32_t required_min_rx;
+ uint32_t desired_min_echo_tx;
+ uint32_t required_min_echo_rx;
+};
+
/*
* Session state information
*/
struct bfd_profile peer_profile;
/* Timers */
- struct bfd_timers timers;
+ struct bfd_config_timers timers;
struct bfd_timers cur_timers;
uint64_t detect_TO;
struct thread *echo_recvtimer_ev;
#define BFD_DEFDETECTMULT 3
#define BFD_DEFDESIREDMINTX (300 * 1000) /* microseconds. */
#define BFD_DEFREQUIREDMINRX (300 * 1000) /* microseconds. */
-#define BFD_DEF_REQ_MIN_ECHO (50 * 1000) /* microseconds. */
+#define BFD_DEF_DES_MIN_ECHO_TX (50 * 1000) /* microseconds. */
+#define BFD_DEF_REQ_MIN_ECHO_RX (50 * 1000) /* microseconds. */
#define BFD_DEF_SLOWTX (1000 * 1000) /* microseconds. */
/** Minimum multi hop TTL. */
#define BFD_DEF_MHOP_TTL 254
cp.timers.required_min_rx =
htonl(bfd->cur_timers.required_min_rx);
}
- cp.timers.required_min_echo = htonl(bfd->timers.required_min_echo);
+ cp.timers.required_min_echo = htonl(bfd->timers.required_min_echo_rx);
if (_ptm_bfd_send(bfd, NULL, &cp, BFD_PKT_LEN) != 0)
return;
#define BPC_DEF_DETECTMULTIPLIER 3
#define BPC_DEF_RECEIVEINTERVAL 300 /* milliseconds */
#define BPC_DEF_TRANSMITINTERVAL 300 /* milliseconds */
-#define BPC_DEF_ECHOINTERVAL 50 /* milliseconds */
+#define BPC_DEF_ECHORECEIVEINTERVAL 50 /* milliseconds */
+#define BPC_DEF_ECHOTRANSMITINTERVAL 50 /* milliseconds */
/* Peer status */
enum bfd_peer_status {
bool bpc_has_txinterval;
uint64_t bpc_txinterval;
- bool bpc_has_echointerval;
- uint64_t bpc_echointerval;
+ bool bpc_has_echorecvinterval;
+ uint64_t bpc_echorecvinterval;
+
+ bool bpc_has_echotxinterval;
+ uint64_t bpc_echotxinterval;
bool bpc_has_minimum_ttl;
uint8_t bpc_minimum_ttl;
/*
* FRR related code.
*/
-DEFINE_MGROUP(BFDD, "Bidirectional Forwarding Detection Daemon")
-DEFINE_MTYPE(BFDD, BFDD_CONTROL, "long-lived control socket memory")
-DEFINE_MTYPE(BFDD, BFDD_NOTIFICATION, "short-lived control notification data")
+DEFINE_MGROUP(BFDD, "Bidirectional Forwarding Detection Daemon");
+DEFINE_MTYPE(BFDD, BFDD_CONTROL, "long-lived control socket memory");
+DEFINE_MTYPE(BFDD, BFDD_NOTIFICATION, "short-lived control notification data");
/* Master of threads. */
struct thread_master *master;
.signals = bfd_signals, .n_signals = array_size(bfd_signals),
.privs = &bglobal.bfdd_privs,
.yang_modules = bfdd_yang_modules,
- .n_yang_modules = array_size(bfdd_yang_modules))
+ .n_yang_modules = array_size(bfdd_yang_modules),
+);
#define OPTION_CTLSOCK 1001
#define OPTION_DPLANEADDR 2000
return CMD_WARNING_CONFIG_FAILED;
}
+ if (!no && !bglobal.bg_use_dplane) {
+ vty_out(vty, "%% Current implementation of echo mode works only when the peer is also FRR.\n");
+ }
+
nb_cli_enqueue_change(vty, "./echo-mode", NB_OP_MODIFY,
no ? "false" : "true");
return nb_cli_apply_changes(vty, NULL);
DEFPY_YANG(
bfd_peer_echo_interval, bfd_peer_echo_interval_cmd,
"echo-interval (10-60000)$interval",
- "Configure peer echo interval\n"
- "Configure peer echo interval value in milliseconds\n")
+ "Configure peer echo intervals\n"
+ "Configure peer echo rx/tx intervals value in milliseconds\n")
+{
+ char value[32];
+
+ if (!bfd_cli_is_profile(vty) && !bfd_cli_is_single_hop(vty)) {
+ vty_out(vty, "%% Echo mode is only available for single hop sessions.\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ snprintf(value, sizeof(value), "%ld", interval * 1000);
+ nb_cli_enqueue_change(vty, "./desired-echo-transmission-interval",
+ NB_OP_MODIFY, value);
+ nb_cli_enqueue_change(vty, "./required-echo-receive-interval",
+ NB_OP_MODIFY, value);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY_YANG(
+ bfd_peer_echo_transmit_interval, bfd_peer_echo_transmit_interval_cmd,
+ "echo transmit-interval (10-60000)$interval",
+ "Configure peer echo intervals\n"
+ "Configure desired transmit interval\n"
+ "Configure interval value in milliseconds\n")
{
char value[32];
return nb_cli_apply_changes(vty, NULL);
}
-void bfd_cli_show_echo_interval(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults)
+void bfd_cli_show_desired_echo_transmission_interval(struct vty *vty,
+ struct lyd_node *dnode, bool show_defaults)
+{
+ uint32_t value;
+
+ if (show_defaults)
+ vty_out(vty, " echo transmit-interval %d\n",
+ BFD_DEF_DES_MIN_ECHO_TX);
+ else {
+ value = yang_dnode_get_uint32(dnode, NULL);
+ vty_out(vty, " echo transmit-interval %u\n", value / 1000);
+ }
+}
+
+DEFPY_YANG(
+ bfd_peer_echo_receive_interval, bfd_peer_echo_receive_interval_cmd,
+ "echo receive-interval <disabled$disabled|(10-60000)$interval>",
+ "Configure peer echo intervals\n"
+ "Configure required receive interval\n"
+ "Disable echo packets receive\n"
+ "Configure interval value in milliseconds\n")
+{
+ char value[32];
+
+ if (!bfd_cli_is_profile(vty) && !bfd_cli_is_single_hop(vty)) {
+ vty_out(vty, "%% Echo mode is only available for single hop sessions.\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ if (disabled)
+ snprintf(value, sizeof(value), "0");
+ else
+ snprintf(value, sizeof(value), "%ld", interval * 1000);
+
+ nb_cli_enqueue_change(vty, "./required-echo-receive-interval",
+ NB_OP_MODIFY, value);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+void bfd_cli_show_required_echo_receive_interval(struct vty *vty,
+ struct lyd_node *dnode, bool show_defaults)
{
uint32_t value;
if (show_defaults)
- vty_out(vty, " echo-interval %d\n",
- BFD_DEF_REQ_MIN_ECHO);
+ vty_out(vty, " echo receive-interval %d\n",
+ BFD_DEF_REQ_MIN_ECHO_RX);
else {
value = yang_dnode_get_uint32(dnode, NULL);
- vty_out(vty, " echo-interval %u\n", value / 1000);
+ if (value)
+ vty_out(vty, " echo receive-interval %u\n",
+ value / 1000);
+ else
+ vty_out(vty, " echo receive-interval disabled\n");
}
}
"Configure peer echo interval\n"
"Configure peer echo interval value in milliseconds\n")
+ALIAS_YANG(
+ bfd_peer_echo_transmit_interval, bfd_profile_echo_transmit_interval_cmd,
+ "echo transmit-interval (10-60000)$interval",
+ "Configure peer echo intervals\n"
+ "Configure desired transmit interval\n"
+ "Configure interval value in milliseconds\n")
+
+ALIAS_YANG(
+ bfd_peer_echo_receive_interval, bfd_profile_echo_receive_interval_cmd,
+ "echo receive-interval <disabled$disabled|(10-60000)$interval>",
+ "Configure peer echo intervals\n"
+ "Configure required receive interval\n"
+ "Disable echo packets receive\n"
+ "Configure interval value in milliseconds\n")
+
DEFPY_YANG(bfd_peer_profile, bfd_peer_profile_cmd,
"[no] profile BFDPROF$pname",
NO_STR
install_element(BFD_PEER_NODE, &bfd_peer_tx_cmd);
install_element(BFD_PEER_NODE, &bfd_peer_echo_cmd);
install_element(BFD_PEER_NODE, &bfd_peer_echo_interval_cmd);
+ install_element(BFD_PEER_NODE, &bfd_peer_echo_transmit_interval_cmd);
+ install_element(BFD_PEER_NODE, &bfd_peer_echo_receive_interval_cmd);
install_element(BFD_PEER_NODE, &bfd_peer_profile_cmd);
install_element(BFD_PEER_NODE, &bfd_peer_passive_cmd);
install_element(BFD_PEER_NODE, &bfd_peer_minimum_ttl_cmd);
install_element(BFD_PROFILE_NODE, &bfd_profile_shutdown_cmd);
install_element(BFD_PROFILE_NODE, &bfd_profile_echo_cmd);
install_element(BFD_PROFILE_NODE, &bfd_profile_echo_interval_cmd);
+ install_element(BFD_PROFILE_NODE, &bfd_profile_echo_transmit_interval_cmd);
+ install_element(BFD_PROFILE_NODE, &bfd_profile_echo_receive_interval_cmd);
install_element(BFD_PROFILE_NODE, &bfd_profile_passive_cmd);
install_element(BFD_PROFILE_NODE, &bfd_profile_minimum_ttl_cmd);
install_element(BFD_PROFILE_NODE, &no_bfd_profile_minimum_ttl_cmd);
.xpath = "/frr-bfdd:bfdd/bfd/profile/desired-echo-transmission-interval",
.cbs = {
.modify = bfdd_bfd_profile_desired_echo_transmission_interval_modify,
- .cli_show = bfd_cli_show_echo_interval,
- }
+ .cli_show = bfd_cli_show_desired_echo_transmission_interval,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/profile/required-echo-receive-interval",
+ .cbs = {
+ .modify = bfdd_bfd_profile_required_echo_receive_interval_modify,
+ .cli_show = bfd_cli_show_required_echo_receive_interval,
+ }
},
{
.xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop",
.xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/desired-echo-transmission-interval",
.cbs = {
.modify = bfdd_bfd_sessions_single_hop_desired_echo_transmission_interval_modify,
- .cli_show = bfd_cli_show_echo_interval,
+ .cli_show = bfd_cli_show_desired_echo_transmission_interval,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/required-echo-receive-interval",
+ .cbs = {
+ .modify = bfdd_bfd_sessions_single_hop_required_echo_receive_interval_modify,
+ .cli_show = bfd_cli_show_required_echo_receive_interval,
}
},
{
int bfdd_bfd_profile_echo_mode_modify(struct nb_cb_modify_args *args);
int bfdd_bfd_profile_desired_echo_transmission_interval_modify(
struct nb_cb_modify_args *args);
+int bfdd_bfd_profile_required_echo_receive_interval_modify(
+ struct nb_cb_modify_args *args);
int bfdd_bfd_sessions_single_hop_create(struct nb_cb_create_args *args);
int bfdd_bfd_sessions_single_hop_destroy(struct nb_cb_destroy_args *args);
const void *
struct nb_cb_modify_args *args);
int bfdd_bfd_sessions_single_hop_desired_echo_transmission_interval_modify(
struct nb_cb_modify_args *args);
+int bfdd_bfd_sessions_single_hop_required_echo_receive_interval_modify(
+ struct nb_cb_modify_args *args);
struct yang_data *
bfdd_bfd_sessions_single_hop_stats_local_discriminator_get_elem(
struct nb_cb_get_elem_args *args);
bool show_defaults);
void bfd_cli_show_echo(struct vty *vty, struct lyd_node *dnode,
bool show_defaults);
-void bfd_cli_show_echo_interval(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
+void bfd_cli_show_desired_echo_transmission_interval(
+ struct vty *vty, struct lyd_node *dnode, bool show_defaults);
+void bfd_cli_show_required_echo_receive_interval(
+ struct vty *vty, struct lyd_node *dnode, bool show_defaults);
void bfd_cli_show_profile(struct vty *vty, struct lyd_node *dnode,
bool show_defaults);
void bfd_cli_peer_profile_show(struct vty *vty, struct lyd_node *dnode,
}
/*
- * XPath: /frr-bfdd:bfdd/bfd/profile/desired-echo-echo-transmission-interval
+ * XPath: /frr-bfdd:bfdd/bfd/profile/desired-echo-transmission-interval
*/
int bfdd_bfd_profile_desired_echo_transmission_interval_modify(
struct nb_cb_modify_args *args)
+{
+ struct bfd_profile *bp;
+ uint32_t min_tx;
+
+ switch (args->event) {
+ case NB_EV_VALIDATE:
+ min_tx = yang_dnode_get_uint32(args->dnode, NULL);
+ if (min_tx < 10000 || min_tx > 60000000)
+ return NB_ERR_VALIDATION;
+ break;
+
+ case NB_EV_PREPARE:
+ /* NOTHING */
+ break;
+
+ case NB_EV_APPLY:
+ min_tx = yang_dnode_get_uint32(args->dnode, NULL);
+ bp = nb_running_get_entry(args->dnode, NULL, true);
+ if (bp->min_echo_tx == min_tx)
+ return NB_OK;
+
+ bp->min_echo_tx = min_tx;
+ bfd_profile_update(bp);
+ break;
+
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-bfdd:bfdd/bfd/profile/required-echo-receive-interval
+ */
+int bfdd_bfd_profile_required_echo_receive_interval_modify(
+ struct nb_cb_modify_args *args)
{
struct bfd_profile *bp;
uint32_t min_rx;
switch (args->event) {
case NB_EV_VALIDATE:
min_rx = yang_dnode_get_uint32(args->dnode, NULL);
+ if (min_rx == 0)
+ return NB_OK;
if (min_rx < 10000 || min_rx > 60000000)
return NB_ERR_VALIDATION;
break;
case NB_EV_APPLY:
bs = nb_running_get_entry(args->dnode, NULL, true);
- if (echo_interval == bs->timers.required_min_echo)
+ if (echo_interval == bs->timers.desired_min_echo_tx)
+ return NB_OK;
+
+ bs->peer_profile.min_echo_tx = echo_interval;
+ bfd_session_apply(bs);
+ break;
+
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-bfdd:bfdd/bfd/sessions/single-hop/required-echo-receive-interval
+ */
+int bfdd_bfd_sessions_single_hop_required_echo_receive_interval_modify(
+ struct nb_cb_modify_args *args)
+{
+ uint32_t echo_interval = yang_dnode_get_uint32(args->dnode, NULL);
+ struct bfd_session *bs;
+
+ switch (args->event) {
+ case NB_EV_VALIDATE:
+ if (echo_interval == 0)
+ return NB_OK;
+ if (echo_interval < 10000 || echo_interval > 60000000)
+ return NB_ERR_VALIDATION;
+ break;
+
+ case NB_EV_PREPARE:
+ /* NOTHING */
+ break;
+
+ case NB_EV_APPLY:
+ bs = nb_running_get_entry(args->dnode, NULL, true);
+ if (echo_interval == bs->timers.required_min_echo_rx)
return NB_OK;
bs->peer_profile.min_echo_rx = echo_interval;
bs->timers.required_min_rx / 1000);
vty_out(vty, "\t\t\tTransmission interval: %ums\n",
bs->timers.desired_min_tx / 1000);
- vty_out(vty, "\t\t\tEcho transmission interval: %ums\n",
- bs->timers.required_min_echo / 1000);
+ if (bs->timers.required_min_echo_rx != 0)
+ vty_out(vty, "\t\t\tEcho receive interval: %ums\n",
+ bs->timers.required_min_echo_rx / 1000);
+ else
+ vty_out(vty, "\t\t\tEcho receive interval: disabled\n");
+ if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
+ vty_out(vty, "\t\t\tEcho transmission interval: %ums\n",
+ bs->timers.desired_min_echo_tx / 1000);
+ else
+ vty_out(vty, "\t\t\tEcho transmission interval: disabled\n");
vty_out(vty, "\t\tRemote timers:\n");
vty_out(vty, "\t\t\tDetect-multiplier: %u\n",
bs->remote_timers.required_min_rx / 1000);
vty_out(vty, "\t\t\tTransmission interval: %ums\n",
bs->remote_timers.desired_min_tx / 1000);
- vty_out(vty, "\t\t\tEcho transmission interval: %ums\n",
- bs->remote_timers.required_min_echo / 1000);
+ if (bs->remote_timers.required_min_echo != 0)
+ vty_out(vty, "\t\t\tEcho receive interval: %ums\n",
+ bs->remote_timers.required_min_echo / 1000);
+ else
+ vty_out(vty, "\t\t\tEcho receive interval: disabled\n");
vty_out(vty, "\n");
}
bs->timers.required_min_rx / 1000);
json_object_int_add(jo, "transmit-interval",
bs->timers.desired_min_tx / 1000);
+ json_object_int_add(jo, "echo-receive-interval",
+ bs->timers.required_min_echo_rx / 1000);
if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
- json_object_int_add(jo, "echo-interval",
- bs->timers.required_min_echo / 1000);
+ json_object_int_add(jo, "echo-transmit-interval",
+ bs->timers.desired_min_echo_tx / 1000);
else
- json_object_int_add(jo, "echo-interval", 0);
+ json_object_int_add(jo, "echo-transmit-interval", 0);
json_object_int_add(jo, "detect-multiplier", bs->detect_mult);
bs->remote_timers.required_min_rx / 1000);
json_object_int_add(jo, "remote-transmit-interval",
bs->remote_timers.desired_min_tx / 1000);
- json_object_int_add(jo, "remote-echo-interval",
+ json_object_int_add(jo, "remote-echo-receive-interval",
bs->remote_timers.required_min_echo / 1000);
json_object_int_add(jo, "remote-detect-multiplier",
bs->remote_detect_mult);
bpc->bpc_detectmultiplier = BPC_DEF_DETECTMULTIPLIER;
bpc->bpc_recvinterval = BPC_DEF_RECEIVEINTERVAL;
bpc->bpc_txinterval = BPC_DEF_TRANSMITINTERVAL;
- bpc->bpc_echointerval = BPC_DEF_ECHOINTERVAL;
+ bpc->bpc_echorecvinterval = BPC_DEF_ECHORECEIVEINTERVAL;
+ bpc->bpc_echotxinterval = BPC_DEF_ECHOTRANSMITINTERVAL;
bpc->bpc_lastevent = monotime(NULL);
/* Safety check: when no error buf is provided len must be zero. */
* jitter.
*/
uint32_t min_rx;
+ /**
+ * Minimum desired echo transmission interval (in microseconds)
+ * without jitter.
+ */
+ uint32_t min_echo_tx;
/**
* Required minimum echo receive interval rate (in microseconds)
* without jitter.
#include "bfd.h"
-DEFINE_MTYPE_STATIC(BFDD, BFDD_LABEL, "long-lived label memory")
+DEFINE_MTYPE_STATIC(BFDD, BFDD_LABEL, "long-lived label memory");
/*
* Definitions
bpc.bpc_detectmultiplier = BFD_DEFDETECTMULT;
bpc.bpc_recvinterval = BFD_DEFREQUIREDMINRX;
bpc.bpc_txinterval = BFD_DEFDESIREDMINTX;
- bpc.bpc_echointerval = BFD_DEF_REQ_MIN_ECHO;
+ bpc.bpc_echorecvinterval = BFD_DEF_REQ_MIN_ECHO_RX;
+ bpc.bpc_echotxinterval = BFD_DEF_DES_MIN_ECHO_TX;
switch (plt) {
case PLT_IPV4:
bpc->bpc_has_txinterval = true;
zlog_debug(" transmit-interval: %" PRIu64,
bpc->bpc_txinterval);
- } else if (strcmp(key, "echo-interval") == 0) {
- bpc->bpc_echointerval = json_object_get_int64(jo_val);
- bpc->bpc_has_echointerval = true;
- zlog_debug(" echo-interval: %" PRIu64,
- bpc->bpc_echointerval);
+ } else if (strcmp(key, "echo-receive-interval") == 0) {
+ bpc->bpc_echorecvinterval = json_object_get_int64(jo_val);
+ bpc->bpc_has_echorecvinterval = true;
+ zlog_debug(" echo-receive-interval: %" PRIu64,
+ bpc->bpc_echorecvinterval);
+ } else if (strcmp(key, "echo-transmit-interval") == 0) {
+ bpc->bpc_echotxinterval = json_object_get_int64(jo_val);
+ bpc->bpc_has_echotxinterval = true;
+ zlog_debug(" echo-transmit-interval: %" PRIu64,
+ bpc->bpc_echotxinterval);
} else if (strcmp(key, "create-only") == 0) {
bpc->bpc_createonly = json_object_get_boolean(jo_val);
zlog_debug(" create-only: %s",
bs->timers.required_min_rx / 1000);
json_object_int_add(resp, "transmit-interval",
bs->timers.desired_min_tx / 1000);
- json_object_int_add(resp, "echo-interval",
- bs->timers.required_min_echo / 1000);
+ json_object_int_add(resp, "echo-receive-interval",
+ bs->timers.required_min_echo_rx / 1000);
+ json_object_int_add(resp, "echo-transmit-interval",
+ bs->timers.desired_min_echo_tx / 1000);
json_object_int_add(resp, "remote-detect-multiplier",
bs->remote_detect_mult);
bs->remote_timers.required_min_rx / 1000);
json_object_int_add(resp, "remote-transmit-interval",
bs->remote_timers.desired_min_tx / 1000);
- json_object_int_add(resp, "remote-echo-interval",
+ json_object_int_add(resp, "remote-echo-receive-interval",
bs->remote_timers.required_min_echo / 1000);
if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
#include "lib/openbsd-queue.h"
-DEFINE_MTYPE_STATIC(BFDD, BFDD_DPLANE_CTX, "Data plane client allocated memory")
+DEFINE_MTYPE_STATIC(BFDD, BFDD_DPLANE_CTX,
+ "Data plane client allocated memory");
/** Data plane client socket buffer size. */
#define BFD_DPLANE_CLIENT_BUF_SIZE 8192
msg->data.session.lid = htonl(bs->discrs.my_discr);
msg->data.session.min_tx = htonl(bs->timers.desired_min_tx);
msg->data.session.min_rx = htonl(bs->timers.required_min_rx);
- msg->data.session.min_echo_rx = htonl(bs->timers.required_min_echo);
+ msg->data.session.min_echo_tx = htonl(bs->timers.desired_min_echo_tx);
+ msg->data.session.min_echo_rx = htonl(bs->timers.required_min_echo_rx);
}
static int _bfd_dplane_add_session(struct bfd_dplane_ctx *bdc,
#include "lib/typesafe.h"
-PREDECL_DLIST(bgp_adv_fifo)
+PREDECL_DLIST(bgp_adv_fifo);
struct update_subgroup;
struct bgp_path_info *pathi;
};
-DECLARE_DLIST(bgp_adv_fifo, struct bgp_advertise, fifo)
+DECLARE_DLIST(bgp_adv_fifo, struct bgp_advertise, fifo);
/* BGP adjacency out. */
struct bgp_adj_out {
#include "thread.h"
#include "buffer.h"
#include "stream.h"
+#include "vrf.h"
#include "zclient.h"
#include "bfd.h"
#include "lib/json.h"
#include "bgpd/bgp_debug.h"
#include "bgpd/bgp_vty.h"
+DEFINE_MTYPE_STATIC(BGPD, BFD_CONFIG, "BFD configuration data");
+
extern struct zclient *zclient;
-/*
- * bgp_bfd_peer_group2peer_copy - Copy the BFD information from peer group
- * template
- * to peer.
- */
-void bgp_bfd_peer_group2peer_copy(struct peer *conf, struct peer *peer)
+static void bfd_session_status_update(struct bfd_session_params *bsp,
+ const struct bfd_session_status *bss,
+ void *arg)
{
- struct bfd_info *bfd_info;
- struct bfd_info *conf_bfd_info;
-
- if (!conf->bfd_info)
- return;
-
- conf_bfd_info = (struct bfd_info *)conf->bfd_info;
- if (!peer->bfd_info)
- peer->bfd_info = bfd_info_create();
-
- bfd_info = (struct bfd_info *)peer->bfd_info;
+ struct peer *peer = arg;
+
+ if (BGP_DEBUG(bfd, BFD_LIB))
+ zlog_debug("%s: neighbor %s vrf %s(%u) bfd state %s -> %s",
+ __func__, peer->conf_if ? peer->conf_if : peer->host,
+ bfd_sess_vrf(bsp), bfd_sess_vrf_id(bsp),
+ bfd_get_status_str(bss->previous_state),
+ bfd_get_status_str(bss->state));
+
+ if (bss->state == BSS_DOWN && bss->previous_state == BSS_UP) {
+ if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_MODE)
+ && bfd_sess_cbit(bsp) && !bss->remote_cbit) {
+ if (BGP_DEBUG(bfd, BFD_LIB))
+ zlog_info(
+ "%s BFD DOWN message ignored in the process of graceful restart when C bit is cleared",
+ peer->host);
+ return;
+ }
+ peer->last_reset = PEER_DOWN_BFD_DOWN;
+ BGP_EVENT_ADD(peer, BGP_Stop);
+ }
- /* Copy BFD parameter values */
- bfd_info->required_min_rx = conf_bfd_info->required_min_rx;
- bfd_info->desired_min_tx = conf_bfd_info->desired_min_tx;
- bfd_info->detect_mult = conf_bfd_info->detect_mult;
- bfd_info->type = conf_bfd_info->type;
+ if (bss->state == BSS_UP && bss->previous_state != BSS_UP
+ && peer->status != Established) {
+ if (!BGP_PEER_START_SUPPRESSED(peer)) {
+ bgp_fsm_nht_update(peer, true);
+ BGP_EVENT_ADD(peer, BGP_Start);
+ }
+ }
}
-/*
- * bgp_bfd_is_peer_multihop - returns whether BFD peer is multi-hop or single
- * hop.
- */
-bool bgp_bfd_is_peer_multihop(struct peer *peer)
+void bgp_peer_config_apply(struct peer *p, struct peer_group *pg)
{
- struct bfd_info *bfd_info;
+ struct listnode *n;
+ struct peer *pn;
+ struct peer *gconfig;
+
+ /* When called on a group, apply to all peers. */
+ if (CHECK_FLAG(p->sflags, PEER_STATUS_GROUP)) {
+ for (ALL_LIST_ELEMENTS_RO(p->group->peer, n, pn))
+ bgp_peer_config_apply(pn, pg);
+ return;
+ }
- bfd_info = (struct bfd_info *)peer->bfd_info;
+ /* No group, just use current configuration. */
+ if (pg == NULL || pg->conf->bfd_config == NULL) {
+ bfd_sess_set_timers(p->bfd_config->session,
+ p->bfd_config->detection_multiplier,
+ p->bfd_config->min_rx,
+ p->bfd_config->min_tx);
+ bfd_sess_set_cbit(p->bfd_config->session, p->bfd_config->cbit);
+ bfd_sess_set_profile(p->bfd_config->session,
+ p->bfd_config->profile);
+ bfd_sess_install(p->bfd_config->session);
+ return;
+ }
- if (!bfd_info)
- return false;
+ /*
+ * Check if the group configuration was overwritten or apply group
+ * configuration.
+ */
+ gconfig = pg->conf;
+
+ /*
+ * If using default control plane independent configuration,
+ * then prefer group's (e.g. it means it wasn't manually configured).
+ */
+ if (!p->bfd_config->cbit)
+ bfd_sess_set_cbit(p->bfd_config->session,
+ gconfig->bfd_config->cbit);
+ else
+ bfd_sess_set_cbit(p->bfd_config->session, p->bfd_config->cbit);
- if ((bfd_info->type == BFD_TYPE_MULTIHOP)
- || ((peer->sort == BGP_PEER_IBGP) && !peer->shared_network)
- || is_ebgp_multihop_configured(peer))
- return true;
+ /* If no profile was specified in peer, then use the group profile. */
+ if (p->bfd_config->profile[0] == 0)
+ bfd_sess_set_profile(p->bfd_config->session,
+ gconfig->bfd_config->profile);
else
- return false;
+ bfd_sess_set_profile(p->bfd_config->session,
+ p->bfd_config->profile);
+
+ /* If no specific timers were configured, then use the group timers. */
+ if (p->bfd_config->detection_multiplier == BFD_DEF_DETECT_MULT
+ || p->bfd_config->min_rx == BFD_DEF_MIN_RX
+ || p->bfd_config->min_tx == BFD_DEF_MIN_TX)
+ bfd_sess_set_timers(p->bfd_config->session,
+ gconfig->bfd_config->detection_multiplier,
+ gconfig->bfd_config->min_rx,
+ gconfig->bfd_config->min_tx);
+ else
+ bfd_sess_set_timers(p->bfd_config->session,
+ p->bfd_config->detection_multiplier,
+ p->bfd_config->min_rx,
+ p->bfd_config->min_tx);
+
+ bfd_sess_install(p->bfd_config->session);
}
-/*
- * bgp_bfd_peer_sendmsg - Format and send a Peer register/Unregister
- * command to Zebra to be forwarded to BFD
- */
-static void bgp_bfd_peer_sendmsg(struct peer *peer, int command)
+void bgp_peer_bfd_update_source(struct peer *p)
{
- struct bfd_session_arg arg = {};
- struct bfd_info *bfd_info;
- int multihop;
- vrf_id_t vrf_id;
- size_t addrlen;
-
- /*
- * XXX: some pointers are dangling during shutdown, so instead of
- * trying to send a message during signal handlers lets just wait BGP
- * to terminate zebra's connection and BFD will automatically find
- * out that we are no longer expecting notifications.
- *
- * The pointer that is causing a crash here is `peer->nexthop.ifp`.
- * That happens because at this point of the shutdown all interfaces are
- * already `free()`d.
- */
- if (bm->terminating)
+ struct bfd_session_params *session = p->bfd_config->session;
+ bool changed = false;
+ int family;
+ union {
+ struct in_addr v4;
+ struct in6_addr v6;
+ } src, dst;
+
+ /* Nothing to do for groups. */
+ if (CHECK_FLAG(p->sflags, PEER_STATUS_GROUP))
return;
- bfd_info = (struct bfd_info *)peer->bfd_info;
+ /* Update peer's source/destination addresses. */
+ bfd_sess_addresses(session, &family, &src.v6, &dst.v6);
+ if (family == AF_INET) {
+ if ((p->su_local
+ && p->su_local->sin.sin_addr.s_addr != src.v4.s_addr)
+ || p->su.sin.sin_addr.s_addr != dst.v4.s_addr) {
+ if (BGP_DEBUG(bfd, BFD_LIB))
+ zlog_debug(
+ "%s: address [%pI4->%pI4] to [%pI4->%pI4]",
+ __func__, &src.v4, &dst.v4,
+ p->su_local ? &p->su_local->sin.sin_addr
+ : &src.v4,
+ &p->su.sin.sin_addr);
+
+ bfd_sess_set_ipv4_addrs(
+ session,
+ p->su_local ? &p->su_local->sin.sin_addr : NULL,
+ &p->su.sin.sin_addr);
+ changed = true;
+ }
+ } else {
+ if ((p->su_local
+ && memcmp(&p->su_local->sin6, &src.v6, sizeof(src.v6)))
+ || memcmp(&p->su.sin6, &dst.v6, sizeof(dst.v6))) {
+ if (BGP_DEBUG(bfd, BFD_LIB))
+ zlog_debug(
+ "%s: address [%pI6->%pI6] to [%pI6->%pI6]",
+ __func__, &src.v6, &dst.v6,
+ p->su_local
+ ? &p->su_local->sin6.sin6_addr
+ : &src.v6,
+ &p->su.sin6.sin6_addr);
+
+ bfd_sess_set_ipv6_addrs(
+ session,
+ p->su_local ? &p->su_local->sin6.sin6_addr
+ : NULL,
+ &p->su.sin6.sin6_addr);
+ changed = true;
+ }
+ }
- vrf_id = peer->bgp->vrf_id;
+ /* Update interface. */
+ if (p->nexthop.ifp && bfd_sess_interface(session) == NULL) {
+ if (BGP_DEBUG(bfd, BFD_LIB))
+ zlog_debug("%s: interface none to %s", __func__,
+ p->nexthop.ifp->name);
- if (command == ZEBRA_BFD_DEST_DEREGISTER) {
- multihop =
- CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_TYPE_MULTIHOP);
- UNSET_FLAG(bfd_info->flags, BFD_FLAG_BFD_TYPE_MULTIHOP);
- } else {
- multihop = bgp_bfd_is_peer_multihop(peer);
- if ((command == ZEBRA_BFD_DEST_REGISTER) && multihop)
- SET_FLAG(bfd_info->flags, BFD_FLAG_BFD_TYPE_MULTIHOP);
+ bfd_sess_set_interface(session, p->nexthop.ifp->name);
+ changed = true;
}
- /* while graceful restart with fwd path preserved
- * and bfd controlplane check not configured is not kept
- * keep bfd independent controlplane bit set to 1
+
+ /*
+ * Update TTL.
+ *
+ * Two cases:
+ * - We detected that the peer is a hop away from us (remove multi hop).
+ * (this happens when `p->shared_network` is set to `true`)
+ * - eBGP multi hop / TTL security changed.
*/
- if (!CHECK_FLAG(peer->bgp->flags, BGP_FLAG_GRACEFUL_RESTART)
- && !CHECK_FLAG(peer->bgp->flags, BGP_FLAG_GR_PRESERVE_FWD)
- && !CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE))
- SET_FLAG(bfd_info->flags, BFD_FLAG_BFD_CBIT_ON);
-
- /* Set all message arguments. */
- arg.family = peer->su.sa.sa_family;
- addrlen = arg.family == AF_INET ? sizeof(struct in_addr)
- : sizeof(struct in6_addr);
-
- if (arg.family == AF_INET)
- memcpy(&arg.dst, &peer->su.sin.sin_addr, addrlen);
- else
- memcpy(&arg.dst, &peer->su.sin6.sin6_addr, addrlen);
+ if (!PEER_IS_MULTIHOP(p) && bfd_sess_hop_count(session) > 1) {
+ if (BGP_DEBUG(bfd, BFD_LIB))
+ zlog_debug("%s: TTL %d to 1", __func__,
+ bfd_sess_hop_count(session));
- if (peer->su_local) {
- if (arg.family == AF_INET)
- memcpy(&arg.src, &peer->su_local->sin.sin_addr,
- addrlen);
- else
- memcpy(&arg.src, &peer->su_local->sin6.sin6_addr,
- addrlen);
+ bfd_sess_set_hop_count(session, 1);
+ changed = true;
}
+ if (PEER_IS_MULTIHOP(p) && p->ttl != bfd_sess_hop_count(session)) {
+ if (BGP_DEBUG(bfd, BFD_LIB))
+ zlog_debug("%s: TTL %d to %d", __func__,
+ bfd_sess_hop_count(session), p->ttl);
- if (peer->nexthop.ifp) {
- arg.ifnamelen = strlen(peer->nexthop.ifp->name);
- strlcpy(arg.ifname, peer->nexthop.ifp->name,
- sizeof(arg.ifname));
+ bfd_sess_set_hop_count(session, p->ttl);
+ changed = true;
}
- if (bfd_info->profile[0]) {
- arg.profilelen = strlen(bfd_info->profile);
- strlcpy(arg.profile, bfd_info->profile, sizeof(arg.profile));
+ /* Update VRF. */
+ if (bfd_sess_vrf_id(session) != p->bgp->vrf_id) {
+ if (BGP_DEBUG(bfd, BFD_LIB))
+ zlog_debug(
+ "%s: VRF %s(%d) to %s(%d)", __func__,
+ bfd_sess_vrf(session), bfd_sess_vrf_id(session),
+ vrf_id_to_name(p->bgp->vrf_id), p->bgp->vrf_id);
+
+ bfd_sess_set_vrf(session, p->bgp->vrf_id);
+ changed = true;
}
- arg.set_flag = 1;
- arg.mhop = multihop;
- arg.ttl = peer->ttl;
- arg.vrf_id = vrf_id;
- arg.command = command;
- arg.bfd_info = bfd_info;
- arg.min_tx = bfd_info->desired_min_tx;
- arg.min_rx = bfd_info->required_min_rx;
- arg.detection_multiplier = bfd_info->detect_mult;
- arg.cbit = CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CBIT_ON);
-
- /* Send message. */
- zclient_bfd_command(zclient, &arg);
+ if (changed)
+ bfd_sess_install(session);
}
-/*
- * bgp_bfd_register_peer - register a peer with BFD through zebra
- * for monitoring the peer rechahability.
+/**
+ * Reset BFD configuration data structure to its defaults settings.
*/
-void bgp_bfd_register_peer(struct peer *peer)
+static void bgp_peer_bfd_reset(struct peer *p)
{
- struct bfd_info *bfd_info;
-
- if (!peer->bfd_info)
- return;
- bfd_info = (struct bfd_info *)peer->bfd_info;
-
- /* Check if BFD is enabled and peer has already been registered with BFD
- */
- if (CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_REG))
- return;
-
- bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_REGISTER);
+ /* Set defaults. */
+ p->bfd_config->detection_multiplier = BFD_DEF_DETECT_MULT;
+ p->bfd_config->min_rx = BFD_DEF_MIN_RX;
+ p->bfd_config->min_tx = BFD_DEF_MIN_TX;
+ p->bfd_config->cbit = false;
+ p->bfd_config->profile[0] = 0;
}
-/**
- * bgp_bfd_deregister_peer - deregister a peer with BFD through zebra
- * for stopping the monitoring of the peer
- * rechahability.
- */
-void bgp_bfd_deregister_peer(struct peer *peer)
+void bgp_peer_configure_bfd(struct peer *p, bool manual)
{
- struct bfd_info *bfd_info;
+ /* Groups should not call this. */
+ assert(!CHECK_FLAG(p->sflags, PEER_STATUS_GROUP));
- if (!peer->bfd_info)
- return;
- bfd_info = (struct bfd_info *)peer->bfd_info;
+ /* Already configured, skip it. */
+ if (p->bfd_config) {
+ /* If manually active update flag. */
+ if (!p->bfd_config->manual)
+ p->bfd_config->manual = manual;
- /* Check if BFD is eanbled and peer has not been registered */
- if (!CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_REG))
return;
+ }
- bfd_info->status = BFD_STATUS_DOWN;
- bfd_info->last_update = bgp_clock();
-
- bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_DEREGISTER);
-}
-
-/*
- * bgp_bfd_update_peer - update peer with BFD with new BFD paramters
- * through zebra.
- */
-static void bgp_bfd_update_peer(struct peer *peer)
-{
- struct bfd_info *bfd_info;
+ /* Allocate memory for configuration overrides. */
+ p->bfd_config = XCALLOC(MTYPE_BFD_CONFIG, sizeof(*p->bfd_config));
+ p->bfd_config->manual = manual;
- if (!peer->bfd_info)
- return;
- bfd_info = (struct bfd_info *)peer->bfd_info;
+ /* Create new session and assign callback. */
+ p->bfd_config->session = bfd_sess_new(bfd_session_status_update, p);
+ bgp_peer_bfd_reset(p);
- /* Check if the peer has been registered with BFD*/
- if (!CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_REG))
- return;
+ /* Configure session with basic BGP peer data. */
+ if (p->su.sa.sa_family == AF_INET)
+ bfd_sess_set_ipv4_addrs(p->bfd_config->session,
+ p->su_local ? &p->su_local->sin.sin_addr
+ : NULL,
+ &p->su.sin.sin_addr);
+ else
+ bfd_sess_set_ipv6_addrs(
+ p->bfd_config->session,
+ p->su_local ? &p->su_local->sin6.sin6_addr : NULL,
+ &p->su.sin6.sin6_addr);
- bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_UPDATE);
-}
+ bfd_sess_set_vrf(p->bfd_config->session, p->bgp->vrf_id);
+ bfd_sess_set_hop_count(p->bfd_config->session,
+ PEER_IS_MULTIHOP(p) ? p->ttl : 1);
-/**
- * bgp_bfd_reset_peer - reinitialise bfd
- * ensures that bfd state machine is restarted
- * to be synced with remote bfd
- */
-void bgp_bfd_reset_peer(struct peer *peer)
-{
- if (!peer->bfd_info)
- return;
+ if (p->nexthop.ifp)
+ bfd_sess_set_interface(p->bfd_config->session,
+ p->nexthop.ifp->name);
- bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_REGISTER);
+ bfd_sess_enable(p->bfd_config->session, true);
}
-/*
- * bgp_bfd_update_type - update session type with BFD through zebra.
- */
-static void bgp_bfd_update_type(struct peer *peer)
+static void bgp_peer_remove_bfd(struct peer *p)
{
- struct bfd_info *bfd_info;
- int multihop;
-
- if (!peer->bfd_info)
- return;
- bfd_info = (struct bfd_info *)peer->bfd_info;
+ /* Groups should not call this. */
+ assert(!CHECK_FLAG(p->sflags, PEER_STATUS_GROUP));
- /* Check if the peer has been registered with BFD*/
- if (!CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_REG))
+ /*
+ * Peer configuration was removed, however we must check if there
+ * is still a group configuration to keep this running.
+ */
+ if (p->group && p->group->conf->bfd_config) {
+ p->bfd_config->manual = false;
+ bgp_peer_bfd_reset(p);
+ bgp_peer_config_apply(p, p->group);
return;
-
- if (bfd_info->type == BFD_TYPE_NOT_CONFIGURED) {
- multihop = bgp_bfd_is_peer_multihop(peer);
- if ((multihop
- && !CHECK_FLAG(bfd_info->flags,
- BFD_FLAG_BFD_TYPE_MULTIHOP))
- || (!multihop && CHECK_FLAG(bfd_info->flags,
- BFD_FLAG_BFD_TYPE_MULTIHOP))) {
- bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_DEREGISTER);
- bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_REGISTER);
- }
- } else {
- if ((bfd_info->type == BFD_TYPE_MULTIHOP
- && !CHECK_FLAG(bfd_info->flags,
- BFD_FLAG_BFD_TYPE_MULTIHOP))
- || (bfd_info->type == BFD_TYPE_SINGLEHOP
- && CHECK_FLAG(bfd_info->flags,
- BFD_FLAG_BFD_TYPE_MULTIHOP))) {
- bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_DEREGISTER);
- bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_REGISTER);
- }
}
-}
-
-/*
- * bgp_bfd_dest_replay - Replay all the peers that have BFD enabled
- * to zebra
- */
-static int bgp_bfd_dest_replay(ZAPI_CALLBACK_ARGS)
-{
- struct listnode *mnode, *node, *nnode;
- struct bgp *bgp;
- struct peer *peer;
-
- if (BGP_DEBUG(zebra, ZEBRA))
- zlog_debug("Zebra: BFD Dest replay request");
-
- /* Send the client registration */
- bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, vrf_id);
-
- /* Replay the peer, if BFD is enabled in BGP */
- for (ALL_LIST_ELEMENTS_RO(bm->bgp, mnode, bgp))
- for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
- bgp_bfd_update_peer(peer);
- }
-
- return 0;
+ bfd_sess_free(&p->bfd_config->session);
+ XFREE(MTYPE_BFD_CONFIG, p->bfd_config);
}
-/*
- * bgp_bfd_peer_status_update - Update the BFD status if it has changed. Bring
- * down the peer if the BFD session went down from
- * * up.
- */
-static void bgp_bfd_peer_status_update(struct peer *peer, int status,
- int remote_cbit)
+static void bgp_group_configure_bfd(struct peer *p)
{
- struct bfd_info *bfd_info;
- int old_status;
+ struct listnode *n;
+ struct peer *pn;
- bfd_info = (struct bfd_info *)peer->bfd_info;
+ /* Peers should not call this. */
+ assert(CHECK_FLAG(p->sflags, PEER_STATUS_GROUP));
- if (bfd_info->status == status)
+ /* Already allocated: do nothing. */
+ if (p->bfd_config)
return;
- old_status = bfd_info->status;
- BFD_SET_CLIENT_STATUS(bfd_info->status, status);
+ p->bfd_config = XCALLOC(MTYPE_BFD_CONFIG, sizeof(*p->bfd_config));
- bfd_info->last_update = bgp_clock();
+ /* Set defaults. */
+ p->bfd_config->detection_multiplier = BFD_DEF_DETECT_MULT;
+ p->bfd_config->min_rx = BFD_DEF_MIN_RX;
+ p->bfd_config->min_tx = BFD_DEF_MIN_TX;
- if (status != old_status) {
- if (BGP_DEBUG(neighbor_events, NEIGHBOR_EVENTS))
- zlog_debug("[%s]: BFD %s", peer->host,
- bfd_get_status_str(status));
- }
- if ((status == BFD_STATUS_DOWN) && (old_status == BFD_STATUS_UP)) {
- if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_MODE) &&
- CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE) &&
- !remote_cbit) {
- zlog_info("%s BFD DOWN message ignored in the process of graceful restart when C bit is cleared",
- peer->host);
- return;
- }
- peer->last_reset = PEER_DOWN_BFD_DOWN;
- BGP_EVENT_ADD(peer, BGP_Stop);
- }
- if ((status == BFD_STATUS_UP) && (old_status == BFD_STATUS_DOWN)
- && peer->status != Established) {
- if (!BGP_PEER_START_SUPPRESSED(peer)) {
- bgp_fsm_nht_update(peer, true);
- BGP_EVENT_ADD(peer, BGP_Start);
- }
- }
+ for (ALL_LIST_ELEMENTS_RO(p->group->peer, n, pn))
+ bgp_peer_configure_bfd(pn, false);
}
-/*
- * bgp_bfd_dest_update - Find the peer for which the BFD status
- * has changed and bring down the peer
- * connectivity if the BFD session went down.
- */
-static int bgp_bfd_dest_update(ZAPI_CALLBACK_ARGS)
+static void bgp_group_remove_bfd(struct peer *p)
{
- struct interface *ifp;
- struct prefix dp;
- struct prefix sp;
- int status;
- int remote_cbit;
+ struct listnode *n;
+ struct peer *pn;
- ifp = bfd_get_peer_info(zclient->ibuf, &dp, &sp, &status,
- &remote_cbit, vrf_id);
+ /* Peers should not call this. */
+ assert(CHECK_FLAG(p->sflags, PEER_STATUS_GROUP));
- if (BGP_DEBUG(zebra, ZEBRA)) {
- struct vrf *vrf;
+ /* Already freed: do nothing. */
+ if (p->bfd_config == NULL)
+ return;
- vrf = vrf_lookup_by_id(vrf_id);
+ /* Free configuration and point to `NULL`. */
+ XFREE(MTYPE_BFD_CONFIG, p->bfd_config);
- if (ifp)
- zlog_debug(
- "Zebra: vrf %s(%u) interface %s bfd destination %pFX %s %s",
- VRF_LOGNAME(vrf), vrf_id, ifp->name, &dp,
- bfd_get_status_str(status),
- remote_cbit ? "(cbit on)" : "");
+ /* Now that it is `NULL` recalculate configuration for all peers. */
+ for (ALL_LIST_ELEMENTS_RO(p->group->peer, n, pn)) {
+ if (pn->bfd_config->manual)
+ bgp_peer_config_apply(pn, NULL);
else
- zlog_debug(
- "Zebra: vrf %s(%u) source %pFX bfd destination %pFX %s %s",
- VRF_LOGNAME(vrf), vrf_id, &sp, &dp,
- bfd_get_status_str(status),
- remote_cbit ? "(cbit on)" : "");
- }
-
- /* Bring the peer down if BFD is enabled in BGP */
- {
- struct listnode *mnode, *node, *nnode;
- struct bgp *bgp;
- struct peer *peer;
-
- for (ALL_LIST_ELEMENTS_RO(bm->bgp, mnode, bgp))
- for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
- if (!peer->bfd_info)
- continue;
-
- if ((dp.family == AF_INET)
- && (peer->su.sa.sa_family == AF_INET)) {
- if (dp.u.prefix4.s_addr
- != peer->su.sin.sin_addr.s_addr)
- continue;
- } else if ((dp.family == AF_INET6)
- && (peer->su.sa.sa_family
- == AF_INET6)) {
- if (memcmp(&dp.u.prefix6,
- &peer->su.sin6.sin6_addr,
- sizeof(struct in6_addr)))
- continue;
- } else
- continue;
-
- if (ifp && (ifp == peer->nexthop.ifp)) {
- bgp_bfd_peer_status_update(peer,
- status,
- remote_cbit);
- } else {
- if (!peer->su_local)
- continue;
-
- if ((sp.family == AF_INET)
- && (peer->su_local->sa.sa_family
- == AF_INET)) {
- if (sp.u.prefix4.s_addr
- != peer->su_local->sin
- .sin_addr.s_addr)
- continue;
- } else if ((sp.family == AF_INET6)
- && (peer->su_local->sa
- .sa_family
- == AF_INET6)) {
- if (memcmp(&sp.u.prefix6,
- &peer->su_local->sin6
- .sin6_addr,
- sizeof(struct
- in6_addr)))
- continue;
- } else
- continue;
-
- if ((vrf_id != VRF_DEFAULT)
- && (peer->bgp->vrf_id != vrf_id))
- continue;
-
- bgp_bfd_peer_status_update(peer,
- status,
- remote_cbit);
- }
- }
- }
-
- return 0;
-}
-
-/*
- * bgp_bfd_peer_param_set - Set the configured BFD paramter values for peer.
- */
-static int bgp_bfd_peer_param_set(struct peer *peer, uint32_t min_rx,
- uint32_t min_tx, uint8_t detect_mult,
- int defaults)
-{
- struct bfd_info *bi;
- struct peer_group *group;
- struct listnode *node, *nnode;
- int command = 0;
-
- bfd_set_param((struct bfd_info **)&(peer->bfd_info), min_rx, min_tx,
- detect_mult, NULL, defaults, &command);
-
- /* This command overrides profile if it was previously applied. */
- bi = peer->bfd_info;
- bi->profile[0] = 0;
-
- if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
- group = peer->group;
- for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
- command = 0;
- bfd_set_param((struct bfd_info **)&(peer->bfd_info),
- min_rx, min_tx, detect_mult, NULL,
- defaults, &command);
-
- /*
- * This command overrides profile if it was previously
- * applied.
- */
- bi = peer->bfd_info;
- bi->profile[0] = 0;
-
- if ((peer->status == Established)
- && (command == ZEBRA_BFD_DEST_REGISTER))
- bgp_bfd_register_peer(peer);
- else if (command == ZEBRA_BFD_DEST_UPDATE)
- bgp_bfd_update_peer(peer);
- }
- } else {
- if ((peer->status == Established)
- && (command == ZEBRA_BFD_DEST_REGISTER))
- bgp_bfd_register_peer(peer);
- else if (command == ZEBRA_BFD_DEST_UPDATE)
- bgp_bfd_update_peer(peer);
- }
- return 0;
-}
-
-/*
- * bgp_bfd_peer_param_unset - Delete the configured BFD paramter values for
- * peer.
- */
-static int bgp_bfd_peer_param_unset(struct peer *peer)
-{
- struct peer_group *group;
- struct listnode *node, *nnode;
-
- if (!peer->bfd_info)
- return 0;
-
- if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
- bfd_info_free(&(peer->bfd_info));
- group = peer->group;
- for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
- bgp_bfd_deregister_peer(peer);
- bfd_info_free(&(peer->bfd_info));
- }
- } else {
- bgp_bfd_deregister_peer(peer);
- bfd_info_free(&(peer->bfd_info));
+ bgp_peer_remove_bfd(pn);
}
- return 0;
}
-/*
- * bgp_bfd_peer_param_type_set - set the BFD session type (multihop or
- * singlehop)
- */
-static int bgp_bfd_peer_param_type_set(struct peer *peer,
- enum bfd_sess_type type)
+void bgp_peer_remove_bfd_config(struct peer *p)
{
- struct peer_group *group;
- struct listnode *node, *nnode;
- int command = 0;
- struct bfd_info *bfd_info;
-
- if (!peer->bfd_info)
- bfd_set_param((struct bfd_info **)&(peer->bfd_info),
- BFD_DEF_MIN_RX, BFD_DEF_MIN_TX,
- BFD_DEF_DETECT_MULT, NULL, 1, &command);
-
- bfd_info = (struct bfd_info *)peer->bfd_info;
- bfd_info->type = type;
-
- if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
- group = peer->group;
- for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
- command = 0;
- if (!peer->bfd_info)
- bfd_set_param(
- (struct bfd_info **)&(peer->bfd_info),
- BFD_DEF_MIN_RX, BFD_DEF_MIN_TX,
- BFD_DEF_DETECT_MULT, NULL, 1, &command);
-
- bfd_info = (struct bfd_info *)peer->bfd_info;
- bfd_info->type = type;
-
- if (peer->status == Established) {
- if (command == ZEBRA_BFD_DEST_REGISTER)
- bgp_bfd_register_peer(peer);
- else
- bgp_bfd_update_type(peer);
- }
- }
- } else {
- if (peer->status == Established) {
- if (command == ZEBRA_BFD_DEST_REGISTER)
- bgp_bfd_register_peer(peer);
- else
- bgp_bfd_update_type(peer);
- }
- }
-
- return 0;
-}
-
-#if HAVE_BFDD > 0
-/**
- * Set peer BFD profile configuration.
- */
-static int bgp_bfd_peer_set_profile(struct peer *peer, const char *profile)
-{
- struct peer_group *group;
- struct listnode *node, *nnode;
- int command = 0;
- struct bfd_info *bfd_info;
-
- bfd_set_param((struct bfd_info **)&(peer->bfd_info), BFD_DEF_MIN_RX,
- BFD_DEF_MIN_TX, BFD_DEF_DETECT_MULT, NULL, 1, &command);
-
- bfd_info = (struct bfd_info *)peer->bfd_info;
-
- /* If profile was specified, then copy string. */
- if (profile)
- strlcpy(bfd_info->profile, profile, sizeof(bfd_info->profile));
- else /* Otherwise just initialize it empty. */
- bfd_info->profile[0] = 0;
-
- if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
- group = peer->group;
- for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
- command = 0;
- bfd_set_param((struct bfd_info **)&(peer->bfd_info),
- BFD_DEF_MIN_RX, BFD_DEF_MIN_TX,
- BFD_DEF_DETECT_MULT, NULL, 1, &command);
-
- bfd_info = (struct bfd_info *)peer->bfd_info;
-
- /* If profile was specified, then copy string. */
- if (profile)
- strlcpy(bfd_info->profile, profile,
- sizeof(bfd_info->profile));
- else /* Otherwise just initialize it empty. */
- bfd_info->profile[0] = 0;
-
- if (peer->status == Established
- && command == ZEBRA_BFD_DEST_REGISTER)
- bgp_bfd_register_peer(peer);
- else if (command == ZEBRA_BFD_DEST_UPDATE)
- bgp_bfd_update_peer(peer);
- }
- } else {
- if (peer->status == Established
- && command == ZEBRA_BFD_DEST_REGISTER)
- bgp_bfd_register_peer(peer);
- else if (command == ZEBRA_BFD_DEST_UPDATE)
- bgp_bfd_update_peer(peer);
- }
-
- return 0;
+ if (CHECK_FLAG(p->sflags, PEER_STATUS_GROUP))
+ bgp_group_remove_bfd(p);
+ else
+ bgp_peer_remove_bfd(p);
}
-#endif
/*
* bgp_bfd_peer_config_write - Write the peer BFD configuration.
*/
-void bgp_bfd_peer_config_write(struct vty *vty, struct peer *peer, char *addr)
+void bgp_bfd_peer_config_write(struct vty *vty, const struct peer *peer,
+ const char *addr)
{
- struct bfd_info *bfd_info;
-
- if (!peer->bfd_info)
- return;
-
- bfd_info = (struct bfd_info *)peer->bfd_info;
-
- if (CHECK_FLAG(bfd_info->flags, BFD_FLAG_PARAM_CFG))
+ /*
+ * Always show group BFD configuration, but peer only when explicitly
+ * configured.
+ */
+ if ((!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)
+ && peer->bfd_config->manual)
+ || CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
#if HAVE_BFDD > 0
vty_out(vty, " neighbor %s bfd\n", addr);
#else
vty_out(vty, " neighbor %s bfd %d %d %d\n", addr,
- bfd_info->detect_mult, bfd_info->required_min_rx,
- bfd_info->desired_min_tx);
+ peer->bfd_config->detection_multiplier,
+ peer->bfd_config->min_rx, peer->bfd_config->min_tx);
#endif /* HAVE_BFDD */
-
- if (bfd_info->type != BFD_TYPE_NOT_CONFIGURED)
- vty_out(vty, " neighbor %s bfd %s\n", addr,
- (bfd_info->type == BFD_TYPE_MULTIHOP) ? "multihop"
- : "singlehop");
-
- if (!CHECK_FLAG(bfd_info->flags, BFD_FLAG_PARAM_CFG)
- && (bfd_info->type == BFD_TYPE_NOT_CONFIGURED)) {
- vty_out(vty, " neighbor %s bfd", addr);
- if (bfd_info->profile[0])
- vty_out(vty, " profile %s", bfd_info->profile);
- vty_out(vty, "\n");
}
- if (CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE))
- vty_out(vty, " neighbor %s bfd check-control-plane-failure\n", addr);
+ if (peer->bfd_config->profile[0])
+ vty_out(vty, " neighbor %s bfd profile %s\n", addr,
+ peer->bfd_config->profile);
+
+ if (peer->bfd_config->cbit)
+ vty_out(vty, " neighbor %s bfd check-control-plane-failure\n",
+ addr);
}
/*
* bgp_bfd_show_info - Show the peer BFD information.
*/
-void bgp_bfd_show_info(struct vty *vty, struct peer *peer, bool use_json,
+void bgp_bfd_show_info(struct vty *vty, const struct peer *peer,
json_object *json_neigh)
{
- bfd_show_info(vty, (struct bfd_info *)peer->bfd_info,
- bgp_bfd_is_peer_multihop(peer), 0, use_json, json_neigh);
+ if (peer->bfd_config->session)
+ bfd_sess_show(vty, json_neigh, peer->bfd_config->session);
}
DEFUN (neighbor_bfd,
{
int idx_peer = 1;
struct peer *peer;
- int ret;
peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
if (!peer)
return CMD_WARNING_CONFIG_FAILED;
- ret = bgp_bfd_peer_param_set(peer, BFD_DEF_MIN_RX, BFD_DEF_MIN_TX,
- BFD_DEF_DETECT_MULT, 1);
- if (ret != 0)
- return bgp_vty_return(vty, ret);
+ if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
+ bgp_group_configure_bfd(peer);
+ else
+ bgp_peer_configure_bfd(peer, true);
+
+ bgp_peer_config_apply(peer, peer->group);
return CMD_SUCCESS;
}
int idx_number_1 = 3;
int idx_number_2 = 4;
int idx_number_3 = 5;
+ long detection_multiplier, min_rx, min_tx;
struct peer *peer;
- uint32_t rx_val;
- uint32_t tx_val;
- uint8_t dm_val;
- int ret;
peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
if (!peer)
return CMD_WARNING_CONFIG_FAILED;
- if ((ret = bfd_validate_param(
- vty, argv[idx_number_1]->arg, argv[idx_number_2]->arg,
- argv[idx_number_3]->arg, &dm_val, &rx_val, &tx_val))
- != CMD_SUCCESS)
- return ret;
-
- ret = bgp_bfd_peer_param_set(peer, rx_val, tx_val, dm_val, 0);
- if (ret != 0)
- return bgp_vty_return(vty, ret);
-
- return CMD_SUCCESS;
-}
-
-DEFUN_HIDDEN (neighbor_bfd_type,
- neighbor_bfd_type_cmd,
- "neighbor <A.B.C.D|X:X::X:X|WORD> bfd <multihop|singlehop>",
- NEIGHBOR_STR
- NEIGHBOR_ADDR_STR2
- "Enables BFD support\n"
- "Multihop session\n"
- "Single hop session\n")
-{
- int idx_peer = 1;
- int idx_hop = 3;
- struct peer *peer;
- enum bfd_sess_type type;
- int ret;
-
- peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
- if (!peer)
- return CMD_WARNING_CONFIG_FAILED;
+ detection_multiplier = strtol(argv[idx_number_1]->arg, NULL, 10);
+ min_rx = strtol(argv[idx_number_2]->arg, NULL, 10);
+ min_tx = strtol(argv[idx_number_3]->arg, NULL, 10);
- if (strmatch(argv[idx_hop]->text, "singlehop"))
- type = BFD_TYPE_SINGLEHOP;
- else if (strmatch(argv[idx_hop]->text, "multihop"))
- type = BFD_TYPE_MULTIHOP;
+ if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
+ bgp_group_configure_bfd(peer);
else
- return CMD_WARNING_CONFIG_FAILED;
-
- ret = bgp_bfd_peer_param_type_set(peer, type);
- if (ret != 0)
- return bgp_vty_return(vty, ret);
+ bgp_peer_configure_bfd(peer, true);
- return CMD_SUCCESS;
-}
-
-static int bgp_bfd_set_check_controlplane_failure_peer(struct vty *vty, struct peer *peer,
- const char *no)
-{
- struct bfd_info *bfd_info;
+ peer->bfd_config->detection_multiplier = detection_multiplier;
+ peer->bfd_config->min_rx = min_rx;
+ peer->bfd_config->min_tx = min_tx;
+ bgp_peer_config_apply(peer, peer->group);
- if (!peer->bfd_info) {
- if (no)
- return CMD_SUCCESS;
- vty_out(vty, "%% Specify bfd command first\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- bfd_info = (struct bfd_info *)peer->bfd_info;
- if (!no) {
- if (!CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE)) {
- SET_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE);
- bgp_bfd_update_peer(peer);
- }
- } else {
- if (CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE)) {
- UNSET_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE);
- bgp_bfd_update_peer(peer);
- }
- }
return CMD_SUCCESS;
}
-
DEFUN (neighbor_bfd_check_controlplane_failure,
neighbor_bfd_check_controlplane_failure_cmd,
"[no] neighbor <A.B.C.D|X:X::X:X|WORD> bfd check-control-plane-failure",
const char *no = strmatch(argv[0]->text, "no") ? "no" : NULL;
int idx_peer = 0;
struct peer *peer;
- struct peer_group *group;
- struct listnode *node, *nnode;
- int ret = CMD_SUCCESS;
if (no)
idx_peer = 2;
vty_out(vty, "%% Specify remote-as or peer-group commands first\n");
return CMD_WARNING_CONFIG_FAILED;
}
- if (!peer->bfd_info) {
- if (no)
- return CMD_SUCCESS;
- vty_out(vty, "%% Specify bfd command first\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
- group = peer->group;
- for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer))
- ret = bgp_bfd_set_check_controlplane_failure_peer(vty, peer, no);
- } else
- ret = bgp_bfd_set_check_controlplane_failure_peer(vty, peer, no);
- return ret;
+
+ if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
+ bgp_group_configure_bfd(peer);
+ else
+ bgp_peer_configure_bfd(peer, true);
+
+ peer->bfd_config->cbit = no == NULL;
+ bgp_peer_config_apply(peer, peer->group);
+
+ return CMD_SUCCESS;
}
DEFUN (no_neighbor_bfd,
{
int idx_peer = 2;
struct peer *peer;
- int ret;
peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
if (!peer)
return CMD_WARNING_CONFIG_FAILED;
- ret = bgp_bfd_peer_param_unset(peer);
- if (ret != 0)
- return bgp_vty_return(vty, ret);
-
- return CMD_SUCCESS;
-}
-
-
-DEFUN_HIDDEN (no_neighbor_bfd_type,
- no_neighbor_bfd_type_cmd,
- "no neighbor <A.B.C.D|X:X::X:X|WORD> bfd <multihop|singlehop>",
- NO_STR
- NEIGHBOR_STR
- NEIGHBOR_ADDR_STR2
- "Disables BFD support\n"
- "Multihop session\n"
- "Singlehop session\n")
-{
- int idx_peer = 2;
- struct peer *peer;
- int ret;
-
- peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
- if (!peer)
- return CMD_WARNING_CONFIG_FAILED;
-
- if (!peer->bfd_info)
- return 0;
-
- ret = bgp_bfd_peer_param_type_set(peer, BFD_TYPE_NOT_CONFIGURED);
- if (ret != 0)
- return bgp_vty_return(vty, ret);
+ if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
+ bgp_group_remove_bfd(peer);
+ else
+ bgp_peer_remove_bfd(peer);
return CMD_SUCCESS;
}
{
int idx_peer = 1, idx_prof = 4;
struct peer *peer;
- int ret;
peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
if (!peer)
return CMD_WARNING_CONFIG_FAILED;
- ret = bgp_bfd_peer_set_profile(peer, argv[idx_prof]->arg);
- if (ret != 0)
- return bgp_vty_return(vty, ret);
+ if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
+ bgp_group_configure_bfd(peer);
+ else
+ bgp_peer_configure_bfd(peer, true);
+
+ strlcpy(peer->bfd_config->profile, argv[idx_prof]->arg,
+ sizeof(peer->bfd_config->profile));
+ bgp_peer_config_apply(peer, peer->group);
return CMD_SUCCESS;
}
{
int idx_peer = 2;
struct peer *peer;
- int ret;
peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
if (!peer)
return CMD_WARNING_CONFIG_FAILED;
- if (!peer->bfd_info)
- return 0;
+ if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
+ bgp_group_configure_bfd(peer);
+ else
+ bgp_peer_configure_bfd(peer, true);
- ret = bgp_bfd_peer_set_profile(peer, NULL);
- if (ret != 0)
- return bgp_vty_return(vty, ret);
+ peer->bfd_config->profile[0] = 0;
+ bgp_peer_config_apply(peer, peer->group);
return CMD_SUCCESS;
}
#endif /* HAVE_BFDD */
-void bgp_bfd_init(void)
+void bgp_bfd_init(struct thread_master *tm)
{
- bfd_gbl_init();
-
/* Initialize BFD client functions */
- zclient->interface_bfd_dest_update = bgp_bfd_dest_update;
- zclient->bfd_dest_replay = bgp_bfd_dest_replay;
+ bfd_protocol_integration_init(zclient, tm);
/* "neighbor bfd" commands. */
install_element(BGP_NODE, &neighbor_bfd_cmd);
install_element(BGP_NODE, &neighbor_bfd_param_cmd);
- install_element(BGP_NODE, &neighbor_bfd_type_cmd);
install_element(BGP_NODE, &neighbor_bfd_check_controlplane_failure_cmd);
install_element(BGP_NODE, &no_neighbor_bfd_cmd);
- install_element(BGP_NODE, &no_neighbor_bfd_type_cmd);
#if HAVE_BFDD > 0
install_element(BGP_NODE, &neighbor_bfd_profile_cmd);
#ifndef _QUAGGA_BGP_BFD_H
#define _QUAGGA_BGP_BFD_H
-extern void bgp_bfd_init(void);
+#define PEER_IS_MULTIHOP(peer) \
+ ((((peer)->sort == BGP_PEER_IBGP) && !(peer)->shared_network) \
+ || is_ebgp_multihop_configured((peer)))
-extern void bgp_bfd_peer_group2peer_copy(struct peer *conf, struct peer *peer);
+extern void bgp_bfd_init(struct thread_master *tm);
-extern void bgp_bfd_register_peer(struct peer *peer);
+extern void bgp_bfd_peer_config_write(struct vty *vty, const struct peer *peer,
+ const char *addr);
-extern void bgp_bfd_deregister_peer(struct peer *peer);
+/**
+ * Show BFD information helper.
+ *
+ * \param vty the VTY pointer.
+ * \param peer the BGP configuration pointer.
+ * \param use_json unused.
+ * \param json_neigh JSON object when called as JSON command.
+ */
+extern void bgp_bfd_show_info(struct vty *vty, const struct peer *peer,
+ json_object *json_neigh);
-extern void bgp_bfd_reset_peer(struct peer *peer);
+/**
+ * When called on a group it applies configuration to all peers in that group,
+ * otherwise just applies the configuration to a single peer.
+ *
+ * This function should be called when configuration changes either on group
+ * or peer.
+ *
+ * \param p the BGP peer pointer.
+ * \param pg the BGP group to copy configuration from (it is usually
+ * `p->group` exception when copying new group configuration
+ * see `peer_group2peer_config_copy` function case).
+ */
+extern void bgp_peer_config_apply(struct peer *p, struct peer_group *pg);
-extern void bgp_bfd_peer_config_write(struct vty *vty, struct peer *peer,
- char *addr);
+/**
+ * Allocates and configure BFD session for peer. If it is already configured,
+ * then it does nothing.
+ *
+ * Always call `bgp_peer_config_apply` afterwards if you need the changes
+ * immediately applied.
+ */
+extern void bgp_peer_configure_bfd(struct peer *p, bool manual);
-extern void bgp_bfd_show_info(struct vty *vty, struct peer *peer, bool use_json,
- json_object *json_neigh);
+/**
+ * Removes BFD configuration from either peer or peer group.
+ */
+extern void bgp_peer_remove_bfd_config(struct peer *p);
-extern bool bgp_bfd_is_peer_multihop(struct peer *peer);
+/**
+ * Special function to handle the case of changing source address. This
+ * happens when the peer/group is configured with `neigbor X update-source Y`.
+ */
+extern void bgp_peer_bfd_update_source(struct peer *p);
#endif /* _QUAGGA_BGP_BFD_H */
static void bmp_active_disconnected(struct bmp_active *ba);
static void bmp_active_put(struct bmp_active *ba);
-DEFINE_MGROUP(BMP, "BMP (BGP Monitoring Protocol)")
-
-DEFINE_MTYPE_STATIC(BMP, BMP_CONN, "BMP connection state")
-DEFINE_MTYPE_STATIC(BMP, BMP_TARGETS, "BMP targets")
-DEFINE_MTYPE_STATIC(BMP, BMP_TARGETSNAME, "BMP targets name")
-DEFINE_MTYPE_STATIC(BMP, BMP_LISTENER, "BMP listener")
-DEFINE_MTYPE_STATIC(BMP, BMP_ACTIVE, "BMP active connection config")
-DEFINE_MTYPE_STATIC(BMP, BMP_ACLNAME, "BMP access-list name")
-DEFINE_MTYPE_STATIC(BMP, BMP_QUEUE, "BMP update queue item")
-DEFINE_MTYPE_STATIC(BMP, BMP, "BMP instance state")
-DEFINE_MTYPE_STATIC(BMP, BMP_MIRRORQ, "BMP route mirroring buffer")
-DEFINE_MTYPE_STATIC(BMP, BMP_PEER, "BMP per BGP peer data")
-DEFINE_MTYPE_STATIC(BMP, BMP_OPEN, "BMP stored BGP OPEN message")
-
-DEFINE_QOBJ_TYPE(bmp_targets)
+DEFINE_MGROUP(BMP, "BMP (BGP Monitoring Protocol)");
+
+DEFINE_MTYPE_STATIC(BMP, BMP_CONN, "BMP connection state");
+DEFINE_MTYPE_STATIC(BMP, BMP_TARGETS, "BMP targets");
+DEFINE_MTYPE_STATIC(BMP, BMP_TARGETSNAME, "BMP targets name");
+DEFINE_MTYPE_STATIC(BMP, BMP_LISTENER, "BMP listener");
+DEFINE_MTYPE_STATIC(BMP, BMP_ACTIVE, "BMP active connection config");
+DEFINE_MTYPE_STATIC(BMP, BMP_ACLNAME, "BMP access-list name");
+DEFINE_MTYPE_STATIC(BMP, BMP_QUEUE, "BMP update queue item");
+DEFINE_MTYPE_STATIC(BMP, BMP, "BMP instance state");
+DEFINE_MTYPE_STATIC(BMP, BMP_MIRRORQ, "BMP route mirroring buffer");
+DEFINE_MTYPE_STATIC(BMP, BMP_PEER, "BMP per BGP peer data");
+DEFINE_MTYPE_STATIC(BMP, BMP_OPEN, "BMP stored BGP OPEN message");
+
+DEFINE_QOBJ_TYPE(bmp_targets);
static int bmp_bgp_cmp(const struct bmp_bgp *a, const struct bmp_bgp *b)
{
return jhash(&e->bgp, sizeof(e->bgp), 0x55aa5a5a);
}
-DECLARE_HASH(bmp_bgph, struct bmp_bgp, bbi, bmp_bgp_cmp, bmp_bgp_hash)
+DECLARE_HASH(bmp_bgph, struct bmp_bgp, bbi, bmp_bgp_cmp, bmp_bgp_hash);
struct bmp_bgph_head bmp_bgph;
}
DECLARE_HASH(bmp_peerh, struct bmp_bgp_peer, bpi,
- bmp_bgp_peer_cmp, bmp_bgp_peer_hash)
+ bmp_bgp_peer_cmp, bmp_bgp_peer_hash);
struct bmp_peerh_head bmp_peerh;
-DECLARE_LIST(bmp_mirrorq, struct bmp_mirrorq, bmi)
+DECLARE_LIST(bmp_mirrorq, struct bmp_mirrorq, bmi);
/* listener management */
return 0;
}
-DECLARE_SORTLIST_UNIQ(bmp_listeners, struct bmp_listener, bli, bmp_listener_cmp)
+DECLARE_SORTLIST_UNIQ(bmp_listeners, struct bmp_listener, bli,
+ bmp_listener_cmp);
static int bmp_targets_cmp(const struct bmp_targets *a,
const struct bmp_targets *b)
return strcmp(a->name, b->name);
}
-DECLARE_SORTLIST_UNIQ(bmp_targets, struct bmp_targets, bti, bmp_targets_cmp)
+DECLARE_SORTLIST_UNIQ(bmp_targets, struct bmp_targets, bti, bmp_targets_cmp);
-DECLARE_LIST(bmp_session, struct bmp, bsi)
+DECLARE_LIST(bmp_session, struct bmp, bsi);
-DECLARE_DLIST(bmp_qlist, struct bmp_queue_entry, bli)
+DECLARE_DLIST(bmp_qlist, struct bmp_queue_entry, bli);
static int bmp_qhash_cmp(const struct bmp_queue_entry *a,
const struct bmp_queue_entry *b)
}
DECLARE_HASH(bmp_qhash, struct bmp_queue_entry, bhi,
- bmp_qhash_cmp, bmp_qhash_hkey)
+ bmp_qhash_cmp, bmp_qhash_hkey);
static int bmp_active_cmp(const struct bmp_active *a,
const struct bmp_active *b)
return 0;
}
-DECLARE_SORTLIST_UNIQ(bmp_actives, struct bmp_active, bai, bmp_active_cmp)
+DECLARE_SORTLIST_UNIQ(bmp_actives, struct bmp_active, bai, bmp_active_cmp);
static struct bmp *bmp_new(struct bmp_targets *bt, int bmp_sock)
{
FRR_MODULE_SETUP(.name = "bgpd_bmp", .version = FRR_VERSION,
.description = "bgpd BMP module",
- .init = bgp_bmp_module_init)
+ .init = bgp_bmp_module_init,
+);
* always happens from the front of the queue.)
*/
-PREDECL_DLIST(bmp_qlist)
-PREDECL_HASH(bmp_qhash)
+PREDECL_DLIST(bmp_qlist);
+PREDECL_HASH(bmp_qhash);
struct bmp_queue_entry {
struct bmp_qlist_item bli;
* with a size limit. Refcount works the same as for monitoring above.
*/
-PREDECL_LIST(bmp_mirrorq)
+PREDECL_LIST(bmp_mirrorq);
struct bmp_mirrorq {
struct bmp_mirrorq_item bmi;
BMP_AFI_LIVE,
};
-PREDECL_LIST(bmp_session)
+PREDECL_LIST(bmp_session);
struct bmp_active;
struct bmp_targets;
* succeeds, "bmp" is set up.
*/
-PREDECL_SORTLIST_UNIQ(bmp_actives)
+PREDECL_SORTLIST_UNIQ(bmp_actives);
#define BMP_DFLT_MINRETRY 30000
#define BMP_DFLT_MAXRETRY 720000
};
/* config & state for passive / listening sockets */
-PREDECL_SORTLIST_UNIQ(bmp_listeners)
+PREDECL_SORTLIST_UNIQ(bmp_listeners);
struct bmp_listener {
struct bmp_listeners_item bli;
* bmp_active items. If they have the same config, BMP session should be
* put in the same targets since that's a bit more effective.
*/
-PREDECL_SORTLIST_UNIQ(bmp_targets)
+PREDECL_SORTLIST_UNIQ(bmp_targets);
struct bmp_targets {
struct bmp_targets_item bti;
uint64_t cnt_accept, cnt_aclrefused;
- QOBJ_FIELDS
+ QOBJ_FIELDS;
};
-DECLARE_QOBJ_TYPE(bmp_targets)
+DECLARE_QOBJ_TYPE(bmp_targets);
/* per struct peer * data. Lookup by peer->qobj_node.nid, created on demand,
* deleted in peer_backward hook. */
-PREDECL_HASH(bmp_peerh)
+PREDECL_HASH(bmp_peerh);
struct bmp_bgp_peer {
struct bmp_peerh_item bpi;
};
/* per struct bgp * data */
-PREDECL_HASH(bmp_bgph)
+PREDECL_HASH(bmp_bgph);
#define BMP_PEER_DOWN_NO_RELEVANT_EVENT_CODE 0x00
BMP_STATS_FRR_NH_INVALID = 65531,
};
-DECLARE_MGROUP(BMP)
+DECLARE_MGROUP(BMP);
#endif /*_BGP_BMP_H_*/
#include <zebra.h>
#include <lib/version.h>
+#include "lib/bfd.h"
#include "lib/printfrr.h"
#include "prefix.h"
#include "linklist.h"
unsigned long conf_bgp_debug_pbr;
unsigned long conf_bgp_debug_graceful_restart;
unsigned long conf_bgp_debug_evpn_mh;
+unsigned long conf_bgp_debug_bfd;
unsigned long term_bgp_debug_as4;
unsigned long term_bgp_debug_neighbor_events;
unsigned long term_bgp_debug_pbr;
unsigned long term_bgp_debug_graceful_restart;
unsigned long term_bgp_debug_evpn_mh;
+unsigned long term_bgp_debug_bfd;
struct list *bgp_debug_neighbor_events_peers = NULL;
struct list *bgp_debug_keepalive_peers = NULL;
return CMD_SUCCESS;
}
+DEFPY(debug_bgp_bfd, debug_bgp_bfd_cmd,
+ "[no] debug bgp bfd",
+ NO_STR
+ DEBUG_STR
+ BGP_STR
+ "Bidirection Forwarding Detection\n")
+{
+ if (vty->node == CONFIG_NODE) {
+ if (no) {
+ DEBUG_OFF(bfd, BFD_LIB);
+ bfd_protocol_integration_set_debug(false);
+ } else {
+ DEBUG_ON(bfd, BFD_LIB);
+ bfd_protocol_integration_set_debug(true);
+ }
+ } else {
+ if (no)
+ TERM_DEBUG_OFF(bfd, BFD_LIB);
+ else
+ TERM_DEBUG_ON(bfd, BFD_LIB);
+ }
+
+ return CMD_SUCCESS;
+}
+
DEFUN (no_debug_bgp,
no_debug_bgp_cmd,
"no debug bgp",
TERM_DEBUG_OFF(graceful_restart, GRACEFUL_RESTART);
TERM_DEBUG_OFF(evpn_mh, EVPN_MH_ES);
TERM_DEBUG_OFF(evpn_mh, EVPN_MH_RT);
+ TERM_DEBUG_OFF(bfd, BFD_LIB);
vty_out(vty, "All possible debugging has been turned off\n");
if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
vty_out(vty, " BGP EVPN-MH route debugging is on\n");
+ if (BGP_DEBUG(bfd, BFD_LIB))
+ vty_out(vty, " BGP BFD library debugging is on\n");
+
vty_out(vty, "\n");
return CMD_SUCCESS;
}
write++;
}
+ if (CONF_BGP_DEBUG(bfd, BFD_LIB)) {
+ vty_out(vty, "debug bgp bfd\n");
+ write++;
+ }
+
return write;
}
install_element(ENABLE_NODE, &debug_bgp_evpn_mh_cmd);
install_element(CONFIG_NODE, &debug_bgp_evpn_mh_cmd);
+
+ /* debug bgp bfd */
+ install_element(ENABLE_NODE, &debug_bgp_bfd_cmd);
+ install_element(CONFIG_NODE, &debug_bgp_bfd_cmd);
}
/* Return true if this prefix is on the per_prefix_list of prefixes to debug
extern unsigned long conf_bgp_debug_pbr;
extern unsigned long conf_bgp_debug_graceful_restart;
extern unsigned long conf_bgp_debug_evpn_mh;
+extern unsigned long conf_bgp_debug_bfd;
extern unsigned long term_bgp_debug_as4;
extern unsigned long term_bgp_debug_neighbor_events;
extern unsigned long term_bgp_debug_pbr;
extern unsigned long term_bgp_debug_graceful_restart;
extern unsigned long term_bgp_debug_evpn_mh;
+extern unsigned long term_bgp_debug_bfd;
extern struct list *bgp_debug_neighbor_events_peers;
extern struct list *bgp_debug_keepalive_peers;
#define BGP_DEBUG_GRACEFUL_RESTART 0x01
+#define BGP_DEBUG_BFD_LIB 0x01
+
#define CONF_DEBUG_ON(a, b) (conf_bgp_debug_ ## a |= (BGP_DEBUG_ ## b))
#define CONF_DEBUG_OFF(a, b) (conf_bgp_debug_ ## a &= ~(BGP_DEBUG_ ## b))
/*
* Definitions and external declarations.
*/
-DEFINE_QOBJ_TYPE(bgpevpn)
-DEFINE_QOBJ_TYPE(bgp_evpn_es)
+DEFINE_QOBJ_TYPE(bgpevpn);
+DEFINE_QOBJ_TYPE(bgp_evpn_es);
/*
int ret;
struct prefix_evpn p;
+ update_type1_routes_for_evi(bgp, vpn);
+
/* Update and advertise the type-3 route (only one) followed by the
* locally learnt type-2 routes (MACIP) - for this VNI.
*
return ret;
ret = install_uninstall_routes_for_vni(bgp, vpn, BGP_EVPN_AD_ROUTE,
- 1);
+ 0);
if (ret)
return ret;
return 0;
}
+/*
+ * This function is called when the export RT for a VNI changes.
+ * Update all type-1 local routes for this VNI from VNI/ES tables and the global
+ * table and advertise these routes to peers.
+ */
+
+void update_type1_routes_for_evi(struct bgp *bgp, struct bgpevpn *vpn)
+{
+ struct prefix_evpn p;
+ struct bgp_evpn_es *es;
+ struct bgp_evpn_es_evi *es_evi;
+ struct bgp_evpn_es_evi *es_evi_next;
+
+ RB_FOREACH_SAFE(es_evi, bgp_es_evi_rb_head,
+ &vpn->es_evi_rb_tree, es_evi_next) {
+ es = es_evi->es;
+
+ /* Update EAD-ES */
+ if (CHECK_FLAG(es->flags, BGP_EVPNES_OPER_UP)) {
+ build_evpn_type1_prefix(&p, BGP_EVPN_AD_ES_ETH_TAG,
+ &es->esi, es->originator_ip);
+ if (bgp_evpn_type1_route_update(bgp, es, NULL, &p))
+ flog_err(EC_BGP_EVPN_ROUTE_CREATE,
+ "%u: EAD-ES route update failure for ESI %s VNI %u",
+ bgp->vrf_id, es->esi_str,
+ es_evi->vpn->vni);
+ }
+
+ /* Update EAD-EVI */
+ if (CHECK_FLAG(es->flags, BGP_EVPNES_ADV_EVI)) {
+ build_evpn_type1_prefix(&p, BGP_EVPN_AD_EVI_ETH_TAG,
+ &es->esi, es->originator_ip);
+ if (bgp_evpn_type1_route_update(bgp, es, es_evi->vpn,
+ &p))
+ flog_err(EC_BGP_EVPN_ROUTE_DELETE,
+ "%u: EAD-EVI route update failure for ESI %s VNI %u",
+ bgp->vrf_id, es->esi_str,
+ es_evi->vpn->vni);
+ }
+ }
+}
+
/* Delete local Type-1 route */
static int bgp_evpn_type1_es_route_delete(struct bgp *bgp,
struct bgp_evpn_es *es, struct prefix_evpn *p)
XFREE(MTYPE_BGP_EVPN_MH_INFO, bgp_mh_info);
}
+
+/* This function is called when disable-ead-evi-rx knob flaps */
+void bgp_evpn_switch_ead_evi_rx(void)
+{
+ struct bgp *bgp;
+ struct bgp_evpn_es *es;
+ struct bgp_evpn_es_evi *es_evi;
+ struct listnode *evi_node = NULL;
+ struct listnode *evi_next = NULL;
+ struct bgp_evpn_es_evi_vtep *vtep;
+ struct listnode *vtep_node = NULL;
+ struct listnode *vtep_next = NULL;
+
+ bgp = bgp_get_evpn();
+ if (!bgp)
+ return;
+
+ /*
+ * Process all the remote es_evi_vteps and reevaluate if the es_evi_vtep
+ * is active.
+ */
+ RB_FOREACH(es, bgp_es_rb_head, &bgp_mh_info->es_rb_tree) {
+ if (!CHECK_FLAG(es->flags, BGP_EVPNES_REMOTE))
+ continue;
+
+ for (ALL_LIST_ELEMENTS(es->es_evi_list, evi_node, evi_next,
+ es_evi)) {
+ if (!CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_REMOTE))
+ continue;
+
+ for (ALL_LIST_ELEMENTS(es_evi->es_evi_vtep_list,
+ vtep_node, vtep_next, vtep))
+ bgp_evpn_es_evi_vtep_re_eval_active(bgp, vtep);
+ }
+ }
+}
/* preference config for BUM-DF election. advertised via the ESR. */
uint16_t df_pref;
- QOBJ_FIELDS
+ QOBJ_FIELDS;
};
-DECLARE_QOBJ_TYPE(bgp_evpn_es)
+DECLARE_QOBJ_TYPE(bgp_evpn_es);
RB_HEAD(bgp_es_rb_head, bgp_evpn_es);
RB_PROTOTYPE(bgp_es_rb_head, bgp_evpn_es, rb_node, bgp_es_rb_cmp);
struct bgp_evpn_es *es, afi_t afi, safi_t safi,
struct prefix_evpn *evp, struct bgp_path_info *pi,
int install);
+extern void update_type1_routes_for_evi(struct bgp *bgp, struct bgpevpn *vpn);
int bgp_evpn_type1_route_process(struct peer *peer, afi_t afi, safi_t safi,
struct attr *attr, uint8_t *pfx, int psize,
uint32_t addpath_id);
extern void bgp_evpn_es_vrf_show(struct vty *vty, bool uj,
struct bgp_evpn_es *es);
extern void bgp_evpn_es_vrf_show_esi(struct vty *vty, esi_t *esi, bool uj);
+extern void bgp_evpn_switch_ead_evi_rx(void);
#endif /* _FRR_BGP_EVPN_MH_H */
/* List of local ESs */
struct list *local_es_evi_list;
- QOBJ_FIELDS
+ QOBJ_FIELDS;
};
-DECLARE_QOBJ_TYPE(bgpevpn)
+DECLARE_QOBJ_TYPE(bgpevpn);
/* Mapping of Import RT to VNIs.
* The Import RTs of all VNIs are maintained in a hash table with each
NO_STR
"Activate PE on EAD-ES even if EAD-EVI is not received\n")
{
- bgp_mh_info->ead_evi_rx = no? true :false;
+ bool ead_evi_rx = no? true :false;
+
+ if (ead_evi_rx != bgp_mh_info->ead_evi_rx) {
+ bgp_mh_info->ead_evi_rx = ead_evi_rx;
+ bgp_evpn_switch_ead_evi_rx();
+ }
return CMD_SUCCESS;
}
regex_t *reg;
char *reg_str;
+
+ /* Sequence number. */
+ int64_t seq;
};
/* AS path filter list. */
struct as_filter *tail;
};
+
+/* Calculate new sequential number. */
+static int64_t bgp_alist_new_seq_get(struct as_list *list)
+{
+ int64_t maxseq;
+ int64_t newseq;
+ struct as_filter *entry;
+
+ maxseq = 0;
+
+ for (entry = list->head; entry; entry = entry->next) {
+ if (maxseq < entry->seq)
+ maxseq = entry->seq;
+ }
+
+ newseq = ((maxseq / 5) * 5) + 5;
+
+ return (newseq > UINT_MAX) ? UINT_MAX : newseq;
+}
+
+/* Return as-list entry which has same seq number. */
+static struct as_filter *bgp_aslist_seq_check(struct as_list *list, int64_t seq)
+{
+ struct as_filter *entry;
+
+ for (entry = list->head; entry; entry = entry->next)
+ if (entry->seq == seq)
+ return entry;
+
+ return NULL;
+}
+
/* as-path access-list 10 permit AS1. */
static struct as_list_master as_list_master = {{NULL, NULL},
return NULL;
}
+static void as_filter_entry_replace(struct as_list *list,
+ struct as_filter *replace,
+ struct as_filter *entry)
+{
+ if (replace->next) {
+ entry->next = replace->next;
+ replace->next->prev = entry;
+ } else {
+ entry->next = NULL;
+ list->tail = entry;
+ }
+
+ if (replace->prev) {
+ entry->prev = replace->prev;
+ replace->prev->next = entry;
+ } else {
+ entry->prev = NULL;
+ list->head = entry;
+ }
+
+ as_filter_free(replace);
+}
+
static void as_list_filter_add(struct as_list *aslist,
struct as_filter *asfilter)
{
- asfilter->next = NULL;
- asfilter->prev = aslist->tail;
+ struct as_filter *point;
+ struct as_filter *replace;
- if (aslist->tail)
- aslist->tail->next = asfilter;
- else
- aslist->head = asfilter;
- aslist->tail = asfilter;
+ if (aslist->tail && asfilter->seq > aslist->tail->seq)
+ point = NULL;
+ else {
+ replace = bgp_aslist_seq_check(aslist, asfilter->seq);
+ if (replace) {
+ as_filter_entry_replace(aslist, replace, asfilter);
+ return;
+ }
+
+ /* Check insert point. */
+ for (point = aslist->head; point; point = point->next)
+ if (point->seq >= asfilter->seq)
+ break;
+ }
+
+ asfilter->next = point;
+
+ if (point) {
+ if (point->prev)
+ point->prev->next = asfilter;
+ else
+ aslist->head = asfilter;
+
+ asfilter->prev = point->prev;
+ point->prev = asfilter;
+ } else {
+ if (aslist->tail)
+ aslist->tail->next = asfilter;
+ else
+ aslist->head = asfilter;
+
+ asfilter->prev = aslist->tail;
+ aslist->tail = asfilter;
+ }
/* Run hook function. */
if (as_list_master.add_hook)
}
DEFUN(as_path, bgp_as_path_cmd,
- "bgp as-path access-list WORD <deny|permit> LINE...",
+ "bgp as-path access-list WORD [seq (0-4294967295)] <deny|permit> LINE...",
BGP_STR
"BGP autonomous system path filter\n"
"Specify an access list name\n"
"Regular expression access list name\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"A regular-expression (1234567890_^|[,{}() ]$*+.?-\\) to match the BGP AS paths\n")
struct as_list *aslist;
regex_t *regex;
char *regstr;
+ int64_t seqnum = ASPATH_SEQ_NUMBER_AUTO;
/* Retrieve access list name */
argv_find(argv, argc, "WORD", &idx);
char *alname = argv[idx]->arg;
+ if (argv_find(argv, argc, "(0-4294967295)", &idx))
+ seqnum = (int64_t)atol(argv[idx]->arg);
+
/* Check the filter type. */
type = argv_find(argv, argc, "deny", &idx) ? AS_FILTER_DENY
: AS_FILTER_PERMIT;
/* Install new filter to the access_list. */
aslist = as_list_get(alname);
+ if (seqnum == ASPATH_SEQ_NUMBER_AUTO)
+ seqnum = bgp_alist_new_seq_get(aslist);
+
+ asfilter->seq = seqnum;
+
/* Duplicate insertion check. */;
if (as_list_dup_check(aslist, asfilter))
as_filter_free(asfilter);
}
DEFUN(no_as_path, no_bgp_as_path_cmd,
- "no bgp as-path access-list WORD <deny|permit> LINE...",
+ "no bgp as-path access-list WORD [seq (0-4294967295)] <deny|permit> LINE...",
NO_STR
BGP_STR
"BGP autonomous system path filter\n"
"Specify an access list name\n"
"Regular expression access list name\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"A regular-expression (1234567890_^|[,{}() ]$*+.?-\\) to match the BGP AS paths\n")
for (aslist = as_list_master.num.head; aslist; aslist = aslist->next)
for (asfilter = aslist->head; asfilter;
asfilter = asfilter->next) {
- vty_out(vty, "bgp as-path access-list %s %s %s\n",
- aslist->name, filter_type_str(asfilter->type),
+ vty_out(vty,
+ "bgp as-path access-list %s seq %" PRId64
+ " %s %s\n",
+ aslist->name, asfilter->seq,
+ filter_type_str(asfilter->type),
asfilter->reg_str);
write++;
}
for (aslist = as_list_master.str.head; aslist; aslist = aslist->next)
for (asfilter = aslist->head; asfilter;
asfilter = asfilter->next) {
- vty_out(vty, "bgp as-path access-list %s %s %s\n",
- aslist->name, filter_type_str(asfilter->type),
+ vty_out(vty,
+ "bgp as-path access-list %s seq %" PRId64
+ " %s %s\n",
+ aslist->name, asfilter->seq,
+ filter_type_str(asfilter->type),
asfilter->reg_str);
write++;
}
#ifndef _QUAGGA_BGP_FILTER_H
#define _QUAGGA_BGP_FILTER_H
+#define ASPATH_SEQ_NUMBER_AUTO -1
+
enum as_filter_type { AS_FILTER_DENY, AS_FILTER_PERMIT };
extern void bgp_filter_init(void);
#include "bgpd/bgp_zebra.h"
#include "bgpd/bgp_vty.h"
-DEFINE_HOOK(peer_backward_transition, (struct peer * peer), (peer))
-DEFINE_HOOK(peer_status_changed, (struct peer * peer), (peer))
+DEFINE_HOOK(peer_backward_transition, (struct peer * peer), (peer));
+DEFINE_HOOK(peer_status_changed, (struct peer * peer), (peer));
/* Definition of display strings corresponding to FSM events. This should be
* kept consistent with the events defined in bgpd.h
bgp_reads_on(peer);
bgp_writes_on(peer);
- thread_add_timer_msec(bm->master, bgp_process_packet, peer, 0,
- &peer->t_process_packet);
+ thread_add_event(bm->master, bgp_process_packet, peer, 0,
+ &peer->t_process_packet);
return (peer);
}
peer->nsf_af_count = 0;
/* deregister peer */
- if (peer->last_reset == PEER_DOWN_UPDATE_SOURCE_CHANGE)
- bgp_bfd_deregister_peer(peer);
+ if (peer->bfd_config
+ && peer->last_reset == PEER_DOWN_UPDATE_SOURCE_CHANGE)
+ bfd_sess_uninstall(peer->bfd_config->session);
if (peer_dynamic_neighbor(peer)
&& !(CHECK_FLAG(peer->flags, PEER_FLAG_DELETE))) {
hash_release(peer->bgp->peerhash, peer);
hash_get(peer->bgp->peerhash, peer, hash_alloc_intern);
- bgp_bfd_reset_peer(peer);
+ /* Start BFD peer if not already running. */
+ if (peer->bfd_config)
+ bgp_peer_bfd_update_source(peer);
+
return ret;
}
extern void bgp_adjust_routeadv(struct peer *);
#include "hook.h"
-DECLARE_HOOK(peer_backward_transition, (struct peer *peer), (peer))
-DECLARE_HOOK(peer_established, (struct peer *peer), (peer))
+DECLARE_HOOK(peer_backward_transition, (struct peer *peer), (peer));
+DECLARE_HOOK(peer_established, (struct peer *peer), (peer));
int bgp_gr_update_all(struct bgp *bgp, int global_gr_cmd);
int bgp_neighbor_graceful_restart(struct peer *peer, int peer_gr_cmd);
thread_add_read(fpt->master, bgp_process_reads, peer, peer->fd,
&peer->t_read);
if (added_pkt)
- thread_add_timer_msec(bm->master, bgp_process_packet,
- peer, 0, &peer->t_process_packet);
+ thread_add_event(bm->master, bgp_process_packet,
+ peer, 0, &peer->t_process_packet);
}
return 0;
/* request this many labels at a time from zebra */
#define LP_CHUNK_SIZE 50
-DEFINE_MTYPE_STATIC(BGPD, BGP_LABEL_CHUNK, "BGP Label Chunk")
-DEFINE_MTYPE_STATIC(BGPD, BGP_LABEL_FIFO, "BGP Label FIFO item")
-DEFINE_MTYPE_STATIC(BGPD, BGP_LABEL_CB, "BGP Dynamic Label Assignment")
-DEFINE_MTYPE_STATIC(BGPD, BGP_LABEL_CBQ, "BGP Dynamic Label Callback")
+DEFINE_MTYPE_STATIC(BGPD, BGP_LABEL_CHUNK, "BGP Label Chunk");
+DEFINE_MTYPE_STATIC(BGPD, BGP_LABEL_FIFO, "BGP Label FIFO item");
+DEFINE_MTYPE_STATIC(BGPD, BGP_LABEL_CB, "BGP Dynamic Label Assignment");
+DEFINE_MTYPE_STATIC(BGPD, BGP_LABEL_CBQ, "BGP Dynamic Label Callback");
struct lp_chunk {
uint32_t first;
struct lp_lcb lcb;
};
-DECLARE_LIST(lp_fifo, struct lp_fifo, fifo)
+DECLARE_LIST(lp_fifo, struct lp_fifo, fifo);
struct lp_cbq_item {
int (*cbfunc)(mpls_label_t label, void *lblid, bool alloc);
#define LP_TYPE_VRF 0x00000001
#define LP_TYPE_BGP_LU 0x00000002
-PREDECL_LIST(lp_fifo)
+PREDECL_LIST(lp_fifo);
struct labelpool {
struct skiplist *ledger; /* all requests */
assert(bm->terminating == false);
bm->terminating = true; /* global flag that shutting down */
+ /* Disable BFD events to avoid wasting processing. */
+ bfd_protocol_integration_set_shutdown(true);
+
bgp_terminate();
bgp_exit(0);
.signals = bgp_signals, .n_signals = array_size(bgp_signals),
.privs = &bgpd_privs, .yang_modules = bgpd_yang_modules,
- .n_yang_modules = array_size(bgpd_yang_modules), )
+ .n_yang_modules = array_size(bgpd_yang_modules),
+);
#define DEPRECATED_OPTIONS ""
/* this file is temporary in nature; definitions should be moved to the
* files they're used in */
-DEFINE_MGROUP(BGPD, "bgpd")
-DEFINE_MTYPE(BGPD, BGP, "BGP instance")
-DEFINE_MTYPE(BGPD, BGP_LISTENER, "BGP listen socket details")
-DEFINE_MTYPE(BGPD, BGP_PEER, "BGP peer")
-DEFINE_MTYPE(BGPD, BGP_PEER_HOST, "BGP peer hostname")
-DEFINE_MTYPE(BGPD, BGP_PEER_IFNAME, "BGP peer ifname")
-DEFINE_MTYPE(BGPD, PEER_GROUP, "Peer group")
-DEFINE_MTYPE(BGPD, PEER_GROUP_HOST, "BGP Peer group hostname")
-DEFINE_MTYPE(BGPD, PEER_DESC, "Peer description")
-DEFINE_MTYPE(BGPD, PEER_PASSWORD, "Peer password string")
-DEFINE_MTYPE(BGPD, BGP_PEER_AF, "BGP peer af")
-DEFINE_MTYPE(BGPD, BGP_UPDGRP, "BGP update group")
-DEFINE_MTYPE(BGPD, BGP_UPD_SUBGRP, "BGP update subgroup")
-DEFINE_MTYPE(BGPD, BGP_PACKET, "BGP packet")
-DEFINE_MTYPE(BGPD, ATTR, "BGP attribute")
-DEFINE_MTYPE(BGPD, AS_PATH, "BGP aspath")
-DEFINE_MTYPE(BGPD, AS_SEG, "BGP aspath seg")
-DEFINE_MTYPE(BGPD, AS_SEG_DATA, "BGP aspath segment data")
-DEFINE_MTYPE(BGPD, AS_STR, "BGP aspath str")
-
-DEFINE_MTYPE(BGPD, BGP_TABLE, "BGP table")
-DEFINE_MTYPE(BGPD, BGP_NODE, "BGP node")
-DEFINE_MTYPE(BGPD, BGP_ROUTE, "BGP route")
-DEFINE_MTYPE(BGPD, BGP_ROUTE_EXTRA, "BGP ancillary route info")
-DEFINE_MTYPE(BGPD, BGP_CONN, "BGP connected")
-DEFINE_MTYPE(BGPD, BGP_STATIC, "BGP static")
-DEFINE_MTYPE(BGPD, BGP_ADVERTISE_ATTR, "BGP adv attr")
-DEFINE_MTYPE(BGPD, BGP_ADVERTISE, "BGP adv")
-DEFINE_MTYPE(BGPD, BGP_SYNCHRONISE, "BGP synchronise")
-DEFINE_MTYPE(BGPD, BGP_ADJ_IN, "BGP adj in")
-DEFINE_MTYPE(BGPD, BGP_ADJ_OUT, "BGP adj out")
-DEFINE_MTYPE(BGPD, BGP_MPATH_INFO, "BGP multipath info")
-
-DEFINE_MTYPE(BGPD, AS_LIST, "BGP AS list")
-DEFINE_MTYPE(BGPD, AS_FILTER, "BGP AS filter")
-DEFINE_MTYPE(BGPD, AS_FILTER_STR, "BGP AS filter str")
-
-DEFINE_MTYPE(BGPD, COMMUNITY, "community")
-DEFINE_MTYPE(BGPD, COMMUNITY_VAL, "community val")
-DEFINE_MTYPE(BGPD, COMMUNITY_STR, "community str")
-
-DEFINE_MTYPE(BGPD, ECOMMUNITY, "extcommunity")
-DEFINE_MTYPE(BGPD, ECOMMUNITY_VAL, "extcommunity val")
-DEFINE_MTYPE(BGPD, ECOMMUNITY_STR, "extcommunity str")
-
-DEFINE_MTYPE(BGPD, COMMUNITY_LIST, "community-list")
-DEFINE_MTYPE(BGPD, COMMUNITY_LIST_NAME, "community-list name")
-DEFINE_MTYPE(BGPD, COMMUNITY_LIST_ENTRY, "community-list entry")
-DEFINE_MTYPE(BGPD, COMMUNITY_LIST_CONFIG, "community-list config")
-DEFINE_MTYPE(BGPD, COMMUNITY_LIST_HANDLER, "community-list handler")
-
-DEFINE_MTYPE(BGPD, CLUSTER, "Cluster list")
-DEFINE_MTYPE(BGPD, CLUSTER_VAL, "Cluster list val")
-
-DEFINE_MTYPE(BGPD, BGP_PROCESS_QUEUE, "BGP Process queue")
-DEFINE_MTYPE(BGPD, BGP_CLEAR_NODE_QUEUE, "BGP node clear queue")
-
-DEFINE_MTYPE(BGPD, TRANSIT, "BGP transit attr")
-DEFINE_MTYPE(BGPD, TRANSIT_VAL, "BGP transit val")
-
-DEFINE_MTYPE(BGPD, BGP_DEBUG_FILTER, "BGP debug filter")
-DEFINE_MTYPE(BGPD, BGP_DEBUG_STR, "BGP debug filter string")
-
-DEFINE_MTYPE(BGPD, BGP_DISTANCE, "BGP distance")
-DEFINE_MTYPE(BGPD, BGP_NEXTHOP_CACHE, "BGP nexthop")
-DEFINE_MTYPE(BGPD, BGP_CONFED_LIST, "BGP confed list")
-DEFINE_MTYPE(BGPD, PEER_UPDATE_SOURCE, "BGP peer update interface")
-DEFINE_MTYPE(BGPD, PEER_CONF_IF, "BGP peer config interface")
-DEFINE_MTYPE(BGPD, BGP_DAMP_INFO, "Dampening info")
-DEFINE_MTYPE(BGPD, BGP_DAMP_ARRAY, "BGP Dampening array")
-DEFINE_MTYPE(BGPD, BGP_DAMP_REUSELIST, "BGP Dampening reuse list")
-DEFINE_MTYPE(BGPD, BGP_REGEXP, "BGP regexp")
-DEFINE_MTYPE(BGPD, BGP_AGGREGATE, "BGP aggregate")
-DEFINE_MTYPE(BGPD, BGP_ADDR, "BGP own address")
-DEFINE_MTYPE(BGPD, TIP_ADDR, "BGP own tunnel-ip address")
-
-DEFINE_MTYPE(BGPD, BGP_REDIST, "BGP redistribution")
-DEFINE_MTYPE(BGPD, BGP_FILTER_NAME, "BGP Filter Information")
-DEFINE_MTYPE(BGPD, BGP_DUMP_STR, "BGP Dump String Information")
-DEFINE_MTYPE(BGPD, ENCAP_TLV, "ENCAP TLV")
-
-DEFINE_MTYPE(BGPD, BGP_TEA_OPTIONS, "BGP TEA Options")
-DEFINE_MTYPE(BGPD, BGP_TEA_OPTIONS_VALUE, "BGP TEA Options Value")
-
-DEFINE_MTYPE(BGPD, LCOMMUNITY, "Large Community")
-DEFINE_MTYPE(BGPD, LCOMMUNITY_STR, "Large Community display string")
-DEFINE_MTYPE(BGPD, LCOMMUNITY_VAL, "Large Community value")
-
-DEFINE_MTYPE(BGPD, BGP_EVPN, "BGP EVPN Information")
-DEFINE_MTYPE(BGPD, BGP_EVPN_MH_INFO, "BGP EVPN MH Information")
-DEFINE_MTYPE(BGPD, BGP_EVPN_ES_VTEP, "BGP EVPN ES VTEP")
-DEFINE_MTYPE(BGPD, BGP_EVPN_PATH_ES_INFO, "BGP EVPN PATH ES Information")
-DEFINE_MTYPE(BGPD, BGP_EVPN_ES_EVI_VTEP, "BGP EVPN ES-EVI VTEP")
-DEFINE_MTYPE(BGPD, BGP_EVPN_ES, "BGP EVPN ESI Information")
-DEFINE_MTYPE(BGPD, BGP_EVPN_ES_EVI, "BGP EVPN ES-per-EVI Information")
-DEFINE_MTYPE(BGPD, BGP_EVPN_ES_VRF, "BGP EVPN ES-per-VRF Information")
-DEFINE_MTYPE(BGPD, BGP_EVPN_IMPORT_RT, "BGP EVPN Import RT")
-DEFINE_MTYPE(BGPD, BGP_EVPN_VRF_IMPORT_RT, "BGP EVPN VRF Import RT")
-DEFINE_MTYPE(BGPD, BGP_EVPN_MACIP, "BGP EVPN MAC IP")
-
-DEFINE_MTYPE(BGPD, BGP_FLOWSPEC, "BGP flowspec")
-DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_RULE, "BGP flowspec rule")
-DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_RULE_STR, "BGP flowspec rule str")
-DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_COMPILED, "BGP flowspec compiled")
-DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_NAME, "BGP flowspec name")
-DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_INDEX, "BGP flowspec index")
-
-DEFINE_MTYPE(BGPD, BGP_SRV6_L3VPN, "BGP prefix-sid srv6 l3vpn servcie")
-DEFINE_MTYPE(BGPD, BGP_SRV6_VPN, "BGP prefix-sid srv6 vpn service")
+DEFINE_MGROUP(BGPD, "bgpd");
+DEFINE_MTYPE(BGPD, BGP, "BGP instance");
+DEFINE_MTYPE(BGPD, BGP_LISTENER, "BGP listen socket details");
+DEFINE_MTYPE(BGPD, BGP_PEER, "BGP peer");
+DEFINE_MTYPE(BGPD, BGP_PEER_HOST, "BGP peer hostname");
+DEFINE_MTYPE(BGPD, BGP_PEER_IFNAME, "BGP peer ifname");
+DEFINE_MTYPE(BGPD, PEER_GROUP, "Peer group");
+DEFINE_MTYPE(BGPD, PEER_GROUP_HOST, "BGP Peer group hostname");
+DEFINE_MTYPE(BGPD, PEER_DESC, "Peer description");
+DEFINE_MTYPE(BGPD, PEER_PASSWORD, "Peer password string");
+DEFINE_MTYPE(BGPD, BGP_PEER_AF, "BGP peer af");
+DEFINE_MTYPE(BGPD, BGP_UPDGRP, "BGP update group");
+DEFINE_MTYPE(BGPD, BGP_UPD_SUBGRP, "BGP update subgroup");
+DEFINE_MTYPE(BGPD, BGP_PACKET, "BGP packet");
+DEFINE_MTYPE(BGPD, ATTR, "BGP attribute");
+DEFINE_MTYPE(BGPD, AS_PATH, "BGP aspath");
+DEFINE_MTYPE(BGPD, AS_SEG, "BGP aspath seg");
+DEFINE_MTYPE(BGPD, AS_SEG_DATA, "BGP aspath segment data");
+DEFINE_MTYPE(BGPD, AS_STR, "BGP aspath str");
+
+DEFINE_MTYPE(BGPD, BGP_TABLE, "BGP table");
+DEFINE_MTYPE(BGPD, BGP_NODE, "BGP node");
+DEFINE_MTYPE(BGPD, BGP_ROUTE, "BGP route");
+DEFINE_MTYPE(BGPD, BGP_ROUTE_EXTRA, "BGP ancillary route info");
+DEFINE_MTYPE(BGPD, BGP_CONN, "BGP connected");
+DEFINE_MTYPE(BGPD, BGP_STATIC, "BGP static");
+DEFINE_MTYPE(BGPD, BGP_ADVERTISE_ATTR, "BGP adv attr");
+DEFINE_MTYPE(BGPD, BGP_ADVERTISE, "BGP adv");
+DEFINE_MTYPE(BGPD, BGP_SYNCHRONISE, "BGP synchronise");
+DEFINE_MTYPE(BGPD, BGP_ADJ_IN, "BGP adj in");
+DEFINE_MTYPE(BGPD, BGP_ADJ_OUT, "BGP adj out");
+DEFINE_MTYPE(BGPD, BGP_MPATH_INFO, "BGP multipath info");
+
+DEFINE_MTYPE(BGPD, AS_LIST, "BGP AS list");
+DEFINE_MTYPE(BGPD, AS_FILTER, "BGP AS filter");
+DEFINE_MTYPE(BGPD, AS_FILTER_STR, "BGP AS filter str");
+
+DEFINE_MTYPE(BGPD, COMMUNITY, "community");
+DEFINE_MTYPE(BGPD, COMMUNITY_VAL, "community val");
+DEFINE_MTYPE(BGPD, COMMUNITY_STR, "community str");
+
+DEFINE_MTYPE(BGPD, ECOMMUNITY, "extcommunity");
+DEFINE_MTYPE(BGPD, ECOMMUNITY_VAL, "extcommunity val");
+DEFINE_MTYPE(BGPD, ECOMMUNITY_STR, "extcommunity str");
+
+DEFINE_MTYPE(BGPD, COMMUNITY_LIST, "community-list");
+DEFINE_MTYPE(BGPD, COMMUNITY_LIST_NAME, "community-list name");
+DEFINE_MTYPE(BGPD, COMMUNITY_LIST_ENTRY, "community-list entry");
+DEFINE_MTYPE(BGPD, COMMUNITY_LIST_CONFIG, "community-list config");
+DEFINE_MTYPE(BGPD, COMMUNITY_LIST_HANDLER, "community-list handler");
+
+DEFINE_MTYPE(BGPD, CLUSTER, "Cluster list");
+DEFINE_MTYPE(BGPD, CLUSTER_VAL, "Cluster list val");
+
+DEFINE_MTYPE(BGPD, BGP_PROCESS_QUEUE, "BGP Process queue");
+DEFINE_MTYPE(BGPD, BGP_CLEAR_NODE_QUEUE, "BGP node clear queue");
+
+DEFINE_MTYPE(BGPD, TRANSIT, "BGP transit attr");
+DEFINE_MTYPE(BGPD, TRANSIT_VAL, "BGP transit val");
+
+DEFINE_MTYPE(BGPD, BGP_DEBUG_FILTER, "BGP debug filter");
+DEFINE_MTYPE(BGPD, BGP_DEBUG_STR, "BGP debug filter string");
+
+DEFINE_MTYPE(BGPD, BGP_DISTANCE, "BGP distance");
+DEFINE_MTYPE(BGPD, BGP_NEXTHOP_CACHE, "BGP nexthop");
+DEFINE_MTYPE(BGPD, BGP_CONFED_LIST, "BGP confed list");
+DEFINE_MTYPE(BGPD, PEER_UPDATE_SOURCE, "BGP peer update interface");
+DEFINE_MTYPE(BGPD, PEER_CONF_IF, "BGP peer config interface");
+DEFINE_MTYPE(BGPD, BGP_DAMP_INFO, "Dampening info");
+DEFINE_MTYPE(BGPD, BGP_DAMP_ARRAY, "BGP Dampening array");
+DEFINE_MTYPE(BGPD, BGP_DAMP_REUSELIST, "BGP Dampening reuse list");
+DEFINE_MTYPE(BGPD, BGP_REGEXP, "BGP regexp");
+DEFINE_MTYPE(BGPD, BGP_AGGREGATE, "BGP aggregate");
+DEFINE_MTYPE(BGPD, BGP_ADDR, "BGP own address");
+DEFINE_MTYPE(BGPD, TIP_ADDR, "BGP own tunnel-ip address");
+
+DEFINE_MTYPE(BGPD, BGP_REDIST, "BGP redistribution");
+DEFINE_MTYPE(BGPD, BGP_FILTER_NAME, "BGP Filter Information");
+DEFINE_MTYPE(BGPD, BGP_DUMP_STR, "BGP Dump String Information");
+DEFINE_MTYPE(BGPD, ENCAP_TLV, "ENCAP TLV");
+
+DEFINE_MTYPE(BGPD, BGP_TEA_OPTIONS, "BGP TEA Options");
+DEFINE_MTYPE(BGPD, BGP_TEA_OPTIONS_VALUE, "BGP TEA Options Value");
+
+DEFINE_MTYPE(BGPD, LCOMMUNITY, "Large Community");
+DEFINE_MTYPE(BGPD, LCOMMUNITY_STR, "Large Community display string");
+DEFINE_MTYPE(BGPD, LCOMMUNITY_VAL, "Large Community value");
+
+DEFINE_MTYPE(BGPD, BGP_EVPN, "BGP EVPN Information");
+DEFINE_MTYPE(BGPD, BGP_EVPN_MH_INFO, "BGP EVPN MH Information");
+DEFINE_MTYPE(BGPD, BGP_EVPN_ES_VTEP, "BGP EVPN ES VTEP");
+DEFINE_MTYPE(BGPD, BGP_EVPN_PATH_ES_INFO, "BGP EVPN PATH ES Information");
+DEFINE_MTYPE(BGPD, BGP_EVPN_ES_EVI_VTEP, "BGP EVPN ES-EVI VTEP");
+DEFINE_MTYPE(BGPD, BGP_EVPN_ES, "BGP EVPN ESI Information");
+DEFINE_MTYPE(BGPD, BGP_EVPN_ES_EVI, "BGP EVPN ES-per-EVI Information");
+DEFINE_MTYPE(BGPD, BGP_EVPN_ES_VRF, "BGP EVPN ES-per-VRF Information");
+DEFINE_MTYPE(BGPD, BGP_EVPN_IMPORT_RT, "BGP EVPN Import RT");
+DEFINE_MTYPE(BGPD, BGP_EVPN_VRF_IMPORT_RT, "BGP EVPN VRF Import RT");
+DEFINE_MTYPE(BGPD, BGP_EVPN_MACIP, "BGP EVPN MAC IP");
+
+DEFINE_MTYPE(BGPD, BGP_FLOWSPEC, "BGP flowspec");
+DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_RULE, "BGP flowspec rule");
+DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_RULE_STR, "BGP flowspec rule str");
+DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_COMPILED, "BGP flowspec compiled");
+DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_NAME, "BGP flowspec name");
+DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_INDEX, "BGP flowspec index");
+
+DEFINE_MTYPE(BGPD, BGP_SRV6_L3VPN, "BGP prefix-sid srv6 l3vpn servcie");
+DEFINE_MTYPE(BGPD, BGP_SRV6_VPN, "BGP prefix-sid srv6 vpn service");
#include "memory.h"
-DECLARE_MGROUP(BGPD)
-DECLARE_MTYPE(BGP)
-DECLARE_MTYPE(BGP_LISTENER)
-DECLARE_MTYPE(BGP_PEER)
-DECLARE_MTYPE(BGP_PEER_HOST)
-DECLARE_MTYPE(BGP_PEER_IFNAME)
-DECLARE_MTYPE(PEER_GROUP)
-DECLARE_MTYPE(PEER_GROUP_HOST)
-DECLARE_MTYPE(PEER_DESC)
-DECLARE_MTYPE(PEER_PASSWORD)
-DECLARE_MTYPE(BGP_PEER_AF)
-DECLARE_MTYPE(BGP_UPDGRP)
-DECLARE_MTYPE(BGP_UPD_SUBGRP)
-DECLARE_MTYPE(BGP_PACKET)
-DECLARE_MTYPE(ATTR)
-DECLARE_MTYPE(AS_PATH)
-DECLARE_MTYPE(AS_SEG)
-DECLARE_MTYPE(AS_SEG_DATA)
-DECLARE_MTYPE(AS_STR)
-
-DECLARE_MTYPE(BGP_TABLE)
-DECLARE_MTYPE(BGP_NODE)
-DECLARE_MTYPE(BGP_ROUTE)
-DECLARE_MTYPE(BGP_ROUTE_EXTRA)
-DECLARE_MTYPE(BGP_CONN)
-DECLARE_MTYPE(BGP_STATIC)
-DECLARE_MTYPE(BGP_ADVERTISE_ATTR)
-DECLARE_MTYPE(BGP_ADVERTISE)
-DECLARE_MTYPE(BGP_SYNCHRONISE)
-DECLARE_MTYPE(BGP_ADJ_IN)
-DECLARE_MTYPE(BGP_ADJ_OUT)
-DECLARE_MTYPE(BGP_MPATH_INFO)
-
-DECLARE_MTYPE(AS_LIST)
-DECLARE_MTYPE(AS_FILTER)
-DECLARE_MTYPE(AS_FILTER_STR)
-
-DECLARE_MTYPE(COMMUNITY)
-DECLARE_MTYPE(COMMUNITY_VAL)
-DECLARE_MTYPE(COMMUNITY_STR)
-
-DECLARE_MTYPE(ECOMMUNITY)
-DECLARE_MTYPE(ECOMMUNITY_VAL)
-DECLARE_MTYPE(ECOMMUNITY_STR)
-
-DECLARE_MTYPE(COMMUNITY_LIST)
-DECLARE_MTYPE(COMMUNITY_LIST_NAME)
-DECLARE_MTYPE(COMMUNITY_LIST_ENTRY)
-DECLARE_MTYPE(COMMUNITY_LIST_CONFIG)
-DECLARE_MTYPE(COMMUNITY_LIST_HANDLER)
-
-DECLARE_MTYPE(CLUSTER)
-DECLARE_MTYPE(CLUSTER_VAL)
-
-DECLARE_MTYPE(BGP_PROCESS_QUEUE)
-DECLARE_MTYPE(BGP_CLEAR_NODE_QUEUE)
-
-DECLARE_MTYPE(TRANSIT)
-DECLARE_MTYPE(TRANSIT_VAL)
-
-DECLARE_MTYPE(BGP_DEBUG_FILTER)
-DECLARE_MTYPE(BGP_DEBUG_STR)
-
-DECLARE_MTYPE(BGP_DISTANCE)
-DECLARE_MTYPE(BGP_NEXTHOP_CACHE)
-DECLARE_MTYPE(BGP_CONFED_LIST)
-DECLARE_MTYPE(PEER_UPDATE_SOURCE)
-DECLARE_MTYPE(PEER_CONF_IF)
-DECLARE_MTYPE(BGP_DAMP_INFO)
-DECLARE_MTYPE(BGP_DAMP_ARRAY)
-DECLARE_MTYPE(BGP_DAMP_REUSELIST)
-DECLARE_MTYPE(BGP_REGEXP)
-DECLARE_MTYPE(BGP_AGGREGATE)
-DECLARE_MTYPE(BGP_ADDR)
-DECLARE_MTYPE(TIP_ADDR)
-
-DECLARE_MTYPE(BGP_REDIST)
-DECLARE_MTYPE(BGP_FILTER_NAME)
-DECLARE_MTYPE(BGP_DUMP_STR)
-DECLARE_MTYPE(ENCAP_TLV)
-
-DECLARE_MTYPE(BGP_TEA_OPTIONS)
-DECLARE_MTYPE(BGP_TEA_OPTIONS_VALUE)
-
-DECLARE_MTYPE(LCOMMUNITY)
-DECLARE_MTYPE(LCOMMUNITY_STR)
-DECLARE_MTYPE(LCOMMUNITY_VAL)
-
-DECLARE_MTYPE(BGP_EVPN_MH_INFO)
-DECLARE_MTYPE(BGP_EVPN_ES)
-DECLARE_MTYPE(BGP_EVPN_ES_EVI)
-DECLARE_MTYPE(BGP_EVPN_ES_VRF)
-DECLARE_MTYPE(BGP_EVPN_ES_VTEP)
-DECLARE_MTYPE(BGP_EVPN_PATH_ES_INFO)
-DECLARE_MTYPE(BGP_EVPN_ES_EVI_VTEP)
-
-DECLARE_MTYPE(BGP_EVPN)
-DECLARE_MTYPE(BGP_EVPN_IMPORT_RT)
-DECLARE_MTYPE(BGP_EVPN_VRF_IMPORT_RT)
-DECLARE_MTYPE(BGP_EVPN_MACIP)
-
-DECLARE_MTYPE(BGP_FLOWSPEC)
-DECLARE_MTYPE(BGP_FLOWSPEC_RULE)
-DECLARE_MTYPE(BGP_FLOWSPEC_RULE_STR)
-DECLARE_MTYPE(BGP_FLOWSPEC_COMPILED)
-DECLARE_MTYPE(BGP_FLOWSPEC_NAME)
-DECLARE_MTYPE(BGP_FLOWSPEC_INDEX)
-
-DECLARE_MTYPE(BGP_SRV6_L3VPN)
-DECLARE_MTYPE(BGP_SRV6_VPN)
+DECLARE_MGROUP(BGPD);
+DECLARE_MTYPE(BGP);
+DECLARE_MTYPE(BGP_LISTENER);
+DECLARE_MTYPE(BGP_PEER);
+DECLARE_MTYPE(BGP_PEER_HOST);
+DECLARE_MTYPE(BGP_PEER_IFNAME);
+DECLARE_MTYPE(PEER_GROUP);
+DECLARE_MTYPE(PEER_GROUP_HOST);
+DECLARE_MTYPE(PEER_DESC);
+DECLARE_MTYPE(PEER_PASSWORD);
+DECLARE_MTYPE(BGP_PEER_AF);
+DECLARE_MTYPE(BGP_UPDGRP);
+DECLARE_MTYPE(BGP_UPD_SUBGRP);
+DECLARE_MTYPE(BGP_PACKET);
+DECLARE_MTYPE(ATTR);
+DECLARE_MTYPE(AS_PATH);
+DECLARE_MTYPE(AS_SEG);
+DECLARE_MTYPE(AS_SEG_DATA);
+DECLARE_MTYPE(AS_STR);
+
+DECLARE_MTYPE(BGP_TABLE);
+DECLARE_MTYPE(BGP_NODE);
+DECLARE_MTYPE(BGP_ROUTE);
+DECLARE_MTYPE(BGP_ROUTE_EXTRA);
+DECLARE_MTYPE(BGP_CONN);
+DECLARE_MTYPE(BGP_STATIC);
+DECLARE_MTYPE(BGP_ADVERTISE_ATTR);
+DECLARE_MTYPE(BGP_ADVERTISE);
+DECLARE_MTYPE(BGP_SYNCHRONISE);
+DECLARE_MTYPE(BGP_ADJ_IN);
+DECLARE_MTYPE(BGP_ADJ_OUT);
+DECLARE_MTYPE(BGP_MPATH_INFO);
+
+DECLARE_MTYPE(AS_LIST);
+DECLARE_MTYPE(AS_FILTER);
+DECLARE_MTYPE(AS_FILTER_STR);
+
+DECLARE_MTYPE(COMMUNITY);
+DECLARE_MTYPE(COMMUNITY_VAL);
+DECLARE_MTYPE(COMMUNITY_STR);
+
+DECLARE_MTYPE(ECOMMUNITY);
+DECLARE_MTYPE(ECOMMUNITY_VAL);
+DECLARE_MTYPE(ECOMMUNITY_STR);
+
+DECLARE_MTYPE(COMMUNITY_LIST);
+DECLARE_MTYPE(COMMUNITY_LIST_NAME);
+DECLARE_MTYPE(COMMUNITY_LIST_ENTRY);
+DECLARE_MTYPE(COMMUNITY_LIST_CONFIG);
+DECLARE_MTYPE(COMMUNITY_LIST_HANDLER);
+
+DECLARE_MTYPE(CLUSTER);
+DECLARE_MTYPE(CLUSTER_VAL);
+
+DECLARE_MTYPE(BGP_PROCESS_QUEUE);
+DECLARE_MTYPE(BGP_CLEAR_NODE_QUEUE);
+
+DECLARE_MTYPE(TRANSIT);
+DECLARE_MTYPE(TRANSIT_VAL);
+
+DECLARE_MTYPE(BGP_DEBUG_FILTER);
+DECLARE_MTYPE(BGP_DEBUG_STR);
+
+DECLARE_MTYPE(BGP_DISTANCE);
+DECLARE_MTYPE(BGP_NEXTHOP_CACHE);
+DECLARE_MTYPE(BGP_CONFED_LIST);
+DECLARE_MTYPE(PEER_UPDATE_SOURCE);
+DECLARE_MTYPE(PEER_CONF_IF);
+DECLARE_MTYPE(BGP_DAMP_INFO);
+DECLARE_MTYPE(BGP_DAMP_ARRAY);
+DECLARE_MTYPE(BGP_DAMP_REUSELIST);
+DECLARE_MTYPE(BGP_REGEXP);
+DECLARE_MTYPE(BGP_AGGREGATE);
+DECLARE_MTYPE(BGP_ADDR);
+DECLARE_MTYPE(TIP_ADDR);
+
+DECLARE_MTYPE(BGP_REDIST);
+DECLARE_MTYPE(BGP_FILTER_NAME);
+DECLARE_MTYPE(BGP_DUMP_STR);
+DECLARE_MTYPE(ENCAP_TLV);
+
+DECLARE_MTYPE(BGP_TEA_OPTIONS);
+DECLARE_MTYPE(BGP_TEA_OPTIONS_VALUE);
+
+DECLARE_MTYPE(LCOMMUNITY);
+DECLARE_MTYPE(LCOMMUNITY_STR);
+DECLARE_MTYPE(LCOMMUNITY_VAL);
+
+DECLARE_MTYPE(BGP_EVPN_MH_INFO);
+DECLARE_MTYPE(BGP_EVPN_ES);
+DECLARE_MTYPE(BGP_EVPN_ES_EVI);
+DECLARE_MTYPE(BGP_EVPN_ES_VRF);
+DECLARE_MTYPE(BGP_EVPN_ES_VTEP);
+DECLARE_MTYPE(BGP_EVPN_PATH_ES_INFO);
+DECLARE_MTYPE(BGP_EVPN_ES_EVI_VTEP);
+
+DECLARE_MTYPE(BGP_EVPN);
+DECLARE_MTYPE(BGP_EVPN_IMPORT_RT);
+DECLARE_MTYPE(BGP_EVPN_VRF_IMPORT_RT);
+DECLARE_MTYPE(BGP_EVPN_MACIP);
+
+DECLARE_MTYPE(BGP_FLOWSPEC);
+DECLARE_MTYPE(BGP_FLOWSPEC_RULE);
+DECLARE_MTYPE(BGP_FLOWSPEC_RULE_STR);
+DECLARE_MTYPE(BGP_FLOWSPEC_COMPILED);
+DECLARE_MTYPE(BGP_FLOWSPEC_NAME);
+DECLARE_MTYPE(BGP_FLOWSPEC_INDEX);
+
+DECLARE_MTYPE(BGP_SRV6_L3VPN);
+DECLARE_MTYPE(BGP_SRV6_VPN);
#endif /* _QUAGGA_BGP_MEMORY_H */
#include "bgpd/bgp_io.h"
#include "bgpd/bgp_damp.h"
-DEFINE_HOOK(bgp_snmp_init_stats, (struct bgp *bgp), (bgp))
+DEFINE_HOOK(bgp_snmp_init_stats, (struct bgp *bgp), (bgp));
FRR_CFG_DEFAULT_ULONG(BGP_CONNECT_RETRY,
{ .val_ulong = 10, .match_profile = "datacenter", },
{ .val_ulong = 120 },
-)
+);
FRR_CFG_DEFAULT_ULONG(BGP_HOLDTIME,
{ .val_ulong = 9, .match_profile = "datacenter", },
{ .val_ulong = 180 },
-)
+);
FRR_CFG_DEFAULT_ULONG(BGP_KEEPALIVE,
{ .val_ulong = 3, .match_profile = "datacenter", },
{ .val_ulong = 60 },
-)
+);
int routing_control_plane_protocols_name_validate(
struct nb_cb_create_args *args)
return NB_OK;
str2sockunion(peer_str, &su);
- ret = peer_remote_as(bgp, &su, NULL, &as, as_type, AFI_IP,
- SAFI_UNICAST);
+ ret = peer_remote_as(bgp, &su, NULL, &as, as_type);
if (bgp_nb_errmsg_return(args->errmsg, args->errmsg_len, ret)
< 0)
return NB_ERR_INCONSISTENCY;
as = yang_dnode_get_uint32(args->dnode, NULL);
str2sockunion(peer_str, &su);
- ret = peer_remote_as(bgp, &su, NULL, &as, as_type, AFI_IP,
- SAFI_UNICAST);
+ ret = peer_remote_as(bgp, &su, NULL, &as, as_type);
if (bgp_nb_errmsg_return(args->errmsg, args->errmsg_len, ret)
< 0)
return NB_ERR_INCONSISTENCY;
"./neighbor-remote-as/remote-as");
}
- if (peer_conf_interface_create(bgp, peer_str, AFI_IP,
- SAFI_UNICAST, v6_only,
+ if (peer_conf_interface_create(bgp, peer_str, v6_only,
peer_grp_str, as_type, as,
args->errmsg, args->errmsg_len))
return NB_ERR_INCONSISTENCY;
v6_only = yang_dnode_get_bool(args->dnode, NULL);
- if (peer_conf_interface_create(
- bgp, peer_str, AFI_IP, SAFI_UNICAST, v6_only, NULL,
- AS_UNSPECIFIED, 0, args->errmsg, args->errmsg_len))
+ if (peer_conf_interface_create(bgp, peer_str, v6_only, NULL,
+ AS_UNSPECIFIED, 0, args->errmsg,
+ args->errmsg_len))
return NB_ERR_INCONSISTENCY;
break;
int ret;
as_t as = 0;
struct peer *peer = NULL;
- afi_t afi = AFI_IP;
- safi_t safi = SAFI_UNICAST;
bgp = nb_running_get_entry(args->dnode, NULL, true);
peer_str = yang_dnode_get_string(args->dnode, "../interface");
peer = peer_lookup_by_conf_if(bgp, peer_str);
- ret = peer_remote_as(bgp, NULL, peer_str, &as, as_type, afi, safi);
+ ret = peer_remote_as(bgp, NULL, peer_str, &as, as_type);
if (ret < 0 && !peer) {
snprintf(args->errmsg, args->errmsg_len,
peer1->host);
peer = peer_create(&su, peer1->conf_if, peer1->bgp, peer1->local_as,
- peer1->as, peer1->as_type, 0, 0, NULL);
+ peer1->as, peer1->as_type, NULL);
hash_release(peer->bgp->peerhash, peer);
hash_get(peer->bgp->peerhash, peer, hash_alloc_intern);
bnc->srte_color, bnc->bgp->name_pretty,
peer);
}
+ } else {
+ if (BGP_DEBUG(nht, NHT)) {
+ char buf[PREFIX2STR_BUFFER];
+
+ zlog_debug(
+ "Found existing bnc %s(%s) flags 0x%x ifindex %d #paths %d peer %p",
+ bnc_str(bnc, buf, PREFIX2STR_BUFFER),
+ bnc->bgp->name_pretty, bnc->flags, bnc->ifindex,
+ bnc->path_count, bnc->nht_info);
+ }
}
if (is_bgp_static_route) {
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
}
+ if (peer && (bnc->ifindex != ifindex)) {
+ UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
+ UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
+ bnc->ifindex = ifindex;
+ }
if (bgp_route->inst_type == BGP_INSTANCE_TYPE_VIEW) {
SET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
SET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
bnc->last_update = bgp_clock();
bnc->change_flags = 0;
+ /*
+ * For interface based routes ( ala the v6 LL routes
+ * that this was written for ) the metric received
+ * for the connected route is 0 not 1.
+ */
+ bnc->metric = 0;
if (up) {
SET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
SET_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED);
- bnc->metric = 1;
bnc->nexthop_num = 1;
} else {
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED);
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
SET_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED);
bnc->nexthop_num = 0;
- bnc->metric = 0;
}
evaluate_paths(bnc);
if (!ifp)
return 0;
+ if (BGP_DEBUG(nht, NHT))
+ zlog_debug(
+ "Handle NHT initial update for Intf %s(%d) status %s",
+ ifp->name, ifp->ifindex, if_is_up(ifp) ? "up" : "down");
+
if (if_is_up(ifp))
bgp_nht_ifp_up(ifp);
else
DEFINE_HOOK(bgp_packet_dump,
(struct peer *peer, uint8_t type, bgp_size_t size,
struct stream *s),
- (peer, type, size, s))
+ (peer, type, size, s));
DEFINE_HOOK(bgp_packet_send,
(struct peer *peer, uint8_t type, bgp_size_t size,
struct stream *s),
- (peer, type, size, s))
+ (peer, type, size, s));
/**
* Sets marker and type fields for a BGP message.
frr_with_mutex(&peer->io_mtx) {
// more work to do, come back later
if (peer->ibuf->count > 0)
- thread_add_timer_msec(
+ thread_add_event(
bm->master, bgp_process_packet, peer, 0,
&peer->t_process_packet);
}
DECLARE_HOOK(bgp_packet_dump,
(struct peer *peer, uint8_t type, bgp_size_t size,
struct stream *s),
- (peer, type, size, s))
+ (peer, type, size, s));
DECLARE_HOOK(bgp_packet_send,
(struct peer *peer, uint8_t type, bgp_size_t size,
struct stream *s),
- (peer, type, size, s))
+ (peer, type, size, s));
#define BGP_NLRI_LENGTH 1U
#define BGP_TOTAL_ATTR_LEN 2U
#include "bgpd/bgp_flowspec_private.h"
#include "bgpd/bgp_errors.h"
-DEFINE_MTYPE_STATIC(BGPD, PBR_MATCH_ENTRY, "PBR match entry")
-DEFINE_MTYPE_STATIC(BGPD, PBR_MATCH, "PBR match")
-DEFINE_MTYPE_STATIC(BGPD, PBR_ACTION, "PBR action")
-DEFINE_MTYPE_STATIC(BGPD, PBR_RULE, "PBR rule")
-DEFINE_MTYPE_STATIC(BGPD, PBR, "BGP PBR Context")
-DEFINE_MTYPE_STATIC(BGPD, PBR_VALMASK, "BGP PBR Val Mask Value")
+DEFINE_MTYPE_STATIC(BGPD, PBR_MATCH_ENTRY, "PBR match entry");
+DEFINE_MTYPE_STATIC(BGPD, PBR_MATCH, "PBR match");
+DEFINE_MTYPE_STATIC(BGPD, PBR_ACTION, "PBR action");
+DEFINE_MTYPE_STATIC(BGPD, PBR_RULE, "PBR rule");
+DEFINE_MTYPE_STATIC(BGPD, PBR, "BGP PBR Context");
+DEFINE_MTYPE_STATIC(BGPD, PBR_VALMASK, "BGP PBR Val Mask Value");
/* chain strings too long to fit in one line */
#define FSPEC_ACTION_EXCEED_LIMIT "flowspec actions exceeds limit"
DEFINE_HOOK(bgp_snmp_update_stats,
(struct bgp_node *rn, struct bgp_path_info *pi, bool added),
- (rn, pi, added))
+ (rn, pi, added));
DEFINE_HOOK(bgp_rpki_prefix_status,
(struct peer *peer, struct attr *attr,
const struct prefix *prefix),
- (peer, attr, prefix))
+ (peer, attr, prefix));
/* Extern from bgp_dump.c */
extern const char *bgp_origin_str[];
DEFINE_HOOK(bgp_process,
(struct bgp * bgp, afi_t afi, safi_t safi, struct bgp_dest *bn,
struct peer *peer, bool withdraw),
- (bgp, afi, safi, bn, peer, withdraw))
+ (bgp, afi, safi, bn, peer, withdraw));
/** Test if path is suppressed. */
static bool bgp_path_suppressed(struct bgp_path_info *pi)
DECLARE_HOOK(bgp_process,
(struct bgp * bgp, afi_t afi, safi_t safi, struct bgp_dest *bn,
struct peer *peer, bool withdraw),
- (bgp, afi, safi, bn, peer, withdraw))
+ (bgp, afi, safi, bn, peer, withdraw));
/* BGP show options */
#define BGP_SHOW_OPT_JSON (1 << 0)
#include "bgpd/bgp_rpki_clippy.c"
#endif
-DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_CACHE, "BGP RPKI Cache server")
-DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_CACHE_GROUP, "BGP RPKI Cache server group")
+DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_CACHE, "BGP RPKI Cache server");
+DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_CACHE_GROUP, "BGP RPKI Cache server group");
#define RPKI_VALID 1
#define RPKI_NOTFOUND 2
FRR_MODULE_SETUP(.name = "bgpd_rpki", .version = "0.3.6",
.description = "Enable RPKI support for FRR.",
- .init = bgp_rpki_module_init)
+ .init = bgp_rpki_module_init,
+);
FRR_MODULE_SETUP(.name = "bgpd_snmp", .version = FRR_VERSION,
.description = "bgpd AgentX SNMP module",
- .init = bgp_snmp_module_init)
+ .init = bgp_snmp_module_init,
+);
#include "lib/json.h"
#include "lib_errors.h"
#include "lib/zclient.h"
+#include "lib/printfrr.h"
#include "prefix.h"
#include "plist.h"
#include "buffer.h"
.match_version = "< 7.4",
},
{ .val_bool = true },
-)
+);
FRR_CFG_DEFAULT_BOOL(BGP_SHOW_HOSTNAME,
{ .val_bool = true, .match_profile = "datacenter", },
{ .val_bool = false },
-)
+);
FRR_CFG_DEFAULT_BOOL(BGP_SHOW_NEXTHOP_HOSTNAME,
{ .val_bool = true, .match_profile = "datacenter", },
{ .val_bool = false },
-)
+);
FRR_CFG_DEFAULT_BOOL(BGP_LOG_NEIGHBOR_CHANGES,
{ .val_bool = true, .match_profile = "datacenter", },
{ .val_bool = false },
-)
+);
FRR_CFG_DEFAULT_BOOL(BGP_DETERMINISTIC_MED,
{ .val_bool = true, .match_profile = "datacenter", },
{ .val_bool = false },
-)
+);
FRR_CFG_DEFAULT_ULONG(BGP_CONNECT_RETRY,
{ .val_ulong = 10, .match_profile = "datacenter", },
{ .val_ulong = 120 },
-)
+);
FRR_CFG_DEFAULT_ULONG(BGP_HOLDTIME,
{ .val_ulong = 9, .match_profile = "datacenter", },
{ .val_ulong = 180 },
-)
+);
FRR_CFG_DEFAULT_ULONG(BGP_KEEPALIVE,
{ .val_ulong = 3, .match_profile = "datacenter", },
{ .val_ulong = 60 },
-)
+);
FRR_CFG_DEFAULT_BOOL(BGP_EBGP_REQUIRES_POLICY,
{ .val_bool = false, .match_profile = "datacenter", },
{ .val_bool = false, .match_version = "< 7.4", },
{ .val_bool = true },
-)
+);
FRR_CFG_DEFAULT_BOOL(BGP_SUPPRESS_DUPLICATES,
{ .val_bool = false, .match_version = "< 7.6", },
{ .val_bool = true },
-)
+);
DEFINE_HOOK(bgp_inst_config_write,
(struct bgp *bgp, struct vty *vty),
- (bgp, vty))
-DEFINE_HOOK(bgp_snmp_update_last_changed, (struct bgp *bgp), (bgp))
+ (bgp, vty));
+DEFINE_HOOK(bgp_snmp_update_last_changed, (struct bgp *bgp), (bgp));
#define GR_NO_OPER \
"The Graceful Restart No Operation was executed as cmd same as previous one."
str = "Operation not allowed on a directly connected neighbor";
break;
case BGP_ERR_PEER_SAFI_CONFLICT:
- str = GR_INVALID;
+ str = "Cannot activate peer for both 'ipv4 unicast' and 'ipv4 labeled-unicast'";
break;
case BGP_ERR_GR_INVALID_CMD:
str = "The Graceful Restart command used is not valid at this moment.";
str = "Operation not allowed on a directly connected neighbor";
break;
case BGP_ERR_PEER_SAFI_CONFLICT:
- str = GR_INVALID;
+ str = "Cannot activate peer for both 'ipv4 unicast' and 'ipv4 labeled-unicast'";
break;
case BGP_ERR_GR_INVALID_CMD:
str = "The Graceful Restart command used is not valid at this moment.";
return CMD_SUCCESS;
}
+/* "no bgp default ipv6-unicast". */
+DEFUN(no_bgp_default_ipv6_unicast, no_bgp_default_ipv6_unicast_cmd,
+ "no bgp default ipv6-unicast", NO_STR
+ "BGP specific commands\n"
+ "Configure BGP defaults\n"
+ "Activate ipv6-unicast for a peer by default\n")
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+ UNSET_FLAG(bgp->flags, BGP_FLAG_DEFAULT_IPV6);
+ return CMD_SUCCESS;
+}
+
+DEFUN(bgp_default_ipv6_unicast, bgp_default_ipv6_unicast_cmd,
+ "bgp default ipv6-unicast",
+ "BGP specific commands\n"
+ "Configure BGP defaults\n"
+ "Activate ipv6-unicast for a peer by default\n")
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+ SET_FLAG(bgp->flags, BGP_FLAG_DEFAULT_IPV6);
+ return CMD_SUCCESS;
+}
+
/* "no bgp default ipv4-unicast". */
DEFUN (no_bgp_default_ipv4_unicast,
no_bgp_default_ipv4_unicast_cmd,
return nb_cli_apply_changes(vty, base_xpath);
}
-int peer_conf_interface_create(struct bgp *bgp, const char *conf_if, afi_t afi,
- safi_t safi, bool v6only,
- const char *peer_group_name, int as_type,
- as_t as, char *errmsg, size_t errmsg_len)
+int peer_conf_interface_create(struct bgp *bgp, const char *conf_if,
+ bool v6only, const char *peer_group_name,
+ int as_type, as_t as, char *errmsg,
+ size_t errmsg_len)
{
struct peer *peer;
struct peer_group *group;
peer = peer_lookup_by_conf_if(bgp, conf_if);
if (peer) {
if (as_type != AS_UNSPECIFIED)
- ret = peer_remote_as(bgp, NULL, conf_if, &as, as_type,
- afi, safi);
+ ret = peer_remote_as(bgp, NULL, conf_if, &as, as_type);
} else {
- if (CHECK_FLAG(bgp->flags, BGP_FLAG_NO_DEFAULT_IPV4)
- && afi == AFI_IP && safi == SAFI_UNICAST)
- peer = peer_create(NULL, conf_if, bgp, bgp->as, as,
- as_type, 0, 0, NULL);
- else
- peer = peer_create(NULL, conf_if, bgp, bgp->as, as,
- as_type, afi, safi, NULL);
+ peer = peer_create(NULL, conf_if, bgp, bgp->as, as, as_type,
+ NULL);
if (!peer) {
snprintf(errmsg, errmsg_len,
"Send Community attribute to this neighbor\n")
{
int idx_peer = 1;
+ char *peer_str = argv[idx_peer]->arg;
+ char base_xpath[XPATH_MAXLEN];
+ char af_xpath[XPATH_MAXLEN];
+ char std_xpath[XPATH_MAXLEN];
+ afi_t afi = bgp_node_afi(vty);
+ safi_t safi = bgp_node_safi(vty);
- return peer_af_flag_set_vty(vty, argv[idx_peer]->arg, bgp_node_afi(vty),
- bgp_node_safi(vty),
- PEER_FLAG_SEND_COMMUNITY);
+ snprintf(af_xpath, sizeof(af_xpath), FRR_BGP_AF_XPATH,
+ yang_afi_safi_value2identity(afi, safi));
+
+ if (peer_and_group_lookup_nb(vty, peer_str, base_xpath,
+ sizeof(base_xpath), af_xpath)
+ < 0)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ snprintf(std_xpath, sizeof(std_xpath),
+ "./%s/send-community/send-community",
+ bgp_afi_safi_get_container_str(afi, safi));
+
+ nb_cli_enqueue_change(vty, std_xpath, NB_OP_MODIFY, "true");
+
+ return nb_cli_apply_changes(vty, base_xpath);
}
ALIAS_HIDDEN(neighbor_send_community, neighbor_send_community_hidden_cmd,
"Send Community attribute to this neighbor\n")
{
int idx_peer = 2;
+ char *peer_str = argv[idx_peer]->arg;
+ char base_xpath[XPATH_MAXLEN];
+ char af_xpath[XPATH_MAXLEN];
+ char std_xpath[XPATH_MAXLEN];
+ afi_t afi = bgp_node_afi(vty);
+ safi_t safi = bgp_node_safi(vty);
- return peer_af_flag_unset_vty(vty, argv[idx_peer]->arg,
- bgp_node_afi(vty), bgp_node_safi(vty),
- PEER_FLAG_SEND_COMMUNITY);
+ snprintf(af_xpath, sizeof(af_xpath), FRR_BGP_AF_XPATH,
+ yang_afi_safi_value2identity(afi, safi));
+
+ if (peer_and_group_lookup_nb(vty, peer_str, base_xpath,
+ sizeof(base_xpath), af_xpath)
+ < 0)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ snprintf(std_xpath, sizeof(std_xpath),
+ "./%s/send-community/send-community",
+ bgp_afi_safi_get_container_str(afi, safi));
+
+ nb_cli_enqueue_change(vty, std_xpath, NB_OP_MODIFY, "false");
+
+ return nb_cli_apply_changes(vty, base_xpath);
}
ALIAS_HIDDEN(no_neighbor_send_community, no_neighbor_send_community_hidden_cmd,
vty_out(vty, "\n");
/* BFD information. */
- bgp_bfd_show_info(vty, p, use_json, json_neigh);
+ if (p->bfd_config)
+ bgp_bfd_show_info(vty, p, json_neigh);
if (use_json) {
if (p->conf_if) /* Configured interface name. */
return CMD_SUCCESS;
}
-static int bgp_show_one_peer_group(struct vty *vty, struct peer_group *group)
+static int bgp_show_one_peer_group(struct vty *vty, struct peer_group *group,
+ json_object *json)
{
struct listnode *node, *nnode;
struct prefix *range;
afi_t afi;
safi_t safi;
const char *peer_status;
- const char *af_str;
int lr_count;
int dynamic;
- int af_cfgd;
+ bool af_cfgd;
+ json_object *json_peer_group = NULL;
+ json_object *json_peer_group_afc = NULL;
+ json_object *json_peer_group_members = NULL;
+ json_object *json_peer_group_dynamic = NULL;
+ json_object *json_peer_group_dynamic_af = NULL;
+ json_object *json_peer_group_ranges = NULL;
conf = group->conf;
+ if (json) {
+ json_peer_group = json_object_new_object();
+ json_peer_group_afc = json_object_new_array();
+ }
+
if (conf->as_type == AS_SPECIFIED || conf->as_type == AS_EXTERNAL) {
- vty_out(vty, "\nBGP peer-group %s, remote AS %u\n",
- group->name, conf->as);
+ if (json)
+ json_object_int_add(json_peer_group, "remoteAs",
+ conf->as);
+ else
+ vty_out(vty, "\nBGP peer-group %s, remote AS %u\n",
+ group->name, conf->as);
} else if (conf->as_type == AS_INTERNAL) {
- vty_out(vty, "\nBGP peer-group %s, remote AS %u\n",
- group->name, group->bgp->as);
+ if (json)
+ json_object_int_add(json_peer_group, "remoteAs",
+ group->bgp->as);
+ else
+ vty_out(vty, "\nBGP peer-group %s, remote AS %u\n",
+ group->name, group->bgp->as);
} else {
- vty_out(vty, "\nBGP peer-group %s\n", group->name);
+ if (!json)
+ vty_out(vty, "\nBGP peer-group %s\n", group->name);
}
- if ((group->bgp->as == conf->as) || (conf->as_type == AS_INTERNAL))
- vty_out(vty, " Peer-group type is internal\n");
- else
- vty_out(vty, " Peer-group type is external\n");
+ if ((group->bgp->as == conf->as) || (conf->as_type == AS_INTERNAL)) {
+ if (json)
+ json_object_string_add(json_peer_group, "type",
+ "internal");
+ else
+ vty_out(vty, " Peer-group type is internal\n");
+ } else {
+ if (json)
+ json_object_string_add(json_peer_group, "type",
+ "external");
+ else
+ vty_out(vty, " Peer-group type is external\n");
+ }
/* Display AFs configured. */
- vty_out(vty, " Configured address-families:");
+ if (!json)
+ vty_out(vty, " Configured address-families:");
+
FOREACH_AFI_SAFI (afi, safi) {
if (conf->afc[afi][safi]) {
- af_cfgd = 1;
- vty_out(vty, " %s;", get_afi_safi_str(afi, safi, false));
+ af_cfgd = true;
+ if (json)
+ json_object_array_add(
+ json_peer_group_afc,
+ json_object_new_string(get_afi_safi_str(
+ afi, safi, false)));
+ else
+ vty_out(vty, " %s;",
+ get_afi_safi_str(afi, safi, false));
}
}
- if (!af_cfgd)
- vty_out(vty, " none\n");
- else
- vty_out(vty, "\n");
+
+ if (json) {
+ json_object_object_add(json_peer_group,
+ "addressFamiliesConfigured",
+ json_peer_group_afc);
+ } else {
+ if (!af_cfgd)
+ vty_out(vty, " none\n");
+ else
+ vty_out(vty, "\n");
+ }
/* Display listen ranges (for dynamic neighbors), if any */
for (afi = AFI_IP; afi < AFI_MAX; afi++) {
- if (afi == AFI_IP)
- af_str = "IPv4";
- else if (afi == AFI_IP6)
- af_str = "IPv6";
- else
- af_str = "???";
lr_count = listcount(group->listen_range[afi]);
if (lr_count) {
- vty_out(vty, " %d %s listen range(s)\n", lr_count,
- af_str);
-
+ if (json) {
+ if (!json_peer_group_dynamic)
+ json_peer_group_dynamic =
+ json_object_new_object();
+
+ json_peer_group_dynamic_af =
+ json_object_new_object();
+ json_peer_group_ranges =
+ json_object_new_array();
+ json_object_int_add(json_peer_group_dynamic_af,
+ "count", lr_count);
+ } else {
+ vty_out(vty, " %d %s listen range(s)\n",
+ lr_count, afi2str(afi));
+ }
for (ALL_LIST_ELEMENTS(group->listen_range[afi], node,
- nnode, range))
- vty_out(vty, " %pFX\n", range);
+ nnode, range)) {
+ if (json) {
+ char buf[BUFSIZ];
+
+ snprintfrr(buf, sizeof(buf), "%pFX",
+ range);
+
+ json_object_array_add(
+ json_peer_group_ranges,
+ json_object_new_string(buf));
+ } else {
+ vty_out(vty, " %pFX\n", range);
+ }
+ }
+
+ if (json) {
+ json_object_object_add(
+ json_peer_group_dynamic_af, "ranges",
+ json_peer_group_ranges);
+
+ json_object_object_add(
+ json_peer_group_dynamic, afi2str(afi),
+ json_peer_group_dynamic_af);
+ }
}
}
+ if (json_peer_group_dynamic)
+ json_object_object_add(json_peer_group, "dynamicRanges",
+ json_peer_group_dynamic);
+
/* Display group members and their status */
if (listcount(group->peer)) {
- vty_out(vty, " Peer-group members:\n");
+ if (json)
+ json_peer_group_members = json_object_new_object();
+ else
+ vty_out(vty, " Peer-group members:\n");
for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
if (CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN)
|| CHECK_FLAG(peer->bgp->flags, BGP_FLAG_SHUTDOWN))
peer->status, NULL);
dynamic = peer_dynamic_neighbor(peer);
- vty_out(vty, " %s %s %s \n", peer->host,
- dynamic ? "(dynamic)" : "", peer_status);
+
+ if (json) {
+ json_object *json_peer_group_member =
+ json_object_new_object();
+
+ json_object_string_add(json_peer_group_member,
+ "status", peer_status);
+
+ if (dynamic)
+ json_object_boolean_true_add(
+ json_peer_group_member,
+ "dynamic");
+
+ json_object_object_add(json_peer_group_members,
+ peer->host,
+ json_peer_group_member);
+ } else {
+ vty_out(vty, " %s %s %s \n", peer->host,
+ dynamic ? "(dynamic)" : "",
+ peer_status);
+ }
}
+ if (json)
+ json_object_object_add(json_peer_group, "members",
+ json_peer_group_members);
}
+ if (json)
+ json_object_object_add(json, group->name, json_peer_group);
+
return CMD_SUCCESS;
}
static int bgp_show_peer_group_vty(struct vty *vty, const char *name,
- const char *group_name)
+ const char *group_name, bool uj)
{
struct bgp *bgp;
struct listnode *node, *nnode;
struct peer_group *group;
bool found = false;
+ json_object *json = NULL;
+
+ if (uj)
+ json = json_object_new_object();
bgp = name ? bgp_lookup_by_name(name) : bgp_get_default();
if (!bgp) {
- vty_out(vty, "%% BGP instance not found\n");
+ if (uj) {
+ vty_out(vty, "%s\n",
+ json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ } else {
+ vty_out(vty, "%% BGP instance not found\n");
+ }
+
return CMD_WARNING;
}
for (ALL_LIST_ELEMENTS(bgp->group, node, nnode, group)) {
if (group_name) {
if (strmatch(group->name, group_name)) {
- bgp_show_one_peer_group(vty, group);
+ bgp_show_one_peer_group(vty, group, json);
found = true;
break;
}
} else {
- bgp_show_one_peer_group(vty, group);
+ bgp_show_one_peer_group(vty, group, json);
}
}
- if (group_name && !found)
+ if (group_name && !found && !uj)
vty_out(vty, "%% No such peer-group\n");
+ if (uj) {
+ vty_out(vty, "%s\n",
+ json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
+
return CMD_SUCCESS;
}
-DEFUN (show_ip_bgp_peer_groups,
- show_ip_bgp_peer_groups_cmd,
- "show [ip] bgp [<view|vrf> VIEWVRFNAME] peer-group [PGNAME]",
- SHOW_STR
- IP_STR
- BGP_STR
- BGP_INSTANCE_HELP_STR
- "Detailed information on BGP peer groups\n"
- "Peer group name\n")
+DEFUN(show_ip_bgp_peer_groups, show_ip_bgp_peer_groups_cmd,
+ "show [ip] bgp [<view|vrf> VIEWVRFNAME] peer-group [PGNAME] [json]",
+ SHOW_STR IP_STR BGP_STR BGP_INSTANCE_HELP_STR
+ "Detailed information on BGP peer groups\n"
+ "Peer group name\n" JSON_STR)
{
char *vrf, *pg;
int idx = 0;
+ bool uj = use_json(argc, argv);
vrf = argv_find(argv, argc, "VIEWVRFNAME", &idx) ? argv[idx]->arg
: NULL;
pg = argv_find(argv, argc, "PGNAME", &idx) ? argv[idx]->arg : NULL;
- return bgp_show_peer_group_vty(vty, vrf, pg);
+ return bgp_show_peer_group_vty(vty, vrf, pg, uj);
}
peer->rtt_expected, peer->rtt_keepalive_conf);
/* bfd */
- if (peer->bfd_info) {
- if (!peer_group_active(peer) || !g_peer->bfd_info) {
- bgp_bfd_peer_config_write(vty, peer, addr);
- }
- }
+ if (peer->bfd_config)
+ bgp_bfd_peer_config_write(vty, peer, addr);
/* password */
if (peergroup_flag_check(peer, PEER_FLAG_PASSWORD))
}
} else {
if (peer->afc[afi][safi]) {
- if ((afi == AFI_IP) && (safi == SAFI_UNICAST)) {
- if (CHECK_FLAG(bgp->flags,
- BGP_FLAG_NO_DEFAULT_IPV4)) {
+ if ((afi == AFI_IP || afi == AFI_IP6)
+ && safi == SAFI_UNICAST) {
+ if (afi == AFI_IP
+ && CHECK_FLAG(bgp->flags,
+ BGP_FLAG_NO_DEFAULT_IPV4)) {
+ vty_out(vty, " neighbor %s activate\n",
+ addr);
+ } else if (afi == AFI_IP6
+ && !CHECK_FLAG(
+ bgp->flags,
+ BGP_FLAG_DEFAULT_IPV6)) {
vty_out(vty, " neighbor %s activate\n",
addr);
}
- } else
+ } else {
vty_out(vty, " neighbor %s activate\n", addr);
+ }
} else {
- if ((afi == AFI_IP) && (safi == SAFI_UNICAST)) {
- if (!CHECK_FLAG(bgp->flags,
- BGP_FLAG_NO_DEFAULT_IPV4)) {
+ if ((afi == AFI_IP || afi == AFI_IP6)
+ && safi == SAFI_UNICAST) {
+ if (afi == AFI_IP
+ && !CHECK_FLAG(bgp->flags,
+ BGP_FLAG_NO_DEFAULT_IPV4)) {
+ vty_out(vty,
+ " no neighbor %s activate\n",
+ addr);
+ } else if (afi == AFI_IP6
+ && CHECK_FLAG(
+ bgp->flags,
+ BGP_FLAG_DEFAULT_IPV6)) {
vty_out(vty,
" no neighbor %s activate\n",
addr);
if (CHECK_FLAG(bgp->flags, BGP_FLAG_NO_DEFAULT_IPV4))
vty_out(vty, " no bgp default ipv4-unicast\n");
+ /* BGP default ipv6-unicast. */
+ if (CHECK_FLAG(bgp->flags, BGP_FLAG_DEFAULT_IPV6))
+ vty_out(vty, " bgp default ipv6-unicast\n");
+
/* BGP default local-preference. */
if (bgp->default_local_pref != BGP_DEFAULT_LOCAL_PREF)
vty_out(vty, " bgp default local-preference %u\n",
install_element(BGP_NODE, &no_bgp_default_ipv4_unicast_cmd);
install_element(BGP_NODE, &bgp_default_ipv4_unicast_cmd);
+ /* "no bgp default ipv6-unicast" commands. */
+ install_element(BGP_NODE, &no_bgp_default_ipv6_unicast_cmd);
+ install_element(BGP_NODE, &bgp_default_ipv6_unicast_cmd);
+
/* "bgp network import-check" commands. */
install_element(BGP_NODE, &bgp_network_import_check_cmd);
install_element(BGP_NODE, &bgp_network_import_check_exact_cmd);
const char *str, char *errmsg,
size_t errmsg_len);
extern int peer_conf_interface_create(struct bgp *bgp, const char *conf_if,
- afi_t afi, safi_t safi, bool v6only,
- const char *peer_group_name, int as_type,
- as_t as, char *errmsg, size_t errmsg_len);
+ bool v6only, const char *peer_group_name,
+ int as_type, as_t as, char *errmsg,
+ size_t errmsg_len);
extern int peer_flag_modify_nb(struct bgp *bgp, const char *ip_str,
struct peer *peer, uint32_t flag, bool set,
char *errmsg, size_t errmsg_len);
/* hook to indicate vrf status change for SNMP */
DEFINE_HOOK(bgp_vrf_status_changed, (struct bgp *bgp, struct interface *ifp),
- (bgp, ifp))
+ (bgp, ifp));
/* Can we install into zebra? */
static inline bool bgp_install_info_to_zebra(struct bgp *bgp)
if (!CHECK_FLAG(bgp->flags, BGP_FLAG_NO_FAST_EXT_FAILOVER)) {
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
-#if defined(HAVE_CUMULUS)
- /* Take down directly connected EBGP peers as well as
- * 1-hop BFD
- * tracked (directly connected) IBGP peers.
- */
- if ((peer->ttl != BGP_DEFAULT_TTL)
- && (peer->gtsm_hops != BGP_GTSM_HOPS_CONNECTED)
- && (!peer->bfd_info
- || bgp_bfd_is_peer_multihop(peer)))
-#else
- /* Take down directly connected EBGP peers */
+ /* Take down directly connected peers. */
if ((peer->ttl != BGP_DEFAULT_TTL)
&& (peer->gtsm_hops != BGP_GTSM_HOPS_CONNECTED))
-#endif
continue;
if (ifp == peer->nexthop.ifp) {
DEFINE_MTYPE_STATIC(BGPD, PEER_TX_SHUTDOWN_MSG, "Peer shutdown message (TX)");
DEFINE_MTYPE_STATIC(BGPD, BGP_EVPN_INFO, "BGP EVPN instance information");
-DEFINE_QOBJ_TYPE(bgp_master)
-DEFINE_QOBJ_TYPE(bgp)
-DEFINE_QOBJ_TYPE(peer)
-DEFINE_HOOK(bgp_inst_delete, (struct bgp *bgp), (bgp))
+DEFINE_QOBJ_TYPE(bgp_master);
+DEFINE_QOBJ_TYPE(bgp);
+DEFINE_QOBJ_TYPE(peer);
+DEFINE_HOOK(bgp_inst_delete, (struct bgp *bgp), (bgp));
/* BGP process wide configuration. */
static struct bgp_master bgp_master;
XFREE(MTYPE_PEER_CONF_IF, peer->conf_if);
- bfd_info_free(&(peer->bfd_info));
+ /* Remove BFD configuration. */
+ if (peer->bfd_config)
+ bgp_peer_remove_bfd_config(peer);
FOREACH_AFI_SAFI (afi, safi)
bgp_addpath_set_peer_type(peer, afi, safi, BGP_ADDPATH_NONE);
for (afidx = BGP_AF_START; afidx < BGP_AF_MAX; afidx++) {
paf = peer_src->peer_af_array[afidx];
- if (paf != NULL)
- peer_af_create(peer_dst, paf->afi, paf->safi);
+ if (paf != NULL) {
+ if (!peer_af_find(peer_dst, paf->afi, paf->safi))
+ peer_af_create(peer_dst, paf->afi, paf->safi);
+ }
}
/* update-source apply */
*/
struct peer *peer_create(union sockunion *su, const char *conf_if,
struct bgp *bgp, as_t local_as, as_t remote_as,
- int as_type, afi_t afi, safi_t safi,
- struct peer_group *group)
+ int as_type, struct peer_group *group)
{
int active;
struct peer *peer;
char buf[SU_ADDRSTRLEN];
+ afi_t afi;
+ safi_t safi;
peer = peer_new(bgp);
if (conf_if) {
SET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE);
- if (afi && safi) {
- peer->afc[afi][safi] = 1;
- peer_af_create(peer, afi, safi);
+ /* If address family is IPv4 and `bgp default ipv4-unicast` (default),
+ * then activate the neighbor for this AF.
+ * If address family is IPv6 and `bgp default ipv6-unicast`
+ * (non-default), then activate the neighbor for this AF.
+ */
+ FOREACH_AFI_SAFI (afi, safi) {
+ if ((afi == AFI_IP || afi == AFI_IP6) && safi == SAFI_UNICAST) {
+ if ((afi == AFI_IP
+ && !CHECK_FLAG(bgp->flags,
+ BGP_FLAG_NO_DEFAULT_IPV4))
+ || (afi == AFI_IP6
+ && CHECK_FLAG(bgp->flags,
+ BGP_FLAG_DEFAULT_IPV6))) {
+ peer->afc[afi][safi] = 1;
+ peer_af_create(peer, afi, safi);
+ }
+ }
}
/* auto shutdown if configured */
/* If peer does not exist, create new one. If peer already exists,
set AS number to the peer. */
int peer_remote_as(struct bgp *bgp, union sockunion *su, const char *conf_if,
- as_t *as, int as_type, afi_t afi, safi_t safi)
+ as_t *as, int as_type)
{
struct peer *peer;
as_t local_as;
else
local_as = bgp->as;
- /* If this is IPv4 unicast configuration and "no bgp default
- ipv4-unicast" is specified. */
-
- if (CHECK_FLAG(bgp->flags, BGP_FLAG_NO_DEFAULT_IPV4)
- && afi == AFI_IP && safi == SAFI_UNICAST)
- peer_create(su, conf_if, bgp, local_as, *as, as_type, 0,
- 0, NULL);
- else
- peer_create(su, conf_if, bgp, local_as, *as, as_type,
- afi, safi, NULL);
+ peer_create(su, conf_if, bgp, local_as, *as, as_type, NULL);
}
return 0;
/* If this is the first peer to be activated for this
* afi/labeled-unicast recalc bestpaths to trigger label allocation */
- if (safi == SAFI_LABELED_UNICAST
+ if (ret != BGP_ERR_PEER_SAFI_CONFLICT && safi == SAFI_LABELED_UNICAST
&& !bgp->allocate_mpls_labels[afi][SAFI_UNICAST]) {
if (BGP_DEBUG(zebra, ZEBRA))
SET_FLAG(peer->flags, PEER_FLAG_DELETE);
- bgp_bfd_deregister_peer(peer);
+ /* Remove BFD settings. */
+ if (peer->bfd_config)
+ bgp_peer_remove_bfd_config(peer);
/* Delete peer route flap dampening configuration. This needs to happen
* before removing the peer from peer groups.
group->conf = peer_new(bgp);
if (!CHECK_FLAG(bgp->flags, BGP_FLAG_NO_DEFAULT_IPV4))
group->conf->afc[AFI_IP][SAFI_UNICAST] = 1;
+ if (CHECK_FLAG(bgp->flags, BGP_FLAG_DEFAULT_IPV6))
+ group->conf->afc[AFI_IP6][SAFI_UNICAST] = 1;
XFREE(MTYPE_BGP_PEER_HOST, group->conf->host);
group->conf->host = XSTRDUP(MTYPE_BGP_PEER_HOST, name);
group->conf->group = group;
/* Update GR flags for the peer. */
bgp_peer_gr_flags_update(peer);
- bgp_bfd_peer_group2peer_copy(conf, peer);
+ /* Apply BFD settings from group to peer if it exists. */
+ if (conf->bfd_config) {
+ bgp_peer_configure_bfd(peer, false);
+ bgp_peer_config_apply(peer, group);
+ }
}
/* Peer group's remote AS configuration. */
XFREE(MTYPE_PEER_GROUP_HOST, group->name);
group->name = NULL;
- bfd_info_free(&(group->conf->bfd_info));
+ if (group->conf->bfd_config)
+ bgp_peer_remove_bfd_config(group->conf);
group->conf->group = NULL;
peer_delete(group->conf);
}
peer = peer_create(su, NULL, bgp, bgp->as, group->conf->as,
- group->conf->as_type, 0, 0, group);
+ group->conf->as_type, group);
peer = peer_lock(peer); /* group->peer list reference */
listnode_add(group->peer, peer);
FOREACH_AFI_SAFI (afi, safi) {
if (group->conf->afc[afi][safi]) {
peer->afc[afi][safi] = 1;
- peer_af_create(peer, afi, safi);
+
+ if (!peer_af_find(peer, afi, safi))
+ peer_af_create(peer, afi, safi);
+
peer_group2peer_config_copy_af(group, peer, afi,
safi);
} else if (peer->afc[afi][safi])
/* Create peer first; we've already checked group config is valid. */
peer = peer_create(su, NULL, bgp, bgp->as, group->conf->as,
- group->conf->as_type, 0, 0, group);
+ group->conf->as_type, group);
if (!peer)
return NULL;
bgp_clist = community_list_init();
/* BFD init */
- bgp_bfd_init();
+ bgp_bfd_init(bm->master);
bgp_lp_vty_init();
#include "bgp_nexthop.h"
#include "bgp_damp.h"
+#include "lib/bfd.h"
+
#define BGP_MAX_HOSTNAME 64 /* Linux max, is larger than most other sys */
#define BGP_PEER_MAX_HASH_SIZE 16384
#define BM_FLAG_SEND_EXTRA_DATA_TO_ZEBRA (1 << 1)
bool terminating; /* global flag that sigint terminate seen */
- QOBJ_FIELDS
+ QOBJ_FIELDS;
};
-DECLARE_QOBJ_TYPE(bgp_master)
+DECLARE_QOBJ_TYPE(bgp_master);
/* BGP route-map structure. */
struct bgp_rmap {
#define BGP_FLAG_SHUTDOWN (1 << 27)
#define BGP_FLAG_SUPPRESS_FIB_PENDING (1 << 28)
#define BGP_FLAG_SUPPRESS_DUPLICATES (1 << 29)
+#define BGP_FLAG_DEFAULT_IPV6 (1 << 30)
enum global_mode GLOBAL_GR_FSM[BGP_GLOBAL_GR_MODE]
[BGP_GLOBAL_GR_EVENT_CMD];
/* BGP route flap dampening configuration */
struct bgp_damp_config damp[AFI_MAX][SAFI_MAX];
- QOBJ_FIELDS
+ QOBJ_FIELDS;
};
-DECLARE_QOBJ_TYPE(bgp)
+DECLARE_QOBJ_TYPE(bgp);
-DECLARE_HOOK(bgp_inst_delete, (struct bgp *bgp), (bgp))
+DECLARE_HOOK(bgp_inst_delete, (struct bgp *bgp), (bgp));
DECLARE_HOOK(bgp_inst_config_write,
(struct bgp *bgp, struct vty *vty),
- (bgp, vty))
+ (bgp, vty));
/* Thread callback information */
struct afi_safi_info {
#define PEER_RMAP_TYPE_EXPORT (1U << 7) /* neighbor route-map export */
#define PEER_RMAP_TYPE_AGGREGATE (1U << 8) /* aggregate-address route-map */
- /* peer specific BFD information */
- struct bfd_info *bfd_info;
+ /** Peer overwrite configuration. */
+ struct bfd_session_config {
+ /**
+ * Manual configuration bit.
+ *
+ * This flag only makes sense for real peers (and not groups),
+ * it keeps track if the user explicitly configured BFD for a
+ * peer.
+ */
+ bool manual;
+ /** Control Plane Independent. */
+ bool cbit;
+ /** Detection multiplier. */
+ uint8_t detection_multiplier;
+ /** Minimum required RX interval. */
+ uint32_t min_rx;
+ /** Minimum required TX interval. */
+ uint32_t min_tx;
+ /** Profile name. */
+ char profile[BFD_PROFILE_NAME_LEN];
+ /** Peer BFD session */
+ struct bfd_session_params *session;
+ } * bfd_config;
/* hostname and domainname advertised by host */
char *hostname;
bool advmap_config_change[AFI_MAX][SAFI_MAX];
bool advmap_table_change;
- QOBJ_FIELDS
+ QOBJ_FIELDS;
};
-DECLARE_QOBJ_TYPE(peer)
+DECLARE_QOBJ_TYPE(peer);
/* Inherit peer attribute from peer-group. */
#define PEER_ATTR_INHERIT(peer, group, attr) \
extern bool peer_active_nego(struct peer *);
extern void bgp_recalculate_all_bestpaths(struct bgp *bgp);
extern struct peer *peer_create(union sockunion *, const char *, struct bgp *,
- as_t, as_t, int, afi_t, safi_t,
- struct peer_group *);
+ as_t, as_t, int, struct peer_group *);
extern struct peer *peer_create_accept(struct bgp *);
extern void peer_xfer_config(struct peer *dst, struct peer *src);
extern char *peer_uptime(time_t uptime2, char *buf, size_t len, bool use_json,
extern int bgp_afi_safi_peer_exists(struct bgp *bgp, afi_t afi, safi_t safi);
extern void peer_as_change(struct peer *, as_t, int);
extern int peer_remote_as(struct bgp *, union sockunion *, const char *, as_t *,
- int, afi_t, safi_t);
+ int);
extern int peer_group_remote_as(struct bgp *, const char *, as_t *, int);
extern int peer_delete(struct peer *peer);
extern void peer_notify_unconfig(struct peer *peer);
/* Hooks */
DECLARE_HOOK(bgp_vrf_status_changed, (struct bgp *bgp, struct interface *ifp),
- (bgp, ifp))
-DECLARE_HOOK(peer_status_changed, (struct peer *peer), (peer))
-DECLARE_HOOK(bgp_snmp_init_stats, (struct bgp *bgp), (bgp))
-DECLARE_HOOK(bgp_snmp_update_last_changed, (struct bgp *bgp), (bgp))
+ (bgp, ifp));
+DECLARE_HOOK(peer_status_changed, (struct peer *peer), (peer));
+DECLARE_HOOK(bgp_snmp_init_stats, (struct bgp *bgp), (bgp));
+DECLARE_HOOK(bgp_snmp_update_last_changed, (struct bgp *bgp), (bgp));
DECLARE_HOOK(bgp_snmp_update_stats,
(struct bgp_node *rn, struct bgp_path_info *pi, bool added),
- (rn, pi, added))
+ (rn, pi, added));
DECLARE_HOOK(bgp_rpki_prefix_status,
(struct peer * peer, struct attr *attr,
const struct prefix *prefix),
- (peer, attr, prefix))
+ (peer, attr, prefix));
void peer_nsf_stop(struct peer *peer);
#undef BGP_VNC_DEBUG_MATCH_GROUP
-DEFINE_MGROUP(RFAPI, "rfapi")
-DEFINE_MTYPE(RFAPI, RFAPI_CFG, "NVE Configuration")
-DEFINE_MTYPE(RFAPI, RFAPI_GROUP_CFG, "NVE Group Configuration")
-DEFINE_MTYPE(RFAPI, RFAPI_L2_CFG, "RFAPI L2 Group Configuration")
-DEFINE_MTYPE(RFAPI, RFAPI_RFP_GROUP_CFG, "RFAPI RFP Group Configuration")
-DEFINE_MTYPE(RFAPI, RFAPI, "RFAPI Generic")
-DEFINE_MTYPE(RFAPI, RFAPI_DESC, "RFAPI Descriptor")
-DEFINE_MTYPE(RFAPI, RFAPI_IMPORTTABLE, "RFAPI Import Table")
-DEFINE_MTYPE(RFAPI, RFAPI_MONITOR, "RFAPI Monitor VPN")
-DEFINE_MTYPE(RFAPI, RFAPI_MONITOR_ENCAP, "RFAPI Monitor Encap")
-DEFINE_MTYPE(RFAPI, RFAPI_NEXTHOP, "RFAPI Next Hop")
-DEFINE_MTYPE(RFAPI, RFAPI_VN_OPTION, "RFAPI VN Option")
-DEFINE_MTYPE(RFAPI, RFAPI_UN_OPTION, "RFAPI UN Option")
-DEFINE_MTYPE(RFAPI, RFAPI_WITHDRAW, "RFAPI Withdraw")
-DEFINE_MTYPE(RFAPI, RFAPI_RFG_NAME, "RFAPI RFGName")
-DEFINE_MTYPE(RFAPI, RFAPI_ADB, "RFAPI Advertisement Data")
-DEFINE_MTYPE(RFAPI, RFAPI_ETI, "RFAPI Export Table Info")
-DEFINE_MTYPE(RFAPI, RFAPI_NVE_ADDR, "RFAPI NVE Address")
-DEFINE_MTYPE(RFAPI, RFAPI_PREFIX_BAG, "RFAPI Prefix Bag")
-DEFINE_MTYPE(RFAPI, RFAPI_IT_EXTRA, "RFAPI IT Extra")
-DEFINE_MTYPE(RFAPI, RFAPI_INFO, "RFAPI Info")
-DEFINE_MTYPE(RFAPI, RFAPI_ADDR, "RFAPI Addr")
-DEFINE_MTYPE(RFAPI, RFAPI_UPDATED_RESPONSE_QUEUE, "RFAPI Updated Rsp Queue")
-DEFINE_MTYPE(RFAPI, RFAPI_RECENT_DELETE, "RFAPI Recently Deleted Route")
-DEFINE_MTYPE(RFAPI, RFAPI_L2ADDR_OPT, "RFAPI L2 Address Option")
-DEFINE_MTYPE(RFAPI, RFAPI_AP, "RFAPI Advertised Prefix")
-DEFINE_MTYPE(RFAPI, RFAPI_MONITOR_ETH, "RFAPI Monitor Ethernet")
-
-DEFINE_QOBJ_TYPE(rfapi_nve_group_cfg)
-DEFINE_QOBJ_TYPE(rfapi_l2_group_cfg)
+DEFINE_MGROUP(RFAPI, "rfapi");
+DEFINE_MTYPE(RFAPI, RFAPI_CFG, "NVE Configuration");
+DEFINE_MTYPE(RFAPI, RFAPI_GROUP_CFG, "NVE Group Configuration");
+DEFINE_MTYPE(RFAPI, RFAPI_L2_CFG, "RFAPI L2 Group Configuration");
+DEFINE_MTYPE(RFAPI, RFAPI_RFP_GROUP_CFG, "RFAPI RFP Group Configuration");
+DEFINE_MTYPE(RFAPI, RFAPI, "RFAPI Generic");
+DEFINE_MTYPE(RFAPI, RFAPI_DESC, "RFAPI Descriptor");
+DEFINE_MTYPE(RFAPI, RFAPI_IMPORTTABLE, "RFAPI Import Table");
+DEFINE_MTYPE(RFAPI, RFAPI_MONITOR, "RFAPI Monitor VPN");
+DEFINE_MTYPE(RFAPI, RFAPI_MONITOR_ENCAP, "RFAPI Monitor Encap");
+DEFINE_MTYPE(RFAPI, RFAPI_NEXTHOP, "RFAPI Next Hop");
+DEFINE_MTYPE(RFAPI, RFAPI_VN_OPTION, "RFAPI VN Option");
+DEFINE_MTYPE(RFAPI, RFAPI_UN_OPTION, "RFAPI UN Option");
+DEFINE_MTYPE(RFAPI, RFAPI_WITHDRAW, "RFAPI Withdraw");
+DEFINE_MTYPE(RFAPI, RFAPI_RFG_NAME, "RFAPI RFGName");
+DEFINE_MTYPE(RFAPI, RFAPI_ADB, "RFAPI Advertisement Data");
+DEFINE_MTYPE(RFAPI, RFAPI_ETI, "RFAPI Export Table Info");
+DEFINE_MTYPE(RFAPI, RFAPI_NVE_ADDR, "RFAPI NVE Address");
+DEFINE_MTYPE(RFAPI, RFAPI_PREFIX_BAG, "RFAPI Prefix Bag");
+DEFINE_MTYPE(RFAPI, RFAPI_IT_EXTRA, "RFAPI IT Extra");
+DEFINE_MTYPE(RFAPI, RFAPI_INFO, "RFAPI Info");
+DEFINE_MTYPE(RFAPI, RFAPI_ADDR, "RFAPI Addr");
+DEFINE_MTYPE(RFAPI, RFAPI_UPDATED_RESPONSE_QUEUE, "RFAPI Updated Rsp Queue");
+DEFINE_MTYPE(RFAPI, RFAPI_RECENT_DELETE, "RFAPI Recently Deleted Route");
+DEFINE_MTYPE(RFAPI, RFAPI_L2ADDR_OPT, "RFAPI L2 Address Option");
+DEFINE_MTYPE(RFAPI, RFAPI_AP, "RFAPI Advertised Prefix");
+DEFINE_MTYPE(RFAPI, RFAPI_MONITOR_ETH, "RFAPI Monitor Ethernet");
+
+DEFINE_QOBJ_TYPE(rfapi_nve_group_cfg);
+DEFINE_QOBJ_TYPE(rfapi_l2_group_cfg);
/***********************************************************************
* RFAPI Support
***********************************************************************/
struct ecommunity *rt_export_list;
void *rfp_cfg; /* rfp owned group config */
- QOBJ_FIELDS
+ QOBJ_FIELDS;
};
-DECLARE_QOBJ_TYPE(rfapi_l2_group_cfg)
+DECLARE_QOBJ_TYPE(rfapi_l2_group_cfg);
typedef enum {
RFAPI_GROUP_CFG_NVE = 1,
/* for VRF type groups */
uint32_t label;
struct rfapi_descriptor *rfd;
- QOBJ_FIELDS
+ QOBJ_FIELDS;
};
-DECLARE_QOBJ_TYPE(rfapi_nve_group_cfg)
+DECLARE_QOBJ_TYPE(rfapi_nve_group_cfg);
struct rfapi_rfg_name {
struct rfapi_nve_group_cfg *rfg;
*/
extern time_t rfapi_time(time_t *t);
-DECLARE_MGROUP(RFAPI)
-DECLARE_MTYPE(RFAPI_CFG)
-DECLARE_MTYPE(RFAPI_GROUP_CFG)
-DECLARE_MTYPE(RFAPI_L2_CFG)
-DECLARE_MTYPE(RFAPI_RFP_GROUP_CFG)
-DECLARE_MTYPE(RFAPI)
-DECLARE_MTYPE(RFAPI_DESC)
-DECLARE_MTYPE(RFAPI_IMPORTTABLE)
-DECLARE_MTYPE(RFAPI_MONITOR)
-DECLARE_MTYPE(RFAPI_MONITOR_ENCAP)
-DECLARE_MTYPE(RFAPI_NEXTHOP)
-DECLARE_MTYPE(RFAPI_VN_OPTION)
-DECLARE_MTYPE(RFAPI_UN_OPTION)
-DECLARE_MTYPE(RFAPI_WITHDRAW)
-DECLARE_MTYPE(RFAPI_RFG_NAME)
-DECLARE_MTYPE(RFAPI_ADB)
-DECLARE_MTYPE(RFAPI_ETI)
-DECLARE_MTYPE(RFAPI_NVE_ADDR)
-DECLARE_MTYPE(RFAPI_PREFIX_BAG)
-DECLARE_MTYPE(RFAPI_IT_EXTRA)
-DECLARE_MTYPE(RFAPI_INFO)
-DECLARE_MTYPE(RFAPI_ADDR)
-DECLARE_MTYPE(RFAPI_UPDATED_RESPONSE_QUEUE)
-DECLARE_MTYPE(RFAPI_RECENT_DELETE)
-DECLARE_MTYPE(RFAPI_L2ADDR_OPT)
-DECLARE_MTYPE(RFAPI_AP)
-DECLARE_MTYPE(RFAPI_MONITOR_ETH)
+DECLARE_MGROUP(RFAPI);
+DECLARE_MTYPE(RFAPI_CFG);
+DECLARE_MTYPE(RFAPI_GROUP_CFG);
+DECLARE_MTYPE(RFAPI_L2_CFG);
+DECLARE_MTYPE(RFAPI_RFP_GROUP_CFG);
+DECLARE_MTYPE(RFAPI);
+DECLARE_MTYPE(RFAPI_DESC);
+DECLARE_MTYPE(RFAPI_IMPORTTABLE);
+DECLARE_MTYPE(RFAPI_MONITOR);
+DECLARE_MTYPE(RFAPI_MONITOR_ENCAP);
+DECLARE_MTYPE(RFAPI_NEXTHOP);
+DECLARE_MTYPE(RFAPI_VN_OPTION);
+DECLARE_MTYPE(RFAPI_UN_OPTION);
+DECLARE_MTYPE(RFAPI_WITHDRAW);
+DECLARE_MTYPE(RFAPI_RFG_NAME);
+DECLARE_MTYPE(RFAPI_ADB);
+DECLARE_MTYPE(RFAPI_ETI);
+DECLARE_MTYPE(RFAPI_NVE_ADDR);
+DECLARE_MTYPE(RFAPI_PREFIX_BAG);
+DECLARE_MTYPE(RFAPI_IT_EXTRA);
+DECLARE_MTYPE(RFAPI_INFO);
+DECLARE_MTYPE(RFAPI_ADDR);
+DECLARE_MTYPE(RFAPI_UPDATED_RESPONSE_QUEUE);
+DECLARE_MTYPE(RFAPI_RECENT_DELETE);
+DECLARE_MTYPE(RFAPI_L2ADDR_OPT);
+DECLARE_MTYPE(RFAPI_AP);
+DECLARE_MTYPE(RFAPI_MONITOR_ETH);
/*
bgpd_bgp_btoa_LDADD = bgpd/libbgp.a $(RFPLDADD) lib/libfrr.la $(LIBCAP) $(LIBM) $(UST_LIBS)
bgpd_bgpd_snmp_la_SOURCES = bgpd/bgp_snmp.c bgpd/bgp_mplsvpn_snmp.c
-bgpd_bgpd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu99
+bgpd_bgpd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu11
bgpd_bgpd_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
bgpd_bgpd_snmp_la_LIBADD = lib/libfrrsnmp.la
fi
if test "$enable_scripting" = "yes"; then
- AX_PROG_LUA([5.3])
- AX_LUA_HEADERS
+ AX_PROG_LUA([5.3], [5.4], [], [
+ AC_MSG_ERROR([Lua 5.3 is required to build with Lua support. No other version is supported.])
+ ])
+ AX_LUA_HEADERS([], [
+ AC_MSG_ERROR([Lua 5.3 headers are required to build with Lua support. No other version is supported.])
+ ])
AX_LUA_LIBS([
- AC_DEFINE([HAVE_SCRIPTING], [1], [Have support for scripting])
- LIBS="$LIBS $LUA_LIB"
+ AC_DEFINE([HAVE_SCRIPTING], [1], [Have support for scripting])
+ LIBS="$LIBS $LUA_LIB"
+ ], [
+ AC_MSG_ERROR([Lua 5.3 libraries are required to build with Lua support. No other version is supported.])
])
fi
if test "$orig_cflags" = ""; then
AC_C_FLAG([-g3])
AC_C_FLAG([-O0])
+ AC_C_FLAG([-ggdb3])
fi
else
if test "$orig_cflags" = ""; then
AC_C_FLAG([-O2])
fi
fi
+
AM_CONDITIONAL([DEV_BUILD], [test "$enable_dev_build" = "yes"])
dnl always want these CFLAGS
AS_IF([test "$enable_pathd" != "no"], [
AC_DEFINE([HAVE_PATHD], [1], [pathd])
-])
-
-AS_IF([test "$enable_pcep" != "no"], [
AC_DEFINE([HAVE_PATHD_PCEP], [1], [pathd-pcep])
])
+
if test "$ac_cv_lib_json_c_json_object_get" = "no" -a "$BFDD" = "bfdd"; then
AC_MSG_ERROR(["you must use json-c library to use bfdd"])
fi
AM_CONDITIONAL([HAVE_PROTOBUF3], [$PROTO3])
dnl PCEP plugin
-AM_CONDITIONAL([HAVE_PATHD_PCEP], [test "$enable_pcep" = "yes"])
-AS_IF([test "$enable_pcep" = "yes"], [
- AC_CHECK_LIB([pcep_pcc], [initialize_pcc], [
- PATHD_PCEP_LIBS="-lpcep_pcc"
- ],[
- AC_MSG_ERROR([PCEP library libpcep_pcc not found])
- ])
- AC_SUBST([PATHD_PCEP_LIBS])
-])
+AS_IF([test "$enable_pathd" != "no"], [
+ AC_SUBST([PATHD_PCEP_LIBS], ["pceplib/libpcep_pcc.la"])
+ AC_SUBST([PATHD_PCEP_INCL], ["-I./pceplib "])
+ ])
+AC_CHECK_LIB([cunit], [CU_initialize_registry], [pcep_cunit=yes],[pcep_cunit=no])
+AM_CONDITIONAL([PATHD_PCEP_TEST], [test "x${pcep_cunit}" = xyes])
+AC_CHECK_PROG(VALGRIND_CHECK, valgrind, yes)
+AM_CONDITIONAL([HAVE_VALGRIND_PCEP], [test "$VALGRIND_CHECK" = "yes"])
dnl daemons
AM_CONDITIONAL([VTYSH], [test "$VTYSH" = "vtysh"])
AM_CONDITIONAL([FABRICD], [test "$enable_fabricd" != "no"])
AM_CONDITIONAL([VRRPD], [test "$enable_vrrpd" != "no"])
AM_CONDITIONAL([PATHD], [test "$enable_pathd" != "no"])
+AM_CONDITIONAL([PATHD_PCEP], [test "$enable_pathd" != "no"])
AC_CONFIG_FILES([Makefile],[
test "$enable_dev_build" = "yes" && makefile_devbuild="--dev-build"
usr/lib/*/frr/modules/zebra_cumulus_mlag.so
usr/lib/*/frr/modules/zebra_fpm.so
usr/lib/*/frr/modules/zebra_irdp.so
+usr/lib/*/frr/modules/pathd_pcep.so
usr/lib/frr/*.sh
usr/lib/frr/*d
usr/lib/frr/watchfrr
.. code-block:: shell
- curl https://bootstrap.pypa.io/2.7/get-pip.py --output get-pip.py
+ curl https://bootstrap.pypa.io/pip/2.7/get-pip.py --output get-pip.py
sudo python2 ./get-pip.py
# And verify the installation
version on the build machine differs from the version of ``protoc`` being linked
to during a gRPC build. The error messages from this defect look like:
-.. code-block:: terminal
+.. code-block:: shell
gens/src/proto/grpc/channelz/channelz.pb.h: In member function ‘void grpc::channelz::v1::ServerRef::set_name(const char*, size_t)’:
gens/src/proto/grpc/channelz/channelz.pb.h:9127:64: error: ‘EmptyDefault’ is not a member of ‘google::protobuf::internal::ArenaStringPtr’
:caption: mydaemon.h
#include "hook.h"
- DECLARE_HOOK(some_update_event, (struct eventinfo *info), (info))
+ DECLARE_HOOK(some_update_event, (struct eventinfo *info), (info));
.. code-block:: c
:caption: mydaemon.c
#include "mydaemon.h"
- DEFINE_HOOK(some_update_event, (struct eventinfo *info), (info))
+ DEFINE_HOOK(some_update_event, (struct eventinfo *info), (info));
...
hook_call(some_update_event, info);
.. code-block:: c
- DECLARE_HOOK(foo, (), ())
- DECLARE_HOOK(bar, (int arg), (arg))
- DECLARE_HOOK(baz, (const void *x, in_addr_t y), (x, y))
+ DECLARE_HOOK(foo, (), ());
+ DECLARE_HOOK(bar, (int arg), (arg));
+ DECLARE_HOOK(baz, (const void *x, in_addr_t y), (x, y));
.. c:macro:: DEFINE_HOOK(name, arglist, passlist)
zebra
vtysh
path
+ pceplib
link-state
#include <typesafe.h>
- PREDECL_XXX(Z)
+ PREDECL_XXX(Z);
struct item {
int otherdata;
struct Z_item mylistitem;
struct Z_head mylisthead;
/* unsorted: */
- DECLARE_XXX(Z, struct item, mylistitem)
+ DECLARE_XXX(Z, struct item, mylistitem);
/* sorted, items that compare as equal cannot be added to list */
int compare_func(const struct item *a, const struct item *b);
- DECLARE_XXX_UNIQ(Z, struct item, mylistitem, compare_func)
+ DECLARE_XXX_UNIQ(Z, struct item, mylistitem, compare_func);
/* sorted, items that compare as equal can be added to list */
int compare_func(const struct item *a, const struct item *b);
- DECLARE_XXX_NONUNIQ(Z, struct item, mylistitem, compare_func)
+ DECLARE_XXX_NONUNIQ(Z, struct item, mylistitem, compare_func);
/* hash tables: */
int compare_func(const struct item *a, const struct item *b);
uint32_t hash_func(const struct item *a);
- DECLARE_XXX(Z, struct item, mylistitem, compare_func, hash_func)
+ DECLARE_XXX(Z, struct item, mylistitem, compare_func, hash_func);
``XXX`` is replaced with the name of the data structure, e.g. ``SKIPLIST``
or ``ATOMLIST``. The ``DECLARE_XXX`` invocation can either occur in a `.h`
.. code-block:: c
:caption: mydaemon.h
- DECLARE_MGROUP(MYDAEMON)
- DECLARE_MTYPE(MYNEIGHBOR)
+ DECLARE_MGROUP(MYDAEMON);
+ DECLARE_MTYPE(MYNEIGHBOR);
.. code-block:: c
:caption: mydaemon.c
- DEFINE_MGROUP( MYDAEMON, "My daemon's memory")
- DEFINE_MTYPE( MYDAEMON, MYNEIGHBOR, "Neighbor entry")
- DEFINE_MTYPE_STATIC(MYDAEMON, MYNEIGHBORNAME, "Neighbor name")
+ DEFINE_MGROUP( MYDAEMON, "My daemon's memory");
+ DEFINE_MTYPE( MYDAEMON, MYNEIGHBOR, "Neighbor entry");
+ DEFINE_MTYPE_STATIC(MYDAEMON, MYNEIGHBORNAME, "Neighbor name");
struct neigh *neighbor_new(const char *name)
{
.version = "0.0",
.description = "my module",
.init = module_init,
- )
+ );
The ``frr_late_init`` hook will be called after the daemon has finished
its other startup and is about to enter the main event loop; this is the
--- /dev/null
+.. _pceplib:
+
+*******
+PCEPlib
+*******
+
+Overview
+========
+
+The PCEPlib is a PCEP implementation library that can be used by either a PCE
+or PCC.
+
+Currently, only the FRR pathd has been implemented as a PCC with the PCEPlib.
+The PCEPlib is able to simultaneously connect to multiple PCEP peers and can
+maintain persistent PCEP connections.
+
+
+PCEPlib compliance
+==================
+
+The PCEPlib implements version 1 of the PCEP protocol, according to `RFC 5440 <https://tools.ietf.org/html/rfc5440>`_.
+
+Additionally, the PCEPlib implements the following PCEP extensions:
+
+- `RFC 8281 <https://tools.ietf.org/html/rfc8281>`_ PCE initiated for PCE-Initiated LSP Setup
+- `RFC 8231 <https://tools.ietf.org/html/rfc8231>`_ Extensions for Stateful PCE
+- `RFC 8232 <https://tools.ietf.org/html/rfc8232>`_ Optimizations of Label Switched Path State Synchronization Procedures for a Stateful PCE
+- `RFC 8282 <https://tools.ietf.org/html/rfc8282>`_ Extensions to PCEP for Inter-Layer MPLS and GMPLS Traffic Engineering
+- `RFC 8408 <https://tools.ietf.org/html/rfc8408>`_ Conveying Path Setup Type in PCE Communication Protocol (PCEP) Messages
+- `draft-ietf-pce-segment-routing-07 <https://tools.ietf.org/html/draft-ietf-pce-segment-routing-07>`_,
+ `draft-ietf-pce-segment-routing-16 <https://tools.ietf.org/html/draft-ietf-pce-segment-routing-16>`_,
+ `RFC 8664 <https://tools.ietf.org/html/rfc8664>`_ Segment routing protocol extensions
+- `RFC 7470 <https://tools.ietf.org/html/rfc7470>`_ Conveying Vendor-Specific Constraints
+- `Draft-ietf-pce-association-group-10 <https://tools.ietf.org/html/draft-ietf-pce-association-group-10>`_
+ Establishing Relationships Between Sets of Label Switched Paths
+- `Draft-barth-pce-segment-routing-policy-cp-04 <https://tools.ietf.org/html/draft-barth-pce-segment-routing-policy-cp-04>`_
+ Segment Routing Policy Candidate Paths
+
+
+PCEPlib Architecture
+====================
+
+The PCEPlib is comprised of the following modules, each of which will be
+detailed in the following sections.
+
+- **pcep_messages**
+ - PCEP messages, objects, and TLVs implementations
+
+- **pcep_pcc**
+ - PCEPlib public PCC API with a sample PCC binary
+
+- **pcep_session_logic**
+ - PCEP Session handling
+
+- **pcep_socket_comm**
+ - Socket communications
+
+- **pcep_timers**
+ - PCEP timers
+
+- **pcep_utils**
+ - Internal utilities used by the PCEPlib modules.
+
+The interaction of these modules can be seen in the following diagram.
+
+PCEPlib Architecture:
+
+.. image:: images/PCEPlib_design.jpg
+
+
+PCEP Session Logic library
+--------------------------
+
+The PCEP Session Logic library orchestrates calls to the rest of the PCC libraries.
+
+PCEP Session Logic library responsibilities:
+
+- Handle messages received from "PCEP Socket Comm"
+- Create and manage "PCEP Session" objects
+- Set timers and react to timer expirations
+- Manage counters
+
+The PCEP Session Logic library will have 2 main triggers controlled by a
+pthread condition variable:
+
+- Timer expirations - ``on_timer_expire()`` callback
+- Messages received from PCEP SocketComm - ``message_received()`` callback
+
+The counters are created and managed using the ``pcep_utils/pcep_utils_counters.h``
+counters library. The following are the different counter groups managed:
+
+- **COUNTER_SUBGROUP_ID_RX_MSG**
+- **COUNTER_SUBGROUP_ID_TX_MSG**
+- **COUNTER_SUBGROUP_ID_RX_OBJ**
+- **COUNTER_SUBGROUP_ID_TX_OBJ**
+- **COUNTER_SUBGROUP_ID_RX_SUBOBJ**
+- **COUNTER_SUBGROUP_ID_TX_SUBOBJ**
+- **COUNTER_SUBGROUP_ID_RX_RO_SR_SUBOBJ**
+- **COUNTER_SUBGROUP_ID_TX_RO_SR_SUBOBJ**
+- **COUNTER_SUBGROUP_ID_RX_TLV**
+- **COUNTER_SUBGROUP_ID_TX_TLV**
+- **COUNTER_SUBGROUP_ID_EVENT**
+
+The counters can be obtained and reset as explained later in the PCEPlib PCC API.
+
+PCEP Socket Comm library
+------------------------
+
+PCEP communication can be configured to be handled internally in this simple
+library. When this library is instantiated by the PCEP Session Logic, callbacks
+are provided to handle received messages and error conditions.
+
+The following diagram illustrates how the library works.
+
+PCEPlib Socket Comm:
+
+.. image:: images/PCEPlib_socket_comm.jpg
+
+
+PCEP Timers library
+-------------------
+
+Timers can be configured to be handled internally by this library. When this
+library is instantiated by the PCEP Session Logic, callbacks are provided to
+ha:0
+ndle timer expirations. The following timers are implemented and handled,
+according to `RFC 5440 <https://tools.ietf.org/html/rfc5440>`_.
+
+- Open KeepWait (fixed at 60 seconds)
+ - Set once the PCC sends an Open, and if it expires before receiving a KeepAlive or PCErr, then the PCC should send a PCErr and close the TCP connection
+
+- Keepalive timer
+ - How often the PCC should send Keepalive messages to the PCE (and vice-versa)
+ - The timer will be reset after any message is sent: any message serves as a Keepalive
+
+- DeadTimer
+ - If no messages are received before expiration, the session is declared as down
+ - Reset everytime any message is received
+
+- PCReq request timer
+ - How long the PCC waits for the PCE to reply to PCReq messages.
+
+PCEPlib Timers:
+
+.. image:: images/PCEPlib_timers.jpg
+
+
+PCEP Messages library
+---------------------
+
+The PCEP Messages library has all of the implemented PCEP messages, objects,
+TLVs, and related functionality.
+
+The following header files can be used for creating and handling received PCEP
+entities.
+
+- pcep-messages.h
+- pcep-objects.h
+- pcep-tlvs.h
+
+
+PCEP Messages
++++++++++++++
+
+The following PCEP messages can be created and received:
+
+- ``struct pcep_message* pcep_msg_create_open(...);``
+- ``struct pcep_message* pcep_msg_create_open_with_tlvs(...);``
+- ``struct pcep_message* pcep_msg_create_request(...);``
+- ``struct pcep_message* pcep_msg_create_request_ipv6(...);``
+- ``struct pcep_message* pcep_msg_create_reply(...);``
+- ``struct pcep_message* pcep_msg_create_close(...);``
+- ``struct pcep_message* pcep_msg_create_error(...);``
+- ``struct pcep_message* pcep_msg_create_error_with_objects(...);``
+- ``struct pcep_message* pcep_msg_create_keepalive(...);``
+- ``struct pcep_message* pcep_msg_create_report(...);``
+- ``struct pcep_message* pcep_msg_create_update(...);``
+- ``struct pcep_message* pcep_msg_create_initiate(...);``
+
+Refer to ``pcep_messages/include/pcep-messages.h`` and the API section
+below for more details.
+
+
+PCEP Objects
+++++++++++++
+
+The following PCEP objects can be created and received:
+
+- ``struct pcep_object_open* pcep_obj_create_open(...);``
+- ``struct pcep_object_rp* pcep_obj_create_rp(...);``
+- ``struct pcep_object_notify* pcep_obj_create_notify(...);``
+- ``struct pcep_object_nopath* pcep_obj_create_nopath(...);``
+- ``struct pcep_object_association_ipv4* pcep_obj_create_association_ipv4(...);``
+- ``struct pcep_object_association_ipv6* pcep_obj_create_association_ipv6(...);``
+- ``struct pcep_object_endpoints_ipv4* pcep_obj_create_endpoint_ipv4(...);``
+- ``struct pcep_object_endpoints_ipv6* pcep_obj_create_endpoint_ipv6(...);``
+- ``struct pcep_object_bandwidth* pcep_obj_create_bandwidth(...);``
+- ``struct pcep_object_metric* pcep_obj_create_metric(...);``
+- ``struct pcep_object_lspa* pcep_obj_create_lspa(...);``
+- ``struct pcep_object_svec* pcep_obj_create_svec(...);``
+- ``struct pcep_object_error* pcep_obj_create_error(...);``
+- ``struct pcep_object_close* pcep_obj_create_close(...);``
+- ``struct pcep_object_srp* pcep_obj_create_srp(...);``
+- ``struct pcep_object_lsp* pcep_obj_create_lsp(...);``
+- ``struct pcep_object_vendor_info* pcep_obj_create_vendor_info(...);``
+- ``struct pcep_object_ro* pcep_obj_create_ero(...);``
+- ``struct pcep_object_ro* pcep_obj_create_rro(...);``
+- ``struct pcep_object_ro* pcep_obj_create_iro(...);``
+- ``struct pcep_ro_subobj_ipv4* pcep_obj_create_ro_subobj_ipv4(...);``
+- ``struct pcep_ro_subobj_ipv6* pcep_obj_create_ro_subobj_ipv6(...);``
+- ``struct pcep_ro_subobj_unnum* pcep_obj_create_ro_subobj_unnum(...);``
+- ``struct pcep_ro_subobj_32label* pcep_obj_create_ro_subobj_32label(...);``
+- ``struct pcep_ro_subobj_asn* pcep_obj_create_ro_subobj_asn(...);``
+- ``struct pcep_ro_subobj_sr* pcep_obj_create_ro_subobj_sr_nonai(...);``
+- ``struct pcep_ro_subobj_sr* pcep_obj_create_ro_subobj_sr_ipv4_node(...);``
+- ``struct pcep_ro_subobj_sr* pcep_obj_create_ro_subobj_sr_ipv6_node(...);``
+- ``struct pcep_ro_subobj_sr* pcep_obj_create_ro_subobj_sr_ipv4_adj(...);``
+- ``struct pcep_ro_subobj_sr* pcep_obj_create_ro_subobj_sr_ipv6_adj(...);``
+- ``struct pcep_ro_subobj_sr* pcep_obj_create_ro_subobj_sr_unnumbered_ipv4_adj(...);``
+- ``struct pcep_ro_subobj_sr* pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj(...);``
+
+Refer to ``pcep_messages/include/pcep-objects.h`` and the API section
+below for more details.
+
+
+PCEP TLVs
++++++++++
+
+The following PCEP TLVs (Tag, Length, Value) can be created and received:
+
+- Open Object TLVs
+ - ``struct pcep_object_tlv_stateful_pce_capability* pcep_tlv_create_stateful_pce_capability(...);``
+ - ``struct pcep_object_tlv_lsp_db_version* pcep_tlv_create_lsp_db_version(...);``
+ - ``struct pcep_object_tlv_speaker_entity_identifier* pcep_tlv_create_speaker_entity_id(...);``
+ - ``struct pcep_object_tlv_path_setup_type* pcep_tlv_create_path_setup_type(...);``
+ - ``struct pcep_object_tlv_path_setup_type_capability* pcep_tlv_create_path_setup_type_capability(...);``
+ - ``struct pcep_object_tlv_sr_pce_capability* pcep_tlv_create_sr_pce_capability(...);``
+
+- LSP Object TLVs
+ - ``struct pcep_object_tlv_ipv4_lsp_identifier* pcep_tlv_create_ipv4_lsp_identifiers(...);``
+ - ``struct pcep_object_tlv_ipv6_lsp_identifier* pcep_tlv_create_ipv6_lsp_identifiers(...);``
+ - ``struct pcep_object_tlv_symbolic_path_name* pcep_tlv_create_symbolic_path_name(...);``
+ - ``struct pcep_object_tlv_lsp_error_code* pcep_tlv_create_lsp_error_code(...);``
+ - ``struct pcep_object_tlv_rsvp_error_spec* pcep_tlv_create_rsvp_ipv4_error_spec(...);``
+ - ``struct pcep_object_tlv_rsvp_error_spec* pcep_tlv_create_rsvp_ipv6_error_spec(...);``
+ - ``struct pcep_object_tlv_nopath_vector* pcep_tlv_create_nopath_vector(...);``
+ - ``struct pcep_object_tlv_vendor_info* pcep_tlv_create_vendor_info(...);``
+ - ``struct pcep_object_tlv_arbitrary* pcep_tlv_create_tlv_arbitrary(...);``
+
+- SRPAG (SR Association Group) TLVs
+ - ``struct pcep_object_tlv_srpag_pol_id *pcep_tlv_create_srpag_pol_id_ipv4(...);``
+ - ``struct pcep_object_tlv_srpag_pol_id *pcep_tlv_create_srpag_pol_id_ipv6(...);``
+ - ``struct pcep_object_tlv_srpag_pol_name *pcep_tlv_create_srpag_pol_name(...);``
+ - ``struct pcep_object_tlv_srpag_cp_id *pcep_tlv_create_srpag_cp_id(...);``
+ - ``struct pcep_object_tlv_srpag_cp_pref *pcep_tlv_create_srpag_cp_pref(...);``
+
+Refer to ``pcep_messages/include/pcep-tlvs.h`` and the API section
+below for more details.
+
+
+PCEP PCC
+--------
+
+This module has a Public PCC API library (explained in detail later) and a
+sample PCC binary. The APIs in this library encapsulate other PCEPlib libraries
+for simplicity. With this API, the PCEPlib PCC can be started and stopped, and
+the PCEPlib event queue can be accessed. The PCEP Messages library is not
+encapsulated, and should be used directly.
+
+
+Internal Dependencies
+---------------------
+
+The following diagram illustrates the internal PCEPlib library dependencies.
+
+PCEPlib internal dependencies:
+
+.. image:: images/PCEPlib_internal_deps.jpg
+
+
+External Dependencies
+---------------------
+
+Originally the PCEPlib was based on the open source `libpcep project <https://www.acreo.se/open-software-libpcep>`_,
+but that dependency has been reduced to just one source file (pcep-tools.[ch]).
+
+
+PCEPlib Threading model
+-----------------------
+
+The PCEPlib can be run in stand-alone mode whereby a thread is launched for
+timers and socket comm, as is illustrated in the following diagram.
+
+PCEPlib Threading model:
+
+.. image:: images/PCEPlib_threading_model.jpg
+
+The PCEPlib can also be configured to use an external timers and socket
+infrastructure like the FRR threads and tasks. In this case, no internal
+threads are launched for timers and socket comm, as is illustrated in the
+following diagram.
+
+PCEPlib Threading model with external infra:
+
+.. image:: images/PCEPlib_threading_model_frr_infra.jpg
+
+
+Building
+--------
+
+The autotools build system is used and integrated with the frr build system.
+
+Testing
+-------
+
+The Unit Tests for an individual library are executed with the ``make check``
+command. The Unit Test binary will be written to the project ``build`` directory.
+All Unit Tests are executed with Valgrind, and any memory issues reported by
+Valgrind will cause the Unit Test to fail.
+
+
+PCEPlib PCC API
+===============
+
+The following sections describe the PCEPlib PCC API.
+
+
+PCEPlib PCC Initialization and Destruction
+------------------------------------------
+
+The PCEPlib can be initialized to handle memory, timers, and socket comm
+internally in what is called stand-alone mode, or with an external
+infrastructure, like FRR.
+
+PCEPlib PCC Initialization and Destruction in stand-alone mode
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+PCEPlib PCC initialization and destruction functions:
+
+- ``bool initialize_pcc();``
+- ``bool initialize_pcc_wait_for_completion();``
+- ``bool destroy_pcc();``
+
+The PCC can be initialized with either ``initialize_pcc()`` or
+``initialize_pcc_wait_for_completion()``.
+
+- ``initialize_pcc_wait_for_completion()`` blocks until ``destroy_pcc()``
+ is called from a separate pthread.
+- ``initialize_pcc()`` is non-blocking and will be stopped when
+ ``destroy_pcc()`` is called.
+
+Both initialize functions will launch 3 pthreads:
+
+- 1 Timer pthread
+- 1 SocketComm pthread
+- 1 SessionLogic pthread
+
+When ``destroy_pcc()`` is called, all pthreads will be stopped and all
+resources will be released.
+
+All 3 functions return true upon success, and false otherwise.
+
+PCEPlib PCC Initialization and Destruction with FRR infrastructure
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+PCEPlib PCC initialization and destruction functions:
+
+- ``bool initialize_pcc_infra(struct pceplib_infra_config *infra_config);``
+- ``bool destroy_pcc();``
+
+The ``pceplib_infra_config`` struct has the following fields:
+
+- **void *pceplib_infra_mt**
+ - FRR Memory type pointer for infra related memory management
+
+- **void *pceplib_messages_mt**
+ - FRR Memory type pointer for PCEP messages related memory management
+
+- **pceplib_malloc_func mfunc**
+ - FRR malloc function pointer
+
+- **pceplib_calloc_func cfunc**
+ - FRR calloc function pointer
+
+- **pceplib_realloc_func rfunc**
+ - FRR realloc function pointer
+
+- **pceplib_strdup_func sfunc**
+ - FRR strdup function pointer
+
+- **pceplib_free_func ffunc**
+ - FRR free function pointer
+
+- **void *external_infra_data**
+ - FRR data used by FRR timers and sockets infrastructure
+
+- **ext_timer_create timer_create_func**
+ - FRR timer create function pointer
+
+- **ext_timer_cancel timer_cancel_func**
+ - FRR timer cancel function pointer
+
+- **ext_socket_write socket_write_func**
+ - FRR socket write function pointer, indicating fd is ready to be written to
+
+- **ext_socket_read socket_read_func**
+ - FRR socket write function pointer, indicating fd is ready to be read from
+
+
+PCEPlib PCC configuration
+-------------------------
+
+PCEPlib PCC configuratoin functions:
+
+- ``pcep_configuration *create_default_pcep_configuration();``
+- ``void destroy_pcep_configuration(pcep_configuration *config);``
+
+A ``pcep_configuration`` object with default values is created with
+``create_default_pcep_configuration()``. These values can be tailored to
+specific use cases.
+
+Created ``pcep_configuration`` objects are destroyed with
+``destroy_pcep_configuration()``.
+
+
+PCEPlib PCC configuration paramaters
+++++++++++++++++++++++++++++++++++++
+
+The ``pcep_configuration`` object is defined in ``pcep_session_logic/include/pcep_session_logic.h``
+The attributes in the ``pcep_configuration`` object are detailed as follows.
+
+PCEP Connection parameters:
+
+- **dst_pcep_port**
+ - Defaults to 0, in which case the default PCEP TCP destination port
+ 4189 will be used.
+ - Set to use a specific PCEP TCP destination port.
+
+- **src_pcep_port**
+ - Defaults to 0, in which case the default PCEP TCP source port
+ 4189 will be used.
+ - Set to use a specific PCEP TCP source port.
+
+- **Source IP**
+ - Defaults to IPv4 INADDR_ANY
+ - Set **src_ip.src_ipv4** and **is_src_ipv6=false** to set the source IPv4.
+ - Set **src_ip.src_ipv6** and **is_src_ipv6=true** to set the source IPv6.
+
+- **socket_connect_timeout_millis**
+ - Maximum amount of time to wait to connect to the PCE TCP socket
+ before failing, in milliseconds.
+
+PCEP Versioning:
+
+- **pcep_msg_versioning->draft_ietf_pce_segment_routing_07**
+ - Defaults to false, in which case draft 16 versioning will be used.
+ - Set to true to use draft 07 versioning.
+
+PCEP Open Message Parameters:
+
+- **keep_alive_seconds**
+ - Sent to PCE in PCEP Open Msg
+ - Recommended value = 30, Minimum value = 1
+ - Disabled by setting value = 0
+
+- **dead_timer_seconds**
+ - Sent to PCE in PCEP Open Msg
+ - Recommended value = 4 * keepalive timer value
+
+- Supported value ranges for PCEP Open Message received from the PCE
+ - **min_keep_alive_seconds**, **max_keep_alive_seconds**
+ - **min_dead_timer_seconds**, **max_dead_timer_seconds**
+
+- **request_time_seconds**
+ - When a PCC sends a PcReq to a PCE, the amount of time a PCC will
+ wait for a PcRep reply from the PCE.
+
+- **max_unknown_requests**
+ - If a PCC/PCE receives PCRep/PCReq messages with unknown requests
+ at a rate equal or greater than MAX-UNKNOWN-REQUESTS per minute,
+ the PCC/PCE MUST send a PCEP CLOSE message.
+ - Recommended value = 5
+
+- **max_unknown_messages**
+ - If a PCC/PCE receives unrecognized messages at a rate equal or
+ greater than MAX-UNKNOWN-MESSAGES per minute, the PCC/PCE MUST
+ send a PCEP CLOSE message
+ - Recommended value = 5
+
+Stateful PCE Capability TLV configuration parameters (RFC 8231, 8232, 8281, and
+draft-ietf-pce-segment-routing-16):
+
+- **support_stateful_pce_lsp_update**
+ - If this flag is true, then a Stateful PCE Capability TLV will
+ be added to the PCEP Open object, with the LSP Update Capability
+ U-flag set true.
+ - The rest of these parameters are used to configure the Stateful
+ PCE Capability TLV
+
+- **support_pce_lsp_instantiation**
+ - Sets the I-flag true, indicating the PCC allows instantiation
+ of an LSP by a PCE.
+
+- **support_include_db_version**
+ - Sets the S-bit true, indicating the PCC will include the
+ LSP-DB-VERSION TLV in each LSP object. See lsp_db_version below.
+
+- **support_lsp_triggered_resync**
+ - Sets the T-bit true, indicating the PCE can trigger resynchronization
+ of LSPs at any point in the life of the session.
+
+- **support_lsp_delta_sync**
+ - Sets the D-bit true, indicating the PCEP speaker allows incremental
+ (delta) State Synchronization.
+
+- **support_pce_triggered_initial_sync**
+ - Sets the F-bit true, indicating the PCE SHOULD trigger initial (first)
+ State Synchronization
+
+LSP DB Version TLV configuration parameters:
+
+- **lsp_db_version**
+ - If this parameter has a value other than 0, and the above
+ support_include_db_version flag is true, then an LSP DB
+ Version TLV will be added to the PCEP Open object.
+ - This parameter should only be set if LSP-DB survived a restart
+ and is available.
+ - This value will be copied over to the pcep_session upon initialization.
+
+SR PCE Capability sub-TLV configuration parameters (draft-ietf-pce-segment-routing-16):
+
+- **support_sr_te_pst**
+ - If this flag is true, then an SR PCE Capability sub-TLV will be
+ added to a Path Setup type Capability TLV, which will be added
+ to the PCEP Open object.
+ - The PST used in the Path Setup type Capability will be 1,
+ indicating the Path is setup using Segment Routing Traffic Engineering.
+
+Only set the following fields if the **support_sr_te_pst** flag is true.
+
+- **pcc_can_resolve_nai_to_sid**
+ - Sets the N-flag true, indicating that the PCC is capable of resolving
+ a Node or Adjacency Identifier to a SID
+
+- **max_sid_depth**
+ - If set other than 0, then the PCC imposes a limit on the Maximum
+ SID depth.
+ - If this parameter is other than 0, then the X bit will be true,
+ and the parameter value will be set in the MSD field.
+
+
+PCEPlib PCC connections
+-----------------------
+
+PCEPlib PCC connect and disconnect functions:
+
+- ``pcep_session *connect_pce(pcep_configuration *config, struct in_addr *pce_ip);``
+- ``pcep_session *connect_pce_ipv6(pcep_configuration *config, struct in6_addr *pce_ip);``
+- ``void disconnect_pce(pcep_session *session);``
+
+When connecting to a PCE, a ``pcep_session`` will be returned on success, NULL
+otherwise.
+
+Refer to the above PCC configuration parameters section for setting the source
+and destination PCEP TCP ports, and the source IP address and version.
+
+
+PCEP Messages, Objects, and TLVs
+--------------------------------
+
+The PCEP messages, objects, and TLVs created in the PCEPlib are high-level API
+structures, meaning they need to be encoded before being sent on-the-wire, and
+the raw data received needs to be decoded into these structures. This makes
+using these objects much easier for the library consumer, since they do not
+need to know the detailed raw format of the PCEP entities.
+
+
+PCEP Messages
++++++++++++++
+
+Received messages (in the ``pcep_event`` explained below) are of type
+``pcep_message``, which have the following fields:
+
+- ``struct pcep_message_header *msg_header;``
+ - Defines the PCEP version and message type
+
+- ``double_linked_list *obj_list;``
+ - A double linked list of the message objects
+ - Each entry is a pointer to a ``struct pcep_object_header``, and
+ using the ``object_class`` and ``object_type`` fields, the pointer
+ can be cast to the appropriate object structure to access the
+ rest of the object fields
+
+- ``uint8_t *encoded_message;``
+ - This field is only populated for received messages or once the
+ ``pcep_encode_message()`` function has been called on the message.
+ - This field is a pointer to the raw PCEP data for the entire
+ message, including all objects and TLVs.
+
+- ``uint16_t encoded_message_length;``
+ - This field is only populated for received messages or once the
+ ``pcep_encode_message()`` function has been called on the message.
+ - This field is the length of the entire raw message, including
+ all objects and TLVs.
+ - This field is in host byte order.
+
+
+PCEP Objects
+++++++++++++
+
+A PCEP message has a double linked list of pointers to ``struct pcep_object_header``
+structures, which have the following fields:
+
+- ``enum pcep_object_classes object_class;``
+- ``enum pcep_object_types object_type;``
+- ``bool flag_p;``
+ - PCC Processing rule bit: When set, the object MUST be taken into
+ account, when cleared the object is optional
+
+- ``bool flag_i;``
+ - PCE Ignore bit: indicates to a PCC whether or not an optional
+ object was processed
+
+- ``double_linked_list *tlv_list;``
+ - A double linked list of the object TLVs
+ - Each entry is a pointer to a ``struct pcep_object_tlv_header``, and
+ using the TLV type field, the pointer can be cast to the
+ appropriate TLV structure to access the rest of the TLV fields
+
+- ``uint8_t *encoded_object;``
+ - This field is only populated for received objects or once the
+ ``pcep_encode_object()`` (called by ``pcep_encode_message()``)
+ function has been called on the object.
+ - Pointer into the encoded_message field (from the pcep_message)
+ where the raw object PCEP data starts.
+
+- ``uint16_t encoded_object_length;``
+ - This field is only populated for received objects or once the
+ ``pcep_encode_object()`` (called by ``pcep_encode_message()``)
+ function has been called on the object.
+ - This field is the length of the entire raw TLV
+ - This field is in host byte order.
+
+The object class and type can be used to cast the ``struct pcep_object_header``
+pointer to the appropriate object structure so the specific object fields can
+be accessed.
+
+
+PCEP TLVs
++++++++++
+
+A PCEP object has a double linked list of pointers to ``struct pcep_object_tlv_header``
+structures, which have the following fields:
+
+- ``enum pcep_object_tlv_types type;``
+- ``uint8_t *encoded_tlv;``
+ - This field is only populated for received TLVs or once the
+ ``pcep_encode_tlv()`` (called by ``pcep_encode_message()``)
+ function has been called on the TLV.
+ - Pointer into the encoded_message field (from the pcep_message)
+ where the raw TLV PCEP data starts.
+
+- ``uint16_t encoded_tlv_length;``
+ - This field is only populated for received TLVs or once the
+ ``pcep_encode_tlv()`` (called by ``pcep_encode_message()``)
+ function has been called on the TLV.
+ - This field is the length of the entire raw TLV
+ - This field is in host byte order.
+
+
+Memory management
++++++++++++++++++
+
+Any of the PCEPlib Message Library functions that receive a pointer to a
+``double_linked_list``, ``pcep_object_header``, or ``pcep_object_tlv_header``,
+transfer the ownership of the entity to the PCEPlib. The memory will be freed
+internally when the encapsulating structure is freed. If the memory for any of
+these is freed by the caller, then there will be a double memory free error
+when the memory is freed internally in the PCEPlib.
+
+Any of the PCEPlib Message Library functions that receive either a pointer to a
+``struct in_addr`` or ``struct in6_addr`` will allocate memory for the IP
+address internally and copy the IP address. It is the responsibility of the
+caller to manage the memory for the IP address passed into the PCEPlib Message
+Library functions.
+
+For messages received via the event queue (explained below), the message will
+be freed when the event is freed by calling ``destroy_pcep_event()``.
+
+When sending messages, the message will be freed internally in the PCEPlib when
+the ``send_message()`` ``pcep_pcc`` API function when the ``free_after_send`` flag
+is set true.
+
+To manually delete a message, call the ``pcep_msg_free_message()`` function.
+Internally, this will call ``pcep_obj_free_object()`` and ``pcep_obj_free_tlv()``
+appropriately.
+
+
+Sending a PCEP Report message
+-----------------------------
+
+This section shows how to send a PCEP Report messages from the PCC to the PCE,
+and serves as an example of how to send other messages. Refer to the sample
+PCC binary located in ``pcep_pcc/src/pcep_pcc.c`` for code examples os sending
+a PCEP Report message.
+
+The Report message must have at least an SRP, LSP, and ERO object.
+
+The PCEP Report message objects are created with the following APIs:
+
+- ``struct pcep_object_srp *pcep_obj_create_srp(...);``
+- ``struct pcep_object_lsp *pcep_obj_create_lsp(...);``
+- ``struct pcep_object_ro *pcep_obj_create_ero(...);``
+ - Create ero subobjects with the ``pcep_obj_create_ro_subobj_*(...);`` functions
+
+PCEP Report message is created with the following API:
+
+- ``struct pcep_header *pcep_msg_create_report(double_linked_list *report_object_list);``
+
+A PCEP report messages is sent with the following API:
+
+- ``void send_message(pcep_session *session, pcep_message *message, bool free_after_send);``
+
+
+PCEPlib Received event queue
+----------------------------
+
+PCEP events and messages of interest to the PCEPlib consumer will be stored
+internally in a message queue for retrieval.
+
+The following are the event types:
+
+- **MESSAGE_RECEIVED**
+- **PCE_CLOSED_SOCKET**
+- **PCE_SENT_PCEP_CLOSE**
+- **PCE_DEAD_TIMER_EXPIRED**
+- **PCE_OPEN_KEEP_WAIT_TIMER_EXPIRED**
+- **PCC_CONNECTED_TO_PCE**
+- **PCC_CONNECTION_FAILURE**
+- **PCC_PCEP_SESSION_CLOSED**
+- **PCC_RCVD_INVALID_OPEN**
+- **PCC_SENT_INVALID_OPEN**
+- **PCC_RCVD_MAX_INVALID_MSGS**
+- **PCC_RCVD_MAX_UNKOWN_MSGS**
+
+The following PCEP messages will not be posted on the message queue, as they
+are handled internally in the library:
+
+- **Open**
+- **Keep Alive**
+- **Close**
+
+Received event queue API:
+
+- ``bool event_queue_is_empty();``
+ - Returns true if the queue is empty, false otherwise
+
+- ``uint32_t event_queue_num_events_available();``
+ - Return the number of events on the queue, 0 if empty
+
+- ``struct pcep_event *event_queue_get_event();``
+ - Return the next event on the queue, NULL if empty
+ - The ``message`` pointer will only be non-NULL if ``event_type``
+ is ``MESSAGE_RECEIVED``
+
+- ``void destroy_pcep_event(struct pcep_event *event);``
+ - Free the PCEP Event resources, including the PCEP message if present
+
+
+PCEPlib Counters
+----------------
+
+The PCEPlib counters are managed in the ``pcep_session_logic`` library, and can
+be accessed in the ``pcep_session_counters`` field of the ``pcep_session`` structure.
+There are 2 API functions to manage the counters:
+
+- ``void dump_pcep_session_counters(pcep_session *session);``
+ - Dump all of the counters to the logs
+
+- ``void reset_pcep_session_counters(pcep_session *session);``
+
This function pushes a single value onto the Lua stack. It is a table whose equivalent in Lua is:
-.. code-block::
+.. code-block:: c
{ ["network"] = "1.2.3.4/24", ["prefixlen"] = 24, ["family"] = 2 }
doc/developer/tracing.rst \
doc/developer/testing.rst \
doc/developer/topotests-snippets.rst \
+ doc/developer/topotests-markers.rst \
doc/developer/topotests.rst \
doc/developer/workflow.rst \
doc/developer/xrefs.rst \
.. code:: shell
+ apt install libsnmp-dev
apt install snmpd snmp
apt install snmp-mibs-downloader
download-mibs
- Format the new code using `black <https://github.com/psf/black>`_
- Create a Pull Request
-.. Note::
+Some things to keep in mind:
+
+- BGP tests MUST use generous convergence timeouts - you must ensure
+ that any test involving BGP uses a convergence timeout of at least
+ 130 seconds.
+- Topotests are run on a range of Linux versions: if your test
+ requires some OS-specific capability (like mpls support, or vrf
+ support), there are test functions available in the libraries that
+ will help you determine whether your test should run or be skipped.
+- Avoid including unstable data in your test: don't rely on link-local
+ addresses or ifindex values, for example, because these can change
+ from run to run.
- BGP tests MUST use generous convergence timeouts - you must ensure
- that any test involving BGP uses a convergence timeout of at least
- 130 seconds.
Topotest File Hierarchy
"""""""""""""""""""""""
- Use `black <https://github.com/psf/black>`_ code formatter before creating
a pull request. This ensures we have a unified code style.
- Mark test modules with pytest markers depending on the daemons used during the
- tests (s. Markers)
+ tests (see :ref:`topotests-markers`)
Tips:
The minimum transmission interval (less jitter) that this system
wants to use to send BFD control packets. Defaults to 300ms.
-.. clicmd:: echo-interval (10-60000)
+.. clicmd:: echo receive-interval <disabled|(10-60000)>
- Configures the minimal echo receive transmission interval that this
- system is capable of handling.
+ Configures the minimum interval that this system is capable of
+ receiving echo packets. Disabled means that this system doesn't want
+ to receive echo packets. The default value is 50 milliseconds.
+
+.. clicmd:: echo transmit-interval (10-60000)
+
+ The minimum transmission interval (less jitter) that this system
+ wants to use to send BFD echo packets. Defaults to 50ms.
.. clicmd:: echo-mode
Enables or disables the echo transmission mode. This mode is disabled
- by default.
+ by default. If you are not using distributed BFD then echo mode works
+ only when the peer is also FRR.
It is recommended that the transmission interval of control packets
to be increased after enabling echo-mode to reduce bandwidth usage.
a new neighbor is found a BFD peer is created to monitor the link
status for fast convergence.
+.. clicmd:: ip ospf bfd profile BFDPROF
+
+ Same as command ``ip ospf bfd``, but applies the BFD profile to the sessions
+ it creates or that already exist.
+
.. _bfd-ospf6-peer-config:
Detect-multiplier: 3
Receive interval: 300ms
Transmission interval: 300ms
+ Echo receive interval: 50ms
Echo transmission interval: disabled
Remote timers:
Detect-multiplier: 3
Receive interval: 300ms
Transmission interval: 300ms
- Echo transmission interval: 50ms
+ Echo receive interval: 50ms
peer 192.168.1.1
label: router3-peer
Detect-multiplier: 3
Receive interval: 300ms
Transmission interval: 300ms
+ Echo receive interval: 50ms
Echo transmission interval: disabled
Remote timers:
Detect-multiplier: 3
Receive interval: 300ms
Transmission interval: 300ms
- Echo transmission interval: 50ms
+ Echo receive interval: 50ms
frr# show bfd peer 192.168.1.1
BFD Peer:
Detect-multiplier: 3
Receive interval: 300ms
Transmission interval: 300ms
+ Echo receive interval: 50ms
Echo transmission interval: disabled
Remote timers:
Detect-multiplier: 3
Receive interval: 300ms
Transmission interval: 300ms
- Echo transmission interval: 50ms
+ Echo receive interval: 50ms
frr# show bfd peer 192.168.0.1 json
- {"multihop":false,"peer":"192.168.0.1","id":1,"remote-id":1,"status":"up","uptime":161,"diagnostic":"ok","remote-diagnostic":"ok","receive-interval":300,"transmit-interval":300,"echo-interval":50,"detect-multiplier":3,"remote-receive-interval":300,"remote-transmit-interval":300,"remote-echo-interval":50,"remote-detect-multiplier":3,"peer-type":"dynamic"}
+ {"multihop":false,"peer":"192.168.0.1","id":1,"remote-id":1,"status":"up","uptime":161,"diagnostic":"ok","remote-diagnostic":"ok","receive-interval":300,"transmit-interval":300,"echo-receive-interval":50,"echo-transmit-interval":0,"detect-multiplier":3,"remote-receive-interval":300,"remote-transmit-interval":300,"remote-echo-receive-interval":50,"remote-detect-multiplier":3,"peer-type":"dynamic"}
You can inspect the current BFD peer status in brief with the following commands:
be used in a setup with two upstreams where each of the upstreams should only
receive either IPv4 or IPv6 annocuments.
+ Using the ``bgp default ipv6-unicast`` configuration, IPv6 unicast
+ address family is enabled by default for all new neighbors.
+
.. _bgp-route-aggregation:
on by default or not. This command defaults to on and is not displayed.
The `no bgp default ipv4-unicast` form of the command is displayed.
+.. clicmd:: bgp default ipv6-unicast
+
+ This command allows the user to specify that v6 peering is turned
+ on by default or not. This command defaults to off and is not displayed.
+ The `bgp default ipv6-unicast` form of the command is displayed.
+
.. clicmd:: bgp default show-hostname
This command shows the hostname of the peer in certain BGP commands
should not be reflected back to the peer. This command only is only
meaningful when there is a single peer defined in the peer-group.
+.. clicmd:: show [ip] bgp peer-group [json]
+
+ This command displays configured BGP peer-groups.
+
+ .. code-block:: frr
+
+ exit1-debian-9# show bgp peer-group
+
+ BGP peer-group test1, remote AS 65001
+ Peer-group type is external
+ Configured address-families: IPv4 Unicast; IPv6 Unicast;
+ 1 IPv4 listen range(s)
+ 192.168.100.0/24
+ 2 IPv6 listen range(s)
+ 2001:db8:1::/64
+ 2001:db8:2::/64
+ Peer-group members:
+ 192.168.200.1 Active
+ 2001:db8::1 Active
+
+ BGP peer-group test2
+ Peer-group type is external
+ Configured address-families: IPv4 Unicast;
+
+ Optional ``json`` parameter is used to display JSON output.
+
+ .. code-block:: frr
+
+ {
+ "test1":{
+ "remoteAs":65001,
+ "type":"external",
+ "addressFamiliesConfigured":[
+ "IPv4 Unicast",
+ "IPv6 Unicast"
+ ],
+ "dynamicRanges":{
+ "IPv4":{
+ "count":1,
+ "ranges":[
+ "192.168.100.0\/24"
+ ]
+ },
+ "IPv6":{
+ "count":2,
+ "ranges":[
+ "2001:db8:1::\/64",
+ "2001:db8:2::\/64"
+ ]
+ }
+ },
+ "members":{
+ "192.168.200.1":{
+ "status":"Active"
+ },
+ "2001:db8::1":{
+ "status":"Active"
+ }
+ }
+ },
+ "test2":{
+ "type":"external",
+ "addressFamiliesConfigured":[
+ "IPv4 Unicast"
+ ]
+ }
+ }
+
Capability Negotiation
^^^^^^^^^^^^^^^^^^^^^^
AS path access list is user defined AS path.
-.. clicmd:: bgp as-path access-list WORD permit|deny LINE
+.. clicmd:: bgp as-path access-list WORD [seq (0-4294967295)] permit|deny LINE
This command defines a new AS path access list.
bgp as-path access-list 99 permit _0_
bgp as-path access-list 99 permit _23456_
bgp as-path access-list 99 permit _1310[0-6][0-9]_|_13107[0-1]_
+ bgp as-path access-list 99 seq 20 permit ^65
.. _bgp-using-as-path-in-route-map:
Display Listen sockets and the vrf that created them. Useful for debugging of when
listen is not working and this is considered a developer debug statement.
+.. clicmd:: debug bgp bfd
+
+ Enable or disable debugging for BFD events. This will show BFD integration
+ library messages and BGP BFD integration messages that are mostly state
+ transitions and validation problems.
+
.. clicmd:: debug bgp neighbor-events
Enable or disable debugging for neighbor events. This provides general
ip prefix-list pl-peer2-network permit 192.168.2.0/24
ip prefix-list pl-peer2-network permit 172.16.1/24
!
- bgp as-path access-list asp-own-as permit ^$
- bgp as-path access-list asp-own-as permit _64512_
+ bgp as-path access-list seq 5 asp-own-as permit ^$
+ bgp as-path access-list seq 10 asp-own-as permit _64512_
!
! #################################################################
! Match communities we provide actions for, on routes receives from
Interface name can also be given. JSON output can be obtained by appending
'json' to the end of command.
-.. index:: show ipv6 ospf6 spf tree [json]
.. clicmd:: show ipv6 ospf6 spf tree [json]
This commands shows the spf tree from the recent spf calculation with the
tree in JSON format. Each area that the router belongs to has it's own
JSON object, with each router having "cost", "isLeafNode" and "children" as
arguments.
-
+
OSPF6 Configuration Examples
============================
Json o/p of this command covers base route information
i.e all LSAs except opaque lsa info.
-.. clicmd:: show ip ospf database [json]
+.. clicmd:: show ip ospf [vrf <NAME|all>] database [json]
-.. clicmd:: show ip ospf database (asbr-summary|external|network|router|summary) [json]
+.. clicmd:: show ip ospf [vrf <NAME|all>] database (asbr-summary|external|network|router|summary) [json]
-.. clicmd:: show ip ospf database (asbr-summary|external|network|router|summary) LINK-STATE-ID [json]
+.. clicmd:: show ip ospf [vrf <NAME|all>] database (asbr-summary|external|network|router|summary) LINK-STATE-ID [json]
-.. clicmd:: show ip ospf database (asbr-summary|external|network|router|summary) LINK-STATE-ID adv-router ADV-ROUTER [json]
+.. clicmd:: show ip ospf [vrf <NAME|all>] database (asbr-summary|external|network|router|summary) LINK-STATE-ID adv-router ADV-ROUTER [json]
-.. clicmd:: show ip ospf database (asbr-summary|external|network|router|summary) adv-router ADV-ROUTER [json]
+.. clicmd:: show ip ospf [vrf <NAME|all>] database (asbr-summary|external|network|router|summary) adv-router ADV-ROUTER [json]
-.. clicmd:: show ip ospf database (asbr-summary|external|network|router|summary) LINK-STATE-ID self-originate [json]
+.. clicmd:: show ip ospf [vrf <NAME|all>] database (asbr-summary|external|network|router|summary) LINK-STATE-ID self-originate [json]
-.. clicmd:: show ip ospf database (asbr-summary|external|network|router|summary) self-originate [json]
+.. clicmd:: show ip ospf [vrf <NAME|all>] database (asbr-summary|external|network|router|summary) self-originate [json]
-.. clicmd:: show ip ospf database max-age [json]
+.. clicmd:: show ip ospf [vrf <NAME|all>] database max-age [json]
-.. clicmd:: show ip ospf database self-originate [json]
+.. clicmd:: show ip ospf [vrf <NAME|all>] database self-originate [json]
+
+ Show the OSPF database summary.
.. clicmd:: show ip ospf route [json]
extensions that are used with MPLS-TE; it does not support a
complete RSVP-TE solution.
-.. clicmd:: show ip ospf database (opaque-link|opaque-area|opaque-external)
+.. clicmd:: show ip ospf [vrf <NAME|all>] database (opaque-link|opaque-area|opaque-external)
-.. clicmd:: show ip ospf database (opaque-link|opaque-area|opaque-external) LINK-STATE-ID
+.. clicmd:: show ip ospf [vrf <NAME|all>] database (opaque-link|opaque-area|opaque-external) LINK-STATE-ID
-.. clicmd:: show ip ospf database (opaque-link|opaque-area|opaque-external) LINK-STATE-ID adv-router ADV-ROUTER
+.. clicmd:: show ip ospf [vrf <NAME|all>] database (opaque-link|opaque-area|opaque-external) LINK-STATE-ID adv-router ADV-ROUTER
-.. clicmd:: show ip ospf database (opaque-link|opaque-area|opaque-external) adv-router ADV-ROUTER
+.. clicmd:: show ip ospf [vrf <NAME|all>] database (opaque-link|opaque-area|opaque-external) adv-router ADV-ROUTER
-.. clicmd:: show ip ospf database (opaque-link|opaque-area|opaque-external) LINK-STATE-ID self-originate
+.. clicmd:: show ip ospf [vrf <NAME|all>] database (opaque-link|opaque-area|opaque-external) LINK-STATE-ID self-originate
-.. clicmd:: show ip ospf database (opaque-link|opaque-area|opaque-external) self-originate
+.. clicmd:: show ip ospf [vrf <NAME|all>] database (opaque-link|opaque-area|opaque-external) self-originate
Show Opaque LSA from the database.
Debugging OSPF
==============
+.. clicmd:: debug ospf bfd
+
+ Enable or disable debugging for BFD events. This will show BFD integration
+ library messages and OSPF BFD integration messages that are mostly state
+ transitions and validation problems.
+
.. clicmd:: debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) [detail]
as_str);
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
- snprintf(xpath_auth, sizeof(xpath_auth), "%s/summarize-address", xpath);
+ snprintf(xpath_auth, sizeof(xpath_auth), "%s/summarize-addresses", xpath);
nb_cli_enqueue_change(vty, xpath_auth, NB_OP_CREATE, prefix_str);
return nb_cli_apply_changes(vty, NULL);
as_str);
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
- snprintf(xpath_auth, sizeof(xpath_auth), "%s/summarize-address", xpath);
+ snprintf(xpath_auth, sizeof(xpath_auth), "%s/summarize-addresses", xpath);
nb_cli_enqueue_change(vty, xpath_auth, NB_OP_DESTROY, prefix_str);
return nb_cli_apply_changes(vty, NULL);
void eigrp_cli_show_summarize_address(struct vty *vty, struct lyd_node *dnode,
bool show_defaults)
{
- const struct eigrp_interface *eif = nb_running_get_entry(dnode, NULL,
- true);
+ const struct lyd_node *instance = yang_dnode_get_parent(dnode, "instance");
+ uint16_t asn = yang_dnode_get_uint16(instance, "./asn");
const char *summarize_address = yang_dnode_get_string(dnode, NULL);
- vty_out(vty, " ip summary-address eigrp %d %s\n",
- eif->eigrp->AS, summarize_address);
+ vty_out(vty, " ip summary-address eigrp %d %s\n", asn,
+ summarize_address);
}
/*
void eigrp_cli_show_authentication(struct vty *vty, struct lyd_node *dnode,
bool show_defaults)
{
- const struct eigrp_interface *eif = nb_running_get_entry(dnode, NULL,
- true);
+ const struct lyd_node *instance = yang_dnode_get_parent(dnode, "instance");
+ uint16_t asn = yang_dnode_get_uint16(instance, "./asn");
const char *crypt = yang_dnode_get_string(dnode, NULL);
- vty_out(vty, " ip authentication mode eigrp %d %s\n",
- eif->eigrp->AS, crypt);
+ vty_out(vty, " ip authentication mode eigrp %d %s\n", asn, crypt);
}
/*
void eigrp_cli_show_keychain(struct vty *vty, struct lyd_node *dnode,
bool show_defaults)
{
- const struct eigrp_interface *eif = nb_running_get_entry(dnode, NULL,
- true);
+ const struct lyd_node *instance = yang_dnode_get_parent(dnode, "instance");
+ uint16_t asn = yang_dnode_get_uint16(instance, "./asn");
const char *keychain = yang_dnode_get_string(dnode, NULL);
- vty_out(vty, " ip authentication key-chain eigrp %d %s\n",
- eif->eigrp->AS, keychain);
+ vty_out(vty, " ip authentication key-chain eigrp %d %s\n", asn,
+ keychain);
}
#include "eigrpd/eigrp_const.h"
#include "eigrpd/eigrp_filter.h"
#include "eigrpd/eigrp_packet.h"
-#include "eigrpd/eigrp_memory.h"
/*
* Distribute-list update functions.
#include "eigrpd/eigrp_vty.h"
#include "eigrpd/eigrp_network.h"
#include "eigrpd/eigrp_topology.h"
-#include "eigrpd/eigrp_memory.h"
#include "eigrpd/eigrp_fsm.h"
#include "eigrpd/eigrp_dump.h"
#include "eigrpd/eigrp_types.h"
#include "eigrpd/eigrp_metric.h"
+DEFINE_MTYPE_STATIC(EIGRPD, EIGRP_IF, "EIGRP interface");
+DEFINE_MTYPE_STATIC(EIGRPD, EIGRP_IF_INFO, "EIGRP Interface Information");
+
struct eigrp_interface *eigrp_if_new(struct eigrp *eigrp, struct interface *ifp,
struct prefix *p)
{
.n_signals = array_size(eigrp_signals),
.privs = &eigrpd_privs, .yang_modules = eigrpd_yang_modules,
- .n_yang_modules = array_size(eigrpd_yang_modules), )
+ .n_yang_modules = array_size(eigrpd_yang_modules),
+);
/* EIGRPd main routine. */
int main(int argc, char **argv, char **envp)
+++ /dev/null
-/* eigrpd memory type definitions
- *
- * Copyright (C) 2017 Donald Sharp
- *
- * This file is part of FRR
- *
- * FRR is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * FRR is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "eigrp_memory.h"
-
-DEFINE_MGROUP(EIGRPD, "eigrpd")
-DEFINE_MTYPE(EIGRPD, EIGRP_TOP, "EIGRP structure")
-DEFINE_MTYPE(EIGRPD, EIGRP_IF, "EIGRP interface")
-DEFINE_MTYPE(EIGRPD, EIGRP_NEIGHBOR, "EIGRP neighbor")
-DEFINE_MTYPE(EIGRPD, EIGRP_IF_PARAMS, "EIGRP Interface Parameters")
-DEFINE_MTYPE(EIGRPD, EIGRP_IF_INFO, "EIGRP Interface Information")
-DEFINE_MTYPE(EIGRPD, EIGRP_FIFO, "EIGRP FIFO")
-DEFINE_MTYPE(EIGRPD, EIGRP_PACKET, "EIGRP Packet")
-DEFINE_MTYPE(EIGRPD, EIGRP_IPV4_INT_TLV, "EIGRP IPv4 TLV")
-DEFINE_MTYPE(EIGRPD, EIGRP_SEQ_TLV, "EIGRP SEQ TLV")
-DEFINE_MTYPE(EIGRPD, EIGRP_AUTH_TLV, "EIGRP AUTH TLV")
-DEFINE_MTYPE(EIGRPD, EIGRP_AUTH_SHA256_TLV, "EIGRP SHA TLV")
-DEFINE_MTYPE(EIGRPD, EIGRP_PREFIX_DESCRIPTOR, "EIGRP Prefix")
-DEFINE_MTYPE(EIGRPD, EIGRP_ROUTE_DESCRIPTOR, "EIGRP Nexthop Entry")
-DEFINE_MTYPE(EIGRPD, EIGRP_FSM_MSG, "EIGRP FSM Message")
+++ /dev/null
-/* eigrpd memory type declarations
- *
- * Copyright (C) 2017 Donald Sharp
- *
- * This file is part of FRR.
- *
- * FRR is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * FRR is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef _FRR_EIGRP_MEMORY_H
-#define _FRR_EIGRP_MEMORY_H
-
-#include "memory.h"
-
-DECLARE_MGROUP(EIGRPD)
-DECLARE_MTYPE(EIGRP_TOP)
-DECLARE_MTYPE(EIGRP_IF)
-DECLARE_MTYPE(EIGRP_NEIGHBOR)
-DECLARE_MTYPE(EIGRP_IF_PARAMS)
-DECLARE_MTYPE(EIGRP_IF_INFO)
-DECLARE_MTYPE(EIGRP_FIFO)
-DECLARE_MTYPE(EIGRP_PACKET)
-DECLARE_MTYPE(EIGRP_IPV4_INT_TLV)
-DECLARE_MTYPE(EIGRP_SEQ_TLV)
-DECLARE_MTYPE(EIGRP_AUTH_TLV)
-DECLARE_MTYPE(EIGRP_AUTH_SHA256_TLV)
-DECLARE_MTYPE(EIGRP_PREFIX_DESCRIPTOR)
-DECLARE_MTYPE(EIGRP_ROUTE_DESCRIPTOR)
-DECLARE_MTYPE(EIGRP_FSM_MSG)
-
-#endif /* _FRR_EIGRP_MEMORY_H */
#include "eigrpd/eigrp_vty.h"
#include "eigrpd/eigrp_network.h"
#include "eigrpd/eigrp_topology.h"
-#include "eigrpd/eigrp_memory.h"
#include "eigrpd/eigrp_errors.h"
+DEFINE_MTYPE_STATIC(EIGRPD, EIGRP_NEIGHBOR, "EIGRP neighbor");
+
struct eigrp_neighbor *eigrp_nbr_new(struct eigrp_interface *ei)
{
struct eigrp_neighbor *nbr;
#include "eigrpd/eigrp_network.h"
#include "eigrpd/eigrp_topology.h"
#include "eigrpd/eigrp_fsm.h"
-#include "eigrpd/eigrp_memory.h"
#include "eigrpd/eigrp_errors.h"
+DEFINE_MTYPE_STATIC(EIGRPD, EIGRP_FIFO, "EIGRP FIFO");
+DEFINE_MTYPE_STATIC(EIGRPD, EIGRP_PACKET, "EIGRP Packet");
+DEFINE_MTYPE_STATIC(EIGRPD, EIGRP_IPV4_INT_TLV, "EIGRP IPv4 TLV");
+DEFINE_MTYPE_STATIC(EIGRPD, EIGRP_SEQ_TLV, "EIGRP SEQ TLV");
+DEFINE_MTYPE_STATIC(EIGRPD, EIGRP_AUTH_TLV, "EIGRP AUTH TLV");
+DEFINE_MTYPE_STATIC(EIGRPD, EIGRP_AUTH_SHA256_TLV, "EIGRP SHA TLV");
+
/* Packet Type String. */
const struct message eigrp_packet_type_str[] = {
{EIGRP_OPC_UPDATE, "Update"},
#include "eigrpd/eigrp_macros.h"
#include "eigrpd/eigrp_topology.h"
#include "eigrpd/eigrp_fsm.h"
-#include "eigrpd/eigrp_memory.h"
uint32_t eigrp_query_send_all(struct eigrp *eigrp)
{
#include "eigrpd/eigrp_macros.h"
#include "eigrpd/eigrp_topology.h"
#include "eigrpd/eigrp_fsm.h"
-#include "eigrpd/eigrp_memory.h"
#include "eigrpd/eigrp_errors.h"
void eigrp_send_reply(struct eigrp_neighbor *nbr,
#include "eigrpd/eigrp_macros.h"
#include "eigrpd/eigrp_topology.h"
#include "eigrpd/eigrp_fsm.h"
-#include "eigrpd/eigrp_memory.h"
/*EIGRP SIA-QUERY read function*/
void eigrp_siaquery_receive(struct eigrp *eigrp, struct ip *iph,
#include "eigrpd/eigrp_macros.h"
#include "eigrpd/eigrp_topology.h"
#include "eigrpd/eigrp_fsm.h"
-#include "eigrpd/eigrp_memory.h"
/*EIGRP SIA-REPLY read function*/
void eigrp_siareply_receive(struct eigrp *eigrp, struct ip *iph,
/* distribute_ctx */
struct distribute_ctx *distribute_ctx;
- QOBJ_FIELDS
+ QOBJ_FIELDS;
};
-DECLARE_QOBJ_TYPE(eigrp)
+DECLARE_QOBJ_TYPE(eigrp);
struct eigrp_if_params {
uint8_t passive_interface;
#include "eigrpd/eigrp_dump.h"
#include "eigrpd/eigrp_topology.h"
#include "eigrpd/eigrp_fsm.h"
-#include "eigrpd/eigrp_memory.h"
#include "eigrpd/eigrp_metric.h"
+DEFINE_MTYPE_STATIC(EIGRPD, EIGRP_ROUTE_DESCRIPTOR, "EIGRP Nexthop Entry");
+DEFINE_MTYPE(EIGRPD, EIGRP_PREFIX_DESCRIPTOR, "EIGRP Prefix");
+
static int eigrp_route_descriptor_cmp(struct eigrp_route_descriptor *rd1,
struct eigrp_route_descriptor *rd2);
#ifndef _ZEBRA_EIGRP_TOPOLOGY_H
#define _ZEBRA_EIGRP_TOPOLOGY_H
+#include "memory.h"
+
+DECLARE_MTYPE(EIGRP_PREFIX_DESCRIPTOR);
+
/* EIGRP Topology table related functions. */
extern struct route_table *eigrp_topology_new(void);
extern void eigrp_topology_init(struct route_table *table);
#include "eigrpd/eigrp_topology.h"
#include "eigrpd/eigrp_fsm.h"
#include "eigrpd/eigrp_network.h"
-#include "eigrpd/eigrp_memory.h"
#include "eigrpd/eigrp_metric.h"
bool eigrp_update_prefix_apply(struct eigrp *eigrp, struct eigrp_interface *ei,
#include "eigrpd/eigrp_packet.h"
#include "eigrpd/eigrp_network.h"
#include "eigrpd/eigrp_topology.h"
-#include "eigrpd/eigrp_memory.h"
#include "eigrpd/eigrp_filter.h"
-DEFINE_QOBJ_TYPE(eigrp)
+DEFINE_MGROUP(EIGRPD, "eigrpd");
+
+DEFINE_MTYPE_STATIC(EIGRPD, EIGRP_TOP, "EIGRP structure");
+
+DEFINE_QOBJ_TYPE(eigrp);
static struct eigrp_master eigrp_master;
#include "filter.h"
#include "log.h"
+#include "memory.h"
+
+DECLARE_MGROUP(EIGRPD);
/* Set EIGRP version is "classic" - wide metrics comes next */
#define EIGRP_MAJOR_VERSION 1
eigrpd/eigrp_fsm.c \
eigrpd/eigrp_hello.c \
eigrpd/eigrp_interface.c \
- eigrpd/eigrp_memory.c \
eigrpd/eigrp_metric.c \
eigrpd/eigrp_neighbor.c \
eigrpd/eigrp_network.c \
eigrpd/eigrp_fsm.h \
eigrpd/eigrp_interface.h \
eigrpd/eigrp_macros.h \
- eigrpd/eigrp_memory.h \
eigrpd/eigrp_metric.h \
eigrpd/eigrp_neighbor.h \
eigrpd/eigrp_network.h \
#include <zebra.h>
#include "isisd/fabricd.h"
#include "isisd/isisd.h"
-#include "isisd/isis_memory.h"
#include "isisd/isis_circuit.h"
#include "isisd/isis_misc.h"
#include "isisd/isis_adjacency.h"
#include "isisd/isis_tx_queue.h"
#include "isisd/isis_csm.h"
-DEFINE_MTYPE_STATIC(ISISD, FABRICD_STATE, "ISIS OpenFabric")
-DEFINE_MTYPE_STATIC(ISISD, FABRICD_NEIGHBOR, "ISIS OpenFabric Neighbor Entry")
-DEFINE_MTYPE_STATIC(ISISD, FABRICD_FLOODING_INFO, "ISIS OpenFabric Flooding Log")
+DEFINE_MTYPE_STATIC(ISISD, FABRICD_STATE, "ISIS OpenFabric");
+DEFINE_MTYPE_STATIC(ISISD, FABRICD_NEIGHBOR, "ISIS OpenFabric Neighbor Entry");
+DEFINE_MTYPE_STATIC(ISISD, FABRICD_FLOODING_INFO, "ISIS OpenFabric Flooding Log");
/* Tracks initial synchronization as per section 2.4
*
#include "isisd/fabricd.h"
#include "isisd/isis_nb.h"
+DEFINE_MTYPE_STATIC(ISISD, ISIS_ADJACENCY, "ISIS adjacency");
+DEFINE_MTYPE(ISISD, ISIS_ADJACENCY_INFO, "ISIS adjacency info");
+
static struct isis_adjacency *adj_alloc(struct isis_circuit *circuit,
const uint8_t *id)
{
return NULL;
}
-DEFINE_HOOK(isis_adj_state_change_hook, (struct isis_adjacency *adj), (adj))
+DEFINE_HOOK(isis_adj_state_change_hook, (struct isis_adjacency *adj), (adj));
void isis_delete_adj(void *arg)
{
adj->threeway_state = next_tw_state;
}
-void isis_log_adj_change(struct isis_adjacency *adj,
- enum isis_adj_state old_state,
- enum isis_adj_state new_state, const char *reason)
+const char *isis_adj_name(const struct isis_adjacency *adj)
{
- const char *adj_name;
+ if (!adj)
+ return "NONE";
+
struct isis_dynhn *dyn;
dyn = dynhn_find_by_id(adj->sysid);
if (dyn)
- adj_name = dyn->hostname;
+ return dyn->hostname;
else
- adj_name = sysid_print(adj->sysid);
-
+ return sysid_print(adj->sysid);
+}
+void isis_log_adj_change(struct isis_adjacency *adj,
+ enum isis_adj_state old_state,
+ enum isis_adj_state new_state, const char *reason)
+{
zlog_info(
"%%ADJCHANGE: Adjacency to %s (%s) for %s changed from %s to %s, %s",
- adj_name, adj->circuit->interface->name,
+ isis_adj_name(adj), adj->circuit->interface->name,
adj_level2string(adj->level), adj_state2string(old_state),
adj_state2string(new_state), reason ? reason : "unspecified");
}
struct isis_dynhn *dyn;
int level;
- dyn = dynhn_find_by_id(adj->sysid);
- if (dyn)
- vty_out(vty, " %-20s", dyn->hostname);
- else
- vty_out(vty, " %-20s", sysid_print(adj->sysid));
+ vty_out(vty, " %-20s", isis_adj_name(adj));
if (detail == ISIS_UI_LEVEL_BRIEF) {
if (adj->circuit)
#include "isisd/isis_tlvs.h"
+DECLARE_MTYPE(ISIS_ADJACENCY_INFO);
+
enum isis_adj_usage {
ISIS_ADJ_NONE,
ISIS_ADJ_LEVEL1,
void isis_adj_process_threeway(struct isis_adjacency *adj,
struct isis_threeway_adj *tw_adj,
enum isis_adj_usage adj_usage);
-DECLARE_HOOK(isis_adj_state_change_hook, (struct isis_adjacency *adj), (adj))
+DECLARE_HOOK(isis_adj_state_change_hook, (struct isis_adjacency *adj), (adj));
DECLARE_HOOK(isis_adj_ip_enabled_hook,
- (struct isis_adjacency *adj, int family), (adj, family))
+ (struct isis_adjacency *adj, int family), (adj, family));
DECLARE_HOOK(isis_adj_ip_disabled_hook,
- (struct isis_adjacency *adj, int family), (adj, family))
+ (struct isis_adjacency *adj, int family), (adj, family));
void isis_log_adj_change(struct isis_adjacency *adj,
enum isis_adj_state old_state,
enum isis_adj_state new_state, const char *reason);
void isis_adj_build_up_list(struct list *adjdb, struct list *list);
int isis_adj_usage2levels(enum isis_adj_usage usage);
int isis_bfd_startup_timer(struct thread *thread);
+const char *isis_adj_name(const struct isis_adjacency *adj);
#endif /* ISIS_ADJACENCY_H */
#include "isisd/isisd.h"
#include "isisd/fabricd.h"
-DEFINE_MTYPE_STATIC(ISISD, BFD_SESSION, "ISIS BFD Session")
+DEFINE_MTYPE_STATIC(ISISD, BFD_SESSION, "ISIS BFD Session");
struct bfd_session {
int family;
static void bfd_adj_event(struct isis_adjacency *adj, struct prefix *dst,
int new_status)
{
- if (!adj->bfd_session)
+ if (!adj->bfd_session) {
+ if (IS_DEBUG_BFD)
+ zlog_debug(
+ "ISIS-BFD: Ignoring update for adjacency with %s, could not find bfd session on the adjacency",
+ isis_adj_name(adj));
return;
+ }
- if (adj->bfd_session->family != dst->family)
+ if (adj->bfd_session->family != dst->family) {
+ if (IS_DEBUG_BFD)
+ zlog_debug(
+ "ISIS-BFD: Ignoring update for adjacency with %s, address family does not match the family on the adjacency",
+ isis_adj_name(adj));
return;
+ }
switch (adj->bfd_session->family) {
case AF_INET:
if (!IPV4_ADDR_SAME(&adj->bfd_session->dst_ip.ipv4,
- &dst->u.prefix4))
+ &dst->u.prefix4)) {
+ if (IS_DEBUG_BFD)
+ zlog_debug(
+ "ISIS-BFD: Ignoring update for adjacency with %s, IPv4 address does not match",
+ isis_adj_name(adj));
return;
+ }
break;
case AF_INET6:
if (!IPV6_ADDR_SAME(&adj->bfd_session->dst_ip.ipv6,
- &dst->u.prefix6))
+ &dst->u.prefix6)) {
+ if (IS_DEBUG_BFD)
+ zlog_debug(
+ "ISIS-BFD: Ignoring update for adjacency with %s, IPv6 address does not match",
+ isis_adj_name(adj));
return;
+ }
break;
default:
flog_err(EC_LIB_DEVELOPMENT, "%s: unknown address-family: %u",
BFD_SET_CLIENT_STATUS(adj->bfd_session->status, new_status);
- if (old_status == new_status)
+ if (old_status == new_status) {
+ if (IS_DEBUG_BFD)
+ zlog_debug(
+ "ISIS-BFD: Ignoring update for adjacency with %s, new status matches current known status",
+ isis_adj_name(adj));
return;
+ }
if (IS_DEBUG_BFD) {
char dst_str[INET6_ADDRSTRLEN];
struct isis_circuit *circuit = circuit_scan_by_ifp(ifp);
- if (!circuit)
+ if (!circuit) {
+ if (IS_DEBUG_BFD)
+ zlog_debug(
+ "ISIS-BFD: Ignoring update, could not find circuit");
return 0;
+ }
if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
struct list *local_ips;
struct prefix *local_ip;
- if (!circuit->bfd_info)
+ if (!circuit->bfd_info) {
+ if (IS_DEBUG_BFD)
+ zlog_debug(
+ "ISIS-BFD: skipping BFD initialization on adjacency with %s because there is no bfd_info in the circuit",
+ isis_adj_name(adj));
goto out;
+ }
/* If IS-IS IPv6 is configured wait for IPv6 address to be programmed
* before starting up BFD
*/
- if ((circuit->ipv6_router && listcount(circuit->ipv6_link) == 0)
- || adj->ipv6_address_count == 0)
+ if (circuit->ipv6_router
+ && (listcount(circuit->ipv6_link) == 0
+ || adj->ipv6_address_count == 0)) {
+ if (IS_DEBUG_BFD)
+ zlog_debug(
+ "ISIS-BFD: skipping BFD initialization on adjacency with %s because IPv6 is enabled but not ready",
+ isis_adj_name(adj));
return;
+ }
/*
* If IS-IS is enabled for both IPv4 and IPv6 on the circuit, prefer
family = AF_INET6;
dst_ip.ipv6 = adj->ipv6_addresses[0];
local_ips = circuit->ipv6_link;
- if (!local_ips || list_isempty(local_ips))
+ if (!local_ips || list_isempty(local_ips)) {
+ if (IS_DEBUG_BFD)
+ zlog_debug(
+ "ISIS-BFD: skipping BFD initialization: IPv6 enabled and no local IPv6 addresses");
goto out;
+ }
local_ip = listgetdata(listhead(local_ips));
src_ip.ipv6 = local_ip->u.prefix6;
} else if (circuit->ip_router && adj->ipv4_address_count) {
family = AF_INET;
dst_ip.ipv4 = adj->ipv4_addresses[0];
local_ips = fabricd_ip_addrs(adj->circuit);
- if (!local_ips || list_isempty(local_ips))
+ if (!local_ips || list_isempty(local_ips)) {
+ if (IS_DEBUG_BFD)
+ zlog_debug(
+ "ISIS-BFD: skipping BFD initialization: IPv4 enabled and no local IPv4 addresses");
goto out;
+ }
local_ip = listgetdata(listhead(local_ips));
src_ip.ipv4 = local_ip->u.prefix4;
} else
bfd_handle_adj_down(adj);
}
- if (!adj->bfd_session)
+ if (!adj->bfd_session) {
+ if (IS_DEBUG_BFD)
+ zlog_debug(
+ "ISIS-BFD: creating BFD session for adjacency with %s",
+ isis_adj_name(adj));
adj->bfd_session = bfd_session_new(family, &dst_ip, &src_ip);
+ }
bfd_debug(adj->bfd_session->family, &adj->bfd_session->dst_ip,
&adj->bfd_session->src_ip, circuit->interface->name, command);
#include "isisd/isis_nb.h"
#include "isisd/isis_ldp_sync.h"
-DEFINE_QOBJ_TYPE(isis_circuit)
+DEFINE_MTYPE_STATIC(ISISD, ISIS_CIRCUIT, "ISIS circuit");
-DEFINE_HOOK(isis_if_new_hook, (struct interface *ifp), (ifp))
+DEFINE_QOBJ_TYPE(isis_circuit);
+
+DEFINE_HOOK(isis_if_new_hook, (struct interface *ifp), (ifp));
/*
* Prototypes.
}
DEFINE_HOOK(isis_circuit_add_addr_hook, (struct isis_circuit *circuit),
- (circuit))
+ (circuit));
void isis_circuit_add_addr(struct isis_circuit *circuit,
struct connected *connected)
#ifdef FABRICD
DEFINE_HOOK(isis_circuit_config_write,
(struct isis_circuit *circuit, struct vty *vty),
- (circuit, vty))
+ (circuit, vty));
static int isis_interface_config_write(struct vty *vty)
{
*/
struct list *snmp_adj_list; /* List in id order */
- QOBJ_FIELDS
+ QOBJ_FIELDS;
};
-DECLARE_QOBJ_TYPE(isis_circuit)
+DECLARE_QOBJ_TYPE(isis_circuit);
void isis_circuit_init(void);
struct isis_circuit *isis_circuit_new(struct isis *isis);
#ifdef FABRICD
DECLARE_HOOK(isis_circuit_config_write,
(struct isis_circuit *circuit, struct vty *vty),
- (circuit, vty))
+ (circuit, vty));
#endif
DECLARE_HOOK(isis_circuit_add_addr_hook, (struct isis_circuit *circuit),
- (circuit))
+ (circuit));
#endif /* _ZEBRA_ISIS_CIRCUIT_H */
vrf = yang_dnode_get_string(dnode, "./vrf");
vty_out(vty, "!\n");
- vty_out(vty, "router isis %s ",
+ vty_out(vty, "router isis %s",
yang_dnode_get_string(dnode, "./area-tag"));
if (!strmatch(vrf, VRF_DEFAULT_NAME))
- vty_out(vty, "vrf %s", yang_dnode_get_string(dnode, "./vrf"));
+ vty_out(vty, " vrf %s", yang_dnode_get_string(dnode, "./vrf"));
vty_out(vty, "\n");
}
if (!yang_dnode_get_bool(dnode, NULL))
vty_out(vty, " no");
- vty_out(vty, " ip router isis %s ",
+ vty_out(vty, " ip router isis %s",
yang_dnode_get_string(dnode, "../area-tag"));
if (!strmatch(vrf, VRF_DEFAULT_NAME))
- vty_out(vty, "vrf %s", vrf);
+ vty_out(vty, " vrf %s", vrf);
vty_out(vty, "\n");
}
if (!yang_dnode_get_bool(dnode, NULL))
vty_out(vty, " no");
- vty_out(vty, " ipv6 router isis %s ",
+ vty_out(vty, " ipv6 router isis %s",
yang_dnode_get_string(dnode, "../area-tag"));
if (!strmatch(vrf, VRF_DEFAULT_NAME))
- vty_out(vty, "vrf %s", vrf);
+ vty_out(vty, " vrf %s", vrf);
vty_out(vty, "\n");
}
#include "isisd/isis_misc.h"
#include "isisd/isis_constants.h"
+DEFINE_MTYPE_STATIC(ISISD, ISIS_DYNHN, "ISIS dyn hostname");
+
extern struct host host;
struct list *dyn_cache = NULL;
DEFINE_MTYPE_STATIC(ISISD, ISIS_LFA_TIEBREAKER, "ISIS LFA Tiebreaker");
DEFINE_MTYPE_STATIC(ISISD, ISIS_LFA_EXCL_IFACE, "ISIS LFA Excluded Interface");
DEFINE_MTYPE_STATIC(ISISD, ISIS_RLFA, "ISIS Remote LFA");
+DEFINE_MTYPE(ISISD, ISIS_NEXTHOP_LABELS, "ISIS nexthop MPLS labels");
static inline int isis_spf_node_compare(const struct isis_spf_node *a,
const struct isis_spf_node *b)
#include "lib/typesafe.h"
#include "lib/zclient.h"
+#include "lib/memory.h"
-PREDECL_RBTREE_UNIQ(lfa_tiebreaker_tree)
-PREDECL_RBTREE_UNIQ(rlfa_tree)
+DECLARE_MTYPE(ISIS_NEXTHOP_LABELS);
+
+PREDECL_RBTREE_UNIQ(lfa_tiebreaker_tree);
+PREDECL_RBTREE_UNIQ(rlfa_tree);
enum lfa_tiebreaker_type {
LFA_TIEBREAKER_DOWNSTREAM = 0,
int lfa_tiebreaker_cmp(const struct lfa_tiebreaker *a,
const struct lfa_tiebreaker *b);
DECLARE_RBTREE_UNIQ(lfa_tiebreaker_tree, struct lfa_tiebreaker, entry,
- lfa_tiebreaker_cmp)
+ lfa_tiebreaker_cmp);
struct rlfa {
struct rlfa_tree_item entry;
struct in_addr pq_address;
};
int rlfa_cmp(const struct rlfa *a, const struct rlfa *b);
-DECLARE_RBTREE_UNIQ(rlfa_tree, struct rlfa, entry, rlfa_cmp)
+DECLARE_RBTREE_UNIQ(rlfa_tree, struct rlfa, entry, rlfa_cmp);
enum isis_tilfa_sid_type {
TILFA_SID_PREFIX = 1,
#include "isisd/isis_tx_queue.h"
#include "isisd/isis_nb.h"
+DEFINE_MTYPE_STATIC(ISISD, ISIS_LSP, "ISIS LSP");
+
static int lsp_refresh(struct thread *thread);
static int lsp_l1_refresh_pseudo(struct thread *thread);
static int lsp_l2_refresh_pseudo(struct thread *thread);
/*
* Schedule LSP refresh ASAP
*/
- timeout = 0;
-
if (area->bfd_signalled_down) {
sched_debug(
- "ISIS (%s): Scheduling immediately due to BDF 'down' message.",
+ "ISIS (%s): Scheduling immediately due to BFD 'down' message.",
area->area_tag);
area->bfd_signalled_down = false;
area->bfd_force_spf_refresh = true;
+ timeout = 0;
} else {
- sched_debug(
- "ISIS (%s): Last generation was more than lsp_gen_interval ago. Scheduling for execution now.",
- area->area_tag);
+ int64_t time_since_last = monotime_since(
+ &area->last_lsp_refresh_event[lvl - 1],
+ NULL);
+ timeout = time_since_last < 100000L
+ ? (100000L - time_since_last)/1000
+ : 0;
+ if (timeout > 0)
+ sched_debug(
+ "ISIS (%s): Last generation was more than lsp_gen_interval ago. Scheduling for execution in %ld ms due to the instability timer.",
+ area->area_tag, timeout);
+ else
+ sched_debug(
+ "ISIS (%s): Last generation was more than lsp_gen_interval ago. Scheduling for execution now.",
+ area->area_tag);
}
}
#include "lib/typesafe.h"
#include "isisd/isis_pdu.h"
-PREDECL_RBTREE_UNIQ(lspdb)
+PREDECL_RBTREE_UNIQ(lspdb);
struct isis;
/* Structure for isis_lsp, this structure will only support the fixed
};
extern int lspdb_compare(const struct isis_lsp *a, const struct isis_lsp *b);
-DECLARE_RBTREE_UNIQ(lspdb, struct isis_lsp, dbe, lspdb_compare)
+DECLARE_RBTREE_UNIQ(lspdb, struct isis_lsp, dbe, lspdb_compare);
void lsp_db_init(struct lspdb_head *head);
void lsp_db_fini(struct lspdb_head *head);
.n_signals = array_size(isisd_signals),
.privs = &isisd_privs, .yang_modules = isisd_yang_modules,
- .n_yang_modules = array_size(isisd_yang_modules), )
+ .n_yang_modules = array_size(isisd_yang_modules),
+);
/*
* Main routine of isisd. Parse arguments and handle IS-IS state machine.
+++ /dev/null
-/* isisd memory type definitions
- *
- * Copyright (C) 2015 David Lamparter
- *
- * This file is part of Quagga.
- *
- * Quagga is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * Quagga is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "isis_memory.h"
-
-DEFINE_MGROUP(ISISD, "isisd")
-DEFINE_MTYPE(ISISD, ISIS, "ISIS")
-DEFINE_MTYPE(ISISD, ISIS_TMP, "ISIS TMP")
-DEFINE_MTYPE(ISISD, ISIS_CIRCUIT, "ISIS circuit")
-DEFINE_MTYPE(ISISD, ISIS_LSP, "ISIS LSP")
-DEFINE_MTYPE(ISISD, ISIS_ADJACENCY, "ISIS adjacency")
-DEFINE_MTYPE(ISISD, ISIS_ADJACENCY_INFO, "ISIS adjacency info")
-DEFINE_MTYPE(ISISD, ISIS_AREA, "ISIS area")
-DEFINE_MTYPE(ISISD, ISIS_AREA_ADDR, "ISIS area address")
-DEFINE_MTYPE(ISISD, ISIS_DYNHN, "ISIS dyn hostname")
-DEFINE_MTYPE(ISISD, ISIS_SPFTREE, "ISIS SPFtree")
-DEFINE_MTYPE(ISISD, ISIS_VERTEX, "ISIS vertex")
-DEFINE_MTYPE(ISISD, ISIS_ROUTE_INFO, "ISIS route info")
-DEFINE_MTYPE(ISISD, ISIS_NEXTHOP, "ISIS nexthop")
-DEFINE_MTYPE(ISISD, ISIS_NEXTHOP_LABELS, "ISIS nexthop MPLS labels")
-DEFINE_MTYPE(ISISD, ISIS_DICT, "ISIS dictionary")
-DEFINE_MTYPE(ISISD, ISIS_DICT_NODE, "ISIS dictionary node")
-DEFINE_MTYPE(ISISD, ISIS_EXT_ROUTE, "ISIS redistributed route")
-DEFINE_MTYPE(ISISD, ISIS_EXT_INFO, "ISIS redistributed route info")
-DEFINE_MTYPE(ISISD, ISIS_MPLS_TE, "ISIS MPLS_TE parameters")
-DEFINE_MTYPE(ISISD, ISIS_ACL_NAME, "ISIS access-list name")
-DEFINE_MTYPE(ISISD, ISIS_PLIST_NAME, "ISIS prefix-list name")
+++ /dev/null
-/* isisd memory type declarations
- *
- * Copyright (C) 2015 David Lamparter
- *
- * This file is part of Quagga.
- *
- * Quagga is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * Quagga is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef _QUAGGA_ISIS_MEMORY_H
-#define _QUAGGA_ISIS_MEMORY_H
-
-#include "memory.h"
-
-DECLARE_MGROUP(ISISD)
-DECLARE_MTYPE(ISIS)
-DECLARE_MTYPE(ISIS_TMP)
-DECLARE_MTYPE(ISIS_CIRCUIT)
-DECLARE_MTYPE(ISIS_LSP)
-DECLARE_MTYPE(ISIS_ADJACENCY)
-DECLARE_MTYPE(ISIS_ADJACENCY_INFO)
-DECLARE_MTYPE(ISIS_AREA)
-DECLARE_MTYPE(ISIS_AREA_ADDR)
-DECLARE_MTYPE(ISIS_DYNHN)
-DECLARE_MTYPE(ISIS_SPFTREE)
-DECLARE_MTYPE(ISIS_VERTEX)
-DECLARE_MTYPE(ISIS_ROUTE_INFO)
-DECLARE_MTYPE(ISIS_NEXTHOP)
-DECLARE_MTYPE(ISIS_NEXTHOP_LABELS)
-DECLARE_MTYPE(ISIS_DICT)
-DECLARE_MTYPE(ISIS_DICT_NODE)
-DECLARE_MTYPE(ISIS_EXT_ROUTE)
-DECLARE_MTYPE(ISIS_EXT_INFO)
-DECLARE_MTYPE(ISIS_MPLS_TE)
-DECLARE_MTYPE(ISIS_ACL_NAME)
-DECLARE_MTYPE(ISIS_PLIST_NAME)
-
-#endif /* _QUAGGA_ISIS_MEMORY_H */
*/
#include <zebra.h>
#include "isisd/isisd.h"
-#include "isisd/isis_memory.h"
#include "isisd/isis_circuit.h"
#include "isisd/isis_adjacency.h"
#include "isisd/isis_misc.h"
#include "isisd/isis_mt.h"
#include "isisd/isis_tlvs.h"
-DEFINE_MTYPE_STATIC(ISISD, MT_AREA_SETTING, "ISIS MT Area Setting")
-DEFINE_MTYPE_STATIC(ISISD, MT_CIRCUIT_SETTING, "ISIS MT Circuit Setting")
-DEFINE_MTYPE_STATIC(ISISD, MT_ADJ_INFO, "ISIS MT Adjacency Info")
+DEFINE_MTYPE_STATIC(ISISD, MT_AREA_SETTING, "ISIS MT Area Setting");
+DEFINE_MTYPE_STATIC(ISISD, MT_CIRCUIT_SETTING, "ISIS MT Circuit Setting");
+DEFINE_MTYPE_STATIC(ISISD, MT_ADJ_INFO, "ISIS MT Adjacency Info");
bool isis_area_ipv6_dstsrc_enabled(struct isis_area *area)
{
#include "isisd/isis_spf.h"
#include "isisd/isis_spf_private.h"
#include "isisd/isis_te.h"
-#include "isisd/isis_memory.h"
#include "isisd/isis_mt.h"
#include "isisd/isis_redist.h"
#include "isisd/isis_ldp_sync.h"
#include "isisd/isis_dr.h"
+DEFINE_MTYPE_STATIC(ISISD, ISIS_MPLS_TE, "ISIS MPLS_TE parameters");
+DEFINE_MTYPE_STATIC(ISISD, ISIS_PLIST_NAME, "ISIS prefix-list name");
+
extern struct zclient *zclient;
/*
#include "if.h"
#include "linklist.h"
#include "memory.h"
-#include "isis_memory.h"
#include "prefix.h"
#include "routemap.h"
#include "stream.h"
#include "isisd/isis_route.h"
#include "isisd/isis_zebra.h"
+DEFINE_MTYPE_STATIC(ISISD, ISIS_EXT_ROUTE, "ISIS redistributed route");
+DEFINE_MTYPE_STATIC(ISISD, ISIS_EXT_INFO, "ISIS redistributed route info");
+DEFINE_MTYPE_STATIC(ISISD, ISIS_RMAP_NAME, "ISIS redistribute route-map name");
+
static int redist_protocol(int family)
{
if (family == AF_INET)
const char *routemap)
{
if (redist->map_name) {
- XFREE(MTYPE_ISIS, redist->map_name);
+ XFREE(MTYPE_ISIS_RMAP_NAME, redist->map_name);
route_map_counter_decrement(redist->map);
redist->map = NULL;
}
if (routemap && strlen(routemap)) {
- redist->map_name = XSTRDUP(MTYPE_ISIS, routemap);
+ redist->map_name = XSTRDUP(MTYPE_ISIS_RMAP_NAME, routemap);
redist->map = route_map_lookup_by_name(routemap);
route_map_counter_increment(redist->map);
}
redist = &area->redist_settings[protocol][type]
[level];
redist->redist = 0;
- XFREE(MTYPE_ISIS, redist->map_name);
+ XFREE(MTYPE_ISIS_RMAP_NAME, redist->map_name);
}
route_table_finish(area->ext_reach[protocol][level]);
}
#include "isis_route.h"
#include "isis_zebra.h"
+DEFINE_MTYPE_STATIC(ISISD, ISIS_NEXTHOP, "ISIS nexthop");
+DEFINE_MTYPE_STATIC(ISISD, ISIS_ROUTE_INFO, "ISIS route info");
+
DEFINE_HOOK(isis_route_update_hook,
(struct isis_area * area, struct prefix *prefix,
struct isis_route_info *route_info),
- (area, prefix, route_info))
+ (area, prefix, route_info));
static struct isis_nexthop *nexthoplookup(struct list *nexthops, int family,
union g_addr *ip, ifindex_t ifindex);
DECLARE_HOOK(isis_route_update_hook,
(struct isis_area * area, struct prefix *prefix,
struct isis_route_info *route_info),
- (area, prefix, route_info))
+ (area, prefix, route_info));
void isis_nexthop_delete(struct isis_nexthop *nexthop);
void adjinfo2nexthop(int family, struct list *nexthops,
#define ISIS_TRAP_LSP_ERROR 18
/* Change this definition if number of traps changes */
-#define ISIS_TRAP_LAST_TRAP ISIS_TRAP_LSP_ERROR
+#define ISIS_TRAP_LAST_TRAP ISIS_TRAP_LSP_ERROR + 1
#define ISIS_SNMP_TRAP_VAR 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0
start = 0;
- if (oid_idx != NULL || oid_idx_len != 0) {
+ if (oid_idx != NULL && oid_idx_len != 0) {
if (oid_idx[0] > SNMP_CIRCUITS_MAX)
return 0;
start = 0;
- if (oid_idx != NULL || oid_idx_len != 0) {
+ if (oid_idx != NULL && oid_idx_len != 0) {
if (oid_idx[0] > SNMP_CIRCUITS_MAX)
return 0;
oid *oid_idx;
size_t oid_idx_len;
struct isis_circuit *circuit;
- uint64_t up_ticks;
- uint64_t delta_ticks;
+ uint32_t up_ticks;
+ uint32_t delta_ticks;
uint32_t now_time;
int res;
if (circuit->last_uptime == 0)
return SNMP_INTEGER(0);
- up_ticks = netsnmp_get_agent_uptime();
+ up_ticks = (uint32_t)netsnmp_get_agent_uptime();
now_time = isis_snmp_time();
if (circuit->last_uptime >= now_time)
if (up_ticks < delta_ticks)
return SNMP_INTEGER(up_ticks);
- return SNMP_INTEGER((uint32_t)(up_ticks - delta_ticks));
+ return SNMP_INTEGER(up_ticks - delta_ticks);
case ISIS_CIRC_3WAYENABLED:
/* Not supported */
int res;
uint32_t val;
struct isis_adjacency *adj;
- uint64_t up_ticks;
- uint64_t delta_ticks;
+ uint32_t up_ticks;
+ uint32_t delta_ticks;
uint32_t now_time;
*write_method = NULL;
if (adj->flaps == 0)
return SNMP_INTEGER(0);
- up_ticks = netsnmp_get_agent_uptime();
+ up_ticks = (uint32_t)netsnmp_get_agent_uptime();
now_time = isis_snmp_time();
if (up_ticks < delta_ticks)
return SNMP_INTEGER(up_ticks);
- return SNMP_INTEGER((uint32_t)(up_ticks - delta_ticks));
+ return SNMP_INTEGER(up_ticks - delta_ticks);
default:
break;
return 0;
}
-FRR_MODULE_SETUP(.name = "isis_snmp", .version = FRR_VERSION,
- .description = "isis AgentX SNMP module",
- .init = isis_snmp_module_init, )
+FRR_MODULE_SETUP(
+ .name = "isis_snmp",
+ .version = FRR_VERSION,
+ .description = "isis AgentX SNMP module",
+ .init = isis_snmp_module_init,
+);
#include "fabricd.h"
#include "isis_spf_private.h"
-DEFINE_MTYPE_STATIC(ISISD, ISIS_SPF_RUN, "ISIS SPF Run Info");
-DEFINE_MTYPE_STATIC(ISISD, ISIS_SPF_ADJ, "ISIS SPF Adjacency");
+DEFINE_MTYPE_STATIC(ISISD, ISIS_SPFTREE, "ISIS SPFtree");
+DEFINE_MTYPE_STATIC(ISISD, ISIS_SPF_RUN, "ISIS SPF Run Info");
+DEFINE_MTYPE_STATIC(ISISD, ISIS_SPF_ADJ, "ISIS SPF Adjacency");
+DEFINE_MTYPE_STATIC(ISISD, ISIS_VERTEX, "ISIS vertex");
DEFINE_MTYPE_STATIC(ISISD, ISIS_VERTEX_ADJ, "ISIS SPF Vertex Adjacency");
static void spf_adj_list_parse_lsp(struct isis_spftree *spftree,
return vertex;
}
+void isis_vertex_del(struct isis_vertex *vertex)
+{
+ list_delete(&vertex->Adj_N);
+ list_delete(&vertex->parents);
+ if (vertex->firsthops) {
+ hash_clean(vertex->firsthops, NULL);
+ hash_free(vertex->firsthops);
+ vertex->firsthops = NULL;
+ }
+
+ memset(vertex, 0, sizeof(struct isis_vertex));
+ XFREE(MTYPE_ISIS_VERTEX, vertex);
+}
+
struct isis_vertex_adj *
isis_vertex_adj_add(struct isis_spftree *spftree, struct isis_vertex *vertex,
struct list *vadj_list, struct isis_spf_adj *sadj,
isis_vertex_queue_hash_cmp, name);
}
-__attribute__((__unused__))
-static void isis_vertex_del(struct isis_vertex *vertex)
-{
- list_delete(&vertex->Adj_N);
- list_delete(&vertex->parents);
- if (vertex->firsthops) {
- hash_clean(vertex->firsthops, NULL);
- hash_free(vertex->firsthops);
- vertex->firsthops = NULL;
- }
-
- memset(vertex, 0, sizeof(struct isis_vertex));
- XFREE(MTYPE_ISIS_VERTEX, vertex);
-}
+void isis_vertex_del(struct isis_vertex *vertex);
bool isis_vertex_adj_exists(const struct isis_spftree *spftree,
const struct isis_vertex *vertex,
#include "isisd/isis_errors.h"
/* Local variables and functions */
-DEFINE_MTYPE_STATIC(ISISD, ISIS_SR_INFO, "ISIS segment routing information")
+DEFINE_MTYPE_STATIC(ISISD, ISIS_SR_INFO, "ISIS segment routing information");
static void sr_local_block_delete(struct isis_area *area);
static int sr_local_block_init(struct isis_area *area);
return prefix_cmp(&a->prefix, &b->prefix);
}
DECLARE_RBTREE_UNIQ(srdb_prefix_cfg, struct sr_prefix_cfg, entry,
- sr_prefix_sid_cfg_compare)
+ sr_prefix_sid_cfg_compare);
/**
* Find SRGB associated to a System ID.
#define SRLB_UPPER_BOUND 15999
/* Segment Routing Data Base (SRDB) RB-Tree structure */
-PREDECL_RBTREE_UNIQ(srdb_prefix_cfg)
+PREDECL_RBTREE_UNIQ(srdb_prefix_cfg);
/*
* Segment Routing Prefix-SID information.
#include "network.h"
#include "isisd/isisd.h"
-#include "isisd/isis_memory.h"
#include "isisd/isis_tlvs.h"
#include "isisd/isis_common.h"
#include "isisd/isis_mt.h"
#include "isisd/isis_te.h"
#include "isisd/isis_sr.h"
-DEFINE_MTYPE_STATIC(ISISD, ISIS_TLV, "ISIS TLVs")
-DEFINE_MTYPE(ISISD, ISIS_SUBTLV, "ISIS Sub-TLVs")
-DEFINE_MTYPE_STATIC(ISISD, ISIS_MT_ITEM_LIST, "ISIS MT Item Lists")
+DEFINE_MTYPE_STATIC(ISISD, ISIS_TLV, "ISIS TLVs");
+DEFINE_MTYPE(ISISD, ISIS_SUBTLV, "ISIS Sub-TLVs");
+DEFINE_MTYPE_STATIC(ISISD, ISIS_MT_ITEM_LIST, "ISIS MT Item Lists");
typedef int (*unpack_tlv_func)(enum isis_tlv_context context, uint8_t tlv_type,
uint8_t tlv_len, struct stream *s,
}
DEFINE_HOOK(isis_adj_ip_enabled_hook, (struct isis_adjacency *adj, int family),
- (adj, family))
+ (adj, family));
DEFINE_HOOK(isis_adj_ip_disabled_hook,
- (struct isis_adjacency *adj, int family), (adj, family))
+ (struct isis_adjacency *adj, int family), (adj, family));
static void tlvs_ipv4_addresses_to_adj(struct isis_tlvs *tlvs,
struct isis_adjacency *adj,
#include "openbsd-tree.h"
#include "prefix.h"
-DECLARE_MTYPE(ISIS_SUBTLV)
+DECLARE_MTYPE(ISIS_SUBTLV);
struct lspdb_head;
struct isis_subtlvs;
#include "jhash.h"
#include "isisd/isisd.h"
-#include "isisd/isis_memory.h"
#include "isisd/isis_flags.h"
#include "isisd/isis_circuit.h"
#include "isisd/isis_lsp.h"
#include "isisd/isis_misc.h"
#include "isisd/isis_tx_queue.h"
-DEFINE_MTYPE_STATIC(ISISD, TX_QUEUE, "ISIS TX Queue")
-DEFINE_MTYPE_STATIC(ISISD, TX_QUEUE_ENTRY, "ISIS TX Queue Entry")
+DEFINE_MTYPE_STATIC(ISISD, TX_QUEUE, "ISIS TX Queue");
+DEFINE_MTYPE_STATIC(ISISD, TX_QUEUE_ENTRY, "ISIS TX Queue Entry");
struct isis_tx_queue {
struct isis_circuit *circuit;
unsigned long debug_ldp_sync;
unsigned long debug_lfa;
-DEFINE_QOBJ_TYPE(isis_area)
+DEFINE_MGROUP(ISISD, "isisd");
+
+DEFINE_MTYPE_STATIC(ISISD, ISIS, "ISIS process");
+DEFINE_MTYPE_STATIC(ISISD, ISIS_NAME, "ISIS process name");
+DEFINE_MTYPE_STATIC(ISISD, ISIS_AREA, "ISIS area");
+DEFINE_MTYPE(ISISD, ISIS_AREA_ADDR, "ISIS area address");
+DEFINE_MTYPE(ISISD, ISIS_ACL_NAME, "ISIS access-list name");
+
+DEFINE_QOBJ_TYPE(isis_area);
/* ISIS process wide configuration. */
static struct isis_master isis_master;
if (vrf) {
isis->vrf_id = vrf->vrf_id;
isis_vrf_link(isis, vrf);
- isis->name = XSTRDUP(MTYPE_ISIS, vrf->name);
+ isis->name = XSTRDUP(MTYPE_ISIS_NAME, vrf->name);
} else {
isis->vrf_id = VRF_UNKNOWN;
- isis->name = XSTRDUP(MTYPE_ISIS, vrf_name);
+ isis->name = XSTRDUP(MTYPE_ISIS_NAME, vrf_name);
}
if (IS_DEBUG_EVENTS)
isis = isis_lookup_by_vrfname(vrf->name);
if (isis) {
if (isis->name && strmatch(vrf->name, VRF_DEFAULT_NAME)) {
- XFREE(MTYPE_ISIS, isis->name);
+ XFREE(MTYPE_ISIS_NAME, isis->name);
isis->name = NULL;
}
old_vrf_id = isis->vrf_id;
vrf = vrf_lookup_by_name(isis->name);
if (vrf)
isis_vrf_unlink(isis, vrf);
- XFREE(MTYPE_ISIS, isis->name);
+ XFREE(MTYPE_ISIS_NAME, isis->name);
} else {
vrf = vrf_lookup_by_id(VRF_DEFAULT);
if (vrf)
#define ISISD_H
#include "vty.h"
+#include "memory.h"
#include "isisd/isis_constants.h"
#include "isisd/isis_common.h"
#include "isis_flags.h"
#include "isis_lsp.h"
#include "isis_lfa.h"
-#include "isis_memory.h"
#include "qobj.h"
#include "ldp_sync.h"
+DECLARE_MGROUP(ISISD);
+
#ifdef FABRICD
static const bool fabricd = true;
#define PROTO_TYPE ZEBRA_ROUTE_OPENFABRIC
uint64_t id_len_mismatches[2];
uint64_t lsp_error_counter[2];
- QOBJ_FIELDS
+ QOBJ_FIELDS;
};
-DECLARE_QOBJ_TYPE(isis_area)
+DECLARE_QOBJ_TYPE(isis_area);
+
+DECLARE_MTYPE(ISIS_ACL_NAME); /* isis_area->spf_prefix_prioritites */
+DECLARE_MTYPE(ISIS_AREA_ADDR); /* isis_area->area_addrs */
-DECLARE_HOOK(isis_area_overload_bit_update, (struct isis_area * area), (area))
+DECLARE_HOOK(isis_area_overload_bit_update, (struct isis_area * area), (area));
void isis_terminate(void);
void isis_finish(struct isis *isis);
isisd/isis_ldp_sync.h \
isisd/isis_lfa.h \
isisd/isis_lsp.h \
- isisd/isis_memory.h \
isisd/isis_misc.h \
isisd/isis_mt.h \
isisd/isis_nb.h \
isisd/isis_ldp_sync.c \
isisd/isis_lfa.c \
isisd/isis_lsp.c \
- isisd/isis_memory.c \
isisd/isis_misc.c \
isisd/isis_mt.c \
isisd/isis_pdu.c \
# end
isisd_isisd_snmp_la_SOURCES = isisd/isis_snmp.c
-isisd_isisd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu99
+isisd_isisd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu11
isisd_isisd_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
isisd_isisd_snmp_la_LIBADD = lib/libfrrsnmp.la
return NULL;
}
+static uint8_t *ldpEntityStatsTable(struct variable *v, oid name[],
+ size_t *length, int exact, size_t *var_len,
+ WriteMethod **write_method)
+{
+ struct in_addr entityLdpId = {.s_addr = 0};
+ int len;
+
+ *write_method = NULL;
+
+ if (smux_header_table(v, name, length, exact, var_len, write_method)
+ == MATCH_FAILED)
+ return NULL;
+
+ if (exact) {
+ if (*length != LDP_ENTITY_TOTAL_LEN)
+ return NULL;
+ } else {
+ len = *length - v->namelen - LDP_ENTITY_MAX_IDX_LEN;
+ if (len > 0)
+ return NULL;
+
+ entityLdpId.s_addr = ldp_rtr_id_get(leconf);
+
+ /* Copy the name out */
+ memcpy(name, v->name, v->namelen * sizeof(oid));
+
+ /* Append index */
+ *length = LDP_ENTITY_TOTAL_LEN;
+ oid_copy_addr(name + v->namelen, &entityLdpId,
+ IN_ADDR_SIZE);
+ name[v->namelen + 4] = 0;
+ name[v->namelen + 5] = 0;
+ name[v->namelen + 6] = LDP_DEFAULT_ENTITY_INDEX;
+ }
+
+ /* Return the current value of the variable */
+ switch (v->magic) {
+ case MPLSLDPENTITYSTATSSESSIONATTEMPTS:
+ return SNMP_INTEGER(leconf->stats.session_attempts);
+ case MPLSLDPENTITYSTATSSESSIONREJHELLO:
+ return SNMP_INTEGER(leconf->stats.session_rejects_hello);
+ case MPLSLDPENTITYSTATSSESSIONREJAD:
+ return SNMP_INTEGER(leconf->stats.session_rejects_ad);
+ case MPLSLDPENTITYSTATSSESSIONREJMAXPDU:
+ return SNMP_INTEGER(leconf->stats.session_rejects_max_pdu);
+ case MPLSLDPENTITYSTATSSESSIONREJLR:
+ return SNMP_INTEGER(leconf->stats.session_rejects_lr);
+ case MPLSLDPENTITYSTATSBADLDPID:
+ return SNMP_INTEGER(leconf->stats.bad_ldp_id);
+ case MPLSLDPENTITYSTATSBADPDULENGTH:
+ return SNMP_INTEGER(leconf->stats.bad_pdu_len);
+ case MPLSLDPENTITYSTATSBADMSGLENGTH:
+ return SNMP_INTEGER(leconf->stats.bad_msg_len);
+ case MPLSLDPENTITYSTATSBADTLVLENGTH:
+ return SNMP_INTEGER(leconf->stats.bad_tlv_len);
+ case MPLSLDPENTITYSTATSMALFORMEDTLV:
+ return SNMP_INTEGER(leconf->stats.malformed_tlv);
+ case MPLSLDPENTITYSTATSKEEPALIVEEXP:
+ return SNMP_INTEGER(leconf->stats.keepalive_timer_exp);
+ case MPLSLDPENTITYSTATSSHUTDOWNRCVNOTIFY:
+ return SNMP_INTEGER(leconf->stats.shutdown_rcv_notify);
+ case MPLSLDPENTITYSTATSSHUTDOWNSENTNOTIFY:
+ return SNMP_INTEGER(leconf->stats.shutdown_send_notify);
+ default:
+ return NULL;
+ }
+
+ return NULL;
+}
+
#define LDP_ADJACENCY_ENTRY_MAX_IDX_LEN 14
static void ldpHelloAdjacencyTable_oid_to_index(
return NULL;
}
+static uint8_t *ldpSessionStatsTable(struct variable *v, oid name[],
+ size_t *length,
+ int exact, size_t *var_len,
+ WriteMethod **write_method)
+{
+ struct in_addr entityLdpId = {.s_addr = 0};
+ uint32_t entityIndex = 0;
+ struct in_addr peerLdpId = {.s_addr = 0};
+
+ if (smux_header_table(v, name, length, exact, var_len, write_method)
+ == MATCH_FAILED)
+ return NULL;
+
+ struct ctl_nbr *ctl_nbr = ldpPeerTable_lookup(v, name, length, exact,
+ &entityLdpId, &entityIndex, &peerLdpId);
+
+ if (!ctl_nbr)
+ return NULL;
+
+ if (!exact) {
+ entityLdpId.s_addr = ldp_rtr_id_get(leconf);
+ entityIndex = LDP_DEFAULT_ENTITY_INDEX;
+ peerLdpId = ctl_nbr->id;
+
+ /* Copy the name out */
+ memcpy(name, v->name, v->namelen * sizeof(oid));
+
+ /* Append index */
+ oid_copy_addr(name + v->namelen, &entityLdpId,
+ sizeof(struct in_addr));
+ name[v->namelen + 4] = 0;
+ name[v->namelen + 5] = 0;
+ name[v->namelen + 6] = entityIndex;
+ oid_copy_addr(name + v->namelen + 7, &peerLdpId,
+ sizeof(struct in_addr));
+ name[v->namelen + 11] = 0;
+ name[v->namelen + 12] = 0;
+
+ *length = v->namelen + LDP_PEER_ENTRY_MAX_IDX_LEN;
+ }
+
+ switch (v->magic) {
+ case MPLSLDPSESSIONSTATSUNKNOWNMESTYPEERRORS:
+ return SNMP_INTEGER(ctl_nbr->stats.unknown_msg);
+ case MPLSLDPSESSIONSTATSUNKNOWNTLVERRORS:
+ return SNMP_INTEGER(ctl_nbr->stats.unknown_tlv);
+ default:
+ return NULL;
+ }
+
+ return NULL;
+}
+
static struct variable ldpe_variables[] = {
{MPLS_LDP_LSR_ID, STRING, RONLY, ldpLsrId, 3, {1, 1, 1}},
{MPLS_LDP_LSR_LOOP_DETECTION_CAPABLE, INTEGER, RONLY,
{MPLSLDPENTITYROWSTATUS, INTEGER, RONLY, ldpEntityTable,
5, {1, 2, 3, 1, 23}},
+ /* MPLS LDP mplsLdpEntityStatsTable. */
+ { MPLSLDPENTITYSTATSSESSIONATTEMPTS, COUNTER32, RONLY,
+ ldpEntityStatsTable, 5, {1, 2, 4, 1, 1}},
+ { MPLSLDPENTITYSTATSSESSIONREJHELLO, COUNTER32, RONLY,
+ ldpEntityStatsTable, 5, {1, 2, 4, 1, 2}},
+ { MPLSLDPENTITYSTATSSESSIONREJAD, COUNTER32, RONLY,
+ ldpEntityStatsTable, 5, {1, 2, 4, 1, 3}},
+ { MPLSLDPENTITYSTATSSESSIONREJMAXPDU, COUNTER32, RONLY,
+ ldpEntityStatsTable, 5, {1, 2, 4, 1, 4}},
+ { MPLSLDPENTITYSTATSSESSIONREJLR, COUNTER32, RONLY,
+ ldpEntityStatsTable, 5, {1, 2, 4, 1, 5}},
+ { MPLSLDPENTITYSTATSBADLDPID, COUNTER32, RONLY,
+ ldpEntityStatsTable, 5, {1, 2, 4, 1, 6}},
+ { MPLSLDPENTITYSTATSBADPDULENGTH, COUNTER32, RONLY,
+ ldpEntityStatsTable, 5, {1, 2, 4, 1, 7}},
+ { MPLSLDPENTITYSTATSBADMSGLENGTH, COUNTER32, RONLY,
+ ldpEntityStatsTable, 5, {1, 2, 4, 1, 8}},
+ { MPLSLDPENTITYSTATSBADTLVLENGTH, COUNTER32, RONLY,
+ ldpEntityStatsTable, 5, {1, 2, 4, 1, 9}},
+ { MPLSLDPENTITYSTATSMALFORMEDTLV, COUNTER32, RONLY,
+ ldpEntityStatsTable, 5, {1, 2, 4, 1, 10}},
+ { MPLSLDPENTITYSTATSKEEPALIVEEXP, COUNTER32, RONLY,
+ ldpEntityStatsTable, 5, {1, 2, 4, 1, 11}},
+ { MPLSLDPENTITYSTATSSHUTDOWNRCVNOTIFY, COUNTER32, RONLY,
+ ldpEntityStatsTable, 5, {1, 2, 4, 1, 12}},
+ { MPLSLDPENTITYSTATSSHUTDOWNSENTNOTIFY, COUNTER32, RONLY,
+ ldpEntityStatsTable, 5, {1, 2, 4, 1, 13}},
+
/* MPLS LDP mplsLdpPeerTable */
{MPLSLDPPEERLDPID, STRING, RONLY, ldpPeerTable, 5, {1, 3, 2, 1, 1}},
{MPLSLDPPEERLABELDISTMETHOD, INTEGER, RONLY, ldpPeerTable,
{MPLSLDPSESSIONDISCONTINUITYTIME, TIMESTAMP, RONLY, ldpSessionTable,
5, {1, 3, 3, 1, 8}},
+ /* MPLS LDP mplsLdpSessionStatsTable */
+ {MPLSLDPSESSIONSTATSUNKNOWNMESTYPEERRORS, COUNTER32, RONLY,
+ ldpSessionStatsTable, 5, {1, 3, 4, 1, 1}},
+ {MPLSLDPSESSIONSTATSUNKNOWNTLVERRORS, COUNTER32, RONLY,
+ ldpSessionStatsTable, 5, {1, 3, 4, 1, 2}},
+
/* MPLS LDP mplsLdpHelloAdjacencyTable. */
{MPLSLDPHELLOADJACENCYINDEX, UNSIGNED32, RONLY,
ldpHelloAdjacencyTable, 6, {1, 3, 5, 1, 1, 1}},
return 0;
}
-FRR_MODULE_SETUP(.name = "ldp_snmp", .version = FRR_VERSION,
- .description = "ldp AgentX SNMP module",
- .init = ldp_snmp_module_init, )
+FRR_MODULE_SETUP(
+ .name = "ldp_snmp",
+ .version = FRR_VERSION,
+ .description = "ldp AgentX SNMP module",
+ .init = ldp_snmp_module_init,
+);
static void merge_l2vpn(struct ldpd_conf *, struct l2vpn *,
struct l2vpn *);
-DEFINE_QOBJ_TYPE(iface)
-DEFINE_QOBJ_TYPE(tnbr)
-DEFINE_QOBJ_TYPE(nbr_params)
-DEFINE_QOBJ_TYPE(l2vpn_if)
-DEFINE_QOBJ_TYPE(l2vpn_pw)
-DEFINE_QOBJ_TYPE(l2vpn)
-DEFINE_QOBJ_TYPE(ldpd_conf)
+DEFINE_QOBJ_TYPE(iface);
+DEFINE_QOBJ_TYPE(tnbr);
+DEFINE_QOBJ_TYPE(nbr_params);
+DEFINE_QOBJ_TYPE(l2vpn_if);
+DEFINE_QOBJ_TYPE(l2vpn_pw);
+DEFINE_QOBJ_TYPE(l2vpn);
+DEFINE_QOBJ_TYPE(ldpd_conf);
struct ldpd_global global;
struct ldpd_init init;
static struct frr_daemon_info ldpd_di;
-DEFINE_HOOK(ldp_register_mib, (struct thread_master * tm), (tm))
+DEFINE_HOOK(ldp_register_mib, (struct thread_master * tm), (tm));
static void ldp_load_module(const char *name)
{
.yang_modules = ldpd_yang_modules,
.n_yang_modules = array_size(ldpd_yang_modules),
-)
+);
static int ldp_config_fork_apply(struct thread *t)
{
struct iface_af ipv4;
struct iface_af ipv6;
struct iface_ldp_sync ldp_sync;
- QOBJ_FIELDS
+ QOBJ_FIELDS;
};
RB_HEAD(iface_head, iface);
RB_PROTOTYPE(iface_head, iface, entry, iface_compare);
-DECLARE_QOBJ_TYPE(iface)
+DECLARE_QOBJ_TYPE(iface);
/* source of targeted hellos */
struct tnbr {
uint16_t pw_count;
uint32_t rlfa_count;
uint8_t flags;
- QOBJ_FIELDS
+ QOBJ_FIELDS;
};
RB_HEAD(tnbr_head, tnbr);
RB_PROTOTYPE(tnbr_head, tnbr, entry, tnbr_compare);
-DECLARE_QOBJ_TYPE(tnbr)
+DECLARE_QOBJ_TYPE(tnbr);
#define F_TNBR_CONFIGURED 0x01
#define F_TNBR_DYNAMIC 0x02
uint8_t md5key_len;
} auth;
uint8_t flags;
- QOBJ_FIELDS
+ QOBJ_FIELDS;
};
RB_HEAD(nbrp_head, nbr_params);
RB_PROTOTYPE(nbrp_head, nbr_params, entry, nbr_params_compare);
-DECLARE_QOBJ_TYPE(nbr_params)
+DECLARE_QOBJ_TYPE(nbr_params);
#define F_NBRP_KEEPALIVE 0x01
#define F_NBRP_GTSM 0x02
#define F_NBRP_GTSM_HOPS 0x04
uint32_t labelrel_rcvd;
uint32_t labelabreq_sent;
uint32_t labelabreq_rcvd;
+ uint32_t unknown_tlv;
+ uint32_t unknown_msg;
};
+struct ldp_entity_stats {
+ uint32_t session_attempts;
+ uint32_t session_rejects_hello;
+ uint32_t session_rejects_ad;
+ uint32_t session_rejects_max_pdu;
+ uint32_t session_rejects_lr;
+ uint32_t bad_ldp_id;
+ uint32_t bad_pdu_len;
+ uint32_t bad_msg_len;
+ uint32_t bad_tlv_len;
+ uint32_t malformed_tlv;
+ uint32_t keepalive_timer_exp;
+ uint32_t shutdown_rcv_notify;
+ uint32_t shutdown_send_notify;
+};
+
struct l2vpn_if {
RB_ENTRY(l2vpn_if) entry;
struct l2vpn *l2vpn;
ifindex_t ifindex;
int operative;
uint8_t mac[ETH_ALEN];
- QOBJ_FIELDS
+ QOBJ_FIELDS;
};
RB_HEAD(l2vpn_if_head, l2vpn_if);
RB_PROTOTYPE(l2vpn_if_head, l2vpn_if, entry, l2vpn_if_compare);
-DECLARE_QOBJ_TYPE(l2vpn_if)
+DECLARE_QOBJ_TYPE(l2vpn_if);
struct l2vpn_pw {
RB_ENTRY(l2vpn_pw) entry;
uint32_t remote_status;
uint8_t flags;
uint8_t reason;
- QOBJ_FIELDS
+ QOBJ_FIELDS;
};
RB_HEAD(l2vpn_pw_head, l2vpn_pw);
RB_PROTOTYPE(l2vpn_pw_head, l2vpn_pw, entry, l2vpn_pw_compare);
-DECLARE_QOBJ_TYPE(l2vpn_pw)
+DECLARE_QOBJ_TYPE(l2vpn_pw);
#define F_PW_STATUSTLV_CONF 0x01 /* status tlv configured */
#define F_PW_STATUSTLV 0x02 /* status tlv negotiated */
#define F_PW_CWORD_CONF 0x04 /* control word configured */
struct l2vpn_if_head if_tree;
struct l2vpn_pw_head pw_tree;
struct l2vpn_pw_head pw_inactive_tree;
- QOBJ_FIELDS
+ QOBJ_FIELDS;
};
RB_HEAD(l2vpn_head, l2vpn);
RB_PROTOTYPE(l2vpn_head, l2vpn, entry, l2vpn_compare);
-DECLARE_QOBJ_TYPE(l2vpn)
+DECLARE_QOBJ_TYPE(l2vpn);
#define L2VPN_TYPE_VPWS 1
#define L2VPN_TYPE_VPLS 2
uint16_t wait_for_sync_interval;
int flags;
time_t config_change_time;
- QOBJ_FIELDS
+ struct ldp_entity_stats stats;
+ QOBJ_FIELDS;
};
-DECLARE_QOBJ_TYPE(ldpd_conf)
+DECLARE_QOBJ_TYPE(ldpd_conf);
#define F_LDPD_NO_FIB_UPDATE 0x0001
#define F_LDPD_DS_CISCO_INTEROP 0x0002
#define F_LDPD_ENABLED 0x0004
(__IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_INTFACELOCAL))
#endif
-DECLARE_HOOK(ldp_register_mib, (struct thread_master * tm), (tm))
+DECLARE_HOOK(ldp_register_mib, (struct thread_master * tm), (tm));
extern void ldp_agentx_enabled(void);
void ldpe_l2vpn_pw_init(struct l2vpn_pw *);
void ldpe_l2vpn_pw_exit(struct l2vpn_pw *);
-DECLARE_HOOK(ldp_nbr_state_change, (struct nbr * nbr, int old_state), (nbr, old_state))
+DECLARE_HOOK(ldp_nbr_state_change, (struct nbr * nbr, int old_state),
+ (nbr, old_state));
#endif /* _LDPE_H_ */
#include "lde.h"
#include "log.h"
-DEFINE_HOOK(ldp_nbr_state_change, (struct nbr * nbr, int old_state), (nbr, old_state))
+DEFINE_HOOK(ldp_nbr_state_change, (struct nbr * nbr, int old_state),
+ (nbr, old_state));
static __inline int nbr_id_compare(const struct nbr *, const struct nbr *);
static __inline int nbr_addr_compare(const struct nbr *,
tcp->nbr->stats.notif_sent++;
}
+ /* update SNMP session counters */
+ switch (nm->status_code) {
+ case S_NO_HELLO:
+ leconf->stats.session_rejects_hello++;
+ break;
+ case S_BAD_LDP_ID:
+ leconf->stats.bad_ldp_id++;
+ break;
+ case S_BAD_PDU_LEN:
+ leconf->stats.bad_pdu_len++;
+ break;
+ case S_BAD_MSG_LEN:
+ leconf->stats.bad_msg_len++;
+ break;
+ case S_BAD_TLV_LEN:
+ leconf->stats.bad_tlv_len++;
+ break;
+ case S_BAD_TLV_VAL:
+ leconf->stats.malformed_tlv++;
+ break;
+ case S_KEEPALIVE_TMR:
+ leconf->stats.keepalive_timer_exp++;
+ break;
+ case S_SHUTDOWN:
+ leconf->stats.shutdown_send_notify++;
+ break;
+ default:
+ break;
+ }
+
evbuf_enqueue(&tcp->wbuf, buf);
}
if (len < STATUS_SIZE) {
session_shutdown(nbr, S_BAD_MSG_LEN, msg.id, msg.type);
+ leconf->stats.bad_msg_len++;
return (-1);
}
memcpy(&st, buf, sizeof(st));
if (ntohs(st.length) > STATUS_SIZE - TLV_HDR_SIZE ||
ntohs(st.length) > len - TLV_HDR_SIZE) {
session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
+ leconf->stats.bad_tlv_len++;
return (-1);
}
buf += STATUS_SIZE;
if (len < sizeof(tlv)) {
session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
+ leconf->stats.bad_tlv_len++;
return (-1);
}
tlv_len = ntohs(tlv.length);
if (tlv_len + TLV_HDR_SIZE > len) {
session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
+ leconf->stats.bad_tlv_len++;
return (-1);
}
buf += TLV_HDR_SIZE;
if (tlen != tlv_len) {
session_shutdown(nbr, S_BAD_TLV_VAL,
msg.id, msg.type);
+ leconf->stats.bad_tlv_len++;
return (-1);
}
nm.flags |= F_NOTIF_FEC;
break;
default:
- if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
+ if (!(ntohs(tlv.type) & UNKNOWN_FLAG)) {
+ nbr->stats.unknown_tlv++;
send_notification_rtlvs(nbr, S_UNKNOWN_TLV,
msg.id, msg.type, tlv_type, tlv_len, buf);
+ }
/* ignore unknown tlv */
break;
}
* initialization, it SHOULD transmit a Shutdown message and
* then close the transport connection".
*/
- if (nbr->state != NBR_STA_OPER && nm.status_code == S_SHUTDOWN)
+ if (nbr->state != NBR_STA_OPER &&
+ nm.status_code == S_SHUTDOWN) {
+ leconf->stats.session_attempts++;
send_notification(nbr->tcp, S_SHUTDOWN,
msg.id, msg.type);
+ }
+ leconf->stats.shutdown_rcv_notify++;
nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION);
return (-1);
}
- /* lde needs to know about a few notification messages */
+ /* lde needs to know about a few notification messages
+ * and update SNMP session counters
+ */
switch (nm.status_code) {
case S_PW_STATUS:
case S_ENDOFLIB:
ldpe_imsg_compose_lde(IMSG_NOTIFICATION, nbr->peerid, 0,
&nm, sizeof(nm));
break;
+ case S_NO_HELLO:
+ leconf->stats.session_rejects_hello++;
+ break;
+ case S_PARM_ADV_MODE:
+ leconf->stats.session_rejects_ad++;
+ break;
+ case S_MAX_PDU_LEN:
+ leconf->stats.session_rejects_max_pdu++;
+ break;
+ case S_PARM_L_RANGE:
+ leconf->stats.session_rejects_lr++;
+ break;
+ case S_BAD_LDP_ID:
+ leconf->stats.bad_ldp_id++;
+ break;
+ case S_BAD_PDU_LEN:
+ leconf->stats.bad_pdu_len++;
+ break;
+ case S_BAD_MSG_LEN:
+ leconf->stats.bad_msg_len++;
+ break;
+ case S_BAD_TLV_LEN:
+ leconf->stats.bad_tlv_len++;
+ break;
+ case S_BAD_TLV_VAL:
+ leconf->stats.malformed_tlv++;
+ break;
+ case S_SHUTDOWN:
+ leconf->stats.shutdown_rcv_notify++;
+ break;
default:
break;
}
default:
log_debug("%s: unknown LDP message from nbr %pI4",
__func__, &nbr->id);
- if (!(ntohs(msg->type) & UNKNOWN_FLAG))
+ if (!(ntohs(msg->type) & UNKNOWN_FLAG)) {
+ nbr->stats.unknown_msg++;
send_notification(nbr->tcp,
S_UNKNOWN_MSG, msg->id, msg->type);
+ }
/* ignore the message */
ret = 0;
break;
case NBR_STA_INITIAL:
case NBR_STA_OPENREC:
case NBR_STA_OPENSENT:
+ /* update SNMP session counters during initialization */
+ leconf->stats.session_attempts++;
+ send_notification(nbr->tcp, status, msg_id, msg_type);
+
+ nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION);
+ break;
case NBR_STA_OPER:
send_notification(nbr->tcp, status, msg_id, msg_type);
ldpd_ldpd_LDADD = ldpd/libldp.a lib/libfrr.la $(LIBCAP)
ldpd_ldpd_snmp_la_SOURCES = ldpd/ldp_snmp.c
-ldpd_ldpd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu99
+ldpd_ldpd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu11
ldpd_ldpd_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
ldpd_ldpd_snmp_la_LIBADD = lib/libfrrsnmp.la
#include "lib_errors.h"
#include "xref.h"
-XREF_SETUP()
+XREF_SETUP();
-DEFINE_HOOK(agentx_enabled, (), ())
+DEFINE_HOOK(agentx_enabled, (), ());
static int agentx_enabled = 0;
/* use as:
*
- * PREDECL_ATOMLIST(namelist)
+ * PREDECL_ATOMLIST(namelist);
* struct name {
* struct namelist_item nlitem;
* }
- * DECLARE_ATOMLIST(namelist, struct name, nlitem)
+ * DECLARE_ATOMLIST(namelist, struct name, nlitem);
*/
#define PREDECL_ATOMLIST(prefix) \
struct prefix ## _head { struct atomlist_head ah; }; \
-struct prefix ## _item { struct atomlist_item ai; };
+struct prefix ## _item { struct atomlist_item ai; }; \
+MACRO_REQUIRE_SEMICOLON() /* end */
#define INIT_ATOMLIST(var) { }
assert(prefix ## _count(h) == 0); \
memset(h, 0, sizeof(*h)); \
} \
-/* ... */
+MACRO_REQUIRE_SEMICOLON() /* end */
/* add_head:
* - contention on ->first pointer
#define _PREDECL_ATOMSORT(prefix) \
struct prefix ## _head { struct atomsort_head ah; }; \
-struct prefix ## _item { struct atomsort_item ai; };
+struct prefix ## _item { struct atomsort_item ai; }; \
+MACRO_REQUIRE_SEMICOLON() /* end */
#define INIT_ATOMSORT_UNIQ(var) { }
#define INIT_ATOMSORT_NONUNIQ(var) { }
struct atomsort_item *p = atomsort_pop(&h->ah); \
return p ? container_of(p, type, field.ai) : NULL; \
} \
-/* ... */
+MACRO_REQUIRE_SEMICOLON() /* end */
#define PREDECL_ATOMSORT_UNIQ(prefix) \
_PREDECL_ATOMSORT(prefix)
} \
\
_DECLARE_ATOMSORT(prefix, type, field, \
- prefix ## __cmp, prefix ## __cmp) \
+ prefix ## __cmp, prefix ## __cmp); \
\
atomic_find_warn \
macro_inline type *prefix ## _find(struct prefix##_head *h, const type *item) \
return NULL; \
return p; \
} \
-/* ... */
+MACRO_REQUIRE_SEMICOLON() /* end */
#define PREDECL_ATOMSORT_NONUNIQ(prefix) \
_PREDECL_ATOMSORT(prefix)
} \
\
_DECLARE_ATOMSORT(prefix, type, field, \
- prefix ## __cmp, prefix ## __cmp_uq) \
-/* ... */
+ prefix ## __cmp, prefix ## __cmp_uq); \
+MACRO_REQUIRE_SEMICOLON() /* end */
struct atomsort_item *atomsort_add(struct atomsort_head *h,
struct atomsort_item *item, int (*cmpfn)(
#include "prefix.h"
#include "thread.h"
#include "stream.h"
+#include "vrf.h"
#include "zclient.h"
#include "table.h"
#include "vty.h"
#include "bfd.h"
-DEFINE_MTYPE_STATIC(LIB, BFD_INFO, "BFD info")
+DEFINE_MTYPE_STATIC(LIB, BFD_INFO, "BFD info");
static int bfd_debug = 0;
static struct bfd_gbl bfd_gbl;
return 0;
}
+
+/**
+ * BFD protocol integration configuration.
+ */
+
+/** Events definitions. */
+enum bfd_session_event {
+ /** Remove the BFD session configuration. */
+ BSE_UNINSTALL,
+ /** Install the BFD session configuration. */
+ BSE_INSTALL,
+};
+
+/**
+ * Data structure to do the necessary tricks to hide the BFD protocol
+ * integration internals.
+ */
+struct bfd_session_params {
+ /** Contains the session parameters and more. */
+ struct bfd_session_arg args;
+ /** Contains the session state. */
+ struct bfd_session_status bss;
+ /** Protocol implementation status update callback. */
+ bsp_status_update updatecb;
+ /** Protocol implementation custom data pointer. */
+ void *arg;
+
+ /**
+ * Next event.
+ *
+ * This variable controls what action to execute when the command batch
+ * finishes. Normally we'd use `thread_add_event` value, however since
+ * that function is going to be called multiple times and the value
+ * might be different we'll use this variable to keep track of it.
+ */
+ enum bfd_session_event lastev;
+ /**
+ * BFD session configuration event.
+ *
+ * Multiple actions might be asked during a command batch (either via
+ * configuration load or northbound batch), so we'll use this to
+ * install/uninstall the BFD session parameters only once.
+ */
+ struct thread *installev;
+
+ /** BFD session installation state. */
+ bool installed;
+ /** BFD session enabled. */
+ bool enabled;
+
+ /** Global BFD paramaters list. */
+ TAILQ_ENTRY(bfd_session_params) entry;
+};
+
+struct bfd_sessions_global {
+ /**
+ * Global BFD session parameters list for (re)installation and update
+ * without code duplication among daemons.
+ */
+ TAILQ_HEAD(bsplist, bfd_session_params) bsplist;
+
+ /** Pointer to FRR's event manager. */
+ struct thread_master *tm;
+ /** Pointer to zebra client data structure. */
+ struct zclient *zc;
+
+ /** Debugging state. */
+ bool debugging;
+ /** Is shutting down? */
+ bool shutting_down;
+};
+
+/** Global configuration variable. */
+static struct bfd_sessions_global bsglobal;
+
+/** Global empty address for IPv4/IPv6. */
+static const struct in6_addr i6a_zero;
+
+struct bfd_session_params *bfd_sess_new(bsp_status_update updatecb, void *arg)
+{
+ struct bfd_session_params *bsp;
+
+ bsp = XCALLOC(MTYPE_BFD_INFO, sizeof(*bsp));
+
+ /* Save application data. */
+ bsp->updatecb = updatecb;
+ bsp->arg = arg;
+
+ /* Set defaults. */
+ bsp->args.detection_multiplier = BFD_DEF_DETECT_MULT;
+ bsp->args.ttl = BFD_SINGLE_HOP_TTL;
+ bsp->args.min_rx = BFD_DEF_MIN_RX;
+ bsp->args.min_tx = BFD_DEF_MIN_TX;
+ bsp->args.vrf_id = VRF_DEFAULT;
+
+ /* Register in global list. */
+ TAILQ_INSERT_TAIL(&bsglobal.bsplist, bsp, entry);
+
+ return bsp;
+}
+
+static bool _bfd_sess_valid(const struct bfd_session_params *bsp)
+{
+ /* Peer/local address not configured. */
+ if (bsp->args.family == 0)
+ return false;
+
+ /* Address configured but invalid. */
+ if (bsp->args.family != AF_INET && bsp->args.family != AF_INET6) {
+ if (bsglobal.debugging)
+ zlog_debug("%s: invalid session family: %d", __func__,
+ bsp->args.family);
+ return false;
+ }
+
+ /* Invalid address. */
+ if (memcmp(&bsp->args.dst, &i6a_zero, sizeof(i6a_zero)) == 0) {
+ if (bsglobal.debugging) {
+ if (bsp->args.family == AF_INET)
+ zlog_debug("%s: invalid address: %pI4",
+ __func__,
+ (struct in_addr *)&bsp->args.dst);
+ else
+ zlog_debug("%s: invalid address: %pI6",
+ __func__, &bsp->args.dst);
+ }
+ return false;
+ }
+
+ /* Multi hop requires local address. */
+ if (bsp->args.mhop
+ && memcmp(&i6a_zero, &bsp->args.src, sizeof(i6a_zero)) == 0) {
+ if (bsglobal.debugging)
+ zlog_debug(
+ "%s: multi hop but no local address provided",
+ __func__);
+ return false;
+ }
+
+ /* Check VRF ID. */
+ if (bsp->args.vrf_id == VRF_UNKNOWN) {
+ if (bsglobal.debugging)
+ zlog_debug("%s: asked for unknown VRF", __func__);
+ return false;
+ }
+
+ return true;
+}
+
+static int _bfd_sess_send(struct thread *t)
+{
+ struct bfd_session_params *bsp = THREAD_ARG(t);
+ int rv;
+
+ /* Validate configuration before trying to send bogus data. */
+ if (!_bfd_sess_valid(bsp))
+ return 0;
+
+ if (bsp->lastev == BSE_INSTALL) {
+ bsp->args.command = bsp->installed ? ZEBRA_BFD_DEST_UPDATE
+ : ZEBRA_BFD_DEST_REGISTER;
+ } else
+ bsp->args.command = ZEBRA_BFD_DEST_DEREGISTER;
+
+ /* If not installed and asked for uninstall, do nothing. */
+ if (!bsp->installed && bsp->args.command == ZEBRA_BFD_DEST_DEREGISTER)
+ return 0;
+
+ rv = zclient_bfd_command(bsglobal.zc, &bsp->args);
+ /* Command was sent successfully. */
+ if (rv == 0) {
+ /* Update installation status. */
+ if (bsp->args.command == ZEBRA_BFD_DEST_DEREGISTER)
+ bsp->installed = false;
+ else if (bsp->args.command == ZEBRA_BFD_DEST_REGISTER)
+ bsp->installed = true;
+ }
+
+ return 0;
+}
+
+static void _bfd_sess_remove(struct bfd_session_params *bsp)
+{
+ /* Not installed, nothing to do. */
+ if (!bsp->installed)
+ return;
+
+ /* Cancel any pending installation request. */
+ THREAD_OFF(bsp->installev);
+
+ /* Send request to remove any session. */
+ bsp->lastev = BSE_UNINSTALL;
+ thread_execute(bsglobal.tm, _bfd_sess_send, bsp, 0);
+}
+
+void bfd_sess_free(struct bfd_session_params **bsp)
+{
+ if (*bsp == NULL)
+ return;
+
+ /* Remove any installed session. */
+ _bfd_sess_remove(*bsp);
+
+ /* Remove from global list. */
+ TAILQ_REMOVE(&bsglobal.bsplist, (*bsp), entry);
+
+ /* Free the memory and point to NULL. */
+ XFREE(MTYPE_BFD_INFO, (*bsp));
+}
+
+void bfd_sess_enable(struct bfd_session_params *bsp, bool enable)
+{
+ /* Remove the session when disabling. */
+ if (!enable)
+ _bfd_sess_remove(bsp);
+
+ bsp->enabled = enable;
+}
+
+void bfd_sess_set_ipv4_addrs(struct bfd_session_params *bsp,
+ struct in_addr *src, struct in_addr *dst)
+{
+ /* If already installed, remove the old setting. */
+ _bfd_sess_remove(bsp);
+
+ bsp->args.family = AF_INET;
+
+ /* Clean memory, set zero value and avoid static analyser warnings. */
+ memset(&bsp->args.src, 0, sizeof(bsp->args.src));
+ memset(&bsp->args.dst, 0, sizeof(bsp->args.dst));
+
+ /* Copy the equivalent of IPv4 to arguments structure. */
+ if (src)
+ memcpy(&bsp->args.src, src, sizeof(struct in_addr));
+
+ assert(dst);
+ memcpy(&bsp->args.dst, dst, sizeof(struct in_addr));
+}
+
+void bfd_sess_set_ipv6_addrs(struct bfd_session_params *bsp,
+ struct in6_addr *src, struct in6_addr *dst)
+{
+ /* If already installed, remove the old setting. */
+ _bfd_sess_remove(bsp);
+
+ bsp->args.family = AF_INET6;
+
+ /* Clean memory, set zero value and avoid static analyser warnings. */
+ memset(&bsp->args.src, 0, sizeof(bsp->args.src));
+
+ if (src)
+ bsp->args.src = *src;
+
+ assert(dst);
+ bsp->args.dst = *dst;
+}
+
+void bfd_sess_set_interface(struct bfd_session_params *bsp, const char *ifname)
+{
+ /* If already installed, remove the old setting. */
+ _bfd_sess_remove(bsp);
+
+ if (ifname == NULL) {
+ bsp->args.ifname[0] = 0;
+ bsp->args.ifnamelen = 0;
+ return;
+ }
+
+ if (strlcpy(bsp->args.ifname, ifname, sizeof(bsp->args.ifname))
+ > sizeof(bsp->args.ifname))
+ zlog_warn("%s: interface name truncated: %s", __func__, ifname);
+
+ bsp->args.ifnamelen = strlen(bsp->args.ifname);
+}
+
+void bfd_sess_set_profile(struct bfd_session_params *bsp, const char *profile)
+{
+ if (profile == NULL) {
+ bsp->args.profile[0] = 0;
+ bsp->args.profilelen = 0;
+ return;
+ }
+
+ if (strlcpy(bsp->args.profile, profile, sizeof(bsp->args.profile))
+ > sizeof(bsp->args.profile))
+ zlog_warn("%s: profile name truncated: %s", __func__, profile);
+
+ bsp->args.profilelen = strlen(bsp->args.profile);
+}
+
+void bfd_sess_set_vrf(struct bfd_session_params *bsp, vrf_id_t vrf_id)
+{
+ /* If already installed, remove the old setting. */
+ _bfd_sess_remove(bsp);
+
+ bsp->args.vrf_id = vrf_id;
+}
+
+void bfd_sess_set_mininum_ttl(struct bfd_session_params *bsp, uint8_t min_ttl)
+{
+ assert(min_ttl != 0);
+
+ /* If already installed, remove the old setting. */
+ _bfd_sess_remove(bsp);
+
+ /* Invert TTL value: protocol expects number of hops. */
+ min_ttl = (BFD_SINGLE_HOP_TTL + 1) - min_ttl;
+ bsp->args.ttl = min_ttl;
+ bsp->args.mhop = (min_ttl > 1);
+}
+
+void bfd_sess_set_hop_count(struct bfd_session_params *bsp, uint8_t min_ttl)
+{
+ /* If already installed, remove the old setting. */
+ _bfd_sess_remove(bsp);
+
+ bsp->args.ttl = min_ttl;
+ bsp->args.mhop = (min_ttl > 1);
+}
+
+
+void bfd_sess_set_cbit(struct bfd_session_params *bsp, bool enable)
+{
+ bsp->args.cbit = enable;
+}
+
+void bfd_sess_set_timers(struct bfd_session_params *bsp,
+ uint8_t detection_multiplier, uint32_t min_rx,
+ uint32_t min_tx)
+{
+ bsp->args.detection_multiplier = detection_multiplier;
+ bsp->args.min_rx = min_rx;
+ bsp->args.min_tx = min_tx;
+}
+
+void bfd_sess_install(struct bfd_session_params *bsp)
+{
+ /* Don't attempt to install/update when disabled. */
+ if (!bsp->enabled)
+ return;
+
+ bsp->lastev = BSE_INSTALL;
+ thread_add_event(bsglobal.tm, _bfd_sess_send, bsp, 0, &bsp->installev);
+}
+
+void bfd_sess_uninstall(struct bfd_session_params *bsp)
+{
+ bsp->lastev = BSE_UNINSTALL;
+ thread_add_event(bsglobal.tm, _bfd_sess_send, bsp, 0, &bsp->installev);
+}
+
+enum bfd_session_state bfd_sess_status(const struct bfd_session_params *bsp)
+{
+ return bsp->bss.state;
+}
+
+uint8_t bfd_sess_minimum_ttl(const struct bfd_session_params *bsp)
+{
+ return ((BFD_SINGLE_HOP_TTL + 1) - bsp->args.ttl);
+}
+
+uint8_t bfd_sess_hop_count(const struct bfd_session_params *bsp)
+{
+ return bsp->args.ttl;
+}
+
+const char *bfd_sess_profile(const struct bfd_session_params *bsp)
+{
+ return bsp->args.profilelen ? bsp->args.profile : NULL;
+}
+
+void bfd_sess_addresses(const struct bfd_session_params *bsp, int *family,
+ struct in6_addr *src, struct in6_addr *dst)
+{
+ *family = bsp->args.family;
+ if (src)
+ *src = bsp->args.src;
+ if (dst)
+ *dst = bsp->args.dst;
+}
+
+const char *bfd_sess_interface(const struct bfd_session_params *bsp)
+{
+ if (bsp->args.ifnamelen)
+ return bsp->args.ifname;
+
+ return NULL;
+}
+
+const char *bfd_sess_vrf(const struct bfd_session_params *bsp)
+{
+ return vrf_id_to_name(bsp->args.vrf_id);
+}
+
+vrf_id_t bfd_sess_vrf_id(const struct bfd_session_params *bsp)
+{
+ return bsp->args.vrf_id;
+}
+
+bool bfd_sess_cbit(const struct bfd_session_params *bsp)
+{
+ return bsp->args.cbit;
+}
+
+void bfd_sess_timers(const struct bfd_session_params *bsp,
+ uint8_t *detection_multiplier, uint32_t *min_rx,
+ uint32_t *min_tx)
+{
+ *detection_multiplier = bsp->args.detection_multiplier;
+ *min_rx = bsp->args.min_rx;
+ *min_tx = bsp->args.min_tx;
+}
+
+void bfd_sess_show(struct vty *vty, struct json_object *json,
+ struct bfd_session_params *bsp)
+{
+ json_object *json_bfd = NULL;
+ char time_buf[64];
+
+ /* Show type. */
+ if (json) {
+ json_bfd = json_object_new_object();
+ if (bsp->args.mhop)
+ json_object_string_add(json_bfd, "type", "multi hop");
+ else
+ json_object_string_add(json_bfd, "type", "single hop");
+ } else
+ vty_out(vty, " BFD: Type: %s\n",
+ bsp->args.mhop ? "multi hop" : "single hop");
+
+ /* Show configuration. */
+ if (json) {
+ json_object_int_add(json_bfd, "detectMultiplier",
+ bsp->args.detection_multiplier);
+ json_object_int_add(json_bfd, "rxMinInterval",
+ bsp->args.min_rx);
+ json_object_int_add(json_bfd, "txMinInterval",
+ bsp->args.min_tx);
+ } else {
+ vty_out(vty,
+ " Detect Multiplier: %d, Min Rx interval: %d, Min Tx interval: %d\n",
+ bsp->args.detection_multiplier, bsp->args.min_rx,
+ bsp->args.min_tx);
+ }
+
+ bfd_last_update(bsp->bss.last_event, time_buf, sizeof(time_buf));
+ if (json) {
+ json_object_string_add(json_bfd, "status",
+ bfd_get_status_str(bsp->bss.state));
+ json_object_string_add(json_bfd, "lastUpdate", time_buf);
+ } else
+ vty_out(vty, " Status: %s, Last update: %s\n",
+ bfd_get_status_str(bsp->bss.state), time_buf);
+
+ if (json)
+ json_object_object_add(json, "peerBfdInfo", json_bfd);
+ else
+ vty_out(vty, "\n");
+}
+
+/*
+ * Zebra communication related.
+ */
+
+/**
+ * Callback for reinstallation of all registered BFD sessions.
+ *
+ * Use this as `zclient` `bfd_dest_replay` callback.
+ */
+static int zclient_bfd_session_reply(ZAPI_CALLBACK_ARGS)
+{
+ struct bfd_session_params *bsp;
+
+ /* Do nothing when shutting down. */
+ if (bsglobal.shutting_down)
+ return 0;
+
+ if (bsglobal.debugging)
+ zlog_debug("%s: sending all sessions registered", __func__);
+
+ /* Send the client registration */
+ bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, vrf_id);
+
+ /* Replay all activated peers. */
+ TAILQ_FOREACH (bsp, &bsglobal.bsplist, entry) {
+ /* Skip disabled sessions. */
+ if (!bsp->enabled)
+ continue;
+
+ /* We are reconnecting, so we must send installation. */
+ bsp->installed = false;
+
+ /* Cancel any pending installation request. */
+ THREAD_OFF(bsp->installev);
+
+ /* Ask for installation. */
+ bsp->lastev = BSE_INSTALL;
+ thread_execute(bsglobal.tm, _bfd_sess_send, bsp, 0);
+ }
+
+ return 0;
+}
+
+static int zclient_bfd_session_update(ZAPI_CALLBACK_ARGS)
+{
+ struct bfd_session_params *bsp;
+ size_t sessions_updated = 0;
+ struct interface *ifp;
+ int remote_cbit = false;
+ int state = BFD_STATUS_UNKNOWN;
+ time_t now;
+ size_t addrlen;
+ struct prefix dp;
+ struct prefix sp;
+ char ifstr[128], cbitstr[32];
+
+ /* Do nothing when shutting down. */
+ if (bsglobal.shutting_down)
+ return 0;
+
+ ifp = bfd_get_peer_info(zclient->ibuf, &dp, &sp, &state, &remote_cbit,
+ vrf_id);
+
+ if (bsglobal.debugging) {
+ ifstr[0] = 0;
+ if (ifp)
+ snprintf(ifstr, sizeof(ifstr), " (interface %s)",
+ ifp->name);
+
+ snprintf(cbitstr, sizeof(cbitstr), " (CPI bit %s)",
+ remote_cbit ? "yes" : "no");
+
+ zlog_debug("%s: %pFX -> %pFX%s VRF %s(%u)%s: %s", __func__, &sp,
+ &dp, ifstr, vrf_id_to_name(vrf_id), vrf_id, cbitstr,
+ bfd_get_status_str(state));
+ }
+
+ switch (dp.family) {
+ case AF_INET:
+ addrlen = sizeof(struct in_addr);
+ break;
+ case AF_INET6:
+ addrlen = sizeof(struct in6_addr);
+ break;
+
+ default:
+ /* Unexpected value. */
+ assert(0);
+ break;
+ }
+
+ /* Cache current time to avoid multiple monotime clock calls. */
+ now = monotime(NULL);
+
+ /* Notify all matching sessions about update. */
+ TAILQ_FOREACH (bsp, &bsglobal.bsplist, entry) {
+ /* Skip disabled or not installed entries. */
+ if (!bsp->enabled || !bsp->installed)
+ continue;
+ /* Skip different VRFs. */
+ if (bsp->args.vrf_id != vrf_id)
+ continue;
+ /* Skip different families. */
+ if (bsp->args.family != dp.family)
+ continue;
+ /* Skip different interface. */
+ if (bsp->args.ifnamelen && ifp
+ && strcmp(bsp->args.ifname, ifp->name) != 0)
+ continue;
+ /* Skip non matching destination addresses. */
+ if (memcmp(&bsp->args.dst, &dp.u, addrlen) != 0)
+ continue;
+ /*
+ * Source comparison test:
+ * We will only compare source if BFD daemon provided the
+ * source address and the protocol set a source address in
+ * the configuration otherwise we'll just skip it.
+ */
+ if (sp.family && memcmp(&bsp->args.src, &i6a_zero, addrlen) != 0
+ && memcmp(&sp.u, &i6a_zero, addrlen) != 0
+ && memcmp(&bsp->args.src, &sp.u, addrlen) != 0)
+ continue;
+ /* No session state change. */
+ if ((int)bsp->bss.state == state)
+ continue;
+
+ bsp->bss.last_event = now;
+ bsp->bss.previous_state = bsp->bss.state;
+ bsp->bss.state = state;
+ bsp->bss.remote_cbit = remote_cbit;
+ bsp->updatecb(bsp, &bsp->bss, bsp->arg);
+ sessions_updated++;
+ }
+
+ if (bsglobal.debugging)
+ zlog_debug("%s: sessions updated: %zu", __func__,
+ sessions_updated);
+
+ return 0;
+}
+
+void bfd_protocol_integration_init(struct zclient *zc, struct thread_master *tm)
+{
+ /* Initialize data structure. */
+ TAILQ_INIT(&bsglobal.bsplist);
+
+ /* Copy pointers. */
+ bsglobal.zc = zc;
+ bsglobal.tm = tm;
+
+ /* Install our callbacks. */
+ zc->interface_bfd_dest_update = zclient_bfd_session_update;
+ zc->bfd_dest_replay = zclient_bfd_session_reply;
+
+ /* Send the client registration */
+ bfd_client_sendmsg(zc, ZEBRA_BFD_CLIENT_REGISTER, VRF_DEFAULT);
+}
+
+void bfd_protocol_integration_set_debug(bool enable)
+{
+ bsglobal.debugging = enable;
+}
+
+void bfd_protocol_integration_set_shutdown(bool enable)
+{
+ bsglobal.shutting_down = enable;
+}
+
+bool bfd_protocol_integration_debug(void)
+{
+ return bsglobal.debugging;
+}
+
+bool bfd_protocol_integration_shutting_down(void)
+{
+ return bsglobal.shutting_down;
+}
* BFD new API.
*/
+/* Forward declaration of argument struct. */
+struct bfd_session_params;
+
+/** Session state definitions. */
+enum bfd_session_state {
+ /** Session state is unknown or not initialized. */
+ BSS_UNKNOWN = BFD_STATUS_UNKNOWN,
+ /** Local or remote peer administratively shutdown the session. */
+ BSS_ADMIN_DOWN = BFD_STATUS_ADMIN_DOWN,
+ /** Session is down. */
+ BSS_DOWN = BFD_STATUS_DOWN,
+ /** Session is up and working correctly. */
+ BSS_UP = BFD_STATUS_UP,
+};
+
+/** BFD session status information */
+struct bfd_session_status {
+ /** Current session state. */
+ enum bfd_session_state state;
+ /** Previous session state. */
+ enum bfd_session_state previous_state;
+ /** Remote Control Plane Independent bit state. */
+ bool remote_cbit;
+ /** Last event occurrence. */
+ time_t last_event;
+};
+
+/**
+ * Session status update callback.
+ *
+ * \param bsp BFD session parameters.
+ * \param bss BFD session status.
+ * \param arg application independent data.
+ */
+typedef void (*bsp_status_update)(struct bfd_session_params *bsp,
+ const struct bfd_session_status *bss,
+ void *arg);
+
+/**
+ * Allocates and initializes the session parameters.
+ *
+ * \param updatedb status update notification callback.
+ * \param args application independent data.
+ *
+ * \returns pointer to configuration storage.
+ */
+struct bfd_session_params *bfd_sess_new(bsp_status_update updatecb, void *args);
+
+/**
+ * Uninstall session if installed and free resources allocated by the
+ * parameters. Already sets pointer to `NULL` to avoid dangling references.
+ *
+ * \param bsp session parameters.
+ */
+void bfd_sess_free(struct bfd_session_params **bsp);
+
+/**
+ * Enable/disable session installation.
+ *
+ * \param bsp session parameters.
+ * \param enable knob variable.
+ */
+void bfd_sess_enable(struct bfd_session_params *bsp, bool enable);
+
+/**
+ * Set the local and peer address of the BFD session.
+ *
+ * \param bsp BFD session parameters.
+ * \param src local address (optional, can be `NULL`).
+ * \param dst remote address (mandatory).
+ */
+void bfd_sess_set_ipv4_addrs(struct bfd_session_params *bsp,
+ struct in_addr *src, struct in_addr *dst);
+
+/**
+ * Set the local and peer address of the BFD session.
+ *
+ * \param bsp BFD session parameters.
+ * \param src local address (optional, can be `NULL`).
+ * \param dst remote address (mandatory).
+ */
+void bfd_sess_set_ipv6_addrs(struct bfd_session_params *bsp,
+ struct in6_addr *src, struct in6_addr *dst);
+
+/**
+ * Configure the BFD session interface.
+ *
+ * \param bsp BFD session parameters.
+ * \param ifname interface name (or `NULL` to remove it).
+ */
+void bfd_sess_set_interface(struct bfd_session_params *bsp, const char *ifname);
+
+/**
+ * Configure the BFD session profile name.
+ *
+ * \param bsp BFD session parameters.
+ * \param profile profile name (or `NULL` to remove it).
+ */
+void bfd_sess_set_profile(struct bfd_session_params *bsp, const char *profile);
+
+/**
+ * Configure the BFD session VRF.
+ *
+ * \param bsp BFD session parameters.
+ * \param vrf_id the VRF identification number.
+ */
+void bfd_sess_set_vrf(struct bfd_session_params *bsp, vrf_id_t vrf_id);
+
+/**
+ * Configure the BFD session single/multi hop setting.
+ *
+ * \param bsp BFD session parameters.
+ * \param min_ttl minimum TTL value expected (255 for single hop, 254 for
+ * multi hop with single hop, 253 for multi hop with two hops
+ * and so on). See `BFD_SINGLE_HOP_TTL` and
+ * `BFD_MULTI_HOP_MIN_TTL` for defaults.
+ *
+ * To simplify things if your protocol only knows the amount of hops it is
+ * better to use `bfd_sess_set_hops` instead.
+ */
+void bfd_sess_set_mininum_ttl(struct bfd_session_params *bsp, uint8_t min_ttl);
+
+/** To use single hop the minimum TTL must be set to this. */
+#define BFD_SINGLE_HOP_TTL 255
+/** To use multi hop the minimum TTL must be set to this or less. */
+#define BFD_MULTI_HOP_MIN_TTL 254
+
+/**
+ * This function is the inverted version of `bfd_sess_set_minimum_ttl`.
+ * Instead of receiving the minimum expected TTL, it receives the amount of
+ * hops the protocol will jump.
+ *
+ * \param bsp BFD session parameters.
+ * \param min_ttl minimum amount of hops expected (1 for single hop, 2 or
+ * more for multi hop).
+ */
+void bfd_sess_set_hop_count(struct bfd_session_params *bsp, uint8_t min_ttl);
+
+/**
+ * Configure the BFD session to set the Control Plane Independent bit.
+ *
+ * \param bsp BFD session parameters.
+ * \param enable BFD Control Plane Independent state.
+ */
+void bfd_sess_set_cbit(struct bfd_session_params *bsp, bool enable);
+
+/**
+ * DEPRECATED: please avoid using timers directly and use profiles instead.
+ *
+ * Configures the BFD session timers to use. This is specially useful with
+ * `ptm-bfd` which does not support timers.
+ *
+ * \param bsp BFD session parameters.
+ * \param detection_multiplier the detection multiplier value.
+ * \param min_rx minimum required receive period.
+ * \param min_tx minimum required transmission period.
+ */
+void bfd_sess_set_timers(struct bfd_session_params *bsp,
+ uint8_t detection_multiplier, uint32_t min_rx,
+ uint32_t min_tx);
+
+/**
+ * Installs or updates the BFD session based on the saved session arguments.
+ *
+ * \param bsp session parameters.
+ */
+void bfd_sess_install(struct bfd_session_params *bsp);
+
+/**
+ * Uninstall the BFD session based on the saved session arguments.
+ *
+ * \param bsp session parameters.
+ */
+void bfd_sess_uninstall(struct bfd_session_params *bsp);
+
+/**
+ * Get BFD session current status.
+ *
+ * \param bsp session parameters.
+ *
+ * \returns BFD session status data structure.
+ */
+enum bfd_session_state bfd_sess_status(const struct bfd_session_params *bsp);
+
+/**
+ * Get BFD session minimum TTL configured value.
+ *
+ * \param bsp session parameters.
+ *
+ * \returns configured minimum TTL.
+ */
+uint8_t bfd_sess_minimum_ttl(const struct bfd_session_params *bsp);
+
+/**
+ * Inverted version of `bfd_sess_minimum_ttl`. Gets the amount of hops in the
+ * way to the peer.
+ *
+ * \param bsp session parameters.
+ *
+ * \returns configured amount of hops.
+ */
+uint8_t bfd_sess_hop_count(const struct bfd_session_params *bsp);
+
+/**
+ * Get BFD session profile configured value.
+ *
+ * \param bsp session parameters.
+ *
+ * \returns configured profile name (or `NULL` if empty).
+ */
+const char *bfd_sess_profile(const struct bfd_session_params *bsp);
+
+/**
+ * Get BFD session addresses.
+ *
+ * \param bsp session parameters.
+ * \param family the address family being used (AF_INET or AF_INET6).
+ * \param src source address (optional, may be `NULL`).
+ * \param dst peer address (optional, may be `NULL`).
+ */
+void bfd_sess_addresses(const struct bfd_session_params *bsp, int *family,
+ struct in6_addr *src, struct in6_addr *dst);
+/**
+ * Get BFD session interface name.
+ *
+ * \param bsp session parameters.
+ *
+ * \returns `NULL` if not set otherwise the interface name.
+ */
+const char *bfd_sess_interface(const struct bfd_session_params *bsp);
+
+/**
+ * Get BFD session VRF name.
+ *
+ * \param bsp session parameters.
+ *
+ * \returns the VRF name.
+ */
+const char *bfd_sess_vrf(const struct bfd_session_params *bsp);
+
+/**
+ * Get BFD session VRF ID.
+ *
+ * \param bsp session parameters.
+ *
+ * \returns the VRF name.
+ */
+vrf_id_t bfd_sess_vrf_id(const struct bfd_session_params *bsp);
+
+/**
+ * Get BFD session control plane independent bit configuration state.
+ *
+ * \param bsp session parameters.
+ *
+ * \returns `true` if enabled otherwise `false`.
+ */
+bool bfd_sess_cbit(const struct bfd_session_params *bsp);
+
+/**
+ * DEPRECATED: please avoid using timers directly and use profiles instead.
+ *
+ * Gets the configured timers.
+ *
+ * \param bsp BFD session parameters.
+ * \param detection_multiplier the detection multiplier value.
+ * \param min_rx minimum required receive period.
+ * \param min_tx minimum required transmission period.
+ */
+void bfd_sess_timers(const struct bfd_session_params *bsp,
+ uint8_t *detection_multiplier, uint32_t *min_rx,
+ uint32_t *min_tx);
+
+/**
+ * Show BFD session configuration and status. If `json` is provided (e.g. not
+ * `NULL`) then information will be inserted in object, otherwise printed to
+ * `vty`.
+ *
+ * \param vty Pointer to `vty` for outputting text.
+ * \param json (optional) JSON object pointer.
+ * \param bsp session parameters.
+ */
+void bfd_sess_show(struct vty *vty, struct json_object *json,
+ struct bfd_session_params *bsp);
+
+/**
+ * Initializes the BFD integration library. This function executes the
+ * following actions:
+ *
+ * - Copy the `struct thread_master` pointer to use as "thread" to execute
+ * the BFD session parameters installation.
+ * - Copy the `struct zclient` pointer to install its callbacks.
+ * - Initializes internal data structures.
+ *
+ * \param tm normally the daemon main thread event manager.
+ * \param zc the zebra client of the daemon.
+ */
+void bfd_protocol_integration_init(struct zclient *zc,
+ struct thread_master *tm);
+
/**
* BFD session registration arguments.
*/
*/
extern int zclient_bfd_command(struct zclient *zc, struct bfd_session_arg *arg);
+/**
+ * Enables or disables BFD protocol integration API debugging.
+ *
+ * \param enable new API debug state.
+ */
+extern void bfd_protocol_integration_set_debug(bool enable);
+
+/**
+ * Sets shutdown mode so no more events are processed.
+ *
+ * This is useful to avoid the event storm that happens caused by network,
+ * interfaces or VRFs removal. It should also avoid some crashes due hanging
+ * pointers left overs by protocol.
+ *
+ * \param enable new API shutdown state.
+ */
+extern void bfd_protocol_integration_set_shutdown(bool enable);
+
+/**
+ * Get API debugging state.
+ */
+extern bool bfd_protocol_integration_debug(void);
+
+/**
+ * Get API shutdown state.
+ */
+extern bool bfd_protocol_integration_shutting_down(void);
+
#ifdef __cplusplus
}
#endif
#include <stddef.h>
-DEFINE_MTYPE_STATIC(LIB, BUFFER, "Buffer")
-DEFINE_MTYPE_STATIC(LIB, BUFFER_DATA, "Buffer data")
+DEFINE_MTYPE_STATIC(LIB, BUFFER, "Buffer");
+DEFINE_MTYPE_STATIC(LIB, BUFFER_DATA, "Buffer data");
/* Buffer master. */
struct buffer {
#include "frrscript.h"
-DEFINE_MTYPE_STATIC(LIB, HOST, "Host config")
-DEFINE_MTYPE(LIB, COMPLETION, "Completion item")
+DEFINE_MTYPE_STATIC(LIB, HOST, "Host config");
+DEFINE_MTYPE(LIB, COMPLETION, "Completion item");
#define item(x) \
{ \
extern "C" {
#endif
-DECLARE_MTYPE(COMPLETION)
+DECLARE_MTYPE(COMPLETION);
/*
* From RFC 1123 (Requirements for Internet Hosts), Section 2.1 on hostnames:
#include "command_graph.h"
-DEFINE_MTYPE_STATIC(LIB, CMD_TOKENS, "Command Tokens")
-DEFINE_MTYPE_STATIC(LIB, CMD_DESC, "Command Token Text")
-DEFINE_MTYPE_STATIC(LIB, CMD_TEXT, "Command Token Help")
-DEFINE_MTYPE(LIB, CMD_ARG, "Command Argument")
-DEFINE_MTYPE_STATIC(LIB, CMD_VAR, "Command Argument Name")
+DEFINE_MTYPE_STATIC(LIB, CMD_TOKENS, "Command Tokens");
+DEFINE_MTYPE_STATIC(LIB, CMD_DESC, "Command Token Text");
+DEFINE_MTYPE_STATIC(LIB, CMD_TEXT, "Command Token Help");
+DEFINE_MTYPE(LIB, CMD_ARG, "Command Argument");
+DEFINE_MTYPE_STATIC(LIB, CMD_VAR, "Command Argument Name");
struct cmd_token *cmd_token_new(enum cmd_token_type type, uint8_t attr,
const char *text, const char *desc)
extern "C" {
#endif
-DECLARE_MTYPE(CMD_ARG)
+DECLARE_MTYPE(CMD_ARG);
struct vty;
#include "command_match.h"
#include "memory.h"
-DEFINE_MTYPE_STATIC(LIB, CMD_MATCHSTACK, "Command Match Stack")
+DEFINE_MTYPE_STATIC(LIB, CMD_MATCHSTACK, "Command Match Stack");
#ifdef TRACE_MATCHER
#define TM 1
#include "command_graph.h"
#include "log.h"
- DECLARE_MTYPE(LEX)
+ DECLARE_MTYPE(LEX);
#define YYSTYPE CMD_YYSTYPE
#define YYLTYPE CMD_YYLTYPE
#undef scanner
-DEFINE_MTYPE(LIB, LEX, "Lexer token (temporary)")
+DEFINE_MTYPE(LIB, LEX, "Lexer token (temporary)");
void
cmd_graph_parse (struct graph *graph, const struct cmd_element *cmd)
extern "C" {
#endif
+#ifdef __cplusplus
+# if __cplusplus < 201103L
+# error FRRouting headers must be compiled in C++11 mode or newer
+# endif
+/* C++ defines static_assert(), but not _Static_assert(). C defines
+ * _Static_assert() and has static_assert() in <assert.h>. However, we mess
+ * with assert() in zassert.h so let's not include <assert.h> here.
+ */
+# define _Static_assert static_assert
+#else
+# if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 201112L
+# error FRRouting must be compiled with min. -std=gnu11 (GNU ISO C11 dialect)
+# endif
+#endif
+
/* function attributes, use like
* void prototype(void) __attribute__((_CONSTRUCTOR(100)));
*/
#define macro_inline static inline __attribute__((unused))
#define macro_pure static inline __attribute__((unused, pure))
+/* if the macro ends with a function definition */
+#define MACRO_REQUIRE_SEMICOLON() \
+ _Static_assert(1, "please add a semicolon after this macro")
+
+#if CONFDATE < 20210601
+#ifdef ENABLE_BGP_VNC
+/* temporarily disabled for transition for LabN CI
+ * NB: it's not possible to generate a deprecation warning for this, hence
+ * the shortened transition period (since otherwise new uses of the old syntax
+ * may creep in without errors)
+ */
+#undef MACRO_REQUIRE_SEMICOLON
+#define MACRO_REQUIRE_SEMICOLON() \
+ /* nothing */
+#endif /* ENABLE_BGP_VNC */
+#else /* CONFDATE >= 20210601 */
+CPP_NOTICE("time to remove this CONFDATE block")
+#endif
/* variadic macros, use like:
* #define V_0() ...
/* if this breaks, 128-bit machines may have entered reality (or <long long>
* is something weird)
*/
-#if __STDC_VERSION__ >= 201112L
_Static_assert(sizeof(_uint64_t) == 8 && sizeof(_int64_t) == 8,
"nobody expects the spanish intquisition");
-#endif
/* since we redefined int64_t, we also need to redefine PRI*64 */
#undef PRIu64
static struct debug_cb_list_head cb_head;
-DECLARE_LIST(debug_cb_list, struct debug_callbacks, item)
+DECLARE_LIST(debug_cb_list, struct debug_callbacks, item);
/* All code in this section should be reentrant and MT-safe */
const char *desc;
};
-PREDECL_LIST(debug_cb_list)
+PREDECL_LIST(debug_cb_list);
/*
* Callback set for debugging code.
*
static void _dfltinit_##varname(void) \
{ \
frr_default_add(&_dflt_##varname); \
- }
+ } \
+ MACRO_REQUIRE_SEMICOLON() /* end */
/* use:
* FRR_CFG_DEFAULT_LONG(SHARP_BLUNTNESS,
#include "distribute.h"
#include "memory.h"
-DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE_CTX, "Distribute ctx")
-DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE, "Distribute list")
-DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE_IFNAME, "Dist-list ifname")
-DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE_NAME, "Dist-list name")
+DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE_CTX, "Distribute ctx");
+DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE, "Distribute list");
+DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE_IFNAME, "Dist-list ifname");
+DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE_NAME, "Dist-list name");
static struct list *dist_ctx_list;
struct elfreloc;
struct elfsect;
-PREDECL_HASH(elfrelocs)
+PREDECL_HASH(elfrelocs);
/* ELFFile and ELFSection intentionally share some behaviour, particularly
* subscript[123:456] access to file data. This is because relocatables
static uint32_t elfreloc_hash(const struct elfreloc *reloc);
DECLARE_HASH(elfrelocs, struct elfreloc, elfrelocs_item,
- elfreloc_cmp, elfreloc_hash)
+ elfreloc_cmp, elfreloc_hash);
static Elf_Scn *elf_find_addr(struct elffile *ef, uint64_t addr, size_t *idx);
static PyObject *elffile_secbyidx(struct elffile *w, Elf_Scn *scn, size_t idx);
#include "linklist.h"
#include "frr_pthread.h"
-DEFINE_MTYPE_STATIC(LIB, ERRINFO, "error information")
+DEFINE_MTYPE_STATIC(LIB, ERRINFO, "error information");
/*
* Thread-specific key for temporary storage of allocated ferr.
#include "libfrr.h"
#include "northbound_cli.h"
-DEFINE_MTYPE_STATIC(LIB, ACCESS_LIST, "Access List")
-DEFINE_MTYPE_STATIC(LIB, ACCESS_LIST_STR, "Access List Str")
-DEFINE_MTYPE_STATIC(LIB, ACCESS_FILTER, "Access Filter")
+DEFINE_MTYPE_STATIC(LIB, ACCESS_LIST, "Access List");
+DEFINE_MTYPE_STATIC(LIB, ACCESS_LIST_STR, "Access List Str");
+DEFINE_MTYPE_STATIC(LIB, ACCESS_FILTER, "Access Filter");
/* Static structure for mac access_list's master. */
static struct access_master access_master_mac = {
ple->le = 0;
}
+static int
+prefix_list_nb_validate_v4_af_type(const struct lyd_node *plist_dnode,
+ char *errmsg, size_t errmsg_len)
+{
+ int af_type;
+
+ af_type = yang_dnode_get_enum(plist_dnode, "./type");
+ if (af_type != YPLT_IPV4) {
+ snprintf(errmsg, errmsg_len,
+ "prefix-list type %u is mismatched.", af_type);
+ return NB_ERR_VALIDATION;
+ }
+
+ return NB_OK;
+}
+
+static int
+prefix_list_nb_validate_v6_af_type(const struct lyd_node *plist_dnode,
+ char *errmsg, size_t errmsg_len)
+{
+ int af_type;
+
+ af_type = yang_dnode_get_enum(plist_dnode, "./type");
+ if (af_type != YPLT_IPV6) {
+ snprintf(errmsg, errmsg_len,
+ "prefix-list type %u is mismatched.", af_type);
+ return NB_ERR_VALIDATION;
+ }
+
+ return NB_OK;
+}
+
+static int lib_prefix_list_entry_prefix_length_lesser_or_equal_modify(
+ struct nb_cb_modify_args *args)
+{
+ struct prefix_list_entry *ple;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ ple = nb_running_get_entry(args->dnode, NULL, true);
+
+ /* Start prefix entry update procedure. */
+ prefix_list_entry_update_start(ple);
+
+ ple->le = yang_dnode_get_uint8(args->dnode, NULL);
+
+ /* Finish prefix entry update procedure. */
+ prefix_list_entry_update_finish(ple);
+
+ return NB_OK;
+}
+
+static int lib_prefix_list_entry_prefix_length_greater_or_equal_destroy(
+ struct nb_cb_destroy_args *args)
+{
+ struct prefix_list_entry *ple;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ ple = nb_running_get_entry(args->dnode, NULL, true);
+
+ /* Start prefix entry update procedure. */
+ prefix_list_entry_update_start(ple);
+
+ ple->ge = 0;
+
+ /* Finish prefix entry update procedure. */
+ prefix_list_entry_update_finish(ple);
+
+ return NB_OK;
+}
+
+static int lib_prefix_list_entry_prefix_length_lesser_or_equal_destroy(
+ struct nb_cb_destroy_args *args)
+{
+ struct prefix_list_entry *ple;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ ple = nb_running_get_entry(args->dnode, NULL, true);
+
+ /* Start prefix entry update procedure. */
+ prefix_list_entry_update_start(ple);
+
+ ple->le = 0;
+
+ /* Finish prefix entry update procedure. */
+ prefix_list_entry_update_finish(ple);
+
+ return NB_OK;
+}
+
/**
* Unsets the cisco style rule for addresses so it becomes disabled (the
* equivalent of setting: `0.0.0.0/32`).
return pda->pda_found;
}
-static bool plist_is_dup_nb(const struct lyd_node *dnode)
-{
- const struct lyd_node *entry_dnode =
- yang_dnode_get_parent(dnode, "entry");
- struct plist_dup_args pda = {};
- int idx = 0, arg_idx = 0;
- static const char *entries[] = {
- "./ipv4-prefix",
- "./ipv4-prefix-length-greater-or-equal",
- "./ipv4-prefix-length-lesser-or-equal",
- "./ipv6-prefix",
- "./ipv6-prefix-length-greater-or-equal",
- "./ipv6-prefix-length-lesser-or-equal",
- "./any",
- NULL
- };
-
- /* Initialize. */
- pda.pda_type = yang_dnode_get_string(entry_dnode, "../type");
- pda.pda_name = yang_dnode_get_string(entry_dnode, "../name");
- pda.pda_entry_dnode = entry_dnode;
-
- /* Load all values/XPaths. */
- while (entries[idx] != NULL) {
- if (!yang_dnode_exists(entry_dnode, entries[idx])) {
- idx++;
- continue;
- }
-
- pda.pda_xpath[arg_idx] = entries[idx];
- pda.pda_value[arg_idx] =
- yang_dnode_get_string(entry_dnode, entries[idx]);
- arg_idx++;
- idx++;
- }
-
- return plist_is_dup(entry_dnode, &pda);
-}
-
/*
* XPath: /frr-filter:lib/access-list
*/
return NB_OK;
}
-/*
- * XPath: /frr-filter:lib/prefix-list/entry/ipv4-prefix
- */
-static int
-lib_prefix_list_entry_ipv4_prefix_modify(struct nb_cb_modify_args *args)
+static int lib_prefix_list_entry_prefix_modify(struct nb_cb_modify_args *args)
{
struct prefix_list_entry *ple;
struct prefix p;
- if (args->event == NB_EV_VALIDATE) {
- if (plist_is_dup_nb(args->dnode)) {
- snprintf(args->errmsg, args->errmsg_len,
- "duplicated prefix list value: %s",
- yang_dnode_get_string(args->dnode, NULL));
- return NB_ERR_VALIDATION;
- }
- return NB_OK;
- }
-
if (args->event != NB_EV_APPLY)
return NB_OK;
return NB_OK;
}
-static int
-lib_prefix_list_entry_ipv4_prefix_destroy(struct nb_cb_destroy_args *args)
+static int lib_prefix_list_entry_prefix_destroy(struct nb_cb_destroy_args *args)
{
struct prefix_list_entry *ple;
return NB_OK;
}
+/*
+ * XPath: /frr-filter:lib/prefix-list/entry/ipv4-prefix
+ */
+static int
+lib_prefix_list_entry_ipv4_prefix_modify(struct nb_cb_modify_args *args)
+{
+ if (args->event == NB_EV_VALIDATE) {
+ const struct lyd_node *plist_dnode =
+ yang_dnode_get_parent(args->dnode, "prefix-list");
+
+ return prefix_list_nb_validate_v4_af_type(
+ plist_dnode, args->errmsg, args->errmsg_len);
+ }
+
+ return lib_prefix_list_entry_prefix_modify(args);
+}
+
+static int
+lib_prefix_list_entry_ipv4_prefix_destroy(struct nb_cb_destroy_args *args)
+{
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ return lib_prefix_list_entry_prefix_destroy(args);
+}
+
+/*
+ * XPath: /frr-filter:lib/prefix-list/entry/ipv6-prefix
+ */
+static int
+lib_prefix_list_entry_ipv6_prefix_modify(struct nb_cb_modify_args *args)
+{
+
+ if (args->event == NB_EV_VALIDATE) {
+ const struct lyd_node *plist_dnode =
+ yang_dnode_get_parent(args->dnode, "prefix-list");
+
+ return prefix_list_nb_validate_v6_af_type(
+ plist_dnode, args->errmsg, args->errmsg_len);
+ }
+
+ return lib_prefix_list_entry_prefix_modify(args);
+}
+
+static int
+lib_prefix_list_entry_ipv6_prefix_destroy(struct nb_cb_destroy_args *args)
+{
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ return lib_prefix_list_entry_prefix_destroy(args);
+}
+
/*
* XPath: /frr-filter:lib/prefix-list/entry/ipv4-prefix-length-greater-or-equal
*/
prefix_list_length_validate(args) != NB_OK)
return NB_ERR_VALIDATION;
- if (args->event == NB_EV_VALIDATE) {
- if (plist_is_dup_nb(args->dnode)) {
- snprintf(args->errmsg, args->errmsg_len,
- "duplicated prefix list value: %s",
- yang_dnode_get_string(args->dnode, NULL));
- return NB_ERR_VALIDATION;
- }
- return NB_OK;
- }
-
if (args->event != NB_EV_APPLY)
return NB_OK;
static int lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_destroy(
struct nb_cb_destroy_args *args)
{
- struct prefix_list_entry *ple;
+ if (args->event == NB_EV_VALIDATE) {
+ const struct lyd_node *plist_dnode =
+ yang_dnode_get_parent(args->dnode, "prefix-list");
- if (args->event != NB_EV_APPLY)
- return NB_OK;
+ return prefix_list_nb_validate_v4_af_type(
+ plist_dnode, args->errmsg, args->errmsg_len);
+ }
- ple = nb_running_get_entry(args->dnode, NULL, true);
+ return lib_prefix_list_entry_prefix_length_greater_or_equal_destroy(
+ args);
+}
- /* Start prefix entry update procedure. */
- prefix_list_entry_update_start(ple);
+/*
+ * XPath: /frr-filter:lib/prefix-list/entry/ipv4-prefix-length-lesser-or-equal
+ */
+static int lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_modify(
+ struct nb_cb_modify_args *args)
+{
+ if (args->event == NB_EV_VALIDATE
+ && prefix_list_length_validate(args) != NB_OK)
+ return NB_ERR_VALIDATION;
- ple->ge = 0;
+ if (args->event == NB_EV_VALIDATE) {
+ const struct lyd_node *plist_dnode =
+ yang_dnode_get_parent(args->dnode, "prefix-list");
- /* Finish prefix entry update procedure. */
- prefix_list_entry_update_finish(ple);
+ return prefix_list_nb_validate_v4_af_type(
+ plist_dnode, args->errmsg, args->errmsg_len);
+ }
- return NB_OK;
+ return lib_prefix_list_entry_prefix_length_lesser_or_equal_modify(args);
+}
+
+static int lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_destroy(
+ struct nb_cb_destroy_args *args)
+{
+ if (args->event == NB_EV_VALIDATE) {
+ const struct lyd_node *plist_dnode =
+ yang_dnode_get_parent(args->dnode, "prefix-list");
+
+ return prefix_list_nb_validate_v4_af_type(
+ plist_dnode, args->errmsg, args->errmsg_len);
+ }
+
+ return lib_prefix_list_entry_prefix_length_lesser_or_equal_destroy(
+ args);
}
/*
- * XPath: /frr-filter:lib/prefix-list/entry/ipv4-prefix-length-lesser-or-equal
+ * XPath: /frr-filter:lib/prefix-list/entry/ipv6-prefix-length-greater-or-equal
*/
-static int lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_modify(
+static int lib_prefix_list_entry_ipv6_prefix_length_greater_or_equal_modify(
struct nb_cb_modify_args *args)
{
struct prefix_list_entry *ple;
- if (args->event == NB_EV_VALIDATE &&
- prefix_list_length_validate(args) != NB_OK)
+ if (args->event == NB_EV_VALIDATE
+ && prefix_list_length_validate(args) != NB_OK)
return NB_ERR_VALIDATION;
if (args->event == NB_EV_VALIDATE) {
- if (plist_is_dup_nb(args->dnode)) {
- snprintf(args->errmsg, args->errmsg_len,
- "duplicated prefix list value: %s",
- yang_dnode_get_string(args->dnode, NULL));
- return NB_ERR_VALIDATION;
- }
- return NB_OK;
+ const struct lyd_node *plist_dnode =
+ yang_dnode_get_parent(args->dnode, "prefix-list");
+
+ return prefix_list_nb_validate_v6_af_type(
+ plist_dnode, args->errmsg, args->errmsg_len);
}
if (args->event != NB_EV_APPLY)
/* Start prefix entry update procedure. */
prefix_list_entry_update_start(ple);
- ple->le = yang_dnode_get_uint8(args->dnode, NULL);
+ ple->ge = yang_dnode_get_uint8(args->dnode, NULL);
/* Finish prefix entry update procedure. */
prefix_list_entry_update_finish(ple);
return NB_OK;
}
-static int lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_destroy(
+static int lib_prefix_list_entry_ipv6_prefix_length_greater_or_equal_destroy(
struct nb_cb_destroy_args *args)
{
- struct prefix_list_entry *ple;
+ if (args->event == NB_EV_VALIDATE) {
+ const struct lyd_node *plist_dnode =
+ yang_dnode_get_parent(args->dnode, "prefix-list");
- if (args->event != NB_EV_APPLY)
- return NB_OK;
+ return prefix_list_nb_validate_v6_af_type(
+ plist_dnode, args->errmsg, args->errmsg_len);
+ }
- ple = nb_running_get_entry(args->dnode, NULL, true);
+ return lib_prefix_list_entry_prefix_length_greater_or_equal_destroy(
+ args);
+}
- /* Start prefix entry update procedure. */
- prefix_list_entry_update_start(ple);
+/*
+ * XPath: /frr-filter:lib/prefix-list/entry/ipv6-prefix-length-lesser-or-equal
+ */
+static int lib_prefix_list_entry_ipv6_prefix_length_lesser_or_equal_modify(
+ struct nb_cb_modify_args *args)
+{
+ if (args->event == NB_EV_VALIDATE
+ && prefix_list_length_validate(args) != NB_OK)
+ return NB_ERR_VALIDATION;
- ple->le = 0;
+ if (args->event == NB_EV_VALIDATE) {
+ const struct lyd_node *plist_dnode =
+ yang_dnode_get_parent(args->dnode, "prefix-list");
- /* Finish prefix entry update procedure. */
- prefix_list_entry_update_finish(ple);
+ return prefix_list_nb_validate_v6_af_type(
+ plist_dnode, args->errmsg, args->errmsg_len);
+ }
- return NB_OK;
+ return lib_prefix_list_entry_prefix_length_lesser_or_equal_modify(args);
}
-/*
- * XPath: /frr-filter:lib/prefix-list/entry/any
- */
-static int lib_prefix_list_entry_any_create(struct nb_cb_create_args *args)
+static int lib_prefix_list_entry_ipv6_prefix_length_lesser_or_equal_destroy(
+ struct nb_cb_destroy_args *args)
{
- struct prefix_list_entry *ple;
- int type;
+ int af_type;
if (args->event == NB_EV_VALIDATE) {
- if (plist_is_dup_nb(args->dnode)) {
+ const struct lyd_node *plist_dnode =
+ yang_dnode_get_parent(args->dnode, "prefix-list");
+ af_type = yang_dnode_get_enum(plist_dnode, "./type");
+ if (af_type != YPLT_IPV6) {
snprintf(args->errmsg, args->errmsg_len,
- "duplicated prefix list value: %s",
- yang_dnode_get_string(args->dnode, NULL));
+ "prefix-list type %u is mismatched.", af_type);
return NB_ERR_VALIDATION;
}
return NB_OK;
}
+ return lib_prefix_list_entry_prefix_length_lesser_or_equal_destroy(
+ args);
+}
+
+/*
+ * XPath: /frr-filter:lib/prefix-list/entry/any
+ */
+static int lib_prefix_list_entry_any_create(struct nb_cb_create_args *args)
+{
+ struct prefix_list_entry *ple;
+ int type;
+
if (args->event != NB_EV_APPLY)
return NB_OK;
{
.xpath = "/frr-filter:lib/prefix-list/entry/ipv6-prefix",
.cbs = {
- .modify = lib_prefix_list_entry_ipv4_prefix_modify,
- .destroy = lib_prefix_list_entry_ipv4_prefix_destroy,
+ .modify = lib_prefix_list_entry_ipv6_prefix_modify,
+ .destroy = lib_prefix_list_entry_ipv6_prefix_destroy,
}
},
{
.xpath = "/frr-filter:lib/prefix-list/entry/ipv6-prefix-length-greater-or-equal",
.cbs = {
- .modify = lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_modify,
- .destroy = lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_destroy,
+ .modify = lib_prefix_list_entry_ipv6_prefix_length_greater_or_equal_modify,
+ .destroy = lib_prefix_list_entry_ipv6_prefix_length_greater_or_equal_destroy,
}
},
{
.xpath = "/frr-filter:lib/prefix-list/entry/ipv6-prefix-length-lesser-or-equal",
.cbs = {
- .modify = lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_modify,
- .destroy = lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_destroy,
+ .modify = lib_prefix_list_entry_ipv6_prefix_length_lesser_or_equal_modify,
+ .destroy = lib_prefix_list_entry_ipv6_prefix_length_lesser_or_equal_destroy,
}
},
{
#include "zlog.h"
#include "libfrr_trace.h"
-DEFINE_MTYPE_STATIC(LIB, FRR_PTHREAD, "FRR POSIX Thread")
-DEFINE_MTYPE_STATIC(LIB, PTHREAD_PRIM, "POSIX sync primitives")
+DEFINE_MTYPE_STATIC(LIB, FRR_PTHREAD, "FRR POSIX Thread");
+DEFINE_MTYPE_STATIC(LIB, PTHREAD_PRIM, "POSIX sync primitives");
/* default frr_pthread start/stop routine prototypes */
static void *fpt_run(void *arg);
#include "log.h"
#include "lib_errors.h"
-DEFINE_MTYPE_STATIC(LIB, ZEROMQ_CB, "ZeroMQ callback")
+DEFINE_MTYPE_STATIC(LIB, ZEROMQ_CB, "ZeroMQ callback");
/* libzmq's context */
void *frrzmq_context = NULL;
#include "seqlock.h"
#include "atomlist.h"
-DEFINE_MTYPE_STATIC(LIB, RCU_THREAD, "RCU thread")
-DEFINE_MTYPE_STATIC(LIB, RCU_NEXT, "RCU sequence barrier")
+DEFINE_MTYPE_STATIC(LIB, RCU_THREAD, "RCU thread");
+DEFINE_MTYPE_STATIC(LIB, RCU_NEXT, "RCU sequence barrier");
-DECLARE_ATOMLIST(rcu_heads, struct rcu_head, head)
+DECLARE_ATOMLIST(rcu_heads, struct rcu_head, head);
-PREDECL_ATOMLIST(rcu_threads)
+PREDECL_ATOMLIST(rcu_threads);
struct rcu_thread {
struct rcu_threads_item head;
/* only accessed by thread itself, not atomic */
unsigned depth;
};
-DECLARE_ATOMLIST(rcu_threads, struct rcu_thread, head)
+DECLARE_ATOMLIST(rcu_threads, struct rcu_thread, head);
static const struct rcu_action rcua_next = { .type = RCUA_NEXT };
static const struct rcu_action rcua_end = { .type = RCUA_END };
};
/* RCU cleanup function queue item */
-PREDECL_ATOMLIST(rcu_heads)
+PREDECL_ATOMLIST(rcu_heads);
struct rcu_head {
struct rcu_heads_item head;
const struct rcu_action *action;
#define GRAMMAR_STR "CLI grammar sandbox\n"
-DEFINE_MTYPE_STATIC(LIB, CMD_TOKENS, "Command desc")
+DEFINE_MTYPE_STATIC(LIB, CMD_TOKENS, "Command desc");
/** headers **/
void grammar_sandbox_init(void);
#include "memory.h"
#include "buffer.h"
-DEFINE_MTYPE_STATIC(LIB, GRAPH, "Graph")
-DEFINE_MTYPE_STATIC(LIB, GRAPH_NODE, "Graph Node")
+DEFINE_MTYPE_STATIC(LIB, GRAPH, "Graph");
+DEFINE_MTYPE_STATIC(LIB, GRAPH_NODE, "Graph Node");
struct graph *graph_new(void)
{
struct graph *graph = XCALLOC(MTYPE_GRAPH, sizeof(struct graph));
#include "frr_pthread.h"
#include "libfrr_trace.h"
-DEFINE_MTYPE_STATIC(LIB, HASH, "Hash")
-DEFINE_MTYPE_STATIC(LIB, HASH_BUCKET, "Hash Bucket")
-DEFINE_MTYPE_STATIC(LIB, HASH_INDEX, "Hash Index")
+DEFINE_MTYPE_STATIC(LIB, HASH, "Hash");
+DEFINE_MTYPE_STATIC(LIB, HASH_BUCKET, "Hash Bucket");
+DEFINE_MTYPE_STATIC(LIB, HASH_INDEX, "Hash Index");
static pthread_mutex_t _hashes_mtx = PTHREAD_MUTEX_INITIALIZER;
static struct list *_hashes;
#include "memory.h"
#include "hook.h"
-DEFINE_MTYPE_STATIC(LIB, HOOK_ENTRY, "Hook entry")
+DEFINE_MTYPE_STATIC(LIB, HOOK_ENTRY, "Hook entry");
void _hook_register(struct hook *hook, struct hookent *stackent, void *funcptr,
void *arg, bool has_arg, struct frrmod_runtime *module,
*
* mydaemon.h:
* #include "hook.h"
- * DECLARE_HOOK (some_update_event, (struct eventinfo *info), (info))
+ * DECLARE_HOOK (some_update_event, (struct eventinfo *info), (info));
*
* mydaemon.c:
- * DEFINE_HOOK (some_update_event, (struct eventinfo *info), (info))
+ * DEFINE_HOOK (some_update_event, (struct eventinfo *info), (info));
* ...
* hook_call (some_update_event, info)
*
#define HOOK_ADDARG(...) (hookarg , ## __VA_ARGS__)
/* use in header file - declares the hook and its arguments
- * usage: DECLARE_HOOK(my_hook, (int arg1, struct foo *arg2), (arg1, arg2))
+ * usage: DECLARE_HOOK(my_hook, (int arg1, struct foo *arg2), (arg1, arg2));
* as above, "passlist" must use the same order and same names as "arglist"
*
* theoretically passlist is not neccessary, but let's keep things simple and
int(*funcptr) HOOK_ADDDEF arglist) \
{ \
return (void *)funcptr; \
- }
+ } \
+ MACRO_REQUIRE_SEMICOLON() /* end */
+
#define DECLARE_KOOH(hookname, arglist, passlist) \
DECLARE_HOOK(hookname, arglist, passlist)
hooksum += hookp.farg HOOK_ADDARG passlist; \
} \
return hooksum; \
- }
+ } \
+ MACRO_REQUIRE_SEMICOLON() /* end */
#define DEFINE_HOOK(hookname, arglist, passlist) \
DEFINE_HOOK_INT(hookname, arglist, passlist, false)
#include <inttypes.h>
-DEFINE_MTYPE_STATIC(LIB, IDALLOC_ALLOCATOR, "ID Number Allocator")
-DEFINE_MTYPE_STATIC(LIB, IDALLOC_ALLOCATOR_NAME, "ID Number Allocator Name")
-DEFINE_MTYPE_STATIC(LIB, IDALLOC_DIRECTORY, "ID Number Allocator Directory")
+DEFINE_MTYPE_STATIC(LIB, IDALLOC_ALLOCATOR, "ID Number Allocator");
+DEFINE_MTYPE_STATIC(LIB, IDALLOC_ALLOCATOR_NAME, "ID Number Allocator Name");
+DEFINE_MTYPE_STATIC(LIB, IDALLOC_DIRECTORY, "ID Number Allocator Directory");
DEFINE_MTYPE_STATIC(LIB, IDALLOC_SUBDIRECTORY,
- "ID Number Allocator Subdirectory")
-DEFINE_MTYPE_STATIC(LIB, IDALLOC_PAGE, "ID Number Allocator Page")
-DEFINE_MTYPE_STATIC(LIB, IDALLOC_POOL, "ID Number temporary holding pool entry")
+ "ID Number Allocator Subdirectory");
+DEFINE_MTYPE_STATIC(LIB, IDALLOC_PAGE, "ID Number Allocator Page");
+DEFINE_MTYPE_STATIC(LIB, IDALLOC_POOL,
+ "ID Number temporary holding pool entry");
#if UINT_MAX >= UINT32_MAX
#define FFS32(x) ffs(x)
#include "lib/if_clippy.c"
#endif
-DEFINE_MTYPE_STATIC(LIB, IF, "Interface")
-DEFINE_MTYPE_STATIC(LIB, CONNECTED, "Connected")
-DEFINE_MTYPE_STATIC(LIB, NBR_CONNECTED, "Neighbor Connected")
-DEFINE_MTYPE(LIB, CONNECTED_LABEL, "Connected interface label")
-DEFINE_MTYPE_STATIC(LIB, IF_LINK_PARAMS, "Informational Link Parameters")
+DEFINE_MTYPE_STATIC(LIB, IF, "Interface");
+DEFINE_MTYPE_STATIC(LIB, CONNECTED, "Connected");
+DEFINE_MTYPE_STATIC(LIB, NBR_CONNECTED, "Neighbor Connected");
+DEFINE_MTYPE(LIB, CONNECTED_LABEL, "Connected interface label");
+DEFINE_MTYPE_STATIC(LIB, IF_LINK_PARAMS, "Informational Link Parameters");
static struct interface *if_lookup_by_ifindex(ifindex_t ifindex,
vrf_id_t vrf_id);
RB_GENERATE(if_name_head, interface, name_entry, if_cmp_func);
RB_GENERATE(if_index_head, interface, index_entry, if_cmp_index_func);
-DEFINE_QOBJ_TYPE(interface)
+DEFINE_QOBJ_TYPE(interface);
-DEFINE_HOOK(if_add, (struct interface * ifp), (ifp))
-DEFINE_KOOH(if_del, (struct interface * ifp), (ifp))
+DEFINE_HOOK(if_add, (struct interface * ifp), (ifp));
+DEFINE_KOOH(if_del, (struct interface * ifp), (ifp));
static struct interface_master{
int (*create_hook)(struct interface *ifp);
extern "C" {
#endif
-DECLARE_MTYPE(CONNECTED_LABEL)
+DECLARE_MTYPE(CONNECTED_LABEL);
/* Interface link-layer type, if known. Derived from:
*
*/
bool configured;
- QOBJ_FIELDS
+ QOBJ_FIELDS;
};
RB_HEAD(if_name_head, interface);
RB_PROTOTYPE(if_name_head, interface, name_entry, if_cmp_func)
RB_HEAD(if_index_head, interface);
RB_PROTOTYPE(if_index_head, interface, index_entry, if_cmp_index_func)
-DECLARE_QOBJ_TYPE(interface)
+DECLARE_QOBJ_TYPE(interface);
#define IFNAME_RB_INSERT(vrf, ifp) \
({ \
* can use 1000+ so they run after the daemon has initialised daemon-specific
* interface data
*/
-DECLARE_HOOK(if_add, (struct interface * ifp), (ifp))
-DECLARE_KOOH(if_del, (struct interface * ifp), (ifp))
+DECLARE_HOOK(if_add, (struct interface * ifp), (ifp));
+DECLARE_KOOH(if_del, (struct interface * ifp), (ifp));
#define METRIC_MAX (~0)
#include "if.h"
#include "if_rmap.h"
-DEFINE_MTYPE_STATIC(LIB, IF_RMAP_CTX, "Interface route map container")
-DEFINE_MTYPE_STATIC(LIB, IF_RMAP_CTX_NAME, "Interface route map container name")
-DEFINE_MTYPE_STATIC(LIB, IF_RMAP, "Interface route map")
-DEFINE_MTYPE_STATIC(LIB, IF_RMAP_NAME, "I.f. route map name")
+DEFINE_MTYPE_STATIC(LIB, IF_RMAP_CTX, "Interface route map container");
+DEFINE_MTYPE_STATIC(LIB, IF_RMAP_CTX_NAME,
+ "Interface route map container name");
+DEFINE_MTYPE_STATIC(LIB, IF_RMAP, "Interface route map");
+DEFINE_MTYPE_STATIC(LIB, IF_RMAP_NAME, "I.f. route map name");
static struct list *if_rmap_ctx_list;
#include "linklist.h"
#include "keychain.h"
-DEFINE_MTYPE_STATIC(LIB, KEY, "Key")
-DEFINE_MTYPE_STATIC(LIB, KEYCHAIN, "Key chain")
+DEFINE_MTYPE_STATIC(LIB, KEY, "Key");
+DEFINE_MTYPE_STATIC(LIB, KEYCHAIN, "Key chain");
-DEFINE_QOBJ_TYPE(keychain)
-DEFINE_QOBJ_TYPE(key)
+DEFINE_QOBJ_TYPE(keychain);
+DEFINE_QOBJ_TYPE(key);
/* Master list of key chain. */
static struct list *keychain_list;
struct list *key;
- QOBJ_FIELDS
+ QOBJ_FIELDS;
};
-DECLARE_QOBJ_TYPE(keychain)
+DECLARE_QOBJ_TYPE(keychain);
struct key_range {
time_t start;
struct key_range send;
struct key_range accept;
- QOBJ_FIELDS
+ QOBJ_FIELDS;
};
-DECLARE_QOBJ_TYPE(key)
+DECLARE_QOBJ_TYPE(key);
extern void keychain_init(void);
extern struct keychain *keychain_lookup(const char *);
#include "ldp_sync.h"
/* Library code */
-DEFINE_MTYPE_STATIC(LIB, LDP_SYNC_INFO, "LDP SYNC info")
+DEFINE_MTYPE_STATIC(LIB, LDP_SYNC_INFO, "LDP SYNC info");
/*
* ldp_sync_info_create - Allocate the LDP_SYNC information
#include "defaults.h"
#include "frrscript.h"
-DEFINE_HOOK(frr_late_init, (struct thread_master * tm), (tm))
-DEFINE_HOOK(frr_very_late_init, (struct thread_master * tm), (tm))
-DEFINE_KOOH(frr_early_fini, (), ())
-DEFINE_KOOH(frr_fini, (), ())
+DEFINE_HOOK(frr_late_init, (struct thread_master * tm), (tm));
+DEFINE_HOOK(frr_very_late_init, (struct thread_master * tm), (tm));
+DEFINE_KOOH(frr_early_fini, (), ());
+DEFINE_KOOH(frr_fini, (), ());
const char frr_sysconfdir[] = SYSCONFDIR;
char frr_vtydir[256];
__VA_ARGS__}; \
FRR_COREMOD_SETUP(.name = #execname, \
.description = #execname " daemon", \
- .version = FRR_VERSION, ) \
-/* end */
+ .version = FRR_VERSION, ); \
+ MACRO_REQUIRE_SEMICOLON() /* end */
extern void frr_init_vtydir(void);
extern void frr_preinit(struct frr_daemon_info *daemon, int argc, char **argv);
extern uint32_t frr_get_fd_limit(void);
extern bool frr_is_startup_fd(int fd);
-DECLARE_HOOK(frr_late_init, (struct thread_master * tm), (tm))
-DECLARE_HOOK(frr_very_late_init, (struct thread_master * tm), (tm))
+DECLARE_HOOK(frr_late_init, (struct thread_master * tm), (tm));
+DECLARE_HOOK(frr_very_late_init, (struct thread_master * tm), (tm));
extern void frr_config_fork(void);
extern void frr_run(struct thread_master *master);
/* these two are before the protocol daemon does its own shutdown
* it's named this way being the counterpart to frr_late_init */
-DECLARE_KOOH(frr_early_fini, (), ())
+DECLARE_KOOH(frr_early_fini, (), ());
extern void frr_early_fini(void);
/* and these two are after the daemon did its own cleanup */
-DECLARE_KOOH(frr_fini, (), ())
+DECLARE_KOOH(frr_fini, (), ());
extern void frr_fini(void);
extern char config_default[512];
#include "link_state.h"
/* Link State Memory allocation */
-DEFINE_MTYPE_STATIC(LIB, LS_DB, "Link State Database")
+DEFINE_MTYPE_STATIC(LIB, LS_DB, "Link State Database");
/**
* Link State Node management functions
*/
/* Link State Vertex structure */
-PREDECL_RBTREE_UNIQ(vertices)
+PREDECL_RBTREE_UNIQ(vertices);
struct ls_vertex {
struct vertices_item entry; /* Entry in RB Tree */
uint64_t key; /* Unique Key identifier */
};
/* Link State Edge structure */
-PREDECL_RBTREE_UNIQ(edges)
+PREDECL_RBTREE_UNIQ(edges);
struct ls_edge {
struct edges_item entry; /* Entry in RB tree */
uint64_t key; /* Unique Key identifier */
};
/* Link State Subnet structure */
-PREDECL_RBTREE_UNIQ(subnets)
+PREDECL_RBTREE_UNIQ(subnets);
struct ls_subnet {
struct subnets_item entry; /* Entry in RB tree */
struct prefix key; /* Unique Key identifier */
{
return (node1->key - node2->key);
}
-DECLARE_RBTREE_UNIQ(vertices, struct ls_vertex, entry, vertex_cmp)
+DECLARE_RBTREE_UNIQ(vertices, struct ls_vertex, entry, vertex_cmp);
macro_inline int edge_cmp(const struct ls_edge *edge1,
const struct ls_edge *edge2)
{
return (edge1->key - edge2->key);
}
-DECLARE_RBTREE_UNIQ(edges, struct ls_edge, entry, edge_cmp)
+DECLARE_RBTREE_UNIQ(edges, struct ls_edge, entry, edge_cmp);
macro_inline int subnet_cmp(const struct ls_subnet *a,
const struct ls_subnet *b)
{
return prefix_cmp(&a->key, &b->key);
}
-DECLARE_RBTREE_UNIQ(subnets, struct ls_subnet, entry, subnet_cmp)
+DECLARE_RBTREE_UNIQ(subnets, struct ls_subnet, entry, subnet_cmp);
/* Link State TED Structure */
struct ls_ted {
#include "memory.h"
#include "libfrr_trace.h"
-DEFINE_MTYPE_STATIC(LIB, LINK_LIST, "Link List")
-DEFINE_MTYPE_STATIC(LIB, LINK_NODE, "Link Node")
+DEFINE_MTYPE_STATIC(LIB, LINK_LIST, "Link List");
+DEFINE_MTYPE_STATIC(LIB, LINK_NODE, "Link Node");
struct list *list_new(void)
{
#define ZLOG_MAXLVL(a, b) MAX(a, b)
-DEFINE_HOOK(zlog_rotate, (), ())
+DEFINE_HOOK(zlog_rotate, (), ());
static const int log_default_lvl = LOG_DEBUG;
return CMD_SUCCESS;
}
+DEFPY (config_log_ec,
+ config_log_ec_cmd,
+ "[no] log error-category",
+ NO_STR
+ "Logging control\n"
+ "Prefix log message text with [EC 9999] code\n")
+{
+ zlog_set_prefix_ec(!no);
+ return CMD_SUCCESS;
+}
+
+DEFPY (config_log_xid,
+ config_log_xid_cmd,
+ "[no] log unique-id",
+ NO_STR
+ "Logging control\n"
+ "Prefix log message text with [XXXXX-XXXXX] identifier\n")
+{
+ zlog_set_prefix_xid(!no);
+ return CMD_SUCCESS;
+}
+
DEFPY (config_log_filterfile,
config_log_filterfile_cmd,
"log filtered-file FILENAME [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>$levelarg]",
if (zt_file.ts_subsec > 0)
vty_out(vty, "log timestamp precision %d\n",
zt_file.ts_subsec);
+
+ if (!zlog_get_prefix_ec())
+ vty_out(vty, "no log error-category\n");
+ if (!zlog_get_prefix_xid())
+ vty_out(vty, "no log unique-id\n");
}
static int log_vty_init(const char *progname, const char *protoname,
zlog_progname = progname;
zlog_protoname = protoname;
+ zlog_set_prefix_ec(true);
+ zlog_set_prefix_xid(true);
+
zlog_filterfile_init(&zt_filterfile);
zlog_file_set_fd(&zt_stdout, STDOUT_FILENO);
install_element(CONFIG_NODE, &no_config_log_record_priority_cmd);
install_element(CONFIG_NODE, &config_log_timestamp_precision_cmd);
install_element(CONFIG_NODE, &no_config_log_timestamp_precision_cmd);
+ install_element(CONFIG_NODE, &config_log_ec_cmd);
+ install_element(CONFIG_NODE, &config_log_xid_cmd);
install_element(VIEW_NODE, &show_log_filter_cmd);
install_element(CONFIG_NODE, &log_filter_cmd);
extern int log_level_match(const char *s);
extern void log_show_syslog(struct vty *vty);
-DECLARE_HOOK(zlog_rotate, (), ())
+DECLARE_HOOK(zlog_rotate, (), ());
extern void zlog_rotate(void);
#ifdef __cplusplus
static struct memgroup *mg_first = NULL;
struct memgroup **mg_insert = &mg_first;
-DEFINE_MGROUP(LIB, "libfrr")
-DEFINE_MTYPE(LIB, TMP, "Temporary memory")
+DEFINE_MGROUP(LIB, "libfrr");
+DEFINE_MTYPE(LIB, TMP, "Temporary memory");
static inline void mt_count_alloc(struct memtype *mt, size_t size, void *ptr)
{
/* macro usage:
*
* mydaemon.h
- * DECLARE_MGROUP(MYDAEMON)
- * DECLARE_MTYPE(MYDAEMON_COMMON)
+ * DECLARE_MGROUP(MYDAEMON);
+ * DECLARE_MTYPE(MYDAEMON_COMMON);
*
* mydaemon.c
- * DEFINE_MGROUP(MYDAEMON, "my daemon memory")
+ * DEFINE_MGROUP(MYDAEMON, "my daemon memory");
* DEFINE_MTYPE(MYDAEMON, MYDAEMON_COMMON,
- * "this mtype is used in multiple files in mydaemon")
+ * "this mtype is used in multiple files in mydaemon");
* foo = qmalloc(MTYPE_MYDAEMON_COMMON, sizeof(*foo))
*
* mydaemon_io.c
* bar = qmalloc(MTYPE_MYDAEMON_COMMON, sizeof(*bar))
*
* DEFINE_MTYPE_STATIC(MYDAEMON, MYDAEMON_IO,
- * "this mtype is used only in this file")
+ * "this mtype is used only in this file");
* baz = qmalloc(MTYPE_MYDAEMON_IO, sizeof(*baz))
*
* Note: Naming conventions (MGROUP_ and MTYPE_ prefixes are enforced
* but MGROUP_* aren't.
*/
-#define DECLARE_MGROUP(name) extern struct memgroup _mg_##name;
+#define DECLARE_MGROUP(name) extern struct memgroup _mg_##name
#define _DEFINE_MGROUP(mname, desc, ...) \
struct memgroup _mg_##mname \
__attribute__((section(".data.mgroups"))) = { \
_mg_##mname.next->ref = _mg_##mname.ref; \
*_mg_##mname.ref = _mg_##mname.next; \
} \
- /* end */
+ MACRO_REQUIRE_SEMICOLON() /* end */
#define DEFINE_MGROUP(mname, desc) \
_DEFINE_MGROUP(mname, desc, )
_DEFINE_MGROUP(mname, desc, .active_at_exit = true)
#define DECLARE_MTYPE(name) \
- extern struct memtype MTYPE_##name[1]; \
+ extern struct memtype MTYPE_##name[1] \
/* end */
#define DEFINE_MTYPE_ATTR(group, mname, attr, desc) \
MTYPE_##mname->next->ref = MTYPE_##mname->ref; \
*MTYPE_##mname->ref = MTYPE_##mname->next; \
} \
- /* end */
+ MACRO_REQUIRE_SEMICOLON() /* end */
#define DEFINE_MTYPE(group, name, desc) \
DEFINE_MTYPE_ATTR(group, name, , desc) \
DEFINE_MTYPE_ATTR(group, name, static, desc) \
/* end */
-DECLARE_MGROUP(LIB)
-DECLARE_MTYPE(TMP)
+DECLARE_MGROUP(LIB);
+DECLARE_MTYPE(TMP);
extern void *qmalloc(struct memtype *mt, size_t size)
#include "memory.h"
#include "version.h"
-DEFINE_MTYPE_STATIC(LIB, MODULE_LOADNAME, "Module loading name")
-DEFINE_MTYPE_STATIC(LIB, MODULE_LOADARGS, "Module loading arguments")
+DEFINE_MTYPE_STATIC(LIB, MODULE_LOADNAME, "Module loading name");
+DEFINE_MTYPE_STATIC(LIB, MODULE_LOADARGS, "Module loading arguments");
static struct frrmod_info frrmod_default_info = {
.name = "libfrr",
},
};
-XREF_SETUP()
+XREF_SETUP();
// if defined(HAVE_SYS_WEAK_ALIAS_ATTRIBUTE)
// union _frrmod_runtime_u _frrmod_this_module
NULL, \
&_frrmod_info, \
}}; \
- XREF_SETUP() \
- /* end */
+ XREF_SETUP(); \
+ MACRO_REQUIRE_SEMICOLON() /* end */
#define FRR_MODULE_SETUP(...) \
- FRR_COREMOD_SETUP(__VA_ARGS__) \
- DSO_SELF struct frrmod_runtime *frr_module = &_frrmod_this_module.r;
+ FRR_COREMOD_SETUP(__VA_ARGS__); \
+ DSO_SELF struct frrmod_runtime *frr_module = &_frrmod_this_module.r; \
+ MACRO_REQUIRE_SEMICOLON() /* end */
extern struct frrmod_runtime *frrmod_list;
#include "vrf.h"
#include "lib_errors.h"
-DEFINE_MTYPE_STATIC(LIB, NS, "NetNS Context")
-DEFINE_MTYPE_STATIC(LIB, NS_NAME, "NetNS Name")
+DEFINE_MTYPE_STATIC(LIB, NS, "NetNS Context");
+DEFINE_MTYPE_STATIC(LIB, NS_NAME, "NetNS Name");
static inline int ns_compare(const struct ns *ns, const struct ns *ns2);
static struct ns *ns_lookup_name_internal(const char *name);
#include "log.h"
#include "memory.h"
-DEFINE_MTYPE_STATIC(LIB, NS, "NetNS Context")
-DEFINE_MTYPE_STATIC(LIB, NS_NAME, "NetNS Name")
+DEFINE_MTYPE_STATIC(LIB, NS, "NetNS Context");
+DEFINE_MTYPE_STATIC(LIB, NS_NAME, "NetNS Name");
static inline int ns_compare(const struct ns *ns, const struct ns *ns2);
#include "vrf.h"
#include "nexthop_group.h"
-DEFINE_MTYPE_STATIC(LIB, NEXTHOP, "Nexthop")
-DEFINE_MTYPE_STATIC(LIB, NH_LABEL, "Nexthop label")
+DEFINE_MTYPE_STATIC(LIB, NEXTHOP, "Nexthop");
+DEFINE_MTYPE_STATIC(LIB, NH_LABEL, "Nexthop label");
static int _nexthop_labels_cmp(const struct nexthop *nh1,
const struct nexthop *nh2)
#include "lib/nexthop_group_clippy.c"
#endif
-DEFINE_MTYPE_STATIC(LIB, NEXTHOP_GROUP, "Nexthop Group")
+DEFINE_MTYPE_STATIC(LIB, NEXTHOP_GROUP, "Nexthop Group");
/*
* Internal struct used to hold nhg config strings
XFREE(MTYPE_TMP, nhgc);
}
-DEFINE_QOBJ_TYPE(nexthop_group_cmd)
+DEFINE_QOBJ_TYPE(nexthop_group_cmd);
DEFUN_NOSH(nexthop_group, nexthop_group_cmd, "nexthop-group NHGNAME",
"Enter into the nexthop-group submode\n"
struct list *nhg_list;
- QOBJ_FIELDS
+ QOBJ_FIELDS;
};
RB_HEAD(nhgc_entry_head, nexthp_group_cmd);
RB_PROTOTYPE(nhgc_entry_head, nexthop_group_cmd, nhgc_entry,
nexthop_group_cmd_compare)
-DECLARE_QOBJ_TYPE(nexthop_group_cmd)
+DECLARE_QOBJ_TYPE(nexthop_group_cmd);
/*
* Initialize nexthop_groups. If you are interested in when
#include "northbound_db.h"
#include "frrstr.h"
-DEFINE_MTYPE_STATIC(LIB, NB_NODE, "Northbound Node")
-DEFINE_MTYPE_STATIC(LIB, NB_CONFIG, "Northbound Configuration")
-DEFINE_MTYPE_STATIC(LIB, NB_CONFIG_ENTRY, "Northbound Configuration Entry")
+DEFINE_MTYPE_STATIC(LIB, NB_NODE, "Northbound Node");
+DEFINE_MTYPE_STATIC(LIB, NB_CONFIG, "Northbound Configuration");
+DEFINE_MTYPE_STATIC(LIB, NB_CONFIG_ENTRY, "Northbound Configuration Entry");
/* Running configuration - shouldn't be modified directly. */
struct nb_config *running_config;
}
if (ret != NB_OK) {
- int priority;
- enum lib_log_refs ref;
-
yang_dnode_get_path(dnode, xpath, sizeof(xpath));
switch (event) {
case NB_EV_VALIDATE:
- priority = LOG_WARNING;
- ref = EC_LIB_NB_CB_CONFIG_VALIDATE;
+ flog_warn(EC_LIB_NB_CB_CONFIG_VALIDATE,
+ "error processing configuration change: error [%s] event [%s] operation [%s] xpath [%s]%s%s",
+ nb_err_name(ret), nb_event_name(event),
+ nb_operation_name(operation), xpath,
+ errmsg[0] ? " message: " : "", errmsg);
break;
case NB_EV_PREPARE:
- priority = LOG_WARNING;
- ref = EC_LIB_NB_CB_CONFIG_PREPARE;
+ flog_warn(EC_LIB_NB_CB_CONFIG_PREPARE,
+ "error processing configuration change: error [%s] event [%s] operation [%s] xpath [%s]%s%s",
+ nb_err_name(ret), nb_event_name(event),
+ nb_operation_name(operation), xpath,
+ errmsg[0] ? " message: " : "", errmsg);
break;
case NB_EV_ABORT:
- priority = LOG_WARNING;
- ref = EC_LIB_NB_CB_CONFIG_ABORT;
+ flog_warn(EC_LIB_NB_CB_CONFIG_ABORT,
+ "error processing configuration change: error [%s] event [%s] operation [%s] xpath [%s]%s%s",
+ nb_err_name(ret), nb_event_name(event),
+ nb_operation_name(operation), xpath,
+ errmsg[0] ? " message: " : "", errmsg);
break;
case NB_EV_APPLY:
- priority = LOG_ERR;
- ref = EC_LIB_NB_CB_CONFIG_APPLY;
+ flog_err(EC_LIB_NB_CB_CONFIG_APPLY,
+ "error processing configuration change: error [%s] event [%s] operation [%s] xpath [%s]%s%s",
+ nb_err_name(ret), nb_event_name(event),
+ nb_operation_name(operation), xpath,
+ errmsg[0] ? " message: " : "", errmsg);
break;
default:
flog_err(EC_LIB_DEVELOPMENT,
event, xpath);
exit(1);
}
-
- flog(priority, ref,
- "error processing configuration change: error [%s] event [%s] operation [%s] xpath [%s]",
- nb_err_name(ret), nb_event_name(event),
- nb_operation_name(operation), xpath);
- if (strlen(errmsg) > 0)
- flog(priority, ref,
- "error processing configuration change: %s",
- errmsg);
}
return ret;
/* Hooks. */
DECLARE_HOOK(nb_notification_send, (const char *xpath, struct list *arguments),
- (xpath, arguments))
-DECLARE_HOOK(nb_client_debug_config_write, (struct vty *vty), (vty))
-DECLARE_HOOK(nb_client_debug_set_all, (uint32_t flags, bool set), (flags, set))
+ (xpath, arguments));
+DECLARE_HOOK(nb_client_debug_config_write, (struct vty *vty), (vty));
+DECLARE_HOOK(nb_client_debug_set_all, (uint32_t flags, bool set), (flags, set));
/* Northbound debugging records */
extern struct debug nb_dbg_cbs_config;
#include <confd_dp.h>
#include <confd_maapi.h>
-DEFINE_MTYPE_STATIC(LIB, CONFD, "ConfD module")
+DEFINE_MTYPE_STATIC(LIB, CONFD, "ConfD module");
static struct debug nb_dbg_client_confd = {0, "Northbound client: ConfD"};
FRR_MODULE_SETUP(.name = "frr_confd", .version = FRR_VERSION,
.description = "FRR ConfD integration module",
- .init = frr_confd_module_init, )
+ .init = frr_confd_module_init,
+);
FRR_MODULE_SETUP(.name = "frr_grpc", .version = FRR_VERSION,
.description = "FRR gRPC northbound module",
- .init = frr_grpc_module_init, )
+ .init = frr_grpc_module_init,
+);
#include <sysrepo/values.h>
#include <sysrepo/xpath.h>
-DEFINE_MTYPE_STATIC(LIB, SYSREPO, "Sysrepo module")
+DEFINE_MTYPE_STATIC(LIB, SYSREPO, "Sysrepo module");
static struct debug nb_dbg_client_sysrepo = {0, "Northbound client: Sysrepo"};
FRR_MODULE_SETUP(.name = "frr_sysrepo", .version = FRR_VERSION,
.description = "FRR sysrepo integration module",
- .init = frr_sr_module_init, )
+ .init = frr_sr_module_init,
+);
#include "plist_int.h"
-DEFINE_MTYPE_STATIC(LIB, PREFIX_LIST, "Prefix List")
-DEFINE_MTYPE_STATIC(LIB, MPREFIX_LIST_STR, "Prefix List Str")
-DEFINE_MTYPE_STATIC(LIB, PREFIX_LIST_ENTRY, "Prefix List Entry")
-DEFINE_MTYPE_STATIC(LIB, PREFIX_LIST_TRIE, "Prefix List Trie Table")
+DEFINE_MTYPE_STATIC(LIB, PREFIX_LIST, "Prefix List");
+DEFINE_MTYPE_STATIC(LIB, MPREFIX_LIST_STR, "Prefix List Str");
+DEFINE_MTYPE_STATIC(LIB, PREFIX_LIST_ENTRY, "Prefix List Entry");
+DEFINE_MTYPE_STATIC(LIB, PREFIX_LIST_TRIE, "Prefix List Trie Table");
/* not currently changeable, code assumes bytes further down */
#define PLC_BITS 8
if (pl->head || pl->tail || pl->desc)
pl->master->recent = pl;
+ ple->next_best = NULL;
ple->installed = false;
}
#include "printfrr.h"
#include "vxlan.h"
-DEFINE_MTYPE_STATIC(LIB, PREFIX, "Prefix")
-DEFINE_MTYPE_STATIC(LIB, PREFIX_FLOWSPEC, "Prefix Flowspec")
+DEFINE_MTYPE_STATIC(LIB, PREFIX, "Prefix");
+DEFINE_MTYPE_STATIC(LIB, PREFIX_FLOWSPEC, "Prefix Flowspec");
/* Maskbit. */
static const uint8_t maskbit[] = {0x00, 0x80, 0xc0, 0xe0, 0xf0,
} \
/* end */
+/* fbuf helper functions */
+
+static inline ssize_t bputs(struct fbuf *buf, const char *str)
+{
+ size_t len = strlen(str);
+ size_t ncopy;
+
+ if (!buf)
+ return len;
+
+ ncopy = MIN(len, (size_t)(buf->buf + buf->len - buf->pos));
+ memcpy(buf->pos, str, ncopy);
+ buf->pos += ncopy;
+
+ return len;
+}
+
+static inline ssize_t bputch(struct fbuf *buf, char ch)
+{
+ if (buf && buf->pos < buf->buf + buf->len)
+ *buf->pos++ = ch;
+ return 1;
+}
+
#ifdef __cplusplus
}
#endif
#include "lib_errors.h"
#include "lib/queue.h"
-DEFINE_MTYPE_STATIC(LIB, PRIVS, "Privilege information")
+DEFINE_MTYPE_STATIC(LIB, PRIVS, "Privilege information");
/*
* Different capabilities/privileges apis have different characteristics: some
int64_t maxspin; /* PULLWR_MAXSPIN */
};
-DEFINE_MTYPE_STATIC(LIB, PULLWR_HEAD, "pull-driven write controller")
-DEFINE_MTYPE_STATIC(LIB, PULLWR_BUF, "pull-driven write buffer")
+DEFINE_MTYPE_STATIC(LIB, PULLWR_HEAD, "pull-driven write controller");
+DEFINE_MTYPE_STATIC(LIB, PULLWR_BUF, "pull-driven write buffer");
static int pullwr_run(struct thread *t);
}
DECLARE_HASH(qobj_nodes, struct qobj_node, nodehash,
- qobj_cmp, qobj_hash)
+ qobj_cmp, qobj_hash);
static pthread_rwlock_t nodes_lock;
static struct qobj_nodes_head nodes = { };
RESERVED_SPACE_STRUCT(qobj_nodetype_capnp, capnp, 256)
};
-PREDECL_HASH(qobj_nodes)
+PREDECL_HASH(qobj_nodes);
/* anchor to be embedded somewhere in the object's struct */
struct qobj_node {
const struct qobj_nodetype *type;
};
-#define QOBJ_FIELDS struct qobj_node qobj_node;
+#define QOBJ_FIELDS struct qobj_node qobj_node
/* call these at the end of any _create function (QOBJ_REG)
* and beginning of any _destroy function (QOBJ_UNREG) */
/* type declarations */
#define DECLARE_QOBJ_TYPE(structname) \
- extern const struct qobj_nodetype qobj_t_##structname;
+ extern const struct qobj_nodetype qobj_t_##structname \
+ /* end */
#define DEFINE_QOBJ_TYPE(structname) \
const struct qobj_nodetype qobj_t_##structname = { \
.node_member_offset = \
- (ptrdiff_t)offsetof(struct structname, qobj_node)};
+ (ptrdiff_t)offsetof(struct structname, qobj_node)} \
+ /* end */
#define DEFINE_QOBJ_TYPE_INIT(structname, ...) \
const struct qobj_nodetype qobj_t_##structname = { \
.node_member_offset = \
(ptrdiff_t)offsetof(struct structname, qobj_node), \
- __VA_ARGS__};
+ __VA_ARGS__} \
+ /* end */
/* ID dereference with typecheck.
* will return NULL if id not found or wrong type. */
#include "command.h"
#include "xref.h"
-XREF_SETUP()
+XREF_SETUP();
struct resolver_state {
ares_channel channel;
#include "ringbuf.h"
#include "memory.h"
-DEFINE_MTYPE_STATIC(LIB, RINGBUFFER, "Ring buffer")
+DEFINE_MTYPE_STATIC(LIB, RINGBUFFER, "Ring buffer");
struct ringbuf *ringbuf_new(size_t size)
{
#include "lib_errors.h"
#include "table.h"
-DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP, "Route map")
-DEFINE_MTYPE(LIB, ROUTE_MAP_NAME, "Route map name")
-DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_INDEX, "Route map index")
-DEFINE_MTYPE(LIB, ROUTE_MAP_RULE, "Route map rule")
-DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_RULE_STR, "Route map rule str")
-DEFINE_MTYPE(LIB, ROUTE_MAP_COMPILED, "Route map compiled")
-DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_DEP, "Route map dependency")
-DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_DEP_DATA, "Route map dependency data")
-
-DEFINE_QOBJ_TYPE(route_map_index)
-DEFINE_QOBJ_TYPE(route_map)
+DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP, "Route map");
+DEFINE_MTYPE(LIB, ROUTE_MAP_NAME, "Route map name");
+DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_INDEX, "Route map index");
+DEFINE_MTYPE(LIB, ROUTE_MAP_RULE, "Route map rule");
+DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_RULE_STR, "Route map rule str");
+DEFINE_MTYPE(LIB, ROUTE_MAP_COMPILED, "Route map compiled");
+DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_DEP, "Route map dependency");
+DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_DEP_DATA, "Route map dependency data");
+
+DEFINE_QOBJ_TYPE(route_map_index);
+DEFINE_QOBJ_TYPE(route_map);
#define IPv4_PREFIX_LIST "ip address prefix-list"
#define IPv6_PREFIX_LIST "ipv6 address prefix-list"
extern "C" {
#endif
-DECLARE_MTYPE(ROUTE_MAP_NAME)
-DECLARE_MTYPE(ROUTE_MAP_RULE)
-DECLARE_MTYPE(ROUTE_MAP_COMPILED)
+DECLARE_MTYPE(ROUTE_MAP_NAME);
+DECLARE_MTYPE(ROUTE_MAP_RULE);
+DECLARE_MTYPE(ROUTE_MAP_COMPILED);
/* Route map's type. */
enum route_map_type { RMAP_PERMIT, RMAP_DENY, RMAP_ANY };
/* List of match/sets contexts. */
TAILQ_HEAD(, routemap_hook_context) rhclist;
- QOBJ_FIELDS
+ QOBJ_FIELDS;
};
-DECLARE_QOBJ_TYPE(route_map_index)
+DECLARE_QOBJ_TYPE(route_map_index);
/* Route map list structure. */
struct route_map {
struct route_table *ipv4_prefix_table;
struct route_table *ipv6_prefix_table;
- QOBJ_FIELDS
+ QOBJ_FIELDS;
};
-DECLARE_QOBJ_TYPE(route_map)
+DECLARE_QOBJ_TYPE(route_map);
/* Prototypes. */
extern void route_map_init(void);
* callbacks for routing to handle configuration events
* based on the control plane protocol
*/
-DECLARE_HOOK(routing_conf_event, (struct nb_cb_create_args *args), (args))
+DECLARE_HOOK(routing_conf_event, (struct nb_cb_create_args *args), (args));
void routing_control_plane_protocols_register_vrf_dependency(void);
#include "routing_nb.h"
-DEFINE_HOOK(routing_conf_event, (struct nb_cb_create_args *args), (args))
+DEFINE_HOOK(routing_conf_event, (struct nb_cb_create_args *args), (args));
/*
* XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol
#include "lib_errors.h"
#include "network.h"
-DEFINE_MTYPE_STATIC(LIB, SKIP_LIST, "Skip List")
-DEFINE_MTYPE_STATIC(LIB, SKIP_LIST_NODE, "Skip Node")
+DEFINE_MTYPE_STATIC(LIB, SKIP_LIST, "Skip List");
+DEFINE_MTYPE_STATIC(LIB, SKIP_LIST_NODE, "Skip Node");
#define BitsInRandom 31
extern void oid2string(oid oid[], int len, char *string);
extern void oid_copy_str(oid oid[], const char *string, int len);
-DECLARE_HOOK(agentx_enabled, (), ())
+DECLARE_HOOK(agentx_enabled, (), ());
#ifdef __cplusplus
}
#include "lib_errors.h"
#include "printfrr.h"
-DEFINE_MTYPE_STATIC(LIB, SOCKUNION, "Socket union")
+DEFINE_MTYPE_STATIC(LIB, SOCKUNION, "Socket union");
const char *inet_sutop(const union sockunion *su, char *str)
{
#include "thread.h"
#include "vty.h"
-DEFINE_MTYPE_STATIC(LIB, SPF_BACKOFF, "SPF backoff")
-DEFINE_MTYPE_STATIC(LIB, SPF_BACKOFF_NAME, "SPF backoff name")
+DEFINE_MTYPE_STATIC(LIB, SPF_BACKOFF, "SPF backoff");
+DEFINE_MTYPE_STATIC(LIB, SPF_BACKOFF_NAME, "SPF backoff name");
static bool debug_spf_backoff = false;
#define backoff_debug(...) \
#include "table.h"
#include "printfrr.h"
-DEFINE_MTYPE_STATIC(LIB, ROUTE_SRC_NODE, "Route source node")
+DEFINE_MTYPE_STATIC(LIB, ROUTE_SRC_NODE, "Route source node");
/* ----- functions to manage rnodes _with_ srcdest table ----- */
struct srcdest_rnode {
#include "frr_pthread.h"
#include "lib_errors.h"
-DEFINE_MTYPE_STATIC(LIB, STREAM, "Stream")
-DEFINE_MTYPE_STATIC(LIB, STREAM_FIFO, "Stream FIFO")
+DEFINE_MTYPE_STATIC(LIB, STREAM, "Stream");
+DEFINE_MTYPE_STATIC(LIB, STREAM_FIFO, "Stream FIFO");
/* Tests whether a position is valid */
#define GETP_VALID(S, G) ((G) <= (S)->endp)
(which the static_assert checks), then by the pigeonhole
principle, the two input strings must overlap, which is
undefined. */
-#if __STDC_VERSION__ >= 201112L
_Static_assert(sizeof(uintptr_t) == sizeof(size_t),
"theoretical maximum object size covers address space");
-#endif
return dest_length + src_length;
}
#endif /* HAVE_STRLCAT */
lib_LTLIBRARIES += lib/libfrrsnmp.la
endif
-lib_libfrrsnmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu99
+lib_libfrrsnmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu11
lib_libfrrsnmp_la_LDFLAGS = -version-info 0:0:0
lib_libfrrsnmp_la_LIBADD = $(SNMP_LIBS)
lib_libfrrsnmp_la_SOURCES = \
#include "sockunion.h"
#include "libfrr_trace.h"
-DEFINE_MTYPE_STATIC(LIB, ROUTE_TABLE, "Route table")
-DEFINE_MTYPE(LIB, ROUTE_NODE, "Route node")
+DEFINE_MTYPE_STATIC(LIB, ROUTE_TABLE, "Route table");
+DEFINE_MTYPE(LIB, ROUTE_NODE, "Route node");
static void route_table_free(struct route_table *);
}
DECLARE_HASH(rn_hash_node, struct route_node, nodehash, route_table_hash_cmp,
- prefix_hash_key)
+ prefix_hash_key);
/*
* route_table_init_with_delegate
*/
extern "C" {
#endif
-DECLARE_MTYPE(ROUTE_NODE)
+DECLARE_MTYPE(ROUTE_NODE);
/*
* Forward declarations.
route_table_destroy_node_func_t destroy_node;
};
-PREDECL_HASH(rn_hash_node)
+PREDECL_HASH(rn_hash_node);
/* Routing table top structure. */
struct route_table {
#include "memory.h"
#include "termtable.h"
-DEFINE_MTYPE_STATIC(LIB, TTABLE, "ASCII table")
+DEFINE_MTYPE_STATIC(LIB, TTABLE, "ASCII table");
/* clang-format off */
const struct ttable_style ttable_styles[] = {
#include "libfrr_trace.h"
#include "libfrr.h"
-DEFINE_MTYPE_STATIC(LIB, THREAD, "Thread")
-DEFINE_MTYPE_STATIC(LIB, THREAD_MASTER, "Thread master")
-DEFINE_MTYPE_STATIC(LIB, THREAD_POLL, "Thread Poll Info")
-DEFINE_MTYPE_STATIC(LIB, THREAD_STATS, "Thread stats")
+DEFINE_MTYPE_STATIC(LIB, THREAD, "Thread");
+DEFINE_MTYPE_STATIC(LIB, THREAD_MASTER, "Thread master");
+DEFINE_MTYPE_STATIC(LIB, THREAD_POLL, "Thread Poll Info");
+DEFINE_MTYPE_STATIC(LIB, THREAD_STATS, "Thread stats");
-DECLARE_LIST(thread_list, struct thread, threaditem)
+DECLARE_LIST(thread_list, struct thread, threaditem);
struct cancel_req {
int flags;
return 0;
}
-DECLARE_HEAP(thread_timer_list, struct thread, timeritem, thread_timer_cmp)
+DECLARE_HEAP(thread_timer_list, struct thread, timeritem, thread_timer_cmp);
#if defined(__APPLE__)
#include <mach/mach.h>
#define GETRUSAGE(X) thread_getrusage(X)
-PREDECL_LIST(thread_list)
-PREDECL_HEAP(thread_timer_list)
+PREDECL_LIST(thread_list);
+PREDECL_HEAP(thread_timer_list);
struct fd_handler {
/* number of pfd that fit in the allocated space of pfds. This is a
#define _PREDECL_RBTREE(prefix) \
struct prefix ## _head { struct typed_rb_root rr; }; \
-struct prefix ## _item { struct typed_rb_entry re; };
+struct prefix ## _item { struct typed_rb_entry re; }; \
+MACRO_REQUIRE_SEMICOLON() /* end */
#define INIT_RBTREE_UNIQ(var) { }
#define INIT_RBTREE_NONUNIQ(var) { }
{ \
return h->rr.count; \
} \
-/* ... */
+MACRO_REQUIRE_SEMICOLON() /* end */
#define PREDECL_RBTREE_UNIQ(prefix) \
_PREDECL_RBTREE(prefix)
} \
TYPESAFE_FIND(prefix, type) \
\
-_DECLARE_RBTREE(prefix, type, field, prefix ## __cmp, prefix ## __cmp) \
-/* ... */
+_DECLARE_RBTREE(prefix, type, field, prefix ## __cmp, prefix ## __cmp); \
+MACRO_REQUIRE_SEMICOLON() /* end */
#define PREDECL_RBTREE_NONUNIQ(prefix) \
_PREDECL_RBTREE(prefix)
return 0; \
} \
\
-_DECLARE_RBTREE(prefix, type, field, prefix ## __cmp, prefix ## __cmp_uq) \
-/* ... */
+_DECLARE_RBTREE(prefix, type, field, prefix ## __cmp, prefix ## __cmp_uq); \
+MACRO_REQUIRE_SEMICOLON() /* end */
#ifdef __cplusplus
}
#include "memory.h"
#include "network.h"
-DEFINE_MTYPE_STATIC(LIB, TYPEDHASH_BUCKET, "Typed-hash bucket")
-DEFINE_MTYPE_STATIC(LIB, SKIPLIST_OFLOW, "Skiplist overflow")
-DEFINE_MTYPE_STATIC(LIB, HEAP_ARRAY, "Typed-heap array")
+DEFINE_MTYPE_STATIC(LIB, TYPEDHASH_BUCKET, "Typed-hash bucket");
+DEFINE_MTYPE_STATIC(LIB, SKIPLIST_OFLOW, "Skiplist overflow");
+DEFINE_MTYPE_STATIC(LIB, HEAP_ARRAY, "Typed-heap array");
#if 0
static void hash_consistency_check(struct thash_head *head)
/* use as:
*
- * PREDECL_LIST(namelist)
+ * PREDECL_LIST(namelist);
* struct name {
* struct namelist_item nlitem;
* }
- * DECLARE_LIST(namelist, struct name, nlitem)
+ * DECLARE_LIST(namelist, struct name, nlitem);
*/
#define PREDECL_LIST(prefix) \
struct prefix ## _head { struct slist_head sh; }; \
-struct prefix ## _item { struct slist_item si; };
+struct prefix ## _item { struct slist_item si; }; \
+MACRO_REQUIRE_SEMICOLON() /* end */
#define INIT_LIST(var) { .sh = { .last_next = &var.sh.first, }, }
{ \
return h->sh.count; \
} \
-/* ... */
+MACRO_REQUIRE_SEMICOLON() /* end */
/* don't use these structs directly */
struct dlist_item {
*/
#define PREDECL_DLIST(prefix) \
struct prefix ## _head { struct dlist_head dh; }; \
-struct prefix ## _item { struct dlist_item di; };
+struct prefix ## _item { struct dlist_item di; }; \
+MACRO_REQUIRE_SEMICOLON() /* end */
#define INIT_DLIST(var) { .dh = { \
.hitem = { &var.dh.hitem, &var.dh.hitem }, }, }
{ \
return h->dh.count; \
} \
-/* ... */
+MACRO_REQUIRE_SEMICOLON() /* end */
/* note: heap currently caps out at 4G items */
#define PREDECL_HEAP(prefix) \
struct prefix ## _head { struct heap_head hh; }; \
-struct prefix ## _item { struct heap_item hi; };
+struct prefix ## _item { struct heap_item hi; }; \
+MACRO_REQUIRE_SEMICOLON() /* end */
#define INIT_HEAP(var) { }
{ \
return h->hh.count; \
} \
-/* ... */
+MACRO_REQUIRE_SEMICOLON() /* end */
extern void typesafe_heap_resize(struct heap_head *head, bool grow);
extern void typesafe_heap_pushdown(struct heap_head *head, uint32_t index,
*/
#define _PREDECL_SORTLIST(prefix) \
struct prefix ## _head { struct ssort_head sh; }; \
-struct prefix ## _item { struct ssort_item si; };
+struct prefix ## _item { struct ssort_item si; }; \
+MACRO_REQUIRE_SEMICOLON() /* end */
#define INIT_SORTLIST_UNIQ(var) { }
#define INIT_SORTLIST_NONUNIQ(var) { }
{ \
return h->sh.count; \
} \
-/* ... */
+MACRO_REQUIRE_SEMICOLON() /* end */
#define DECLARE_SORTLIST_UNIQ(prefix, type, field, cmpfn) \
- _DECLARE_SORTLIST(prefix, type, field, cmpfn, cmpfn) \
+ _DECLARE_SORTLIST(prefix, type, field, cmpfn, cmpfn); \
\
macro_inline const type *prefix ## _const_find(const struct prefix##_head *h, \
const type *item) \
return container_of(sitem, type, field.si); \
} \
TYPESAFE_FIND(prefix, type) \
-/* ... */
+MACRO_REQUIRE_SEMICOLON() /* end */
#define DECLARE_SORTLIST_NONUNIQ(prefix, type, field, cmpfn) \
macro_inline int _ ## prefix ## _cmp(const type *a, const type *b) \
return 1; \
return 0; \
} \
- _DECLARE_SORTLIST(prefix, type, field, cmpfn, _ ## prefix ## _cmp) \
-/* ... */
+ _DECLARE_SORTLIST(prefix, type, field, cmpfn, _ ## prefix ## _cmp); \
+MACRO_REQUIRE_SEMICOLON() /* end */
/* hash, "sorted" by hash value
*/
#define PREDECL_HASH(prefix) \
struct prefix ## _head { struct thash_head hh; }; \
-struct prefix ## _item { struct thash_item hi; };
+struct prefix ## _item { struct thash_item hi; }; \
+MACRO_REQUIRE_SEMICOLON() /* end */
#define INIT_HASH(var) { }
{ \
return h->hh.count; \
} \
-/* ... */
+MACRO_REQUIRE_SEMICOLON() /* end */
/* skiplist, sorted.
* can be used as priority queue with add / pop
*/
#define _PREDECL_SKIPLIST(prefix) \
struct prefix ## _head { struct sskip_head sh; }; \
-struct prefix ## _item { struct sskip_item si; };
+struct prefix ## _item { struct sskip_item si; }; \
+MACRO_REQUIRE_SEMICOLON() /* end */
#define INIT_SKIPLIST_UNIQ(var) { }
#define INIT_SKIPLIST_NONUNIQ(var) { }
{ \
return h->sh.count; \
} \
-/* ... */
+MACRO_REQUIRE_SEMICOLON() /* end */
#define PREDECL_SKIPLIST_UNIQ(prefix) \
_PREDECL_SKIPLIST(prefix)
TYPESAFE_FIND(prefix, type) \
\
_DECLARE_SKIPLIST(prefix, type, field, \
- prefix ## __cmp, prefix ## __cmp) \
-/* ... */
+ prefix ## __cmp, prefix ## __cmp); \
+MACRO_REQUIRE_SEMICOLON() /* end */
#define PREDECL_SKIPLIST_NONUNIQ(prefix) \
_PREDECL_SKIPLIST(prefix)
} \
\
_DECLARE_SKIPLIST(prefix, type, field, \
- prefix ## __cmp, prefix ## __cmp_uq) \
-/* ... */
+ prefix ## __cmp, prefix ## __cmp_uq); \
+MACRO_REQUIRE_SEMICOLON() /* end */
extern struct sskip_item *typesafe_skiplist_add(struct sskip_head *head,
#include "vector.h"
#include "memory.h"
-DEFINE_MTYPE_STATIC(LIB, VECTOR, "Vector")
-DEFINE_MTYPE_STATIC(LIB, VECTOR_INDEX, "Vector index")
+DEFINE_MTYPE_STATIC(LIB, VECTOR, "Vector");
+DEFINE_MTYPE_STATIC(LIB, VECTOR_INDEX, "Vector index");
/* Initialize vector : allocate memory and return vector. */
vector vector_init(unsigned int size)
/* default VRF name value used when VRF backend is not NETNS */
#define VRF_DEFAULT_NAME_INTERNAL "default"
-DEFINE_MTYPE_STATIC(LIB, VRF, "VRF")
-DEFINE_MTYPE_STATIC(LIB, VRF_BITMAP, "VRF bit-map")
+DEFINE_MTYPE_STATIC(LIB, VRF, "VRF");
+DEFINE_MTYPE_STATIC(LIB, VRF_BITMAP, "VRF bit-map");
-DEFINE_QOBJ_TYPE(vrf)
+DEFINE_QOBJ_TYPE(vrf);
static __inline int vrf_id_compare(const struct vrf *, const struct vrf *);
static __inline int vrf_name_compare(const struct vrf *, const struct vrf *);
/* Back pointer to namespace context */
void *ns_ctxt;
- QOBJ_FIELDS
+ QOBJ_FIELDS;
};
RB_HEAD(vrf_id_head, vrf);
RB_PROTOTYPE(vrf_id_head, vrf, id_entry, vrf_id_compare)
RB_HEAD(vrf_name_head, vrf);
RB_PROTOTYPE(vrf_name_head, vrf, name_entry, vrf_name_compare)
-DECLARE_QOBJ_TYPE(vrf)
+DECLARE_QOBJ_TYPE(vrf);
/* Allow VRF with netns as backend */
enum vrf_backend_type {
#include "lib/vty_clippy.c"
#endif
-DEFINE_MTYPE_STATIC(LIB, VTY, "VTY")
-DEFINE_MTYPE_STATIC(LIB, VTY_OUT_BUF, "VTY output buffer")
-DEFINE_MTYPE_STATIC(LIB, VTY_HIST, "VTY history")
+DEFINE_MTYPE_STATIC(LIB, VTY, "VTY");
+DEFINE_MTYPE_STATIC(LIB, VTY_OUT_BUF, "VTY output buffer");
+DEFINE_MTYPE_STATIC(LIB, VTY_HIST, "VTY history");
/* Vty events */
enum event {
#include "wheel.h"
#include "log.h"
-DEFINE_MTYPE_STATIC(LIB, TIMER_WHEEL, "Timer Wheel")
-DEFINE_MTYPE_STATIC(LIB, TIMER_WHEEL_LIST, "Timer Wheel Slot List")
+DEFINE_MTYPE_STATIC(LIB, TIMER_WHEEL, "Timer Wheel");
+DEFINE_MTYPE_STATIC(LIB, TIMER_WHEEL_LIST, "Timer Wheel Slot List");
static int debug_timer_wheel = 0;
#include "command.h"
#include "log.h"
-DEFINE_MTYPE(LIB, WORK_QUEUE, "Work queue")
-DEFINE_MTYPE_STATIC(LIB, WORK_QUEUE_ITEM, "Work queue item")
-DEFINE_MTYPE_STATIC(LIB, WORK_QUEUE_NAME, "Work queue name string")
+DEFINE_MTYPE(LIB, WORK_QUEUE, "Work queue");
+DEFINE_MTYPE_STATIC(LIB, WORK_QUEUE_ITEM, "Work queue item");
+DEFINE_MTYPE_STATIC(LIB, WORK_QUEUE_NAME, "Work queue name string");
/* master list of work_queues */
static struct list _work_queues;
extern "C" {
#endif
-DECLARE_MTYPE(WORK_QUEUE)
+DECLARE_MTYPE(WORK_QUEUE);
/* Hold time for the initial schedule of a queue run, in millisec */
#define WORK_QUEUE_DEFAULT_HOLD 50
q = memrchr(filename, '/', p - filename);
if (q)
filename = q + 1;
- else
- filename = p + 1;
}
SHA256_Init(&sha);
xref_block_add(&_xref_block); \
} \
asm(XREF_NOTE); \
- /* end */
+ MACRO_REQUIRE_SEMICOLON() /* end */
/* the following blurb emits an ELF note indicating start and end of the xref
* array in the binary. This is technically the "correct" entry point for
#include <libyang/user_types.h>
-DEFINE_MTYPE_STATIC(LIB, YANG_MODULE, "YANG module")
-DEFINE_MTYPE_STATIC(LIB, YANG_DATA, "YANG data structure")
+DEFINE_MTYPE_STATIC(LIB, YANG_MODULE, "YANG module");
+DEFINE_MTYPE_STATIC(LIB, YANG_DATA, "YANG data structure");
/* libyang container. */
struct ly_ctx *ly_native_ctx;
#include "yang_translator.h"
#include "frrstr.h"
-DEFINE_MTYPE_STATIC(LIB, YANG_TRANSLATOR, "YANG Translator")
-DEFINE_MTYPE_STATIC(LIB, YANG_TRANSLATOR_MODULE, "YANG Translator Module")
-DEFINE_MTYPE_STATIC(LIB, YANG_TRANSLATOR_MAPPING, "YANG Translator Mapping")
+DEFINE_MTYPE_STATIC(LIB, YANG_TRANSLATOR, "YANG Translator");
+DEFINE_MTYPE_STATIC(LIB, YANG_TRANSLATOR_MODULE, "YANG Translator Module");
+DEFINE_MTYPE_STATIC(LIB, YANG_TRANSLATOR_MAPPING, "YANG Translator Mapping");
/* Generate the yang_translators tree. */
static inline int yang_translator_compare(const struct yang_translator *a,
__attribute__((noreturn));
#undef __ASSERT_FUNCTION
-
-#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
#define __ASSERT_FUNCTION __func__
-#elif defined(__GNUC__)
-#define __ASSERT_FUNCTION __FUNCTION__
-#else
-#define __ASSERT_FUNCTION NULL
-#endif
#define zassert(EX) \
((void)((EX) ? 0 : (_zlog_assert_failed(#EX, __FILE__, __LINE__, \
#include "srte.h"
#include "printfrr.h"
-DEFINE_MTYPE_STATIC(LIB, ZCLIENT, "Zclient")
-DEFINE_MTYPE_STATIC(LIB, REDIST_INST, "Redistribution instance IDs")
+DEFINE_MTYPE_STATIC(LIB, ZCLIENT, "Zclient");
+DEFINE_MTYPE_STATIC(LIB, REDIST_INST, "Redistribution instance IDs");
/* Zebra client events. */
enum event { ZCLIENT_SCHEDULE, ZCLIENT_READ, ZCLIENT_CONNECT };
/* misc include group */
#include <stdarg.h>
-#if !(defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)
-/* Not C99; do we need to define va_copy? */
-#ifndef va_copy
-#ifdef __va_copy
-#define va_copy(DST,SRC) __va_copy(DST,SRC)
-#else
-/* Now we are desperate; this should work on many typical platforms.
- But this is slightly dangerous, because the standard does not require
- va_copy to be a macro. */
-#define va_copy(DST,SRC) memcpy(&(DST), &(SRC), sizeof(va_list))
-#warning "Not C99 and no va_copy macro available, falling back to memcpy"
-#endif /* __va_copy */
-#endif /* !va_copy */
-#endif /* !C99 */
-
#ifdef HAVE_LCAPS
#include <sys/capability.h>
#include "zlog.h"
#include "libfrr_trace.h"
-DEFINE_MTYPE_STATIC(LIB, LOG_MESSAGE, "log message")
-DEFINE_MTYPE_STATIC(LIB, LOG_TLSBUF, "log thread-local buffer")
+DEFINE_MTYPE_STATIC(LIB, LOG_MESSAGE, "log message");
+DEFINE_MTYPE_STATIC(LIB, LOG_TLSBUF, "log thread-local buffer");
DEFINE_HOOK(zlog_init, (const char *progname, const char *protoname,
unsigned short instance, uid_t uid, gid_t gid),
- (progname, protoname, instance, uid, gid))
-DEFINE_KOOH(zlog_fini, (), ())
+ (progname, protoname, instance, uid, gid));
+DEFINE_KOOH(zlog_fini, (), ());
DEFINE_HOOK(zlog_aux_init, (const char *prefix, int prio_min),
- (prefix, prio_min))
+ (prefix, prio_min));
char zlog_prefix[128];
size_t zlog_prefixsz;
int zlog_tmpdirfd = -1;
+static atomic_bool zlog_ec = true, zlog_xid = true;
+
/* these are kept around because logging is initialized (and directories
* & files created) before zprivs code switches to the FRR user; therefore
* we need to chown() things so we don't get permission errors later when
{
if (!msg->text) {
va_list args;
+ bool do_xid, do_ec;
+ size_t need = 0, hdrlen;
+ struct fbuf fb = {
+ .buf = msg->stackbuf,
+ .pos = msg->stackbuf,
+ .len = msg->stackbufsz,
+ };
+
+ do_ec = atomic_load_explicit(&zlog_ec, memory_order_relaxed);
+ do_xid = atomic_load_explicit(&zlog_xid, memory_order_relaxed);
+
+ if (msg->xref && do_xid && msg->xref->xref.xrefdata->uid[0]) {
+ need += bputch(&fb, '[');
+ need += bputs(&fb, msg->xref->xref.xrefdata->uid);
+ need += bputch(&fb, ']');
+ }
+ if (msg->xref && do_ec && msg->xref->ec)
+ need += bprintfrr(&fb, "[EC %u]", msg->xref->ec);
+ if (need)
+ need += bputch(&fb, ' ');
+
+ hdrlen = need;
+ assert(hdrlen < msg->stackbufsz);
va_copy(args, msg->args);
- msg->text = vasnprintfrr(MTYPE_LOG_MESSAGE, msg->stackbuf,
- msg->stackbufsz, msg->fmt, args);
- msg->textlen = strlen(msg->text);
+ need += vbprintfrr(&fb, msg->fmt, args);
va_end(args);
+
+ msg->textlen = need;
+ need += bputch(&fb, '\0');
+
+ if (need <= msg->stackbufsz)
+ msg->text = msg->stackbuf;
+ else {
+ msg->text = XMALLOC(MTYPE_LOG_MESSAGE, need);
+
+ memcpy(msg->text, msg->stackbuf, hdrlen);
+
+ fb.buf = msg->text;
+ fb.len = need;
+ fb.pos = msg->text + hdrlen;
+
+ va_copy(args, msg->args);
+ vbprintfrr(&fb, msg->fmt, args);
+ va_end(args);
+
+ bputch(&fb, '\0');
+ }
}
if (textlen)
*textlen = msg->textlen;
}
}
+void zlog_set_prefix_ec(bool enable)
+{
+ atomic_store_explicit(&zlog_ec, enable, memory_order_relaxed);
+}
+
+bool zlog_get_prefix_ec(void)
+{
+ return atomic_load_explicit(&zlog_ec, memory_order_relaxed);
+}
+
+void zlog_set_prefix_xid(bool enable)
+{
+ atomic_store_explicit(&zlog_xid, enable, memory_order_relaxed);
+}
+
+bool zlog_get_prefix_xid(void)
+{
+ return atomic_load_explicit(&zlog_xid, memory_order_relaxed);
+}
+
/* setup functions */
struct zlog_target *zlog_target_clone(struct memtype *mt,
va_end(ap);
}
-#define _zlog_ref(prio, msg, ...) \
- do { \
- static struct xrefdata _xrefdata = { \
- .xref = NULL, \
- .uid = {}, \
- .hashstr = (msg), \
- .hashu32 = {(prio), 0}, \
- }; \
- static const struct xref_logmsg _xref __attribute__( \
- (used)) = { \
- .xref = XREF_INIT(XREFT_LOGMSG, &_xrefdata, __func__), \
- .fmtstring = (msg), \
- .priority = (prio), \
- .args = (#__VA_ARGS__), \
- }; \
- XREF_LINK(_xref.xref); \
- zlog_ref(&_xref, (msg), ##__VA_ARGS__); \
- } while (0)
-
-#define zlog_err(...) _zlog_ref(LOG_ERR, __VA_ARGS__)
-#define zlog_warn(...) _zlog_ref(LOG_WARNING, __VA_ARGS__)
-#define zlog_info(...) _zlog_ref(LOG_INFO, __VA_ARGS__)
-#define zlog_notice(...) _zlog_ref(LOG_NOTICE, __VA_ARGS__)
-#define zlog_debug(...) _zlog_ref(LOG_DEBUG, __VA_ARGS__)
-
#define _zlog_ecref(ec_, prio, msg, ...) \
do { \
static struct xrefdata _xrefdata = { \
.args = (#__VA_ARGS__), \
}; \
XREF_LINK(_xref.xref); \
- zlog_ref(&_xref, "[EC %u] " msg, ec_, ##__VA_ARGS__); \
+ zlog_ref(&_xref, (msg), ##__VA_ARGS__); \
} while (0)
+#define zlog_err(...) _zlog_ecref(0, LOG_ERR, __VA_ARGS__)
+#define zlog_warn(...) _zlog_ecref(0, LOG_WARNING, __VA_ARGS__)
+#define zlog_info(...) _zlog_ecref(0, LOG_INFO, __VA_ARGS__)
+#define zlog_notice(...) _zlog_ecref(0, LOG_NOTICE, __VA_ARGS__)
+#define zlog_debug(...) _zlog_ecref(0, LOG_DEBUG, __VA_ARGS__)
+
#define flog_err(ferr_id, format, ...) \
_zlog_ecref(ferr_id, LOG_ERR, format, ## __VA_ARGS__)
#define flog_warn(ferr_id, format, ...) \
_zlog_ecref(ferr_id, LOG_WARNING, format, ## __VA_ARGS__)
#define flog_err_sys(ferr_id, format, ...) \
- flog_err(ferr_id, format, ##__VA_ARGS__)
-#define flog(priority, ferr_id, format, ...) \
- zlog(priority, "[EC %u] " format, ferr_id, ##__VA_ARGS__)
+ _zlog_ecref(ferr_id, LOG_ERR, format, ## __VA_ARGS__)
extern void zlog_sigsafe(const char *text, size_t len);
* additional options. It MUST be the first field in that larger struct.
*/
-PREDECL_ATOMLIST(zlog_targets)
+PREDECL_ATOMLIST(zlog_targets);
struct zlog_target {
struct zlog_targets_item head;
unsigned short instance, uid_t uid, gid_t gid);
DECLARE_HOOK(zlog_init, (const char *progname, const char *protoname,
unsigned short instance, uid_t uid, gid_t gid),
- (progname, protoname, instance, uid, gid))
+ (progname, protoname, instance, uid, gid));
extern void zlog_fini(void);
-DECLARE_KOOH(zlog_fini, (), ())
+DECLARE_KOOH(zlog_fini, (), ());
+
+extern void zlog_set_prefix_ec(bool enable);
+extern bool zlog_get_prefix_ec(void);
+extern void zlog_set_prefix_xid(bool enable);
+extern bool zlog_get_prefix_xid(void);
/* for tools & test programs, i.e. anything not a daemon.
* (no cleanup needed at exit)
*/
extern void zlog_aux_init(const char *prefix, int prio_min);
DECLARE_HOOK(zlog_aux_init, (const char *prefix, int prio_min),
- (prefix, prio_min))
+ (prefix, prio_min));
extern void zlog_startup_end(void);
* absolute end.
*/
-DECLARE_MGROUP(LOG)
-DEFINE_MGROUP_ACTIVEATEXIT(LOG, "logging subsystem")
+DECLARE_MGROUP(LOG);
+DEFINE_MGROUP_ACTIVEATEXIT(LOG, "logging subsystem");
-DEFINE_MTYPE_STATIC(LOG, LOG_FD, "log file target")
-DEFINE_MTYPE_STATIC(LOG, LOG_FD_NAME, "log file name")
-DEFINE_MTYPE_STATIC(LOG, LOG_FD_ROTATE, "log file rotate helper")
-DEFINE_MTYPE_STATIC(LOG, LOG_SYSL, "syslog target")
+DEFINE_MTYPE_STATIC(LOG, LOG_FD, "log file target");
+DEFINE_MTYPE_STATIC(LOG, LOG_FD_NAME, "log file name");
+DEFINE_MTYPE_STATIC(LOG, LOG_FD_ROTATE, "log file rotate helper");
+DEFINE_MTYPE_STATIC(LOG, LOG_SYSL, "syslog target");
struct zlt_fd {
struct zlog_target zt;
# functions on Solaris that doesn't have a non-functional libc stub.
# We try pthread_create on general principles.
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>
- static void routine(void *a) { a = 0; }
+ static void routine(void *a) { if (a) a = 0; }
static void *start_routine(void *a) { return a; }],
[pthread_t th; pthread_attr_t attr;
pthread_create(&th, 0, start_routine, 0);
extern unsigned int debug_flags;
-#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
-
#define debugf(level, ...) \
do { \
if (unlikely(debug_flags & level)) \
zlog_debug(__VA_ARGS__); \
} while (0)
-
-#elif defined __GNUC__
-
-#define debugf(level, _args...) \
- do { \
- if (unlikely(debug_flags & level)) \
- zlog_debug(_args); \
- } while (0)
-
-#else
-
-static inline void debugf(int level, const char *format, ...)
-{
-}
-
-#endif
#include "netlink.h"
-DEFINE_MTYPE_STATIC(NHRPD, NHRP_CACHE, "NHRP cache entry")
-DEFINE_MTYPE_STATIC(NHRPD, NHRP_CACHE_CONFIG, "NHRP cache config entry")
+DEFINE_MTYPE_STATIC(NHRPD, NHRP_CACHE, "NHRP cache entry");
+DEFINE_MTYPE_STATIC(NHRPD, NHRP_CACHE_CONFIG, "NHRP cache config entry");
unsigned long nhrp_cache_counts[NHRP_CACHE_NUM_TYPES];
#include "os.h"
#include "netlink.h"
-DEFINE_MTYPE_STATIC(NHRPD, NHRP_IF, "NHRP interface")
+DEFINE_MTYPE_STATIC(NHRPD, NHRP_IF, "NHRP interface");
static void nhrp_interface_update_cache_config(struct interface *ifp,
bool available,
{
struct nhrp_interface *nifp = ifp->info;
- if (nifp->ipsec_profile)
+ if (nifp->ipsec_profile) {
+ vici_terminate_vc_by_profile_name(nifp->ipsec_profile);
+ nhrp_vc_reset();
free(nifp->ipsec_profile);
+ }
nifp->ipsec_profile = profile ? strdup(profile) : NULL;
- if (nifp->ipsec_fallback_profile)
+ if (nifp->ipsec_fallback_profile) {
+ vici_terminate_vc_by_profile_name(nifp->ipsec_fallback_profile);
+ nhrp_vc_reset();
free(nifp->ipsec_fallback_profile);
+ }
nifp->ipsec_fallback_profile =
fallback_profile ? strdup(fallback_profile) : NULL;
- notifier_call(&nifp->notifier_list, NOTIFY_INTERFACE_ADDRESS_CHANGED);
+ notifier_call(&nifp->notifier_list, NOTIFY_INTERFACE_IPSEC_CHANGED);
}
void nhrp_interface_set_source(struct interface *ifp, const char *ifname)
#include "netlink.h"
#include "nhrp_errors.h"
-DEFINE_MGROUP(NHRPD, "NHRP")
+DEFINE_MGROUP(NHRPD, "NHRP");
unsigned int debug_flags = 0;
.signals = sighandlers, .n_signals = array_size(sighandlers),
.privs = &nhrpd_privs, .yang_modules = nhrpd_yang_modules,
- .n_yang_modules = array_size(nhrpd_yang_modules), )
+ .n_yang_modules = array_size(nhrpd_yang_modules),
+);
int main(int argc, char **argv)
{
#include "nhrpd.h"
#include "nhrp_protocol.h"
-DEFINE_MTYPE_STATIC(NHRPD, NHRP_NHS, "NHRP next hop server")
-DEFINE_MTYPE_STATIC(NHRPD, NHRP_REGISTRATION, "NHRP registration entries")
+DEFINE_MTYPE_STATIC(NHRPD, NHRP_NHS, "NHRP next hop server");
+DEFINE_MTYPE_STATIC(NHRPD, NHRP_REGISTRATION, "NHRP registration entries");
static int nhrp_nhs_resolve(struct thread *t);
static int nhrp_reg_send_req(struct thread *t);
}
r->timeout <<= 1;
- if (r->timeout > 64)
+ if (r->timeout > 64) {
+ /* If registration fails repeatedly, this may be because the
+ * IPSec connection is not working. Close the connection so it
+ * can be re-established correctly
+ */
+ if (r->peer && r->peer->vc && r->peer->vc->ike_uniqueid) {
+ debugf(NHRP_DEBUG_COMMON,
+ "Terminating IPSec Connection for %d",
+ r->peer->vc->ike_uniqueid);
+ vici_terminate_vc_by_ike_id(r->peer->vc->ike_uniqueid);
+ r->peer->vc->ike_uniqueid = 0;
+ }
r->timeout = 2;
+ }
thread_add_timer_msec(master, nhrp_reg_send_req, r, 10, &r->t_register);
return 0;
#include "nhrp_protocol.h"
#include "os.h"
-DEFINE_MTYPE_STATIC(NHRPD, NHRP_PEER, "NHRP peer entry")
+DEFINE_MTYPE_STATIC(NHRPD, NHRP_PEER, "NHRP peer entry");
struct ipv6hdr {
uint8_t priority_version;
case NOTIFY_INTERFACE_ADDRESS_CHANGED:
notifier_call(&p->notifier_list, NOTIFY_PEER_IFCONFIG_CHANGED);
break;
+ case NOTIFY_INTERFACE_IPSEC_CHANGED:
+ __nhrp_peer_check(p);
+ notifier_call(&p->notifier_list, NOTIFY_PEER_IFCONFIG_CHANGED);
+ break;
case NOTIFY_INTERFACE_MTU_CHANGED:
notifier_call(&p->notifier_list, NOTIFY_PEER_MTU_CHANGED);
break;
#include "log.h"
#include "zclient.h"
-DEFINE_MTYPE_STATIC(NHRPD, NHRP_ROUTE, "NHRP routing entry")
+DEFINE_MTYPE_STATIC(NHRPD, NHRP_ROUTE, "NHRP routing entry");
static struct zclient *zclient;
static struct route_table *zebra_rib[AFI_MAX];
#include "log.h"
#include "nhrp_protocol.h"
-DEFINE_MTYPE_STATIC(NHRPD, NHRP_SHORTCUT, "NHRP shortcut")
+DEFINE_MTYPE_STATIC(NHRPD, NHRP_SHORTCUT, "NHRP shortcut");
static struct route_table *shortcut_rib[AFI_MAX];
#include "nhrpd.h"
#include "os.h"
-DEFINE_MTYPE_STATIC(NHRPD, NHRP_VC, "NHRP virtual connection")
+DEFINE_MTYPE_STATIC(NHRPD, NHRP_VC, "NHRP virtual connection");
struct child_sa {
uint32_t id;
#include "memory.h"
#include "resolver.h"
-DECLARE_MGROUP(NHRPD)
+DECLARE_MGROUP(NHRPD);
#define NHRPD_DEFAULT_HOLDTIME 7200
NOTIFY_INTERFACE_ADDRESS_CHANGED,
NOTIFY_INTERFACE_NBMA_CHANGED,
NOTIFY_INTERFACE_MTU_CHANGED,
+ NOTIFY_INTERFACE_IPSEC_CHANGED,
NOTIFY_VC_IPSEC_CHANGED,
NOTIFY_VC_IPSEC_UPDATE_NBMA,
struct nhrp_vc {
struct notifier_list notifier_list;
uint32_t ipsec;
+ uint32_t ike_uniqueid;
uint8_t updating;
uint8_t abort_migration;
void vici_init(void);
void vici_terminate(void);
+void vici_terminate_vc_by_profile_name(char *profile_name);
+void vici_terminate_vc_by_ike_id(unsigned int ike_id);
void vici_request_vc(const char *profile, union sockunion *src,
union sockunion *dst, int prio);
nhrp_vc_ipsec_updown(
sactx->child_uniqueid,
vc);
+ vc->ike_uniqueid = sactx->ike_uniqueid;
}
} else {
nhrp_vc_ipsec_updown(sactx->child_uniqueid, 0);
{
}
+void vici_terminate_vc_by_profile_name(char *profile_name)
+{
+ struct vici_conn *vici = &vici_connection;
+
+ debugf(NHRP_DEBUG_VICI, "Terminate profile = %s", profile_name);
+ vici_submit_request(vici, "terminate", VICI_KEY_VALUE, "ike",
+ strlen(profile_name), profile_name, VICI_END);
+}
+
+void vici_terminate_vc_by_ike_id(unsigned int ike_id)
+{
+ struct vici_conn *vici = &vici_connection;
+ char ike_id_str[10];
+
+ snprintf(ike_id_str, sizeof(ike_id_str), "%d", ike_id);
+ debugf(NHRP_DEBUG_VICI, "Terminate ike_id_str = %s", ike_id_str);
+ vici_submit_request(vici, "terminate", VICI_KEY_VALUE, "ike-id",
+ strlen(ike_id_str), ike_id_str, VICI_END);
+}
+
void vici_request_vc(const char *profile, union sockunion *src,
union sockunion *dst, int prio)
{
#define ERRNO_IO_RETRY(EN) (((EN) == EAGAIN) || ((EN) == EWOULDBLOCK) || ((EN) == EINTR))
-DEFINE_MTYPE_STATIC(NHRPD, ZBUF_DATA, "NHRPD zbuf data")
+DEFINE_MTYPE_STATIC(NHRPD, ZBUF_DATA, "NHRPD zbuf data");
struct zbuf *zbuf_alloc(size_t size)
{
#include "ospf6d.h"
#include "lib/json.h"
-DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_PLISTNAME, "Prefix list name")
+DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_AREA, "OSPF6 area");
+DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_PLISTNAME, "Prefix list name");
int ospf6_area_cmp(void *va, void *vb)
{
#include "ospf6d.h"
#include "lib/json.h"
+DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_EXTERNAL_INFO, "OSPF6 ext. info");
+DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_DIST_ARGS, "OSPF6 Distribute arguments");
+DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_REDISTRIBUTE, "OSPF6 Redistribute arguments");
+
static void ospf6_asbr_redistribute_set(int type, vrf_id_t vrf_id);
static void ospf6_asbr_redistribute_unset(struct ospf6 *ospf6,
struct ospf6_redist *red, int type);
struct listnode *node, *nnode;
struct ospf6_area *area;
struct ospf6 *ospf6 = oa->ospf6;
-
+ const struct route_node *iterend;
/* skip if router is in other non-stub areas */
for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, area))
return;
/* if router is only in a stub area then purge AS-External LSAs */
- for (ALL_LSDB(oa->ospf6->lsdb, lsa, lsanext)) {
+ iterend = ospf6_lsdb_head(ospf6->lsdb, 0, 0, 0, &lsa);
+ while (lsa != NULL) {
+ lsanext = ospf6_lsdb_next(iterend, lsa);
if (ntohs(lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL)
ospf6_lsdb_remove(lsa, ospf6->lsdb);
+ lsa = lsanext;
}
}
#include "ospf6_zebra.h"
#include "lib/json.h"
-DEFINE_MTYPE_STATIC(OSPF6D, CFG_PLIST_NAME, "configured prefix list names")
-DEFINE_QOBJ_TYPE(ospf6_interface)
+DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_IF, "OSPF6 interface");
+DEFINE_MTYPE_STATIC(OSPF6D, CFG_PLIST_NAME, "configured prefix list names");
+DEFINE_QOBJ_TYPE(ospf6_interface);
DEFINE_HOOK(ospf6_interface_change,
(struct ospf6_interface * oi, int state, int old_state),
- (oi, state, old_state))
+ (oi, state, old_state));
unsigned char conf_debug_ospf6_interface = 0;
return CMD_WARNING;
}
+ if (CHECK_FLAG(oi->flag, OSPF6_INTERFACE_DISABLE)) {
+ vty_out(vty, "Interface %s not attached to area\n",
+ argv[idx_ifname]->arg);
+ return CMD_WARNING;
+ }
+
ospf6_route_table_show(vty, idx_prefix, argc, argv, oi->route_connected,
uj);
FOR_ALL_INTERFACES (vrf, ifp) {
oi = (struct ospf6_interface *)ifp->info;
- if (oi == NULL)
+ if (oi == NULL || CHECK_FLAG(oi->flag, OSPF6_INTERFACE_DISABLE))
continue;
ospf6_route_table_show(vty, idx_prefix, argc, argv,
uint32_t ls_ack_out;
uint32_t discarded;
- QOBJ_FIELDS
+ QOBJ_FIELDS;
};
-DECLARE_QOBJ_TYPE(ospf6_interface)
+DECLARE_QOBJ_TYPE(ospf6_interface);
/* interface state */
#define OSPF6_INTERFACE_NONE 0
DECLARE_HOOK(ospf6_interface_change,
(struct ospf6_interface * oi, int state, int old_state),
- (oi, state, old_state))
+ (oi, state, old_state));
#endif /* OSPF6_INTERFACE_H */
#include "ospf6_flood.h"
#include "ospf6d.h"
+DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_LSA, "OSPF6 LSA");
+DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_LSA_HEADER, "OSPF6 LSA header");
+DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_LSA_SUMMARY, "OSPF6 LSA summary");
+
vector ospf6_lsa_handler_vector;
struct ospf6 *ospf6_get_by_lsdb(struct ospf6_lsa *lsa)
vty_out(vty, "\n");
}
+struct ospf6_lsa *ospf6_lsa_alloc(size_t lsa_length)
+{
+ struct ospf6_lsa *lsa;
+
+ lsa = XCALLOC(MTYPE_OSPF6_LSA, sizeof(struct ospf6_lsa));
+ lsa->header = XMALLOC(MTYPE_OSPF6_LSA_HEADER, lsa_length);
+
+ return lsa;
+}
+
/* OSPFv3 LSA creation/deletion function */
struct ospf6_lsa *ospf6_lsa_create(struct ospf6_lsa_header *header)
{
struct ospf6_lsa *lsa = NULL;
- struct ospf6_lsa_header *new_header = NULL;
uint16_t lsa_size = 0;
/* size of the entire LSA */
lsa_size = ntohs(header->length); /* XXX vulnerable */
- /* allocate memory for this LSA */
- new_header = XMALLOC(MTYPE_OSPF6_LSA_HEADER, lsa_size);
+ lsa = ospf6_lsa_alloc(lsa_size);
/* copy LSA from original header */
- memcpy(new_header, header, lsa_size);
-
- /* LSA information structure */
- /* allocate memory */
- lsa = XCALLOC(MTYPE_OSPF6_LSA, sizeof(struct ospf6_lsa));
-
- lsa->header = new_header;
+ memcpy(lsa->header, header, lsa_size);
/* dump string */
ospf6_lsa_printbuf(lsa, lsa->name, sizeof(lsa->name));
struct ospf6_lsa *ospf6_lsa_create_headeronly(struct ospf6_lsa_header *header)
{
struct ospf6_lsa *lsa = NULL;
- struct ospf6_lsa_header *new_header = NULL;
- /* allocate memory for this LSA */
- new_header = XMALLOC(MTYPE_OSPF6_LSA_HEADER,
- sizeof(struct ospf6_lsa_header));
+ lsa = ospf6_lsa_alloc(sizeof(struct ospf6_lsa_header));
- /* copy LSA from original header */
- memcpy(new_header, header, sizeof(struct ospf6_lsa_header));
-
- /* LSA information structure */
- /* allocate memory */
- lsa = XCALLOC(MTYPE_OSPF6_LSA, sizeof(struct ospf6_lsa));
+ memcpy(lsa->header, header, sizeof(struct ospf6_lsa_header));
- lsa->header = new_header;
SET_FLAG(lsa->flag, OSPF6_LSA_HEADERONLY);
/* dump string */
extern void ospf6_lsa_show(struct vty *vty, struct ospf6_lsa *lsa,
json_object *json, bool use_json);
+extern struct ospf6_lsa *ospf6_lsa_alloc(size_t lsa_length);
extern struct ospf6_lsa *ospf6_lsa_create(struct ospf6_lsa_header *header);
extern struct ospf6_lsa *
ospf6_lsa_create_headeronly(struct ospf6_lsa_header *header);
#include "ospf6d.h"
#include "bitfield.h"
+DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_LSDB, "OSPF6 LSA database");
+
struct ospf6_lsdb *ospf6_lsdb_create(void *data)
{
struct ospf6_lsdb *lsdb;
.n_signals = array_size(ospf6_signals),
.privs = &ospf6d_privs, .yang_modules = ospf6d_yang_modules,
- .n_yang_modules = array_size(ospf6d_yang_modules), )
+ .n_yang_modules = array_size(ospf6d_yang_modules),
+);
/* Main routine of ospf6d. Treatment of argument and starting ospf finite
state machine is handled here. */
+++ /dev/null
-/* ospf6d memory type definitions
- *
- * Copyright (C) 2015 David Lamparter
- *
- * This file is part of Quagga.
- *
- * Quagga is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * Quagga is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "ospf6_memory.h"
-
-DEFINE_MGROUP(OSPF6D, "ospf6d")
-DEFINE_MTYPE(OSPF6D, OSPF6_TOP, "OSPF6 top")
-DEFINE_MTYPE(OSPF6D, OSPF6_AREA, "OSPF6 area")
-DEFINE_MTYPE(OSPF6D, OSPF6_IF, "OSPF6 interface")
-DEFINE_MTYPE(OSPF6D, OSPF6_NEIGHBOR, "OSPF6 neighbor")
-DEFINE_MTYPE(OSPF6D, OSPF6_ROUTE, "OSPF6 route")
-DEFINE_MTYPE(OSPF6D, OSPF6_PREFIX, "OSPF6 prefix")
-DEFINE_MTYPE(OSPF6D, OSPF6_MESSAGE, "OSPF6 message")
-DEFINE_MTYPE(OSPF6D, OSPF6_LSA, "OSPF6 LSA")
-DEFINE_MTYPE(OSPF6D, OSPF6_LSA_HEADER, "OSPF6 LSA header")
-DEFINE_MTYPE(OSPF6D, OSPF6_LSA_SUMMARY, "OSPF6 LSA summary")
-DEFINE_MTYPE(OSPF6D, OSPF6_LSDB, "OSPF6 LSA database")
-DEFINE_MTYPE(OSPF6D, OSPF6_VERTEX, "OSPF6 vertex")
-DEFINE_MTYPE(OSPF6D, OSPF6_SPFTREE, "OSPF6 SPF tree")
-DEFINE_MTYPE(OSPF6D, OSPF6_NEXTHOP, "OSPF6 nexthop")
-DEFINE_MTYPE(OSPF6D, OSPF6_EXTERNAL_INFO, "OSPF6 ext. info")
-DEFINE_MTYPE(OSPF6D, OSPF6_PATH, "OSPF6 Path")
-DEFINE_MTYPE(OSPF6D, OSPF6_DIST_ARGS, "OSPF6 Distribute arguments")
-DEFINE_MTYPE(OSPF6D, OSPF6_OTHER, "OSPF6 other")
-DEFINE_MTYPE(OSPF6D, OSPF6_REDISTRIBUTE, "OSPF6 Redistribute arguments")
+++ /dev/null
-/* ospf6d memory type declarations
- *
- * Copyright (C) 2015 David Lamparter
- *
- * This file is part of Quagga.
- *
- * Quagga is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * Quagga is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef _QUAGGA_OSPF6_MEMORY_H
-#define _QUAGGA_OSPF6_MEMORY_H
-
-#include "memory.h"
-
-DECLARE_MGROUP(OSPF6D)
-DECLARE_MTYPE(OSPF6_TOP)
-DECLARE_MTYPE(OSPF6_AREA)
-DECLARE_MTYPE(OSPF6_IF)
-DECLARE_MTYPE(OSPF6_NEIGHBOR)
-DECLARE_MTYPE(OSPF6_ROUTE)
-DECLARE_MTYPE(OSPF6_PREFIX)
-DECLARE_MTYPE(OSPF6_MESSAGE)
-DECLARE_MTYPE(OSPF6_LSA)
-DECLARE_MTYPE(OSPF6_LSA_HEADER)
-DECLARE_MTYPE(OSPF6_LSA_SUMMARY)
-DECLARE_MTYPE(OSPF6_LSDB)
-DECLARE_MTYPE(OSPF6_VERTEX)
-DECLARE_MTYPE(OSPF6_SPFTREE)
-DECLARE_MTYPE(OSPF6_NEXTHOP)
-DECLARE_MTYPE(OSPF6_EXTERNAL_INFO)
-DECLARE_MTYPE(OSPF6_PATH)
-DECLARE_MTYPE(OSPF6_DIST_ARGS)
-DECLARE_MTYPE(OSPF6_REDISTRIBUTE)
-DECLARE_MTYPE(OSPF6_OTHER)
-
-#endif /* _QUAGGA_OSPF6_MEMORY_H */
#include <netinet/ip6.h>
+DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_MESSAGE, "OSPF6 message");
+
unsigned char conf_debug_ospf6_message[6] = {0x03, 0, 0, 0, 0, 0};
static const struct message ospf6_message_type_str[] = {
{OSPF6_MESSAGE_TYPE_HELLO, "Hello"},
/* MTU check */
if (p - sendbuf + sizeof(struct ospf6_lsa_header)
> ospf6_packet_max(on->ospf6_if)) {
- ospf6_lsdb_lsa_unlock(lsa);
+ ospf6_lsa_unlock(lsa);
+ if (lsanext)
+ ospf6_lsa_unlock(lsanext);
break;
}
memcpy(p, lsa->header, sizeof(struct ospf6_lsa_header));
if (size + sizeof(struct ospf6_lsa_header)
> ospf6_packet_max(on->ospf6_if)) {
- ospf6_lsdb_lsa_unlock(lsa);
+ ospf6_lsa_unlock(lsa);
+ if (lsanext)
+ ospf6_lsa_unlock(lsanext);
break;
}
/* MTU check */
if (p - sendbuf + sizeof(struct ospf6_lsreq_entry)
> ospf6_packet_max(on->ospf6_if)) {
- ospf6_lsdb_lsa_unlock(lsa);
+ ospf6_lsa_unlock(lsa);
+ if (lsanext)
+ ospf6_lsa_unlock(lsanext);
break;
}
thread_add_event(master, ospf6_lsack_send_interface, oi,
0, &oi->thread_send_lsack);
- ospf6_lsdb_lsa_unlock(lsa);
+ ospf6_lsa_unlock(lsa);
+ if (lsanext)
+ ospf6_lsa_unlock(lsanext);
break;
}
#include "ospf6_zebra.h"
#include "lib/json.h"
+DEFINE_MTYPE(OSPF6D, OSPF6_NEIGHBOR, "OSPF6 neighbor");
+
DEFINE_HOOK(ospf6_neighbor_change,
(struct ospf6_neighbor * on, int state, int next_state),
- (on, state, next_state))
+ (on, state, next_state));
unsigned char conf_debug_ospf6_neighbor = 0;
DECLARE_HOOK(ospf6_neighbor_change,
(struct ospf6_neighbor * on, int state, int next_state),
- (on, state, next_state))
+ (on, state, next_state));
#endif /* OSPF6_NEIGHBOR_H */
#include "ospf6d.h"
#include "ospf6_zebra.h"
+DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_ROUTE, "OSPF6 route");
+DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_NEXTHOP, "OSPF6 nexthop");
+DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_PATH, "OSPF6 Path");
+
unsigned char conf_debug_ospf6_route = 0;
static char *ospf6_route_table_name(struct ospf6_route_table *table)
FRR_MODULE_SETUP(.name = "ospf6d_snmp", .version = FRR_VERSION,
.description = "ospf6d AgentX SNMP module",
- .init = ospf6_snmp_module_init, )
+ .init = ospf6_snmp_module_init,
+);
#include "ospf6d.h"
#include "ospf6_abr.h"
+DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_VERTEX, "OSPF6 vertex");
+
unsigned char conf_debug_ospf6_spf = 0;
static void ospf6_spf_copy_nexthops_to_route(struct ospf6_route *rt,
return 0;
}
DECLARE_SKIPLIST_NONUNIQ(vertex_pqueue, struct ospf6_vertex, pqi,
- ospf6_vertex_cmp)
+ ospf6_vertex_cmp);
static int ospf6_vertex_id_cmp(void *a, void *b)
{
return NULL;
}
- /* Allocate memory for this LSA */
- new_header = XMALLOC(MTYPE_OSPF6_LSA_HEADER, total_lsa_length);
-
- /* LSA information structure */
- lsa = XCALLOC(MTYPE_OSPF6_LSA, sizeof(struct ospf6_lsa));
-
- lsa->header = (struct ospf6_lsa_header *)new_header;
+ lsa = ospf6_lsa_alloc(total_lsa_length);
+ new_header = (uint8_t *)lsa->header;
lsa->lsdb = area->temp_router_lsa_lsdb;
#define IS_OSPF6_DEBUG_SPF(level) \
(conf_debug_ospf6_spf & OSPF6_DEBUG_SPF_##level)
-PREDECL_SKIPLIST_NONUNIQ(vertex_pqueue)
+PREDECL_SKIPLIST_NONUNIQ(vertex_pqueue);
/* Transit Vertex */
struct ospf6_vertex {
/* type of this vertex */
#include "ospf6d.h"
#include "lib/json.h"
-DEFINE_QOBJ_TYPE(ospf6)
+DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_TOP, "OSPF6 top");
+
+DEFINE_QOBJ_TYPE(ospf6);
FRR_CFG_DEFAULT_BOOL(OSPF6_LOG_ADJACENCY_CHANGES,
{ .val_bool = true, .match_profile = "datacenter", },
{ .val_bool = false },
-)
+);
/* global ospf6d variable */
static struct ospf6_master ospf6_master;
/* Verify Area */
if (oi->area == NULL) {
- vty_out(vty, "No such Area-ID: %s\n", argv[idx_ipv4]->arg);
+ vty_out(vty, "%s not attached to area %s\n",
+ oi->interface->name, oi->area->name);
return CMD_SUCCESS;
}
UNSET_FLAG(oa->flag, OSPF6_AREA_ENABLE);
ospf6_abr_disable_area(oa);
}
- ospf6_interface_delete(oi);
return CMD_SUCCESS;
}
*/
uint16_t max_multipath;
- QOBJ_FIELDS
+ QOBJ_FIELDS;
};
-DECLARE_QOBJ_TYPE(ospf6)
+DECLARE_QOBJ_TYPE(ospf6);
#define OSPF6_DISABLED 0x01
#define OSPF6_STUB_ROUTER 0x02
#include "ospf6_area.h"
#include "lib/json.h"
-DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_DISTANCE, "OSPF6 distance")
+DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_DISTANCE, "OSPF6 distance");
unsigned char conf_debug_ospf6_zebra = 0;
#include "ospf6_bfd.h"
#include "lib/json.h"
+DEFINE_MGROUP(OSPF6D, "ospf6d");
+
struct route_node *route_prev(struct route_node *node)
{
struct route_node *end;
#include "libospf.h"
#include "thread.h"
+#include "memory.h"
-#include "ospf6_memory.h"
+DECLARE_MGROUP(OSPF6D);
/* global variables */
extern struct thread_master *master;
ospf6d/ospf6_intra.c \
ospf6d/ospf6_lsa.c \
ospf6d/ospf6_lsdb.c \
- ospf6d/ospf6_memory.c \
ospf6d/ospf6_message.c \
ospf6d/ospf6_neighbor.c \
ospf6d/ospf6_network.c \
ospf6d/ospf6_intra.h \
ospf6d/ospf6_lsa.h \
ospf6d/ospf6_lsdb.h \
- ospf6d/ospf6_memory.h \
ospf6d/ospf6_message.h \
ospf6d/ospf6_neighbor.h \
ospf6d/ospf6_network.h \
# end
ospf6d_ospf6d_snmp_la_SOURCES = ospf6d/ospf6_snmp.c
-ospf6d_ospf6d_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu99
+ospf6d_ospf6d_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu11
ospf6d_ospf6d_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
ospf6d_ospf6d_snmp_la_LIBADD = lib/libfrrsnmp.la
#include "ospfd/ospf_dump_api.c"
#include "ospfd/ospf_api.c"
-XREF_SETUP()
+XREF_SETUP();
-DEFINE_MGROUP(OSPFCLIENT, "libospfapiclient")
-DEFINE_MTYPE_STATIC(OSPFCLIENT, OSPF_APICLIENT, "OSPF-API client")
+DEFINE_MGROUP(OSPFCLIENT, "libospfapiclient");
+DEFINE_MTYPE_STATIC(OSPFCLIENT, OSPF_APICLIENT, "OSPF-API client");
/* Backlog for listen */
#define BACKLOG 5
#include <zebra.h>
#include "command.h"
+#include "json.h"
#include "linklist.h"
#include "memory.h"
#include "prefix.h"
#include "ospf_dump.h"
#include "ospf_vty.h"
-extern struct zclient *zclient;
-
-/*
- * ospf_bfd_info_free - Free BFD info structure
- */
-void ospf_bfd_info_free(void **bfd_info)
-{
- bfd_info_free((struct bfd_info **)bfd_info);
-}
-
-/*
- * ospf_bfd_reg_dereg_nbr - Register/Deregister a neighbor with BFD through
- * zebra for starting/stopping the monitoring of
- * the neighbor rechahability.
- */
-static void ospf_bfd_reg_dereg_nbr(struct ospf_neighbor *nbr, int command)
-{
- struct ospf_interface *oi = nbr->oi;
- struct interface *ifp = oi->ifp;
- struct ospf_if_params *params;
- struct bfd_info *bfd_info;
- int cbit;
-
- /* Check if BFD is enabled */
- params = IF_DEF_PARAMS(ifp);
-
- /* Check if BFD is enabled */
- if (!params->bfd_info)
- return;
- bfd_info = (struct bfd_info *)params->bfd_info;
-
- if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE))
- zlog_debug("%s nbr (%pI4) with BFD. OSPF vrf %s",
- bfd_get_command_dbg_str(command),
- &nbr->src,
- ospf_vrf_id_to_name(oi->ospf->vrf_id));
-
- cbit = CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CBIT_ON);
-
- bfd_peer_sendmsg(zclient, bfd_info, AF_INET, &nbr->src, NULL, ifp->name,
- 0, 0, cbit, command, 0, oi->ospf->vrf_id);
-}
+DEFINE_MTYPE_STATIC(OSPFD, BFD_CONFIG, "BFD configuration data");
/*
* ospf_bfd_trigger_event - Neighbor is registered/deregistered with BFD when
void ospf_bfd_trigger_event(struct ospf_neighbor *nbr, int old_state, int state)
{
if ((old_state < NSM_TwoWay) && (state >= NSM_TwoWay))
- ospf_bfd_reg_dereg_nbr(nbr, ZEBRA_BFD_DEST_REGISTER);
+ bfd_sess_install(nbr->bfd_session);
else if ((old_state >= NSM_TwoWay) && (state < NSM_TwoWay))
- ospf_bfd_reg_dereg_nbr(nbr, ZEBRA_BFD_DEST_DEREGISTER);
+ bfd_sess_uninstall(nbr->bfd_session);
}
-/*
- * ospf_bfd_reg_dereg_all_nbr - Register/Deregister all neighbors associated
- * with a interface with BFD through
- * zebra for starting/stopping the monitoring of
- * the neighbor rechahability.
- */
-static int ospf_bfd_reg_dereg_all_nbr(struct interface *ifp, int command)
+static void ospf_bfd_session_change(struct bfd_session_params *bsp,
+ const struct bfd_session_status *bss,
+ void *arg)
{
- struct ospf_interface *oi;
- struct route_table *nbrs;
- struct ospf_neighbor *nbr;
- struct route_node *irn;
- struct route_node *nrn;
-
- for (irn = route_top(IF_OIFS(ifp)); irn; irn = route_next(irn)) {
- if ((oi = irn->info) == NULL)
- continue;
+ struct ospf_neighbor *nbr = arg;
- if ((nbrs = oi->nbrs) == NULL)
- continue;
-
- for (nrn = route_top(nbrs); nrn; nrn = route_next(nrn)) {
- if ((nbr = nrn->info) == NULL || nbr == oi->nbr_self)
- continue;
-
- if (command != ZEBRA_BFD_DEST_DEREGISTER)
- ospf_bfd_info_nbr_create(oi, nbr);
- else
- bfd_info_free(
- (struct bfd_info **)&nbr->bfd_info);
-
- if (nbr->state < NSM_TwoWay)
- continue;
+ /* BFD peer went down. */
+ if (bss->state == BFD_STATUS_DOWN
+ && bss->previous_state == BFD_STATUS_UP) {
+ if (IS_DEBUG_OSPF(bfd, BFD_LIB))
+ zlog_debug("%s: NSM[%s:%pI4]: BFD Down", __func__,
+ IF_NAME(nbr->oi), &nbr->address.u.prefix4);
- ospf_bfd_reg_dereg_nbr(nbr, command);
- }
+ OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_InactivityTimer);
}
- return 0;
+ /* BFD peer went up. */
+ if (bss->state == BSS_UP && bss->previous_state == BSS_DOWN)
+ if (IS_DEBUG_OSPF(bfd, BFD_LIB))
+ zlog_debug("%s: NSM[%s:%pI4]: BFD Up", __func__,
+ IF_NAME(nbr->oi), &nbr->address.u.prefix4);
}
-/*
- * ospf_bfd_nbr_replay - Replay all the neighbors that have BFD enabled
- * to zebra
- */
-static int ospf_bfd_nbr_replay(ZAPI_CALLBACK_ARGS)
+void ospf_neighbor_bfd_apply(struct ospf_neighbor *nbr)
{
- struct listnode *inode, *node, *onode;
- struct ospf *ospf;
- struct ospf_interface *oi;
- struct route_table *nbrs;
- struct route_node *rn;
- struct ospf_neighbor *nbr;
- struct ospf_if_params *params;
+ struct ospf_interface *oi = nbr->oi;
+ struct ospf_if_params *oip = IF_DEF_PARAMS(oi->ifp);
- if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE)) {
- zlog_debug("Zebra: BFD Dest replay request");
+ /* BFD configuration was removed. */
+ if (oip->bfd_config == NULL) {
+ bfd_sess_free(&nbr->bfd_session);
+ return;
}
- /* Send the client registration */
- bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, vrf_id);
-
- /* Replay the neighbor, if BFD is enabled in OSPF */
- for (ALL_LIST_ELEMENTS(om->ospf, node, onode, ospf)) {
- for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, inode, oi)) {
- if ((nbrs = oi->nbrs) == NULL)
- continue;
-
- params = IF_DEF_PARAMS(oi->ifp);
- if (!params->bfd_info)
- continue;
-
- for (rn = route_top(nbrs); rn; rn = route_next(rn)) {
- if ((nbr = rn->info) == NULL
- || nbr == oi->nbr_self)
- continue;
+ /* New BFD session. */
+ if (nbr->bfd_session == NULL) {
+ nbr->bfd_session = bfd_sess_new(ospf_bfd_session_change, nbr);
+ bfd_sess_set_ipv4_addrs(nbr->bfd_session, NULL, &nbr->src);
+ bfd_sess_set_interface(nbr->bfd_session, oi->ifp->name);
+ bfd_sess_set_vrf(nbr->bfd_session, oi->ospf->vrf_id);
+ bfd_sess_enable(nbr->bfd_session, true);
+ }
- if (nbr->state < NSM_TwoWay)
- continue;
+ /* Set new configuration. */
+ bfd_sess_set_timers(nbr->bfd_session,
+ oip->bfd_config->detection_multiplier,
+ oip->bfd_config->min_rx, oip->bfd_config->min_tx);
+ bfd_sess_set_profile(nbr->bfd_session, oip->bfd_config->profile);
- if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE))
- zlog_debug("Replaying nbr (%pI4) to BFD",
- &nbr->src);
+ /* Don't start sessions on down OSPF sessions. */
+ if (nbr->state < NSM_TwoWay)
+ return;
- ospf_bfd_reg_dereg_nbr(nbr,
- ZEBRA_BFD_DEST_UPDATE);
- }
- }
- }
- return 0;
+ bfd_sess_install(nbr->bfd_session);
}
-/*
- * ospf_bfd_interface_dest_update - Find the neighbor for which the BFD status
- * has changed and bring down the neighbor
- * connectivity if the BFD status changed to
- * down.
- */
-static int ospf_bfd_interface_dest_update(ZAPI_CALLBACK_ARGS)
+static void ospf_interface_bfd_apply(struct interface *ifp)
{
- struct interface *ifp;
struct ospf_interface *oi;
- struct ospf_if_params *params;
- struct ospf_neighbor *nbr = NULL;
- struct route_node *node;
- struct route_node *n_node;
- struct prefix p, src_p;
- int status;
- int old_status;
- struct bfd_info *bfd_info;
- struct timeval tv;
-
- ifp = bfd_get_peer_info(zclient->ibuf, &p, &src_p, &status, NULL,
- vrf_id);
-
- if ((ifp == NULL) || (p.family != AF_INET))
- return 0;
-
- if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE))
- zlog_debug("Zebra: interface %s bfd destination %pFX %s",
- ifp->name, &p, bfd_get_status_str(status));
-
- params = IF_DEF_PARAMS(ifp);
- if (!params->bfd_info)
- return 0;
-
- for (node = route_top(IF_OIFS(ifp)); node; node = route_next(node)) {
- if ((oi = node->info) == NULL)
- continue;
-
- /* walk the neighbor list for point-to-point network */
- if (oi->type == OSPF_IFTYPE_POINTOPOINT) {
- for (n_node = route_top(oi->nbrs); n_node;
- n_node = route_next(n_node)) {
- nbr = n_node->info;
- if (nbr) {
- /* skip myself */
- if (nbr == oi->nbr_self) {
- nbr = NULL;
- continue;
- }
-
- /* Found the matching neighbor */
- if (nbr->src.s_addr ==
- p.u.prefix4.s_addr)
- break;
- }
- }
- } else {
- nbr = ospf_nbr_lookup_by_addr(oi->nbrs, &p.u.prefix4);
- }
+ struct route_table *nbrs;
+ struct ospf_neighbor *nbr;
+ struct route_node *irn;
+ struct route_node *nrn;
- if (!nbr || !nbr->bfd_info)
+ /* Iterate over all interfaces and set neighbors BFD session. */
+ for (irn = route_top(IF_OIFS(ifp)); irn; irn = route_next(irn)) {
+ if ((oi = irn->info) == NULL)
continue;
-
- bfd_info = (struct bfd_info *)nbr->bfd_info;
- if (bfd_info->status == status)
+ if ((nbrs = oi->nbrs) == NULL)
continue;
+ for (nrn = route_top(nbrs); nrn; nrn = route_next(nrn)) {
+ if ((nbr = nrn->info) == NULL || nbr == oi->nbr_self)
+ continue;
- old_status = bfd_info->status;
- BFD_SET_CLIENT_STATUS(bfd_info->status, status);
- monotime(&tv);
- bfd_info->last_update = tv.tv_sec;
-
- if ((status == BFD_STATUS_DOWN)
- && (old_status == BFD_STATUS_UP)) {
- if (IS_DEBUG_OSPF(nsm, NSM_EVENTS))
- zlog_debug("NSM[%s:%pI4]: BFD Down",
- IF_NAME(nbr->oi),
- &nbr->address.u.prefix4);
-
- OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_InactivityTimer);
- }
- if ((status == BFD_STATUS_UP)
- && (old_status == BFD_STATUS_DOWN)) {
- if (IS_DEBUG_OSPF(nsm, NSM_EVENTS))
- zlog_debug("NSM[%s:%pI4]: BFD Up",
- IF_NAME(nbr->oi),
- &nbr->address.u.prefix4);
+ ospf_neighbor_bfd_apply(nbr);
}
}
-
- return 0;
}
-/*
- * ospf_bfd_info_nbr_create - Create/update BFD information for a neighbor.
- */
-void ospf_bfd_info_nbr_create(struct ospf_interface *oi,
- struct ospf_neighbor *nbr)
+static void ospf_interface_enable_bfd(struct interface *ifp)
{
- struct bfd_info *oi_bfd_info;
- struct bfd_info *nbr_bfd_info;
- struct interface *ifp = oi->ifp;
- struct ospf_if_params *params;
-
- /* Check if BFD is enabled */
- params = IF_DEF_PARAMS(ifp);
+ struct ospf_if_params *oip = IF_DEF_PARAMS(ifp);
- /* Check if BFD is enabled */
- if (!params->bfd_info)
+ if (oip->bfd_config)
return;
- oi_bfd_info = (struct bfd_info *)params->bfd_info;
- if (!nbr->bfd_info)
- nbr->bfd_info = bfd_info_create();
+ /* Allocate memory for configurations and set defaults. */
+ oip->bfd_config = XCALLOC(MTYPE_BFD_CONFIG, sizeof(*oip->bfd_config));
+ oip->bfd_config->detection_multiplier = BFD_DEF_DETECT_MULT;
+ oip->bfd_config->min_rx = BFD_DEF_MIN_RX;
+ oip->bfd_config->min_tx = BFD_DEF_MIN_TX;
+}
- nbr_bfd_info = (struct bfd_info *)nbr->bfd_info;
- nbr_bfd_info->detect_mult = oi_bfd_info->detect_mult;
- nbr_bfd_info->desired_min_tx = oi_bfd_info->desired_min_tx;
- nbr_bfd_info->required_min_rx = oi_bfd_info->required_min_rx;
+void ospf_interface_disable_bfd(struct interface *ifp,
+ struct ospf_if_params *oip)
+{
+ XFREE(MTYPE_BFD_CONFIG, oip->bfd_config);
+ ospf_interface_bfd_apply(ifp);
}
/*
* ospf_bfd_write_config - Write the interface BFD configuration.
*/
-void ospf_bfd_write_config(struct vty *vty, struct ospf_if_params *params)
-
+void ospf_bfd_write_config(struct vty *vty, const struct ospf_if_params *params
+ __attribute__((unused)))
{
#if HAVE_BFDD == 0
- struct bfd_info *bfd_info;
-#endif /* ! HAVE_BFDD */
-
- if (!params->bfd_info)
- return;
-
-#if HAVE_BFDD == 0
- bfd_info = (struct bfd_info *)params->bfd_info;
-
if (CHECK_FLAG(bfd_info->flags, BFD_FLAG_PARAM_CFG))
- vty_out(vty, " ip ospf bfd %d %d %d\n", bfd_info->detect_mult,
- bfd_info->required_min_rx, bfd_info->desired_min_tx);
+ vty_out(vty, " ip ospf bfd %d %d %d\n",
+ params->bfd_config->detection_multiplier,
+ params->bfd_config->min_rx, params->bfd_config->min_tx);
else
#endif /* ! HAVE_BFDD */
vty_out(vty, " ip ospf bfd\n");
-}
-/*
- * ospf_bfd_show_info - Show BFD info structure
- */
-void ospf_bfd_show_info(struct vty *vty, void *bfd_info, json_object *json_obj,
- bool use_json, int param_only)
-{
- if (param_only)
- bfd_show_param(vty, (struct bfd_info *)bfd_info, 1, 0, use_json,
- json_obj);
- else
- bfd_show_info(vty, (struct bfd_info *)bfd_info, 0, 1, use_json,
- json_obj);
+ if (params->bfd_config->profile[0])
+ vty_out(vty, " ip ospf bfd profile %s\n",
+ params->bfd_config->profile);
}
-/*
- * ospf_bfd_interface_show - Show the interface BFD configuration.
- */
-void ospf_bfd_interface_show(struct vty *vty, struct interface *ifp,
- json_object *json_interface_sub, bool use_json)
+void ospf_interface_bfd_show(struct vty *vty, const struct interface *ifp,
+ struct json_object *json)
{
- struct ospf_if_params *params;
-
- params = IF_DEF_PARAMS(ifp);
+ struct ospf_if_params *params = IF_DEF_PARAMS(ifp);
+ struct bfd_configuration *bfd_config = params->bfd_config;
+ struct json_object *json_bfd;
- ospf_bfd_show_info(vty, params->bfd_info, json_interface_sub, use_json,
- 1);
-}
-
-/*
- * ospf_bfd_if_param_set - Set the configured BFD paramter values for
- * interface.
- */
-static void ospf_bfd_if_param_set(struct interface *ifp, uint32_t min_rx,
- uint32_t min_tx, uint8_t detect_mult,
- int defaults)
-{
- struct ospf_if_params *params;
- int command = 0;
-
- params = IF_DEF_PARAMS(ifp);
+ if (bfd_config == NULL)
+ return;
- bfd_set_param((struct bfd_info **)&(params->bfd_info), min_rx, min_tx,
- detect_mult, NULL, defaults, &command);
- if (command)
- ospf_bfd_reg_dereg_all_nbr(ifp, command);
+ if (json) {
+ json_bfd = json_object_new_object();
+ json_object_int_add(json_bfd, "detectionMultiplier",
+ bfd_config->detection_multiplier);
+ json_object_int_add(json_bfd, "rxMinInterval",
+ bfd_config->min_rx);
+ json_object_int_add(json_bfd, "txMinInterval",
+ bfd_config->min_tx);
+ json_object_object_add(json, "peerBfdInfo", json_bfd);
+ } else
+ vty_out(vty,
+ " BFD: Detect Multiplier: %d, Min Rx interval: %d, Min Tx interval: %d\n",
+ bfd_config->detection_multiplier, bfd_config->min_rx,
+ bfd_config->min_tx);
}
DEFUN (ip_ospf_bfd,
"Enables BFD support\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
- struct ospf_if_params *params;
- struct bfd_info *bfd_info;
-
- assert(ifp);
- params = IF_DEF_PARAMS(ifp);
- bfd_info = params->bfd_info;
-
- if (!bfd_info || !CHECK_FLAG(bfd_info->flags, BFD_FLAG_PARAM_CFG))
- ospf_bfd_if_param_set(ifp, BFD_DEF_MIN_RX, BFD_DEF_MIN_TX,
- BFD_DEF_DETECT_MULT, 1);
-
+ ospf_interface_enable_bfd(ifp);
+ ospf_interface_bfd_apply(ifp);
return CMD_SUCCESS;
}
"Desired min transmit interval\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct ospf_if_params *params;
int idx_number = 3;
int idx_number_2 = 4;
int idx_number_3 = 5;
- uint32_t rx_val;
- uint32_t tx_val;
- uint8_t dm_val;
- int ret;
- assert(ifp);
+ ospf_interface_enable_bfd(ifp);
+
+ params = IF_DEF_PARAMS(ifp);
+ params->bfd_config->detection_multiplier =
+ strtol(argv[idx_number]->arg, NULL, 10);
+ params->bfd_config->min_rx = strtol(argv[idx_number_2]->arg, NULL, 10);
+ params->bfd_config->min_tx = strtol(argv[idx_number_3]->arg, NULL, 10);
+
+ ospf_interface_bfd_apply(ifp);
+
+ return CMD_SUCCESS;
+}
- if ((ret = bfd_validate_param(
- vty, argv[idx_number]->arg, argv[idx_number_2]->arg,
- argv[idx_number_3]->arg, &dm_val, &rx_val, &tx_val))
- != CMD_SUCCESS)
- return ret;
+DEFUN (ip_ospf_bfd_prof,
+ ip_ospf_bfd_prof_cmd,
+ "ip ospf bfd profile BFDPROF",
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Enables BFD support\n"
+ BFD_PROFILE_STR
+ BFD_PROFILE_NAME_STR)
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct ospf_if_params *params;
+ int idx_prof = 4;
- ospf_bfd_if_param_set(ifp, rx_val, tx_val, dm_val, 0);
+ ospf_interface_enable_bfd(ifp);
+ params = IF_DEF_PARAMS(ifp);
+ strlcpy(params->bfd_config->profile, argv[idx_prof]->arg,
+ sizeof(params->bfd_config->profile));
+ ospf_interface_bfd_apply(ifp);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_ospf_bfd_prof,
+ no_ip_ospf_bfd_prof_cmd,
+ "no ip ospf bfd profile [BFDPROF]",
+ NO_STR
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Enables BFD support\n"
+ BFD_PROFILE_STR
+ BFD_PROFILE_NAME_STR)
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct ospf_if_params *params;
+
+ ospf_interface_enable_bfd(ifp);
+ params = IF_DEF_PARAMS(ifp);
+ params->bfd_config->profile[0] = 0;
+ ospf_interface_bfd_apply(ifp);
return CMD_SUCCESS;
}
)
{
VTY_DECLVAR_CONTEXT(interface, ifp);
- struct ospf_if_params *params;
-
- assert(ifp);
-
- params = IF_DEF_PARAMS(ifp);
- if (params->bfd_info) {
- ospf_bfd_reg_dereg_all_nbr(ifp, ZEBRA_BFD_DEST_DEREGISTER);
- bfd_info_free(&(params->bfd_info));
- }
-
+ ospf_interface_disable_bfd(ifp, IF_DEF_PARAMS(ifp));
return CMD_SUCCESS;
}
-void ospf_bfd_init(void)
+void ospf_bfd_init(struct thread_master *tm)
{
- bfd_gbl_init();
-
- /* Initialize BFD client functions */
- zclient->interface_bfd_dest_update = ospf_bfd_interface_dest_update;
- zclient->bfd_dest_replay = ospf_bfd_nbr_replay;
+ bfd_protocol_integration_init(zclient, tm);
/* Install BFD command */
install_element(INTERFACE_NODE, &ip_ospf_bfd_cmd);
install_element(INTERFACE_NODE, &ip_ospf_bfd_param_cmd);
+ install_element(INTERFACE_NODE, &ip_ospf_bfd_prof_cmd);
+ install_element(INTERFACE_NODE, &no_ip_ospf_bfd_prof_cmd);
install_element(INTERFACE_NODE, &no_ip_ospf_bfd_cmd);
}
#ifndef _ZEBRA_OSPF_BFD_H
#define _ZEBRA_OSPF_BFD_H
+#include "ospfd/ospf_interface.h"
#include "json.h"
-extern void ospf_bfd_init(void);
+extern void ospf_bfd_init(struct thread_master *tm);
extern void ospf_bfd_write_config(struct vty *vty,
- struct ospf_if_params *params);
+ const struct ospf_if_params *params);
extern void ospf_bfd_trigger_event(struct ospf_neighbor *nbr, int old_state,
int state);
-extern void ospf_bfd_interface_show(struct vty *vty, struct interface *ifp,
- json_object *json_interface_sub,
- bool use_json);
-
-extern void ospf_bfd_info_nbr_create(struct ospf_interface *oi,
- struct ospf_neighbor *nbr);
+/**
+ * Legacy information: it is the peers who actually have this information
+ * and the protocol should not need to know about timers.
+ */
+extern void ospf_interface_bfd_show(struct vty *vty,
+ const struct interface *ifp,
+ struct json_object *json);
-extern void ospf_bfd_show_info(struct vty *vty, void *bfd_info,
- json_object *json_obj, bool use_json,
- int param_only);
+/**
+ * Disables interface BFD configuration and remove settings from all peers.
+ */
+extern void ospf_interface_disable_bfd(struct interface *ifp,
+ struct ospf_if_params *oip);
-extern void ospf_bfd_info_free(void **bfd_info);
+/**
+ * Create/update BFD session for this OSPF neighbor.
+ */
+extern void ospf_neighbor_bfd_apply(struct ospf_neighbor *nbr);
#endif /* _ZEBRA_OSPF_BFD_H */
#include <zebra.h>
+#include "lib/bfd.h"
#include "monotime.h"
#include "linklist.h"
#include "thread.h"
unsigned long conf_debug_ospf_defaultinfo = 0;
unsigned long conf_debug_ospf_ldp_sync = 0;
unsigned long conf_debug_ospf_gr = 0;
+unsigned long conf_debug_ospf_bfd;
/* Enable debug option variables -- valid only session. */
unsigned long term_debug_ospf_packet[5] = {0, 0, 0, 0, 0};
unsigned long term_debug_ospf_defaultinfo;
unsigned long term_debug_ospf_ldp_sync;
unsigned long term_debug_ospf_gr = 0;
+unsigned long term_debug_ospf_bfd;
const char *ospf_redist_string(unsigned int route_type)
{
return CMD_SUCCESS;
}
+DEFPY(debug_ospf_bfd, debug_ospf_bfd_cmd,
+ "[no] debug ospf bfd",
+ NO_STR
+ DEBUG_STR
+ OSPF_STR
+ "Bidirection Forwarding Detection\n")
+{
+ if (vty->node == CONFIG_NODE) {
+ if (no) {
+ bfd_protocol_integration_set_debug(false);
+ CONF_DEBUG_OFF(bfd, BFD_LIB);
+ } else {
+ bfd_protocol_integration_set_debug(true);
+ CONF_DEBUG_ON(bfd, BFD_LIB);
+ }
+ }
+
+ if (no)
+ TERM_DEBUG_OFF(bfd, BFD_LIB);
+ else
+ TERM_DEBUG_ON(bfd, BFD_LIB);
+
+ return CMD_SUCCESS;
+}
+
DEFUN (no_debug_ospf,
no_debug_ospf_cmd,
"no debug ospf",
DEBUG_OFF(defaultinfo, DEFAULTINFO);
DEBUG_OFF(ldp_sync, LDP_SYNC);
+ /* BFD debugging is two parts: OSPF and library. */
+ DEBUG_OFF(bfd, BFD_LIB);
+ bfd_protocol_integration_set_debug(false);
+
for (i = 0; i < 5; i++)
DEBUG_PACKET_OFF(i, flag);
}
TERM_DEBUG_OFF(zebra, ZEBRA_REDISTRIBUTE);
TERM_DEBUG_OFF(defaultinfo, DEFAULTINFO);
TERM_DEBUG_OFF(ldp_sync, LDP_SYNC);
+ TERM_DEBUG_OFF(bfd, BFD_LIB);
return CMD_SUCCESS;
}
if (IS_DEBUG_OSPF(gr, GR_HELPER) == OSPF_DEBUG_GR_HELPER)
vty_out(vty, " OSPF Graceful Restart Helper debugging is on\n");
+ if (IS_DEBUG_OSPF(bfd, BFD_LIB) == OSPF_DEBUG_BFD_LIB)
+ vty_out(vty,
+ " OSPF BFD integration library debugging is on\n");
+
vty_out(vty, "\n");
return CMD_SUCCESS;
write = 1;
}
+ if (IS_CONF_DEBUG_OSPF(bfd, BFD_LIB) == OSPF_DEBUG_BFD_LIB) {
+ vty_out(vty, "debug ospf%s bfd\n", str);
+ write = 1;
+ }
+
return write;
}
install_element(ENABLE_NODE, &no_debug_ospf_default_info_cmd);
install_element(ENABLE_NODE, &no_debug_ospf_ldp_sync_cmd);
install_element(ENABLE_NODE, &debug_ospf_gr_cmd);
+ install_element(ENABLE_NODE, &debug_ospf_bfd_cmd);
install_element(ENABLE_NODE, &show_debugging_ospf_instance_cmd);
install_element(ENABLE_NODE, &debug_ospf_packet_cmd);
install_element(CONFIG_NODE, &no_debug_ospf_default_info_cmd);
install_element(CONFIG_NODE, &no_debug_ospf_ldp_sync_cmd);
install_element(CONFIG_NODE, &debug_ospf_gr_cmd);
+ install_element(CONFIG_NODE, &debug_ospf_bfd_cmd);
install_element(CONFIG_NODE, &debug_ospf_instance_nsm_cmd);
install_element(CONFIG_NODE, &debug_ospf_instance_lsa_cmd);
#define OSPF_DEBUG_GR_HELPER 0x01
#define OSPF_DEBUG_GR 0x03
+#define OSPF_DEBUG_BFD_LIB 0x01
+
/* Macro for setting debug option. */
#define CONF_DEBUG_PACKET_ON(a, b) conf_debug_ospf_packet[a] |= (b)
#define CONF_DEBUG_PACKET_OFF(a, b) conf_debug_ospf_packet[a] &= ~(b)
extern unsigned long term_debug_ospf_defaultinfo;
extern unsigned long term_debug_ospf_ldp_sync;
extern unsigned long term_debug_ospf_gr;
+extern unsigned long term_debug_ospf_bfd;
/* Message Strings. */
extern char *ospf_lsa_type_str[];
#include "ldp_sync.h"
#include "ospfd/ospfd.h"
+#include "ospfd/ospf_bfd.h"
#include "ospfd/ospf_spf.h"
#include "ospfd/ospf_interface.h"
#include "ospfd/ospf_ism.h"
#include "ospfd/ospf_dump.h"
#include "ospfd/ospf_ldp_sync.h"
-DEFINE_QOBJ_TYPE(ospf_interface)
-DEFINE_HOOK(ospf_vl_add, (struct ospf_vl_data * vd), (vd))
-DEFINE_HOOK(ospf_vl_delete, (struct ospf_vl_data * vd), (vd))
-DEFINE_HOOK(ospf_if_update, (struct interface * ifp), (ifp))
-DEFINE_HOOK(ospf_if_delete, (struct interface * ifp), (ifp))
+DEFINE_QOBJ_TYPE(ospf_interface);
+DEFINE_HOOK(ospf_vl_add, (struct ospf_vl_data * vd), (vd));
+DEFINE_HOOK(ospf_vl_delete, (struct ospf_vl_data * vd), (vd));
+DEFINE_HOOK(ospf_if_update, (struct interface * ifp), (ifp));
+DEFINE_HOOK(ospf_if_delete, (struct interface * ifp), (ifp));
int ospf_interface_neighbor_count(struct ospf_interface *oi)
{
return oip;
}
-void ospf_del_if_params(struct ospf_if_params *oip)
+static void ospf_del_if_params(struct interface *ifp,
+ struct ospf_if_params *oip)
{
list_delete(&oip->auth_crypt);
- bfd_info_free(&(oip->bfd_info));
+ ospf_interface_disable_bfd(ifp, oip);
ldp_sync_info_free(&(oip->ldp_sync_info));
XFREE(MTYPE_OSPF_IF_PARAMS, oip);
}
&& !OSPF_IF_PARAM_CONFIGURED(oip, auth_type)
&& !OSPF_IF_PARAM_CONFIGURED(oip, if_area)
&& listcount(oip->auth_crypt) == 0) {
- ospf_del_if_params(oip);
+ ospf_del_if_params(ifp, oip);
rn->info = NULL;
route_unlock_node(rn);
}
for (rn = route_top(IF_OIFS_PARAMS(ifp)); rn; rn = route_next(rn))
if (rn->info)
- ospf_del_if_params(rn->info);
+ ospf_del_if_params(ifp, rn->info);
route_table_finish(IF_OIFS_PARAMS(ifp));
- ospf_del_if_params((struct ospf_if_params *)IF_DEF_PARAMS(ifp));
+ ospf_del_if_params(ifp, IF_DEF_PARAMS(ifp));
XFREE(MTYPE_OSPF_IF_INFO, ifp->info);
return rc;
#ifndef _ZEBRA_OSPF_INTERFACE_H
#define _ZEBRA_OSPF_INTERFACE_H
+#include "lib/bfd.h"
#include "qobj.h"
#include "hook.h"
#include "ospfd/ospf_packet.h"
uint32_t network_lsa_seqnum; /* Network LSA seqnum */
/* BFD configuration */
- struct bfd_info *bfd_info;
+ struct bfd_configuration {
+ /** BFD session detection multiplier. */
+ uint8_t detection_multiplier;
+ /** BFD session minimum required receive interval. */
+ uint32_t min_rx;
+ /** BFD session minimum required transmission interval. */
+ uint32_t min_tx;
+ /** BFD profile. */
+ char profile[BFD_PROFILE_NAME_LEN];
+ } *bfd_config;
/* MPLS LDP-IGP Sync configuration */
struct ldp_sync_info *ldp_sync_info;
uint32_t full_nbrs;
- QOBJ_FIELDS
+ QOBJ_FIELDS;
};
-DECLARE_QOBJ_TYPE(ospf_interface)
+DECLARE_QOBJ_TYPE(ospf_interface);
/* Prototypes. */
extern char *ospf_if_name(struct ospf_interface *);
struct in_addr);
extern struct ospf_if_params *ospf_get_if_params(struct interface *,
struct in_addr);
-extern void ospf_del_if_params(struct ospf_if_params *);
extern void ospf_free_if_params(struct interface *, struct in_addr);
extern void ospf_if_update_params(struct interface *, struct in_addr);
extern void ospf_if_interface(struct interface *ifp);
-DECLARE_HOOK(ospf_vl_add, (struct ospf_vl_data * vd), (vd))
-DECLARE_HOOK(ospf_vl_delete, (struct ospf_vl_data * vd), (vd))
+DECLARE_HOOK(ospf_vl_add, (struct ospf_vl_data * vd), (vd));
+DECLARE_HOOK(ospf_vl_delete, (struct ospf_vl_data * vd), (vd));
-DECLARE_HOOK(ospf_if_update, (struct interface * ifp), (ifp))
-DECLARE_HOOK(ospf_if_delete, (struct interface * ifp), (ifp))
+DECLARE_HOOK(ospf_if_update, (struct interface * ifp), (ifp));
+DECLARE_HOOK(ospf_if_delete, (struct interface * ifp), (ifp));
#endif /* _ZEBRA_OSPF_INTERFACE_H */
DEFINE_HOOK(ospf_ism_change,
(struct ospf_interface * oi, int state, int oldstate),
- (oi, state, oldstate))
+ (oi, state, oldstate));
/* elect DR and BDR. Refer to RFC2319 section 9.4 */
static struct ospf_neighbor *ospf_dr_election_sub(struct list *routers)
DECLARE_HOOK(ospf_ism_change,
(struct ospf_interface * oi, int state, int oldstate),
- (oi, state, oldstate))
+ (oi, state, oldstate));
#endif /* _ZEBRA_OSPF_ISM_H */
#include <zebra.h>
#include <lib/version.h>
+#include "bfd.h"
#include "getopt.h"
#include "thread.h"
#include "prefix.h"
static void sigint(void)
{
zlog_notice("Terminating on signal");
+ bfd_protocol_integration_set_shutdown(true);
ospf_terminate();
exit(0);
}
.signals = ospf_signals, .n_signals = array_size(ospf_signals),
.privs = &ospfd_privs, .yang_modules = ospfd_yang_modules,
- .n_yang_modules = array_size(ospfd_yang_modules), )
+ .n_yang_modules = array_size(ospfd_yang_modules),
+);
/* OSPFd main routine. */
int main(int argc, char **argv)
ospf_vty_clear_init();
/* OSPF BFD init */
- ospf_bfd_init();
+ ospf_bfd_init(master);
/* OSPF LDP IGP Sync init */
ospf_ldp_sync_init();
#include "ospf_memory.h"
-DEFINE_MGROUP(OSPFD, "ospfd")
-DEFINE_MTYPE(OSPFD, OSPF_TOP, "OSPF top")
-DEFINE_MTYPE(OSPFD, OSPF_AREA, "OSPF area")
-DEFINE_MTYPE(OSPFD, OSPF_AREA_RANGE, "OSPF area range")
-DEFINE_MTYPE(OSPFD, OSPF_NETWORK, "OSPF network")
-DEFINE_MTYPE(OSPFD, OSPF_NEIGHBOR_STATIC, "OSPF static nbr")
-DEFINE_MTYPE(OSPFD, OSPF_IF, "OSPF interface")
-DEFINE_MTYPE(OSPFD, OSPF_NEIGHBOR, "OSPF neighbor")
-DEFINE_MTYPE(OSPFD, OSPF_ROUTE, "OSPF route")
-DEFINE_MTYPE(OSPFD, OSPF_TMP, "OSPF tmp mem")
-DEFINE_MTYPE(OSPFD, OSPF_LSA, "OSPF LSA")
-DEFINE_MTYPE(OSPFD, OSPF_LSA_DATA, "OSPF LSA data")
-DEFINE_MTYPE(OSPFD, OSPF_LSDB, "OSPF LSDB")
-DEFINE_MTYPE(OSPFD, OSPF_PACKET, "OSPF packet")
-DEFINE_MTYPE(OSPFD, OSPF_FIFO, "OSPF FIFO queue")
-DEFINE_MTYPE(OSPFD, OSPF_VERTEX, "OSPF vertex")
-DEFINE_MTYPE(OSPFD, OSPF_VERTEX_PARENT, "OSPF vertex parent")
-DEFINE_MTYPE(OSPFD, OSPF_NEXTHOP, "OSPF nexthop")
-DEFINE_MTYPE(OSPFD, OSPF_PATH, "OSPF path")
-DEFINE_MTYPE(OSPFD, OSPF_VL_DATA, "OSPF VL data")
-DEFINE_MTYPE(OSPFD, OSPF_CRYPT_KEY, "OSPF crypt key")
-DEFINE_MTYPE(OSPFD, OSPF_EXTERNAL_INFO, "OSPF ext. info")
-DEFINE_MTYPE(OSPFD, OSPF_DISTANCE, "OSPF distance")
-DEFINE_MTYPE(OSPFD, OSPF_IF_INFO, "OSPF if info")
-DEFINE_MTYPE(OSPFD, OSPF_IF_PARAMS, "OSPF if params")
-DEFINE_MTYPE(OSPFD, OSPF_MESSAGE, "OSPF message")
-DEFINE_MTYPE(OSPFD, OSPF_MPLS_TE, "OSPF MPLS parameters")
-DEFINE_MTYPE(OSPFD, OSPF_ROUTER_INFO, "OSPF Router Info parameters")
-DEFINE_MTYPE(OSPFD, OSPF_PCE_PARAMS, "OSPF PCE parameters")
-DEFINE_MTYPE(OSPFD, OSPF_EXT_PARAMS, "OSPF Extended parameters")
-DEFINE_MTYPE(OSPFD, OSPF_SR_PARAMS, "OSPF Segment Routing parameters")
-DEFINE_MTYPE(OSPFD, OSPF_GR_HELPER, "OSPF Graceful Restart Helper")
-DEFINE_MTYPE(OSPFD, OSPF_EXTERNAL_RT_AGGR, "OSPF External Route Summarisation")
-DEFINE_MTYPE(OSPFD, OSPF_P_SPACE, "OSPF TI-LFA P-Space")
-DEFINE_MTYPE(OSPFD, OSPF_Q_SPACE, "OSPF TI-LFA Q-Space")
+DEFINE_MGROUP(OSPFD, "ospfd");
+DEFINE_MTYPE(OSPFD, OSPF_TOP, "OSPF top");
+DEFINE_MTYPE(OSPFD, OSPF_AREA, "OSPF area");
+DEFINE_MTYPE(OSPFD, OSPF_AREA_RANGE, "OSPF area range");
+DEFINE_MTYPE(OSPFD, OSPF_NETWORK, "OSPF network");
+DEFINE_MTYPE(OSPFD, OSPF_NEIGHBOR_STATIC, "OSPF static nbr");
+DEFINE_MTYPE(OSPFD, OSPF_IF, "OSPF interface");
+DEFINE_MTYPE(OSPFD, OSPF_NEIGHBOR, "OSPF neighbor");
+DEFINE_MTYPE(OSPFD, OSPF_ROUTE, "OSPF route");
+DEFINE_MTYPE(OSPFD, OSPF_TMP, "OSPF tmp mem");
+DEFINE_MTYPE(OSPFD, OSPF_LSA, "OSPF LSA");
+DEFINE_MTYPE(OSPFD, OSPF_LSA_DATA, "OSPF LSA data");
+DEFINE_MTYPE(OSPFD, OSPF_LSDB, "OSPF LSDB");
+DEFINE_MTYPE(OSPFD, OSPF_PACKET, "OSPF packet");
+DEFINE_MTYPE(OSPFD, OSPF_FIFO, "OSPF FIFO queue");
+DEFINE_MTYPE(OSPFD, OSPF_VERTEX, "OSPF vertex");
+DEFINE_MTYPE(OSPFD, OSPF_VERTEX_PARENT, "OSPF vertex parent");
+DEFINE_MTYPE(OSPFD, OSPF_NEXTHOP, "OSPF nexthop");
+DEFINE_MTYPE(OSPFD, OSPF_PATH, "OSPF path");
+DEFINE_MTYPE(OSPFD, OSPF_VL_DATA, "OSPF VL data");
+DEFINE_MTYPE(OSPFD, OSPF_CRYPT_KEY, "OSPF crypt key");
+DEFINE_MTYPE(OSPFD, OSPF_EXTERNAL_INFO, "OSPF ext. info");
+DEFINE_MTYPE(OSPFD, OSPF_DISTANCE, "OSPF distance");
+DEFINE_MTYPE(OSPFD, OSPF_IF_INFO, "OSPF if info");
+DEFINE_MTYPE(OSPFD, OSPF_IF_PARAMS, "OSPF if params");
+DEFINE_MTYPE(OSPFD, OSPF_MESSAGE, "OSPF message");
+DEFINE_MTYPE(OSPFD, OSPF_MPLS_TE, "OSPF MPLS parameters");
+DEFINE_MTYPE(OSPFD, OSPF_ROUTER_INFO, "OSPF Router Info parameters");
+DEFINE_MTYPE(OSPFD, OSPF_PCE_PARAMS, "OSPF PCE parameters");
+DEFINE_MTYPE(OSPFD, OSPF_EXT_PARAMS, "OSPF Extended parameters");
+DEFINE_MTYPE(OSPFD, OSPF_SR_PARAMS, "OSPF Segment Routing parameters");
+DEFINE_MTYPE(OSPFD, OSPF_GR_HELPER, "OSPF Graceful Restart Helper");
+DEFINE_MTYPE(OSPFD, OSPF_EXTERNAL_RT_AGGR, "OSPF External Route Summarisation");
+DEFINE_MTYPE(OSPFD, OSPF_P_SPACE, "OSPF TI-LFA P-Space");
+DEFINE_MTYPE(OSPFD, OSPF_Q_SPACE, "OSPF TI-LFA Q-Space");
#include "memory.h"
-DECLARE_MGROUP(OSPFD)
-DECLARE_MTYPE(OSPF_TOP)
-DECLARE_MTYPE(OSPF_AREA)
-DECLARE_MTYPE(OSPF_AREA_RANGE)
-DECLARE_MTYPE(OSPF_NETWORK)
-DECLARE_MTYPE(OSPF_NEIGHBOR_STATIC)
-DECLARE_MTYPE(OSPF_IF)
-DECLARE_MTYPE(OSPF_NEIGHBOR)
-DECLARE_MTYPE(OSPF_ROUTE)
-DECLARE_MTYPE(OSPF_TMP)
-DECLARE_MTYPE(OSPF_LSA)
-DECLARE_MTYPE(OSPF_LSA_DATA)
-DECLARE_MTYPE(OSPF_LSDB)
-DECLARE_MTYPE(OSPF_PACKET)
-DECLARE_MTYPE(OSPF_FIFO)
-DECLARE_MTYPE(OSPF_VERTEX)
-DECLARE_MTYPE(OSPF_VERTEX_PARENT)
-DECLARE_MTYPE(OSPF_NEXTHOP)
-DECLARE_MTYPE(OSPF_PATH)
-DECLARE_MTYPE(OSPF_VL_DATA)
-DECLARE_MTYPE(OSPF_CRYPT_KEY)
-DECLARE_MTYPE(OSPF_EXTERNAL_INFO)
-DECLARE_MTYPE(OSPF_DISTANCE)
-DECLARE_MTYPE(OSPF_IF_INFO)
-DECLARE_MTYPE(OSPF_IF_PARAMS)
-DECLARE_MTYPE(OSPF_MESSAGE)
-DECLARE_MTYPE(OSPF_MPLS_TE)
-DECLARE_MTYPE(OSPF_ROUTER_INFO)
-DECLARE_MTYPE(OSPF_PCE_PARAMS)
-DECLARE_MTYPE(OSPF_SR_PARAMS)
-DECLARE_MTYPE(OSPF_EXT_PARAMS)
-DECLARE_MTYPE(OSPF_GR_HELPER)
-DECLARE_MTYPE(OSPF_EXTERNAL_RT_AGGR)
-DECLARE_MTYPE(OSPF_P_SPACE)
-DECLARE_MTYPE(OSPF_Q_SPACE)
+DECLARE_MGROUP(OSPFD);
+DECLARE_MTYPE(OSPF_TOP);
+DECLARE_MTYPE(OSPF_AREA);
+DECLARE_MTYPE(OSPF_AREA_RANGE);
+DECLARE_MTYPE(OSPF_NETWORK);
+DECLARE_MTYPE(OSPF_NEIGHBOR_STATIC);
+DECLARE_MTYPE(OSPF_IF);
+DECLARE_MTYPE(OSPF_NEIGHBOR);
+DECLARE_MTYPE(OSPF_ROUTE);
+DECLARE_MTYPE(OSPF_TMP);
+DECLARE_MTYPE(OSPF_LSA);
+DECLARE_MTYPE(OSPF_LSA_DATA);
+DECLARE_MTYPE(OSPF_LSDB);
+DECLARE_MTYPE(OSPF_PACKET);
+DECLARE_MTYPE(OSPF_FIFO);
+DECLARE_MTYPE(OSPF_VERTEX);
+DECLARE_MTYPE(OSPF_VERTEX_PARENT);
+DECLARE_MTYPE(OSPF_NEXTHOP);
+DECLARE_MTYPE(OSPF_PATH);
+DECLARE_MTYPE(OSPF_VL_DATA);
+DECLARE_MTYPE(OSPF_CRYPT_KEY);
+DECLARE_MTYPE(OSPF_EXTERNAL_INFO);
+DECLARE_MTYPE(OSPF_DISTANCE);
+DECLARE_MTYPE(OSPF_IF_INFO);
+DECLARE_MTYPE(OSPF_IF_PARAMS);
+DECLARE_MTYPE(OSPF_MESSAGE);
+DECLARE_MTYPE(OSPF_MPLS_TE);
+DECLARE_MTYPE(OSPF_ROUTER_INFO);
+DECLARE_MTYPE(OSPF_PCE_PARAMS);
+DECLARE_MTYPE(OSPF_SR_PARAMS);
+DECLARE_MTYPE(OSPF_EXT_PARAMS);
+DECLARE_MTYPE(OSPF_GR_HELPER);
+DECLARE_MTYPE(OSPF_EXTERNAL_RT_AGGR);
+DECLARE_MTYPE(OSPF_P_SPACE);
+DECLARE_MTYPE(OSPF_Q_SPACE);
#endif /* _QUAGGA_OSPF_MEMORY_H */
#include <zebra.h>
+#include "lib/bfd.h"
#include "linklist.h"
#include "prefix.h"
#include "memory.h"
nbr->crypt_seqnum = 0;
- ospf_bfd_info_nbr_create(oi, nbr);
-
/* Initialize GR Helper info*/
nbr->gr_helper_info.recvd_grace_period = 0;
nbr->gr_helper_info.actual_grace_period = 0;
/* Cancel all events. */ /* Thread lookup cost would be negligible. */
thread_cancel_event(master, nbr);
- ospf_bfd_info_free(&nbr->bfd_info);
+ bfd_sess_free(&nbr->bfd_session);
OSPF_NSM_TIMER_OFF(nbr->gr_helper_info.t_grace_timer);
if (ntohs(ospfh->auth_type) == OSPF_AUTH_CRYPTOGRAPHIC)
nbr->crypt_seqnum = ospfh->u.crypt.crypt_seqnum;
+ /* Configure BFD if interface has it. */
+ ospf_neighbor_bfd_apply(nbr);
+
if (IS_DEBUG_OSPF_EVENT)
zlog_debug("NSM[%s:%pI4]: start", IF_NAME(oi),
&nbr->router_id);
uint32_t state_change; /* NSM state change counter */
/* BFD information */
- void *bfd_info;
+ struct bfd_session_params *bfd_session;
/* ospf graceful restart HELPER info */
struct ospf_helper_info gr_helper_info;
DEFINE_HOOK(ospf_nsm_change,
(struct ospf_neighbor * on, int state, int oldstate),
- (on, state, oldstate))
+ (on, state, oldstate));
static void nsm_clear_adj(struct ospf_neighbor *);
if (state == NSM_Down)
nbr->crypt_seqnum = 0;
- ospf_bfd_trigger_event(nbr, old_state, state);
+ if (nbr->bfd_session)
+ ospf_bfd_trigger_event(nbr, old_state, state);
/* Preserve old status? */
}
extern int nsm_should_adj(struct ospf_neighbor *nbr);
DECLARE_HOOK(ospf_nsm_change,
(struct ospf_neighbor * on, int state, int oldstate),
- (on, state, oldstate))
+ (on, state, oldstate));
#endif /* _ZEBRA_OSPF_NSM_H */
#include "ospfd/ospf_ext.h"
#include "ospfd/ospf_errors.h"
-DEFINE_MTYPE_STATIC(OSPFD, OSPF_OPAQUE_FUNCTAB, "OSPF opaque function table")
-DEFINE_MTYPE_STATIC(OSPFD, OPAQUE_INFO_PER_TYPE, "OSPF opaque per-type info")
-DEFINE_MTYPE_STATIC(OSPFD, OPAQUE_INFO_PER_ID, "OSPF opaque per-ID info")
+DEFINE_MTYPE_STATIC(OSPFD, OSPF_OPAQUE_FUNCTAB, "OSPF opaque function table");
+DEFINE_MTYPE_STATIC(OSPFD, OPAQUE_INFO_PER_TYPE, "OSPF opaque per-type info");
+DEFINE_MTYPE_STATIC(OSPFD, OPAQUE_INFO_PER_ID, "OSPF opaque per-ID info");
/*------------------------------------------------------------------------*
* Followings are initialize/terminate functions for Opaque-LSAs handling.
FRR_MODULE_SETUP(.name = "ospfd_snmp", .version = FRR_VERSION,
.description = "ospfd AgentX SNMP module",
- .init = ospf_snmp_module_init, )
+ .init = ospf_snmp_module_init,
+);
}
return 0;
}
-DECLARE_SKIPLIST_NONUNIQ(vertex_pqueue, struct vertex, pqi, vertex_cmp)
+DECLARE_SKIPLIST_NONUNIQ(vertex_pqueue, struct vertex, pqi, vertex_cmp);
static void lsdb_clean_stat(struct ospf_lsdb *lsdb)
{
/* The "root" is the node running the SPF calculation */
-PREDECL_SKIPLIST_NONUNIQ(vertex_pqueue)
+PREDECL_SKIPLIST_NONUNIQ(vertex_pqueue);
/* A router or network in an area */
struct vertex {
struct vertex_pqueue_item pqi;
DECLARE_RBTREE_UNIQ(p_spaces, struct p_space, p_spaces_item,
- p_spaces_compare_func)
+ p_spaces_compare_func);
DECLARE_RBTREE_UNIQ(q_spaces, struct q_space, q_spaces_item,
- q_spaces_compare_func)
+ q_spaces_compare_func);
static void
ospf_ti_lfa_generate_p_space(struct ospf_area *area, struct vertex *child,
FRR_CFG_DEFAULT_BOOL(OSPF_LOG_ADJACENCY_CHANGES,
{ .val_bool = true, .match_profile = "datacenter", },
{ .val_bool = false },
-)
+);
static const char *const ospf_network_type_str[] = {
"Null", "POINTOPOINT", "BROADCAST", "NBMA", "POINTOMULTIPOINT",
" Neighbor Count is %d, Adjacent neighbor count is %d\n",
ospf_nbr_count(oi, 0),
ospf_nbr_count(oi, NSM_Full));
- ospf_bfd_interface_show(vty, ifp, json_interface_sub, use_json);
+
+ ospf_interface_bfd_show(vty, ifp, json_interface_sub);
/* OSPF Authentication information */
ospf_interface_auth_show(vty, oi, json_interface_sub, use_json);
.helper_exit_reason));
}
- ospf_bfd_show_info(vty, nbr->bfd_info, json_neigh, use_json, 0);
+ bfd_sess_show(vty, json_neigh, nbr->bfd_session);
if (use_json)
json_object_array_add(json_neigh_array, json_neigh);
return ret;
}
-DEFUN (show_ip_ospf_instance_database,
- show_ip_ospf_instance_database_cmd,
- "show ip ospf [{(1-65535)|vrf NAME}] database [<asbr-summary|external|network|router|summary|nssa-external|opaque-link|opaque-area|opaque-as> [A.B.C.D [<self-originate|adv-router A.B.C.D>]]] [json]",
+ALIAS (show_ip_ospf_database_max,
+ show_ip_ospf_database_cmd,
+ "show ip ospf [vrf <NAME|all>] database [<asbr-summary|external|network|router|summary|nssa-external|opaque-link|opaque-area|opaque-as> [A.B.C.D [<self-originate|adv-router A.B.C.D>]]] [json]",
SHOW_STR
IP_STR
"OSPF information\n"
- "Instance ID\n"
VRF_CMD_HELP_STR
+ "All VRFs\n"
"Database summary\n"
OSPF_LSA_TYPES_DESC
"Link State ID (as an IP address)\n"
"Advertising Router link states\n"
"Advertising Router (as an IP address)\n"
JSON_STR)
-{
- struct ospf *ospf;
- unsigned short instance = 0;
- struct listnode *node = NULL;
- char *vrf_name = NULL;
- bool all_vrf = false;
- int ret = CMD_SUCCESS;
- int inst = 0;
- int idx = 0;
- uint8_t use_vrf = 0;
- bool uj = use_json(argc, argv);
- json_object *json = NULL;
-
- if (uj)
- json = json_object_new_object();
-
- if (argv_find(argv, argc, "(1-65535)", &idx)) {
- instance = strtoul(argv[idx]->arg, NULL, 10);
- if (instance != ospf_instance)
- return CMD_NOT_MY_INSTANCE;
-
- ospf = ospf_lookup_instance(instance);
- if (!ospf || !ospf->oi_running)
- return CMD_SUCCESS;
-
- return (show_ip_ospf_database_common(
- vty, ospf, idx ? 1 : 0, argc, argv, use_vrf, json, uj));
- } else if (argv_find(argv, argc, "vrf", &idx)) {
- vrf_name = argv[++idx]->arg;
- all_vrf = strmatch(vrf_name, "all");
- }
-
- if (vrf_name) {
- use_vrf = 1;
- if (all_vrf) {
- for (ALL_LIST_ELEMENTS_RO(om->ospf, node, ospf)) {
- if (!ospf->oi_running)
- continue;
- ret = (show_ip_ospf_database_common(
- vty, ospf, idx ? 2 : 0, argc, argv,
- use_vrf, json, uj));
- }
- } else {
- ospf = ospf_lookup_by_inst_name(inst, vrf_name);
- if ((ospf == NULL) || !ospf->oi_running) {
- vty_out(vty, "%% OSPF instance not found\n");
- return CMD_SUCCESS;
- }
-
- ret = (show_ip_ospf_database_common(
- vty, ospf, idx ? 2 : 0, argc, argv, use_vrf,
- json, uj));
- }
- } else {
- /* Display default ospf (instance 0) info */
- ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
- if (ospf == NULL || !ospf->oi_running) {
- vty_out(vty, "%% OSPF instance not found\n");
- return CMD_SUCCESS;
- }
-
- ret = (show_ip_ospf_database_common(vty, ospf, 0, argc, argv,
- use_vrf, json, uj));
- }
-
- if (uj) {
- vty_out(vty, "%s\n", json_object_to_json_string(json));
- json_object_free(json);
- }
-
- return ret;
-}
DEFUN (show_ip_ospf_instance_database_max,
show_ip_ospf_instance_database_max_cmd,
return CMD_SUCCESS;
}
+ALIAS (show_ip_ospf_instance_database_max,
+ show_ip_ospf_instance_database_cmd,
+ "show ip ospf (1-65535) database [<asbr-summary|external|network|router|summary|nssa-external|opaque-link|opaque-area|opaque-as> [A.B.C.D [<self-originate|adv-router A.B.C.D>]]] [json]",
+ SHOW_STR
+ IP_STR
+ "OSPF information\n"
+ "Instance ID\n"
+ "Database summary\n"
+ OSPF_LSA_TYPES_DESC
+ "Link State ID (as an IP address)\n"
+ "Self-originated link states\n"
+ "Advertising Router link states\n"
+ "Advertising Router (as an IP address)\n"
+ JSON_STR)
static int show_ip_ospf_database_type_adv_router_common(struct vty *vty,
struct ospf *ospf,
return CMD_SUCCESS;
}
-DEFUN (show_ip_ospf_instance_database_type_adv_router,
- show_ip_ospf_instance_database_type_adv_router_cmd,
- "show ip ospf [{(1-65535)|vrf NAME}] database <asbr-summary|external|network|router|summary|nssa-external|opaque-link|opaque-area|opaque-as> <adv-router A.B.C.D|self-originate> [json]",
+DEFUN (show_ip_ospf_database_type_adv_router,
+ show_ip_ospf_database_type_adv_router_cmd,
+ "show ip ospf [vrf <NAME|all>] database <asbr-summary|external|network|router|summary|nssa-external|opaque-link|opaque-area|opaque-as> <adv-router A.B.C.D|self-originate> [json]",
SHOW_STR
IP_STR
"OSPF information\n"
- "Instance ID\n"
VRF_CMD_HELP_STR
+ "All VRFs\n"
"Database summary\n"
OSPF_LSA_TYPES_DESC
"Advertising Router link states\n"
JSON_STR)
{
struct ospf *ospf = NULL;
- unsigned short instance = 0;
struct listnode *node = NULL;
char *vrf_name = NULL;
bool all_vrf = false;
if (uj)
json = json_object_new_object();
- if (argv_find(argv, argc, "(1-65535)", &idx)) {
- instance = strtoul(argv[idx]->arg, NULL, 10);
- if (instance != ospf_instance)
- return CMD_NOT_MY_INSTANCE;
-
- ospf = ospf_lookup_instance(instance);
- if (!ospf || !ospf->oi_running)
- return CMD_SUCCESS;
-
- return (show_ip_ospf_database_type_adv_router_common(
- vty, ospf, idx ? 1 : 0, argc, argv, use_vrf, json, uj));
- }
-
OSPF_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
if (vrf_name) {
}
return ret;
- /*return (show_ip_ospf_database_type_adv_router_common(
- vty, ospf, idx ? 1 : 0, argc, argv));*/
+}
+
+DEFUN (show_ip_ospf_instance_database_type_adv_router,
+ show_ip_ospf_instance_database_type_adv_router_cmd,
+ "show ip ospf (1-65535) database <asbr-summary|external|network|router|summary|nssa-external|opaque-link|opaque-area|opaque-as> <adv-router A.B.C.D|self-originate> [json]",
+ SHOW_STR
+ IP_STR
+ "OSPF information\n"
+ "Instance ID\n"
+ "Database summary\n"
+ OSPF_LSA_TYPES_DESC
+ "Advertising Router link states\n"
+ "Advertising Router (as an IP address)\n"
+ "Self-originated link states\n"
+ JSON_STR)
+{
+ int idx_number = 3;
+ struct ospf *ospf;
+ unsigned short instance = 0;
+ bool uj = use_json(argc, argv);
+ json_object *json = NULL;
+
+ if (uj)
+ json = json_object_new_object();
+
+ instance = strtoul(argv[idx_number]->arg, NULL, 10);
+ if (instance != ospf_instance)
+ return CMD_NOT_MY_INSTANCE;
+
+ ospf = ospf_lookup_instance(instance);
+ if (!ospf || !ospf->oi_running)
+ return CMD_SUCCESS;
+
+ show_ip_ospf_database_type_adv_router_common(vty, ospf, 1, argc, argv,
+ 0, json, uj);
+
+ if (uj) {
+ vty_out(vty, "%s\n",
+ json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
+
+ return CMD_SUCCESS;
}
DEFUN (ip_ospf_authentication_args,
}
/* bfd print. */
- if (params && params->bfd_info)
+ if (params && params->bfd_config)
ospf_bfd_write_config(vty, params);
/* MTU ignore print. */
install_element(VIEW_NODE, &show_ip_ospf_instance_cmd);
/* "show ip ospf database" commands. */
+ install_element(VIEW_NODE, &show_ip_ospf_database_cmd);
install_element(VIEW_NODE, &show_ip_ospf_database_max_cmd);
-
+ install_element(VIEW_NODE,
+ &show_ip_ospf_database_type_adv_router_cmd);
install_element(VIEW_NODE,
&show_ip_ospf_instance_database_type_adv_router_cmd);
install_element(VIEW_NODE, &show_ip_ospf_instance_database_cmd);
#include "ospfd/ospf_sr.h"
#include "ospfd/ospf_ldp_sync.h"
-DEFINE_MTYPE_STATIC(OSPFD, OSPF_EXTERNAL, "OSPF External route table")
-DEFINE_MTYPE_STATIC(OSPFD, OSPF_REDISTRIBUTE, "OSPF Redistriute")
-DEFINE_MTYPE_STATIC(OSPFD, OSPF_DIST_ARGS, "OSPF Distribute arguments")
+DEFINE_MTYPE_STATIC(OSPFD, OSPF_EXTERNAL, "OSPF External route table");
+DEFINE_MTYPE_STATIC(OSPFD, OSPF_REDISTRIBUTE, "OSPF Redistriute");
+DEFINE_MTYPE_STATIC(OSPFD, OSPF_DIST_ARGS, "OSPF Distribute arguments");
/* Zebra structure to hold current status. */
#include "ldp_sync.h"
#include "ospfd/ospfd.h"
+#include "ospfd/ospf_bfd.h"
#include "ospfd/ospf_network.h"
#include "ospfd/ospf_interface.h"
#include "ospfd/ospf_ism.h"
#include "ospfd/ospf_gr_helper.h"
-DEFINE_QOBJ_TYPE(ospf)
+DEFINE_QOBJ_TYPE(ospf);
/* OSPF process wide configuration. */
static struct ospf_master ospf_master;
}
DECLARE_RBTREE_UNIQ(p_spaces, struct p_space, p_spaces_item,
- p_spaces_compare_func)
+ p_spaces_compare_func);
void ospf_process_refresh_data(struct ospf *ospf, bool reset)
{
nbr_nbma->nbr = nbr;
+ /* Configure BFD if interface has it. */
+ ospf_neighbor_bfd_apply(nbr);
+
OSPF_NSM_EVENT_EXECUTE(nbr, NSM_Start);
}
}
bool ti_lfa_enabled;
enum protection_type ti_lfa_protection_type;
- QOBJ_FIELDS
+ QOBJ_FIELDS;
};
-DECLARE_QOBJ_TYPE(ospf)
+DECLARE_QOBJ_TYPE(ospf);
enum ospf_ti_lfa_p_q_space_adjacency {
OSPF_TI_LFA_P_Q_SPACE_ADJACENT,
struct in_addr router_id;
};
-PREDECL_RBTREE_UNIQ(q_spaces)
+PREDECL_RBTREE_UNIQ(q_spaces);
struct q_space {
struct vertex *root;
struct list *vertex_list;
struct q_spaces_item q_spaces_item;
};
-PREDECL_RBTREE_UNIQ(p_spaces)
+PREDECL_RBTREE_UNIQ(p_spaces);
struct p_space {
struct vertex *root;
struct protected_resource *protected_resource;
ospfd_ospfd_SOURCES = ospfd/ospf_main.c
ospfd_ospfd_snmp_la_SOURCES = ospfd/ospf_snmp.c
-ospfd_ospfd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu99
+ospfd_ospfd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu11
ospfd_ospfd_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
ospfd_ospfd_snmp_la_LIBADD = lib/libfrrsnmp.la
#include <math.h>
#include <zebra.h>
+#include "memory.h"
#include "log.h"
#include "command.h"
#include "mpls.h"
#include "pathd/pathd.h"
#include "pathd/path_nb.h"
-#include "pathd/path_memory.h"
#ifndef VTYSH_EXTRACT_PL
#include "pathd/path_cli_clippy.c"
#endif
static int config_write_segment_lists(struct vty *vty);
static int config_write_sr_policies(struct vty *vty);
-DEFINE_MTYPE_STATIC(PATHD, PATH_CLI, "Client")
+DEFINE_MTYPE_STATIC(PATHD, PATH_CLI, "Client");
/* Vty node structures. */
static struct cmd_node segment_routing_node = {
.signals = path_signals, .n_signals = array_size(path_signals),
.privs = &pathd_privs, .yang_modules = pathd_yang_modules,
- .n_yang_modules = array_size(pathd_yang_modules), )
+ .n_yang_modules = array_size(pathd_yang_modules),
+);
int main(int argc, char **argv, char **envp)
{
+++ /dev/null
-/*
- * Copyright (C) 2020 NetDEF, Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <zebra.h>
-
-#include <memory.h>
-
-#include "pathd/path_memory.h"
-
-DEFINE_MGROUP(PATHD, "pathd")
+++ /dev/null
-/*
- * Copyright (C) 2020 NetDEF, Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef _FRR_PATH_MEMORY_H_
-#define _FRR_PATH_MEMORY_H_
-
-#include "memory.h"
-
-DECLARE_MGROUP(PATHD)
-
-#endif /* _FRR_PATH_MEMORY_H_ */
*/
#include <zebra.h>
-#include <pcep_utils_counters.h>
+#include "pceplib/pcep_utils_counters.h"
+#include "memory.h"
#include "log.h"
#include "command.h"
#include "libfrr.h"
#include "pathd/pathd.h"
#include "pathd/path_errors.h"
-#include "pathd/path_pcep_memory.h"
#include "pathd/path_pcep.h"
#include "pathd/path_pcep_cli.h"
#include "pathd/path_pcep_controller.h"
#include "pathd/path_pcep_lib.h"
#include "pathd/path_pcep_config.h"
+DEFINE_MTYPE(PATHD, PCEP, "PCEP module");
/*
* Globals.
ret = path_pcep_config_update_path(path);
if (ret != PATH_NB_ERR && path->srp_id != 0) {
- /* ODL and Cisco requires the first reported
- * LSP to have a DOWN status, the later status changes
- * will be comunicated through hook calls.
- */
- enum pcep_lsp_operational_status real_status;
if ((resp = path_pcep_config_get_path(&path->nbkey))) {
resp->srp_id = path->srp_id;
- real_status = resp->status;
- resp->status = PCEP_LSP_OPERATIONAL_DOWN;
- pcep_ctrl_send_report(pcep_g->fpt, path->pcc_id, resp);
- /* If the update did not have any effect and the real
- * status is not DOWN, we need to send a second report
- * so the PCE is aware of the real status. This is due
- * to the fact that NO notification will be received
- * if the update did not apply any changes */
- if ((ret == PATH_NB_NO_CHANGE)
- && (real_status != PCEP_LSP_OPERATIONAL_DOWN)) {
- resp->status = real_status;
- resp->srp_id = 0;
- pcep_ctrl_send_report(pcep_g->fpt, path->pcc_id,
- resp);
- }
- pcep_free_path(resp);
+ pcep_ctrl_send_report(pcep_g->fpt, path->pcc_id, resp,
+ ret == PATH_NB_NO_CHANGE);
}
}
return ret;
FRR_MODULE_SETUP(.name = "frr_pathd_pcep", .version = FRR_VERSION,
.description = "FRR pathd PCEP module",
- .init = pcep_module_init)
+ .init = pcep_module_init,
+);
#include <stdbool.h>
#include <debug.h>
#include <netinet/tcp.h>
-#include <pcep_utils_logging.h>
-#include <pcep_pcc_api.h>
+#include "memory.h"
+#include "pceplib/pcep_utils_logging.h"
+#include "pceplib/pcep_pcc_api.h"
#include "mpls.h"
#include "pathd/pathd.h"
-#include "pathd/path_pcep_memory.h"
+
+DECLARE_MTYPE(PCEP);
#define PCEP_DEFAULT_PORT 4189
#define MAX_PCC 32
*/
#include <zebra.h>
-#include <pcep_utils_counters.h>
-#include <pcep_session_logic.h>
+#include "pceplib/pcep_utils_counters.h"
+#include "pceplib/pcep_session_logic.h"
#include "log.h"
#include "command.h"
#include "pathd/pathd.h"
#include "pathd/path_errors.h"
-#include "pathd/path_pcep_memory.h"
#include "pathd/path_pcep.h"
#include "pathd/path_pcep_cli.h"
#include "pathd/path_pcep_controller.h"
default_pcep_config_group_opts_g.tcp_md5_auth;
}
}
- strncpy(pce_opts_cli->pce_opts.config_opts.tcp_md5_auth,
- tcp_md5_auth_str, TCP_MD5SIG_MAXKEYLEN);
+ strlcpy(pce_opts_cli->pce_opts.config_opts.tcp_md5_auth,
+ tcp_md5_auth_str,
+ sizeof(pce_opts_cli->pce_opts.config_opts.tcp_md5_auth));
struct ipaddr *source_ip =
&pce_opts_cli->pce_config_group_opts.source_ip;
tm_info = localtime(&group->start_time);
strftime(tm_buffer, sizeof(tm_buffer), "%Y-%m-%d %H:%M:%S", tm_info);
- vty_out(vty, "PCEP counters since %s (%luh %lum %lus):\n", tm_buffer,
- diff_time / 3600, (diff_time / 60) % 60, diff_time % 60);
+ vty_out(vty, "PCEP counters since %s (%uh %um %us):\n", tm_buffer,
+ (uint32_t)(diff_time / 3600), (uint32_t)((diff_time / 60) % 60),
+ (uint32_t)(diff_time % 60));
/* Prepare table. */
tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
return CMD_ERR_NO_MATCH;
}
- strncpy(pce_config->tcp_md5_auth, tcp_md5_auth, TCP_MD5SIG_MAXKEYLEN);
+ strlcpy(pce_config->tcp_md5_auth, tcp_md5_auth,
+ sizeof(pce_config->tcp_md5_auth));
return CMD_SUCCESS;
}
XMALLOC(MTYPE_PCEP, sizeof(struct pcc_opts));
memcpy(&pcc_opts_copy->addr,
&pce_opts_cli->pce_opts.config_opts.source_ip,
- sizeof(struct pcc_opts));
+ sizeof(pcc_opts_copy->addr));
pcc_opts_copy->msd = pcc_msd_g;
pcc_opts_copy->port = pce_opts_cli->pce_opts.config_opts.source_port;
if (pcep_ctrl_update_pcc_options(pcep_g->fpt, pcc_opts_copy)) {
localtime_r(¤t_time, <);
gmtime_r(&session->time_connected, <);
vty_out(vty,
- " Connected for %ld seconds, since %d-%02d-%02d %02d:%02d:%02d UTC\n",
- (current_time - session->time_connected),
+ " Connected for %u seconds, since %d-%02d-%02d %02d:%02d:%02d UTC\n",
+ (uint32_t)(current_time
+ - session->time_connected),
lt.tm_year + 1900, lt.tm_mon + 1, lt.tm_mday,
lt.tm_hour, lt.tm_min, lt.tm_sec);
}
#include <northbound.h>
#include <yang.h>
#include <printfrr.h>
-#include <pcep-objects.h>
+#include "pceplib/pcep_msg_objects.h"
#include "pathd/pathd.h"
#include "pathd/path_pcep.h"
#include "pathd/path_pcep_config.h"
static enum pcep_sr_subobj_nai pcep_nai_type(enum srte_segment_nai_type type);
static enum srte_segment_nai_type srte_nai_type(enum pcep_sr_subobj_nai type);
-static int path_pcep_config_lookup_cb(struct thread *t)
+void path_pcep_refine_path(struct path *path)
{
- struct path *path = THREAD_ARG(t);
struct srte_candidate *candidate = lookup_candidate(&path->nbkey);
struct srte_lsp *lsp;
if (candidate == NULL)
- return 0;
+ return;
lsp = candidate->lsp;
if ((path->update_origin == SRTE_ORIGIN_UNDEFINED)
&& (lsp->segment_list != NULL))
path->update_origin = lsp->segment_list->protocol_origin;
-
- return 0;
-}
-
-void path_pcep_config_lookup(struct path *path)
-{
- /*
- * Configuration access is strictly done via the main thread
- */
- thread_execute(master, path_pcep_config_lookup_cb, path, 0);
}
struct path *path_pcep_config_get_path(struct lsp_nb_key *key)
SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
for (metric = path->first_metric; metric != NULL; metric = metric->next)
- srte_lsp_set_metric(candidate->lsp, metric->type, metric->value,
- metric->enforce, metric->is_bound,
- metric->is_computed);
+ srte_lsp_set_metric(
+ candidate->lsp,
+ (enum srte_candidate_metric_type)metric->type,
+ metric->value, metric->enforce, metric->is_bound,
+ metric->is_computed);
if (path->has_bandwidth)
srte_lsp_set_bandwidth(candidate->lsp, path->bandwidth,
typedef int (*path_list_cb_t)(struct path *path, void *arg);
/* Lookup the candidate path and fill up the missing path attributes like name
- and type. Used for path generated from PCEP message received from the PCE
- so they contains more information about the candidate path. If no matching
- policy or candidate path is found, nothing is changed */
-void path_pcep_config_lookup(struct path *path);
+ * and type. Used for path generated from PCEP message received from the PCE
+ * so they contains more information about the candidate path. If no matching
+ * policy or candidate path is found, nothing is changed.
+ * MUST BE CALLED FROM THE MAIN THREAD */
+void path_pcep_refine_path(struct path *path);
struct path *path_pcep_config_get_path(struct lsp_nb_key *key);
void path_pcep_config_list_path(path_list_cb_t cb, void *arg);
int path_pcep_config_update_path(struct path *path);
EV_SYNC_PATH,
EV_SYNC_DONE,
EV_PCEPLIB_EVENT,
- EV_RESET_PCC_SESSION
+ EV_RESET_PCC_SESSION,
+ EV_SEND_REPORT,
+ EV_PATH_REFINED
};
struct pcep_ctrl_event_data {
void *payload;
};
-/* Synchronous call arguments */
-
-struct get_counters_args {
+struct pcep_refine_path_event_data {
struct ctrl_state *ctrl_state;
int pcc_id;
- struct counters_group *counters;
+ pcep_refine_callback_t continue_lsp_update_handler;
+ struct path *path;
+ void *payload;
};
-struct send_report_args {
+/* Synchronous call arguments */
+
+struct get_counters_args {
struct ctrl_state *ctrl_state;
int pcc_id;
- struct path *path;
+ struct counters_group *counters;
};
struct get_pcep_session_args {
/* Internal Functions Called From Main Thread */
static int pcep_ctrl_halt_cb(struct frr_pthread *fpt, void **res);
+static int pcep_refine_path_event_cb(struct thread *thread);
/* Internal Functions Called From Controller Thread */
static int pcep_thread_finish_event_handler(struct thread *thread);
-static int pcep_thread_get_counters_callback(struct thread *t);
-static int pcep_thread_send_report_callback(struct thread *t);
-static int pcep_thread_get_pcep_session_callback(struct thread *t);
-static int pcep_thread_get_pcc_info_callback(struct thread *t);
/* Controller Thread Timer Handler */
static int schedule_thread_timer(struct ctrl_state *ctrl_state, int pcc_id,
static int pcep_thread_event_pathd_event(struct ctrl_state *ctrl_state,
enum pcep_pathd_event_type type,
struct path *path);
+static void
+pcep_thread_path_refined_event(struct ctrl_state *ctrl_state,
+ struct pcep_refine_path_event_data *data);
/* Main Thread Event Handler */
static int send_to_main(struct ctrl_state *ctrl_state, int pcc_id,
int pcc_id)
{
struct ctrl_state *ctrl_state = get_ctrl_state(fpt);
- struct get_counters_args args = {
- .ctrl_state = ctrl_state, .pcc_id = pcc_id, .counters = NULL};
- thread_execute(ctrl_state->self, pcep_thread_get_counters_callback,
- &args, 0);
- return args.counters;
+ struct counters_group *counters = NULL;
+ struct pcc_state *pcc_state;
+ pcc_state = pcep_pcc_get_pcc_by_id(ctrl_state->pcc, pcc_id);
+ if (pcc_state) {
+ counters = pcep_lib_copy_counters(pcc_state->sess);
+ }
+ return counters;
}
pcep_session *pcep_ctrl_get_pcep_session(struct frr_pthread *fpt, int pcc_id)
{
struct ctrl_state *ctrl_state = get_ctrl_state(fpt);
- struct get_pcep_session_args args = {.ctrl_state = ctrl_state,
- .pcc_id = pcc_id,
- .pcep_session = NULL};
- thread_execute(ctrl_state->self, pcep_thread_get_pcep_session_callback,
- &args, 0);
- return args.pcep_session;
+ struct pcc_state *pcc_state;
+ pcep_session *session = NULL;
+
+ pcc_state = pcep_pcc_get_pcc_by_id(ctrl_state->pcc, pcc_id);
+ if (pcc_state) {
+ session = pcep_lib_copy_pcep_session(pcc_state->sess);
+ }
+ return session;
}
struct pcep_pcc_info *pcep_ctrl_get_pcc_info(struct frr_pthread *fpt,
const char *pce_name)
{
struct ctrl_state *ctrl_state = get_ctrl_state(fpt);
- struct pcep_pcc_info *args = XCALLOC(MTYPE_PCEP, sizeof(*args));
- args->ctrl_state = ctrl_state;
- strncpy(args->pce_name, pce_name, sizeof(args->pce_name));
- thread_execute(ctrl_state->self, pcep_thread_get_pcc_info_callback,
- args, 0);
+ struct pcep_pcc_info *pcc_info = XCALLOC(MTYPE_PCEP, sizeof(*pcc_info));
+ if( pcc_info && ctrl_state){
+ strlcpy(pcc_info->pce_name, pce_name, sizeof(pcc_info->pce_name));
+ pcep_pcc_copy_pcc_info(ctrl_state->pcc, pcc_info);
+ }
- return args;
+ return pcc_info;
}
-void pcep_ctrl_send_report(struct frr_pthread *fpt, int pcc_id,
- struct path *path)
+int pcep_ctrl_send_report(struct frr_pthread *fpt, int pcc_id,
+ struct path *path, bool is_stable)
{
- /* Sends a report stynchronously */
struct ctrl_state *ctrl_state = get_ctrl_state(fpt);
- struct send_report_args args = {
- .ctrl_state = ctrl_state, .pcc_id = pcc_id, .path = path};
- thread_execute(ctrl_state->self, pcep_thread_send_report_callback,
- &args, 0);
+ return send_to_thread(ctrl_state, pcc_id, EV_SEND_REPORT, is_stable,
+ path);
}
+
/* ------------ Internal Functions Called from Main Thread ------------ */
int pcep_ctrl_halt_cb(struct frr_pthread *fpt, void **res)
return 0;
}
+int pcep_refine_path_event_cb(struct thread *thread)
+{
+ struct pcep_refine_path_event_data *data = THREAD_ARG(thread);
+ assert(data != NULL);
+ struct ctrl_state *ctrl_state = data->ctrl_state;
+ struct path *path = data->path;
+ assert(path != NULL);
+ int pcc_id = data->pcc_id;
+
+
+ path_pcep_refine_path(path);
+ return send_to_thread(ctrl_state, pcc_id, EV_PATH_REFINED, 0, data);
+}
+
/* ------------ API Functions Called From Controller Thread ------------ */
return ctrl_state->pcc_count;
}
+int pcep_thread_refine_path(struct ctrl_state *ctrl_state, int pcc_id,
+ pcep_refine_callback_t cb, struct path *path,
+ void *payload)
+{
+ struct pcep_refine_path_event_data *data;
+
+ data = XCALLOC(MTYPE_PCEP, sizeof(*data));
+ data->ctrl_state = ctrl_state;
+ data->path = path;
+ data->pcc_id = pcc_id;
+ data->continue_lsp_update_handler = cb;
+ data->payload = payload;
+
+ thread_add_event(ctrl_state->main, pcep_refine_path_event_cb,
+ (void *)data, 0, NULL);
+ return 0;
+}
+
+void pcep_thread_path_refined_event(struct ctrl_state *ctrl_state,
+ struct pcep_refine_path_event_data *data)
+{
+ assert(data != NULL);
+ int pcc_id = data->pcc_id;
+ pcep_refine_callback_t continue_lsp_update_handler = data->continue_lsp_update_handler;
+ assert(continue_lsp_update_handler != NULL);
+ struct path *path = data->path;
+ void *payload = data->payload;
+ struct pcc_state *pcc_state = NULL;
+ XFREE(MTYPE_PCEP, data);
+
+ pcc_state = pcep_pcc_get_pcc_by_id(ctrl_state->pcc, pcc_id);
+ continue_lsp_update_handler(ctrl_state, pcc_state, path, payload);
+}
+
+
/* ------------ Internal Functions Called From Controller Thread ------------ */
int pcep_thread_finish_event_handler(struct thread *thread)
return 0;
}
-int pcep_thread_get_counters_callback(struct thread *t)
-{
- struct get_counters_args *args = THREAD_ARG(t);
- assert(args != NULL);
- struct ctrl_state *ctrl_state = args->ctrl_state;
- assert(ctrl_state != NULL);
- struct pcc_state *pcc_state;
-
- pcc_state = pcep_pcc_get_pcc_by_id(ctrl_state->pcc, args->pcc_id);
- if (pcc_state) {
- args->counters = pcep_lib_copy_counters(pcc_state->sess);
- } else {
- args->counters = NULL;
- }
-
- return 0;
-}
-
-int pcep_thread_send_report_callback(struct thread *t)
-{
- struct send_report_args *args = THREAD_ARG(t);
- assert(args != NULL);
- struct ctrl_state *ctrl_state = args->ctrl_state;
- assert(ctrl_state != NULL);
- struct pcc_state *pcc_state;
-
- if (args->pcc_id == 0) {
- for (int i = 0; i < MAX_PCC; i++) {
- if (ctrl_state->pcc[i]) {
- pcep_pcc_send_report(ctrl_state,
- ctrl_state->pcc[i],
- args->path);
- }
- }
- } else {
- pcc_state =
- pcep_pcc_get_pcc_by_id(ctrl_state->pcc, args->pcc_id);
- pcep_pcc_send_report(ctrl_state, pcc_state, args->path);
- }
-
- return 0;
-}
-
-int pcep_thread_get_pcep_session_callback(struct thread *t)
-{
- struct get_pcep_session_args *args = THREAD_ARG(t);
- assert(args != NULL);
- struct ctrl_state *ctrl_state = args->ctrl_state;
- assert(ctrl_state != NULL);
- struct pcc_state *pcc_state;
-
- pcc_state = pcep_pcc_get_pcc_by_id(ctrl_state->pcc, args->pcc_id);
- if (pcc_state) {
- args->pcep_session =
- pcep_lib_copy_pcep_session(pcc_state->sess);
- }
-
- return 0;
-}
-
-int pcep_thread_get_pcc_info_callback(struct thread *t)
-{
- struct pcep_pcc_info *args = THREAD_ARG(t);
- assert(args != NULL);
- struct ctrl_state *ctrl_state = args->ctrl_state;
- assert(ctrl_state != NULL);
-
- pcep_pcc_copy_pcc_info(ctrl_state->pcc, args);
-
- return 0;
-}
-
/* ------------ Controller Thread Timer Handler ------------ */
int schedule_thread_timer_with_cb(struct ctrl_state *ctrl_state, int pcc_id,
/* Possible sub-type values */
enum pcep_pathd_event_type path_event_type = PCEP_PATH_UNDEFINED;
- /* Possible payload values */
+ /* Possible payload values, maybe an union would be better... */
struct path *path = NULL;
struct pcc_opts *pcc_opts = NULL;
struct pce_opts *pce_opts = NULL;
struct pcc_state *pcc_state = NULL;
+ struct pcep_refine_path_event_data *refine_data = NULL;
+
+ struct path *path_copy = NULL;
switch (type) {
case EV_UPDATE_PCC_OPTS:
(const char *)payload);
}
break;
+ case EV_SEND_REPORT:
+ assert(payload != NULL);
+ path = (struct path *)payload;
+ if (pcc_id == 0) {
+ for (int i = 0; i < MAX_PCC; i++) {
+ if (ctrl_state->pcc[i]) {
+ path_copy = pcep_copy_path(path);
+ pcep_pcc_send_report(
+ ctrl_state, ctrl_state->pcc[i],
+ path_copy, (bool)sub_type);
+ }
+ }
+ } else {
+ pcc_state =
+ pcep_pcc_get_pcc_by_id(ctrl_state->pcc, pcc_id);
+ pcep_pcc_send_report(ctrl_state, pcc_state, path,
+ (bool)sub_type);
+ }
+ break;
+ case EV_PATH_REFINED:
+ assert(payload != NULL);
+ refine_data = (struct pcep_refine_path_event_data *)payload;
+ pcep_thread_path_refined_event(ctrl_state, refine_data);
+ break;
default:
flog_warn(EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR,
"Unexpected event received in controller thread: %u",
/* ------------ Helper functions ------------ */
+
void set_ctrl_state(struct frr_pthread *fpt, struct ctrl_state *ctrl_state)
{
assert(fpt != NULL);
#include "pathd/path_pcep.h"
+struct ctrl_state;
+struct pcc_state;
enum pcep_main_event_type {
PCEP_MAIN_EVENT_UNDEFINED = 0,
PCEP_MAIN_EVENT_START_SYNC,
PCEP_MAIN_EVENT_UPDATE_CANDIDATE,
- PCEP_MAIN_EVENT_REMOVE_CANDIDATE_LSP
+ PCEP_MAIN_EVENT_REMOVE_CANDIDATE_LSP,
};
typedef int (*pcep_main_event_handler_t)(enum pcep_main_event_type type,
int pcc_id, void *payload);
+typedef void (*pcep_refine_callback_t)(struct ctrl_state *ctrl_state,
+ struct pcc_state *pcc_state,
+ struct path *path, void *payload);
enum pcep_pathd_event_type {
PCEP_PATH_UNDEFINED = 0,
struct pcep_pcc_info *pcep_ctrl_get_pcc_info(struct frr_pthread *fpt,
const char *pce_name);
-/* Synchronously send a report, the caller is responsible to free the path,
- * If `pcc_id` is `0` the report is sent by all PCCs */
-void pcep_ctrl_send_report(struct frr_pthread *fpt, int pcc_id,
- struct path *path);
+/* Asynchronously send a report. The caller is giving away the path structure,
+ * it shouldn't be allocated on the stack. If `pcc_id` is `0` the report is
+ * sent by all PCCs. The parameter is_stable is used to hint wether the status
+ * will soon change, this is used to ensure all report updates are sent even
+ * when missing status update events */
+int pcep_ctrl_send_report(struct frr_pthread *fpt, int pcc_id,
+ struct path *path, bool is_stable);
/* Functions called from the controller thread */
void pcep_thread_start_sync(struct ctrl_state *ctrl_state, int pcc_id);
pcep_ctrl_thread_callback cb);
int pcep_thread_pcep_event(struct thread *thread);
int pcep_thread_pcc_count(struct ctrl_state *ctrl_state);
+/* Called by the PCC to refine a path in the main thread */
+int pcep_thread_refine_path(struct ctrl_state *ctrl_state, int pcc_id,
+ pcep_refine_callback_t cb, struct path *path,
+ void *payload);
#endif // _PATH_PCEP_CONTROLLER_H_
return "UPDATE";
case PCEP_TYPE_INITIATE:
return "INITIATE";
- case PCEP_TYPE_UNKOWN_MSG:
- return "UNKOWN_MSG";
+ case PCEP_TYPE_START_TLS:
+ return "START_TLS";
default:
return "UNKNOWN";
}
&hop->nai.remote_addr.ipaddr_v6);
break;
case PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY:
- PATHD_FORMAT("%*sNAI: %pI4(%u)/%pI4(%u)\n", ps, "",
+ PATHD_FORMAT("%*sNAI: %pI6(%u)/%pI6(%u)\n", ps, "",
&hop->nai.local_addr.ipaddr_v6,
hop->nai.local_iface,
&hop->nai.remote_addr.ipaddr_v6,
#define _PATH_PCEP_DEBUG_H_
#include "pathd/path_debug.h"
-#include <pcep_pcc_api.h>
-#include <pcep-objects.h>
+#include "pceplib/pcep_pcc_api.h"
+#include "pceplib/pcep_msg_objects.h"
#include "pathd/path_pcep.h"
#include "pathd/path_pcep_controller.h"
#include "pathd/path_pcep_pcc.h"
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <zebra.h>
+
+#include "memory.h"
+
#include <debug.h>
-#include <pcep_utils_counters.h>
-#include <pcep_timers.h>
+#include "pceplib/pcep_utils_counters.h"
+#include "pceplib/pcep_timers.h"
#include "pathd/path_errors.h"
-#include "pathd/path_memory.h"
#include "pathd/path_pcep.h"
#include "pathd/path_pcep_lib.h"
#include "pathd/path_pcep_debug.h"
-#include "pathd/path_pcep_memory.h"
+
+DEFINE_MTYPE_STATIC(PATHD, PCEPLIB_INFRA, "PCEPlib Infrastructure");
+DEFINE_MTYPE_STATIC(PATHD, PCEPLIB_MESSAGES, "PCEPlib PCEP Messages");
#define CLASS_TYPE(CLASS, TYPE) (((CLASS) << 16) | (TYPE))
#define DEFAULT_LSAP_SETUP_PRIO 4
/* TODO when available in the pceplib, set it here
pcep_options->state_timeout_inteval_seconds;*/
- if (pcep_options->tcp_md5_auth != NULL
- && pcep_options->tcp_md5_auth[0] != '\0') {
+ if (pcep_options->tcp_md5_auth[0] != '\0') {
config->is_tcp_auth_md5 = true;
- strncpy(config->tcp_authentication_str,
- pcep_options->tcp_md5_auth, TCP_MD5SIG_MAXKEYLEN);
+ strlcpy(config->tcp_authentication_str,
+ pcep_options->tcp_md5_auth,
+ sizeof(config->tcp_authentication_str));
} else {
config->is_tcp_auth_md5 = false;
}
#define _PATH_PCEP_LIB_H_
#include <stdbool.h>
-#include <pcep_pcc_api.h>
+#include "pceplib/pcep_pcc_api.h"
#include "frr_pthread.h"
#include "pathd/path_pcep.h"
+++ /dev/null
-/*
- * Copyright (C) 2020 NetDEF, Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <zebra.h>
-
-#include <memory.h>
-
-#include "pathd/path_pcep_memory.h"
-
-DEFINE_MTYPE(PATHD, PCEP, "PCEP module")
-DEFINE_MTYPE(PATHD, PCEPLIB_INFRA, "PCEPlib Infrastructure")
-DEFINE_MTYPE(PATHD, PCEPLIB_MESSAGES, "PCEPlib PCEP Messages")
+++ /dev/null
-/*
- * Copyright (C) 2020 NetDEF, Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef _FRR_PATH_PCEP_MEMORY_H_
-#define _FRR_PATH_PCEP_MEMORY_H_
-
-#include "pathd/path_memory.h"
-
-DECLARE_MTYPE(PCEP)
-DECLARE_MTYPE(PCEPLIB_INFRA)
-DECLARE_MTYPE(PCEPLIB_MESSAGES)
-
-#endif /* _FRR_PATH_PCEP_MEMORY_H_ */
#include "pathd/pathd.h"
#include "pathd/path_zebra.h"
#include "pathd/path_errors.h"
-#include "pathd/path_pcep_memory.h"
#include "pathd/path_pcep.h"
#include "pathd/path_pcep_controller.h"
#include "pathd/path_pcep_lib.h"
#define MAX_ERROR_MSG_SIZE 256
#define MAX_COMPREQ_TRIES 3
+pthread_mutex_t g_pcc_info_mtx = PTHREAD_MUTEX_INITIALIZER;
/* PCEP Event Handler */
static void handle_pcep_open(struct ctrl_state *ctrl_state,
static void handle_pcep_message(struct ctrl_state *ctrl_state,
struct pcc_state *pcc_state,
struct pcep_message *msg);
+static void handle_pcep_lsp_initiate(struct ctrl_state *ctrl_state,
+ struct pcc_state *pcc_state,
+ struct pcep_message *msg);
static void handle_pcep_lsp_update(struct ctrl_state *ctrl_state,
struct pcc_state *pcc_state,
struct pcep_message *msg);
-static void handle_pcep_lsp_initiate(struct ctrl_state *ctrl_state,
+static void continue_pcep_lsp_update(struct ctrl_state *ctrl_state,
struct pcc_state *pcc_state,
- struct pcep_message *msg);
+ struct path *path, void *payload);
static void handle_pcep_comp_reply(struct ctrl_state *ctrl_state,
struct pcc_state *pcc_state,
struct pcep_message *msg);
/* Data Structure Declarations */
DECLARE_HASH(plspid_map, struct plspid_map_data, mi, plspid_map_cmp,
- plspid_map_hash)
+ plspid_map_hash);
DECLARE_HASH(nbkey_map, struct nbkey_map_data, mi, nbkey_map_cmp,
- nbkey_map_hash)
-DECLARE_HASH(req_map, struct req_map_data, mi, req_map_cmp, req_map_hash)
+ nbkey_map_hash);
+DECLARE_HASH(req_map, struct req_map_data, mi, req_map_cmp, req_map_hash);
static inline int req_entry_compare(const struct req_entry *a,
const struct req_entry *b)
int pcep_pcc_enable(struct ctrl_state *ctrl_state, struct pcc_state *pcc_state)
{
- char pcc_buff[40];
- char pce_buff[40];
-
assert(pcc_state->status == PCEP_PCC_DISCONNECTED);
assert(pcc_state->sess == NULL);
if (!CHECK_FLAG(pcc_state->flags, F_PCC_STATE_HAS_IPV4)) {
if (pcc_state->retry_count < OTHER_FAMILY_MAX_RETRIES) {
flog_warn(EC_PATH_PCEP_MISSING_SOURCE_ADDRESS,
- "skipping connection to PCE %s:%d due to "
- "missing PCC IPv4 address",
- ipaddr2str(&pcc_state->pce_opts->addr,
- pce_buff, sizeof(pce_buff)),
+ "skipping connection to PCE %pIA:%d due to missing PCC IPv4 address",
+ &pcc_state->pce_opts->addr,
pcc_state->pce_opts->port);
schedule_reconnect(ctrl_state, pcc_state);
return 0;
} else {
flog_warn(EC_PATH_PCEP_MISSING_SOURCE_ADDRESS,
- "missing IPv4 PCC address, IPv4 candidate "
- "paths will be ignored");
+ "missing IPv4 PCC address, IPv4 candidate paths will be ignored");
}
}
if (!CHECK_FLAG(pcc_state->flags, F_PCC_STATE_HAS_IPV6)) {
if (pcc_state->retry_count < OTHER_FAMILY_MAX_RETRIES) {
flog_warn(EC_PATH_PCEP_MISSING_SOURCE_ADDRESS,
- "skipping connection to PCE %s:%d due to "
- "missing PCC IPv6 address",
- ipaddr2str(&pcc_state->pce_opts->addr,
- pce_buff, sizeof(pce_buff)),
+ "skipping connection to PCE %pIA:%d due to missing PCC IPv6 address",
+ &pcc_state->pce_opts->addr,
pcc_state->pce_opts->port);
schedule_reconnect(ctrl_state, pcc_state);
return 0;
} else {
flog_warn(EC_PATH_PCEP_MISSING_SOURCE_ADDRESS,
- "missing IPv6 PCC address, IPv6 candidate "
- "paths will be ignored");
+ "missing IPv6 PCC address, IPv6 candidate paths will be ignored");
}
}
* have been spent, we still need the one for the transport familly */
if (pcc_state->pcc_addr_tr.ipa_type == IPADDR_NONE) {
flog_warn(EC_PATH_PCEP_MISSING_SOURCE_ADDRESS,
- "skipping connection to PCE %s:%d due to missing "
- "PCC address",
- ipaddr2str(&pcc_state->pce_opts->addr, pce_buff,
- sizeof(pce_buff)),
+ "skipping connection to PCE %pIA:%d due to missing PCC address",
+ &pcc_state->pce_opts->addr,
pcc_state->pce_opts->port);
schedule_reconnect(ctrl_state, pcc_state);
return 0;
if (pcc_state->sess == NULL) {
flog_warn(EC_PATH_PCEP_LIB_CONNECT,
- "failed to connect to PCE %s:%d from %s:%d",
- ipaddr2str(&pcc_state->pce_opts->addr, pce_buff,
- sizeof(pce_buff)),
+ "failed to connect to PCE %pIA:%d from %pIA:%d",
+ &pcc_state->pce_opts->addr,
pcc_state->pce_opts->port,
- ipaddr2str(&pcc_state->pcc_addr_tr, pcc_buff,
- sizeof(pcc_buff)),
+ &pcc_state->pcc_addr_tr,
pcc_state->pcc_opts->port);
schedule_reconnect(ctrl_state, pcc_state);
return 0;
send_report(pcc_state, path);
} else {
PCEP_DEBUG(
- "%s Skipping %s candidate path %s "
- "synchronization",
+ "%s Skipping %s candidate path %s synchronization",
pcc_state->tag,
ipaddr_type_name(&path->nbkey.endpoint),
path->name);
}
void pcep_pcc_send_report(struct ctrl_state *ctrl_state,
- struct pcc_state *pcc_state, struct path *path)
+ struct pcc_state *pcc_state, struct path *path,
+ bool is_stable)
{
- if (pcc_state->status != PCEP_PCC_OPERATING)
+ if ((pcc_state->status != PCEP_PCC_OPERATING)
+ || (!pcc_state->caps.is_stateful)) {
+ pcep_free_path(path);
return;
+ }
- if (pcc_state->caps.is_stateful) {
- PCEP_DEBUG("%s Send report for candidate path %s",
- pcc_state->tag, path->name);
+ PCEP_DEBUG("%s Send report for candidate path %s", pcc_state->tag,
+ path->name);
+
+ /* ODL and Cisco requires the first reported
+ * LSP to have a DOWN status, the later status changes
+ * will be comunicated through hook calls.
+ */
+ enum pcep_lsp_operational_status real_status = path->status;
+ path->status = PCEP_LSP_OPERATIONAL_DOWN;
+ send_report(pcc_state, path);
+
+ /* If no update is expected and the real status wasn't down, we need to
+ * send a second report with the real status */
+ if (is_stable && (real_status != PCEP_LSP_OPERATIONAL_DOWN)) {
+ path->srp_id = 0;
+ path->status = real_status;
send_report(pcc_state, path);
}
+
+ pcep_free_path(path);
}
+
/* ------------ Timeout handler ------------ */
void pcep_pcc_timeout_handler(struct ctrl_state *ctrl_state,
struct pcc_state *pcc_state,
- enum pcep_ctrl_timer_type type, void *param)
+ enum pcep_ctrl_timeout_type type, void *param)
{
struct req_entry *req;
// Changed of state so ...
if (step_0_best != best_pce) {
+ pthread_mutex_lock(&g_pcc_info_mtx);
// Calculate previous
previous_best_pce = step_0_best;
// Clean state
}
}
}
+ pthread_mutex_unlock(&g_pcc_info_mtx);
}
return ((best_pce == -1) ? 0 : pcc[best_pce]->id);
}
pcc_info->ctrl_state = NULL;
- pcc_info->msd = pcc_state->pcc_opts->msd;
- pcc_info->pcc_port = pcc_state->pcc_opts->port;
+ if(pcc_state->pcc_opts){
+ pcc_info->msd = pcc_state->pcc_opts->msd;
+ pcc_info->pcc_port = pcc_state->pcc_opts->port;
+ }
pcc_info->next_plspid = pcc_state->next_plspid;
pcc_info->next_reqid = pcc_state->next_reqid;
pcc_info->status = pcc_state->status;
pcc_info->pcc_id = pcc_state->id;
+ pthread_mutex_lock(&g_pcc_info_mtx);
pcc_info->is_best_multi_pce = pcc_state->is_best;
pcc_info->previous_best = pcc_state->previous_best;
+ pthread_mutex_unlock(&g_pcc_info_mtx);
pcc_info->precedence =
pcc_state->pce_opts ? pcc_state->pce_opts->precedence : 0;
- memcpy(&pcc_info->pcc_addr, &pcc_state->pcc_addr_tr,
- sizeof(struct ipaddr));
+ if(pcc_state->pcc_addr_tr.ipa_type != IPADDR_NONE){
+ memcpy(&pcc_info->pcc_addr, &pcc_state->pcc_addr_tr,
+ sizeof(struct ipaddr));
+ }
}
struct pcc_state *pcc_state,
struct pcep_message *msg)
{
- char err[MAX_ERROR_MSG_SIZE] = "";
struct path *path;
path = pcep_lib_parse_path(msg);
lookup_nbkey(pcc_state, path);
- /* TODO: Investigate if this is safe to do in the controller thread */
- path_pcep_config_lookup(path);
+ pcep_thread_refine_path(ctrl_state, pcc_state->id,
+ &continue_pcep_lsp_update, path, NULL);
+}
+
+void continue_pcep_lsp_update(struct ctrl_state *ctrl_state,
+ struct pcc_state *pcc_state, struct path *path,
+ void *payload)
+{
+ char err[MAX_ERROR_MSG_SIZE] = {0};
+
specialize_incoming_path(pcc_state, path);
PCEP_DEBUG("%s Received LSP update", pcc_state->tag);
PCEP_DEBUG_PATH("%s", format_path(path));
* the connection if more that a given rate.
*/
PCEP_DEBUG(
- "%s Received computation reply for unknown request "
- "%d",
+ "%s Received computation reply for unknown request %d",
pcc_state->tag, path->req_id);
PCEP_DEBUG_PATH("%s", format_path(path));
send_pcep_error(pcc_state, PCEP_ERRT_UNKNOWN_REQ_REF,
* address */
if (IS_IPADDR_V4(&pcc_state->pce_opts->addr)) {
if (CHECK_FLAG(pcc_state->flags, F_PCC_STATE_HAS_IPV4)) {
- taddr->ipa_type = IPADDR_V4;
taddr->ipaddr_v4 = pcc_state->pcc_addr_v4;
+ taddr->ipa_type = IPADDR_V4;
}
} else {
if (CHECK_FLAG(pcc_state->flags, F_PCC_STATE_HAS_IPV6)) {
- taddr->ipa_type = IPADDR_V6;
taddr->ipaddr_v6 = pcc_state->pcc_addr_v6;
+ taddr->ipa_type = IPADDR_V6;
}
}
}
assert(lookup_reqid(pcc_state, req->path) == req->path->req_id);
int timeout;
- char buff[40];
struct pcep_message *msg;
if (!pcc_state->is_best) {
specialize_outgoing_path(pcc_state, req->path);
PCEP_DEBUG(
- "%s Sending computation request %d for path %s to %s (retry %d)",
+ "%s Sending computation request %d for path %s to %pIA (retry %d)",
pcc_state->tag, req->path->req_id, req->path->name,
- ipaddr2str(&req->path->nbkey.endpoint, buff, sizeof(buff)),
- req->retry_count);
+ &req->path->nbkey.endpoint, req->retry_count);
PCEP_DEBUG_PATH("%s Computation request path %s: %s", pcc_state->tag,
req->path->name, format_path(req->path));
void cancel_comp_request(struct ctrl_state *ctrl_state,
struct pcc_state *pcc_state, struct req_entry *req)
{
- char buff[40];
struct pcep_message *msg;
if (req->was_sent) {
}
PCEP_DEBUG(
- "%s Canceling computation request %d for path %s to %s (retry %d)",
+ "%s Canceling computation request %d for path %s to %pIA (retry %d)",
pcc_state->tag, req->path->req_id, req->path->name,
- ipaddr2str(&req->path->nbkey.endpoint, buff, sizeof(buff)),
- req->retry_count);
+ &req->path->nbkey.endpoint, req->retry_count);
PCEP_DEBUG_PATH("%s Canceled computation request path %s: %s",
pcc_state->tag, req->path->name,
format_path(req->path));
PCEP_PCC_OPERATING
};
-PREDECL_HASH(plspid_map)
-PREDECL_HASH(nbkey_map)
-PREDECL_HASH(req_map)
+PREDECL_HASH(plspid_map);
+PREDECL_HASH(nbkey_map);
+PREDECL_HASH(req_map);
struct plspid_map_data {
struct plspid_map_item mi;
struct path *path);
void pcep_pcc_timeout_handler(struct ctrl_state *ctrl_state,
struct pcc_state *pcc_state,
- enum pcep_ctrl_timer_type type, void *param);
+ enum pcep_ctrl_timeout_type type, void *param);
void pcep_pcc_sync_path(struct ctrl_state *ctrl_state,
struct pcc_state *pcc_state, struct path *path);
void pcep_pcc_sync_done(struct ctrl_state *ctrl_state,
struct pcc_state *pcc_state);
+/* Send a report explicitly. When doing so the PCC may send multiple reports
+ * due to expectations from vendors for the first report to be with a DOWN
+ * status. The parameter is_stable is used for that purpose as a hint wheter
+ * to expect an update for the report */
void pcep_pcc_send_report(struct ctrl_state *ctrl_state,
- struct pcc_state *pcc_state, struct path *path);
+ struct pcc_state *pcc_state, struct path *path,
+ bool is_stable);
int pcep_pcc_multi_pce_sync_path(struct ctrl_state *ctrl_state, int pcc_id,
struct pcc_state **pcc_state_list);
int pcep_pcc_multi_pce_remove_pcc(struct ctrl_state *ctrl_state,
#include "network.h"
#include "pathd/pathd.h"
-#include "pathd/path_memory.h"
#include "pathd/path_zebra.h"
#include "pathd/path_debug.h"
#define HOOK_DELAY 3
-DEFINE_MTYPE_STATIC(PATHD, PATH_SEGMENT_LIST, "Segment List")
-DEFINE_MTYPE_STATIC(PATHD, PATH_SR_POLICY, "SR Policy")
-DEFINE_MTYPE_STATIC(PATHD, PATH_SR_CANDIDATE, "SR Policy candidate path")
+DEFINE_MGROUP(PATHD, "pathd");
+
+DEFINE_MTYPE_STATIC(PATHD, PATH_SEGMENT_LIST, "Segment List");
+DEFINE_MTYPE_STATIC(PATHD, PATH_SR_POLICY, "SR Policy");
+DEFINE_MTYPE_STATIC(PATHD, PATH_SR_CANDIDATE, "SR Policy candidate path");
DEFINE_HOOK(pathd_candidate_created, (struct srte_candidate * candidate),
- (candidate))
+ (candidate));
DEFINE_HOOK(pathd_candidate_updated, (struct srte_candidate * candidate),
- (candidate))
+ (candidate));
DEFINE_HOOK(pathd_candidate_removed, (struct srte_candidate * candidate),
- (candidate))
+ (candidate));
static void trigger_pathd_candidate_created(struct srte_candidate *candidate);
static int trigger_pathd_candidate_created_timer(struct thread *thread);
char endpoint[46];
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
zlog_debug(
- "SR-TE(%s, %u): candidate %s %sconfig metric %s (%u) set to %f "
- "(is-bound: %s; is_computed: %s)",
+ "SR-TE(%s, %u): candidate %s %sconfig metric %s (%u) set to %f (is-bound: %s; is_computed: %s)",
endpoint, policy->color, candidate->name,
required ? "required " : "", srte_candidate_metric_name(type),
type, value, is_bound ? "true" : "false",
char endpoint[46];
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
zlog_debug(
- "SR-TE(%s, %u): candidate %s %slsp metric %s (%u) set to %f "
- "(is-bound: %s; is_computed: %s)",
+ "SR-TE(%s, %u): candidate %s %slsp metric %s (%u) set to %f (is-bound: %s; is_computed: %s)",
endpoint, policy->color, candidate->name,
required ? "required " : "", srte_candidate_metric_name(type),
type, value, is_bound ? "true" : "false",
if (segment_list->protocol_origin
== SRTE_ORIGIN_LOCAL) {
zlog_warn(
- "Cannot unset segment list %s because it "
- "was created locally",
+ "Cannot unset segment list %s because it was created locally",
segment_list->name);
continue;
}
#ifndef _FRR_PATHD_H_
#define _FRR_PATHD_H_
+#include "lib/memory.h"
#include "lib/mpls.h"
#include "lib/ipaddr.h"
#include "lib/srte.h"
#include "lib/hook.h"
+DECLARE_MGROUP(PATHD);
+
enum srte_protocol_origin {
SRTE_ORIGIN_UNDEFINED = 0,
SRTE_ORIGIN_PCEP = 1,
RB_PROTOTYPE(srte_policy_head, srte_policy, entry, srte_policy_compare)
DECLARE_HOOK(pathd_candidate_created, (struct srte_candidate * candidate),
- (candidate))
+ (candidate));
DECLARE_HOOK(pathd_candidate_updated, (struct srte_candidate * candidate),
- (candidate))
+ (candidate));
DECLARE_HOOK(pathd_candidate_removed, (struct srte_candidate * candidate),
- (candidate))
+ (candidate));
extern struct srte_segment_list_head srte_segment_lists;
extern struct srte_policy_head srte_policies;
# TODO add man page
#man8 += $(MANBUILD)/pathd.8
-if HAVE_PATHD_PCEP
+if PATHD_PCEP
vtysh_scan += $(top_srcdir)/pathd/path_pcep_cli.c
module_LTLIBRARIES += pathd/pathd_pcep.la
endif
pathd/path_debug.c \
pathd/path_errors.c \
pathd/path_main.c \
- pathd/path_memory.c \
pathd/path_nb.c \
pathd/path_nb_config.c \
pathd/path_nb_state.c \
noinst_HEADERS += \
pathd/path_debug.h \
pathd/path_errors.h \
- pathd/path_memory.h \
pathd/path_nb.h \
pathd/path_pcep.h \
pathd/path_pcep_cli.h \
pathd/path_pcep_controller.h \
pathd/path_pcep_debug.h \
pathd/path_pcep_lib.h \
- pathd/path_pcep_memory.h \
pathd/path_pcep_config.h \
pathd/path_pcep_pcc.h \
pathd/path_zebra.h \
pathd/path_pcep_controller.c \
pathd/path_pcep_debug.c \
pathd/path_pcep_lib.c \
- pathd/path_pcep_memory.c \
pathd/path_pcep_config.c \
pathd/path_pcep_pcc.c \
# end
+
+if PATHD_PCEP
+pathd_pathd_pcep_la_CPPFLAGS = -I./pceplib $(AM_CPPFLAGS)
+pathd_pathd_pcep_la_LIBADD = pceplib/libpcep_pcc.la
+else
+pathd_pathd_pcep_la_CPPFLAGS = $(AM_CPPFLAGS)
+pathd_pathd_pcep_la_LIBADD =
+endif
+
+
pathd_pathd_pcep_la_CFLAGS = $(WERROR)
pathd_pathd_pcep_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
-pathd_pathd_pcep_la_LIBADD = @PATHD_PCEP_LIBS@
.privs = &pbr_privs,
.yang_modules = pbrd_yang_modules,
- .n_yang_modules = array_size(pbrd_yang_modules), )
+ .n_yang_modules = array_size(pbrd_yang_modules),
+);
int main(int argc, char **argv, char **envp)
{
#include "pbr_debug.h"
#include "pbr_vrf.h"
-DEFINE_MTYPE_STATIC(PBRD, PBR_MAP, "PBR Map")
-DEFINE_MTYPE_STATIC(PBRD, PBR_MAP_SEQNO, "PBR Map Sequence")
-DEFINE_MTYPE_STATIC(PBRD, PBR_MAP_INTERFACE, "PBR Map Interface")
+DEFINE_MTYPE_STATIC(PBRD, PBR_MAP, "PBR Map");
+DEFINE_MTYPE_STATIC(PBRD, PBR_MAP_SEQNO, "PBR Map Sequence");
+DEFINE_MTYPE_STATIC(PBRD, PBR_MAP_INTERFACE, "PBR Map Interface");
static uint32_t pbr_map_sequence_unique;
struct pbr_map_entry_head pbr_maps = RB_INITIALIZER(&pbr_maps);
-DEFINE_QOBJ_TYPE(pbr_map_sequence)
+DEFINE_QOBJ_TYPE(pbr_map_sequence);
static inline int pbr_map_compare(const struct pbr_map *pbrmap1,
const struct pbr_map *pbrmap2)
#define PBR_MAP_INVALID_VRF (1 << 5)
uint64_t reason;
- QOBJ_FIELDS
+ QOBJ_FIELDS;
};
-DECLARE_QOBJ_TYPE(pbr_map_sequence)
+DECLARE_QOBJ_TYPE(pbr_map_sequence);
extern struct pbr_map_entry_head pbr_maps;
#include "pbrd/pbr_memory.h"
-DEFINE_MGROUP(PBRD, "pbrd")
+DEFINE_MGROUP(PBRD, "pbrd");
*/
#ifndef __PBR_MEMORY_H__
-DECLARE_MGROUP(PBRD)
+DECLARE_MGROUP(PBRD);
#endif
#include "pbrd/pbr_memory.h"
#include "pbrd/pbr_debug.h"
-DEFINE_MTYPE_STATIC(PBRD, PBR_NHG, "PBR Nexthop Groups")
+DEFINE_MTYPE_STATIC(PBRD, PBR_NHG, "PBR Nexthop Groups");
struct hash *pbr_nhg_hash;
static struct hash *pbr_nhrc_hash;
#include "pbr_nht.h"
#include "pbr_zebra.h"
-DEFINE_MTYPE_STATIC(PBRD, PBR_MAP_VRF, "PBR Map VRF")
+DEFINE_MTYPE_STATIC(PBRD, PBR_MAP_VRF, "PBR Map VRF");
static struct pbr_vrf *pbr_vrf_alloc(void)
{
#include "pbr_debug.h"
#include "pbr_vrf.h"
-DEFINE_MTYPE_STATIC(PBRD, PBR_INTERFACE, "PBR Interface")
+DEFINE_MTYPE_STATIC(PBRD, PBR_INTERFACE, "PBR Interface");
/* Zebra structure to hold current status. */
struct zclient *zclient;
--- /dev/null
+pcep_pcc
+test/pcep_msg_tests
+test/pcep_pcc_api_tests
+test/pcep_session_logic_tests
+test/pcep_socket_comm_tests
+test/pcep_timers_tests
+test/pcep_utils_tests
+test/valgrind.pcep_msg_tests.log
+test/valgrind.pcep_pcc_api_tests.log
+test/valgrind.pcep_session_logic_tests.log
+test/valgrind.pcep_socket_comm_tests.log
+test/valgrind.pcep_timers_tests.log
+test/valgrind.pcep_utils_tests.log
+../test-driver
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Javier Garcia <javier.garcia@voltanet.io>
+ *
+ */
+
+
+#ifndef PCEP_H_
+#define PCEP_H_
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if defined(linux) || defined(GNU_LINUX)
+//#include <netinet/in.h>
+#define ipv6_u __in6_u
+#else
+// bsd family
+#define TCP_MD5SIG_MAXKEYLEN 80
+//#include <netinet/in.h>
+#define ipv6_u __u6_addr
+#ifdef __FreeBSD__
+#include <sys/endian.h>
+#else
+#include <endian.h>
+#endif /* __FreeBSD__ */
+#endif
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#endif
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+/*
+ * Definitions for encoding and decoding PCEP messages, objects, and TLVs.
+ */
+
+#ifndef PCEP_ENCODING_H
+#define PCEP_ENCODING_H
+
+#include <stdbool.h>
+
+#include "pcep_msg_messages.h"
+#include "pcep_msg_objects.h"
+#include "pcep_msg_tlvs.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct pcep_versioning {
+ bool draft_ietf_pce_segment_routing_07; /* If false, use draft16 */
+ /* As more draft versions are incorporated, add appropriate attributes
+ */
+};
+
+#define MESSAGE_HEADER_LENGTH 4
+#define PCEP_MESSAGE_LENGTH 65535
+#define OBJECT_HEADER_LENGTH 4
+#define OBJECT_RO_SUBOBJ_HEADER_LENGTH 2
+#define TLV_HEADER_LENGTH 4
+#define LENGTH_1WORD sizeof(uint32_t)
+#define LENGTH_2WORDS sizeof(uint32_t) * 2
+#define LENGTH_3WORDS sizeof(uint32_t) * 3
+#define LENGTH_4WORDS sizeof(uint32_t) * 4
+#define LENGTH_5WORDS sizeof(uint32_t) * 5
+#define LENGTH_6WORDS sizeof(uint32_t) * 6
+#define LENGTH_7WORDS sizeof(uint32_t) * 7
+#define LENGTH_8WORDS sizeof(uint32_t) * 8
+#define LENGTH_9WORDS sizeof(uint32_t) * 9
+#define LENGTH_10WORDS sizeof(uint32_t) * 10
+#define LENGTH_11WORDS sizeof(uint32_t) * 11
+#define LENGTH_12WORDS sizeof(uint32_t) * 12
+#define LENGTH_13WORDS sizeof(uint32_t) * 13
+
+/* When iterating sub-objects or TLVs, limit to 10 in case corrupt data is
+ * received */
+#define MAX_ITERATIONS 10
+
+struct pcep_versioning *create_default_pcep_versioning(void);
+void destroy_pcep_versioning(struct pcep_versioning *versioning);
+
+/*
+ * Message encoding / decoding functions
+ */
+
+/* Called before sending messages to encode the message to a byte buffer in
+ * Network byte order. This function will also encode all the objects and their
+ * TLVs in the message. The result will be stored in the encoded_message field
+ * in the pcep_message. Implemented in pcep-messages-encoding.c */
+void pcep_encode_message(struct pcep_message *message,
+ struct pcep_versioning *versioning);
+
+/* Decode the message header and return the message length.
+ * Returns < 0 for invalid message headers. */
+int32_t pcep_decode_validate_msg_header(const uint8_t *msg_buf);
+
+/* Decode the entire message */
+struct pcep_message *pcep_decode_message(const uint8_t *message_buffer);
+
+
+/*
+ * Object encoding / decoding functions
+ */
+
+/* Implemented in pcep-objects-encoding.c
+ * Encode the object in struct pcep_object_header* into the uint8_t *buf,
+ * and return the encoded object_length. */
+uint16_t pcep_encode_object(struct pcep_object_header *object_hdr,
+ struct pcep_versioning *versioning, uint8_t *buf);
+
+/* Implemented in pcep-objects-encoding.c
+ * Decode the object, including the TLVs (if any) and return the object.
+ * Returns object on success, NULL otherwise. */
+struct pcep_object_header *pcep_decode_object(const uint8_t *msg_buf);
+
+/* Internal util functions implemented in pcep-objects-encoding.c */
+void encode_ipv6(struct in6_addr *src_ipv6, uint32_t *dst);
+void decode_ipv6(const uint32_t *src, struct in6_addr *dst_ipv6);
+uint16_t normalize_pcep_tlv_length(uint16_t length);
+bool pcep_object_has_tlvs(struct pcep_object_header *object_hdr);
+uint16_t pcep_object_get_length_by_hdr(struct pcep_object_header *object_hdr);
+uint16_t pcep_object_get_length(enum pcep_object_classes object_class,
+ enum pcep_object_types object_type);
+
+
+/*
+ * TLV encoding / decoding functions
+ */
+
+/* Implemented in pcep-tlv-encoding.c
+ * Encode the tlv in struct pcep_tlv_header* into the uint8_t *buf,
+ * and return the encoded tlv_length. */
+uint16_t pcep_encode_tlv(struct pcep_object_tlv_header *tlv_hdr,
+ struct pcep_versioning *versioning, uint8_t *buf);
+
+/* Decode the TLV in tlv_buf and return a pointer to the object */
+struct pcep_object_tlv_header *pcep_decode_tlv(const uint8_t *tlv_buf);
+
+
+/*
+ * utils mainly for testing purposes
+ */
+bool validate_message_objects(struct pcep_message *msg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+/*
+ * This is the implementation of a High Level PCEP message API.
+ */
+
+#include <string.h>
+#include <arpa/inet.h>
+#include <stdarg.h>
+#include <unistd.h>
+
+#include "pcep_msg_encoding.h"
+#include "pcep_msg_messages.h"
+#include "pcep_msg_objects.h"
+#include "pcep_utils_double_linked_list.h"
+#include "pcep_utils_logging.h"
+#include "pcep_utils_memory.h"
+
+static struct pcep_message *
+pcep_msg_create_common_with_obj_list(enum pcep_message_types msg_type,
+ double_linked_list *obj_list)
+{
+ struct pcep_message *message =
+ pceplib_malloc(PCEPLIB_MESSAGES, sizeof(struct pcep_message));
+ memset(message, 0, sizeof(struct pcep_message));
+ message->msg_header = pceplib_malloc(
+ PCEPLIB_MESSAGES, sizeof(struct pcep_message_header));
+ memset(message->msg_header, 0, sizeof(struct pcep_message_header));
+ message->msg_header->type = msg_type;
+ message->msg_header->pcep_version = PCEP_MESSAGE_HEADER_VERSION;
+ message->obj_list = ((obj_list == NULL) ? dll_initialize() : obj_list);
+
+ return message;
+}
+
+static struct pcep_message *
+pcep_msg_create_common(enum pcep_message_types msg_type)
+{
+ return pcep_msg_create_common_with_obj_list(msg_type, NULL);
+}
+
+struct pcep_message *pcep_msg_create_open(uint8_t keepalive, uint8_t deadtimer,
+ uint8_t sid)
+{
+ struct pcep_message *message = pcep_msg_create_common(PCEP_TYPE_OPEN);
+ dll_append(message->obj_list,
+ pcep_obj_create_open(keepalive, deadtimer, sid, NULL));
+
+ return message;
+}
+
+struct pcep_message *
+pcep_msg_create_open_with_tlvs(uint8_t keepalive, uint8_t deadtimer,
+ uint8_t sid, double_linked_list *tlv_list)
+{
+ struct pcep_message *message = pcep_msg_create_common(PCEP_TYPE_OPEN);
+ dll_append(message->obj_list,
+ pcep_obj_create_open(keepalive, deadtimer, sid, tlv_list));
+
+ return message;
+}
+
+
+struct pcep_message *
+pcep_msg_create_request(struct pcep_object_rp *rp,
+ struct pcep_object_endpoints_ipv4 *endpoints,
+ double_linked_list *object_list)
+{
+ if ((rp == NULL) || (endpoints == NULL)) {
+ return NULL;
+ }
+
+ struct pcep_message *message = pcep_msg_create_common_with_obj_list(
+ PCEP_TYPE_PCREQ, object_list);
+ dll_prepend(message->obj_list, endpoints);
+ dll_prepend(message->obj_list, rp);
+
+ return message;
+}
+
+struct pcep_message *
+pcep_msg_create_request_ipv6(struct pcep_object_rp *rp,
+ struct pcep_object_endpoints_ipv6 *endpoints,
+ double_linked_list *object_list)
+{
+ if ((rp == NULL) || (endpoints == NULL)) {
+ return NULL;
+ }
+
+ struct pcep_message *message = pcep_msg_create_common_with_obj_list(
+ PCEP_TYPE_PCREQ, object_list);
+ dll_prepend(message->obj_list, endpoints);
+ dll_prepend(message->obj_list, rp);
+
+ return message;
+}
+
+struct pcep_message *pcep_msg_create_reply(struct pcep_object_rp *rp,
+ double_linked_list *object_list)
+{
+ struct pcep_message *message = pcep_msg_create_common_with_obj_list(
+ PCEP_TYPE_PCREP, object_list);
+
+ if (rp != NULL) {
+ dll_prepend(message->obj_list, rp);
+ }
+
+ return message;
+}
+
+struct pcep_message *pcep_msg_create_close(uint8_t reason)
+{
+ struct pcep_message *message = pcep_msg_create_common(PCEP_TYPE_CLOSE);
+ dll_append(message->obj_list, pcep_obj_create_close(reason));
+
+ return message;
+}
+
+struct pcep_message *pcep_msg_create_error(uint8_t error_type,
+ uint8_t error_value)
+{
+ struct pcep_message *message = pcep_msg_create_common(PCEP_TYPE_ERROR);
+ dll_append(message->obj_list,
+ pcep_obj_create_error(error_type, error_value));
+
+ return message;
+}
+
+struct pcep_message *
+pcep_msg_create_error_with_objects(uint8_t error_type, uint8_t error_value,
+ double_linked_list *object_list)
+{
+ struct pcep_message *message = pcep_msg_create_common_with_obj_list(
+ PCEP_TYPE_ERROR, object_list);
+ dll_prepend(message->obj_list,
+ pcep_obj_create_error(error_type, error_value));
+
+ return message;
+}
+
+struct pcep_message *pcep_msg_create_keepalive()
+{
+ return (pcep_msg_create_common(PCEP_TYPE_KEEPALIVE));
+}
+
+struct pcep_message *
+pcep_msg_create_report(double_linked_list *state_report_object_list)
+{
+ return (state_report_object_list == NULL
+ ? NULL
+ : pcep_msg_create_common_with_obj_list(
+ PCEP_TYPE_REPORT, state_report_object_list));
+}
+
+struct pcep_message *
+pcep_msg_create_update(double_linked_list *update_request_object_list)
+{
+ if (update_request_object_list == NULL) {
+ pcep_log(
+ LOG_INFO,
+ "%s: pcep_msg_create_update NULL update_request_object_list",
+ __func__);
+ return NULL;
+ }
+
+ /* There must be at least 3 objects:
+ * These 3 are mandatory: SRP, LSP, and ERO. The ERO may be empty */
+ if (update_request_object_list->num_entries < 3) {
+ pcep_log(
+ LOG_INFO,
+ "%s: pcep_msg_create_update there must be at least 3 update objects",
+ __func__);
+ return NULL;
+ }
+
+ double_linked_list_node *node = update_request_object_list->head;
+ struct pcep_object_header *obj_hdr =
+ (struct pcep_object_header *)node->data;
+
+ /* Check for the mandatory first SRP object */
+ if (obj_hdr->object_class != PCEP_OBJ_CLASS_SRP) {
+ /* If the SRP object is missing, the receiving PCC MUST send a
+ * PCErr message with Error-type=6 (Mandatory Object missing)
+ * and Error-value=10 (SRP object missing). */
+ pcep_log(
+ LOG_INFO,
+ "%s: pcep_msg_create_update missing mandatory first SRP object",
+ __func__);
+ return NULL;
+ }
+
+ /* Check for the mandatory 2nd LSP object */
+ node = node->next_node;
+ obj_hdr = (struct pcep_object_header *)node->data;
+ if (obj_hdr->object_class != PCEP_OBJ_CLASS_LSP) {
+ /* If the LSP object is missing, the receiving PCC MUST send a
+ * PCErr message with Error-type=6 (Mandatory Object missing)
+ * and Error-value=8 (LSP object missing). */
+ pcep_log(
+ LOG_INFO,
+ "%s: pcep_msg_create_update missing mandatory second LSP object",
+ __func__);
+ return NULL;
+ }
+
+ /* Check for the mandatory 3rd ERO object */
+ node = node->next_node;
+ obj_hdr = (struct pcep_object_header *)node->data;
+ if (obj_hdr->object_class != PCEP_OBJ_CLASS_ERO) {
+ /* If the ERO object is missing, the receiving PCC MUST send a
+ * PCErr message with Error-type=6 (Mandatory Object missing)
+ * and Error-value=9 (ERO object missing). */
+ pcep_log(
+ LOG_INFO,
+ "%s: pcep_msg_create_update missing mandatory third ERO object",
+ __func__);
+ return NULL;
+ }
+
+ return (pcep_msg_create_common_with_obj_list(
+ PCEP_TYPE_UPDATE, update_request_object_list));
+}
+
+struct pcep_message *
+pcep_msg_create_initiate(double_linked_list *lsp_object_list)
+{
+ if (lsp_object_list == NULL) {
+ pcep_log(
+ LOG_INFO,
+ "%s: pcep_msg_create_initiate NULL update_request_object_list",
+ __func__);
+ return NULL;
+ }
+
+ /* There must be at least 2 objects: SRP and LSP. */
+ if (lsp_object_list->num_entries < 2) {
+ pcep_log(
+ LOG_INFO,
+ "%s: pcep_msg_create_initiate there must be at least 2 objects",
+ __func__);
+ return NULL;
+ }
+
+ double_linked_list_node *node = lsp_object_list->head;
+ struct pcep_object_header *obj_hdr =
+ (struct pcep_object_header *)node->data;
+
+ /* Check for the mandatory first SRP object */
+ if (obj_hdr->object_class != PCEP_OBJ_CLASS_SRP) {
+ pcep_log(
+ LOG_INFO,
+ "%s: pcep_msg_create_initiate missing mandatory first SRP object",
+ __func__);
+ return NULL;
+ }
+
+ /* Check for the mandatory 2nd LSP object */
+ node = node->next_node;
+ obj_hdr = (struct pcep_object_header *)node->data;
+ if (obj_hdr->object_class != PCEP_OBJ_CLASS_LSP) {
+ pcep_log(
+ LOG_INFO,
+ "%s: pcep_msg_create_initiate missing mandatory second LSP object",
+ __func__);
+ return NULL;
+ }
+
+ return (pcep_msg_create_common_with_obj_list(PCEP_TYPE_INITIATE,
+ lsp_object_list));
+}
+
+struct pcep_message *pcep_msg_create_notify(struct pcep_object_notify *notify,
+ double_linked_list *object_list)
+{
+ if (notify == NULL) {
+ pcep_log(LOG_INFO,
+ "%s: pcep_msg_create_notify NULL notify object",
+ __func__);
+ return NULL;
+ }
+
+ struct pcep_message *message = pcep_msg_create_common_with_obj_list(
+ PCEP_TYPE_PCNOTF, object_list);
+ dll_prepend(message->obj_list, notify);
+
+ return message;
+}
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ */
+
+
+/*
+ * This is a High Level PCEP message API.
+ */
+
+#ifndef PCEP_MESSAGES_H
+#define PCEP_MESSAGES_H
+
+#include <stdint.h>
+#include <netinet/in.h> /* struct in_addr */
+
+#include "pcep_utils_double_linked_list.h"
+#include "pcep_msg_objects.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum pcep_message_types {
+ PCEP_TYPE_OPEN = 1,
+ PCEP_TYPE_KEEPALIVE = 2,
+ PCEP_TYPE_PCREQ = 3,
+ PCEP_TYPE_PCREP = 4,
+ PCEP_TYPE_PCNOTF = 5,
+ PCEP_TYPE_ERROR = 6,
+ PCEP_TYPE_CLOSE = 7,
+ PCEP_TYPE_REPORT = 10,
+ PCEP_TYPE_UPDATE = 11,
+ PCEP_TYPE_INITIATE = 12,
+ PCEP_TYPE_START_TLS = 13,
+ PCEP_TYPE_MAX,
+};
+
+#define PCEP_MESSAGE_HEADER_VERSION 1
+
+struct pcep_message_header {
+ uint8_t pcep_version; /* Current version is 1. */
+ enum pcep_message_types
+ type; /* Defines message type:
+ OPEN/KEEPALIVE/PCREQ/PCREP/PCNOTF/ERROR/CLOSE */
+};
+
+/* The obj_list is a double_linked_list of struct pcep_object_header pointers.
+ */
+struct pcep_message {
+ struct pcep_message_header *msg_header;
+ double_linked_list *obj_list;
+ uint8_t *encoded_message;
+ uint16_t encoded_message_length;
+};
+
+
+/*
+ * Regarding memory usage:
+ * When creating messages, any objects and tlvs passed into these APIs will be
+ * free'd when the pcep_message is free'd. That includes the
+ * double_linked_list's. So, just create the objects and TLVs, put them in their
+ * double_linked_list's, and everything will be managed internally. The message
+ * will be deleted by pcep_msg_free_message() or pcep_msg_free_message_list()
+ * which, in turn will call one of: pcep_obj_free_object() and
+ * pcep_obj_free_tlv(). For received messages, call pcep_msg_free_message() to
+ * free them.
+ */
+
+struct pcep_message *pcep_msg_create_open(uint8_t keepalive, uint8_t deadtimer,
+ uint8_t sid);
+struct pcep_message *
+pcep_msg_create_open_with_tlvs(uint8_t keepalive, uint8_t deadtimer,
+ uint8_t sid, double_linked_list *tlv_list);
+struct pcep_message *
+pcep_msg_create_request(struct pcep_object_rp *rp,
+ struct pcep_object_endpoints_ipv4 *endpoints,
+ double_linked_list *object_list);
+struct pcep_message *
+pcep_msg_create_request_ipv6(struct pcep_object_rp *rp,
+ struct pcep_object_endpoints_ipv6 *endpoints,
+ double_linked_list *object_list);
+struct pcep_message *pcep_msg_create_reply(struct pcep_object_rp *rp,
+ double_linked_list *object_list);
+struct pcep_message *pcep_msg_create_close(uint8_t reason);
+struct pcep_message *pcep_msg_create_error(uint8_t error_type,
+ uint8_t error_value);
+struct pcep_message *pcep_msg_create_error_with_objects(
+ uint8_t error_type, uint8_t error_value,
+ double_linked_list *object_list); /* include the offending objects */
+struct pcep_message *pcep_msg_create_keepalive(void);
+struct pcep_message *pcep_msg_create_notify(struct pcep_object_notify *notify,
+ double_linked_list *object_list);
+
+/* Message defined in RFC 8231 section 6.1. Expecting double_linked_list of
+ * struct pcep_object_header* objects of type SRP, LSP, or path (ERO, Bandwidth,
+ * metrics, and RRO objects). */
+struct pcep_message *
+pcep_msg_create_report(double_linked_list *state_report_object_list);
+/* Message defined in RFC 8231. Expecting double_linked_list of at least 3
+ * struct pcep_object_header* objects of type SRP, LSP, and path (ERO and
+ * intended-attribute-list). The ERO must be present, but may be empty if
+ * the PCE cannot find a valid path for a delegated LSP. */
+struct pcep_message *
+pcep_msg_create_update(double_linked_list *update_request_object_list);
+/* Message defined in RFC 8281. Expecting double_linked_list of at least 2
+ * struct pcep_object_header* objects of type SRP and LSP for LSP deletion, and
+ * may also contain Endpoints, ERO and an attribute list for LSP creation. */
+struct pcep_message *
+pcep_msg_create_initiate(double_linked_list *lsp_object_list);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+/*
+ * Encoding and decoding for PCEP messages.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "pcep_msg_encoding.h"
+#include "pcep_msg_messages.h"
+#include "pcep_msg_objects.h"
+#include "pcep_msg_tools.h"
+#include "pcep_utils_logging.h"
+#include "pcep_utils_memory.h"
+
+#define ANY_OBJECT 0
+#define NO_OBJECT -1
+#define NUM_CHECKED_OBJECTS 4
+/* It wont compile with this definition:
+ static const int
+ MANDATORY_MESSAGE_OBJECT_CLASSES[PCEP_TYPE_INITIATE+1][NUM_CHECKED_OBJECTS]
+ */
+static const enum pcep_object_classes MANDATORY_MESSAGE_OBJECT_CLASSES[13][4] =
+ {
+ {NO_OBJECT, NO_OBJECT, NO_OBJECT,
+ NO_OBJECT}, /* unsupported message ID = 0 */
+ {PCEP_OBJ_CLASS_OPEN, NO_OBJECT, NO_OBJECT,
+ NO_OBJECT}, /* PCEP_TYPE_OPEN = 1 */
+ {NO_OBJECT, NO_OBJECT, NO_OBJECT,
+ NO_OBJECT}, /* PCEP_TYPE_KEEPALIVE = 2 */
+ {PCEP_OBJ_CLASS_RP, PCEP_OBJ_CLASS_ENDPOINTS, ANY_OBJECT,
+ ANY_OBJECT}, /* PCEP_TYPE_PCREQ = 3 */
+ {PCEP_OBJ_CLASS_RP, ANY_OBJECT, ANY_OBJECT,
+ ANY_OBJECT}, /* PCEP_TYPE_PCREP = 4 */
+ {PCEP_OBJ_CLASS_NOTF, ANY_OBJECT, ANY_OBJECT,
+ ANY_OBJECT}, /* PCEP_TYPE_PCNOTF = 5 */
+ {PCEP_OBJ_CLASS_ERROR, ANY_OBJECT, ANY_OBJECT,
+ ANY_OBJECT}, /* PCEP_TYPE_ERROR = 6 */
+ {PCEP_OBJ_CLASS_CLOSE, NO_OBJECT, NO_OBJECT,
+ NO_OBJECT}, /* PCEP_TYPE_CLOSE = 7 */
+ {NO_OBJECT, NO_OBJECT, NO_OBJECT,
+ NO_OBJECT}, /* unsupported message ID = 8 */
+ {NO_OBJECT, NO_OBJECT, NO_OBJECT,
+ NO_OBJECT}, /* unsupported message ID = 9 */
+ {PCEP_OBJ_CLASS_SRP, PCEP_OBJ_CLASS_LSP, ANY_OBJECT,
+ ANY_OBJECT}, /* PCEP_TYPE_REPORT = 10 */
+ {PCEP_OBJ_CLASS_SRP, PCEP_OBJ_CLASS_LSP, ANY_OBJECT,
+ ANY_OBJECT}, /* PCEP_TYPE_UPDATE = 11 */
+ {PCEP_OBJ_CLASS_SRP, PCEP_OBJ_CLASS_LSP, ANY_OBJECT,
+ ANY_OBJECT}, /* PCEP_TYPE_INITIATE = 12 */
+};
+
+/* PCEP Message Common Header, According to RFC 5440
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Ver | Flags | Message-Type | Message-Length |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * Ver (Version - 3 bits): PCEP version number. Current version is version 1.
+ *
+ * Flags (5 bits): No flags are currently defined. Unassigned bits are
+ * considered as reserved. They MUST be set to zero on transmission
+ * and MUST be ignored on receipt.
+ */
+void pcep_encode_message(struct pcep_message *message,
+ struct pcep_versioning *versioning)
+{
+ if (message == NULL) {
+ return;
+ }
+
+ if (message->msg_header == NULL) {
+ return;
+ }
+
+ /* Internal buffer used for the entire message. Later, once the entire
+ * length is known, memory will be allocated and this buffer will be
+ * copied. */
+ uint8_t message_buffer[PCEP_MESSAGE_LENGTH] = {0};
+
+ /* Write the message header. The message header length will be
+ * written when the entire length is known. */
+ uint32_t message_length = MESSAGE_HEADER_LENGTH;
+ uint16_t net_order_length = 0;
+ message_buffer[0] = (message->msg_header->pcep_version << 5) & 0xf0;
+ message_buffer[1] = message->msg_header->type;
+
+ if (message->obj_list == NULL) {
+ net_order_length = htons(message_length);
+ memcpy(message_buffer + 2, &net_order_length,
+ sizeof(net_order_length));
+ message->encoded_message =
+ pceplib_malloc(PCEPLIB_MESSAGES, message_length);
+ memcpy(message->encoded_message, message_buffer,
+ message_length);
+ message->encoded_message_length = message_length;
+
+ return;
+ }
+
+ /* Encode each of the objects */
+ double_linked_list_node *node = message->obj_list->head;
+ for (; node != NULL; node = node->next_node) {
+ message_length +=
+ pcep_encode_object(node->data, versioning,
+ message_buffer + message_length);
+ if (message_length >= PCEP_MESSAGE_LENGTH) {
+ message->encoded_message = NULL;
+ message->encoded_message_length = 0;
+ return;
+ }
+ }
+
+ net_order_length = htons(message_length);
+ memcpy(message_buffer + 2, &net_order_length, sizeof(net_order_length));
+ message->encoded_message =
+ pceplib_malloc(PCEPLIB_MESSAGES, message_length);
+ memcpy(message->encoded_message, message_buffer, message_length);
+ message->encoded_message_length = message_length;
+}
+
+/*
+ * Decoding functions
+ */
+
+/* Expecting Host byte ordered header */
+static bool validate_msg_header(uint8_t msg_version, uint8_t msg_flags,
+ uint8_t msg_type, uint16_t msg_length)
+{
+ /* Invalid message if the length is less than the header
+ * size or if its not a multiple of 4 */
+ if (msg_length < MESSAGE_HEADER_LENGTH || (msg_length % 4) != 0) {
+ pcep_log(LOG_INFO,
+ "%s: Invalid PCEP message header length [%d]",
+ __func__, msg_length);
+ return false;
+ }
+
+ if (msg_version != PCEP_MESSAGE_HEADER_VERSION) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Invalid PCEP message header version [0x%x] expected version [0x%x]",
+ __func__, msg_version, PCEP_MESSAGE_HEADER_VERSION);
+ return false;
+ }
+
+ if (msg_flags != 0) {
+ pcep_log(LOG_INFO,
+ "%s: Invalid PCEP message header flags [0x%x]",
+ __func__, msg_flags);
+ return false;
+ }
+
+ switch (msg_type) {
+ /* Supported message types */
+ case PCEP_TYPE_OPEN:
+ case PCEP_TYPE_KEEPALIVE:
+ case PCEP_TYPE_PCREQ:
+ case PCEP_TYPE_PCREP:
+ case PCEP_TYPE_PCNOTF:
+ case PCEP_TYPE_ERROR:
+ case PCEP_TYPE_CLOSE:
+ case PCEP_TYPE_REPORT:
+ case PCEP_TYPE_UPDATE:
+ case PCEP_TYPE_INITIATE:
+ break;
+ default:
+ pcep_log(LOG_INFO, "%s: Invalid PCEP message header type [%d]",
+ __func__, msg_type);
+ return false;
+ break;
+ }
+
+ return true;
+}
+
+/* Internal util function */
+static uint16_t pcep_decode_msg_header(const uint8_t *msg_buf,
+ uint8_t *msg_version, uint8_t *msg_flags,
+ uint8_t *msg_type)
+{
+ // Check RFC 5440 for version and flags position.
+ // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ //| Ver | Flags | Message-Type | Message-Length |
+ //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *msg_version = (msg_buf[0] >> 5) & 0x07;
+ *msg_flags = (msg_buf[0] & 0x1f);
+ *msg_type = msg_buf[1];
+ uint16_t host_order_length;
+ memcpy(&host_order_length, msg_buf + 2, sizeof(host_order_length));
+ return ntohs(host_order_length);
+}
+
+/* Decode the message header and return the message length */
+int32_t pcep_decode_validate_msg_header(const uint8_t *msg_buf)
+{
+ uint8_t msg_version;
+ uint8_t msg_flags;
+ uint8_t msg_type;
+ uint32_t msg_length;
+
+ msg_length = pcep_decode_msg_header(msg_buf, &msg_version, &msg_flags,
+ &msg_type);
+
+ return ((validate_msg_header(msg_version, msg_flags, msg_type,
+ msg_length)
+ == false)
+ ? -1
+ : (int32_t)msg_length);
+}
+
+bool validate_message_objects(struct pcep_message *msg)
+{
+ if (msg->msg_header->type >= PCEP_TYPE_START_TLS) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Rejecting received message: Unknown message type [%d]",
+ __func__, msg->msg_header->type);
+ return false;
+ }
+
+ const enum pcep_object_classes *object_classes =
+ MANDATORY_MESSAGE_OBJECT_CLASSES[msg->msg_header->type];
+ double_linked_list_node *node;
+ int index;
+ for (node = (msg->obj_list == NULL ? NULL : msg->obj_list->head),
+ index = 0;
+ index < NUM_CHECKED_OBJECTS;
+ index++, (node = (node == NULL ? NULL : node->next_node))) {
+ struct pcep_object_header *obj =
+ ((node == NULL)
+ ? NULL
+ : (struct pcep_object_header *)node->data);
+
+ if ((int)object_classes[index] == NO_OBJECT) {
+ if (node != NULL) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Rejecting received message: Unexpected object [%d] present",
+ __func__, obj->object_class);
+ return false;
+ }
+ } else if (object_classes[index] != ANY_OBJECT) {
+ if (node == NULL) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Rejecting received message: Expecting object in position [%d], but none received",
+ __func__, index);
+ return false;
+ } else if (object_classes[index] != obj->object_class) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Rejecting received message: Unexpected Object Class received [%d]",
+ __func__, object_classes[index]);
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+struct pcep_message *pcep_decode_message(const uint8_t *msg_buf)
+{
+ uint8_t msg_version;
+ uint8_t msg_flags;
+ uint8_t msg_type;
+ uint16_t msg_length;
+
+ msg_length = pcep_decode_msg_header(msg_buf, &msg_version, &msg_flags,
+ &msg_type);
+ if (msg_length == 0) {
+ pcep_log(LOG_INFO, "%s: Discarding empty message", __func__);
+ return NULL;
+ }
+ if (msg_length >= PCEP_MESSAGE_LENGTH) {
+ pcep_log(LOG_INFO, "%s: Discarding message too big", __func__);
+ return NULL;
+ }
+
+ struct pcep_message *msg =
+ pceplib_calloc(PCEPLIB_MESSAGES, sizeof(struct pcep_message));
+
+ msg->msg_header = pceplib_malloc(PCEPLIB_MESSAGES,
+ sizeof(struct pcep_message_header));
+ msg->msg_header->pcep_version = msg_version;
+ msg->msg_header->type = msg_type;
+
+ msg->obj_list = dll_initialize();
+ msg->encoded_message = pceplib_malloc(PCEPLIB_MESSAGES, msg_length);
+ memcpy(msg->encoded_message, msg_buf, msg_length);
+ msg->encoded_message_length = msg_length;
+
+ uint16_t bytes_read = MESSAGE_HEADER_LENGTH;
+ while ((msg_length - bytes_read) >= OBJECT_HEADER_LENGTH) {
+ struct pcep_object_header *obj_hdr =
+ pcep_decode_object(msg_buf + bytes_read);
+
+ if (obj_hdr == NULL) {
+ pcep_log(LOG_INFO, "%s: Discarding invalid message",
+ __func__);
+ pcep_msg_free_message(msg);
+
+ return NULL;
+ }
+
+ dll_append(msg->obj_list, obj_hdr);
+ bytes_read += obj_hdr->encoded_object_length;
+ }
+
+ if (validate_message_objects(msg) == false) {
+ pcep_log(LOG_INFO, "%s: Discarding invalid message", __func__);
+ pcep_msg_free_message(msg);
+
+ return NULL;
+ }
+
+ return msg;
+}
+
+struct pcep_versioning *create_default_pcep_versioning()
+{
+ struct pcep_versioning *versioning =
+ pceplib_malloc(PCEPLIB_INFRA, sizeof(struct pcep_versioning));
+ memset(versioning, 0, sizeof(struct pcep_versioning));
+
+ return versioning;
+}
+
+void destroy_pcep_versioning(struct pcep_versioning *versioning)
+{
+ pceplib_free(PCEPLIB_INFRA, versioning);
+}
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ */
+
+#include <stdlib.h>
+
+#include "pcep_msg_object_error_types.h"
+#include "pcep_utils_logging.h"
+
+/* All of these values were copied from:
+ * https://www.iana.org/assignments/pcep/pcep.xhtml#pcep-error-object
+ * Which was last updated 2020-06-02 */
+
+static const char *error_type_strings[] = {
+ "Reserved",
+ "PCEP session establishment failure",
+ "Capability not supported",
+ "Unknown Object",
+ "Not supported object",
+ "Policy violation",
+ "Mandatory Object missing",
+ "Synchronized path computation request missing",
+ "Unknown request reference",
+ "Attempt to establish a second PCEP session",
+
+ "Reception of an invalid object", /* 10 */
+ "Unrecognized EXRS subobject",
+ "Diffserv-aware TE error",
+ "BRPC procedure completion failure",
+ "Unassigned 14",
+ "Global Concurrent Optimization Error",
+ "P2MP Capability Error",
+ "P2MP END-POINTS Error",
+ "P2MP Fragmentation Error",
+ "Invalid Operation",
+
+ "LSP State Synchronization Error", /* 20 */
+ "Invalid traffic engineering path setup type",
+ "Unassigned 22",
+ "Bad parameter value",
+ "LSP instantiation error",
+ "PCEP StartTLS failure",
+ "Association Error",
+ "WSON RWA Error",
+ "H-PCE Error",
+ "Path computation failure",
+ "Unassigned 30"};
+
+static const char *error_value_strings[MAX_ERROR_TYPE][MAX_ERROR_VALUE] = {
+
+ /* 0 Reserved */
+ {"Unassigned"},
+
+ /* 1 PCEP session establishment failure */
+ {
+ "Unassigned",
+ "reception of an invalid Open message or a non Open message.",
+ "no Open message received before the expiration of the OpenWait timer",
+ "unacceptable and non negotiable session characteristics",
+ "unacceptable but negotiable session characteristics",
+ "reception of a second Open message with still unacceptable session characteristics",
+ "reception of a PCErr message proposing unacceptable session characteristics",
+ "No Keepalive or PCErr message received before the expiration of the KeepWait timer",
+ "PCEP version not supported",
+ },
+
+ /* 2 Capability not supported */
+ {"Unassigned"},
+
+ /* 3 Unknown Object */
+ {
+ "Unassigned",
+ "Unrecognized object class",
+ "Unrecognized object Type",
+ },
+
+ /* 4 Not supported object */
+ {
+ "Unassigned",
+ "Not supported object class",
+ "Not supported object Type",
+ "Unassigned",
+ "Unsupported parameter",
+ "Unsupported network performance constraint",
+ "Bandwidth Object type 3 or 4 not supported",
+ "Unsupported endpoint type in END-POINTS Generalized Endpoint object type",
+ "Unsupported TLV present in END-POINTS Generalized Endpoint object type",
+ "Unsupported granularity in the RP object flags",
+ },
+
+ /* 5 Policy violation */
+ {
+ "Unassigned",
+ "C bit of the METRIC object set (request rejected)",
+ "O bit of the RP object cleared (request rejected)",
+ "objective function not allowed (request rejected)",
+ "OF bit of the RP object set (request rejected)",
+ "Global concurrent optimization not allowed",
+ "Monitoring message supported but rejected due to policy violation",
+ "P2MP Path computation is not allowed",
+ "Not allowed network performance constraint",
+ },
+
+ /* 6 Mandatory Object missing */
+ {
+ "Unassigned",
+ "RP object missing",
+ "RRO missing for a reoptimization request (R bit of the RP object set)",
+ "END-POINTS object missing",
+ "MONITORING object missing",
+ "Unassigned",
+ "Unassigned",
+ "Unassigned",
+ "LSP object missing",
+ "ERO object missing",
+ "SRP object missing",
+ "LSP-IDENTIFIERS TLV missing",
+ "LSP-DB-VERSION TLV missing",
+ "S2LS object missing",
+ "P2MP-LSP-IDENTIFIERS TLV missing",
+ "DISJOINTNESS-CONFIGURATION TLV missing",
+ },
+
+ /* 7 Synchronized path computation request missing */
+ {"Unassigned"},
+
+ /* 8 Unknown request reference */
+ {"Unassigned"},
+
+ /* 9 Attempt to establish a second PCEP session */
+ {"Unassigned"},
+
+ /* 10 Reception of an invalid object */
+ {
+ "Unassigned",
+ "reception of an object with P flag not set although the P-flag must be set according to this specification.",
+ "Bad label value",
+ "Unsupported number of SR-ERO subobjects",
+ "Bad label format",
+ "ERO mixes SR-ERO subobjects with other subobject types",
+ "Both SID and NAI are absent in the SR-ERO subobject",
+ "Both SID and NAI are absent in the SR-RRO subobject",
+ "SYMBOLIC-PATH-NAME TLV missing",
+ "MSD exceeds the default for the PCEP session",
+ "RRO mixes SR-RRO subobjects with other subobject types",
+ "Malformed object",
+ "Missing PCE-SR-CAPABILITY sub-TLV",
+ "Unsupported NAI Type in the SR-ERO/SR-RRO subobject",
+ "Unknown SID",
+ "NAI cannot be resolved to a SID",
+ "Could not find SRGB",
+ "SID index exceeds SRGB size",
+ "Could not find SRLB",
+ "SID index exceeds SRLB size",
+ "Inconsistent SIDs in SR-ERO / SR-RRO subobjects",
+ "MSD must be nonzero",
+ "Mismatch of O field in S2LS and LSP object",
+ "Incompatible OF codes in H-PCE",
+ "Bad Bandwidth Object type 3 (Generalized bandwidth) or 4 (Generalized bandwidth of existing TE-LSP for which a reoptimization is requested)",
+ "Unsupported LSP Protection Flags in PROTECTION-ATTRIBUTE TLV",
+ "Unsupported Secondary LSP Protection Flags in PROTECTION-ATTRIBUTE TLV",
+ "Unsupported Link Protection Type in PROTECTION-ATTRIBUTE TLV",
+ "LABEL-SET TLV present with 0 bit set but without R bit set in RP",
+ "Wrong LABEL-SET TLV present with 0 and L bit set",
+ "Wrong LABEL-SET with O bit set and wrong format",
+ "Missing GMPLS-CAPABILITY TLV",
+ "Incompatible OF code",
+ },
+
+ /* 11 Unrecognized EXRS subobject */
+ {"Unassigned"},
+
+ /* 12 Diffserv-aware TE error */
+ {
+ "Unassigned",
+ "Unsupported class-type",
+ "Invalid class-type",
+ "Class-Type and setup priority do not form a configured TE-class",
+ },
+
+ /* 13 BRPC procedure completion failure */
+ {
+ "Unassigned",
+ "BRPC procedure not supported by one or more PCEs along the domain path",
+ },
+
+ /* 14 Unassigned */
+ {"Unassigned"},
+
+ /* 15 Global Concurrent Optimization Error */
+ {
+ "Unassigned",
+ "Insufficient memory",
+ "Global concurrent optimization not supported",
+ },
+
+ /* 16 P2MP Capability Error */
+ {
+ "Unassigned",
+ "The PCE cannot satisfy the request due to insufficient memory",
+ "The PCE is not capable of P2MP computation",
+ },
+
+ /* 17 P2MP END-POINTS Error */
+ {
+ "Unassigned",
+ "The PCE cannot satisfy the request due to no END-POINTS with leaf type 2",
+ "The PCE cannot satisfy the request due to no END-POINTS with leaf type 3",
+ "The PCE cannot satisfy the request due to no END-POINTS with leaf type 4",
+ "The PCE cannot satisfy the request due to inconsistent END-POINTS",
+ },
+
+ /* 18 P2MP Fragmentation Error */
+ {
+ "Unassigned",
+ "Fragmented request failure",
+ "Fragmented Report failure",
+ "Fragmented Update failure",
+ "Fragmented Instantiation failure",
+ },
+
+ /* 19 Invalid Operation */
+ {
+ "Unassigned",
+ "Attempted LSP Update Request for a non-delegated LSP. The PCEP-ERROR object is followed by the LSP object that identifies the LSP.",
+ "Attempted LSP Update Request if the stateful PCE capability was not advertised.",
+ "Attempted LSP Update Request for an LSP identified by an unknown PLSP-ID.",
+ "Unassigned",
+ "Attempted LSP State Report if active stateful PCE capability was not advertised.",
+ "PCE-initiated LSP limit reached",
+ "Delegation for PCE-initiated LSP cannot be revoked",
+ "Non-zero PLSP-ID in LSP Initiate Request",
+ "LSP is not PCE initiated",
+ "PCE-initiated operation-frequency limit reached",
+ "Attempted LSP State Report for P2MP if stateful PCE capability for P2MP was not advertised",
+ "Attempted LSP Update Request for P2MP if active stateful PCE capability for P2MP was not advertised",
+ "Attempted LSP Instantiation Request for P2MP if stateful PCE instantiation capability for P2MP was not advertised",
+ "Auto-Bandwidth capability was not advertised",
+ },
+
+ /* 20 LSP State Synchronization Error */
+ {
+ "Unassigned",
+ "A PCE indicates to a PCC that it cannot process (an otherwise valid) LSP State Report. The PCEP- ERROR object is followed by the LSP object that identifies the LSP.",
+ "LSP-DB version mismatch.",
+ "Attempt to trigger synchronization before PCE trigger.",
+ "Attempt to trigger a synchronization when the PCE triggered synchronization capability has not been advertised.",
+ "A PCC indicates to a PCE that it cannot complete the State Synchronization.",
+ "Received an invalid LSP-DB Version Number.",
+ "Received an invalid Speaker Entity Identifier.",
+ },
+
+ /* 21 Invalid traffic engineering path setup type */
+ {
+ "Unassigned",
+ "Unsupported path setup type",
+ "Mismatched path setup type",
+ },
+
+ /* 22 Unassigned */
+ {"Unassigned"},
+
+ /* 23 Bad parameter value */
+ {
+ "Unassigned",
+ "SYMBOLIC-PATH-NAME in use",
+ "Speaker identity included for an LSP that is not PCE initiated",
+ },
+
+ /* 24 LSP instantiation error */
+ {
+ "Unassigned",
+ "Unacceptable instantiation parameters",
+ "Internal error",
+ "Signaling error",
+ },
+
+ /* 25 PCEP StartTLS failure */
+ {
+ "Unassigned",
+ "Reception of StartTLS after any PCEP exchange",
+ "Reception of any other message apart from StartTLS, Open, or PCErr",
+ "Failure, connection without TLS is not possible",
+ "Failure, connection without TLS is possible",
+ "No StartTLS message (nor PCErr/Open) before StartTLSWait timer expiry",
+ },
+
+ /* 26 Association Error */
+ {
+ "Unassigned",
+ "Association Type is not supported",
+ "Too many LSPs in the association group",
+ "Too many association groups",
+ "Association unknown",
+ "Operator-configured association information mismatch",
+ "Association information mismatch",
+ "Cannot join the association group",
+ "Association ID not in range",
+ "Tunnel ID or End points mismatch for Path Protection Association",
+ "Attempt to add another working/protection LSP for Path Protection Association",
+ "Protection type is not supported",
+ },
+
+ /* 27 WSON RWA Error */
+ {
+ "Unassigned",
+ "Insufficient Memory",
+ "RWA computation Not supported",
+ "Syntactical Encoding error",
+ },
+
+ /* 28 H-PCE Error */
+ {
+ "Unassigned",
+ "H-PCE Capability not advertised",
+ "Parent PCE Capability cannot be provided",
+ },
+
+ /* 29 Path computation failure */
+ {
+ "Unassigned",
+ "Unacceptable request message",
+ "Generalized bandwidth value not supported",
+ "Label Set constraint could not be met",
+ "Label constraint could not be met",
+ }
+
+ /* 30-255 Unassigned */
+};
+
+
+const char *get_error_type_str(enum pcep_error_type error_type)
+{
+ if (error_type < 0 || error_type >= MAX_ERROR_TYPE) {
+ pcep_log(
+ LOG_DEBUG,
+ "%s: get_error_type_str: error_type [%d] out of range [0..%d]",
+ __func__, error_type, MAX_ERROR_TYPE);
+
+ return NULL;
+ }
+
+ return error_type_strings[error_type];
+}
+
+const char *get_error_value_str(enum pcep_error_type error_type,
+ enum pcep_error_value error_value)
+{
+ if (error_type < 0 || error_type >= MAX_ERROR_TYPE) {
+ pcep_log(
+ LOG_DEBUG,
+ "%s: get_error_value_str: error_type [%d] out of range [0..%d]",
+ __func__, error_type, MAX_ERROR_TYPE);
+
+ return NULL;
+ }
+
+ if (error_value < 0 || error_value >= MAX_ERROR_VALUE) {
+ pcep_log(
+ LOG_DEBUG,
+ "%s: get_error_value_str: error_value [%d] out of range [0..%d]",
+ __func__, error_value, MAX_ERROR_VALUE);
+
+ return NULL;
+ }
+
+ if (error_value_strings[error_type][error_value] == NULL) {
+ return "Unassigned";
+ }
+
+ return error_value_strings[error_type][error_value];
+}
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ */
+
+
+/*
+ * Error Object Type and Value definitions
+ */
+
+#ifndef PCEP_OBJECT_ERROR_TYPES_H
+#define PCEP_OBJECT_ERROR_TYPES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MAX_ERROR_TYPE 30
+#define MAX_ERROR_VALUE 255
+
+enum pcep_error_type {
+ PCEP_ERRT_SESSION_FAILURE = 1,
+ PCEP_ERRT_CAPABILITY_NOT_SUPPORTED = 2,
+ PCEP_ERRT_UNKNOW_OBJECT = 3,
+ PCEP_ERRT_NOT_SUPPORTED_OBJECT = 4,
+ PCEP_ERRT_POLICY_VIOLATION = 5,
+ PCEP_ERRT_MANDATORY_OBJECT_MISSING = 6,
+ PCEP_ERRT_SYNC_PC_REQ_MISSING = 7,
+ PCEP_ERRT_UNKNOWN_REQ_REF = 8,
+ PCEP_ERRT_ATTEMPT_TO_ESTABLISH_2ND_PCEP_SESSION = 9,
+ PCEP_ERRT_RECEPTION_OF_INV_OBJECT = 10,
+
+ PCEP_ERRT_UNRECOGNIZED_EXRS_SUBOBJ = 11,
+ PCEP_ERRT_DIFFSERV_AWARE_TE_ERROR = 12,
+ PCEP_ERRT_BRPC_PROC_COMPLETION_ERROR = 13,
+ PCEP_ERRT_UNASSIGNED14 = 14,
+ PCEP_ERRT_GLOBAL_CONCURRENT_ERROR = 15,
+ PCEP_ERRT_P2PMP_CAP_ERROR = 16,
+ PCEP_ERRT_P2P_ENDPOINTS_ERROR = 17,
+ PCEP_ERRT_P2P_FRAGMENTATION_ERROR = 18,
+ PCEP_ERRT_INVALID_OPERATION = 19,
+ PCEP_ERRT_LSP_STATE_SYNC_ERROR = 20,
+
+ PCEP_ERRT_INVALID_TE_PATH_SETUP_TYPE = 21,
+ PCEP_ERRT_UNASSIGNED22 = 22,
+ PCEP_ERRT_BAD_PARAMETER_VALUE = 23,
+ PCEP_ERRT_LSP_INSTANTIATE_ERROR = 24,
+ PCEP_ERRT_START_TLS_FAILURE = 25,
+ PCEP_ERRT_ASSOCIATION_ERROR = 26,
+ PCEP_ERRT_WSON_RWA_ERROR = 27,
+ PCEP_ERRT_H_PCE_ERROR = 28,
+ PCEP_ERRT_PATH_COMP_FAILURE = 29,
+ PCEP_ERRT_UNASSIGNED30 = 30 /* 30 - 255 Unassigned */
+};
+
+enum pcep_error_value {
+ /* Error Value for Error Types that do not use an Error Value:
+ * PCEP_ERRT_CAPABILITY_NOT_SUPPORTED=2
+ * PCEP_ERRT_SYNC_PC_REQ_MISSING=7
+ * PCEP_ERRT_UNKNOWN_REQ_REF=8
+ * PCEP_ERRT_ATTEMPT_TO_ESTABLISH_2ND_PCEP_SESSION=9
+ * PCEP_ERRT_UNRECOGNIZED_EXRS_SUBOBJ=11 */
+ PCEP_ERRV_UNASSIGNED = 0,
+
+ /* Error Values for PCEP_ERRT_SESSION_FAILURE=1 */
+ PCEP_ERRV_RECVD_INVALID_OPEN_MSG = 1,
+ PCEP_ERRV_OPENWAIT_TIMED_OUT = 2,
+ PCEP_ERRV_UNACCEPTABLE_OPEN_MSG_NO_NEG = 3,
+ PCEP_ERRV_UNACCEPTABLE_OPEN_MSG_NEG = 4,
+ PCEP_ERRV_RECVD_SECOND_OPEN_MSG_UNACCEPTABLE = 5,
+ PCEP_ERRV_RECVD_PCERR = 6,
+ PCEP_ERRV_KEEPALIVEWAIT_TIMED_OUT = 7,
+ PCEP_ERRV_PCEP_VERSION_NOT_SUPPORTED = 8,
+
+ /* Error Values for PCEP_ERRT_UNKNOW_OBJECT=3 */
+ PCEP_ERRV_UNREC_OBJECT_CLASS = 1,
+ PCEP_ERRV_UNREC_OBJECT_TYPE = 2,
+
+ /* Error Values for PCEP_ERRT_NOT_SUPPORTED_OBJECT=4 */
+ PCEP_ERRV_NOT_SUPPORTED_OBJECT_CLASS = 1,
+ PCEP_ERRV_NOT_SUPPORTED_OBJECT_TYPE = 2,
+ /* 3: Unassigned */
+ PCEP_ERRV_UNSUPPORTED_PARAM = 4,
+ PCEP_ERRV_UNSUPPORTED_NW_PERF_CONSTRAINT = 5,
+ PCEP_ERRV_NOT_SUPPORTED_BW_OBJECT_3_4 = 6,
+ PCEP_ERRV_UNSUPPORTED_ENDPOINT_TYPE = 7,
+ PCEP_ERRV_UNSUPPORTED_ENDPOINT_TLV = 8,
+ PCEP_ERRV_UNSUPPORTED_RP_FLAG_GRANULARITY = 9,
+
+ /* Error Values for PCEP_ERRT_POLICY_VIOLATION=5 */
+ PCEP_ERRV_C_BIT_SET_IN_METRIC_OBJECT = 1,
+ PCEP_ERRV_O_BIT_CLEARD_IN_RP_OBJECT = 2,
+ PCEP_ERRV_OBJECTIVE_FUNC_NOT_ALLOWED = 3,
+ PCEP_ERRV_RP_OF_BIT_SET = 4,
+ PCEP_ERRV_GLOBAL_CONCURRENCY_NOT_ALLOWED = 5,
+ PCEP_ERRV_MONITORING_MSG_REJECTED = 6,
+ PCEP_ERRV_P2MP_PATH_COMP_NOT_ALLOWED = 7,
+ PCEP_ERRV_UNALLOWED_NW_PERF_CONSTRAINT = 8,
+
+ /* Error Values for PCEP_ERRT_MANDATORY_OBJECT_MISSING=6 */
+ PCEP_ERRV_RP_OBJECT_MISSING = 1,
+ PCEP_ERRV_RRO_OBJECT_MISSING_FOR_REOP = 2,
+ PCEP_ERRV_EP_OBJECT_MISSING = 3,
+ PCEP_ERRV_MONITOR_OBJECT_MISSING = 4,
+ /* 5 - 7 Unassigned */
+ PCEP_ERRV_LSP_OBJECT_MISSING = 8,
+ PCEP_ERRV_ERO_OBJECT_MISSING = 9,
+ PCEP_ERRV_SRP_OBJECT_MISSING = 10,
+ PCEP_ERRV_LSP_ID_TLV_MISSING = 11,
+ PCEP_ERRV_LSP_DB_TLV_MISSING = 12,
+ PCEP_ERRV_S2LS_OBJECT_MISSING = 13,
+ PCEP_ERRV_P2MP_LSP_ID_TLV_MISSING = 14,
+ PCEP_ERRV_DISJOINTED_CONF_TLV_MISSING = 15,
+
+ /* Error Values for PCEP_ERRT_RECEPTION_OF_INV_OBJECT=10 */
+ PCEP_ERRV_P_FLAG_NOT_CORRECT_IN_OBJECT = 1,
+ PCEP_ERRV_BAD_LABEL_VALUE = 2,
+ PCEP_ERRV_UNSUPPORTED_NUM_SR_ERO_SUBOBJECTS = 3,
+ PCEP_ERRV_BAD_LABEL_FORMAT = 4,
+ PCEP_ERRV_ERO_SR_ERO_MIX = 5,
+ PCEP_ERRV_SR_ERO_SID_NAI_ABSENT = 6,
+ PCEP_ERRV_SR_RRO_SID_NAI_ABSENT = 7,
+ PCEP_ERRV_SYMBOLIC_PATH_NAME_TLV_MISSING = 8,
+ PCEP_ERRV_MSD_EXCEEDS_PCEP_SESSION_MAX = 9,
+
+ PCEP_ERRV_RRO_SR_RRO_MIX = 10,
+ PCEP_ERRV_MALFORMED_OBJECT = 11,
+ PCEP_ERRV_MISSING_PCE_SR_CAP_TLV = 12,
+ PCEP_ERRV_UNSUPPORTED_NAI = 13,
+ PCEP_ERRV_UNKNOWN_SID = 14,
+ PCEP_ERRV_CANNOT_RESOLVE_NAI_TO_SID = 15,
+ PCEP_ERRV_COULD_NOT_FIND_SRGB = 16,
+ PCEP_ERRV_SID_EXCEEDS_SRGB = 17,
+ PCEP_ERRV_COULD_NOT_FIND_SRLB = 18,
+ PCEP_ERRV_SID_EXCEEDS_SRLB = 19,
+
+ PCEP_ERRV_INCONSISTENT_SID = 20,
+ PCEP_ERRV_MSD_MUST_BE_NONZERO = 21,
+ PCEP_ERRV_MISMATCH_O_S2LS_LSP = 22,
+ PCEP_ERRV_INCOMPATIBLE_H_PCE_OF = 23,
+ PCEP_ERRV_BAD_BANDWIDTH_TYPE_3_4 = 24,
+ PCEP_ERRV_UNSUPPORTED_LSP_PROT_FLAGS = 25,
+ PCEP_ERRV_UNSUPPORTED_2ND_LSP_PROT_FLAGS = 26,
+ PCEP_ERRV_UNSUPPORTED_LINK_PROT_TYPE = 27,
+ PCEP_ERRV_LABEL_SET_TLV_NO_RP_R = 28,
+ PCEP_ERRV_WRONG_LABEL_SET_TLV_O_L_SET = 29,
+
+ PCEP_ERRV_WRONG_LABEL_SET_O_SET = 30,
+ PCEP_ERRV_MISSING_GMPLS_CAP_TLV = 31,
+ PCEP_ERRV_INCOMPATIBLE_OF_CODE = 32,
+
+ /* PCEP_ERRT_DIFFSERV_AWARE_TE_ERROR = 12 */
+ PCEP_ERRV_UNSUPPORTED_CLASS_TYPE = 1,
+ PCEP_ERRV_INVALID_CLASS_TYPE = 2,
+ PCEP_ERRV_CLASS_SETUP_TYPE_NOT_TE_CLASS = 3,
+
+ /* PCEP_ERRT_BRPC_PROC_COMPLETION_ERROR = 13 */
+ PCEP_ERRV_BRPC_PROC_NOT_SUPPORTED = 1,
+
+ /* PCEP_ERRT_UNASSIGNED14 = 14 */
+
+ /* PCEP_ERRT_GLOBAL_CONCURRENT_ERROR = 15 */
+ PCEP_ERRV_INSUFFICIENT_MEMORY = 1,
+ PCEP_ERRV_GLOBAL_CONCURRENT_OPT_NOT_SUPPORTED = 2,
+
+ /* PCEP_ERRT_P2PMP_CAP_ERROR = 16 */
+ PCEP_ERRV_PCE_INSUFFICIENT_MEMORY = 1,
+ PCEP_ERRV_PCE_NOT_CAPABLE_P2MP_COMP = 2,
+
+ /* PCEP_ERRT_P2P_ENDPOINTS_ERROR = 17 */
+ PCEP_ERRV_NO_EP_WITH_LEAF_TYPE2 = 1,
+ PCEP_ERRV_NO_EP_WITH_LEAF_TYPE3 = 2,
+ PCEP_ERRV_NO_EP_WITH_LEAF_TYPE4 = 3,
+ PCEP_ERRV_INCONSITENT_EP = 4,
+
+ /* PCEP_ERRT_P2P_FRAGMENTATION_ERROR = 18 */
+ PCEP_ERRV_FRAG_REQUEST_FAILURE = 1,
+ PCEP_ERRV_FRAG_REPORT_FAILURE = 2,
+ PCEP_ERRV_FRAG_UPDATE_FAILURE = 3,
+ PCEP_ERRV_FRAG_INSTANTIATION_FAILURE = 4,
+
+ /* Error Values for PCEP_ERRT_INVALID_OPERATION=19 */
+ PCEP_ERRV_LSP_UPDATE_FOR_NON_DELEGATED_LSP = 1,
+ PCEP_ERRV_LSP_UPDATE_NON_ADVERTISED_PCE = 2,
+ PCEP_ERRV_LSP_UPDATE_UNKNOWN_PLSP_ID = 3,
+ /* 4: unassigned */
+ PCEP_ERRV_LSP_REPORT_NON_ADVERTISED_PCE = 5,
+ PCEP_ERRV_PCE_INIT_LSP_LIMIT_REACHED = 6,
+ PCEP_ERRV_PCE_INIT_LSP_DELEGATION_CANT_REVOKE = 7,
+ PCEP_ERRV_LSP_INIT_NON_ZERO_PLSP_ID = 8,
+ PCEP_ERRV_LSP_NOT_PCE_INITIATED = 9,
+ PCEP_ERRV_PCE_INIT_OP_FREQ_LIMIT_REACHED = 10,
+ PCEP_ERRV_LSP_REPORT_P2MP_NOT_ADVERTISED = 11,
+ PCEP_ERRV_LSP_UPDATE_P2MP_NOT_ADVERTISED = 12,
+ PCEP_ERRV_LSP_INSTANTIATION_P2MP_NOT_ADVERTISED = 13,
+ PCEP_ERRV_AUTO_BW_CAP_NOT_ADVERTISED = 14,
+
+ /* Error Values for PCEP_ERRT_LSP_STATE_SYNC_ERROR=20 */
+ PCEP_ERRV_PCE_CANT_PROCESS_LSP_REPORT = 1,
+ PCEP_ERRV_LSP_DB_VERSION_MISMATCH = 2,
+ PCEP_ERRV_TRIGGER_ATTEMPT_BEFORE_PCE_TRIGGER = 3,
+ PCEP_ERRV_TRIGGER_ATTEMPT_NO_PCE_TRIGGER_CAP = 4,
+ PCEP_ERRV_PCC_CANT_COMPLETE_STATE_SYNC = 5,
+ PCEP_ERRV_INVALID_LSP_DB_VERSION_NUMBER = 6,
+ PCEP_ERRV_INVALID_SPEAKER_ENTITY_ID = 7,
+
+ /* PCEP_ERRT_INVALID_TE_PATH_SETUP_TYPE = 21 */
+ PCEP_ERRV_UNSUPPORTED_PATH_SETUP_TYPE = 1,
+ PCEP_ERRV_MISMATCHED_PATH_SETUP_TYPE = 2,
+
+ /* PCEP_ERRT_UNASSIGNED22 = 22 */
+
+ /* Error Values for PCEP_ERRT_BAD_PARAMETER_VALUE=23 */
+ PCEP_ERRV_SYMBOLIC_PATH_NAME_IN_USE = 1,
+ PCEP_ERRV_LSP_SPEAKER_ID_NOT_PCE_INITIATED = 2,
+
+ /* Error Values for PCEP_ERRT_LSP_INSTANTIATE_ERROR=24 */
+ PCEP_ERRV_UNACCEPTABLE_INSTANTIATE_ERROR = 1,
+ PCEP_ERRV_INTERNAL_ERROR = 2,
+ PCEP_ERRV_SIGNALLING_ERROR = 3,
+
+ /* PCEP_ERRT_START_TLS_FAILURE = 25 */
+ PCEP_ERRV_START_TLS_AFTER_PCEP_EXCHANGE = 1,
+ PCEP_ERRV_MSG_NOT_START_TLS_OPEN_ERROR = 2,
+ PCEP_ERRV_CONNECTION_WO_TLS_NOT_POSSIBLE = 3,
+ PCEP_ERRV_CONNECTION_WO_TLS_IS_POSSIBLE = 4,
+ PCEP_ERRV_NO_START_TLS_BEFORE_START_TLS_WAIT_TIMER = 5,
+
+ /* PCEP_ERRT_ASSOCIATION_ERROR = 26 */
+ PCEP_ERRV_ASSOC_TYPE_NOT_SUPPORTED = 1,
+ PCEP_ERRV_TOO_MANY_LSPS_IN_ASSOC_GRP = 2,
+ PCEP_ERRV_TOO_MANY_ASSOC_GROUPS = 3,
+ PCEP_ERRV_ASSOCIATION_UNKNOWN = 4,
+ PCEP_ERRV_OP_CONF_ASSOC_INFO_MISMATCH = 5,
+ PCEP_ERRV_ASSOC_INFO_MISMATCH = 6,
+ PCEP_ERRV_CANNOT_JOIN_ASSOC_GROUP = 7,
+ PCEP_ERRV_ASSOC_ID_NOT_IN_RANGE = 8,
+ PCEP_ERRV_TUNNEL_EP_MISMATCH_PATH_PROT_ASSOC = 9,
+ PCEP_ERRV_ATTEMPTED_ADD_LSP_PATH_PROT_ASSOC = 10,
+ PCEP_ERRV_PROTECTION_TYPE_NOT_SUPPORTED = 11,
+
+ /* PCEP_ERRT_WSON_RWA_ERROR = 27 */
+ PCEP_ERRV_RWA_INSUFFICIENT_MEMORY = 1,
+ PCEP_ERRV_RWA_COMP_NOT_SUPPORTED = 2,
+ PCEP_ERRV_SYNTAX_ENC_ERROR = 3,
+
+ /* PCEP_ERRT_H_PCE_ERROR = 28 */
+ PCEP_ERRV_H_PCE_CAP_NOT_ADVERTISED = 1,
+ PCEP_ERRV_PARENT_PCE_CAP_CANT_BE_PROVIDED = 2,
+
+ /* PCEP_ERRT_PATH_COMP_FAILURE = 29 */
+ PCEP_ERRV_UNACCEPTABLE_REQUEST_MSG = 1,
+ PCEP_ERRV_GENERALIZED_BW_VAL_NOT_SUPPORTED = 2,
+ PCEP_ERRV_LABEL_SET_CONSTRAINT_COULD_NOT_BE_MET = 3,
+ PCEP_ERRV_LABEL_CONSTRAINT_COULD_NOT_BE_MET = 4,
+
+};
+
+const char *get_error_type_str(enum pcep_error_type error_type);
+const char *get_error_value_str(enum pcep_error_type error_type,
+ enum pcep_error_value error_value);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+/*
+ * This is the implementation of a High Level PCEP message object API.
+ */
+
+#include <string.h>
+#include <arpa/inet.h>
+#include <stdarg.h>
+#include <unistd.h>
+
+#include "pcep_msg_objects.h"
+#include "pcep_msg_tlvs.h"
+#include "pcep_utils_double_linked_list.h"
+#include "pcep_utils_logging.h"
+#include "pcep_utils_memory.h"
+
+/* Internal common function used to create a pcep_object and populate the header
+ */
+static struct pcep_object_header *pcep_obj_create_common_with_tlvs(
+ uint8_t obj_length, enum pcep_object_classes object_class,
+ enum pcep_object_types object_type, double_linked_list *tlv_list)
+{
+ uint8_t *buffer = pceplib_malloc(PCEPLIB_MESSAGES, obj_length);
+ memset(buffer, 0, obj_length);
+
+ /* The flag_p and flag_i flags will be set externally */
+ struct pcep_object_header *hdr = (struct pcep_object_header *)buffer;
+ hdr->object_class = object_class;
+ hdr->object_type = object_type;
+ hdr->tlv_list = tlv_list;
+
+ return hdr;
+}
+
+static struct pcep_object_header *
+pcep_obj_create_common(uint8_t obj_length,
+ enum pcep_object_classes object_class,
+ enum pcep_object_types object_type)
+{
+ return pcep_obj_create_common_with_tlvs(obj_length, object_class,
+ object_type, NULL);
+}
+
+struct pcep_object_open *pcep_obj_create_open(uint8_t keepalive,
+ uint8_t deadtimer, uint8_t sid,
+ double_linked_list *tlv_list)
+{
+ struct pcep_object_open *open =
+ (struct pcep_object_open *)pcep_obj_create_common_with_tlvs(
+ sizeof(struct pcep_object_open), PCEP_OBJ_CLASS_OPEN,
+ PCEP_OBJ_TYPE_OPEN, tlv_list);
+
+ open->open_version =
+ PCEP_OBJECT_OPEN_VERSION; /* PCEP version. Current version is 1
+ /No flags are currently defined. */
+ open->open_keepalive =
+ keepalive; /* Maximum period of time between two consecutive
+ PCEP messages sent by the sender. */
+ open->open_deadtimer = deadtimer; /* Specifies the amount of time before
+ closing the session down. */
+ open->open_sid = sid; /* PCEP session number that identifies the current
+ session. */
+
+ return open;
+}
+
+struct pcep_object_rp *pcep_obj_create_rp(uint8_t priority, bool flag_r,
+ bool flag_b, bool flag_s,
+ bool flag_of, uint32_t reqid,
+ double_linked_list *tlv_list)
+{
+ if (priority > OBJECT_RP_MAX_PRIORITY) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Error creating RP object, invalid priority [%d], max priority [%d].",
+ __func__, priority, OBJECT_RP_MAX_PRIORITY);
+ return NULL;
+ }
+
+ struct pcep_object_rp *obj =
+ (struct pcep_object_rp *)pcep_obj_create_common_with_tlvs(
+ sizeof(struct pcep_object_rp), PCEP_OBJ_CLASS_RP,
+ PCEP_OBJ_TYPE_RP, tlv_list);
+
+ obj->priority = priority;
+ obj->flag_reoptimization = flag_r;
+ obj->flag_bidirectional = flag_b;
+ obj->flag_strict = flag_s;
+ obj->flag_of = flag_of;
+ obj->request_id = reqid;
+
+ return obj;
+}
+
+struct pcep_object_notify *
+pcep_obj_create_notify(enum pcep_notification_types notification_type,
+ enum pcep_notification_values notification_value)
+{
+ struct pcep_object_notify *obj =
+ (struct pcep_object_notify *)pcep_obj_create_common(
+ sizeof(struct pcep_object_notify), PCEP_OBJ_CLASS_NOTF,
+ PCEP_OBJ_TYPE_NOTF);
+
+ obj->notification_type = notification_type;
+ obj->notification_value = notification_value;
+
+ return obj;
+}
+
+struct pcep_object_nopath *
+pcep_obj_create_nopath(uint8_t ni, bool flag_c,
+ enum pcep_nopath_tlv_err_codes error_code)
+{
+ struct pcep_object_tlv_nopath_vector *tlv =
+ pcep_tlv_create_nopath_vector(error_code);
+ double_linked_list *tlv_list = dll_initialize();
+ dll_append(tlv_list, tlv);
+
+ struct pcep_object_nopath *obj =
+ (struct pcep_object_nopath *)pcep_obj_create_common_with_tlvs(
+ sizeof(struct pcep_object_nopath),
+ PCEP_OBJ_CLASS_NOPATH, PCEP_OBJ_TYPE_NOPATH, tlv_list);
+
+ obj->ni = ni;
+ obj->flag_c = flag_c;
+ obj->err_code = error_code;
+
+ return obj;
+}
+
+struct pcep_object_association_ipv4 *
+pcep_obj_create_association_ipv4(bool r_flag, uint16_t association_type,
+ uint16_t association_id, struct in_addr src)
+{
+ struct pcep_object_association_ipv4 *obj =
+ (struct pcep_object_association_ipv4 *)pcep_obj_create_common(
+ sizeof(struct pcep_object_association_ipv4),
+ PCEP_OBJ_CLASS_ASSOCIATION,
+ PCEP_OBJ_TYPE_ASSOCIATION_IPV4);
+
+ obj->R_flag = r_flag;
+ obj->association_type = association_type;
+ obj->association_id = association_id;
+ obj->src = src;
+
+ return obj;
+}
+struct pcep_object_association_ipv6 *
+pcep_obj_create_association_ipv6(bool r_flag, uint16_t association_type,
+ uint16_t association_id, struct in6_addr src)
+{
+ struct pcep_object_association_ipv6 *obj =
+ (struct pcep_object_association_ipv6 *)pcep_obj_create_common(
+ sizeof(struct pcep_object_association_ipv6),
+ PCEP_OBJ_CLASS_ASSOCIATION,
+ PCEP_OBJ_TYPE_ASSOCIATION_IPV6);
+
+ obj->R_flag = r_flag;
+ obj->association_type = association_type;
+ obj->association_id = association_id;
+ obj->src = src;
+
+ return obj;
+}
+struct pcep_object_endpoints_ipv4 *
+pcep_obj_create_endpoint_ipv4(const struct in_addr *src_ipv4,
+ const struct in_addr *dst_ipv4)
+{
+ if (src_ipv4 == NULL || dst_ipv4 == NULL) {
+ return NULL;
+ }
+
+ struct pcep_object_endpoints_ipv4 *obj =
+ (struct pcep_object_endpoints_ipv4 *)pcep_obj_create_common(
+ sizeof(struct pcep_object_endpoints_ipv4),
+ PCEP_OBJ_CLASS_ENDPOINTS, PCEP_OBJ_TYPE_ENDPOINT_IPV4);
+
+ obj->src_ipv4.s_addr = src_ipv4->s_addr;
+ obj->dst_ipv4.s_addr = dst_ipv4->s_addr;
+
+ return obj;
+}
+
+struct pcep_object_endpoints_ipv6 *
+pcep_obj_create_endpoint_ipv6(const struct in6_addr *src_ipv6,
+ const struct in6_addr *dst_ipv6)
+{
+ if (src_ipv6 == NULL || dst_ipv6 == NULL) {
+ return NULL;
+ }
+
+ struct pcep_object_endpoints_ipv6 *obj =
+ (struct pcep_object_endpoints_ipv6 *)pcep_obj_create_common(
+ sizeof(struct pcep_object_endpoints_ipv6),
+ PCEP_OBJ_CLASS_ENDPOINTS, PCEP_OBJ_TYPE_ENDPOINT_IPV6);
+
+ memcpy(&obj->src_ipv6, src_ipv6, sizeof(struct in6_addr));
+ memcpy(&obj->dst_ipv6, dst_ipv6, sizeof(struct in6_addr));
+
+ return obj;
+}
+
+struct pcep_object_bandwidth *pcep_obj_create_bandwidth(float bandwidth)
+{
+ struct pcep_object_bandwidth *obj =
+ (struct pcep_object_bandwidth *)pcep_obj_create_common(
+ sizeof(struct pcep_object_bandwidth),
+ PCEP_OBJ_CLASS_BANDWIDTH, PCEP_OBJ_TYPE_BANDWIDTH_REQ);
+
+ obj->bandwidth = bandwidth;
+
+ return obj;
+}
+
+struct pcep_object_metric *pcep_obj_create_metric(enum pcep_metric_types type,
+ bool flag_b, bool flag_c,
+ float value)
+{
+ struct pcep_object_metric *obj =
+ (struct pcep_object_metric *)pcep_obj_create_common(
+ sizeof(struct pcep_object_metric),
+ PCEP_OBJ_CLASS_METRIC, PCEP_OBJ_TYPE_METRIC);
+
+ obj->flag_b = flag_b;
+ obj->flag_c = flag_c;
+ obj->type = type;
+ obj->value = value;
+
+ return obj;
+}
+
+struct pcep_object_lspa *
+pcep_obj_create_lspa(uint32_t exclude_any, uint32_t include_any,
+ uint32_t include_all, uint8_t setup_priority,
+ uint8_t holding_priority, bool flag_local_protection)
+{
+ struct pcep_object_lspa *obj =
+ (struct pcep_object_lspa *)pcep_obj_create_common(
+ sizeof(struct pcep_object_lspa), PCEP_OBJ_CLASS_LSPA,
+ PCEP_OBJ_TYPE_LSPA);
+
+ obj->lspa_exclude_any = exclude_any;
+ obj->lspa_include_any = include_any;
+ obj->lspa_include_all = include_all;
+ obj->setup_priority = setup_priority;
+ obj->holding_priority = holding_priority;
+ obj->flag_local_protection = flag_local_protection;
+
+ return obj;
+}
+
+struct pcep_object_svec *
+pcep_obj_create_svec(bool srlg, bool node, bool link,
+ double_linked_list *request_id_list)
+{
+ if (request_id_list == NULL) {
+ return NULL;
+ }
+
+ struct pcep_object_svec *obj =
+ (struct pcep_object_svec *)pcep_obj_create_common(
+ sizeof(struct pcep_object_svec), PCEP_OBJ_CLASS_SVEC,
+ PCEP_OBJ_TYPE_SVEC);
+
+ obj->flag_srlg_diverse = srlg;
+ obj->flag_node_diverse = node;
+ obj->flag_link_diverse = link;
+ obj->request_id_list = request_id_list;
+
+ return obj;
+}
+
+struct pcep_object_error *
+pcep_obj_create_error(enum pcep_error_type error_type,
+ enum pcep_error_value error_value)
+{
+ struct pcep_object_error *obj =
+ (struct pcep_object_error *)pcep_obj_create_common(
+ sizeof(struct pcep_object_error), PCEP_OBJ_CLASS_ERROR,
+ PCEP_OBJ_TYPE_ERROR);
+
+ obj->error_type = error_type;
+ obj->error_value = error_value;
+
+ return obj;
+}
+
+struct pcep_object_close *pcep_obj_create_close(enum pcep_close_reason reason)
+{
+ struct pcep_object_close *obj =
+ (struct pcep_object_close *)pcep_obj_create_common(
+ sizeof(struct pcep_object_close), PCEP_OBJ_CLASS_CLOSE,
+ PCEP_OBJ_TYPE_CLOSE);
+
+ obj->reason = reason;
+
+ return obj;
+}
+
+struct pcep_object_srp *pcep_obj_create_srp(bool lsp_remove,
+ uint32_t srp_id_number,
+ double_linked_list *tlv_list)
+{
+ struct pcep_object_srp *obj =
+ (struct pcep_object_srp *)pcep_obj_create_common_with_tlvs(
+ sizeof(struct pcep_object_srp), PCEP_OBJ_CLASS_SRP,
+ PCEP_OBJ_TYPE_SRP, tlv_list);
+
+ obj->flag_lsp_remove = lsp_remove;
+ obj->srp_id_number = srp_id_number;
+
+ return obj;
+}
+
+struct pcep_object_lsp *
+pcep_obj_create_lsp(uint32_t plsp_id, enum pcep_lsp_operational_status status,
+ bool c_flag, bool a_flag, bool r_flag, bool s_flag,
+ bool d_flag, double_linked_list *tlv_list)
+{
+ /* The plsp_id is only 20 bits */
+ if (plsp_id > MAX_PLSP_ID) {
+ pcep_log(
+ LOG_INFO,
+ "%s: pcep_obj_create_lsp invalid plsp_id [%d] max value [%d]",
+ __func__, plsp_id, MAX_PLSP_ID);
+ return NULL;
+ }
+
+ /* The status is only 3 bits */
+ if (status > MAX_LSP_STATUS) {
+ pcep_log(
+ LOG_INFO,
+ "%s: pcep_obj_create_lsp invalid status [%d] max value [%d]",
+ __func__, plsp_id, MAX_PLSP_ID);
+ return NULL;
+ }
+
+ struct pcep_object_lsp *obj =
+ (struct pcep_object_lsp *)pcep_obj_create_common_with_tlvs(
+ sizeof(struct pcep_object_lsp), PCEP_OBJ_CLASS_LSP,
+ PCEP_OBJ_TYPE_LSP, tlv_list);
+
+ obj->plsp_id = plsp_id;
+ obj->operational_status = status;
+ obj->flag_c = c_flag;
+ obj->flag_a = a_flag;
+ obj->flag_r = r_flag;
+ obj->flag_s = s_flag;
+ obj->flag_d = d_flag;
+
+ return obj;
+}
+
+struct pcep_object_vendor_info *
+pcep_obj_create_vendor_info(uint32_t enterprise_number,
+ uint32_t enterprise_spec_info)
+{
+ struct pcep_object_vendor_info *obj =
+ (struct pcep_object_vendor_info *)pcep_obj_create_common(
+ sizeof(struct pcep_object_vendor_info),
+ PCEP_OBJ_CLASS_VENDOR_INFO, PCEP_OBJ_TYPE_VENDOR_INFO);
+
+ obj->enterprise_number = enterprise_number;
+ obj->enterprise_specific_info = enterprise_spec_info;
+
+ return obj;
+}
+
+struct pcep_object_inter_layer *
+pcep_obj_create_inter_layer(bool flag_i, bool flag_m, bool flag_t)
+{
+ struct pcep_object_inter_layer *obj =
+ (struct pcep_object_inter_layer *)pcep_obj_create_common(
+ sizeof(struct pcep_object_inter_layer),
+ PCEP_OBJ_CLASS_INTER_LAYER, PCEP_OBJ_TYPE_INTER_LAYER);
+
+ obj->flag_i = flag_i;
+ obj->flag_m = flag_m;
+ obj->flag_t = flag_t;
+
+ return obj;
+}
+
+struct pcep_object_switch_layer *
+pcep_obj_create_switch_layer(double_linked_list *switch_layer_rows)
+{
+ struct pcep_object_switch_layer *obj =
+ (struct pcep_object_switch_layer *)pcep_obj_create_common(
+ sizeof(struct pcep_object_switch_layer),
+ PCEP_OBJ_CLASS_SWITCH_LAYER,
+ PCEP_OBJ_TYPE_SWITCH_LAYER);
+
+ obj->switch_layer_rows = switch_layer_rows;
+
+ return obj;
+}
+
+struct pcep_object_req_adap_cap *
+pcep_obj_create_req_adap_cap(enum pcep_switching_capability sw_cap,
+ enum pcep_lsp_encoding_type encoding)
+{
+ struct pcep_object_req_adap_cap *obj =
+ (struct pcep_object_req_adap_cap *)pcep_obj_create_common(
+ sizeof(struct pcep_object_req_adap_cap),
+ PCEP_OBJ_CLASS_REQ_ADAP_CAP,
+ PCEP_OBJ_TYPE_REQ_ADAP_CAP);
+
+ obj->switching_capability = sw_cap;
+ obj->encoding = encoding;
+
+ return obj;
+}
+
+struct pcep_object_server_indication *
+pcep_obj_create_server_indication(enum pcep_switching_capability sw_cap,
+ enum pcep_lsp_encoding_type encoding,
+ double_linked_list *tlv_list)
+{
+ struct pcep_object_server_indication *obj =
+ (struct pcep_object_server_indication *)
+ pcep_obj_create_common_with_tlvs(
+ sizeof(struct pcep_object_server_indication),
+ PCEP_OBJ_CLASS_SERVER_IND,
+ PCEP_OBJ_TYPE_SERVER_IND, tlv_list);
+
+ obj->switching_capability = sw_cap;
+ obj->encoding = encoding;
+
+ return obj;
+}
+
+struct pcep_object_objective_function *
+pcep_obj_create_objective_function(uint16_t of_code,
+ double_linked_list *tlv_list)
+{
+ struct pcep_object_objective_function *obj =
+ (struct pcep_object_objective_function *)
+ pcep_obj_create_common_with_tlvs(
+ sizeof(struct pcep_object_objective_function),
+ PCEP_OBJ_CLASS_OF, PCEP_OBJ_TYPE_OF, tlv_list);
+
+ obj->of_code = of_code;
+
+ return obj;
+}
+
+/* Wrap a list of ro subobjects in a structure with an object header */
+struct pcep_object_ro *pcep_obj_create_ero(double_linked_list *ero_list)
+{
+ struct pcep_object_ro *ero =
+ (struct pcep_object_ro *)pcep_obj_create_common(
+ sizeof(struct pcep_object_ro), PCEP_OBJ_CLASS_ERO,
+ PCEP_OBJ_TYPE_ERO);
+ ero->sub_objects = ero_list;
+
+ return ero;
+}
+
+/* Wrap a list of ro subobjects in a structure with an object header */
+struct pcep_object_ro *pcep_obj_create_iro(double_linked_list *iro_list)
+{
+ struct pcep_object_ro *iro =
+ (struct pcep_object_ro *)pcep_obj_create_common(
+ sizeof(struct pcep_object_ro), PCEP_OBJ_CLASS_IRO,
+ PCEP_OBJ_TYPE_IRO);
+ iro->sub_objects = iro_list;
+
+ return iro;
+}
+
+/* Wrap a list of ro subobjects in a structure with an object header */
+struct pcep_object_ro *pcep_obj_create_rro(double_linked_list *rro_list)
+{
+ struct pcep_object_ro *rro =
+ (struct pcep_object_ro *)pcep_obj_create_common(
+ sizeof(struct pcep_object_ro), PCEP_OBJ_CLASS_RRO,
+ PCEP_OBJ_TYPE_RRO);
+ rro->sub_objects = rro_list;
+
+ return rro;
+}
+
+/*
+ * Route Object Sub-object creation functions
+ */
+
+static struct pcep_object_ro_subobj *
+pcep_obj_create_ro_subobj_common(uint8_t subobj_size,
+ enum pcep_ro_subobj_types ro_subobj_type,
+ bool flag_subobj_loose_hop)
+{
+ struct pcep_object_ro_subobj *ro_subobj =
+ pceplib_malloc(PCEPLIB_MESSAGES, subobj_size);
+ memset(ro_subobj, 0, subobj_size);
+ ro_subobj->flag_subobj_loose_hop = flag_subobj_loose_hop;
+ ro_subobj->ro_subobj_type = ro_subobj_type;
+
+ return ro_subobj;
+}
+
+struct pcep_ro_subobj_ipv4 *
+pcep_obj_create_ro_subobj_ipv4(bool loose_hop, const struct in_addr *rro_ipv4,
+ uint8_t prefix_length, bool flag_local_prot)
+{
+ if (rro_ipv4 == NULL) {
+ return NULL;
+ }
+
+ struct pcep_ro_subobj_ipv4 *obj =
+ (struct pcep_ro_subobj_ipv4 *)pcep_obj_create_ro_subobj_common(
+ sizeof(struct pcep_ro_subobj_ipv4), RO_SUBOBJ_TYPE_IPV4,
+ loose_hop);
+ obj->ip_addr.s_addr = rro_ipv4->s_addr;
+ obj->prefix_length = prefix_length;
+ obj->flag_local_protection = flag_local_prot;
+
+ return obj;
+}
+
+struct pcep_ro_subobj_ipv6 *
+pcep_obj_create_ro_subobj_ipv6(bool loose_hop, const struct in6_addr *rro_ipv6,
+ uint8_t prefix_length, bool flag_local_prot)
+{
+ if (rro_ipv6 == NULL) {
+ return NULL;
+ }
+
+ struct pcep_ro_subobj_ipv6 *obj =
+ (struct pcep_ro_subobj_ipv6 *)pcep_obj_create_ro_subobj_common(
+ sizeof(struct pcep_ro_subobj_ipv6), RO_SUBOBJ_TYPE_IPV6,
+ loose_hop);
+ obj->prefix_length = prefix_length;
+ obj->flag_local_protection = flag_local_prot;
+ memcpy(&obj->ip_addr, rro_ipv6, sizeof(struct in6_addr));
+
+ return obj;
+}
+
+struct pcep_ro_subobj_unnum *
+pcep_obj_create_ro_subobj_unnum(struct in_addr *router_id, uint32_t if_id)
+{
+ if (router_id == NULL) {
+ return NULL;
+ }
+
+ struct pcep_ro_subobj_unnum *obj =
+ (struct pcep_ro_subobj_unnum *)pcep_obj_create_ro_subobj_common(
+ sizeof(struct pcep_ro_subobj_unnum),
+ RO_SUBOBJ_TYPE_UNNUM, false);
+ obj->interface_id = if_id;
+ obj->router_id.s_addr = router_id->s_addr;
+
+ return obj;
+}
+
+struct pcep_ro_subobj_32label *
+pcep_obj_create_ro_subobj_32label(bool flag_global_label, uint8_t class_type,
+ uint32_t label)
+{
+ struct pcep_ro_subobj_32label *obj = (struct pcep_ro_subobj_32label *)
+ pcep_obj_create_ro_subobj_common(
+ sizeof(struct pcep_ro_subobj_32label),
+ RO_SUBOBJ_TYPE_LABEL, false);
+ obj->class_type = class_type;
+ obj->flag_global_label = flag_global_label;
+ obj->label = label;
+
+ return obj;
+}
+
+struct pcep_ro_subobj_asn *pcep_obj_create_ro_subobj_asn(uint16_t asn)
+{
+ struct pcep_ro_subobj_asn *obj =
+ (struct pcep_ro_subobj_asn *)pcep_obj_create_ro_subobj_common(
+ sizeof(struct pcep_ro_subobj_asn), RO_SUBOBJ_TYPE_ASN,
+ false);
+ obj->asn = asn;
+
+ return obj;
+}
+
+/* Internal util function to create pcep_ro_subobj_sr sub-objects */
+static struct pcep_ro_subobj_sr *
+pcep_obj_create_ro_subobj_sr_common(enum pcep_sr_subobj_nai nai_type,
+ bool loose_hop, bool f_flag, bool s_flag,
+ bool c_flag_in, bool m_flag_in)
+{
+ struct pcep_ro_subobj_sr *obj =
+ (struct pcep_ro_subobj_sr *)pcep_obj_create_ro_subobj_common(
+ sizeof(struct pcep_ro_subobj_sr), RO_SUBOBJ_TYPE_SR,
+ loose_hop);
+
+ /* Flag logic according to draft-ietf-pce-segment-routing-16 */
+ bool c_flag = c_flag_in;
+ bool m_flag = m_flag_in;
+ if (s_flag) {
+ c_flag = false;
+ m_flag = false;
+ }
+
+ if (m_flag == false) {
+ c_flag = false;
+ }
+
+ obj->nai_type = nai_type;
+ obj->flag_f = f_flag;
+ obj->flag_s = s_flag;
+ obj->flag_c = c_flag;
+ obj->flag_m = m_flag;
+
+ return obj;
+}
+
+struct pcep_ro_subobj_sr *pcep_obj_create_ro_subobj_sr_nonai(bool loose_hop,
+ uint32_t sid,
+ bool c_flag,
+ bool m_flag)
+{
+ /* According to draft-ietf-pce-segment-routing-16#section-5.2.1
+ * If NT=0, the F bit MUST be 1, the S bit MUST be zero and the
+ * Length MUST be 8. */
+ struct pcep_ro_subobj_sr *obj = pcep_obj_create_ro_subobj_sr_common(
+ PCEP_SR_SUBOBJ_NAI_ABSENT, loose_hop, true, false, c_flag,
+ m_flag);
+ obj->sid = sid;
+
+ return obj;
+}
+
+struct pcep_ro_subobj_sr *
+pcep_obj_create_ro_subobj_sr_ipv4_node(bool loose_hop, bool sid_absent,
+ bool c_flag, bool m_flag, uint32_t sid,
+ struct in_addr *ipv4_node_id)
+{
+ if (ipv4_node_id == NULL) {
+ return NULL;
+ }
+
+ /* According to draft-ietf-pce-segment-routing-16#section-5.2.1
+ * If NT=1, the F bit MUST be zero. If the S bit is 1, the Length
+ * MUST be 8, otherwise the Length MUST be 12 */
+ struct pcep_ro_subobj_sr *obj = pcep_obj_create_ro_subobj_sr_common(
+ PCEP_SR_SUBOBJ_NAI_IPV4_NODE, loose_hop, false, sid_absent,
+ c_flag, m_flag);
+
+ if (!sid_absent) {
+ obj->sid = sid;
+ }
+ obj->nai_list = dll_initialize();
+ /* Since the IP has to be stored in the list, copy it so the caller
+ * doesnt have any restrictions about the type of memory used externally
+ * for the IP. This memory will be freed with the object is freed. */
+ struct in_addr *ipv4_node_id_copy =
+ pceplib_malloc(PCEPLIB_MESSAGES, sizeof(struct in_addr));
+ ipv4_node_id_copy->s_addr = ipv4_node_id->s_addr;
+ dll_append(obj->nai_list, ipv4_node_id_copy);
+
+ return obj;
+}
+
+struct pcep_ro_subobj_sr *
+pcep_obj_create_ro_subobj_sr_ipv6_node(bool loose_hop, bool sid_absent,
+ bool c_flag, bool m_flag, uint32_t sid,
+ struct in6_addr *ipv6_node_id)
+{
+ if (ipv6_node_id == NULL) {
+ return NULL;
+ }
+
+ /* According to draft-ietf-pce-segment-routing-16#section-5.2.1
+ * If NT=2, the F bit MUST be zero. If the S bit is 1, the Length
+ * MUST be 20, otherwise the Length MUST be 24. */
+ struct pcep_ro_subobj_sr *obj = pcep_obj_create_ro_subobj_sr_common(
+ PCEP_SR_SUBOBJ_NAI_IPV6_NODE, loose_hop, false, sid_absent,
+ c_flag, m_flag);
+
+ if (!sid_absent) {
+ obj->sid = sid;
+ }
+ obj->nai_list = dll_initialize();
+ struct in6_addr *ipv6_node_id_copy =
+ pceplib_malloc(PCEPLIB_MESSAGES, sizeof(struct in6_addr));
+ memcpy(ipv6_node_id_copy, ipv6_node_id, sizeof(struct in6_addr));
+ dll_append(obj->nai_list, ipv6_node_id_copy);
+
+ return obj;
+}
+
+struct pcep_ro_subobj_sr *pcep_obj_create_ro_subobj_sr_ipv4_adj(
+ bool loose_hop, bool sid_absent, bool c_flag, bool m_flag, uint32_t sid,
+ struct in_addr *local_ipv4, struct in_addr *remote_ipv4)
+{
+ if (local_ipv4 == NULL || remote_ipv4 == NULL) {
+ return NULL;
+ }
+
+ /* According to draft-ietf-pce-segment-routing-16#section-5.2.1
+ * If NT=3, the F bit MUST be zero. If the S bit is 1, the Length
+ * MUST be 12, otherwise the Length MUST be 16 */
+ struct pcep_ro_subobj_sr *obj = pcep_obj_create_ro_subobj_sr_common(
+ PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY, loose_hop, false, sid_absent,
+ c_flag, m_flag);
+
+ if (!sid_absent) {
+ obj->sid = sid;
+ }
+ obj->nai_list = dll_initialize();
+ struct in_addr *local_ipv4_copy =
+ pceplib_malloc(PCEPLIB_MESSAGES, sizeof(struct in_addr));
+ struct in_addr *remote_ipv4_copy =
+ pceplib_malloc(PCEPLIB_MESSAGES, sizeof(struct in_addr));
+ local_ipv4_copy->s_addr = local_ipv4->s_addr;
+ remote_ipv4_copy->s_addr = remote_ipv4->s_addr;
+ dll_append(obj->nai_list, local_ipv4_copy);
+ dll_append(obj->nai_list, remote_ipv4_copy);
+
+ return obj;
+}
+
+struct pcep_ro_subobj_sr *pcep_obj_create_ro_subobj_sr_ipv6_adj(
+ bool loose_hop, bool sid_absent, bool c_flag, bool m_flag, uint32_t sid,
+ struct in6_addr *local_ipv6, struct in6_addr *remote_ipv6)
+{
+ if (local_ipv6 == NULL || remote_ipv6 == NULL) {
+ return NULL;
+ }
+
+ /* According to draft-ietf-pce-segment-routing-16#section-5.2.1
+ * If NT=4, the F bit MUST be zero. If the S bit is 1, the Length
+ * MUST be 36, otherwise the Length MUST be 40 */
+ struct pcep_ro_subobj_sr *obj = pcep_obj_create_ro_subobj_sr_common(
+ PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY, loose_hop, false, sid_absent,
+ c_flag, m_flag);
+
+ if (!sid_absent) {
+ obj->sid = sid;
+ }
+ obj->nai_list = dll_initialize();
+ struct in6_addr *local_ipv6_copy =
+ pceplib_malloc(PCEPLIB_MESSAGES, sizeof(struct in6_addr));
+ struct in6_addr *remote_ipv6_copy =
+ pceplib_malloc(PCEPLIB_MESSAGES, sizeof(struct in6_addr));
+ memcpy(local_ipv6_copy, local_ipv6, sizeof(struct in6_addr));
+ memcpy(remote_ipv6_copy, remote_ipv6, sizeof(struct in6_addr));
+ dll_append(obj->nai_list, local_ipv6_copy);
+ dll_append(obj->nai_list, remote_ipv6_copy);
+
+ return obj;
+}
+
+struct pcep_ro_subobj_sr *pcep_obj_create_ro_subobj_sr_unnumbered_ipv4_adj(
+ bool loose_hop, bool sid_absent, bool c_flag, bool m_flag, uint32_t sid,
+ uint32_t local_node_id, uint32_t local_if_id, uint32_t remote_node_id,
+ uint32_t remote_if_id)
+{
+ /* According to draft-ietf-pce-segment-routing-16#section-5.2.1
+ * If NT=5, the F bit MUST be zero. If the S bit is 1, the Length
+ * MUST be 20, otherwise the Length MUST be 24. */
+ struct pcep_ro_subobj_sr *obj = pcep_obj_create_ro_subobj_sr_common(
+ PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY, loose_hop, false,
+ sid_absent, c_flag, m_flag);
+
+ if (!sid_absent) {
+ obj->sid = sid;
+ }
+
+ obj->nai_list = dll_initialize();
+ uint32_t *local_node_id_copy =
+ pceplib_malloc(PCEPLIB_MESSAGES, sizeof(uint32_t));
+ *local_node_id_copy = local_node_id;
+ dll_append(obj->nai_list, local_node_id_copy);
+
+ uint32_t *local_if_id_copy =
+ pceplib_malloc(PCEPLIB_MESSAGES, sizeof(uint32_t));
+ *local_if_id_copy = local_if_id;
+ dll_append(obj->nai_list, local_if_id_copy);
+
+ uint32_t *remote_node_id_copy =
+ pceplib_malloc(PCEPLIB_MESSAGES, sizeof(uint32_t));
+ *remote_node_id_copy = remote_node_id;
+ dll_append(obj->nai_list, remote_node_id_copy);
+
+ uint32_t *remote_if_id_copy =
+ pceplib_malloc(PCEPLIB_MESSAGES, sizeof(uint32_t));
+ *remote_if_id_copy = remote_if_id;
+ dll_append(obj->nai_list, remote_if_id_copy);
+
+ return obj;
+}
+
+struct pcep_ro_subobj_sr *pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj(
+ bool loose_hop, bool sid_absent, bool c_flag, bool m_flag, uint32_t sid,
+ struct in6_addr *local_ipv6, uint32_t local_if_id,
+ struct in6_addr *remote_ipv6, uint32_t remote_if_id)
+{
+ if (local_ipv6 == NULL || remote_ipv6 == NULL) {
+ return NULL;
+ }
+
+ /* According to draft-ietf-pce-segment-routing-16#section-5.2.1
+ * If NT=6, the F bit MUST be zero. If the S bit is 1, the Length
+ * MUST be 44, otherwise the Length MUST be 48 */
+ struct pcep_ro_subobj_sr *obj = pcep_obj_create_ro_subobj_sr_common(
+ PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY, loose_hop, false,
+ sid_absent, c_flag, m_flag);
+
+ if (!sid_absent) {
+ obj->sid = sid;
+ }
+ obj->nai_list = dll_initialize();
+ struct in6_addr *local_ipv6_copy =
+ pceplib_malloc(PCEPLIB_MESSAGES, sizeof(struct in6_addr));
+ memcpy(local_ipv6_copy, local_ipv6, sizeof(struct in6_addr));
+ dll_append(obj->nai_list, local_ipv6_copy);
+
+ uint32_t *local_if_id_copy =
+ pceplib_malloc(PCEPLIB_MESSAGES, sizeof(uint32_t));
+ *local_if_id_copy = local_if_id;
+ dll_append(obj->nai_list, local_if_id_copy);
+
+ struct in6_addr *remote_ipv6_copy =
+ pceplib_malloc(PCEPLIB_MESSAGES, sizeof(struct in6_addr));
+ memcpy(remote_ipv6_copy, remote_ipv6, sizeof(struct in6_addr));
+ dll_append(obj->nai_list, remote_ipv6_copy);
+
+ uint32_t *remote_if_id_copy =
+ pceplib_malloc(PCEPLIB_MESSAGES, sizeof(uint32_t));
+ *remote_if_id_copy = remote_if_id;
+ dll_append(obj->nai_list, remote_if_id_copy);
+
+ return obj;
+}
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ */
+
+
+/*
+ * This is a High Level PCEP message object API.
+ */
+
+#ifndef PCEP_OBJECTS_H
+#define PCEP_OBJECTS_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "pcep.h"
+#include "pcep_utils_double_linked_list.h"
+#include "pcep_msg_object_error_types.h"
+#include "pcep_msg_tlvs.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Regarding memory usage:
+ * When creating objects, any objects passed into these APIs will be free'd when
+ * the enclosing pcep_message is free'd. That includes the double_linked_list's.
+ * So, just create the objects and TLVs, put them in their double_linked_list's,
+ * and everything will be managed internally. The enclosing message will be
+ * deleted by pcep_msg_free_message() or pcep_msg_free_message_list() which,
+ * in turn will call one of: pcep_obj_free_object() and pcep_obj_free_tlv().
+ * For received messages with objects, call pcep_msg_free_message() to free
+ * them.
+ */
+
+enum pcep_object_classes {
+ PCEP_OBJ_CLASS_OPEN = 1,
+ PCEP_OBJ_CLASS_RP = 2,
+ PCEP_OBJ_CLASS_NOPATH = 3,
+ PCEP_OBJ_CLASS_ENDPOINTS = 4,
+ PCEP_OBJ_CLASS_BANDWIDTH = 5,
+ PCEP_OBJ_CLASS_METRIC = 6,
+ PCEP_OBJ_CLASS_ERO = 7,
+ PCEP_OBJ_CLASS_RRO = 8,
+ PCEP_OBJ_CLASS_LSPA = 9,
+ PCEP_OBJ_CLASS_IRO = 10,
+ PCEP_OBJ_CLASS_SVEC = 11,
+ PCEP_OBJ_CLASS_NOTF = 12,
+ PCEP_OBJ_CLASS_ERROR = 13,
+ PCEP_OBJ_CLASS_CLOSE = 15,
+ PCEP_OBJ_CLASS_OF = 21,
+ PCEP_OBJ_CLASS_LSP = 32,
+ PCEP_OBJ_CLASS_SRP = 33,
+ PCEP_OBJ_CLASS_VENDOR_INFO = 34,
+ PCEP_OBJ_CLASS_INTER_LAYER = 36, /* RFC 8282 */
+ PCEP_OBJ_CLASS_SWITCH_LAYER = 37, /* RFC 8282 */
+ PCEP_OBJ_CLASS_REQ_ADAP_CAP = 38, /* RFC 8282 */
+ PCEP_OBJ_CLASS_SERVER_IND = 39, /* RFC 8282 */
+ PCEP_OBJ_CLASS_ASSOCIATION = 40, /*draft-ietf-pce-association-group-10*/
+ PCEP_OBJ_CLASS_MAX,
+};
+
+enum pcep_object_types {
+ PCEP_OBJ_TYPE_OPEN = 1,
+ PCEP_OBJ_TYPE_RP = 1,
+ PCEP_OBJ_TYPE_NOPATH = 1,
+ PCEP_OBJ_TYPE_ENDPOINT_IPV4 = 1,
+ PCEP_OBJ_TYPE_ENDPOINT_IPV6 = 2,
+ PCEP_OBJ_TYPE_BANDWIDTH_REQ = 1,
+ PCEP_OBJ_TYPE_BANDWIDTH_TELSP = 2,
+ PCEP_OBJ_TYPE_BANDWIDTH_CISCO =
+ 5, /* IANA unassigned, but rcvd from Cisco PCE */
+ PCEP_OBJ_TYPE_SRP = 1,
+ PCEP_OBJ_TYPE_VENDOR_INFO = 1,
+ PCEP_OBJ_TYPE_LSP = 1,
+ PCEP_OBJ_TYPE_METRIC = 1,
+ PCEP_OBJ_TYPE_ERO = 1,
+ PCEP_OBJ_TYPE_RRO = 1,
+ PCEP_OBJ_TYPE_LSPA = 1,
+ PCEP_OBJ_TYPE_IRO = 1,
+ PCEP_OBJ_TYPE_SVEC = 1,
+ PCEP_OBJ_TYPE_NOTF = 1,
+ PCEP_OBJ_TYPE_ERROR = 1,
+ PCEP_OBJ_TYPE_CLOSE = 1,
+ PCEP_OBJ_TYPE_INTER_LAYER = 1,
+ PCEP_OBJ_TYPE_SWITCH_LAYER = 1,
+ PCEP_OBJ_TYPE_REQ_ADAP_CAP = 1,
+ PCEP_OBJ_TYPE_SERVER_IND = 1,
+ PCEP_OBJ_TYPE_ASSOCIATION_IPV4 =
+ 1, /*draft-ietf-pce-association-group-10*/
+ PCEP_OBJ_TYPE_ASSOCIATION_IPV6 =
+ 2, /*draft-ietf-pce-association-group-10*/
+ PCEP_OBJ_TYPE_OF = 1,
+ PCEP_OBJ_TYPE_MAX = 2,
+};
+
+#define OBJECT_HEADER_FLAG_I 0x01
+#define OBJECT_HEADER_FLAG_P 0x02
+
+/* The flag_p and flag_i arent set via the APIs, if they need to be set, just
+ * set them on the returned object once it has been created. */
+struct pcep_object_header {
+ enum pcep_object_classes object_class;
+ enum pcep_object_types object_type;
+ bool flag_p; /* PCC Processing rule bit: When set, the object MUST be
+ taken into account, when cleared the object is optional.
+ */
+ bool flag_i; /* PCE Ignore bit: indicates to a PCC whether or not an
+ optional object was processed */
+ double_linked_list *tlv_list;
+ /* Pointer into encoded_message field from the pcep_message */
+ const uint8_t *encoded_object;
+ uint16_t encoded_object_length;
+};
+
+#define PCEP_OBJECT_OPEN_VERSION 1
+
+struct pcep_object_open {
+ struct pcep_object_header header;
+ uint8_t open_version; /* PCEP version. Current version is 1 */
+ uint8_t open_keepalive; /* Maximum period of time between two
+ consecutive PCEP messages sent by the sender.
+ */
+ uint8_t open_deadtimer; /* Specifies the amount of time before closing
+ the session down. */
+ uint8_t open_sid; /* PCEP session number that identifies the current
+ session. */
+};
+
+#define OBJECT_RP_FLAG_R 0x08
+#define OBJECT_RP_FLAG_B 0x10
+#define OBJECT_RP_FLAG_O 0x20
+#define OBJECT_RP_FLAG_OF 0x80
+#define OBJECT_RP_MAX_PRIORITY 0x07
+
+struct pcep_object_rp {
+ struct pcep_object_header header;
+ uint8_t priority; /* 3 bit priority, max priority is 7 */
+ bool flag_reoptimization;
+ bool flag_bidirectional;
+ bool flag_strict; /* when set, a loose path is acceptable */
+ bool flag_of; /* Supply Objective Function on Response */
+ uint32_t request_id; /* The Request-id-number value combined with the
+ source for PCC & PCE creates a uniquely number.
+ */
+};
+
+enum pcep_notification_types {
+ PCEP_NOTIFY_TYPE_PENDING_REQUEST_CANCELLED = 1,
+ PCEP_NOTIFY_TYPE_PCE_OVERLOADED = 2
+};
+
+enum pcep_notification_values {
+ PCEP_NOTIFY_VALUE_PCC_CANCELLED_REQUEST = 1,
+ PCEP_NOTIFY_VALUE_PCE_CANCELLED_REQUEST = 2,
+ PCEP_NOTIFY_VALUE_PCE_CURRENTLY_OVERLOADED = 1,
+ PCEP_NOTIFY_VALUE_PCE_NO_LONGER_OVERLOADED = 2
+};
+
+struct pcep_object_notify {
+ struct pcep_object_header header;
+ enum pcep_notification_types notification_type;
+ enum pcep_notification_values notification_value;
+};
+
+enum pcep_association_type {
+ PCEP_ASSOCIATION_TYPE_PATH_PROTECTION_ASSOCIATION =
+ 1, // iana unique value define as 2020-01-08!
+ PCEP_ASSOCIATION_TYPE_SR_POLICY_ASSOCIATION_TYPE =
+ 65535 // TBD1 draft-barth-pce-segment-routing-policy-cp-04
+};
+#define OBJECT_ASSOCIATION_FLAG_R 0x01
+struct pcep_object_association_ipv4 { // draft-ietf-pce-association-group-10
+ struct pcep_object_header header;
+ bool R_flag;
+ uint16_t association_type;
+ uint16_t association_id;
+ struct in_addr src;
+};
+
+struct pcep_object_association_ipv6 { // draft-ietf-pce-association-group-10
+ struct pcep_object_header header;
+ bool R_flag;
+ uint16_t association_type;
+ uint16_t association_id;
+ struct in6_addr src;
+};
+
+
+enum pcep_nopath_nature_of_issue {
+ PCEP_NOPATH_NI_NO_PATH_FOUND = 0,
+ PCEP_NOPATH_NI_PCE_CHAIN_BROKEN = 1,
+};
+
+enum pcep_nopath_tlv_err_codes {
+ PCEP_NOPATH_TLV_ERR_NO_TLV = 0,
+ PCEP_NOPATH_TLV_ERR_PCE_UNAVAILABLE = 1,
+ PCEP_NOPATH_TLV_ERR_UNKNOWN_DST = 2,
+ PCEP_NOPATH_TLV_ERR_UNKNOWN_SRC = 3
+};
+
+#define OBJECT_NOPATH_FLAG_C 0x80
+
+struct pcep_object_nopath {
+ struct pcep_object_header header;
+ uint8_t ni; /* Nature of Issue, reports the nature of the issue that led
+ to a negative reply */
+ bool flag_c; /* when set, indicates the unsatisfied constraints by
+ including relevant PCEP objects. */
+ enum pcep_nopath_tlv_err_codes
+ err_code; /* When set other than 0, an appropriate TLV will be
+ included */
+};
+
+struct pcep_object_endpoints_ipv4 {
+ struct pcep_object_header header;
+ struct in_addr src_ipv4;
+ struct in_addr dst_ipv4;
+};
+
+struct pcep_object_endpoints_ipv6 {
+ struct pcep_object_header header;
+ struct in6_addr src_ipv6;
+ struct in6_addr dst_ipv6;
+};
+
+/* PCEP floats are encoded according to:
+ * https://en.wikipedia.org/wiki/IEEE_754-1985
+ * Luckily, this is the same encoding used by C */
+struct pcep_object_bandwidth {
+ struct pcep_object_header header;
+ float bandwidth;
+};
+
+enum pcep_metric_types {
+ /* RFC 5440 */
+ PCEP_METRIC_IGP = 1,
+ PCEP_METRIC_TE = 2,
+ PCEP_METRIC_HOP_COUNT = 3,
+ /* RFC 5541 */
+ PCEP_METRIC_AGGREGATE_BW = 4,
+ PCEP_METRIC_MOST_LOADED_LINK = 5,
+ PCEP_METRIC_CUMULATIVE_IGP = 6,
+ PCEP_METRIC_CUMULATIVE_TE = 7,
+ /* RFC 8306 */
+ PCEP_METRIC_P2MP_IGP = 8,
+ PCEP_METRIC_P2MP_TE = 9,
+ PCEP_METRIC_P2MP_HOP_COUNT = 10,
+ /* RFC 8864 */
+ PCEP_METRIC_SEGMENT_ID_DEPTH = 11,
+ /* RFC 8233 */
+ PCEP_METRIC_PATH_DELAY = 12,
+ PCEP_METRIC_PATH_DELAY_VARIATION = 13,
+ PCEP_METRIC_PATH_LOSS = 14,
+ PCEP_METRIC_P2MP_PATH_DELAY = 15,
+ PCEP_METRIC_P2MP_PATH_DELAY_VARIATION = 16,
+ PCEP_METRIC_P2MP_PATH_LOSS = 17,
+ /* RFC 8282 */
+ PCEP_METRIC_NUM_PATH_ADAPTATIONS = 18,
+ PCEP_METRIC_NUM_PATH_LAYERS = 19,
+ /* RFC 8685 */
+ PCEP_METRIC_DOMAIN_COUNT = 20,
+ PCEP_METRIC_BORDER_NODE_COUNT = 21,
+};
+
+#define OBJECT_METRIC_FLAC_B 0x01
+#define OBJECT_METRIC_FLAC_C 0x02
+
+/* PCEP floats are encoded according to:
+ * https://en.wikipedia.org/wiki/IEEE_754-1985
+ * Luckily, this is the same encoding used by C */
+struct pcep_object_metric {
+ struct pcep_object_header header;
+ enum pcep_metric_types type;
+ bool flag_b; /* Bound flag */
+ bool flag_c; /* Computed metric */
+ float value; /* Metric value in 32 bits */
+};
+
+#define OBJECT_LSPA_FLAG_L 0x01
+
+struct pcep_object_lspa {
+ struct pcep_object_header header;
+ uint32_t lspa_exclude_any;
+ uint32_t lspa_include_any;
+ uint32_t lspa_include_all;
+ uint8_t setup_priority;
+ uint8_t holding_priority;
+ bool flag_local_protection; /* Local protection desired bit */
+};
+
+/* The SVEC object with some custom extensions. */
+#define OBJECT_SVEC_FLAG_L 0x01
+#define OBJECT_SVEC_FLAG_N 0x02
+#define OBJECT_SVEC_FLAG_S 0x04
+
+struct pcep_object_svec {
+ struct pcep_object_header header;
+ bool flag_link_diverse;
+ bool flag_node_diverse;
+ bool flag_srlg_diverse;
+ double_linked_list
+ *request_id_list; /* list of 32-bit request ID pointers */
+};
+
+struct pcep_object_error {
+ struct pcep_object_header header;
+ enum pcep_error_type error_type;
+ enum pcep_error_value error_value;
+};
+
+struct pcep_object_load_balancing {
+ struct pcep_object_header header;
+ uint8_t load_maxlsp; /* Maximum number of TE LSPs in the set */
+ uint32_t load_minband; /* Specifies the minimum bandwidth of each
+ element */
+};
+
+enum pcep_close_reason {
+ PCEP_CLOSE_REASON_NO = 1,
+ PCEP_CLOSE_REASON_DEADTIMER = 2,
+ PCEP_CLOSE_REASON_FORMAT = 3,
+ PCEP_CLOSE_REASON_UNKNOWN_REQ = 4,
+ PCEP_CLOSE_REASON_UNREC_MSG = 5
+};
+
+struct pcep_object_close {
+ struct pcep_object_header header;
+ enum pcep_close_reason reason;
+};
+
+/* Stateful PCE Request Parameters RFC 8231, 8281 */
+
+#define OBJECT_SRP_FLAG_R 0x01
+
+struct pcep_object_srp {
+ struct pcep_object_header header;
+ bool flag_lsp_remove; /* RFC 8281 */
+ uint32_t srp_id_number;
+};
+
+/* Label Switched Path Object RFC 8231 */
+enum pcep_lsp_operational_status {
+ PCEP_LSP_OPERATIONAL_DOWN = 0,
+ PCEP_LSP_OPERATIONAL_UP = 1,
+ PCEP_LSP_OPERATIONAL_ACTIVE = 2,
+ PCEP_LSP_OPERATIONAL_GOING_DOWN = 3,
+ PCEP_LSP_OPERATIONAL_GOING_UP = 4,
+};
+
+#define MAX_PLSP_ID 0x000fffff /* The plsp_id is only 20 bits */
+#define MAX_LSP_STATUS 0x0007 /* The status is only 3 bits */
+#define OBJECT_LSP_FLAG_D 0x01
+#define OBJECT_LSP_FLAG_S 0x02
+#define OBJECT_LSP_FLAG_R 0x04
+#define OBJECT_LSP_FLAG_A 0x08
+#define OBJECT_LSP_FLAG_C 0x80
+
+struct pcep_object_lsp {
+ struct pcep_object_header header;
+ uint32_t plsp_id; /* plsp_id is 20 bits, must be <= MAX_PLSP_ID*/
+ enum pcep_lsp_operational_status operational_status; /* max 3 bits */
+ bool flag_d;
+ bool flag_s;
+ bool flag_r;
+ bool flag_a;
+ bool flag_c;
+};
+
+/* RFC 7470 */
+struct pcep_object_vendor_info {
+ struct pcep_object_header header;
+ uint32_t enterprise_number;
+ uint32_t enterprise_specific_info;
+};
+
+/* RFC 8282 */
+#define OBJECT_INTER_LAYER_FLAG_I 0x01
+#define OBJECT_INTER_LAYER_FLAG_M 0x02
+#define OBJECT_INTER_LAYER_FLAG_T 0x04
+
+struct pcep_object_inter_layer {
+ struct pcep_object_header header;
+ bool flag_i;
+ bool flag_m;
+ bool flag_t;
+};
+
+/* RFC 8282 */
+#define OBJECT_SWITCH_LAYER_FLAG_I 0x01
+enum pcep_lsp_encoding_type {
+ /* Values taken from RFC 3471 as suggested by RFC 8282 */
+ PCEP_LSP_ENC_PACKET = 1,
+ PCEP_LSP_ENC_ETHERNET = 2,
+ PCEP_LSP_ENC_PDH = 3,
+ PCEP_LSP_ENC_RESERVED4 = 4,
+ PCEP_LSP_ENC_SDH_SONET = 5,
+ PCEP_LSP_ENC_RESERVED6 = 6,
+ PCEP_LSP_ENC_DIG_WRAPPER = 7,
+ PCEP_LSP_ENC_LAMBDA = 8,
+ PCEP_LSP_ENC_FIBER = 9,
+ PCEP_LSP_ENC_RESERVED10 = 10,
+ PCEP_LSP_ENC_FIBER_CHAN = 11
+};
+
+enum pcep_switching_capability {
+ /* Switching capability values taken from RFC 4203/3471 as suggested by
+ RFC 8282 */
+ PCEP_SW_CAP_PSC1 = 1, /* Packet-Switch Capable-1 (PSC-1) */
+ PCEP_SW_CAP_PSC2 = 2,
+ PCEP_SW_CAP_PSC3 = 3,
+ PCEP_SW_CAP_PSC4 = 4,
+ PCEP_SW_CAP_L2SC = 51, /* Layer-2 Switch Capable */
+ PCEP_SW_CAP_TDM = 100, /* Time-Division-Multiplex Capable */
+ PCEP_SW_CAP_LSC = 150, /* Lambda-Switch Capable */
+ PCEP_SW_CAP_FSC = 200 /* Fiber-Switch Capable */
+};
+
+struct pcep_object_switch_layer_row {
+ enum pcep_lsp_encoding_type lsp_encoding_type;
+ enum pcep_switching_capability switching_type;
+ bool flag_i;
+};
+
+struct pcep_object_switch_layer {
+ struct pcep_object_header header;
+ double_linked_list
+ *switch_layer_rows; /* list of struct
+ pcep_object_switch_layer_row */
+};
+
+/* RFC 8282
+ * Requested Adaptation capability */
+
+struct pcep_object_req_adap_cap {
+ struct pcep_object_header header;
+ enum pcep_switching_capability switching_capability;
+ enum pcep_lsp_encoding_type encoding;
+};
+
+/* RFC 8282 */
+
+struct pcep_object_server_indication {
+ struct pcep_object_header header;
+ enum pcep_switching_capability switching_capability;
+ enum pcep_lsp_encoding_type encoding;
+ /* This object is identical to req_adap_cap, except it allows TLVs */
+};
+
+/* Objective Function Object: RFC 5541 */
+
+struct pcep_object_objective_function {
+ struct pcep_object_header header;
+ uint16_t of_code;
+};
+
+/*
+ * Common Route Object sub-object definitions
+ * used by ERO, IRO, and RRO
+ */
+
+/* Common Route Object sub-object types
+ * used by ERO, IRO, and RRO */
+enum pcep_ro_subobj_types {
+ RO_SUBOBJ_TYPE_IPV4 = 1, /* RFC 3209 */
+ RO_SUBOBJ_TYPE_IPV6 = 2, /* RFC 3209 */
+ RO_SUBOBJ_TYPE_LABEL = 3, /* RFC 3209 */
+ RO_SUBOBJ_TYPE_UNNUM = 4, /* RFC 3477 */
+ RO_SUBOBJ_TYPE_ASN = 32, /* RFC 3209, Section 4.3.3.4 */
+ RO_SUBOBJ_TYPE_SR = 36, /* RFC 8408, draft-ietf-pce-segment-routing-16.
+ Type 5 for draft07 has been assigned to
+ something else. */
+ RO_SUBOBJ_UNKNOWN
+};
+
+struct pcep_object_ro {
+ struct pcep_object_header header;
+ double_linked_list
+ *sub_objects; /* list of struct pcep_object_ro_subobj */
+};
+
+struct pcep_object_ro_subobj {
+ bool flag_subobj_loose_hop; /* L subobj flag */
+ enum pcep_ro_subobj_types ro_subobj_type;
+};
+
+#define OBJECT_SUBOBJ_IP_FLAG_LOCAL_PROT 0x01
+
+struct pcep_ro_subobj_ipv4 {
+ struct pcep_object_ro_subobj ro_subobj;
+ struct in_addr ip_addr;
+ uint8_t prefix_length;
+ bool flag_local_protection;
+};
+
+struct pcep_ro_subobj_ipv6 {
+ struct pcep_object_ro_subobj ro_subobj;
+ struct in6_addr ip_addr;
+ uint8_t prefix_length;
+ bool flag_local_protection;
+};
+
+struct pcep_ro_subobj_unnum {
+ struct pcep_object_ro_subobj ro_subobj;
+ struct in_addr router_id;
+ uint32_t interface_id;
+};
+
+#define OBJECT_SUBOBJ_LABEL_FLAG_GLOGAL 0x01
+struct pcep_ro_subobj_32label {
+ struct pcep_object_ro_subobj ro_subobj;
+ bool flag_global_label;
+ uint8_t class_type; /* label class-type (generalized label = 2) */
+ uint32_t label; /* label supported */
+};
+
+struct pcep_ro_subobj_asn {
+ struct pcep_object_ro_subobj ro_subobj;
+ uint16_t asn; /* Autonomous system number */
+};
+
+/* The SR ERO and SR RRO subojbects are the same, except
+ * the SR-RRO does not have the L flag in the Type field.
+ * Defined in draft-ietf-pce-segment-routing-16 */
+enum pcep_sr_subobj_nai {
+ PCEP_SR_SUBOBJ_NAI_ABSENT = 0,
+ PCEP_SR_SUBOBJ_NAI_IPV4_NODE = 1,
+ PCEP_SR_SUBOBJ_NAI_IPV6_NODE = 2,
+ PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY = 3,
+ PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY = 4,
+ PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY = 5,
+ PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY = 6,
+ PCEP_SR_SUBOBJ_NAI_UNKNOWN
+};
+
+#define OBJECT_SUBOBJ_SR_FLAG_M 0x01
+#define OBJECT_SUBOBJ_SR_FLAG_C 0x02
+#define OBJECT_SUBOBJ_SR_FLAG_S 0x04
+#define OBJECT_SUBOBJ_SR_FLAG_F 0x08
+
+struct pcep_ro_subobj_sr {
+ struct pcep_object_ro_subobj ro_subobj;
+ enum pcep_sr_subobj_nai nai_type;
+ bool flag_f;
+ bool flag_s;
+ bool flag_c;
+ bool flag_m;
+
+ /* The SID and NAI are optional depending on the flags,
+ * and the NAI can be variable length */
+ uint32_t sid;
+ double_linked_list
+ *nai_list; /* double linked list of in_addr or in6_addr */
+};
+
+/* Macros to make a SID Label
+ *
+ * 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Label
+ | Label | TC |S| TTL | Stack
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Entry
+ */
+#define ENCODE_SR_ERO_SID(label_20bits, tc_3bits, stack_bottom_bit, ttl_8bits) \
+ ((((label_20bits) << 12) & 0xfffff000) \
+ | (((tc_3bits) << 9) & 0x00000e00) \
+ | (((stack_bottom_bit) << 8) & 0x00000100) | ((ttl_8bits)&0xff))
+#define GET_SR_ERO_SID_LABEL(SID) ((SID & 0xfffff000) >> 12)
+#define GET_SR_ERO_SID_TC(SID) ((SID & 0x00000e00) >> 9)
+#define GET_SR_ERO_SID_S(SID) ((SID & 0x00000100) >> 8)
+#define GET_SR_ERO_SID_TTL(SID) ((SID & 0x000000ff))
+
+/*
+ * All created objects will be in Host byte order, except for IPs.
+ * All IP addresses are expected to be passed-in in Network byte order,
+ * and any objects received will have their IPs in Network byte order.
+ * The message containing the objects should be converted to Network byte order
+ * with pcep_encode_msg_header() before sending, which will also convert the
+ * Objects, TLVs, and sub-objects.
+ */
+
+struct pcep_object_open *pcep_obj_create_open(uint8_t keepalive,
+ uint8_t deadtimer, uint8_t sid,
+ double_linked_list *tlv_list);
+struct pcep_object_rp *pcep_obj_create_rp(uint8_t priority, bool flag_r,
+ bool flag_b, bool flag_s,
+ bool flag_of, uint32_t reqid,
+ double_linked_list *tlv_list);
+struct pcep_object_notify *
+pcep_obj_create_notify(enum pcep_notification_types notification_type,
+ enum pcep_notification_values notification_value);
+struct pcep_object_nopath *
+pcep_obj_create_nopath(uint8_t ni, bool flag_c,
+ enum pcep_nopath_tlv_err_codes error_code);
+struct pcep_object_association_ipv4 *
+pcep_obj_create_association_ipv4(bool r_flag, uint16_t association_type,
+ uint16_t association_id, struct in_addr src);
+struct pcep_object_association_ipv6 *
+pcep_obj_create_association_ipv6(bool r_flag, uint16_t association_type,
+ uint16_t association_id, struct in6_addr src);
+struct pcep_object_endpoints_ipv4 *
+pcep_obj_create_endpoint_ipv4(const struct in_addr *src_ipv4,
+ const struct in_addr *dst_ipv4);
+struct pcep_object_endpoints_ipv6 *
+pcep_obj_create_endpoint_ipv6(const struct in6_addr *src_ipv6,
+ const struct in6_addr *dst_ipv6);
+struct pcep_object_bandwidth *pcep_obj_create_bandwidth(float bandwidth);
+struct pcep_object_metric *pcep_obj_create_metric(enum pcep_metric_types type,
+ bool flag_b, bool flag_c,
+ float value);
+struct pcep_object_lspa *
+pcep_obj_create_lspa(uint32_t exclude_any, uint32_t include_any,
+ uint32_t include_all, uint8_t setup_priority,
+ uint8_t holding_priority, bool flag_local_protection);
+struct pcep_object_svec *
+pcep_obj_create_svec(bool srlg, bool node, bool link,
+ double_linked_list *request_id_list);
+struct pcep_object_error *
+pcep_obj_create_error(enum pcep_error_type error_type,
+ enum pcep_error_value error_value);
+struct pcep_object_close *pcep_obj_create_close(enum pcep_close_reason reason);
+struct pcep_object_srp *pcep_obj_create_srp(bool lsp_remove,
+ uint32_t srp_id_number,
+ double_linked_list *tlv_list);
+struct pcep_object_lsp *
+pcep_obj_create_lsp(uint32_t plsp_id, enum pcep_lsp_operational_status status,
+ bool c_flag, bool a_flag, bool r_flag, bool s_flag,
+ bool d_flag, double_linked_list *tlv_list);
+struct pcep_object_vendor_info *
+pcep_obj_create_vendor_info(uint32_t enterprise_number,
+ uint32_t enterprise_spec_info);
+struct pcep_object_inter_layer *
+pcep_obj_create_inter_layer(bool flag_i, bool flag_m, bool flag_t);
+struct pcep_object_switch_layer *
+pcep_obj_create_switch_layer(double_linked_list *switch_layer_rows);
+struct pcep_object_req_adap_cap *
+pcep_obj_create_req_adap_cap(enum pcep_switching_capability sw_cap,
+ enum pcep_lsp_encoding_type encoding);
+struct pcep_object_server_indication *
+pcep_obj_create_server_indication(enum pcep_switching_capability sw_cap,
+ enum pcep_lsp_encoding_type encoding,
+ double_linked_list *tlv_list);
+struct pcep_object_objective_function *
+pcep_obj_create_objective_function(uint16_t of_code,
+ double_linked_list *tlv_list);
+
+/* Route Object (Explicit ero, Reported rro, and Include iro) functions
+ * First, the sub-objects should be created and appended to a
+ * double_linked_list, then call one of these Route Object creation functions
+ * with the subobj list */
+struct pcep_object_ro *pcep_obj_create_ero(double_linked_list *ero_list);
+struct pcep_object_ro *pcep_obj_create_rro(double_linked_list *rro_list);
+struct pcep_object_ro *pcep_obj_create_iro(double_linked_list *iro_list);
+/* Route Object sub-object creation functions */
+struct pcep_ro_subobj_ipv4 *
+pcep_obj_create_ro_subobj_ipv4(bool loose_hop, const struct in_addr *ro_ipv4,
+ uint8_t prefix_len, bool flag_local_prot);
+struct pcep_ro_subobj_ipv6 *
+pcep_obj_create_ro_subobj_ipv6(bool loose_hop, const struct in6_addr *ro_ipv6,
+ uint8_t prefix_len, bool flag_local_prot);
+struct pcep_ro_subobj_unnum *
+pcep_obj_create_ro_subobj_unnum(struct in_addr *router_id, uint32_t if_id);
+struct pcep_ro_subobj_32label *
+pcep_obj_create_ro_subobj_32label(bool flag_global_label, uint8_t class_type,
+ uint32_t label);
+struct pcep_ro_subobj_asn *pcep_obj_create_ro_subobj_asn(uint16_t asn);
+
+/* SR ERO and SR RRO creation functions for different NAI (Node/Adj ID) types.
+ * - The loose_hop is only used for sr ero and must always be false for sr rro.
+ * - The NAI value will be set internally, depending on which function is used.
+ * m_flag:
+ * - If this flag is true, the SID value represents an MPLS label stack
+ * entry as specified in [RFC3032]. Otherwise, the SID value is an
+ * administratively configured value which represents an index into
+ * an MPLS label space (either SRGB or SRLB) per [RFC8402].
+ * c_flag:
+ * - If the M flag and the C flag are both true, then the TC, S, and TTL
+ * fields in the MPLS label stack entry are specified by the PCE. However,
+ * a PCC MAY choose to override these values according to its local policy
+ * and MPLS forwarding rules.
+ * - If the M flag is true but the C flag is false, then the TC, S, and TTL
+ * fields MUST be ignored by the PCC.
+ * - The PCC MUST set these fields according to its local policy and MPLS
+ * forwarding rules.
+ * - If the M flag is false then the C bit MUST be false. */
+struct pcep_ro_subobj_sr *pcep_obj_create_ro_subobj_sr_nonai(bool loose_hop,
+ uint32_t sid,
+ bool c_flag,
+ bool m_flag);
+
+/* The ipv4_node_id will be copied internally */
+struct pcep_ro_subobj_sr *
+pcep_obj_create_ro_subobj_sr_ipv4_node(bool loose_hop, bool sid_absent,
+ bool c_flag, bool m_flag, uint32_t sid,
+ struct in_addr *ipv4_node_id);
+/* The ipv6_node_id will be copied internally */
+struct pcep_ro_subobj_sr *
+pcep_obj_create_ro_subobj_sr_ipv6_node(bool loose_hop, bool sid_absent,
+ bool c_flag, bool m_flag, uint32_t sid,
+ struct in6_addr *ipv6_node_id);
+/* The local_ipv4 and remote_ipv4 will be copied internally */
+struct pcep_ro_subobj_sr *pcep_obj_create_ro_subobj_sr_ipv4_adj(
+ bool loose_hop, bool sid_absent, bool c_flag, bool m_flag, uint32_t sid,
+ struct in_addr *local_ipv4, struct in_addr *remote_ipv4);
+/* The local_ipv6 and remote_ipv6 will be copied internally */
+struct pcep_ro_subobj_sr *pcep_obj_create_ro_subobj_sr_ipv6_adj(
+ bool loose_hop, bool sid_absent, bool c_flag, bool m_flag, uint32_t sid,
+ struct in6_addr *local_ipv6, struct in6_addr *remote_ipv6);
+struct pcep_ro_subobj_sr *pcep_obj_create_ro_subobj_sr_unnumbered_ipv4_adj(
+ bool loose_hop, bool sid_absent, bool c_flag, bool m_flag, uint32_t sid,
+ uint32_t local_node_id, uint32_t local_if_id, uint32_t remote_node_id,
+ uint32_t remote_if_id);
+/* The local_ipv6 and remote_ipv6 will be copied internally */
+struct pcep_ro_subobj_sr *pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj(
+ bool loose_hop, bool sid_absent, bool c_flag, bool m_flag, uint32_t sid,
+ struct in6_addr *local_ipv6, uint32_t local_if_id,
+ struct in6_addr *remote_ipv6, uint32_t remote_if_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+/*
+ * Encoding and decoding for PCEP Objects.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "pcep_msg_objects.h"
+#include "pcep_msg_encoding.h"
+#include "pcep_utils_logging.h"
+#include "pcep_utils_memory.h"
+
+void write_object_header(struct pcep_object_header *object_hdr,
+ uint16_t object_length, uint8_t *buf);
+void pcep_decode_object_hdr(const uint8_t *obj_buf,
+ struct pcep_object_header *obj_hdr);
+void set_ro_subobj_fields(struct pcep_object_ro_subobj *subobj, bool flag_l,
+ uint8_t subobj_type);
+
+/*
+ * forward declarations for initialize_object_encoders()
+ */
+uint16_t pcep_encode_obj_open(struct pcep_object_header *obj,
+ struct pcep_versioning *versioning, uint8_t *buf);
+uint16_t pcep_encode_obj_rp(struct pcep_object_header *obj,
+ struct pcep_versioning *versioning, uint8_t *buf);
+uint16_t pcep_encode_obj_nopath(struct pcep_object_header *obj,
+ struct pcep_versioning *versioning,
+ uint8_t *buf);
+uint16_t pcep_encode_obj_endpoints(struct pcep_object_header *obj,
+ struct pcep_versioning *versioning,
+ uint8_t *buf);
+uint16_t pcep_encode_obj_association(struct pcep_object_header *obj,
+ struct pcep_versioning *versioning,
+ uint8_t *buf);
+uint16_t pcep_encode_obj_bandwidth(struct pcep_object_header *obj,
+ struct pcep_versioning *versioning,
+ uint8_t *buf);
+uint16_t pcep_encode_obj_metric(struct pcep_object_header *obj,
+ struct pcep_versioning *versioning,
+ uint8_t *buf);
+uint16_t pcep_encode_obj_ro(struct pcep_object_header *obj,
+ struct pcep_versioning *versioning, uint8_t *buf);
+uint16_t pcep_encode_obj_lspa(struct pcep_object_header *obj,
+ struct pcep_versioning *versioning, uint8_t *buf);
+uint16_t pcep_encode_obj_svec(struct pcep_object_header *obj,
+ struct pcep_versioning *versioning, uint8_t *buf);
+uint16_t pcep_encode_obj_notify(struct pcep_object_header *obj,
+ struct pcep_versioning *versioning,
+ uint8_t *buf);
+uint16_t pcep_encode_obj_error(struct pcep_object_header *error,
+ struct pcep_versioning *versioning,
+ uint8_t *buf);
+uint16_t pcep_encode_obj_close(struct pcep_object_header *close,
+ struct pcep_versioning *versioning,
+ uint8_t *buf);
+uint16_t pcep_encode_obj_srp(struct pcep_object_header *obj,
+ struct pcep_versioning *versioning, uint8_t *buf);
+uint16_t pcep_encode_obj_lsp(struct pcep_object_header *obj,
+ struct pcep_versioning *versioning, uint8_t *buf);
+uint16_t pcep_encode_obj_vendor_info(struct pcep_object_header *obj,
+ struct pcep_versioning *versioning,
+ uint8_t *buf);
+uint16_t pcep_encode_obj_inter_layer(struct pcep_object_header *obj,
+ struct pcep_versioning *versioning,
+ uint8_t *buf);
+uint16_t pcep_encode_obj_switch_layer(struct pcep_object_header *obj,
+ struct pcep_versioning *versioning,
+ uint8_t *buf);
+uint16_t pcep_encode_obj_req_adap_cap(struct pcep_object_header *obj,
+ struct pcep_versioning *versioning,
+ uint8_t *buf);
+uint16_t pcep_encode_obj_server_ind(struct pcep_object_header *obj,
+ struct pcep_versioning *versioning,
+ uint8_t *buf);
+uint16_t pcep_encode_obj_objective_function(struct pcep_object_header *obj,
+ struct pcep_versioning *versioning,
+ uint8_t *buf);
+typedef uint16_t (*object_encoder_funcptr)(struct pcep_object_header *,
+ struct pcep_versioning *versioning,
+ uint8_t *buf);
+
+#define MAX_OBJECT_ENCODER_INDEX 64
+
+#define PCEP_ENCODERS_ARGS \
+ struct pcep_object_header *, struct pcep_versioning *versioning, \
+ uint8_t *buf
+uint16_t (*const object_encoders[MAX_OBJECT_ENCODER_INDEX])(
+ PCEP_ENCODERS_ARGS) = {
+ [PCEP_OBJ_CLASS_OPEN] = pcep_encode_obj_open,
+ [PCEP_OBJ_CLASS_RP] = pcep_encode_obj_rp,
+ [PCEP_OBJ_CLASS_NOPATH] = pcep_encode_obj_nopath,
+ [PCEP_OBJ_CLASS_ENDPOINTS] = pcep_encode_obj_endpoints,
+ [PCEP_OBJ_CLASS_BANDWIDTH] = pcep_encode_obj_bandwidth,
+ [PCEP_OBJ_CLASS_METRIC] = pcep_encode_obj_metric,
+ [PCEP_OBJ_CLASS_ERO] = pcep_encode_obj_ro,
+ [PCEP_OBJ_CLASS_RRO] = pcep_encode_obj_ro,
+ [PCEP_OBJ_CLASS_LSPA] = pcep_encode_obj_lspa,
+ [PCEP_OBJ_CLASS_IRO] = pcep_encode_obj_ro,
+ [PCEP_OBJ_CLASS_SVEC] = pcep_encode_obj_svec,
+ [PCEP_OBJ_CLASS_NOTF] = pcep_encode_obj_notify,
+ [PCEP_OBJ_CLASS_ERROR] = pcep_encode_obj_error,
+ [PCEP_OBJ_CLASS_CLOSE] = pcep_encode_obj_close,
+ [PCEP_OBJ_CLASS_LSP] = pcep_encode_obj_lsp,
+ [PCEP_OBJ_CLASS_SRP] = pcep_encode_obj_srp,
+ [PCEP_OBJ_CLASS_ASSOCIATION] = pcep_encode_obj_association,
+ [PCEP_OBJ_CLASS_INTER_LAYER] = pcep_encode_obj_inter_layer,
+ [PCEP_OBJ_CLASS_SWITCH_LAYER] = pcep_encode_obj_switch_layer,
+ [PCEP_OBJ_CLASS_REQ_ADAP_CAP] = pcep_encode_obj_req_adap_cap,
+ [PCEP_OBJ_CLASS_SERVER_IND] = pcep_encode_obj_server_ind,
+ [PCEP_OBJ_CLASS_VENDOR_INFO] = pcep_encode_obj_vendor_info,
+ [PCEP_OBJ_CLASS_OF] = pcep_encode_obj_objective_function,
+};
+/*
+ * forward declarations for initialize_object_decoders()
+ */
+struct pcep_object_header *pcep_decode_obj_open(struct pcep_object_header *hdr,
+ const uint8_t *buf);
+struct pcep_object_header *pcep_decode_obj_rp(struct pcep_object_header *hdr,
+ const uint8_t *buf);
+struct pcep_object_header *
+pcep_decode_obj_nopath(struct pcep_object_header *hdr, const uint8_t *buf);
+struct pcep_object_header *
+pcep_decode_obj_endpoints(struct pcep_object_header *hdr, const uint8_t *buf);
+struct pcep_object_header *
+pcep_decode_obj_association(struct pcep_object_header *hdr, const uint8_t *buf);
+struct pcep_object_header *
+pcep_decode_obj_bandwidth(struct pcep_object_header *hdr, const uint8_t *buf);
+struct pcep_object_header *
+pcep_decode_obj_metric(struct pcep_object_header *hdr, const uint8_t *buf);
+struct pcep_object_header *pcep_decode_obj_ro(struct pcep_object_header *hdr,
+ const uint8_t *buf);
+struct pcep_object_header *pcep_decode_obj_lspa(struct pcep_object_header *hdr,
+ const uint8_t *buf);
+struct pcep_object_header *pcep_decode_obj_svec(struct pcep_object_header *hdr,
+ const uint8_t *buf);
+struct pcep_object_header *
+pcep_decode_obj_notify(struct pcep_object_header *hdr, const uint8_t *buf);
+struct pcep_object_header *pcep_decode_obj_error(struct pcep_object_header *hdr,
+ const uint8_t *buf);
+struct pcep_object_header *pcep_decode_obj_close(struct pcep_object_header *hdr,
+ const uint8_t *buf);
+struct pcep_object_header *pcep_decode_obj_srp(struct pcep_object_header *hdr,
+ const uint8_t *buf);
+struct pcep_object_header *pcep_decode_obj_lsp(struct pcep_object_header *hdr,
+ const uint8_t *buf);
+struct pcep_object_header *
+pcep_decode_obj_vendor_info(struct pcep_object_header *hdr, const uint8_t *buf);
+struct pcep_object_header *
+pcep_decode_obj_inter_layer(struct pcep_object_header *hdr, const uint8_t *buf);
+struct pcep_object_header *
+pcep_decode_obj_switch_layer(struct pcep_object_header *hdr,
+ const uint8_t *buf);
+struct pcep_object_header *
+pcep_decode_obj_req_adap_cap(struct pcep_object_header *hdr,
+ const uint8_t *buf);
+struct pcep_object_header *
+pcep_decode_obj_server_ind(struct pcep_object_header *hdr, const uint8_t *buf);
+struct pcep_object_header *
+pcep_decode_obj_objective_function(struct pcep_object_header *hdr,
+ const uint8_t *buf);
+typedef struct pcep_object_header *(*object_decoder_funcptr)(
+ struct pcep_object_header *, const uint8_t *buf);
+
+#define PCEP_DECODERS_ARGS struct pcep_object_header *, const uint8_t *buf
+
+struct pcep_object_header *(*const object_decoders[MAX_OBJECT_ENCODER_INDEX])(
+ PCEP_DECODERS_ARGS) = {
+ [PCEP_OBJ_CLASS_OPEN] = pcep_decode_obj_open,
+ [PCEP_OBJ_CLASS_RP] = pcep_decode_obj_rp,
+ [PCEP_OBJ_CLASS_NOPATH] = pcep_decode_obj_nopath,
+ [PCEP_OBJ_CLASS_ENDPOINTS] = pcep_decode_obj_endpoints,
+ [PCEP_OBJ_CLASS_BANDWIDTH] = pcep_decode_obj_bandwidth,
+ [PCEP_OBJ_CLASS_METRIC] = pcep_decode_obj_metric,
+ [PCEP_OBJ_CLASS_ERO] = pcep_decode_obj_ro,
+ [PCEP_OBJ_CLASS_RRO] = pcep_decode_obj_ro,
+ [PCEP_OBJ_CLASS_LSPA] = pcep_decode_obj_lspa,
+ [PCEP_OBJ_CLASS_IRO] = pcep_decode_obj_ro,
+ [PCEP_OBJ_CLASS_SVEC] = pcep_decode_obj_svec,
+ [PCEP_OBJ_CLASS_NOTF] = pcep_decode_obj_notify,
+ [PCEP_OBJ_CLASS_ERROR] = pcep_decode_obj_error,
+ [PCEP_OBJ_CLASS_CLOSE] = pcep_decode_obj_close,
+ [PCEP_OBJ_CLASS_LSP] = pcep_decode_obj_lsp,
+ [PCEP_OBJ_CLASS_SRP] = pcep_decode_obj_srp,
+ [PCEP_OBJ_CLASS_ASSOCIATION] = pcep_decode_obj_association,
+ [PCEP_OBJ_CLASS_INTER_LAYER] = pcep_decode_obj_inter_layer,
+ [PCEP_OBJ_CLASS_SWITCH_LAYER] = pcep_decode_obj_switch_layer,
+ [PCEP_OBJ_CLASS_REQ_ADAP_CAP] = pcep_decode_obj_req_adap_cap,
+ [PCEP_OBJ_CLASS_SERVER_IND] = pcep_decode_obj_server_ind,
+ [PCEP_OBJ_CLASS_VENDOR_INFO] = pcep_decode_obj_vendor_info,
+ [PCEP_OBJ_CLASS_OF] = pcep_decode_obj_objective_function,
+};
+
+/* Object lengths, including the Object Header.
+ * Used by pcep_object_get_length() and pcep_object_has_tlvs() */
+static uint8_t pcep_object_class_lengths[] = {
+ 0, /* Object class 0 unused */
+ 8, /* PCEP_OBJ_CLASS_OPEN = 1 */
+ 12, /* PCEP_OBJ_CLASS_RP = 2 */
+ 16, /* PCEP_OBJ_CLASS_NOPATH = 3, includes 8 for mandatory TLV */
+ 0, /* PCEP_OBJ_CLASS_ENDPOINTS = 4, could be ipv4 or ipv6, setting to 0
+ */
+ 8, /* PCEP_OBJ_CLASS_BANDWIDTH = 5 */
+ 12, /* PCEP_OBJ_CLASS_METRIC = 6 */
+ 0, /* PCEP_OBJ_CLASS_ERO = 7, setting 0, ROs cannot have TLVs */
+ 0, /* PCEP_OBJ_CLASS_RRO = 8, setting 0, ROs cannot have TLVs */
+ 20, /* PCEP_OBJ_CLASS_LSPA = 9 */
+ 0, /* PCEP_OBJ_CLASS_IRO = 10, setting 0, ROs cannot have TLVs */
+ 0, /* PCEP_OBJ_CLASS_SVEC = 11, SVECs cannot have TLVs */
+ 8, /* PCEP_OBJ_CLASS_NOTF = 12 */
+ 8, /* PCEP_OBJ_CLASS_ERROR = 13 */
+ 0, /* Object class 14 unused */
+ 8, /* PCEP_OBJ_CLASS_CLOSE = 15 */
+ 0, 0, 0, 0, 0, /* Object classes 16 - 20 are not used */
+ 8, /* PCEP_OBJ_CLASS_OF = 21 */
+ 0, 0, 0, 0, 0, /* Object classes 22 - 26 are not used */
+ 0, 0, 0, 0, 0, /* Object classes 27 - 31 are not used */
+ 8, /* PCEP_OBJ_CLASS_LSP = 32 */
+ 12, /* PCEP_OBJ_CLASS_SRP = 33 */
+ 12, /* PCEP_OBJ_CLASS_VENDOR_INFO = 34 */
+ 0, /* Object class 35 unused */
+ 0, /* PCEP_OBJ_CLASS_INTER_LAYER = 36, cannot have TLVs */
+ 0, /* PCEP_OBJ_CLASS_SWITCH_LAYER = 37, cannot have TLVs */
+ 0, /* PCEP_OBJ_CLASS_REQ_ADAP_CAP = 38, cannot have TLVs*/
+ 8, /* PCEP_OBJ_CLASS_SERVER_IND = 39 */
+ 0, /* PCEP_OBJ_CLASS_ASSOCIATION = 40, cannot have TLVs */
+};
+
+/*
+ * The TLVs can have strange length values, since they do not include padding in
+ * the TLV header length, but that extra padding must be taken into account by
+ * the enclosing object by rounding up to the next 4 byte boundary.
+ * Example returned lengths:
+ * normalize_length(4) = 4, normalize_length(5) = 8, normalize_length(6)
+ * = 8, normalize_length(7) = 8, normalize_length(8) = 8
+ * normalize_length(9) = 12, normalize_length(10) = 12, normalize_length(11) =
+ * 12, normalize_length(12) = 12, normalize_length(13) = 13...
+ */
+uint16_t normalize_pcep_tlv_length(uint16_t length)
+{
+ return (length % 4 == 0) ? length : (length + (4 - (length % 4)));
+}
+
+/*
+ * Encoding functions
+ */
+uint16_t pcep_encode_object(struct pcep_object_header *object_hdr,
+ struct pcep_versioning *versioning, uint8_t *buf)
+{
+
+ if (object_hdr->object_class >= MAX_OBJECT_ENCODER_INDEX) {
+ pcep_log(LOG_INFO,
+ "%s: Cannot encode unknown Object class [%d]",
+ __func__, object_hdr->object_class);
+ return 0;
+ }
+
+ object_encoder_funcptr obj_encoder =
+ object_encoders[object_hdr->object_class];
+ if (obj_encoder == NULL) {
+ pcep_log(LOG_INFO,
+ "%s: No object encoder found for Object class [%d]",
+ __func__, object_hdr->object_class);
+ return 0;
+ }
+
+ uint16_t object_length = OBJECT_HEADER_LENGTH
+ + obj_encoder(object_hdr, versioning,
+ buf + OBJECT_HEADER_LENGTH);
+ double_linked_list_node *node =
+ (object_hdr->tlv_list == NULL ? NULL
+ : object_hdr->tlv_list->head);
+ for (; node != NULL; node = node->next_node) {
+ /* Returns the length of the TLV, including the TLV header */
+ object_length += pcep_encode_tlv(
+ (struct pcep_object_tlv_header *)node->data, versioning,
+ buf + object_length);
+ }
+ object_length = normalize_pcep_tlv_length(object_length);
+ write_object_header(object_hdr, object_length, buf);
+ object_hdr->encoded_object = buf;
+ object_hdr->encoded_object_length = object_length;
+
+ return object_length;
+}
+
+
+/* Object Header
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Object-Class | OT |Res|P|I| Object Length (bytes) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * // (Object body) //
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ */
+
+void write_object_header(struct pcep_object_header *object_hdr,
+ uint16_t object_length, uint8_t *buf)
+{
+ buf[0] = object_hdr->object_class;
+ buf[1] = ((object_hdr->object_type << 4)
+ | (object_hdr->flag_p ? OBJECT_HEADER_FLAG_P : 0x00)
+ | (object_hdr->flag_i ? OBJECT_HEADER_FLAG_I : 0x00));
+ uint16_t net_order_length = htons(object_length);
+ memcpy(buf + 2, &net_order_length, sizeof(net_order_length));
+}
+
+
+/*
+ * Functions to encode objects
+ * - they will be passed a pointer to a buffer to write the object body,
+ * which is past the object header.
+ * - they should return the object body length, not including the object header
+ * length.
+ */
+
+uint16_t pcep_encode_obj_open(struct pcep_object_header *hdr,
+ struct pcep_versioning *versioning,
+ uint8_t *obj_body_buf)
+{
+ (void)versioning;
+ struct pcep_object_open *open = (struct pcep_object_open *)hdr;
+ obj_body_buf[0] = (open->open_version << 5) & 0xe0;
+ obj_body_buf[1] = open->open_keepalive;
+ obj_body_buf[2] = open->open_deadtimer;
+ obj_body_buf[3] = open->open_sid;
+
+ return LENGTH_1WORD;
+}
+
+uint16_t pcep_encode_obj_rp(struct pcep_object_header *hdr,
+ struct pcep_versioning *versioning,
+ uint8_t *obj_body_buf)
+{
+ (void)versioning;
+ struct pcep_object_rp *rp = (struct pcep_object_rp *)hdr;
+ obj_body_buf[3] = ((rp->flag_strict ? OBJECT_RP_FLAG_O : 0x00)
+ | (rp->flag_bidirectional ? OBJECT_RP_FLAG_B : 0x00)
+ | (rp->flag_reoptimization ? OBJECT_RP_FLAG_R : 0x00)
+ | (rp->flag_of ? OBJECT_RP_FLAG_OF : 0x00)
+ | (rp->priority & 0x07));
+ uint32_t *uint32_ptr = (uint32_t *)(obj_body_buf + 4);
+ *uint32_ptr = htonl(rp->request_id);
+
+ return LENGTH_2WORDS;
+}
+
+uint16_t pcep_encode_obj_notify(struct pcep_object_header *hdr,
+ struct pcep_versioning *versioning,
+ uint8_t *obj_body_buf)
+{
+ (void)versioning;
+ struct pcep_object_notify *notify = (struct pcep_object_notify *)hdr;
+ obj_body_buf[2] = notify->notification_type;
+ obj_body_buf[3] = notify->notification_value;
+
+ return LENGTH_1WORD;
+}
+
+uint16_t pcep_encode_obj_nopath(struct pcep_object_header *hdr,
+ struct pcep_versioning *versioning,
+ uint8_t *obj_body_buf)
+{
+ (void)versioning;
+ struct pcep_object_nopath *nopath = (struct pcep_object_nopath *)hdr;
+ obj_body_buf[0] = nopath->ni;
+ obj_body_buf[1] = ((nopath->flag_c) ? OBJECT_NOPATH_FLAG_C : 0x00);
+
+ return LENGTH_1WORD;
+}
+
+uint16_t pcep_encode_obj_association(struct pcep_object_header *hdr,
+ struct pcep_versioning *versioning,
+ uint8_t *obj_body_buf)
+{
+ (void)versioning;
+ uint16_t *uint16_ptr = (uint16_t *)obj_body_buf;
+ uint32_t *uint32_ptr = (uint32_t *)obj_body_buf;
+ if (hdr->object_type == PCEP_OBJ_TYPE_ASSOCIATION_IPV4) {
+ struct pcep_object_association_ipv4 *ipv4 =
+ (struct pcep_object_association_ipv4 *)hdr;
+ obj_body_buf[3] =
+ (ipv4->R_flag ? OBJECT_ASSOCIATION_FLAG_R : 0x00);
+ uint16_ptr[2] = htons(ipv4->association_type);
+ uint16_ptr[3] = htons(ipv4->association_id);
+ uint32_ptr[2] = ipv4->src.s_addr;
+
+ return LENGTH_3WORDS;
+ } else {
+ struct pcep_object_association_ipv6 *ipv6 =
+ (struct pcep_object_association_ipv6 *)hdr;
+ obj_body_buf[3] =
+ (ipv6->R_flag ? OBJECT_ASSOCIATION_FLAG_R : 0x00);
+ uint16_ptr[2] = htons(ipv6->association_type);
+ uint16_ptr[3] = htons(ipv6->association_id);
+ memcpy(uint32_ptr, &ipv6->src, sizeof(struct in6_addr));
+
+ return LENGTH_6WORDS;
+ }
+}
+
+uint16_t pcep_encode_obj_endpoints(struct pcep_object_header *hdr,
+ struct pcep_versioning *versioning,
+ uint8_t *obj_body_buf)
+{
+ (void)versioning;
+ uint32_t *uint32_ptr = (uint32_t *)obj_body_buf;
+ if (hdr->object_type == PCEP_OBJ_TYPE_ENDPOINT_IPV4) {
+ struct pcep_object_endpoints_ipv4 *ipv4 =
+ (struct pcep_object_endpoints_ipv4 *)hdr;
+ uint32_ptr[0] = ipv4->src_ipv4.s_addr;
+ uint32_ptr[1] = ipv4->dst_ipv4.s_addr;
+
+ return LENGTH_2WORDS;
+ } else {
+ struct pcep_object_endpoints_ipv6 *ipv6 =
+ (struct pcep_object_endpoints_ipv6 *)hdr;
+ memcpy(uint32_ptr, &ipv6->src_ipv6, sizeof(struct in6_addr));
+ memcpy(&uint32_ptr[4], &ipv6->dst_ipv6,
+ sizeof(struct in6_addr));
+
+ return LENGTH_8WORDS;
+ }
+}
+
+uint16_t pcep_encode_obj_bandwidth(struct pcep_object_header *hdr,
+ struct pcep_versioning *versioning,
+ uint8_t *obj_body_buf)
+{
+ (void)versioning;
+ struct pcep_object_bandwidth *bandwidth =
+ (struct pcep_object_bandwidth *)hdr;
+ uint32_t *uint32_ptr = (uint32_t *)obj_body_buf;
+ /* Seems like the compiler doesnt correctly copy the float, so memcpy()
+ * it */
+ memcpy(uint32_ptr, &(bandwidth->bandwidth), sizeof(uint32_t));
+ *uint32_ptr = htonl(*uint32_ptr);
+
+ return LENGTH_1WORD;
+}
+
+uint16_t pcep_encode_obj_metric(struct pcep_object_header *hdr,
+ struct pcep_versioning *versioning,
+ uint8_t *obj_body_buf)
+{
+ (void)versioning;
+ struct pcep_object_metric *metric = (struct pcep_object_metric *)hdr;
+ obj_body_buf[2] = ((metric->flag_c ? OBJECT_METRIC_FLAC_C : 0x00)
+ | (metric->flag_b ? OBJECT_METRIC_FLAC_B : 0x00));
+ obj_body_buf[3] = metric->type;
+ uint32_t *uint32_ptr = (uint32_t *)(obj_body_buf + 4);
+ /* Seems like the compiler doesnt correctly copy the float, so memcpy()
+ * it */
+ memcpy(uint32_ptr, &(metric->value), sizeof(uint32_t));
+ *uint32_ptr = htonl(*uint32_ptr);
+
+ return LENGTH_2WORDS;
+}
+
+uint16_t pcep_encode_obj_lspa(struct pcep_object_header *hdr,
+ struct pcep_versioning *versioning,
+ uint8_t *obj_body_buf)
+{
+ (void)versioning;
+ struct pcep_object_lspa *lspa = (struct pcep_object_lspa *)hdr;
+ uint32_t *uint32_ptr = (uint32_t *)obj_body_buf;
+ uint32_ptr[0] = htonl(lspa->lspa_exclude_any);
+ uint32_ptr[1] = htonl(lspa->lspa_include_any);
+ uint32_ptr[2] = htonl(lspa->lspa_include_all);
+ obj_body_buf[12] = lspa->setup_priority;
+ obj_body_buf[13] = lspa->holding_priority;
+ obj_body_buf[14] =
+ (lspa->flag_local_protection ? OBJECT_LSPA_FLAG_L : 0x00);
+
+ return LENGTH_4WORDS;
+}
+
+uint16_t pcep_encode_obj_svec(struct pcep_object_header *hdr,
+ struct pcep_versioning *versioning,
+ uint8_t *obj_body_buf)
+{
+ (void)versioning;
+ struct pcep_object_svec *svec = (struct pcep_object_svec *)hdr;
+ obj_body_buf[3] =
+ ((svec->flag_srlg_diverse ? OBJECT_SVEC_FLAG_S : 0x00)
+ | (svec->flag_node_diverse ? OBJECT_SVEC_FLAG_N : 0x00)
+ | (svec->flag_link_diverse ? OBJECT_SVEC_FLAG_L : 0x00));
+
+ if (svec->request_id_list == NULL) {
+ return LENGTH_1WORD;
+ }
+
+ int index = 1;
+ uint32_t *uint32_ptr = (uint32_t *)obj_body_buf;
+ double_linked_list_node *node = svec->request_id_list->head;
+ for (; node != NULL; node = node->next_node) {
+ uint32_ptr[index++] = htonl(*((uint32_t *)(node->data)));
+ }
+
+ return LENGTH_1WORD
+ + (svec->request_id_list->num_entries * sizeof(uint32_t));
+}
+
+uint16_t pcep_encode_obj_error(struct pcep_object_header *hdr,
+ struct pcep_versioning *versioning,
+ uint8_t *obj_body_buf)
+{
+ (void)versioning;
+ struct pcep_object_error *error = (struct pcep_object_error *)hdr;
+ obj_body_buf[2] = error->error_type;
+ obj_body_buf[3] = error->error_value;
+
+ return LENGTH_1WORD;
+}
+
+uint16_t pcep_encode_obj_close(struct pcep_object_header *hdr,
+ struct pcep_versioning *versioning,
+ uint8_t *obj_body_buf)
+{
+ (void)versioning;
+ struct pcep_object_close *close = (struct pcep_object_close *)hdr;
+ obj_body_buf[3] = close->reason;
+
+ return LENGTH_1WORD;
+}
+
+uint16_t pcep_encode_obj_srp(struct pcep_object_header *hdr,
+ struct pcep_versioning *versioning,
+ uint8_t *obj_body_buf)
+{
+ (void)versioning;
+ struct pcep_object_srp *srp = (struct pcep_object_srp *)hdr;
+ obj_body_buf[3] = (srp->flag_lsp_remove ? OBJECT_SRP_FLAG_R : 0x00);
+ uint32_t *uint32_ptr = (uint32_t *)(obj_body_buf + 4);
+ *uint32_ptr = htonl(srp->srp_id_number);
+
+ return LENGTH_2WORDS;
+}
+
+uint16_t pcep_encode_obj_lsp(struct pcep_object_header *hdr,
+ struct pcep_versioning *versioning,
+ uint8_t *obj_body_buf)
+{
+ (void)versioning;
+ struct pcep_object_lsp *lsp = (struct pcep_object_lsp *)hdr;
+ uint32_t *uint32_ptr = (uint32_t *)obj_body_buf;
+ uint32_ptr[0] = htonl((lsp->plsp_id << 12) & 0xfffff000);
+ obj_body_buf[3] = ((lsp->flag_c ? OBJECT_LSP_FLAG_C : 0x00)
+ | ((lsp->operational_status << 4) & 0x70)
+ | (lsp->flag_a ? OBJECT_LSP_FLAG_A : 0x00)
+ | (lsp->flag_r ? OBJECT_LSP_FLAG_R : 0x00)
+ | (lsp->flag_s ? OBJECT_LSP_FLAG_S : 0x00)
+ | (lsp->flag_d ? OBJECT_LSP_FLAG_D : 0x00));
+
+ return LENGTH_1WORD;
+}
+
+uint16_t pcep_encode_obj_vendor_info(struct pcep_object_header *hdr,
+ struct pcep_versioning *versioning,
+ uint8_t *obj_body_buf)
+{
+ (void)versioning;
+ struct pcep_object_vendor_info *obj =
+ (struct pcep_object_vendor_info *)hdr;
+ uint32_t *uint32_ptr = (uint32_t *)obj_body_buf;
+ uint32_ptr[0] = htonl(obj->enterprise_number);
+ uint32_ptr[1] = htonl(obj->enterprise_specific_info);
+
+ return LENGTH_2WORDS;
+}
+
+uint16_t pcep_encode_obj_inter_layer(struct pcep_object_header *hdr,
+ struct pcep_versioning *versioning,
+ uint8_t *obj_body_buf)
+{
+ (void)versioning;
+ struct pcep_object_inter_layer *obj =
+ (struct pcep_object_inter_layer *)hdr;
+ obj_body_buf[3] = ((obj->flag_i ? OBJECT_INTER_LAYER_FLAG_I : 0x00)
+ | (obj->flag_m ? OBJECT_INTER_LAYER_FLAG_M : 0x00)
+ | (obj->flag_t ? OBJECT_INTER_LAYER_FLAG_T : 0x00));
+
+ return LENGTH_1WORD;
+}
+
+uint16_t pcep_encode_obj_switch_layer(struct pcep_object_header *hdr,
+ struct pcep_versioning *versioning,
+ uint8_t *obj_body_buf)
+{
+ (void)versioning;
+ struct pcep_object_switch_layer *obj =
+ (struct pcep_object_switch_layer *)hdr;
+ uint8_t buf_index = 0;
+
+ double_linked_list_node *node = obj->switch_layer_rows->head;
+ while (node != NULL) {
+ struct pcep_object_switch_layer_row *row = node->data;
+ if (row == NULL) {
+ break;
+ }
+
+ obj_body_buf[buf_index] = row->lsp_encoding_type;
+ obj_body_buf[buf_index + 1] = row->switching_type;
+ obj_body_buf[buf_index + 3] =
+ (row->flag_i ? OBJECT_SWITCH_LAYER_FLAG_I : 0x00);
+
+ buf_index += LENGTH_1WORD;
+ }
+
+ return buf_index;
+}
+
+uint16_t pcep_encode_obj_req_adap_cap(struct pcep_object_header *hdr,
+ struct pcep_versioning *versioning,
+ uint8_t *obj_body_buf)
+{
+ (void)versioning;
+ struct pcep_object_req_adap_cap *obj =
+ (struct pcep_object_req_adap_cap *)hdr;
+
+ obj_body_buf[0] = obj->switching_capability;
+ obj_body_buf[1] = obj->encoding;
+
+ return LENGTH_1WORD;
+}
+
+uint16_t pcep_encode_obj_server_ind(struct pcep_object_header *hdr,
+ struct pcep_versioning *versioning,
+ uint8_t *obj_body_buf)
+{
+ (void)versioning;
+ struct pcep_object_server_indication *obj =
+ (struct pcep_object_server_indication *)hdr;
+
+ obj_body_buf[0] = obj->switching_capability;
+ obj_body_buf[1] = obj->encoding;
+
+ return LENGTH_1WORD;
+}
+
+uint16_t pcep_encode_obj_objective_function(struct pcep_object_header *hdr,
+ struct pcep_versioning *versioning,
+ uint8_t *obj_body_buf)
+{
+ (void)versioning;
+ struct pcep_object_objective_function *obj =
+ (struct pcep_object_objective_function *)hdr;
+
+ uint16_t *uint16_ptr = (uint16_t *)obj_body_buf;
+ *uint16_ptr = htons(obj->of_code);
+
+ return LENGTH_1WORD;
+}
+
+uint16_t pcep_encode_obj_ro(struct pcep_object_header *hdr,
+ struct pcep_versioning *versioning,
+ uint8_t *obj_body_buf)
+{
+ (void)versioning;
+ struct pcep_object_ro *ro = (struct pcep_object_ro *)hdr;
+ if (ro == NULL || ro->sub_objects == NULL) {
+ return 0;
+ }
+
+ /* RO Subobject format
+ *
+ * 0 1
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-------------//----------------+
+ * |L| Type | Length | (Subobject contents) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-------------//----------------+
+ */
+
+ uint16_t index = 0;
+ double_linked_list_node *node = ro->sub_objects->head;
+ for (; node != NULL; node = node->next_node) {
+ struct pcep_object_ro_subobj *ro_subobj = node->data;
+ obj_body_buf[index++] =
+ ((ro_subobj->flag_subobj_loose_hop ? 0x80 : 0x00)
+ | (ro_subobj->ro_subobj_type));
+ /* The length will be written below, depending on the subobj
+ * type */
+ uint8_t *length_ptr = &(obj_body_buf[index++]);
+ uint32_t *uint32_ptr = (uint32_t *)(obj_body_buf + index);
+
+ /* - The index has already been incremented past the header,
+ * and now points to the ro_subobj body. Below it just needs
+ * to be incremented past the body.
+ *
+ * - Each section below needs to write the total length,
+ * including the 2 byte subobj header. */
+
+ switch (ro_subobj->ro_subobj_type) {
+ case RO_SUBOBJ_TYPE_IPV4: {
+ struct pcep_ro_subobj_ipv4 *ipv4 =
+ (struct pcep_ro_subobj_ipv4 *)ro_subobj;
+ uint32_ptr[0] = ipv4->ip_addr.s_addr;
+ index += LENGTH_1WORD;
+ obj_body_buf[index++] = ipv4->prefix_length;
+ obj_body_buf[index++] =
+ (ipv4->flag_local_protection
+ ? OBJECT_SUBOBJ_IP_FLAG_LOCAL_PROT
+ : 0x00);
+ *length_ptr = LENGTH_2WORDS;
+ } break;
+
+ case RO_SUBOBJ_TYPE_IPV6: {
+ struct pcep_ro_subobj_ipv6 *ipv6 =
+ (struct pcep_ro_subobj_ipv6 *)ro_subobj;
+ encode_ipv6(&ipv6->ip_addr, uint32_ptr);
+ index += LENGTH_4WORDS;
+ obj_body_buf[index++] = ipv6->prefix_length;
+ obj_body_buf[index++] =
+ (ipv6->flag_local_protection
+ ? OBJECT_SUBOBJ_IP_FLAG_LOCAL_PROT
+ : 0x00);
+ *length_ptr = LENGTH_5WORDS;
+ } break;
+
+ case RO_SUBOBJ_TYPE_LABEL: {
+ struct pcep_ro_subobj_32label *label =
+ (struct pcep_ro_subobj_32label *)ro_subobj;
+ obj_body_buf[index++] =
+ (label->flag_global_label
+ ? OBJECT_SUBOBJ_LABEL_FLAG_GLOGAL
+ : 0x00);
+ obj_body_buf[index++] = label->class_type;
+ uint32_ptr = (uint32_t *)(obj_body_buf + index);
+ *uint32_ptr = htonl(label->label);
+ *length_ptr = LENGTH_2WORDS;
+ index += LENGTH_1WORD;
+ } break;
+
+ case RO_SUBOBJ_TYPE_UNNUM: {
+ struct pcep_ro_subobj_unnum *unum =
+ (struct pcep_ro_subobj_unnum *)ro_subobj;
+ index += 2; /* increment past 2 reserved bytes */
+ uint32_ptr = (uint32_t *)(obj_body_buf + index);
+ uint32_ptr[0] = unum->router_id.s_addr;
+ uint32_ptr[1] = htonl(unum->interface_id);
+ *length_ptr = LENGTH_3WORDS;
+ index += LENGTH_2WORDS;
+ } break;
+
+ case RO_SUBOBJ_TYPE_ASN: {
+ struct pcep_ro_subobj_asn *asn =
+ (struct pcep_ro_subobj_asn *)ro_subobj;
+ uint16_t *uint16_ptr =
+ (uint16_t *)(obj_body_buf + index);
+ *uint16_ptr = htons(asn->asn);
+ *length_ptr = LENGTH_1WORD;
+ index += 2;
+ } break;
+
+ case RO_SUBOBJ_TYPE_SR: {
+ /* SR-ERO subobject format
+ *
+ * 0 1 2 3 0 1 2 3 4
+ * 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |L| Type=36 | Length | NT | Flags
+ * |F|S|C|M|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | SID (optional) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * // NAI (variable, optional) //
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+ struct pcep_ro_subobj_sr *sr_subobj =
+ (struct pcep_ro_subobj_sr *)ro_subobj;
+ obj_body_buf[index++] =
+ ((sr_subobj->nai_type << 4) & 0xf0);
+ obj_body_buf[index++] =
+ ((sr_subobj->flag_f ? OBJECT_SUBOBJ_SR_FLAG_F
+ : 0x00)
+ | (sr_subobj->flag_s ? OBJECT_SUBOBJ_SR_FLAG_S
+ : 0x00)
+ | (sr_subobj->flag_c ? OBJECT_SUBOBJ_SR_FLAG_C
+ : 0x00)
+ | (sr_subobj->flag_m ? OBJECT_SUBOBJ_SR_FLAG_M
+ : 0x00));
+ uint32_ptr = (uint32_t *)(obj_body_buf + index);
+ /* Start with LENGTH_1WORD for the SubObj HDR + NT +
+ * Flags */
+ uint8_t sr_base_length = LENGTH_1WORD;
+ /* If the sid_absent flag is true, then dont convert the
+ * sid */
+ if (sr_subobj->flag_s == false) {
+ uint32_ptr[0] = htonl(sr_subobj->sid);
+ index += LENGTH_1WORD;
+ uint32_ptr = (uint32_t *)(obj_body_buf + index);
+ sr_base_length += LENGTH_1WORD;
+ }
+
+ /* The lengths below need to include:
+ * - sr_base_length: set above to include SR SubObj Hdr
+ * and the SID if present
+ * - Number of bytes written to the NAI
+ * The index will only be incremented below by the
+ * number of bytes written to the NAI, since the RO SR
+ * subobj header and the SID have already been written.
+ */
+
+ double_linked_list_node *nai_node =
+ (sr_subobj->nai_list == NULL
+ ? NULL
+ : sr_subobj->nai_list->head);
+ if (nai_node == NULL) {
+ if (sr_subobj->nai_type
+ == PCEP_SR_SUBOBJ_NAI_ABSENT) {
+ *length_ptr = sr_base_length;
+ continue;
+ } else {
+ return 0;
+ }
+ }
+ switch (sr_subobj->nai_type) {
+ case PCEP_SR_SUBOBJ_NAI_IPV4_NODE:
+ uint32_ptr[0] =
+ ((struct in_addr *)nai_node->data)
+ ->s_addr;
+ *length_ptr = sr_base_length + LENGTH_1WORD;
+ index += LENGTH_1WORD;
+ break;
+
+ case PCEP_SR_SUBOBJ_NAI_IPV6_NODE:
+ encode_ipv6((struct in6_addr *)nai_node->data,
+ uint32_ptr);
+ *length_ptr = sr_base_length + LENGTH_4WORDS;
+ index += LENGTH_4WORDS;
+ break;
+
+ case PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY:
+ uint32_ptr[0] =
+ ((struct in_addr *)nai_node->data)
+ ->s_addr;
+ nai_node = nai_node->next_node;
+ uint32_ptr[1] =
+ ((struct in_addr *)nai_node->data)
+ ->s_addr;
+ nai_node = nai_node->next_node;
+ uint32_ptr[2] =
+ ((struct in_addr *)nai_node->data)
+ ->s_addr;
+ nai_node = nai_node->next_node;
+ uint32_ptr[3] =
+ ((struct in_addr *)nai_node->data)
+ ->s_addr;
+ *length_ptr = sr_base_length + LENGTH_4WORDS;
+ index += LENGTH_4WORDS;
+ break;
+
+ case PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY:
+ uint32_ptr[0] =
+ ((struct in_addr *)nai_node->data)
+ ->s_addr;
+ nai_node = nai_node->next_node;
+ uint32_ptr[1] =
+ ((struct in_addr *)nai_node->data)
+ ->s_addr;
+ *length_ptr = sr_base_length + LENGTH_2WORDS;
+ index += LENGTH_2WORDS;
+ break;
+
+ case PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY:
+ encode_ipv6((struct in6_addr *)nai_node->data,
+ uint32_ptr);
+ nai_node = nai_node->next_node;
+ encode_ipv6((struct in6_addr *)nai_node->data,
+ uint32_ptr + 4);
+ *length_ptr = sr_base_length + LENGTH_8WORDS;
+ index += LENGTH_8WORDS;
+ break;
+
+ case PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY:
+ encode_ipv6((struct in6_addr *)nai_node->data,
+ uint32_ptr);
+ nai_node = nai_node->next_node;
+ uint32_ptr[4] =
+ ((struct in_addr *)nai_node->data)
+ ->s_addr;
+ nai_node = nai_node->next_node;
+ encode_ipv6((struct in6_addr *)nai_node->data,
+ uint32_ptr + 5);
+ nai_node = nai_node->next_node;
+ uint32_ptr[9] =
+ ((struct in_addr *)nai_node->data)
+ ->s_addr;
+ *length_ptr = sr_base_length + LENGTH_10WORDS;
+ index += LENGTH_10WORDS;
+ break;
+
+ default:
+ break;
+ }
+ } break;
+
+ default:
+ break;
+ }
+ }
+
+ return index;
+}
+
+void encode_ipv6(struct in6_addr *src_ipv6, uint32_t *dst)
+{
+ memcpy(dst, src_ipv6, sizeof(struct in6_addr));
+}
+
+/*
+ * Decoding functions.
+ */
+
+void pcep_decode_object_hdr(const uint8_t *obj_buf,
+ struct pcep_object_header *obj_hdr)
+{
+ memset(obj_hdr, 0, sizeof(struct pcep_object_header));
+
+ obj_hdr->object_class = obj_buf[0];
+ obj_hdr->object_type = (obj_buf[1] >> 4) & 0x0f;
+ obj_hdr->flag_p = (obj_buf[1] & OBJECT_HEADER_FLAG_P);
+ obj_hdr->flag_i = (obj_buf[1] & OBJECT_HEADER_FLAG_I);
+ uint16_t net_order_length;
+ memcpy(&net_order_length, obj_buf + 2, sizeof(net_order_length));
+ obj_hdr->encoded_object_length = ntohs(net_order_length);
+ obj_hdr->encoded_object = obj_buf;
+}
+
+uint16_t pcep_object_get_length(enum pcep_object_classes object_class,
+ enum pcep_object_types object_type)
+{
+ uint8_t object_length = pcep_object_class_lengths[object_class];
+ if (object_length == 0) {
+ if (object_class == PCEP_OBJ_CLASS_ENDPOINTS) {
+ if (object_type == PCEP_OBJ_TYPE_ENDPOINT_IPV4) {
+ return 12;
+ } else if (object_type == PCEP_OBJ_TYPE_ENDPOINT_IPV6) {
+ return 36;
+ }
+ }
+
+ return 0;
+ }
+
+ return object_length;
+}
+
+uint16_t pcep_object_get_length_by_hdr(struct pcep_object_header *object_hdr)
+{
+ return (pcep_object_get_length(object_hdr->object_class,
+ object_hdr->object_type));
+}
+
+bool pcep_object_has_tlvs(struct pcep_object_header *object_hdr)
+{
+ uint8_t object_length = pcep_object_get_length_by_hdr(object_hdr);
+ if (object_length == 0) {
+ return false;
+ }
+
+ return (object_hdr->encoded_object_length - object_length) > 0;
+}
+
+struct pcep_object_header *pcep_decode_object(const uint8_t *obj_buf)
+{
+
+ struct pcep_object_header object_hdr;
+ /* Only initializes and decodes the Object Header: class, type, flags,
+ * and length */
+ pcep_decode_object_hdr(obj_buf, &object_hdr);
+
+ if (object_hdr.object_class >= MAX_OBJECT_ENCODER_INDEX) {
+ pcep_log(LOG_INFO,
+ "%s: Cannot decode unknown Object class [%d]",
+ __func__, object_hdr.object_class);
+ return NULL;
+ }
+
+ object_decoder_funcptr obj_decoder =
+ object_decoders[object_hdr.object_class];
+ if (obj_decoder == NULL) {
+ pcep_log(LOG_INFO,
+ "%s: No object decoder found for Object class [%d]",
+ __func__, object_hdr.object_class);
+ return NULL;
+ }
+
+ /* The object decoders will start decoding the object body, if
+ * anything from the header is needed, they have the object_hdr */
+ struct pcep_object_header *object =
+ obj_decoder(&object_hdr, obj_buf + OBJECT_HEADER_LENGTH);
+ if (object == NULL) {
+ pcep_log(LOG_INFO, "%s: Unable to decode Object class [%d].",
+ __func__, object_hdr.object_class);
+ return NULL;
+ }
+
+ if (pcep_object_has_tlvs(&object_hdr)) {
+ object->tlv_list = dll_initialize();
+ int num_iterations = 0;
+ uint16_t tlv_index = pcep_object_get_length_by_hdr(&object_hdr);
+ while ((object->encoded_object_length - tlv_index) > 0
+ && num_iterations++ < MAX_ITERATIONS) {
+ struct pcep_object_tlv_header *tlv =
+ pcep_decode_tlv(obj_buf + tlv_index);
+ if (tlv == NULL) {
+ /* TODO should we do anything else here ? */
+ return object;
+ }
+
+ /* The TLV length does not include the TLV header */
+ tlv_index += normalize_pcep_tlv_length(
+ tlv->encoded_tlv_length + TLV_HEADER_LENGTH);
+ dll_append(object->tlv_list, tlv);
+ }
+ }
+
+ return object;
+}
+
+static struct pcep_object_header *
+common_object_create(struct pcep_object_header *hdr, uint16_t new_obj_length)
+{
+ struct pcep_object_header *new_object =
+ pceplib_malloc(PCEPLIB_MESSAGES, new_obj_length);
+ memset(new_object, 0, new_obj_length);
+ memcpy(new_object, hdr, sizeof(struct pcep_object_header));
+
+ return new_object;
+}
+
+/*
+ * Decoders
+ */
+
+struct pcep_object_header *pcep_decode_obj_open(struct pcep_object_header *hdr,
+ const uint8_t *obj_buf)
+{
+ struct pcep_object_open *obj =
+ (struct pcep_object_open *)common_object_create(
+ hdr, sizeof(struct pcep_object_open));
+
+ obj->open_version = (obj_buf[0] >> 5) & 0x07;
+ obj->open_keepalive = obj_buf[1];
+ obj->open_deadtimer = obj_buf[2];
+ obj->open_sid = obj_buf[3];
+
+ return (struct pcep_object_header *)obj;
+}
+
+struct pcep_object_header *pcep_decode_obj_rp(struct pcep_object_header *hdr,
+ const uint8_t *obj_buf)
+{
+ struct pcep_object_rp *obj =
+ (struct pcep_object_rp *)common_object_create(
+ hdr, sizeof(struct pcep_object_rp));
+
+ obj->flag_reoptimization = (obj_buf[3] & OBJECT_RP_FLAG_R);
+ obj->flag_bidirectional = (obj_buf[3] & OBJECT_RP_FLAG_B);
+ obj->flag_strict = (obj_buf[3] & OBJECT_RP_FLAG_O);
+ obj->flag_of = (obj_buf[3] & OBJECT_RP_FLAG_OF);
+ obj->priority = (obj_buf[3] & 0x07);
+ obj->request_id = ntohl(*((uint32_t *)(obj_buf + 4)));
+
+ return (struct pcep_object_header *)obj;
+}
+
+struct pcep_object_header *
+pcep_decode_obj_notify(struct pcep_object_header *hdr, const uint8_t *obj_buf)
+{
+ struct pcep_object_notify *obj =
+ (struct pcep_object_notify *)common_object_create(
+ hdr, sizeof(struct pcep_object_notify));
+
+ obj->notification_type = obj_buf[2];
+ obj->notification_value = obj_buf[3];
+
+ return (struct pcep_object_header *)obj;
+}
+
+struct pcep_object_header *
+pcep_decode_obj_nopath(struct pcep_object_header *hdr, const uint8_t *obj_buf)
+{
+ struct pcep_object_nopath *obj =
+ (struct pcep_object_nopath *)common_object_create(
+ hdr, sizeof(struct pcep_object_nopath));
+
+ obj->ni = (obj_buf[0] >> 1);
+ obj->flag_c = (obj_buf[0] & OBJECT_NOPATH_FLAG_C);
+
+ return (struct pcep_object_header *)obj;
+}
+
+struct pcep_object_header *
+pcep_decode_obj_association(struct pcep_object_header *hdr,
+ const uint8_t *obj_buf)
+{
+ uint16_t *uint16_ptr = (uint16_t *)obj_buf;
+ uint32_t *uint32_ptr = (uint32_t *)obj_buf;
+
+ if (hdr->object_type == PCEP_OBJ_TYPE_ASSOCIATION_IPV4) {
+ struct pcep_object_association_ipv4 *obj =
+ (struct pcep_object_association_ipv4 *)
+ common_object_create(
+ hdr,
+ sizeof(struct
+ pcep_object_association_ipv4));
+ obj->R_flag = (obj_buf[3] & OBJECT_ASSOCIATION_FLAG_R);
+ obj->association_type = ntohs(uint16_ptr[2]);
+ obj->association_id = ntohs(uint16_ptr[3]);
+ obj->src.s_addr = uint32_ptr[2];
+
+ return (struct pcep_object_header *)obj;
+ } else if (hdr->object_type == PCEP_OBJ_TYPE_ENDPOINT_IPV6) {
+ struct pcep_object_association_ipv6 *obj =
+ (struct pcep_object_association_ipv6 *)
+ common_object_create(
+ hdr,
+ sizeof(struct
+ pcep_object_association_ipv6));
+
+ obj->R_flag = (obj_buf[3] & OBJECT_ASSOCIATION_FLAG_R);
+ obj->association_type = ntohs(uint16_ptr[2]);
+ obj->association_id = ntohs(uint16_ptr[3]);
+ memcpy(&obj->src, &uint32_ptr[2], sizeof(struct in6_addr));
+
+ return (struct pcep_object_header *)obj;
+ }
+
+ return NULL;
+}
+struct pcep_object_header *
+pcep_decode_obj_endpoints(struct pcep_object_header *hdr,
+ const uint8_t *obj_buf)
+{
+ uint32_t *uint32_ptr = (uint32_t *)obj_buf;
+
+ if (hdr->object_type == PCEP_OBJ_TYPE_ENDPOINT_IPV4) {
+ struct pcep_object_endpoints_ipv4 *obj =
+ (struct pcep_object_endpoints_ipv4 *)
+ common_object_create(
+ hdr,
+ sizeof(struct
+ pcep_object_endpoints_ipv4));
+ obj->src_ipv4.s_addr = uint32_ptr[0];
+ obj->dst_ipv4.s_addr = uint32_ptr[1];
+
+ return (struct pcep_object_header *)obj;
+ } else if (hdr->object_type == PCEP_OBJ_TYPE_ENDPOINT_IPV6) {
+ struct pcep_object_endpoints_ipv6 *obj =
+ (struct pcep_object_endpoints_ipv6 *)
+ common_object_create(
+ hdr,
+ sizeof(struct
+ pcep_object_endpoints_ipv6));
+
+ memcpy(&obj->src_ipv6, &uint32_ptr[0], sizeof(struct in6_addr));
+ memcpy(&obj->dst_ipv6, &uint32_ptr[4], sizeof(struct in6_addr));
+
+ return (struct pcep_object_header *)obj;
+ }
+
+ return NULL;
+}
+
+struct pcep_object_header *
+pcep_decode_obj_bandwidth(struct pcep_object_header *hdr,
+ const uint8_t *obj_buf)
+{
+ struct pcep_object_bandwidth *obj =
+ (struct pcep_object_bandwidth *)common_object_create(
+ hdr, sizeof(struct pcep_object_bandwidth));
+
+ uint32_t value = ntohl(*((uint32_t *)obj_buf));
+ /* Seems like the compiler doesnt correctly copy to the float, so
+ * memcpy() it */
+ memcpy(&obj->bandwidth, &value, sizeof(uint32_t));
+
+ return (struct pcep_object_header *)obj;
+}
+
+struct pcep_object_header *
+pcep_decode_obj_metric(struct pcep_object_header *hdr, const uint8_t *obj_buf)
+{
+ struct pcep_object_metric *obj =
+ (struct pcep_object_metric *)common_object_create(
+ hdr, sizeof(struct pcep_object_metric));
+ obj->flag_b = (obj_buf[2] & OBJECT_METRIC_FLAC_B);
+ obj->flag_c = (obj_buf[2] & OBJECT_METRIC_FLAC_C);
+ obj->type = obj_buf[3];
+ uint32_t value = ntohl(*((uint32_t *)(obj_buf + 4)));
+ /* Seems like the compiler doesnt correctly copy to the float, so
+ * memcpy() it */
+ memcpy(&obj->value, &value, sizeof(uint32_t));
+
+ return (struct pcep_object_header *)obj;
+}
+
+struct pcep_object_header *pcep_decode_obj_lspa(struct pcep_object_header *hdr,
+ const uint8_t *obj_buf)
+{
+ struct pcep_object_lspa *obj =
+ (struct pcep_object_lspa *)common_object_create(
+ hdr, sizeof(struct pcep_object_lspa));
+ uint32_t *uint32_ptr = (uint32_t *)obj_buf;
+
+ obj->lspa_exclude_any = ntohl(uint32_ptr[0]);
+ obj->lspa_include_any = ntohl(uint32_ptr[1]);
+ obj->lspa_include_all = ntohl(uint32_ptr[2]);
+ obj->setup_priority = obj_buf[12];
+ obj->holding_priority = obj_buf[13];
+ obj->flag_local_protection = (obj_buf[14] & OBJECT_LSPA_FLAG_L);
+
+ return (struct pcep_object_header *)obj;
+}
+
+struct pcep_object_header *pcep_decode_obj_svec(struct pcep_object_header *hdr,
+ const uint8_t *obj_buf)
+{
+ struct pcep_object_svec *obj =
+ (struct pcep_object_svec *)common_object_create(
+ hdr, sizeof(struct pcep_object_svec));
+
+ obj->flag_link_diverse = (obj_buf[3] & OBJECT_SVEC_FLAG_L);
+ obj->flag_node_diverse = (obj_buf[3] & OBJECT_SVEC_FLAG_N);
+ obj->flag_srlg_diverse = (obj_buf[3] & OBJECT_SVEC_FLAG_S);
+
+ if (hdr->encoded_object_length > LENGTH_2WORDS) {
+ obj->request_id_list = dll_initialize();
+ uint16_t index = 1;
+ uint32_t *uint32_ptr = (uint32_t *)obj_buf;
+ for (;
+ index < ((hdr->encoded_object_length - LENGTH_2WORDS) / 4);
+ index++) {
+ uint32_t *req_id_ptr = pceplib_malloc(PCEPLIB_MESSAGES,
+ sizeof(uint32_t));
+ *req_id_ptr = uint32_ptr[index];
+ dll_append(obj->request_id_list, req_id_ptr);
+ }
+ }
+
+ return (struct pcep_object_header *)obj;
+}
+
+struct pcep_object_header *pcep_decode_obj_error(struct pcep_object_header *hdr,
+ const uint8_t *obj_buf)
+{
+ struct pcep_object_error *obj =
+ (struct pcep_object_error *)common_object_create(
+ hdr, sizeof(struct pcep_object_error));
+
+ obj->error_type = obj_buf[2];
+ obj->error_value = obj_buf[3];
+
+ return (struct pcep_object_header *)obj;
+}
+
+struct pcep_object_header *pcep_decode_obj_close(struct pcep_object_header *hdr,
+ const uint8_t *obj_buf)
+{
+ struct pcep_object_close *obj =
+ (struct pcep_object_close *)common_object_create(
+ hdr, sizeof(struct pcep_object_close));
+
+ obj->reason = obj_buf[3];
+
+ return (struct pcep_object_header *)obj;
+}
+
+struct pcep_object_header *pcep_decode_obj_srp(struct pcep_object_header *hdr,
+ const uint8_t *obj_buf)
+{
+ struct pcep_object_srp *obj =
+ (struct pcep_object_srp *)common_object_create(
+ hdr, sizeof(struct pcep_object_srp));
+
+ obj->flag_lsp_remove = (obj_buf[3] & OBJECT_SRP_FLAG_R);
+ obj->srp_id_number = ntohl(*((uint32_t *)(obj_buf + 4)));
+
+ return (struct pcep_object_header *)obj;
+}
+
+struct pcep_object_header *pcep_decode_obj_lsp(struct pcep_object_header *hdr,
+ const uint8_t *obj_buf)
+{
+ struct pcep_object_lsp *obj =
+ (struct pcep_object_lsp *)common_object_create(
+ hdr, sizeof(struct pcep_object_lsp));
+
+ obj->flag_d = (obj_buf[3] & OBJECT_LSP_FLAG_D);
+ obj->flag_s = (obj_buf[3] & OBJECT_LSP_FLAG_S);
+ obj->flag_r = (obj_buf[3] & OBJECT_LSP_FLAG_R);
+ obj->flag_a = (obj_buf[3] & OBJECT_LSP_FLAG_A);
+ obj->flag_c = (obj_buf[3] & OBJECT_LSP_FLAG_C);
+ obj->operational_status = ((obj_buf[3] >> 4) & 0x07);
+ obj->plsp_id = ((ntohl(*((uint32_t *)obj_buf)) >> 12) & 0x000fffff);
+
+ return (struct pcep_object_header *)obj;
+}
+
+struct pcep_object_header *
+pcep_decode_obj_vendor_info(struct pcep_object_header *hdr,
+ const uint8_t *obj_buf)
+{
+ struct pcep_object_vendor_info *obj =
+ (struct pcep_object_vendor_info *)common_object_create(
+ hdr, sizeof(struct pcep_object_vendor_info));
+ obj->enterprise_number = ntohl(*((uint32_t *)(obj_buf)));
+ obj->enterprise_specific_info = ntohl(*((uint32_t *)(obj_buf + 4)));
+
+ return (struct pcep_object_header *)obj;
+}
+
+struct pcep_object_header *
+pcep_decode_obj_inter_layer(struct pcep_object_header *hdr,
+ const uint8_t *obj_buf)
+{
+ struct pcep_object_inter_layer *obj =
+ (struct pcep_object_inter_layer *)common_object_create(
+ hdr, sizeof(struct pcep_object_inter_layer));
+ obj->flag_t = (obj_buf[3] & OBJECT_INTER_LAYER_FLAG_T);
+ obj->flag_m = (obj_buf[3] & OBJECT_INTER_LAYER_FLAG_M);
+ obj->flag_i = (obj_buf[3] & OBJECT_INTER_LAYER_FLAG_I);
+
+ return (struct pcep_object_header *)obj;
+}
+
+struct pcep_object_header *
+pcep_decode_obj_switch_layer(struct pcep_object_header *hdr,
+ const uint8_t *obj_buf)
+{
+ struct pcep_object_switch_layer *obj =
+ (struct pcep_object_switch_layer *)common_object_create(
+ hdr, sizeof(struct pcep_object_switch_layer));
+ obj->switch_layer_rows = dll_initialize();
+ int num_rows = ((hdr->encoded_object_length - 4) / 4);
+ uint8_t buf_index = 0;
+
+ int i = 0;
+ for (; i < num_rows; i++) {
+ struct pcep_object_switch_layer_row *row = pceplib_malloc(
+ PCEPLIB_MESSAGES,
+ sizeof(struct pcep_object_switch_layer_row));
+ row->lsp_encoding_type = obj_buf[buf_index];
+ row->switching_type = obj_buf[buf_index + 1];
+ row->flag_i =
+ (obj_buf[buf_index + 3] & OBJECT_SWITCH_LAYER_FLAG_I);
+ dll_append(obj->switch_layer_rows, row);
+
+ buf_index += LENGTH_1WORD;
+ }
+
+ return (struct pcep_object_header *)obj;
+}
+
+struct pcep_object_header *
+pcep_decode_obj_req_adap_cap(struct pcep_object_header *hdr,
+ const uint8_t *obj_buf)
+{
+ struct pcep_object_req_adap_cap *obj =
+ (struct pcep_object_req_adap_cap *)common_object_create(
+ hdr, sizeof(struct pcep_object_req_adap_cap));
+
+ obj->switching_capability = obj_buf[0];
+ obj->encoding = obj_buf[1];
+
+ return (struct pcep_object_header *)obj;
+}
+
+struct pcep_object_header *
+pcep_decode_obj_server_ind(struct pcep_object_header *hdr,
+ const uint8_t *obj_buf)
+{
+ struct pcep_object_server_indication *obj =
+ (struct pcep_object_server_indication *)common_object_create(
+ hdr, sizeof(struct pcep_object_server_indication));
+
+ obj->switching_capability = obj_buf[0];
+ obj->encoding = obj_buf[1];
+
+ return (struct pcep_object_header *)obj;
+}
+
+struct pcep_object_header *
+pcep_decode_obj_objective_function(struct pcep_object_header *hdr,
+ const uint8_t *obj_buf)
+{
+ struct pcep_object_objective_function *obj =
+ (struct pcep_object_objective_function *)common_object_create(
+ hdr, sizeof(struct pcep_object_objective_function));
+
+ uint16_t *uint16_ptr = (uint16_t *)obj_buf;
+ obj->of_code = ntohs(*uint16_ptr);
+
+ return (struct pcep_object_header *)obj;
+}
+
+void set_ro_subobj_fields(struct pcep_object_ro_subobj *subobj, bool flag_l,
+ uint8_t subobj_type)
+{
+ subobj->flag_subobj_loose_hop = flag_l;
+ subobj->ro_subobj_type = subobj_type;
+}
+
+void decode_ipv6(const uint32_t *src, struct in6_addr *dst_ipv6)
+{
+ memcpy(dst_ipv6, src, sizeof(struct in6_addr));
+}
+struct pcep_object_header *pcep_decode_obj_ro(struct pcep_object_header *hdr,
+ const uint8_t *obj_buf)
+{
+ struct pcep_object_ro *obj =
+ (struct pcep_object_ro *)common_object_create(
+ hdr, sizeof(struct pcep_object_ro));
+ obj->sub_objects = dll_initialize();
+
+ /* RO Subobject format
+ *
+ * 0 1
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-------------//----------------+
+ * |L| Type | Length | (Subobject contents) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-------------//----------------+
+ */
+
+ uint16_t read_count = 0;
+ int num_sub_objects = 1;
+ uint32_t *uint32_ptr;
+ uint16_t obj_body_length =
+ hdr->encoded_object_length - OBJECT_HEADER_LENGTH;
+
+ while ((obj_body_length - read_count) > OBJECT_RO_SUBOBJ_HEADER_LENGTH
+ && num_sub_objects < MAX_ITERATIONS) {
+ num_sub_objects++;
+ /* Read the Sub-Object Header */
+ bool flag_l = (obj_buf[read_count] & 0x80);
+ uint8_t subobj_type = (obj_buf[read_count++] & 0x7f);
+ uint8_t subobj_length = obj_buf[read_count++];
+
+ if (subobj_length <= OBJECT_RO_SUBOBJ_HEADER_LENGTH) {
+ pcep_log(LOG_INFO,
+ "%s: Invalid ro subobj type [%d] length [%d]",
+ __func__, subobj_type, subobj_length);
+ pceplib_free(PCEPLIB_MESSAGES, obj);
+ return NULL;
+ }
+
+ switch (subobj_type) {
+ case RO_SUBOBJ_TYPE_IPV4: {
+ struct pcep_ro_subobj_ipv4 *ipv4 = pceplib_malloc(
+ PCEPLIB_MESSAGES,
+ sizeof(struct pcep_ro_subobj_ipv4));
+ ipv4->ro_subobj.flag_subobj_loose_hop = flag_l;
+ ipv4->ro_subobj.ro_subobj_type = subobj_type;
+ uint32_ptr = (uint32_t *)(obj_buf + read_count);
+ ipv4->ip_addr.s_addr = *uint32_ptr;
+ read_count += LENGTH_1WORD;
+ ipv4->prefix_length = obj_buf[read_count++];
+ ipv4->flag_local_protection =
+ (obj_buf[read_count++]
+ & OBJECT_SUBOBJ_IP_FLAG_LOCAL_PROT);
+
+ dll_append(obj->sub_objects, ipv4);
+ } break;
+
+ case RO_SUBOBJ_TYPE_IPV6: {
+ struct pcep_ro_subobj_ipv6 *ipv6 = pceplib_malloc(
+ PCEPLIB_MESSAGES,
+ sizeof(struct pcep_ro_subobj_ipv6));
+ ipv6->ro_subobj.flag_subobj_loose_hop = flag_l;
+ ipv6->ro_subobj.ro_subobj_type = subobj_type;
+ decode_ipv6((uint32_t *)obj_buf, &ipv6->ip_addr);
+ read_count += LENGTH_4WORDS;
+ ipv6->prefix_length = obj_buf[read_count++];
+ ipv6->flag_local_protection =
+ (obj_buf[read_count++]
+ & OBJECT_SUBOBJ_IP_FLAG_LOCAL_PROT);
+
+ dll_append(obj->sub_objects, ipv6);
+ } break;
+
+ case RO_SUBOBJ_TYPE_LABEL: {
+ struct pcep_ro_subobj_32label *label = pceplib_malloc(
+ PCEPLIB_MESSAGES,
+ sizeof(struct pcep_ro_subobj_32label));
+ label->ro_subobj.flag_subobj_loose_hop = flag_l;
+ label->ro_subobj.ro_subobj_type = subobj_type;
+ label->flag_global_label =
+ (obj_buf[read_count++]
+ & OBJECT_SUBOBJ_LABEL_FLAG_GLOGAL);
+ label->class_type = obj_buf[read_count++];
+ label->label = ntohl(obj_buf[read_count]);
+ read_count += LENGTH_1WORD;
+
+ dll_append(obj->sub_objects, label);
+ } break;
+
+ case RO_SUBOBJ_TYPE_UNNUM: {
+ struct pcep_ro_subobj_unnum *unum = pceplib_malloc(
+ PCEPLIB_MESSAGES,
+ sizeof(struct pcep_ro_subobj_unnum));
+ unum->ro_subobj.flag_subobj_loose_hop = flag_l;
+ unum->ro_subobj.ro_subobj_type = subobj_type;
+ set_ro_subobj_fields(
+ (struct pcep_object_ro_subobj *)unum, flag_l,
+ subobj_type);
+ uint32_ptr = (uint32_t *)(obj_buf + read_count);
+ unum->interface_id = ntohl(uint32_ptr[0]);
+ unum->router_id.s_addr = uint32_ptr[1];
+ read_count += 2;
+
+ dll_append(obj->sub_objects, unum);
+ } break;
+
+ case RO_SUBOBJ_TYPE_ASN: {
+ struct pcep_ro_subobj_asn *asn = pceplib_malloc(
+ PCEPLIB_MESSAGES,
+ sizeof(struct pcep_ro_subobj_asn));
+ asn->ro_subobj.flag_subobj_loose_hop = flag_l;
+ asn->ro_subobj.ro_subobj_type = subobj_type;
+ uint16_t *uint16_ptr =
+ (uint16_t *)(obj_buf + read_count);
+ asn->asn = ntohs(*uint16_ptr);
+ read_count += 2;
+
+ dll_append(obj->sub_objects, asn);
+ } break;
+
+ case RO_SUBOBJ_TYPE_SR: {
+ /* SR-ERO subobject format
+ *
+ * 0 1 2 3 0 1 2 3 4
+ * 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |L| Type=36 | Length | NT | Flags
+ * |F|S|C|M|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | SID (optional) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * // NAI (variable, optional) //
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+ struct pcep_ro_subobj_sr *sr_subobj = pceplib_malloc(
+ PCEPLIB_MESSAGES,
+ sizeof(struct pcep_ro_subobj_sr));
+ sr_subobj->ro_subobj.flag_subobj_loose_hop = flag_l;
+ sr_subobj->ro_subobj.ro_subobj_type = subobj_type;
+ dll_append(obj->sub_objects, sr_subobj);
+
+ sr_subobj->nai_list = dll_initialize();
+ sr_subobj->nai_type =
+ ((obj_buf[read_count++] >> 4) & 0x0f);
+ sr_subobj->flag_f =
+ (obj_buf[read_count] & OBJECT_SUBOBJ_SR_FLAG_F);
+ sr_subobj->flag_s =
+ (obj_buf[read_count] & OBJECT_SUBOBJ_SR_FLAG_S);
+ sr_subobj->flag_c =
+ (obj_buf[read_count] & OBJECT_SUBOBJ_SR_FLAG_C);
+ sr_subobj->flag_m =
+ (obj_buf[read_count] & OBJECT_SUBOBJ_SR_FLAG_M);
+ read_count++;
+
+ /* If the sid_absent flag is true, then dont decode the
+ * sid */
+ uint32_ptr = (uint32_t *)(obj_buf + read_count);
+ if (sr_subobj->flag_s == false) {
+ sr_subobj->sid = ntohl(*uint32_ptr);
+ read_count += LENGTH_1WORD;
+ uint32_ptr += 1;
+ }
+
+ switch (sr_subobj->nai_type) {
+ case PCEP_SR_SUBOBJ_NAI_IPV4_NODE: {
+ struct in_addr *ipv4 =
+ pceplib_malloc(PCEPLIB_MESSAGES,
+ sizeof(struct in_addr));
+ ipv4->s_addr = *uint32_ptr;
+ dll_append(sr_subobj->nai_list, ipv4);
+ read_count += LENGTH_1WORD;
+ } break;
+
+ case PCEP_SR_SUBOBJ_NAI_IPV6_NODE: {
+ struct in6_addr *ipv6 =
+ pceplib_malloc(PCEPLIB_MESSAGES,
+ sizeof(struct in6_addr));
+ decode_ipv6(uint32_ptr, ipv6);
+ dll_append(sr_subobj->nai_list, ipv6);
+ read_count += LENGTH_4WORDS;
+ } break;
+
+ case PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY: {
+ struct in_addr *ipv4 =
+ pceplib_malloc(PCEPLIB_MESSAGES,
+ sizeof(struct in_addr));
+ ipv4->s_addr = uint32_ptr[0];
+ dll_append(sr_subobj->nai_list, ipv4);
+
+ ipv4 = pceplib_malloc(PCEPLIB_MESSAGES,
+ sizeof(struct in_addr));
+ ipv4->s_addr = uint32_ptr[1];
+ dll_append(sr_subobj->nai_list, ipv4);
+
+ ipv4 = pceplib_malloc(PCEPLIB_MESSAGES,
+ sizeof(struct in_addr));
+ ipv4->s_addr = uint32_ptr[2];
+ dll_append(sr_subobj->nai_list, ipv4);
+
+ ipv4 = pceplib_malloc(PCEPLIB_MESSAGES,
+ sizeof(struct in_addr));
+ ipv4->s_addr = uint32_ptr[3];
+ dll_append(sr_subobj->nai_list, ipv4);
+
+ read_count += LENGTH_4WORDS;
+ } break;
+
+ case PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY: {
+ struct in_addr *ipv4 =
+ pceplib_malloc(PCEPLIB_MESSAGES,
+ sizeof(struct in_addr));
+ ipv4->s_addr = uint32_ptr[0];
+ dll_append(sr_subobj->nai_list, ipv4);
+
+ ipv4 = pceplib_malloc(PCEPLIB_MESSAGES,
+ sizeof(struct in_addr));
+ ipv4->s_addr = uint32_ptr[1];
+ dll_append(sr_subobj->nai_list, ipv4);
+
+ read_count += LENGTH_2WORDS;
+ } break;
+
+ case PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY: {
+ struct in6_addr *ipv6 =
+ pceplib_malloc(PCEPLIB_MESSAGES,
+ sizeof(struct in6_addr));
+ decode_ipv6(uint32_ptr, ipv6);
+ dll_append(sr_subobj->nai_list, ipv6);
+
+ ipv6 = pceplib_malloc(PCEPLIB_MESSAGES,
+ sizeof(struct in6_addr));
+ decode_ipv6(uint32_ptr + 4, ipv6);
+ dll_append(sr_subobj->nai_list, ipv6);
+
+ read_count += LENGTH_8WORDS;
+ } break;
+
+ case PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY: {
+ struct in6_addr *ipv6 =
+ pceplib_malloc(PCEPLIB_MESSAGES,
+ sizeof(struct in6_addr));
+ decode_ipv6(uint32_ptr, ipv6);
+ dll_append(sr_subobj->nai_list, ipv6);
+
+ struct in_addr *ipv4 =
+ pceplib_malloc(PCEPLIB_MESSAGES,
+ sizeof(struct in_addr));
+ ipv4->s_addr = uint32_ptr[4];
+ dll_append(sr_subobj->nai_list, ipv4);
+
+ ipv6 = pceplib_malloc(PCEPLIB_MESSAGES,
+ sizeof(struct in6_addr));
+ decode_ipv6(uint32_ptr + 5, ipv6);
+ dll_append(sr_subobj->nai_list, ipv6);
+
+ ipv4 = pceplib_malloc(PCEPLIB_MESSAGES,
+ sizeof(struct in_addr));
+ ipv4->s_addr = uint32_ptr[9];
+ dll_append(sr_subobj->nai_list, ipv4);
+
+ read_count += LENGTH_10WORDS;
+ } break;
+
+ case PCEP_SR_SUBOBJ_NAI_ABSENT:
+ default:
+ break;
+ }
+ } break;
+
+ default:
+ pcep_log(
+ LOG_INFO,
+ "%s: pcep_decode_obj_ro skipping unrecognized sub-object type [%d]",
+ __func__, subobj_type);
+ read_count += subobj_length;
+ break;
+ }
+ }
+
+ return (struct pcep_object_header *)obj;
+}
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+/*
+ * This is the implementation of a High Level PCEP message object TLV API.
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "pcep_msg_tlvs.h"
+#include "pcep_msg_encoding.h"
+#include "pcep_utils_memory.h"
+
+static struct pcep_object_tlv_header *
+pcep_tlv_common_create(enum pcep_object_tlv_types type, uint16_t size)
+{
+ struct pcep_object_tlv_header *tlv =
+ pceplib_malloc(PCEPLIB_MESSAGES, size);
+ memset(tlv, 0, size);
+ tlv->type = type;
+
+ return tlv;
+}
+
+/*
+ * Open Object TLVs
+ */
+
+struct pcep_object_tlv_stateful_pce_capability *
+pcep_tlv_create_stateful_pce_capability(
+ bool flag_u_lsp_update_capability, bool flag_s_include_db_version,
+ bool flag_i_lsp_instantiation_capability, bool flag_t_triggered_resync,
+ bool flag_d_delta_lsp_sync, bool flag_f_triggered_initial_sync)
+{
+ struct pcep_object_tlv_stateful_pce_capability *tlv =
+ (struct pcep_object_tlv_stateful_pce_capability *)
+ pcep_tlv_common_create(
+ PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY,
+ sizeof(struct
+ pcep_object_tlv_stateful_pce_capability));
+ tlv->flag_u_lsp_update_capability = flag_u_lsp_update_capability;
+ tlv->flag_s_include_db_version = flag_s_include_db_version;
+ tlv->flag_i_lsp_instantiation_capability =
+ flag_i_lsp_instantiation_capability;
+ tlv->flag_t_triggered_resync = flag_t_triggered_resync;
+ tlv->flag_d_delta_lsp_sync = flag_d_delta_lsp_sync;
+ tlv->flag_f_triggered_initial_sync = flag_f_triggered_initial_sync;
+
+ return tlv;
+}
+
+struct pcep_object_tlv_lsp_db_version *
+pcep_tlv_create_lsp_db_version(uint64_t lsp_db_version)
+{
+ struct pcep_object_tlv_lsp_db_version *tlv =
+ (struct pcep_object_tlv_lsp_db_version *)pcep_tlv_common_create(
+ PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION,
+ sizeof(struct pcep_object_tlv_lsp_db_version));
+ tlv->lsp_db_version = lsp_db_version;
+
+ return tlv;
+}
+
+struct pcep_object_tlv_speaker_entity_identifier *
+pcep_tlv_create_speaker_entity_id(double_linked_list *speaker_entity_id_list)
+{
+ if (speaker_entity_id_list == NULL) {
+ return NULL;
+ }
+
+ if (speaker_entity_id_list->num_entries == 0) {
+ return NULL;
+ }
+
+ struct pcep_object_tlv_speaker_entity_identifier *tlv =
+ (struct pcep_object_tlv_speaker_entity_identifier *)
+ pcep_tlv_common_create(
+ PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID,
+ sizeof(struct
+ pcep_object_tlv_speaker_entity_identifier));
+ tlv->speaker_entity_id_list = speaker_entity_id_list;
+
+ return tlv;
+}
+
+struct pcep_object_tlv_path_setup_type *
+pcep_tlv_create_path_setup_type(uint8_t pst)
+{
+ struct pcep_object_tlv_path_setup_type *tlv =
+ (struct pcep_object_tlv_path_setup_type *)
+ pcep_tlv_common_create(
+ PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE,
+ sizeof(struct pcep_object_tlv_path_setup_type));
+ tlv->path_setup_type = pst;
+
+ return tlv;
+}
+
+struct pcep_object_tlv_path_setup_type_capability *
+pcep_tlv_create_path_setup_type_capability(double_linked_list *pst_list,
+ double_linked_list *sub_tlv_list)
+{
+ if (pst_list == NULL) {
+ return NULL;
+ }
+
+ if (pst_list->num_entries == 0) {
+ return NULL;
+ }
+
+ struct pcep_object_tlv_path_setup_type_capability *tlv =
+ (struct pcep_object_tlv_path_setup_type_capability *)
+ pcep_tlv_common_create(
+ PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY,
+ sizeof(struct
+ pcep_object_tlv_path_setup_type_capability));
+
+ tlv->pst_list = pst_list;
+ tlv->sub_tlv_list = sub_tlv_list;
+
+ return tlv;
+}
+
+struct pcep_object_tlv_sr_pce_capability *
+pcep_tlv_create_sr_pce_capability(bool flag_n, bool flag_x,
+ uint8_t max_sid_depth)
+{
+ struct pcep_object_tlv_sr_pce_capability *tlv =
+ (struct pcep_object_tlv_sr_pce_capability *)
+ pcep_tlv_common_create(
+ PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY,
+ sizeof(struct
+ pcep_object_tlv_sr_pce_capability));
+ tlv->flag_n = flag_n;
+ tlv->flag_x = flag_x;
+ tlv->max_sid_depth = max_sid_depth;
+
+ return tlv;
+}
+
+struct pcep_object_tlv_of_list *
+pcep_tlv_create_of_list(double_linked_list *of_list)
+{
+ if (of_list == NULL) {
+ return NULL;
+ }
+
+ struct pcep_object_tlv_of_list *tlv =
+ (struct pcep_object_tlv_of_list *)pcep_tlv_common_create(
+ PCEP_OBJ_TLV_TYPE_OBJECTIVE_FUNCTION_LIST,
+ sizeof(struct pcep_object_tlv_of_list));
+
+ tlv->of_list = of_list;
+
+ return tlv;
+}
+
+/*
+ * LSP Object TLVs
+ */
+
+struct pcep_object_tlv_ipv4_lsp_identifier *
+pcep_tlv_create_ipv4_lsp_identifiers(struct in_addr *ipv4_tunnel_sender,
+ struct in_addr *ipv4_tunnel_endpoint,
+ uint16_t lsp_id, uint16_t tunnel_id,
+ struct in_addr *extended_tunnel_id)
+{
+ if (ipv4_tunnel_sender == NULL || ipv4_tunnel_endpoint == NULL) {
+ return NULL;
+ }
+
+ struct pcep_object_tlv_ipv4_lsp_identifier *tlv =
+ (struct pcep_object_tlv_ipv4_lsp_identifier *)
+ pcep_tlv_common_create(
+ PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS,
+ sizeof(struct
+ pcep_object_tlv_ipv4_lsp_identifier));
+ tlv->ipv4_tunnel_sender.s_addr = ipv4_tunnel_sender->s_addr;
+ tlv->ipv4_tunnel_endpoint.s_addr = ipv4_tunnel_endpoint->s_addr;
+ tlv->lsp_id = lsp_id;
+ tlv->tunnel_id = tunnel_id;
+ tlv->extended_tunnel_id.s_addr =
+ (extended_tunnel_id == NULL ? INADDR_ANY
+ : extended_tunnel_id->s_addr);
+
+ return tlv;
+}
+
+struct pcep_object_tlv_ipv6_lsp_identifier *
+pcep_tlv_create_ipv6_lsp_identifiers(struct in6_addr *ipv6_tunnel_sender,
+ struct in6_addr *ipv6_tunnel_endpoint,
+ uint16_t lsp_id, uint16_t tunnel_id,
+ struct in6_addr *extended_tunnel_id)
+{
+ if (ipv6_tunnel_sender == NULL || ipv6_tunnel_endpoint == NULL) {
+ return NULL;
+ }
+
+ struct pcep_object_tlv_ipv6_lsp_identifier *tlv =
+ (struct pcep_object_tlv_ipv6_lsp_identifier *)
+ pcep_tlv_common_create(
+ PCEP_OBJ_TLV_TYPE_IPV6_LSP_IDENTIFIERS,
+ sizeof(struct
+ pcep_object_tlv_ipv6_lsp_identifier));
+
+ memcpy(&tlv->ipv6_tunnel_sender, ipv6_tunnel_sender,
+ sizeof(struct in6_addr));
+
+ tlv->tunnel_id = tunnel_id;
+ tlv->lsp_id = lsp_id;
+
+ memcpy(&tlv->extended_tunnel_id, extended_tunnel_id,
+ sizeof(struct in6_addr));
+
+ memcpy(&tlv->ipv6_tunnel_endpoint, ipv6_tunnel_endpoint,
+ sizeof(struct in6_addr));
+
+ return tlv;
+}
+
+struct pcep_object_tlv_symbolic_path_name *
+pcep_tlv_create_symbolic_path_name(const char *symbolic_path_name,
+ uint16_t symbolic_path_name_length)
+{
+ /* symbolic_path_name_length should NOT include the null terminator and
+ * cannot be zero */
+ if (symbolic_path_name == NULL || symbolic_path_name_length == 0) {
+ return NULL;
+ }
+
+ struct pcep_object_tlv_symbolic_path_name *tlv =
+ (struct pcep_object_tlv_symbolic_path_name *)
+ pcep_tlv_common_create(
+ PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME,
+ sizeof(struct
+ pcep_object_tlv_symbolic_path_name));
+
+ uint16_t length = (symbolic_path_name_length > MAX_SYMBOLIC_PATH_NAME)
+ ? MAX_SYMBOLIC_PATH_NAME
+ : symbolic_path_name_length;
+ memcpy(tlv->symbolic_path_name, symbolic_path_name, length);
+ tlv->symbolic_path_name_length = length;
+
+ return tlv;
+}
+
+struct pcep_object_tlv_lsp_error_code *
+pcep_tlv_create_lsp_error_code(enum pcep_tlv_lsp_error_codes lsp_error_code)
+{
+ struct pcep_object_tlv_lsp_error_code *tlv =
+ (struct pcep_object_tlv_lsp_error_code *)pcep_tlv_common_create(
+ PCEP_OBJ_TLV_TYPE_LSP_ERROR_CODE,
+ sizeof(struct pcep_object_tlv_lsp_error_code));
+ tlv->lsp_error_code = lsp_error_code;
+
+ return tlv;
+}
+
+struct pcep_object_tlv_rsvp_error_spec *
+pcep_tlv_create_rsvp_ipv4_error_spec(struct in_addr *error_node_ip,
+ uint8_t error_code, uint16_t error_value)
+{
+ if (error_node_ip == NULL) {
+ return NULL;
+ }
+
+ struct pcep_object_tlv_rsvp_error_spec *tlv =
+ (struct pcep_object_tlv_rsvp_error_spec *)
+ pcep_tlv_common_create(
+ PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC,
+ sizeof(struct pcep_object_tlv_rsvp_error_spec));
+
+ tlv->c_type = RSVP_ERROR_SPEC_IPV4_CTYPE;
+ tlv->class_num = RSVP_ERROR_SPEC_CLASS_NUM;
+ tlv->error_code = error_code;
+ tlv->error_value = error_value;
+ tlv->error_spec_ip.ipv4_error_node_address.s_addr =
+ error_node_ip->s_addr;
+
+ return tlv;
+}
+
+struct pcep_object_tlv_rsvp_error_spec *
+pcep_tlv_create_rsvp_ipv6_error_spec(struct in6_addr *error_node_ip,
+ uint8_t error_code, uint16_t error_value)
+{
+ if (error_node_ip == NULL) {
+ return NULL;
+ }
+
+ struct pcep_object_tlv_rsvp_error_spec *tlv =
+ (struct pcep_object_tlv_rsvp_error_spec *)
+ pcep_tlv_common_create(
+ PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC,
+ sizeof(struct pcep_object_tlv_rsvp_error_spec));
+
+ tlv->c_type = RSVP_ERROR_SPEC_IPV6_CTYPE;
+ tlv->class_num = RSVP_ERROR_SPEC_CLASS_NUM;
+ tlv->error_code = error_code;
+ tlv->error_value = error_value;
+ memcpy(&tlv->error_spec_ip, error_node_ip, sizeof(struct in6_addr));
+
+ return tlv;
+}
+
+struct pcep_object_tlv_nopath_vector *
+pcep_tlv_create_nopath_vector(uint32_t error_code)
+{
+ struct pcep_object_tlv_nopath_vector *tlv =
+ (struct pcep_object_tlv_nopath_vector *)pcep_tlv_common_create(
+ PCEP_OBJ_TLV_TYPE_NO_PATH_VECTOR,
+ sizeof(struct pcep_object_tlv_nopath_vector));
+
+ tlv->error_code = error_code;
+
+ return tlv;
+}
+
+struct pcep_object_tlv_vendor_info *
+pcep_tlv_create_vendor_info(uint32_t enterprise_number,
+ uint32_t enterprise_specific_info)
+{
+ struct pcep_object_tlv_vendor_info *tlv =
+ (struct pcep_object_tlv_vendor_info *)pcep_tlv_common_create(
+ PCEP_OBJ_TLV_TYPE_VENDOR_INFO,
+ sizeof(struct pcep_object_tlv_vendor_info));
+
+ tlv->enterprise_number = enterprise_number;
+ tlv->enterprise_specific_info = enterprise_specific_info;
+
+ return tlv;
+}
+
+/*
+ * SRPAG (SR Association Group) TLVs
+ */
+
+struct pcep_object_tlv_srpag_pol_id *
+pcep_tlv_create_srpag_pol_id_ipv4(uint32_t color, struct in_addr *ipv4)
+{
+ struct pcep_object_tlv_srpag_pol_id *tlv =
+ (struct pcep_object_tlv_srpag_pol_id *)pcep_tlv_common_create(
+ PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_ID,
+ sizeof(struct pcep_object_tlv_srpag_pol_id));
+ tlv->color = color;
+ tlv->is_ipv4 = true;
+ memcpy(&tlv->end_point.ipv4.s_addr, ipv4, sizeof(struct in_addr));
+
+ return tlv;
+}
+
+struct pcep_object_tlv_srpag_pol_id *
+pcep_tlv_create_srpag_pol_id_ipv6(uint32_t color, struct in6_addr *ipv6)
+{
+ struct pcep_object_tlv_srpag_pol_id *tlv =
+ (struct pcep_object_tlv_srpag_pol_id *)pcep_tlv_common_create(
+ PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_ID,
+ sizeof(struct pcep_object_tlv_srpag_pol_id));
+ tlv->color = color;
+ tlv->is_ipv4 = false;
+ memcpy(&tlv->end_point.ipv6, ipv6, sizeof(struct in6_addr));
+
+ return tlv;
+}
+
+
+struct pcep_object_tlv_srpag_pol_name *
+pcep_tlv_create_srpag_pol_name(const char *pol_name, uint16_t pol_name_length)
+{
+ if (pol_name == NULL) {
+ return NULL;
+ }
+ struct pcep_object_tlv_srpag_pol_name *tlv =
+ (struct pcep_object_tlv_srpag_pol_name *)pcep_tlv_common_create(
+ PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_NAME,
+ sizeof(struct pcep_object_tlv_srpag_pol_name));
+ uint16_t length =
+ (normalize_pcep_tlv_length(pol_name_length) > MAX_POLICY_NAME)
+ ? MAX_POLICY_NAME
+ : pol_name_length;
+ memcpy(tlv->name, pol_name, length);
+ tlv->name_length = length;
+
+ return tlv;
+}
+struct pcep_object_tlv_srpag_cp_id *
+pcep_tlv_create_srpag_cp_id(uint8_t proto_origin, uint32_t asn,
+ struct in6_addr *in6_addr_with_mapped_ipv4,
+ uint32_t discriminator)
+{
+ if (!in6_addr_with_mapped_ipv4) {
+ return NULL;
+ }
+
+ struct pcep_object_tlv_srpag_cp_id *tlv =
+ (struct pcep_object_tlv_srpag_cp_id *)pcep_tlv_common_create(
+ PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_ID,
+ sizeof(struct pcep_object_tlv_srpag_cp_id));
+ tlv->proto = proto_origin;
+ tlv->orig_asn = asn;
+ memcpy(&(tlv->orig_addres), in6_addr_with_mapped_ipv4,
+ sizeof(*in6_addr_with_mapped_ipv4));
+ tlv->discriminator = discriminator;
+
+ return tlv;
+}
+struct pcep_object_tlv_srpag_cp_pref *
+pcep_tlv_create_srpag_cp_pref(uint32_t pref)
+{
+
+ struct pcep_object_tlv_srpag_cp_pref *tlv =
+ (struct pcep_object_tlv_srpag_cp_pref *)pcep_tlv_common_create(
+ PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_PREFERENCE,
+ sizeof(struct pcep_object_tlv_srpag_cp_pref));
+ tlv->preference = pref;
+
+ return tlv;
+}
+
+struct pcep_object_tlv_arbitrary *
+pcep_tlv_create_tlv_arbitrary(const char *data, uint16_t data_length,
+ int tlv_id)
+{
+ if (data == NULL || data_length == 0) {
+ return NULL;
+ }
+
+ struct pcep_object_tlv_arbitrary *tlv =
+ (struct pcep_object_tlv_arbitrary *)pcep_tlv_common_create(
+ PCEP_OBJ_TLV_TYPE_ARBITRARY,
+ sizeof(struct pcep_object_tlv_arbitrary));
+
+ uint16_t length = (data_length > MAX_ARBITRARY_SIZE)
+ ? MAX_ARBITRARY_SIZE
+ : data_length;
+ memcpy(tlv->data, data, length);
+ tlv->data_length = length;
+ tlv->arbitraty_type = tlv_id;
+
+ return tlv;
+}
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ */
+
+
+/*
+ * This is a High Level PCEP message object TLV API.
+ */
+
+#ifndef PCEP_TLVS_H_
+#define PCEP_TLVS_H_
+
+#include <arpa/inet.h>
+#include <stdint.h>
+
+#include "pcep.h"
+#include "pcep_utils_double_linked_list.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Regarding memory usage:
+ * When creating TLVs, any TLVs passed into messages or objects with these APIs
+ * will be free'd when the the enclosing pcep_message is free'd. That includes
+ * the double_linked_list's. So, just create the objects and TLVs, put them in
+ * their double_linked_list's, and everything will be managed internally. The
+ * enclosing message will be deleted by pcep_msg_free_message() or
+ * pcep_msg_free_message_list() which, * in turn will call one of:
+ * pcep_obj_free_object() and pcep_obj_free_tlv().
+ * For received messages, call pcep_msg_free_message() to free them.
+ */
+
+/* These numbers can be found here:
+ * https://www.iana.org/assignments/pcep/pcep.xhtml */
+enum pcep_object_tlv_types {
+ PCEP_OBJ_TLV_TYPE_NO_PATH_VECTOR = 1,
+ PCEP_OBJ_TLV_TYPE_OBJECTIVE_FUNCTION_LIST = 4, /* RFC 5541 */
+ PCEP_OBJ_TLV_TYPE_VENDOR_INFO = 7, /* RFC 7470 */
+ PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY = 16, /* RFC 8231 */
+ PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME = 17, /* RFC 8232 */
+ PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS = 18, /* RFC 8231 */
+ PCEP_OBJ_TLV_TYPE_IPV6_LSP_IDENTIFIERS = 19, /* RFC 8231 */
+ PCEP_OBJ_TLV_TYPE_LSP_ERROR_CODE = 20, /* RFC 8232 */
+ PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC = 21, /* RFC 8232 */
+ PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION = 23, /* RFC 8232 */
+ PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID = 24, /* RFC 8232 */
+ PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY =
+ 26, /* draft-ietf-pce-segment-routing-16 */
+ PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE = 28, /* RFC 8408 */
+ PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY =
+ 34, /* RFC 8408, draft-ietf-pce-segment-routing-16 */
+ PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_ID =
+ 60, /*TDB2 draft-barth-pce-segment-routing-policy-cp-04 */
+ PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_NAME =
+ 61, /*TDB3 draft-barth-pce-segment-routing-policy-cp-04 */
+ PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_ID =
+ 62, /*TDB4 draft-barth-pce-segment-routing-policy-cp-04 */
+ PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_PREFERENCE =
+ 63, /*TDB5 draft-barth-pce-segment-routing-policy-cp-04 */
+ PCEP_OBJ_TLV_TYPE_UNKNOWN = 128,
+ PCEP_OBJ_TLV_TYPE_ARBITRARY =
+ 65533 /* Max IANA To write arbitrary data */
+};
+
+struct pcep_object_tlv_header {
+ enum pcep_object_tlv_types type;
+ /* Pointer into encoded_message field from the pcep_message */
+ const uint8_t *encoded_tlv;
+ uint16_t encoded_tlv_length;
+};
+
+/* STATEFUL-PCE-CAPABILITY TLV, Used in Open Object. RFCs: 8231, 8232, 8281 */
+#define TLV_STATEFUL_PCE_CAP_FLAG_U 0x01
+#define TLV_STATEFUL_PCE_CAP_FLAG_S 0x02
+#define TLV_STATEFUL_PCE_CAP_FLAG_I 0x04
+#define TLV_STATEFUL_PCE_CAP_FLAG_T 0x08
+#define TLV_STATEFUL_PCE_CAP_FLAG_D 0x10
+#define TLV_STATEFUL_PCE_CAP_FLAG_F 0x20
+
+struct pcep_object_tlv_stateful_pce_capability {
+ struct pcep_object_tlv_header header;
+ bool flag_u_lsp_update_capability; /* RFC 8231 */
+ bool flag_s_include_db_version; /* RFC 8232 */
+ bool flag_i_lsp_instantiation_capability; /* RFC 8281 */
+ bool flag_t_triggered_resync; /* RFC 8232 */
+ bool flag_d_delta_lsp_sync; /* RFC 8232 */
+ bool flag_f_triggered_initial_sync; /* RFC 8232 */
+};
+
+/* NOPATH-VECTOR TLV, Used in the Reply NoPath Object. */
+struct pcep_object_tlv_nopath_vector {
+ struct pcep_object_tlv_header header;
+ uint32_t error_code;
+};
+
+/* STATEFUL-PCE-CAPABILITY TLV, Used in Open Object. RFCs: 8232 */
+struct pcep_object_tlv_lsp_db_version {
+ struct pcep_object_tlv_header header;
+ uint64_t lsp_db_version;
+};
+
+/* Speaker Entity Identifier TLV, Used in Open Object. RFCs: 8232 */
+struct pcep_object_tlv_speaker_entity_identifier {
+ struct pcep_object_tlv_header header;
+ double_linked_list *speaker_entity_id_list; /* list of uint32_t speaker
+ entity ids */
+};
+
+/* Ipv4 LSP Identifier TLV, Used in LSP Object. RFCs: 8231 */
+struct pcep_object_tlv_ipv4_lsp_identifier {
+ struct pcep_object_tlv_header header;
+ struct in_addr ipv4_tunnel_sender;
+ uint16_t lsp_id;
+ uint16_t tunnel_id;
+ struct in_addr extended_tunnel_id;
+ struct in_addr ipv4_tunnel_endpoint;
+};
+
+/* Ipv6 LSP Identifier TLV, Used in LSP Object. RFCs: 8231 */
+struct pcep_object_tlv_ipv6_lsp_identifier {
+ struct pcep_object_tlv_header header;
+ struct in6_addr ipv6_tunnel_sender;
+ uint16_t lsp_id;
+ uint16_t tunnel_id;
+ struct in6_addr extended_tunnel_id;
+ struct in6_addr ipv6_tunnel_endpoint;
+};
+
+/* Symbolic Path Name TLV, Used in LSP Object. RFCs: 8231 */
+#define MAX_SYMBOLIC_PATH_NAME 256
+
+struct pcep_object_tlv_symbolic_path_name {
+ struct pcep_object_tlv_header header;
+ uint16_t symbolic_path_name_length;
+ char symbolic_path_name[MAX_SYMBOLIC_PATH_NAME];
+};
+
+/* LSP Error Code TLV, Used in LSP Object. RFCs: 8231 */
+enum pcep_tlv_lsp_error_codes {
+ PCEP_TLV_LSP_ERROR_CODE_UNKNOWN = 1,
+ PCEP_TLV_LSP_ERROR_CODE_LSP_LIMIT_REACHED = 2,
+ PCEP_TLV_LSP_ERROR_CODE_TOO_MANY_PENDING_LSP_UPDATES = 3,
+ PCEP_TLV_LSP_ERROR_CODE_UNACCEPTABLE_PARAMS = 4,
+ PCEP_TLV_LSP_ERROR_CODE_INTERNAL_ERROR = 5,
+ PCEP_TLV_LSP_ERROR_CODE_LSP_BROUGHT_DOWN = 6,
+ PCEP_TLV_LSP_ERROR_CODE_LSP_PREEMPTED = 7,
+ PCEP_TLV_LSP_ERROR_CODE_RSVP_SIGNALING_ERROR = 8,
+};
+
+struct pcep_object_tlv_lsp_error_code {
+ struct pcep_object_tlv_header header;
+ enum pcep_tlv_lsp_error_codes lsp_error_code;
+};
+
+/* Path Setup Type TLV, Used in RP and SRP Object. RFCs: 8408,
+ * draft-ietf-pce-segment-routing-16 */
+#define SR_TE_PST 1
+
+struct pcep_object_tlv_path_setup_type {
+ struct pcep_object_tlv_header header;
+ uint8_t path_setup_type;
+};
+
+/* Path Setup Type Capability TLV, Used in Open Object. RFCs: 8408,
+ * draft-ietf-pce-segment-routing-16 */
+struct pcep_object_tlv_path_setup_type_capability {
+ struct pcep_object_tlv_header header;
+ double_linked_list *pst_list; /* list of uint8_t PSTs */
+ double_linked_list *sub_tlv_list; /* list of sub_tlvs */
+};
+
+/* SR PCE Capability sub-TLV, Used in Open Object. RFCs:
+ * draft-ietf-pce-segment-routing-16 */
+#define TLV_SR_PCE_CAP_FLAG_X 0x01
+#define TLV_SR_PCE_CAP_FLAG_N 0x02
+
+struct pcep_object_tlv_sr_pce_capability {
+ struct pcep_object_tlv_header header;
+ bool flag_n;
+ bool flag_x;
+ uint8_t max_sid_depth;
+};
+
+
+/* RSVP Error Spec TLV, Used in LSP Object. RFCs: 8231, 2205 */
+#define RSVP_ERROR_SPEC_IPV4_CTYPE 1
+#define RSVP_ERROR_SPEC_IPV6_CTYPE 2
+#define RSVP_ERROR_SPEC_CLASS_NUM 6
+
+struct pcep_object_tlv_rsvp_error_spec {
+ struct pcep_object_tlv_header header;
+ uint8_t class_num;
+ uint8_t c_type;
+ uint8_t error_code;
+ uint16_t error_value;
+ /* Use the c_type to determine which union entry to use */
+ union error_spec_ip {
+ struct in_addr ipv4_error_node_address;
+ struct in6_addr ipv6_error_node_address;
+ } error_spec_ip;
+};
+
+/* SR Policy Identifier TLV Used in Association Object.
+ * draft-barth-pce-segment-routing-policy-cp-04*/
+struct pcep_object_tlv_srpag_pol_id {
+ struct pcep_object_tlv_header header;
+ uint32_t color;
+ bool is_ipv4;
+ union end_point_ {
+ struct in_addr ipv4;
+ struct in6_addr ipv6;
+ } end_point;
+};
+
+/*draft-ietf-spring-segment-routing-policy-06*/
+#define MAX_POLICY_NAME 256
+
+/* SR Policy Name TLV Used in Association Object.
+ * draft-barth-pce-segment-routing-policy-cp-04*/
+struct pcep_object_tlv_srpag_pol_name {
+ struct pcep_object_tlv_header header;
+ uint16_t name_length;
+ char name[MAX_POLICY_NAME];
+};
+
+/* SR Candidate Path Id TLV Used in Association Object.
+ * draft-barth-pce-segment-routing-policy-cp-04*/
+struct pcep_object_tlv_srpag_cp_id {
+ struct pcep_object_tlv_header header;
+ uint8_t proto;
+ uint32_t orig_asn;
+ struct in6_addr orig_addres; /*With ipv4 embedded*/
+ uint32_t discriminator;
+};
+
+/* SR Candidate Preference TLV Used in Association Object.
+ * draft-barth-pce-segment-routing-policy-cp-04*/
+struct pcep_object_tlv_srpag_cp_pref {
+ struct pcep_object_tlv_header header;
+ uint32_t preference;
+};
+
+struct pcep_object_tlv_vendor_info {
+ struct pcep_object_tlv_header header;
+ uint32_t enterprise_number;
+ uint32_t enterprise_specific_info;
+};
+
+/* arbitrary TLV 65535 */
+#define MAX_ARBITRARY_SIZE 256
+struct pcep_object_tlv_arbitrary {
+ struct pcep_object_tlv_header header;
+ enum pcep_object_tlv_types arbitraty_type;
+ uint16_t data_length;
+ char data[MAX_ARBITRARY_SIZE];
+};
+
+/* Objective Functions List RFC 5541
+ * At least the following 6 OF codes must be supported */
+enum objective_function_codes {
+ PCEP_OF_CODE_MINIMUM_COST_PATH = 1, /* MCP */
+ PCEP_OF_CODE_MINIMUM_LOAD_PATH = 2, /* MLP */
+ PCEP_OF_CODE_MAXIMUM_BW_PATH = 3, /* MBP */
+ PCEP_OF_CODE_MINIMIZE_AGGR_BW_CONSUMPTION = 4, /* MBC */
+ PCEP_OF_CODE_MINIMIZE_MOST_LOADED_LINK = 5, /* MLL */
+ PCEP_OF_CODE_MINIMIZE_CUMULATIVE_COST_PATHS = 6, /* MCC */
+};
+
+struct pcep_object_tlv_of_list {
+ struct pcep_object_tlv_header header;
+ double_linked_list *of_list; /* list of uint16_t OF code points */
+};
+
+/*
+ * TLV creation functions
+ */
+
+/*
+ * Open Object TLVs
+ */
+
+struct pcep_object_tlv_stateful_pce_capability *
+pcep_tlv_create_stateful_pce_capability(
+ bool flag_u_lsp_update_capability, bool flag_s_include_db_version,
+ bool flag_i_lsp_instantiation_capability, bool flag_t_triggered_resync,
+ bool flag_d_delta_lsp_sync, bool flag_f_triggered_initial_sync);
+struct pcep_object_tlv_lsp_db_version *
+pcep_tlv_create_lsp_db_version(uint64_t lsp_db_version);
+struct pcep_object_tlv_speaker_entity_identifier *
+pcep_tlv_create_speaker_entity_id(double_linked_list *speaker_entity_id_list);
+struct pcep_object_tlv_path_setup_type *
+pcep_tlv_create_path_setup_type(uint8_t pst);
+struct pcep_object_tlv_path_setup_type_capability *
+pcep_tlv_create_path_setup_type_capability(double_linked_list *pst_list,
+ double_linked_list *sub_tlv_list);
+struct pcep_object_tlv_sr_pce_capability *
+pcep_tlv_create_sr_pce_capability(bool flag_n, bool flag_x,
+ uint8_t max_sid_depth);
+struct pcep_object_tlv_of_list *
+pcep_tlv_create_of_list(double_linked_list *of_list);
+
+/*
+ * LSP Object TLVs
+ */
+
+struct pcep_object_tlv_ipv4_lsp_identifier *
+pcep_tlv_create_ipv4_lsp_identifiers(struct in_addr *ipv4_tunnel_sender,
+ struct in_addr *ipv4_tunnel_endpoint,
+ uint16_t lsp_id, uint16_t tunnel_id,
+ struct in_addr *extended_tunnel_id);
+struct pcep_object_tlv_ipv6_lsp_identifier *
+pcep_tlv_create_ipv6_lsp_identifiers(struct in6_addr *ipv6_tunnel_sender,
+ struct in6_addr *extended_tunnel_id,
+ uint16_t lsp_id, uint16_t tunnel_id,
+ struct in6_addr *ipv6_tunnel_endpoint);
+/* symbolic_path_name_length should NOT include the null terminator and cannot
+ * be zero */
+struct pcep_object_tlv_symbolic_path_name *
+pcep_tlv_create_symbolic_path_name(const char *symbolic_path_name,
+ uint16_t symbolic_path_name_length);
+struct pcep_object_tlv_lsp_error_code *
+pcep_tlv_create_lsp_error_code(enum pcep_tlv_lsp_error_codes lsp_error_code);
+struct pcep_object_tlv_rsvp_error_spec *
+pcep_tlv_create_rsvp_ipv4_error_spec(struct in_addr *error_node_ip,
+ uint8_t error_code, uint16_t error_value);
+struct pcep_object_tlv_rsvp_error_spec *
+pcep_tlv_create_rsvp_ipv6_error_spec(struct in6_addr *error_node_ip,
+ uint8_t error_code, uint16_t error_value);
+
+struct pcep_object_tlv_nopath_vector *
+pcep_tlv_create_nopath_vector(uint32_t error_code);
+struct pcep_object_tlv_vendor_info *
+pcep_tlv_create_vendor_info(uint32_t enterprise_number,
+ uint32_t enterprise_specific_info);
+
+struct pcep_object_tlv_arbitrary *
+pcep_tlv_create_tlv_arbitrary(const char *data, uint16_t data_length,
+ int tlv_id);
+/*
+ * SRPAG (SR Association Group) TLVs
+ */
+
+struct pcep_object_tlv_srpag_pol_id *
+pcep_tlv_create_srpag_pol_id_ipv4(uint32_t color, struct in_addr *ipv4);
+struct pcep_object_tlv_srpag_pol_id *
+pcep_tlv_create_srpag_pol_id_ipv6(uint32_t color, struct in6_addr *ipv6);
+struct pcep_object_tlv_srpag_pol_name *
+pcep_tlv_create_srpag_pol_name(const char *pol_name, uint16_t pol_name_length);
+struct pcep_object_tlv_srpag_cp_id *
+pcep_tlv_create_srpag_cp_id(uint8_t proto_origin, uint32_t asn,
+ struct in6_addr *in6_addr_with_mapped_ipv4,
+ uint32_t discriminator);
+struct pcep_object_tlv_srpag_cp_pref *
+pcep_tlv_create_srpag_cp_pref(uint32_t pref);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PCEP_TLVS_H_ */
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+/*
+ * Encoding and decoding for PCEP Object TLVs.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "pcep.h"
+#include "pcep_msg_encoding.h"
+#include "pcep_msg_tlvs.h"
+#include "pcep_utils_logging.h"
+#include "pcep_utils_memory.h"
+
+void write_tlv_header(struct pcep_object_tlv_header *tlv_hdr,
+ uint16_t tlv_length, struct pcep_versioning *versioning,
+ uint8_t *buf);
+void pcep_decode_tlv_hdr(const uint8_t *tlv_buf,
+ struct pcep_object_tlv_header *tlv_hdr);
+
+/*
+ * forward declarations for initialize_tlv_encoders()
+ */
+uint16_t pcep_encode_tlv_no_path_vector(struct pcep_object_tlv_header *tlv,
+ struct pcep_versioning *versioning,
+ uint8_t *tlv_body_buf);
+uint16_t
+pcep_encode_tlv_stateful_pce_capability(struct pcep_object_tlv_header *tlv,
+ struct pcep_versioning *versioning,
+ uint8_t *tlv_body_buf);
+uint16_t pcep_encode_tlv_symbolic_path_name(struct pcep_object_tlv_header *tlv,
+ struct pcep_versioning *versioning,
+ uint8_t *tlv_body_buf);
+uint16_t
+pcep_encode_tlv_ipv4_lsp_identifiers(struct pcep_object_tlv_header *tlv,
+ struct pcep_versioning *versioning,
+ uint8_t *tlv_body_buf);
+uint16_t
+pcep_encode_tlv_ipv6_lsp_identifiers(struct pcep_object_tlv_header *tlv,
+ struct pcep_versioning *versioning,
+ uint8_t *tlv_body_buf);
+uint16_t pcep_encode_tlv_lsp_error_code(struct pcep_object_tlv_header *tlv,
+ struct pcep_versioning *versioning,
+ uint8_t *tlv_body_buf);
+uint16_t pcep_encode_tlv_rsvp_error_spec(struct pcep_object_tlv_header *tlv,
+ struct pcep_versioning *versioning,
+ uint8_t *tlv_body_buf);
+uint16_t pcep_encode_tlv_lsp_db_version(struct pcep_object_tlv_header *tlv,
+ struct pcep_versioning *versioning,
+ uint8_t *tlv_body_buf);
+uint16_t pcep_encode_tlv_speaker_entity_id(struct pcep_object_tlv_header *tlv,
+ struct pcep_versioning *versioning,
+ uint8_t *tlv_body_buf);
+uint16_t pcep_encode_tlv_sr_pce_capability(struct pcep_object_tlv_header *tlv,
+ struct pcep_versioning *versioning,
+ uint8_t *tlv_body_buf);
+uint16_t pcep_encode_tlv_path_setup_type(struct pcep_object_tlv_header *tlv,
+ struct pcep_versioning *versioning,
+ uint8_t *tlv_body_buf);
+uint16_t
+pcep_encode_tlv_path_setup_type_capability(struct pcep_object_tlv_header *tlv,
+ struct pcep_versioning *versioning,
+ uint8_t *tlv_body_buf);
+uint16_t pcep_encode_tlv_pol_id(struct pcep_object_tlv_header *tlv,
+ struct pcep_versioning *versioning,
+ uint8_t *tlv_body_buf);
+uint16_t pcep_encode_tlv_pol_name(struct pcep_object_tlv_header *tlv,
+ struct pcep_versioning *versioning,
+ uint8_t *tlv_body_buf);
+uint16_t pcep_encode_tlv_cpath_id(struct pcep_object_tlv_header *tlv,
+ struct pcep_versioning *versioning,
+ uint8_t *tlv_body_buf);
+uint16_t pcep_encode_tlv_cpath_preference(struct pcep_object_tlv_header *tlv,
+ struct pcep_versioning *versioning,
+ uint8_t *tlv_body_buf);
+uint16_t pcep_encode_tlv_vendor_info(struct pcep_object_tlv_header *tlv,
+ struct pcep_versioning *versioning,
+ uint8_t *tlv_body_buf);
+uint16_t pcep_encode_tlv_arbitrary(struct pcep_object_tlv_header *tlv,
+ struct pcep_versioning *versioning,
+ uint8_t *tlv_body_buf);
+uint16_t pcep_encode_tlv_of_list(struct pcep_object_tlv_header *tlv,
+ struct pcep_versioning *versioning,
+ uint8_t *tlv_body_buf);
+typedef uint16_t (*tlv_encoder_funcptr)(struct pcep_object_tlv_header *,
+ struct pcep_versioning *versioning,
+ uint8_t *tlv_body_buf);
+
+#define MAX_TLV_ENCODER_INDEX 65533 + 1 // 65
+
+#define PCEP_TLV_ENCODERS_ARGS \
+ struct pcep_object_tlv_header *, struct pcep_versioning *versioning, \
+ uint8_t *tlv_body_buf
+uint16_t (*const tlv_encoders[MAX_TLV_ENCODER_INDEX])(
+ PCEP_TLV_ENCODERS_ARGS) = {
+ [PCEP_OBJ_TLV_TYPE_NO_PATH_VECTOR] = pcep_encode_tlv_no_path_vector,
+ [PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY] =
+ pcep_encode_tlv_stateful_pce_capability,
+ [PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME] =
+ pcep_encode_tlv_symbolic_path_name,
+ [PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS] =
+ pcep_encode_tlv_ipv4_lsp_identifiers,
+ [PCEP_OBJ_TLV_TYPE_IPV6_LSP_IDENTIFIERS] =
+ pcep_encode_tlv_ipv6_lsp_identifiers,
+ [PCEP_OBJ_TLV_TYPE_LSP_ERROR_CODE] = pcep_encode_tlv_lsp_error_code,
+ [PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC] = pcep_encode_tlv_rsvp_error_spec,
+ [PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION] = pcep_encode_tlv_lsp_db_version,
+ [PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID] =
+ pcep_encode_tlv_speaker_entity_id,
+ [PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY] =
+ pcep_encode_tlv_sr_pce_capability,
+ [PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE] = pcep_encode_tlv_path_setup_type,
+ [PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY] =
+ pcep_encode_tlv_path_setup_type_capability,
+ [PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_ID] = pcep_encode_tlv_pol_id,
+ [PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_NAME] = pcep_encode_tlv_pol_name,
+ [PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_ID] = pcep_encode_tlv_cpath_id,
+ [PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_PREFERENCE] =
+ pcep_encode_tlv_cpath_preference,
+ [PCEP_OBJ_TLV_TYPE_VENDOR_INFO] = pcep_encode_tlv_vendor_info,
+ [PCEP_OBJ_TLV_TYPE_ARBITRARY] = pcep_encode_tlv_arbitrary,
+ [PCEP_OBJ_TLV_TYPE_OBJECTIVE_FUNCTION_LIST] = pcep_encode_tlv_of_list,
+};
+/*
+ * forward declarations for initialize_tlv_decoders()
+ */
+struct pcep_object_tlv_header *
+pcep_decode_tlv_no_path_vector(struct pcep_object_tlv_header *tlv_hdr,
+ const uint8_t *tlv_body_buf);
+struct pcep_object_tlv_header *
+pcep_decode_tlv_stateful_pce_capability(struct pcep_object_tlv_header *tlv_hdr,
+ const uint8_t *tlv_body_buf);
+struct pcep_object_tlv_header *
+pcep_decode_tlv_symbolic_path_name(struct pcep_object_tlv_header *tlv_hdr,
+ const uint8_t *tlv_body_buf);
+struct pcep_object_tlv_header *
+pcep_decode_tlv_ipv4_lsp_identifiers(struct pcep_object_tlv_header *tlv_hdr,
+ const uint8_t *tlv_body_buf);
+struct pcep_object_tlv_header *
+pcep_decode_tlv_ipv6_lsp_identifiers(struct pcep_object_tlv_header *tlv_hdr,
+ const uint8_t *tlv_body_buf);
+struct pcep_object_tlv_header *
+pcep_decode_tlv_lsp_error_code(struct pcep_object_tlv_header *tlv_hdr,
+ const uint8_t *tlv_body_buf);
+struct pcep_object_tlv_header *
+pcep_decode_tlv_rsvp_error_spec(struct pcep_object_tlv_header *tlv_hdr,
+ const uint8_t *tlv_body_buf);
+struct pcep_object_tlv_header *
+pcep_decode_tlv_lsp_db_version(struct pcep_object_tlv_header *tlv_hdr,
+ const uint8_t *tlv_body_buf);
+struct pcep_object_tlv_header *
+pcep_decode_tlv_speaker_entity_id(struct pcep_object_tlv_header *tlv_hdr,
+ const uint8_t *tlv_body_buf);
+struct pcep_object_tlv_header *
+pcep_decode_tlv_sr_pce_capability(struct pcep_object_tlv_header *tlv_hdr,
+ const uint8_t *tlv_body_buf);
+struct pcep_object_tlv_header *
+pcep_decode_tlv_path_setup_type(struct pcep_object_tlv_header *tlv_hdr,
+ const uint8_t *tlv_body_buf);
+struct pcep_object_tlv_header *pcep_decode_tlv_path_setup_type_capability(
+ struct pcep_object_tlv_header *tlv_hdr, const uint8_t *tlv_body_buf);
+struct pcep_object_tlv_header *
+pcep_decode_tlv_pol_id(struct pcep_object_tlv_header *tlv_hdr,
+ const uint8_t *tlv_body_buf);
+struct pcep_object_tlv_header *
+pcep_decode_tlv_pol_name(struct pcep_object_tlv_header *tlv_hdr,
+ const uint8_t *tlv_body_buf);
+struct pcep_object_tlv_header *
+pcep_decode_tlv_cpath_id(struct pcep_object_tlv_header *tlv_hdr,
+ const uint8_t *tlv_body_buf);
+struct pcep_object_tlv_header *
+pcep_decode_tlv_cpath_preference(struct pcep_object_tlv_header *tlv_hdr,
+ const uint8_t *tlv_body_buf);
+struct pcep_object_tlv_header *
+pcep_decode_tlv_vendor_info(struct pcep_object_tlv_header *tlv_hdr,
+ const uint8_t *tlv_body_buf);
+struct pcep_object_tlv_header *
+pcep_decode_tlv_arbitrary(struct pcep_object_tlv_header *tlv_hdr,
+ const uint8_t *tlv_body_buf);
+struct pcep_object_tlv_header *
+pcep_decode_tlv_of_list(struct pcep_object_tlv_header *tlv_hdr,
+ const uint8_t *tlv_body_buf);
+typedef struct pcep_object_tlv_header *(*tlv_decoder_funcptr)(
+ struct pcep_object_tlv_header *tlv_hdr, const uint8_t *tlv_body_buf);
+
+// tlv_decoder_funcptr tlv_decoders[MAX_TLV_ENCODER_INDEX];
+
+#define PCEP_TLV_DECODERS_ARGS \
+ struct pcep_object_tlv_header *tlv_hdr, const uint8_t *tlv_body_buf
+
+struct pcep_object_tlv_header *(*const tlv_decoders[MAX_TLV_ENCODER_INDEX])(
+ PCEP_TLV_DECODERS_ARGS) = {
+ [PCEP_OBJ_TLV_TYPE_NO_PATH_VECTOR] = pcep_decode_tlv_no_path_vector,
+ [PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY] =
+ pcep_decode_tlv_stateful_pce_capability,
+ [PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME] =
+ pcep_decode_tlv_symbolic_path_name,
+ [PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS] =
+ pcep_decode_tlv_ipv4_lsp_identifiers,
+ [PCEP_OBJ_TLV_TYPE_IPV6_LSP_IDENTIFIERS] =
+ pcep_decode_tlv_ipv6_lsp_identifiers,
+ [PCEP_OBJ_TLV_TYPE_LSP_ERROR_CODE] = pcep_decode_tlv_lsp_error_code,
+ [PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC] = pcep_decode_tlv_rsvp_error_spec,
+ [PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION] = pcep_decode_tlv_lsp_db_version,
+ [PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID] =
+ pcep_decode_tlv_speaker_entity_id,
+ [PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY] =
+ pcep_decode_tlv_sr_pce_capability,
+ [PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE] = pcep_decode_tlv_path_setup_type,
+ [PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY] =
+ pcep_decode_tlv_path_setup_type_capability,
+ [PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_ID] = pcep_decode_tlv_pol_id,
+ [PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_NAME] = pcep_decode_tlv_pol_name,
+ [PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_ID] = pcep_decode_tlv_cpath_id,
+ [PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_PREFERENCE] =
+ pcep_decode_tlv_cpath_preference,
+ [PCEP_OBJ_TLV_TYPE_VENDOR_INFO] = pcep_decode_tlv_vendor_info,
+ [PCEP_OBJ_TLV_TYPE_ARBITRARY] = pcep_decode_tlv_arbitrary,
+ [PCEP_OBJ_TLV_TYPE_OBJECTIVE_FUNCTION_LIST] = pcep_decode_tlv_of_list,
+};
+
+static void initialize_tlv_coders()
+{
+ static bool initialized = false;
+
+ if (initialized == true) {
+ return;
+ }
+
+ initialized = true;
+
+ /* Encoders */
+ /*
+ memset(tlv_encoders, 0, sizeof(tlv_encoder_funcptr) *
+ MAX_TLV_ENCODER_INDEX); tlv_encoders[PCEP_OBJ_TLV_TYPE_NO_PATH_VECTOR] =
+ pcep_encode_tlv_no_path_vector;
+ tlv_encoders[PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY] =
+ pcep_encode_tlv_stateful_pce_capability;
+ tlv_encoders[PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME] =
+ pcep_encode_tlv_symbolic_path_name;
+ tlv_encoders[PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS] =
+ pcep_encode_tlv_ipv4_lsp_identifiers;
+ tlv_encoders[PCEP_OBJ_TLV_TYPE_IPV6_LSP_IDENTIFIERS] =
+ pcep_encode_tlv_ipv6_lsp_identifiers;
+ tlv_encoders[PCEP_OBJ_TLV_TYPE_LSP_ERROR_CODE] =
+ pcep_encode_tlv_lsp_error_code;
+ tlv_encoders[PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC] =
+ pcep_encode_tlv_rsvp_error_spec;
+ tlv_encoders[PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION] =
+ pcep_encode_tlv_lsp_db_version;
+ tlv_encoders[PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID] =
+ pcep_encode_tlv_speaker_entity_id;
+ tlv_encoders[PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY] =
+ pcep_encode_tlv_sr_pce_capability;
+ tlv_encoders[PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE] =
+ pcep_encode_tlv_path_setup_type;
+ tlv_encoders[PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY] =
+ pcep_encode_tlv_path_setup_type_capability;
+ tlv_encoders[PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_ID] =
+ pcep_encode_tlv_pol_id;
+ tlv_encoders[PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_NAME] =
+ pcep_encode_tlv_pol_name;
+ tlv_encoders[PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_ID] =
+ pcep_encode_tlv_cpath_id;
+ tlv_encoders[PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_PREFERENCE] =
+ pcep_encode_tlv_cpath_preference;
+ tlv_encoders[PCEP_OBJ_TLV_TYPE_VENDOR_INFO] =
+ pcep_encode_tlv_vendor_info; tlv_encoders[PCEP_OBJ_TLV_TYPE_ARBITRARY] =
+ pcep_encode_tlv_arbitrary;
+ tlv_encoders[PCEP_OBJ_TLV_TYPE_OBJECTIVE_FUNCTION_LIST] =
+ pcep_encode_tlv_of_list;
+ */
+
+ /* Decoders */
+ /*
+ memset(tlv_decoders, 0, sizeof(tlv_decoder_funcptr) *
+ MAX_TLV_ENCODER_INDEX); tlv_decoders[PCEP_OBJ_TLV_TYPE_NO_PATH_VECTOR] =
+ pcep_decode_tlv_no_path_vector;
+ tlv_decoders[PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY] =
+ pcep_decode_tlv_stateful_pce_capability;
+ tlv_decoders[PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME] =
+ pcep_decode_tlv_symbolic_path_name;
+ tlv_decoders[PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS] =
+ pcep_decode_tlv_ipv4_lsp_identifiers;
+ tlv_decoders[PCEP_OBJ_TLV_TYPE_IPV6_LSP_IDENTIFIERS] =
+ pcep_decode_tlv_ipv6_lsp_identifiers;
+ tlv_decoders[PCEP_OBJ_TLV_TYPE_LSP_ERROR_CODE] =
+ pcep_decode_tlv_lsp_error_code;
+ tlv_decoders[PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC] =
+ pcep_decode_tlv_rsvp_error_spec;
+ tlv_decoders[PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION] =
+ pcep_decode_tlv_lsp_db_version;
+ tlv_decoders[PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID] =
+ pcep_decode_tlv_speaker_entity_id;
+ tlv_decoders[PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY] =
+ pcep_decode_tlv_sr_pce_capability;
+ tlv_decoders[PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE] =
+ pcep_decode_tlv_path_setup_type;
+ tlv_decoders[PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY] =
+ pcep_decode_tlv_path_setup_type_capability;
+ tlv_decoders[PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_ID] =
+ pcep_decode_tlv_pol_id;
+ tlv_decoders[PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_NAME] =
+ pcep_decode_tlv_pol_name;
+ tlv_decoders[PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_ID] =
+ pcep_decode_tlv_cpath_id;
+ tlv_decoders[PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_PREFERENCE] =
+ pcep_decode_tlv_cpath_preference;
+ tlv_decoders[PCEP_OBJ_TLV_TYPE_VENDOR_INFO] =
+ pcep_decode_tlv_vendor_info; tlv_decoders[PCEP_OBJ_TLV_TYPE_ARBITRARY] =
+ pcep_decode_tlv_arbitrary;
+ tlv_decoders[PCEP_OBJ_TLV_TYPE_OBJECTIVE_FUNCTION_LIST] =
+ pcep_decode_tlv_of_list;
+ */
+}
+
+uint16_t pcep_encode_tlv(struct pcep_object_tlv_header *tlv_hdr,
+ struct pcep_versioning *versioning, uint8_t *buf)
+{
+ initialize_tlv_coders();
+
+ if (tlv_hdr->type >= MAX_TLV_ENCODER_INDEX) {
+ pcep_log(LOG_INFO,
+ "%s: Cannot encode unknown Object class [%d]",
+ __func__, tlv_hdr->type);
+ return 0;
+ }
+
+ tlv_encoder_funcptr tlv_encoder = tlv_encoders[tlv_hdr->type];
+ if (tlv_encoder == NULL) {
+ pcep_log(LOG_INFO,
+ "%s: No object encoder found for Object class [%d]",
+ __func__, tlv_hdr->type);
+ return 0;
+ }
+
+ /* Notice: The length in the TLV header does not include the TLV header,
+ * so the length returned from the tlv_encoder() is only the TLV body.
+ */
+ uint16_t tlv_length =
+ tlv_encoder(tlv_hdr, versioning, buf + TLV_HEADER_LENGTH);
+ write_tlv_header(tlv_hdr, tlv_length, versioning, buf);
+ tlv_hdr->encoded_tlv = buf;
+ tlv_hdr->encoded_tlv_length = tlv_length;
+
+ return normalize_pcep_tlv_length(tlv_length + TLV_HEADER_LENGTH);
+}
+
+/* TLV Header format
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Type (2 bytes) | Length (2 bytes) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Value (Variable) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+void write_tlv_header(struct pcep_object_tlv_header *tlv_hdr,
+ uint16_t tlv_length, struct pcep_versioning *versioning,
+ uint8_t *buf)
+{
+ (void)versioning;
+ uint16_t *uint16_ptr = (uint16_t *)buf;
+ uint16_ptr[0] = htons(tlv_hdr->type);
+ uint16_ptr[1] = htons(tlv_length);
+}
+
+/*
+ * Functions to encode TLVs
+ */
+
+uint16_t pcep_encode_tlv_no_path_vector(struct pcep_object_tlv_header *tlv,
+ struct pcep_versioning *versioning,
+ uint8_t *tlv_body_buf)
+{
+ (void)versioning;
+ struct pcep_object_tlv_nopath_vector *nopath_tlv =
+ (struct pcep_object_tlv_nopath_vector *)tlv;
+ uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf;
+ *uint32_ptr = htonl(nopath_tlv->error_code);
+
+ return LENGTH_1WORD;
+}
+
+uint16_t
+pcep_encode_tlv_stateful_pce_capability(struct pcep_object_tlv_header *tlv,
+ struct pcep_versioning *versioning,
+ uint8_t *tlv_body_buf)
+{
+ (void)versioning;
+ struct pcep_object_tlv_stateful_pce_capability *spc_tlv =
+ (struct pcep_object_tlv_stateful_pce_capability *)tlv;
+ tlv_body_buf[3] =
+ ((spc_tlv->flag_f_triggered_initial_sync == true
+ ? TLV_STATEFUL_PCE_CAP_FLAG_F
+ : 0x00)
+ | (spc_tlv->flag_d_delta_lsp_sync == true
+ ? TLV_STATEFUL_PCE_CAP_FLAG_D
+ : 0x00)
+ | (spc_tlv->flag_t_triggered_resync == true
+ ? TLV_STATEFUL_PCE_CAP_FLAG_T
+ : 0x00)
+ | (spc_tlv->flag_i_lsp_instantiation_capability == true
+ ? TLV_STATEFUL_PCE_CAP_FLAG_I
+ : 0x00)
+ | (spc_tlv->flag_s_include_db_version == true
+ ? TLV_STATEFUL_PCE_CAP_FLAG_S
+ : 0x00)
+ | (spc_tlv->flag_u_lsp_update_capability == true
+ ? TLV_STATEFUL_PCE_CAP_FLAG_U
+ : 0x00));
+
+ return LENGTH_1WORD;
+}
+
+uint16_t pcep_encode_tlv_symbolic_path_name(struct pcep_object_tlv_header *tlv,
+ struct pcep_versioning *versioning,
+ uint8_t *tlv_body_buf)
+{
+ (void)versioning;
+ struct pcep_object_tlv_symbolic_path_name *spn_tlv =
+ (struct pcep_object_tlv_symbolic_path_name *)tlv;
+ memcpy(tlv_body_buf, spn_tlv->symbolic_path_name,
+ spn_tlv->symbolic_path_name_length);
+
+ return spn_tlv->symbolic_path_name_length;
+}
+
+uint16_t
+pcep_encode_tlv_ipv4_lsp_identifiers(struct pcep_object_tlv_header *tlv,
+ struct pcep_versioning *versioning,
+ uint8_t *tlv_body_buf)
+{
+ (void)versioning;
+ struct pcep_object_tlv_ipv4_lsp_identifier *ipv4_lsp =
+ (struct pcep_object_tlv_ipv4_lsp_identifier *)tlv;
+ uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf;
+ uint32_ptr[0] = ipv4_lsp->ipv4_tunnel_sender.s_addr;
+ /* uint32_t[1] is lsp_id and tunnel_id, below */
+ uint32_ptr[2] = ipv4_lsp->extended_tunnel_id.s_addr;
+ uint32_ptr[3] = ipv4_lsp->ipv4_tunnel_endpoint.s_addr;
+
+ uint16_t *uint16_ptr = (uint16_t *)(tlv_body_buf + LENGTH_1WORD);
+ uint16_ptr[0] = htons(ipv4_lsp->lsp_id);
+ uint16_ptr[1] = htons(ipv4_lsp->tunnel_id);
+
+ return LENGTH_4WORDS;
+}
+
+uint16_t
+pcep_encode_tlv_ipv6_lsp_identifiers(struct pcep_object_tlv_header *tlv,
+ struct pcep_versioning *versioning,
+ uint8_t *tlv_body_buf)
+{
+ (void)versioning;
+ struct pcep_object_tlv_ipv6_lsp_identifier *ipv6_lsp =
+ (struct pcep_object_tlv_ipv6_lsp_identifier *)tlv;
+ uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf;
+ encode_ipv6(&ipv6_lsp->ipv6_tunnel_sender, uint32_ptr);
+ encode_ipv6(&ipv6_lsp->extended_tunnel_id, uint32_ptr + 5);
+ encode_ipv6(&ipv6_lsp->ipv6_tunnel_endpoint, uint32_ptr + 9);
+
+ uint16_t *uint16_ptr = (uint16_t *)(tlv_body_buf + LENGTH_4WORDS);
+ uint16_ptr[0] = htons(ipv6_lsp->lsp_id);
+ uint16_ptr[1] = htons(ipv6_lsp->tunnel_id);
+
+ return LENGTH_13WORDS;
+}
+
+uint16_t pcep_encode_tlv_lsp_error_code(struct pcep_object_tlv_header *tlv,
+ struct pcep_versioning *versioning,
+ uint8_t *tlv_body_buf)
+{
+ (void)versioning;
+ struct pcep_object_tlv_lsp_error_code *lsp_error_tlv =
+ (struct pcep_object_tlv_lsp_error_code *)tlv;
+ uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf;
+ *uint32_ptr = htonl(lsp_error_tlv->lsp_error_code);
+
+ return LENGTH_1WORD;
+}
+
+uint16_t pcep_encode_tlv_rsvp_error_spec(struct pcep_object_tlv_header *tlv,
+ struct pcep_versioning *versioning,
+ uint8_t *tlv_body_buf)
+{
+ /* Same decode tlv function for both types:
+ pcep_create_tlv_rsvp_ipv4_error_spec(tlv);
+ pcep_create_tlv_rsvp_ipv6_error_spec(tlv); */
+
+ /* RSVP Object Header
+ *
+ * 0 1 2 3
+ * +-------------+-------------+-------------+-------------+
+ * | Length (bytes) | Class-Num | C-Type |
+ * +-------------+-------------+-------------+-------------+
+ * | |
+ * // (Object contents) //
+ * | |
+ * +-------------+-------------+-------------+-------------+
+ *
+ * IPv4 ERROR_SPEC object: Class = 6, C-Type = 1
+ * +-------------+-------------+-------------+-------------+
+ * | IPv4 Error Node Address (4 bytes) |
+ * +-------------+-------------+-------------+-------------+
+ * | Flags | Error Code | Error Value |
+ * +-------------+-------------+-------------+-------------+
+ *
+ * IPv6 ERROR_SPEC object: Class = 6, C-Type = 2
+ * +-------------+-------------+-------------+-------------+
+ * | IPv6 Error Node Address (16 bytes) |
+ * +-------------+-------------+-------------+-------------+
+ * | Flags | Error Code | Error Value |
+ * +-------------+-------------+-------------+-------------+
+ */
+
+ (void)versioning;
+ struct pcep_object_tlv_rsvp_error_spec *rsvp_hdr =
+ (struct pcep_object_tlv_rsvp_error_spec *)tlv;
+ tlv_body_buf[2] = rsvp_hdr->class_num;
+ tlv_body_buf[3] = rsvp_hdr->c_type;
+
+ uint16_t *length_ptr = (uint16_t *)tlv_body_buf;
+ uint32_t *uint32_ptr = (uint32_t *)(tlv_body_buf + LENGTH_1WORD);
+ if (rsvp_hdr->c_type == RSVP_ERROR_SPEC_IPV4_CTYPE) {
+ *length_ptr = htons(LENGTH_3WORDS);
+ *uint32_ptr =
+ rsvp_hdr->error_spec_ip.ipv4_error_node_address.s_addr;
+ tlv_body_buf[LENGTH_2WORDS + 1] = rsvp_hdr->error_code;
+ uint16_t *uint16_ptr =
+ (uint16_t *)(tlv_body_buf + LENGTH_2WORDS + 2);
+ *uint16_ptr = htons(rsvp_hdr->error_value);
+
+ return LENGTH_3WORDS;
+ } else if (rsvp_hdr->c_type == RSVP_ERROR_SPEC_IPV6_CTYPE) {
+ *length_ptr = htons(LENGTH_6WORDS);
+ encode_ipv6(&rsvp_hdr->error_spec_ip.ipv6_error_node_address,
+ uint32_ptr);
+ tlv_body_buf[LENGTH_5WORDS + 1] = rsvp_hdr->error_code;
+ uint16_t *uint16_ptr =
+ (uint16_t *)(tlv_body_buf + LENGTH_5WORDS + 2);
+ *uint16_ptr = htons(rsvp_hdr->error_value);
+
+ return LENGTH_6WORDS;
+ }
+
+ return 0;
+}
+
+uint16_t pcep_encode_tlv_lsp_db_version(struct pcep_object_tlv_header *tlv,
+ struct pcep_versioning *versioning,
+ uint8_t *tlv_body_buf)
+{
+ (void)versioning;
+ struct pcep_object_tlv_lsp_db_version *lsp_db_ver =
+ (struct pcep_object_tlv_lsp_db_version *)tlv;
+ *((uint64_t *)tlv_body_buf) = htobe64(lsp_db_ver->lsp_db_version);
+
+ return LENGTH_2WORDS;
+}
+
+uint16_t pcep_encode_tlv_speaker_entity_id(struct pcep_object_tlv_header *tlv,
+ struct pcep_versioning *versioning,
+ uint8_t *tlv_body_buf)
+{
+ (void)versioning;
+ struct pcep_object_tlv_speaker_entity_identifier *speaker_id =
+ (struct pcep_object_tlv_speaker_entity_identifier *)tlv;
+ if (speaker_id->speaker_entity_id_list == NULL) {
+ return 0;
+ }
+
+ int index = 0;
+ uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf;
+ double_linked_list_node *node =
+ speaker_id->speaker_entity_id_list->head;
+ for (; node != NULL; node = node->next_node) {
+ uint32_ptr[index++] = htonl(*((uint32_t *)node->data));
+ }
+
+ return speaker_id->speaker_entity_id_list->num_entries * LENGTH_1WORD;
+}
+
+uint16_t pcep_encode_tlv_sr_pce_capability(struct pcep_object_tlv_header *tlv,
+ struct pcep_versioning *versioning,
+ uint8_t *tlv_body_buf)
+{
+ (void)versioning;
+ struct pcep_object_tlv_sr_pce_capability *sr_pce_cap =
+ (struct pcep_object_tlv_sr_pce_capability *)tlv;
+ tlv_body_buf[2] =
+ ((sr_pce_cap->flag_n == true ? TLV_SR_PCE_CAP_FLAG_N : 0x00)
+ | (sr_pce_cap->flag_x == true ? TLV_SR_PCE_CAP_FLAG_X : 0x00));
+ tlv_body_buf[3] = sr_pce_cap->max_sid_depth;
+
+ return LENGTH_1WORD;
+}
+
+uint16_t pcep_encode_tlv_path_setup_type(struct pcep_object_tlv_header *tlv,
+ struct pcep_versioning *versioning,
+ uint8_t *tlv_body_buf)
+{
+ (void)versioning;
+ struct pcep_object_tlv_path_setup_type *pst =
+ (struct pcep_object_tlv_path_setup_type *)tlv;
+ tlv_body_buf[3] = pst->path_setup_type;
+
+ return LENGTH_1WORD;
+}
+
+uint16_t
+pcep_encode_tlv_path_setup_type_capability(struct pcep_object_tlv_header *tlv,
+ struct pcep_versioning *versioning,
+ uint8_t *tlv_body_buf)
+{
+ (void)versioning;
+ struct pcep_object_tlv_path_setup_type_capability *pst_cap =
+ (struct pcep_object_tlv_path_setup_type_capability *)tlv;
+ if (pst_cap->pst_list == NULL) {
+ return 0;
+ }
+
+ tlv_body_buf[3] = pst_cap->pst_list->num_entries;
+
+ /* Index past the reserved and NumPSTs fields */
+ int index = 4;
+ double_linked_list_node *node = pst_cap->pst_list->head;
+ for (; node != NULL; node = node->next_node) {
+ tlv_body_buf[index++] = *((uint8_t *)node->data);
+ }
+
+ uint16_t pst_length = normalize_pcep_tlv_length(
+ LENGTH_1WORD + pst_cap->pst_list->num_entries);
+ if (pst_cap->sub_tlv_list == NULL) {
+ return pst_length;
+ }
+
+ /* Any padding used for the PSTs should not be included in the tlv
+ * header length */
+ index = normalize_pcep_tlv_length(index);
+ uint16_t sub_tlvs_length = 0;
+ node = pst_cap->sub_tlv_list->head;
+ for (; node != NULL; node = node->next_node) {
+ struct pcep_object_tlv_header *sub_tlv =
+ (struct pcep_object_tlv_header *)node->data;
+ uint16_t sub_tlv_length = pcep_encode_tlv(sub_tlv, versioning,
+ tlv_body_buf + index);
+ index += sub_tlv_length;
+ sub_tlvs_length += sub_tlv_length;
+ }
+
+ return sub_tlvs_length + pst_length;
+}
+uint16_t pcep_encode_tlv_pol_id(struct pcep_object_tlv_header *tlv,
+ struct pcep_versioning *versioning,
+ uint8_t *tlv_body_buf)
+{
+ (void)versioning;
+ uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf;
+ struct pcep_object_tlv_srpag_pol_id *ipv4 =
+ (struct pcep_object_tlv_srpag_pol_id *)tlv;
+ if (ipv4->is_ipv4) {
+ uint32_ptr[0] = htonl(ipv4->color);
+ uint32_ptr[1] = ipv4->end_point.ipv4.s_addr;
+ return LENGTH_2WORDS;
+ } else {
+ struct pcep_object_tlv_srpag_pol_id *ipv6 =
+ (struct pcep_object_tlv_srpag_pol_id *)tlv;
+ uint32_ptr[0] = htonl(ipv6->color);
+ encode_ipv6(&ipv6->end_point.ipv6, &uint32_ptr[1]);
+ return LENGTH_5WORDS;
+ }
+}
+
+uint16_t pcep_encode_tlv_pol_name(struct pcep_object_tlv_header *tlv,
+ struct pcep_versioning *versioning,
+ uint8_t *tlv_body_buf)
+{
+ (void)versioning;
+ struct pcep_object_tlv_srpag_pol_name *pol_name_tlv =
+ (struct pcep_object_tlv_srpag_pol_name *)tlv;
+ memcpy(tlv_body_buf, pol_name_tlv->name, pol_name_tlv->name_length);
+
+ return normalize_pcep_tlv_length(pol_name_tlv->name_length);
+}
+
+uint16_t pcep_encode_tlv_cpath_id(struct pcep_object_tlv_header *tlv,
+ struct pcep_versioning *versioning,
+ uint8_t *tlv_body_buf)
+{
+ (void)versioning;
+ struct pcep_object_tlv_srpag_cp_id *cpath_id_tlv =
+ (struct pcep_object_tlv_srpag_cp_id *)tlv;
+
+ uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf;
+ tlv_body_buf[0] = cpath_id_tlv->proto;
+ uint32_ptr[1] = htonl(cpath_id_tlv->orig_asn);
+ encode_ipv6(&cpath_id_tlv->orig_addres, &uint32_ptr[2]);
+ uint32_ptr[6] = htonl(cpath_id_tlv->discriminator);
+
+ return sizeof(cpath_id_tlv->proto) + sizeof(cpath_id_tlv->orig_asn)
+ + sizeof(cpath_id_tlv->orig_addres)
+ + sizeof(cpath_id_tlv->discriminator);
+}
+
+uint16_t pcep_encode_tlv_cpath_preference(struct pcep_object_tlv_header *tlv,
+ struct pcep_versioning *versioning,
+ uint8_t *tlv_body_buf)
+{
+ (void)versioning;
+ struct pcep_object_tlv_srpag_cp_pref *cpath_pref_tlv =
+ (struct pcep_object_tlv_srpag_cp_pref *)tlv;
+
+ uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf;
+ uint32_ptr[0] = htonl(cpath_pref_tlv->preference);
+
+ return sizeof(cpath_pref_tlv->preference);
+}
+
+uint16_t pcep_encode_tlv_vendor_info(struct pcep_object_tlv_header *tlv,
+ struct pcep_versioning *versioning,
+ uint8_t *tlv_body_buf)
+{
+ (void)versioning;
+ struct pcep_object_tlv_vendor_info *vendor_info =
+ (struct pcep_object_tlv_vendor_info *)tlv;
+
+ uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf;
+ uint32_ptr[0] = htonl(vendor_info->enterprise_number);
+ uint32_ptr[1] = htonl(vendor_info->enterprise_specific_info);
+
+ return LENGTH_2WORDS;
+}
+
+uint16_t pcep_encode_tlv_arbitrary(struct pcep_object_tlv_header *tlv,
+ struct pcep_versioning *versioning,
+ uint8_t *tlv_body_buf)
+{
+ (void)versioning;
+ struct pcep_object_tlv_arbitrary *tlv_arbitrary =
+ (struct pcep_object_tlv_arbitrary *)tlv;
+ memcpy(tlv_body_buf, tlv_arbitrary->data, tlv_arbitrary->data_length);
+ tlv->type = tlv_arbitrary->arbitraty_type;
+
+ return tlv_arbitrary->data_length;
+}
+
+uint16_t pcep_encode_tlv_of_list(struct pcep_object_tlv_header *tlv,
+ struct pcep_versioning *versioning,
+ uint8_t *tlv_body_buf)
+{
+ (void)versioning;
+ struct pcep_object_tlv_of_list *of_list =
+ (struct pcep_object_tlv_of_list *)tlv;
+
+ if (of_list->of_list == NULL) {
+ return 0;
+ }
+
+ int index = 0;
+ double_linked_list_node *node = of_list->of_list->head;
+ while (node != NULL) {
+ uint16_t *of_code = (uint16_t *)node->data;
+ if (of_code == NULL) {
+ return 0;
+ }
+
+ uint16_t *uint16_ptr = (uint16_t *)(tlv_body_buf + index);
+ *uint16_ptr = *of_code;
+ index += 2;
+
+ node = node->next_node;
+ }
+
+ return of_list->of_list->num_entries * 2;
+}
+
+/*
+ * Decoding functions
+ */
+
+void pcep_decode_tlv_hdr(const uint8_t *tlv_buf,
+ struct pcep_object_tlv_header *tlv_hdr)
+{
+ memset(tlv_hdr, 0, sizeof(struct pcep_object_tlv_header));
+
+ uint16_t *uint16_ptr = (uint16_t *)tlv_buf;
+ tlv_hdr->type = ntohs(uint16_ptr[0]);
+ tlv_hdr->encoded_tlv_length = ntohs(uint16_ptr[1]);
+ tlv_hdr->encoded_tlv = tlv_buf;
+}
+
+struct pcep_object_tlv_header *pcep_decode_tlv(const uint8_t *tlv_buf)
+{
+ initialize_tlv_coders();
+
+ struct pcep_object_tlv_header tlv_hdr;
+ /* Only initializes and decodes the Object Header: class, type, flags,
+ * and length */
+ pcep_decode_tlv_hdr(tlv_buf, &tlv_hdr);
+
+ if (tlv_hdr.type >= MAX_TLV_ENCODER_INDEX) {
+ pcep_log(LOG_INFO, "%s: Cannot decode unknown TLV type [%d]",
+ __func__, tlv_hdr.type);
+ return NULL;
+ }
+
+ tlv_decoder_funcptr tlv_decoder = tlv_decoders[tlv_hdr.type];
+ if (tlv_decoder == NULL) {
+ pcep_log(LOG_INFO, "%s: No TLV decoder found for TLV type [%d]",
+ __func__, tlv_hdr.type);
+ return NULL;
+ }
+
+ return tlv_decoder(&tlv_hdr, tlv_buf + LENGTH_1WORD);
+}
+
+static struct pcep_object_tlv_header *
+common_tlv_create(struct pcep_object_tlv_header *hdr, uint16_t new_tlv_length)
+{
+ struct pcep_object_tlv_header *new_tlv =
+ pceplib_malloc(PCEPLIB_MESSAGES, new_tlv_length);
+ memset(new_tlv, 0, new_tlv_length);
+ memcpy(new_tlv, hdr, sizeof(struct pcep_object_tlv_header));
+
+ return new_tlv;
+}
+
+struct pcep_object_tlv_header *
+pcep_decode_tlv_no_path_vector(struct pcep_object_tlv_header *tlv_hdr,
+ const uint8_t *tlv_body_buf)
+{
+ struct pcep_object_tlv_nopath_vector *tlv =
+ (struct pcep_object_tlv_nopath_vector *)common_tlv_create(
+ tlv_hdr, sizeof(struct pcep_object_tlv_nopath_vector));
+
+ tlv->error_code = ntohl(*((uint32_t *)tlv_body_buf));
+
+ return (struct pcep_object_tlv_header *)tlv;
+}
+
+struct pcep_object_tlv_header *
+pcep_decode_tlv_stateful_pce_capability(struct pcep_object_tlv_header *tlv_hdr,
+ const uint8_t *tlv_body_buf)
+{
+ struct pcep_object_tlv_stateful_pce_capability *tlv =
+ (struct pcep_object_tlv_stateful_pce_capability *)
+ common_tlv_create(
+ tlv_hdr,
+ sizeof(struct
+ pcep_object_tlv_stateful_pce_capability));
+
+ tlv->flag_f_triggered_initial_sync =
+ (tlv_body_buf[3] & TLV_STATEFUL_PCE_CAP_FLAG_F);
+ tlv->flag_d_delta_lsp_sync =
+ (tlv_body_buf[3] & TLV_STATEFUL_PCE_CAP_FLAG_D);
+ tlv->flag_t_triggered_resync =
+ (tlv_body_buf[3] & TLV_STATEFUL_PCE_CAP_FLAG_T);
+ tlv->flag_i_lsp_instantiation_capability =
+ (tlv_body_buf[3] & TLV_STATEFUL_PCE_CAP_FLAG_I);
+ tlv->flag_s_include_db_version =
+ (tlv_body_buf[3] & TLV_STATEFUL_PCE_CAP_FLAG_S);
+ tlv->flag_u_lsp_update_capability =
+ (tlv_body_buf[3] & TLV_STATEFUL_PCE_CAP_FLAG_U);
+
+ return (struct pcep_object_tlv_header *)tlv;
+}
+
+struct pcep_object_tlv_header *
+pcep_decode_tlv_symbolic_path_name(struct pcep_object_tlv_header *tlv_hdr,
+ const uint8_t *tlv_body_buf)
+{
+ struct pcep_object_tlv_symbolic_path_name *tlv =
+ (struct pcep_object_tlv_symbolic_path_name *)common_tlv_create(
+ tlv_hdr,
+ sizeof(struct pcep_object_tlv_symbolic_path_name));
+
+ uint16_t length = tlv_hdr->encoded_tlv_length;
+ if (length > MAX_SYMBOLIC_PATH_NAME) {
+ /* TODO should we also reset the tlv_hdr->encoded_tlv_length ?
+ */
+ length = MAX_SYMBOLIC_PATH_NAME;
+ pcep_log(
+ LOG_INFO,
+ "%s: Decoding Symbolic Path Name TLV, truncate path name from [%d] to [%d].\",",
+ __func__, tlv_hdr->encoded_tlv_length,
+ MAX_SYMBOLIC_PATH_NAME);
+ }
+
+ tlv->symbolic_path_name_length = length;
+ memcpy(tlv->symbolic_path_name, tlv_body_buf, length);
+
+ return (struct pcep_object_tlv_header *)tlv;
+}
+
+struct pcep_object_tlv_header *
+pcep_decode_tlv_ipv4_lsp_identifiers(struct pcep_object_tlv_header *tlv_hdr,
+ const uint8_t *tlv_body_buf)
+{
+ struct pcep_object_tlv_ipv4_lsp_identifier *tlv =
+ (struct pcep_object_tlv_ipv4_lsp_identifier *)common_tlv_create(
+ tlv_hdr,
+ sizeof(struct pcep_object_tlv_ipv4_lsp_identifier));
+
+ uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf;
+ tlv->ipv4_tunnel_sender.s_addr = uint32_ptr[0];
+ /* uint32_t[1] is lsp_id and tunnel_id, below */
+ tlv->extended_tunnel_id.s_addr = uint32_ptr[2];
+ tlv->ipv4_tunnel_endpoint.s_addr = uint32_ptr[3];
+
+ uint16_t *uint16_ptr = (uint16_t *)(tlv_body_buf + LENGTH_1WORD);
+ tlv->lsp_id = ntohs(uint16_ptr[0]);
+ tlv->tunnel_id = ntohs(uint16_ptr[1]);
+
+ return (struct pcep_object_tlv_header *)tlv;
+}
+
+struct pcep_object_tlv_header *
+pcep_decode_tlv_ipv6_lsp_identifiers(struct pcep_object_tlv_header *tlv_hdr,
+ const uint8_t *tlv_body_buf)
+{
+ struct pcep_object_tlv_ipv6_lsp_identifier *tlv =
+ (struct pcep_object_tlv_ipv6_lsp_identifier *)common_tlv_create(
+ tlv_hdr,
+ sizeof(struct pcep_object_tlv_ipv6_lsp_identifier));
+
+ uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf;
+ decode_ipv6(uint32_ptr, &tlv->ipv6_tunnel_sender);
+ decode_ipv6(uint32_ptr + 5, &tlv->extended_tunnel_id);
+ decode_ipv6(uint32_ptr + 9, &tlv->ipv6_tunnel_endpoint);
+
+ uint16_t *uint16_ptr = (uint16_t *)(tlv_body_buf + LENGTH_4WORDS);
+ tlv->lsp_id = htons(uint16_ptr[0]);
+ tlv->tunnel_id = htons(uint16_ptr[1]);
+
+ return (struct pcep_object_tlv_header *)tlv;
+}
+
+struct pcep_object_tlv_header *
+pcep_decode_tlv_lsp_error_code(struct pcep_object_tlv_header *tlv_hdr,
+ const uint8_t *tlv_body_buf)
+{
+ struct pcep_object_tlv_lsp_error_code *tlv =
+ (struct pcep_object_tlv_lsp_error_code *)common_tlv_create(
+ tlv_hdr, sizeof(struct pcep_object_tlv_lsp_error_code));
+
+ tlv->lsp_error_code = ntohl(*((uint32_t *)tlv_body_buf));
+
+ return (struct pcep_object_tlv_header *)tlv;
+}
+
+struct pcep_object_tlv_header *
+pcep_decode_tlv_rsvp_error_spec(struct pcep_object_tlv_header *tlv_hdr,
+ const uint8_t *tlv_body_buf)
+{
+ uint8_t class_num = tlv_body_buf[2];
+ uint8_t ctype = tlv_body_buf[3];
+
+ if (class_num != RSVP_ERROR_SPEC_CLASS_NUM) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Decoding RSVP Error Spec TLV, unknown class num [%d]",
+ __func__, class_num);
+ return NULL;
+ }
+
+ if (ctype != RSVP_ERROR_SPEC_IPV4_CTYPE
+ && ctype != RSVP_ERROR_SPEC_IPV6_CTYPE) {
+ pcep_log(LOG_INFO,
+ "%s: Decoding RSVP Error Spec TLV, unknown ctype [%d]",
+ __func__, ctype);
+ return NULL;
+ }
+
+ struct pcep_object_tlv_rsvp_error_spec *tlv =
+ (struct pcep_object_tlv_rsvp_error_spec *)common_tlv_create(
+ tlv_hdr,
+ sizeof(struct pcep_object_tlv_rsvp_error_spec));
+
+ tlv->class_num = class_num;
+ tlv->c_type = ctype;
+
+ uint32_t *uint32_ptr = (uint32_t *)(tlv_body_buf + LENGTH_1WORD);
+ if (ctype == RSVP_ERROR_SPEC_IPV4_CTYPE) {
+ tlv->error_spec_ip.ipv4_error_node_address.s_addr = *uint32_ptr;
+ tlv->error_code = tlv_body_buf[LENGTH_2WORDS + 1];
+ tlv->error_value = ntohs(
+ *((uint16_t *)(tlv_body_buf + LENGTH_2WORDS + 2)));
+ } else /* RSVP_ERROR_SPEC_IPV6_CTYPE */
+ {
+ decode_ipv6(uint32_ptr,
+ &tlv->error_spec_ip.ipv6_error_node_address);
+ tlv->error_code = tlv_body_buf[LENGTH_5WORDS + 1];
+ tlv->error_value = ntohs(
+ *((uint16_t *)(tlv_body_buf + LENGTH_5WORDS + 2)));
+ }
+
+ return (struct pcep_object_tlv_header *)tlv;
+}
+
+struct pcep_object_tlv_header *
+pcep_decode_tlv_lsp_db_version(struct pcep_object_tlv_header *tlv_hdr,
+ const uint8_t *tlv_body_buf)
+{
+ struct pcep_object_tlv_lsp_db_version *tlv =
+ (struct pcep_object_tlv_lsp_db_version *)common_tlv_create(
+ tlv_hdr, sizeof(struct pcep_object_tlv_lsp_db_version));
+
+ tlv->lsp_db_version = be64toh(*((uint64_t *)tlv_body_buf));
+
+ return (struct pcep_object_tlv_header *)tlv;
+}
+
+struct pcep_object_tlv_header *
+pcep_decode_tlv_speaker_entity_id(struct pcep_object_tlv_header *tlv_hdr,
+ const uint8_t *tlv_body_buf)
+{
+ struct pcep_object_tlv_speaker_entity_identifier *tlv =
+ (struct pcep_object_tlv_speaker_entity_identifier *)
+ common_tlv_create(
+ tlv_hdr,
+ sizeof(struct
+ pcep_object_tlv_speaker_entity_identifier));
+
+ uint8_t num_entity_ids = tlv_hdr->encoded_tlv_length / LENGTH_1WORD;
+ if (num_entity_ids > MAX_ITERATIONS) {
+ num_entity_ids = MAX_ITERATIONS;
+ pcep_log(
+ LOG_INFO,
+ "%s: Decode Speaker Entity ID, truncating num entities from [%d] to [%d].",
+ __func__, num_entity_ids, MAX_ITERATIONS);
+ }
+
+ uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf;
+ tlv->speaker_entity_id_list = dll_initialize();
+ int i;
+ for (i = 0; i < num_entity_ids; i++) {
+ uint32_t *entity_id =
+ pceplib_malloc(PCEPLIB_MESSAGES, sizeof(uint32_t));
+ *entity_id = ntohl(uint32_ptr[i]);
+ dll_append(tlv->speaker_entity_id_list, entity_id);
+ }
+
+ return (struct pcep_object_tlv_header *)tlv;
+}
+
+struct pcep_object_tlv_header *
+pcep_decode_tlv_sr_pce_capability(struct pcep_object_tlv_header *tlv_hdr,
+ const uint8_t *tlv_body_buf)
+{
+ struct pcep_object_tlv_sr_pce_capability *tlv =
+ (struct pcep_object_tlv_sr_pce_capability *)common_tlv_create(
+ tlv_hdr,
+ sizeof(struct pcep_object_tlv_sr_pce_capability));
+
+ tlv->flag_n = (tlv_body_buf[2] & TLV_SR_PCE_CAP_FLAG_N);
+ tlv->flag_x = (tlv_body_buf[2] & TLV_SR_PCE_CAP_FLAG_X);
+ tlv->max_sid_depth = tlv_body_buf[3];
+
+ return (struct pcep_object_tlv_header *)tlv;
+}
+
+struct pcep_object_tlv_header *
+pcep_decode_tlv_path_setup_type(struct pcep_object_tlv_header *tlv_hdr,
+ const uint8_t *tlv_body_buf)
+{
+ struct pcep_object_tlv_path_setup_type *tlv =
+ (struct pcep_object_tlv_path_setup_type *)common_tlv_create(
+ tlv_hdr,
+ sizeof(struct pcep_object_tlv_path_setup_type));
+
+ tlv->path_setup_type = tlv_body_buf[3];
+
+ return (struct pcep_object_tlv_header *)tlv;
+}
+
+struct pcep_object_tlv_header *pcep_decode_tlv_path_setup_type_capability(
+ struct pcep_object_tlv_header *tlv_hdr, const uint8_t *tlv_body_buf)
+{
+ struct pcep_object_tlv_path_setup_type_capability *tlv =
+ (struct pcep_object_tlv_path_setup_type_capability *)
+ common_tlv_create(
+ tlv_hdr,
+ sizeof(struct
+ pcep_object_tlv_path_setup_type_capability));
+
+ uint8_t num_psts = tlv_body_buf[3];
+ if (num_psts > MAX_ITERATIONS) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Decode Path Setup Type Capability num PSTs [%d] exceeds MAX [%d] continuing anyways",
+ __func__, num_psts, MAX_ITERATIONS);
+ }
+
+ int i;
+ tlv->pst_list = dll_initialize();
+ for (i = 0; i < num_psts; i++) {
+ uint8_t *pst =
+ pceplib_malloc(PCEPLIB_MESSAGES, sizeof(uint8_t));
+ *pst = tlv_body_buf[i + LENGTH_1WORD];
+ dll_append(tlv->pst_list, pst);
+ }
+
+ if (tlv->header.encoded_tlv_length
+ == (TLV_HEADER_LENGTH + LENGTH_1WORD + num_psts)) {
+ return (struct pcep_object_tlv_header *)tlv;
+ }
+
+ uint8_t num_iterations = 0;
+ tlv->sub_tlv_list = dll_initialize();
+ uint16_t buf_index = normalize_pcep_tlv_length(
+ TLV_HEADER_LENGTH + LENGTH_1WORD + num_psts);
+ while ((tlv->header.encoded_tlv_length - buf_index) > TLV_HEADER_LENGTH
+ && num_iterations++ < MAX_ITERATIONS) {
+ struct pcep_object_tlv_header *sub_tlv =
+ pcep_decode_tlv(tlv_body_buf + buf_index);
+ if (sub_tlv == NULL) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Decode PathSetupType Capability sub-TLV decode returned NULL",
+ __func__);
+ return (struct pcep_object_tlv_header *)tlv;
+ }
+
+ buf_index +=
+ normalize_pcep_tlv_length(sub_tlv->encoded_tlv_length);
+ dll_append(tlv->sub_tlv_list, sub_tlv);
+ }
+
+ return (struct pcep_object_tlv_header *)tlv;
+}
+struct pcep_object_tlv_header *
+pcep_decode_tlv_pol_id(struct pcep_object_tlv_header *tlv_hdr,
+ const uint8_t *tlv_body_buf)
+{
+ uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf;
+ struct pcep_object_tlv_srpag_pol_id *ipv4 =
+ (struct pcep_object_tlv_srpag_pol_id *)common_tlv_create(
+ tlv_hdr, sizeof(struct pcep_object_tlv_srpag_pol_id));
+ if (tlv_hdr->encoded_tlv_length == 8) {
+ ipv4->is_ipv4 = true;
+ ipv4->color = ntohl(uint32_ptr[0]);
+ ipv4->end_point.ipv4.s_addr = uint32_ptr[1];
+ return (struct pcep_object_tlv_header *)ipv4;
+ } else {
+ ipv4->is_ipv4 = false;
+ struct pcep_object_tlv_srpag_pol_id *ipv6 =
+ (struct pcep_object_tlv_srpag_pol_id *)ipv4;
+ ipv6->color = ntohl(uint32_ptr[0]);
+ decode_ipv6(&uint32_ptr[1], &ipv6->end_point.ipv6);
+ return (struct pcep_object_tlv_header *)ipv6;
+ }
+}
+struct pcep_object_tlv_header *
+pcep_decode_tlv_pol_name(struct pcep_object_tlv_header *tlv_hdr,
+ const uint8_t *tlv_body_buf)
+{
+ struct pcep_object_tlv_srpag_pol_name *tlv =
+ (struct pcep_object_tlv_srpag_pol_name *)common_tlv_create(
+ tlv_hdr, sizeof(struct pcep_object_tlv_srpag_pol_name));
+
+ memcpy(tlv->name, tlv_body_buf, tlv->header.encoded_tlv_length);
+
+ return (struct pcep_object_tlv_header *)tlv;
+}
+struct pcep_object_tlv_header *
+pcep_decode_tlv_cpath_id(struct pcep_object_tlv_header *tlv_hdr,
+ const uint8_t *tlv_body_buf)
+{
+ uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf;
+ struct pcep_object_tlv_srpag_cp_id *tlv =
+ (struct pcep_object_tlv_srpag_cp_id *)common_tlv_create(
+ tlv_hdr, sizeof(struct pcep_object_tlv_srpag_cp_id));
+
+ tlv->proto = tlv_body_buf[0];
+ tlv->orig_asn = ntohl(uint32_ptr[1]);
+ decode_ipv6(&uint32_ptr[2], &tlv->orig_addres);
+ tlv->discriminator = ntohl(uint32_ptr[6]);
+
+ return (struct pcep_object_tlv_header *)tlv;
+}
+struct pcep_object_tlv_header *
+pcep_decode_tlv_cpath_preference(struct pcep_object_tlv_header *tlv_hdr,
+ const uint8_t *tlv_body_buf)
+{
+ uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf;
+ struct pcep_object_tlv_srpag_cp_pref *tlv =
+ (struct pcep_object_tlv_srpag_cp_pref *)common_tlv_create(
+ tlv_hdr, sizeof(struct pcep_object_tlv_srpag_cp_pref));
+
+ tlv->preference = ntohl(uint32_ptr[0]);
+
+ return (struct pcep_object_tlv_header *)tlv;
+}
+
+struct pcep_object_tlv_header *
+pcep_decode_tlv_vendor_info(struct pcep_object_tlv_header *tlv_hdr,
+ const uint8_t *tlv_body_buf)
+{
+ struct pcep_object_tlv_vendor_info *tlv =
+ (struct pcep_object_tlv_vendor_info *)common_tlv_create(
+ tlv_hdr, sizeof(struct pcep_object_tlv_vendor_info));
+
+ uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf;
+ tlv->enterprise_number = ntohl(uint32_ptr[0]);
+ tlv->enterprise_specific_info = ntohl(uint32_ptr[1]);
+
+ return (struct pcep_object_tlv_header *)tlv;
+}
+
+struct pcep_object_tlv_header *
+pcep_decode_tlv_arbitrary(struct pcep_object_tlv_header *tlv_hdr,
+ const uint8_t *tlv_body_buf)
+{
+ struct pcep_object_tlv_arbitrary *tlv_arbitrary =
+ (struct pcep_object_tlv_arbitrary *)common_tlv_create(
+ tlv_hdr, sizeof(struct pcep_object_tlv_arbitrary));
+
+ uint16_t length = tlv_hdr->encoded_tlv_length;
+ if (length > MAX_ARBITRARY_SIZE) {
+ /* TODO should we also reset the tlv_hdr->encoded_tlv_length ?
+ */
+ length = MAX_ARBITRARY_SIZE;
+ pcep_log(
+ LOG_INFO,
+ "%s: Decoding Arbitrary TLV , truncate path name from [%d] to [%d].\",",
+ __func__, tlv_hdr->encoded_tlv_length,
+ MAX_ARBITRARY_SIZE);
+ }
+
+ tlv_arbitrary->data_length = length;
+ tlv_arbitrary->arbitraty_type = tlv_hdr->type;
+ tlv_hdr->type = PCEP_OBJ_TLV_TYPE_ARBITRARY;
+ memcpy(tlv_arbitrary->data, tlv_body_buf, length);
+
+ return (struct pcep_object_tlv_header *)tlv_arbitrary;
+}
+
+struct pcep_object_tlv_header *
+pcep_decode_tlv_of_list(struct pcep_object_tlv_header *tlv_hdr,
+ const uint8_t *tlv_body_buf)
+{
+ struct pcep_object_tlv_of_list *of_tlv =
+ (struct pcep_object_tlv_of_list *)common_tlv_create(
+ tlv_hdr, sizeof(struct pcep_object_tlv_of_list));
+
+ of_tlv->of_list = dll_initialize();
+ uint16_t *uint16_ptr = (uint16_t *)tlv_body_buf;
+ int i = 0;
+ for (; i < tlv_hdr->encoded_tlv_length && i < MAX_ITERATIONS; i++) {
+ uint16_t *of_code_ptr =
+ pceplib_malloc(PCEPLIB_MESSAGES, sizeof(uint16_t));
+ *of_code_ptr = ntohs(uint16_ptr[i]);
+ dll_append(of_tlv->of_list, of_code_ptr);
+ }
+
+ return (struct pcep_object_tlv_header *)of_tlv;
+}
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "pcep_msg_tools.h"
+#include "pcep_msg_encoding.h"
+#include "pcep_utils_logging.h"
+#include "pcep_utils_memory.h"
+
+static const char *message_type_strs[] = {"NOT_IMPLEMENTED0",
+ "OPEN",
+ "KEEPALIVE",
+ "PCREQ",
+ "PCREP",
+ "PCNOTF",
+ "ERROR",
+ "CLOSE",
+ "NOT_IMPLEMENTED8",
+ "NOT_IMPLEMENTED9",
+ "REPORT",
+ "UPDATE",
+ "INITIATE",
+ "UNKOWN_MESSAGE_TYPE"};
+
+static const char *object_class_strs[] = {"NOT_IMPLEMENTED0",
+ "OPEN",
+ "RP",
+ "NOPATH",
+ "ENDPOINTS",
+ "BANDWIDTH",
+ "METRIC",
+ "ERO",
+ "RRO",
+ "LSPA",
+ "IRO",
+ "SVEC",
+ "NOTF",
+ "ERROR",
+ "NOT_IMPLEMENTED14",
+ "CLOSE",
+ "NOT_IMPLEMENTED16",
+ "NOT_IMPLEMENTED17",
+ "NOT_IMPLEMENTED18",
+ "NOT_IMPLEMENTED19",
+ "NOT_IMPLEMENTED20",
+ "OBJECTIVE_FUNCTION",
+ "NOT_IMPLEMENTED22",
+ "NOT_IMPLEMENTED23",
+ "NOT_IMPLEMENTED24",
+ "NOT_IMPLEMENTED25",
+ "NOT_IMPLEMENTED26",
+ "NOT_IMPLEMENTED27",
+ "NOT_IMPLEMENTED28",
+ "NOT_IMPLEMENTED29",
+ "NOT_IMPLEMENTED30",
+ "NOT_IMPLEMENTED31",
+ "LSP",
+ "SRP",
+ "VENDOR_INFO",
+ "NOT_IMPLEMENTED35",
+ "INTER_LAYER",
+ "SWITCH_LAYER",
+ "REQ_ADAP_CAP",
+ "SERVER_IND",
+ "ASSOCIATION", /* 40 */
+ "UNKNOWN_MESSAGE_TYPE"};
+
+
+double_linked_list *pcep_msg_read(int sock_fd)
+{
+ int ret;
+ uint8_t buffer[PCEP_MESSAGE_LENGTH] = {0};
+ uint16_t buffer_read = 0;
+
+
+ ret = read(sock_fd, &buffer, PCEP_MESSAGE_LENGTH);
+
+ if (ret < 0) {
+ pcep_log(
+ LOG_INFO,
+ "%s: pcep_msg_read: Failed to read from socket fd [%d] errno [%d %s]",
+ __func__, sock_fd, errno, strerror(errno));
+ return NULL;
+ } else if (ret == 0) {
+ pcep_log(LOG_INFO, "%s: pcep_msg_read: Remote shutdown fd [%d]",
+ __func__, sock_fd);
+ return NULL;
+ }
+
+ double_linked_list *msg_list = dll_initialize();
+ struct pcep_message *msg = NULL;
+
+ while (((uint16_t)ret - buffer_read) >= MESSAGE_HEADER_LENGTH) {
+
+ /* Get the Message header, validate it, and return the msg
+ * length */
+ int32_t msg_length =
+ pcep_decode_validate_msg_header(buffer + buffer_read);
+ if (msg_length < 0 || msg_length > PCEP_MESSAGE_LENGTH) {
+ /* If the message header is invalid, we cant keep
+ * reading since the length may be invalid */
+ pcep_log(
+ LOG_INFO,
+ "%s: pcep_msg_read: Received an invalid message fd [%d]",
+ __func__, sock_fd);
+ return msg_list;
+ }
+
+ /* Check if the msg_length is longer than what was read,
+ * in which case, we need to read the rest of the message. */
+ if ((ret - buffer_read) < msg_length) {
+ int read_len = (msg_length - (ret - buffer_read));
+ int read_ret = 0;
+ pcep_log(
+ LOG_INFO,
+ "%s: pcep_msg_read: Message not fully read! Trying to read %d bytes more, fd [%d]",
+ __func__, read_len, sock_fd);
+
+ if (PCEP_MESSAGE_LENGTH - ret - buffer_read >= read_len )
+ read_ret =
+ read(sock_fd, &buffer[ret], read_len);
+ else {
+ pcep_log(
+ LOG_ERR,
+ "%s: Trying to read size (%d) offset (%d) in a buff of size (%d)",
+ __func__, read_len, ret, PCEP_MESSAGE_LENGTH);
+ return msg_list;
+ }
+
+ if (read_ret != read_len) {
+ pcep_log(
+ LOG_INFO,
+ "%s: pcep_msg_read: Did not manage to read enough data (%d != %d) fd [%d]",
+ __func__, read_ret, read_len, sock_fd);
+ return msg_list;
+ }
+ }
+
+ msg = pcep_decode_message(buffer + buffer_read);
+ buffer_read += msg_length;
+
+ if (msg == NULL) {
+ return msg_list;
+ } else {
+ dll_append(msg_list, msg);
+ }
+ }
+
+ return msg_list;
+}
+
+struct pcep_message *pcep_msg_get(double_linked_list *msg_list, uint8_t type)
+{
+ if (msg_list == NULL) {
+ return NULL;
+ }
+
+ double_linked_list_node *node;
+ for (node = msg_list->head; node != NULL; node = node->next_node) {
+ if (((struct pcep_message *)node->data)->msg_header->type
+ == type) {
+ return (struct pcep_message *)node->data;
+ }
+ }
+
+ return NULL;
+}
+
+struct pcep_message *pcep_msg_get_next(double_linked_list *list,
+ struct pcep_message *current,
+ uint8_t type)
+{
+ if (list == NULL || current == NULL) {
+ return NULL;
+ }
+
+ if (list->head == NULL) {
+ return NULL;
+ }
+
+ double_linked_list_node *node;
+ for (node = list->head; node != NULL; node = node->next_node) {
+ if (node->data == current) {
+ continue;
+ }
+
+ if (((struct pcep_message *)node->data)->msg_header->type
+ == type) {
+ return (struct pcep_message *)node->data;
+ }
+ }
+
+ return NULL;
+}
+
+struct pcep_object_header *pcep_obj_get(double_linked_list *list,
+ uint8_t object_class)
+{
+ if (list == NULL) {
+ return NULL;
+ }
+
+ if (list->head == NULL) {
+ return NULL;
+ }
+
+ double_linked_list_node *obj_item;
+ for (obj_item = list->head; obj_item != NULL;
+ obj_item = obj_item->next_node) {
+ if (((struct pcep_object_header *)obj_item->data)->object_class
+ == object_class) {
+ return (struct pcep_object_header *)obj_item->data;
+ }
+ }
+
+ return NULL;
+}
+
+struct pcep_object_header *pcep_obj_get_next(double_linked_list *list,
+ struct pcep_object_header *current,
+ uint8_t object_class)
+{
+ if (list == NULL || current == NULL) {
+ return NULL;
+ }
+
+ if (list->head == NULL) {
+ return NULL;
+ }
+
+ double_linked_list_node *node;
+ for (node = list->head; node != NULL; node = node->next_node) {
+ if (node->data == current) {
+ continue;
+ }
+
+ if (((struct pcep_object_header *)node->data)->object_class
+ == object_class) {
+ return (struct pcep_object_header *)node->data;
+ }
+ }
+
+ return NULL;
+}
+
+void pcep_obj_free_tlv(struct pcep_object_tlv_header *tlv)
+{
+ /* Specific TLV freeing */
+ switch (tlv->type) {
+ case PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID:
+ if (((struct pcep_object_tlv_speaker_entity_identifier *)tlv)
+ ->speaker_entity_id_list
+ != NULL) {
+ dll_destroy_with_data_memtype(
+ ((struct
+ pcep_object_tlv_speaker_entity_identifier *)
+ tlv)
+ ->speaker_entity_id_list,
+ PCEPLIB_MESSAGES);
+ }
+ break;
+
+ case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY:
+ if (((struct pcep_object_tlv_path_setup_type_capability *)tlv)
+ ->pst_list
+ != NULL) {
+ dll_destroy_with_data_memtype(
+ ((struct
+ pcep_object_tlv_path_setup_type_capability *)
+ tlv)
+ ->pst_list,
+ PCEPLIB_MESSAGES);
+ }
+
+ if (((struct pcep_object_tlv_path_setup_type_capability *)tlv)
+ ->sub_tlv_list
+ != NULL) {
+ dll_destroy_with_data_memtype(
+ ((struct
+ pcep_object_tlv_path_setup_type_capability *)
+ tlv)
+ ->sub_tlv_list,
+ PCEPLIB_MESSAGES);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ pceplib_free(PCEPLIB_MESSAGES, tlv);
+}
+
+void pcep_obj_free_object(struct pcep_object_header *obj)
+{
+ /* Iterate the TLVs and free each one */
+ if (obj->tlv_list != NULL) {
+ struct pcep_object_tlv_header *tlv;
+ while ((tlv = (struct pcep_object_tlv_header *)
+ dll_delete_first_node(obj->tlv_list))
+ != NULL) {
+ pcep_obj_free_tlv(tlv);
+ }
+
+ dll_destroy(obj->tlv_list);
+ }
+
+ /* Specific object freeing */
+ switch (obj->object_class) {
+ case PCEP_OBJ_CLASS_ERO:
+ case PCEP_OBJ_CLASS_IRO:
+ case PCEP_OBJ_CLASS_RRO: {
+ if (((struct pcep_object_ro *)obj)->sub_objects != NULL) {
+ double_linked_list_node *node =
+ ((struct pcep_object_ro *)obj)
+ ->sub_objects->head;
+ for (; node != NULL; node = node->next_node) {
+ struct pcep_object_ro_subobj *ro_subobj =
+ (struct pcep_object_ro_subobj *)
+ node->data;
+ if (ro_subobj->ro_subobj_type
+ == RO_SUBOBJ_TYPE_SR) {
+ if (((struct pcep_ro_subobj_sr *)
+ ro_subobj)
+ ->nai_list
+ != NULL) {
+ dll_destroy_with_data_memtype(
+ ((struct
+ pcep_ro_subobj_sr *)
+ ro_subobj)
+ ->nai_list,
+ PCEPLIB_MESSAGES);
+ }
+ }
+ }
+ dll_destroy_with_data_memtype(
+ ((struct pcep_object_ro *)obj)->sub_objects,
+ PCEPLIB_MESSAGES);
+ }
+ } break;
+
+ case PCEP_OBJ_CLASS_SVEC:
+ if (((struct pcep_object_svec *)obj)->request_id_list != NULL) {
+ dll_destroy_with_data_memtype(
+ ((struct pcep_object_svec *)obj)
+ ->request_id_list,
+ PCEPLIB_MESSAGES);
+ }
+ break;
+
+ case PCEP_OBJ_CLASS_SWITCH_LAYER:
+ if (((struct pcep_object_switch_layer *)obj)->switch_layer_rows
+ != NULL) {
+ dll_destroy_with_data_memtype(
+ ((struct pcep_object_switch_layer *)obj)
+ ->switch_layer_rows,
+ PCEPLIB_MESSAGES);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ pceplib_free(PCEPLIB_MESSAGES, obj);
+}
+
+void pcep_msg_free_message(struct pcep_message *message)
+{
+ /* Iterate the objects and free each one */
+ if (message->obj_list != NULL) {
+ struct pcep_object_header *obj;
+ while ((obj = (struct pcep_object_header *)
+ dll_delete_first_node(message->obj_list))
+ != NULL) {
+ pcep_obj_free_object(obj);
+ }
+
+ dll_destroy(message->obj_list);
+ }
+
+ if (message->msg_header != NULL) {
+ pceplib_free(PCEPLIB_MESSAGES, message->msg_header);
+ }
+
+ if (message->encoded_message != NULL) {
+ pceplib_free(PCEPLIB_MESSAGES, message->encoded_message);
+ }
+
+ pceplib_free(PCEPLIB_MESSAGES, message);
+}
+
+void pcep_msg_free_message_list(double_linked_list *list)
+{
+ /* Iterate the messages and free each one */
+ struct pcep_message *msg;
+ while ((msg = (struct pcep_message *)dll_delete_first_node(list))
+ != NULL) {
+ pcep_msg_free_message(msg);
+ }
+
+ dll_destroy(list);
+}
+
+const char *get_message_type_str(uint8_t type)
+{
+ uint8_t msg_type =
+ (type > PCEP_TYPE_INITIATE) ? PCEP_TYPE_INITIATE + 1 : type;
+
+ return message_type_strs[msg_type];
+}
+
+const char *get_object_class_str(uint8_t class)
+{
+ uint8_t object_class =
+ (class > PCEP_OBJ_CLASS_SRP) ? PCEP_OBJ_CLASS_SRP + 1 : class;
+
+ return object_class_strs[object_class];
+}
+
+/* Expecting a list of struct pcep_message pointers */
+void pcep_msg_print(double_linked_list *msg_list)
+{
+ double_linked_list_node *node;
+ for (node = msg_list->head; node != NULL; node = node->next_node) {
+ struct pcep_message *msg = (struct pcep_message *)node->data;
+ pcep_log(LOG_INFO, "%s: PCEP_MSG %s", __func__,
+ get_message_type_str(msg->msg_header->type));
+
+ double_linked_list_node *obj_node =
+ (msg->obj_list == NULL ? NULL : msg->obj_list->head);
+ for (; obj_node != NULL; obj_node = obj_node->next_node) {
+ struct pcep_object_header *obj_header =
+ ((struct pcep_object_header *)obj_node->data);
+ pcep_log(
+ LOG_INFO, "%s: PCEP_OBJ %s", __func__,
+ get_object_class_str(obj_header->object_class));
+ }
+ }
+}
+
+int pcep_msg_send(int sock_fd, struct pcep_message *msg)
+{
+ if (msg == NULL) {
+ return 0;
+ }
+ int msg_length = ntohs(msg->encoded_message_length);
+ if (msg_length > PCEP_MESSAGE_LENGTH) {
+ pcep_log(LOG_ERR, "%s: Not sended, size(% d) exceed max(% d) ",
+ __func__, msg_length, PCEP_MESSAGE_LENGTH);
+ return 0;
+ }
+
+ return write(sock_fd, msg->encoded_message, msg_length);
+}
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ */
+
+#ifndef PCEP_TOOLS_H
+#define PCEP_TOOLS_H
+
+#include <stdint.h>
+#include <netinet/in.h> // struct in_addr
+
+#include "pcep_utils_double_linked_list.h"
+#include "pcep_msg_messages.h"
+#include "pcep_msg_objects.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define PCEP_MAX_SIZE 6000
+
+/* Returns a double linked list of PCEP messages */
+double_linked_list *pcep_msg_read(int sock_fd);
+/* Given a double linked list of PCEP messages, return the first node that has
+ * the same message type */
+struct pcep_message *pcep_msg_get(double_linked_list *msg_list, uint8_t type);
+/* Given a double linked list of PCEP messages, return the next node after
+ * current node that has the same message type */
+struct pcep_message *pcep_msg_get_next(double_linked_list *msg_list,
+ struct pcep_message *current,
+ uint8_t type);
+struct pcep_object_header *pcep_obj_get(double_linked_list *list,
+ uint8_t object_class);
+struct pcep_object_header *pcep_obj_get_next(double_linked_list *list,
+ struct pcep_object_header *current,
+ uint8_t object_class);
+struct pcep_object_tlv_header *pcep_tlv_get(double_linked_list *list,
+ uint16_t type);
+struct pcep_object_tlv_header *
+pcep_tlv_get_next(double_linked_list *list,
+ struct pcep_object_tlv_header *current, uint16_t type);
+void pcep_obj_free_tlv(struct pcep_object_tlv_header *tlv);
+void pcep_obj_free_object(struct pcep_object_header *obj);
+void pcep_msg_free_message(struct pcep_message *message);
+void pcep_msg_free_message_list(double_linked_list *list);
+void pcep_msg_print(double_linked_list *list);
+const char *get_message_type_str(uint8_t type);
+const char *get_object_class_str(uint8_t class);
+int pcep_msg_send(int sock_fd, struct pcep_message *hdr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+/*
+ * Sample PCC implementation
+ */
+
+#include <zebra.h>
+
+#include <netdb.h> // gethostbyname
+#include <netinet/tcp.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "pcep_pcc_api.h"
+#include "pcep_utils_double_linked_list.h"
+#include "pcep_utils_logging.h"
+#include "pcep_utils_memory.h"
+
+/*
+ * PCEP PCC design spec:
+ * https://docs.google.com/presentation/d/1DYc3ZhYA1c_qg9A552HjhneJXQKdh_yrKW6v3NRYPtnbw/edit?usp=sharing
+ */
+#define MAX_SRC_IP_STR 40
+#define MAX_DST_IP_STR 40
+struct cmd_line_args {
+ char src_ip_str[MAX_SRC_IP_STR];
+ char dest_ip_str[MAX_DST_IP_STR];
+ short src_tcp_port;
+ short dest_tcp_port;
+ char tcp_md5_str[TCP_MD5SIG_MAXKEYLEN]; /* RFC 2385 */
+ bool is_ipv6;
+ bool eventpoll; /* poll for pcep_event's, or use callback (default) */
+};
+
+bool pcc_active_ = true;
+pcep_session *session = NULL;
+struct cmd_line_args *cmd_line_args = NULL;
+/* pcep_event callback variables */
+bool pcep_event_condition = false;
+struct pcep_event *event = NULL;
+pthread_mutex_t pcep_event_mutex;
+pthread_cond_t pcep_event_cond_var;
+
+static const char DEFAULT_DEST_HOSTNAME[] = "localhost";
+static const char DEFAULT_DEST_HOSTNAME_IPV6[] = "ip6-localhost";
+static const short DEFAULT_SRC_TCP_PORT = 4999;
+
+// Private fn's
+struct cmd_line_args *get_cmdline_args(int argc, char *argv[]);
+void handle_signal_action(int sig_number);
+int setup_signals(void);
+void send_pce_path_request_message(pcep_session *session);
+void send_pce_report_message(pcep_session *session);
+void print_queue_event(struct pcep_event *event);
+void pcep_event_callback(void *cb_data, pcep_event *e);
+
+struct cmd_line_args *get_cmdline_args(int argc, char *argv[])
+{
+ /* Allocate and set default values */
+ struct cmd_line_args *cmd_line_args =
+ malloc(sizeof(struct cmd_line_args));
+ memset(cmd_line_args, 0, sizeof(struct cmd_line_args));
+ strlcpy(cmd_line_args->dest_ip_str, DEFAULT_DEST_HOSTNAME,
+ MAX_DST_IP_STR);
+ cmd_line_args->src_tcp_port = DEFAULT_SRC_TCP_PORT;
+ cmd_line_args->is_ipv6 = false;
+
+ /* Parse the cmd_line args:
+ * -ipv6
+ * -srcip localhost
+ * -destip 192.168.0.2
+ * -srcport 4999
+ * -dstport 4189
+ * -tcpmd5 hello
+ * -event_poll */
+ int i = 1;
+ for (; i < argc; ++i) {
+ if (strcmp(argv[i], "-help") == 0
+ || strcmp(argv[i], "--help") == 0
+ || strcmp(argv[i], "-h") == 0) {
+ pcep_log(
+ LOG_INFO,
+ "%s: pcep_pcc [-ipv6] [-srcip localhost] [-destip 192.168.0.1] [-srcport 4999] [-dstport 4189] [-tcpmd5 authstr] [-eventpoll]",
+ __func__);
+ free(cmd_line_args);
+ return NULL;
+ } else if (strcmp(argv[i], "-ipv6") == 0) {
+ cmd_line_args->is_ipv6 = true;
+ if (argc == 2) {
+ strlcpy(cmd_line_args->dest_ip_str,
+ DEFAULT_DEST_HOSTNAME_IPV6,
+ MAX_DST_IP_STR);
+ }
+ } else if (strcmp(argv[i], "-eventpoll") == 0) {
+ cmd_line_args->eventpoll = true;
+ } else if (strcmp(argv[i], "-srcip") == 0) {
+ if (argc >= i + 2) {
+ strlcpy(cmd_line_args->src_ip_str, argv[++i],
+ MAX_SRC_IP_STR);
+ } else {
+ pcep_log(
+ LOG_ERR,
+ "%s: Invalid number of cmd_line_args for \"-srcip\"",
+ __func__);
+ free(cmd_line_args);
+ return NULL;
+ }
+ } else if (strcmp(argv[i], "-destip") == 0) {
+ if (argc >= i + 2) {
+ strlcpy(cmd_line_args->dest_ip_str, argv[++i],
+ MAX_DST_IP_STR);
+ } else {
+ pcep_log(
+ LOG_ERR,
+ "%s: Invalid number of cmd_line_args for \"-destip\"",
+ __func__);
+ free(cmd_line_args);
+ return NULL;
+ }
+ } else if (strcmp(argv[i], "-srcport") == 0) {
+ if (argc >= i + 2) {
+ cmd_line_args->src_tcp_port = atoi(argv[++i]);
+ } else {
+ pcep_log(
+ LOG_ERR,
+ "%s: Invalid number of cmd_line_args for \"-srcport\"",
+ __func__);
+ free(cmd_line_args);
+ return NULL;
+ }
+ } else if (strcmp(argv[i], "-destport") == 0) {
+ if (argc >= i + 2) {
+ cmd_line_args->dest_tcp_port = atoi(argv[++i]);
+ } else {
+ pcep_log(
+ LOG_ERR,
+ "%s: Invalid number of cmd_line_args for \"-destport\"",
+ __func__);
+ free(cmd_line_args);
+ return NULL;
+ }
+ } else if (strcmp(argv[i], "-tcpmd5") == 0) {
+ if (argc >= i + 2) {
+ strlcpy(cmd_line_args->tcp_md5_str, argv[++i],
+ sizeof(cmd_line_args->tcp_md5_str));
+ } else {
+ pcep_log(
+ LOG_ERR,
+ "%s: Invalid number of cmd_line_args for \"-tcpmd5\"",
+ __func__);
+ free(cmd_line_args);
+ return NULL;
+ }
+ } else {
+ pcep_log(LOG_ERR, "%s: Invalid cmd_line_arg[%d] = %s",
+ __func__, i, argv[i]);
+ free(cmd_line_args);
+ return NULL;
+ }
+ }
+
+ return cmd_line_args;
+}
+
+void handle_signal_action(int sig_number)
+{
+ if (sig_number == SIGINT) {
+ pcep_log(LOG_INFO, "%s: SIGINT was caught!", __func__);
+ pcc_active_ = false;
+ if (cmd_line_args->eventpoll == false) {
+ pthread_mutex_lock(&pcep_event_mutex);
+ pcep_event_condition = true;
+ pthread_cond_signal(&pcep_event_cond_var);
+ pthread_mutex_unlock(&pcep_event_mutex);
+ }
+ } else if (sig_number == SIGUSR1) {
+ pcep_log(LOG_INFO, "%s: SIGUSR1 was caught, dumping counters",
+ __func__);
+ dump_pcep_session_counters(session);
+ pceplib_memory_dump();
+ } else if (sig_number == SIGUSR2) {
+ pcep_log(LOG_INFO, "%s: SIGUSR2 was caught, reseting counters",
+ __func__);
+ reset_pcep_session_counters(session);
+ }
+}
+
+
+int setup_signals()
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(struct sigaction));
+ sa.sa_handler = handle_signal_action;
+ if (sigaction(SIGINT, &sa, 0) != 0) {
+ perror("sigaction()");
+ return -1;
+ }
+
+ if (sigaction(SIGUSR1, &sa, 0) != 0) {
+ perror("sigaction()");
+ return -1;
+ }
+
+ if (sigaction(SIGUSR2, &sa, 0) != 0) {
+ perror("sigaction()");
+ return -1;
+ }
+
+ return 0;
+}
+
+void send_pce_path_request_message(pcep_session *session)
+{
+ struct in_addr src_ipv4;
+ struct in_addr dst_ipv4;
+ inet_pton(AF_INET, "1.2.3.4", &src_ipv4);
+ inet_pton(AF_INET, "10.20.30.40", &dst_ipv4);
+
+ struct pcep_object_rp *rp_object =
+ pcep_obj_create_rp(1, false, false, false, false, 42, NULL);
+ struct pcep_object_endpoints_ipv4 *ep_object =
+ pcep_obj_create_endpoint_ipv4(&src_ipv4, &dst_ipv4);
+
+ struct pcep_message *path_request =
+ pcep_msg_create_request(rp_object, ep_object, NULL);
+ send_message(session, path_request, true);
+}
+
+void send_pce_report_message(pcep_session *session)
+{
+ double_linked_list *report_list = dll_initialize();
+
+ /* SRP Path Setup Type TLV */
+ struct pcep_object_tlv_path_setup_type *pst_tlv =
+ pcep_tlv_create_path_setup_type(SR_TE_PST);
+ double_linked_list *srp_tlv_list = dll_initialize();
+ dll_append(srp_tlv_list, pst_tlv);
+
+ /*
+ * Create the SRP object
+ */
+ uint32_t srp_id_number = 0x10203040;
+ struct pcep_object_header *obj =
+ (struct pcep_object_header *)pcep_obj_create_srp(
+ false, srp_id_number, srp_tlv_list);
+ if (obj == NULL) {
+ pcep_log(LOG_WARNING,
+ "%s: send_pce_report_message SRP object was NULL",
+ __func__);
+ dll_destroy_with_data(report_list);
+ return;
+ }
+ dll_append(report_list, obj);
+
+ /* LSP Symbolic path name TLV */
+ char symbolic_path_name[] = "second-default";
+ struct pcep_object_tlv_symbolic_path_name *spn_tlv =
+ pcep_tlv_create_symbolic_path_name(symbolic_path_name, 14);
+ double_linked_list *lsp_tlv_list = dll_initialize();
+ dll_append(lsp_tlv_list, spn_tlv);
+
+ /* LSP IPv4 LSP ID TLV */
+ struct in_addr ipv4_tunnel_sender;
+ struct in_addr ipv4_tunnel_endpoint;
+ inet_pton(AF_INET, "9.9.1.1", &ipv4_tunnel_sender);
+ inet_pton(AF_INET, "9.9.2.1", &ipv4_tunnel_endpoint);
+ struct pcep_object_tlv_ipv4_lsp_identifier *ipv4_lsp_id_tlv =
+ pcep_tlv_create_ipv4_lsp_identifiers(&ipv4_tunnel_sender,
+ &ipv4_tunnel_endpoint, 42,
+ 1, NULL);
+ dll_append(lsp_tlv_list, ipv4_lsp_id_tlv);
+
+ /*
+ * Create the LSP object
+ */
+ uint32_t plsp_id = 42;
+ enum pcep_lsp_operational_status lsp_status =
+ PCEP_LSP_OPERATIONAL_ACTIVE;
+ bool c_flag = false; /* Lsp was created by PcInitiate msg */
+ bool a_flag = false; /* Admin state, active / inactive */
+ bool r_flag = false; /* true if LSP has been removed */
+ bool s_flag = true; /* Synchronization */
+ bool d_flag = false; /* Delegate LSP to PCE */
+ obj = (struct pcep_object_header *)pcep_obj_create_lsp(
+ plsp_id, lsp_status, c_flag, a_flag, r_flag, s_flag, d_flag,
+ lsp_tlv_list);
+ if (obj == NULL) {
+ pcep_log(LOG_WARNING,
+ "%s: send_pce_report_message LSP object was NULL",
+ __func__);
+ dll_destroy_with_data(report_list);
+ return;
+ }
+ dll_append(report_list, obj);
+
+ /* Create 2 ERO NONAI sub-objects */
+ double_linked_list *ero_subobj_list = dll_initialize();
+ struct pcep_ro_subobj_sr *sr_subobj_nonai1 =
+ pcep_obj_create_ro_subobj_sr_nonai(false, 503808, true, true);
+ dll_append(ero_subobj_list, sr_subobj_nonai1);
+
+ struct pcep_ro_subobj_sr *sr_subobj_nonai2 =
+ pcep_obj_create_ro_subobj_sr_nonai(false, 1867776, true, true);
+ dll_append(ero_subobj_list, sr_subobj_nonai2);
+
+ /* Create ERO IPv4 node sub-object */
+ struct in_addr sr_subobj_ipv4;
+ inet_pton(AF_INET, "9.9.9.1", &sr_subobj_ipv4);
+ struct pcep_ro_subobj_sr *sr_subobj_ipv4node =
+ pcep_obj_create_ro_subobj_sr_ipv4_node(
+ false, false, false, true, 16060, &sr_subobj_ipv4);
+ if (sr_subobj_ipv4node == NULL) {
+ pcep_log(LOG_WARNING,
+ "%s: send_pce_report_message ERO sub-object was NULL",
+ __func__);
+ return;
+ }
+ dll_append(ero_subobj_list, sr_subobj_ipv4node);
+
+ /*
+ * Create the ERO object
+ */
+ obj = (struct pcep_object_header *)pcep_obj_create_ero(ero_subobj_list);
+ if (obj == NULL) {
+ pcep_log(LOG_WARNING,
+ "%s: send_pce_report_message ERO object was NULL",
+ __func__);
+ dll_destroy_with_data(report_list);
+ return;
+ }
+ dll_append(report_list, obj);
+
+ /*
+ * Create the Metric object
+ */
+ obj = (struct pcep_object_header *)pcep_obj_create_metric(
+ PCEP_METRIC_TE, false, true, 16.0);
+ dll_append(report_list, obj);
+
+ /* Create and send the report message */
+ struct pcep_message *report_msg = pcep_msg_create_report(report_list);
+ send_message(session, report_msg, true);
+}
+
+void print_queue_event(struct pcep_event *event)
+{
+ pcep_log(
+ LOG_INFO,
+ "%s: [%ld-%ld] Received Event: type [%s] on session [%d] occurred at [%ld]",
+ __func__, time(NULL), pthread_self(),
+ get_event_type_str(event->event_type),
+ event->session->session_id, event->event_time);
+
+ if (event->event_type == MESSAGE_RECEIVED) {
+ pcep_log(
+ LOG_INFO, "%s: \t Event message type [%s]", __func__,
+ get_message_type_str(event->message->msg_header->type));
+ }
+}
+
+/* Called by pcep_session_logic when pcep_event's are ready */
+void pcep_event_callback(void *cb_data, pcep_event *e)
+{
+ (void)cb_data;
+ pcep_log(LOG_NOTICE, "%s: [%ld-%ld] pcep_event_callback", __func__,
+ time(NULL), pthread_self());
+ pthread_mutex_lock(&pcep_event_mutex);
+ event = e;
+ pcep_event_condition = true;
+ pthread_cond_signal(&pcep_event_cond_var);
+ pthread_mutex_unlock(&pcep_event_mutex);
+}
+
+int main(int argc, char **argv)
+{
+ pcep_log(LOG_NOTICE, "%s: [%ld-%ld] starting pcc_pcep example client",
+ __func__, time(NULL), pthread_self());
+
+ cmd_line_args = get_cmdline_args(argc, argv);
+ if (cmd_line_args == NULL) {
+ return -1;
+ }
+
+ setup_signals();
+
+ if (cmd_line_args->eventpoll == false) {
+ struct pceplib_infra_config infra_config;
+ memset(&infra_config, 0, sizeof(infra_config));
+ infra_config.pcep_event_func = pcep_event_callback;
+ if (!initialize_pcc_infra(&infra_config)) {
+ pcep_log(LOG_ERR,
+ "%s: Error initializing PCC with infra.",
+ __func__);
+ return -1;
+ }
+ } else {
+ if (!initialize_pcc()) {
+ pcep_log(LOG_ERR, "%s: Error initializing PCC.",
+ __func__);
+ return -1;
+ }
+ }
+
+ pcep_configuration *config = create_default_pcep_configuration();
+ config->pcep_msg_versioning->draft_ietf_pce_segment_routing_07 = true;
+ config->src_pcep_port = cmd_line_args->src_tcp_port;
+ config->is_tcp_auth_md5 = true;
+
+ strlcpy(config->tcp_authentication_str, cmd_line_args->tcp_md5_str,
+ sizeof(config->tcp_authentication_str));
+
+ int af = (cmd_line_args->is_ipv6 ? AF_INET6 : AF_INET);
+ struct hostent *host_info =
+ gethostbyname2(cmd_line_args->dest_ip_str, af);
+ if (host_info == NULL) {
+ pcep_log(LOG_ERR, "%s: Error getting IP address.", __func__);
+ return -1;
+ }
+
+ if (cmd_line_args->is_ipv6) {
+ struct in6_addr host_address;
+ memcpy(&host_address, host_info->h_addr, host_info->h_length);
+ session = connect_pce_ipv6(config, &host_address);
+ } else {
+ struct in_addr host_address;
+ memcpy(&host_address, host_info->h_addr, host_info->h_length);
+ session = connect_pce(config, &host_address);
+ }
+
+ if (session == NULL) {
+ pcep_log(LOG_WARNING, "%s: Error in connect_pce.", __func__);
+ destroy_pcep_configuration(config);
+ return -1;
+ }
+
+ sleep(2);
+
+ send_pce_report_message(session);
+ /*send_pce_path_request_message(session);*/
+
+ /* Wait for pcep_event's either by polling the event queue or by
+ * callback */
+ if (cmd_line_args->eventpoll == true) {
+ /* Poll the pcep_event queue*/
+ while (pcc_active_) {
+ if (event_queue_is_empty() == false) {
+ struct pcep_event *event =
+ event_queue_get_event();
+ print_queue_event(event);
+ destroy_pcep_event(event);
+ }
+
+ sleep(5);
+ }
+ } else {
+ /* Get events via callback and conditional variable */
+ pthread_mutex_init(&pcep_event_mutex, NULL);
+ pthread_cond_init(&pcep_event_cond_var, NULL);
+ while (pcc_active_) {
+ pthread_mutex_lock(&pcep_event_mutex);
+
+ /* this internal loop helps avoid spurious interrupts */
+ while (!pcep_event_condition) {
+ pthread_cond_wait(&pcep_event_cond_var,
+ &pcep_event_mutex);
+ }
+
+ /* Check if we have been interrupted by SIGINT */
+ if (pcc_active_) {
+ print_queue_event(event);
+ destroy_pcep_event(event);
+ }
+
+ pcep_event_condition = false;
+ pthread_mutex_unlock(&pcep_event_mutex);
+ }
+
+ pthread_mutex_destroy(&pcep_event_mutex);
+ pthread_cond_destroy(&pcep_event_cond_var);
+ }
+
+ pcep_log(LOG_NOTICE, "%s: Disconnecting from PCE", __func__);
+ disconnect_pce(session);
+ destroy_pcep_configuration(config);
+ free(cmd_line_args);
+
+ if (!destroy_pcc()) {
+ pcep_log(LOG_NOTICE, "%s: Error stopping PCC.", __func__);
+ }
+
+ pceplib_memory_dump();
+
+ return 0;
+}
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+/*
+ * Public PCEPlib PCC API implementation
+ */
+
+#include <zebra.h>
+
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "pcep_msg_messages.h"
+#include "pcep_pcc_api.h"
+#include "pcep_utils_counters.h"
+#include "pcep_utils_logging.h"
+
+/* Not using an array here since the enum pcep_event_type indeces go into the
+ * 100's */
+const char MESSAGE_RECEIVED_STR[] = "MESSAGE_RECEIVED";
+const char PCE_CLOSED_SOCKET_STR[] = "PCE_CLOSED_SOCKET";
+const char PCE_SENT_PCEP_CLOSE_STR[] = "PCE_SENT_PCEP_CLOSE";
+const char PCE_DEAD_TIMER_EXPIRED_STR[] = "PCE_DEAD_TIMER_EXPIRED";
+const char PCE_OPEN_KEEP_WAIT_TIMER_EXPIRED_STR[] =
+ "PCE_OPEN_KEEP_WAIT_TIMER_EXPIRED";
+const char PCC_CONNECTED_TO_PCE_STR[] = "PCC_CONNECTED_TO_PCE";
+const char PCC_PCEP_SESSION_CLOSED_STR[] = "PCC_PCEP_SESSION_CLOSED";
+const char PCC_RCVD_INVALID_OPEN_STR[] = "PCC_RCVD_INVALID_OPEN";
+const char PCC_RCVD_MAX_INVALID_MSGS_STR[] = "PCC_RCVD_MAX_INVALID_MSGS";
+const char PCC_RCVD_MAX_UNKOWN_MSGS_STR[] = "PCC_RCVD_MAX_UNKOWN_MSGS";
+const char UNKNOWN_EVENT_STR[] = "UNKNOWN Event Type";
+
+/* Session Logic Handle managed in pcep_session_logic.c */
+extern pcep_event_queue *session_logic_event_queue_;
+
+bool initialize_pcc()
+{
+ if (!run_session_logic()) {
+ pcep_log(LOG_ERR, "%s: Error initializing PCC session logic.",
+ __func__);
+ return false;
+ }
+
+ return true;
+}
+
+
+bool initialize_pcc_infra(struct pceplib_infra_config *infra_config)
+{
+ if (infra_config == NULL) {
+ return initialize_pcc();
+ }
+
+ if (!run_session_logic_with_infra(infra_config)) {
+ pcep_log(LOG_ERR,
+ "%s: Error initializing PCC session logic with infra.",
+ __func__);
+ return false;
+ }
+
+ return true;
+}
+
+
+/* this function is blocking */
+bool initialize_pcc_wait_for_completion()
+{
+ return run_session_logic_wait_for_completion();
+}
+
+
+bool destroy_pcc()
+{
+ if (!stop_session_logic()) {
+ pcep_log(LOG_WARNING, "%s: Error stopping PCC session logic.",
+ __func__);
+ return false;
+ }
+
+ return true;
+}
+
+
+pcep_configuration *create_default_pcep_configuration()
+{
+ pcep_configuration *config =
+ pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_configuration));
+ memset(config, 0, sizeof(pcep_configuration));
+
+ config->keep_alive_seconds = DEFAULT_CONFIG_KEEP_ALIVE;
+ /* This value will possibly be overwritten later with PCE config data */
+ config->keep_alive_pce_negotiated_timer_seconds =
+ DEFAULT_CONFIG_KEEP_ALIVE;
+ config->min_keep_alive_seconds = DEFAULT_MIN_CONFIG_KEEP_ALIVE;
+ config->max_keep_alive_seconds = DEFAULT_MAX_CONFIG_KEEP_ALIVE;
+
+ config->dead_timer_seconds = DEFAULT_CONFIG_DEAD_TIMER;
+ /* This value will be overwritten later with PCE config data */
+ config->dead_timer_pce_negotiated_seconds = DEFAULT_CONFIG_DEAD_TIMER;
+ config->min_dead_timer_seconds = DEFAULT_MIN_CONFIG_DEAD_TIMER;
+ config->max_dead_timer_seconds = DEFAULT_MAX_CONFIG_DEAD_TIMER;
+
+ config->request_time_seconds = DEFAULT_CONFIG_REQUEST_TIME;
+ config->max_unknown_messages = DEFAULT_CONFIG_MAX_UNKNOWN_MESSAGES;
+ config->max_unknown_requests = DEFAULT_CONFIG_MAX_UNKNOWN_REQUESTS;
+
+ config->socket_connect_timeout_millis =
+ DEFAULT_TCP_CONNECT_TIMEOUT_MILLIS;
+ config->support_stateful_pce_lsp_update = true;
+ config->support_pce_lsp_instantiation = true;
+ config->support_include_db_version = true;
+ config->lsp_db_version = 0;
+ config->support_lsp_triggered_resync = true;
+ config->support_lsp_delta_sync = true;
+ config->support_pce_triggered_initial_sync = true;
+ config->support_sr_te_pst = true;
+ config->pcc_can_resolve_nai_to_sid = true;
+ config->max_sid_depth = 0;
+ config->dst_pcep_port = 0;
+ config->src_pcep_port = 0;
+ config->src_ip.src_ipv4.s_addr = INADDR_ANY;
+ config->is_src_ipv6 = false;
+ config->pcep_msg_versioning = create_default_pcep_versioning();
+ config->tcp_authentication_str[0] = '\0';
+ config->is_tcp_auth_md5 = true;
+
+ return config;
+}
+
+void destroy_pcep_configuration(pcep_configuration *config)
+{
+ destroy_pcep_versioning(config->pcep_msg_versioning);
+ pceplib_free(PCEPLIB_INFRA, config);
+}
+
+pcep_session *connect_pce(pcep_configuration *config, struct in_addr *pce_ip)
+{
+ return create_pcep_session(config, pce_ip);
+}
+
+pcep_session *connect_pce_ipv6(pcep_configuration *config,
+ struct in6_addr *pce_ip)
+{
+ return create_pcep_session_ipv6(config, pce_ip);
+}
+
+void disconnect_pce(pcep_session *session)
+{
+ if (session_exists(session) == false) {
+ pcep_log(
+ LOG_WARNING,
+ "%s: disconnect_pce session [%p] has already been deleted",
+ __func__, session);
+ return;
+ }
+
+ if (session->socket_comm_session == NULL
+ || session->socket_comm_session->socket_fd < 0) {
+ /* If the socket has already been closed, just destroy the
+ * session */
+ destroy_pcep_session(session);
+ } else {
+ /* This will cause the session to be destroyed AFTER the close
+ * message is sent */
+ session->destroy_session_after_write = true;
+
+ /* Send a PCEP close message */
+ close_pcep_session(session);
+ }
+}
+
+void send_message(pcep_session *session, struct pcep_message *msg,
+ bool free_after_send)
+{
+ if (session == NULL || msg == NULL) {
+ pcep_log(LOG_DEBUG,
+ "%s: send_message NULL params session [%p] msg [%p]",
+ __func__, session, msg);
+
+ return;
+ }
+
+ if (session_exists(session) == false) {
+ pcep_log(
+ LOG_WARNING,
+ "%s: send_message session [%p] has already been deleted",
+ __func__, session);
+ return;
+ }
+
+ pcep_encode_message(msg, session->pcc_config.pcep_msg_versioning);
+ socket_comm_session_send_message(
+ session->socket_comm_session, (char *)msg->encoded_message,
+ msg->encoded_message_length, free_after_send);
+
+ increment_message_tx_counters(session, msg);
+
+ if (free_after_send == true) {
+ /* The encoded_message will be deleted once sent, so everything
+ * else in the message will be freed */
+ msg->encoded_message = NULL;
+ pcep_msg_free_message(msg);
+ }
+}
+
+/* Returns true if the queue is empty, false otherwise */
+bool event_queue_is_empty()
+{
+ if (session_logic_event_queue_ == NULL) {
+ pcep_log(
+ LOG_WARNING,
+ "%s: event_queue_is_empty Session Logic is not initialized yet",
+ __func__);
+ return false;
+ }
+
+ pthread_mutex_lock(&session_logic_event_queue_->event_queue_mutex);
+ bool is_empty =
+ (session_logic_event_queue_->event_queue->num_entries == 0);
+ pthread_mutex_unlock(&session_logic_event_queue_->event_queue_mutex);
+
+ return is_empty;
+}
+
+
+/* Return the number of events on the queue, 0 if empty */
+uint32_t event_queue_num_events_available()
+{
+ if (session_logic_event_queue_ == NULL) {
+ pcep_log(
+ LOG_WARNING,
+ "%s: event_queue_num_events_available Session Logic is not initialized yet",
+ __func__);
+ return 0;
+ }
+
+ pthread_mutex_lock(&session_logic_event_queue_->event_queue_mutex);
+ uint32_t num_events =
+ session_logic_event_queue_->event_queue->num_entries;
+ pthread_mutex_unlock(&session_logic_event_queue_->event_queue_mutex);
+
+ return num_events;
+}
+
+
+/* Return the next event on the queue, NULL if empty */
+struct pcep_event *event_queue_get_event()
+{
+ if (session_logic_event_queue_ == NULL) {
+ pcep_log(
+ LOG_WARNING,
+ "%s: event_queue_get_event Session Logic is not initialized yet",
+ __func__);
+ return NULL;
+ }
+
+ pthread_mutex_lock(&session_logic_event_queue_->event_queue_mutex);
+ struct pcep_event *event = (struct pcep_event *)queue_dequeue(
+ session_logic_event_queue_->event_queue);
+ pthread_mutex_unlock(&session_logic_event_queue_->event_queue_mutex);
+
+ return event;
+}
+
+
+/* Free the PCEP Event resources, including the PCEP message */
+void destroy_pcep_event(struct pcep_event *event)
+{
+ if (event == NULL) {
+ pcep_log(LOG_WARNING,
+ "%s: destroy_pcep_event cannot destroy NULL event",
+ __func__);
+ return;
+ }
+
+ if (event->event_type == MESSAGE_RECEIVED && event->message != NULL) {
+ pcep_msg_free_message(event->message);
+ }
+
+ pceplib_free(PCEPLIB_INFRA, event);
+}
+
+const char *get_event_type_str(int event_type)
+{
+ switch (event_type) {
+ case MESSAGE_RECEIVED:
+ return MESSAGE_RECEIVED_STR;
+ break;
+ case PCE_CLOSED_SOCKET:
+ return PCE_CLOSED_SOCKET_STR;
+ break;
+ case PCE_SENT_PCEP_CLOSE:
+ return PCE_SENT_PCEP_CLOSE_STR;
+ break;
+ case PCE_DEAD_TIMER_EXPIRED:
+ return PCE_DEAD_TIMER_EXPIRED_STR;
+ break;
+ case PCE_OPEN_KEEP_WAIT_TIMER_EXPIRED:
+ return PCE_OPEN_KEEP_WAIT_TIMER_EXPIRED_STR;
+ break;
+ case PCC_CONNECTED_TO_PCE:
+ return PCC_CONNECTED_TO_PCE_STR;
+ break;
+ case PCC_PCEP_SESSION_CLOSED:
+ return PCC_PCEP_SESSION_CLOSED_STR;
+ break;
+ case PCC_RCVD_INVALID_OPEN:
+ return PCC_RCVD_INVALID_OPEN_STR;
+ break;
+ case PCC_RCVD_MAX_INVALID_MSGS:
+ return PCC_RCVD_MAX_INVALID_MSGS_STR;
+ break;
+ case PCC_RCVD_MAX_UNKOWN_MSGS:
+ return PCC_RCVD_MAX_UNKOWN_MSGS_STR;
+ break;
+ default:
+ return UNKNOWN_EVENT_STR;
+ break;
+ }
+}
+
+void dump_pcep_session_counters(pcep_session *session)
+{
+ if (session_exists(session) == false) {
+ pcep_log(
+ LOG_WARNING,
+ "%s: dump_pcep_session_counters session [%p] has already been deleted",
+ __func__, session);
+ return;
+ }
+
+ /* Update the counters group name so that the PCE session connected time
+ * is accurate */
+ time_t now = time(NULL);
+ char counters_name[MAX_COUNTER_STR_LENGTH] = {0};
+ char ip_str[40] = {0};
+ if (session->socket_comm_session->is_ipv6) {
+ inet_ntop(AF_INET6,
+ &session->socket_comm_session->dest_sock_addr
+ .dest_sock_addr_ipv6.sin6_addr,
+ ip_str, 40);
+ } else {
+ inet_ntop(AF_INET,
+ &session->socket_comm_session->dest_sock_addr
+ .dest_sock_addr_ipv4.sin_addr,
+ ip_str, 40);
+ }
+ snprintf(counters_name, MAX_COUNTER_STR_LENGTH,
+ "PCEP Session [%d], connected to [%s] for [%u seconds]",
+ session->session_id, ip_str,
+ (uint32_t)(now - session->time_connected));
+ strlcpy(session->pcep_session_counters->counters_group_name,
+ counters_name,
+ sizeof(session->pcep_session_counters->counters_group_name));
+
+ dump_counters_group_to_log(session->pcep_session_counters);
+}
+
+void reset_pcep_session_counters(pcep_session *session)
+{
+ if (session_exists(session) == false) {
+ pcep_log(
+ LOG_WARNING,
+ "%s: reset_pcep_session_counters session [%p] has already been deleted",
+ session);
+ return;
+ }
+
+ reset_group_counters(session->pcep_session_counters);
+}
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+/*
+ * Public PCEPlib PCC API
+ */
+
+#ifndef PCEPPCC_INCLUDE_PCEPPCCAPI_H_
+#define PCEPPCC_INCLUDE_PCEPPCCAPI_H_
+
+#include <stdbool.h>
+
+#include "pcep_session_logic.h"
+#include "pcep_timers.h"
+
+#define DEFAULT_PCEP_TCP_PORT 4189
+#define DEFAULT_CONFIG_KEEP_ALIVE 30
+#define DEFAULT_CONFIG_DEAD_TIMER DEFAULT_CONFIG_KEEP_ALIVE * 4
+#define DEFAULT_CONFIG_REQUEST_TIME 30
+#define DEFAULT_CONFIG_MAX_UNKNOWN_REQUESTS 5
+#define DEFAULT_CONFIG_MAX_UNKNOWN_MESSAGES 5
+#define DEFAULT_TCP_CONNECT_TIMEOUT_MILLIS 250
+
+/* Acceptable MIN and MAX values used in deciding if the PCEP
+ * Open received from a PCE should be accepted or rejected. */
+#define DEFAULT_MIN_CONFIG_KEEP_ALIVE 5
+#define DEFAULT_MAX_CONFIG_KEEP_ALIVE 120
+#define DEFAULT_MIN_CONFIG_DEAD_TIMER DEFAULT_MIN_CONFIG_KEEP_ALIVE * 4
+#define DEFAULT_MAX_CONFIG_DEAD_TIMER DEFAULT_MAX_CONFIG_KEEP_ALIVE * 4
+
+/*
+ * PCEP PCC library initialization/teardown functions
+ */
+
+/* Later when this is integrated with FRR pathd, it will be changed
+ * to just initialize_pcc(struct pceplib_infra_config *infra_config) */
+bool initialize_pcc(void);
+bool initialize_pcc_infra(struct pceplib_infra_config *infra_config);
+/* this function is blocking */
+bool initialize_pcc_wait_for_completion(void);
+bool destroy_pcc(void);
+
+
+/*
+ * PCEP session functions
+ */
+
+pcep_configuration *create_default_pcep_configuration(void);
+void destroy_pcep_configuration(pcep_configuration *config);
+
+/* Uses the standard PCEP TCP src and dest port = 4189.
+ * To use a specific dest or src port, set them other than 0 in the
+ * pcep_configuration. If src_ip is not set, INADDR_ANY will be used. */
+pcep_session *connect_pce(pcep_configuration *config, struct in_addr *pce_ip);
+pcep_session *connect_pce_ipv6(pcep_configuration *config,
+ struct in6_addr *pce_ip);
+void disconnect_pce(pcep_session *session);
+void send_message(pcep_session *session, struct pcep_message *msg,
+ bool free_after_send);
+
+void dump_pcep_session_counters(pcep_session *session);
+void reset_pcep_session_counters(pcep_session *session);
+
+/*
+ * Event Queue functions
+ */
+
+/* Returns true if the queue is empty, false otherwise */
+bool event_queue_is_empty(void);
+
+/* Return the number of events on the queue, 0 if empty */
+uint32_t event_queue_num_events_available(void);
+
+/* Return the next event on the queue, NULL if empty */
+struct pcep_event *event_queue_get_event(void);
+
+/* Free the PCEP Event resources, including the PCEP message */
+void destroy_pcep_event(struct pcep_event *event);
+
+const char *get_event_type_str(int event_type);
+
+
+#endif /* PCEPPCC_INCLUDE_PCEPPCCAPI_H_ */
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <errno.h>
+#include <limits.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include "pcep_msg_encoding.h"
+#include "pcep_session_logic.h"
+#include "pcep_session_logic_internals.h"
+#include "pcep_timers.h"
+#include "pcep_utils_counters.h"
+#include "pcep_utils_ordered_list.h"
+#include "pcep_utils_logging.h"
+#include "pcep_utils_memory.h"
+
+/*
+ * public API function implementations for the session_logic
+ */
+
+pcep_session_logic_handle *session_logic_handle_ = NULL;
+pcep_event_queue *session_logic_event_queue_ = NULL;
+int session_id_ = 0;
+
+void send_pcep_open(pcep_session *session); /* forward decl */
+
+static bool run_session_logic_common()
+{
+ if (session_logic_handle_ != NULL) {
+ pcep_log(LOG_WARNING,
+ "%s: Session Logic is already initialized.", __func__);
+ return false;
+ }
+
+ session_logic_handle_ = pceplib_malloc(
+ PCEPLIB_INFRA, sizeof(pcep_session_logic_handle));
+ memset(session_logic_handle_, 0, sizeof(pcep_session_logic_handle));
+
+ session_logic_handle_->active = true;
+ session_logic_handle_->session_list =
+ ordered_list_initialize(pointer_compare_function);
+ session_logic_handle_->session_event_queue = queue_initialize();
+
+ /* Initialize the event queue */
+ session_logic_event_queue_ =
+ pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_event_queue));
+ session_logic_event_queue_->event_queue = queue_initialize();
+ if (pthread_mutex_init(&(session_logic_event_queue_->event_queue_mutex),
+ NULL)
+ != 0) {
+ pcep_log(
+ LOG_ERR,
+ "%s: Cannot initialize session_logic event queue mutex.",
+ __func__);
+ return false;
+ }
+
+ pthread_cond_init(&(session_logic_handle_->session_logic_cond_var),
+ NULL);
+
+ if (pthread_mutex_init(&(session_logic_handle_->session_logic_mutex),
+ NULL)
+ != 0) {
+ pcep_log(LOG_ERR, "%s: Cannot initialize session_logic mutex.",
+ __func__);
+ return false;
+ }
+
+ pthread_mutex_lock(&(session_logic_handle_->session_logic_mutex));
+ session_logic_handle_->session_logic_condition = true;
+ pthread_cond_signal(&(session_logic_handle_->session_logic_cond_var));
+ pthread_mutex_unlock(&(session_logic_handle_->session_logic_mutex));
+
+ if (pthread_mutex_init(&(session_logic_handle_->session_list_mutex),
+ NULL)
+ != 0) {
+ pcep_log(LOG_ERR, "%s: Cannot initialize session_list mutex.",
+ __func__);
+ return false;
+ }
+
+ return true;
+}
+
+
+bool run_session_logic()
+{
+ if (!run_session_logic_common()) {
+ return false;
+ }
+
+ if (pthread_create(&(session_logic_handle_->session_logic_thread), NULL,
+ session_logic_loop, session_logic_handle_)) {
+ pcep_log(LOG_ERR, "%s: Cannot initialize session_logic thread.",
+ __func__);
+ return false;
+ }
+
+ if (!initialize_timers(session_logic_timer_expire_handler)) {
+ pcep_log(LOG_ERR, "%s: Cannot initialize session_logic timers.",
+ __func__);
+ return false;
+ }
+
+ /* No need to call initialize_socket_comm_loop() since it will be
+ * called internally when the first socket_comm_session is created. */
+
+ return true;
+}
+
+
+bool run_session_logic_with_infra(pceplib_infra_config *infra_config)
+{
+ if (infra_config == NULL) {
+ return run_session_logic();
+ }
+
+ /* Initialize the memory infrastructure before anything gets allocated
+ */
+ if (infra_config->pceplib_infra_mt != NULL
+ && infra_config->pceplib_messages_mt != NULL) {
+ pceplib_memory_initialize(
+ infra_config->pceplib_infra_mt,
+ infra_config->pceplib_messages_mt,
+ infra_config->malloc_func, infra_config->calloc_func,
+ infra_config->realloc_func, infra_config->strdup_func,
+ infra_config->free_func);
+ }
+
+ if (!run_session_logic_common()) {
+ return false;
+ }
+
+ /* Create the pcep_session_logic pthread so it can be managed externally
+ */
+ if (infra_config->pthread_create_func != NULL) {
+ if (infra_config->pthread_create_func(
+ &(session_logic_handle_->session_logic_thread),
+ NULL, session_logic_loop, session_logic_handle_,
+ "pcep_session_logic")) {
+ pcep_log(
+ LOG_ERR,
+ "%s: Cannot initialize external session_logic thread.",
+ __func__);
+ return false;
+ }
+ } else {
+ if (pthread_create(
+ &(session_logic_handle_->session_logic_thread),
+ NULL, session_logic_loop, session_logic_handle_)) {
+ pcep_log(LOG_ERR,
+ "%s: Cannot initialize session_logic thread.",
+ __func__);
+ return false;
+ }
+ }
+
+ session_logic_event_queue_->event_callback =
+ infra_config->pcep_event_func;
+ session_logic_event_queue_->event_callback_data =
+ infra_config->external_infra_data;
+
+ if (!initialize_timers_external_infra(
+ session_logic_timer_expire_handler,
+ infra_config->external_infra_data,
+ infra_config->timer_create_func,
+ infra_config->timer_cancel_func,
+ infra_config->pthread_create_func)) {
+ pcep_log(
+ LOG_ERR,
+ "%s: Cannot initialize session_logic timers with infra.",
+ __func__);
+ return false;
+ }
+
+ /* We found a problem with the FRR sockets, where not all the KeepAlive
+ * messages were received, so if the pthread_create_func is set, the
+ * internal PCEPlib socket infrastructure will be used. */
+
+ /* For the SocketComm, the socket_read/write_func and the
+ * pthread_create_func are mutually exclusive. */
+ if (infra_config->pthread_create_func != NULL) {
+ if (!initialize_socket_comm_external_infra(
+ infra_config->external_infra_data, NULL, NULL,
+ infra_config->pthread_create_func)) {
+ pcep_log(
+ LOG_ERR,
+ "%s: Cannot initialize session_logic socket comm with infra.",
+ __func__);
+ return false;
+ }
+ } else if (infra_config->socket_read_func != NULL
+ && infra_config->socket_write_func != NULL) {
+ if (!initialize_socket_comm_external_infra(
+ infra_config->external_infra_data,
+ infra_config->socket_read_func,
+ infra_config->socket_write_func, NULL)) {
+ pcep_log(
+ LOG_ERR,
+ "%s: Cannot initialize session_logic socket comm with infra.",
+ __func__);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool run_session_logic_wait_for_completion()
+{
+ if (!run_session_logic()) {
+ return false;
+ }
+
+ /* Blocking call, waits for session logic thread to complete */
+ pthread_join(session_logic_handle_->session_logic_thread, NULL);
+
+ return true;
+}
+
+
+bool stop_session_logic()
+{
+ if (session_logic_handle_ == NULL) {
+ pcep_log(LOG_WARNING, "%s: Session logic already stopped",
+ __func__);
+ return false;
+ }
+
+ session_logic_handle_->active = false;
+ teardown_timers();
+
+ pthread_mutex_lock(&(session_logic_handle_->session_logic_mutex));
+ session_logic_handle_->session_logic_condition = true;
+ pthread_cond_signal(&(session_logic_handle_->session_logic_cond_var));
+ pthread_mutex_unlock(&(session_logic_handle_->session_logic_mutex));
+ pthread_join(session_logic_handle_->session_logic_thread, NULL);
+
+ pthread_mutex_destroy(&(session_logic_handle_->session_logic_mutex));
+ pthread_mutex_destroy(&(session_logic_handle_->session_list_mutex));
+ ordered_list_destroy(session_logic_handle_->session_list);
+ queue_destroy(session_logic_handle_->session_event_queue);
+
+ /* destroy the event_queue */
+ pthread_mutex_destroy(&(session_logic_event_queue_->event_queue_mutex));
+ queue_destroy(session_logic_event_queue_->event_queue);
+ pceplib_free(PCEPLIB_INFRA, session_logic_event_queue_);
+
+ /* Explicitly stop the socket comm loop started by the pcep_sessions */
+ destroy_socket_comm_loop();
+
+ pceplib_free(PCEPLIB_INFRA, session_logic_handle_);
+ session_logic_handle_ = NULL;
+
+ return true;
+}
+
+
+void close_pcep_session(pcep_session *session)
+{
+ close_pcep_session_with_reason(session, PCEP_CLOSE_REASON_NO);
+}
+
+void close_pcep_session_with_reason(pcep_session *session,
+ enum pcep_close_reason reason)
+{
+ struct pcep_message *close_msg = pcep_msg_create_close(reason);
+
+ pcep_log(
+ LOG_INFO,
+ "%s: [%ld-%ld] pcep_session_logic send pcep_close message for session [%d]",
+ __func__, time(NULL), pthread_self(), session->session_id);
+
+ session_send_message(session, close_msg);
+ socket_comm_session_close_tcp_after_write(session->socket_comm_session);
+ session->session_state = SESSION_STATE_INITIALIZED;
+}
+
+
+void destroy_pcep_session(pcep_session *session)
+{
+ if (session == NULL) {
+ pcep_log(LOG_WARNING, "%s: Cannot destroy NULL session",
+ __func__);
+ return;
+ }
+
+ /* Remove the session from the session_list and synchronize session
+ * destroy with the session_logic_loop, so that no in-flight events
+ * will be handled now that the session is destroyed. */
+ pthread_mutex_lock(&(session_logic_handle_->session_list_mutex));
+ ordered_list_remove_first_node_equals(
+ session_logic_handle_->session_list, session);
+ pcep_log(LOG_DEBUG,
+ "%s: destroy_pcep_session delete session_list sessionPtr %p",
+ __func__, session);
+
+ pcep_session_cancel_timers(session);
+ delete_counters_group(session->pcep_session_counters);
+ queue_destroy_with_data(session->num_unknown_messages_time_queue);
+ socket_comm_session_teardown(session->socket_comm_session);
+
+ if (session->pcc_config.pcep_msg_versioning != NULL) {
+ pceplib_free(PCEPLIB_INFRA,
+ session->pcc_config.pcep_msg_versioning);
+ }
+
+ if (session->pce_config.pcep_msg_versioning != NULL) {
+ pceplib_free(PCEPLIB_INFRA,
+ session->pce_config.pcep_msg_versioning);
+ }
+
+ int session_id = session->session_id;
+ pceplib_free(PCEPLIB_INFRA, session);
+ pcep_log(LOG_INFO, "%s: [%ld-%ld] session [%d] destroyed", __func__,
+ time(NULL), pthread_self(), session_id);
+ pthread_mutex_unlock(&(session_logic_handle_->session_list_mutex));
+}
+
+void pcep_session_cancel_timers(pcep_session *session)
+{
+ if (session == NULL) {
+ return;
+ }
+
+ if (session->timer_id_dead_timer != TIMER_ID_NOT_SET) {
+ cancel_timer(session->timer_id_dead_timer);
+ }
+
+ if (session->timer_id_keep_alive != TIMER_ID_NOT_SET) {
+ cancel_timer(session->timer_id_keep_alive);
+ }
+
+ if (session->timer_id_open_keep_wait != TIMER_ID_NOT_SET) {
+ cancel_timer(session->timer_id_open_keep_wait);
+ }
+
+ if (session->timer_id_open_keep_alive != TIMER_ID_NOT_SET) {
+ cancel_timer(session->timer_id_open_keep_alive);
+ }
+}
+
+/* Internal util function */
+static int get_next_session_id()
+{
+ if (session_id_ == INT_MAX) {
+ session_id_ = 0;
+ }
+
+ return session_id_++;
+}
+
+/* Internal util function */
+static pcep_session *create_pcep_session_pre_setup(pcep_configuration *config)
+{
+ if (config == NULL) {
+ pcep_log(LOG_WARNING,
+ "%s: Cannot create pcep session with NULL config",
+ __func__);
+ return NULL;
+ }
+
+ pcep_session *session =
+ pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_session));
+ memset(session, 0, sizeof(pcep_session));
+ session->session_id = get_next_session_id();
+ session->session_state = SESSION_STATE_INITIALIZED;
+ session->timer_id_open_keep_wait = TIMER_ID_NOT_SET;
+ session->timer_id_open_keep_alive = TIMER_ID_NOT_SET;
+ session->timer_id_dead_timer = TIMER_ID_NOT_SET;
+ session->timer_id_keep_alive = TIMER_ID_NOT_SET;
+ session->stateful_pce = false;
+ session->num_unknown_messages_time_queue = queue_initialize();
+ session->pce_open_received = false;
+ session->pce_open_rejected = false;
+ session->pce_open_keep_alive_sent = false;
+ session->pcc_open_rejected = false;
+ session->pce_open_accepted = false;
+ session->pcc_open_accepted = false;
+ session->destroy_session_after_write = false;
+ session->lsp_db_version = config->lsp_db_version;
+ memcpy(&(session->pcc_config), config, sizeof(pcep_configuration));
+ /* copy the pcc_config to the pce_config until we receive the open
+ * keep_alive response */
+ memcpy(&(session->pce_config), config, sizeof(pcep_configuration));
+ if (config->pcep_msg_versioning != NULL) {
+ session->pcc_config.pcep_msg_versioning = pceplib_malloc(
+ PCEPLIB_INFRA, sizeof(struct pcep_versioning));
+ memcpy(session->pcc_config.pcep_msg_versioning,
+ config->pcep_msg_versioning,
+ sizeof(struct pcep_versioning));
+ session->pce_config.pcep_msg_versioning = pceplib_malloc(
+ PCEPLIB_INFRA, sizeof(struct pcep_versioning));
+ memcpy(session->pce_config.pcep_msg_versioning,
+ config->pcep_msg_versioning,
+ sizeof(struct pcep_versioning));
+ }
+
+ pthread_mutex_lock(&(session_logic_handle_->session_list_mutex));
+ ordered_list_add_node(session_logic_handle_->session_list, session);
+ pcep_log(
+ LOG_DEBUG,
+ "%s: create_pcep_session_pre_setup add session_list sessionPtr %p",
+ __func__, session);
+ pthread_mutex_unlock(&(session_logic_handle_->session_list_mutex));
+
+ return session;
+}
+
+/* Internal util function */
+static bool create_pcep_session_post_setup(pcep_session *session)
+{
+ if (!socket_comm_session_connect_tcp(session->socket_comm_session)) {
+ pcep_log(LOG_WARNING, "%s: Cannot establish TCP socket.",
+ __func__);
+ destroy_pcep_session(session);
+
+ return false;
+ }
+
+ session->time_connected = time(NULL);
+ create_session_counters(session);
+
+ send_pcep_open(session);
+
+ session->session_state = SESSION_STATE_PCEP_CONNECTING;
+ session->timer_id_open_keep_wait =
+ create_timer(session->pcc_config.keep_alive_seconds, session);
+ // session->session_state = SESSION_STATE_OPENED;
+
+ return true;
+}
+
+pcep_session *create_pcep_session(pcep_configuration *config,
+ struct in_addr *pce_ip)
+{
+ if (pce_ip == NULL) {
+ pcep_log(LOG_WARNING,
+ "%s: Cannot create pcep session with NULL pce_ip",
+ __func__);
+ return NULL;
+ }
+
+ pcep_session *session = create_pcep_session_pre_setup(config);
+ if (session == NULL) {
+ return NULL;
+ }
+
+ session->socket_comm_session = socket_comm_session_initialize_with_src(
+ NULL, session_logic_msg_ready_handler,
+ session_logic_message_sent_handler,
+ session_logic_conn_except_notifier, &(config->src_ip.src_ipv4),
+ ((config->src_pcep_port == 0) ? PCEP_TCP_PORT
+ : config->src_pcep_port),
+ pce_ip,
+ ((config->dst_pcep_port == 0) ? PCEP_TCP_PORT
+ : config->dst_pcep_port),
+ config->socket_connect_timeout_millis,
+ config->tcp_authentication_str, config->is_tcp_auth_md5,
+ session);
+ if (session->socket_comm_session == NULL) {
+ pcep_log(LOG_WARNING,
+ "%s: Cannot establish socket_comm_session.", __func__);
+ destroy_pcep_session(session);
+
+ return NULL;
+ }
+
+ if (create_pcep_session_post_setup(session) == false) {
+ return NULL;
+ }
+
+ return session;
+}
+
+pcep_session *create_pcep_session_ipv6(pcep_configuration *config,
+ struct in6_addr *pce_ip)
+{
+ if (pce_ip == NULL) {
+ pcep_log(LOG_WARNING,
+ "%s: Cannot create pcep session with NULL pce_ip",
+ __func__);
+ return NULL;
+ }
+
+ pcep_session *session = create_pcep_session_pre_setup(config);
+ if (session == NULL) {
+ return NULL;
+ }
+
+ session->socket_comm_session =
+ socket_comm_session_initialize_with_src_ipv6(
+ NULL, session_logic_msg_ready_handler,
+ session_logic_message_sent_handler,
+ session_logic_conn_except_notifier,
+ &(config->src_ip.src_ipv6),
+ ((config->src_pcep_port == 0) ? PCEP_TCP_PORT
+ : config->src_pcep_port),
+ pce_ip,
+ ((config->dst_pcep_port == 0) ? PCEP_TCP_PORT
+ : config->dst_pcep_port),
+ config->socket_connect_timeout_millis,
+ config->tcp_authentication_str, config->is_tcp_auth_md5,
+ session);
+ if (session->socket_comm_session == NULL) {
+ pcep_log(LOG_WARNING,
+ "%s: Cannot establish ipv6 socket_comm_session.",
+ __func__);
+ destroy_pcep_session(session);
+
+ return NULL;
+ }
+
+ if (create_pcep_session_post_setup(session) == false) {
+ return NULL;
+ }
+
+ return session;
+}
+
+
+void session_send_message(pcep_session *session, struct pcep_message *message)
+{
+ pcep_encode_message(message, session->pcc_config.pcep_msg_versioning);
+ socket_comm_session_send_message(session->socket_comm_session,
+ (char *)message->encoded_message,
+ message->encoded_message_length, true);
+
+ increment_message_tx_counters(session, message);
+
+ /* The message->encoded_message will be freed in
+ * socket_comm_session_send_message() once sent.
+ * Setting to NULL here so pcep_msg_free_message() does not free it */
+ message->encoded_message = NULL;
+ pcep_msg_free_message(message);
+}
+
+
+/* This function is also used in pcep_session_logic_states.c */
+struct pcep_message *create_pcep_open(pcep_session *session)
+{
+ /* create and send PCEP open
+ * with PCEP, the PCC sends the config the PCE should use in the open
+ * message,
+ * and the PCE will send an open with the config the PCC should use. */
+ double_linked_list *tlv_list = dll_initialize();
+ if (session->pcc_config.support_stateful_pce_lsp_update
+ || session->pcc_config.support_pce_lsp_instantiation
+ || session->pcc_config.support_include_db_version
+ || session->pcc_config.support_lsp_triggered_resync
+ || session->pcc_config.support_lsp_delta_sync
+ || session->pcc_config.support_pce_triggered_initial_sync) {
+ /* Prepend this TLV as the first in the list */
+ dll_append(
+ tlv_list,
+ pcep_tlv_create_stateful_pce_capability(
+ /* U flag */
+ session->pcc_config
+ .support_stateful_pce_lsp_update,
+ /* S flag */
+ session->pcc_config.support_include_db_version,
+ /* I flag */
+ session->pcc_config
+ .support_pce_lsp_instantiation,
+ /* T flag */
+ session->pcc_config.support_lsp_triggered_resync,
+ /* D flag */
+ session->pcc_config.support_lsp_delta_sync,
+ /* F flag */
+ session->pcc_config.support_pce_triggered_initial_sync));
+ }
+
+ if (session->pcc_config.support_include_db_version) {
+ if (session->pcc_config.lsp_db_version != 0) {
+ dll_append(tlv_list,
+ pcep_tlv_create_lsp_db_version(
+ session->pcc_config.lsp_db_version));
+ }
+ }
+
+ if (session->pcc_config.support_sr_te_pst) {
+ bool flag_n = false;
+ bool flag_x = false;
+ if (session->pcc_config.pcep_msg_versioning
+ ->draft_ietf_pce_segment_routing_07
+ == false) {
+ flag_n = session->pcc_config.pcc_can_resolve_nai_to_sid;
+ flag_x = (session->pcc_config.max_sid_depth == 0);
+ }
+
+ struct pcep_object_tlv_sr_pce_capability *sr_pce_cap_tlv =
+ pcep_tlv_create_sr_pce_capability(
+ flag_n, flag_x,
+ session->pcc_config.max_sid_depth);
+
+ double_linked_list *sub_tlv_list = NULL;
+ if (session->pcc_config.pcep_msg_versioning
+ ->draft_ietf_pce_segment_routing_07
+ == true) {
+ /* With draft07, send the sr_pce_cap_tlv as a normal TLV
+ */
+ dll_append(tlv_list, sr_pce_cap_tlv);
+ } else {
+ /* With draft16, send the sr_pce_cap_tlv as a sub-TLV in
+ * the path_setup_type_capability TLV */
+ sub_tlv_list = dll_initialize();
+ dll_append(sub_tlv_list, sr_pce_cap_tlv);
+ }
+
+ uint8_t *pst =
+ pceplib_malloc(PCEPLIB_MESSAGES, sizeof(uint8_t));
+ *pst = SR_TE_PST;
+ double_linked_list *pst_list = dll_initialize();
+ dll_append(pst_list, pst);
+ dll_append(tlv_list, pcep_tlv_create_path_setup_type_capability(
+ pst_list, sub_tlv_list));
+ }
+
+ struct pcep_message *open_msg = pcep_msg_create_open_with_tlvs(
+ session->pcc_config.keep_alive_seconds,
+ session->pcc_config.dead_timer_seconds, session->session_id,
+ tlv_list);
+
+ pcep_log(
+ LOG_INFO,
+ "%s: [%ld-%ld] pcep_session_logic create open message: TLVs [%d] for session [%d]",
+ __func__, time(NULL), pthread_self(), tlv_list->num_entries,
+ session->session_id);
+
+ return (open_msg);
+}
+
+
+void send_pcep_open(pcep_session *session)
+{
+ session_send_message(session, create_pcep_open(session));
+}
+
+/* This is a blocking call, since it is synchronized with destroy_pcep_session()
+ * and session_logic_loop(). It may be possible that the session has been
+ * deleted but API users havent been informed yet.
+ */
+bool session_exists(pcep_session *session)
+{
+ if (session_logic_handle_ == NULL) {
+ pcep_log(LOG_DEBUG,
+ "%s: session_exists session_logic_handle_ is NULL",
+ __func__);
+ return false;
+ }
+
+ pthread_mutex_lock(&(session_logic_handle_->session_list_mutex));
+ bool retval =
+ (ordered_list_find(session_logic_handle_->session_list, session)
+ != NULL);
+ pthread_mutex_unlock(&(session_logic_handle_->session_list_mutex));
+
+ return retval;
+}
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#ifndef INCLUDE_PCEPSESSIONLOGIC_H_
+#define INCLUDE_PCEPSESSIONLOGIC_H_
+
+#include <stdbool.h>
+#include <netinet/tcp.h>
+
+#include "pcep_msg_encoding.h"
+#include "pcep_socket_comm.h"
+#include "pcep_msg_objects.h"
+#include "pcep_msg_tools.h"
+#include "pcep_timers.h"
+#include "pcep_utils_queue.h"
+#include "pcep_utils_memory.h"
+
+#define PCEP_TCP_PORT 4189
+
+typedef struct pcep_configuration_ {
+ /* These are the configuration values that will
+ * be sent to the PCE in the PCEP Open message */
+ int keep_alive_seconds;
+ int dead_timer_seconds;
+ int dead_timer_pce_negotiated_seconds; /* Config data negotiated with
+ PCE */
+ int keep_alive_pce_negotiated_timer_seconds; /* Config data negotiated
+ with PCE */
+ int request_time_seconds;
+
+ /* These are the acceptable ranges of values received by
+ * the PCE in the initial PCEP Open Message. If a value is
+ * received outside of these ranges, then the Open message
+ * will be rejected. */
+ int min_keep_alive_seconds;
+ int max_keep_alive_seconds;
+ int min_dead_timer_seconds;
+ int max_dead_timer_seconds;
+
+ /* If more than this many unknown messages/requests are received
+ * per minute, then the session will be closed. */
+ int max_unknown_messages;
+ int max_unknown_requests;
+
+ /* Maximum amount of time to wait to connect to the
+ * PCE TCP socket before failing, in milliseconds. */
+ uint32_t socket_connect_timeout_millis;
+
+ /* Set if the PCE/PCC will support stateful PCE LSP Updates
+ * according to RCF8231, section 7.1.1, defaults to true.
+ * Will cause an additional TLV to be sent from the PCC in
+ * the PCEP Open */
+ bool support_stateful_pce_lsp_update;
+
+ /* RFC 8281: I-bit, the PCC allows instantiation of an LSP by a PCE */
+ bool support_pce_lsp_instantiation;
+
+ /* RFC 8232: S-bit, the PCC will include the LSP-DB-VERSION
+ * TLV in each LSP object */
+ bool support_include_db_version;
+
+ /* Only set if support_include_db_version is true and if the LSP-DB
+ * survived a restart and is available. If this has a value other than
+ * 0, then a LSP-DB-VERSION TLV will be sent in the OPEN object. This
+ * value will be copied over to the pcep_session upon init. */
+ uint64_t lsp_db_version;
+
+ /* RFC 8232: T-bit, the PCE can trigger resynchronization of
+ * LSPs at any point in the life of the session */
+ bool support_lsp_triggered_resync;
+
+ /* RFC 8232: D-bit, the PCEP speaker allows incremental (delta)
+ * State Synchronization */
+ bool support_lsp_delta_sync;
+
+ /* RFC 8232: F-bit, the PCE SHOULD trigger initial (first)
+ * State Synchronization */
+ bool support_pce_triggered_initial_sync;
+
+ /* draft-ietf-pce-segment-routing-16: Send a SR PCE Capability
+ * sub-TLV in a Path Setup Type Capability TLV with a PST = 1,
+ * Path is setup using SR TE. */
+ bool support_sr_te_pst;
+ /* Used in the SR PCE Capability sub-TLV */
+ bool pcc_can_resolve_nai_to_sid;
+ /* Used in the SR TE Capability sub-TLV, 0 means there are no max sid
+ * limits */
+ uint8_t max_sid_depth;
+
+ /* If set to 0, then the default 4189 PCEP port will be used */
+ uint16_t dst_pcep_port;
+
+ /* If set to 0, then the default 4189 PCEP port will be used.
+ * This is according to the RFC5440, Section 5 */
+ uint16_t src_pcep_port;
+
+ union src_ip {
+ struct in_addr src_ipv4;
+ struct in6_addr src_ipv6;
+ } src_ip;
+ bool is_src_ipv6;
+
+ struct pcep_versioning *pcep_msg_versioning;
+
+ char tcp_authentication_str[TCP_MD5SIG_MAXKEYLEN];
+ bool is_tcp_auth_md5; /* true: RFC 2385, false: RFC 5925 */
+
+} pcep_configuration;
+
+
+typedef enum pcep_session_state_ {
+ SESSION_STATE_UNKNOWN = 0,
+ SESSION_STATE_INITIALIZED = 1,
+ SESSION_STATE_PCEP_CONNECTING = 2,
+ SESSION_STATE_PCEP_CONNECTED = 3
+
+} pcep_session_state;
+
+
+typedef struct pcep_session_ {
+ int session_id;
+ pcep_session_state session_state;
+ int timer_id_open_keep_wait;
+ int timer_id_open_keep_alive;
+ int timer_id_dead_timer;
+ int timer_id_keep_alive;
+ bool pce_open_received;
+ bool pce_open_rejected;
+ bool pce_open_accepted;
+ bool pce_open_keep_alive_sent;
+ bool pcc_open_rejected;
+ bool pcc_open_accepted;
+ bool stateful_pce;
+ time_t time_connected;
+ uint64_t lsp_db_version;
+ queue_handle *num_unknown_messages_time_queue;
+ /* set this flag when finalizing the session */
+ bool destroy_session_after_write;
+ pcep_socket_comm_session *socket_comm_session;
+ /* Configuration sent from the PCC to the PCE */
+ pcep_configuration pcc_config;
+ /* Configuration received from the PCE, to be used in the PCC */
+ pcep_configuration pce_config;
+ struct counters_group *pcep_session_counters;
+
+} pcep_session;
+
+
+typedef enum pcep_event_type {
+ MESSAGE_RECEIVED = 0,
+ PCE_CLOSED_SOCKET = 1,
+ PCE_SENT_PCEP_CLOSE = 2,
+ PCE_DEAD_TIMER_EXPIRED = 3,
+ PCE_OPEN_KEEP_WAIT_TIMER_EXPIRED = 4,
+ PCC_CONNECTED_TO_PCE = 100,
+ PCC_CONNECTION_FAILURE = 101,
+ PCC_PCEP_SESSION_CLOSED = 102,
+ PCC_RCVD_INVALID_OPEN = 103,
+ PCC_SENT_INVALID_OPEN = 104,
+ PCC_RCVD_MAX_INVALID_MSGS = 105,
+ PCC_RCVD_MAX_UNKOWN_MSGS = 106
+
+} pcep_event_type;
+
+
+typedef struct pcep_event {
+ enum pcep_event_type event_type;
+ time_t event_time;
+ struct pcep_message *message;
+ pcep_session *session;
+
+} pcep_event;
+
+typedef void (*pceplib_pcep_event_callback)(void *cb_data, pcep_event *);
+typedef int (*pthread_create_callback)(pthread_t *pthread_id,
+ const pthread_attr_t *attr,
+ void *(*start_routine)(void *),
+ void *data, const char *thread_name);
+
+
+typedef struct pcep_event_queue {
+ /* The event_queue and event_callback are mutually exclusive.
+ * If the event_callback is configured, then the event_queue
+ * will not be used. */
+ queue_handle *event_queue;
+ pthread_mutex_t event_queue_mutex;
+ pceplib_pcep_event_callback event_callback;
+ void *event_callback_data;
+
+} pcep_event_queue;
+
+
+typedef struct pceplib_infra_config {
+ /* Memory infrastructure */
+ void *pceplib_infra_mt;
+ void *pceplib_messages_mt;
+ pceplib_malloc_func malloc_func;
+ pceplib_calloc_func calloc_func;
+ pceplib_realloc_func realloc_func;
+ pceplib_strdup_func strdup_func;
+ pceplib_free_func free_func;
+
+ /* External Timer and Socket infrastructure */
+ void *external_infra_data;
+ ext_timer_create timer_create_func;
+ ext_timer_cancel timer_cancel_func;
+ ext_socket_write socket_write_func;
+ ext_socket_read socket_read_func;
+
+ /* External pcep_event infrastructure */
+ pceplib_pcep_event_callback pcep_event_func;
+
+ /* Callback to create pthreads */
+ pthread_create_callback pthread_create_func;
+
+} pceplib_infra_config;
+
+/*
+ * Counters Sub-groups definitions
+ */
+typedef enum pcep_session_counters_subgroup_ids {
+ COUNTER_SUBGROUP_ID_RX_MSG = 0,
+ COUNTER_SUBGROUP_ID_TX_MSG = 1,
+ COUNTER_SUBGROUP_ID_RX_OBJ = 2,
+ COUNTER_SUBGROUP_ID_TX_OBJ = 3,
+ COUNTER_SUBGROUP_ID_RX_SUBOBJ = 4,
+ COUNTER_SUBGROUP_ID_TX_SUBOBJ = 5,
+ COUNTER_SUBGROUP_ID_RX_RO_SR_SUBOBJ = 6,
+ COUNTER_SUBGROUP_ID_TX_RO_SR_SUBOBJ = 7,
+ COUNTER_SUBGROUP_ID_RX_TLV = 8,
+ COUNTER_SUBGROUP_ID_TX_TLV = 9,
+ COUNTER_SUBGROUP_ID_EVENT = 10
+
+} pcep_session_counters_subgroup_ids;
+
+bool run_session_logic(void);
+bool run_session_logic_with_infra(pceplib_infra_config *infra_config);
+
+bool run_session_logic_wait_for_completion(void);
+
+bool stop_session_logic(void);
+
+/* Uses the standard PCEP TCP dest port = 4189 and an ephemeral src port.
+ * To use a specific dest or src port, set them other than 0 in the
+ * pcep_configuration. */
+pcep_session *create_pcep_session(pcep_configuration *config,
+ struct in_addr *pce_ip);
+pcep_session *create_pcep_session_ipv6(pcep_configuration *config,
+ struct in6_addr *pce_ip);
+
+/* Send a PCEP close for this pcep_session */
+void close_pcep_session(pcep_session *session);
+void close_pcep_session_with_reason(pcep_session *session,
+ enum pcep_close_reason);
+
+/* Destroy the PCEP session, a PCEP close should have
+ * already been sent with close_pcep_session() */
+void destroy_pcep_session(pcep_session *session);
+
+void pcep_session_cancel_timers(pcep_session *session);
+
+/* Increments transmitted message counters, additionally counters for the
+ * objects, sub-objects, and TLVs in the message will be incremented. Received
+ * counters are incremented internally. */
+void increment_message_tx_counters(pcep_session *session,
+ struct pcep_message *message);
+
+bool session_exists(pcep_session *session);
+
+#endif /* INCLUDE_PCEPSESSIONLOGIC_H_ */
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+/*
+ * PCEP session logic counters configuration.
+ */
+
+#include <stdio.h>
+#include <time.h>
+
+#include "pcep_session_logic.h"
+#include "pcep_session_logic_internals.h"
+#include "pcep_utils_counters.h"
+#include "pcep_utils_logging.h"
+
+void increment_message_counters(pcep_session *session,
+ struct pcep_message *message, bool is_rx);
+
+void create_session_counters(pcep_session *session)
+{
+ /*
+ * Message RX and TX counters
+ */
+ struct counters_subgroup *rx_msg_subgroup = create_counters_subgroup(
+ "RX Message counters", COUNTER_SUBGROUP_ID_RX_MSG,
+ PCEP_TYPE_MAX + 1);
+ create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_OPEN,
+ "Message Open");
+ create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_KEEPALIVE,
+ "Message KeepAlive");
+ create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_PCREQ,
+ "Message PcReq");
+ create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_PCREP,
+ "Message PcRep");
+ create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_PCNOTF,
+ "Message Notify");
+ create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_ERROR,
+ "Message Error");
+ create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_CLOSE,
+ "Message Close");
+ create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_REPORT,
+ "Message Report");
+ create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_UPDATE,
+ "Message Update");
+ create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_INITIATE,
+ "Message Initiate");
+ create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_START_TLS,
+ "Message StartTls");
+ create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_MAX,
+ "Message Erroneous");
+
+ struct counters_subgroup *tx_msg_subgroup =
+ clone_counters_subgroup(rx_msg_subgroup, "TX Message counters",
+ COUNTER_SUBGROUP_ID_TX_MSG);
+
+ /*
+ * Object RX and TX counters
+ */
+
+ /* For the Endpoints, the ID will be either 64 or 65, so setting
+ * num_counters to 100 */
+ struct counters_subgroup *rx_obj_subgroup = create_counters_subgroup(
+ "RX Object counters", COUNTER_SUBGROUP_ID_RX_OBJ, 100);
+ create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_OPEN,
+ "Object Open");
+ create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_RP,
+ "Object RP");
+ create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_NOPATH,
+ "Object Nopath");
+ create_subgroup_counter(
+ rx_obj_subgroup,
+ ((PCEP_OBJ_CLASS_ENDPOINTS << 4) | PCEP_OBJ_TYPE_ENDPOINT_IPV4),
+ "Object Endpoint IPv4");
+ create_subgroup_counter(
+ rx_obj_subgroup,
+ ((PCEP_OBJ_CLASS_ENDPOINTS << 4) | PCEP_OBJ_TYPE_ENDPOINT_IPV6),
+ "Object Endpoint IPv6");
+ create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_BANDWIDTH,
+ "Object Bandwidth");
+ create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_METRIC,
+ "Object Metric");
+ create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_ERO,
+ "Object ERO");
+ create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_RRO,
+ "Object RRO");
+ create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_LSPA,
+ "Object LSPA");
+ create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_IRO,
+ "Object IRO");
+ create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_SVEC,
+ "Object SVEC");
+ create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_NOTF,
+ "Object Notify");
+ create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_ERROR,
+ "Object Error");
+ create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_CLOSE,
+ "Object Close");
+ create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_LSP,
+ "Object LSP");
+ create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_SRP,
+ "Object SRP");
+ create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_VENDOR_INFO,
+ "Object Vendor Info");
+ create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_INTER_LAYER,
+ "Object Inter-Layer");
+ create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_SWITCH_LAYER,
+ "Object Switch-Layer");
+ create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_REQ_ADAP_CAP,
+ "Object Requested Adap-Cap");
+ create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_SERVER_IND,
+ "Object Server-Indication");
+ create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_ASSOCIATION,
+ "Object Association");
+ create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_MAX,
+ "Object Unknown");
+ create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_MAX + 1,
+ "Object Erroneous");
+
+ struct counters_subgroup *tx_obj_subgroup =
+ clone_counters_subgroup(rx_obj_subgroup, "TX Object counters",
+ COUNTER_SUBGROUP_ID_TX_OBJ);
+
+ /*
+ * Sub-Object RX and TX counters
+ */
+ struct counters_subgroup *rx_subobj_subgroup = create_counters_subgroup(
+ "RX RO Sub-Object counters", COUNTER_SUBGROUP_ID_RX_SUBOBJ,
+ RO_SUBOBJ_UNKNOWN + 2);
+ create_subgroup_counter(rx_subobj_subgroup, RO_SUBOBJ_TYPE_IPV4,
+ "RO Sub-Object IPv4");
+ create_subgroup_counter(rx_subobj_subgroup, RO_SUBOBJ_TYPE_IPV6,
+ "RO Sub-Object IPv6");
+ create_subgroup_counter(rx_subobj_subgroup, RO_SUBOBJ_TYPE_LABEL,
+ "RO Sub-Object Label");
+ create_subgroup_counter(rx_subobj_subgroup, RO_SUBOBJ_TYPE_UNNUM,
+ "RO Sub-Object Unnum");
+ create_subgroup_counter(rx_subobj_subgroup, RO_SUBOBJ_TYPE_ASN,
+ "RO Sub-Object ASN");
+ create_subgroup_counter(rx_subobj_subgroup, RO_SUBOBJ_TYPE_SR,
+ "RO Sub-Object SR");
+ create_subgroup_counter(rx_subobj_subgroup, RO_SUBOBJ_UNKNOWN,
+ "RO Sub-Object Unknown");
+ create_subgroup_counter(rx_subobj_subgroup, RO_SUBOBJ_UNKNOWN + 1,
+ "RO Sub-Object Erroneous");
+
+ struct counters_subgroup *tx_subobj_subgroup = clone_counters_subgroup(
+ rx_subobj_subgroup, "TX RO Sub-Object counters",
+ COUNTER_SUBGROUP_ID_TX_SUBOBJ);
+
+ /*
+ * RO SR Sub-Object RX and TX counters
+ */
+ struct counters_subgroup *rx_subobj_sr_nai_subgroup =
+ create_counters_subgroup("RX RO SR NAI Sub-Object counters",
+ COUNTER_SUBGROUP_ID_RX_RO_SR_SUBOBJ,
+ PCEP_SR_SUBOBJ_NAI_UNKNOWN + 1);
+ create_subgroup_counter(rx_subobj_sr_nai_subgroup,
+ PCEP_SR_SUBOBJ_NAI_ABSENT,
+ "RO Sub-Object SR NAI absent");
+ create_subgroup_counter(rx_subobj_sr_nai_subgroup,
+ PCEP_SR_SUBOBJ_NAI_IPV4_NODE,
+ "RO Sub-Object SR NAI IPv4 Node");
+ create_subgroup_counter(rx_subobj_sr_nai_subgroup,
+ PCEP_SR_SUBOBJ_NAI_IPV6_NODE,
+ "RO Sub-Object SR NAI IPv6 Node");
+ create_subgroup_counter(rx_subobj_sr_nai_subgroup,
+ PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY,
+ "RO Sub-Object SR NAI IPv4 Adj");
+ create_subgroup_counter(rx_subobj_sr_nai_subgroup,
+ PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY,
+ "RO Sub-Object SR NAI IPv6 Adj");
+ create_subgroup_counter(rx_subobj_sr_nai_subgroup,
+ PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY,
+ "RO Sub-Object SR NAI Unnumbered IPv4 Adj");
+ create_subgroup_counter(rx_subobj_sr_nai_subgroup,
+ PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY,
+ "RO Sub-Object SR NAI Link Local IPv6 Adj");
+ create_subgroup_counter(rx_subobj_sr_nai_subgroup,
+ PCEP_SR_SUBOBJ_NAI_UNKNOWN,
+ "RO Sub-Object SR NAI Unknown");
+
+ struct counters_subgroup *tx_subobj_sr_nai_subgroup =
+ clone_counters_subgroup(rx_subobj_sr_nai_subgroup,
+ "TX RO SR NAI Sub-Object counters",
+ COUNTER_SUBGROUP_ID_TX_RO_SR_SUBOBJ);
+
+ /*
+ * TLV RX and TX counters
+ */
+ struct counters_subgroup *rx_tlv_subgroup = create_counters_subgroup(
+ "RX TLV counters", COUNTER_SUBGROUP_ID_RX_TLV,
+ PCEP_OBJ_TLV_TYPE_UNKNOWN + 1);
+ create_subgroup_counter(rx_tlv_subgroup,
+ PCEP_OBJ_TLV_TYPE_NO_PATH_VECTOR,
+ "TLV No Path Vector");
+ create_subgroup_counter(rx_tlv_subgroup, PCEP_OBJ_TLV_TYPE_VENDOR_INFO,
+ "TLV Vendor Info");
+ create_subgroup_counter(rx_tlv_subgroup,
+ PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY,
+ "TLV Stateful PCE Capability");
+ create_subgroup_counter(rx_tlv_subgroup,
+ PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME,
+ "TLV Symbolic Path Name");
+ create_subgroup_counter(rx_tlv_subgroup,
+ PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS,
+ "TLV IPv4 LSP Identifier");
+ create_subgroup_counter(rx_tlv_subgroup,
+ PCEP_OBJ_TLV_TYPE_IPV6_LSP_IDENTIFIERS,
+ "TLV IPv6 LSP Identifier");
+ create_subgroup_counter(rx_tlv_subgroup,
+ PCEP_OBJ_TLV_TYPE_LSP_ERROR_CODE,
+ "TLV LSP Error Code");
+ create_subgroup_counter(rx_tlv_subgroup,
+ PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC,
+ "TLV RSVP Error Spec");
+ create_subgroup_counter(rx_tlv_subgroup,
+ PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION,
+ "TLV LSP DB Version");
+ create_subgroup_counter(rx_tlv_subgroup,
+ PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID,
+ "TLV Speaker Entity ID");
+ create_subgroup_counter(rx_tlv_subgroup,
+ PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY,
+ "TLV SR PCE Capability");
+ create_subgroup_counter(rx_tlv_subgroup,
+ PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE,
+ "TLV Path Setup Type");
+ create_subgroup_counter(rx_tlv_subgroup,
+ PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY,
+ "TLV Path Setup Type Capability");
+ create_subgroup_counter(rx_tlv_subgroup,
+ PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_ID,
+ "TLV SR Policy PolId");
+ create_subgroup_counter(rx_tlv_subgroup,
+ PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_NAME,
+ "TLV SR Policy PolName");
+ create_subgroup_counter(rx_tlv_subgroup,
+ PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_ID,
+ "TLV SR Policy CpathId");
+ create_subgroup_counter(rx_tlv_subgroup,
+ PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_PREFERENCE,
+ "TLV SR Policy CpathRef");
+ create_subgroup_counter(rx_tlv_subgroup, PCEP_OBJ_TLV_TYPE_UNKNOWN,
+ "TLV Unknown");
+
+ struct counters_subgroup *tx_tlv_subgroup = clone_counters_subgroup(
+ rx_tlv_subgroup, "TX TLV counters", COUNTER_SUBGROUP_ID_TX_TLV);
+
+ /*
+ * PCEP Event counters
+ */
+ struct counters_subgroup *events_subgroup = create_counters_subgroup(
+ "Events counters", COUNTER_SUBGROUP_ID_EVENT, MAX_COUNTERS);
+ create_subgroup_counter(events_subgroup,
+ PCEP_EVENT_COUNTER_ID_PCC_CONNECT,
+ "PCC connect");
+ create_subgroup_counter(events_subgroup,
+ PCEP_EVENT_COUNTER_ID_PCE_CONNECT,
+ "PCE connect");
+ create_subgroup_counter(events_subgroup,
+ PCEP_EVENT_COUNTER_ID_PCC_DISCONNECT,
+ "PCC disconnect");
+ create_subgroup_counter(events_subgroup,
+ PCEP_EVENT_COUNTER_ID_PCE_DISCONNECT,
+ "PCE disconnect");
+ create_subgroup_counter(events_subgroup,
+ PCEP_EVENT_COUNTER_ID_TIMER_KEEPALIVE,
+ "Timer KeepAlive expired");
+ create_subgroup_counter(events_subgroup,
+ PCEP_EVENT_COUNTER_ID_TIMER_DEADTIMER,
+ "Timer DeadTimer expired");
+ create_subgroup_counter(events_subgroup,
+ PCEP_EVENT_COUNTER_ID_TIMER_OPENKEEPWAIT,
+ "Timer OpenKeepWait expired");
+ create_subgroup_counter(events_subgroup,
+ PCEP_EVENT_COUNTER_ID_TIMER_OPENKEEPALIVE,
+ "Timer OpenKeepAlive expired");
+
+ /*
+ * Create the parent counters group
+ */
+ time_t now = time(NULL);
+ char counters_name[MAX_COUNTER_STR_LENGTH] = {0};
+ char ip_str[40] = {0};
+ if (session->socket_comm_session->is_ipv6) {
+ inet_ntop(AF_INET6,
+ &session->socket_comm_session->dest_sock_addr
+ .dest_sock_addr_ipv6.sin6_addr,
+ ip_str, 40);
+ } else {
+ inet_ntop(AF_INET,
+ &session->socket_comm_session->dest_sock_addr
+ .dest_sock_addr_ipv4.sin_addr,
+ ip_str, 40);
+ }
+ snprintf(counters_name, MAX_COUNTER_STR_LENGTH,
+ "PCEP Session [%d], connected to [%s] for [%u seconds]",
+ session->session_id, ip_str,
+ (uint32_t)(now - session->time_connected));
+ /* The (time(NULL) - session->time_connected) will probably be 0,
+ * so the group name will be updated when the counters are dumped */
+ session->pcep_session_counters =
+ create_counters_group(counters_name, MAX_COUNTER_GROUPS);
+
+ /*
+ * Add all the subgroups to the parent counters group
+ */
+ add_counters_subgroup(session->pcep_session_counters, rx_msg_subgroup);
+ add_counters_subgroup(session->pcep_session_counters, tx_msg_subgroup);
+ add_counters_subgroup(session->pcep_session_counters, rx_obj_subgroup);
+ add_counters_subgroup(session->pcep_session_counters, tx_obj_subgroup);
+ add_counters_subgroup(session->pcep_session_counters,
+ rx_subobj_subgroup);
+ add_counters_subgroup(session->pcep_session_counters,
+ tx_subobj_subgroup);
+ add_counters_subgroup(session->pcep_session_counters,
+ rx_subobj_sr_nai_subgroup);
+ add_counters_subgroup(session->pcep_session_counters,
+ tx_subobj_sr_nai_subgroup);
+ add_counters_subgroup(session->pcep_session_counters, rx_tlv_subgroup);
+ add_counters_subgroup(session->pcep_session_counters, tx_tlv_subgroup);
+ add_counters_subgroup(session->pcep_session_counters, events_subgroup);
+}
+
+/* Internal util function used by increment_message_rx_counters or
+ * increment_message_tx_counters */
+void increment_message_counters(pcep_session *session,
+ struct pcep_message *message, bool is_rx)
+{
+ uint16_t counter_subgroup_id_msg = (is_rx ? COUNTER_SUBGROUP_ID_RX_MSG
+ : COUNTER_SUBGROUP_ID_TX_MSG);
+ uint16_t counter_subgroup_id_obj = (is_rx ? COUNTER_SUBGROUP_ID_RX_OBJ
+ : COUNTER_SUBGROUP_ID_TX_OBJ);
+ uint16_t counter_subgroup_id_subobj =
+ (is_rx ? COUNTER_SUBGROUP_ID_RX_SUBOBJ
+ : COUNTER_SUBGROUP_ID_TX_SUBOBJ);
+ uint16_t counter_subgroup_id_ro_sr_subobj =
+ (is_rx ? COUNTER_SUBGROUP_ID_RX_RO_SR_SUBOBJ
+ : COUNTER_SUBGROUP_ID_TX_RO_SR_SUBOBJ);
+ uint16_t counter_subgroup_id_tlv = (is_rx ? COUNTER_SUBGROUP_ID_RX_TLV
+ : COUNTER_SUBGROUP_ID_TX_TLV);
+
+ increment_counter(session->pcep_session_counters,
+ counter_subgroup_id_msg, message->msg_header->type);
+
+ /* Iterate the objects */
+ double_linked_list_node *obj_node =
+ (message->obj_list == NULL ? NULL : message->obj_list->head);
+ for (; obj_node != NULL; obj_node = obj_node->next_node) {
+ struct pcep_object_header *obj =
+ (struct pcep_object_header *)obj_node->data;
+
+ /* Handle class: PCEP_OBJ_CLASS_ENDPOINTS,
+ * type: PCEP_OBJ_TYPE_ENDPOINT_IPV4 or
+ * PCEP_OBJ_TYPE_ENDPOINT_IPV6 */
+ uint16_t obj_counter_id =
+ (obj->object_class == PCEP_OBJ_CLASS_ENDPOINTS
+ ? (obj->object_class << 4) | obj->object_type
+ : obj->object_class);
+
+ increment_counter(session->pcep_session_counters,
+ counter_subgroup_id_obj, obj_counter_id);
+
+ /* Iterate the RO Sub-objects */
+ if (obj->object_class == PCEP_OBJ_CLASS_ERO
+ || obj->object_class == PCEP_OBJ_CLASS_IRO
+ || obj->object_class == PCEP_OBJ_CLASS_RRO) {
+ struct pcep_object_ro *ro_obj =
+ (struct pcep_object_ro *)obj;
+
+ double_linked_list_node *ro_subobj_node =
+ (ro_obj->sub_objects == NULL
+ ? NULL
+ : ro_obj->sub_objects->head);
+ for (; ro_subobj_node != NULL;
+ ro_subobj_node = ro_subobj_node->next_node) {
+ struct pcep_object_ro_subobj *ro_subobj =
+ (struct pcep_object_ro_subobj *)
+ ro_subobj_node->data;
+ increment_counter(
+ session->pcep_session_counters,
+ counter_subgroup_id_subobj,
+ ro_subobj->ro_subobj_type);
+
+ /* Handle the ro subobj type RO_SUBOBJ_TYPE_SR
+ * different NAI types */
+ if (ro_subobj->ro_subobj_type
+ == RO_SUBOBJ_TYPE_SR) {
+ struct pcep_ro_subobj_sr *ro_sr_subobj =
+ (struct pcep_ro_subobj_sr *)
+ ro_subobj;
+ increment_counter(
+ session->pcep_session_counters,
+ counter_subgroup_id_ro_sr_subobj,
+ ro_sr_subobj->nai_type);
+ }
+ }
+ }
+
+ /* Iterate the TLVs */
+ double_linked_list_node *tlv_node =
+ (obj->tlv_list == NULL ? NULL : obj->tlv_list->head);
+ for (; tlv_node != NULL; tlv_node = tlv_node->next_node) {
+ struct pcep_object_tlv_header *tlv =
+ (struct pcep_object_tlv_header *)tlv_node->data;
+ increment_counter(session->pcep_session_counters,
+ counter_subgroup_id_tlv, tlv->type);
+ }
+ }
+}
+
+void increment_message_rx_counters(pcep_session *session,
+ struct pcep_message *message)
+{
+ increment_message_counters(session, message, true);
+}
+
+void increment_message_tx_counters(pcep_session *session,
+ struct pcep_message *message)
+{
+ increment_message_counters(session, message, false);
+}
+
+void increment_event_counters(
+ pcep_session *session,
+ pcep_session_counters_event_counter_ids counter_id)
+{
+ increment_counter(session->pcep_session_counters,
+ COUNTER_SUBGROUP_ID_EVENT, counter_id);
+}
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+/*
+ * Internal Session Logic declarations, not intended to be in the public API.
+ */
+
+#ifndef SRC_PCEPSESSIONLOGICINTERNALS_H_
+#define SRC_PCEPSESSIONLOGICINTERNALS_H_
+
+
+#include <pthread.h>
+#include <stdbool.h>
+
+#include "pcep_msg_tools.h"
+
+#include "pcep_utils_double_linked_list.h"
+#include "pcep_utils_ordered_list.h"
+#include "pcep_utils_queue.h"
+
+
+typedef struct pcep_session_logic_handle_ {
+ pthread_t session_logic_thread;
+ pthread_mutex_t session_logic_mutex;
+ pthread_cond_t session_logic_cond_var;
+ bool session_logic_condition;
+ bool active;
+
+ ordered_list_handle *session_list;
+ pthread_mutex_t session_list_mutex;
+ /* Internal timers and socket events */
+ queue_handle *session_event_queue;
+
+} pcep_session_logic_handle;
+
+
+/* Used internally for Session events: message received, timer expired,
+ * or socket closed */
+typedef struct pcep_session_event_ {
+ pcep_session *session;
+ int expired_timer_id;
+ double_linked_list *received_msg_list;
+ bool socket_closed;
+
+} pcep_session_event;
+
+/* Event Counters counter-id definitions */
+typedef enum pcep_session_counters_event_counter_ids {
+ PCEP_EVENT_COUNTER_ID_PCC_CONNECT = 0,
+ PCEP_EVENT_COUNTER_ID_PCE_CONNECT = 1,
+ PCEP_EVENT_COUNTER_ID_PCC_DISCONNECT = 2,
+ PCEP_EVENT_COUNTER_ID_PCE_DISCONNECT = 3,
+ PCEP_EVENT_COUNTER_ID_TIMER_KEEPALIVE = 4,
+ PCEP_EVENT_COUNTER_ID_TIMER_DEADTIMER = 5,
+ PCEP_EVENT_COUNTER_ID_TIMER_OPENKEEPWAIT = 6,
+ PCEP_EVENT_COUNTER_ID_TIMER_OPENKEEPALIVE = 7
+
+} pcep_session_counters_event_counter_ids;
+
+/* functions implemented in pcep_session_logic_loop.c */
+void *session_logic_loop(void *data);
+int session_logic_msg_ready_handler(void *data, int socket_fd);
+void session_logic_message_sent_handler(void *data, int socket_fd);
+void session_logic_conn_except_notifier(void *data, int socket_fd);
+void session_logic_timer_expire_handler(void *data, int timer_id);
+
+void handle_timer_event(pcep_session_event *event);
+void handle_socket_comm_event(pcep_session_event *event);
+void session_send_message(pcep_session *session, struct pcep_message *message);
+
+/* defined in pcep_session_logic_states.c */
+void send_pcep_error(pcep_session *session, enum pcep_error_type error_type,
+ enum pcep_error_value error_value);
+void enqueue_event(pcep_session *session, pcep_event_type event_type,
+ struct pcep_message *message);
+void increment_unknown_message(pcep_session *session);
+
+/* defined in pcep_session_logic_counters.c */
+void create_session_counters(pcep_session *session);
+void increment_event_counters(
+ pcep_session *session,
+ pcep_session_counters_event_counter_ids counter_id);
+void increment_message_rx_counters(pcep_session *session,
+ struct pcep_message *message);
+
+/* defined in pcep_session_logic.c, also used in pcep_session_logic_states.c */
+struct pcep_message *create_pcep_open(pcep_session *session);
+
+#endif /* SRC_PCEPSESSIONLOGICINTERNALS_H_ */
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdio.h>
+
+#include "pcep_session_logic.h"
+#include "pcep_session_logic_internals.h"
+#include "pcep_timers.h"
+#include "pcep_utils_logging.h"
+#include "pcep_utils_memory.h"
+
+/* global var needed for callback handlers */
+extern pcep_session_logic_handle *session_logic_handle_;
+
+/* internal util function to create session_event's */
+static pcep_session_event *create_session_event(pcep_session *session)
+{
+ pcep_session_event *event =
+ pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_session_event));
+ event->session = session;
+ event->expired_timer_id = TIMER_ID_NOT_SET;
+ event->received_msg_list = NULL;
+ event->socket_closed = false;
+
+ return event;
+}
+
+
+/* A function pointer to this function is passed to pcep_socket_comm
+ * for each pcep_session creation, so it will be called whenever
+ * messages are ready to be read. This function will be called
+ * by the socket_comm thread.
+ * This function will decode the read PCEP message and give it
+ * to the session_logic_loop so it can be handled by the session_logic
+ * state machine. */
+int session_logic_msg_ready_handler(void *data, int socket_fd)
+{
+ if (data == NULL) {
+ pcep_log(LOG_WARNING,
+ "%s: Cannot handle msg_ready with NULL data",
+ __func__);
+ return -1;
+ }
+
+ if (session_logic_handle_->active == false) {
+ pcep_log(
+ LOG_WARNING,
+ "%s: Received a message ready notification while the session logic is not active",
+ __func__);
+ return -1;
+ }
+
+ pcep_session *session = (pcep_session *)data;
+
+ pthread_mutex_lock(&(session_logic_handle_->session_logic_mutex));
+ session_logic_handle_->session_logic_condition = true;
+
+ /* This event will ultimately be handled by handle_socket_comm_event()
+ * in pcep_session_logic_states.c */
+ pcep_session_event *rcvd_msg_event = create_session_event(session);
+
+ int msg_length = 0;
+ double_linked_list *msg_list = pcep_msg_read(socket_fd);
+
+ if (msg_list == NULL) {
+ /* The socket was closed, or there was a socket read error */
+ pcep_log(LOG_INFO,
+ "%s: PCEP connection closed for session [%d]",
+ __func__, session->session_id);
+ dll_destroy(msg_list);
+ rcvd_msg_event->socket_closed = true;
+ socket_comm_session_teardown(session->socket_comm_session);
+ pcep_session_cancel_timers(session);
+ session->socket_comm_session = NULL;
+ session->session_state = SESSION_STATE_INITIALIZED;
+ enqueue_event(session, PCE_CLOSED_SOCKET, NULL);
+ } else if (msg_list->num_entries == 0) {
+ /* Invalid message received */
+ increment_unknown_message(session);
+ dll_destroy_with_data(msg_list);
+ } else {
+ /* Just logging the first of potentially several messages
+ * received */
+ struct pcep_message *msg =
+ ((struct pcep_message *)msg_list->head->data);
+ pcep_log(
+ LOG_INFO,
+ "%s: [%ld-%ld] session_logic_msg_ready_handler received message of type [%d] len [%d] on session [%d]",
+ __func__, time(NULL), pthread_self(),
+ msg->msg_header->type, msg->encoded_message_length,
+ session->session_id);
+
+ rcvd_msg_event->received_msg_list = msg_list;
+ msg_length = msg->encoded_message_length;
+ }
+
+ queue_enqueue(session_logic_handle_->session_event_queue,
+ rcvd_msg_event);
+ pthread_cond_signal(&(session_logic_handle_->session_logic_cond_var));
+ pthread_mutex_unlock(&(session_logic_handle_->session_logic_mutex));
+
+ return msg_length;
+}
+
+
+/* A function pointer to this function was passed to pcep_socket_comm,
+ * so it will be called when a message is sent. This is useful since
+ * message sending is asynchronous, and there are times that actions
+ * need to be performed only after a message has been sent. */
+void session_logic_message_sent_handler(void *data, int socket_fd)
+{
+ (void)socket_fd;
+
+ if (data == NULL) {
+ pcep_log(LOG_WARNING,
+ "%s: Cannot handle msg_sent with NULL data", __func__);
+ return;
+ }
+
+ pcep_session *session = (pcep_session *)data;
+ if (session->destroy_session_after_write == true) {
+ /* Do not call destroy until all of the queued messages are
+ * written */
+ if (session->socket_comm_session != NULL
+ && session->socket_comm_session->message_queue->num_entries
+ == 0) {
+ destroy_pcep_session(session);
+ }
+ } else {
+ /* Reset the keep alive timer for every message sent on
+ * the session, only if the session is not destroyed */
+ if (session->timer_id_keep_alive == TIMER_ID_NOT_SET) {
+ pcep_log(
+ LOG_INFO,
+ "%s: [%ld-%ld] pcep_session_logic set keep alive timer [%d secs] for session [%d]",
+ __func__, time(NULL), pthread_self(),
+ session->pcc_config
+ .keep_alive_pce_negotiated_timer_seconds,
+ session->session_id);
+ session->timer_id_keep_alive = create_timer(
+ session->pcc_config
+ .keep_alive_pce_negotiated_timer_seconds,
+ session);
+ } else {
+ pcep_log(
+ LOG_INFO,
+ "%s: [%ld-%ld] pcep_session_logic reset keep alive timer [%d secs] for session [%d]",
+ __func__, time(NULL), pthread_self(),
+ session->pcc_config
+ .keep_alive_pce_negotiated_timer_seconds,
+ session->session_id);
+ reset_timer(session->timer_id_keep_alive);
+ }
+ }
+}
+
+
+/* A function pointer to this function was passed to pcep_socket_comm,
+ * so it will be called whenever the socket is closed. this function
+ * will be called by the socket_comm thread. */
+void session_logic_conn_except_notifier(void *data, int socket_fd)
+{
+ if (data == NULL) {
+ pcep_log(LOG_WARNING,
+ "%s: Cannot handle conn_except with NULL data",
+ __func__);
+ return;
+ }
+
+ if (session_logic_handle_->active == false) {
+ pcep_log(
+ LOG_WARNING,
+ "%s: Received a connection exception notification while the session logic is not active",
+ __func__);
+ return;
+ }
+
+ pcep_session *session = (pcep_session *)data;
+ pcep_log(
+ LOG_INFO,
+ "%s: [%ld-%ld] pcep_session_logic session_logic_conn_except_notifier socket closed [%d], session [%d]",
+ __func__, time(NULL), pthread_self(), socket_fd,
+ session->session_id);
+
+ pthread_mutex_lock(&(session_logic_handle_->session_logic_mutex));
+ pcep_session_event *socket_event = create_session_event(session);
+ socket_event->socket_closed = true;
+ queue_enqueue(session_logic_handle_->session_event_queue, socket_event);
+ session_logic_handle_->session_logic_condition = true;
+
+ pthread_cond_signal(&(session_logic_handle_->session_logic_cond_var));
+ pthread_mutex_unlock(&(session_logic_handle_->session_logic_mutex));
+}
+
+
+/*
+ * this method is the timer expire handler, and will only
+ * pass the event to the session_logic loop and notify it
+ * that there is a timer available. this function will be
+ * called by the timers thread.
+ */
+void session_logic_timer_expire_handler(void *data, int timer_id)
+{
+ if (data == NULL) {
+ pcep_log(LOG_WARNING, "%s: Cannot handle timer with NULL data",
+ __func__);
+ return;
+ }
+
+ if (session_logic_handle_->active == false) {
+ pcep_log(
+ LOG_WARNING,
+ "%s: Received a timer expiration while the session logic is not active",
+ __func__);
+ return;
+ }
+
+ pcep_log(LOG_INFO, "%s: [%ld-%ld] timer expired handler timer_id [%d]",
+ __func__, time(NULL), pthread_self(), timer_id);
+ pcep_session_event *expired_timer_event =
+ create_session_event((pcep_session *)data);
+ expired_timer_event->expired_timer_id = timer_id;
+
+ pthread_mutex_lock(&(session_logic_handle_->session_logic_mutex));
+ session_logic_handle_->session_logic_condition = true;
+ queue_enqueue(session_logic_handle_->session_event_queue,
+ expired_timer_event);
+
+ pthread_cond_signal(&(session_logic_handle_->session_logic_cond_var));
+ pthread_mutex_unlock(&(session_logic_handle_->session_logic_mutex));
+}
+
+
+/*
+ * session_logic event loop
+ * this function is called upon thread creation from pcep_session_logic.c
+ */
+void *session_logic_loop(void *data)
+{
+ if (data == NULL) {
+ pcep_log(LOG_WARNING,
+ "%s: Cannot start session_logic_loop with NULL data",
+ __func__);
+
+ return NULL;
+ }
+
+ pcep_log(LOG_NOTICE, "%s: [%ld-%ld] Starting session_logic_loop thread",
+ __func__, time(NULL), pthread_self());
+
+ pcep_session_logic_handle *session_logic_handle =
+ (pcep_session_logic_handle *)data;
+
+ while (session_logic_handle->active) {
+ /* Mutex locking for session_logic_loop condition variable */
+ pthread_mutex_lock(
+ &(session_logic_handle->session_logic_mutex));
+
+ /* this internal loop helps avoid spurious interrupts */
+ while (!session_logic_handle->session_logic_condition) {
+ pthread_cond_wait(
+ &(session_logic_handle->session_logic_cond_var),
+ &(session_logic_handle->session_logic_mutex));
+ }
+
+ pcep_session_event *event = queue_dequeue(
+ session_logic_handle->session_event_queue);
+ while (event != NULL) {
+ if (event->session == NULL) {
+ pcep_log(
+ LOG_INFO,
+ "%s: [%ld-%ld] Invalid session_logic_loop event [%s] with NULL session",
+ __func__, time(NULL), pthread_self(),
+ (event->expired_timer_id
+ != TIMER_ID_NOT_SET)
+ ? "timer"
+ : "message");
+ pceplib_free(PCEPLIB_INFRA, event);
+ event = queue_dequeue(
+ session_logic_handle
+ ->session_event_queue);
+ continue;
+ }
+
+ /* Check if the session still exists, and synchronize
+ * possible session destroy */
+ pcep_log(
+ LOG_DEBUG,
+ "%s: session_logic_loop checking session_list sessionPtr %p",
+ __func__, event->session);
+ pthread_mutex_lock(
+ &(session_logic_handle->session_list_mutex));
+ if (ordered_list_find(
+ session_logic_handle->session_list,
+ event->session)
+ == NULL) {
+ pcep_log(
+ LOG_INFO,
+ "%s: [%ld-%ld] In-flight event [%s] for destroyed session being discarded",
+ __func__, time(NULL), pthread_self(),
+ (event->expired_timer_id
+ != TIMER_ID_NOT_SET)
+ ? "timer"
+ : "message");
+ pceplib_free(PCEPLIB_INFRA, event);
+ event = queue_dequeue(
+ session_logic_handle
+ ->session_event_queue);
+ pthread_mutex_unlock(
+ &(session_logic_handle_
+ ->session_list_mutex));
+ continue;
+ }
+
+ if (event->expired_timer_id != TIMER_ID_NOT_SET) {
+ handle_timer_event(event);
+ }
+
+ if (event->received_msg_list != NULL) {
+ handle_socket_comm_event(event);
+ }
+
+ pceplib_free(PCEPLIB_INFRA, event);
+ event = queue_dequeue(
+ session_logic_handle->session_event_queue);
+
+ pthread_mutex_unlock(
+ &(session_logic_handle_->session_list_mutex));
+ }
+
+ session_logic_handle->session_logic_condition = false;
+ pthread_mutex_unlock(
+ &(session_logic_handle->session_logic_mutex));
+ }
+
+ pcep_log(LOG_NOTICE, "%s: [%ld-%ld] Finished session_logic_loop thread",
+ __func__, time(NULL), pthread_self());
+
+ return NULL;
+}
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "pcep_msg_encoding.h"
+#include "pcep_session_logic.h"
+#include "pcep_session_logic_internals.h"
+#include "pcep_timers.h"
+#include "pcep_utils_logging.h"
+#include "pcep_utils_memory.h"
+
+#define TIMER_OPEN_KEEP_ALIVE_SECONDS 1
+
+/* Session Logic Handle managed in pcep_session_logic.c */
+extern pcep_event_queue *session_logic_event_queue_;
+void send_keep_alive(pcep_session *session);
+void send_pcep_error_with_object(pcep_session *session,
+ enum pcep_error_type error_type,
+ enum pcep_error_value error_value,
+ struct pcep_object_header *object);
+void reset_dead_timer(pcep_session *session);
+bool verify_pcep_open_object(pcep_session *session,
+ struct pcep_object_open *open_object);
+void send_reconciled_pcep_open(pcep_session *session,
+ struct pcep_message *error_msg);
+bool handle_pcep_update(pcep_session *session, struct pcep_message *upd_msg);
+bool handle_pcep_initiate(pcep_session *session, struct pcep_message *init_msg);
+bool check_and_send_open_keep_alive(pcep_session *session);
+void log_pcc_pce_connection(pcep_session *session);
+bool handle_pcep_open(pcep_session *session, struct pcep_message *open_msg);
+
+/*
+ * util functions called by the state handling below
+ */
+
+void send_keep_alive(pcep_session *session)
+{
+ struct pcep_message *keep_alive_msg = pcep_msg_create_keepalive();
+
+ pcep_log(
+ LOG_INFO,
+ "%s: [%ld-%ld] pcep_session_logic send keep_alive message for session [%d]",
+ __func__, time(NULL), pthread_self(), session->session_id);
+
+ session_send_message(session, keep_alive_msg);
+
+ /* The keep alive timer will be (re)set once the message
+ * is sent in session_logic_message_sent_handler() */
+}
+
+
+/* Send an error message with the corrected or offending object */
+void send_pcep_error_with_object(pcep_session *session,
+ enum pcep_error_type error_type,
+ enum pcep_error_value error_value,
+ struct pcep_object_header *object)
+{
+ double_linked_list *obj_list = dll_initialize();
+ dll_append(obj_list, object);
+ struct pcep_message *error_msg = pcep_msg_create_error_with_objects(
+ error_type, error_value, obj_list);
+
+ pcep_log(
+ LOG_INFO,
+ "%s: [%ld-%ld] pcep_session_logic send error message with object [%d][%d] for session [%d]",
+ __func__, time(NULL), pthread_self(), error_type, error_value,
+ session->session_id);
+
+ session_send_message(session, error_msg);
+}
+
+
+void send_pcep_error(pcep_session *session, enum pcep_error_type error_type,
+ enum pcep_error_value error_value)
+{
+ struct pcep_message *error_msg =
+ pcep_msg_create_error(error_type, error_value);
+
+ pcep_log(
+ LOG_INFO,
+ "%s: [%ld-%ld] pcep_session_logic send error message [%d][%d] for session [%d]",
+ __func__, time(NULL), pthread_self(), error_type, error_value,
+ session->session_id);
+
+ session_send_message(session, error_msg);
+}
+
+
+void reset_dead_timer(pcep_session *session)
+{
+ /* Default to configured dead_timer if its not set yet or set to 0 by
+ * the PCE */
+ int dead_timer_seconds =
+ (session->pcc_config.dead_timer_pce_negotiated_seconds == 0)
+ ? session->pcc_config.dead_timer_seconds
+ : session->pcc_config.dead_timer_pce_negotiated_seconds;
+
+ if (session->timer_id_dead_timer == TIMER_ID_NOT_SET) {
+ session->timer_id_dead_timer =
+ create_timer(dead_timer_seconds, session);
+ pcep_log(
+ LOG_INFO,
+ "%s: [%ld-%ld] pcep_session_logic set dead timer [%d secs] id [%d] for session [%d]",
+ __func__, time(NULL), pthread_self(),
+ dead_timer_seconds, session->timer_id_dead_timer,
+ session->session_id);
+ } else {
+ pcep_log(
+ LOG_INFO,
+ "%s: [%ld-%ld] pcep_session_logic reset dead timer [%d secs] id [%d] for session [%d]",
+ __func__, time(NULL), pthread_self(),
+ dead_timer_seconds, session->timer_id_dead_timer,
+ session->session_id);
+ reset_timer(session->timer_id_dead_timer);
+ }
+}
+
+
+void enqueue_event(pcep_session *session, pcep_event_type event_type,
+ struct pcep_message *message)
+{
+ if (event_type == MESSAGE_RECEIVED && message == NULL) {
+ pcep_log(
+ LOG_WARNING,
+ "%s: enqueue_event cannot enqueue a NULL message session [%d]",
+ __func__, session->session_id);
+ return;
+ }
+
+ pcep_event *event = pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_event));
+ memset(event, 0, sizeof(pcep_event));
+
+ event->session = session;
+ event->event_type = event_type;
+ event->event_time = time(NULL);
+ event->message = message;
+
+ pthread_mutex_lock(&session_logic_event_queue_->event_queue_mutex);
+ if (session_logic_event_queue_->event_callback != NULL) {
+ session_logic_event_queue_->event_callback(
+ session_logic_event_queue_->event_callback_data, event);
+ } else {
+ queue_enqueue(session_logic_event_queue_->event_queue, event);
+ }
+ pthread_mutex_unlock(&session_logic_event_queue_->event_queue_mutex);
+}
+
+/* Verify the received PCEP Open object parameters are acceptable. If not,
+ * update the unacceptable value(s) with an acceptable value so it can be sent
+ * back to the sender. */
+bool verify_pcep_open_object(pcep_session *session,
+ struct pcep_object_open *open_object)
+{
+ int retval = true;
+
+ if (open_object->open_keepalive
+ < session->pcc_config.min_keep_alive_seconds) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Rejecting unsupported Open Keep Alive value [%d] min [%d]",
+ __func__, open_object->open_keepalive,
+ session->pcc_config.min_keep_alive_seconds);
+ open_object->open_keepalive =
+ session->pcc_config.min_keep_alive_seconds;
+ retval = false;
+ } else if (open_object->open_keepalive
+ > session->pcc_config.max_keep_alive_seconds) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Rejecting unsupported Open Keep Alive value [%d] max [%d]",
+ __func__, open_object->open_keepalive,
+ session->pcc_config.max_keep_alive_seconds);
+ open_object->open_keepalive =
+ session->pcc_config.max_keep_alive_seconds;
+ retval = false;
+ }
+
+ if (open_object->open_deadtimer
+ < session->pcc_config.min_dead_timer_seconds) {
+ pcep_log(LOG_INFO,
+ "%s: Rejecting unsupported Open Dead Timer value [%d]",
+ __func__, open_object->open_deadtimer);
+ open_object->open_deadtimer =
+ session->pcc_config.min_dead_timer_seconds;
+ retval = false;
+ } else if (open_object->open_deadtimer
+ > session->pcc_config.max_dead_timer_seconds) {
+ pcep_log(LOG_INFO,
+ "%s: Rejecting unsupported Open Dead Timer value [%d]",
+ __func__, open_object->open_deadtimer);
+ open_object->open_deadtimer =
+ session->pcc_config.max_dead_timer_seconds;
+ retval = false;
+ }
+
+ /* Check for Open Object TLVs */
+ if (pcep_object_has_tlvs((struct pcep_object_header *)open_object)
+ == false) {
+ /* There are no TLVs, all done */
+ return retval;
+ }
+
+ double_linked_list_node *tlv_node = open_object->header.tlv_list->head;
+ while (tlv_node != NULL) {
+ struct pcep_object_tlv_header *tlv = tlv_node->data;
+ tlv_node = tlv_node->next_node;
+
+ /* Supported Open Object TLVs */
+ switch (tlv->type) {
+ case PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION:
+ case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY:
+ case PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID:
+ case PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY:
+ case PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY:
+ break;
+
+ default:
+ /* TODO how to handle unrecognized TLV ?? */
+ pcep_log(
+ LOG_INFO,
+ "%s: Unhandled OPEN Object TLV type: %d, length %d",
+ __func__, tlv->type, tlv->encoded_tlv_length);
+ break;
+ }
+
+ /* Verify the STATEFUL-PCE-CAPABILITY TLV */
+ if (tlv->type == PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY) {
+ struct pcep_object_tlv_stateful_pce_capability
+ *pce_cap_tlv =
+ (struct
+ pcep_object_tlv_stateful_pce_capability
+ *)tlv;
+
+ /* If the U flag is set, then the PCE is
+ * capable of updating LSP parameters */
+ if (pce_cap_tlv->flag_u_lsp_update_capability) {
+ if (session->pce_config
+ .support_stateful_pce_lsp_update
+ == false) {
+ /* Turn off the U bit, as it is not
+ * supported */
+ pcep_log(
+ LOG_INFO,
+ "%s: Rejecting unsupported Open STATEFUL-PCE-CAPABILITY TLV U flag",
+ __func__);
+ pce_cap_tlv
+ ->flag_u_lsp_update_capability =
+ false;
+ retval = false;
+ } else {
+ session->stateful_pce = true;
+ pcep_log(
+ LOG_INFO,
+ "%s: Setting PCEP session [%d] STATEFUL to support LSP updates",
+ __func__, session->session_id);
+ }
+ }
+ /* TODO the rest of the flags are not implemented yet */
+ else if (pce_cap_tlv->flag_s_include_db_version) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Ignoring Open STATEFUL-PCE-CAPABILITY TLV S Include DB Version flag",
+ __func__);
+ } else if (
+ pce_cap_tlv
+ ->flag_i_lsp_instantiation_capability) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Ignoring Open STATEFUL-PCE-CAPABILITY TLV I LSP Instantiation Capability flag",
+ __func__);
+ } else if (pce_cap_tlv->flag_t_triggered_resync) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Ignoring Open STATEFUL-PCE-CAPABILITY TLV T Triggered Resync flag",
+ __func__);
+ } else if (pce_cap_tlv->flag_d_delta_lsp_sync) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Ignoring Open STATEFUL-PCE-CAPABILITY TLV D Delta LSP Sync flag",
+ __func__);
+ } else if (pce_cap_tlv->flag_f_triggered_initial_sync) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Ignoring Open STATEFUL-PCE-CAPABILITY TLV F Triggered Initial Sync flag",
+ __func__);
+ }
+ } else if (tlv->type == PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION) {
+ if (session->pce_config.support_include_db_version
+ == false) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Rejecting unsupported Open LSP DB VERSION TLV",
+ __func__);
+ /* Remove this TLV from the list */
+ dll_delete_node(open_object->header.tlv_list,
+ tlv_node);
+ retval = false;
+ }
+ }
+ }
+
+ return retval;
+}
+
+
+bool handle_pcep_open(pcep_session *session, struct pcep_message *open_msg)
+{
+ /* Open Message validation and errors according to:
+ * https://tools.ietf.org/html/rfc5440#section-7.15 */
+
+ if (session->session_state != SESSION_STATE_PCEP_CONNECTING
+ && session->session_state != SESSION_STATE_INITIALIZED) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Received unexpected OPEN, current session state [%d, replying with error]",
+ __func__, session->session_state);
+ send_pcep_error(session,
+ PCEP_ERRT_ATTEMPT_TO_ESTABLISH_2ND_PCEP_SESSION,
+ PCEP_ERRV_RECVD_INVALID_OPEN_MSG);
+ return false;
+ }
+
+ if (session->pce_open_received == true
+ && session->pce_open_rejected == false) {
+ pcep_log(LOG_INFO,
+ "%s: Received duplicate OPEN, replying with error",
+ __func__);
+ send_pcep_error(session,
+ PCEP_ERRT_ATTEMPT_TO_ESTABLISH_2ND_PCEP_SESSION,
+ PCEP_ERRV_RECVD_INVALID_OPEN_MSG);
+ return false;
+ }
+
+ struct pcep_object_open *open_object =
+ (struct pcep_object_open *)pcep_obj_get(open_msg->obj_list,
+ PCEP_OBJ_CLASS_OPEN);
+ if (open_object == NULL) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Received OPEN message with no OPEN object, replying with error",
+ __func__);
+ send_pcep_error(session, PCEP_ERRT_SESSION_FAILURE,
+ PCEP_ERRV_RECVD_INVALID_OPEN_MSG);
+ return false;
+ }
+
+ /* Check for additional Open Msg objects */
+ if (open_msg->obj_list->num_entries > 1) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Found additional unsupported objects in the Open message, replying with error",
+ __func__);
+ send_pcep_error(session, PCEP_ERRT_SESSION_FAILURE,
+ PCEP_ERRV_RECVD_INVALID_OPEN_MSG);
+ return false;
+ }
+
+ session->pce_open_received = true;
+
+ /* Verify the open object parameters and TLVs */
+ if (verify_pcep_open_object(session, open_object) == false) {
+ enqueue_event(session, PCC_RCVD_INVALID_OPEN, NULL);
+ if (session->pce_open_rejected) {
+ /* The Open message was already rejected once, so
+ * according to the spec, send an error message and
+ * close the TCP connection. */
+ pcep_log(
+ LOG_INFO,
+ "%s: Received 2 consecutive unsupported Open messages, closing the connection.",
+ __func__);
+ send_pcep_error(
+ session, PCEP_ERRT_SESSION_FAILURE,
+ PCEP_ERRV_RECVD_SECOND_OPEN_MSG_UNACCEPTABLE);
+ socket_comm_session_close_tcp_after_write(
+ session->socket_comm_session);
+ session->session_state = SESSION_STATE_INITIALIZED;
+ enqueue_event(session, PCC_CONNECTION_FAILURE, NULL);
+ } else {
+ session->pce_open_rejected = true;
+ /* Clone the object here, since the encapsulating
+ * message will be deleted in handle_socket_comm_event()
+ * most likely before this error message is sent */
+ struct pcep_object_open *cloned_open_object =
+ pceplib_malloc(PCEPLIB_MESSAGES,
+ sizeof(struct pcep_object_open));
+ memcpy(cloned_open_object, open_object,
+ sizeof(struct pcep_object_open));
+ open_object->header.tlv_list = NULL;
+ cloned_open_object->header.encoded_object = NULL;
+ cloned_open_object->header.encoded_object_length = 0;
+ send_pcep_error_with_object(
+ session, PCEP_ERRT_SESSION_FAILURE,
+ PCEP_ERRV_UNACCEPTABLE_OPEN_MSG_NEG,
+ &cloned_open_object->header);
+ }
+
+ return false;
+ }
+
+ /*
+ * Open Message accepted
+ * Sending the keep-alive response will be managed the function caller
+ */
+
+ session->timer_id_open_keep_alive =
+ create_timer(TIMER_OPEN_KEEP_ALIVE_SECONDS, session);
+ session->pcc_config.dead_timer_pce_negotiated_seconds =
+ (int)open_object->open_deadtimer;
+ /* Cancel the timer so we can change the dead_timer value */
+ cancel_timer(session->timer_id_dead_timer);
+ session->timer_id_dead_timer = TIMER_ID_NOT_SET;
+ reset_dead_timer(session);
+
+ return true;
+}
+
+
+/* The original PCEP Open message sent to the PCE was rejected,
+ * try to reconcile the differences and re-send a new Open. */
+void send_reconciled_pcep_open(pcep_session *session,
+ struct pcep_message *error_msg)
+{
+ struct pcep_message *open_msg = create_pcep_open(session);
+
+ struct pcep_object_open *error_open_obj =
+ (struct pcep_object_open *)pcep_obj_get(error_msg->obj_list,
+ PCEP_OBJ_CLASS_OPEN);
+ if (error_open_obj == NULL) {
+ /* Nothing to reconcile, send the same Open message again */
+ pcep_log(
+ LOG_INFO,
+ "%s: No Open object received in Error, sending the same Open message",
+ __func__);
+ session_send_message(session, open_msg);
+ return;
+ }
+
+ struct pcep_object_open *open_obj =
+ (struct pcep_object_open *)pcep_obj_get(open_msg->obj_list,
+ PCEP_OBJ_CLASS_OPEN);
+ // open_msg can not have empty obj_list
+ assert(open_obj != NULL);
+
+ if (error_open_obj->open_deadtimer
+ != session->pce_config.dead_timer_seconds) {
+ if (error_open_obj->open_deadtimer
+ >= session->pce_config.min_dead_timer_seconds
+ && error_open_obj->open_deadtimer
+ <= session->pce_config.max_dead_timer_seconds) {
+ open_obj->open_deadtimer =
+ error_open_obj->open_deadtimer;
+ session->pcc_config.dead_timer_pce_negotiated_seconds =
+ error_open_obj->open_deadtimer;
+ pcep_log(
+ LOG_INFO,
+ "%s: Open deadtimer value [%d] rejected, using PCE value [%d]",
+ __func__,
+ session->pcc_config.dead_timer_seconds,
+ session->pcc_config
+ .dead_timer_pce_negotiated_seconds);
+ /* Reset the timer with the new value */
+ cancel_timer(session->timer_id_dead_timer);
+ session->timer_id_dead_timer = TIMER_ID_NOT_SET;
+ reset_dead_timer(session);
+ } else {
+ pcep_log(
+ LOG_INFO,
+ "%s: Can not reconcile Open with suggested deadtimer [%d]",
+ __func__, error_open_obj->open_deadtimer);
+ }
+ }
+
+ if (error_open_obj->open_keepalive
+ != session->pce_config.keep_alive_seconds) {
+ if (error_open_obj->open_keepalive
+ >= session->pce_config.min_keep_alive_seconds
+ && error_open_obj->open_keepalive
+ <= session->pce_config.max_keep_alive_seconds) {
+ open_obj->open_keepalive =
+ error_open_obj->open_keepalive;
+ session->pcc_config
+ .keep_alive_pce_negotiated_timer_seconds =
+ error_open_obj->open_keepalive;
+ pcep_log(
+ LOG_INFO,
+ "%s: Open keep alive value [%d] rejected, using PCE value [%d]",
+ __func__,
+ session->pcc_config.keep_alive_seconds,
+ session->pcc_config
+ .keep_alive_pce_negotiated_timer_seconds);
+ /* Cancel the timer, the timer will be set again with
+ * the new value when this open message is sent */
+ cancel_timer(session->timer_id_keep_alive);
+ session->timer_id_keep_alive = TIMER_ID_NOT_SET;
+ } else {
+ pcep_log(
+ LOG_INFO,
+ "%s: Can not reconcile Open with suggested keepalive [%d]",
+ __func__, error_open_obj->open_keepalive);
+ }
+ }
+
+ /* TODO reconcile the TLVs */
+
+ session_send_message(session, open_msg);
+ reset_timer(session->timer_id_open_keep_alive);
+}
+
+
+bool handle_pcep_update(pcep_session *session, struct pcep_message *upd_msg)
+{
+ /* Update Message validation and errors according to:
+ * https://tools.ietf.org/html/rfc8231#section-6.2 */
+
+ if (upd_msg->obj_list == NULL) {
+ pcep_log(LOG_INFO,
+ "%s: Invalid PcUpd message: Message has no objects",
+ __func__);
+ send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING,
+ PCEP_ERRV_SRP_OBJECT_MISSING);
+ return false;
+ }
+
+ /* Verify the mandatory objects are present */
+ struct pcep_object_header *obj =
+ pcep_obj_get(upd_msg->obj_list, PCEP_OBJ_CLASS_SRP);
+ if (obj == NULL) {
+ pcep_log(LOG_INFO,
+ "%s: Invalid PcUpd message: Missing SRP object",
+ __func__);
+ send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING,
+ PCEP_ERRV_SRP_OBJECT_MISSING);
+ return false;
+ }
+
+ obj = pcep_obj_get(upd_msg->obj_list, PCEP_OBJ_CLASS_LSP);
+ if (obj == NULL) {
+ pcep_log(LOG_INFO,
+ "%s: Invalid PcUpd message: Missing LSP object",
+ __func__);
+ send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING,
+ PCEP_ERRV_LSP_OBJECT_MISSING);
+ return false;
+ }
+
+ obj = pcep_obj_get(upd_msg->obj_list, PCEP_OBJ_CLASS_ERO);
+ if (obj == NULL) {
+ pcep_log(LOG_INFO,
+ "%s: Invalid PcUpd message: Missing ERO object",
+ __func__);
+ send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING,
+ PCEP_ERRV_ERO_OBJECT_MISSING);
+ return false;
+ }
+
+ /* Verify the objects are are in the correct order */
+ double_linked_list_node *node = upd_msg->obj_list->head;
+ struct pcep_object_srp *srp_object =
+ (struct pcep_object_srp *)node->data;
+ if (srp_object->header.object_class != PCEP_OBJ_CLASS_SRP) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Invalid PcUpd message: First object must be an SRP, found [%d]",
+ __func__, srp_object->header.object_class);
+ send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING,
+ PCEP_ERRV_SRP_OBJECT_MISSING);
+ return false;
+ }
+
+ node = node->next_node;
+ struct pcep_object_lsp *lsp_object =
+ (struct pcep_object_lsp *)node->data;
+ if (lsp_object->header.object_class != PCEP_OBJ_CLASS_LSP) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Invalid PcUpd message: Second object must be an LSP, found [%d]",
+ __func__, lsp_object->header.object_class);
+ send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING,
+ PCEP_ERRV_LSP_OBJECT_MISSING);
+ return false;
+ }
+
+ node = node->next_node;
+ struct pcep_object_ro *ero_object = node->data;
+ if (ero_object->header.object_class != PCEP_OBJ_CLASS_ERO) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Invalid PcUpd message: Third object must be an ERO, found [%d]",
+ __func__, ero_object->header.object_class);
+ send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING,
+ PCEP_ERRV_ERO_OBJECT_MISSING);
+ return false;
+ }
+
+ return true;
+}
+
+bool handle_pcep_initiate(pcep_session *session, struct pcep_message *init_msg)
+{
+ /* Instantiate Message validation and errors according to:
+ * https://tools.ietf.org/html/rfc8281#section-5 */
+
+ if (init_msg->obj_list == NULL) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Invalid PcInitiate message: Message has no objects",
+ __func__);
+ send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING,
+ PCEP_ERRV_SRP_OBJECT_MISSING);
+ return false;
+ }
+
+ /* Verify the mandatory objects are present */
+ struct pcep_object_header *obj =
+ pcep_obj_get(init_msg->obj_list, PCEP_OBJ_CLASS_SRP);
+ if (obj == NULL) {
+ pcep_log(LOG_INFO,
+ "%s: Invalid PcInitiate message: Missing SRP object",
+ __func__);
+ send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING,
+ PCEP_ERRV_SRP_OBJECT_MISSING);
+ return false;
+ }
+
+ obj = pcep_obj_get(init_msg->obj_list, PCEP_OBJ_CLASS_LSP);
+ if (obj == NULL) {
+ pcep_log(LOG_INFO,
+ "%s: Invalid PcInitiate message: Missing LSP object",
+ __func__);
+ send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING,
+ PCEP_ERRV_LSP_OBJECT_MISSING);
+ return false;
+ }
+
+ /* Verify the objects are are in the correct order */
+ double_linked_list_node *node = init_msg->obj_list->head;
+ struct pcep_object_srp *srp_object =
+ (struct pcep_object_srp *)node->data;
+ if (srp_object->header.object_class != PCEP_OBJ_CLASS_SRP) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Invalid PcInitiate message: First object must be an SRP, found [%d]",
+ __func__, srp_object->header.object_class);
+ send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING,
+ PCEP_ERRV_SRP_OBJECT_MISSING);
+ return false;
+ }
+
+ node = node->next_node;
+ struct pcep_object_lsp *lsp_object =
+ (struct pcep_object_lsp *)node->data;
+ if (lsp_object->header.object_class != PCEP_OBJ_CLASS_LSP) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Invalid PcInitiate message: Second object must be an LSP, found [%d]",
+ __func__, lsp_object->header.object_class);
+ send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING,
+ PCEP_ERRV_LSP_OBJECT_MISSING);
+ return false;
+ }
+
+ /* There may be more optional objects */
+ return true;
+}
+
+void increment_unknown_message(pcep_session *session)
+{
+ /* https://tools.ietf.org/html/rfc5440#section-6.9
+ * If a PCC/PCE receives unrecognized messages at a rate equal or
+ * greater than MAX-UNKNOWN-MESSAGES unknown message requests per
+ * minute, the PCC/PCE MUST send a PCEP CLOSE message */
+
+ time_t *unknown_message_time =
+ pceplib_malloc(PCEPLIB_INFRA, sizeof(time_t));
+ *unknown_message_time = time(NULL);
+ time_t expire_time = *unknown_message_time + 60;
+ queue_enqueue(session->num_unknown_messages_time_queue,
+ unknown_message_time);
+
+ /* Purge any entries older than 1 minute. The oldest entries are at the
+ * queue head */
+ queue_node *time_node = session->num_unknown_messages_time_queue->head;
+ while (time_node != NULL) {
+ if (*((time_t *)time_node->data) > expire_time) {
+ pceplib_free(
+ PCEPLIB_INFRA,
+ queue_dequeue(
+ session->num_unknown_messages_time_queue));
+ time_node =
+ session->num_unknown_messages_time_queue->head;
+ } else {
+ time_node = NULL;
+ }
+ }
+
+ if ((int)session->num_unknown_messages_time_queue->num_entries
+ >= session->pcc_config.max_unknown_messages) {
+ pcep_log(
+ LOG_INFO,
+ "%s: [%ld-%ld] Max unknown messages reached [%d] closing session [%d]",
+ __func__, time(NULL), pthread_self(),
+ session->pcc_config.max_unknown_messages,
+ session->session_id);
+
+ close_pcep_session_with_reason(session,
+ PCEP_CLOSE_REASON_UNREC_MSG);
+ enqueue_event(session, PCC_RCVD_MAX_UNKOWN_MSGS, NULL);
+ }
+}
+
+bool check_and_send_open_keep_alive(pcep_session *session)
+{
+ if (session->pce_open_received == true
+ && session->pce_open_rejected == false
+ && session->pce_open_keep_alive_sent == false) {
+ /* Send the PCE Open keep-alive response if it hasnt been sent
+ * yet */
+ cancel_timer(session->timer_id_open_keep_alive);
+ session->timer_id_open_keep_alive = TIMER_ID_NOT_SET;
+ send_keep_alive(session);
+ session->pce_open_keep_alive_sent = true;
+
+ return true;
+ }
+
+ return false;
+}
+
+void log_pcc_pce_connection(pcep_session *session)
+{
+ if (session->socket_comm_session == NULL) {
+ /* This only happens in UT */
+ return;
+ }
+
+ char src_ip_buf[40] = {0}, dst_ip_buf[40] = {0};
+ uint16_t src_port, dst_port;
+
+ if (session->socket_comm_session->is_ipv6) {
+ inet_ntop(AF_INET6,
+ &session->socket_comm_session->src_sock_addr
+ .src_sock_addr_ipv6.sin6_addr,
+ src_ip_buf, sizeof(src_ip_buf));
+ inet_ntop(AF_INET6,
+ &session->socket_comm_session->dest_sock_addr
+ .dest_sock_addr_ipv6.sin6_addr,
+ dst_ip_buf, sizeof(dst_ip_buf));
+ src_port = htons(session->socket_comm_session->src_sock_addr
+ .src_sock_addr_ipv6.sin6_port);
+ dst_port = htons(session->socket_comm_session->dest_sock_addr
+ .dest_sock_addr_ipv6.sin6_port);
+ } else {
+ inet_ntop(AF_INET,
+ &session->socket_comm_session->src_sock_addr
+ .src_sock_addr_ipv4.sin_addr,
+ src_ip_buf, sizeof(src_ip_buf));
+ inet_ntop(AF_INET,
+ &session->socket_comm_session->dest_sock_addr
+ .dest_sock_addr_ipv4.sin_addr,
+ dst_ip_buf, sizeof(dst_ip_buf));
+ src_port = htons(session->socket_comm_session->src_sock_addr
+ .src_sock_addr_ipv4.sin_port);
+ dst_port = htons(session->socket_comm_session->dest_sock_addr
+ .dest_sock_addr_ipv4.sin_port);
+ }
+
+ pcep_log(
+ LOG_INFO,
+ "%s: [%ld-%ld] Successful PCC [%s:%d] connection to PCE [%s:%d] session [%d] fd [%d]",
+ __func__, time(NULL), pthread_self(), src_ip_buf, src_port,
+ dst_ip_buf, dst_port, session->session_id,
+ session->socket_comm_session->socket_fd);
+}
+
+/*
+ * these functions are called by session_logic_loop() from
+ * pcep_session_logic_loop.c these functions are executed in the
+ * session_logic_loop thread, and the mutex is locked before calling these
+ * functions, so they are thread safe.
+ */
+
+/* state machine handling for expired timers */
+void handle_timer_event(pcep_session_event *event)
+{
+ if (event == NULL) {
+ pcep_log(LOG_INFO, "%s: handle_timer_event NULL event",
+ __func__);
+ return;
+ }
+
+ pcep_session *session = event->session;
+
+ pcep_log(
+ LOG_INFO,
+ "%s: [%ld-%ld] pcep_session_logic handle_timer_event: session [%d] event timer_id [%d] session timers [OKW, OKA, DT, KA] [%d, %d, %d, %d]",
+ __func__, time(NULL), pthread_self(), session->session_id,
+ event->expired_timer_id, session->timer_id_open_keep_wait,
+ session->timer_id_open_keep_alive, session->timer_id_dead_timer,
+ session->timer_id_keep_alive);
+
+ /*
+ * these timer expirations are independent of the session state
+ */
+ if (event->expired_timer_id == session->timer_id_dead_timer) {
+ session->timer_id_dead_timer = TIMER_ID_NOT_SET;
+ increment_event_counters(session,
+ PCEP_EVENT_COUNTER_ID_TIMER_DEADTIMER);
+ close_pcep_session_with_reason(session,
+ PCEP_CLOSE_REASON_DEADTIMER);
+ enqueue_event(session, PCE_DEAD_TIMER_EXPIRED, NULL);
+ return;
+ } else if (event->expired_timer_id == session->timer_id_keep_alive) {
+ session->timer_id_keep_alive = TIMER_ID_NOT_SET;
+ increment_event_counters(session,
+ PCEP_EVENT_COUNTER_ID_TIMER_KEEPALIVE);
+ send_keep_alive(session);
+ return;
+ }
+
+ /*
+ * handle timers that depend on the session state
+ */
+ switch (session->session_state) {
+ case SESSION_STATE_PCEP_CONNECTING:
+ if (event->expired_timer_id
+ == session->timer_id_open_keep_wait) {
+ /* close the TCP session */
+ pcep_log(
+ LOG_INFO,
+ "%s: handle_timer_event open_keep_wait timer expired for session [%d]",
+ __func__, session->session_id);
+ increment_event_counters(
+ session,
+ PCEP_EVENT_COUNTER_ID_TIMER_OPENKEEPWAIT);
+ socket_comm_session_close_tcp_after_write(
+ session->socket_comm_session);
+ session->session_state = SESSION_STATE_INITIALIZED;
+ session->timer_id_open_keep_wait = TIMER_ID_NOT_SET;
+ enqueue_event(session, PCE_OPEN_KEEP_WAIT_TIMER_EXPIRED,
+ NULL);
+ }
+
+ if (event->expired_timer_id
+ == session->timer_id_open_keep_alive) {
+ increment_event_counters(
+ session,
+ PCEP_EVENT_COUNTER_ID_TIMER_OPENKEEPALIVE);
+ session->timer_id_open_keep_alive = TIMER_ID_NOT_SET;
+ if (check_and_send_open_keep_alive(session) == true) {
+ if (session->pcc_open_accepted == true
+ && session->session_state
+ != SESSION_STATE_PCEP_CONNECTED) {
+ log_pcc_pce_connection(session);
+ session->session_state =
+ SESSION_STATE_PCEP_CONNECTED;
+ increment_event_counters(
+ session,
+ PCEP_EVENT_COUNTER_ID_PCE_CONNECT);
+ enqueue_event(session,
+ PCC_CONNECTED_TO_PCE,
+ NULL);
+ }
+ }
+ return;
+ }
+ break;
+
+ case SESSION_STATE_INITIALIZED:
+ case SESSION_STATE_PCEP_CONNECTED:
+ default:
+ pcep_log(
+ LOG_INFO,
+ "%s: handle_timer_event unrecognized state transition, timer_id [%d] state [%d] session [%d]",
+ __func__, event->expired_timer_id,
+ session->session_state, session->session_id);
+ break;
+ }
+}
+
+/* State machine handling for received messages.
+ * This event was created in session_logic_msg_ready_handler() in
+ * pcep_session_logic_loop.c */
+void handle_socket_comm_event(pcep_session_event *event)
+{
+ if (event == NULL) {
+ pcep_log(LOG_INFO, "%s: handle_socket_comm_event NULL event",
+ __func__);
+ return;
+ }
+
+ pcep_session *session = event->session;
+
+ pcep_log(
+ LOG_INFO,
+ "%s: [%ld-%ld] pcep_session_logic handle_socket_comm_event: session [%d] num messages [%d] socket_closed [%d]",
+ __func__, time(NULL), pthread_self(), session->session_id,
+ (event->received_msg_list == NULL
+ ? -1
+ : (int)event->received_msg_list->num_entries),
+ event->socket_closed);
+
+ /*
+ * independent of the session state
+ */
+ if (event->socket_closed) {
+ pcep_log(
+ LOG_INFO,
+ "%s: handle_socket_comm_event socket closed for session [%d]",
+ __func__, session->session_id);
+ socket_comm_session_close_tcp(session->socket_comm_session);
+ enqueue_event(session, PCE_CLOSED_SOCKET, NULL);
+ if (session->session_state == SESSION_STATE_PCEP_CONNECTING) {
+ enqueue_event(session, PCC_CONNECTION_FAILURE, NULL);
+ }
+ session->session_state = SESSION_STATE_INITIALIZED;
+ increment_event_counters(session,
+ PCEP_EVENT_COUNTER_ID_PCE_DISCONNECT);
+ return;
+ }
+
+ reset_dead_timer(session);
+
+ if (event->received_msg_list == NULL) {
+ return;
+ }
+
+ /* Message received on socket */
+ double_linked_list_node *msg_node;
+ for (msg_node = event->received_msg_list->head; msg_node != NULL;
+ msg_node = msg_node->next_node) {
+ bool message_enqueued = false;
+ struct pcep_message *msg =
+ (struct pcep_message *)msg_node->data;
+ pcep_log(LOG_INFO, "%s: \t %s message", __func__,
+ get_message_type_str(msg->msg_header->type));
+
+ increment_message_rx_counters(session, msg);
+
+ switch (msg->msg_header->type) {
+ case PCEP_TYPE_OPEN:
+ /* handle_pcep_open() checks session state, and for
+ * duplicate erroneous open messages, and replies with
+ * error messages as needed. It also sets
+ * pce_open_received. */
+ if (handle_pcep_open(session, msg) == true) {
+ /* PCE Open Message Accepted */
+ enqueue_event(session, MESSAGE_RECEIVED, msg);
+ message_enqueued = true;
+ session->pce_open_accepted = true;
+ session->pce_open_rejected = false;
+ if (session->pcc_open_accepted) {
+ /* If both the PCC and PCE Opens are
+ * accepted, then the session is
+ * connected */
+
+ check_and_send_open_keep_alive(session);
+ log_pcc_pce_connection(session);
+ session->session_state =
+ SESSION_STATE_PCEP_CONNECTED;
+ increment_event_counters(
+ session,
+ PCEP_EVENT_COUNTER_ID_PCE_CONNECT);
+ enqueue_event(session,
+ PCC_CONNECTED_TO_PCE,
+ NULL);
+ }
+ }
+ break;
+
+ case PCEP_TYPE_KEEPALIVE:
+ if (session->session_state
+ == SESSION_STATE_PCEP_CONNECTING) {
+ /* PCC Open Message Accepted */
+ cancel_timer(session->timer_id_open_keep_wait);
+ session->timer_id_open_keep_wait =
+ TIMER_ID_NOT_SET;
+ session->pcc_open_accepted = true;
+ session->pcc_open_rejected = false;
+ check_and_send_open_keep_alive(session);
+
+ if (session->pce_open_accepted) {
+ /* If both the PCC and PCE Opens are
+ * accepted, then the session is
+ * connected */
+ log_pcc_pce_connection(session);
+ session->session_state =
+ SESSION_STATE_PCEP_CONNECTED;
+ increment_event_counters(
+ session,
+ PCEP_EVENT_COUNTER_ID_PCC_CONNECT);
+ enqueue_event(session,
+ PCC_CONNECTED_TO_PCE,
+ NULL);
+ }
+ }
+ /* The dead_timer was already reset above, so nothing
+ * extra to do here */
+ break;
+
+ case PCEP_TYPE_PCREP:
+ enqueue_event(session, MESSAGE_RECEIVED, msg);
+ message_enqueued = true;
+ break;
+
+ case PCEP_TYPE_CLOSE:
+ session->session_state = SESSION_STATE_INITIALIZED;
+ socket_comm_session_close_tcp(
+ session->socket_comm_session);
+ /* TODO should we also enqueue the message, so they can
+ * see the reasons?? */
+ enqueue_event(session, PCE_SENT_PCEP_CLOSE, NULL);
+ /* TODO could this duplicate the disconnect counter with
+ * socket close ?? */
+ increment_event_counters(
+ session, PCEP_EVENT_COUNTER_ID_PCE_DISCONNECT);
+ break;
+
+ case PCEP_TYPE_PCREQ:
+ /* The PCC does not support receiving PcReq messages */
+ send_pcep_error(session,
+ PCEP_ERRT_CAPABILITY_NOT_SUPPORTED,
+ PCEP_ERRV_UNASSIGNED);
+ break;
+
+ case PCEP_TYPE_REPORT:
+ /* The PCC does not support receiving Report messages */
+ send_pcep_error(session,
+ PCEP_ERRT_CAPABILITY_NOT_SUPPORTED,
+ PCEP_ERRV_UNASSIGNED);
+ break;
+
+ case PCEP_TYPE_UPDATE:
+ /* Should reply with a PcRpt */
+ if (handle_pcep_update(session, msg) == true) {
+ enqueue_event(session, MESSAGE_RECEIVED, msg);
+ message_enqueued = true;
+ }
+ break;
+
+ case PCEP_TYPE_INITIATE:
+ /* Should reply with a PcRpt */
+ if (handle_pcep_initiate(session, msg) == true) {
+ enqueue_event(session, MESSAGE_RECEIVED, msg);
+ message_enqueued = true;
+ }
+ break;
+
+ case PCEP_TYPE_PCNOTF:
+ enqueue_event(session, MESSAGE_RECEIVED, msg);
+ message_enqueued = true;
+ break;
+
+ case PCEP_TYPE_ERROR:
+ if (msg->obj_list != NULL
+ && msg->obj_list->num_entries > 0) {
+ struct pcep_object_header *obj_hdr =
+ pcep_obj_get(msg->obj_list,
+ PCEP_OBJ_CLASS_ERROR);
+ if (obj_hdr != NULL) {
+ struct pcep_object_error *error_obj =
+ (struct pcep_object_error *)
+ obj_hdr;
+ pcep_log(
+ LOG_DEBUG,
+ "%s: Error object [type, value] = [%s, %s]",
+ __func__,
+ get_error_type_str(
+ error_obj->error_type),
+ get_error_value_str(
+ error_obj->error_type,
+ error_obj
+ ->error_value));
+ }
+ }
+
+ if (session->session_state
+ == SESSION_STATE_PCEP_CONNECTING) {
+ /* A PCC_CONNECTION_FAILURE event will be sent
+ * when the socket is closed, if the state is
+ * SESSION_STATE_PCEP_CONNECTING, in case the
+ * PCE allows more than 2 failed open messages.
+ */
+ pcep_log(LOG_INFO,
+ "%s: PCC Open message rejected by PCE",
+ __func__);
+ session->pcc_open_rejected = true;
+ send_reconciled_pcep_open(session, msg);
+ enqueue_event(session, PCC_SENT_INVALID_OPEN,
+ NULL);
+ }
+ enqueue_event(session, MESSAGE_RECEIVED, msg);
+ message_enqueued = true;
+ break;
+
+ default:
+ pcep_log(LOG_INFO, "%s: \t UnSupported message",
+ __func__);
+ send_pcep_error(session,
+ PCEP_ERRT_CAPABILITY_NOT_SUPPORTED,
+ PCEP_ERRV_UNASSIGNED);
+ increment_unknown_message(session);
+ break;
+ }
+
+ /* if the message was enqueued, dont free it yet */
+ if (message_enqueued == false) {
+ pcep_msg_free_message(msg);
+ }
+ }
+ dll_destroy(event->received_msg_list);
+}
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+/*
+ * Implementation of public API functions.
+ */
+
+#include <zebra.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h> // gethostbyname
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h> // close
+
+#include <arpa/inet.h> // sockets etc.
+#include <sys/types.h> // sockets etc.
+#include <sys/socket.h> // sockets etc.
+
+#include "pcep.h"
+#include "pcep_socket_comm.h"
+#include "pcep_socket_comm_internals.h"
+#include "pcep_utils_logging.h"
+#include "pcep_utils_memory.h"
+#include "pcep_utils_ordered_list.h"
+#include "pcep_utils_queue.h"
+
+bool initialize_socket_comm_pre(void);
+bool socket_comm_session_initialize_post(
+ pcep_socket_comm_session *socket_comm_session);
+
+pcep_socket_comm_handle *socket_comm_handle_ = NULL;
+
+
+/* simple compare method callback used by pcep_utils_ordered_list
+ * for ordered list insertion. */
+int socket_fd_node_compare(void *list_entry, void *new_entry)
+{
+ return ((pcep_socket_comm_session *)new_entry)->socket_fd
+ - ((pcep_socket_comm_session *)list_entry)->socket_fd;
+}
+
+
+bool initialize_socket_comm_pre()
+{
+ socket_comm_handle_ =
+ pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_socket_comm_handle));
+ memset(socket_comm_handle_, 0, sizeof(pcep_socket_comm_handle));
+
+ socket_comm_handle_->active = true;
+ socket_comm_handle_->num_active_sessions = 0;
+ socket_comm_handle_->read_list =
+ ordered_list_initialize(socket_fd_node_compare);
+ socket_comm_handle_->write_list =
+ ordered_list_initialize(socket_fd_node_compare);
+ socket_comm_handle_->session_list =
+ ordered_list_initialize(pointer_compare_function);
+ FD_ZERO(&socket_comm_handle_->except_master_set);
+ FD_ZERO(&socket_comm_handle_->read_master_set);
+ FD_ZERO(&socket_comm_handle_->write_master_set);
+
+ if (pthread_mutex_init(&(socket_comm_handle_->socket_comm_mutex), NULL)
+ != 0) {
+ pcep_log(LOG_ERR, "%s: Cannot initialize socket_comm mutex.",
+ __func__);
+ pceplib_free(PCEPLIB_INFRA, socket_comm_handle_);
+ socket_comm_handle_ = NULL;
+
+ return false;
+ }
+
+ return true;
+}
+
+bool initialize_socket_comm_external_infra(
+ void *external_infra_data, ext_socket_read socket_read_cb,
+ ext_socket_write socket_write_cb,
+ ext_socket_pthread_create_callback thread_create_func)
+{
+ if (socket_comm_handle_ != NULL) {
+ /* already initialized */
+ return true;
+ }
+
+ if (initialize_socket_comm_pre() == false) {
+ return false;
+ }
+
+ /* Notice: If the thread_create_func is set, then both the
+ * socket_read_cb and the socket_write_cb SHOULD be NULL. */
+ if (thread_create_func != NULL) {
+ if (thread_create_func(
+ &(socket_comm_handle_->socket_comm_thread), NULL,
+ socket_comm_loop, socket_comm_handle_,
+ "pceplib_timers")) {
+ pcep_log(
+ LOG_ERR,
+ "%s: Cannot initialize external socket_comm thread.",
+ __func__);
+ return false;
+ }
+ }
+
+ socket_comm_handle_->external_infra_data = external_infra_data;
+ socket_comm_handle_->socket_write_func = socket_write_cb;
+ socket_comm_handle_->socket_read_func = socket_read_cb;
+
+ return true;
+}
+
+bool initialize_socket_comm_loop()
+{
+ if (socket_comm_handle_ != NULL) {
+ /* already initialized */
+ return true;
+ }
+
+ if (initialize_socket_comm_pre() == false) {
+ return false;
+ }
+
+ /* Launch socket comm loop pthread */
+ if (pthread_create(&(socket_comm_handle_->socket_comm_thread), NULL,
+ socket_comm_loop, socket_comm_handle_)) {
+ pcep_log(LOG_ERR, "%s: Cannot initialize socket_comm thread.",
+ __func__);
+ return false;
+ }
+
+ return true;
+}
+
+
+bool destroy_socket_comm_loop()
+{
+ socket_comm_handle_->active = false;
+
+ pthread_join(socket_comm_handle_->socket_comm_thread, NULL);
+ ordered_list_destroy(socket_comm_handle_->read_list);
+ ordered_list_destroy(socket_comm_handle_->write_list);
+ ordered_list_destroy(socket_comm_handle_->session_list);
+ pthread_mutex_destroy(&(socket_comm_handle_->socket_comm_mutex));
+
+ pceplib_free(PCEPLIB_INFRA, socket_comm_handle_);
+ socket_comm_handle_ = NULL;
+
+ return true;
+}
+
+/* Internal common init function */
+static pcep_socket_comm_session *socket_comm_session_initialize_pre(
+ message_received_handler message_handler,
+ message_ready_to_read_handler message_ready_handler,
+ message_sent_notifier msg_sent_notifier,
+ connection_except_notifier notifier, uint32_t connect_timeout_millis,
+ const char *tcp_authentication_str, bool is_tcp_auth_md5,
+ void *session_data)
+{
+ /* check that not both message handlers were set */
+ if (message_handler != NULL && message_ready_handler != NULL) {
+ pcep_log(
+ LOG_WARNING,
+ "%s: Only one of <message_received_handler | message_ready_to_read_handler> can be set.",
+ __func__);
+ return NULL;
+ }
+
+ /* check that at least one message handler was set */
+ if (message_handler == NULL && message_ready_handler == NULL) {
+ pcep_log(
+ LOG_WARNING,
+ "%s: At least one of <message_received_handler | message_ready_to_read_handler> must be set.",
+ __func__);
+ return NULL;
+ }
+
+ if (!initialize_socket_comm_loop()) {
+ pcep_log(LOG_WARNING,
+ "%s: ERROR: cannot initialize socket_comm_loop.",
+ __func__);
+
+ return NULL;
+ }
+
+ /* initialize everything for a pcep_session socket_comm */
+
+ pcep_socket_comm_session *socket_comm_session =
+ pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_socket_comm_session));
+ memset(socket_comm_session, 0, sizeof(pcep_socket_comm_session));
+
+ socket_comm_handle_->num_active_sessions++;
+ socket_comm_session->close_after_write = false;
+ socket_comm_session->session_data = session_data;
+ socket_comm_session->message_handler = message_handler;
+ socket_comm_session->message_ready_to_read_handler =
+ message_ready_handler;
+ socket_comm_session->message_sent_handler = msg_sent_notifier;
+ socket_comm_session->conn_except_notifier = notifier;
+ socket_comm_session->message_queue = queue_initialize();
+ socket_comm_session->connect_timeout_millis = connect_timeout_millis;
+ socket_comm_session->external_socket_data = NULL;
+ if (tcp_authentication_str != NULL) {
+ socket_comm_session->is_tcp_auth_md5 = is_tcp_auth_md5;
+ strlcpy(socket_comm_session->tcp_authentication_str,
+ tcp_authentication_str,
+ sizeof(socket_comm_session->tcp_authentication_str));
+ }
+
+ return socket_comm_session;
+}
+
+/* Internal common init function */
+bool socket_comm_session_initialize_post(
+ pcep_socket_comm_session *socket_comm_session)
+{
+ /* If we dont use SO_REUSEADDR, the socket will take 2 TIME_WAIT
+ * periods before being closed in the kernel if bind() was called */
+ int reuse_addr = 1;
+ if (setsockopt(socket_comm_session->socket_fd, SOL_SOCKET, SO_REUSEADDR,
+ &reuse_addr, sizeof(int))
+ < 0) {
+ pcep_log(
+ LOG_WARNING,
+ "%s: Error in setsockopt() SO_REUSEADDR errno [%d %s].",
+ __func__, errno, strerror(errno));
+ socket_comm_session_teardown(socket_comm_session);
+
+ return false;
+ }
+
+ struct sockaddr *src_sock_addr =
+ (socket_comm_session->is_ipv6
+ ? (struct sockaddr *)&(
+ socket_comm_session->src_sock_addr
+ .src_sock_addr_ipv6)
+ : (struct sockaddr *)&(
+ socket_comm_session->src_sock_addr
+ .src_sock_addr_ipv4));
+ int addr_len = (socket_comm_session->is_ipv6
+ ? sizeof(socket_comm_session->src_sock_addr
+ .src_sock_addr_ipv6)
+ : sizeof(socket_comm_session->src_sock_addr
+ .src_sock_addr_ipv4));
+ if (bind(socket_comm_session->socket_fd, src_sock_addr, addr_len)
+ == -1) {
+ pcep_log(LOG_WARNING,
+ "%s: Cannot bind address to socket errno [%d %s].",
+ __func__, errno, strerror(errno));
+ socket_comm_session_teardown(socket_comm_session);
+
+ return false;
+ }
+
+ /* Register the session as active with the Socket Comm Loop */
+ pthread_mutex_lock(&(socket_comm_handle_->socket_comm_mutex));
+ ordered_list_add_node(socket_comm_handle_->session_list,
+ socket_comm_session);
+ pthread_mutex_unlock(&(socket_comm_handle_->socket_comm_mutex));
+
+ /* dont connect to the destination yet, since the PCE will have a timer
+ * for max time between TCP connect and PCEP open. we'll connect later
+ * when we send the PCEP open. */
+
+ return true;
+}
+
+
+pcep_socket_comm_session *socket_comm_session_initialize(
+ message_received_handler message_handler,
+ message_ready_to_read_handler message_ready_handler,
+ message_sent_notifier msg_sent_notifier,
+ connection_except_notifier notifier, struct in_addr *dest_ip,
+ short dest_port, uint32_t connect_timeout_millis,
+ const char *tcp_authentication_str, bool is_tcp_auth_md5,
+ void *session_data)
+{
+ return socket_comm_session_initialize_with_src(
+ message_handler, message_ready_handler, msg_sent_notifier,
+ notifier, NULL, 0, dest_ip, dest_port, connect_timeout_millis,
+ tcp_authentication_str, is_tcp_auth_md5, session_data);
+}
+
+pcep_socket_comm_session *socket_comm_session_initialize_ipv6(
+ message_received_handler message_handler,
+ message_ready_to_read_handler message_ready_handler,
+ message_sent_notifier msg_sent_notifier,
+ connection_except_notifier notifier, struct in6_addr *dest_ip,
+ short dest_port, uint32_t connect_timeout_millis,
+ const char *tcp_authentication_str, bool is_tcp_auth_md5,
+ void *session_data)
+{
+ return socket_comm_session_initialize_with_src_ipv6(
+ message_handler, message_ready_handler, msg_sent_notifier,
+ notifier, NULL, 0, dest_ip, dest_port, connect_timeout_millis,
+ tcp_authentication_str, is_tcp_auth_md5, session_data);
+}
+
+
+pcep_socket_comm_session *socket_comm_session_initialize_with_src(
+ message_received_handler message_handler,
+ message_ready_to_read_handler message_ready_handler,
+ message_sent_notifier msg_sent_notifier,
+ connection_except_notifier notifier, struct in_addr *src_ip,
+ short src_port, struct in_addr *dest_ip, short dest_port,
+ uint32_t connect_timeout_millis, const char *tcp_authentication_str,
+ bool is_tcp_auth_md5, void *session_data)
+{
+ if (dest_ip == NULL) {
+ pcep_log(LOG_WARNING, "%s: dest_ipv4 is NULL", __func__);
+ return NULL;
+ }
+
+ pcep_socket_comm_session *socket_comm_session =
+ socket_comm_session_initialize_pre(
+ message_handler, message_ready_handler,
+ msg_sent_notifier, notifier, connect_timeout_millis,
+ tcp_authentication_str, is_tcp_auth_md5, session_data);
+ if (socket_comm_session == NULL) {
+ return NULL;
+ }
+
+ socket_comm_session->socket_fd =
+ socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (socket_comm_session->socket_fd == -1) {
+ pcep_log(LOG_WARNING,
+ "%s: Cannot create ipv4 socket errno [%d %s].",
+ __func__, errno, strerror(errno));
+ socket_comm_session_teardown(
+ socket_comm_session); // socket_comm_session freed
+ // inside fn so NOLINT next.
+
+ return NULL; // NOLINT(clang-analyzer-unix.Malloc)
+ }
+
+ socket_comm_session->is_ipv6 = false;
+ socket_comm_session->dest_sock_addr.dest_sock_addr_ipv4.sin_family =
+ AF_INET;
+ socket_comm_session->src_sock_addr.src_sock_addr_ipv4.sin_family =
+ AF_INET;
+ socket_comm_session->dest_sock_addr.dest_sock_addr_ipv4.sin_port =
+ htons(dest_port);
+ socket_comm_session->src_sock_addr.src_sock_addr_ipv4.sin_port =
+ htons(src_port);
+ socket_comm_session->dest_sock_addr.dest_sock_addr_ipv4.sin_addr
+ .s_addr = dest_ip->s_addr;
+ if (src_ip != NULL) {
+ socket_comm_session->src_sock_addr.src_sock_addr_ipv4.sin_addr
+ .s_addr = src_ip->s_addr;
+ } else {
+ socket_comm_session->src_sock_addr.src_sock_addr_ipv4.sin_addr
+ .s_addr = INADDR_ANY;
+ }
+
+ if (socket_comm_session_initialize_post(socket_comm_session) == false) {
+ return NULL;
+ }
+
+ return socket_comm_session;
+}
+
+pcep_socket_comm_session *socket_comm_session_initialize_with_src_ipv6(
+ message_received_handler message_handler,
+ message_ready_to_read_handler message_ready_handler,
+ message_sent_notifier msg_sent_notifier,
+ connection_except_notifier notifier, struct in6_addr *src_ip,
+ short src_port, struct in6_addr *dest_ip, short dest_port,
+ uint32_t connect_timeout_millis, const char *tcp_authentication_str,
+ bool is_tcp_auth_md5, void *session_data)
+{
+ if (dest_ip == NULL) {
+ pcep_log(LOG_WARNING, "%s: dest_ipv6 is NULL", __func__);
+ return NULL;
+ }
+
+ pcep_socket_comm_session *socket_comm_session =
+ socket_comm_session_initialize_pre(
+ message_handler, message_ready_handler,
+ msg_sent_notifier, notifier, connect_timeout_millis,
+ tcp_authentication_str, is_tcp_auth_md5, session_data);
+ if (socket_comm_session == NULL) {
+ return NULL;
+ }
+
+ socket_comm_session->socket_fd =
+ socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP);
+ if (socket_comm_session->socket_fd == -1) {
+ pcep_log(LOG_WARNING,
+ "%s: Cannot create ipv6 socket errno [%d %s].",
+ __func__, errno, strerror(errno));
+ socket_comm_session_teardown(
+ socket_comm_session); // socket_comm_session freed
+ // inside fn so NOLINT next.
+
+ return NULL; // NOLINT(clang-analyzer-unix.Malloc)
+ }
+
+ socket_comm_session->is_ipv6 = true;
+ socket_comm_session->dest_sock_addr.dest_sock_addr_ipv6.sin6_family =
+ AF_INET6;
+ socket_comm_session->src_sock_addr.src_sock_addr_ipv6.sin6_family =
+ AF_INET6;
+ socket_comm_session->dest_sock_addr.dest_sock_addr_ipv6.sin6_port =
+ htons(dest_port);
+ socket_comm_session->src_sock_addr.src_sock_addr_ipv6.sin6_port =
+ htons(src_port);
+ memcpy(&socket_comm_session->dest_sock_addr.dest_sock_addr_ipv6
+ .sin6_addr,
+ dest_ip, sizeof(struct in6_addr));
+ if (src_ip != NULL) {
+ memcpy(&socket_comm_session->src_sock_addr.src_sock_addr_ipv6
+ .sin6_addr,
+ src_ip, sizeof(struct in6_addr));
+ } else {
+ socket_comm_session->src_sock_addr.src_sock_addr_ipv6
+ .sin6_addr = in6addr_any;
+ }
+
+ if (socket_comm_session_initialize_post(socket_comm_session) == false) {
+ return NULL;
+ }
+
+ return socket_comm_session;
+}
+
+
+bool socket_comm_session_connect_tcp(
+ pcep_socket_comm_session *socket_comm_session)
+{
+ if (socket_comm_session == NULL) {
+ pcep_log(
+ LOG_WARNING,
+ "%s: socket_comm_session_connect_tcp NULL socket_comm_session.",
+ __func__);
+ return NULL;
+ }
+
+ /* Set the socket to non-blocking, so connect() does not block */
+ int fcntl_arg;
+ if ((fcntl_arg = fcntl(socket_comm_session->socket_fd, F_GETFL, NULL))
+ < 0) {
+ pcep_log(LOG_WARNING, "%s: Error fcntl(..., F_GETFL) [%d %s]",
+ __func__, errno, strerror(errno));
+ return false;
+ }
+
+ fcntl_arg |= O_NONBLOCK;
+ if (fcntl(socket_comm_session->socket_fd, F_SETFL, fcntl_arg) < 0) {
+ pcep_log(LOG_WARNING, "%s: Error fcntl(..., F_SETFL) [%d %s]",
+ __func__, errno, strerror(errno));
+ return false;
+ }
+
+#if HAVE_DECL_TCP_MD5SIG
+ /* TCP authentication, currently only TCP MD5 RFC2385 is supported */
+ if (socket_comm_session->tcp_authentication_str[0] != '\0') {
+#if defined(linux) || defined(GNU_LINUX)
+ struct tcp_md5sig sig;
+ memset(&sig, 0, sizeof(sig));
+ if (socket_comm_session->is_ipv6) {
+ memcpy(&sig.tcpm_addr,
+ &socket_comm_session->dest_sock_addr
+ .dest_sock_addr_ipv6,
+ sizeof(struct sockaddr_in6));
+ } else {
+ memcpy(&sig.tcpm_addr,
+ &socket_comm_session->dest_sock_addr
+ .dest_sock_addr_ipv4,
+ sizeof(struct sockaddr_in));
+ }
+ sig.tcpm_keylen =
+ strlen(socket_comm_session->tcp_authentication_str);
+ memcpy(sig.tcpm_key,
+ socket_comm_session->tcp_authentication_str,
+ sig.tcpm_keylen);
+#else
+ int sig = 1;
+#endif
+ if (setsockopt(socket_comm_session->socket_fd, IPPROTO_TCP,
+ TCP_MD5SIG, &sig, sizeof(sig))
+ == -1) {
+ pcep_log(LOG_ERR, "%s: Failed to setsockopt(): [%d %s]",
+ __func__, errno, strerror(errno));
+ return false;
+ }
+ }
+#endif
+
+ int connect_result = 0;
+ if (socket_comm_session->is_ipv6) {
+ connect_result = connect(
+ socket_comm_session->socket_fd,
+ (struct sockaddr *)&(socket_comm_session->dest_sock_addr
+ .dest_sock_addr_ipv6),
+ sizeof(socket_comm_session->dest_sock_addr
+ .dest_sock_addr_ipv6));
+ } else {
+ connect_result = connect(
+ socket_comm_session->socket_fd,
+ (struct sockaddr *)&(socket_comm_session->dest_sock_addr
+ .dest_sock_addr_ipv4),
+ sizeof(socket_comm_session->dest_sock_addr
+ .dest_sock_addr_ipv4));
+ }
+
+ if (connect_result < 0) {
+ if (errno == EINPROGRESS) {
+ /* Calculate the configured timeout in seconds and
+ * microseconds */
+ struct timeval tv;
+ if (socket_comm_session->connect_timeout_millis
+ > 1000) {
+ tv.tv_sec = socket_comm_session
+ ->connect_timeout_millis
+ / 1000;
+ tv.tv_usec = (socket_comm_session
+ ->connect_timeout_millis
+ - (tv.tv_sec * 1000))
+ * 1000;
+ } else {
+ tv.tv_sec = 0;
+ tv.tv_usec = socket_comm_session
+ ->connect_timeout_millis
+ * 1000;
+ }
+
+ /* Use select to wait a max timeout for connect
+ * https://stackoverflow.com/questions/2597608/c-socket-connection-timeout
+ */
+ fd_set fdset;
+ FD_ZERO(&fdset);
+ FD_SET(socket_comm_session->socket_fd, &fdset);
+ if (select(socket_comm_session->socket_fd + 1, NULL,
+ &fdset, NULL, &tv)
+ > 0) {
+ int so_error;
+ socklen_t len = sizeof(so_error);
+ getsockopt(socket_comm_session->socket_fd,
+ SOL_SOCKET, SO_ERROR, &so_error,
+ &len);
+ if (so_error) {
+ pcep_log(
+ LOG_WARNING,
+ "%s: TCP connect failed on socket_fd [%d].",
+ __func__,
+ socket_comm_session->socket_fd);
+ return false;
+ }
+ } else {
+ pcep_log(
+ LOG_WARNING,
+ "%s: TCP connect timed-out on socket_fd [%d].",
+ __func__,
+ socket_comm_session->socket_fd);
+ return false;
+ }
+ } else {
+ pcep_log(
+ LOG_WARNING,
+ "%s: TCP connect, error connecting on socket_fd [%d] errno [%d %s]",
+ __func__, socket_comm_session->socket_fd, errno,
+ strerror(errno));
+ return false;
+ }
+ }
+
+ pthread_mutex_lock(&(socket_comm_handle_->socket_comm_mutex));
+ /* once the TCP connection is open, we should be ready to read at any
+ * time */
+ ordered_list_add_node(socket_comm_handle_->read_list,
+ socket_comm_session);
+
+ if (socket_comm_handle_->socket_read_func != NULL) {
+ socket_comm_handle_->socket_read_func(
+ socket_comm_handle_->external_infra_data,
+ &socket_comm_session->external_socket_data,
+ socket_comm_session->socket_fd, socket_comm_handle_);
+ }
+ pthread_mutex_unlock(&(socket_comm_handle_->socket_comm_mutex));
+
+ return true;
+}
+
+
+bool socket_comm_session_close_tcp(
+ pcep_socket_comm_session *socket_comm_session)
+{
+ if (socket_comm_session == NULL) {
+ pcep_log(
+ LOG_WARNING,
+ "%s: socket_comm_session_close_tcp NULL socket_comm_session.",
+ __func__);
+ return false;
+ }
+
+ pcep_log(LOG_DEBUG,
+ "%s: socket_comm_session_close_tcp close() socket fd [%d]",
+ __func__, socket_comm_session->socket_fd);
+
+ pthread_mutex_lock(&(socket_comm_handle_->socket_comm_mutex));
+ ordered_list_remove_first_node_equals(socket_comm_handle_->read_list,
+ socket_comm_session);
+ ordered_list_remove_first_node_equals(socket_comm_handle_->write_list,
+ socket_comm_session);
+ // TODO should it be close() or shutdown()??
+ close(socket_comm_session->socket_fd);
+ socket_comm_session->socket_fd = -1;
+ pthread_mutex_unlock(&(socket_comm_handle_->socket_comm_mutex));
+
+ return true;
+}
+
+
+bool socket_comm_session_close_tcp_after_write(
+ pcep_socket_comm_session *socket_comm_session)
+{
+ if (socket_comm_session == NULL) {
+ pcep_log(
+ LOG_WARNING,
+ "%s: socket_comm_session_close_tcp_after_write NULL socket_comm_session.",
+ __func__);
+ return false;
+ }
+
+ pthread_mutex_lock(&(socket_comm_handle_->socket_comm_mutex));
+ socket_comm_session->close_after_write = true;
+ pthread_mutex_unlock(&(socket_comm_handle_->socket_comm_mutex));
+
+ return true;
+}
+
+
+bool socket_comm_session_teardown(pcep_socket_comm_session *socket_comm_session)
+{
+ if (socket_comm_handle_ == NULL) {
+ pcep_log(LOG_WARNING,
+ "%s: Cannot teardown NULL socket_comm_handle",
+ __func__);
+ return false;
+ }
+
+ if (socket_comm_session == NULL) {
+ pcep_log(LOG_WARNING, "%s: Cannot teardown NULL session",
+ __func__);
+ return false;
+ }
+
+ if (comm_session_exists_locking(socket_comm_handle_,
+ socket_comm_session)
+ == false) {
+ pcep_log(LOG_WARNING,
+ "%s: Cannot teardown session that does not exist",
+ __func__);
+ return false;
+ }
+
+ if (socket_comm_session->socket_fd >= 0) {
+ shutdown(socket_comm_session->socket_fd, SHUT_RDWR);
+ close(socket_comm_session->socket_fd);
+ }
+
+ pthread_mutex_lock(&(socket_comm_handle_->socket_comm_mutex));
+ queue_destroy(socket_comm_session->message_queue);
+ ordered_list_remove_first_node_equals(socket_comm_handle_->session_list,
+ socket_comm_session);
+ ordered_list_remove_first_node_equals(socket_comm_handle_->read_list,
+ socket_comm_session);
+ ordered_list_remove_first_node_equals(socket_comm_handle_->write_list,
+ socket_comm_session);
+ socket_comm_handle_->num_active_sessions--;
+ pthread_mutex_unlock(&(socket_comm_handle_->socket_comm_mutex));
+
+ pcep_log(
+ LOG_INFO,
+ "%s: [%ld-%ld] socket_comm_session fd [%d] destroyed, [%d] sessions remaining",
+ __func__, time(NULL), pthread_self(),
+ socket_comm_session->socket_fd,
+ socket_comm_handle_->num_active_sessions);
+
+ pceplib_free(PCEPLIB_INFRA, socket_comm_session);
+
+ /* It would be nice to call destroy_socket_comm_loop() here if
+ * socket_comm_handle_->num_active_sessions == 0, but this function
+ * will usually be called from the message_sent_notifier callback,
+ * which gets called in the middle of the socket_comm_loop, and that
+ * is dangerous, so destroy_socket_comm_loop() must be called upon
+ * application exit. */
+
+ return true;
+}
+
+
+void socket_comm_session_send_message(
+ pcep_socket_comm_session *socket_comm_session,
+ const char *encoded_message, unsigned int msg_length,
+ bool free_after_send)
+{
+ if (socket_comm_session == NULL) {
+ pcep_log(
+ LOG_WARNING,
+ "%s: socket_comm_session_send_message NULL socket_comm_session.",
+ __func__);
+ return;
+ }
+
+ pcep_socket_comm_queued_message *queued_message = pceplib_malloc(
+ PCEPLIB_MESSAGES, sizeof(pcep_socket_comm_queued_message));
+ queued_message->encoded_message = encoded_message;
+ queued_message->msg_length = msg_length;
+ queued_message->free_after_send = free_after_send;
+
+ pthread_mutex_lock(&(socket_comm_handle_->socket_comm_mutex));
+
+ /* Do not proceed if the socket_comm_session has been deleted */
+ if (ordered_list_find(socket_comm_handle_->session_list,
+ socket_comm_session)
+ == NULL) {
+ /* Should never get here, only if the session was deleted and
+ * someone still tries to write on it */
+ pcep_log(
+ LOG_WARNING,
+ "%s: Cannot write a message on a deleted socket comm session, discarding message",
+ __func__);
+ pthread_mutex_unlock(&(socket_comm_handle_->socket_comm_mutex));
+ pceplib_free(PCEPLIB_MESSAGES, queued_message);
+
+ return;
+ }
+
+ /* Do not proceed if the socket has been closed */
+ if (socket_comm_session->socket_fd < 0) {
+ /* Should never get here, only if the session was deleted and
+ * someone still tries to write on it */
+ pcep_log(
+ LOG_WARNING,
+ "%s: Cannot write a message on a closed socket, discarding message",
+ __func__);
+ pthread_mutex_unlock(&(socket_comm_handle_->socket_comm_mutex));
+ pceplib_free(PCEPLIB_MESSAGES, queued_message);
+
+ return;
+ }
+
+ queue_enqueue(socket_comm_session->message_queue, queued_message);
+
+ /* Add it to the write list only if its not already there */
+ if (ordered_list_find(socket_comm_handle_->write_list,
+ socket_comm_session)
+ == NULL) {
+ ordered_list_add_node(socket_comm_handle_->write_list,
+ socket_comm_session);
+ }
+
+ if (socket_comm_handle_->socket_write_func != NULL) {
+ socket_comm_handle_->socket_write_func(
+ socket_comm_handle_->external_infra_data,
+ &socket_comm_session->external_socket_data,
+ socket_comm_session->socket_fd, socket_comm_handle_);
+ }
+ pthread_mutex_unlock(&(socket_comm_handle_->socket_comm_mutex));
+}
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+/*
+ * Declaration of public API functions.
+ */
+
+#ifndef INCLUDE_PCEPSOCKETCOMM_H_
+#define INCLUDE_PCEPSOCKETCOMM_H_
+
+#include "pcep.h"
+#include <arpa/inet.h> // sockaddr_in
+#include <netinet/tcp.h>
+#include <stdbool.h>
+
+#include "pcep_utils_queue.h"
+
+#define MAX_RECVD_MSG_SIZE 2048
+
+/*
+ * A socket_comm_session can be initialized with 1 of 2 types of mutually
+ * exclusive message callbacks:
+ * - message_received_handler : the socket_comm library reads the message and
+ * calls the callback with the message_data and message_length. this callback
+ * should be used for smaller/simpler messages.
+ * - message_ready_to_read_handler : the socket_comm library will call this
+ * callback when a message is ready to be read on a socket_fd. this callback
+ * should be used if the
+ */
+
+/* message received handler that receives the message data and message length */
+typedef void (*message_received_handler)(void *session_data,
+ const char *message_data,
+ unsigned int message_length);
+/* message ready received handler that should read the message on socket_fd
+ * and return the number of bytes read */
+typedef int (*message_ready_to_read_handler)(void *session_data, int socket_fd);
+/* callback handler called when a messages is sent */
+typedef void (*message_sent_notifier)(void *session_data, int socket_fd);
+/* callback handler called when the socket is closed */
+typedef void (*connection_except_notifier)(void *session_data, int socket_fd);
+
+/* Function pointers when an external socket infrastructure is used */
+typedef int (*ext_socket_write)(void *infra_data, void **infra_socket_data,
+ int fd, void *data);
+typedef int (*ext_socket_read)(void *infra_data, void **infra_socket_data,
+ int fd, void *data);
+typedef int (*ext_socket_pthread_create_callback)(
+ pthread_t *pthread_id, const pthread_attr_t *attr,
+ void *(*start_routine)(void *), void *data, const char *thread_name);
+
+typedef struct pcep_socket_comm_session_ {
+ message_received_handler message_handler;
+ message_ready_to_read_handler message_ready_to_read_handler;
+ message_sent_notifier message_sent_handler;
+ connection_except_notifier conn_except_notifier;
+ union src_sock_addr {
+ struct sockaddr_in src_sock_addr_ipv4;
+ struct sockaddr_in6 src_sock_addr_ipv6;
+ } src_sock_addr;
+ union dest_sock_addr {
+ struct sockaddr_in dest_sock_addr_ipv4;
+ struct sockaddr_in6 dest_sock_addr_ipv6;
+ } dest_sock_addr;
+ bool is_ipv6;
+ uint32_t connect_timeout_millis;
+ int socket_fd;
+ void *session_data;
+ queue_handle *message_queue;
+ char received_message[MAX_RECVD_MSG_SIZE];
+ int received_bytes;
+ bool close_after_write;
+ void *external_socket_data; /* used for external socket infra */
+ char tcp_authentication_str[TCP_MD5SIG_MAXKEYLEN
+ + 1]; /* should be used with is_tcp_auth_md5
+ flag */
+ bool is_tcp_auth_md5; /* flag to distinguish between rfc 2385 (md5) and
+ rfc 5925 (tcp-ao) */
+
+} pcep_socket_comm_session;
+
+
+/* Need to document that when the msg_rcv_handler is called, the data needs
+ * to be handled in the same function call, else it may be overwritten by
+ * the next read from this socket */
+
+
+/* Initialize the Socket Comm infrastructure, with either an internal pthread
+ * or with an external infrastructure.
+ * If an internal pthread infrastructure is to be used, then it is not necessary
+ * to explicitly call initialize_socket_comm_loop() as it will be called
+ * internally when a socket comm session is initialized. */
+
+/* Initialize the Socket Comm infrastructure with an internal pthread */
+bool initialize_socket_comm_loop(void);
+/* Initialize the Socket Comm infrastructure with an external infrastructure.
+ * Notice: If the thread_create_func is set, then both the socket_read_cb
+ * and the socket_write_cb SHOULD be NULL. */
+bool initialize_socket_comm_external_infra(
+ void *external_infra_data, ext_socket_read socket_read_cb,
+ ext_socket_write socket_write_cb,
+ ext_socket_pthread_create_callback thread_create_func);
+
+/* The msg_rcv_handler and msg_ready_handler are mutually exclusive, and only
+ * one can be set (as explained above), else NULL will be returned. */
+pcep_socket_comm_session *
+socket_comm_session_initialize(message_received_handler msg_rcv_handler,
+ message_ready_to_read_handler msg_ready_handler,
+ message_sent_notifier msg_sent_notifier,
+ connection_except_notifier notifier,
+ struct in_addr *dst_ip, short dst_port,
+ uint32_t connect_timeout_millis,
+ const char *tcp_authentication_str,
+ bool is_tcp_auth_md5, void *session_data);
+
+pcep_socket_comm_session *socket_comm_session_initialize_ipv6(
+ message_received_handler msg_rcv_handler,
+ message_ready_to_read_handler msg_ready_handler,
+ message_sent_notifier msg_sent_notifier,
+ connection_except_notifier notifier, struct in6_addr *dst_ip,
+ short dst_port, uint32_t connect_timeout_millis,
+ const char *tcp_authentication_str, bool is_tcp_auth_md5,
+ void *session_data);
+
+pcep_socket_comm_session *socket_comm_session_initialize_with_src(
+ message_received_handler msg_rcv_handler,
+ message_ready_to_read_handler msg_ready_handler,
+ message_sent_notifier msg_sent_notifier,
+ connection_except_notifier notifier, struct in_addr *src_ip,
+ short src_port, struct in_addr *dst_ip, short dst_port,
+ uint32_t connect_timeout_millis, const char *tcp_authentication_str,
+ bool is_tcp_auth_md5, void *session_data);
+
+pcep_socket_comm_session *socket_comm_session_initialize_with_src_ipv6(
+ message_received_handler msg_rcv_handler,
+ message_ready_to_read_handler msg_ready_handler,
+ message_sent_notifier msg_sent_notifier,
+ connection_except_notifier notifier, struct in6_addr *src_ip,
+ short src_port, struct in6_addr *dst_ip, short dst_port,
+ uint32_t connect_timeout_millis, const char *tcp_authentication_str,
+ bool is_tcp_auth_md5, void *session_data);
+
+bool socket_comm_session_teardown(
+ pcep_socket_comm_session *socket_comm_session);
+
+bool socket_comm_session_connect_tcp(
+ pcep_socket_comm_session *socket_comm_session);
+
+/* Immediately close the TCP connection, irregardless if there are pending
+ * messages to be sent. */
+bool socket_comm_session_close_tcp(
+ pcep_socket_comm_session *socket_comm_session);
+
+/* Sets a flag to close the TCP connection either after all the pending messages
+ * are written, or if there are no pending messages, the next time the socket is
+ * checked to be writeable. */
+bool socket_comm_session_close_tcp_after_write(
+ pcep_socket_comm_session *socket_comm_session);
+
+void socket_comm_session_send_message(
+ pcep_socket_comm_session *socket_comm_session,
+ const char *encoded_message, unsigned int msg_length,
+ bool free_after_send);
+
+/* If an external Socket infra like FRR is used, then these functions will
+ * be called when a socket is ready to read/write in the external infra.
+ * Implemented in pcep_socket_comm_loop.c */
+int pceplib_external_socket_read(int fd, void *payload);
+int pceplib_external_socket_write(int fd, void *payload);
+
+/* the socket comm loop is started internally by
+ * socket_comm_session_initialize()
+ * but needs to be explicitly stopped with this call. */
+bool destroy_socket_comm_loop(void);
+
+int socket_fd_node_compare(void *list_entry, void *new_entry);
+
+#endif /* INCLUDE_PCEPSOCKETCOMM_H_ */
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#ifndef SRC_PCEPSOCKETCOMMINTERNALS_H_
+#define SRC_PCEPSOCKETCOMMINTERNALS_H_
+
+#include <pthread.h>
+#include <stdbool.h>
+
+#include "pcep_utils_ordered_list.h"
+#include "pcep_socket_comm.h"
+
+
+typedef struct pcep_socket_comm_handle_ {
+ bool active;
+ pthread_t socket_comm_thread;
+ pthread_mutex_t socket_comm_mutex;
+ fd_set read_master_set;
+ fd_set write_master_set;
+ fd_set except_master_set;
+ /* ordered_list of socket_descriptors to read from */
+ ordered_list_handle *read_list;
+ /* ordered_list of socket_descriptors to write to */
+ ordered_list_handle *write_list;
+ ordered_list_handle *session_list;
+ int num_active_sessions;
+ void *external_infra_data;
+ ext_socket_write socket_write_func;
+ ext_socket_read socket_read_func;
+
+} pcep_socket_comm_handle;
+
+
+typedef struct pcep_socket_comm_queued_message_ {
+ const char *encoded_message;
+ int msg_length;
+ bool free_after_send;
+
+} pcep_socket_comm_queued_message;
+
+
+/* Functions implemented in pcep_socket_comm_loop.c */
+void *socket_comm_loop(void *data);
+bool comm_session_exists(pcep_socket_comm_handle *socket_comm_handle,
+ pcep_socket_comm_session *socket_comm_session);
+bool comm_session_exists_locking(pcep_socket_comm_handle *socket_comm_handle,
+ pcep_socket_comm_session *socket_comm_session);
+
+#endif /* SRC_PCEPSOCKETCOMMINTERNALS_H_ */
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+#include <assert.h>
+
+#include "pcep_socket_comm_internals.h"
+#include "pcep_socket_comm_loop.h"
+#include "pcep_utils_logging.h"
+#include "pcep_utils_ordered_list.h"
+#include "pcep_utils_logging.h"
+#include "pcep_utils_memory.h"
+
+void write_message(int socket_fd, const char *message, unsigned int msg_length);
+unsigned int read_message(int socket_fd, char *received_message,
+ unsigned int max_message_size);
+int build_fd_sets(pcep_socket_comm_handle *socket_comm_handle);
+void handle_writes(pcep_socket_comm_handle *socket_comm_handle);
+void handle_excepts(pcep_socket_comm_handle *socket_comm_handle);
+
+bool comm_session_exists(pcep_socket_comm_handle *socket_comm_handle,
+ pcep_socket_comm_session *socket_comm_session)
+{
+ if (socket_comm_handle == NULL) {
+ return false;
+ }
+
+ return (ordered_list_find(socket_comm_handle->session_list,
+ socket_comm_session)
+ != NULL);
+}
+
+
+bool comm_session_exists_locking(pcep_socket_comm_handle *socket_comm_handle,
+ pcep_socket_comm_session *socket_comm_session)
+{
+ if (socket_comm_handle == NULL) {
+ return false;
+ }
+
+ pthread_mutex_lock(&(socket_comm_handle->socket_comm_mutex));
+ bool exists =
+ comm_session_exists(socket_comm_handle, socket_comm_session);
+ pthread_mutex_unlock(&(socket_comm_handle->socket_comm_mutex));
+
+ return exists;
+}
+
+
+void write_message(int socket_fd, const char *message, unsigned int msg_length)
+{
+ ssize_t bytes_sent = 0;
+ unsigned int total_bytes_sent = 0;
+
+ while ((uint32_t)bytes_sent < msg_length) {
+ bytes_sent = write(socket_fd, message + total_bytes_sent,
+ msg_length);
+
+ pcep_log(
+ LOG_INFO,
+ "%s: [%ld-%ld] socket_comm writing on socket fd [%d] msg_lenth [%u] bytes sent [%d]",
+ __func__, time(NULL), pthread_self(), socket_fd,
+ msg_length, bytes_sent);
+
+ if (bytes_sent < 0) {
+ if (errno != EAGAIN && errno != EWOULDBLOCK) {
+ pcep_log(LOG_WARNING, "%s: send() failure",
+ __func__);
+
+ return;
+ }
+ } else {
+ total_bytes_sent += bytes_sent;
+ }
+ }
+}
+
+
+unsigned int read_message(int socket_fd, char *received_message,
+ unsigned int max_message_size)
+{
+ /* TODO what if bytes_read == max_message_size? there could be more to
+ * read */
+ unsigned int bytes_read =
+ read(socket_fd, received_message, max_message_size);
+ pcep_log(
+ LOG_INFO,
+ "%s: [%ld-%ld] socket_comm read message bytes_read [%u] on socket fd [%d]",
+ __func__, time(NULL), pthread_self(), bytes_read, socket_fd);
+
+ return bytes_read;
+}
+
+
+int build_fd_sets(pcep_socket_comm_handle *socket_comm_handle)
+{
+ int max_fd = 0;
+
+ pthread_mutex_lock(&(socket_comm_handle->socket_comm_mutex));
+
+ FD_ZERO(&socket_comm_handle->except_master_set);
+ FD_ZERO(&socket_comm_handle->read_master_set);
+ ordered_list_node *node = socket_comm_handle->read_list->head;
+ pcep_socket_comm_session *comm_session;
+ while (node != NULL) {
+ comm_session = (pcep_socket_comm_session *)node->data;
+ if (comm_session->socket_fd > max_fd) {
+ max_fd = comm_session->socket_fd;
+ } else if (comm_session->socket_fd < 0) {
+ pcep_log(LOG_ERR, "%s: Negative fd", __func__);
+ assert(comm_session->socket_fd > 0);
+ }
+
+ /*pcep_log(LOG_DEBUG, ld] socket_comm::build_fdSets set
+ ready_toRead
+ [%d]", __func__, time(NULL), comm_session->socket_fd);*/
+ FD_SET(comm_session->socket_fd,
+ &socket_comm_handle->read_master_set);
+ FD_SET(comm_session->socket_fd,
+ &socket_comm_handle->except_master_set);
+ node = node->next_node;
+ }
+
+ FD_ZERO(&socket_comm_handle->write_master_set);
+ node = socket_comm_handle->write_list->head;
+ while (node != NULL) {
+ comm_session = (pcep_socket_comm_session *)node->data;
+ if (comm_session->socket_fd > max_fd) {
+ max_fd = comm_session->socket_fd;
+ } else if (comm_session->socket_fd < 0) {
+ pcep_log(LOG_ERR, "%s: Negative fd", __func__);
+ assert(comm_session->socket_fd > 0);
+ }
+
+ /*pcep_log(LOG_DEBUG, "%s: [%ld] socket_comm::build_fdSets set
+ ready_toWrite [%d]", __func__, time(NULL),
+ comm_session->socket_fd);*/
+ FD_SET(comm_session->socket_fd,
+ &socket_comm_handle->write_master_set);
+ FD_SET(comm_session->socket_fd,
+ &socket_comm_handle->except_master_set);
+ node = node->next_node;
+ }
+
+ pthread_mutex_unlock(&(socket_comm_handle->socket_comm_mutex));
+
+ return max_fd + 1;
+}
+
+
+void handle_reads(pcep_socket_comm_handle *socket_comm_handle)
+{
+
+ /*
+ * iterate all the socket_fd's in the read_list. it may be that not
+ * all of them have something to read. dont remove the socket_fd
+ * from the read_list since messages could come at any time.
+ */
+
+ /* Notice: Only locking the mutex when accessing the read_list,
+ * since the read callbacks may end up calling back into the socket
+ * comm module to write messages which could be a deadlock. */
+ pthread_mutex_lock(&(socket_comm_handle->socket_comm_mutex));
+ ordered_list_node *node = socket_comm_handle->read_list->head;
+ pthread_mutex_unlock(&(socket_comm_handle->socket_comm_mutex));
+
+ while (node != NULL) {
+ pcep_socket_comm_session *comm_session =
+ (pcep_socket_comm_session *)node->data;
+
+ pthread_mutex_lock(&(socket_comm_handle->socket_comm_mutex));
+ node = node->next_node;
+ if (!comm_session_exists(socket_comm_handle, comm_session)) {
+ /* This comm_session has been deleted, move on to the
+ * next one */
+ pthread_mutex_unlock(
+ &(socket_comm_handle->socket_comm_mutex));
+ continue;
+ }
+
+ int is_set = FD_ISSET(comm_session->socket_fd,
+ &(socket_comm_handle->read_master_set));
+ /* Upon read failure, the comm_session might be free'd, so we
+ * cant store the received_bytes in the comm_session, until we
+ * know the read was successful. */
+ int received_bytes = 0;
+ pthread_mutex_unlock(&(socket_comm_handle->socket_comm_mutex));
+
+ if (is_set) {
+ FD_CLR(comm_session->socket_fd,
+ &(socket_comm_handle->read_master_set));
+
+ /* either read the message locally, or call the
+ * message_ready_handler to read it */
+ if (comm_session->message_handler != NULL) {
+ received_bytes = read_message(
+ comm_session->socket_fd,
+ comm_session->received_message,
+ MAX_RECVD_MSG_SIZE);
+ if (received_bytes > 0) {
+ /* Send the received message to the
+ * handler */
+ comm_session->received_bytes =
+ received_bytes;
+ comm_session->message_handler(
+ comm_session->session_data,
+ comm_session->received_message,
+ comm_session->received_bytes);
+ }
+ } else {
+ /* Tell the handler a message is ready to be
+ * read. The comm_session may be destroyed in
+ * this call, if
+ * there is an error reading or if the socket is
+ * closed. */
+ received_bytes =
+ comm_session
+ ->message_ready_to_read_handler(
+ comm_session
+ ->session_data,
+ comm_session
+ ->socket_fd);
+ }
+
+ /* handle the read results */
+ if (received_bytes == 0) {
+ if (comm_session_exists_locking(
+ socket_comm_handle, comm_session)) {
+ comm_session->received_bytes = 0;
+ /* the socket was closed */
+ /* TODO should we define a socket except
+ * enum? or will the only time we call
+ * this is when the socket is closed??
+ */
+ if (comm_session->conn_except_notifier
+ != NULL) {
+ comm_session->conn_except_notifier(
+ comm_session
+ ->session_data,
+ comm_session
+ ->socket_fd);
+ }
+
+ /* stop reading from the socket if its
+ * closed */
+ pthread_mutex_lock(
+ &(socket_comm_handle
+ ->socket_comm_mutex));
+ ordered_list_remove_first_node_equals(
+ socket_comm_handle->read_list,
+ comm_session);
+ pthread_mutex_unlock(
+ &(socket_comm_handle
+ ->socket_comm_mutex));
+ }
+ } else if (received_bytes < 0) {
+ /* TODO should we call conn_except_notifier()
+ * here ? */
+ pcep_log(
+ LOG_WARNING,
+ "%s: Error on socket fd [%d] : errno [%d][%s]",
+ __func__, comm_session->socket_fd,
+ errno, strerror(errno));
+ } else {
+ comm_session->received_bytes = received_bytes;
+ }
+ }
+ }
+}
+
+
+void handle_writes(pcep_socket_comm_handle *socket_comm_handle)
+{
+ pthread_mutex_lock(&(socket_comm_handle->socket_comm_mutex));
+
+ /*
+ * iterate all the socket_fd's in the write_list. it may be that not
+ * all of them are ready to be written to. only remove the socket_fd
+ * from the list if it is ready to be written to.
+ */
+
+ ordered_list_node *node = socket_comm_handle->write_list->head;
+ pcep_socket_comm_session *comm_session;
+ bool msg_written;
+ while (node != NULL) {
+ comm_session = (pcep_socket_comm_session *)node->data;
+ node = node->next_node;
+ msg_written = false;
+
+ if (!comm_session_exists(socket_comm_handle, comm_session)) {
+ /* This comm_session has been deleted, move on to the
+ * next one */
+ continue;
+ }
+
+ if (FD_ISSET(comm_session->socket_fd,
+ &(socket_comm_handle->write_master_set))) {
+ /* only remove the entry from the list, if it is written
+ * to */
+ ordered_list_remove_first_node_equals(
+ socket_comm_handle->write_list, comm_session);
+ FD_CLR(comm_session->socket_fd,
+ &(socket_comm_handle->write_master_set));
+
+ /* dequeue all the comm_session messages and send them
+ */
+ pcep_socket_comm_queued_message *queued_message =
+ queue_dequeue(comm_session->message_queue);
+ while (queued_message != NULL) {
+ msg_written = true;
+ write_message(comm_session->socket_fd,
+ queued_message->encoded_message,
+ queued_message->msg_length);
+ if (queued_message->free_after_send) {
+ pceplib_free(PCEPLIB_MESSAGES,
+ (void *)queued_message
+ ->encoded_message);
+ }
+ pceplib_free(PCEPLIB_MESSAGES, queued_message);
+ queued_message = queue_dequeue(
+ comm_session->message_queue);
+ }
+ }
+
+ /* check if the socket should be closed after writing */
+ if (comm_session->close_after_write == true) {
+ if (comm_session->message_queue->num_entries == 0) {
+ /* TODO check to make sure modifying the
+ * write_list while iterating it doesnt cause
+ * problems. */
+ pcep_log(
+ LOG_DEBUG,
+ "%s: handle_writes close() socket fd [%d]",
+ __func__, comm_session->socket_fd);
+ ordered_list_remove_first_node_equals(
+ socket_comm_handle->read_list,
+ comm_session);
+ ordered_list_remove_first_node_equals(
+ socket_comm_handle->write_list,
+ comm_session);
+ close(comm_session->socket_fd);
+ comm_session->socket_fd = -1;
+ }
+ }
+
+ if (comm_session->message_sent_handler != NULL
+ && msg_written == true) {
+ /* Unlocking to allow the message_sent_handler to
+ * make calls like destroy_socket_comm_session */
+ pthread_mutex_unlock(
+ &(socket_comm_handle->socket_comm_mutex));
+ comm_session->message_sent_handler(
+ comm_session->session_data,
+ comm_session->socket_fd);
+ pthread_mutex_lock(
+ &(socket_comm_handle->socket_comm_mutex));
+ }
+ }
+
+ pthread_mutex_unlock(&(socket_comm_handle->socket_comm_mutex));
+}
+
+
+void handle_excepts(pcep_socket_comm_handle *socket_comm_handle)
+{
+ /* TODO finish this */
+ (void)socket_comm_handle;
+}
+
+
+/* pcep_socket_comm::initialize_socket_comm_loop() will create a thread and
+ * invoke this method */
+void *socket_comm_loop(void *data)
+{
+ if (data == NULL) {
+ pcep_log(
+ LOG_WARNING,
+ "%s: Cannot start socket_comm_loop with NULL pcep_socketcomm_handle",
+ __func__);
+ return NULL;
+ }
+
+ pcep_log(LOG_NOTICE, "%s: [%ld-%ld] Starting socket_comm_loop thread",
+ __func__, time(NULL), pthread_self());
+
+ pcep_socket_comm_handle *socket_comm_handle =
+ (pcep_socket_comm_handle *)data;
+ struct timeval timer;
+ int max_fd;
+
+ while (socket_comm_handle->active) {
+ /* check the FD's every 1/4 sec, 250 milliseconds */
+ timer.tv_sec = 0;
+ timer.tv_usec = 250000;
+ max_fd = build_fd_sets(socket_comm_handle);
+
+ if (select(max_fd, &(socket_comm_handle->read_master_set),
+ &(socket_comm_handle->write_master_set),
+ &(socket_comm_handle->except_master_set), &timer)
+ < 0) {
+ /* TODO handle the error */
+ pcep_log(
+ LOG_WARNING,
+ "%s: ERROR socket_comm_loop on select : errno [%d][%s]",
+ __func__, errno, strerror(errno));
+ }
+
+ handle_reads(socket_comm_handle);
+ handle_writes(socket_comm_handle);
+ handle_excepts(socket_comm_handle);
+ }
+
+ pcep_log(LOG_NOTICE, "%s: [%ld-%ld] Finished socket_comm_loop thread",
+ __func__, time(NULL), pthread_self());
+
+ return NULL;
+}
+
+int pceplib_external_socket_read(int fd, void *payload)
+{
+ pcep_socket_comm_handle *socket_comm_handle =
+ (pcep_socket_comm_handle *)payload;
+ if (socket_comm_handle == NULL) {
+ return -1;
+ }
+
+ pthread_mutex_lock(&(socket_comm_handle->socket_comm_mutex));
+ FD_SET(fd, &(socket_comm_handle->read_master_set));
+ pthread_mutex_unlock(&(socket_comm_handle->socket_comm_mutex));
+
+ handle_reads(socket_comm_handle);
+
+ /* Get the socket_comm_session */
+ pcep_socket_comm_session find_session = {.socket_fd = fd};
+ pthread_mutex_lock(&(socket_comm_handle->socket_comm_mutex));
+ ordered_list_node *node =
+ ordered_list_find(socket_comm_handle->read_list, &find_session);
+
+ /* read again */
+ if (node != NULL) {
+ socket_comm_handle->socket_read_func(
+ socket_comm_handle->external_infra_data,
+ &((pcep_socket_comm_session *)node)
+ ->external_socket_data,
+ fd, socket_comm_handle);
+ }
+ pthread_mutex_unlock(&(socket_comm_handle->socket_comm_mutex));
+
+ return 0;
+}
+
+int pceplib_external_socket_write(int fd, void *payload)
+{
+ pcep_socket_comm_handle *socket_comm_handle =
+ (pcep_socket_comm_handle *)payload;
+ if (socket_comm_handle == NULL) {
+ return -1;
+ }
+
+ pthread_mutex_lock(&(socket_comm_handle->socket_comm_mutex));
+ FD_SET(fd, &(socket_comm_handle->write_master_set));
+ pthread_mutex_unlock(&(socket_comm_handle->socket_comm_mutex));
+
+ handle_writes(socket_comm_handle);
+
+ /* TODO do we need to cancel this FD from writing?? */
+
+ return 0;
+}
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Javier Garcia <javier.garcia@voltanet.io>
+ *
+ */
+
+/*
+ * Timer definitions to be used internally by the pcep_timers library.
+ */
+
+#ifndef PCEPSOCKETCOMMLOOP_H_
+#define PCEPSOCKETCOMMLOOP_H_
+
+void handle_reads(pcep_socket_comm_handle *socket_comm_handle);
+
+#endif /* PCEPTIMERINTERNALS_H_ */
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+/*
+ * This module is built into a separate library, and is used by several
+ * other modules for unit testing, so that real sockets dont have to be
+ * created.
+ */
+
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <CUnit/CUnit.h>
+
+#include "pcep_socket_comm.h"
+#include "pcep_socket_comm_mock.h"
+#include "pcep_utils_queue.h"
+
+/* reset_mock_socket_comm_info() should be used before each test */
+mock_socket_comm_info mock_socket_metadata;
+
+void setup_mock_socket_comm_info(void)
+{
+ mock_socket_metadata.socket_comm_session_initialize_times_called = 0;
+ mock_socket_metadata.socket_comm_session_initialize_src_times_called =
+ 0;
+ mock_socket_metadata.socket_comm_session_teardown_times_called = 0;
+ mock_socket_metadata.socket_comm_session_connect_tcp_times_called = 0;
+ mock_socket_metadata.socket_comm_session_send_message_times_called = 0;
+ mock_socket_metadata
+ .socket_comm_session_close_tcp_after_write_times_called = 0;
+ mock_socket_metadata.socket_comm_session_close_tcp_times_called = 0;
+ mock_socket_metadata.destroy_socket_comm_loop_times_called = 0;
+ mock_socket_metadata.send_message_save_message = false;
+ mock_socket_metadata.sent_message_list = dll_initialize();
+}
+
+void teardown_mock_socket_comm_info(void)
+{
+ dll_destroy(mock_socket_metadata.sent_message_list);
+}
+
+void reset_mock_socket_comm_info(void)
+{
+ teardown_mock_socket_comm_info();
+ setup_mock_socket_comm_info();
+}
+
+mock_socket_comm_info *get_mock_socket_comm_info(void)
+{
+ return &mock_socket_metadata;
+}
+
+void verify_socket_comm_times_called(int initialized, int teardown, int connect,
+ int send_message,
+ int close_tcp_after_write, int close_tcp,
+ int destroy)
+{
+ CU_ASSERT_EQUAL(initialized,
+ mock_socket_metadata
+ .socket_comm_session_initialize_times_called);
+ CU_ASSERT_EQUAL(
+ teardown,
+ mock_socket_metadata.socket_comm_session_teardown_times_called);
+ CU_ASSERT_EQUAL(connect,
+ mock_socket_metadata
+ .socket_comm_session_connect_tcp_times_called);
+ CU_ASSERT_EQUAL(send_message,
+ mock_socket_metadata
+ .socket_comm_session_send_message_times_called);
+ CU_ASSERT_EQUAL(
+ close_tcp_after_write,
+ mock_socket_metadata
+ .socket_comm_session_close_tcp_after_write_times_called);
+ CU_ASSERT_EQUAL(close_tcp,
+ mock_socket_metadata
+ .socket_comm_session_close_tcp_times_called);
+ CU_ASSERT_EQUAL(
+ destroy,
+ mock_socket_metadata.destroy_socket_comm_loop_times_called);
+}
+
+
+/*
+ * Mock the socket_comm functions used by session_logic for Unit Testing
+ */
+
+bool initialize_socket_comm_external_infra(
+ void *external_infra_data, ext_socket_read socket_read_cb,
+ ext_socket_write socket_write_cb,
+ ext_socket_pthread_create_callback thread_create_func)
+{
+ (void)external_infra_data;
+ (void)socket_read_cb;
+ (void)socket_write_cb;
+ (void)thread_create_func;
+
+ mock_socket_metadata
+ .socket_comm_initialize_external_infra_times_called++;
+
+ return true;
+}
+
+bool destroy_socket_comm_loop()
+{
+ mock_socket_metadata.destroy_socket_comm_loop_times_called++;
+
+ return false;
+}
+
+pcep_socket_comm_session *
+socket_comm_session_initialize(message_received_handler msg_rcv_handler,
+ message_ready_to_read_handler msg_ready_handler,
+ message_sent_notifier msg_sent_notifier,
+ connection_except_notifier notifier,
+ struct in_addr *dst_ip, short dst_port,
+ uint32_t connect_timeout_millis,
+ const char *tcp_authentication_str,
+ bool is_tcp_auth_md5, void *session_data)
+{
+ (void)msg_sent_notifier;
+ (void)tcp_authentication_str;
+ (void)is_tcp_auth_md5;
+
+ mock_socket_metadata.socket_comm_session_initialize_times_called++;
+
+ pcep_socket_comm_session *comm_session =
+ malloc(sizeof(pcep_socket_comm_session));
+ memset(comm_session, 0, sizeof(pcep_socket_comm_session));
+
+ comm_session->message_handler = msg_rcv_handler;
+ comm_session->message_ready_to_read_handler = msg_ready_handler;
+ comm_session->conn_except_notifier = notifier;
+ comm_session->message_queue = queue_initialize();
+ comm_session->session_data = session_data;
+ comm_session->close_after_write = false;
+ comm_session->connect_timeout_millis = connect_timeout_millis;
+ comm_session->is_ipv6 = false;
+ comm_session->dest_sock_addr.dest_sock_addr_ipv4.sin_family = AF_INET;
+ comm_session->dest_sock_addr.dest_sock_addr_ipv4.sin_port =
+ htons(dst_port);
+ comm_session->dest_sock_addr.dest_sock_addr_ipv4.sin_addr.s_addr =
+ dst_ip->s_addr;
+
+ return comm_session;
+}
+
+pcep_socket_comm_session *socket_comm_session_initialize_ipv6(
+ message_received_handler msg_rcv_handler,
+ message_ready_to_read_handler msg_ready_handler,
+ message_sent_notifier msg_sent_notifier,
+ connection_except_notifier notifier, struct in6_addr *dst_ip,
+ short dst_port, uint32_t connect_timeout_millis,
+ const char *tcp_authentication_str, bool is_tcp_auth_md5,
+ void *session_data)
+{
+ (void)msg_sent_notifier;
+ (void)tcp_authentication_str;
+ (void)is_tcp_auth_md5;
+
+ mock_socket_metadata.socket_comm_session_initialize_times_called++;
+
+ pcep_socket_comm_session *comm_session =
+ malloc(sizeof(pcep_socket_comm_session));
+ memset(comm_session, 0, sizeof(pcep_socket_comm_session));
+
+ comm_session->message_handler = msg_rcv_handler;
+ comm_session->message_ready_to_read_handler = msg_ready_handler;
+ comm_session->conn_except_notifier = notifier;
+ comm_session->message_queue = queue_initialize();
+ comm_session->session_data = session_data;
+ comm_session->close_after_write = false;
+ comm_session->connect_timeout_millis = connect_timeout_millis;
+ comm_session->is_ipv6 = true;
+ comm_session->dest_sock_addr.dest_sock_addr_ipv6.sin6_family = AF_INET6;
+ comm_session->dest_sock_addr.dest_sock_addr_ipv6.sin6_port =
+ htons(dst_port);
+ memcpy(&comm_session->dest_sock_addr.dest_sock_addr_ipv6.sin6_addr,
+ dst_ip, sizeof(struct in6_addr));
+
+ return comm_session;
+}
+
+pcep_socket_comm_session *socket_comm_session_initialize_with_src(
+ message_received_handler msg_rcv_handler,
+ message_ready_to_read_handler msg_ready_handler,
+ message_sent_notifier msg_sent_notifier,
+ connection_except_notifier notifier, struct in_addr *src_ip,
+ short src_port, struct in_addr *dst_ip, short dst_port,
+ uint32_t connect_timeout_millis, const char *tcp_authentication_str,
+ bool is_tcp_auth_md5, void *session_data)
+{
+ (void)msg_sent_notifier;
+ (void)tcp_authentication_str;
+ (void)is_tcp_auth_md5;
+
+ mock_socket_metadata.socket_comm_session_initialize_src_times_called++;
+
+ pcep_socket_comm_session *comm_session =
+ malloc(sizeof(pcep_socket_comm_session));
+ memset(comm_session, 0, sizeof(pcep_socket_comm_session));
+
+ comm_session->message_handler = msg_rcv_handler;
+ comm_session->message_ready_to_read_handler = msg_ready_handler;
+ comm_session->conn_except_notifier = notifier;
+ comm_session->message_queue = queue_initialize();
+ comm_session->session_data = session_data;
+ comm_session->close_after_write = false;
+ comm_session->connect_timeout_millis = connect_timeout_millis;
+ comm_session->is_ipv6 = false;
+ comm_session->src_sock_addr.src_sock_addr_ipv4.sin_family = AF_INET;
+ comm_session->src_sock_addr.src_sock_addr_ipv4.sin_port =
+ htons(src_port);
+ comm_session->src_sock_addr.src_sock_addr_ipv4.sin_addr.s_addr =
+ ((src_ip == NULL) ? INADDR_ANY : src_ip->s_addr);
+ comm_session->dest_sock_addr.dest_sock_addr_ipv4.sin_family = AF_INET;
+ comm_session->dest_sock_addr.dest_sock_addr_ipv4.sin_port =
+ htons(dst_port);
+ comm_session->dest_sock_addr.dest_sock_addr_ipv4.sin_addr.s_addr =
+ dst_ip->s_addr;
+
+ return comm_session;
+}
+
+pcep_socket_comm_session *socket_comm_session_initialize_with_src_ipv6(
+ message_received_handler msg_rcv_handler,
+ message_ready_to_read_handler msg_ready_handler,
+ message_sent_notifier msg_sent_notifier,
+ connection_except_notifier notifier, struct in6_addr *src_ip,
+ short src_port, struct in6_addr *dst_ip, short dst_port,
+ uint32_t connect_timeout_millis, const char *tcp_authentication_str,
+ bool is_tcp_auth_md5, void *session_data)
+{
+ (void)msg_sent_notifier;
+ (void)tcp_authentication_str;
+ (void)is_tcp_auth_md5;
+
+ mock_socket_metadata.socket_comm_session_initialize_src_times_called++;
+
+ pcep_socket_comm_session *comm_session =
+ malloc(sizeof(pcep_socket_comm_session));
+ memset(comm_session, 0, sizeof(pcep_socket_comm_session));
+
+ comm_session->message_handler = msg_rcv_handler;
+ comm_session->message_ready_to_read_handler = msg_ready_handler;
+ comm_session->conn_except_notifier = notifier;
+ comm_session->message_queue = queue_initialize();
+ comm_session->session_data = session_data;
+ comm_session->close_after_write = false;
+ comm_session->connect_timeout_millis = connect_timeout_millis;
+ comm_session->is_ipv6 = true;
+ comm_session->src_sock_addr.src_sock_addr_ipv6.sin6_family = AF_INET6;
+ comm_session->src_sock_addr.src_sock_addr_ipv6.sin6_port =
+ htons(src_port);
+ if (src_ip == NULL) {
+ comm_session->src_sock_addr.src_sock_addr_ipv6.sin6_addr =
+ in6addr_any;
+ } else {
+ memcpy(&comm_session->src_sock_addr.src_sock_addr_ipv6
+ .sin6_addr,
+ src_ip, sizeof(struct in6_addr));
+ }
+ comm_session->dest_sock_addr.dest_sock_addr_ipv6.sin6_family = AF_INET6;
+ comm_session->dest_sock_addr.dest_sock_addr_ipv6.sin6_port =
+ htons(dst_port);
+ memcpy(&comm_session->dest_sock_addr.dest_sock_addr_ipv6.sin6_addr,
+ dst_ip, sizeof(struct in6_addr));
+
+ return comm_session;
+}
+
+bool socket_comm_session_teardown(pcep_socket_comm_session *socket_comm_session)
+{
+ mock_socket_metadata.socket_comm_session_teardown_times_called++;
+
+ if (socket_comm_session != NULL) {
+ queue_destroy(socket_comm_session->message_queue);
+ free(socket_comm_session);
+ }
+
+ return true;
+}
+
+
+bool socket_comm_session_connect_tcp(
+ pcep_socket_comm_session *socket_comm_session)
+{
+ (void)socket_comm_session;
+
+ mock_socket_metadata.socket_comm_session_connect_tcp_times_called++;
+
+ return true;
+}
+
+
+void socket_comm_session_send_message(
+ pcep_socket_comm_session *socket_comm_session,
+ const char *encoded_message, unsigned int msg_length,
+ bool delete_after_send)
+{
+ (void)socket_comm_session;
+ (void)msg_length;
+
+ mock_socket_metadata.socket_comm_session_send_message_times_called++;
+
+ if (mock_socket_metadata.send_message_save_message == true) {
+ /* the caller/test case is responsible for freeing the message
+ */
+ dll_append(mock_socket_metadata.sent_message_list,
+ (char *)encoded_message);
+ } else {
+ if (delete_after_send == true) {
+ free((void *)encoded_message);
+ }
+ }
+
+ return;
+}
+
+
+bool socket_comm_session_close_tcp_after_write(
+ pcep_socket_comm_session *socket_comm_session)
+{
+ (void)socket_comm_session;
+
+ mock_socket_metadata
+ .socket_comm_session_close_tcp_after_write_times_called++;
+
+ return true;
+}
+
+
+bool socket_comm_session_close_tcp(
+ pcep_socket_comm_session *socket_comm_session)
+{
+ (void)socket_comm_session;
+
+ mock_socket_metadata.socket_comm_session_close_tcp_times_called++;
+
+ return true;
+}
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+/*
+ * This module is built into a separate library, and is used by several
+ * other modules for unit testing, so that real sockets dont have to be
+ * created.
+ */
+
+#ifndef PCEP_SOCKET_COMM_MOCK_SOCKET_COMM_H_
+#define PCEP_SOCKET_COMM_MOCK_SOCKET_COMM_H_
+
+#include <stdbool.h>
+
+#include "pcep_utils_double_linked_list.h"
+
+typedef struct mock_socket_comm_info_ {
+ int socket_comm_initialize_external_infra_times_called;
+ int socket_comm_session_initialize_times_called;
+ int socket_comm_session_initialize_src_times_called;
+ int socket_comm_session_teardown_times_called;
+ int socket_comm_session_connect_tcp_times_called;
+ int socket_comm_session_send_message_times_called;
+ int socket_comm_session_close_tcp_after_write_times_called;
+ int socket_comm_session_close_tcp_times_called;
+ int destroy_socket_comm_loop_times_called;
+
+ /* TODO later if necessary, we can add return values for
+ * those functions that return something */
+
+ /* Used to access messages sent with socket_comm_session_send_message()
+ */
+ bool send_message_save_message;
+ double_linked_list *sent_message_list;
+
+} mock_socket_comm_info;
+
+void setup_mock_socket_comm_info(void);
+void teardown_mock_socket_comm_info(void);
+void reset_mock_socket_comm_info(void);
+bool destroy_socket_comm_loop(void);
+
+mock_socket_comm_info *get_mock_socket_comm_info(void);
+void verify_socket_comm_times_called(int initialized, int teardown, int connect,
+ int send_message, int close_after_write,
+ int close, int destroy);
+
+#endif /* PCEP_SOCKET_COMM_MOCK_SOCKET_COMM_H_ */
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+/*
+ * Timer definitions to be used internally by the pcep_timers library.
+ */
+
+#ifndef PCEPTIMERINTERNALS_H_
+#define PCEPTIMERINTERNALS_H_
+
+#include <stdint.h>
+#include <pthread.h>
+
+#include "pcep_utils_ordered_list.h"
+
+/* Function pointer to be called when timers expire.
+ * Parameters:
+ * void *data - passed into create_timer
+ * int timer_id - the timer_id returned by create_timer
+ */
+typedef void (*timer_expire_handler)(void *, int);
+
+/* Function pointer when an external timer infrastructure is used */
+typedef void (*ext_timer_create)(void *infra_data, void **timer, int seconds,
+ void *data);
+typedef void (*ext_timer_cancel)(void **timer);
+typedef int (*ext_pthread_create_callback)(pthread_t *pthread_id,
+ const pthread_attr_t *attr,
+ void *(*start_routine)(void *),
+ void *data, const char *thread_name);
+
+typedef struct pcep_timer_ {
+ time_t expire_time;
+ uint16_t sleep_seconds;
+ int timer_id;
+ void *data;
+ void *external_timer;
+
+} pcep_timer;
+
+typedef struct pcep_timers_context_ {
+ ordered_list_handle *timer_list;
+ bool active;
+ timer_expire_handler expire_handler;
+ pthread_t event_loop_thread;
+ pthread_mutex_t timer_list_lock;
+ void *external_timer_infra_data;
+ ext_timer_create timer_create_func;
+ ext_timer_cancel timer_cancel_func;
+
+} pcep_timers_context;
+
+/* functions implemented in pcep_timers_loop.c */
+void *event_loop(void *context);
+
+
+#endif /* PCEPTIMERINTERNALS_H_ */
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+/*
+ * Implementation of public API timer functions.
+ */
+
+#include <limits.h>
+#include <pthread.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include "pcep_timers.h"
+#include "pcep_utils_logging.h"
+#include "pcep_utils_memory.h"
+#include "pcep_utils_ordered_list.h"
+
+static pcep_timers_context *timers_context_ = NULL;
+static int timer_id_ = 0;
+
+
+/* simple compare method callback used by pcep_utils_ordered_list
+ * for ordered list insertion. */
+int timer_list_node_compare(void *list_entry, void *new_entry)
+{
+ /* return:
+ * < 0 if new_entry < list_entry
+ * == 0 if new_entry == list_entry (new_entry will be inserted after
+ * list_entry) > 0 if new_entry > list_entry */
+ return ((pcep_timer *)new_entry)->expire_time
+ - ((pcep_timer *)list_entry)->expire_time;
+}
+
+
+/* simple compare method callback used by pcep_utils_ordered_list
+ * ordered_list_remove_first_node_equals2 to remove a timer based on
+ * its timer_id. */
+int timer_list_node_timer_id_compare(void *list_entry, void *new_entry)
+{
+ return ((pcep_timer *)new_entry)->timer_id
+ - ((pcep_timer *)list_entry)->timer_id;
+}
+
+/* simple compare method callback used by pcep_utils_ordered_list
+ * ordered_list_remove_first_node_equals2 to remove a timer based on
+ * its address. */
+int timer_list_node_timer_ptr_compare(void *list_entry, void *new_entry)
+{
+ return ((char *)new_entry - (char *)list_entry);
+}
+
+/* internal util method */
+static pcep_timers_context *create_timers_context_()
+{
+ if (timers_context_ == NULL) {
+ timers_context_ = pceplib_malloc(PCEPLIB_INFRA,
+ sizeof(pcep_timers_context));
+ memset(timers_context_, 0, sizeof(pcep_timers_context));
+ timers_context_->active = false;
+ }
+
+ return timers_context_;
+}
+
+
+/* Internal util function */
+static bool initialize_timers_common(timer_expire_handler expire_handler)
+{
+ if (expire_handler == NULL) {
+ /* Cannot have a NULL handler function */
+ return false;
+ }
+
+ timers_context_ = create_timers_context_();
+
+ if (timers_context_->active == true) {
+ /* already initialized */
+ return false;
+ }
+
+ timers_context_->active = true;
+ timers_context_->timer_list =
+ ordered_list_initialize(timer_list_node_compare);
+ timers_context_->expire_handler = expire_handler;
+
+ if (pthread_mutex_init(&(timers_context_->timer_list_lock), NULL)
+ != 0) {
+ pcep_log(
+ LOG_ERR,
+ "%s: ERROR initializing timers, cannot initialize the mutex",
+ __func__);
+ return false;
+ }
+
+ return true;
+}
+
+bool initialize_timers(timer_expire_handler expire_handler)
+{
+ if (initialize_timers_common(expire_handler) == false) {
+ return false;
+ }
+
+ if (pthread_create(&(timers_context_->event_loop_thread), NULL,
+ event_loop, timers_context_)) {
+ pcep_log(
+ LOG_ERR,
+ "%s: ERROR initializing timers, cannot initialize the thread",
+ __func__);
+ return false;
+ }
+
+ return true;
+}
+
+bool initialize_timers_external_infra(
+ timer_expire_handler expire_handler, void *external_timer_infra_data,
+ ext_timer_create timer_create_func, ext_timer_cancel timer_cancel_func,
+ ext_pthread_create_callback thread_create_func)
+{
+ if (initialize_timers_common(expire_handler) == false) {
+ return false;
+ }
+
+ if (thread_create_func != NULL) {
+ if (thread_create_func(&(timers_context_->event_loop_thread),
+ NULL, event_loop, timers_context_,
+ "pceplib_timers")) {
+ pcep_log(
+ LOG_ERR,
+ "%s: Cannot initialize external timers thread.",
+ __func__);
+ return false;
+ }
+ } else {
+ if (pthread_create(&(timers_context_->event_loop_thread), NULL,
+ event_loop, timers_context_)) {
+ pcep_log(
+ LOG_ERR,
+ "%s: ERROR initializing timers, cannot initialize the thread",
+ __func__);
+ return false;
+ }
+ }
+
+ timers_context_->external_timer_infra_data = external_timer_infra_data;
+ timers_context_->timer_create_func = timer_create_func;
+ timers_context_->timer_cancel_func = timer_cancel_func;
+
+ return true;
+}
+
+/*
+ * This function is only used to tear_down the timer data.
+ * Only the timer data is deleted, not the list itself,
+ * which is deleted by ordered_list_destroy().
+ */
+void free_all_timers(pcep_timers_context *timers_context)
+{
+ pthread_mutex_lock(&timers_context->timer_list_lock);
+
+ ordered_list_node *timer_node = timers_context->timer_list->head;
+
+ while (timer_node != NULL) {
+ if (timer_node->data != NULL) {
+ pceplib_free(PCEPLIB_INFRA, timer_node->data);
+ }
+ timer_node = timer_node->next_node;
+ }
+
+ pthread_mutex_unlock(&timers_context->timer_list_lock);
+}
+
+
+bool teardown_timers()
+{
+ if (timers_context_ == NULL) {
+ pcep_log(
+ LOG_WARNING,
+ "%s: Trying to teardown the timers, but they are not initialized",
+ __func__);
+ return false;
+ }
+
+ if (timers_context_->active == false) {
+ pcep_log(
+ LOG_WARNING,
+ "%s: Trying to teardown the timers, but they are not active",
+ __func__);
+ return false;
+ }
+
+ timers_context_->active = false;
+ if (timers_context_->event_loop_thread != 0) {
+ /* TODO this does not build
+ * Instead of calling pthread_join() which could block if the
+ thread
+ * is blocked, try joining for at most 1 second.
+ struct timespec ts;
+ clock_gettime(CLOCK_REALTIME, &ts);
+ ts.tv_sec += 1;
+ int retval =
+ pthread_timedjoin_np(timers_context_->event_loop_thread, NULL,
+ &ts); if (retval != 0)
+ {
+ pcep_log(LOG_WARNING, "%s: thread did not stop after 1
+ second waiting on it.", __func__);
+ }
+ */
+ pthread_join(timers_context_->event_loop_thread, NULL);
+ }
+
+ free_all_timers(timers_context_);
+ ordered_list_destroy(timers_context_->timer_list);
+
+ if (pthread_mutex_destroy(&(timers_context_->timer_list_lock)) != 0) {
+ pcep_log(
+ LOG_WARNING,
+ "%s: Trying to teardown the timers, cannot destroy the mutex",
+ __func__);
+ }
+
+ pceplib_free(PCEPLIB_INFRA, timers_context_);
+ timers_context_ = NULL;
+
+ return true;
+}
+
+
+int get_next_timer_id()
+{
+ if (timer_id_ == INT_MAX) {
+ timer_id_ = 0;
+ }
+
+ return timer_id_++;
+}
+
+int create_timer(uint16_t sleep_seconds, void *data)
+{
+ if (timers_context_ == NULL) {
+ pcep_log(
+ LOG_WARNING,
+ "%s: Trying to create a timer: the timers have not been initialized",
+ __func__);
+ return -1;
+ }
+
+ pcep_timer *timer = pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_timer));
+ memset(timer, 0, sizeof(pcep_timer));
+ timer->data = data;
+ timer->sleep_seconds = sleep_seconds;
+ timer->expire_time = time(NULL) + sleep_seconds;
+
+ pthread_mutex_lock(&timers_context_->timer_list_lock);
+ timer->timer_id = get_next_timer_id();
+
+ /* implemented in pcep_utils_ordered_list.c */
+ if (ordered_list_add_node(timers_context_->timer_list, timer) == NULL) {
+ pceplib_free(PCEPLIB_INFRA, timer);
+ pthread_mutex_unlock(&timers_context_->timer_list_lock);
+ pcep_log(
+ LOG_WARNING,
+ "%s: Trying to create a timer, cannot add the timer to the timer list",
+ __func__);
+
+ return -1;
+ }
+
+ pthread_mutex_unlock(&timers_context_->timer_list_lock);
+
+ if (timers_context_->timer_create_func) {
+ timers_context_->timer_create_func(
+ timers_context_->external_timer_infra_data,
+ &timer->external_timer, sleep_seconds, timer);
+ }
+
+ return timer->timer_id;
+}
+
+
+bool cancel_timer(int timer_id)
+{
+ static pcep_timer compare_timer;
+
+ if (timers_context_ == NULL) {
+ pcep_log(
+ LOG_WARNING,
+ "%s: Trying to cancel a timer: the timers have not been initialized",
+ __func__);
+ return false;
+ }
+
+ pthread_mutex_lock(&timers_context_->timer_list_lock);
+
+ compare_timer.timer_id = timer_id;
+ pcep_timer *timer_toRemove = ordered_list_remove_first_node_equals2(
+ timers_context_->timer_list, &compare_timer,
+ timer_list_node_timer_id_compare);
+ if (timer_toRemove == NULL) {
+ pthread_mutex_unlock(&timers_context_->timer_list_lock);
+ pcep_log(
+ LOG_WARNING,
+ "%s: Trying to cancel a timer [%d] that does not exist",
+ __func__, timer_id);
+ return false;
+ }
+
+ pthread_mutex_unlock(&timers_context_->timer_list_lock);
+
+ if (timers_context_->timer_cancel_func) {
+ timers_context_->timer_cancel_func(
+ &timer_toRemove->external_timer);
+ }
+
+ pceplib_free(PCEPLIB_INFRA, timer_toRemove);
+
+ return true;
+}
+
+
+bool reset_timer(int timer_id)
+{
+ static pcep_timer compare_timer;
+
+ if (timers_context_ == NULL) {
+ pcep_log(
+ LOG_WARNING,
+ "%s: Trying to reset a timer: the timers have not been initialized",
+ __func__);
+
+ return false;
+ }
+
+ pthread_mutex_lock(&timers_context_->timer_list_lock);
+
+ compare_timer.timer_id = timer_id;
+ ordered_list_node *timer_to_reset_node =
+ ordered_list_find2(timers_context_->timer_list, &compare_timer,
+ timer_list_node_timer_id_compare);
+ if (timer_to_reset_node == NULL) {
+ pthread_mutex_unlock(&timers_context_->timer_list_lock);
+ pcep_log(LOG_WARNING,
+ "%s: Trying to reset a timer node that does not exist",
+ __func__);
+
+ return false;
+ }
+
+ pcep_timer *timer_to_reset = timer_to_reset_node->data;
+ if (timer_to_reset == NULL) {
+ pthread_mutex_unlock(&timers_context_->timer_list_lock);
+ pcep_log(LOG_WARNING,
+ "%s: Trying to reset a timer that does not exist",
+ __func__);
+
+ return false;
+ }
+
+ /* First check if the timer to reset already has the same expire time,
+ * which means multiple reset_timer() calls were made on the same timer
+ * in the same second */
+ time_t expire_time = time(NULL) + timer_to_reset->sleep_seconds;
+ if (timer_to_reset->expire_time == expire_time) {
+ pthread_mutex_unlock(&timers_context_->timer_list_lock);
+ return true;
+ }
+
+ ordered_list_remove_node2(timers_context_->timer_list,
+ timer_to_reset_node);
+
+ timer_to_reset->expire_time = expire_time;
+ if (ordered_list_add_node(timers_context_->timer_list, timer_to_reset)
+ == NULL) {
+ pceplib_free(PCEPLIB_INFRA, timer_to_reset);
+ pthread_mutex_unlock(&timers_context_->timer_list_lock);
+ pcep_log(
+ LOG_WARNING,
+ "%s: Trying to reset a timer, cannot add the timer to the timer list",
+ __func__);
+
+ return false;
+ }
+
+ pthread_mutex_unlock(&timers_context_->timer_list_lock);
+
+ if (timers_context_->timer_cancel_func) {
+ /* Keeping this log for now, since in older versions of FRR the
+ * timer cancellation was blocking. This allows us to see how
+ * long the it takes.*/
+ pcep_log(LOG_DEBUG, "%s: Reseting timer [%d] with callback",
+ __func__, timer_to_reset->timer_id);
+ timers_context_->timer_cancel_func(
+ &timer_to_reset->external_timer);
+ timer_to_reset->external_timer = NULL;
+ }
+
+ if (timers_context_->timer_create_func) {
+ timers_context_->timer_create_func(
+ timers_context_->external_timer_infra_data,
+ &timer_to_reset->external_timer,
+ timer_to_reset->sleep_seconds, timer_to_reset);
+ /* Keeping this log for now, since in older versions of FRR the
+ * timer cancellation was blocking. This allows us to see how
+ * long the it takes.*/
+ pcep_log(LOG_DEBUG, "%s: Reset timer [%d] with callback",
+ __func__, timer_to_reset->timer_id);
+ }
+
+ return true;
+}
+
+
+void pceplib_external_timer_expire_handler(void *data)
+{
+ if (timers_context_ == NULL) {
+ pcep_log(
+ LOG_WARNING,
+ "%s: External timer expired but timers_context is not initialized",
+ __func__);
+ return;
+ }
+
+ if (timers_context_->expire_handler == NULL) {
+ pcep_log(
+ LOG_WARNING,
+ "%s: External timer expired but expire_handler is not initialized",
+ __func__);
+ return;
+ }
+
+ if (data == NULL) {
+ pcep_log(LOG_WARNING,
+ "%s: External timer expired with NULL data", __func__);
+ return;
+ }
+
+ pcep_timer *timer = (pcep_timer *)data;
+ pthread_mutex_lock(&timers_context_->timer_list_lock);
+ ordered_list_node *timer_node =
+ ordered_list_find2(timers_context_->timer_list, timer,
+ timer_list_node_timer_ptr_compare);
+ pthread_mutex_unlock(&timers_context_->timer_list_lock);
+
+ /* Cannot continue if the timer does not exist */
+ if (timer_node == NULL) {
+ pcep_log(
+ LOG_WARNING,
+ "%s: pceplib_external_timer_expire_handler timer [%p] id [%d] does not exist",
+ __func__, timer, timer->timer_id);
+ return;
+ }
+
+ timers_context_->expire_handler(timer->data, timer->timer_id);
+
+ pthread_mutex_lock(&timers_context_->timer_list_lock);
+ ordered_list_remove_node2(timers_context_->timer_list, timer_node);
+ pthread_mutex_unlock(&timers_context_->timer_list_lock);
+
+ pceplib_free(PCEPLIB_INFRA, timer);
+}
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+/*
+ * Public API for pcep_timers
+ */
+
+#ifndef PCEPTIMERS_H_
+#define PCEPTIMERS_H_
+
+#include <pthread.h>
+#include <stdbool.h>
+
+#include "pcep_timer_internals.h"
+
+#define TIMER_ID_NOT_SET -1
+
+/*
+ * Initialize the timers module.
+ * The timer_expire_handler function pointer will be called each time a timer
+ * expires. Return true for successful initialization, false otherwise.
+ */
+bool initialize_timers(timer_expire_handler expire_handler);
+
+/*
+ * Initialize the timers module with an external back-end infrastructure, like
+ * FRR.
+ */
+bool initialize_timers_external_infra(
+ timer_expire_handler expire_handler, void *external_timer_infra_data,
+ ext_timer_create timer_create_func, ext_timer_cancel timer_cancel_func,
+ ext_pthread_create_callback thread_create_func);
+
+/*
+ * Teardown the timers module.
+ */
+bool teardown_timers(void);
+
+/*
+ * Create a new timer for "sleep_seconds" seconds.
+ * If the timer expires before being cancelled, the timer_expire_handler
+ * passed to initialize_timers() will be called with the pointer to "data".
+ * Returns a timer_id <= 0 that can be used to cancel_timer.
+ * Returns < 0 on error.
+ */
+int create_timer(uint16_t sleep_seconds, void *data);
+
+/*
+ * Cancel a timer created with create_timer().
+ * Returns true if the timer was found and cancelled, false otherwise.
+ */
+bool cancel_timer(int timer_id);
+
+/*
+ * Reset an previously created timer, maintaining the same timer_id.
+ * Returns true if the timer was found and reset, false otherwise.
+ */
+bool reset_timer(int timer_id);
+
+/*
+ * If an external timer infra like FRR is used, then this function
+ * will be called when the timers expire in the external infra.
+ */
+void pceplib_external_timer_expire_handler(void *data);
+
+int timer_list_node_compare(void *list_entry, void *new_entry);
+int timer_list_node_timer_id_compare(void *list_entry, void *new_entry);
+int timer_list_node_timer_ptr_compare(void *list_entry, void *new_entry);
+void free_all_timers(pcep_timers_context *timers_context);
+int get_next_timer_id(void);
+
+#endif /* PCEPTIMERS_H_ */
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <sys/select.h>
+
+#include "pcep_timers_event_loop.h"
+#include "pcep_timer_internals.h"
+#include "pcep_utils_ordered_list.h"
+#include "pcep_utils_logging.h"
+#include "pcep_utils_memory.h"
+
+/* For each expired timer: remove the timer from the list, call the
+ * expire_handler, and free the timer. */
+void walk_and_process_timers(pcep_timers_context *timers_context)
+{
+ pthread_mutex_lock(&timers_context->timer_list_lock);
+
+ bool keep_walking = true;
+ ordered_list_node *timer_node = timers_context->timer_list->head;
+ time_t now = time(NULL);
+ pcep_timer *timer_data;
+
+ /* the timers are sorted by expire_time, so we will only
+ * remove the top node each time through the loop */
+ while (timer_node != NULL && keep_walking) {
+ timer_data = (pcep_timer *)timer_node->data;
+ if (timer_data->expire_time <= now) {
+ timer_node = timer_node->next_node;
+ ordered_list_remove_first_node(
+ timers_context->timer_list);
+ /* call the timer expired handler */
+ timers_context->expire_handler(timer_data->data,
+ timer_data->timer_id);
+ pceplib_free(PCEPLIB_INFRA, timer_data);
+ } else {
+ keep_walking = false;
+ }
+ }
+
+ pthread_mutex_unlock(&timers_context->timer_list_lock);
+}
+
+
+/* pcep_timers::initialize() will create a thread and invoke this method */
+void *event_loop(void *context)
+{
+ if (context == NULL) {
+ pcep_log(
+ LOG_WARNING,
+ "%s: pcep_timers_event_loop cannot start event_loop with NULL data",
+ __func__);
+ return NULL;
+ }
+
+ pcep_log(LOG_NOTICE, "%s: [%ld-%ld] Starting timers_event_loop thread",
+ __func__, time(NULL), pthread_self());
+
+ pcep_timers_context *timers_context = (pcep_timers_context *)context;
+ struct timeval timer;
+ int retval;
+
+ while (timers_context->active) {
+ /* check the timers every half second */
+ timer.tv_sec = 0;
+ timer.tv_usec = 500000;
+
+ do {
+ /* if the select() call gets interrupted, select() will
+ * set the remaining time in timer, so we need to call
+ * it again.
+ */
+ retval = select(0, NULL, NULL, NULL, &timer);
+ } while (retval != 0 && errno == EINTR);
+
+ walk_and_process_timers(timers_context);
+ }
+
+ pcep_log(LOG_WARNING, "%s: [%ld-%ld] Finished timers_event_loop thread",
+ __func__, time(NULL), pthread_self());
+
+ return NULL;
+}
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Javier Garcia <javier.garcia@voltanet.io>
+ *
+ */
+
+/*
+ * Timer definitions to be used internally by the pcep_timers library.
+ */
+
+#ifndef PCEP_TIMERS_EVENT_LOOP_H_
+#define PCEP_TIMERS_EVENT_LOOP_H_
+
+#include "pcep_timer_internals.h"
+
+void walk_and_process_timers(pcep_timers_context *timers_context);
+
+#endif
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+/*
+ * Implementation of PCEP Counters.
+ */
+
+#include <zebra.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "pcep_utils_counters.h"
+#include "pcep_utils_logging.h"
+#include "pcep_utils_memory.h"
+
+struct counters_group *create_counters_group(const char *group_name,
+ uint16_t max_subgroups)
+{
+ if (group_name == NULL) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Cannot create counters group: group_name is NULL.",
+ __func__);
+ return NULL;
+ }
+
+ if (max_subgroups > MAX_COUNTER_GROUPS) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Cannot create counters group: max_subgroups [%d] is larger than max the [%d].",
+ __func__, max_subgroups, MAX_COUNTER_GROUPS);
+ return NULL;
+ }
+
+ struct counters_group *group =
+ pceplib_malloc(PCEPLIB_INFRA, sizeof(struct counters_group));
+ memset(group, 0, sizeof(struct counters_group));
+ group->subgroups =
+ pceplib_malloc(PCEPLIB_INFRA, sizeof(struct counters_subgroup *)
+ * (max_subgroups + 1));
+ memset(group->subgroups, 0,
+ sizeof(struct counters_subgroup *) * (max_subgroups + 1));
+
+ strlcpy(group->counters_group_name, group_name,
+ sizeof(group->counters_group_name));
+ group->max_subgroups = max_subgroups;
+ group->start_time = time(NULL);
+
+ return group;
+}
+
+struct counters_subgroup *create_counters_subgroup(const char *subgroup_name,
+ uint16_t subgroup_id,
+ uint16_t max_counters)
+{
+ if (subgroup_name == NULL) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Cannot create counters subgroup: subgroup_name is NULL.",
+ __func__);
+ return NULL;
+ }
+
+ if (max_counters > MAX_COUNTERS) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Cannot create counters subgroup: max_counters [%d] is larger than the max [%d].",
+ __func__, max_counters, MAX_COUNTERS);
+ return NULL;
+ }
+
+ if (subgroup_id > MAX_COUNTER_GROUPS) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Cannot create counters subgroup: subgroup_id [%d] is larger than max the [%d].",
+ __func__, subgroup_id, MAX_COUNTER_GROUPS);
+ return NULL;
+ }
+
+ struct counters_subgroup *subgroup =
+ pceplib_malloc(PCEPLIB_INFRA, sizeof(struct counters_subgroup));
+ memset(subgroup, 0, sizeof(struct counters_subgroup));
+ subgroup->counters = pceplib_malloc(
+ PCEPLIB_INFRA, sizeof(struct counter *) * (max_counters + 1));
+ memset(subgroup->counters, 0,
+ sizeof(struct counter *) * (max_counters + 1));
+
+ strlcpy(subgroup->counters_subgroup_name, subgroup_name,
+ sizeof(subgroup->counters_subgroup_name));
+ subgroup->subgroup_id = subgroup_id;
+ subgroup->max_counters = max_counters;
+
+ return subgroup;
+}
+
+struct counters_subgroup *
+clone_counters_subgroup(struct counters_subgroup *subgroup,
+ const char *subgroup_name, uint16_t subgroup_id)
+{
+ if (subgroup == NULL) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Cannot clone counters subgroup: input counters_subgroup is NULL.",
+ __func__);
+ return NULL;
+ }
+
+ if (subgroup_name == NULL) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Cannot clone counters subgroup: subgroup_name is NULL.",
+ __func__);
+ return NULL;
+ }
+
+ if (subgroup_id > MAX_COUNTER_GROUPS) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Cannot clone counters subgroup: subgroup_id [%d] is larger than max the [%d].",
+ __func__, subgroup_id, MAX_COUNTER_GROUPS);
+ return NULL;
+ }
+
+ struct counters_subgroup *cloned_subgroup = create_counters_subgroup(
+ subgroup_name, subgroup_id, subgroup->max_counters);
+ int i = 0;
+ for (; i <= subgroup->max_counters; i++) {
+ struct counter *counter = subgroup->counters[i];
+ if (counter != NULL) {
+ create_subgroup_counter(cloned_subgroup,
+ counter->counter_id,
+ counter->counter_name);
+ }
+ }
+
+ return cloned_subgroup;
+}
+
+bool add_counters_subgroup(struct counters_group *group,
+ struct counters_subgroup *subgroup)
+{
+ if (group == NULL) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Cannot add counters subgroup: counters_group is NULL.",
+ __func__);
+ return false;
+ }
+
+ if (subgroup == NULL) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Cannot add counters subgroup: counters_subgroup is NULL.",
+ __func__);
+ return false;
+ }
+
+ if (subgroup->subgroup_id >= group->max_subgroups) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Cannot add counters subgroup: counters_subgroup id [%d] is larger than the group max_subgroups [%d].",
+ __func__, subgroup->subgroup_id, group->max_subgroups);
+ return false;
+ }
+
+ group->num_subgroups++;
+ group->subgroups[subgroup->subgroup_id] = subgroup;
+
+ return true;
+}
+
+bool create_subgroup_counter(struct counters_subgroup *subgroup,
+ uint32_t counter_id, const char *counter_name)
+{
+ if (subgroup == NULL) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Cannot create subgroup counter: counters_subgroup is NULL.",
+ __func__);
+ return false;
+ }
+
+ if (counter_id >= subgroup->max_counters) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Cannot create subgroup counter: counter_id [%d] is larger than the subgroup max_counters [%d].",
+ __func__, counter_id, subgroup->max_counters);
+ return false;
+ }
+
+ if (counter_name == NULL) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Cannot create subgroup counter: counter_name is NULL.",
+ __func__);
+ return NULL;
+ }
+
+ struct counter *counter =
+ pceplib_malloc(PCEPLIB_INFRA, sizeof(struct counter));
+ memset(counter, 0, sizeof(struct counter));
+ counter->counter_id = counter_id;
+ strlcpy(counter->counter_name, counter_name,
+ sizeof(counter->counter_name));
+
+ subgroup->num_counters++;
+ subgroup->counters[counter->counter_id] = counter;
+
+ return true;
+}
+
+bool delete_counters_group(struct counters_group *group)
+{
+ if (group == NULL) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Cannot delete group counters: counters_group is NULL.",
+ __func__);
+ return false;
+ }
+
+ int i = 0;
+ for (; i <= group->max_subgroups; i++) {
+ struct counters_subgroup *subgroup = group->subgroups[i];
+ if (subgroup != NULL) {
+ delete_counters_subgroup(subgroup);
+ }
+ }
+
+ pceplib_free(PCEPLIB_INFRA, group->subgroups);
+ pceplib_free(PCEPLIB_INFRA, group);
+
+ return true;
+}
+
+bool delete_counters_subgroup(struct counters_subgroup *subgroup)
+{
+ if (subgroup == NULL || subgroup->counters == NULL) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Cannot delete subgroup counters: counters_subgroup is NULL.",
+ __func__);
+ return false;
+ }
+
+ int i = 0;
+ for (; i <= subgroup->max_counters; i++) {
+ struct counter *counter = subgroup->counters[i];
+ if (counter != NULL) {
+ pceplib_free(PCEPLIB_INFRA, counter);
+ }
+ }
+
+ pceplib_free(PCEPLIB_INFRA, subgroup->counters);
+ pceplib_free(PCEPLIB_INFRA, subgroup);
+
+ return true;
+}
+
+bool reset_group_counters(struct counters_group *group)
+{
+ if (group == NULL) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Cannot reset group counters: counters_group is NULL.",
+ __func__);
+ return false;
+ }
+
+ int i = 0;
+ for (; i <= group->max_subgroups; i++) {
+ struct counters_subgroup *subgroup = group->subgroups[i];
+ if (subgroup != NULL) {
+ reset_subgroup_counters(subgroup);
+ }
+ }
+
+ group->start_time = time(NULL);
+
+ return true;
+}
+
+bool reset_subgroup_counters(struct counters_subgroup *subgroup)
+{
+ if (subgroup == NULL) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Cannot reset subgroup counters: counters_subgroup is NULL.",
+ __func__);
+ return false;
+ }
+
+ int i = 0;
+ for (; i <= subgroup->max_counters; i++) {
+ struct counter *counter = subgroup->counters[i];
+ if (counter != NULL) {
+ counter->counter_value = 0;
+ }
+ }
+
+ return true;
+}
+
+bool increment_counter(struct counters_group *group, uint16_t subgroup_id,
+ uint16_t counter_id)
+{
+ if (group == NULL) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Cannot increment counter: counters_group is NULL.",
+ __func__);
+ return false;
+ }
+
+ if (subgroup_id >= group->max_subgroups) {
+ pcep_log(
+ LOG_DEBUG,
+ "%s: Cannot increment counter: subgroup_id [%d] is larger than the group max_subgroups [%d].",
+ __func__, subgroup_id, group->max_subgroups);
+ return false;
+ }
+
+ struct counters_subgroup *subgroup = group->subgroups[subgroup_id];
+ if (subgroup == NULL) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Cannot increment counter: counters_subgroup in counters_group is NULL.",
+ __func__);
+ return false;
+ }
+
+ return increment_subgroup_counter(subgroup, counter_id);
+}
+
+bool increment_subgroup_counter(struct counters_subgroup *subgroup,
+ uint16_t counter_id)
+{
+ if (subgroup == NULL) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Cannot increment counter: counters_subgroup is NULL.",
+ __func__);
+ return false;
+ }
+
+ if (counter_id >= subgroup->max_counters) {
+ pcep_log(
+ LOG_DEBUG,
+ "%s: Cannot increment counter: counter_id [%d] is larger than the subgroup max_counters [%d].",
+ __func__, counter_id, subgroup->max_counters);
+ return false;
+ }
+
+ if (subgroup->counters[counter_id] == NULL) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Cannot increment counter: No counter exists for counter_id [%d].",
+ __func__, counter_id);
+ return false;
+ }
+
+ subgroup->counters[counter_id]->counter_value++;
+
+ return true;
+}
+
+bool dump_counters_group_to_log(struct counters_group *group)
+{
+ if (group == NULL) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Cannot dump group counters to log: counters_group is NULL.",
+ __func__);
+ return false;
+ }
+
+ time_t now = time(NULL);
+ pcep_log(
+ LOG_INFO,
+ "%s: PCEP Counters group:\n %s \n Sub-Groups [%d] \n Active for [%d seconds]",
+ __func__, group->counters_group_name, group->num_subgroups,
+ (now - group->start_time));
+
+ int i = 0;
+ for (; i <= group->max_subgroups; i++) {
+ struct counters_subgroup *subgroup = group->subgroups[i];
+ if (subgroup != NULL) {
+ dump_counters_subgroup_to_log(subgroup);
+ }
+ }
+
+ return true;
+}
+
+bool dump_counters_subgroup_to_log(struct counters_subgroup *subgroup)
+{
+ if (subgroup == NULL) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Cannot dump subgroup counters to log: counters_subgroup is NULL.",
+ __func__);
+ return false;
+ }
+
+ pcep_log(LOG_INFO,
+ "%s: \tPCEP Counters sub-group [%s] with [%d] counters",
+ __func__, subgroup->counters_subgroup_name,
+ subgroup->num_counters);
+
+ int i = 0;
+ for (; i <= subgroup->max_counters; i++) {
+ struct counter *counter = subgroup->counters[i];
+ if (counter != NULL) {
+ pcep_log(LOG_INFO, "%s: \t\t%s %d", __func__,
+ counter->counter_name, counter->counter_value);
+ }
+ }
+
+ return true;
+}
+
+struct counters_subgroup *find_subgroup(const struct counters_group *group,
+ uint16_t subgroup_id)
+{
+ int i = 0;
+ for (; i <= group->max_subgroups; i++) {
+ struct counters_subgroup *subgroup = group->subgroups[i];
+ if (subgroup != NULL) {
+ if (subgroup->subgroup_id == subgroup_id) {
+ return subgroup;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+uint32_t subgroup_counters_total(struct counters_subgroup *subgroup)
+{
+ if (subgroup == NULL) {
+ return 0;
+ }
+ uint32_t counter_total = 0;
+ int i = 0;
+ for (; i <= subgroup->max_counters; i++) {
+ struct counter *counter = subgroup->counters[i];
+ if (counter != NULL) {
+ counter_total += counter->counter_value;
+ }
+ }
+
+ return counter_total;
+}
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+/*
+ * Definitions of PCEP Counters.
+ */
+
+#ifndef PCEP_UTILS_INCLUDE_PCEP_UTILS_COUNTERS_H_
+#define PCEP_UTILS_INCLUDE_PCEP_UTILS_COUNTERS_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Example Counter group with sub-groups and counters
+ *
+ * pcep_counters {
+ * counters_group_rx {
+ * message_open;
+ * message_keepalive;
+ * message_pcreq;
+ * }
+ * counters_group_tx {
+ * message_open;
+ * message_keepalive;
+ * message_pcreq;
+ * }
+ * counters_group_events {
+ * pcc_connect;
+ * pce_connect;
+ * pcc_disconnect;
+ * pce_disconnect;
+ * }
+ * }
+ *
+ * To create the above structure of groups, sub-groups, and counters, do the
+ * following:
+ *
+ * struct counters_subgroup *rx_subgroup = create_counters_subgroup("rx
+ * counters", 3); struct counters_subgroup *tx_subgroup =
+ * create_counters_subgroup("tx counters", 3); struct counters_subgroup
+ * *events_subgroup = create_counters_subgroup("events counters", 4);
+ *
+ * Use message_id: PCEP_TYPE_OPEN=1
+ * create_subgroup_counter(rx_subgroup, 1, "Message Open");
+ * create_subgroup_counter(rx_subgroup, 2, "Message KeepAlive");
+ * create_subgroup_counter(rx_subgroup, 3, "Message PcReq");
+ *
+ * create_subgroup_counter(tx_subgroup, 1, "Message Open");
+ * create_subgroup_counter(tx_subgroup, 2, "Message KeepAlive");
+ * create_subgroup_counter(tx_subgroup, 3, "Message PcReq");
+ *
+ * create_subgroup_counter(events_subgroup, 1, "PCC Connect");
+ * create_subgroup_counter(events_subgroup, 2, "PCE Connect");
+ * create_subgroup_counter(events_subgroup, 3, "PCC Disconnect");
+ * create_subgroup_counter(events_subgroup, 4, "PCE Disconnect");
+ *
+ * struct counters_group *cntrs_group = create_counters_group("PCEP Counters",
+ * 3); add_counters_subgroup(cntrs_group, rx_subgroup);
+ * add_counters_subgroup(cntrs_group, tx_subgroup);
+ * add_counters_subgroup(cntrs_group, events_subgroup);
+ */
+
+#define MAX_COUNTER_STR_LENGTH 128
+#define MAX_COUNTER_GROUPS 500
+#define MAX_COUNTERS 500
+
+struct counter {
+ uint16_t counter_id;
+ char counter_name[MAX_COUNTER_STR_LENGTH];
+ uint32_t counter_value;
+};
+
+struct counters_subgroup {
+ char counters_subgroup_name[MAX_COUNTER_STR_LENGTH];
+ uint16_t subgroup_id;
+ uint16_t num_counters;
+ uint16_t max_counters;
+ /* Array of (struct counter *) allocated when the subgroup is created.
+ * The array is indexed by the struct counter->counter_id */
+ struct counter **counters;
+};
+
+struct counters_group {
+ char counters_group_name[MAX_COUNTER_STR_LENGTH];
+ uint16_t num_subgroups;
+ uint16_t max_subgroups;
+ time_t start_time;
+ /* Array of (struct counters_subgroup *) allocated when the group is
+ * created. The subgroup is indexed by the (struct counters_subgroup
+ * *)->subgroup_id */
+ struct counters_subgroup **subgroups;
+};
+
+/*
+ * Create a counters group with the given group_name and number of subgroups.
+ * Subgroup_ids are 0-based, so take that into account when setting
+ * max_subgroups. Return true on success or false if group_name is NULL or
+ * max_subgroups >= MAX_COUNTER_GROUPS.
+ */
+struct counters_group *create_counters_group(const char *group_name,
+ uint16_t max_subgroups);
+
+/*
+ * Create a counters subgroup with the given subgroup_name, subgroup_id and
+ * number of counters. The subgroup_id is 0-based. counter_ids are 0-based, so
+ * take that into account when setting max_counters. Return true on success or
+ * false if subgroup_name is NULL, subgroup_id >= MAX_COUNTER_GROUPS, or
+ * max_counters >= MAX_COUNTERS.
+ */
+struct counters_subgroup *create_counters_subgroup(const char *subgroup_name,
+ uint16_t subgroup_id,
+ uint16_t max_counters);
+
+/*
+ * Add a counter_subgroup to a counter_group.
+ * Return true on success or false if group is NULL or if subgroup is NULL.
+ */
+bool add_counters_subgroup(struct counters_group *group,
+ struct counters_subgroup *subgroup);
+
+/*
+ * Clone a subgroup and set a new name and subgroup_id for the new subgroup.
+ * This is useful for RX and TX counters: just create the RX counters and clone
+ * it for the TX counters.
+ */
+struct counters_subgroup *
+clone_counters_subgroup(struct counters_subgroup *subgroup,
+ const char *subgroup_name, uint16_t subgroup_id);
+
+/*
+ * Create a counter in a subgroup with the given counter_id and counter_name.
+ * The counter_id is 0-based.
+ * Return true on success or false if subgroup is NULL, counter_id >=
+ * MAX_COUNTERS, or if counter_name is NULL.
+ */
+bool create_subgroup_counter(struct counters_subgroup *subgroup,
+ uint32_t counter_id, const char *counter_name);
+
+/*
+ * Delete the counters_group and recursively delete all subgroups and their
+ * counters. Return true on success or false if group is NULL.
+ */
+bool delete_counters_group(struct counters_group *group);
+
+/*
+ * Delete the counters_subgroup and all its counters counters.
+ * Return true on success or false if subgroup is NULL.
+ */
+bool delete_counters_subgroup(struct counters_subgroup *subgroup);
+
+/*
+ * Reset all the counters in all sub-groups contained in this group.
+ * Return true on success or false if group is NULL.
+ */
+bool reset_group_counters(struct counters_group *group);
+
+/*
+ * Reset all the counters in this subgroup.
+ * Return true on success or false if subgroup is NULL.
+ */
+bool reset_subgroup_counters(struct counters_subgroup *subgroup);
+
+/*
+ * Increment a counter given a counter_group, subgroup_id, and counter_id.
+ * Return true on success or false if group is NULL, subgroup_id >=
+ * MAX_COUNTER_GROUPS, or counter_id >= MAX_COUNTERS.
+ */
+bool increment_counter(struct counters_group *group, uint16_t subgroup_id,
+ uint16_t counter_id);
+
+/*
+ * Increment a counter given the counter_subgroup and counter_id.
+ * Return true on success or false if subgroup is NULL or counter_id >=
+ * MAX_COUNTERS.
+ */
+bool increment_subgroup_counter(struct counters_subgroup *subgroup,
+ uint16_t counter_id);
+
+/*
+ * Dump the counter_group info and all its counter_subgroups.
+ * Return true on success or false if group is NULL.
+ */
+bool dump_counters_group_to_log(struct counters_group *group);
+
+/*
+ * Dump all the counters in a counter_subgroup.
+ * Return true on success or false if subgroup is NULL.
+ */
+bool dump_counters_subgroup_to_log(struct counters_subgroup *subgroup);
+
+/*
+ * Search for a counters_subgroup by subgroup_id in a counters_group
+ * and return it, if found, else return NULL.
+ */
+struct counters_subgroup *find_subgroup(const struct counters_group *group,
+ uint16_t subgroup_id);
+
+/*
+ * Given a counters_subgroup, return the sum of all the counters.
+ */
+uint32_t subgroup_counters_total(struct counters_subgroup *subgroup);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PCEP_UTILS_INCLUDE_PCEP_UTILS_COUNTERS_H_ */
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+#include <stddef.h>
+#include <string.h>
+
+#include "pcep_utils_double_linked_list.h"
+#include "pcep_utils_logging.h"
+#include "pcep_utils_memory.h"
+
+double_linked_list *dll_initialize()
+{
+ double_linked_list *handle =
+ pceplib_malloc(PCEPLIB_INFRA, sizeof(double_linked_list));
+ if (handle != NULL) {
+ memset(handle, 0, sizeof(double_linked_list));
+ handle->num_entries = 0;
+ handle->head = NULL;
+ handle->tail = NULL;
+ } else {
+ pcep_log(LOG_WARNING,
+ "%s: dll_initialize cannot allocate memory for handle",
+ __func__);
+ return NULL;
+ }
+
+ return handle;
+}
+
+
+void dll_destroy(double_linked_list *handle)
+{
+ if (handle == NULL) {
+ pcep_log(LOG_WARNING,
+ "%s: dll_destroy cannot destroy NULL handle",
+ __func__);
+ return;
+ }
+
+ double_linked_list_node *node = handle->head;
+ while (node != NULL) {
+ double_linked_list_node *node_to_delete = node;
+ node = node->next_node;
+ pceplib_free(PCEPLIB_INFRA, node_to_delete);
+ }
+
+ pceplib_free(PCEPLIB_INFRA, handle);
+}
+
+
+void dll_destroy_with_data_memtype(double_linked_list *handle,
+ void *data_memory_type)
+{
+ if (handle == NULL) {
+ pcep_log(LOG_WARNING,
+ "%s: dll_destroy_with_data cannot destroy NULL handle",
+ __func__);
+ return;
+ }
+
+ double_linked_list_node *node = handle->head;
+ while (node != NULL) {
+ double_linked_list_node *node_to_delete = node;
+ pceplib_free(data_memory_type, node->data);
+ node = node->next_node;
+ pceplib_free(PCEPLIB_INFRA, node_to_delete);
+ }
+
+ pceplib_free(PCEPLIB_INFRA, handle);
+}
+
+
+void dll_destroy_with_data(double_linked_list *handle)
+{
+ /* Default to destroying the data with the INFRA mem type */
+ dll_destroy_with_data_memtype(handle, PCEPLIB_INFRA);
+}
+
+
+/* Creates a node and adds it as the first item in the list */
+double_linked_list_node *dll_prepend(double_linked_list *handle, void *data)
+{
+ if (handle == NULL) {
+ pcep_log(LOG_WARNING, "%s: dll_prepend_data NULL handle",
+ __func__);
+ return NULL;
+ }
+
+ /* Create the new node */
+ double_linked_list_node *new_node =
+ pceplib_malloc(PCEPLIB_INFRA, sizeof(double_linked_list_node));
+ memset(new_node, 0, sizeof(double_linked_list_node));
+ new_node->data = data;
+
+ if (handle->head == NULL) {
+ handle->head = new_node;
+ handle->tail = new_node;
+ } else {
+ new_node->next_node = handle->head;
+ handle->head->prev_node = new_node;
+ handle->head = new_node;
+ }
+
+ (handle->num_entries)++;
+
+ return new_node;
+}
+
+
+/* Creates a node and adds it as the last item in the list */
+double_linked_list_node *dll_append(double_linked_list *handle, void *data)
+{
+ if (handle == NULL) {
+ pcep_log(LOG_WARNING, "%s: dll_append_data NULL handle",
+ __func__);
+ return NULL;
+ }
+
+ /* Create the new node */
+ double_linked_list_node *new_node =
+ pceplib_malloc(PCEPLIB_INFRA, sizeof(double_linked_list_node));
+ memset(new_node, 0, sizeof(double_linked_list_node));
+ new_node->data = data;
+
+ if (handle->head == NULL) {
+ handle->head = new_node;
+ handle->tail = new_node;
+ } else {
+ new_node->prev_node = handle->tail;
+ handle->tail->next_node = new_node;
+ handle->tail = new_node;
+ }
+
+ (handle->num_entries)++;
+
+ return new_node;
+}
+
+
+/* Delete the first node in the list, and return the data */
+void *dll_delete_first_node(double_linked_list *handle)
+{
+ if (handle == NULL) {
+ pcep_log(LOG_WARNING, "%s: dll_delete_first_node NULL handle",
+ __func__);
+ return NULL;
+ }
+
+ if (handle->head == NULL) {
+ return NULL;
+ }
+
+ double_linked_list_node *delete_node = handle->head;
+ void *data = delete_node->data;
+
+ if (delete_node->next_node == NULL) {
+ /* Its the last node in the list */
+ handle->head = NULL;
+ handle->tail = NULL;
+ } else {
+ handle->head = delete_node->next_node;
+ handle->head->prev_node = NULL;
+ }
+
+ pceplib_free(PCEPLIB_INFRA, delete_node);
+ (handle->num_entries)--;
+
+ return data;
+}
+
+
+/* Delete the last node in the list, and return the data */
+void *dll_delete_last_node(double_linked_list *handle)
+{
+ if (handle == NULL) {
+ pcep_log(LOG_WARNING, "%s: dll_delete_last_node NULL handle",
+ __func__);
+ return NULL;
+ }
+
+ if (handle->head == NULL) {
+ return NULL;
+ }
+
+ double_linked_list_node *delete_node = handle->tail;
+ void *data = delete_node->data;
+
+ if (delete_node->prev_node == NULL) {
+ /* Its the last node in the list */
+ handle->head = NULL;
+ handle->tail = NULL;
+ } else {
+ handle->tail = delete_node->prev_node;
+ handle->tail->next_node = NULL;
+ }
+
+ pceplib_free(PCEPLIB_INFRA, delete_node);
+ (handle->num_entries)--;
+
+ return data;
+}
+
+
+/* Delete the designated node in the list, and return the data */
+void *dll_delete_node(double_linked_list *handle, double_linked_list_node *node)
+{
+ if (handle == NULL) {
+ pcep_log(LOG_WARNING, "%s: dll_delete_node NULL handle",
+ __func__);
+ return NULL;
+ }
+
+ if (node == NULL) {
+ return NULL;
+ }
+
+ if (handle->head == NULL) {
+ return NULL;
+ }
+
+ void *data = node->data;
+
+ if (handle->head == handle->tail) {
+ /* Its the last node in the list */
+ handle->head = NULL;
+ handle->tail = NULL;
+ } else if (handle->head == node) {
+ handle->head = node->next_node;
+ handle->head->prev_node = NULL;
+ } else if (handle->tail == node) {
+ handle->tail = node->prev_node;
+ handle->tail->next_node = NULL;
+ } else {
+ /* Its somewhere in the middle of the list */
+ node->next_node->prev_node = node->prev_node;
+ node->prev_node->next_node = node->next_node;
+ }
+
+ pceplib_free(PCEPLIB_INFRA, node);
+ (handle->num_entries)--;
+
+ return data;
+}
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#ifndef PCEP_UTILS_INCLUDE_PCEP_UTILS_DOUBLE_LINKED_LIST_H_
+#define PCEP_UTILS_INCLUDE_PCEP_UTILS_DOUBLE_LINKED_LIST_H_
+
+typedef struct double_linked_list_node_ {
+ struct double_linked_list_node_ *prev_node;
+ struct double_linked_list_node_ *next_node;
+ void *data;
+
+} double_linked_list_node;
+
+
+typedef struct double_linked_list_ {
+ double_linked_list_node *head;
+ double_linked_list_node *tail;
+ unsigned int num_entries;
+
+} double_linked_list;
+
+
+/* Initialize a double linked list */
+double_linked_list *dll_initialize(void);
+
+/* Destroy a double linked list, by freeing the handle and nodes,
+ * user data will not be freed, and may be leaked if not handled
+ * externally. */
+void dll_destroy(double_linked_list *handle);
+/* Destroy a double linked list, by freeing the handle and nodes,
+ * and the user data. */
+void dll_destroy_with_data(double_linked_list *handle);
+void dll_destroy_with_data_memtype(double_linked_list *handle,
+ void *data_memory_type);
+
+/* Creates a node and adds it as the first item in the list */
+double_linked_list_node *dll_prepend(double_linked_list *handle, void *data);
+
+/* Creates a node and adds it as the last item in the list */
+double_linked_list_node *dll_append(double_linked_list *handle, void *data);
+
+/* Delete the first node in the list, and return the data */
+void *dll_delete_first_node(double_linked_list *handle);
+
+/* Delete the last node in the list, and return the data */
+void *dll_delete_last_node(double_linked_list *handle);
+
+/* Delete the designated node in the list, and return the data */
+void *dll_delete_node(double_linked_list *handle,
+ double_linked_list_node *node);
+
+#endif /* PCEP_UTILS_INCLUDE_PCEP_UTILS_DOUBLE_LINKED_LIST_H_ */
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <stdarg.h>
+#include <stdio.h>
+#include "pcep_utils_logging.h"
+
+/* Forward declaration */
+int pcep_stdout_logger(int priority, const char *format, va_list args);
+
+static pcep_logger_func logger_func = pcep_stdout_logger;
+static int logging_level_ = LOG_INFO;
+
+void register_logger(pcep_logger_func logger)
+{
+ logger_func = logger;
+}
+
+void set_logging_level(int level)
+{
+ logging_level_ = level;
+}
+
+int get_logging_level()
+{
+ return logging_level_;
+}
+
+void pcep_log(int priority, const char *format, ...)
+{
+ va_list va;
+ va_start(va, format);
+ logger_func(priority, format, va);
+ va_end(va);
+}
+
+void pcep_log_hexbytes(int priority, const char *message, const uint8_t *bytes,
+ uint8_t bytes_len)
+{
+ char byte_str[2048] = {0};
+ int i = 0;
+
+ snprintf(byte_str, 2048, "%s ", message);
+ for (; i < bytes_len; i++) {
+ snprintf(byte_str, 2048, "%02x ", bytes[i]);
+ }
+ snprintf(byte_str, 2048, "\n");
+
+ pcep_log(priority, "%s", byte_str);
+}
+
+/* Defined with a return type to match the FRR logging signature.
+ * Assuming glibc printf() is thread-safe. */
+int pcep_stdout_logger(int priority, const char *format, va_list args)
+{
+ if (priority <= logging_level_) {
+ vprintf(format, args);
+ printf("\n");
+ }
+
+ return 0;
+}
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#ifndef PCEP_UTILS_INCLUDE_PCEP_UTILS_LOGGING_H_
+#define PCEP_UTILS_INCLUDE_PCEP_UTILS_LOGGING_H_
+
+#include <syslog.h> /* Logging levels */
+#include <stdarg.h> /* va_list */
+#include <stdint.h> /* uint8_t */
+
+/*
+ * The logging defined here i intended to provide the infrastructure to
+ * be able to plug-in an external logger, primarily the FRR logger. There
+ * will be a default internal logger implemented that will write to stdout,
+ * but any other advanced logging features should be implemented externally.
+ */
+
+/* Only the following logging levels from syslog.h should be used:
+ *
+ * LOG_DEBUG - For all messages that are enabled by optional debugging
+ * features, typically preceded by "if (IS...DEBUG...)"
+ * LOG_INFO - Information that may be of interest, but
+ * everything seems to be working properly.
+ * LOG_NOTICE - Only for message pertaining to daemon startup or shutdown.
+ * LOG_WARNING - Warning conditions: unexpected events, but the daemon
+ * believes it can continue to operate correctly.
+ * LOG_ERR - Error situations indicating malfunctions.
+ * Probably requires attention.
+ */
+
+
+/* The signature of this logger function is the same as the FRR logger */
+typedef int (*pcep_logger_func)(int, const char *, va_list);
+void register_logger(pcep_logger_func logger);
+
+/* These functions only take affect when using the internal stdout logger */
+void set_logging_level(int level);
+int get_logging_level(void);
+
+/* Log messages either to a previously registered
+ * logger or to the internal default stdout logger. */
+void pcep_log(int priority, const char *format, ...);
+void pcep_log_hexbytes(int priority, const char *message, const uint8_t *bytes,
+ uint8_t bytes_len);
+
+#endif /* PCEP_UTILS_INCLUDE_PCEP_UTILS_LOGGING_H_ */
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "pcep_utils_logging.h"
+#include "pcep_utils_memory.h"
+
+/* Set default values for memory function pointers */
+static pceplib_malloc_func mfunc = NULL;
+static pceplib_calloc_func cfunc = NULL;
+static pceplib_realloc_func rfunc = NULL;
+static pceplib_strdup_func sfunc = NULL;
+static pceplib_free_func ffunc = NULL;
+
+/* Internal memory types */
+struct pceplib_memory_type pceplib_infra_mt = {
+ .memory_type_name = "PCEPlib Infrastructure memory",
+ .total_bytes_allocated = 0,
+ .num_allocates = 0,
+ .total_bytes_freed = 0,
+ .num_frees = 0};
+struct pceplib_memory_type pceplib_messages_mt = {
+ .memory_type_name = "PCEPlib Messages memory",
+ .total_bytes_allocated = 0,
+ .num_allocates = 0,
+ .total_bytes_freed = 0,
+ .num_frees = 0};
+
+/* The memory type pointers default to the internal memory types */
+void *PCEPLIB_INFRA = &pceplib_infra_mt;
+void *PCEPLIB_MESSAGES = &pceplib_messages_mt;
+
+/* Initialize memory function pointers and memory type pointers */
+bool pceplib_memory_initialize(void *pceplib_infra_mt,
+ void *pceplib_messages_mt,
+ pceplib_malloc_func mf, pceplib_calloc_func cf,
+ pceplib_realloc_func rf, pceplib_strdup_func sf,
+ pceplib_free_func ff)
+{
+ PCEPLIB_INFRA = (pceplib_infra_mt ? pceplib_infra_mt : PCEPLIB_INFRA);
+ PCEPLIB_MESSAGES =
+ (pceplib_messages_mt ? pceplib_messages_mt : PCEPLIB_MESSAGES);
+
+ mfunc = (mf ? mf : mfunc);
+ cfunc = (cf ? cf : cfunc);
+ rfunc = (rf ? rf : rfunc);
+ sfunc = (sf ? sf : sfunc);
+ ffunc = (ff ? ff : ffunc);
+
+ return true;
+}
+
+void pceplib_memory_reset()
+{
+ pceplib_infra_mt.total_bytes_allocated = 0;
+ pceplib_infra_mt.num_allocates = 0;
+ pceplib_infra_mt.total_bytes_freed = 0;
+ pceplib_infra_mt.num_frees = 0;
+
+ pceplib_messages_mt.total_bytes_allocated = 0;
+ pceplib_messages_mt.num_allocates = 0;
+ pceplib_messages_mt.total_bytes_freed = 0;
+ pceplib_messages_mt.num_frees = 0;
+}
+
+void pceplib_memory_dump()
+{
+ if (PCEPLIB_INFRA) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Memory Type [%s] Total [allocs, alloc bytes, frees] [%d, %d, %d]",
+ __func__,
+ ((struct pceplib_memory_type *)PCEPLIB_INFRA)
+ ->memory_type_name,
+ ((struct pceplib_memory_type *)PCEPLIB_INFRA)
+ ->num_allocates,
+ ((struct pceplib_memory_type *)PCEPLIB_INFRA)
+ ->total_bytes_allocated,
+ ((struct pceplib_memory_type *)PCEPLIB_INFRA)
+ ->num_frees);
+ }
+
+ if (PCEPLIB_MESSAGES) {
+ pcep_log(
+ LOG_INFO,
+ "%s: Memory Type [%s] Total [allocs, alloc bytes, frees] [%d, %d, %d]",
+ __func__,
+ ((struct pceplib_memory_type *)PCEPLIB_MESSAGES)
+ ->memory_type_name,
+ ((struct pceplib_memory_type *)PCEPLIB_MESSAGES)
+ ->num_allocates,
+ ((struct pceplib_memory_type *)PCEPLIB_MESSAGES)
+ ->total_bytes_allocated,
+ ((struct pceplib_memory_type *)PCEPLIB_MESSAGES)
+ ->num_frees);
+ }
+}
+
+/* PCEPlib memory functions:
+ * They either call the supplied function pointers, or use the internal
+ * implementations, which just increment simple counters and call the
+ * C stdlib memory implementations. */
+
+void *pceplib_malloc(void *mem_type, size_t size)
+{
+ if (mfunc == NULL) {
+ if (mem_type != NULL) {
+ ((struct pceplib_memory_type *)mem_type)
+ ->total_bytes_allocated += size;
+ ((struct pceplib_memory_type *)mem_type)
+ ->num_allocates++;
+ }
+
+ return malloc(size);
+ } else {
+ return mfunc(mem_type, size);
+ }
+}
+
+void *pceplib_calloc(void *mem_type, size_t size)
+{
+ if (cfunc == NULL) {
+ if (mem_type != NULL) {
+ ((struct pceplib_memory_type *)mem_type)
+ ->total_bytes_allocated += size;
+ ((struct pceplib_memory_type *)mem_type)
+ ->num_allocates++;
+ }
+
+ return calloc(1, size);
+ } else {
+ return cfunc(mem_type, size);
+ }
+}
+
+void *pceplib_realloc(void *mem_type, void *ptr, size_t size)
+{
+ if (rfunc == NULL) {
+ if (mem_type != NULL) {
+ /* TODO should add previous allocated bytes to
+ * total_bytes_freed */
+ ((struct pceplib_memory_type *)mem_type)
+ ->total_bytes_allocated += size;
+ ((struct pceplib_memory_type *)mem_type)
+ ->num_allocates++;
+ }
+
+ return realloc(ptr, size);
+ } else {
+ return rfunc(mem_type, ptr, size);
+ }
+}
+
+void *pceplib_strdup(void *mem_type, const char *str)
+{
+ if (sfunc == NULL) {
+ if (mem_type != NULL) {
+ ((struct pceplib_memory_type *)mem_type)
+ ->total_bytes_allocated += strlen(str);
+ ((struct pceplib_memory_type *)mem_type)
+ ->num_allocates++;
+ }
+
+ return strdup(str);
+ } else {
+ return sfunc(mem_type, str);
+ }
+}
+
+void pceplib_free(void *mem_type, void *ptr)
+{
+ if (ffunc == NULL) {
+ if (mem_type != NULL) {
+ /* TODO in order to increment total_bytes_freed, we need
+ * to keep track of the bytes allocated per pointer.
+ * Currently not implemented. */
+ ((struct pceplib_memory_type *)mem_type)->num_frees++;
+ if (((struct pceplib_memory_type *)mem_type)
+ ->num_allocates
+ < ((struct pceplib_memory_type *)mem_type)
+ ->num_frees) {
+ pcep_log(
+ LOG_ERR,
+ "%s: pceplib_free MT N_Alloc < N_Free: MemType [%s] NumAllocates [%d] NumFrees [%d]",
+ __func__,
+ ((struct pceplib_memory_type *)mem_type)
+ ->memory_type_name,
+ ((struct pceplib_memory_type *)mem_type)
+ ->num_allocates,
+ ((struct pceplib_memory_type *)mem_type)
+ ->num_frees);
+ }
+ }
+
+ return free(ptr);
+ } else {
+ return ffunc(mem_type, ptr);
+ }
+}
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+#ifndef PCEP_UTILS_INCLUDE_PCEP_UTILS_MEMORY_H_
+#define PCEP_UTILS_INCLUDE_PCEP_UTILS_MEMORY_H_
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+/* This module is intended to be used primarily with FRR's memory module,
+ * which has memory groups and memory types, although any memory infrastructure
+ * can be used that has memory types or the memory types in this module can be
+ * set to NULL. The PCEPlib can be used stand-alone, in which case the simple
+ * internal memory type system will be used.
+ */
+
+/* These memory function pointers are modeled after the memory functions
+ * in frr/lib/memory.h */
+typedef void *(*pceplib_malloc_func)(void *mem_type, size_t size);
+typedef void *(*pceplib_calloc_func)(void *mem_type, size_t size);
+typedef void *(*pceplib_realloc_func)(void *mem_type, void *ptr, size_t size);
+typedef void *(*pceplib_strdup_func)(void *mem_type, const char *str);
+typedef void (*pceplib_free_func)(void *mem_type, void *ptr);
+
+/* Either an internal pceplib_memory_type pointer
+ * or could be an FRR memory type pointer */
+extern void *PCEPLIB_INFRA;
+extern void *PCEPLIB_MESSAGES;
+
+/* Internal PCEPlib memory type */
+struct pceplib_memory_type {
+ char memory_type_name[64];
+ uint32_t total_bytes_allocated;
+ uint32_t num_allocates;
+ uint32_t total_bytes_freed; /* currently not used */
+ uint32_t num_frees;
+};
+
+/* Initialize this module by passing in the 2 memory types used in the PCEPlib
+ * and by passing in the different memory allocation/free function pointers.
+ * Any of these parameters can be NULL, in which case an internal implementation
+ * will be used.
+ */
+bool pceplib_memory_initialize(void *pceplib_infra_mt,
+ void *pceplib_messages_mt,
+ pceplib_malloc_func mfunc,
+ pceplib_calloc_func cfunc,
+ pceplib_realloc_func rfunc,
+ pceplib_strdup_func sfunc,
+ pceplib_free_func ffunc);
+
+/* Reset the internal allocation/free counters. Used mainly for internal
+ * testing. */
+void pceplib_memory_reset(void);
+void pceplib_memory_dump(void);
+
+/* Memory functions to be used throughout the PCEPlib. Internally, these
+ * functions will either used the function pointers passed in via
+ * pceplib_memory_initialize() or a simple internal implementation. The
+ * internal implementations just increment the internal memory type
+ * counters and call the C stdlib memory functions.
+ */
+void *pceplib_malloc(void *mem_type, size_t size);
+void *pceplib_calloc(void *mem_type, size_t size);
+void *pceplib_realloc(void *mem_type, void *ptr, size_t size);
+void *pceplib_strdup(void *mem_type, const char *str);
+void pceplib_free(void *mem_type, void *ptr);
+
+#endif /* PCEP_UTILS_INCLUDE_PCEP_UTILS_MEMORY_H_ */
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+
+#include "pcep_utils_logging.h"
+#include "pcep_utils_memory.h"
+#include "pcep_utils_ordered_list.h"
+
+/* Compare function that simply compares pointers.
+ * return:
+ * < 0 if new_entry < list_entry
+ * == 0 if new_entry == list_entry (new_entry will be inserted after
+ * list_entry) > 0 if new_entry > list_entry
+ */
+int pointer_compare_function(void *list_entry, void *new_entry)
+{
+ return (char *)new_entry - (char *)list_entry;
+}
+
+ordered_list_handle *ordered_list_initialize(ordered_compare_function func_ptr)
+{
+ ordered_list_handle *handle =
+ pceplib_malloc(PCEPLIB_INFRA, sizeof(ordered_list_handle));
+ memset(handle, 0, sizeof(ordered_list_handle));
+ handle->head = NULL;
+ handle->num_entries = 0;
+ handle->compare_function = func_ptr;
+
+ return handle;
+}
+
+
+/* free all the ordered_list_node resources and the ordered_list_handle.
+ * it is assumed that the user is responsible fore freeing the data
+ * pointed to by the nodes.
+ */
+void ordered_list_destroy(ordered_list_handle *handle)
+{
+ if (handle == NULL) {
+ return;
+ }
+
+ ordered_list_node *node = handle->head;
+ ordered_list_node *next;
+
+ while (node != NULL) {
+ next = node->next_node;
+ pceplib_free(PCEPLIB_INFRA, node);
+ node = next;
+ }
+
+ pceplib_free(PCEPLIB_INFRA, handle);
+}
+
+
+ordered_list_node *ordered_list_add_node(ordered_list_handle *handle,
+ void *data)
+{
+ if (handle == NULL) {
+ pcep_log(
+ LOG_WARNING,
+ "%s: ordered_list_add_node, the list has not been initialized",
+ __func__);
+ return NULL;
+ }
+ handle->num_entries++;
+
+ ordered_list_node *new_node =
+ pceplib_malloc(PCEPLIB_INFRA, sizeof(ordered_list_node));
+ memset(new_node, 0, sizeof(ordered_list_node));
+ new_node->data = data;
+ new_node->next_node = NULL;
+
+ /* check if its an empty list */
+ if (handle->head == NULL) {
+ handle->head = new_node;
+
+ return new_node;
+ }
+
+ ordered_list_node *prev_node = handle->head;
+ ordered_list_node *node = prev_node;
+ int compare_result;
+
+ while (node != NULL) {
+ compare_result = handle->compare_function(node->data, data);
+ if (compare_result < 0) {
+ /* insert the node */
+ new_node->next_node = node;
+ if (handle->head == node) {
+ /* add it at the beginning of the list */
+ handle->head = new_node;
+ } else {
+ prev_node->next_node = new_node;
+ }
+
+ return new_node;
+ }
+
+ /* keep searching with the next node in the list */
+ prev_node = node;
+ node = node->next_node;
+ }
+
+ /* at the end of the list, add it here */
+ prev_node->next_node = new_node;
+
+ return new_node;
+}
+
+
+ordered_list_node *ordered_list_find2(ordered_list_handle *handle, void *data,
+ ordered_compare_function compare_func)
+{
+ if (handle == NULL) {
+ pcep_log(
+ LOG_WARNING,
+ "%s: ordered_list_find2, the list has not been initialized",
+ __func__);
+ return NULL;
+ }
+
+ ordered_list_node *node = handle->head;
+ int compare_result;
+
+ while (node != NULL) {
+ compare_result = compare_func(node->data, data);
+ if (compare_result == 0) {
+ return node;
+ } else {
+ node = node->next_node;
+ }
+ }
+
+ return NULL;
+}
+
+
+ordered_list_node *ordered_list_find(ordered_list_handle *handle, void *data)
+{
+ if (handle == NULL) {
+ pcep_log(
+ LOG_WARNING,
+ "%s: ordered_list_find, the list has not been initialized",
+ __func__);
+ return NULL;
+ }
+
+ return ordered_list_find2(handle, data, handle->compare_function);
+}
+
+
+void *ordered_list_remove_first_node(ordered_list_handle *handle)
+{
+ if (handle == NULL) {
+ pcep_log(
+ LOG_WARNING,
+ "%s: ordered_list_remove_first_node, the list has not been initialized",
+ __func__);
+ return NULL;
+ }
+
+ if (handle->head == NULL) {
+ return NULL;
+ }
+ handle->num_entries--;
+
+ void *data = handle->head->data;
+ ordered_list_node *next_node = handle->head->next_node;
+ pceplib_free(PCEPLIB_INFRA, handle->head);
+ handle->head = next_node;
+
+ return data;
+}
+
+
+void *
+ordered_list_remove_first_node_equals2(ordered_list_handle *handle, void *data,
+ ordered_compare_function compare_func)
+{
+ if (handle == NULL) {
+ pcep_log(
+ LOG_WARNING,
+ "%s: ordered_list_remove_first_node_equals2, the list has not been initialized",
+ __func__);
+ return NULL;
+ }
+
+ if (handle->head == NULL) {
+ return NULL;
+ }
+
+ ordered_list_node *prev_node = handle->head;
+ ordered_list_node *node = prev_node;
+ bool keep_walking = true;
+ void *return_data = NULL;
+ int compare_result;
+
+ while (node != NULL && keep_walking) {
+ compare_result = compare_func(node->data, data);
+ if (compare_result == 0) {
+ return_data = node->data;
+ keep_walking = false;
+ handle->num_entries--;
+
+ /* adjust the corresponding pointers accordingly */
+ if (handle->head == node) {
+ /* its the first node in the list */
+ handle->head = node->next_node;
+ } else {
+ prev_node->next_node = node->next_node;
+ }
+
+ pceplib_free(PCEPLIB_INFRA, node);
+ } else {
+ prev_node = node;
+ node = node->next_node;
+ }
+ }
+
+ return return_data;
+}
+
+
+void *ordered_list_remove_first_node_equals(ordered_list_handle *handle,
+ void *data)
+{
+ if (handle == NULL) {
+ pcep_log(
+ LOG_WARNING,
+ "%s: ordered_list_remove_first_node_equals, the list has not been initialized",
+ __func__);
+ return NULL;
+ }
+
+ return ordered_list_remove_first_node_equals2(handle, data,
+ handle->compare_function);
+}
+
+
+void *ordered_list_remove_node(ordered_list_handle *handle,
+ ordered_list_node *prev_node,
+ ordered_list_node *node_toRemove)
+{
+ if (handle == NULL) {
+ pcep_log(
+ LOG_WARNING,
+ "%s: ordered_list_remove_node, the list has not been initialized",
+ __func__);
+ return NULL;
+ }
+
+ if (handle->head == NULL) {
+ return NULL;
+ }
+
+ void *return_data = node_toRemove->data;
+ handle->num_entries--;
+
+ if (node_toRemove == handle->head) {
+ handle->head = node_toRemove->next_node;
+ } else {
+ prev_node->next_node = node_toRemove->next_node;
+ }
+
+ pceplib_free(PCEPLIB_INFRA, node_toRemove);
+
+ return return_data;
+}
+
+void *ordered_list_remove_node2(ordered_list_handle *handle,
+ ordered_list_node *node_to_remove)
+{
+ if (handle == NULL) {
+ pcep_log(
+ LOG_WARNING,
+ "%s: ordered_list_remove_node2, the list has not been initialized",
+ __func__);
+ return NULL;
+ }
+
+ if (handle->head == NULL) {
+ return NULL;
+ }
+
+ ordered_list_node *node = handle->head;
+ ordered_list_node *prev_node = handle->head;
+
+ while (node != NULL) {
+ if (node == node_to_remove) {
+ return (ordered_list_remove_node(handle, prev_node,
+ node));
+ } else {
+ prev_node = node;
+ node = node->next_node;
+ }
+ }
+
+ return NULL;
+}
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#ifndef INCLUDE_PCEPUTILSORDEREDLIST_H_
+#define INCLUDE_PCEPUTILSORDEREDLIST_H_
+
+#include <stdbool.h>
+
+typedef struct ordered_list_node_ {
+ struct ordered_list_node_ *next_node;
+ void *data;
+
+} ordered_list_node;
+
+/* The implementation of this function will receive a pointer to the
+ * new data to be inserted and a pointer to the list_entry, and should
+ * return:
+ * < 0 if new_entry < list_entry
+ * == 0 if new_entry == list_entry (new_entry will be inserted after
+ * list_entry) > 0 if new_entry > list_entry
+ */
+typedef int (*ordered_compare_function)(void *list_entry, void *new_entry);
+
+/* Compare function that compares pointers */
+int pointer_compare_function(void *list_entry, void *new_entry);
+
+typedef struct ordered_list_handle_ {
+ ordered_list_node *head;
+ unsigned int num_entries;
+ ordered_compare_function compare_function;
+
+} ordered_list_handle;
+
+ordered_list_handle *ordered_list_initialize(ordered_compare_function func_ptr);
+void ordered_list_destroy(ordered_list_handle *handle);
+
+/* Add a new ordered_list_node to the list, using the ordered_compare_function
+ * to determine where in the list to add it. The newly created ordered_list_node
+ * will be returned.
+ */
+ordered_list_node *ordered_list_add_node(ordered_list_handle *handle,
+ void *data);
+
+/* Find an entry in the ordered_list using the ordered_compare_function to
+ * compare the data passed in.
+ * Return the node if found, NULL otherwise.
+ */
+ordered_list_node *ordered_list_find(ordered_list_handle *handle, void *data);
+
+/* The same as the previous function, but with a specific orderedComparefunction
+ */
+ordered_list_node *ordered_list_find2(ordered_list_handle *handle, void *data,
+ ordered_compare_function compare_func);
+
+/* Remove the first entry in the list and return the data it points to.
+ * Will return NULL if the handle is NULL or if the list is empty.
+ */
+void *ordered_list_remove_first_node(ordered_list_handle *handle);
+
+/* Remove the first entry in the list that has the same data, using the
+ * ordered_compare_function, and return the data it points to.
+ * Will return NULL if the handle is NULL or if the list is empty or
+ * if no entry is found that equals data.
+ */
+void *ordered_list_remove_first_node_equals(ordered_list_handle *handle,
+ void *data);
+
+/* The same as the previous function, but with a specific orderedComparefunction
+ */
+void *ordered_list_remove_first_node_equals2(ordered_list_handle *handle,
+ void *data,
+ ordered_compare_function func_ptr);
+
+/* Remove the node "node_to_remove" and adjust the "prev_node" pointers
+ * accordingly, returning the data pointed to by "node_to_remove". Will return
+ * NULL if the handle is NULL or if the list is empty.
+ */
+void *ordered_list_remove_node(ordered_list_handle *handle,
+ ordered_list_node *prev_node,
+ ordered_list_node *node_to_remove);
+
+/* Remove the node "node_to_remove" by searching for it in the entire list,
+ * returning the data pointed to by "node_to_remove".
+ * Will return NULL if the handle is NULL or if the list is empty.
+ */
+void *ordered_list_remove_node2(ordered_list_handle *handle,
+ ordered_list_node *node_to_remove);
+
+#endif /* INCLUDE_PCEPUTILSORDEREDLIST_H_ */
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "pcep_utils_logging.h"
+#include "pcep_utils_memory.h"
+#include "pcep_utils_queue.h"
+
+queue_handle *queue_initialize()
+{
+ /* Set the max_entries to 0 to disable it */
+ return queue_initialize_with_size(0);
+}
+
+
+queue_handle *queue_initialize_with_size(unsigned int max_entries)
+{
+ queue_handle *handle =
+ pceplib_malloc(PCEPLIB_INFRA, sizeof(queue_handle));
+ memset(handle, 0, sizeof(queue_handle));
+ handle->max_entries = max_entries;
+
+ return handle;
+}
+
+
+void queue_destroy(queue_handle *handle)
+{
+ if (handle == NULL) {
+ pcep_log(
+ LOG_DEBUG,
+ "%s: queue_destroy, the queue has not been initialized",
+ __func__);
+ return;
+ }
+
+ while (queue_dequeue(handle) != NULL) {
+ }
+ pceplib_free(PCEPLIB_INFRA, handle);
+}
+
+
+void queue_destroy_with_data(queue_handle *handle)
+{
+ if (handle == NULL) {
+ pcep_log(
+ LOG_DEBUG,
+ "%s: queue_destroy_with_data, the queue has not been initialized",
+ __func__);
+ return;
+ }
+
+ void *data = queue_dequeue(handle);
+ while (data != NULL) {
+ pceplib_free(PCEPLIB_INFRA, data);
+ data = queue_dequeue(handle);
+ }
+ pceplib_free(PCEPLIB_INFRA, handle);
+}
+
+
+queue_node *queue_enqueue(queue_handle *handle, void *data)
+{
+ if (handle == NULL) {
+ pcep_log(
+ LOG_DEBUG,
+ "%s: queue_enqueue, the queue has not been initialized",
+ __func__);
+ return NULL;
+ }
+
+ if (handle->max_entries > 0
+ && handle->num_entries >= handle->max_entries) {
+ pcep_log(
+ LOG_DEBUG,
+ "%s: queue_enqueue, cannot enqueue: max entries hit [%u]",
+ handle->num_entries);
+ return NULL;
+ }
+
+ queue_node *new_node =
+ pceplib_malloc(PCEPLIB_INFRA, sizeof(queue_node));
+ memset(new_node, 0, sizeof(queue_node));
+ new_node->data = data;
+ new_node->next_node = NULL;
+
+ (handle->num_entries)++;
+ if (handle->head == NULL) {
+ /* its the first entry in the queue */
+ handle->head = handle->tail = new_node;
+ } else {
+ handle->tail->next_node = new_node;
+ handle->tail = new_node;
+ }
+
+ return new_node;
+}
+
+
+void *queue_dequeue(queue_handle *handle)
+{
+ if (handle == NULL) {
+ pcep_log(
+ LOG_DEBUG,
+ "%s: queue_dequeue, the queue has not been initialized",
+ __func__);
+ return NULL;
+ }
+
+ if (handle->head == NULL) {
+ return NULL;
+ }
+
+ void *node_data = handle->head->data;
+ queue_node *node = handle->head;
+ (handle->num_entries)--;
+ if (handle->head == handle->tail) {
+ /* its the last entry in the queue */
+ handle->head = handle->tail = NULL;
+ } else {
+ handle->head = node->next_node;
+ }
+
+ pceplib_free(PCEPLIB_INFRA, node);
+
+ return node_data;
+}
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#ifndef INCLUDE_PCEPUTILSQUEUE_H_
+#define INCLUDE_PCEPUTILSQUEUE_H_
+
+typedef struct queue_node_ {
+ struct queue_node_ *next_node;
+ void *data;
+
+} queue_node;
+
+typedef struct queue_handle_ {
+ queue_node *head;
+ queue_node *tail;
+ unsigned int num_entries;
+ /* Set to 0 to disable */
+ unsigned int max_entries;
+
+} queue_handle;
+
+queue_handle *queue_initialize(void);
+queue_handle *queue_initialize_with_size(unsigned int max_entries);
+void queue_destroy(queue_handle *handle);
+void queue_destroy_with_data(queue_handle *handle);
+queue_node *queue_enqueue(queue_handle *handle, void *data);
+void *queue_dequeue(queue_handle *handle);
+
+#endif /* INCLUDE_PCEPUTILSQUEUE_H_ */
--- /dev/null
+if PATHD_PCEP
+
+noinst_LTLIBRARIES = pceplib/libpcep_pcc.la pceplib/libsocket_comm_mock.la
+pceplib_libpcep_pcc_la_CFLAGS = -fPIC
+pceplib_libpcep_pcc_la_SOURCES = pceplib/pcep_msg_messages.c \
+ pceplib/pcep_msg_objects.c \
+ pceplib/pcep_msg_tlvs.c \
+ pceplib/pcep_msg_tools.c \
+ pceplib/pcep_msg_messages_encoding.c \
+ pceplib/pcep_msg_objects_encoding.c \
+ pceplib/pcep_msg_tlvs_encoding.c \
+ pceplib/pcep_msg_object_error_types.c \
+ pceplib/pcep_pcc_api.c \
+ pceplib/pcep_session_logic.c \
+ pceplib/pcep_session_logic_loop.c \
+ pceplib/pcep_session_logic_states.c \
+ pceplib/pcep_session_logic_counters.c \
+ pceplib/pcep_socket_comm_loop.c \
+ pceplib/pcep_socket_comm.c \
+ pceplib/pcep_timers_event_loop.c \
+ pceplib/pcep_timers.c \
+ pceplib/pcep_utils_counters.c \
+ pceplib/pcep_utils_double_linked_list.c \
+ pceplib/pcep_utils_logging.c \
+ pceplib/pcep_utils_memory.c \
+ pceplib/pcep_utils_ordered_list.c \
+ pceplib/pcep_utils_queue.c
+
+if PATHD_PCEP_TEST
+# SocketComm Mock library used for Unit Testing
+pceplib_libsocket_comm_mock_la_SOURCES = pceplib/pcep_socket_comm_mock.c
+endif
+
+noinst_HEADERS += pceplib/pcep.h \
+ pceplib/pcep_msg_encoding.h \
+ pceplib/pcep_msg_messages.h \
+ pceplib/pcep_msg_object_error_types.h \
+ pceplib/pcep_msg_objects.h \
+ pceplib/pcep_msg_tlvs.h \
+ pceplib/pcep_msg_tools.h \
+ pceplib/pcep_pcc_api.h \
+ pceplib/pcep_session_logic.h \
+ pceplib/pcep_session_logic_internals.h \
+ pceplib/pcep_socket_comm.h \
+ pceplib/pcep_socket_comm_internals.h \
+ pceplib/pcep_socket_comm_loop.h \
+ pceplib/pcep_socket_comm_mock.h \
+ pceplib/pcep_timer_internals.h \
+ pceplib/pcep_timers.h \
+ pceplib/pcep_timers_event_loop.h \
+ pceplib/pcep_utils_counters.h \
+ pceplib/pcep_utils_double_linked_list.h \
+ pceplib/pcep_utils_logging.h \
+ pceplib/pcep_utils_memory.h \
+ pceplib/pcep_utils_ordered_list.h \
+ pceplib/pcep_utils_queue.h
+
+noinst_PROGRAMS += pceplib/pcep_pcc
+pceplib_pcep_pcc_SOURCES = pceplib/pcep_pcc.c
+pceplib_pcep_pcc_LDADD = pceplib/libpcep_pcc.la lib/libfrr.la -lpthread
+
+endif
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <stdlib.h>
+
+#include <CUnit/CUnit.h>
+
+#include "pcep_msg_encoding.h"
+#include "pcep_msg_messages.h"
+#include "pcep_msg_objects.h"
+#include "pcep_msg_tools.h"
+#include "pcep_utils_double_linked_list.h"
+#include "pcep_utils_memory.h"
+#include "pcep_msg_messages_test.h"
+
+/*
+ * Notice:
+ * All of these message Unit Tests encode the created messages by explicitly
+ * calling pcep_encode_message() thus testing the message creation and the
+ * message encoding.
+ */
+
+static struct pcep_versioning *versioning = NULL;
+
+int pcep_messages_test_suite_setup(void)
+{
+ pceplib_memory_reset();
+ return 0;
+}
+
+int pcep_messages_test_suite_teardown(void)
+{
+ printf("\n");
+ pceplib_memory_dump();
+ return 0;
+}
+
+void pcep_messages_test_setup()
+{
+ versioning = create_default_pcep_versioning();
+}
+
+void pcep_messages_test_teardown()
+{
+ destroy_pcep_versioning(versioning);
+}
+
+void test_pcep_msg_create_open()
+{
+ uint8_t keepalive = 30;
+ uint8_t deadtimer = 60;
+ uint8_t sid = 255;
+
+ struct pcep_message *message =
+ pcep_msg_create_open(keepalive, deadtimer, sid);
+ CU_ASSERT_PTR_NOT_NULL(message);
+ pcep_encode_message(message, versioning);
+ CU_ASSERT_PTR_NOT_NULL(message->msg_header);
+ CU_ASSERT_PTR_NOT_NULL(message->obj_list);
+ CU_ASSERT_EQUAL(message->obj_list->num_entries, 1);
+ CU_ASSERT_EQUAL(message->encoded_message_length,
+ MESSAGE_HEADER_LENGTH
+ + pcep_object_get_length(PCEP_OBJ_CLASS_OPEN,
+ PCEP_OBJ_TYPE_OPEN));
+ CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_OPEN);
+ CU_ASSERT_EQUAL(message->msg_header->pcep_version,
+ PCEP_MESSAGE_HEADER_VERSION);
+
+ /* Just check the class and type, the rest of the hdr fields
+ * are verified in pcep-objects-test.c */
+ struct pcep_object_open *open_obj =
+ (struct pcep_object_open *)message->obj_list->head->data;
+ CU_ASSERT_EQUAL(open_obj->header.object_class, PCEP_OBJ_CLASS_OPEN);
+ CU_ASSERT_EQUAL(open_obj->header.object_type, PCEP_OBJ_TYPE_OPEN);
+
+ CU_ASSERT_EQUAL(open_obj->open_deadtimer, deadtimer);
+ CU_ASSERT_EQUAL(open_obj->open_keepalive, keepalive);
+ CU_ASSERT_EQUAL(open_obj->open_sid, sid);
+ CU_ASSERT_EQUAL(open_obj->open_version, PCEP_OBJECT_OPEN_VERSION);
+ pcep_msg_free_message(message);
+}
+
+
+void test_pcep_msg_create_request()
+{
+ /* First test with NULL objects */
+ struct pcep_message *message =
+ pcep_msg_create_request(NULL, NULL, NULL);
+ CU_ASSERT_PTR_NULL(message);
+
+ /* Test IPv4 */
+ struct pcep_object_rp *rp_obj =
+ pcep_obj_create_rp(0, false, false, false, false, 10, NULL);
+ struct in_addr src_addr={}, dst_addr={};
+ struct pcep_object_endpoints_ipv4 *ipv4_obj =
+ pcep_obj_create_endpoint_ipv4(&src_addr, &dst_addr);
+ message = pcep_msg_create_request(rp_obj, ipv4_obj, NULL);
+
+ CU_ASSERT_PTR_NOT_NULL(message);
+ pcep_encode_message(message, versioning);
+ CU_ASSERT_PTR_NOT_NULL(message->msg_header);
+ CU_ASSERT_PTR_NOT_NULL(message->obj_list);
+ CU_ASSERT_EQUAL(message->obj_list->num_entries, 2);
+ CU_ASSERT_EQUAL(
+ message->encoded_message_length,
+ MESSAGE_HEADER_LENGTH
+ + pcep_object_get_length_by_hdr(&rp_obj->header)
+ + pcep_object_get_length_by_hdr(&ipv4_obj->header));
+ CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_PCREQ);
+ CU_ASSERT_EQUAL(message->msg_header->pcep_version,
+ PCEP_MESSAGE_HEADER_VERSION);
+ pcep_msg_free_message(message);
+
+ /* Test IPv6 */
+ rp_obj = pcep_obj_create_rp(0, false, false, false, false, 10, NULL);
+ struct in6_addr src_addr_ipv6, dst_addr_ipv6;
+ struct pcep_object_endpoints_ipv6 *ipv6_obj =
+ pcep_obj_create_endpoint_ipv6(&src_addr_ipv6, &dst_addr_ipv6);
+ message = pcep_msg_create_request_ipv6(rp_obj, ipv6_obj, NULL);
+
+ CU_ASSERT_PTR_NOT_NULL(message);
+ pcep_encode_message(message, versioning);
+ CU_ASSERT_PTR_NOT_NULL(message->msg_header);
+ CU_ASSERT_PTR_NOT_NULL(message->obj_list);
+ CU_ASSERT_EQUAL(message->obj_list->num_entries, 2);
+ CU_ASSERT_EQUAL(
+ message->encoded_message_length,
+ MESSAGE_HEADER_LENGTH
+ + pcep_object_get_length_by_hdr(&rp_obj->header)
+ + pcep_object_get_length_by_hdr(&ipv6_obj->header));
+ CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_PCREQ);
+ CU_ASSERT_EQUAL(message->msg_header->pcep_version,
+ PCEP_MESSAGE_HEADER_VERSION);
+ pcep_msg_free_message(message);
+
+ /* The objects get deleted with the message, so they need to be created
+ * again */
+ rp_obj = pcep_obj_create_rp(0, false, false, false, false, 10, NULL);
+ ipv4_obj = pcep_obj_create_endpoint_ipv4(&src_addr, &dst_addr);
+ struct pcep_object_bandwidth *bandwidth_obj =
+ pcep_obj_create_bandwidth(4.2);
+ double_linked_list *obj_list = dll_initialize();
+ dll_append(obj_list, bandwidth_obj);
+ message = pcep_msg_create_request(rp_obj, ipv4_obj, obj_list);
+
+ CU_ASSERT_PTR_NOT_NULL(message);
+ pcep_encode_message(message, versioning);
+ CU_ASSERT_PTR_NOT_NULL(message->msg_header);
+ CU_ASSERT_PTR_NOT_NULL(message->obj_list);
+ CU_ASSERT_EQUAL(message->obj_list->num_entries, 3);
+ CU_ASSERT_EQUAL(
+ message->encoded_message_length,
+ MESSAGE_HEADER_LENGTH
+ + pcep_object_get_length_by_hdr(&rp_obj->header)
+ + pcep_object_get_length_by_hdr(&ipv4_obj->header)
+ + pcep_object_get_length_by_hdr(
+ &bandwidth_obj->header));
+ CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_PCREQ);
+ CU_ASSERT_EQUAL(message->msg_header->pcep_version,
+ PCEP_MESSAGE_HEADER_VERSION);
+ pcep_msg_free_message(message);
+}
+
+
+void test_pcep_msg_create_request_svec()
+{
+}
+
+
+void test_pcep_msg_create_reply_nopath()
+{
+ struct pcep_object_rp *rp_obj =
+ pcep_obj_create_rp(0, false, false, false, false, 10, NULL);
+ struct pcep_object_nopath *nopath_obj = pcep_obj_create_nopath(
+ false, false, PCEP_NOPATH_TLV_ERR_NO_TLV);
+ double_linked_list *obj_list = dll_initialize();
+ dll_append(obj_list, nopath_obj);
+
+ struct pcep_message *message = pcep_msg_create_reply(rp_obj, obj_list);
+ CU_ASSERT_PTR_NOT_NULL(message);
+ pcep_encode_message(message, versioning);
+ CU_ASSERT_PTR_NOT_NULL(message->msg_header);
+ CU_ASSERT_PTR_NOT_NULL(message->obj_list);
+ CU_ASSERT_EQUAL(message->obj_list->num_entries, 2);
+ CU_ASSERT_EQUAL(message->encoded_message_length,
+ (MESSAGE_HEADER_LENGTH
+ + pcep_object_get_length_by_hdr(&rp_obj->header)
+ + pcep_object_get_length_by_hdr(&nopath_obj->header)));
+ CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_PCREP);
+ CU_ASSERT_EQUAL(message->msg_header->pcep_version,
+ PCEP_MESSAGE_HEADER_VERSION);
+ pcep_msg_free_message(message);
+}
+
+
+void test_pcep_msg_create_reply()
+{
+ /* First test with NULL ero and rp objects */
+ struct pcep_message *message = pcep_msg_create_reply(NULL, NULL);
+
+ CU_ASSERT_PTR_NOT_NULL(message);
+ pcep_encode_message(message, versioning);
+ CU_ASSERT_PTR_NOT_NULL(message->msg_header);
+ CU_ASSERT_PTR_NOT_NULL(message->obj_list);
+ CU_ASSERT_EQUAL(message->obj_list->num_entries, 0);
+ CU_ASSERT_EQUAL(message->encoded_message_length, MESSAGE_HEADER_LENGTH);
+ CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_PCREP);
+ CU_ASSERT_EQUAL(message->msg_header->pcep_version,
+ PCEP_MESSAGE_HEADER_VERSION);
+ pcep_msg_free_message(message);
+
+ double_linked_list *ero_subobj_list = dll_initialize();
+ struct pcep_object_ro_subobj *ero_subobj =
+ (struct pcep_object_ro_subobj *)
+ pcep_obj_create_ro_subobj_32label(true, 1, 10);
+ dll_append(ero_subobj_list, ero_subobj);
+ struct pcep_object_ro *ero = pcep_obj_create_ero(ero_subobj_list);
+
+ double_linked_list *object_list = dll_initialize();
+ dll_append(object_list, ero);
+ struct pcep_object_rp *rp_obj =
+ pcep_obj_create_rp(0, false, false, false, false, 10, NULL);
+ message = pcep_msg_create_reply(rp_obj, object_list);
+ CU_ASSERT_PTR_NOT_NULL(message);
+ pcep_encode_message(message, versioning);
+ CU_ASSERT_PTR_NOT_NULL(message->msg_header);
+ CU_ASSERT_PTR_NOT_NULL(message->obj_list);
+ CU_ASSERT_EQUAL(message->obj_list->num_entries, 2);
+ CU_ASSERT_EQUAL(message->encoded_message_length,
+ MESSAGE_HEADER_LENGTH
+ + pcep_object_get_length_by_hdr(&rp_obj->header)
+ + OBJECT_HEADER_LENGTH
+ + OBJECT_RO_SUBOBJ_HEADER_LENGTH
+ + 6 /* size of the 32label */);
+ CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_PCREP);
+ CU_ASSERT_EQUAL(message->msg_header->pcep_version,
+ PCEP_MESSAGE_HEADER_VERSION);
+ pcep_msg_free_message(message);
+}
+
+
+void test_pcep_msg_create_close()
+{
+ uint8_t reason = PCEP_CLOSE_REASON_UNREC_MSG;
+
+ struct pcep_message *message = pcep_msg_create_close(reason);
+ CU_ASSERT_PTR_NOT_NULL(message);
+ pcep_encode_message(message, versioning);
+ CU_ASSERT_PTR_NOT_NULL(message->msg_header);
+ CU_ASSERT_PTR_NOT_NULL(message->obj_list);
+ CU_ASSERT_EQUAL(message->obj_list->num_entries, 1);
+ CU_ASSERT_EQUAL(message->encoded_message_length,
+ MESSAGE_HEADER_LENGTH
+ + pcep_object_get_length(PCEP_OBJ_CLASS_CLOSE,
+ PCEP_OBJ_TYPE_CLOSE));
+ CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_CLOSE);
+ CU_ASSERT_EQUAL(message->msg_header->pcep_version,
+ PCEP_MESSAGE_HEADER_VERSION);
+
+ /* Just check the class and type, the rest of the hdr fields
+ * are verified in pcep-objects-test.c */
+ struct pcep_object_close *close_obj =
+ (struct pcep_object_close *)message->obj_list->head->data;
+ CU_ASSERT_EQUAL(close_obj->header.object_class, PCEP_OBJ_CLASS_CLOSE);
+ CU_ASSERT_EQUAL(close_obj->header.object_type, PCEP_OBJ_TYPE_CLOSE);
+ CU_ASSERT_EQUAL(close_obj->reason, reason);
+ pcep_msg_free_message(message);
+}
+
+
+void test_pcep_msg_create_error()
+{
+ uint8_t error_type = PCEP_ERRT_RECEPTION_OF_INV_OBJECT;
+ uint8_t error_value = PCEP_ERRV_KEEPALIVEWAIT_TIMED_OUT;
+
+ struct pcep_message *message =
+ pcep_msg_create_error(error_type, error_value);
+ CU_ASSERT_PTR_NOT_NULL(message);
+ pcep_encode_message(message, versioning);
+ CU_ASSERT_PTR_NOT_NULL(message->msg_header);
+ CU_ASSERT_PTR_NOT_NULL(message->obj_list);
+ CU_ASSERT_EQUAL(message->obj_list->num_entries, 1);
+ CU_ASSERT_EQUAL(message->encoded_message_length,
+ MESSAGE_HEADER_LENGTH
+ + pcep_object_get_length(PCEP_OBJ_CLASS_ERROR,
+ PCEP_OBJ_TYPE_ERROR));
+ CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_ERROR);
+ CU_ASSERT_EQUAL(message->msg_header->pcep_version,
+ PCEP_MESSAGE_HEADER_VERSION);
+
+ /* Just check the class and type, the rest of the hdr fields
+ * are verified in pcep-objects-test.c */
+ struct pcep_object_error *error_obj =
+ (struct pcep_object_error *)message->obj_list->head->data;
+ CU_ASSERT_EQUAL(error_obj->header.object_class, PCEP_OBJ_CLASS_ERROR);
+ CU_ASSERT_EQUAL(error_obj->header.object_type, PCEP_OBJ_TYPE_ERROR);
+
+ CU_ASSERT_EQUAL(error_obj->error_type, error_type);
+ CU_ASSERT_EQUAL(error_obj->error_value, error_value);
+ pcep_msg_free_message(message);
+}
+
+
+void test_pcep_msg_create_keepalive()
+{
+ struct pcep_message *message = pcep_msg_create_keepalive();
+ CU_ASSERT_PTR_NOT_NULL(message);
+ pcep_encode_message(message, versioning);
+ CU_ASSERT_PTR_NOT_NULL(message->msg_header);
+ CU_ASSERT_PTR_NOT_NULL(message->obj_list);
+ CU_ASSERT_EQUAL(message->obj_list->num_entries, 0);
+ CU_ASSERT_EQUAL(message->encoded_message_length, MESSAGE_HEADER_LENGTH);
+ CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_KEEPALIVE);
+ CU_ASSERT_EQUAL(message->msg_header->pcep_version,
+ PCEP_MESSAGE_HEADER_VERSION);
+ pcep_msg_free_message(message);
+}
+
+void test_pcep_msg_create_report()
+{
+ double_linked_list *obj_list = dll_initialize();
+
+ /* Should return NULL if obj_list is empty */
+ struct pcep_message *message = pcep_msg_create_report(NULL);
+ CU_ASSERT_PTR_NULL(message);
+
+ struct pcep_object_lsp *lsp =
+ pcep_obj_create_lsp(100, PCEP_LSP_OPERATIONAL_UP, true, true,
+ true, true, true, NULL);
+ dll_append(obj_list, lsp);
+ message = pcep_msg_create_report(obj_list);
+ CU_ASSERT_PTR_NOT_NULL(message);
+ pcep_encode_message(message, versioning);
+ CU_ASSERT_PTR_NOT_NULL(message->msg_header);
+ CU_ASSERT_PTR_NOT_NULL(message->obj_list);
+ CU_ASSERT_EQUAL(message->obj_list->num_entries, 1);
+ CU_ASSERT_EQUAL(message->encoded_message_length,
+ MESSAGE_HEADER_LENGTH
+ + lsp->header.encoded_object_length);
+ CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_REPORT);
+ CU_ASSERT_EQUAL(message->msg_header->pcep_version,
+ PCEP_MESSAGE_HEADER_VERSION);
+
+ pcep_msg_free_message(message);
+}
+
+void test_pcep_msg_create_update()
+{
+ double_linked_list *obj_list = dll_initialize();
+ double_linked_list *ero_subobj_list = dll_initialize();
+
+ struct pcep_message *message = pcep_msg_create_update(NULL);
+ CU_ASSERT_PTR_NULL(message);
+
+ /* Should return NULL if obj_list is empty */
+ message = pcep_msg_create_update(obj_list);
+ CU_ASSERT_PTR_NULL(message);
+ if (message != NULL) {
+ pcep_msg_free_message(message);
+ message = NULL;
+ }
+
+ struct pcep_object_srp *srp = pcep_obj_create_srp(false, 100, NULL);
+ struct pcep_object_lsp *lsp =
+ pcep_obj_create_lsp(100, PCEP_LSP_OPERATIONAL_UP, true, true,
+ true, true, true, NULL);
+ dll_append(ero_subobj_list, pcep_obj_create_ro_subobj_asn(0x0102));
+ struct pcep_object_ro *ero = pcep_obj_create_ero(ero_subobj_list);
+
+ /* Should return NULL if obj_list does not have 3 entries */
+ dll_append(obj_list, srp);
+ dll_append(obj_list, lsp);
+ message = pcep_msg_create_update(obj_list);
+ CU_ASSERT_PTR_NULL(message);
+
+ dll_append(obj_list, ero);
+ if (message != NULL) {
+ pcep_msg_free_message(message);
+ message = NULL;
+ }
+ message = pcep_msg_create_update(obj_list);
+ CU_ASSERT_PTR_NOT_NULL(message);
+ pcep_encode_message(message, versioning);
+ CU_ASSERT_PTR_NOT_NULL(message->msg_header);
+ CU_ASSERT_PTR_NOT_NULL(message->obj_list);
+ CU_ASSERT_EQUAL(message->obj_list->num_entries, 3);
+ CU_ASSERT_EQUAL(message->encoded_message_length,
+ MESSAGE_HEADER_LENGTH
+ + srp->header.encoded_object_length
+ + lsp->header.encoded_object_length
+ + ero->header.encoded_object_length);
+ CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_UPDATE);
+ CU_ASSERT_EQUAL(message->msg_header->pcep_version,
+ PCEP_MESSAGE_HEADER_VERSION);
+
+ pcep_msg_free_message(message);
+}
+
+void test_pcep_msg_create_initiate()
+{
+ double_linked_list *obj_list = dll_initialize();
+ double_linked_list *ero_subobj_list = dll_initialize();
+
+ /* Should return NULL if obj_list is empty */
+ struct pcep_message *message = pcep_msg_create_initiate(NULL);
+ CU_ASSERT_PTR_NULL(message);
+ if (message != NULL) {
+ pcep_msg_free_message(message);
+ message = NULL;
+ }
+
+ struct pcep_object_srp *srp = pcep_obj_create_srp(false, 100, NULL);
+ struct pcep_object_lsp *lsp =
+ pcep_obj_create_lsp(100, PCEP_LSP_OPERATIONAL_UP, true, true,
+ true, true, true, NULL);
+ dll_append(ero_subobj_list, pcep_obj_create_ro_subobj_asn(0x0102));
+ struct pcep_object_ro *ero = pcep_obj_create_ero(ero_subobj_list);
+
+ /* Should return NULL if obj_list does not have 2 entries */
+ dll_append(obj_list, srp);
+ message = pcep_msg_create_initiate(obj_list);
+ CU_ASSERT_PTR_NULL(message);
+ if (message != NULL) {
+ pcep_msg_free_message(message);
+ message = NULL;
+ }
+
+ dll_append(obj_list, lsp);
+ dll_append(obj_list, ero);
+ message = pcep_msg_create_initiate(obj_list);
+ CU_ASSERT_PTR_NOT_NULL(message);
+ pcep_encode_message(message, versioning);
+ CU_ASSERT_PTR_NOT_NULL(message->msg_header);
+ CU_ASSERT_PTR_NOT_NULL(message->obj_list);
+ CU_ASSERT_EQUAL(message->obj_list->num_entries, 3);
+ CU_ASSERT_EQUAL(message->encoded_message_length,
+ MESSAGE_HEADER_LENGTH
+ + srp->header.encoded_object_length
+ + lsp->header.encoded_object_length
+ + ero->header.encoded_object_length);
+ CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_INITIATE);
+ CU_ASSERT_EQUAL(message->msg_header->pcep_version,
+ PCEP_MESSAGE_HEADER_VERSION);
+
+ pcep_msg_free_message(message);
+}
+
+void test_pcep_msg_create_notify(void)
+{
+ struct pcep_object_notify *notify_obj = pcep_obj_create_notify(
+ PCEP_NOTIFY_TYPE_PENDING_REQUEST_CANCELLED,
+ PCEP_NOTIFY_VALUE_PCC_CANCELLED_REQUEST);
+
+ /* Should return NULL if the notify obj is empty */
+ struct pcep_message *message = pcep_msg_create_notify(NULL, NULL);
+ CU_ASSERT_PTR_NULL(message);
+
+ message = pcep_msg_create_notify(notify_obj, NULL);
+ CU_ASSERT_PTR_NOT_NULL(message);
+ pcep_encode_message(message, versioning);
+ CU_ASSERT_PTR_NOT_NULL(message->obj_list);
+ CU_ASSERT_EQUAL(message->obj_list->num_entries, 1);
+ CU_ASSERT_EQUAL(message->encoded_message_length,
+ MESSAGE_HEADER_LENGTH
+ + notify_obj->header.encoded_object_length);
+ CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_PCNOTF);
+ CU_ASSERT_EQUAL(message->msg_header->pcep_version,
+ PCEP_MESSAGE_HEADER_VERSION);
+
+ pcep_msg_free_message(message);
+
+ struct pcep_object_rp *rp_obj =
+ pcep_obj_create_rp(0, false, false, false, false, 10, NULL);
+ double_linked_list *obj_list = dll_initialize();
+ dll_append(obj_list, rp_obj);
+ notify_obj = pcep_obj_create_notify(
+ PCEP_NOTIFY_TYPE_PENDING_REQUEST_CANCELLED,
+ PCEP_NOTIFY_VALUE_PCC_CANCELLED_REQUEST);
+
+ message = pcep_msg_create_notify(notify_obj, obj_list);
+ CU_ASSERT_PTR_NOT_NULL(message);
+ pcep_encode_message(message, versioning);
+ CU_ASSERT_PTR_NOT_NULL(message->obj_list);
+ CU_ASSERT_EQUAL(message->obj_list->num_entries, 2);
+ CU_ASSERT_EQUAL(message->encoded_message_length,
+ MESSAGE_HEADER_LENGTH
+ + notify_obj->header.encoded_object_length
+ + rp_obj->header.encoded_object_length);
+ CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_PCNOTF);
+ CU_ASSERT_EQUAL(message->msg_header->pcep_version,
+ PCEP_MESSAGE_HEADER_VERSION);
+
+ pcep_msg_free_message(message);
+}
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Javier Garcia <javier.garcia@voltanet.io>
+ *
+ */
+
+/*
+ * Timer definitions to be used internally by the pcep_timers library.
+ */
+
+#ifndef PCEP_MSG_MSG_TEST_H_
+#define PCEP_MSG_MSG_TEST_H_
+
+/* functions to be tested from pcep-messages.c */
+int pcep_messages_test_suite_setup(void);
+int pcep_messages_test_suite_teardown(void);
+void pcep_messages_test_setup(void);
+void pcep_messages_test_teardown(void);
+void test_pcep_msg_create_open(void);
+void test_pcep_msg_create_request(void);
+void test_pcep_msg_create_request_svec(void);
+void test_pcep_msg_create_reply_nopath(void);
+void test_pcep_msg_create_reply(void);
+void test_pcep_msg_create_close(void);
+void test_pcep_msg_create_error(void);
+void test_pcep_msg_create_keepalive(void);
+void test_pcep_msg_create_report(void);
+void test_pcep_msg_create_update(void);
+void test_pcep_msg_create_initiate(void);
+void test_pcep_msg_create_notify(void);
+
+#endif /* PCEPTIMERINTERNALS_H_ */
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <CUnit/Basic.h>
+#include <CUnit/CUnit.h>
+#include <CUnit/TestDB.h>
+
+#include "pcep_msg_messages_test.h"
+#include "pcep_msg_tools_test.h"
+#include "pcep_msg_object_error_types.h"
+#include "pcep_msg_object_error_types_test.h"
+#include "pcep_msg_tlvs_test.h"
+#include "pcep_msg_objects_test.h"
+
+
+int main(int argc, char **argv)
+{
+ /* Unused parameters cause compilation warnings */
+ (void)argc;
+ (void)argv;
+
+ CU_initialize_registry();
+
+ CU_pSuite messages_suite = CU_add_suite_with_setup_and_teardown(
+ "PCEP Messages Test Suite", pcep_messages_test_suite_setup,
+ pcep_messages_test_suite_teardown, /* suite setup and cleanup
+ function pointers */
+ pcep_messages_test_setup, pcep_messages_test_teardown);
+ CU_add_test(messages_suite, "test_pcep_msg_create_open",
+ test_pcep_msg_create_open);
+ CU_add_test(messages_suite, "test_pcep_msg_create_request",
+ test_pcep_msg_create_request);
+ CU_add_test(messages_suite, "test_pcep_msg_create_request_svec",
+ test_pcep_msg_create_request_svec);
+ CU_add_test(messages_suite, "test_pcep_msg_create_reply_nopath",
+ test_pcep_msg_create_reply_nopath);
+ CU_add_test(messages_suite, "test_pcep_msg_create_reply",
+ test_pcep_msg_create_reply);
+ CU_add_test(messages_suite, "test_pcep_msg_create_close",
+ test_pcep_msg_create_close);
+ CU_add_test(messages_suite, "test_pcep_msg_create_error",
+ test_pcep_msg_create_error);
+ CU_add_test(messages_suite, "test_pcep_msg_create_keepalive",
+ test_pcep_msg_create_keepalive);
+ CU_add_test(messages_suite, "test_pcep_msg_create_report",
+ test_pcep_msg_create_report);
+ CU_add_test(messages_suite, "test_pcep_msg_create_update",
+ test_pcep_msg_create_update);
+ CU_add_test(messages_suite, "test_pcep_msg_create_initiate",
+ test_pcep_msg_create_initiate);
+ CU_add_test(messages_suite, "test_pcep_msg_create_notify",
+ test_pcep_msg_create_notify);
+
+ CU_pSuite tlvs_suite = CU_add_suite_with_setup_and_teardown(
+ "PCEP TLVs Test Suite", pcep_tlvs_test_suite_setup,
+ pcep_tlvs_test_suite_teardown, /* suite setup and cleanup
+ function pointers */
+ pcep_tlvs_test_setup, pcep_tlvs_test_teardown);
+ CU_add_test(tlvs_suite, "test_pcep_tlv_create_stateful_pce_capability",
+ test_pcep_tlv_create_stateful_pce_capability);
+ CU_add_test(tlvs_suite, "test_pcep_tlv_create_speaker_entity_id",
+ test_pcep_tlv_create_speaker_entity_id);
+ CU_add_test(tlvs_suite, "test_pcep_tlv_create_lsp_db_version",
+ test_pcep_tlv_create_lsp_db_version);
+ CU_add_test(tlvs_suite, "test_pcep_tlv_create_path_setup_type",
+ test_pcep_tlv_create_path_setup_type);
+ CU_add_test(tlvs_suite,
+ "test_pcep_tlv_create_path_setup_type_capability",
+ test_pcep_tlv_create_path_setup_type_capability);
+ CU_add_test(tlvs_suite, "test_pcep_tlv_create_sr_pce_capability",
+ test_pcep_tlv_create_sr_pce_capability);
+ CU_add_test(tlvs_suite, "test_pcep_tlv_create_symbolic_path_name",
+ test_pcep_tlv_create_symbolic_path_name);
+ CU_add_test(tlvs_suite, "test_pcep_tlv_create_ipv4_lsp_identifiers",
+ test_pcep_tlv_create_ipv4_lsp_identifiers);
+ CU_add_test(tlvs_suite, "test_pcep_tlv_create_ipv6_lsp_identifiers",
+ test_pcep_tlv_create_ipv6_lsp_identifiers);
+ CU_add_test(tlvs_suite, "test_pcep_tlv_create_srpag_pol_id_ipv4",
+ test_pcep_tlv_create_srpag_pol_id_ipv4);
+ CU_add_test(tlvs_suite, "test_pcep_tlv_create_srpag_pol_id_ipv6",
+ test_pcep_tlv_create_srpag_pol_id_ipv6);
+ CU_add_test(tlvs_suite, "test_pcep_tlv_create_srpag_pol_name",
+ test_pcep_tlv_create_srpag_pol_name);
+ CU_add_test(tlvs_suite, "test_pcep_tlv_create_srpag_cp_id",
+ test_pcep_tlv_create_srpag_cp_id);
+ CU_add_test(tlvs_suite, "test_pcep_tlv_create_srpag_cp_pref",
+ test_pcep_tlv_create_srpag_cp_pref);
+ CU_add_test(tlvs_suite, "test_pcep_tlv_create_lsp_error_code",
+ test_pcep_tlv_create_lsp_error_code);
+ CU_add_test(tlvs_suite, "test_pcep_tlv_create_rsvp_ipv4_error_spec",
+ test_pcep_tlv_create_rsvp_ipv4_error_spec);
+ CU_add_test(tlvs_suite, "test_pcep_tlv_create_rsvp_ipv6_error_spec",
+ test_pcep_tlv_create_rsvp_ipv6_error_spec);
+ CU_add_test(tlvs_suite, "test_pcep_tlv_create_nopath_vector",
+ test_pcep_tlv_create_nopath_vector);
+ CU_add_test(tlvs_suite, "test_pcep_tlv_create_arbitrary",
+ test_pcep_tlv_create_arbitrary);
+
+ CU_pSuite objects_suite = CU_add_suite_with_setup_and_teardown(
+ "PCEP Objects Test Suite", pcep_objects_test_suite_setup,
+ pcep_objects_test_suite_teardown, /* suite setup and cleanup
+ function pointers */
+ pcep_objects_test_setup, pcep_objects_test_teardown);
+ CU_add_test(objects_suite, "test_pcep_obj_create_open",
+ test_pcep_obj_create_open);
+ CU_add_test(objects_suite, "test_pcep_obj_create_open",
+ test_pcep_obj_create_open_with_tlvs);
+ CU_add_test(objects_suite, "test_pcep_obj_create_rp",
+ test_pcep_obj_create_rp);
+ CU_add_test(objects_suite, "test_pcep_obj_create_nopath",
+ test_pcep_obj_create_nopath);
+ CU_add_test(objects_suite, "test_pcep_obj_create_enpoint_ipv4",
+ test_pcep_obj_create_endpoint_ipv4);
+ CU_add_test(objects_suite, "test_pcep_obj_create_enpoint_ipv6",
+ test_pcep_obj_create_endpoint_ipv6);
+ CU_add_test(objects_suite, "test_pcep_obj_create_association_ipv4",
+ test_pcep_obj_create_association_ipv4);
+ CU_add_test(objects_suite, "test_pcep_obj_create_association_ipv6",
+ test_pcep_obj_create_association_ipv6);
+ CU_add_test(objects_suite, "test_pcep_obj_create_bandwidth",
+ test_pcep_obj_create_bandwidth);
+ CU_add_test(objects_suite, "test_pcep_obj_create_metric",
+ test_pcep_obj_create_metric);
+ CU_add_test(objects_suite, "test_pcep_obj_create_lspa",
+ test_pcep_obj_create_lspa);
+ CU_add_test(objects_suite, "test_pcep_obj_create_svec",
+ test_pcep_obj_create_svec);
+ CU_add_test(objects_suite, "test_pcep_obj_create_error",
+ test_pcep_obj_create_error);
+ CU_add_test(objects_suite, "test_pcep_obj_create_close",
+ test_pcep_obj_create_close);
+ CU_add_test(objects_suite, "test_pcep_obj_create_srp",
+ test_pcep_obj_create_srp);
+ CU_add_test(objects_suite, "test_pcep_obj_create_lsp",
+ test_pcep_obj_create_lsp);
+ CU_add_test(objects_suite, "test_pcep_obj_create_vendor_info",
+ test_pcep_obj_create_vendor_info);
+
+ CU_add_test(objects_suite, "test_pcep_obj_create_ero",
+ test_pcep_obj_create_ero);
+ CU_add_test(objects_suite, "test_pcep_obj_create_rro",
+ test_pcep_obj_create_rro);
+ CU_add_test(objects_suite, "test_pcep_obj_create_iro",
+ test_pcep_obj_create_iro);
+ CU_add_test(objects_suite, "test_pcep_obj_create_ro_subobj_ipv4",
+ test_pcep_obj_create_ro_subobj_ipv4);
+ CU_add_test(objects_suite, "test_pcep_obj_create_ro_subobj_ipv6",
+ test_pcep_obj_create_ro_subobj_ipv6);
+ CU_add_test(objects_suite, "test_pcep_obj_create_ro_subobj_unnum",
+ test_pcep_obj_create_ro_subobj_unnum);
+ CU_add_test(objects_suite, "test_pcep_obj_create_ro_subobj_32label",
+ test_pcep_obj_create_ro_subobj_32label);
+ CU_add_test(objects_suite, "test_pcep_obj_create_ro_subobj_asn",
+ test_pcep_obj_create_ro_subobj_asn);
+
+ CU_add_test(objects_suite, "test_pcep_obj_create_ro_subobj_sr_nonai",
+ test_pcep_obj_create_ro_subobj_sr_nonai);
+ CU_add_test(objects_suite,
+ "test_pcep_obj_create_ro_subobj_sr_ipv4_node",
+ test_pcep_obj_create_ro_subobj_sr_ipv4_node);
+ CU_add_test(objects_suite,
+ "test_pcep_obj_create_ro_subobj_sr_ipv6_node",
+ test_pcep_obj_create_ro_subobj_sr_ipv6_node);
+ CU_add_test(objects_suite, "test_pcep_obj_create_ro_subobj_sr_ipv4_adj",
+ test_pcep_obj_create_ro_subobj_sr_ipv4_adj);
+ CU_add_test(objects_suite, "test_pcep_obj_create_ro_subobj_sr_ipv6_adj",
+ test_pcep_obj_create_ro_subobj_sr_ipv6_adj);
+ CU_add_test(objects_suite,
+ "test_pcep_obj_create_ro_subobj_sr_unnumbered_ipv4_adj",
+ test_pcep_obj_create_ro_subobj_sr_unnumbered_ipv4_adj);
+ CU_add_test(objects_suite,
+ "test_pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj",
+ test_pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj);
+
+ CU_pSuite tools_suite = CU_add_suite_with_setup_and_teardown(
+ "PCEP Tools Test Suite", pcep_tools_test_suite_setup,
+ pcep_tools_test_suite_teardown, pcep_tools_test_setup,
+ pcep_tools_test_teardown);
+ CU_add_test(tools_suite, "test_pcep_msg_read_pcep_initiate",
+ test_pcep_msg_read_pcep_initiate);
+ CU_add_test(tools_suite, "test_pcep_msg_read_pcep_initiate2",
+ test_pcep_msg_read_pcep_initiate2);
+ CU_add_test(tools_suite, "test_pcep_msg_read_pcep_update",
+ test_pcep_msg_read_pcep_update);
+ CU_add_test(tools_suite, "test_pcep_msg_read_pcep_open",
+ test_pcep_msg_read_pcep_open);
+ CU_add_test(tools_suite, "test_pcep_msg_read_pcep_open_initiate",
+ test_pcep_msg_read_pcep_open_initiate);
+ CU_add_test(tools_suite, "test_validate_message_header",
+ test_validate_message_header);
+ CU_add_test(tools_suite, "test_validate_message_objects",
+ test_validate_message_objects);
+ CU_add_test(tools_suite, "test_validate_message_objects_invalid",
+ test_validate_message_objects_invalid);
+ CU_add_test(tools_suite, "test_pcep_msg_read_pcep_open_cisco_pce",
+ test_pcep_msg_read_pcep_open_cisco_pce);
+ CU_add_test(tools_suite, "test_pcep_msg_read_pcep_update_cisco_pce",
+ test_pcep_msg_read_pcep_update_cisco_pce);
+ CU_add_test(tools_suite, "test_pcep_msg_read_pcep_report_cisco_pcc",
+ test_pcep_msg_read_pcep_report_cisco_pcc);
+ CU_add_test(tools_suite, "test_pcep_msg_read_pcep_initiate_cisco_pcc",
+ test_pcep_msg_read_pcep_initiate_cisco_pcc);
+
+ CU_pSuite obj_errors_suite = CU_add_suite_with_setup_and_teardown(
+ "PCEP Object Error Types Test Suite",
+ pcep_object_error_types_test_suite_setup,
+ pcep_object_error_types_test_suite_teardown,
+ pcep_object_error_types_test_setup,
+ pcep_object_error_types_test_teardown);
+ CU_add_test(obj_errors_suite, "test_get_error_type_str",
+ test_get_error_type_str);
+ CU_add_test(obj_errors_suite, "test_get_error_value_str",
+ test_get_error_value_str);
+
+ CU_basic_set_mode(CU_BRM_VERBOSE);
+ CU_basic_run_tests();
+ CU_FailureRecord *failure_record = CU_get_failure_list();
+ if (failure_record != NULL) {
+ printf("\nFailed tests:\n\t [Suite] [Test] [File:line-number]\n");
+ do {
+ printf("\t [%s] [%s] [%s:%d]\n",
+ failure_record->pSuite->pName,
+ failure_record->pTest->pName,
+ failure_record->strFileName,
+ failure_record->uiLineNumber);
+ failure_record = failure_record->pNext;
+
+ } while (failure_record != NULL);
+ }
+
+ CU_pRunSummary run_summary = CU_get_run_summary();
+ int result = run_summary->nTestsFailed;
+ CU_cleanup_registry();
+
+ return result;
+}
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <stdio.h>
+
+#include <CUnit/CUnit.h>
+
+#include "pcep_msg_object_error_types.h"
+#include "pcep_msg_object_error_types_test.h"
+#include "pcep_utils_logging.h"
+#include "pcep_utils_memory.h"
+
+int pcep_object_error_types_test_suite_setup(void)
+{
+ pceplib_memory_reset();
+ set_logging_level(LOG_DEBUG);
+ return 0;
+}
+
+int pcep_object_error_types_test_suite_teardown(void)
+{
+ printf("\n");
+ pceplib_memory_dump();
+ return 0;
+}
+
+void pcep_object_error_types_test_setup(void)
+{
+}
+
+void pcep_object_error_types_test_teardown(void)
+{
+}
+
+void test_get_error_type_str()
+{
+ const char *error_type_str;
+ int i = 0;
+ for (; i < MAX_ERROR_TYPE; i++) {
+ error_type_str = get_error_type_str(i);
+ CU_ASSERT_PTR_NOT_NULL(error_type_str);
+ }
+
+ CU_ASSERT_PTR_NULL(get_error_type_str(-1));
+ CU_ASSERT_PTR_NULL(get_error_type_str(MAX_ERROR_TYPE));
+}
+
+void test_get_error_value_str()
+{
+ const char *error_value_str;
+ int i = 0, j = 0;
+
+ for (; i < MAX_ERROR_TYPE; i++) {
+ for (; j < MAX_ERROR_VALUE; j++) {
+ error_value_str = get_error_value_str(i, j);
+ CU_ASSERT_PTR_NOT_NULL(error_value_str);
+ }
+ }
+
+ CU_ASSERT_PTR_NULL(get_error_value_str(-1, 0));
+ CU_ASSERT_PTR_NULL(get_error_value_str(MAX_ERROR_TYPE, 0));
+ CU_ASSERT_PTR_NULL(get_error_value_str(1, -1));
+ CU_ASSERT_PTR_NULL(get_error_value_str(1, MAX_ERROR_VALUE));
+}
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Javier Garcia <javier.garcia@voltanet.io>
+ *
+ */
+
+/*
+ * Timer definitions to be used internally by the pcep_timers library.
+ */
+
+#ifndef PCEP_MSG_OBJECT_ERROR_TYPES_TEST_
+#define PCEP_MSG_OBJECT_ERROR_TYPES_TEST_
+
+int pcep_object_error_types_test_suite_setup(void);
+int pcep_object_error_types_test_suite_teardown(void);
+void pcep_object_error_types_test_setup(void);
+void pcep_object_error_types_test_teardown(void);
+void test_get_error_type_str(void);
+void test_get_error_value_str(void);
+
+#endif /* PCEPTIMERINTERNALS_H_ */
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <stdlib.h>
+
+#include <CUnit/CUnit.h>
+
+#include "pcep_msg_encoding.h"
+#include "pcep_msg_objects.h"
+#include "pcep_msg_tools.h"
+#include "pcep_utils_memory.h"
+#include "pcep_msg_objects_test.h"
+
+/*
+ * Notice:
+ * All of these object Unit Tests encode the created objects by explicitly
+ * calling pcep_encode_object() thus testing the object creation and the object
+ * encoding. All APIs expect IPs to be in network byte order.
+ */
+
+static struct pcep_versioning *versioning = NULL;
+static uint8_t object_buf[2000];
+
+void reset_objects_buffer(void);
+
+int pcep_objects_test_suite_setup(void)
+{
+ pceplib_memory_reset();
+ return 0;
+}
+
+int pcep_objects_test_suite_teardown(void)
+{
+ printf("\n");
+ pceplib_memory_dump();
+ return 0;
+}
+
+void reset_objects_buffer()
+{
+ memset(object_buf, 0, 2000);
+}
+
+void pcep_objects_test_setup()
+{
+ versioning = create_default_pcep_versioning();
+ reset_objects_buffer();
+}
+
+void pcep_objects_test_teardown()
+{
+ destroy_pcep_versioning(versioning);
+}
+
+/* Internal util verification function */
+static void verify_pcep_obj_header2(uint8_t obj_class, uint8_t obj_type,
+ uint16_t obj_length, const uint8_t *obj_buf)
+{
+ /* Object Header
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Object-Class | OT |Res|P|I| Object Length (bytes) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+ /* Not using CU_ASSERT_EQUAL here, so that in case of failure,
+ * we can provide more info in the error message. */
+ if (obj_buf[0] != obj_class) {
+ fprintf(stderr,
+ "Test failure obj_class expected [%d] found [%d]\n",
+ obj_class, obj_buf[0]);
+ CU_FAIL("Object Header Class");
+ }
+
+ uint8_t found8 = (obj_buf[1] >> 4) & 0x0f;
+ if (obj_type != found8) {
+ fprintf(stderr,
+ "Test failure obj_class [%d] obj_type expected [%d] found [%d]\n",
+ obj_class, obj_type, found8);
+ CU_FAIL("Object Header Type");
+ }
+
+ uint8_t exp8 = 0;
+ found8 = obj_buf[1] & 0x0f;
+ if (exp8 != found8) {
+ fprintf(stderr,
+ "Test failure obj_class [%d] flags expected [%d] found [%d]\n",
+ obj_class, exp8, found8);
+ CU_FAIL("Object Header Flags");
+ }
+
+ uint16_t found16 = ntohs(*((uint16_t *)(obj_buf + 2)));
+ if (obj_length != found16) {
+ fprintf(stderr,
+ "Test failure obj_class [%d] obj_length expected [%d] found [%d]\n",
+ obj_class, obj_length, found16);
+ CU_FAIL("Object Header Length");
+ }
+}
+
+/* Internal util verification function */
+static void verify_pcep_obj_header(uint8_t obj_class, uint8_t obj_type,
+ struct pcep_object_header *obj_hdr)
+{
+ verify_pcep_obj_header2(obj_class, obj_type,
+ pcep_object_get_length_by_hdr(obj_hdr),
+ obj_hdr->encoded_object);
+}
+
+void test_pcep_obj_create_open()
+{
+ uint8_t deadtimer = 60;
+ uint8_t keepalive = 30;
+ uint8_t sid = 1;
+
+ struct pcep_object_open *open =
+ pcep_obj_create_open(keepalive, deadtimer, sid, NULL);
+
+ CU_ASSERT_PTR_NOT_NULL(open);
+ pcep_encode_object(&open->header, versioning, object_buf);
+ verify_pcep_obj_header(PCEP_OBJ_CLASS_OPEN, PCEP_OBJ_TYPE_OPEN,
+ &open->header);
+
+ CU_ASSERT_EQUAL(open->header.encoded_object[4],
+ (PCEP_OBJECT_OPEN_VERSION << 5) & 0xe0);
+ CU_ASSERT_EQUAL(open->header.encoded_object[4] & 0x1f, 0);
+ CU_ASSERT_EQUAL(open->header.encoded_object[5], keepalive);
+ CU_ASSERT_EQUAL(open->header.encoded_object[6], deadtimer);
+ CU_ASSERT_EQUAL(open->header.encoded_object[7], sid);
+
+ pcep_obj_free_object((struct pcep_object_header *)open);
+}
+
+void test_pcep_obj_create_open_with_tlvs()
+{
+ uint8_t deadtimer = 60;
+ uint8_t keepalive = 30;
+ uint8_t sid = 1;
+ double_linked_list *tlv_list = dll_initialize();
+
+ struct pcep_object_tlv_stateful_pce_capability *tlv =
+ pcep_tlv_create_stateful_pce_capability(true, true, true, true,
+ true, true);
+ dll_append(tlv_list, tlv);
+ struct pcep_object_open *open =
+ pcep_obj_create_open(keepalive, deadtimer, sid, tlv_list);
+
+ CU_ASSERT_PTR_NOT_NULL(open);
+ pcep_encode_object(&open->header, versioning, object_buf);
+ verify_pcep_obj_header2(PCEP_OBJ_CLASS_OPEN, PCEP_OBJ_TYPE_OPEN,
+ pcep_object_get_length_by_hdr(&open->header)
+ + sizeof(uint32_t) * 2,
+ open->header.encoded_object);
+ CU_ASSERT_PTR_NOT_NULL(open->header.tlv_list);
+ CU_ASSERT_EQUAL(open->header.tlv_list->num_entries, 1);
+
+ CU_ASSERT_EQUAL(open->header.encoded_object[4],
+ (PCEP_OBJECT_OPEN_VERSION << 5) & 0xe0);
+ CU_ASSERT_EQUAL(open->header.encoded_object[4] & 0x1f, 0);
+ CU_ASSERT_EQUAL(open->header.encoded_object[5], keepalive);
+ CU_ASSERT_EQUAL(open->header.encoded_object[6], deadtimer);
+ CU_ASSERT_EQUAL(open->header.encoded_object[7], sid);
+
+ pcep_obj_free_object((struct pcep_object_header *)open);
+}
+
+void test_pcep_obj_create_rp()
+{
+ uint32_t reqid = 15;
+ uint8_t invalid_priority = 100;
+ uint8_t priority = 7;
+
+ struct pcep_object_rp *rp = pcep_obj_create_rp(
+ invalid_priority, true, false, false, true, reqid, NULL);
+ CU_ASSERT_PTR_NULL(rp);
+
+ rp = pcep_obj_create_rp(priority, true, false, false, true, reqid,
+ NULL);
+ CU_ASSERT_PTR_NOT_NULL(rp);
+ pcep_encode_object(&rp->header, versioning, object_buf);
+ verify_pcep_obj_header(PCEP_OBJ_CLASS_RP, PCEP_OBJ_TYPE_RP,
+ &rp->header);
+
+ CU_ASSERT_EQUAL(rp->header.encoded_object[4], 0);
+ CU_ASSERT_EQUAL(rp->header.encoded_object[5], 0);
+ CU_ASSERT_EQUAL(rp->header.encoded_object[6], 0);
+ CU_ASSERT_EQUAL((rp->header.encoded_object[7] & 0x07), priority);
+ CU_ASSERT_TRUE(rp->header.encoded_object[7] & OBJECT_RP_FLAG_R);
+ CU_ASSERT_TRUE(rp->header.encoded_object[7] & OBJECT_RP_FLAG_OF);
+ CU_ASSERT_TRUE(rp->header.encoded_object[7] & ~OBJECT_RP_FLAG_B);
+ CU_ASSERT_TRUE(rp->header.encoded_object[7] & ~OBJECT_RP_FLAG_O);
+ CU_ASSERT_EQUAL(*((uint32_t *)(rp->header.encoded_object + 8)),
+ htonl(reqid));
+
+ pcep_obj_free_object((struct pcep_object_header *)rp);
+}
+
+void test_pcep_obj_create_nopath()
+{
+ uint8_t ni = 8;
+ uint32_t errorcode = 42;
+
+ struct pcep_object_nopath *nopath =
+ pcep_obj_create_nopath(ni, true, errorcode);
+
+ CU_ASSERT_PTR_NOT_NULL(nopath);
+ pcep_encode_object(&nopath->header, versioning, object_buf);
+ verify_pcep_obj_header(PCEP_OBJ_CLASS_NOPATH, PCEP_OBJ_TYPE_NOPATH,
+ &nopath->header);
+
+ CU_ASSERT_EQUAL(nopath->header.encoded_object[4], ni);
+ CU_ASSERT_TRUE(nopath->header.encoded_object[5] & OBJECT_NOPATH_FLAG_C);
+ CU_ASSERT_EQUAL(nopath->header.encoded_object[6], 0);
+ CU_ASSERT_EQUAL(nopath->header.encoded_object[7], 0);
+
+ /* Verify the TLV */
+ CU_ASSERT_PTR_NOT_NULL(nopath->header.tlv_list);
+ struct pcep_object_tlv_nopath_vector *tlv =
+ (struct pcep_object_tlv_nopath_vector *)
+ nopath->header.tlv_list->head->data;
+ CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, 4);
+ CU_ASSERT_EQUAL(tlv->header.type, 1);
+ CU_ASSERT_EQUAL(tlv->error_code, errorcode);
+
+ CU_ASSERT_EQUAL(*((uint16_t *)(nopath->header.encoded_object + 8)),
+ htons(PCEP_OBJ_TLV_TYPE_NO_PATH_VECTOR));
+ CU_ASSERT_EQUAL(*((uint16_t *)(nopath->header.encoded_object + 10)),
+ htons(4));
+ CU_ASSERT_EQUAL(*((uint32_t *)(nopath->header.encoded_object + 12)),
+ htonl(errorcode));
+
+ pcep_obj_free_object((struct pcep_object_header *)nopath);
+}
+void test_pcep_obj_create_association_ipv4()
+{
+
+ uint16_t all_assoc_groups = 0xffff;
+ struct in_addr src;
+ inet_pton(AF_INET, "192.168.1.2", &src);
+
+ struct pcep_object_association_ipv4 *assoc =
+ pcep_obj_create_association_ipv4(
+ false, PCEP_ASSOCIATION_TYPE_SR_POLICY_ASSOCIATION_TYPE,
+ all_assoc_groups, src);
+ CU_ASSERT_PTR_NOT_NULL(assoc);
+ CU_ASSERT_EQUAL(assoc->association_type,
+ PCEP_ASSOCIATION_TYPE_SR_POLICY_ASSOCIATION_TYPE);
+ CU_ASSERT_EQUAL(assoc->association_id, all_assoc_groups);
+ CU_ASSERT_EQUAL(assoc->header.object_class, PCEP_OBJ_CLASS_ASSOCIATION);
+ CU_ASSERT_EQUAL(assoc->header.object_type,
+ PCEP_OBJ_TYPE_ASSOCIATION_IPV4);
+ CU_ASSERT_EQUAL(assoc->src.s_addr, src.s_addr);
+
+ pcep_obj_free_object((struct pcep_object_header *)assoc);
+}
+
+void test_pcep_obj_create_association_ipv6()
+{
+ uint32_t all_assoc_groups = 0xffff;
+ struct in6_addr src;
+ inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &src);
+
+ struct pcep_object_association_ipv6 *assoc =
+ pcep_obj_create_association_ipv6(
+ false, PCEP_ASSOCIATION_TYPE_SR_POLICY_ASSOCIATION_TYPE,
+ all_assoc_groups, src);
+ CU_ASSERT_PTR_NOT_NULL(assoc);
+ CU_ASSERT_EQUAL(assoc->association_type,
+ PCEP_ASSOCIATION_TYPE_SR_POLICY_ASSOCIATION_TYPE);
+ CU_ASSERT_EQUAL(assoc->association_id, all_assoc_groups);
+ CU_ASSERT_EQUAL(assoc->header.object_class, PCEP_OBJ_CLASS_ASSOCIATION);
+ CU_ASSERT_EQUAL(assoc->header.object_type,
+ PCEP_OBJ_TYPE_ASSOCIATION_IPV6);
+ CU_ASSERT_EQUAL(assoc->src.__in6_u.__u6_addr32[0],
+ (src.__in6_u.__u6_addr32[0]));
+ CU_ASSERT_EQUAL(assoc->src.__in6_u.__u6_addr32[1],
+ (src.__in6_u.__u6_addr32[1]));
+ CU_ASSERT_EQUAL(assoc->src.__in6_u.__u6_addr32[2],
+ (src.__in6_u.__u6_addr32[2]));
+ CU_ASSERT_EQUAL(assoc->src.__in6_u.__u6_addr32[3],
+ (src.__in6_u.__u6_addr32[3]));
+
+ pcep_obj_free_object((struct pcep_object_header *)assoc);
+}
+
+void test_pcep_obj_create_endpoint_ipv4()
+{
+ struct in_addr src_ipv4, dst_ipv4;
+ inet_pton(AF_INET, "192.168.1.2", &src_ipv4);
+ inet_pton(AF_INET, "172.168.1.2", &dst_ipv4);
+
+ struct pcep_object_endpoints_ipv4 *ipv4 =
+ pcep_obj_create_endpoint_ipv4(NULL, NULL);
+ CU_ASSERT_PTR_NULL(ipv4);
+
+ ipv4 = pcep_obj_create_endpoint_ipv4(&src_ipv4, NULL);
+ CU_ASSERT_PTR_NULL(ipv4);
+
+ ipv4 = pcep_obj_create_endpoint_ipv4(NULL, &dst_ipv4);
+ CU_ASSERT_PTR_NULL(ipv4);
+
+ ipv4 = pcep_obj_create_endpoint_ipv4(&src_ipv4, &dst_ipv4);
+ CU_ASSERT_PTR_NOT_NULL(ipv4);
+ pcep_encode_object(&ipv4->header, versioning, object_buf);
+ verify_pcep_obj_header(PCEP_OBJ_CLASS_ENDPOINTS,
+ PCEP_OBJ_TYPE_ENDPOINT_IPV4, &ipv4->header);
+ CU_ASSERT_EQUAL(*((uint32_t *)(ipv4->header.encoded_object + 4)),
+ src_ipv4.s_addr);
+ CU_ASSERT_EQUAL(*((uint32_t *)(ipv4->header.encoded_object + 8)),
+ dst_ipv4.s_addr);
+
+ pcep_obj_free_object((struct pcep_object_header *)ipv4);
+}
+
+void test_pcep_obj_create_endpoint_ipv6()
+{
+ struct in6_addr src_ipv6, dst_ipv6;
+ inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &src_ipv6);
+ inet_pton(AF_INET6, "2001:db8::8a2e:370:8446", &dst_ipv6);
+
+ struct pcep_object_endpoints_ipv6 *ipv6 =
+ pcep_obj_create_endpoint_ipv6(NULL, NULL);
+ CU_ASSERT_PTR_NULL(ipv6);
+
+ ipv6 = pcep_obj_create_endpoint_ipv6(&src_ipv6, NULL);
+ CU_ASSERT_PTR_NULL(ipv6);
+
+ ipv6 = pcep_obj_create_endpoint_ipv6(NULL, &dst_ipv6);
+ CU_ASSERT_PTR_NULL(ipv6);
+
+ ipv6 = pcep_obj_create_endpoint_ipv6(&src_ipv6, &dst_ipv6);
+ CU_ASSERT_PTR_NOT_NULL(ipv6);
+ pcep_encode_object(&ipv6->header, versioning, object_buf);
+ verify_pcep_obj_header(PCEP_OBJ_CLASS_ENDPOINTS,
+ PCEP_OBJ_TYPE_ENDPOINT_IPV6, &ipv6->header);
+ uint32_t *uint32_ptr = (uint32_t *)(ipv6->header.encoded_object + 4);
+ CU_ASSERT_EQUAL(uint32_ptr[0], src_ipv6.__in6_u.__u6_addr32[0]);
+ CU_ASSERT_EQUAL(uint32_ptr[1], src_ipv6.__in6_u.__u6_addr32[1]);
+ CU_ASSERT_EQUAL(uint32_ptr[2], src_ipv6.__in6_u.__u6_addr32[2]);
+ CU_ASSERT_EQUAL(uint32_ptr[3], src_ipv6.__in6_u.__u6_addr32[3]);
+ CU_ASSERT_EQUAL(uint32_ptr[4], dst_ipv6.__in6_u.__u6_addr32[0]);
+ CU_ASSERT_EQUAL(uint32_ptr[5], dst_ipv6.__in6_u.__u6_addr32[1]);
+ CU_ASSERT_EQUAL(uint32_ptr[6], dst_ipv6.__in6_u.__u6_addr32[2]);
+ CU_ASSERT_EQUAL(uint32_ptr[7], dst_ipv6.__in6_u.__u6_addr32[3]);
+
+ pcep_obj_free_object((struct pcep_object_header *)ipv6);
+}
+
+void test_pcep_obj_create_bandwidth()
+{
+ /* 1.8 => binary 1.11001101
+ * exponent = 127 => 0111 1111
+ * fraction = 1100 1101 0000 0000 0000 000 */
+ float bandwidth = 1.8;
+
+ struct pcep_object_bandwidth *bw = pcep_obj_create_bandwidth(bandwidth);
+
+ CU_ASSERT_PTR_NOT_NULL(bw);
+ pcep_encode_object(&bw->header, versioning, object_buf);
+ verify_pcep_obj_header(PCEP_OBJ_CLASS_BANDWIDTH,
+ PCEP_OBJ_TYPE_BANDWIDTH_REQ, &bw->header);
+ CU_ASSERT_EQUAL(bw->header.encoded_object[4], 0x3f);
+ CU_ASSERT_EQUAL(bw->header.encoded_object[5], 0xe6);
+ CU_ASSERT_EQUAL(bw->header.encoded_object[6], 0x66);
+ CU_ASSERT_EQUAL(bw->header.encoded_object[7], 0x66);
+
+ pcep_obj_free_object((struct pcep_object_header *)bw);
+}
+
+void test_pcep_obj_create_metric()
+{
+ uint8_t type = PCEP_METRIC_BORDER_NODE_COUNT;
+ /* https://en.wikipedia.org/wiki/IEEE_754-1985
+ * 0.15625 = 1/8 + 1/32 = binary 0.00101 = 1.01 x 10^-3
+ * Exponent bias = 127, so exponent = (127-3) = 124 = 0111 1100
+ * Sign Exponent Fraction
+ * (8 bits) (23 bits)
+ * 0.15625 => 0 0111 1100 010 0000 ... 0000 */
+ float value = 0.15625;
+
+ struct pcep_object_metric *metric =
+ pcep_obj_create_metric(type, true, true, value);
+
+ CU_ASSERT_PTR_NOT_NULL(metric);
+ pcep_encode_object(&metric->header, versioning, object_buf);
+ verify_pcep_obj_header(PCEP_OBJ_CLASS_METRIC, PCEP_OBJ_TYPE_METRIC,
+ &metric->header);
+ CU_ASSERT_EQUAL(metric->header.encoded_object[4], 0);
+ CU_ASSERT_EQUAL(metric->header.encoded_object[5], 0);
+ CU_ASSERT_TRUE(metric->header.encoded_object[6] & OBJECT_METRIC_FLAC_B);
+ CU_ASSERT_TRUE(metric->header.encoded_object[6] & OBJECT_METRIC_FLAC_C);
+ CU_ASSERT_EQUAL(metric->header.encoded_object[7], type);
+ /* See comments above for explanation of these values */
+ CU_ASSERT_EQUAL(metric->header.encoded_object[8], 0x3e);
+ CU_ASSERT_EQUAL(metric->header.encoded_object[9], 0x20);
+ CU_ASSERT_EQUAL(metric->header.encoded_object[10], 0x00);
+ CU_ASSERT_EQUAL(metric->header.encoded_object[11], 0x00);
+
+ pcep_obj_free_object((struct pcep_object_header *)metric);
+}
+
+void test_pcep_obj_create_lspa()
+{
+ uint32_t exclude_any = 10;
+ uint32_t include_any = 20;
+ uint32_t include_all = 30;
+ uint8_t prio = 0;
+ uint8_t hold_prio = 10;
+
+ struct pcep_object_lspa *lspa = pcep_obj_create_lspa(
+ exclude_any, include_any, include_all, prio, hold_prio, true);
+
+ CU_ASSERT_PTR_NOT_NULL(lspa);
+ pcep_encode_object(&lspa->header, versioning, object_buf);
+ verify_pcep_obj_header(PCEP_OBJ_CLASS_LSPA, PCEP_OBJ_TYPE_LSPA,
+ &lspa->header);
+ uint32_t *uint32_ptr = (uint32_t *)(lspa->header.encoded_object + 4);
+ CU_ASSERT_EQUAL(uint32_ptr[0], htonl(exclude_any));
+ CU_ASSERT_EQUAL(uint32_ptr[1], htonl(include_any));
+ CU_ASSERT_EQUAL(uint32_ptr[2], htonl(include_all));
+ CU_ASSERT_EQUAL(lspa->header.encoded_object[16], prio);
+ CU_ASSERT_EQUAL(lspa->header.encoded_object[17], hold_prio);
+ CU_ASSERT_TRUE(lspa->header.encoded_object[18] & OBJECT_LSPA_FLAG_L);
+ CU_ASSERT_EQUAL(lspa->header.encoded_object[19], 0);
+
+ pcep_obj_free_object((struct pcep_object_header *)lspa);
+}
+
+void test_pcep_obj_create_svec()
+{
+ struct pcep_object_svec *svec =
+ pcep_obj_create_svec(true, true, true, NULL);
+ CU_ASSERT_PTR_NULL(svec);
+
+ double_linked_list *id_list = dll_initialize();
+ uint32_t *uint32_ptr =
+ pceplib_malloc(PCEPLIB_MESSAGES, sizeof(uint32_t));
+ *uint32_ptr = 10;
+ dll_append(id_list, uint32_ptr);
+
+ svec = pcep_obj_create_svec(true, true, true, id_list);
+ CU_ASSERT_PTR_NOT_NULL(svec);
+ pcep_encode_object(&svec->header, versioning, object_buf);
+ verify_pcep_obj_header2(PCEP_OBJ_CLASS_SVEC, PCEP_OBJ_TYPE_SVEC,
+ (OBJECT_HEADER_LENGTH + sizeof(uint32_t) * 2),
+ svec->header.encoded_object);
+ CU_ASSERT_EQUAL(svec->header.encoded_object[4], 0);
+ CU_ASSERT_EQUAL(svec->header.encoded_object[5], 0);
+ CU_ASSERT_EQUAL(svec->header.encoded_object[6], 0);
+ CU_ASSERT_TRUE(svec->header.encoded_object[7] & OBJECT_SVEC_FLAG_S);
+ CU_ASSERT_TRUE(svec->header.encoded_object[7] & OBJECT_SVEC_FLAG_N);
+ CU_ASSERT_TRUE(svec->header.encoded_object[7] & OBJECT_SVEC_FLAG_L);
+ CU_ASSERT_EQUAL(*((uint32_t *)(svec->header.encoded_object + 8)),
+ htonl(*uint32_ptr));
+
+ pcep_obj_free_object((struct pcep_object_header *)svec);
+}
+
+void test_pcep_obj_create_error()
+{
+ uint8_t error_type = PCEP_ERRT_SESSION_FAILURE;
+ uint8_t error_value = PCEP_ERRV_RECVD_INVALID_OPEN_MSG;
+
+ struct pcep_object_error *error =
+ pcep_obj_create_error(error_type, error_value);
+
+ CU_ASSERT_PTR_NOT_NULL(error);
+ pcep_encode_object(&error->header, versioning, object_buf);
+ verify_pcep_obj_header(PCEP_OBJ_CLASS_ERROR, PCEP_OBJ_TYPE_ERROR,
+ &error->header);
+ CU_ASSERT_EQUAL(error->header.encoded_object[4], 0);
+ CU_ASSERT_EQUAL(error->header.encoded_object[5], 0);
+ CU_ASSERT_EQUAL(error->header.encoded_object[6], error_type);
+ CU_ASSERT_EQUAL(error->header.encoded_object[7], error_value);
+
+ pcep_obj_free_object((struct pcep_object_header *)error);
+}
+
+void test_pcep_obj_create_close()
+{
+ uint8_t reason = PCEP_CLOSE_REASON_DEADTIMER;
+
+ struct pcep_object_close *close = pcep_obj_create_close(reason);
+
+ CU_ASSERT_PTR_NOT_NULL(close);
+ pcep_encode_object(&close->header, versioning, object_buf);
+ verify_pcep_obj_header(PCEP_OBJ_CLASS_CLOSE, PCEP_OBJ_TYPE_CLOSE,
+ &close->header);
+ CU_ASSERT_EQUAL(close->header.encoded_object[4], 0);
+ CU_ASSERT_EQUAL(close->header.encoded_object[5], 0);
+ CU_ASSERT_EQUAL(close->header.encoded_object[6], 0);
+ CU_ASSERT_EQUAL(close->header.encoded_object[7], reason);
+
+ pcep_obj_free_object((struct pcep_object_header *)close);
+}
+
+void test_pcep_obj_create_srp()
+{
+ bool lsp_remove = true;
+ uint32_t srp_id_number = 0x89674523;
+ struct pcep_object_srp *srp =
+ pcep_obj_create_srp(lsp_remove, srp_id_number, NULL);
+
+ CU_ASSERT_PTR_NOT_NULL(srp);
+ pcep_encode_object(&srp->header, versioning, object_buf);
+ verify_pcep_obj_header(PCEP_OBJ_CLASS_SRP, PCEP_OBJ_TYPE_SRP,
+ &srp->header);
+ CU_ASSERT_EQUAL(srp->header.encoded_object[4], 0);
+ CU_ASSERT_EQUAL(srp->header.encoded_object[5], 0);
+ CU_ASSERT_EQUAL(srp->header.encoded_object[6], 0);
+ CU_ASSERT_TRUE(srp->header.encoded_object[7] & OBJECT_SRP_FLAG_R);
+ CU_ASSERT_EQUAL(*((uint32_t *)(srp->header.encoded_object + 8)),
+ htonl(srp_id_number));
+
+ pcep_obj_free_object((struct pcep_object_header *)srp);
+}
+
+void test_pcep_obj_create_lsp()
+{
+ uint32_t plsp_id = 0x000fffff;
+ enum pcep_lsp_operational_status status = PCEP_LSP_OPERATIONAL_ACTIVE;
+ bool c_flag = true;
+ bool a_flag = true;
+ bool r_flag = true;
+ bool s_flag = true;
+ bool d_flag = true;
+
+ /* Should return for invalid plsp_id */
+ struct pcep_object_lsp *lsp =
+ pcep_obj_create_lsp(0x001fffff, status, c_flag, a_flag, r_flag,
+ s_flag, d_flag, NULL);
+ CU_ASSERT_PTR_NULL(lsp);
+
+ /* Should return for invalid status */
+ lsp = pcep_obj_create_lsp(plsp_id, 8, c_flag, a_flag, r_flag, s_flag,
+ d_flag, NULL);
+ CU_ASSERT_PTR_NULL(lsp);
+
+ lsp = pcep_obj_create_lsp(plsp_id, status, c_flag, a_flag, r_flag,
+ s_flag, d_flag, NULL);
+
+ CU_ASSERT_PTR_NOT_NULL(lsp);
+ pcep_encode_object(&lsp->header, versioning, object_buf);
+ verify_pcep_obj_header(PCEP_OBJ_CLASS_LSP, PCEP_OBJ_TYPE_LSP,
+ &lsp->header);
+ CU_ASSERT_EQUAL((ntohl(*((uint32_t *)(lsp->header.encoded_object + 4)))
+ >> 12) & 0x000fffff,
+ plsp_id);
+ CU_ASSERT_EQUAL((lsp->header.encoded_object[7] >> 4) & 0x07, status);
+ CU_ASSERT_TRUE(lsp->header.encoded_object[7] & OBJECT_LSP_FLAG_A);
+ CU_ASSERT_TRUE(lsp->header.encoded_object[7] & OBJECT_LSP_FLAG_C);
+ CU_ASSERT_TRUE(lsp->header.encoded_object[7] & OBJECT_LSP_FLAG_D);
+ CU_ASSERT_TRUE(lsp->header.encoded_object[7] & OBJECT_LSP_FLAG_R);
+ CU_ASSERT_TRUE(lsp->header.encoded_object[7] & OBJECT_LSP_FLAG_S);
+
+ pcep_obj_free_object((struct pcep_object_header *)lsp);
+}
+
+void test_pcep_obj_create_vendor_info()
+{
+ uint32_t enterprise_number = 0x01020304;
+ uint32_t enterprise_specific_info = 0x05060708;
+
+ struct pcep_object_vendor_info *obj = pcep_obj_create_vendor_info(
+ enterprise_number, enterprise_specific_info);
+
+ CU_ASSERT_PTR_NOT_NULL(obj);
+ pcep_encode_object(&obj->header, versioning, object_buf);
+ verify_pcep_obj_header(PCEP_OBJ_CLASS_VENDOR_INFO,
+ PCEP_OBJ_TYPE_VENDOR_INFO, &obj->header);
+ uint32_t *uint32_ptr = (uint32_t *)(obj->header.encoded_object + 4);
+ CU_ASSERT_EQUAL(uint32_ptr[0], htonl(enterprise_number));
+ CU_ASSERT_EQUAL(uint32_ptr[1], htonl(enterprise_specific_info));
+
+ pcep_obj_free_object((struct pcep_object_header *)obj);
+}
+
+/* Internal test function. The only difference between pcep_obj_create_ero(),
+ * pcep_obj_create_iro(), and pcep_obj_create_rro() is the object_class
+ * and the object_type.
+ */
+typedef struct pcep_object_ro *(*ro_func)(double_linked_list *);
+static void test_pcep_obj_create_object_common(ro_func func_to_test,
+ uint8_t object_class,
+ uint8_t object_type)
+{
+ double_linked_list *ero_list = dll_initialize();
+
+ struct pcep_object_ro *ero = func_to_test(NULL);
+ CU_ASSERT_PTR_NOT_NULL(ero);
+ pcep_encode_object(&ero->header, versioning, object_buf);
+ verify_pcep_obj_header2(object_class, object_type, OBJECT_HEADER_LENGTH,
+ ero->header.encoded_object);
+ pcep_obj_free_object((struct pcep_object_header *)ero);
+
+ reset_objects_buffer();
+ ero = func_to_test(ero_list);
+ CU_ASSERT_PTR_NOT_NULL(ero);
+ pcep_encode_object(&ero->header, versioning, object_buf);
+ verify_pcep_obj_header2(object_class, object_type, OBJECT_HEADER_LENGTH,
+ ero->header.encoded_object);
+ pcep_obj_free_object((struct pcep_object_header *)ero);
+
+ reset_objects_buffer();
+ struct pcep_ro_subobj_32label *ro_subobj =
+ pcep_obj_create_ro_subobj_32label(false, 0, 101);
+ ero_list = dll_initialize();
+ dll_append(ero_list, ro_subobj);
+ ero = func_to_test(ero_list);
+ CU_ASSERT_PTR_NOT_NULL(ero);
+ pcep_encode_object(&ero->header, versioning, object_buf);
+ /* 4 bytes for obj header +
+ * 2 bytes for ro_subobj header +
+ * 2 bytes for lable c-type and flags +
+ * 4 bytes for label */
+ verify_pcep_obj_header2(object_class, object_type,
+ OBJECT_HEADER_LENGTH + sizeof(uint32_t) * 2,
+ ero->header.encoded_object);
+ pcep_obj_free_object((struct pcep_object_header *)ero);
+}
+
+void test_pcep_obj_create_ero()
+{
+ test_pcep_obj_create_object_common(
+ pcep_obj_create_ero, PCEP_OBJ_CLASS_ERO, PCEP_OBJ_TYPE_ERO);
+}
+
+void test_pcep_obj_create_rro()
+{
+ test_pcep_obj_create_object_common(
+ pcep_obj_create_rro, PCEP_OBJ_CLASS_RRO, PCEP_OBJ_TYPE_RRO);
+}
+
+void test_pcep_obj_create_iro()
+{
+ test_pcep_obj_create_object_common(
+ pcep_obj_create_iro, PCEP_OBJ_CLASS_IRO, PCEP_OBJ_TYPE_IRO);
+}
+
+/* Internal util function to wrap an RO Subobj in a RO and encode it */
+static struct pcep_object_ro *encode_ro_subobj(struct pcep_object_ro_subobj *sr)
+{
+ double_linked_list *sr_subobj_list = dll_initialize();
+ dll_append(sr_subobj_list, sr);
+ struct pcep_object_ro *ro = pcep_obj_create_ero(sr_subobj_list);
+ pcep_encode_object(&ro->header, versioning, object_buf);
+
+ return ro;
+}
+
+static void verify_pcep_obj_ro_header(struct pcep_object_ro *ro,
+ struct pcep_object_ro_subobj *ro_subobj,
+ uint8_t ro_subobj_type, bool loose_hop,
+ uint16_t length)
+{
+ (void)ro_subobj;
+
+ verify_pcep_obj_header2(PCEP_OBJ_CLASS_ERO, PCEP_OBJ_TYPE_ERO, length,
+ ro->header.encoded_object);
+
+ /* TODO consider printing the stack trace:
+ * https://stackoverflow.com/questions/105659/how-can-one-grab-a-stack-trace-in-c
+ */
+
+ /* Not using CU_ASSERT_EQUAL here, so that in case of failure,
+ * we can provide more info in the error message. */
+ uint8_t found_type = (ro->header.encoded_object[4]
+ & 0x7f); /* remove the Loose hop bit */
+ if (found_type != ro_subobj_type) {
+ fprintf(stderr,
+ "Test failure ro_sub_obj_type expected [%d] found [%d]\n",
+ ro_subobj_type, found_type);
+ CU_FAIL("Sub Object Header Type");
+ }
+
+ bool loose_hop_found = (ro->header.encoded_object[4] & 0x80);
+ if (loose_hop != loose_hop_found) {
+ fprintf(stderr,
+ "Test failure ro_sub_obj Loose Hop bit expected [%d] found [%d]\n",
+ loose_hop, loose_hop_found);
+ CU_FAIL("Sub Object Header Loose Hop bit");
+ }
+
+ if (length - 4 != ro->header.encoded_object[5]) {
+ fprintf(stderr,
+ "Test failure ro_sub_obj length expected [%d] found [%d]\n",
+ length - 4, ro->header.encoded_object[5]);
+ CU_FAIL("Sub Object Length");
+ }
+}
+
+static void
+verify_pcep_obj_ro_sr_header(struct pcep_object_ro *ro,
+ struct pcep_object_ro_subobj *ro_subobj,
+ uint8_t nai_type, bool loose_hop, uint16_t length)
+{
+ verify_pcep_obj_ro_header(ro, ro_subobj, RO_SUBOBJ_TYPE_SR, loose_hop,
+ length);
+ uint8_t found_nai_type = ((ro->header.encoded_object[6] >> 4) & 0x0f);
+ if (nai_type != found_nai_type) {
+ fprintf(stderr,
+ "Test failure ro_sr_sub_obj nai_type expected [%d] found [%d]\n",
+ nai_type, found_nai_type);
+ CU_FAIL("Sub Object SR NAI Type");
+ }
+}
+
+void test_pcep_obj_create_ro_subobj_ipv4()
+{
+ struct in_addr ro_ipv4;
+ inet_pton(AF_INET, "192.168.1.2", &ro_ipv4);
+ uint8_t prefix_len = 8;
+
+ struct pcep_ro_subobj_ipv4 *ipv4 =
+ pcep_obj_create_ro_subobj_ipv4(true, NULL, prefix_len, false);
+ CU_ASSERT_PTR_NULL(ipv4);
+
+ ipv4 = pcep_obj_create_ro_subobj_ipv4(false, &ro_ipv4, prefix_len,
+ true);
+ CU_ASSERT_PTR_NOT_NULL(ipv4);
+ struct pcep_object_ro *ro = encode_ro_subobj(&ipv4->ro_subobj);
+ verify_pcep_obj_ro_header(ro, &ipv4->ro_subobj, RO_SUBOBJ_TYPE_IPV4,
+ false, sizeof(uint32_t) * 3);
+ CU_ASSERT_EQUAL(*((uint32_t *)(ro->header.encoded_object + 6)),
+ ro_ipv4.s_addr);
+ CU_ASSERT_EQUAL(ro->header.encoded_object[10], prefix_len);
+ CU_ASSERT_TRUE(ro->header.encoded_object[11]
+ & OBJECT_SUBOBJ_IP_FLAG_LOCAL_PROT);
+ pcep_obj_free_object((struct pcep_object_header *)ro);
+
+ reset_objects_buffer();
+ ipv4 = pcep_obj_create_ro_subobj_ipv4(true, &ro_ipv4, prefix_len,
+ false);
+ CU_ASSERT_PTR_NOT_NULL(ipv4);
+ ro = encode_ro_subobj(&ipv4->ro_subobj);
+ verify_pcep_obj_ro_header(ro, &ipv4->ro_subobj, RO_SUBOBJ_TYPE_IPV4,
+ true, sizeof(uint32_t) * 3);
+ CU_ASSERT_EQUAL(*((uint32_t *)(ro->header.encoded_object + 6)),
+ ro_ipv4.s_addr);
+ CU_ASSERT_EQUAL(ro->header.encoded_object[10], prefix_len);
+ CU_ASSERT_EQUAL(ro->header.encoded_object[11], 0);
+ pcep_obj_free_object((struct pcep_object_header *)ro);
+}
+
+void test_pcep_obj_create_ro_subobj_ipv6()
+{
+ struct in6_addr ro_ipv6;
+ uint8_t prefix_len = 16;
+
+ struct pcep_ro_subobj_ipv6 *ipv6 =
+ pcep_obj_create_ro_subobj_ipv6(true, NULL, prefix_len, true);
+ CU_ASSERT_PTR_NULL(ipv6);
+
+ inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &ro_ipv6);
+ ipv6 = pcep_obj_create_ro_subobj_ipv6(false, &ro_ipv6, prefix_len,
+ true);
+ CU_ASSERT_PTR_NOT_NULL(ipv6);
+ struct pcep_object_ro *ro = encode_ro_subobj(&ipv6->ro_subobj);
+ verify_pcep_obj_ro_header(ro, &ipv6->ro_subobj, RO_SUBOBJ_TYPE_IPV6,
+ false, sizeof(uint32_t) * 6);
+ uint32_t *uint32_ptr = (uint32_t *)(ro->header.encoded_object + 6);
+ CU_ASSERT_EQUAL(uint32_ptr[0], ro_ipv6.__in6_u.__u6_addr32[0]);
+ CU_ASSERT_EQUAL(uint32_ptr[1], ro_ipv6.__in6_u.__u6_addr32[1]);
+ CU_ASSERT_EQUAL(uint32_ptr[2], ro_ipv6.__in6_u.__u6_addr32[2]);
+ CU_ASSERT_EQUAL(uint32_ptr[3], ro_ipv6.__in6_u.__u6_addr32[3]);
+ CU_ASSERT_EQUAL(ro->header.encoded_object[22], prefix_len);
+ CU_ASSERT_TRUE(ro->header.encoded_object[23]
+ & OBJECT_SUBOBJ_IP_FLAG_LOCAL_PROT);
+ pcep_obj_free_object((struct pcep_object_header *)ro);
+
+ reset_objects_buffer();
+ ipv6 = pcep_obj_create_ro_subobj_ipv6(true, &ro_ipv6, prefix_len,
+ false);
+ CU_ASSERT_PTR_NOT_NULL(ipv6);
+ ro = encode_ro_subobj(&ipv6->ro_subobj);
+ verify_pcep_obj_ro_header(ro, &ipv6->ro_subobj, RO_SUBOBJ_TYPE_IPV6,
+ true, sizeof(uint32_t) * 6);
+ uint32_ptr = (uint32_t *)(ro->header.encoded_object + 6);
+ CU_ASSERT_EQUAL(uint32_ptr[0], ro_ipv6.__in6_u.__u6_addr32[0]);
+ CU_ASSERT_EQUAL(uint32_ptr[1], ro_ipv6.__in6_u.__u6_addr32[1]);
+ CU_ASSERT_EQUAL(uint32_ptr[2], ro_ipv6.__in6_u.__u6_addr32[2]);
+ CU_ASSERT_EQUAL(uint32_ptr[3], ro_ipv6.__in6_u.__u6_addr32[3]);
+ CU_ASSERT_EQUAL(ro->header.encoded_object[22], prefix_len);
+ CU_ASSERT_EQUAL(ro->header.encoded_object[23], 0);
+ pcep_obj_free_object((struct pcep_object_header *)ro);
+}
+
+void test_pcep_obj_create_ro_subobj_unnum()
+{
+ struct in_addr router_id;
+ uint32_t if_id = 123;
+
+ struct pcep_ro_subobj_unnum *unnum =
+ pcep_obj_create_ro_subobj_unnum(NULL, if_id);
+ CU_ASSERT_PTR_NULL(unnum);
+
+ inet_pton(AF_INET, "192.168.1.2", &router_id);
+ unnum = pcep_obj_create_ro_subobj_unnum(&router_id, if_id);
+ CU_ASSERT_PTR_NOT_NULL(unnum);
+ struct pcep_object_ro *ro = encode_ro_subobj(&unnum->ro_subobj);
+ verify_pcep_obj_ro_header(ro, &unnum->ro_subobj, RO_SUBOBJ_TYPE_UNNUM,
+ false, sizeof(uint32_t) * 4);
+ CU_ASSERT_EQUAL(ro->header.encoded_object[6], 0);
+ CU_ASSERT_EQUAL(ro->header.encoded_object[7], 0);
+ CU_ASSERT_EQUAL(*((uint32_t *)(ro->header.encoded_object + 8)),
+ router_id.s_addr);
+ CU_ASSERT_EQUAL(*((uint32_t *)(ro->header.encoded_object + 12)),
+ htonl(if_id));
+
+ pcep_obj_free_object((struct pcep_object_header *)ro);
+}
+
+void test_pcep_obj_create_ro_subobj_32label()
+{
+ uint8_t class_type = 1;
+ uint32_t label = 0xeeffaabb;
+
+ struct pcep_ro_subobj_32label *label32 =
+ pcep_obj_create_ro_subobj_32label(true, class_type, label);
+ CU_ASSERT_PTR_NOT_NULL(label32);
+ struct pcep_object_ro *ro = encode_ro_subobj(&label32->ro_subobj);
+ verify_pcep_obj_ro_header(ro, &label32->ro_subobj, RO_SUBOBJ_TYPE_LABEL,
+ false, sizeof(uint32_t) * 3);
+ CU_ASSERT_TRUE(ro->header.encoded_object[6]
+ & OBJECT_SUBOBJ_LABEL_FLAG_GLOGAL);
+ CU_ASSERT_EQUAL(ro->header.encoded_object[7], class_type);
+ CU_ASSERT_EQUAL(*((uint32_t *)(ro->header.encoded_object + 8)),
+ htonl(label));
+
+ pcep_obj_free_object((struct pcep_object_header *)ro);
+}
+
+void test_pcep_obj_create_ro_subobj_asn()
+{
+ uint16_t asn = 0x0102;
+
+ struct pcep_ro_subobj_asn *asn_obj = pcep_obj_create_ro_subobj_asn(asn);
+ CU_ASSERT_PTR_NOT_NULL(asn_obj);
+ struct pcep_object_ro *ro = encode_ro_subobj(&asn_obj->ro_subobj);
+ verify_pcep_obj_ro_header(ro, &asn_obj->ro_subobj, RO_SUBOBJ_TYPE_ASN,
+ false, sizeof(uint32_t) * 2);
+ CU_ASSERT_EQUAL(*((uint16_t *)(ro->header.encoded_object + 6)),
+ htons(asn));
+
+ pcep_obj_free_object((struct pcep_object_header *)ro);
+}
+
+void test_pcep_obj_create_ro_subobj_sr_nonai()
+{
+ uint32_t sid = 0x01020304;
+
+ struct pcep_ro_subobj_sr *sr =
+ pcep_obj_create_ro_subobj_sr_nonai(false, sid, false, false);
+ CU_ASSERT_PTR_NOT_NULL(sr);
+ struct pcep_object_ro *ro = encode_ro_subobj(&sr->ro_subobj);
+ verify_pcep_obj_ro_sr_header(ro, &sr->ro_subobj,
+ PCEP_SR_SUBOBJ_NAI_ABSENT, false,
+ sizeof(uint32_t) * 3);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_S);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_F);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_C);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_M);
+ pcep_obj_free_object((struct pcep_object_header *)ro);
+
+ reset_objects_buffer();
+ sr = pcep_obj_create_ro_subobj_sr_nonai(true, sid, true, true);
+ CU_ASSERT_PTR_NOT_NULL(sr);
+ ro = encode_ro_subobj(&sr->ro_subobj);
+ verify_pcep_obj_ro_sr_header(ro, &sr->ro_subobj,
+ PCEP_SR_SUBOBJ_NAI_ABSENT, true,
+ sizeof(uint32_t) * 3);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_S);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_F);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_C);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_M);
+ pcep_obj_free_object((struct pcep_object_header *)ro);
+}
+
+void test_pcep_obj_create_ro_subobj_sr_ipv4_node()
+{
+ uint32_t sid = 0x01020304;
+ struct in_addr ipv4_node_id;
+ inet_pton(AF_INET, "192.168.1.2", &ipv4_node_id);
+
+ /* (loose_hop, sid_absent, c_flag, m_flag, sid, ipv4_node_id) */
+ struct pcep_ro_subobj_sr *sr = pcep_obj_create_ro_subobj_sr_ipv4_node(
+ true, false, true, true, sid, NULL);
+ CU_ASSERT_PTR_NULL(sr);
+
+ /* Test the sid is absent */
+ sr = pcep_obj_create_ro_subobj_sr_ipv4_node(true, true, false, false,
+ sid, &ipv4_node_id);
+ CU_ASSERT_PTR_NOT_NULL(sr);
+ struct pcep_object_ro *ro = encode_ro_subobj(&sr->ro_subobj);
+ verify_pcep_obj_ro_sr_header(ro, &sr->ro_subobj,
+ PCEP_SR_SUBOBJ_NAI_IPV4_NODE, true,
+ sizeof(uint32_t) * 3);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_S);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_F);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_C);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_M);
+ CU_ASSERT_EQUAL(sr->sid, 0);
+ CU_ASSERT_EQUAL(*((uint32_t *)(ro->header.encoded_object + 8)),
+ ipv4_node_id.s_addr);
+ pcep_obj_free_object((struct pcep_object_header *)ro);
+
+ /* Test the sid is present */
+ reset_objects_buffer();
+ inet_pton(AF_INET, "192.168.1.2", &ipv4_node_id);
+ sr = pcep_obj_create_ro_subobj_sr_ipv4_node(false, false, true, true,
+ sid, &ipv4_node_id);
+ CU_ASSERT_PTR_NOT_NULL(sr);
+ ro = encode_ro_subobj(&sr->ro_subobj);
+ verify_pcep_obj_ro_sr_header(ro, &sr->ro_subobj,
+ PCEP_SR_SUBOBJ_NAI_IPV4_NODE, false,
+ sizeof(uint32_t) * 4);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_C);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_M);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_S);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_F);
+ CU_ASSERT_EQUAL(*((uint32_t *)(ro->header.encoded_object + 8)),
+ htonl(sid));
+ CU_ASSERT_EQUAL(*((uint32_t *)(ro->header.encoded_object + 12)),
+ ipv4_node_id.s_addr);
+ pcep_obj_free_object((struct pcep_object_header *)ro);
+}
+
+void test_pcep_obj_create_ro_subobj_sr_ipv6_node()
+{
+ uint32_t sid = 0x01020304;
+ struct in6_addr ipv6_node_id;
+ inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &ipv6_node_id);
+
+ /* (loose_hop, sid_absent, c_flag, m_flag, sid, ipv6_node_id) */
+ struct pcep_ro_subobj_sr *sr = pcep_obj_create_ro_subobj_sr_ipv6_node(
+ false, true, true, true, sid, NULL);
+ CU_ASSERT_PTR_NULL(sr);
+
+ /* Test the sid is absent */
+ sr = pcep_obj_create_ro_subobj_sr_ipv6_node(true, true, true, true, sid,
+ &ipv6_node_id);
+ CU_ASSERT_PTR_NOT_NULL(sr);
+ struct pcep_object_ro *ro = encode_ro_subobj(&sr->ro_subobj);
+ verify_pcep_obj_ro_sr_header(ro, &sr->ro_subobj,
+ PCEP_SR_SUBOBJ_NAI_IPV6_NODE, true,
+ sizeof(uint32_t) * 6);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_S);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_F);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_C);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_M);
+ uint32_t *uint32_ptr = (uint32_t *)(ro->header.encoded_object + 8);
+ CU_ASSERT_EQUAL(uint32_ptr[0], ipv6_node_id.__in6_u.__u6_addr32[0]);
+ CU_ASSERT_EQUAL(uint32_ptr[1], ipv6_node_id.__in6_u.__u6_addr32[1]);
+ CU_ASSERT_EQUAL(uint32_ptr[2], ipv6_node_id.__in6_u.__u6_addr32[2]);
+ CU_ASSERT_EQUAL(uint32_ptr[3], ipv6_node_id.__in6_u.__u6_addr32[3]);
+ pcep_obj_free_object((struct pcep_object_header *)ro);
+
+ /* Test the sid is present */
+ reset_objects_buffer();
+ inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &ipv6_node_id);
+ sr = pcep_obj_create_ro_subobj_sr_ipv6_node(false, false, true, true,
+ sid, &ipv6_node_id);
+ CU_ASSERT_PTR_NOT_NULL(sr);
+ ro = encode_ro_subobj(&sr->ro_subobj);
+ verify_pcep_obj_ro_sr_header(ro, &sr->ro_subobj,
+ PCEP_SR_SUBOBJ_NAI_IPV6_NODE, false,
+ sizeof(uint32_t) * 7);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_M);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_C);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_S);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_F);
+ uint32_ptr = (uint32_t *)(ro->header.encoded_object + 8);
+ CU_ASSERT_EQUAL(uint32_ptr[0], htonl(sid));
+ CU_ASSERT_EQUAL(uint32_ptr[1], ipv6_node_id.__in6_u.__u6_addr32[0]);
+ CU_ASSERT_EQUAL(uint32_ptr[2], ipv6_node_id.__in6_u.__u6_addr32[1]);
+ CU_ASSERT_EQUAL(uint32_ptr[3], ipv6_node_id.__in6_u.__u6_addr32[2]);
+ CU_ASSERT_EQUAL(uint32_ptr[4], ipv6_node_id.__in6_u.__u6_addr32[3]);
+ pcep_obj_free_object((struct pcep_object_header *)ro);
+}
+
+void test_pcep_obj_create_ro_subobj_sr_ipv4_adj()
+{
+ struct in_addr local_ipv4;
+ struct in_addr remote_ipv4;
+ inet_pton(AF_INET, "192.168.1.2", &local_ipv4);
+ inet_pton(AF_INET, "172.168.1.2", &remote_ipv4);
+
+ uint32_t sid = ENCODE_SR_ERO_SID(3, 7, 0, 188);
+ CU_ASSERT_EQUAL(sid, 16060);
+
+ /* (loose_hop, sid_absent, c_flag, m_flag, sid, local_ipv4, remote_ipv4)
+ */
+ struct pcep_ro_subobj_sr *sr = pcep_obj_create_ro_subobj_sr_ipv4_adj(
+ false, true, true, true, sid, NULL, NULL);
+ CU_ASSERT_PTR_NULL(sr);
+
+ sr = pcep_obj_create_ro_subobj_sr_ipv4_adj(false, true, true, true, sid,
+ &local_ipv4, NULL);
+ CU_ASSERT_PTR_NULL(sr);
+
+ sr = pcep_obj_create_ro_subobj_sr_ipv4_adj(false, true, true, true, sid,
+ NULL, &remote_ipv4);
+ CU_ASSERT_PTR_NULL(sr);
+
+ /* Test the sid is absent */
+ sr = pcep_obj_create_ro_subobj_sr_ipv4_adj(true, true, true, true, sid,
+ &local_ipv4, &remote_ipv4);
+ CU_ASSERT_PTR_NOT_NULL(sr);
+ struct pcep_object_ro *ro = encode_ro_subobj(&sr->ro_subobj);
+ verify_pcep_obj_ro_sr_header(ro, &sr->ro_subobj,
+ PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY, true,
+ sizeof(uint32_t) * 4);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_S);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_F);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_C);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_M);
+ CU_ASSERT_EQUAL(sr->sid, 0);
+ uint32_t *uint32_ptr = (uint32_t *)(ro->header.encoded_object + 8);
+ CU_ASSERT_EQUAL(uint32_ptr[0], local_ipv4.s_addr);
+ CU_ASSERT_EQUAL(uint32_ptr[1], remote_ipv4.s_addr);
+ pcep_obj_free_object((struct pcep_object_header *)ro);
+
+ /* Test the sid is present */
+ inet_pton(AF_INET, "192.168.1.2", &local_ipv4);
+ inet_pton(AF_INET, "172.168.1.2", &remote_ipv4);
+ reset_objects_buffer();
+ sr = pcep_obj_create_ro_subobj_sr_ipv4_adj(
+ false, false, true, true, sid, &local_ipv4, &remote_ipv4);
+ CU_ASSERT_PTR_NOT_NULL(sr);
+ ro = encode_ro_subobj(&sr->ro_subobj);
+ verify_pcep_obj_ro_sr_header(ro, &sr->ro_subobj,
+ PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY, false,
+ sizeof(uint32_t) * 5);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_C);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_M);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_S);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_F);
+ uint32_ptr = (uint32_t *)(ro->header.encoded_object + 8);
+ CU_ASSERT_EQUAL(uint32_ptr[0], htonl(sid));
+ CU_ASSERT_EQUAL(uint32_ptr[1], local_ipv4.s_addr);
+ CU_ASSERT_EQUAL(uint32_ptr[2], remote_ipv4.s_addr);
+ pcep_obj_free_object((struct pcep_object_header *)ro);
+}
+
+void test_pcep_obj_create_ro_subobj_sr_ipv6_adj()
+{
+ uint32_t sid = 0x01020304;
+ struct in6_addr local_ipv6;
+ struct in6_addr remote_ipv6;
+ inet_pton(AF_INET6, "2001:db8::8a2e:370:8221", &local_ipv6);
+ inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &remote_ipv6);
+
+ /* (loose_hop, sid_absent, c_flag, m_flag, sid, local_ipv6, remote_ipv6)
+ */
+ struct pcep_ro_subobj_sr *sr = pcep_obj_create_ro_subobj_sr_ipv6_adj(
+ false, true, true, true, sid, NULL, NULL);
+ CU_ASSERT_PTR_NULL(sr);
+
+ sr = pcep_obj_create_ro_subobj_sr_ipv6_adj(false, true, true, true, sid,
+ &local_ipv6, NULL);
+ CU_ASSERT_PTR_NULL(sr);
+
+ sr = pcep_obj_create_ro_subobj_sr_ipv6_adj(false, true, true, true, sid,
+ NULL, &remote_ipv6);
+ CU_ASSERT_PTR_NULL(sr);
+
+ /* Test the sid is absent */
+ sr = pcep_obj_create_ro_subobj_sr_ipv6_adj(true, true, true, true, sid,
+ &local_ipv6, &remote_ipv6);
+ CU_ASSERT_PTR_NOT_NULL(sr);
+ struct pcep_object_ro *ro = encode_ro_subobj(&sr->ro_subobj);
+ verify_pcep_obj_ro_sr_header(ro, &sr->ro_subobj,
+ PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY, true,
+ sizeof(uint32_t) * 10);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_S);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_F);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_C);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_M);
+ CU_ASSERT_EQUAL(sr->sid, 0);
+ uint32_t *uint32_ptr = (uint32_t *)(ro->header.encoded_object + 8);
+ CU_ASSERT_EQUAL(uint32_ptr[0], local_ipv6.__in6_u.__u6_addr32[0]);
+ CU_ASSERT_EQUAL(uint32_ptr[1], local_ipv6.__in6_u.__u6_addr32[1]);
+ CU_ASSERT_EQUAL(uint32_ptr[2], local_ipv6.__in6_u.__u6_addr32[2]);
+ CU_ASSERT_EQUAL(uint32_ptr[3], local_ipv6.__in6_u.__u6_addr32[3]);
+
+ CU_ASSERT_EQUAL(uint32_ptr[4], remote_ipv6.__in6_u.__u6_addr32[0]);
+ CU_ASSERT_EQUAL(uint32_ptr[5], remote_ipv6.__in6_u.__u6_addr32[1]);
+ CU_ASSERT_EQUAL(uint32_ptr[6], remote_ipv6.__in6_u.__u6_addr32[2]);
+ CU_ASSERT_EQUAL(uint32_ptr[7], remote_ipv6.__in6_u.__u6_addr32[3]);
+ pcep_obj_free_object((struct pcep_object_header *)ro);
+
+ /* Test the sid is present */
+ reset_objects_buffer();
+ inet_pton(AF_INET6, "2001:db8::8a2e:370:8221", &local_ipv6);
+ inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &remote_ipv6);
+ sr = pcep_obj_create_ro_subobj_sr_ipv6_adj(
+ false, false, true, false, sid, &local_ipv6, &remote_ipv6);
+ CU_ASSERT_PTR_NOT_NULL(sr);
+ ro = encode_ro_subobj(&sr->ro_subobj);
+ verify_pcep_obj_ro_sr_header(ro, &sr->ro_subobj,
+ PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY, false,
+ sizeof(uint32_t) * 11);
+ /* All flags are false */
+ CU_ASSERT_EQUAL(ro->header.encoded_object[7], 0);
+ uint32_ptr = (uint32_t *)(ro->header.encoded_object + 8);
+ CU_ASSERT_EQUAL(uint32_ptr[0], htonl(sid));
+ CU_ASSERT_EQUAL(uint32_ptr[1], local_ipv6.__in6_u.__u6_addr32[0]);
+ CU_ASSERT_EQUAL(uint32_ptr[2], local_ipv6.__in6_u.__u6_addr32[1]);
+ CU_ASSERT_EQUAL(uint32_ptr[3], local_ipv6.__in6_u.__u6_addr32[2]);
+ CU_ASSERT_EQUAL(uint32_ptr[4], local_ipv6.__in6_u.__u6_addr32[3]);
+
+ CU_ASSERT_EQUAL(uint32_ptr[5], remote_ipv6.__in6_u.__u6_addr32[0]);
+ CU_ASSERT_EQUAL(uint32_ptr[6], remote_ipv6.__in6_u.__u6_addr32[1]);
+ CU_ASSERT_EQUAL(uint32_ptr[7], remote_ipv6.__in6_u.__u6_addr32[2]);
+ CU_ASSERT_EQUAL(uint32_ptr[8], remote_ipv6.__in6_u.__u6_addr32[3]);
+ pcep_obj_free_object((struct pcep_object_header *)ro);
+}
+
+void test_pcep_obj_create_ro_subobj_sr_unnumbered_ipv4_adj()
+{
+ uint32_t sid = 0x01020304;
+ uint32_t local_node_id = 0x11223344;
+ uint32_t local_if_id = 0x55667788;
+ uint32_t remote_node_id = 0x99aabbcc;
+ uint32_t remote_if_id = 0xddeeff11;
+
+ /* (loose_hop, sid_absent, c_flag, m_flag,
+ sid, local_node_id, local_if_id, remote_node_id, remote_if_id) */
+
+ /* Test the sid is absent */
+ struct pcep_ro_subobj_sr *sr =
+ pcep_obj_create_ro_subobj_sr_unnumbered_ipv4_adj(
+ true, true, true, true, sid, local_node_id, local_if_id,
+ remote_node_id, remote_if_id);
+ CU_ASSERT_PTR_NOT_NULL(sr);
+ struct pcep_object_ro *ro = encode_ro_subobj(&sr->ro_subobj);
+ verify_pcep_obj_ro_sr_header(
+ ro, &sr->ro_subobj,
+ PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY, true,
+ sizeof(uint32_t) * 6);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_S);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_F);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_C);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_M);
+ CU_ASSERT_EQUAL(sr->sid, 0);
+ uint32_t *uint32_ptr = (uint32_t *)(ro->header.encoded_object + 8);
+ CU_ASSERT_EQUAL(uint32_ptr[0], local_node_id);
+ CU_ASSERT_EQUAL(uint32_ptr[1], local_if_id);
+ CU_ASSERT_EQUAL(uint32_ptr[2], remote_node_id);
+ CU_ASSERT_EQUAL(uint32_ptr[3], remote_if_id);
+ pcep_obj_free_object((struct pcep_object_header *)ro);
+
+ /* Test the sid is present */
+ reset_objects_buffer();
+ sr = pcep_obj_create_ro_subobj_sr_unnumbered_ipv4_adj(
+ false, false, true, true, sid, local_node_id, local_if_id,
+ remote_node_id, remote_if_id);
+ CU_ASSERT_PTR_NOT_NULL(sr);
+ ro = encode_ro_subobj(&sr->ro_subobj);
+ verify_pcep_obj_ro_sr_header(
+ ro, &sr->ro_subobj,
+ PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY, false,
+ sizeof(uint32_t) * 7);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_C);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_M);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_S);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_F);
+ uint32_ptr = (uint32_t *)(ro->header.encoded_object + 8);
+ CU_ASSERT_EQUAL(uint32_ptr[0], htonl(sid));
+ CU_ASSERT_EQUAL(uint32_ptr[1], local_node_id);
+ CU_ASSERT_EQUAL(uint32_ptr[2], local_if_id);
+ CU_ASSERT_EQUAL(uint32_ptr[3], remote_node_id);
+ CU_ASSERT_EQUAL(uint32_ptr[4], remote_if_id);
+ pcep_obj_free_object((struct pcep_object_header *)ro);
+
+ /* TODO Test draft07 types */
+}
+
+void test_pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj()
+{
+ uint32_t sid = 0x01020304;
+ uint32_t local_if_id = 0x11002200;
+ uint32_t remote_if_id = 0x00110022;
+ struct in6_addr local_ipv6;
+ struct in6_addr remote_ipv6;
+ inet_pton(AF_INET6, "2001:db8::8a2e:370:8221", &local_ipv6);
+ inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &remote_ipv6);
+
+ /* (loose_hop, sid_absent, c_flag, m_flag, sid, local_ipv6, local_if_id,
+ * remote_ipv6, remote_if_id */
+ struct pcep_ro_subobj_sr *sr =
+ pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj(
+ false, true, true, true, sid, NULL, local_if_id, NULL,
+ remote_if_id);
+ CU_ASSERT_PTR_NULL(sr);
+
+ sr = pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj(
+ false, true, true, true, sid, &local_ipv6, local_if_id, NULL,
+ remote_if_id);
+ CU_ASSERT_PTR_NULL(sr);
+
+ sr = pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj(
+ false, true, true, true, sid, NULL, local_if_id, &remote_ipv6,
+ remote_if_id);
+ CU_ASSERT_PTR_NULL(sr);
+
+ /* Test the sid is absent */
+ sr = pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj(
+ true, true, true, true, sid, &local_ipv6, local_if_id,
+ &remote_ipv6, remote_if_id);
+ CU_ASSERT_PTR_NOT_NULL(sr);
+ struct pcep_object_ro *ro = encode_ro_subobj(&sr->ro_subobj);
+ verify_pcep_obj_ro_sr_header(
+ ro, &sr->ro_subobj,
+ PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY, true,
+ sizeof(uint32_t) * 12);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_S);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_F);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_C);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_M);
+ CU_ASSERT_EQUAL(sr->sid, 0);
+ uint32_t *uint32_ptr = (uint32_t *)(ro->header.encoded_object + 8);
+ CU_ASSERT_EQUAL(uint32_ptr[0], local_ipv6.__in6_u.__u6_addr32[0]);
+ CU_ASSERT_EQUAL(uint32_ptr[1], local_ipv6.__in6_u.__u6_addr32[1]);
+ CU_ASSERT_EQUAL(uint32_ptr[2], local_ipv6.__in6_u.__u6_addr32[2]);
+ CU_ASSERT_EQUAL(uint32_ptr[3], local_ipv6.__in6_u.__u6_addr32[3]);
+ CU_ASSERT_EQUAL(uint32_ptr[4], local_if_id);
+
+ CU_ASSERT_EQUAL(uint32_ptr[5], remote_ipv6.__in6_u.__u6_addr32[0]);
+ CU_ASSERT_EQUAL(uint32_ptr[6], remote_ipv6.__in6_u.__u6_addr32[1]);
+ CU_ASSERT_EQUAL(uint32_ptr[7], remote_ipv6.__in6_u.__u6_addr32[2]);
+ CU_ASSERT_EQUAL(uint32_ptr[8], remote_ipv6.__in6_u.__u6_addr32[3]);
+ CU_ASSERT_EQUAL(uint32_ptr[9], remote_if_id);
+ pcep_obj_free_object((struct pcep_object_header *)ro);
+
+ /* Test the sid is present */
+ inet_pton(AF_INET6, "2001:db8::8a2e:370:8221", &local_ipv6);
+ inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &remote_ipv6);
+ reset_objects_buffer();
+ sr = pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj(
+ false, false, true, true, sid, &local_ipv6, local_if_id,
+ &remote_ipv6, remote_if_id);
+ CU_ASSERT_PTR_NOT_NULL(sr);
+ ro = encode_ro_subobj(&sr->ro_subobj);
+ verify_pcep_obj_ro_sr_header(
+ ro, &sr->ro_subobj,
+ PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY, false,
+ sizeof(uint32_t) * 13);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_C);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_M);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_S);
+ CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_F);
+ uint32_ptr = (uint32_t *)(ro->header.encoded_object + 8);
+ CU_ASSERT_EQUAL(uint32_ptr[0], htonl(sid));
+ CU_ASSERT_EQUAL(uint32_ptr[1], local_ipv6.__in6_u.__u6_addr32[0]);
+ CU_ASSERT_EQUAL(uint32_ptr[2], local_ipv6.__in6_u.__u6_addr32[1]);
+ CU_ASSERT_EQUAL(uint32_ptr[3], local_ipv6.__in6_u.__u6_addr32[2]);
+ CU_ASSERT_EQUAL(uint32_ptr[4], local_ipv6.__in6_u.__u6_addr32[3]);
+ CU_ASSERT_EQUAL(uint32_ptr[5], local_if_id);
+
+ CU_ASSERT_EQUAL(uint32_ptr[6], remote_ipv6.__in6_u.__u6_addr32[0]);
+ CU_ASSERT_EQUAL(uint32_ptr[7], remote_ipv6.__in6_u.__u6_addr32[1]);
+ CU_ASSERT_EQUAL(uint32_ptr[8], remote_ipv6.__in6_u.__u6_addr32[2]);
+ CU_ASSERT_EQUAL(uint32_ptr[9], remote_ipv6.__in6_u.__u6_addr32[3]);
+ CU_ASSERT_EQUAL(uint32_ptr[10], remote_if_id);
+ pcep_obj_free_object((struct pcep_object_header *)ro);
+}
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Javier Garcia <javier.garcia@voltanet.io>
+ *
+ */
+
+
+#ifndef PCEP_MSG_OBJECTS_TEST_H_
+#define PCEP_MSG_OBJECTS_TEST_H_
+
+int pcep_objects_test_suite_setup(void);
+int pcep_objects_test_suite_teardown(void);
+void pcep_objects_test_setup(void);
+void pcep_objects_test_teardown(void);
+void test_pcep_obj_create_open(void);
+void test_pcep_obj_create_open_with_tlvs(void);
+void test_pcep_obj_create_rp(void);
+void test_pcep_obj_create_nopath(void);
+void test_pcep_obj_create_endpoint_ipv4(void);
+void test_pcep_obj_create_endpoint_ipv6(void);
+void test_pcep_obj_create_association_ipv4(void);
+void test_pcep_obj_create_association_ipv6(void);
+void test_pcep_obj_create_bandwidth(void);
+void test_pcep_obj_create_metric(void);
+void test_pcep_obj_create_lspa(void);
+void test_pcep_obj_create_svec(void);
+void test_pcep_obj_create_error(void);
+void test_pcep_obj_create_close(void);
+void test_pcep_obj_create_srp(void);
+void test_pcep_obj_create_lsp(void);
+void test_pcep_obj_create_vendor_info(void);
+void test_pcep_obj_create_ero(void);
+void test_pcep_obj_create_rro(void);
+void test_pcep_obj_create_iro(void);
+void test_pcep_obj_create_ro_subobj_ipv4(void);
+void test_pcep_obj_create_ro_subobj_ipv6(void);
+void test_pcep_obj_create_ro_subobj_unnum(void);
+void test_pcep_obj_create_ro_subobj_32label(void);
+void test_pcep_obj_create_ro_subobj_asn(void);
+void test_pcep_obj_create_ro_subobj_sr_nonai(void);
+void test_pcep_obj_create_ro_subobj_sr_ipv4_node(void);
+void test_pcep_obj_create_ro_subobj_sr_ipv6_node(void);
+void test_pcep_obj_create_ro_subobj_sr_ipv4_adj(void);
+void test_pcep_obj_create_ro_subobj_sr_ipv6_adj(void);
+void test_pcep_obj_create_ro_subobj_sr_unnumbered_ipv4_adj(void);
+void test_pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj(void);
+
+#endif
--- /dev/null
+source pceplib/test/pcep_tests_valgrind.sh
+valgrind_test pceplib/test/pcep_msg_tests
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <stdlib.h>
+
+#include <CUnit/CUnit.h>
+
+#include "pcep_msg_encoding.h"
+#include "pcep_msg_objects.h"
+#include "pcep_msg_tlvs.h"
+#include "pcep_msg_tools.h"
+#include "pcep_utils_memory.h"
+#include "pcep_msg_tlvs_test.h"
+
+/*
+ * Notice:
+ * All of these TLV Unit Tests encode the created TLVs by explicitly calling
+ * pcep_encode_tlv() thus testing the TLV creation and the TLV encoding.
+ * All APIs expect IPs to be in network byte order.
+ */
+
+static struct pcep_versioning *versioning = NULL;
+static uint8_t tlv_buf[2000];
+
+void reset_tlv_buffer(void);
+
+int pcep_tlvs_test_suite_setup(void)
+{
+ pceplib_memory_reset();
+ return 0;
+}
+
+int pcep_tlvs_test_suite_teardown(void)
+{
+ printf("\n");
+ pceplib_memory_dump();
+ return 0;
+}
+
+void reset_tlv_buffer()
+{
+ memset(tlv_buf, 0, 2000);
+}
+
+void pcep_tlvs_test_setup()
+{
+ versioning = create_default_pcep_versioning();
+ reset_tlv_buffer();
+}
+
+void pcep_tlvs_test_teardown()
+{
+ destroy_pcep_versioning(versioning);
+}
+
+void test_pcep_tlv_create_stateful_pce_capability()
+{
+ struct pcep_object_tlv_stateful_pce_capability *tlv =
+ pcep_tlv_create_stateful_pce_capability(true, true, true, true,
+ true, true);
+ CU_ASSERT_PTR_NOT_NULL(tlv);
+
+ pcep_encode_tlv(&tlv->header, versioning, tlv_buf);
+ CU_ASSERT_EQUAL(tlv->header.type,
+ PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY);
+ CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, sizeof(uint32_t));
+ CU_ASSERT_TRUE(tlv->flag_u_lsp_update_capability);
+ CU_ASSERT_TRUE(tlv->flag_s_include_db_version);
+ CU_ASSERT_TRUE(tlv->flag_i_lsp_instantiation_capability);
+ CU_ASSERT_TRUE(tlv->flag_t_triggered_resync);
+ CU_ASSERT_TRUE(tlv->flag_d_delta_lsp_sync);
+ CU_ASSERT_TRUE(tlv->flag_f_triggered_initial_sync);
+ CU_ASSERT_EQUAL(tlv->header.encoded_tlv[7], 0x3f);
+ /* TODO add a new function: verify_tlv_header(tlv->header.encoded_tlv)
+ * to all tests */
+
+ pcep_obj_free_tlv(&tlv->header);
+}
+
+void test_pcep_tlv_create_speaker_entity_id()
+{
+ struct pcep_object_tlv_speaker_entity_identifier *tlv =
+ pcep_tlv_create_speaker_entity_id(NULL);
+ CU_ASSERT_PTR_NULL(tlv);
+
+ double_linked_list *list = dll_initialize();
+ tlv = pcep_tlv_create_speaker_entity_id(list);
+ CU_ASSERT_PTR_NULL(tlv);
+ if (tlv != NULL) {
+ pceplib_free(PCEPLIB_INFRA, tlv);
+ tlv = NULL;
+ }
+
+ uint32_t *speaker_entity =
+ pceplib_malloc(PCEPLIB_MESSAGES, sizeof(uint32_t));
+ *speaker_entity = 42;
+ dll_append(list, speaker_entity);
+ tlv = pcep_tlv_create_speaker_entity_id(list);
+ CU_ASSERT_PTR_NOT_NULL(tlv);
+
+ pcep_encode_tlv(&tlv->header, versioning, tlv_buf);
+ CU_ASSERT_EQUAL(tlv->header.type, PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID);
+ CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, sizeof(uint32_t));
+ CU_ASSERT_PTR_NOT_NULL(tlv->speaker_entity_id_list);
+ CU_ASSERT_EQUAL(tlv->speaker_entity_id_list->num_entries, 1);
+ uint32_t *uint32_ptr = (uint32_t *)tlv->header.encoded_tlv;
+ CU_ASSERT_EQUAL(uint32_ptr[1], htonl(*speaker_entity));
+
+ pcep_obj_free_tlv(&tlv->header);
+}
+
+void test_pcep_tlv_create_lsp_db_version()
+{
+ uint64_t lsp_db_version = 0xf005ba11ba5eba11;
+ struct pcep_object_tlv_lsp_db_version *tlv =
+ pcep_tlv_create_lsp_db_version(lsp_db_version);
+ CU_ASSERT_PTR_NOT_NULL(tlv);
+
+ pcep_encode_tlv(&tlv->header, versioning, tlv_buf);
+ CU_ASSERT_EQUAL(tlv->header.type, PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION);
+ CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, sizeof(uint64_t));
+ CU_ASSERT_EQUAL(tlv->lsp_db_version, lsp_db_version);
+ CU_ASSERT_EQUAL(*((uint64_t *)(tlv->header.encoded_tlv + 4)),
+ be64toh(lsp_db_version));
+
+ pcep_obj_free_tlv(&tlv->header);
+}
+
+void test_pcep_tlv_create_path_setup_type()
+{
+ uint8_t pst = 0x89;
+
+ struct pcep_object_tlv_path_setup_type *tlv =
+ pcep_tlv_create_path_setup_type(pst);
+ CU_ASSERT_PTR_NOT_NULL(tlv);
+ pcep_encode_tlv(&tlv->header, versioning, tlv_buf);
+ CU_ASSERT_EQUAL(tlv->header.type, PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE);
+ CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, sizeof(uint32_t));
+ CU_ASSERT_EQUAL(tlv->path_setup_type, pst);
+ uint32_t *uint32_ptr = (uint32_t *)tlv->header.encoded_tlv;
+ CU_ASSERT_EQUAL(uint32_ptr[1], htonl(0x000000FF & pst));
+
+ pcep_obj_free_tlv(&tlv->header);
+}
+
+void test_pcep_tlv_create_path_setup_type_capability()
+{
+ /* The sub_tlv list is optional */
+
+ /* Should return NULL if pst_list is NULL */
+ struct pcep_object_tlv_path_setup_type_capability *tlv =
+ pcep_tlv_create_path_setup_type_capability(NULL, NULL);
+ CU_ASSERT_PTR_NULL(tlv);
+
+ /* Should return NULL if pst_list is empty */
+ double_linked_list *pst_list = dll_initialize();
+ tlv = pcep_tlv_create_path_setup_type_capability(pst_list, NULL);
+ CU_ASSERT_PTR_NULL(tlv);
+ if (tlv != NULL) {
+ pcep_obj_free_tlv(&tlv->header);
+ tlv = NULL;
+ }
+
+ /* Should still return NULL if pst_list is NULL */
+ double_linked_list *sub_tlv_list = dll_initialize();
+ tlv = pcep_tlv_create_path_setup_type_capability(NULL, sub_tlv_list);
+ CU_ASSERT_PTR_NULL(tlv);
+ if (tlv != NULL) {
+ pcep_obj_free_tlv(&tlv->header);
+ tlv = NULL;
+ }
+
+ /* Should still return NULL if pst_list is empty */
+ tlv = pcep_tlv_create_path_setup_type_capability(pst_list,
+ sub_tlv_list);
+ CU_ASSERT_PTR_NULL(tlv);
+ if (tlv != NULL) {
+ pcep_obj_free_tlv(&tlv->header);
+ tlv = NULL;
+ }
+
+ /* Test only populating the pst list */
+ uint8_t *pst1 = pceplib_malloc(PCEPLIB_MESSAGES, 1);
+ uint8_t *pst2 = pceplib_malloc(PCEPLIB_MESSAGES, 1);
+ uint8_t *pst3 = pceplib_malloc(PCEPLIB_MESSAGES, 1);
+ *pst1 = 1;
+ *pst2 = 2;
+ *pst3 = 3;
+ dll_append(pst_list, pst1);
+ dll_append(pst_list, pst2);
+ dll_append(pst_list, pst3);
+ tlv = pcep_tlv_create_path_setup_type_capability(pst_list,
+ sub_tlv_list);
+ CU_ASSERT_PTR_NOT_NULL(tlv);
+ if (tlv == NULL) {
+ CU_ASSERT_TRUE(tlv != NULL);
+ return;
+ }
+
+ pcep_encode_tlv(&tlv->header, versioning, tlv_buf);
+ CU_ASSERT_EQUAL(tlv->header.type,
+ PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY);
+ CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, sizeof(uint32_t) * 2);
+ CU_ASSERT_PTR_NOT_NULL(tlv->pst_list);
+ CU_ASSERT_EQUAL(tlv->pst_list->num_entries, 3);
+ uint32_t *uint32_ptr = (uint32_t *)tlv->header.encoded_tlv;
+ CU_ASSERT_EQUAL(uint32_ptr[1], htonl(0x00000003));
+ CU_ASSERT_EQUAL(uint32_ptr[2], htonl(0x01020300));
+ pcep_obj_free_tlv(&tlv->header);
+
+ /* Now test populating both the pst_list and the sub_tlv_list */
+ reset_tlv_buffer();
+ struct pcep_object_tlv_header *sub_tlv =
+ (struct pcep_object_tlv_header *)
+ pcep_tlv_create_sr_pce_capability(true, true, 0);
+ pst_list = dll_initialize();
+ sub_tlv_list = dll_initialize();
+ pst1 = pceplib_malloc(PCEPLIB_MESSAGES, 1);
+ *pst1 = 1;
+ dll_append(pst_list, pst1);
+ dll_append(sub_tlv_list, sub_tlv);
+ tlv = pcep_tlv_create_path_setup_type_capability(pst_list,
+ sub_tlv_list);
+ CU_ASSERT_PTR_NOT_NULL(tlv);
+
+ pcep_encode_tlv(&tlv->header, versioning, tlv_buf);
+ CU_ASSERT_EQUAL(tlv->header.type,
+ PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY);
+ CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length,
+ sizeof(uint32_t) * 2 + TLV_HEADER_LENGTH
+ + sub_tlv->encoded_tlv_length);
+ CU_ASSERT_PTR_NOT_NULL(tlv->pst_list);
+ CU_ASSERT_PTR_NOT_NULL(tlv->sub_tlv_list);
+ uint32_ptr = (uint32_t *)tlv->header.encoded_tlv;
+ uint16_t *uint16_ptr = (uint16_t *)tlv->header.encoded_tlv;
+ CU_ASSERT_EQUAL(uint16_ptr[0],
+ htons(PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY));
+ CU_ASSERT_EQUAL(uint16_ptr[1], htons(tlv->header.encoded_tlv_length));
+ CU_ASSERT_EQUAL(uint32_ptr[1], htonl(0x00000001));
+ CU_ASSERT_EQUAL(uint32_ptr[2], htonl(0x01000000));
+ /* Verify the Sub-TLV */
+ uint16_ptr = (uint16_t *)(tlv->header.encoded_tlv + 12);
+ CU_ASSERT_EQUAL(uint16_ptr[0],
+ htons(PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY));
+ CU_ASSERT_EQUAL(uint16_ptr[1], htons(4));
+ CU_ASSERT_EQUAL(uint16_ptr[2], 0);
+ CU_ASSERT_EQUAL(uint16_ptr[3], htons(0x0300));
+
+ pcep_obj_free_tlv(&tlv->header);
+}
+
+void test_pcep_tlv_create_sr_pce_capability()
+{
+ struct pcep_object_tlv_sr_pce_capability *tlv =
+ pcep_tlv_create_sr_pce_capability(true, true, 8);
+ CU_ASSERT_PTR_NOT_NULL(tlv);
+
+ pcep_encode_tlv(&tlv->header, versioning, tlv_buf);
+ CU_ASSERT_EQUAL(tlv->header.type, PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY);
+ CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, sizeof(uint32_t));
+ uint16_t *uint16_ptr = (uint16_t *)tlv->header.encoded_tlv;
+ CU_ASSERT_EQUAL(uint16_ptr[0],
+ htons(PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY));
+ CU_ASSERT_EQUAL(uint16_ptr[1], htons(tlv->header.encoded_tlv_length));
+ uint32_t *uint32_ptr = (uint32_t *)tlv->header.encoded_tlv;
+ CU_ASSERT_EQUAL(uint32_ptr[1], htonl(0x00000308));
+
+ pcep_obj_free_tlv(&tlv->header);
+}
+
+void test_pcep_tlv_create_symbolic_path_name()
+{
+ /* char *symbolic_path_name, uint16_t symbolic_path_name_length); */
+ char path_name[16] = "Some Path Name";
+ uint16_t path_name_length = 14;
+ struct pcep_object_tlv_symbolic_path_name *tlv =
+ pcep_tlv_create_symbolic_path_name(path_name, path_name_length);
+ CU_ASSERT_PTR_NOT_NULL(tlv);
+
+ pcep_encode_tlv(&tlv->header, versioning, tlv_buf);
+ CU_ASSERT_EQUAL(tlv->header.type, PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME);
+ CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, path_name_length);
+ /* Test the padding is correct */
+ CU_ASSERT_EQUAL(0, strncmp((char *)&(tlv->header.encoded_tlv[4]),
+ &path_name[0], 4));
+ CU_ASSERT_EQUAL(0, strncmp((char *)&(tlv->header.encoded_tlv[8]),
+ &path_name[4], 4));
+ CU_ASSERT_EQUAL(0, strncmp((char *)&(tlv->header.encoded_tlv[12]),
+ &path_name[8], 4));
+ CU_ASSERT_EQUAL(tlv->header.encoded_tlv[16], 'm');
+ CU_ASSERT_EQUAL(tlv->header.encoded_tlv[17], 'e');
+ CU_ASSERT_EQUAL(tlv->header.encoded_tlv[18], 0);
+ CU_ASSERT_EQUAL(tlv->header.encoded_tlv[19], 0);
+ pcep_obj_free_tlv(&tlv->header);
+
+ reset_tlv_buffer();
+ tlv = pcep_tlv_create_symbolic_path_name(path_name, 3);
+ CU_ASSERT_PTR_NOT_NULL(tlv);
+ pcep_encode_tlv(&tlv->header, versioning, tlv_buf);
+ CU_ASSERT_EQUAL(tlv->header.type, PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME);
+ CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, 3);
+ CU_ASSERT_EQUAL(tlv->header.encoded_tlv[4], 'S');
+ CU_ASSERT_EQUAL(tlv->header.encoded_tlv[5], 'o');
+ CU_ASSERT_EQUAL(tlv->header.encoded_tlv[6], 'm');
+ CU_ASSERT_EQUAL(tlv->header.encoded_tlv[7], 0);
+
+ pcep_obj_free_tlv(&tlv->header);
+}
+
+void test_pcep_tlv_create_ipv4_lsp_identifiers()
+{
+ struct in_addr sender_ip, endpoint_ip;
+ uint16_t lsp_id = 7;
+ uint16_t tunnel_id = 16;
+ struct in_addr extended_tunnel_id;
+ extended_tunnel_id.s_addr = 256;
+ inet_pton(AF_INET, "192.168.1.1", &sender_ip);
+ inet_pton(AF_INET, "192.168.1.2", &endpoint_ip);
+
+ struct pcep_object_tlv_ipv4_lsp_identifier *tlv =
+ pcep_tlv_create_ipv4_lsp_identifiers(NULL, &endpoint_ip, lsp_id,
+ tunnel_id,
+ &extended_tunnel_id);
+ CU_ASSERT_PTR_NULL(tlv);
+
+ tlv = pcep_tlv_create_ipv4_lsp_identifiers(
+ &sender_ip, NULL, lsp_id, tunnel_id, &extended_tunnel_id);
+ CU_ASSERT_PTR_NULL(tlv);
+
+ tlv = pcep_tlv_create_ipv4_lsp_identifiers(
+ NULL, NULL, lsp_id, tunnel_id, &extended_tunnel_id);
+ CU_ASSERT_PTR_NULL(tlv);
+
+ tlv = pcep_tlv_create_ipv4_lsp_identifiers(&sender_ip, &endpoint_ip,
+ lsp_id, tunnel_id,
+ &extended_tunnel_id);
+ CU_ASSERT_PTR_NOT_NULL(tlv);
+
+ pcep_encode_tlv(&tlv->header, versioning, tlv_buf);
+ CU_ASSERT_EQUAL(tlv->header.type,
+ PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS);
+ CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, sizeof(uint32_t) * 4);
+ uint32_t *uint32_ptr = (uint32_t *)tlv->header.encoded_tlv;
+ CU_ASSERT_EQUAL(uint32_ptr[1], sender_ip.s_addr);
+ CU_ASSERT_EQUAL(uint32_ptr[2],
+ (uint32_t)(htons(tunnel_id) << 16) | htons(lsp_id));
+ CU_ASSERT_EQUAL(uint32_ptr[3], extended_tunnel_id.s_addr);
+ CU_ASSERT_EQUAL(uint32_ptr[4], endpoint_ip.s_addr);
+ pcep_obj_free_tlv(&tlv->header);
+
+ reset_tlv_buffer();
+ tlv = pcep_tlv_create_ipv4_lsp_identifiers(&sender_ip, &endpoint_ip,
+ lsp_id, tunnel_id, NULL);
+ CU_ASSERT_PTR_NOT_NULL(tlv);
+
+ pcep_encode_tlv(&tlv->header, versioning, tlv_buf);
+ CU_ASSERT_EQUAL(tlv->header.type,
+ PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS);
+ CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, sizeof(uint32_t) * 4);
+ uint32_ptr = (uint32_t *)tlv->header.encoded_tlv;
+ CU_ASSERT_EQUAL(uint32_ptr[1], sender_ip.s_addr);
+ CU_ASSERT_EQUAL(uint32_ptr[2],
+ (uint32_t)(htons(tunnel_id) << 16) | htons(lsp_id));
+ CU_ASSERT_EQUAL(uint32_ptr[3], INADDR_ANY);
+ CU_ASSERT_EQUAL(uint32_ptr[4], endpoint_ip.s_addr);
+ pcep_obj_free_tlv(&tlv->header);
+}
+
+void test_pcep_tlv_create_ipv6_lsp_identifiers()
+{
+ struct in6_addr sender_ip, endpoint_ip;
+ uint16_t lsp_id = 3;
+ uint16_t tunnel_id = 16;
+ uint32_t extended_tunnel_id[4];
+
+ inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &sender_ip);
+ inet_pton(AF_INET6, "2001:db8::8a2e:370:8446", &endpoint_ip);
+ extended_tunnel_id[0] = 1;
+ extended_tunnel_id[1] = 2;
+ extended_tunnel_id[2] = 3;
+ extended_tunnel_id[3] = 4;
+
+ struct pcep_object_tlv_ipv6_lsp_identifier *tlv =
+ pcep_tlv_create_ipv6_lsp_identifiers(
+ NULL, &endpoint_ip, lsp_id, tunnel_id,
+ (struct in6_addr *)&extended_tunnel_id);
+ CU_ASSERT_PTR_NULL(tlv);
+
+ tlv = pcep_tlv_create_ipv6_lsp_identifiers(
+ &sender_ip, NULL, lsp_id, tunnel_id,
+ (struct in6_addr *)&extended_tunnel_id);
+ CU_ASSERT_PTR_NULL(tlv);
+
+ tlv = pcep_tlv_create_ipv6_lsp_identifiers(
+ NULL, NULL, lsp_id, tunnel_id,
+ (struct in6_addr *)&extended_tunnel_id);
+ CU_ASSERT_PTR_NULL(tlv);
+
+ tlv = pcep_tlv_create_ipv6_lsp_identifiers(
+ &sender_ip, &endpoint_ip, lsp_id, tunnel_id,
+ (struct in6_addr *)&extended_tunnel_id);
+ CU_ASSERT_PTR_NOT_NULL(tlv);
+
+ pcep_encode_tlv(&tlv->header, versioning, tlv_buf);
+ CU_ASSERT_EQUAL(tlv->header.type,
+ PCEP_OBJ_TLV_TYPE_IPV6_LSP_IDENTIFIERS);
+ CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, 52);
+ uint32_t *uint32_ptr = (uint32_t *)tlv->header.encoded_tlv;
+ CU_ASSERT_EQUAL(uint32_ptr[5],
+ (uint32_t)(htons(tunnel_id) << 16) | htons(lsp_id));
+
+ pcep_obj_free_tlv(&tlv->header);
+}
+void test_pcep_tlv_create_srpag_pol_id_ipv4()
+{
+ uint32_t color = 1;
+ struct in_addr src;
+ inet_pton(AF_INET, "192.168.1.2", &src);
+
+ struct pcep_object_tlv_srpag_pol_id *tlv =
+ pcep_tlv_create_srpag_pol_id_ipv4(color, (void *)&src);
+ CU_ASSERT_PTR_NOT_NULL(tlv);
+
+ pcep_encode_tlv(&tlv->header, versioning, tlv_buf);
+ CU_ASSERT_EQUAL(tlv->header.type, (PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_ID));
+ CU_ASSERT_EQUAL(
+ tlv->header.encoded_tlv_length,
+ (8 /*draft-barth-pce-segment-routing-policy-cp-04#5.1*/));
+ CU_ASSERT_EQUAL(tlv->color, (color));
+ uint32_t aux_color = htonl(color); // Is color right encoded
+ CU_ASSERT_EQUAL(0, memcmp(&tlv_buf[0] + TLV_HEADER_LENGTH, &aux_color,
+ sizeof(color)));
+ CU_ASSERT_EQUAL(tlv->end_point.ipv4.s_addr, (src.s_addr));
+ // Are simetrical?
+ struct pcep_object_tlv_header *dec_hdr = pcep_decode_tlv(tlv_buf);
+ struct pcep_object_tlv_srpag_pol_id *dec_tlv =
+ (struct pcep_object_tlv_srpag_pol_id *)dec_hdr;
+ CU_ASSERT_EQUAL(tlv->color, dec_tlv->color);
+
+ pceplib_free(PCEPLIB_MESSAGES, dec_hdr);
+ pcep_obj_free_tlv(&tlv->header);
+}
+void test_pcep_tlv_create_srpag_pol_id_ipv6()
+{
+
+ uint32_t color = 1;
+ struct in6_addr src;
+ inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &src);
+
+ struct pcep_object_tlv_srpag_pol_id *tlv =
+ pcep_tlv_create_srpag_pol_id_ipv6(color, &src);
+
+ pcep_encode_tlv(&tlv->header, versioning, tlv_buf);
+ CU_ASSERT_EQUAL(tlv->header.type, (PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_ID));
+ CU_ASSERT_EQUAL(
+ tlv->header.encoded_tlv_length,
+ (20 /*draft-barth-pce-segment-routing-policy-cp-04#5.1*/));
+ CU_ASSERT_EQUAL(tlv->color, (color));
+ CU_ASSERT_EQUAL(0, memcmp(&tlv->end_point.ipv6, &src, sizeof(src)));
+
+ uint32_t aux_color = htonl(color);
+ CU_ASSERT_EQUAL(0, memcmp(&aux_color, tlv_buf + TLV_HEADER_LENGTH,
+ sizeof(tlv->color)));
+ // Are simetrical?
+ struct pcep_object_tlv_header *dec_hdr = pcep_decode_tlv(tlv_buf);
+ struct pcep_object_tlv_srpag_pol_id *dec_tlv =
+ (struct pcep_object_tlv_srpag_pol_id *)dec_hdr;
+ CU_ASSERT_EQUAL(tlv->color, dec_tlv->color);
+
+ pceplib_free(PCEPLIB_MESSAGES, dec_hdr);
+ pcep_obj_free_tlv(&tlv->header);
+}
+void test_pcep_tlv_create_srpag_pol_name()
+{
+ const char *pol_name = "Some Pol Name";
+
+ struct pcep_object_tlv_srpag_pol_name *tlv =
+ pcep_tlv_create_srpag_pol_name(pol_name, strlen(pol_name));
+ CU_ASSERT_PTR_NOT_NULL(tlv);
+
+ pcep_encode_tlv(&tlv->header, versioning, tlv_buf);
+ CU_ASSERT_EQUAL(tlv->header.type,
+ (PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_NAME));
+ CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length,
+ (normalize_pcep_tlv_length(strlen(pol_name))));
+ CU_ASSERT_EQUAL(0, strcmp(pol_name, (char *)tlv->name));
+
+
+ pcep_obj_free_tlv(&tlv->header);
+}
+
+void test_pcep_tlv_create_srpag_cp_id()
+{
+ // draft-ietf-spring-segment-routing-policy-06.pdf#2.3
+ // 10 PCEP, 20 BGP SR Policy, 30 Via Configuration
+ uint8_t proto_origin = 10;
+ uint32_t ASN = 0;
+ struct in6_addr with_mapped_ipv4;
+ inet_pton(AF_INET6, "::ffff:192.0.2.128", &with_mapped_ipv4);
+ uint32_t discriminator = 0;
+
+ struct pcep_object_tlv_srpag_cp_id *tlv = pcep_tlv_create_srpag_cp_id(
+ proto_origin, ASN, &with_mapped_ipv4, discriminator);
+
+ pcep_encode_tlv(&tlv->header, versioning, tlv_buf);
+ CU_ASSERT_EQUAL(tlv->header.type,
+ (PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_ID));
+ CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length,
+ (sizeof(proto_origin) + sizeof(ASN)
+ + sizeof(with_mapped_ipv4) + sizeof(discriminator)));
+ CU_ASSERT_EQUAL(tlv->proto, (proto_origin));
+ CU_ASSERT_EQUAL(tlv->orig_asn, (ASN));
+ CU_ASSERT_EQUAL(0, memcmp(&tlv->orig_addres, &with_mapped_ipv4,
+ sizeof(with_mapped_ipv4)));
+ CU_ASSERT_EQUAL(tlv->discriminator, (discriminator));
+ // Are simetrical?
+ struct pcep_object_tlv_header *dec_hdr = pcep_decode_tlv(tlv_buf);
+ struct pcep_object_tlv_srpag_cp_id *dec_tlv =
+ (struct pcep_object_tlv_srpag_cp_id *)dec_hdr;
+ CU_ASSERT_EQUAL(tlv->proto, dec_tlv->proto);
+
+ pceplib_free(PCEPLIB_MESSAGES, dec_hdr);
+ pcep_obj_free_tlv(&tlv->header);
+}
+
+void test_pcep_tlv_create_srpag_cp_pref()
+{
+ uint32_t preference_default = 100;
+
+ struct pcep_object_tlv_srpag_cp_pref *tlv =
+ pcep_tlv_create_srpag_cp_pref(preference_default);
+ CU_ASSERT_PTR_NOT_NULL(tlv);
+
+ pcep_encode_tlv(&tlv->header, versioning, tlv_buf);
+ CU_ASSERT_EQUAL(tlv->header.type,
+ (PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_PREFERENCE));
+ printf(" encoded length vs sizeof pref (%d) vs (%ld)\n",
+ tlv->header.encoded_tlv_length, sizeof(preference_default));
+ CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length,
+ sizeof(preference_default));
+ CU_ASSERT_EQUAL(tlv->preference, (preference_default));
+ uint32_t aux_pref = htonl(preference_default); // Is pref right encoded
+ CU_ASSERT_EQUAL(0, memcmp(tlv_buf + TLV_HEADER_LENGTH, &aux_pref,
+ sizeof(preference_default)));
+ // Are simetrical?
+ struct pcep_object_tlv_header *dec_hdr = pcep_decode_tlv(tlv_buf);
+ struct pcep_object_tlv_srpag_cp_pref *dec_tlv =
+ (struct pcep_object_tlv_srpag_cp_pref *)dec_hdr;
+ CU_ASSERT_EQUAL(tlv->preference, dec_tlv->preference);
+
+ pceplib_free(PCEPLIB_MESSAGES, dec_hdr);
+ pcep_obj_free_tlv(&tlv->header);
+}
+void test_pcep_tlv_create_lsp_error_code()
+{
+ struct pcep_object_tlv_lsp_error_code *tlv =
+ pcep_tlv_create_lsp_error_code(
+ PCEP_TLV_LSP_ERROR_CODE_RSVP_SIGNALING_ERROR);
+ CU_ASSERT_PTR_NOT_NULL(tlv);
+
+ pcep_encode_tlv(&tlv->header, versioning, tlv_buf);
+ CU_ASSERT_EQUAL(tlv->header.type, PCEP_OBJ_TLV_TYPE_LSP_ERROR_CODE);
+ CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, sizeof(uint32_t));
+ uint32_t *uint32_ptr = (uint32_t *)tlv->header.encoded_tlv;
+ CU_ASSERT_EQUAL(uint32_ptr[1],
+ htonl(PCEP_TLV_LSP_ERROR_CODE_RSVP_SIGNALING_ERROR));
+
+ pcep_obj_free_tlv(&tlv->header);
+}
+
+void test_pcep_tlv_create_rsvp_ipv4_error_spec()
+{
+ struct in_addr error_node_ip;
+ inet_pton(AF_INET, "192.168.1.1", &error_node_ip);
+ uint8_t error_code = 8;
+ uint16_t error_value = 0xaabb;
+
+ struct pcep_object_tlv_rsvp_error_spec *tlv =
+ pcep_tlv_create_rsvp_ipv4_error_spec(NULL, error_code,
+ error_value);
+ CU_ASSERT_PTR_NULL(tlv);
+
+ tlv = pcep_tlv_create_rsvp_ipv4_error_spec(&error_node_ip, error_code,
+ error_value);
+ CU_ASSERT_PTR_NOT_NULL(tlv);
+
+ pcep_encode_tlv(&tlv->header, versioning, tlv_buf);
+ CU_ASSERT_EQUAL(tlv->header.type, PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC);
+ CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, 12);
+
+ pcep_obj_free_tlv(&tlv->header);
+}
+
+void test_pcep_tlv_create_rsvp_ipv6_error_spec()
+{
+ struct in6_addr error_node_ip;
+ inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &error_node_ip);
+ uint8_t error_code = 8;
+ uint16_t error_value = 0xaabb;
+
+ struct pcep_object_tlv_rsvp_error_spec *tlv =
+ pcep_tlv_create_rsvp_ipv6_error_spec(NULL, error_code,
+ error_value);
+ CU_ASSERT_PTR_NULL(tlv);
+
+ tlv = pcep_tlv_create_rsvp_ipv6_error_spec(&error_node_ip, error_code,
+ error_value);
+ CU_ASSERT_PTR_NOT_NULL(tlv);
+
+ pcep_encode_tlv(&tlv->header, versioning, tlv_buf);
+ CU_ASSERT_EQUAL(tlv->header.type, PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC);
+ CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, 24);
+
+ pcep_obj_free_tlv(&tlv->header);
+}
+
+void test_pcep_tlv_create_nopath_vector()
+{
+ uint32_t enterprise_number = 0x01020304;
+ uint32_t enterprise_specific_info = 0x05060708;
+
+ struct pcep_object_tlv_vendor_info *tlv = pcep_tlv_create_vendor_info(
+ enterprise_number, enterprise_specific_info);
+ CU_ASSERT_PTR_NOT_NULL(tlv);
+
+ pcep_encode_tlv(&tlv->header, versioning, tlv_buf);
+ CU_ASSERT_EQUAL(tlv->header.type, PCEP_OBJ_TLV_TYPE_VENDOR_INFO);
+ CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, 8);
+ uint32_t *uint32_ptr = (uint32_t *)tlv->header.encoded_tlv;
+ CU_ASSERT_EQUAL(uint32_ptr[1], htonl(enterprise_number));
+ CU_ASSERT_EQUAL(uint32_ptr[2], htonl(enterprise_specific_info));
+
+ pcep_obj_free_tlv(&tlv->header);
+}
+
+void test_pcep_tlv_create_arbitrary()
+{
+ char data[16] = "Some Data";
+ uint16_t data_length = 9;
+ uint16_t tlv_id_unknown = 1; // 65505; // Whatever id to be created
+ struct pcep_object_tlv_arbitrary *tlv = pcep_tlv_create_tlv_arbitrary(
+ data, data_length, tlv_id_unknown);
+ CU_ASSERT_PTR_NOT_NULL(tlv);
+
+ pcep_encode_tlv(&tlv->header, versioning, tlv_buf);
+ CU_ASSERT_EQUAL(tlv->header.type, tlv_id_unknown);
+ CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, data_length);
+ /* Test the padding is correct */
+ CU_ASSERT_EQUAL(
+ 0, strncmp((char *)&(tlv->header.encoded_tlv[4]), &data[0], 4));
+ CU_ASSERT_EQUAL(
+ 0, strncmp((char *)&(tlv->header.encoded_tlv[8]), &data[4], 4));
+ CU_ASSERT_EQUAL(tlv->header.encoded_tlv[11], 't');
+ CU_ASSERT_EQUAL(tlv->header.encoded_tlv[12], 'a');
+ CU_ASSERT_EQUAL(tlv->header.encoded_tlv[13], 0);
+ CU_ASSERT_EQUAL(tlv->header.encoded_tlv[14], 0);
+ pcep_obj_free_tlv(&tlv->header);
+
+ reset_tlv_buffer();
+ tlv = pcep_tlv_create_tlv_arbitrary(data, 3, tlv_id_unknown);
+ CU_ASSERT_PTR_NOT_NULL(tlv);
+ pcep_encode_tlv(&tlv->header, versioning, tlv_buf);
+ CU_ASSERT_EQUAL(tlv->header.type, tlv_id_unknown);
+ CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, 3);
+ CU_ASSERT_EQUAL(tlv->header.encoded_tlv[4], 'S');
+ CU_ASSERT_EQUAL(tlv->header.encoded_tlv[5], 'o');
+ CU_ASSERT_EQUAL(tlv->header.encoded_tlv[6], 'm');
+ CU_ASSERT_EQUAL(tlv->header.encoded_tlv[7], 0);
+
+ pcep_obj_free_tlv(&tlv->header);
+}
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Javier Garcia <javier.garcia@voltanet.io>
+ *
+ */
+
+#ifndef PCEP_MSG_TLVS_TEST_H_
+#define PCEP_MSG_TLVS_TEST_H_
+
+int pcep_tlvs_test_suite_setup(void);
+int pcep_tlvs_test_suite_teardown(void);
+void pcep_tlvs_test_setup(void);
+void pcep_tlvs_test_teardown(void);
+void test_pcep_tlv_create_stateful_pce_capability(void);
+void test_pcep_tlv_create_speaker_entity_id(void);
+void test_pcep_tlv_create_lsp_db_version(void);
+void test_pcep_tlv_create_path_setup_type(void);
+void test_pcep_tlv_create_path_setup_type_capability(void);
+void test_pcep_tlv_create_sr_pce_capability(void);
+void test_pcep_tlv_create_symbolic_path_name(void);
+void test_pcep_tlv_create_ipv4_lsp_identifiers(void);
+void test_pcep_tlv_create_ipv6_lsp_identifiers(void);
+void test_pcep_tlv_create_lsp_error_code(void);
+void test_pcep_tlv_create_rsvp_ipv4_error_spec(void);
+void test_pcep_tlv_create_rsvp_ipv6_error_spec(void);
+void test_pcep_tlv_create_srpag_pol_id_ipv4(void);
+void test_pcep_tlv_create_srpag_pol_id_ipv6(void);
+void test_pcep_tlv_create_srpag_pol_name(void);
+void test_pcep_tlv_create_srpag_cp_id(void);
+void test_pcep_tlv_create_srpag_cp_pref(void);
+void test_pcep_tlv_create_nopath_vector(void);
+void test_pcep_tlv_create_arbitrary(void);
+
+
+#endif
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+
+#include <CUnit/CUnit.h>
+
+#include "pcep_msg_encoding.h"
+#include "pcep_msg_messages.h"
+#include "pcep_msg_tools.h"
+#include "pcep_msg_tools_test.h"
+#include "pcep_utils_double_linked_list.h"
+#include "pcep_utils_logging.h"
+#include "pcep_utils_memory.h"
+
+const uint8_t any_obj_class = 255;
+
+uint16_t pcep_open_hexbyte_strs_length = 28;
+const char *pcep_open_odl_hexbyte_strs[] = {
+ "20", "01", "00", "1c", "01", "10", "00", "18", "20", "1e",
+ "78", "55", "00", "10", "00", "04", "00", "00", "00", "3f",
+ "00", "1a", "00", "04", "00", "00", "00", "00"};
+
+/* PCEP INITIATE str received from ODL with 4 objects: [SRP, LSP, Endpoints,
+ * ERO] The LSP has a SYMBOLIC_PATH_NAME TLV. The ERO has 2 IPV4 Endpoints. */
+uint16_t pcep_initiate_hexbyte_strs_length = 68;
+const char *pcep_initiate_hexbyte_strs[] = {
+ "20", "0c", "00", "44", "21", "12", "00", "0c", "00", "00", "00", "00",
+ "00", "00", "00", "01", "20", "10", "00", "14", "00", "00", "00", "09",
+ "00", "11", "00", "08", "66", "61", "39", "33", "33", "39", "32", "39",
+ "04", "10", "00", "0c", "7f", "00", "00", "01", "28", "28", "28", "28",
+ "07", "10", "00", "14", "01", "08", "0a", "00", "01", "01", "18", "00",
+ "01", "08", "0a", "00", "07", "04", "18", "00"};
+
+uint16_t pcep_initiate2_hexbyte_strs_length = 72;
+const char *pcep_initiate2_hexbyte_strs[] = {
+ "20", "0c", "00", "48", "21", "12", "00", "14", "00", "00", "00", "00",
+ "00", "00", "00", "01", "00", "1c", "00", "04", "00", "00", "00", "01",
+ "20", "10", "00", "14", "00", "00", "00", "09", "00", "11", "00", "08",
+ "36", "65", "31", "31", "38", "39", "32", "31", "04", "10", "00", "0c",
+ "c0", "a8", "14", "05", "01", "01", "01", "01", "07", "10", "00", "10",
+ "05", "0c", "10", "01", "03", "e8", "a0", "00", "01", "01", "01", "01"};
+
+uint16_t pcep_update_hexbyte_strs_length = 48;
+const char *pcep_update_hexbyte_strs[] = {
+ "20", "0b", "00", "30", "21", "12", "00", "14", "00", "00", "00", "00",
+ "00", "00", "00", "01", "00", "1c", "00", "04", "00", "00", "00", "01",
+ "20", "10", "00", "08", "00", "02", "a0", "09", "07", "10", "00", "10",
+ "05", "0c", "10", "01", "03", "e8", "a0", "00", "01", "01", "01", "01"};
+
+/* Test that pcep_msg_read() can read multiple messages in 1 call */
+uint16_t pcep_open_initiate_hexbyte_strs_length = 100;
+const char *pcep_open_initiate_odl_hexbyte_strs[] = {
+ "20", "01", "00", "1c", "01", "10", "00", "18", "20", "1e", "78", "55",
+ "00", "10", "00", "04", "00", "00", "00", "3f", "00", "1a", "00", "04",
+ "00", "00", "00", "00", "20", "0c", "00", "48", "21", "12", "00", "14",
+ "00", "00", "00", "00", "00", "00", "00", "01", "00", "1c", "00", "04",
+ "00", "00", "00", "01", "20", "10", "00", "14", "00", "00", "00", "09",
+ "00", "11", "00", "08", "36", "65", "31", "31", "38", "39", "32", "31",
+ "04", "10", "00", "0c", "c0", "a8", "14", "05", "01", "01", "01", "01",
+ "07", "10", "00", "10", "05", "0c", "10", "01", "03", "e8", "a0", "00",
+ "01", "01", "01", "01"};
+
+uint16_t pcep_open_cisco_pce_hexbyte_strs_length = 28;
+const char *pcep_open_cisco_pce_hexbyte_strs[] = {
+ "20", "01", "00", "1c", "01", "10", "00", "18", "20", "3c",
+ "78", "00", "00", "10", "00", "04", "00", "00", "00", "05",
+ "00", "1a", "00", "04", "00", "00", "00", "0a"};
+
+uint16_t pcep_update_cisco_pce_hexbyte_strs_length = 100;
+const char *pcep_update_cisco_pce_hexbyte_strs[] = {
+ "20", "0b", "00", "64", "21", "10", "00", "14", "00", "00", "00", "00",
+ "00", "00", "00", "01", "00", "1c", "00", "04", "00", "00", "00", "01",
+ "20", "10", "00", "18", "80", "00", "f0", "89", "00", "07", "00", "0c",
+ "00", "00", "00", "09", "00", "03", "00", "04", "00", "00", "00", "01",
+ "07", "10", "00", "28", "24", "0c", "10", "01", "04", "65", "50", "00",
+ "0a", "0a", "0a", "05", "24", "0c", "10", "01", "04", "65", "20", "00",
+ "0a", "0a", "0a", "02", "24", "0c", "10", "01", "04", "65", "10", "00",
+ "0a", "0a", "0a", "01", "06", "10", "00", "0c", "00", "00", "00", "02",
+ "41", "f0", "00", "00"};
+
+uint16_t pcep_report_cisco_pcc_hexbyte_strs_length = 148;
+const char *pcep_report_cisco_pcc_hexbyte_strs[] = {
+ "20", "0a", "00", "94", "21", "10", "00", "14", "00", "00", "00", "00",
+ "00", "00", "00", "00", "00", "1c", "00", "04", "00", "00", "00", "01",
+ "20", "10", "00", "3c", "80", "00", "f0", "09", "00", "12", "00", "10",
+ "0a", "0a", "0a", "06", "00", "02", "00", "0f", "0a", "0a", "0a", "06",
+ "0a", "0a", "0a", "01", "00", "11", "00", "0d", "63", "66", "67", "5f",
+ "52", "36", "2d", "74", "6f", "2d", "52", "31", "00", "00", "00", "00",
+ "ff", "e1", "00", "06", "00", "00", "05", "dd", "70", "00", "00", "00",
+ "07", "10", "00", "04", "09", "10", "00", "14", "00", "00", "00", "00",
+ "00", "00", "00", "00", "00", "00", "00", "00", "07", "07", "01", "00",
+ "05", "12", "00", "08", "00", "00", "00", "00", "05", "52", "00", "08",
+ "00", "00", "00", "00", "06", "10", "00", "0c", "00", "00", "00", "02",
+ "00", "00", "00", "00", "06", "10", "00", "0c", "00", "00", "01", "04",
+ "41", "80", "00", "00"};
+
+/* Cisco PcInitiate with the following objects:
+ * SRP, LSP, Endpoint, Inter-layer, Switch-layer, ERO
+ */
+uint16_t pcep_initiate_cisco_pcc_hexbyte_strs_length = 104;
+const char *pcep_initiate_cisco_pcc_hexbyte_strs[] = {
+ "20", "0c", "00", "68", "21", "10", "00", "14", "00", "00", "00", "00",
+ "00", "00", "00", "01", "00", "1c", "00", "04", "00", "00", "00", "01",
+ "20", "10", "00", "30", "00", "00", "00", "89", "00", "11", "00", "13",
+ "50", "4f", "4c", "31", "5f", "50", "43", "49", "4e", "49", "54", "41",
+ "54", "45", "5f", "54", "45", "53", "54", "00", "00", "07", "00", "0c",
+ "00", "00", "00", "09", "00", "03", "00", "04", "00", "00", "00", "01",
+ "04", "10", "00", "0c", "0a", "0a", "0a", "0a", "0a", "0a", "0a", "04",
+ "24", "10", "00", "08", "00", "00", "01", "4d", "25", "10", "00", "08",
+ "00", "00", "00", "64", "07", "10", "00", "04"};
+
+struct pcep_message *create_message(uint8_t msg_type, uint8_t obj1_class,
+ uint8_t obj2_class, uint8_t obj3_class,
+ uint8_t obj4_class);
+int convert_hexstrs_to_binary(const char *hexbyte_strs[],
+ uint16_t hexbyte_strs_length);
+
+int pcep_tools_test_suite_setup(void)
+{
+ pceplib_memory_reset();
+ return 0;
+}
+
+int pcep_tools_test_suite_teardown(void)
+{
+ printf("\n");
+ pceplib_memory_dump();
+ return 0;
+}
+
+void pcep_tools_test_setup(void)
+{
+}
+
+void pcep_tools_test_teardown(void)
+{
+}
+
+/* Reads an array of hexbyte strs, and writes them to a temporary file.
+ * The caller should close the returned file. */
+int convert_hexstrs_to_binary(const char *hexbyte_strs[],
+ uint16_t hexbyte_strs_length)
+{
+ mode_t oldumask;
+ oldumask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH);
+ /* Set umask before anything for security */
+ umask(0027);
+ char tmpfile[] = "/tmp/pceplib_XXXXXX";
+ int fd = mkstemp(tmpfile);
+ umask(oldumask);
+ if (fd == -1)
+ return -1;
+
+ int i = 0;
+ for (; i < hexbyte_strs_length; i++) {
+ uint8_t byte = (uint8_t)strtol(hexbyte_strs[i], 0, 16);
+ if (write(fd, (char *)&byte, 1) < 0) {
+ return -1;
+ }
+ }
+
+ /* Go back to the beginning of the file */
+ lseek(fd, 0, SEEK_SET);
+ return fd;
+}
+
+static bool pcep_obj_has_tlv(struct pcep_object_header *obj_hdr)
+{
+ if (obj_hdr->tlv_list == NULL) {
+ return false;
+ }
+
+ return (obj_hdr->tlv_list->num_entries > 0);
+}
+
+void test_pcep_msg_read_pcep_initiate()
+{
+ int fd = convert_hexstrs_to_binary(pcep_initiate_hexbyte_strs,
+ pcep_initiate_hexbyte_strs_length);
+ if(fd == -1){
+ CU_ASSERT_TRUE(fd>=0);
+ return;
+ }
+ double_linked_list *msg_list = pcep_msg_read(fd);
+ CU_ASSERT_PTR_NOT_NULL(msg_list);
+ CU_ASSERT_EQUAL(msg_list->num_entries, 1);
+
+ struct pcep_message *msg = (struct pcep_message *)msg_list->head->data;
+ CU_ASSERT_EQUAL(msg->obj_list->num_entries, 4);
+ CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_INITIATE);
+ CU_ASSERT_EQUAL(msg->encoded_message_length,
+ pcep_initiate_hexbyte_strs_length);
+
+ /* Verify each of the object types */
+
+ /* SRP object */
+ double_linked_list_node *node = msg->obj_list->head;
+ struct pcep_object_header *obj_hdr =
+ (struct pcep_object_header *)node->data;
+ CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_SRP);
+ CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_SRP);
+ CU_ASSERT_EQUAL(obj_hdr->encoded_object_length,
+ pcep_object_get_length_by_hdr(obj_hdr));
+ CU_ASSERT_FALSE(pcep_obj_has_tlv(obj_hdr));
+
+ /* LSP object and its TLV*/
+ node = node->next_node;
+ obj_hdr = (struct pcep_object_header *)node->data;
+ CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_LSP);
+ CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_LSP);
+ CU_ASSERT_EQUAL(obj_hdr->encoded_object_length, 20);
+ CU_ASSERT_EQUAL(((struct pcep_object_lsp *)obj_hdr)->plsp_id, 0);
+ CU_ASSERT_TRUE(((struct pcep_object_lsp *)obj_hdr)->flag_d);
+ CU_ASSERT_TRUE(((struct pcep_object_lsp *)obj_hdr)->flag_a);
+ CU_ASSERT_FALSE(((struct pcep_object_lsp *)obj_hdr)->flag_s);
+ CU_ASSERT_FALSE(((struct pcep_object_lsp *)obj_hdr)->flag_r);
+ CU_ASSERT_FALSE(((struct pcep_object_lsp *)obj_hdr)->flag_c);
+
+ /* LSP TLV */
+ CU_ASSERT_TRUE(pcep_obj_has_tlv(obj_hdr));
+ CU_ASSERT_EQUAL(obj_hdr->tlv_list->num_entries, 1);
+ struct pcep_object_tlv_header *tlv =
+ (struct pcep_object_tlv_header *)obj_hdr->tlv_list->head->data;
+ CU_ASSERT_EQUAL(tlv->type, PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME);
+ CU_ASSERT_EQUAL(tlv->encoded_tlv_length, 8);
+
+ /* Endpoints object */
+ node = node->next_node;
+ obj_hdr = (struct pcep_object_header *)node->data;
+ CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_ENDPOINTS);
+ CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_ENDPOINT_IPV4);
+ CU_ASSERT_EQUAL(obj_hdr->encoded_object_length,
+ pcep_object_get_length_by_hdr(obj_hdr));
+ CU_ASSERT_FALSE(pcep_obj_has_tlv(obj_hdr));
+
+ /* ERO object */
+ node = node->next_node;
+ obj_hdr = (struct pcep_object_header *)node->data;
+ CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_ERO);
+ CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_ERO);
+ CU_ASSERT_EQUAL(obj_hdr->encoded_object_length, 20);
+
+ /* ERO Subobjects */
+ double_linked_list *ero_subobj_list =
+ ((struct pcep_object_ro *)obj_hdr)->sub_objects;
+ CU_ASSERT_PTR_NOT_NULL(ero_subobj_list);
+ CU_ASSERT_EQUAL(ero_subobj_list->num_entries, 2);
+ double_linked_list_node *subobj_node = ero_subobj_list->head;
+ struct pcep_object_ro_subobj *subobj_hdr =
+ (struct pcep_object_ro_subobj *)subobj_node->data;
+ CU_ASSERT_EQUAL(subobj_hdr->ro_subobj_type, RO_SUBOBJ_TYPE_IPV4);
+ struct in_addr ero_subobj_ip;
+ inet_pton(AF_INET, "10.0.1.1", &ero_subobj_ip);
+ CU_ASSERT_EQUAL(
+ ((struct pcep_ro_subobj_ipv4 *)subobj_hdr)->ip_addr.s_addr,
+ ero_subobj_ip.s_addr);
+ CU_ASSERT_EQUAL(
+ ((struct pcep_ro_subobj_ipv4 *)subobj_hdr)->prefix_length, 24);
+
+ subobj_hdr =
+ (struct pcep_object_ro_subobj *)subobj_node->next_node->data;
+ CU_ASSERT_EQUAL(subobj_hdr->ro_subobj_type, RO_SUBOBJ_TYPE_IPV4);
+ inet_pton(AF_INET, "10.0.7.4", &ero_subobj_ip);
+ CU_ASSERT_EQUAL(
+ ((struct pcep_ro_subobj_ipv4 *)subobj_hdr)->ip_addr.s_addr,
+ ero_subobj_ip.s_addr);
+ CU_ASSERT_EQUAL(
+ ((struct pcep_ro_subobj_ipv4 *)subobj_hdr)->prefix_length, 24);
+
+ pcep_msg_free_message_list(msg_list);
+ close(fd);
+}
+
+
+void test_pcep_msg_read_pcep_initiate2()
+{
+ int fd = convert_hexstrs_to_binary(pcep_initiate2_hexbyte_strs,
+ pcep_initiate2_hexbyte_strs_length);
+ if(fd == -1){
+ CU_ASSERT_TRUE(fd>=0);
+ return;
+ }
+ double_linked_list *msg_list = pcep_msg_read(fd);
+ CU_ASSERT_PTR_NOT_NULL(msg_list);
+ CU_ASSERT_EQUAL(msg_list->num_entries, 1);
+
+ struct pcep_message *msg = (struct pcep_message *)msg_list->head->data;
+ CU_ASSERT_EQUAL(msg->obj_list->num_entries, 4);
+ CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_INITIATE);
+ CU_ASSERT_EQUAL(msg->encoded_message_length,
+ pcep_initiate2_hexbyte_strs_length);
+
+ /* Verify each of the object types */
+
+ /* SRP object */
+ double_linked_list_node *node = msg->obj_list->head;
+ struct pcep_object_header *obj_hdr =
+ (struct pcep_object_header *)node->data;
+ CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_SRP);
+ CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_SRP);
+ CU_ASSERT_EQUAL(obj_hdr->encoded_object_length, 20);
+ CU_ASSERT_TRUE(pcep_obj_has_tlv(obj_hdr));
+ /* TODO test the TLVs */
+
+ /* LSP object and its TLV*/
+ node = node->next_node;
+ obj_hdr = (struct pcep_object_header *)node->data;
+ CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_LSP);
+ CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_LSP);
+ CU_ASSERT_EQUAL(obj_hdr->encoded_object_length, 20);
+
+ /* LSP TLV */
+ CU_ASSERT_TRUE(pcep_obj_has_tlv(obj_hdr));
+ CU_ASSERT_EQUAL(obj_hdr->tlv_list->num_entries, 1);
+ struct pcep_object_tlv_header *tlv =
+ (struct pcep_object_tlv_header *)obj_hdr->tlv_list->head->data;
+ CU_ASSERT_EQUAL(tlv->type, PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME);
+ CU_ASSERT_EQUAL(tlv->encoded_tlv_length, 8);
+
+ /* Endpoints object */
+ node = node->next_node;
+ obj_hdr = (struct pcep_object_header *)node->data;
+ CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_ENDPOINTS);
+ CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_ENDPOINT_IPV4);
+ CU_ASSERT_EQUAL(obj_hdr->encoded_object_length,
+ pcep_object_get_length_by_hdr(obj_hdr));
+ CU_ASSERT_FALSE(pcep_obj_has_tlv(obj_hdr));
+
+ /* ERO object */
+ node = node->next_node;
+ obj_hdr = (struct pcep_object_header *)node->data;
+ CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_ERO);
+ CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_ERO);
+ CU_ASSERT_EQUAL(obj_hdr->encoded_object_length, 16);
+
+ /* ERO Subobjects */
+ double_linked_list *ero_subobj_list =
+ ((struct pcep_object_ro *)obj_hdr)->sub_objects;
+ CU_ASSERT_PTR_NOT_NULL(ero_subobj_list);
+ CU_ASSERT_EQUAL(ero_subobj_list->num_entries, 0);
+ double_linked_list_node *subobj_node = ero_subobj_list->head;
+ CU_ASSERT_PTR_NULL(subobj_node);
+ /* We no longer support draft07 SR sub-object type=5, and only support
+ type=36 struct pcep_object_ro_subobj *subobj_hdr = (struct
+ pcep_object_ro_subobj *) subobj_node->data;
+ CU_ASSERT_EQUAL(subobj_hdr->ro_subobj_type, RO_SUBOBJ_TYPE_SR);
+ struct pcep_ro_subobj_sr *subobj_sr = (struct pcep_ro_subobj_sr *)
+ subobj_hdr; CU_ASSERT_EQUAL(subobj_sr->nai_type,
+ PCEP_SR_SUBOBJ_NAI_IPV4_NODE); CU_ASSERT_TRUE(subobj_sr->flag_m);
+ CU_ASSERT_FALSE(subobj_sr->flag_c);
+ CU_ASSERT_FALSE(subobj_sr->flag_s);
+ CU_ASSERT_FALSE(subobj_sr->flag_f);
+ CU_ASSERT_EQUAL(subobj_sr->sid, 65576960);
+ CU_ASSERT_EQUAL(*((uint32_t *) subobj_sr->nai_list->head->data),
+ 0x01010101);
+ */
+
+ pcep_msg_free_message_list(msg_list);
+ close(fd);
+}
+
+void test_pcep_msg_read_pcep_open()
+{
+ int fd = convert_hexstrs_to_binary(pcep_open_odl_hexbyte_strs,
+ pcep_open_hexbyte_strs_length);
+ if(fd == -1){
+ CU_ASSERT_TRUE(fd>=0);
+ return;
+ }
+ double_linked_list *msg_list = pcep_msg_read(fd);
+ CU_ASSERT_PTR_NOT_NULL(msg_list);
+ CU_ASSERT_EQUAL(msg_list->num_entries, 1);
+
+ struct pcep_message *msg = (struct pcep_message *)msg_list->head->data;
+ CU_ASSERT_EQUAL(msg->obj_list->num_entries, 1);
+ CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_OPEN);
+ CU_ASSERT_EQUAL(msg->encoded_message_length,
+ pcep_open_hexbyte_strs_length);
+
+ /* Verify the Open message */
+ struct pcep_object_header *obj_hdr =
+ (struct pcep_object_header *)msg->obj_list->head->data;
+ CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_OPEN);
+ CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_OPEN);
+ CU_ASSERT_EQUAL(obj_hdr->encoded_object_length, 24);
+ CU_ASSERT_TRUE(pcep_obj_has_tlv(obj_hdr));
+
+ /* Open TLV: Stateful PCE Capability */
+ CU_ASSERT_EQUAL(obj_hdr->tlv_list->num_entries, 2);
+ double_linked_list_node *tlv_node = obj_hdr->tlv_list->head;
+ struct pcep_object_tlv_header *tlv =
+ (struct pcep_object_tlv_header *)tlv_node->data;
+ CU_ASSERT_EQUAL(tlv->type, PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY);
+ CU_ASSERT_EQUAL(tlv->encoded_tlv_length, 4);
+
+ /* Open TLV: SR PCE Capability */
+ tlv_node = tlv_node->next_node;
+ tlv = (struct pcep_object_tlv_header *)tlv_node->data;
+ CU_ASSERT_EQUAL(tlv->type, PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY);
+ CU_ASSERT_EQUAL(tlv->encoded_tlv_length, 4);
+
+ pcep_msg_free_message_list(msg_list);
+ close(fd);
+}
+
+void test_pcep_msg_read_pcep_update()
+{
+ int fd = convert_hexstrs_to_binary(pcep_update_hexbyte_strs,
+ pcep_update_hexbyte_strs_length);
+ if(fd == -1){
+ CU_ASSERT_TRUE(fd>=0);
+ return;
+ }
+ double_linked_list *msg_list = pcep_msg_read(fd);
+ CU_ASSERT_PTR_NOT_NULL(msg_list);
+ CU_ASSERT_EQUAL(msg_list->num_entries, 1);
+
+ struct pcep_message *msg = (struct pcep_message *)msg_list->head->data;
+ CU_ASSERT_EQUAL(msg->obj_list->num_entries, 3);
+
+ CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_UPDATE);
+ CU_ASSERT_EQUAL(msg->encoded_message_length,
+ pcep_update_hexbyte_strs_length);
+
+ /* Verify each of the object types */
+
+ double_linked_list_node *node = msg->obj_list->head;
+
+ /* SRP object */
+ struct pcep_object_header *obj_hdr =
+ (struct pcep_object_header *)node->data;
+ CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_SRP);
+ CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_SRP);
+ CU_ASSERT_EQUAL(obj_hdr->encoded_object_length, 20);
+ CU_ASSERT_TRUE(pcep_obj_has_tlv(obj_hdr));
+
+ /* SRP TLV */
+ CU_ASSERT_EQUAL(obj_hdr->tlv_list->num_entries, 1);
+ struct pcep_object_tlv_header *tlv =
+ (struct pcep_object_tlv_header *)obj_hdr->tlv_list->head->data;
+ CU_ASSERT_EQUAL(tlv->type, PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE);
+ CU_ASSERT_EQUAL(tlv->encoded_tlv_length, 4);
+ /* TODO verify the path setup type */
+
+ /* LSP object */
+ node = node->next_node;
+ obj_hdr = (struct pcep_object_header *)node->data;
+ CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_LSP);
+ CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_LSP);
+ CU_ASSERT_EQUAL(obj_hdr->encoded_object_length,
+ pcep_object_get_length_by_hdr(obj_hdr));
+ CU_ASSERT_FALSE(pcep_obj_has_tlv(obj_hdr));
+
+ /* ERO object */
+ node = node->next_node;
+ obj_hdr = (struct pcep_object_header *)node->data;
+ CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_ERO);
+ CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_ERO);
+ CU_ASSERT_EQUAL(obj_hdr->encoded_object_length, 16);
+
+ /* ERO Subobjects */
+ double_linked_list *ero_subobj_list =
+ ((struct pcep_object_ro *)obj_hdr)->sub_objects;
+ CU_ASSERT_PTR_NOT_NULL(ero_subobj_list);
+ CU_ASSERT_EQUAL(ero_subobj_list->num_entries, 0);
+ double_linked_list_node *subobj_node = ero_subobj_list->head;
+ CU_ASSERT_PTR_NULL(subobj_node);
+ /* We no longer support draft07 SR sub-object type=5, and only support
+ type=36 struct pcep_object_ro_subobj *subobj_hdr = (struct
+ pcep_object_ro_subobj *) subobj_node->data;
+ CU_ASSERT_EQUAL(subobj_hdr->ro_subobj_type, RO_SUBOBJ_TYPE_SR);
+ struct pcep_ro_subobj_sr *subobj_sr = (struct pcep_ro_subobj_sr *)
+ subobj_hdr; CU_ASSERT_EQUAL(subobj_sr->nai_type,
+ PCEP_SR_SUBOBJ_NAI_IPV4_NODE); CU_ASSERT_TRUE(subobj_sr->flag_m);
+ CU_ASSERT_FALSE(subobj_sr->flag_c);
+ CU_ASSERT_FALSE(subobj_sr->flag_s);
+ CU_ASSERT_FALSE(subobj_sr->flag_f);
+ CU_ASSERT_EQUAL(subobj_sr->sid, 65576960);
+ CU_ASSERT_EQUAL(*((uint32_t *) subobj_sr->nai_list->head->data),
+ 0x01010101);
+ */
+
+ pcep_msg_free_message_list(msg_list);
+ close(fd);
+}
+
+void test_pcep_msg_read_pcep_open_initiate()
+{
+ int fd = convert_hexstrs_to_binary(
+ pcep_open_initiate_odl_hexbyte_strs,
+ pcep_open_initiate_hexbyte_strs_length);
+ if(fd == -1){
+ CU_ASSERT_TRUE(fd>=0);
+ return;
+ }
+ double_linked_list *msg_list = pcep_msg_read(fd);
+ CU_ASSERT_PTR_NOT_NULL(msg_list);
+ CU_ASSERT_EQUAL(msg_list->num_entries, 2);
+
+ struct pcep_message *msg = (struct pcep_message *)msg_list->head->data;
+ CU_ASSERT_EQUAL(msg->obj_list->num_entries, 1);
+ CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_OPEN);
+ CU_ASSERT_EQUAL(msg->encoded_message_length,
+ pcep_open_hexbyte_strs_length);
+
+ msg = (struct pcep_message *)msg_list->head->next_node->data;
+ CU_ASSERT_EQUAL(msg->obj_list->num_entries, 4);
+ CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_INITIATE);
+ CU_ASSERT_EQUAL(msg->encoded_message_length,
+ pcep_initiate2_hexbyte_strs_length);
+
+ pcep_msg_free_message_list(msg_list);
+ close(fd);
+}
+
+void test_pcep_msg_read_pcep_open_cisco_pce()
+{
+ int fd = convert_hexstrs_to_binary(
+ pcep_open_cisco_pce_hexbyte_strs,
+ pcep_open_cisco_pce_hexbyte_strs_length);
+ if(fd == -1){
+ CU_ASSERT_TRUE(fd>=0);
+ return;
+ }
+ double_linked_list *msg_list = pcep_msg_read(fd);
+ CU_ASSERT_PTR_NOT_NULL(msg_list);
+ CU_ASSERT_EQUAL(msg_list->num_entries, 1);
+
+ struct pcep_message *msg = (struct pcep_message *)msg_list->head->data;
+ CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_OPEN);
+ CU_ASSERT_EQUAL(msg->encoded_message_length,
+ pcep_open_hexbyte_strs_length);
+ CU_ASSERT_EQUAL(msg->obj_list->num_entries, 1);
+
+ /* Open object */
+ struct pcep_object_open *open =
+ (struct pcep_object_open *)msg->obj_list->head->data;
+ CU_ASSERT_EQUAL(open->header.object_class, PCEP_OBJ_CLASS_OPEN);
+ CU_ASSERT_EQUAL(open->header.object_type, PCEP_OBJ_TYPE_OPEN);
+ CU_ASSERT_EQUAL(open->header.encoded_object_length, 24);
+ CU_ASSERT_EQUAL(open->open_deadtimer, 120);
+ CU_ASSERT_EQUAL(open->open_keepalive, 60);
+ CU_ASSERT_EQUAL(open->open_sid, 0);
+ CU_ASSERT_EQUAL(open->open_version, 1);
+ CU_ASSERT_PTR_NOT_NULL(open->header.tlv_list);
+ CU_ASSERT_EQUAL(open->header.tlv_list->num_entries, 2);
+
+ /* Stateful PCE Capability TLV */
+ double_linked_list_node *tlv_node = open->header.tlv_list->head;
+ struct pcep_object_tlv_stateful_pce_capability *pce_cap_tlv =
+ (struct pcep_object_tlv_stateful_pce_capability *)
+ tlv_node->data;
+ CU_ASSERT_EQUAL(pce_cap_tlv->header.type,
+ PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY);
+ CU_ASSERT_EQUAL(pce_cap_tlv->header.encoded_tlv_length, 4);
+ CU_ASSERT_TRUE(pce_cap_tlv->flag_u_lsp_update_capability);
+ CU_ASSERT_TRUE(pce_cap_tlv->flag_i_lsp_instantiation_capability);
+ CU_ASSERT_FALSE(pce_cap_tlv->flag_s_include_db_version);
+ CU_ASSERT_FALSE(pce_cap_tlv->flag_t_triggered_resync);
+ CU_ASSERT_FALSE(pce_cap_tlv->flag_d_delta_lsp_sync);
+ CU_ASSERT_FALSE(pce_cap_tlv->flag_f_triggered_initial_sync);
+
+ /* SR PCE Capability TLV */
+ tlv_node = tlv_node->next_node;
+ struct pcep_object_tlv_sr_pce_capability *sr_pce_cap_tlv =
+ (struct pcep_object_tlv_sr_pce_capability *)tlv_node->data;
+ CU_ASSERT_EQUAL(sr_pce_cap_tlv->header.type,
+ PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY);
+ CU_ASSERT_EQUAL(sr_pce_cap_tlv->header.encoded_tlv_length, 4);
+ CU_ASSERT_FALSE(sr_pce_cap_tlv->flag_n);
+ CU_ASSERT_FALSE(sr_pce_cap_tlv->flag_x);
+ CU_ASSERT_EQUAL(sr_pce_cap_tlv->max_sid_depth, 10);
+
+ pcep_msg_free_message_list(msg_list);
+ close(fd);
+}
+
+void test_pcep_msg_read_pcep_update_cisco_pce()
+{
+ int fd = convert_hexstrs_to_binary(
+ pcep_update_cisco_pce_hexbyte_strs,
+ pcep_update_cisco_pce_hexbyte_strs_length);
+ if(fd == -1){
+ CU_ASSERT_TRUE(fd>=0);
+ return;
+ }
+ double_linked_list *msg_list = pcep_msg_read(fd);
+ CU_ASSERT_PTR_NOT_NULL(msg_list);
+ CU_ASSERT_EQUAL(msg_list->num_entries, 1);
+
+ struct pcep_message *msg = (struct pcep_message *)msg_list->head->data;
+ CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_UPDATE);
+ CU_ASSERT_EQUAL(msg->encoded_message_length,
+ pcep_update_cisco_pce_hexbyte_strs_length);
+ CU_ASSERT_EQUAL(msg->obj_list->num_entries, 4);
+
+ /* SRP object */
+ double_linked_list_node *obj_node = msg->obj_list->head;
+ struct pcep_object_srp *srp = (struct pcep_object_srp *)obj_node->data;
+ CU_ASSERT_EQUAL(srp->header.object_class, PCEP_OBJ_CLASS_SRP);
+ CU_ASSERT_EQUAL(srp->header.object_type, PCEP_OBJ_TYPE_SRP);
+ CU_ASSERT_EQUAL(srp->header.encoded_object_length, 20);
+ CU_ASSERT_PTR_NOT_NULL(srp->header.tlv_list);
+ CU_ASSERT_EQUAL(srp->header.tlv_list->num_entries, 1);
+ CU_ASSERT_EQUAL(srp->srp_id_number, 1);
+ CU_ASSERT_FALSE(srp->flag_lsp_remove);
+
+ /* SRP Path Setup Type TLV */
+ double_linked_list_node *tlv_node = srp->header.tlv_list->head;
+ struct pcep_object_tlv_path_setup_type *pst_tlv =
+ (struct pcep_object_tlv_path_setup_type *)tlv_node->data;
+ CU_ASSERT_EQUAL(pst_tlv->header.type,
+ PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE);
+ CU_ASSERT_EQUAL(pst_tlv->header.encoded_tlv_length, 4);
+ CU_ASSERT_EQUAL(pst_tlv->path_setup_type, 1);
+
+ /* LSP object */
+ obj_node = obj_node->next_node;
+ struct pcep_object_lsp *lsp = (struct pcep_object_lsp *)obj_node->data;
+ CU_ASSERT_EQUAL(lsp->header.object_class, PCEP_OBJ_CLASS_LSP);
+ CU_ASSERT_EQUAL(lsp->header.object_type, PCEP_OBJ_TYPE_LSP);
+ CU_ASSERT_EQUAL(lsp->header.encoded_object_length, 24);
+ CU_ASSERT_PTR_NOT_NULL(lsp->header.tlv_list);
+ CU_ASSERT_EQUAL(lsp->header.tlv_list->num_entries, 1);
+ CU_ASSERT_EQUAL(lsp->plsp_id, 524303);
+ CU_ASSERT_EQUAL(lsp->operational_status, PCEP_LSP_OPERATIONAL_DOWN);
+ CU_ASSERT_TRUE(lsp->flag_a);
+ CU_ASSERT_TRUE(lsp->flag_c);
+ CU_ASSERT_TRUE(lsp->flag_d);
+ CU_ASSERT_FALSE(lsp->flag_r);
+ CU_ASSERT_FALSE(lsp->flag_s);
+
+ /* LSP Vendor Info TLV */
+ tlv_node = lsp->header.tlv_list->head;
+ struct pcep_object_tlv_vendor_info *vendor_tlv =
+ (struct pcep_object_tlv_vendor_info *)tlv_node->data;
+ CU_ASSERT_EQUAL(vendor_tlv->header.type, PCEP_OBJ_TLV_TYPE_VENDOR_INFO);
+ CU_ASSERT_EQUAL(vendor_tlv->header.encoded_tlv_length, 12);
+ CU_ASSERT_EQUAL(vendor_tlv->enterprise_number, 9);
+ CU_ASSERT_EQUAL(vendor_tlv->enterprise_specific_info, 0x00030004);
+
+ /* ERO object */
+ obj_node = obj_node->next_node;
+ struct pcep_object_ro *ero = (struct pcep_object_ro *)obj_node->data;
+ CU_ASSERT_EQUAL(ero->header.object_class, PCEP_OBJ_CLASS_ERO);
+ CU_ASSERT_EQUAL(ero->header.object_type, PCEP_OBJ_TYPE_ERO);
+ CU_ASSERT_EQUAL(ero->header.encoded_object_length, 40);
+ CU_ASSERT_PTR_NULL(ero->header.tlv_list);
+ CU_ASSERT_PTR_NOT_NULL(ero->sub_objects);
+ CU_ASSERT_EQUAL(ero->sub_objects->num_entries, 3);
+
+ /* ERO Subobjects */
+ double_linked_list_node *ero_subobj_node = ero->sub_objects->head;
+ struct pcep_ro_subobj_sr *sr_subobj_ipv4_node =
+ (struct pcep_ro_subobj_sr *)ero_subobj_node->data;
+ CU_ASSERT_EQUAL(sr_subobj_ipv4_node->ro_subobj.ro_subobj_type,
+ RO_SUBOBJ_TYPE_SR);
+ CU_ASSERT_FALSE(sr_subobj_ipv4_node->ro_subobj.flag_subobj_loose_hop);
+ CU_ASSERT_EQUAL(sr_subobj_ipv4_node->nai_type,
+ PCEP_SR_SUBOBJ_NAI_IPV4_NODE);
+ CU_ASSERT_TRUE(sr_subobj_ipv4_node->flag_m);
+ CU_ASSERT_FALSE(sr_subobj_ipv4_node->flag_c);
+ CU_ASSERT_FALSE(sr_subobj_ipv4_node->flag_f);
+ CU_ASSERT_FALSE(sr_subobj_ipv4_node->flag_s);
+ CU_ASSERT_EQUAL(sr_subobj_ipv4_node->sid, 73748480);
+ CU_ASSERT_EQUAL(
+ *((uint32_t *)sr_subobj_ipv4_node->nai_list->head->data),
+ htonl(0x0a0a0a05));
+
+ ero_subobj_node = ero_subobj_node->next_node;
+ sr_subobj_ipv4_node = (struct pcep_ro_subobj_sr *)ero_subobj_node->data;
+ CU_ASSERT_EQUAL(sr_subobj_ipv4_node->ro_subobj.ro_subobj_type,
+ RO_SUBOBJ_TYPE_SR);
+ CU_ASSERT_FALSE(sr_subobj_ipv4_node->ro_subobj.flag_subobj_loose_hop);
+ CU_ASSERT_EQUAL(sr_subobj_ipv4_node->nai_type,
+ PCEP_SR_SUBOBJ_NAI_IPV4_NODE);
+ CU_ASSERT_TRUE(sr_subobj_ipv4_node->flag_m);
+ CU_ASSERT_FALSE(sr_subobj_ipv4_node->flag_c);
+ CU_ASSERT_FALSE(sr_subobj_ipv4_node->flag_f);
+ CU_ASSERT_FALSE(sr_subobj_ipv4_node->flag_s);
+ CU_ASSERT_EQUAL(sr_subobj_ipv4_node->sid, 73736192);
+ CU_ASSERT_EQUAL(
+ *((uint32_t *)sr_subobj_ipv4_node->nai_list->head->data),
+ htonl(0x0a0a0a02));
+
+ ero_subobj_node = ero_subobj_node->next_node;
+ sr_subobj_ipv4_node = (struct pcep_ro_subobj_sr *)ero_subobj_node->data;
+ CU_ASSERT_EQUAL(sr_subobj_ipv4_node->ro_subobj.ro_subobj_type,
+ RO_SUBOBJ_TYPE_SR);
+ CU_ASSERT_FALSE(sr_subobj_ipv4_node->ro_subobj.flag_subobj_loose_hop);
+ CU_ASSERT_EQUAL(sr_subobj_ipv4_node->nai_type,
+ PCEP_SR_SUBOBJ_NAI_IPV4_NODE);
+ CU_ASSERT_TRUE(sr_subobj_ipv4_node->flag_m);
+ CU_ASSERT_FALSE(sr_subobj_ipv4_node->flag_c);
+ CU_ASSERT_FALSE(sr_subobj_ipv4_node->flag_f);
+ CU_ASSERT_FALSE(sr_subobj_ipv4_node->flag_s);
+ CU_ASSERT_EQUAL(sr_subobj_ipv4_node->sid, 73732096);
+ CU_ASSERT_EQUAL(
+ *((uint32_t *)sr_subobj_ipv4_node->nai_list->head->data),
+ htonl(0x0a0a0a01));
+
+ /* Metric object */
+ obj_node = obj_node->next_node;
+ struct pcep_object_metric *metric =
+ (struct pcep_object_metric *)obj_node->data;
+ CU_ASSERT_EQUAL(metric->header.object_class, PCEP_OBJ_CLASS_METRIC);
+ CU_ASSERT_EQUAL(metric->header.object_type, PCEP_OBJ_TYPE_METRIC);
+ CU_ASSERT_EQUAL(metric->header.encoded_object_length, 12);
+ CU_ASSERT_PTR_NULL(metric->header.tlv_list);
+ CU_ASSERT_FALSE(metric->flag_b);
+ CU_ASSERT_FALSE(metric->flag_c);
+ CU_ASSERT_EQUAL(metric->type, PCEP_METRIC_TE);
+ CU_ASSERT_EQUAL(metric->value, 30.0);
+
+ pcep_msg_free_message_list(msg_list);
+ close(fd);
+}
+
+void test_pcep_msg_read_pcep_report_cisco_pcc()
+{
+ int fd = convert_hexstrs_to_binary(
+ pcep_report_cisco_pcc_hexbyte_strs,
+ pcep_report_cisco_pcc_hexbyte_strs_length);
+ if(fd == -1){
+ CU_ASSERT_TRUE(fd>=0);
+ return;
+ }
+ double_linked_list *msg_list = pcep_msg_read(fd);
+ CU_ASSERT_PTR_NOT_NULL(msg_list);
+ CU_ASSERT_EQUAL(msg_list->num_entries, 1);
+
+ struct pcep_message *msg = (struct pcep_message *)msg_list->head->data;
+ CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_REPORT);
+ CU_ASSERT_EQUAL(msg->encoded_message_length,
+ pcep_report_cisco_pcc_hexbyte_strs_length);
+ CU_ASSERT_EQUAL(msg->obj_list->num_entries, 8);
+
+ /* SRP object */
+ double_linked_list_node *obj_node = msg->obj_list->head;
+ struct pcep_object_srp *srp = (struct pcep_object_srp *)obj_node->data;
+ CU_ASSERT_EQUAL(srp->header.object_class, PCEP_OBJ_CLASS_SRP);
+ CU_ASSERT_EQUAL(srp->header.object_type, PCEP_OBJ_TYPE_SRP);
+ CU_ASSERT_EQUAL(srp->header.encoded_object_length, 20);
+ CU_ASSERT_PTR_NOT_NULL(srp->header.tlv_list);
+ CU_ASSERT_EQUAL(srp->header.tlv_list->num_entries, 1);
+ CU_ASSERT_EQUAL(srp->srp_id_number, 0);
+ CU_ASSERT_FALSE(srp->flag_lsp_remove);
+
+ /* SRP Path Setup Type TLV */
+ double_linked_list_node *tlv_node = srp->header.tlv_list->head;
+ struct pcep_object_tlv_path_setup_type *pst_tlv =
+ (struct pcep_object_tlv_path_setup_type *)tlv_node->data;
+ CU_ASSERT_EQUAL(pst_tlv->header.type,
+ PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE);
+ CU_ASSERT_EQUAL(pst_tlv->header.encoded_tlv_length, 4);
+ CU_ASSERT_EQUAL(pst_tlv->path_setup_type, 1);
+
+ /* LSP object */
+ obj_node = obj_node->next_node;
+ struct pcep_object_lsp *lsp = (struct pcep_object_lsp *)obj_node->data;
+ CU_ASSERT_EQUAL(lsp->header.object_class, PCEP_OBJ_CLASS_LSP);
+ CU_ASSERT_EQUAL(lsp->header.object_type, PCEP_OBJ_TYPE_LSP);
+ CU_ASSERT_EQUAL(lsp->header.encoded_object_length, 60);
+ CU_ASSERT_PTR_NOT_NULL(lsp->header.tlv_list);
+ /* The TLV with ID 65505 is not recognized, and its not in the list */
+ CU_ASSERT_EQUAL(lsp->header.tlv_list->num_entries, 2);
+ CU_ASSERT_EQUAL(lsp->plsp_id, 524303);
+ CU_ASSERT_EQUAL(lsp->operational_status, PCEP_LSP_OPERATIONAL_DOWN);
+ CU_ASSERT_TRUE(lsp->flag_a);
+ CU_ASSERT_TRUE(lsp->flag_d);
+ CU_ASSERT_FALSE(lsp->flag_c);
+ CU_ASSERT_FALSE(lsp->flag_r);
+ CU_ASSERT_FALSE(lsp->flag_s);
+
+ /* LSP IPv4 LSP Identifier TLV */
+ tlv_node = lsp->header.tlv_list->head;
+ struct pcep_object_tlv_ipv4_lsp_identifier *ipv4_lsp_id =
+ (struct pcep_object_tlv_ipv4_lsp_identifier *)tlv_node->data;
+ CU_ASSERT_EQUAL(ipv4_lsp_id->header.type,
+ PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS);
+ CU_ASSERT_EQUAL(ipv4_lsp_id->header.encoded_tlv_length, 16);
+ CU_ASSERT_EQUAL(ipv4_lsp_id->ipv4_tunnel_sender.s_addr,
+ htonl(0x0a0a0a06));
+ CU_ASSERT_EQUAL(ipv4_lsp_id->ipv4_tunnel_endpoint.s_addr,
+ htonl(0x0a0a0a01));
+ CU_ASSERT_EQUAL(ipv4_lsp_id->extended_tunnel_id.s_addr,
+ htonl(0x0a0a0a06));
+ CU_ASSERT_EQUAL(ipv4_lsp_id->tunnel_id, 15);
+ CU_ASSERT_EQUAL(ipv4_lsp_id->lsp_id, 2);
+
+ /* LSP Symbolic Path Name TLV */
+ tlv_node = tlv_node->next_node;
+ struct pcep_object_tlv_symbolic_path_name *sym_path_name =
+ (struct pcep_object_tlv_symbolic_path_name *)tlv_node->data;
+ CU_ASSERT_EQUAL(sym_path_name->header.type,
+ PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME);
+ CU_ASSERT_EQUAL(sym_path_name->header.encoded_tlv_length, 13);
+ CU_ASSERT_EQUAL(sym_path_name->symbolic_path_name_length, 13);
+ CU_ASSERT_EQUAL(
+ strncmp(sym_path_name->symbolic_path_name, "cfg_R6-to-R1", 13),
+ 0);
+
+ /* ERO object */
+ obj_node = obj_node->next_node;
+ struct pcep_object_ro *ero = (struct pcep_object_ro *)obj_node->data;
+ CU_ASSERT_EQUAL(ero->header.object_class, PCEP_OBJ_CLASS_ERO);
+ CU_ASSERT_EQUAL(ero->header.object_type, PCEP_OBJ_TYPE_ERO);
+ CU_ASSERT_EQUAL(ero->header.encoded_object_length, 4);
+ CU_ASSERT_PTR_NULL(ero->header.tlv_list);
+ CU_ASSERT_PTR_NOT_NULL(ero->sub_objects);
+ CU_ASSERT_EQUAL(ero->sub_objects->num_entries, 0);
+
+ /* LSPA object */
+ obj_node = obj_node->next_node;
+ struct pcep_object_lspa *lspa =
+ (struct pcep_object_lspa *)obj_node->data;
+ CU_ASSERT_EQUAL(lspa->header.object_class, PCEP_OBJ_CLASS_LSPA);
+ CU_ASSERT_EQUAL(lspa->header.object_type, PCEP_OBJ_TYPE_LSPA);
+ CU_ASSERT_EQUAL(lspa->header.encoded_object_length, 20);
+ CU_ASSERT_PTR_NULL(lspa->header.tlv_list);
+ CU_ASSERT_TRUE(lspa->flag_local_protection);
+ CU_ASSERT_EQUAL(lspa->holding_priority, 7);
+ CU_ASSERT_EQUAL(lspa->setup_priority, 7);
+ CU_ASSERT_EQUAL(lspa->lspa_include_all, 0);
+ CU_ASSERT_EQUAL(lspa->lspa_include_any, 0);
+ CU_ASSERT_EQUAL(lspa->lspa_exclude_any, 0);
+
+ /* Bandwidth object 1 */
+ obj_node = obj_node->next_node;
+ struct pcep_object_bandwidth *bandwidth =
+ (struct pcep_object_bandwidth *)obj_node->data;
+ CU_ASSERT_EQUAL(bandwidth->header.object_class,
+ PCEP_OBJ_CLASS_BANDWIDTH);
+ CU_ASSERT_EQUAL(bandwidth->header.object_type,
+ PCEP_OBJ_TYPE_BANDWIDTH_REQ);
+ CU_ASSERT_EQUAL(bandwidth->header.encoded_object_length, 8);
+ CU_ASSERT_EQUAL(bandwidth->bandwidth, 0);
+
+ /* Bandwidth object 2 */
+ obj_node = obj_node->next_node;
+ bandwidth = (struct pcep_object_bandwidth *)obj_node->data;
+ CU_ASSERT_EQUAL(bandwidth->header.object_class,
+ PCEP_OBJ_CLASS_BANDWIDTH);
+ CU_ASSERT_EQUAL(bandwidth->header.object_type,
+ PCEP_OBJ_TYPE_BANDWIDTH_CISCO);
+ CU_ASSERT_EQUAL(bandwidth->header.encoded_object_length, 8);
+ CU_ASSERT_EQUAL(bandwidth->bandwidth, 0);
+
+ /* Metric object 1 */
+ obj_node = obj_node->next_node;
+ struct pcep_object_metric *metric =
+ (struct pcep_object_metric *)obj_node->data;
+ CU_ASSERT_EQUAL(metric->header.object_class, PCEP_OBJ_CLASS_METRIC);
+ CU_ASSERT_EQUAL(metric->header.object_type, PCEP_OBJ_TYPE_METRIC);
+ CU_ASSERT_EQUAL(metric->header.encoded_object_length, 12);
+ CU_ASSERT_PTR_NULL(metric->header.tlv_list);
+ CU_ASSERT_FALSE(metric->flag_b);
+ CU_ASSERT_FALSE(metric->flag_c);
+ CU_ASSERT_EQUAL(metric->type, PCEP_METRIC_TE);
+ CU_ASSERT_EQUAL(metric->value, 0);
+
+ /* Metric object 2 */
+ obj_node = obj_node->next_node;
+ metric = (struct pcep_object_metric *)obj_node->data;
+ CU_ASSERT_EQUAL(metric->header.object_class, PCEP_OBJ_CLASS_METRIC);
+ CU_ASSERT_EQUAL(metric->header.object_type, PCEP_OBJ_TYPE_METRIC);
+ CU_ASSERT_EQUAL(metric->header.encoded_object_length, 12);
+ CU_ASSERT_PTR_NULL(metric->header.tlv_list);
+ CU_ASSERT_TRUE(metric->flag_b);
+ CU_ASSERT_FALSE(metric->flag_c);
+ CU_ASSERT_EQUAL(metric->type, PCEP_METRIC_AGGREGATE_BW);
+ CU_ASSERT_EQUAL(metric->value, 16.0);
+
+ pcep_msg_free_message_list(msg_list);
+ close(fd);
+}
+
+void test_pcep_msg_read_pcep_initiate_cisco_pcc()
+{
+ int fd = convert_hexstrs_to_binary(
+ pcep_initiate_cisco_pcc_hexbyte_strs,
+ pcep_initiate_cisco_pcc_hexbyte_strs_length);
+ if(fd == -1){
+ CU_ASSERT_TRUE(fd>=0);
+ return;
+ }
+ double_linked_list *msg_list = pcep_msg_read(fd);
+ CU_ASSERT_PTR_NOT_NULL(msg_list);
+ CU_ASSERT_EQUAL(msg_list->num_entries, 1);
+
+ struct pcep_message *msg = (struct pcep_message *)msg_list->head->data;
+ CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_INITIATE);
+ CU_ASSERT_EQUAL(msg->encoded_message_length,
+ pcep_initiate_cisco_pcc_hexbyte_strs_length);
+ CU_ASSERT_EQUAL(msg->obj_list->num_entries, 6);
+
+ /* SRP object */
+ double_linked_list_node *obj_node = msg->obj_list->head;
+ struct pcep_object_srp *srp = (struct pcep_object_srp *)obj_node->data;
+ CU_ASSERT_EQUAL(srp->header.object_class, PCEP_OBJ_CLASS_SRP);
+ CU_ASSERT_EQUAL(srp->header.object_type, PCEP_OBJ_TYPE_SRP);
+ CU_ASSERT_EQUAL(srp->header.encoded_object_length, 20);
+ CU_ASSERT_PTR_NOT_NULL(srp->header.tlv_list);
+ CU_ASSERT_EQUAL(srp->header.tlv_list->num_entries, 1);
+ CU_ASSERT_EQUAL(srp->srp_id_number, 1);
+ CU_ASSERT_FALSE(srp->flag_lsp_remove);
+
+ /* LSP object */
+ obj_node = obj_node->next_node;
+ struct pcep_object_lsp *lsp = (struct pcep_object_lsp *)obj_node->data;
+ CU_ASSERT_EQUAL(lsp->header.object_class, PCEP_OBJ_CLASS_LSP);
+ CU_ASSERT_EQUAL(lsp->header.object_type, PCEP_OBJ_TYPE_LSP);
+ CU_ASSERT_EQUAL(lsp->header.encoded_object_length, 48);
+ CU_ASSERT_PTR_NOT_NULL(lsp->header.tlv_list);
+ CU_ASSERT_EQUAL(lsp->header.tlv_list->num_entries, 2);
+ CU_ASSERT_EQUAL(lsp->plsp_id, 0);
+ CU_ASSERT_EQUAL(lsp->operational_status, PCEP_LSP_OPERATIONAL_DOWN);
+ CU_ASSERT_TRUE(lsp->flag_a);
+ CU_ASSERT_TRUE(lsp->flag_d);
+ CU_ASSERT_TRUE(lsp->flag_c);
+ CU_ASSERT_FALSE(lsp->flag_r);
+ CU_ASSERT_FALSE(lsp->flag_s);
+
+ /* Endpoint object */
+ obj_node = obj_node->next_node;
+ struct pcep_object_endpoints_ipv4 *endpoint =
+ (struct pcep_object_endpoints_ipv4 *)obj_node->data;
+ CU_ASSERT_EQUAL(endpoint->header.object_class,
+ PCEP_OBJ_CLASS_ENDPOINTS);
+ CU_ASSERT_EQUAL(endpoint->header.object_type,
+ PCEP_OBJ_TYPE_ENDPOINT_IPV4);
+ CU_ASSERT_EQUAL(endpoint->header.encoded_object_length, 12);
+ CU_ASSERT_PTR_NULL(endpoint->header.tlv_list);
+ CU_ASSERT_EQUAL(endpoint->src_ipv4.s_addr, htonl(0x0a0a0a0a));
+ CU_ASSERT_EQUAL(endpoint->dst_ipv4.s_addr, htonl(0x0a0a0a04));
+
+ /* Inter-Layer object */
+ obj_node = obj_node->next_node;
+ struct pcep_object_inter_layer *inter_layer =
+ (struct pcep_object_inter_layer *)obj_node->data;
+ CU_ASSERT_EQUAL(inter_layer->header.object_class,
+ PCEP_OBJ_CLASS_INTER_LAYER);
+ CU_ASSERT_EQUAL(inter_layer->header.object_type,
+ PCEP_OBJ_TYPE_INTER_LAYER);
+ CU_ASSERT_EQUAL(inter_layer->header.encoded_object_length, 8);
+ CU_ASSERT_PTR_NULL(inter_layer->header.tlv_list);
+ CU_ASSERT_TRUE(inter_layer->flag_i);
+ CU_ASSERT_FALSE(inter_layer->flag_m);
+ CU_ASSERT_TRUE(inter_layer->flag_t);
+
+ /* Switch-Layer object */
+ obj_node = obj_node->next_node;
+ struct pcep_object_switch_layer *switch_layer =
+ (struct pcep_object_switch_layer *)obj_node->data;
+ CU_ASSERT_EQUAL(switch_layer->header.object_class,
+ PCEP_OBJ_CLASS_SWITCH_LAYER);
+ CU_ASSERT_EQUAL(switch_layer->header.object_type,
+ PCEP_OBJ_TYPE_SWITCH_LAYER);
+ CU_ASSERT_EQUAL(switch_layer->header.encoded_object_length, 8);
+ CU_ASSERT_PTR_NULL(switch_layer->header.tlv_list);
+ CU_ASSERT_PTR_NOT_NULL(switch_layer->switch_layer_rows);
+ CU_ASSERT_EQUAL(switch_layer->switch_layer_rows->num_entries, 1);
+ struct pcep_object_switch_layer_row *switch_layer_row =
+ (struct pcep_object_switch_layer_row *)
+ switch_layer->switch_layer_rows->head->data;
+ CU_ASSERT_EQUAL(switch_layer_row->lsp_encoding_type, 0);
+ CU_ASSERT_EQUAL(switch_layer_row->switching_type, 0);
+ CU_ASSERT_FALSE(switch_layer_row->flag_i);
+
+ /* ERO object */
+ obj_node = obj_node->next_node;
+ struct pcep_object_ro *ero = (struct pcep_object_ro *)obj_node->data;
+ CU_ASSERT_EQUAL(ero->header.object_class, PCEP_OBJ_CLASS_ERO);
+ CU_ASSERT_EQUAL(ero->header.object_type, PCEP_OBJ_TYPE_ERO);
+ CU_ASSERT_EQUAL(ero->header.encoded_object_length, 4);
+ CU_ASSERT_PTR_NULL(ero->header.tlv_list);
+
+ pcep_msg_free_message_list(msg_list);
+ close(fd);
+}
+
+void test_validate_message_header()
+{
+ uint8_t pcep_message_invalid_version[] = {0x40, 0x01, 0x04, 0x00};
+ uint8_t pcep_message_invalid_flags[] = {0x22, 0x01, 0x04, 0x00};
+ uint8_t pcep_message_invalid_length[] = {0x20, 0x01, 0x00, 0x00};
+ uint8_t pcep_message_invalid_type[] = {0x20, 0xff, 0x04, 0x00};
+ uint8_t pcep_message_valid[] = {0x20, 0x01, 0x00, 0x04};
+
+ /* Verify invalid message header version */
+ CU_ASSERT_TRUE(
+ pcep_decode_validate_msg_header(pcep_message_invalid_version)
+ < 0);
+
+ /* Verify invalid message header flags */
+ CU_ASSERT_TRUE(
+ pcep_decode_validate_msg_header(pcep_message_invalid_flags)
+ < 0);
+
+ /* Verify invalid message header lengths */
+ CU_ASSERT_TRUE(
+ pcep_decode_validate_msg_header(pcep_message_invalid_length)
+ < 0);
+ pcep_message_invalid_length[3] = 0x05;
+ CU_ASSERT_TRUE(
+ pcep_decode_validate_msg_header(pcep_message_invalid_length)
+ < 0);
+
+ /* Verify invalid message header types */
+ CU_ASSERT_TRUE(
+ pcep_decode_validate_msg_header(pcep_message_invalid_type) < 0);
+ pcep_message_invalid_type[1] = 0x00;
+ CU_ASSERT_TRUE(
+ pcep_decode_validate_msg_header(pcep_message_invalid_type) < 0);
+
+ /* Verify a valid message header */
+ CU_ASSERT_EQUAL(pcep_decode_validate_msg_header(pcep_message_valid), 4);
+}
+
+/* Internal util function */
+struct pcep_message *create_message(uint8_t msg_type, uint8_t obj1_class,
+ uint8_t obj2_class, uint8_t obj3_class,
+ uint8_t obj4_class)
+{
+ struct pcep_message *msg =
+ pceplib_malloc(PCEPLIB_MESSAGES, sizeof(struct pcep_message));
+ msg->obj_list = dll_initialize();
+ msg->msg_header = pceplib_malloc(PCEPLIB_MESSAGES,
+ sizeof(struct pcep_message_header));
+ msg->msg_header->type = msg_type;
+ msg->encoded_message = NULL;
+
+ if (obj1_class > 0) {
+ struct pcep_object_header *obj_hdr = pceplib_malloc(
+ PCEPLIB_MESSAGES, sizeof(struct pcep_object_header));
+ obj_hdr->object_class = obj1_class;
+ obj_hdr->tlv_list = NULL;
+ dll_append(msg->obj_list, obj_hdr);
+ }
+
+ if (obj2_class > 0) {
+ struct pcep_object_header *obj_hdr = pceplib_malloc(
+ PCEPLIB_MESSAGES, sizeof(struct pcep_object_header));
+ obj_hdr->object_class = obj2_class;
+ obj_hdr->tlv_list = NULL;
+ dll_append(msg->obj_list, obj_hdr);
+ }
+
+ if (obj3_class > 0) {
+ struct pcep_object_header *obj_hdr = pceplib_malloc(
+ PCEPLIB_MESSAGES, sizeof(struct pcep_object_header));
+ obj_hdr->object_class = obj3_class;
+ obj_hdr->tlv_list = NULL;
+ dll_append(msg->obj_list, obj_hdr);
+ }
+
+ if (obj4_class > 0) {
+ struct pcep_object_header *obj_hdr = pceplib_malloc(
+ PCEPLIB_MESSAGES, sizeof(struct pcep_object_header));
+ obj_hdr->object_class = obj4_class;
+ obj_hdr->tlv_list = NULL;
+ dll_append(msg->obj_list, obj_hdr);
+ }
+
+ return msg;
+}
+
+void test_validate_message_objects()
+{
+ /* Valid Open message */
+ struct pcep_message *msg =
+ create_message(PCEP_TYPE_OPEN, PCEP_OBJ_CLASS_OPEN, 0, 0, 0);
+ CU_ASSERT_TRUE(validate_message_objects(msg));
+ pcep_msg_free_message(msg);
+
+ /* Valid KeepAlive message */
+ msg = create_message(PCEP_TYPE_KEEPALIVE, 0, 0, 0, 0);
+ CU_ASSERT_TRUE(validate_message_objects(msg));
+ pcep_msg_free_message(msg);
+
+ /* Valid PcReq message */
+ /* Using object_class=255 to verify it can take any object */
+ msg = create_message(PCEP_TYPE_PCREQ, PCEP_OBJ_CLASS_RP,
+ PCEP_OBJ_CLASS_ENDPOINTS, any_obj_class, 0);
+ CU_ASSERT_TRUE(validate_message_objects(msg));
+ pcep_msg_free_message(msg);
+
+ /* Valid PcRep message */
+ msg = create_message(PCEP_TYPE_PCREP, PCEP_OBJ_CLASS_RP, any_obj_class,
+ 0, 0);
+ CU_ASSERT_TRUE(validate_message_objects(msg));
+ pcep_msg_free_message(msg);
+
+ /* Valid Notify message */
+ msg = create_message(PCEP_TYPE_PCNOTF, PCEP_OBJ_CLASS_NOTF,
+ any_obj_class, 0, 0);
+ CU_ASSERT_TRUE(validate_message_objects(msg));
+ pcep_msg_free_message(msg);
+
+ /* Valid Error message */
+ msg = create_message(PCEP_TYPE_ERROR, PCEP_OBJ_CLASS_ERROR,
+ any_obj_class, 0, 0);
+ CU_ASSERT_TRUE(validate_message_objects(msg));
+ pcep_msg_free_message(msg);
+
+ /* Valid Close message */
+ msg = create_message(PCEP_TYPE_CLOSE, PCEP_OBJ_CLASS_CLOSE, 0, 0, 0);
+ CU_ASSERT_TRUE(validate_message_objects(msg));
+ pcep_msg_free_message(msg);
+
+ /* Valid Report message */
+ msg = create_message(PCEP_TYPE_REPORT, PCEP_OBJ_CLASS_SRP,
+ PCEP_OBJ_CLASS_LSP, any_obj_class, any_obj_class);
+ CU_ASSERT_TRUE(validate_message_objects(msg));
+ pcep_msg_free_message(msg);
+
+ /* Valid Update message */
+ msg = create_message(PCEP_TYPE_UPDATE, PCEP_OBJ_CLASS_SRP,
+ PCEP_OBJ_CLASS_LSP, any_obj_class, any_obj_class);
+ CU_ASSERT_TRUE(validate_message_objects(msg));
+ pcep_msg_free_message(msg);
+
+ /* Valid Initiate message */
+ msg = create_message(PCEP_TYPE_INITIATE, PCEP_OBJ_CLASS_SRP,
+ PCEP_OBJ_CLASS_LSP, any_obj_class, any_obj_class);
+ CU_ASSERT_TRUE(validate_message_objects(msg));
+ pcep_msg_free_message(msg);
+}
+
+void test_validate_message_objects_invalid()
+{
+ /* unsupported message ID = 0
+ * {NO_OBJECT, NO_OBJECT, NO_OBJECT, NO_OBJECT} */
+ struct pcep_message *msg = create_message(0, any_obj_class, 0, 0, 0);
+ CU_ASSERT_FALSE(validate_message_objects(msg));
+ pcep_msg_free_message(msg);
+
+ /* Open message
+ * {PCEP_OBJ_CLASS_OPEN, NO_OBJECT, NO_OBJECT, NO_OBJECT} */
+ msg = create_message(PCEP_TYPE_OPEN, 0, 0, 0, 0);
+ CU_ASSERT_FALSE(validate_message_objects(msg));
+ pcep_msg_free_message(msg);
+
+ msg = create_message(PCEP_TYPE_OPEN, any_obj_class, 0, 0, 0);
+ CU_ASSERT_FALSE(validate_message_objects(msg));
+ pcep_msg_free_message(msg);
+
+ msg = create_message(PCEP_TYPE_OPEN, PCEP_OBJ_CLASS_OPEN, any_obj_class,
+ 0, 0);
+ CU_ASSERT_FALSE(validate_message_objects(msg));
+ pcep_msg_free_message(msg);
+
+ /* KeepAlive message
+ * {NO_OBJECT, NO_OBJECT, NO_OBJECT, NO_OBJECT} */
+ msg = create_message(PCEP_TYPE_KEEPALIVE, any_obj_class, 0, 0, 0);
+ CU_ASSERT_FALSE(validate_message_objects(msg));
+ pcep_msg_free_message(msg);
+
+ /* PcReq message
+ * {PCEP_OBJ_CLASS_RP, PCEP_OBJ_CLASS_ENDPOINTS, ANY_OBJECT, ANY_OBJECT}
+ */
+ msg = create_message(PCEP_TYPE_PCREQ, 0, 0, 0, 0);
+ CU_ASSERT_FALSE(validate_message_objects(msg));
+ pcep_msg_free_message(msg);
+
+ msg = create_message(PCEP_TYPE_PCREQ, PCEP_OBJ_CLASS_RP, any_obj_class,
+ 0, 0);
+ CU_ASSERT_FALSE(validate_message_objects(msg));
+ pcep_msg_free_message(msg);
+
+ /* PcRep message
+ * {PCEP_OBJ_CLASS_RP, ANY_OBJECT, ANY_OBJECT, ANY_OBJECT} */
+ msg = create_message(PCEP_TYPE_PCREP, 0, 0, 0, 0);
+ CU_ASSERT_FALSE(validate_message_objects(msg));
+ pcep_msg_free_message(msg);
+
+ msg = create_message(PCEP_TYPE_PCREP, any_obj_class, 0, 0, 0);
+ CU_ASSERT_FALSE(validate_message_objects(msg));
+ pcep_msg_free_message(msg);
+
+ /* Notify message
+ * {PCEP_OBJ_CLASS_NOTF, ANY_OBJECT, ANY_OBJECT, ANY_OBJECT} */
+ msg = create_message(PCEP_TYPE_PCNOTF, 0, 0, 0, 0);
+ CU_ASSERT_FALSE(validate_message_objects(msg));
+ pcep_msg_free_message(msg);
+
+ msg = create_message(PCEP_TYPE_PCNOTF, any_obj_class, 0, 0, 0);
+ CU_ASSERT_FALSE(validate_message_objects(msg));
+ pcep_msg_free_message(msg);
+
+ /* Error message
+ * {PCEP_OBJ_CLASS_ERROR, ANY_OBJECT, ANY_OBJECT, ANY_OBJECT} */
+ msg = create_message(PCEP_TYPE_ERROR, 0, 0, 0, 0);
+ CU_ASSERT_FALSE(validate_message_objects(msg));
+ pcep_msg_free_message(msg);
+
+ msg = create_message(PCEP_TYPE_ERROR, any_obj_class, 0, 0, 0);
+ CU_ASSERT_FALSE(validate_message_objects(msg));
+ pcep_msg_free_message(msg);
+
+ /* Close message
+ * {PCEP_OBJ_CLASS_CLOSE, NO_OBJECT, NO_OBJECT, NO_OBJECT} */
+ msg = create_message(PCEP_TYPE_CLOSE, 0, 0, 0, 0);
+ CU_ASSERT_FALSE(validate_message_objects(msg));
+ pcep_msg_free_message(msg);
+
+ msg = create_message(PCEP_TYPE_CLOSE, any_obj_class, 0, 0, 0);
+ CU_ASSERT_FALSE(validate_message_objects(msg));
+ pcep_msg_free_message(msg);
+
+ /* unsupported message ID = 8
+ * {NO_OBJECT, NO_OBJECT, NO_OBJECT, NO_OBJECT} */
+ msg = create_message(8, any_obj_class, 0, 0, 0);
+ CU_ASSERT_FALSE(validate_message_objects(msg));
+ pcep_msg_free_message(msg);
+
+ /* unsupported message ID = 9
+ * {NO_OBJECT, NO_OBJECT, NO_OBJECT, NO_OBJECT} */
+ msg = create_message(9, any_obj_class, 0, 0, 0);
+ CU_ASSERT_FALSE(validate_message_objects(msg));
+ pcep_msg_free_message(msg);
+
+ /* Report message
+ * {PCEP_OBJ_CLASS_SRP, PCEP_OBJ_CLASS_LSP, ANY_OBJECT, ANY_OBJECT} */
+ msg = create_message(PCEP_TYPE_REPORT, 0, 0, 0, 0);
+ CU_ASSERT_FALSE(validate_message_objects(msg));
+ pcep_msg_free_message(msg);
+
+ msg = create_message(PCEP_TYPE_REPORT, any_obj_class, 0, 0, 0);
+ CU_ASSERT_FALSE(validate_message_objects(msg));
+ pcep_msg_free_message(msg);
+
+ msg = create_message(PCEP_TYPE_REPORT, PCEP_OBJ_CLASS_SRP, 0, 0, 0);
+ CU_ASSERT_FALSE(validate_message_objects(msg));
+ pcep_msg_free_message(msg);
+
+ msg = create_message(PCEP_TYPE_REPORT, PCEP_OBJ_CLASS_SRP,
+ any_obj_class, 0, 0);
+ CU_ASSERT_FALSE(validate_message_objects(msg));
+ pcep_msg_free_message(msg);
+
+ /* Update message
+ * {PCEP_OBJ_CLASS_SRP, PCEP_OBJ_CLASS_LSP, ANY_OBJECT, ANY_OBJECT} */
+ msg = create_message(PCEP_TYPE_UPDATE, 0, 0, 0, 0);
+ CU_ASSERT_FALSE(validate_message_objects(msg));
+ pcep_msg_free_message(msg);
+
+ msg = create_message(PCEP_TYPE_UPDATE, any_obj_class, 0, 0, 0);
+ CU_ASSERT_FALSE(validate_message_objects(msg));
+ pcep_msg_free_message(msg);
+
+ msg = create_message(PCEP_TYPE_UPDATE, PCEP_OBJ_CLASS_SRP, 0, 0, 0);
+ CU_ASSERT_FALSE(validate_message_objects(msg));
+ pcep_msg_free_message(msg);
+
+ msg = create_message(PCEP_TYPE_UPDATE, PCEP_OBJ_CLASS_SRP,
+ any_obj_class, 0, 0);
+ CU_ASSERT_FALSE(validate_message_objects(msg));
+ pcep_msg_free_message(msg);
+
+ /* Initiate message
+ * {PCEP_OBJ_CLASS_SRP, PCEP_OBJ_CLASS_LSP, ANY_OBJECT, ANY_OBJECT} */
+ msg = create_message(PCEP_TYPE_INITIATE, 0, 0, 0, 0);
+ CU_ASSERT_FALSE(validate_message_objects(msg));
+ pcep_msg_free_message(msg);
+
+ msg = create_message(PCEP_TYPE_INITIATE, any_obj_class, 0, 0, 0);
+ CU_ASSERT_FALSE(validate_message_objects(msg));
+ pcep_msg_free_message(msg);
+
+ msg = create_message(PCEP_TYPE_INITIATE, PCEP_OBJ_CLASS_SRP, 0, 0, 0);
+ CU_ASSERT_FALSE(validate_message_objects(msg));
+ pcep_msg_free_message(msg);
+
+ msg = create_message(PCEP_TYPE_INITIATE, PCEP_OBJ_CLASS_SRP,
+ any_obj_class, 0, 0);
+ CU_ASSERT_FALSE(validate_message_objects(msg));
+ pcep_msg_free_message(msg);
+}
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Javier Garcia <javier.garcia@voltanet.io>
+ *
+ */
+
+/*
+ * Timer definitions to be used internally by the pcep_timers library.
+ */
+
+#ifndef PCEP_MSG_TOOLS_TEST_H_
+#define PCEP_MSG_TOOLS_TEST_H_
+
+
+int pcep_tools_test_suite_setup(void);
+int pcep_tools_test_suite_teardown(void);
+void pcep_tools_test_setup(void);
+void pcep_tools_test_teardown(void);
+void test_pcep_msg_read_pcep_initiate(void);
+void test_pcep_msg_read_pcep_initiate2(void);
+void test_pcep_msg_read_pcep_update(void);
+void test_pcep_msg_read_pcep_open(void);
+void test_pcep_msg_read_pcep_open_initiate(void);
+void test_validate_message_header(void);
+void test_validate_message_objects(void);
+void test_validate_message_objects_invalid(void);
+void test_pcep_msg_read_pcep_open_cisco_pce(void);
+void test_pcep_msg_read_pcep_update_cisco_pce(void);
+void test_pcep_msg_read_pcep_report_cisco_pcc(void);
+void test_pcep_msg_read_pcep_initiate_cisco_pcc(void);
+
+#endif /* PCEPTIMERINTERNALS_H_ */
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <netdb.h> // gethostbyname
+#include <pthread.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <CUnit/CUnit.h>
+
+#include "pcep_pcc_api.h"
+#include "pcep_pcc_api_test.h"
+#include "pcep_socket_comm_mock.h"
+#include "pcep_utils_memory.h"
+
+extern pcep_event_queue *session_logic_event_queue_;
+extern const char MESSAGE_RECEIVED_STR[];
+extern const char UNKNOWN_EVENT_STR[];
+
+/*
+ * Test suite setup and teardown called before AND after the test suite.
+ */
+
+int pcep_pcc_api_test_suite_setup()
+{
+ pceplib_memory_reset();
+ return 0;
+}
+
+int pcep_pcc_api_test_suite_teardown()
+{
+ printf("\n");
+ pceplib_memory_dump();
+ return 0;
+}
+
+/*
+ * Test case setup and teardown called before AND after each test.
+ */
+
+void pcep_pcc_api_test_setup()
+{
+ setup_mock_socket_comm_info();
+}
+
+
+void pcep_pcc_api_test_teardown()
+{
+ teardown_mock_socket_comm_info();
+}
+
+/*
+ * Unit test cases
+ */
+
+void test_initialize_pcc()
+{
+ CU_ASSERT_TRUE(initialize_pcc());
+ /* Give the PCC time to initialize */
+ sleep(1);
+ CU_ASSERT_TRUE(destroy_pcc());
+}
+
+void test_connect_pce()
+{
+ pcep_configuration *config = create_default_pcep_configuration();
+ struct hostent *host_info = gethostbyname("localhost");
+ struct in_addr dest_address;
+ memcpy(&dest_address, host_info->h_addr, host_info->h_length);
+ mock_socket_comm_info *mock_info = get_mock_socket_comm_info();
+ mock_info->send_message_save_message = true;
+
+ initialize_pcc();
+
+ pcep_session *session = connect_pce(config, &dest_address);
+
+ CU_ASSERT_PTR_NOT_NULL(session);
+ CU_ASSERT_EQUAL(mock_info->sent_message_list->num_entries, 1);
+ /* What gets saved in the mock is the msg byte buffer. The msg struct
+ * was deleted when it was sent. Instead of inspecting the msg byte
+ * buffer, lets just decode it. */
+ uint8_t *encoded_msg =
+ dll_delete_first_node(mock_info->sent_message_list);
+ CU_ASSERT_PTR_NOT_NULL(encoded_msg);
+ struct pcep_message *open_msg = pcep_decode_message(encoded_msg);
+ CU_ASSERT_PTR_NOT_NULL(open_msg);
+ CU_ASSERT_EQUAL(open_msg->msg_header->type, PCEP_TYPE_OPEN);
+
+ pcep_msg_free_message(open_msg);
+ destroy_pcep_session(session);
+ destroy_pcep_configuration(config);
+ pceplib_free(PCEPLIB_MESSAGES, encoded_msg);
+
+ destroy_pcc();
+}
+
+void test_connect_pce_ipv6()
+{
+ pcep_configuration *config = create_default_pcep_configuration();
+ struct in6_addr dest_address;
+ dest_address.__in6_u.__u6_addr32[0] = 0;
+ dest_address.__in6_u.__u6_addr32[1] = 0;
+ dest_address.__in6_u.__u6_addr32[2] = 0;
+ dest_address.__in6_u.__u6_addr32[3] = htonl(1);
+ mock_socket_comm_info *mock_info = get_mock_socket_comm_info();
+ mock_info->send_message_save_message = true;
+
+ initialize_pcc();
+
+ pcep_session *session = connect_pce_ipv6(config, &dest_address);
+
+ CU_ASSERT_PTR_NOT_NULL(session);
+ CU_ASSERT_TRUE(session->socket_comm_session->is_ipv6);
+ CU_ASSERT_EQUAL(mock_info->sent_message_list->num_entries, 1);
+ /* What gets saved in the mock is the msg byte buffer. The msg struct
+ * was deleted when it was sent. Instead of inspecting the msg byte
+ * buffer, lets just decode it. */
+ uint8_t *encoded_msg =
+ dll_delete_first_node(mock_info->sent_message_list);
+ CU_ASSERT_PTR_NOT_NULL(encoded_msg);
+ struct pcep_message *open_msg = pcep_decode_message(encoded_msg);
+ CU_ASSERT_PTR_NOT_NULL(open_msg);
+ CU_ASSERT_EQUAL(open_msg->msg_header->type, PCEP_TYPE_OPEN);
+
+ pcep_msg_free_message(open_msg);
+ destroy_pcep_session(session);
+ destroy_pcep_configuration(config);
+ pceplib_free(PCEPLIB_MESSAGES, encoded_msg);
+
+ destroy_pcc();
+}
+
+void test_connect_pce_with_src_ip()
+{
+ pcep_configuration *config = create_default_pcep_configuration();
+ struct hostent *host_info = gethostbyname("localhost");
+ struct in_addr dest_address;
+ memcpy(&dest_address, host_info->h_addr, host_info->h_length);
+ mock_socket_comm_info *mock_info = get_mock_socket_comm_info();
+ mock_info->send_message_save_message = true;
+ config->src_ip.src_ipv4.s_addr = 0x0a0a0102;
+
+ initialize_pcc();
+
+ pcep_session *session = connect_pce(config, &dest_address);
+
+ CU_ASSERT_PTR_NOT_NULL(session);
+ CU_ASSERT_EQUAL(mock_info->sent_message_list->num_entries, 1);
+ uint8_t *encoded_msg =
+ dll_delete_first_node(mock_info->sent_message_list);
+ CU_ASSERT_PTR_NOT_NULL(encoded_msg);
+ struct pcep_message *open_msg = pcep_decode_message(encoded_msg);
+ CU_ASSERT_PTR_NOT_NULL(open_msg);
+ CU_ASSERT_EQUAL(open_msg->msg_header->type, PCEP_TYPE_OPEN);
+
+ pcep_msg_free_message(open_msg);
+ destroy_pcep_session(session);
+ destroy_pcep_configuration(config);
+ pceplib_free(PCEPLIB_MESSAGES, encoded_msg);
+
+ destroy_pcc();
+}
+
+void test_disconnect_pce()
+{
+ pcep_configuration *config = create_default_pcep_configuration();
+ struct hostent *host_info = gethostbyname("localhost");
+ struct in_addr dest_address;
+ memcpy(&dest_address, host_info->h_addr, host_info->h_length);
+ mock_socket_comm_info *mock_info = get_mock_socket_comm_info();
+ mock_info->send_message_save_message = true;
+
+ initialize_pcc();
+
+ pcep_session *session = connect_pce(config, &dest_address);
+ disconnect_pce(session);
+
+ CU_ASSERT_EQUAL(mock_info->sent_message_list->num_entries, 2);
+
+ /* First there should be an open message from connect_pce() */
+ uint8_t *encoded_msg =
+ dll_delete_first_node(mock_info->sent_message_list);
+ CU_ASSERT_PTR_NOT_NULL(encoded_msg);
+ struct pcep_message *msg = pcep_decode_message(encoded_msg);
+ CU_ASSERT_PTR_NOT_NULL(msg);
+ CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_OPEN);
+ pcep_msg_free_message(msg);
+ pceplib_free(PCEPLIB_MESSAGES, encoded_msg);
+
+ /* Then there should be a close message from disconnect_pce() */
+ encoded_msg = dll_delete_first_node(mock_info->sent_message_list);
+ CU_ASSERT_PTR_NOT_NULL(encoded_msg);
+ msg = pcep_decode_message(encoded_msg);
+ CU_ASSERT_PTR_NOT_NULL(msg);
+ CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_CLOSE);
+
+ pcep_msg_free_message(msg);
+ destroy_pcep_session(session);
+ destroy_pcep_configuration(config);
+ pceplib_free(PCEPLIB_MESSAGES, encoded_msg);
+
+ destroy_pcc();
+}
+
+
+void test_send_message()
+{
+ pcep_configuration *config = create_default_pcep_configuration();
+ struct hostent *host_info = gethostbyname("localhost");
+ struct in_addr dest_address;
+
+ initialize_pcc();
+
+ memcpy(&dest_address, host_info->h_addr, host_info->h_length);
+ pcep_session *session = connect_pce(config, &dest_address);
+ verify_socket_comm_times_called(0, 0, 1, 1, 0, 0, 0);
+
+ struct pcep_message *msg = pcep_msg_create_keepalive();
+ send_message(session, msg, false);
+
+ verify_socket_comm_times_called(0, 0, 1, 2, 0, 0, 0);
+
+ pcep_msg_free_message(msg);
+ destroy_pcep_session(session);
+ destroy_pcep_configuration(config);
+
+ destroy_pcc();
+}
+
+void test_event_queue()
+{
+ /* This initializes the event_queue */
+ CU_ASSERT_TRUE(initialize_pcc());
+
+ /* Verify correct behavior when the queue is empty */
+ CU_ASSERT_TRUE(event_queue_is_empty());
+ CU_ASSERT_EQUAL(event_queue_num_events_available(), 0);
+ CU_ASSERT_PTR_NULL(event_queue_get_event());
+ destroy_pcep_event(NULL);
+
+ /* Create an empty event and put it on the queue */
+ pcep_event *event = pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_event));
+ memset(event, 0, sizeof(pcep_event));
+ pthread_mutex_lock(&session_logic_event_queue_->event_queue_mutex);
+ queue_enqueue(session_logic_event_queue_->event_queue, event);
+ pthread_mutex_unlock(&session_logic_event_queue_->event_queue_mutex);
+
+ /* Verify correct behavior when there is an entry in the queue */
+ CU_ASSERT_FALSE(event_queue_is_empty());
+ CU_ASSERT_EQUAL(event_queue_num_events_available(), 1);
+ pcep_event *queued_event = event_queue_get_event();
+ CU_ASSERT_PTR_NOT_NULL(queued_event);
+ CU_ASSERT_PTR_EQUAL(event, queued_event);
+ destroy_pcep_event(queued_event);
+
+ CU_ASSERT_TRUE(destroy_pcc());
+}
+
+void test_get_event_type_str()
+{
+ CU_ASSERT_EQUAL(strcmp(get_event_type_str(MESSAGE_RECEIVED),
+ MESSAGE_RECEIVED_STR),
+ 0);
+ CU_ASSERT_EQUAL(strcmp(get_event_type_str(1000), UNKNOWN_EVENT_STR), 0);
+}
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Javier Garcia <javier.garcia@voltanet.io>
+ *
+ */
+
+/*
+ * Timer definitions to be used internally by the pcep_timers library.
+ */
+
+#ifndef PCEP_PCC_API_TEST_
+#define PCEP_PCC_API_TEST_
+
+int pcep_pcc_api_test_suite_setup(void);
+int pcep_pcc_api_test_suite_teardown(void);
+void pcep_pcc_api_test_setup(void);
+void pcep_pcc_api_test_teardown(void);
+void test_initialize_pcc(void);
+void test_connect_pce(void);
+void test_connect_pce_ipv6(void);
+void test_connect_pce_with_src_ip(void);
+void test_disconnect_pce(void);
+void test_send_message(void);
+void test_event_queue(void);
+void test_get_event_type_str(void);
+
+#endif /* PCEPTIMERINTERNALS_H_ */
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <CUnit/Basic.h>
+#include <CUnit/CUnit.h>
+#include <CUnit/TestDB.h>
+
+#include "pcep_pcc_api_test.h"
+
+int main(int argc, char **argv)
+{
+ /* Unused parameters cause compilation warnings */
+ (void)argc;
+ (void)argv;
+
+ CU_initialize_registry();
+
+ /*
+ * Tests defined in pcep_socket_comm_test.c
+ */
+ CU_pSuite test_pcc_api_suite = CU_add_suite_with_setup_and_teardown(
+ "PCEP PCC API Test Suite",
+ pcep_pcc_api_test_suite_setup, // suite setup and cleanup
+ // function pointers
+ pcep_pcc_api_test_suite_teardown,
+ pcep_pcc_api_test_setup, // test case setup function pointer
+ pcep_pcc_api_test_teardown); // test case teardown function
+ // pointer
+
+ CU_add_test(test_pcc_api_suite, "test_initialize_pcc",
+ test_initialize_pcc);
+ CU_add_test(test_pcc_api_suite, "test_connect_pce", test_connect_pce);
+ CU_add_test(test_pcc_api_suite, "test_connect_pce_ipv6",
+ test_connect_pce_ipv6);
+ CU_add_test(test_pcc_api_suite, "test_connect_pce_with_src_ip",
+ test_connect_pce_with_src_ip);
+ CU_add_test(test_pcc_api_suite, "test_disconnect_pce",
+ test_disconnect_pce);
+ CU_add_test(test_pcc_api_suite, "test_send_message", test_send_message);
+ CU_add_test(test_pcc_api_suite, "test_event_queue", test_event_queue);
+ CU_add_test(test_pcc_api_suite, "test_get_event_type_str",
+ test_get_event_type_str);
+
+ /*
+ * Run the tests and cleanup.
+ */
+ CU_basic_set_mode(CU_BRM_VERBOSE);
+ CU_basic_run_tests();
+ CU_FailureRecord *failure_record = CU_get_failure_list();
+ if (failure_record != NULL) {
+ printf("\nFailed tests:\n\t [Suite] [Test] [File:line-number]\n");
+ do {
+ printf("\t [%s] [%s] [%s:%d]\n",
+ failure_record->pSuite->pName,
+ failure_record->pTest->pName,
+ failure_record->strFileName,
+ failure_record->uiLineNumber);
+ failure_record = failure_record->pNext;
+
+ } while (failure_record != NULL);
+ }
+
+ CU_pRunSummary run_summary = CU_get_run_summary();
+ int result = run_summary->nTestsFailed;
+ CU_cleanup_registry();
+
+ return result;
+}
--- /dev/null
+source pceplib/test/pcep_tests_valgrind.sh
+valgrind_test pceplib/test/pcep_pcc_api_tests
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <CUnit/CUnit.h>
+
+#include "pcep_msg_encoding.h"
+#include "pcep_session_logic.h"
+#include "pcep_session_logic_internals.h"
+#include "pcep_timers.h"
+#include "pcep_utils_ordered_list.h"
+#include "pcep_utils_memory.h"
+#include "pcep_session_logic_loop_test.h"
+
+
+extern pcep_session_logic_handle *session_logic_handle_;
+extern pcep_event_queue *session_logic_event_queue_;
+
+/*
+ * Test suite setup and teardown called before AND after the test suite.
+ */
+
+int pcep_session_logic_loop_test_suite_setup(void)
+{
+ pceplib_memory_reset();
+ return 0;
+}
+
+int pcep_session_logic_loop_test_suite_teardown(void)
+{
+ printf("\n");
+ pceplib_memory_dump();
+ return 0;
+}
+
+
+/*
+ * Test case setup and teardown called before AND after each test.
+ */
+
+void pcep_session_logic_loop_test_setup()
+{
+ /* We need to setup the session_logic_handle_ without starting the
+ * thread */
+ session_logic_handle_ = pceplib_malloc(
+ PCEPLIB_INFRA, sizeof(pcep_session_logic_handle));
+ memset(session_logic_handle_, 0, sizeof(pcep_session_logic_handle));
+ session_logic_handle_->active = true;
+ session_logic_handle_->session_list =
+ ordered_list_initialize(pointer_compare_function);
+ session_logic_handle_->session_event_queue = queue_initialize();
+ pthread_cond_init(&(session_logic_handle_->session_logic_cond_var),
+ NULL);
+ pthread_mutex_init(&(session_logic_handle_->session_logic_mutex), NULL);
+ pthread_mutex_init(&(session_logic_handle_->session_list_mutex), NULL);
+
+ pthread_mutex_lock(&(session_logic_handle_->session_logic_mutex));
+ session_logic_handle_->session_logic_condition = true;
+ pthread_cond_signal(&(session_logic_handle_->session_logic_cond_var));
+ pthread_mutex_unlock(&(session_logic_handle_->session_logic_mutex));
+
+ session_logic_event_queue_ =
+ pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_event_queue));
+ memset(session_logic_event_queue_, 0, sizeof(pcep_event_queue));
+ session_logic_event_queue_->event_queue = queue_initialize();
+}
+
+
+void pcep_session_logic_loop_test_teardown()
+{
+ ordered_list_destroy(session_logic_handle_->session_list);
+ queue_destroy(session_logic_handle_->session_event_queue);
+ pthread_mutex_unlock(&(session_logic_handle_->session_logic_mutex));
+ pthread_mutex_destroy(&(session_logic_handle_->session_logic_mutex));
+ pthread_mutex_destroy(&(session_logic_handle_->session_list_mutex));
+ pceplib_free(PCEPLIB_INFRA, session_logic_handle_);
+ session_logic_handle_ = NULL;
+
+ queue_destroy(session_logic_event_queue_->event_queue);
+ pceplib_free(PCEPLIB_INFRA, session_logic_event_queue_);
+ session_logic_event_queue_ = NULL;
+}
+
+
+/*
+ * Test cases
+ */
+
+void test_session_logic_loop_null_data()
+{
+ /* Just testing that it does not core dump */
+ session_logic_loop(NULL);
+}
+
+
+void test_session_logic_loop_inactive()
+{
+ session_logic_handle_->active = false;
+
+ session_logic_loop(session_logic_handle_);
+}
+
+
+void test_session_logic_msg_ready_handler()
+{
+ /* Just testing that it does not core dump */
+ CU_ASSERT_EQUAL(session_logic_msg_ready_handler(NULL, 0), -1);
+
+ /* Read from an empty file should return 0, thus
+ * session_logic_msg_ready_handler returns -1 */
+ mode_t oldumask;
+ oldumask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH);
+ /* Set umask before anything for security */
+ umask(0027);
+ char tmpfile[] = "/tmp/pceplib_XXXXXX";
+ int fd = mkstemp(tmpfile);
+ umask(oldumask);
+ if (fd == -1){
+ CU_ASSERT_TRUE(fd>=0);
+ return;
+ }
+ pcep_session session;
+ memset(&session, 0, sizeof(pcep_session));
+ session.session_id = 100;
+ CU_ASSERT_EQUAL(session_logic_msg_ready_handler(&session, fd), 0);
+ CU_ASSERT_EQUAL(session_logic_handle_->session_event_queue->num_entries,
+ 1);
+ pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue);
+ CU_ASSERT_EQUAL(PCE_CLOSED_SOCKET, e->event_type);
+ pceplib_free(PCEPLIB_INFRA, e);
+ pcep_session_event *socket_event = (pcep_session_event *)queue_dequeue(
+ session_logic_handle_->session_event_queue);
+ CU_ASSERT_PTR_NOT_NULL(socket_event);
+ CU_ASSERT_TRUE(socket_event->socket_closed);
+ pceplib_free(PCEPLIB_INFRA, socket_event);
+
+ /* A pcep_session_event should be created */
+ struct pcep_versioning *versioning = create_default_pcep_versioning();
+ struct pcep_message *keep_alive_msg = pcep_msg_create_keepalive();
+ pcep_encode_message(keep_alive_msg, versioning);
+ int retval = write(fd, (char *)keep_alive_msg->encoded_message,
+ keep_alive_msg->encoded_message_length);
+ CU_ASSERT_TRUE(retval > 0);
+ lseek(fd, 0, SEEK_SET);
+ CU_ASSERT_EQUAL(session_logic_msg_ready_handler(&session, fd),
+ keep_alive_msg->encoded_message_length);
+ CU_ASSERT_EQUAL(session_logic_handle_->session_event_queue->num_entries,
+ 1);
+ socket_event = (pcep_session_event *)queue_dequeue(
+ session_logic_handle_->session_event_queue);
+ CU_ASSERT_PTR_NOT_NULL(socket_event);
+ CU_ASSERT_FALSE(socket_event->socket_closed);
+ CU_ASSERT_PTR_EQUAL(socket_event->session, &session);
+ CU_ASSERT_EQUAL(socket_event->expired_timer_id, TIMER_ID_NOT_SET);
+ CU_ASSERT_PTR_NOT_NULL(socket_event->received_msg_list);
+ pcep_msg_free_message_list(socket_event->received_msg_list);
+ pcep_msg_free_message(keep_alive_msg);
+ destroy_pcep_versioning(versioning);
+ pceplib_free(PCEPLIB_INFRA, socket_event);
+ close(fd);
+}
+
+
+void test_session_logic_conn_except_notifier()
+{
+ /* Just testing that it does not core dump */
+ session_logic_conn_except_notifier(NULL, 1);
+
+ /* A pcep_session_event should be created */
+ pcep_session session;
+ memset(&session, 0, sizeof(pcep_session));
+ session.session_id = 100;
+ session_logic_conn_except_notifier(&session, 10);
+ CU_ASSERT_EQUAL(session_logic_handle_->session_event_queue->num_entries,
+ 1);
+ pcep_session_event *socket_event = (pcep_session_event *)queue_dequeue(
+ session_logic_handle_->session_event_queue);
+ CU_ASSERT_PTR_NOT_NULL_FATAL(socket_event);
+ CU_ASSERT_TRUE(socket_event->socket_closed);
+ CU_ASSERT_PTR_EQUAL(socket_event->session, &session);
+ CU_ASSERT_EQUAL(socket_event->expired_timer_id, TIMER_ID_NOT_SET);
+ CU_ASSERT_PTR_NULL(socket_event->received_msg_list);
+
+ pceplib_free(PCEPLIB_INFRA, socket_event);
+}
+
+
+void test_session_logic_timer_expire_handler()
+{
+ /* Just testing that it does not core dump */
+ session_logic_timer_expire_handler(NULL, 42);
+
+ /* A pcep_session_event should be created */
+ pcep_session session;
+ memset(&session, 0, sizeof(pcep_session));
+ session.session_id = 100;
+ session_logic_timer_expire_handler(&session, 42);
+ CU_ASSERT_EQUAL(session_logic_handle_->session_event_queue->num_entries,
+ 1);
+ pcep_session_event *socket_event = (pcep_session_event *)queue_dequeue(
+ session_logic_handle_->session_event_queue);
+ CU_ASSERT_PTR_NOT_NULL_FATAL(socket_event);
+ CU_ASSERT_FALSE(socket_event->socket_closed);
+ CU_ASSERT_PTR_EQUAL(socket_event->session, &session);
+ CU_ASSERT_EQUAL(socket_event->expired_timer_id, 42);
+ CU_ASSERT_PTR_NULL(socket_event->received_msg_list);
+
+ pceplib_free(PCEPLIB_INFRA, socket_event);
+}
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Javier Garcia <javier.garcia@voltanet.io>
+ *
+ */
+
+/*
+ * Timer definitions to be used internally by the pcep_timers library.
+ */
+
+#ifndef PCEP_SESSION_LOGIC_LOOP_TEST_H_
+#define PCEP_SESSION_LOGIC_LOOP_TEST_H_
+
+int pcep_session_logic_loop_test_suite_setup(void);
+int pcep_session_logic_loop_test_suite_teardown(void);
+void pcep_session_logic_loop_test_setup(void);
+void pcep_session_logic_loop_test_teardown(void);
+void test_session_logic_loop_null_data(void);
+void test_session_logic_loop_inactive(void);
+void test_session_logic_msg_ready_handler(void);
+void test_session_logic_conn_except_notifier(void);
+void test_session_logic_timer_expire_handler(void);
+
+#endif /* PCEPTIMERINTERNALS_H_ */
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <CUnit/CUnit.h>
+
+#include "pcep_socket_comm_mock.h"
+#include "pcep_session_logic.h"
+#include "pcep_session_logic_internals.h"
+#include "pcep_timers.h"
+#include "pcep_utils_ordered_list.h"
+#include "pcep_utils_double_linked_list.h"
+#include "pcep_utils_memory.h"
+#include "pcep_msg_objects.h"
+#include "pcep_msg_tools.h"
+#include "pcep_session_logic_states_test.h"
+
+/* Functions being tested */
+extern pcep_session_logic_handle *session_logic_handle_;
+extern pcep_event_queue *session_logic_event_queue_;
+
+static pcep_session_event event;
+static pcep_session session;
+/* A message list is a dll of struct pcep_messages_list_node items */
+static double_linked_list *msg_list;
+struct pcep_message *message;
+static bool free_msg_list;
+static bool msg_enqueued;
+/* Forward declaration */
+void destroy_message_for_test(void);
+void create_message_for_test(uint8_t msg_type, bool free_msg_list_at_teardown,
+ bool was_msg_enqueued);
+void test_handle_timer_event_open_keep_alive(void);
+
+/*
+ * Test suite setup and teardown called before AND after the test suite.
+ */
+
+int pcep_session_logic_states_test_suite_setup(void)
+{
+ pceplib_memory_reset();
+ return 0;
+}
+
+int pcep_session_logic_states_test_suite_teardown(void)
+{
+ printf("\n");
+ pceplib_memory_dump();
+ return 0;
+}
+
+/*
+ * Test case setup and teardown called before AND after each test.
+ */
+
+void pcep_session_logic_states_test_setup()
+{
+ session_logic_handle_ = pceplib_malloc(
+ PCEPLIB_INFRA, sizeof(pcep_session_logic_handle));
+ memset(session_logic_handle_, 0, sizeof(pcep_session_logic_handle));
+
+ session_logic_event_queue_ =
+ pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_event_queue));
+ memset(session_logic_event_queue_, 0, sizeof(pcep_event_queue));
+ session_logic_event_queue_->event_queue = queue_initialize();
+
+ memset(&session, 0, sizeof(pcep_session));
+ session.pcc_config.keep_alive_seconds = 5;
+ session.pcc_config.keep_alive_pce_negotiated_timer_seconds = 5;
+ session.pcc_config.min_keep_alive_seconds = 1;
+ session.pcc_config.max_keep_alive_seconds = 10;
+ session.pcc_config.dead_timer_seconds = 5;
+ session.pcc_config.dead_timer_pce_negotiated_seconds = 5;
+ session.pcc_config.min_dead_timer_seconds = 1;
+ session.pcc_config.max_dead_timer_seconds = 10;
+ session.pcc_config.max_unknown_messages = 2;
+ memcpy(&session.pce_config, &session.pcc_config,
+ sizeof(pcep_configuration));
+ session.num_unknown_messages_time_queue = queue_initialize();
+
+ memset(&event, 0, sizeof(pcep_session_event));
+ event.socket_closed = false;
+ event.session = &session;
+
+ setup_mock_socket_comm_info();
+ free_msg_list = false;
+ msg_enqueued = false;
+}
+
+
+void pcep_session_logic_states_test_teardown()
+{
+ destroy_message_for_test();
+ pceplib_free(PCEPLIB_INFRA, session_logic_handle_);
+ queue_destroy(session_logic_event_queue_->event_queue);
+ pceplib_free(PCEPLIB_INFRA, session_logic_event_queue_);
+ session_logic_handle_ = NULL;
+ session_logic_event_queue_ = NULL;
+ queue_destroy_with_data(session.num_unknown_messages_time_queue);
+ teardown_mock_socket_comm_info();
+}
+
+void create_message_for_test(uint8_t msg_type, bool free_msg_list_at_teardown,
+ bool was_msg_enqueued)
+{
+ /* See the comments in destroy_message_for_test() about these 2
+ * variables */
+ free_msg_list = free_msg_list_at_teardown;
+ msg_enqueued = was_msg_enqueued;
+
+ message = pceplib_malloc(PCEPLIB_MESSAGES, sizeof(struct pcep_message));
+ memset(message, 0, sizeof(struct pcep_message));
+
+ message->msg_header = pceplib_malloc(
+ PCEPLIB_MESSAGES, sizeof(struct pcep_message_header));
+ memset(message->msg_header, 0, sizeof(struct pcep_message_header));
+ message->obj_list = dll_initialize();
+ message->msg_header->type = msg_type;
+
+ msg_list = dll_initialize();
+ dll_append(msg_list, message);
+ event.received_msg_list = msg_list;
+}
+
+void destroy_message_for_test()
+{
+ /* Some test cases internally free the message list, so we dont
+ * want to double free it */
+ if (free_msg_list == true) {
+ /* This will destroy both the msg_list and the obj_list */
+ pcep_msg_free_message_list(msg_list);
+ }
+
+ /* Some tests cause the message to be enqueued and dont delete it,
+ * so we have to delete it here */
+ if (msg_enqueued == true) {
+ pcep_msg_free_message(message);
+ }
+}
+
+/*
+ * Test cases
+ */
+
+void test_handle_timer_event_dead_timer()
+{
+ /* Dead Timer expired */
+ event.expired_timer_id = session.timer_id_dead_timer = 100;
+
+ handle_timer_event(&event);
+
+ CU_ASSERT_EQUAL(session.timer_id_dead_timer, TIMER_ID_NOT_SET);
+ CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_INITIALIZED);
+ CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+ 1);
+
+ pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue);
+ CU_ASSERT_EQUAL(PCE_DEAD_TIMER_EXPIRED, e->event_type);
+ pceplib_free(PCEPLIB_INFRA, e);
+
+ /* verify_socket_comm_times_called(
+ * initialized, teardown, connect, send_message, close_after_write,
+ * close, destroy); */
+ verify_socket_comm_times_called(0, 0, 0, 1, 1, 0, 0);
+}
+
+
+void test_handle_timer_event_keep_alive()
+{
+ /* Keep Alive timer expired */
+ event.expired_timer_id = session.timer_id_keep_alive = 200;
+
+ handle_timer_event(&event);
+
+ CU_ASSERT_EQUAL(session.timer_id_keep_alive, TIMER_ID_NOT_SET);
+ verify_socket_comm_times_called(0, 0, 0, 1, 0, 0, 0);
+}
+
+
+void test_handle_timer_event_open_keep_wait()
+{
+ /* Open Keep Wait timer expired */
+ event.expired_timer_id = session.timer_id_open_keep_wait = 300;
+ session.session_state = SESSION_STATE_PCEP_CONNECTING;
+ handle_timer_event(&event);
+
+ CU_ASSERT_EQUAL(session.timer_id_open_keep_wait, TIMER_ID_NOT_SET);
+ CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_INITIALIZED);
+ CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+ 1);
+ verify_socket_comm_times_called(0, 0, 0, 0, 1, 0, 0);
+
+ pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue);
+ CU_ASSERT_EQUAL(PCE_OPEN_KEEP_WAIT_TIMER_EXPIRED, e->event_type);
+ pceplib_free(PCEPLIB_INFRA, e);
+
+ /* If the state is not SESSION_STATE_PCEP_CONNECTED, then nothing should
+ * happen */
+ reset_mock_socket_comm_info();
+ session.session_state = SESSION_STATE_UNKNOWN;
+ event.expired_timer_id = session.timer_id_open_keep_wait = 300;
+ handle_timer_event(&event);
+
+ CU_ASSERT_EQUAL(session.timer_id_open_keep_wait, 300);
+ CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_UNKNOWN);
+ verify_socket_comm_times_called(0, 0, 0, 0, 0, 0, 0);
+}
+
+
+void test_handle_timer_event_open_keep_alive()
+{
+ /* Open Keep Alive timer expired, but the Keep Alive should not be sent
+ * since the PCE Open has not been received yet */
+ event.expired_timer_id = session.timer_id_open_keep_alive = 300;
+ session.session_state = SESSION_STATE_PCEP_CONNECTING;
+ session.pce_open_keep_alive_sent = false;
+ session.pce_open_received = false;
+ handle_timer_event(&event);
+
+ CU_ASSERT_EQUAL(session.timer_id_open_keep_alive, TIMER_ID_NOT_SET);
+ CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_PCEP_CONNECTING);
+ CU_ASSERT_FALSE(session.pce_open_keep_alive_sent);
+
+ /* Open Keep Alive timer expired, the Keep Alive should be sent,
+ * but the session should not be connected, since the PCC Open
+ * has not been accepted yet */
+ event.expired_timer_id = session.timer_id_open_keep_alive = 300;
+ session.session_state = SESSION_STATE_PCEP_CONNECTING;
+ session.pce_open_keep_alive_sent = false;
+ session.pce_open_received = true;
+ session.pce_open_rejected = false;
+ session.pcc_open_accepted = false;
+ handle_timer_event(&event);
+
+ CU_ASSERT_EQUAL(session.timer_id_open_keep_alive, TIMER_ID_NOT_SET);
+ CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_PCEP_CONNECTING);
+ CU_ASSERT_TRUE(session.pce_open_keep_alive_sent);
+
+ /* Open Keep Alive timer expired, the Keep Alive should be sent,
+ * and the session is connected */
+ event.expired_timer_id = session.timer_id_open_keep_alive = 300;
+ session.session_state = SESSION_STATE_PCEP_CONNECTING;
+ session.pce_open_keep_alive_sent = false;
+ session.pce_open_received = true;
+ session.pce_open_rejected = false;
+ session.pcc_open_accepted = true;
+ handle_timer_event(&event);
+
+ CU_ASSERT_EQUAL(session.timer_id_open_keep_alive, TIMER_ID_NOT_SET);
+ CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_PCEP_CONNECTED);
+ CU_ASSERT_FALSE(session.pce_open_keep_alive_sent);
+}
+
+
+void test_handle_socket_comm_event_null_params()
+{
+ /* Verify it doesnt core dump */
+ handle_socket_comm_event(NULL);
+ verify_socket_comm_times_called(0, 0, 0, 0, 0, 0, 0);
+ reset_mock_socket_comm_info();
+
+ event.received_msg_list = NULL;
+ handle_socket_comm_event(&event);
+ verify_socket_comm_times_called(0, 0, 0, 0, 0, 0, 0);
+}
+
+
+void test_handle_socket_comm_event_close()
+{
+ event.socket_closed = true;
+ handle_socket_comm_event(&event);
+
+ CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_INITIALIZED);
+ CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+ 1);
+ verify_socket_comm_times_called(0, 0, 0, 0, 0, 1, 0);
+
+ pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue);
+ CU_ASSERT_EQUAL(PCE_CLOSED_SOCKET, e->event_type);
+ pceplib_free(PCEPLIB_INFRA, e);
+}
+
+
+void test_handle_socket_comm_event_open()
+{
+ /*
+ * Test when a PCE Open is received, but the PCC Open has not been
+ * accepted yet
+ */
+ create_message_for_test(PCEP_TYPE_OPEN, false, true);
+ struct pcep_object_open *open_object =
+ pcep_obj_create_open(1, 1, 1, NULL);
+ dll_append(message->obj_list, open_object);
+ session.pcc_open_accepted = false;
+ session.pce_open_received = false;
+ session.pce_open_accepted = false;
+ session.timer_id_open_keep_alive = 100;
+ session.session_state = SESSION_STATE_PCEP_CONNECTING;
+
+ handle_socket_comm_event(&event);
+
+ CU_ASSERT_TRUE(session.pce_open_received);
+ CU_ASSERT_TRUE(session.pce_open_accepted);
+ CU_ASSERT_FALSE(session.pce_open_rejected);
+ CU_ASSERT_FALSE(session.pce_open_keep_alive_sent);
+ CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_PCEP_CONNECTING);
+ CU_ASSERT_NOT_EQUAL(session.timer_id_open_keep_alive, 100);
+ /* A keep alive response should NOT be sent yet */
+ verify_socket_comm_times_called(0, 0, 0, 0, 0, 0, 0);
+ CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+ 1);
+ pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue);
+ CU_ASSERT_EQUAL(MESSAGE_RECEIVED, e->event_type);
+ CU_ASSERT_EQUAL(PCEP_TYPE_OPEN, e->message->msg_header->type);
+ pceplib_free(PCEPLIB_INFRA, e);
+ destroy_message_for_test();
+
+ /*
+ * Test when a PCE Open is received, and the PCC Open has been accepted
+ */
+ create_message_for_test(PCEP_TYPE_OPEN, false, true);
+ reset_mock_socket_comm_info();
+ open_object = pcep_obj_create_open(1, 1, 1, NULL);
+ dll_append(message->obj_list, open_object);
+ session.pcc_open_accepted = true;
+ session.pce_open_received = false;
+ session.pce_open_accepted = false;
+ session.session_state = SESSION_STATE_PCEP_CONNECTING;
+
+ handle_socket_comm_event(&event);
+
+ CU_ASSERT_TRUE(session.pce_open_received);
+ CU_ASSERT_TRUE(session.pce_open_accepted);
+ CU_ASSERT_FALSE(session.pce_open_rejected);
+ CU_ASSERT_TRUE(session.pce_open_keep_alive_sent);
+ CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_PCEP_CONNECTED);
+ /* A keep alive response should be sent, accepting the Open */
+ verify_socket_comm_times_called(0, 0, 0, 1, 0, 0, 0);
+ CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+ 2);
+ e = queue_dequeue(session_logic_event_queue_->event_queue);
+ CU_ASSERT_EQUAL(MESSAGE_RECEIVED, e->event_type);
+ CU_ASSERT_EQUAL(PCEP_TYPE_OPEN, e->message->msg_header->type);
+ pceplib_free(PCEPLIB_INFRA, e);
+ e = queue_dequeue(session_logic_event_queue_->event_queue);
+ CU_ASSERT_EQUAL(PCC_CONNECTED_TO_PCE, e->event_type);
+ pceplib_free(PCEPLIB_INFRA, e);
+ destroy_message_for_test();
+
+ /*
+ * Send a 2nd Open, an error should be sent
+ */
+ create_message_for_test(PCEP_TYPE_OPEN, false, false);
+ reset_mock_socket_comm_info();
+ mock_socket_comm_info *mock_info = get_mock_socket_comm_info();
+ mock_info->send_message_save_message = true;
+
+ handle_socket_comm_event(&event);
+
+ CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+ 0);
+ verify_socket_comm_times_called(0, 0, 0, 1, 0, 0, 0);
+ /* What gets saved in the mock is the msg byte buffer. The msg struct
+ * was deleted when it was sent. Instead of inspecting the msg byte
+ * buffer, lets just decode it. */
+ uint8_t *encoded_msg =
+ dll_delete_first_node(mock_info->sent_message_list);
+ CU_ASSERT_PTR_NOT_NULL(encoded_msg);
+ struct pcep_message *msg = pcep_decode_message(encoded_msg);
+ CU_ASSERT_PTR_NOT_NULL(msg);
+ CU_ASSERT_EQUAL(PCEP_TYPE_ERROR, msg->msg_header->type);
+ /* Verify the error object */
+ CU_ASSERT_EQUAL(1, msg->obj_list->num_entries);
+ struct pcep_object_error *error_obj = msg->obj_list->head->data;
+ CU_ASSERT_EQUAL(PCEP_OBJ_CLASS_ERROR, error_obj->header.object_class);
+ CU_ASSERT_EQUAL(PCEP_OBJ_TYPE_ERROR, error_obj->header.object_type);
+ CU_ASSERT_EQUAL(PCEP_ERRT_ATTEMPT_TO_ESTABLISH_2ND_PCEP_SESSION,
+ error_obj->error_type);
+ CU_ASSERT_EQUAL(PCEP_ERRV_RECVD_INVALID_OPEN_MSG,
+ error_obj->error_value);
+ pcep_msg_free_message(msg);
+ pceplib_free(PCEPLIB_MESSAGES, encoded_msg);
+}
+
+
+void test_handle_socket_comm_event_open_error()
+{
+ /* Test when the PCE rejects the PCC Open with an Error
+ * that a "corrected" Open message is sent. */
+
+ create_message_for_test(PCEP_TYPE_ERROR, false, true);
+ struct pcep_object_error *error_object = pcep_obj_create_error(
+ PCEP_ERRT_SESSION_FAILURE, PCEP_ERRV_UNACCEPTABLE_OPEN_MSG_NEG);
+ struct pcep_object_open *error_open_object =
+ pcep_obj_create_open(1, 1, 1, NULL);
+ /* The configured [Keep-alive, Dead-timer] values are [5, 5],
+ * this error open object will request they be changed to [10, 10] */
+ error_open_object->open_keepalive = 10;
+ error_open_object->open_deadtimer = 10;
+ dll_append(message->obj_list, error_object);
+ dll_append(message->obj_list, error_open_object);
+ session.session_state = SESSION_STATE_PCEP_CONNECTING;
+ mock_socket_comm_info *mock_info = get_mock_socket_comm_info();
+ mock_info->send_message_save_message = true;
+
+ handle_socket_comm_event(&event);
+
+ CU_ASSERT_TRUE(session.pcc_open_rejected);
+ CU_ASSERT_FALSE(session.pce_open_keep_alive_sent);
+ CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_PCEP_CONNECTING);
+ /* Another Open should be sent */
+ verify_socket_comm_times_called(0, 0, 0, 1, 0, 0, 0);
+ CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+ 2);
+
+ pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue);
+ CU_ASSERT_EQUAL(PCC_SENT_INVALID_OPEN, e->event_type);
+ pceplib_free(PCEPLIB_INFRA, e);
+
+ e = queue_dequeue(session_logic_event_queue_->event_queue);
+ CU_ASSERT_EQUAL(MESSAGE_RECEIVED, e->event_type);
+ CU_ASSERT_EQUAL(PCEP_TYPE_ERROR, e->message->msg_header->type);
+ pceplib_free(PCEPLIB_INFRA, e);
+
+ /* Check the Corrected Open Message */
+
+ /* What gets saved in the mock is the msg byte buffer. The msg struct
+ * was deleted when it was sent. Instead of inspecting the msg byte
+ * buffer, lets just decode it. */
+ uint8_t *encoded_msg =
+ dll_delete_first_node(mock_info->sent_message_list);
+ CU_ASSERT_PTR_NOT_NULL(encoded_msg);
+ struct pcep_message *open_msg_corrected =
+ pcep_decode_message(encoded_msg);
+ CU_ASSERT_PTR_NOT_NULL(open_msg_corrected);
+ struct pcep_object_open *open_object_corrected =
+ (struct pcep_object_open *)pcep_obj_get(
+ open_msg_corrected->obj_list, PCEP_OBJ_CLASS_OPEN);
+ CU_ASSERT_PTR_NOT_NULL(open_object_corrected);
+ /* Verify the Keep-alive and Dead timers have been negotiated */
+ CU_ASSERT_EQUAL(error_open_object->open_keepalive,
+ open_object_corrected->open_keepalive);
+ CU_ASSERT_EQUAL(error_open_object->open_deadtimer,
+ open_object_corrected->open_deadtimer);
+ CU_ASSERT_EQUAL(session.pcc_config.dead_timer_pce_negotiated_seconds,
+ open_object_corrected->open_deadtimer);
+ CU_ASSERT_EQUAL(
+ session.pcc_config.keep_alive_pce_negotiated_timer_seconds,
+ open_object_corrected->open_keepalive);
+ CU_ASSERT_NOT_EQUAL(
+ session.pcc_config.dead_timer_pce_negotiated_seconds,
+ session.pcc_config.dead_timer_seconds);
+ CU_ASSERT_NOT_EQUAL(
+ session.pcc_config.keep_alive_pce_negotiated_timer_seconds,
+ session.pcc_config.keep_alive_seconds);
+
+ pcep_msg_free_message(open_msg_corrected);
+ pceplib_free(PCEPLIB_MESSAGES, encoded_msg);
+}
+
+
+void test_handle_socket_comm_event_keep_alive()
+{
+ /* Test when a Keep Alive is received, but the PCE Open has not been
+ * received yet */
+ create_message_for_test(PCEP_TYPE_KEEPALIVE, false, false);
+ session.session_state = SESSION_STATE_PCEP_CONNECTING;
+ session.timer_id_dead_timer = 100;
+ session.timer_id_open_keep_wait = 200;
+ session.pce_open_accepted = false;
+ session.pce_open_received = false;
+ session.pcc_open_accepted = false;
+
+ handle_socket_comm_event(&event);
+
+ CU_ASSERT_TRUE(session.pcc_open_accepted);
+ CU_ASSERT_FALSE(session.pce_open_keep_alive_sent);
+ CU_ASSERT_FALSE(session.pcc_open_rejected);
+ CU_ASSERT_FALSE(session.pce_open_accepted);
+ CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_PCEP_CONNECTING);
+ CU_ASSERT_EQUAL(session.timer_id_open_keep_wait, TIMER_ID_NOT_SET);
+ CU_ASSERT_EQUAL(session.timer_id_dead_timer, 100);
+ verify_socket_comm_times_called(0, 0, 0, 0, 0, 0, 0);
+ CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+ 0);
+
+ /* Test when a Keep Alive is received, and the PCE Open has been
+ * received and accepted */
+ create_message_for_test(PCEP_TYPE_KEEPALIVE, false, false);
+ session.session_state = SESSION_STATE_PCEP_CONNECTING;
+ session.timer_id_dead_timer = 100;
+ session.timer_id_open_keep_wait = 200;
+ session.pce_open_received = true;
+ session.pce_open_accepted = true;
+ session.pcc_open_accepted = false;
+
+ handle_socket_comm_event(&event);
+
+ CU_ASSERT_TRUE(session.pcc_open_accepted);
+ CU_ASSERT_TRUE(session.pce_open_keep_alive_sent);
+ CU_ASSERT_FALSE(session.pcc_open_rejected);
+ CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_PCEP_CONNECTED);
+ CU_ASSERT_EQUAL(session.timer_id_open_keep_wait, TIMER_ID_NOT_SET);
+ CU_ASSERT_EQUAL(session.timer_id_dead_timer, 100);
+ verify_socket_comm_times_called(0, 0, 0, 1, 0, 0, 0);
+
+ /* Test when a Keep Alive is received, and the PCE Open has been
+ * received and rejected */
+ create_message_for_test(PCEP_TYPE_KEEPALIVE, false, false);
+ session.session_state = SESSION_STATE_PCEP_CONNECTING;
+ session.timer_id_dead_timer = 100;
+ session.timer_id_open_keep_wait = 200;
+ session.pce_open_received = true;
+ session.pce_open_accepted = false;
+ session.pce_open_rejected = true;
+ session.pce_open_keep_alive_sent = false;
+ session.pcc_open_accepted = true;
+
+ handle_socket_comm_event(&event);
+
+ CU_ASSERT_TRUE(session.pcc_open_accepted);
+ CU_ASSERT_FALSE(session.pce_open_keep_alive_sent);
+ CU_ASSERT_FALSE(session.pcc_open_rejected);
+ CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_PCEP_CONNECTING);
+ CU_ASSERT_EQUAL(session.timer_id_open_keep_wait, TIMER_ID_NOT_SET);
+ CU_ASSERT_EQUAL(session.timer_id_dead_timer, 100);
+ verify_socket_comm_times_called(0, 0, 0, 1, 0, 0, 0);
+
+ /* The session is considered connected, when both the
+ * PCE and PCC Open messages have been accepted */
+ pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue);
+ CU_ASSERT_EQUAL(PCC_CONNECTED_TO_PCE, e->event_type);
+ pceplib_free(PCEPLIB_INFRA, e);
+}
+
+
+void test_handle_socket_comm_event_pcrep()
+{
+ create_message_for_test(PCEP_TYPE_PCREP, false, true);
+ struct pcep_object_rp *rp =
+ pcep_obj_create_rp(1, true, true, true, true, 1, NULL);
+ dll_append(message->obj_list, rp);
+
+ handle_socket_comm_event(&event);
+
+ CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+ 1);
+ verify_socket_comm_times_called(0, 0, 0, 0, 0, 0, 0);
+ pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue);
+ CU_ASSERT_EQUAL(MESSAGE_RECEIVED, e->event_type);
+ pceplib_free(PCEPLIB_INFRA, e);
+}
+
+
+void test_handle_socket_comm_event_pcreq()
+{
+ create_message_for_test(PCEP_TYPE_PCREQ, false, false);
+ mock_socket_comm_info *mock_info = get_mock_socket_comm_info();
+ mock_info->send_message_save_message = true;
+
+ handle_socket_comm_event(&event);
+
+ /* The PCC does not support receiving PcReq messages, so an error should
+ * be sent */
+ CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+ 0);
+ verify_socket_comm_times_called(0, 0, 0, 1, 0, 0, 0);
+ uint8_t *encoded_msg =
+ dll_delete_first_node(mock_info->sent_message_list);
+ CU_ASSERT_PTR_NOT_NULL(encoded_msg);
+ struct pcep_message *error_msg = pcep_decode_message(encoded_msg);
+ CU_ASSERT_PTR_NOT_NULL(error_msg);
+ CU_ASSERT_EQUAL(PCEP_TYPE_ERROR, error_msg->msg_header->type);
+ /* Verify the error object */
+ CU_ASSERT_EQUAL(1, error_msg->obj_list->num_entries);
+ struct pcep_object_error *obj = error_msg->obj_list->head->data;
+ CU_ASSERT_EQUAL(PCEP_OBJ_CLASS_ERROR, obj->header.object_class);
+ CU_ASSERT_EQUAL(PCEP_OBJ_TYPE_ERROR, obj->header.object_type);
+ CU_ASSERT_EQUAL(PCEP_ERRT_CAPABILITY_NOT_SUPPORTED, obj->error_type);
+ CU_ASSERT_EQUAL(PCEP_ERRV_UNASSIGNED, obj->error_value);
+ pcep_msg_free_message(error_msg);
+ pceplib_free(PCEPLIB_MESSAGES, encoded_msg);
+}
+
+
+void test_handle_socket_comm_event_report()
+{
+ create_message_for_test(PCEP_TYPE_REPORT, false, false);
+ mock_socket_comm_info *mock_info = get_mock_socket_comm_info();
+ mock_info->send_message_save_message = true;
+
+ handle_socket_comm_event(&event);
+
+ /* The PCC does not support receiving Report messages, so an error
+ * should be sent */
+ CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+ 0);
+ verify_socket_comm_times_called(0, 0, 0, 1, 0, 0, 0);
+ uint8_t *encoded_msg =
+ dll_delete_first_node(mock_info->sent_message_list);
+ CU_ASSERT_PTR_NOT_NULL(encoded_msg);
+ struct pcep_message *error_msg = pcep_decode_message(encoded_msg);
+ CU_ASSERT_PTR_NOT_NULL(error_msg);
+ CU_ASSERT_EQUAL(PCEP_TYPE_ERROR, error_msg->msg_header->type);
+ /* Verify the error object */
+ CU_ASSERT_EQUAL(1, error_msg->obj_list->num_entries);
+ struct pcep_object_error *obj = error_msg->obj_list->head->data;
+ CU_ASSERT_EQUAL(PCEP_OBJ_CLASS_ERROR, obj->header.object_class);
+ CU_ASSERT_EQUAL(PCEP_OBJ_TYPE_ERROR, obj->header.object_type);
+ CU_ASSERT_EQUAL(PCEP_ERRT_CAPABILITY_NOT_SUPPORTED, obj->error_type);
+ CU_ASSERT_EQUAL(PCEP_ERRV_UNASSIGNED, obj->error_value);
+ pcep_msg_free_message(error_msg);
+ pceplib_free(PCEPLIB_MESSAGES, encoded_msg);
+}
+
+
+void test_handle_socket_comm_event_update()
+{
+ create_message_for_test(PCEP_TYPE_UPDATE, false, true);
+ struct pcep_object_srp *srp = pcep_obj_create_srp(false, 100, NULL);
+ struct pcep_object_lsp *lsp =
+ pcep_obj_create_lsp(100, PCEP_LSP_OPERATIONAL_UP, true, true,
+ true, true, true, NULL);
+ double_linked_list *ero_subobj_list = dll_initialize();
+ dll_append(ero_subobj_list, pcep_obj_create_ro_subobj_asn(0x0102));
+ struct pcep_object_ro *ero = pcep_obj_create_ero(ero_subobj_list);
+ struct pcep_object_metric *metric =
+ pcep_obj_create_metric(PCEP_METRIC_TE, false, true, 16.0);
+ dll_append(message->obj_list, srp);
+ dll_append(message->obj_list, lsp);
+ dll_append(message->obj_list, ero);
+ dll_append(message->obj_list, metric);
+ mock_socket_comm_info *mock_info = get_mock_socket_comm_info();
+ mock_info->send_message_save_message = true;
+
+ handle_socket_comm_event(&event);
+
+ CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+ 1);
+ verify_socket_comm_times_called(0, 0, 0, 0, 0, 0, 0);
+ pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue);
+ CU_ASSERT_EQUAL(MESSAGE_RECEIVED, e->event_type);
+ CU_ASSERT_EQUAL(PCEP_TYPE_UPDATE, e->message->msg_header->type);
+ pceplib_free(PCEPLIB_INFRA, e);
+}
+
+
+void test_handle_socket_comm_event_initiate()
+{
+ create_message_for_test(PCEP_TYPE_INITIATE, false, true);
+ struct pcep_object_srp *srp = pcep_obj_create_srp(false, 100, NULL);
+ struct pcep_object_lsp *lsp =
+ pcep_obj_create_lsp(100, PCEP_LSP_OPERATIONAL_UP, true, true,
+ true, true, true, NULL);
+ dll_append(message->obj_list, srp);
+ dll_append(message->obj_list, lsp);
+ mock_socket_comm_info *mock_info = get_mock_socket_comm_info();
+ mock_info->send_message_save_message = true;
+
+ handle_socket_comm_event(&event);
+
+ CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+ 1);
+ verify_socket_comm_times_called(0, 0, 0, 0, 0, 0, 0);
+ pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue);
+ CU_ASSERT_EQUAL(MESSAGE_RECEIVED, e->event_type);
+ CU_ASSERT_EQUAL(PCEP_TYPE_INITIATE, e->message->msg_header->type);
+ pceplib_free(PCEPLIB_INFRA, e);
+}
+
+
+void test_handle_socket_comm_event_notify()
+{
+ create_message_for_test(PCEP_TYPE_PCNOTF, false, true);
+ handle_socket_comm_event(&event);
+
+ CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+ 1);
+ verify_socket_comm_times_called(0, 0, 0, 0, 0, 0, 0);
+ pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue);
+ CU_ASSERT_EQUAL(MESSAGE_RECEIVED, e->event_type);
+ CU_ASSERT_EQUAL(PCEP_TYPE_PCNOTF, e->message->msg_header->type);
+ pceplib_free(PCEPLIB_INFRA, e);
+}
+
+
+void test_handle_socket_comm_event_error()
+{
+ create_message_for_test(PCEP_TYPE_ERROR, false, true);
+ handle_socket_comm_event(&event);
+
+ CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+ 1);
+ verify_socket_comm_times_called(0, 0, 0, 0, 0, 0, 0);
+ pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue);
+ CU_ASSERT_EQUAL(MESSAGE_RECEIVED, e->event_type);
+ CU_ASSERT_EQUAL(PCEP_TYPE_ERROR, e->message->msg_header->type);
+ pceplib_free(PCEPLIB_INFRA, e);
+}
+
+
+void test_handle_socket_comm_event_unknown_msg()
+{
+ create_message_for_test(13, false, false);
+ mock_socket_comm_info *mock_info = get_mock_socket_comm_info();
+ mock_info->send_message_save_message = true;
+
+ handle_socket_comm_event(&event);
+
+ /* Sending an unsupported message type, so an error should be sent,
+ * but the connection should remain open, since max_unknown_messages = 2
+ */
+ CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+ 0);
+ verify_socket_comm_times_called(0, 0, 0, 1, 0, 0, 0);
+ uint8_t *encoded_msg =
+ dll_delete_first_node(mock_info->sent_message_list);
+ CU_ASSERT_PTR_NOT_NULL(encoded_msg);
+ struct pcep_message *msg = pcep_decode_message(encoded_msg);
+ CU_ASSERT_PTR_NOT_NULL(msg);
+ CU_ASSERT_EQUAL(PCEP_TYPE_ERROR, msg->msg_header->type);
+ /* Verify the error object */
+ CU_ASSERT_EQUAL(1, msg->obj_list->num_entries);
+ struct pcep_object_error *error_obj = msg->obj_list->head->data;
+ CU_ASSERT_EQUAL(PCEP_OBJ_CLASS_ERROR, error_obj->header.object_class);
+ CU_ASSERT_EQUAL(PCEP_OBJ_TYPE_ERROR, error_obj->header.object_type);
+ CU_ASSERT_EQUAL(PCEP_ERRT_CAPABILITY_NOT_SUPPORTED,
+ error_obj->error_type);
+ CU_ASSERT_EQUAL(PCEP_ERRV_UNASSIGNED, error_obj->error_value);
+ pcep_msg_free_message(msg);
+ pceplib_free(PCEPLIB_MESSAGES, encoded_msg);
+ destroy_message_for_test();
+
+ /* Send another unsupported message type, an error should be sent and
+ * the connection should be closed, since max_unknown_messages = 2 */
+ create_message_for_test(13, false, false);
+ reset_mock_socket_comm_info();
+ mock_info = get_mock_socket_comm_info();
+ mock_info->send_message_save_message = true;
+
+ handle_socket_comm_event(&event);
+
+ verify_socket_comm_times_called(0, 0, 0, 2, 1, 0, 0);
+ CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+ 1);
+ pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue);
+ CU_ASSERT_EQUAL(PCC_RCVD_MAX_UNKOWN_MSGS, e->event_type);
+ pceplib_free(PCEPLIB_INFRA, e);
+
+ /* Verify the error message */
+ encoded_msg = dll_delete_first_node(mock_info->sent_message_list);
+ CU_ASSERT_PTR_NOT_NULL(encoded_msg);
+ msg = pcep_decode_message(encoded_msg);
+ CU_ASSERT_PTR_NOT_NULL(msg);
+ CU_ASSERT_EQUAL(PCEP_TYPE_ERROR, msg->msg_header->type);
+ /* Verify the error object */
+ CU_ASSERT_EQUAL(1, msg->obj_list->num_entries);
+ error_obj = msg->obj_list->head->data;
+ CU_ASSERT_EQUAL(PCEP_OBJ_CLASS_ERROR, error_obj->header.object_class);
+ CU_ASSERT_EQUAL(PCEP_OBJ_TYPE_ERROR, error_obj->header.object_type);
+ CU_ASSERT_EQUAL(PCEP_ERRT_CAPABILITY_NOT_SUPPORTED,
+ error_obj->error_type);
+ CU_ASSERT_EQUAL(PCEP_ERRV_UNASSIGNED, error_obj->error_value);
+ pcep_msg_free_message(msg);
+ pceplib_free(PCEPLIB_MESSAGES, encoded_msg);
+
+ /* Verify the Close message */
+ encoded_msg = dll_delete_first_node(mock_info->sent_message_list);
+ CU_ASSERT_PTR_NOT_NULL(encoded_msg);
+ msg = pcep_decode_message(encoded_msg);
+ CU_ASSERT_PTR_NOT_NULL(msg);
+ CU_ASSERT_EQUAL(PCEP_TYPE_CLOSE, msg->msg_header->type);
+ /* Verify the error object */
+ CU_ASSERT_EQUAL(1, msg->obj_list->num_entries);
+ struct pcep_object_close *close_obj = msg->obj_list->head->data;
+ CU_ASSERT_EQUAL(PCEP_OBJ_CLASS_CLOSE, close_obj->header.object_class);
+ CU_ASSERT_EQUAL(PCEP_OBJ_TYPE_CLOSE, close_obj->header.object_type);
+ CU_ASSERT_EQUAL(PCEP_CLOSE_REASON_UNREC_MSG, close_obj->reason);
+ pcep_msg_free_message(msg);
+ pceplib_free(PCEPLIB_MESSAGES, encoded_msg);
+}
+
+
+void test_connection_failure(void)
+{
+ /*
+ * Test when 2 invalid Open messages are received that a
+ * PCC_CONNECTION_FAILURE event is generated.
+ */
+ create_message_for_test(PCEP_TYPE_OPEN, false, false);
+ reset_mock_socket_comm_info();
+ struct pcep_object_open *open_object =
+ pcep_obj_create_open(1, 1, 1, NULL);
+ /* Make the Open message invalid */
+ open_object->open_deadtimer =
+ session.pcc_config.max_dead_timer_seconds + 1;
+ dll_append(message->obj_list, open_object);
+ session.pce_open_received = false;
+ session.pce_open_accepted = false;
+ session.pce_open_rejected = false;
+ session.session_state = SESSION_STATE_PCEP_CONNECTING;
+
+ handle_socket_comm_event(&event);
+
+ CU_ASSERT_TRUE(session.pce_open_received);
+ CU_ASSERT_TRUE(session.pce_open_rejected);
+ CU_ASSERT_FALSE(session.pce_open_accepted);
+ CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_PCEP_CONNECTING);
+ /* An error response should be sent, rejecting the Open */
+ verify_socket_comm_times_called(0, 0, 0, 1, 0, 0, 0);
+ CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+ 1);
+ pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue);
+ CU_ASSERT_EQUAL(PCC_RCVD_INVALID_OPEN, e->event_type);
+ pceplib_free(PCEPLIB_INFRA, e);
+ destroy_message_for_test();
+
+ /* Send the same erroneous Open again */
+ create_message_for_test(PCEP_TYPE_OPEN, false, false);
+ reset_mock_socket_comm_info();
+ open_object = pcep_obj_create_open(1, 1, 1, NULL);
+ /* Make the Open message invalid */
+ open_object->open_deadtimer =
+ session.pcc_config.max_dead_timer_seconds + 1;
+ dll_append(message->obj_list, open_object);
+
+ handle_socket_comm_event(&event);
+
+ CU_ASSERT_TRUE(session.pce_open_received);
+ CU_ASSERT_TRUE(session.pce_open_rejected);
+ CU_ASSERT_FALSE(session.pce_open_accepted);
+ CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_INITIALIZED);
+ /* An error response should be sent, rejecting the Open */
+ verify_socket_comm_times_called(0, 0, 0, 1, 1, 0, 0);
+ CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+ 2);
+ e = queue_dequeue(session_logic_event_queue_->event_queue);
+ CU_ASSERT_EQUAL(PCC_RCVD_INVALID_OPEN, e->event_type);
+ pceplib_free(PCEPLIB_INFRA, e);
+ e = queue_dequeue(session_logic_event_queue_->event_queue);
+ CU_ASSERT_EQUAL(PCC_CONNECTION_FAILURE, e->event_type);
+ pceplib_free(PCEPLIB_INFRA, e);
+
+ destroy_message_for_test();
+
+ /*
+ * Test when 2 invalid Open messages are sent that a
+ * PCC_CONNECTION_FAILURE event is generated.
+ */
+ create_message_for_test(PCEP_TYPE_ERROR, false, false);
+ reset_mock_socket_comm_info();
+ struct pcep_object_error *error_object = pcep_obj_create_error(
+ PCEP_ERRT_SESSION_FAILURE, PCEP_ERRV_UNACCEPTABLE_OPEN_MSG_NEG);
+ dll_append(message->obj_list, error_object);
+ session.pcc_open_accepted = false;
+ session.pcc_open_rejected = false;
+ session.session_state = SESSION_STATE_PCEP_CONNECTING;
+
+ handle_socket_comm_event(&event);
+
+ CU_ASSERT_TRUE(session.pcc_open_rejected);
+ CU_ASSERT_FALSE(session.pcc_open_accepted);
+ CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_PCEP_CONNECTING);
+ /* Another Open should be sent */
+ verify_socket_comm_times_called(0, 0, 0, 1, 0, 0, 0);
+ CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+ 2);
+ e = queue_dequeue(session_logic_event_queue_->event_queue);
+ CU_ASSERT_EQUAL(PCC_SENT_INVALID_OPEN, e->event_type);
+ pceplib_free(PCEPLIB_INFRA, e);
+ e = queue_dequeue(session_logic_event_queue_->event_queue);
+ CU_ASSERT_EQUAL(MESSAGE_RECEIVED, e->event_type);
+ CU_ASSERT_EQUAL(PCEP_TYPE_ERROR, e->message->msg_header->type);
+ pceplib_free(PCEPLIB_INFRA, e);
+ destroy_message_for_test();
+
+ /* Send a socket close while connecting, which should
+ * generate a PCC_CONNECTION_FAILURE event */
+ reset_mock_socket_comm_info();
+ event.socket_closed = true;
+ event.received_msg_list = NULL;
+
+ handle_socket_comm_event(&event);
+
+ CU_ASSERT_TRUE(session.pcc_open_rejected);
+ CU_ASSERT_FALSE(session.pcc_open_accepted);
+ CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_INITIALIZED);
+ verify_socket_comm_times_called(0, 0, 0, 0, 0, 1, 0);
+ CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+ 2);
+ e = queue_dequeue(session_logic_event_queue_->event_queue);
+ CU_ASSERT_EQUAL(PCE_CLOSED_SOCKET, e->event_type);
+ pceplib_free(PCEPLIB_INFRA, e);
+ e = queue_dequeue(session_logic_event_queue_->event_queue);
+ CU_ASSERT_EQUAL(PCC_CONNECTION_FAILURE, e->event_type);
+ pceplib_free(PCEPLIB_INFRA, e);
+}
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Javier Garcia <javier.garcia@voltanet.io>
+ *
+ */
+
+/*
+ * Timer definitions to be used internally by the pcep_timers library.
+ */
+
+#ifndef PCEP_SESSION_LOGIC_STATES_TEST_H
+#define PCEP_SESSION_LOGIC_STATES_TEST_H
+
+int pcep_session_logic_states_test_suite_setup(void);
+int pcep_session_logic_states_test_suite_teardown(void);
+void pcep_session_logic_states_test_setup(void);
+void pcep_session_logic_states_test_teardown(void);
+void test_handle_timer_event_dead_timer(void);
+void test_handle_timer_event_keep_alive(void);
+void test_handle_timer_event_open_keep_wait(void);
+void test_handle_socket_comm_event_null_params(void);
+void test_handle_socket_comm_event_close(void);
+void test_handle_socket_comm_event_open(void);
+void test_handle_socket_comm_event_open_error(void);
+void test_handle_socket_comm_event_keep_alive(void);
+void test_handle_socket_comm_event_pcrep(void);
+void test_handle_socket_comm_event_pcreq(void);
+void test_handle_socket_comm_event_report(void);
+void test_handle_socket_comm_event_update(void);
+void test_handle_socket_comm_event_initiate(void);
+void test_handle_socket_comm_event_notify(void);
+void test_handle_socket_comm_event_error(void);
+void test_handle_socket_comm_event_unknown_msg(void);
+void test_connection_failure(void);
+
+#endif /* PCEPTIMERINTERNALS_H_ */
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <CUnit/CUnit.h>
+
+#include "pcep_socket_comm_mock.h"
+#include "pcep_session_logic.h"
+#include "pcep_session_logic_test.h"
+
+/*
+ * Test suite setup and teardown called before AND after the test suite.
+ */
+
+int pcep_session_logic_test_suite_setup(void)
+{
+ pceplib_memory_reset();
+ return 0;
+}
+
+int pcep_session_logic_test_suite_teardown(void)
+{
+ printf("\n");
+ pceplib_memory_dump();
+ return 0;
+}
+
+/*
+ * Test case setup and teardown called before AND after each test.
+ */
+
+void pcep_session_logic_test_setup()
+{
+ setup_mock_socket_comm_info();
+}
+
+
+void pcep_session_logic_test_teardown()
+{
+ stop_session_logic();
+ teardown_mock_socket_comm_info();
+}
+
+
+/*
+ * Test cases
+ */
+
+void test_run_stop_session_logic()
+{
+ CU_ASSERT_TRUE(run_session_logic());
+ CU_ASSERT_TRUE(stop_session_logic());
+}
+
+
+void test_run_session_logic_twice()
+{
+ CU_ASSERT_TRUE(run_session_logic());
+ CU_ASSERT_FALSE(run_session_logic());
+}
+
+
+void test_session_logic_without_run()
+{
+ /* Verify the functions that depend on run_session_logic() being called
+ */
+ CU_ASSERT_FALSE(stop_session_logic());
+}
+
+
+void test_create_pcep_session_null_params()
+{
+ pcep_configuration config;
+ struct in_addr pce_ip;
+
+ CU_ASSERT_PTR_NULL(create_pcep_session(NULL, NULL));
+ CU_ASSERT_PTR_NULL(create_pcep_session(NULL, &pce_ip));
+ CU_ASSERT_PTR_NULL(create_pcep_session(&config, NULL));
+}
+
+
+void test_create_destroy_pcep_session()
+{
+ pcep_session *session;
+ pcep_configuration config;
+ struct in_addr pce_ip;
+
+ run_session_logic();
+
+ memset(&config, 0, sizeof(pcep_configuration));
+ config.keep_alive_seconds = 5;
+ config.dead_timer_seconds = 5;
+ config.request_time_seconds = 5;
+ config.max_unknown_messages = 5;
+ config.max_unknown_requests = 5;
+ inet_pton(AF_INET, "127.0.0.1", &(pce_ip));
+
+ mock_socket_comm_info *mock_info = get_mock_socket_comm_info();
+ mock_info->send_message_save_message = true;
+ session = create_pcep_session(&config, &pce_ip);
+ CU_ASSERT_PTR_NOT_NULL(session);
+ /* What gets saved in the mock is the msg byte buffer. The msg struct
+ * was deleted when it was sent. Instead of inspecting the msg byte
+ * buffer, lets just decode it. */
+ uint8_t *encoded_msg =
+ dll_delete_first_node(mock_info->sent_message_list);
+ CU_ASSERT_PTR_NOT_NULL(encoded_msg);
+ struct pcep_message *open_msg = pcep_decode_message(encoded_msg);
+ CU_ASSERT_PTR_NOT_NULL(open_msg);
+ /* Should be an Open, with no TLVs: length = 12 */
+ CU_ASSERT_EQUAL(open_msg->msg_header->type, PCEP_TYPE_OPEN);
+ CU_ASSERT_EQUAL(open_msg->encoded_message_length, 12);
+ destroy_pcep_session(session);
+ pcep_msg_free_message(open_msg);
+ pceplib_free(PCEPLIB_MESSAGES, encoded_msg);
+
+ stop_session_logic();
+}
+
+
+void test_create_destroy_pcep_session_ipv6()
+{
+ pcep_session *session;
+ pcep_configuration config;
+ struct in6_addr pce_ip;
+
+ run_session_logic();
+
+ memset(&config, 0, sizeof(pcep_configuration));
+ config.keep_alive_seconds = 5;
+ config.dead_timer_seconds = 5;
+ config.request_time_seconds = 5;
+ config.max_unknown_messages = 5;
+ config.max_unknown_requests = 5;
+ config.is_src_ipv6 = true;
+ inet_pton(AF_INET6, "::1", &pce_ip);
+
+ mock_socket_comm_info *mock_info = get_mock_socket_comm_info();
+ mock_info->send_message_save_message = true;
+ session = create_pcep_session_ipv6(&config, &pce_ip);
+ CU_ASSERT_PTR_NOT_NULL(session);
+ CU_ASSERT_TRUE(session->socket_comm_session->is_ipv6);
+ /* What gets saved in the mock is the msg byte buffer. The msg struct
+ * was deleted when it was sent. Instead of inspecting the msg byte
+ * buffer, lets just decode it. */
+ uint8_t *encoded_msg =
+ dll_delete_first_node(mock_info->sent_message_list);
+ CU_ASSERT_PTR_NOT_NULL(encoded_msg);
+ struct pcep_message *open_msg = pcep_decode_message(encoded_msg);
+ CU_ASSERT_PTR_NOT_NULL(open_msg);
+ /* Should be an Open, with no TLVs: length = 12 */
+ CU_ASSERT_EQUAL(open_msg->msg_header->type, PCEP_TYPE_OPEN);
+ CU_ASSERT_EQUAL(open_msg->encoded_message_length, 12);
+ destroy_pcep_session(session);
+ pcep_msg_free_message(open_msg);
+ pceplib_free(PCEPLIB_MESSAGES, encoded_msg);
+
+ stop_session_logic();
+}
+
+
+void test_create_pcep_session_open_tlvs()
+{
+ pcep_session *session;
+ struct in_addr pce_ip;
+ struct pcep_message *open_msg;
+ struct pcep_object_header *open_obj;
+ pcep_configuration config;
+ memset(&config, 0, sizeof(pcep_configuration));
+ config.pcep_msg_versioning = create_default_pcep_versioning();
+ inet_pton(AF_INET, "127.0.0.1", &(pce_ip));
+
+ run_session_logic();
+
+ /* Verify the created Open message only has 1 TLV:
+ * pcep_tlv_create_stateful_pce_capability() */
+ mock_socket_comm_info *mock_info = get_mock_socket_comm_info();
+ mock_info->send_message_save_message = true;
+ config.support_stateful_pce_lsp_update = true;
+ config.pcep_msg_versioning->draft_ietf_pce_segment_routing_07 = false;
+ config.support_sr_te_pst = false;
+
+ session = create_pcep_session(&config, &pce_ip);
+ CU_ASSERT_PTR_NOT_NULL(session);
+ /* Get and verify the Open Message */
+ uint8_t *encoded_msg =
+ dll_delete_first_node(mock_info->sent_message_list);
+ CU_ASSERT_PTR_NOT_NULL(encoded_msg);
+ open_msg = pcep_decode_message(encoded_msg);
+ CU_ASSERT_PTR_NOT_NULL(open_msg);
+ /* Get and verify the Open Message objects */
+ CU_ASSERT_PTR_NOT_NULL(open_msg->obj_list);
+ CU_ASSERT_TRUE(open_msg->obj_list->num_entries > 0);
+ /* Get and verify the Open object */
+ open_obj = pcep_obj_get(open_msg->obj_list, PCEP_OBJ_CLASS_OPEN);
+ CU_ASSERT_PTR_NOT_NULL(open_obj);
+ /* Get and verify the Open object TLVs */
+ CU_ASSERT_PTR_NOT_NULL(open_obj->tlv_list);
+ CU_ASSERT_EQUAL(open_obj->tlv_list->num_entries, 1);
+ CU_ASSERT_EQUAL(((struct pcep_object_tlv_header *)
+ open_obj->tlv_list->head->data)
+ ->type,
+ PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY);
+
+ destroy_pcep_session(session);
+ pcep_msg_free_message(open_msg);
+ pceplib_free(PCEPLIB_MESSAGES, encoded_msg);
+
+ /* Verify the created Open message only has 2 TLVs:
+ * pcep_tlv_create_stateful_pce_capability()
+ * pcep_tlv_create_lsp_db_version() */
+ reset_mock_socket_comm_info();
+ mock_info->send_message_save_message = true;
+ config.support_include_db_version = true;
+ config.lsp_db_version = 100;
+
+ session = create_pcep_session(&config, &pce_ip);
+ CU_ASSERT_PTR_NOT_NULL(session);
+ /* Get and verify the Open Message */
+ encoded_msg = dll_delete_first_node(mock_info->sent_message_list);
+ CU_ASSERT_PTR_NOT_NULL(encoded_msg);
+ open_msg = pcep_decode_message(encoded_msg);
+ CU_ASSERT_PTR_NOT_NULL(open_msg);
+ /* Get and verify the Open Message objects */
+ CU_ASSERT_PTR_NOT_NULL(open_msg->obj_list);
+ CU_ASSERT_TRUE(open_msg->obj_list->num_entries > 0);
+ /* Get and verify the Open object */
+ open_obj = pcep_obj_get(open_msg->obj_list, PCEP_OBJ_CLASS_OPEN);
+ CU_ASSERT_PTR_NOT_NULL(open_obj);
+ /* Get and verify the Open object TLVs */
+ CU_ASSERT_PTR_NOT_NULL(open_obj->tlv_list);
+ CU_ASSERT_EQUAL(open_obj->tlv_list->num_entries, 2);
+ CU_ASSERT_EQUAL(((struct pcep_object_tlv_header *)
+ open_obj->tlv_list->head->data)
+ ->type,
+ PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY);
+ CU_ASSERT_EQUAL(((struct pcep_object_tlv_header *)
+ open_obj->tlv_list->head->next_node->data)
+ ->type,
+ PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION);
+
+ destroy_pcep_session(session);
+ pcep_msg_free_message(open_msg);
+ pceplib_free(PCEPLIB_MESSAGES, encoded_msg);
+
+
+ /* Verify the created Open message only has 4 TLVs:
+ * pcep_tlv_create_stateful_pce_capability()
+ * pcep_tlv_create_lsp_db_version()
+ * pcep_tlv_create_sr_pce_capability()
+ * pcep_tlv_create_path_setup_type_capability() */
+ reset_mock_socket_comm_info();
+ mock_info->send_message_save_message = true;
+ config.support_sr_te_pst = true;
+
+ session = create_pcep_session(&config, &pce_ip);
+ CU_ASSERT_PTR_NOT_NULL(session);
+ /* Get and verify the Open Message */
+ encoded_msg = dll_delete_first_node(mock_info->sent_message_list);
+ CU_ASSERT_PTR_NOT_NULL(encoded_msg);
+ open_msg = pcep_decode_message(encoded_msg);
+ CU_ASSERT_PTR_NOT_NULL(open_msg);
+ /* Get and verify the Open Message objects */
+ CU_ASSERT_PTR_NOT_NULL(open_msg->obj_list);
+ CU_ASSERT_TRUE(open_msg->obj_list->num_entries > 0);
+ /* Get and verify the Open object */
+ open_obj = pcep_obj_get(open_msg->obj_list, PCEP_OBJ_CLASS_OPEN);
+ CU_ASSERT_PTR_NOT_NULL(open_obj);
+ /* Get and verify the Open object TLVs */
+ CU_ASSERT_PTR_NOT_NULL(open_obj->tlv_list);
+ CU_ASSERT_EQUAL(open_obj->tlv_list->num_entries, 3);
+ double_linked_list_node *tlv_node = open_obj->tlv_list->head;
+ CU_ASSERT_EQUAL(((struct pcep_object_tlv_header *)tlv_node->data)->type,
+ PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY);
+ tlv_node = tlv_node->next_node;
+ CU_ASSERT_EQUAL(((struct pcep_object_tlv_header *)tlv_node->data)->type,
+ PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION);
+ tlv_node = tlv_node->next_node;
+ CU_ASSERT_EQUAL(((struct pcep_object_tlv_header *)tlv_node->data)->type,
+ PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY);
+
+ destroy_pcep_session(session);
+ pcep_msg_free_message(open_msg);
+ pceplib_free(PCEPLIB_MESSAGES, encoded_msg);
+
+ /* Verify the created Open message only has 4 TLVs:
+ * pcep_tlv_create_stateful_pce_capability()
+ * pcep_tlv_create_lsp_db_version()
+ * pcep_tlv_create_sr_pce_capability()
+ * pcep_tlv_create_path_setup_type_capability() */
+ reset_mock_socket_comm_info();
+ mock_info->send_message_save_message = true;
+ config.pcep_msg_versioning->draft_ietf_pce_segment_routing_07 = true;
+
+ session = create_pcep_session(&config, &pce_ip);
+ CU_ASSERT_PTR_NOT_NULL(session);
+ /* Get and verify the Open Message */
+ encoded_msg = dll_delete_first_node(mock_info->sent_message_list);
+ CU_ASSERT_PTR_NOT_NULL(encoded_msg);
+ open_msg = pcep_decode_message(encoded_msg);
+ CU_ASSERT_PTR_NOT_NULL(open_msg);
+ /* Get and verify the Open Message objects */
+ CU_ASSERT_PTR_NOT_NULL(open_msg->obj_list);
+ CU_ASSERT_TRUE(open_msg->obj_list->num_entries > 0);
+ /* Get and verify the Open object */
+ open_obj = pcep_obj_get(open_msg->obj_list, PCEP_OBJ_CLASS_OPEN);
+ CU_ASSERT_PTR_NOT_NULL(open_obj);
+ /* Get and verify the Open object TLVs */
+ CU_ASSERT_PTR_NOT_NULL(open_obj->tlv_list);
+ CU_ASSERT_EQUAL(open_obj->tlv_list->num_entries, 4);
+ tlv_node = open_obj->tlv_list->head;
+ CU_ASSERT_EQUAL(((struct pcep_object_tlv_header *)tlv_node->data)->type,
+ PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY);
+ tlv_node = tlv_node->next_node;
+ CU_ASSERT_EQUAL(((struct pcep_object_tlv_header *)tlv_node->data)->type,
+ PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION);
+ tlv_node = tlv_node->next_node;
+ CU_ASSERT_EQUAL(((struct pcep_object_tlv_header *)tlv_node->data)->type,
+ PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY);
+ tlv_node = tlv_node->next_node;
+ CU_ASSERT_EQUAL(((struct pcep_object_tlv_header *)tlv_node->data)->type,
+ PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY);
+
+ destroy_pcep_versioning(config.pcep_msg_versioning);
+ destroy_pcep_session(session);
+ pcep_msg_free_message(open_msg);
+ pceplib_free(PCEPLIB_MESSAGES, encoded_msg);
+
+ stop_session_logic();
+}
+
+
+void test_destroy_pcep_session_null_session()
+{
+ /* Just testing that it does not core dump */
+ destroy_pcep_session(NULL);
+}
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Javier Garcia <javier.garcia@voltanet.io>
+ *
+ */
+
+/*
+ * Timer definitions to be used internally by the pcep_timers library.
+ */
+
+#ifndef PCEP_SESSION_LOGIC_TEST_H_
+#define PCEP_SESSION_LOGIC_TEST_H_
+
+int pcep_session_logic_test_suite_setup(void);
+int pcep_session_logic_test_suite_teardown(void);
+void pcep_session_logic_test_setup(void);
+void pcep_session_logic_test_teardown(void);
+void test_run_stop_session_logic(void);
+void test_run_session_logic_twice(void);
+void test_session_logic_without_run(void);
+void test_create_pcep_session_null_params(void);
+void test_create_destroy_pcep_session(void);
+void test_create_destroy_pcep_session_ipv6(void);
+void test_create_pcep_session_open_tlvs(void);
+void test_destroy_pcep_session_null_session(void);
+
+#endif /* PCEPTIMERINTERNALS_H_ */
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <CUnit/Basic.h>
+#include <CUnit/CUnit.h>
+#include <CUnit/TestDB.h>
+
+#include "pcep_session_logic_loop_test.h"
+#include "pcep_session_logic_states_test.h"
+#include "pcep_session_logic_test.h"
+
+
+int main(int argc, char **argv)
+{
+ /* Unused parameters cause compilation warnings */
+ (void)argc;
+ (void)argv;
+
+ CU_initialize_registry();
+
+ /*
+ * Tests defined in pcep_socket_comm_test.c
+ */
+ CU_pSuite test_session_logic_suite =
+ CU_add_suite_with_setup_and_teardown(
+ "PCEP Session Logic Test Suite",
+ pcep_session_logic_test_suite_setup, // suite setup and
+ // cleanup function
+ // pointers
+ pcep_session_logic_test_suite_teardown,
+ pcep_session_logic_test_setup, // test case setup
+ // function pointer
+ pcep_session_logic_test_teardown); // test case teardown
+ // function pointer
+
+ CU_add_test(test_session_logic_suite, "test_run_stop_session_logic",
+ test_run_stop_session_logic);
+ CU_add_test(test_session_logic_suite, "test_run_session_logic_twice",
+ test_run_session_logic_twice);
+ CU_add_test(test_session_logic_suite, "test_session_logic_without_run",
+ test_session_logic_without_run);
+ CU_add_test(test_session_logic_suite,
+ "test_create_pcep_session_null_params",
+ test_create_pcep_session_null_params);
+ CU_add_test(test_session_logic_suite,
+ "test_create_destroy_pcep_session",
+ test_create_destroy_pcep_session);
+ CU_add_test(test_session_logic_suite,
+ "test_create_destroy_pcep_session_ipv6",
+ test_create_destroy_pcep_session_ipv6);
+ CU_add_test(test_session_logic_suite,
+ "test_create_pcep_session_open_tlvs",
+ test_create_pcep_session_open_tlvs);
+ CU_add_test(test_session_logic_suite,
+ "test_destroy_pcep_session_null_session",
+ test_destroy_pcep_session_null_session);
+
+ CU_pSuite test_session_logic_loop_suite =
+ CU_add_suite_with_setup_and_teardown(
+ "PCEP Session Logic Loop Test Suite",
+ pcep_session_logic_loop_test_suite_setup, // suite setup
+ // and cleanup
+ // function
+ // pointers
+ pcep_session_logic_loop_test_suite_teardown,
+ pcep_session_logic_loop_test_setup, // test case setup
+ // function pointer
+ pcep_session_logic_loop_test_teardown); // test case
+ // teardown
+ // function
+ // pointer
+
+ CU_add_test(test_session_logic_loop_suite,
+ "test_session_logic_loop_null_data",
+ test_session_logic_loop_null_data);
+ CU_add_test(test_session_logic_loop_suite,
+ "test_session_logic_loop_inactive",
+ test_session_logic_loop_inactive);
+ CU_add_test(test_session_logic_loop_suite,
+ "test_session_logic_msg_ready_handler",
+ test_session_logic_msg_ready_handler);
+ CU_add_test(test_session_logic_loop_suite,
+ "test_session_logic_conn_except_notifier",
+ test_session_logic_conn_except_notifier);
+ CU_add_test(test_session_logic_loop_suite,
+ "test_session_logic_timer_expire_handler",
+ test_session_logic_timer_expire_handler);
+
+ CU_pSuite test_session_logic_states_suite =
+ CU_add_suite_with_setup_and_teardown(
+ "PCEP Session Logic States Test Suite",
+ pcep_session_logic_states_test_suite_setup, // suite
+ // setup and
+ // cleanup
+ // function
+ // pointers
+ pcep_session_logic_states_test_suite_teardown,
+ pcep_session_logic_states_test_setup, // test case setup
+ // function
+ // pointer
+ pcep_session_logic_states_test_teardown); // test case
+ // teardown
+ // function
+ // pointer
+
+ CU_add_test(test_session_logic_states_suite,
+ "test_handle_timer_event_dead_timer",
+ test_handle_timer_event_dead_timer);
+ CU_add_test(test_session_logic_states_suite,
+ "test_handle_timer_event_keep_alive",
+ test_handle_timer_event_keep_alive);
+ CU_add_test(test_session_logic_states_suite,
+ "test_handle_timer_event_open_keep_wait",
+ test_handle_timer_event_open_keep_wait);
+ CU_add_test(test_session_logic_states_suite,
+ "test_handle_socket_comm_event_null_params",
+ test_handle_socket_comm_event_null_params);
+ CU_add_test(test_session_logic_states_suite,
+ "test_handle_socket_comm_event_close",
+ test_handle_socket_comm_event_close);
+ CU_add_test(test_session_logic_states_suite,
+ "test_handle_socket_comm_event_open",
+ test_handle_socket_comm_event_open);
+ CU_add_test(test_session_logic_states_suite,
+ "test_handle_socket_comm_event_open_error",
+ test_handle_socket_comm_event_open_error);
+ CU_add_test(test_session_logic_states_suite,
+ "test_handle_socket_comm_event_keep_alive",
+ test_handle_socket_comm_event_keep_alive);
+ CU_add_test(test_session_logic_states_suite,
+ "test_handle_socket_comm_event_pcrep",
+ test_handle_socket_comm_event_pcrep);
+ CU_add_test(test_session_logic_states_suite,
+ "test_handle_socket_comm_event_pcreq",
+ test_handle_socket_comm_event_pcreq);
+ CU_add_test(test_session_logic_states_suite,
+ "test_handle_socket_comm_event_report",
+ test_handle_socket_comm_event_report);
+ CU_add_test(test_session_logic_states_suite,
+ "test_handle_socket_comm_event_update",
+ test_handle_socket_comm_event_update);
+ CU_add_test(test_session_logic_states_suite,
+ "test_handle_socket_comm_event_initiate",
+ test_handle_socket_comm_event_initiate);
+ CU_add_test(test_session_logic_states_suite,
+ "test_handle_socket_comm_event_notify",
+ test_handle_socket_comm_event_notify);
+ CU_add_test(test_session_logic_states_suite,
+ "test_handle_socket_comm_event_error",
+ test_handle_socket_comm_event_error);
+ CU_add_test(test_session_logic_states_suite,
+ "test_handle_socket_comm_event_unknown_msg",
+ test_handle_socket_comm_event_unknown_msg);
+ CU_add_test(test_session_logic_states_suite, "test_connection_failure",
+ test_connection_failure);
+
+ /*
+ * Run the tests and cleanup.
+ */
+ CU_basic_set_mode(CU_BRM_VERBOSE);
+ CU_basic_run_tests();
+ CU_FailureRecord *failure_record = CU_get_failure_list();
+ if (failure_record != NULL) {
+ printf("\nFailed tests:\n\t [Suite] [Test] [File:line-number]\n");
+ do {
+ printf("\t [%s] [%s] [%s:%d]\n",
+ failure_record->pSuite->pName,
+ failure_record->pTest->pName,
+ failure_record->strFileName,
+ failure_record->uiLineNumber);
+ failure_record = failure_record->pNext;
+
+ } while (failure_record != NULL);
+ }
+
+ CU_pRunSummary run_summary = CU_get_run_summary();
+ int result = run_summary->nTestsFailed;
+ CU_cleanup_registry();
+
+ return result;
+}
--- /dev/null
+source pceplib/test/pcep_tests_valgrind.sh
+valgrind_test pceplib/test/pcep_session_logic_tests
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <pthread.h>
+#include <stdlib.h>
+
+#include <CUnit/CUnit.h>
+
+#include "pcep_socket_comm_internals.h"
+#include "pcep_socket_comm_loop.h"
+#include "pcep_socket_comm_loop_test.h"
+#include "pcep_socket_comm.h"
+#include "pcep_utils_memory.h"
+
+void test_loop_conn_except_notifier(void *session_data, int socket_fd);
+
+/*
+ * Functions to be tested, implemented in pcep_socket_comm_loop.c
+ */
+
+typedef struct ready_to_read_handler_info_ {
+ bool handler_called;
+ bool except_handler_called;
+ void *data;
+ int socket_fd;
+ int bytes_read;
+
+} ready_to_read_handler_info;
+
+static ready_to_read_handler_info read_handler_info;
+static pcep_socket_comm_session *test_comm_session;
+static pcep_socket_comm_handle *test_socket_comm_handle = NULL;
+
+static int test_loop_message_ready_to_read_handler(void *session_data,
+ int socket_fd)
+{
+ read_handler_info.handler_called = true;
+ read_handler_info.data = session_data;
+ read_handler_info.socket_fd = socket_fd;
+
+ return read_handler_info.bytes_read;
+}
+
+
+void test_loop_conn_except_notifier(void *session_data, int socket_fd)
+{
+ (void)session_data;
+ (void)socket_fd;
+ read_handler_info.except_handler_called = true;
+}
+
+
+/*
+ * Test case setup and teardown called before AND after each test.
+ */
+void pcep_socket_comm_loop_test_setup()
+{
+ test_socket_comm_handle =
+ pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_socket_comm_handle));
+ memset(test_socket_comm_handle, 0, sizeof(pcep_socket_comm_handle));
+ test_socket_comm_handle->active = false;
+ test_socket_comm_handle->read_list =
+ ordered_list_initialize(socket_fd_node_compare);
+ test_socket_comm_handle->write_list =
+ ordered_list_initialize(socket_fd_node_compare);
+ test_socket_comm_handle->session_list =
+ ordered_list_initialize(pointer_compare_function);
+ pthread_mutex_init(&test_socket_comm_handle->socket_comm_mutex, NULL);
+ test_socket_comm_handle->num_active_sessions = 0;
+
+ test_comm_session =
+ pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_socket_comm_session));
+ memset(test_comm_session, 0, sizeof(pcep_socket_comm_session));
+ test_comm_session->message_ready_to_read_handler =
+ test_loop_message_ready_to_read_handler;
+ ordered_list_add_node(test_socket_comm_handle->session_list,
+ test_comm_session);
+
+ read_handler_info.handler_called = false;
+ read_handler_info.except_handler_called = false;
+ read_handler_info.data = NULL;
+ read_handler_info.socket_fd = -1;
+ read_handler_info.bytes_read = 0;
+}
+
+
+void pcep_socket_comm_loop_test_teardown()
+{
+ pthread_mutex_destroy(&test_socket_comm_handle->socket_comm_mutex);
+ ordered_list_destroy(test_socket_comm_handle->read_list);
+ ordered_list_destroy(test_socket_comm_handle->write_list);
+ ordered_list_destroy(test_socket_comm_handle->session_list);
+ pceplib_free(PCEPLIB_INFRA, test_socket_comm_handle);
+ test_socket_comm_handle = NULL;
+
+ if (test_comm_session != NULL) {
+ pceplib_free(PCEPLIB_INFRA, test_comm_session);
+ test_comm_session = NULL;
+ }
+}
+
+
+/*
+ * Test cases
+ */
+
+void test_socket_comm_loop_null_handle()
+{
+ /* Verify that socket_comm_loop() correctly handles a NULL
+ * timers_context */
+ socket_comm_loop(NULL);
+}
+
+
+void test_socket_comm_loop_not_active()
+{
+ /* Verify that event_loop() correctly handles an inactive flag */
+ pcep_socket_comm_handle handle;
+ handle.active = false;
+ socket_comm_loop(&handle);
+}
+
+
+void test_handle_reads_no_read()
+{
+ CU_ASSERT_PTR_NULL(test_socket_comm_handle->read_list->head);
+
+ handle_reads(test_socket_comm_handle);
+
+ CU_ASSERT_FALSE(read_handler_info.handler_called);
+ CU_ASSERT_FALSE(read_handler_info.except_handler_called);
+ CU_ASSERT_PTR_NULL(test_socket_comm_handle->read_list->head);
+}
+
+
+void test_handle_reads_read_message()
+{
+ /* Setup the comm session so that it can read.
+ * It should read 100 bytes, which simulates a successful read */
+ test_comm_session->socket_fd = 10;
+ read_handler_info.bytes_read = 100;
+ FD_SET(test_comm_session->socket_fd,
+ &test_socket_comm_handle->read_master_set);
+ ordered_list_add_node(test_socket_comm_handle->read_list,
+ test_comm_session);
+
+ handle_reads(test_socket_comm_handle);
+
+ CU_ASSERT_TRUE(read_handler_info.handler_called);
+ CU_ASSERT_FALSE(read_handler_info.except_handler_called);
+ CU_ASSERT_EQUAL(test_comm_session->received_bytes,
+ read_handler_info.bytes_read);
+}
+
+
+void test_handle_reads_read_message_close()
+{
+ /* Setup the comm session so that it can read.
+ * It should read 0 bytes, which simulates that the socket closed */
+ test_comm_session->socket_fd = 11;
+ read_handler_info.bytes_read = 0;
+ FD_SET(test_comm_session->socket_fd,
+ &test_socket_comm_handle->read_master_set);
+ ordered_list_add_node(test_socket_comm_handle->read_list,
+ test_comm_session);
+
+ handle_reads(test_socket_comm_handle);
+
+ CU_ASSERT_TRUE(read_handler_info.handler_called);
+ CU_ASSERT_FALSE(read_handler_info.except_handler_called);
+ CU_ASSERT_EQUAL(test_comm_session->received_bytes,
+ read_handler_info.bytes_read);
+ CU_ASSERT_PTR_NULL(test_socket_comm_handle->read_list->head);
+}
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Javier Garcia <javier.garcia@voltanet.io>
+ *
+ */
+
+/*
+ * Timer definitions to be used internally by the pcep_timers library.
+ */
+
+#ifndef PCEP_SOCKET_COMM_LOOP_TEST_H_
+#define PCEP_SOCKET_COMM_LOOP_TEST_H_
+
+void pcep_socket_comm_loop_test_setup(void);
+void pcep_socket_comm_loop_test_teardown(void);
+void test_socket_comm_loop_null_handle(void);
+void test_socket_comm_loop_not_active(void);
+void test_handle_reads_no_read(void);
+void test_handle_reads_read_message(void);
+void test_handle_reads_read_message_close(void);
+
+#endif /* PCEPTIMERINTERNALS_H_ */
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <netinet/in.h>
+
+#include <CUnit/CUnit.h>
+
+#include "pcep_socket_comm.h"
+#include "pcep_socket_comm_internals.h"
+#include "pcep_socket_comm_test.h"
+
+extern pcep_socket_comm_handle *socket_comm_handle_;
+
+static pcep_socket_comm_session *test_session = NULL;
+static struct in_addr test_host_ip;
+static struct in_addr test_src_ip;
+static struct in6_addr test_host_ipv6;
+static struct in6_addr test_src_ipv6;
+static short test_port = 4789;
+static short test_src_port = 4999;
+static uint32_t connect_timeout_millis = 500;
+
+/*
+ * Unit Test Basic pcep_socket_comm API usage.
+ * Testing sending messages, etc via sockets should be done
+ * with integration tests, not unit tests.
+ */
+
+/*
+ * Different socket_comm handler test implementations
+ */
+static void test_message_received_handler(void *session_data,
+ const char *message_data,
+ unsigned int message_length)
+{
+ (void)session_data;
+ (void)message_data;
+ (void)message_length;
+}
+
+static int test_message_ready_to_read_handler(void *session_data, int socket_fd)
+{
+ (void)session_data;
+ (void)socket_fd;
+ return 1;
+}
+
+static void test_message_sent_handler(void *session_data, int socket_fd)
+{
+ (void)session_data;
+ (void)socket_fd;
+ return;
+}
+
+static void test_connection_except_notifier(void *session_data, int socket_fd)
+{
+ (void)session_data;
+ (void)socket_fd;
+}
+
+
+/*
+ * Test case setup and teardown called before AND after each test.
+ */
+void pcep_socket_comm_test_setup()
+{
+ inet_pton(AF_INET, "127.0.0.1", &(test_host_ip));
+ inet_pton(AF_INET, "127.0.0.1", &(test_src_ip));
+ inet_pton(AF_INET6, "::1", &(test_host_ipv6));
+ inet_pton(AF_INET6, "::1", &(test_src_ipv6));
+}
+
+void pcep_socket_comm_test_teardown()
+{
+ socket_comm_session_teardown(test_session);
+ test_session = NULL;
+}
+
+
+/*
+ * Test cases
+ */
+
+void test_pcep_socket_comm_initialize()
+{
+ test_session = socket_comm_session_initialize(
+ test_message_received_handler, NULL, NULL,
+ test_connection_except_notifier, &test_host_ip, test_port,
+ connect_timeout_millis, NULL, false, NULL);
+ CU_ASSERT_PTR_NOT_NULL(test_session);
+ CU_ASSERT_FALSE(test_session->is_ipv6);
+}
+
+
+void test_pcep_socket_comm_initialize_ipv6()
+{
+ test_session = socket_comm_session_initialize_ipv6(
+ test_message_received_handler, NULL, NULL,
+ test_connection_except_notifier, &test_host_ipv6, test_port,
+ connect_timeout_millis, NULL, false, NULL);
+ CU_ASSERT_PTR_NOT_NULL(test_session);
+ CU_ASSERT_TRUE(test_session->is_ipv6);
+}
+
+
+void test_pcep_socket_comm_initialize_with_src()
+{
+ /* Test that INADDR_ANY will be used when src_ip is NULL */
+ test_session = socket_comm_session_initialize_with_src(
+ test_message_received_handler, NULL, NULL,
+ test_connection_except_notifier, NULL, 0, &test_host_ip,
+ test_port, connect_timeout_millis, NULL, false, NULL);
+ CU_ASSERT_PTR_NOT_NULL(test_session);
+ CU_ASSERT_EQUAL(
+ test_session->src_sock_addr.src_sock_addr_ipv4.sin_addr.s_addr,
+ INADDR_ANY);
+ CU_ASSERT_FALSE(test_session->is_ipv6);
+
+ socket_comm_session_teardown(test_session);
+ test_session = socket_comm_session_initialize_with_src(
+ test_message_received_handler, NULL, NULL,
+ test_connection_except_notifier, &test_src_ip, test_src_port,
+ &test_host_ip, test_port, connect_timeout_millis, NULL, false,
+ NULL);
+ CU_ASSERT_PTR_NOT_NULL(test_session);
+ CU_ASSERT_EQUAL(
+ test_session->src_sock_addr.src_sock_addr_ipv4.sin_addr.s_addr,
+ test_src_ip.s_addr);
+ CU_ASSERT_EQUAL(test_session->src_sock_addr.src_sock_addr_ipv4.sin_port,
+ ntohs(test_src_port));
+ CU_ASSERT_FALSE(test_session->is_ipv6);
+}
+
+
+void test_pcep_socket_comm_initialize_with_src_ipv6()
+{
+ /* Test that INADDR6_ANY will be used when src_ip is NULL */
+ test_session = socket_comm_session_initialize_with_src_ipv6(
+ test_message_received_handler, NULL, NULL,
+ test_connection_except_notifier, NULL, 0, &test_host_ipv6,
+ test_port, connect_timeout_millis, NULL, false, NULL);
+ CU_ASSERT_PTR_NOT_NULL(test_session);
+ CU_ASSERT_EQUAL(memcmp(&test_session->src_sock_addr.src_sock_addr_ipv6
+ .sin6_addr,
+ &in6addr_any, sizeof(struct in6_addr)),
+ 0);
+ CU_ASSERT_TRUE(test_session->is_ipv6);
+
+ socket_comm_session_teardown(test_session);
+ test_session = socket_comm_session_initialize_with_src_ipv6(
+ test_message_received_handler, NULL, NULL,
+ test_connection_except_notifier, &test_src_ipv6, test_src_port,
+ &test_host_ipv6, test_port, connect_timeout_millis, NULL, false,
+ NULL);
+ CU_ASSERT_PTR_NOT_NULL(test_session);
+ CU_ASSERT_EQUAL(memcmp(&test_session->src_sock_addr.src_sock_addr_ipv6
+ .sin6_addr,
+ &test_src_ipv6, sizeof(struct in6_addr)),
+ 0);
+ CU_ASSERT_EQUAL(
+ test_session->src_sock_addr.src_sock_addr_ipv6.sin6_port,
+ ntohs(test_src_port));
+ CU_ASSERT_TRUE(test_session->is_ipv6);
+}
+
+
+void test_pcep_socket_comm_initialize_tcpmd5()
+{
+ char tcp_md5_str[] = "hello";
+ int tcp_md5_strlen = strlen(tcp_md5_str);
+
+ test_session = socket_comm_session_initialize(
+ test_message_received_handler, NULL, NULL,
+ test_connection_except_notifier, &test_host_ip, test_port, 1,
+ tcp_md5_str, true, NULL);
+ CU_ASSERT_PTR_NOT_NULL(test_session);
+ CU_ASSERT_EQUAL(0, strncmp(tcp_md5_str,
+ test_session->tcp_authentication_str,
+ tcp_md5_strlen));
+ CU_ASSERT_TRUE(test_session->is_tcp_auth_md5);
+ CU_ASSERT_FALSE(socket_comm_session_connect_tcp(test_session));
+ /* This call does not work, it returns errno=92, Protocol not available
+ getsockopt(test_session->socket_fd, SOL_SOCKET, TCP_MD5SIG, &sig,
+ &siglen);*/
+
+ socket_comm_session_teardown(test_session);
+ test_session = socket_comm_session_initialize(
+ test_message_received_handler, NULL, NULL,
+ test_connection_except_notifier, &test_host_ip, test_port, 1,
+ tcp_md5_str, false, NULL);
+ CU_ASSERT_PTR_NOT_NULL(test_session);
+ CU_ASSERT_EQUAL(0, strncmp(tcp_md5_str,
+ test_session->tcp_authentication_str,
+ tcp_md5_strlen));
+ CU_ASSERT_FALSE(test_session->is_tcp_auth_md5);
+ CU_ASSERT_FALSE(socket_comm_session_connect_tcp(test_session));
+}
+
+
+void test_pcep_socket_comm_initialize_ipv6_tcpmd5()
+{
+ char tcp_md5_str[] = "hello";
+ int tcp_md5_strlen = strlen(tcp_md5_str);
+
+ test_session = socket_comm_session_initialize_ipv6(
+ test_message_received_handler, NULL, NULL,
+ test_connection_except_notifier, &test_host_ipv6, test_port, 1,
+ tcp_md5_str, true, NULL);
+ CU_ASSERT_PTR_NOT_NULL(test_session);
+ CU_ASSERT_EQUAL(0, strncmp(tcp_md5_str,
+ test_session->tcp_authentication_str,
+ tcp_md5_strlen));
+ CU_ASSERT_TRUE(test_session->is_tcp_auth_md5);
+ CU_ASSERT_FALSE(socket_comm_session_connect_tcp(test_session));
+ /* This call does not work, it returns errno=92, Protocol not available
+ getsockopt(test_session->socket_fd, SOL_SOCKET, TCP_MD5SIG, &sig,
+ &siglen);*/
+
+ socket_comm_session_teardown(test_session);
+ test_session = socket_comm_session_initialize_ipv6(
+ test_message_received_handler, NULL, NULL,
+ test_connection_except_notifier, &test_host_ipv6, test_port, 1,
+ tcp_md5_str, false, NULL);
+ CU_ASSERT_PTR_NOT_NULL(test_session);
+ CU_ASSERT_EQUAL(0, strncmp(tcp_md5_str,
+ test_session->tcp_authentication_str,
+ tcp_md5_strlen));
+ CU_ASSERT_FALSE(test_session->is_tcp_auth_md5);
+ CU_ASSERT_FALSE(socket_comm_session_connect_tcp(test_session));
+}
+
+
+void test_pcep_socket_comm_initialize_handlers()
+{
+ /* Verify incorrect handler usage is correctly handled */
+
+ /* Both receive handlers cannot be NULL */
+ test_session = socket_comm_session_initialize(
+ NULL, NULL, NULL, test_connection_except_notifier,
+ &test_host_ip, test_port, connect_timeout_millis, NULL, false,
+ NULL);
+ CU_ASSERT_PTR_NULL(test_session);
+
+ /* Both receive handlers cannot be set */
+ test_session = socket_comm_session_initialize(
+ test_message_received_handler,
+ test_message_ready_to_read_handler, test_message_sent_handler,
+ test_connection_except_notifier, &test_host_ip, test_port,
+ connect_timeout_millis, NULL, false, NULL);
+ CU_ASSERT_PTR_NULL(test_session);
+
+ /* Only one receive handler can be set */
+ test_session = socket_comm_session_initialize(
+ NULL, test_message_ready_to_read_handler,
+ test_message_sent_handler, test_connection_except_notifier,
+ &test_host_ip, test_port, connect_timeout_millis, NULL, false,
+ NULL);
+ CU_ASSERT_PTR_NOT_NULL(test_session);
+}
+
+
+void test_pcep_socket_comm_session_not_initialized()
+{
+ CU_ASSERT_FALSE(socket_comm_session_connect_tcp(NULL));
+ CU_ASSERT_FALSE(socket_comm_session_close_tcp(NULL));
+ CU_ASSERT_FALSE(socket_comm_session_close_tcp_after_write(NULL));
+ socket_comm_session_send_message(NULL, NULL, 0, true);
+ CU_ASSERT_FALSE(socket_comm_session_teardown(NULL));
+}
+
+
+void test_pcep_socket_comm_session_destroy()
+{
+ test_session = socket_comm_session_initialize(
+ test_message_received_handler, NULL, test_message_sent_handler,
+ test_connection_except_notifier, &test_host_ip, test_port,
+ connect_timeout_millis, NULL, false, NULL);
+ CU_ASSERT_PTR_NOT_NULL(test_session);
+ CU_ASSERT_PTR_NOT_NULL(socket_comm_handle_);
+ CU_ASSERT_EQUAL(socket_comm_handle_->num_active_sessions, 1);
+
+ CU_ASSERT_TRUE(socket_comm_session_teardown(test_session));
+ test_session = NULL;
+ CU_ASSERT_PTR_NOT_NULL(socket_comm_handle_);
+
+ CU_ASSERT_TRUE(destroy_socket_comm_loop());
+ CU_ASSERT_PTR_NULL(socket_comm_handle_);
+}
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Javier Garcia <javier.garcia@voltanet.io>
+ *
+ */
+
+/*
+ * Timer definitions to be used internally by the pcep_timers library.
+ */
+
+#ifndef PCEP_SOCKET_COMM_TEST_H_
+#define PCEP_SOCKET_COMM_TEST_H_
+
+void pcep_socket_comm_test_teardown(void);
+void pcep_socket_comm_test_setup(void);
+void test_pcep_socket_comm_initialize(void);
+void test_pcep_socket_comm_initialize_ipv6(void);
+void test_pcep_socket_comm_initialize_with_src(void);
+void test_pcep_socket_comm_initialize_with_src_ipv6(void);
+void test_pcep_socket_comm_initialize_tcpmd5(void);
+void test_pcep_socket_comm_initialize_ipv6_tcpmd5(void);
+void test_pcep_socket_comm_initialize_handlers(void);
+void test_pcep_socket_comm_session_not_initialized(void);
+void test_pcep_socket_comm_session_destroy(void);
+
+#endif
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <CUnit/Basic.h>
+#include <CUnit/CUnit.h>
+#include <CUnit/TestDB.h>
+
+#include "pcep_socket_comm_loop_test.h"
+#include "pcep_socket_comm_test.h"
+
+
+int main(int argc, char **argv)
+{
+ /* Unused parameters cause compilation warnings */
+ (void)argc;
+ (void)argv;
+
+ CU_initialize_registry();
+
+ /*
+ * Tests defined in pcep_socket_comm_test.c
+ */
+ CU_pSuite test_socket_comm_suite = CU_add_suite_with_setup_and_teardown(
+ "PCEP Socket Comm Test Suite", NULL,
+ NULL, // suite setup and cleanup function pointers
+ pcep_socket_comm_test_setup, // test case setup function pointer
+ pcep_socket_comm_test_teardown); // test case teardown function
+ // pointer
+
+ CU_add_test(test_socket_comm_suite, "test_pcep_socket_comm_initialize",
+ test_pcep_socket_comm_initialize);
+ CU_add_test(test_socket_comm_suite,
+ "test_pcep_socket_comm_initialize_ipv6",
+ test_pcep_socket_comm_initialize_ipv6);
+ CU_add_test(test_socket_comm_suite,
+ "test_pcep_socket_comm_initialize_with_src",
+ test_pcep_socket_comm_initialize_with_src);
+ CU_add_test(test_socket_comm_suite,
+ "test_pcep_socket_comm_initialize_with_src_ipv6",
+ test_pcep_socket_comm_initialize_with_src_ipv6);
+ CU_add_test(test_socket_comm_suite,
+ "test_pcep_socket_comm_initialize_tcpmd5",
+ test_pcep_socket_comm_initialize_tcpmd5);
+ CU_add_test(test_socket_comm_suite,
+ "test_pcep_socket_comm_initialize_ipv6_tcpmd5",
+ test_pcep_socket_comm_initialize_ipv6_tcpmd5);
+ CU_add_test(test_socket_comm_suite,
+ "test_pcep_socket_comm_initialize_handlers",
+ test_pcep_socket_comm_initialize_handlers);
+ CU_add_test(test_socket_comm_suite,
+ "test_pcep_socket_comm_session_not_initialized",
+ test_pcep_socket_comm_session_not_initialized);
+ CU_add_test(test_socket_comm_suite,
+ "test_pcep_socket_comm_session_destroy",
+ test_pcep_socket_comm_session_destroy);
+
+ /*
+ * Tests defined in pcep_socket_comm_loop_test.c
+ */
+ CU_pSuite test_socket_comm_loop_suite =
+ CU_add_suite_with_setup_and_teardown(
+ "PCEP Socket Comm Loop Test Suite", NULL, NULL,
+ pcep_socket_comm_loop_test_setup, // suite setup
+ // function pointer
+ pcep_socket_comm_loop_test_teardown); // suite cleanup
+ // function
+ // pointer
+
+ CU_add_test(test_socket_comm_loop_suite,
+ "test_socket_comm_loop_null_handle",
+ test_socket_comm_loop_null_handle);
+ CU_add_test(test_socket_comm_loop_suite,
+ "test_socket_comm_loop_not_active",
+ test_socket_comm_loop_not_active);
+ CU_add_test(test_socket_comm_loop_suite, "test_handle_reads_no_read",
+ test_handle_reads_no_read);
+ CU_add_test(test_socket_comm_loop_suite,
+ "test_handle_reads_read_message",
+ test_handle_reads_read_message);
+ CU_add_test(test_socket_comm_loop_suite,
+ "test_handle_reads_read_message_close",
+ test_handle_reads_read_message_close);
+
+ /*
+ * Run the tests and cleanup.
+ */
+ CU_basic_set_mode(CU_BRM_VERBOSE);
+ CU_basic_run_tests();
+ CU_FailureRecord *failure_record = CU_get_failure_list();
+ if (failure_record != NULL) {
+ printf("\nFailed tests:\n\t [Suite] [Test] [File:line-number]\n");
+ do {
+ printf("\t [%s] [%s] [%s:%d]\n",
+ failure_record->pSuite->pName,
+ failure_record->pTest->pName,
+ failure_record->strFileName,
+ failure_record->uiLineNumber);
+ failure_record = failure_record->pNext;
+
+ } while (failure_record != NULL);
+ }
+
+ CU_pRunSummary run_summary = CU_get_run_summary();
+ int result = run_summary->nTestsFailed;
+ CU_cleanup_registry();
+
+ return result;
+}
--- /dev/null
+source pceplib/test/pcep_tests_valgrind.sh
+valgrind_test pceplib/test/pcep_socket_comm_tests
--- /dev/null
+#
+# Common function definition for PCEPlib valgrind tests
+#
+
+function valgrind_test()
+{
+ local test_suite=$1
+ [[ -z ${test_suite} ]] && { echo "${FUNCNAME}(): test_suite not specified."; exit 1; }
+ [[ ! -x "${test_suite}" ]] && { echo "${test_suite} is not an executable file."; exit 1; }
+
+ G_SLICE=always-malloc
+ G_DEBUG=gc-friendly
+ VALGRIND="valgrind -v --tool=memcheck --leak-check=full --num-callers=40 --error-exitcode=1"
+ ${VALGRIND} --log-file=${test_suite}.val.log ./${test_suite} || ({ echo "Valgrind memory check error"; exit 1; })
+}
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <stdlib.h>
+
+#include <CUnit/CUnit.h>
+
+#include "pcep_timers.h"
+#include "pcep_utils_memory.h"
+#include "pcep_timers_event_loop.h"
+#include "pcep_timers_event_loop_test.h"
+
+
+typedef struct timer_expire_handler_info_ {
+ bool handler_called;
+ void *data;
+ int timerId;
+
+} timer_expire_handler_info;
+
+static pcep_timers_context *test_timers_context = NULL;
+static timer_expire_handler_info expire_handler_info;
+#define TEST_EVENT_LOOP_TIMER_ID 500
+
+
+/* Called when a timer expires */
+static void test_timer_expire_handler(void *data, int timerId)
+{
+ expire_handler_info.handler_called = true;
+ expire_handler_info.data = data;
+ expire_handler_info.timerId = timerId;
+}
+
+
+/* Test case setup called before each test.
+ * Declared in pcep_timers_tests.c */
+void pcep_timers_event_loop_test_setup()
+{
+ test_timers_context =
+ pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_timers_context));
+ memset(test_timers_context, 0, sizeof(pcep_timers_context));
+ if (pthread_mutex_init(&(test_timers_context->timer_list_lock), NULL)
+ != 0) {
+ fprintf(stderr,
+ "ERROR initializing timers, cannot initialize the mutex\n");
+ }
+ test_timers_context->active = false;
+ test_timers_context->expire_handler = test_timer_expire_handler;
+ test_timers_context->timer_list =
+ ordered_list_initialize(timer_list_node_timer_id_compare);
+
+ expire_handler_info.handler_called = false;
+ expire_handler_info.data = NULL;
+ expire_handler_info.timerId = -1;
+}
+
+
+/* Test case teardown called after each test.
+ * Declared in pcep_timers_tests.c */
+void pcep_timers_event_loop_test_teardown()
+{
+ pthread_mutex_unlock(&test_timers_context->timer_list_lock);
+ pthread_mutex_destroy(&(test_timers_context->timer_list_lock));
+ ordered_list_destroy(test_timers_context->timer_list);
+ pceplib_free(PCEPLIB_INFRA, test_timers_context);
+ test_timers_context = NULL;
+}
+
+
+/*
+ * Test functions
+ */
+
+void test_walk_and_process_timers_no_timers()
+{
+ CU_ASSERT_EQUAL(test_timers_context->timer_list->num_entries, 0);
+ CU_ASSERT_PTR_NULL(test_timers_context->timer_list->head);
+
+ walk_and_process_timers(test_timers_context);
+
+ CU_ASSERT_FALSE(expire_handler_info.handler_called);
+ CU_ASSERT_EQUAL(test_timers_context->timer_list->num_entries, 0);
+ CU_ASSERT_PTR_NULL(test_timers_context->timer_list->head);
+}
+
+
+void test_walk_and_process_timers_timer_not_expired()
+{
+ pcep_timer timer;
+ timer.data = &timer;
+ // Set the timer to expire 100 seconds from now
+ timer.expire_time = time(NULL) + 100;
+ timer.timer_id = TEST_EVENT_LOOP_TIMER_ID;
+ ordered_list_add_node(test_timers_context->timer_list, &timer);
+
+ walk_and_process_timers(test_timers_context);
+
+ /* The timer should still be in the list, since it hasnt expired yet */
+ CU_ASSERT_FALSE(expire_handler_info.handler_called);
+ CU_ASSERT_EQUAL(test_timers_context->timer_list->num_entries, 1);
+ CU_ASSERT_PTR_NOT_NULL(test_timers_context->timer_list->head);
+}
+
+
+void test_walk_and_process_timers_timer_expired()
+{
+ /* We need to alloc it, since it will be free'd in
+ * walk_and_process_timers */
+ pcep_timer *timer = pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_timer));
+ timer->data = timer;
+ // Set the timer to expire 10 seconds ago
+ timer->expire_time = time(NULL) - 10;
+ pthread_mutex_lock(&test_timers_context->timer_list_lock);
+ timer->timer_id = TEST_EVENT_LOOP_TIMER_ID;
+ pthread_mutex_unlock(&test_timers_context->timer_list_lock);
+ ordered_list_add_node(test_timers_context->timer_list, timer);
+
+ walk_and_process_timers(test_timers_context);
+
+ /* Since the timer expired, the expire_handler should have been called
+ * and the timer should have been removed from the timer list */
+ CU_ASSERT_TRUE(expire_handler_info.handler_called);
+ CU_ASSERT_PTR_EQUAL(expire_handler_info.data, timer);
+ CU_ASSERT_EQUAL(expire_handler_info.timerId, TEST_EVENT_LOOP_TIMER_ID);
+ CU_ASSERT_EQUAL(test_timers_context->timer_list->num_entries, 0);
+ CU_ASSERT_PTR_NULL(test_timers_context->timer_list->head);
+}
+
+void test_event_loop_null_handle()
+{
+ /* Verify that event_loop() correctly handles a NULL timers_context */
+ event_loop(NULL);
+}
+
+
+void test_event_loop_not_active()
+{
+ /* Verify that event_loop() correctly handles an inactive timers_context
+ * flag */
+ test_timers_context->active = false;
+ event_loop(test_timers_context);
+}
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Javier Garcia <javier.garcia@voltanet.io>
+ *
+ */
+
+/*
+ * Timer definitions to be used internally by the pcep_timers library.
+ */
+
+#ifndef PCEP_TIMERS_EVENT_LOOP_TEST_H_
+#define PCEP_TIMERS_EVENT_LOOP_TEST_H_
+
+void pcep_timers_event_loop_test_setup(void);
+void pcep_timers_event_loop_test_teardown(void);
+void test_walk_and_process_timers_no_timers(void);
+void test_walk_and_process_timers_timer_not_expired(void);
+void test_walk_and_process_timers_timer_expired(void);
+void test_event_loop_null_handle(void);
+void test_event_loop_not_active(void);
+
+#endif /* PCEPTIMERINTERNALS_H_ */
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <stdbool.h>
+#include <CUnit/CUnit.h>
+
+#include "pcep_timers.h"
+#include "pcep_timers_test.h"
+
+/* Test case teardown called after each test.
+ * Declared in pcep_timers_tests.c */
+void pcep_timers_test_teardown()
+{
+ teardown_timers();
+}
+
+static void test_timer_expire_handler(void *data, int timerId)
+{
+ (void)data;
+ (void)timerId;
+}
+
+
+void test_double_initialization(void)
+{
+ CU_ASSERT_EQUAL(initialize_timers(test_timer_expire_handler), true);
+ CU_ASSERT_EQUAL(initialize_timers(test_timer_expire_handler), false);
+}
+
+
+void test_initialization_null_callback(void)
+{
+ CU_ASSERT_EQUAL(initialize_timers(NULL), false);
+}
+
+
+void test_not_initialized(void)
+{
+ /* All of these should fail if initialize_timers() hasnt been called */
+ CU_ASSERT_EQUAL(create_timer(5, NULL), -1);
+ CU_ASSERT_EQUAL(cancel_timer(7), false);
+ CU_ASSERT_EQUAL(reset_timer(7), false);
+ CU_ASSERT_EQUAL(teardown_timers(), false);
+}
+
+
+void test_create_timer(void)
+{
+ CU_ASSERT_EQUAL(initialize_timers(test_timer_expire_handler), true);
+
+ int timer_id = create_timer(0, NULL);
+ CU_ASSERT_TRUE(timer_id > -1);
+}
+
+
+void test_cancel_timer(void)
+{
+ CU_ASSERT_EQUAL(initialize_timers(test_timer_expire_handler), true);
+
+ int timer_id = create_timer(10, NULL);
+ CU_ASSERT_TRUE(timer_id > -1);
+
+ CU_ASSERT_EQUAL(cancel_timer(timer_id), true);
+}
+
+
+void test_cancel_timer_invalid(void)
+{
+ CU_ASSERT_EQUAL(initialize_timers(test_timer_expire_handler), true);
+ CU_ASSERT_EQUAL(cancel_timer(1), false);
+}
+
+
+void test_reset_timer(void)
+{
+ CU_ASSERT_EQUAL(initialize_timers(test_timer_expire_handler), true);
+
+ int timer_id = create_timer(10, NULL);
+ CU_ASSERT_TRUE(timer_id > -1);
+
+ CU_ASSERT_EQUAL(reset_timer(timer_id), true);
+}
+
+
+void test_reset_timer_invalid(void)
+{
+ CU_ASSERT_EQUAL(initialize_timers(test_timer_expire_handler), true);
+ CU_ASSERT_EQUAL(reset_timer(1), false);
+}
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Javier Garcia <javier.garcia@voltanet.io>
+ *
+ */
+
+/*
+ * Timer definitions to be used internally by the pcep_timers library.
+ */
+
+#ifndef PCEP_TIMERS_TEST_H_
+#define PCEP_TIMERS_TEST_H_
+
+void pcep_timers_test_teardown(void);
+void test_double_initialization(void);
+void test_initialization_null_callback(void);
+void test_not_initialized(void);
+void test_create_timer(void);
+void test_cancel_timer(void);
+void test_cancel_timer_invalid(void);
+void test_reset_timer(void);
+void test_reset_timer_invalid(void);
+
+#endif /* PCEPTIMERINTERNALS_H_ */
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <CUnit/Basic.h>
+#include <CUnit/CUnit.h>
+#include <CUnit/TestDB.h>
+
+#include "pcep_timers_test.h"
+#include "pcep_timers_event_loop_test.h"
+
+
+int main(int argc, char **argv)
+{
+ /* Unused parameters cause compilation warnings */
+ (void)argc;
+ (void)argv;
+
+ CU_initialize_registry();
+
+ /*
+ * Tests defined in pcep_timers_test.c
+ */
+ CU_pSuite test_timers_suite = CU_add_suite_with_setup_and_teardown(
+ "PCEP Timers Test Suite", NULL,
+ NULL, // suite setup and cleanup function pointers
+ NULL, pcep_timers_test_teardown); // test case setup and
+ // teardown function pointers
+ CU_add_test(test_timers_suite, "test_double_initialization",
+ test_double_initialization);
+ CU_add_test(test_timers_suite, "test_initialization_null_callback",
+ test_initialization_null_callback);
+ CU_add_test(test_timers_suite, "test_not_initialized",
+ test_not_initialized);
+ CU_add_test(test_timers_suite, "test_create_timer", test_create_timer);
+ CU_add_test(test_timers_suite, "test_cancel_timer", test_cancel_timer);
+ CU_add_test(test_timers_suite, "test_cancel_timer_invalid",
+ test_cancel_timer_invalid);
+ CU_add_test(test_timers_suite, "test_reset_timer", test_reset_timer);
+ CU_add_test(test_timers_suite, "test_reset_timer_invalid",
+ test_reset_timer_invalid);
+
+ /*
+ * Tests defined in pcep_timers_event_loop_test.c
+ */
+ CU_pSuite test_timers_event_loop_suite =
+ CU_add_suite_with_setup_and_teardown(
+ "PCEP Timers Event Loop Test Suite", NULL,
+ NULL, // suite setup and cleanup function pointers
+ pcep_timers_event_loop_test_setup, // test case setup
+ // function pointer
+ pcep_timers_event_loop_test_teardown); // test case
+ // teardown
+ // function
+ // pointer
+ CU_add_test(test_timers_event_loop_suite,
+ "test_walk_and_process_timers_no_timers",
+ test_walk_and_process_timers_no_timers);
+ CU_add_test(test_timers_event_loop_suite,
+ "test_walk_and_process_timers_timer_not_expired",
+ test_walk_and_process_timers_timer_not_expired);
+ CU_add_test(test_timers_event_loop_suite,
+ "test_walk_and_process_timers_timer_expired",
+ test_walk_and_process_timers_timer_expired);
+ CU_add_test(test_timers_event_loop_suite, "test_event_loop_null_handle",
+ test_event_loop_null_handle);
+ CU_add_test(test_timers_event_loop_suite, "test_event_loop_not_active",
+ test_event_loop_not_active);
+
+ /*
+ * Run the tests and cleanup.
+ */
+ CU_basic_set_mode(CU_BRM_VERBOSE);
+ CU_basic_run_tests();
+ CU_FailureRecord *failure_record = CU_get_failure_list();
+ if (failure_record != NULL) {
+ printf("\nFailed tests:\n\t [Suite] [Test] [File:line-number]\n");
+ do {
+ printf("\t [%s] [%s] [%s:%d]\n",
+ failure_record->pSuite->pName,
+ failure_record->pTest->pName,
+ failure_record->strFileName,
+ failure_record->uiLineNumber);
+ failure_record = failure_record->pNext;
+
+ } while (failure_record != NULL);
+ }
+
+ CU_pRunSummary run_summary = CU_get_run_summary();
+ int result = run_summary->nTestsFailed;
+ CU_cleanup_registry();
+
+ return result;
+}
--- /dev/null
+source pceplib/test/pcep_tests_valgrind.sh
+valgrind_test pceplib/test/pcep_timers_tests
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <stdlib.h>
+
+#include <CUnit/CUnit.h>
+
+#include "pcep_utils_counters.h"
+#include "pcep_utils_counters_test.h"
+
+
+void test_create_counters_group()
+{
+ const char group_name[] = "group";
+ uint16_t num_subgroups = 10;
+
+ struct counters_group *group =
+ create_counters_group(NULL, num_subgroups);
+ CU_ASSERT_PTR_NULL(group);
+
+ group = create_counters_group(group_name, MAX_COUNTER_GROUPS + 1);
+ CU_ASSERT_PTR_NULL(group);
+
+ group = create_counters_group(group_name, num_subgroups);
+ CU_ASSERT_PTR_NOT_NULL(group);
+
+ CU_ASSERT_EQUAL(group->num_subgroups, 0);
+ CU_ASSERT_EQUAL(group->max_subgroups, num_subgroups);
+ CU_ASSERT_EQUAL(strcmp(group->counters_group_name, group_name), 0);
+
+ delete_counters_group(group);
+}
+
+void test_create_counters_subgroup()
+{
+ const char subgroup_name[] = "subgroup";
+ uint16_t subgroup_id = 10;
+ uint16_t num_counters = 20;
+
+ struct counters_subgroup *subgroup =
+ create_counters_subgroup(NULL, subgroup_id, num_counters);
+ CU_ASSERT_PTR_NULL(subgroup);
+
+ subgroup = create_counters_subgroup(
+ subgroup_name, MAX_COUNTER_GROUPS + 1, num_counters);
+ CU_ASSERT_PTR_NULL(subgroup);
+
+ subgroup = create_counters_subgroup(subgroup_name, subgroup_id,
+ MAX_COUNTERS + 1);
+ CU_ASSERT_PTR_NULL(subgroup);
+
+ subgroup = create_counters_subgroup(subgroup_name, subgroup_id,
+ num_counters);
+ CU_ASSERT_PTR_NOT_NULL(subgroup);
+
+ CU_ASSERT_EQUAL(subgroup->subgroup_id, subgroup_id);
+ CU_ASSERT_EQUAL(subgroup->num_counters, 0);
+ CU_ASSERT_EQUAL(subgroup->max_counters, num_counters);
+ CU_ASSERT_EQUAL(strcmp(subgroup->counters_subgroup_name, subgroup_name),
+ 0);
+
+ delete_counters_subgroup(subgroup);
+}
+
+void test_add_counters_subgroup()
+{
+ struct counters_group *group = create_counters_group("group", 1);
+ struct counters_subgroup *subgroup1 =
+ create_counters_subgroup("subgroup", 0, 5);
+ struct counters_subgroup *subgroup2 =
+ create_counters_subgroup("subgroup", 1, 5);
+
+ CU_ASSERT_FALSE(add_counters_subgroup(NULL, NULL));
+ CU_ASSERT_FALSE(add_counters_subgroup(NULL, subgroup1));
+ CU_ASSERT_FALSE(add_counters_subgroup(group, NULL));
+
+ CU_ASSERT_EQUAL(group->num_subgroups, 0);
+ CU_ASSERT_TRUE(add_counters_subgroup(group, subgroup1));
+ CU_ASSERT_EQUAL(group->num_subgroups, 1);
+ /* Cant add more than num_subgroups to the group */
+ CU_ASSERT_FALSE(add_counters_subgroup(group, subgroup2));
+
+ CU_ASSERT_PTR_NOT_NULL(find_subgroup(group, 0));
+ CU_ASSERT_PTR_NULL(find_subgroup(group, 1));
+
+ delete_counters_group(group);
+ delete_counters_subgroup(subgroup2);
+}
+
+void test_create_subgroup_counter()
+{
+ uint16_t counter_id = 1;
+ char counter_name[] = "my counter";
+ struct counters_subgroup *subgroup =
+ create_counters_subgroup("subgroup", 1, 2);
+
+ CU_ASSERT_FALSE(
+ create_subgroup_counter(NULL, counter_id, counter_name));
+ CU_ASSERT_FALSE(create_subgroup_counter(subgroup, counter_id + 1,
+ counter_name));
+ CU_ASSERT_FALSE(create_subgroup_counter(subgroup, counter_id, NULL));
+ CU_ASSERT_EQUAL(subgroup->num_counters, 0);
+ CU_ASSERT_TRUE(
+ create_subgroup_counter(subgroup, counter_id, counter_name));
+ CU_ASSERT_EQUAL(subgroup->num_counters, 1);
+
+ delete_counters_subgroup(subgroup);
+}
+
+void test_delete_counters_group()
+{
+ struct counters_group *group = create_counters_group("group", 1);
+
+ CU_ASSERT_FALSE(delete_counters_group(NULL));
+ CU_ASSERT_TRUE(delete_counters_group(group));
+}
+
+void test_delete_counters_subgroup()
+{
+ struct counters_subgroup *subgroup =
+ create_counters_subgroup("subgroup", 1, 1);
+
+ CU_ASSERT_FALSE(delete_counters_subgroup(NULL));
+ CU_ASSERT_TRUE(delete_counters_subgroup(subgroup));
+}
+
+void test_reset_group_counters()
+{
+ uint16_t subgroup_id = 1;
+ uint16_t counter_id = 1;
+ struct counters_group *group = create_counters_group("group", 10);
+ struct counters_subgroup *subgroup =
+ create_counters_subgroup("subgroup", subgroup_id, 10);
+ create_subgroup_counter(subgroup, counter_id, "counter");
+ add_counters_subgroup(group, subgroup);
+
+ struct counter *counter = subgroup->counters[counter_id];
+ counter->counter_value = 100;
+
+ CU_ASSERT_FALSE(reset_group_counters(NULL));
+ CU_ASSERT_TRUE(reset_group_counters(group));
+ CU_ASSERT_EQUAL(counter->counter_value, 0);
+
+ delete_counters_group(group);
+}
+
+void test_reset_subgroup_counters()
+{
+ uint16_t counter_id = 1;
+ struct counters_subgroup *subgroup =
+ create_counters_subgroup("subgroup", 1, 10);
+ create_subgroup_counter(subgroup, counter_id, "counter");
+
+ struct counter *counter = subgroup->counters[counter_id];
+ counter->counter_value = 100;
+
+ CU_ASSERT_FALSE(reset_subgroup_counters(NULL));
+ CU_ASSERT_TRUE(reset_subgroup_counters(subgroup));
+ CU_ASSERT_EQUAL(counter->counter_value, 0);
+
+ delete_counters_subgroup(subgroup);
+}
+
+void test_increment_counter()
+{
+ uint16_t subgroup_id = 1;
+ uint16_t counter_id = 1;
+ struct counters_group *group = create_counters_group("group", 10);
+ struct counters_subgroup *subgroup =
+ create_counters_subgroup("subgroup", subgroup_id, 10);
+ create_subgroup_counter(subgroup, counter_id, "counter");
+ add_counters_subgroup(group, subgroup);
+
+ struct counter *counter = subgroup->counters[counter_id];
+ counter->counter_value = 100;
+
+ CU_ASSERT_FALSE(increment_counter(NULL, subgroup_id, counter_id));
+ CU_ASSERT_FALSE(increment_counter(group, 100, counter_id));
+ CU_ASSERT_FALSE(increment_counter(group, subgroup_id, 123));
+ CU_ASSERT_TRUE(increment_counter(group, subgroup_id, counter_id));
+ CU_ASSERT_EQUAL(counter->counter_value, 101);
+ CU_ASSERT_EQUAL(subgroup_counters_total(subgroup), 101);
+
+ delete_counters_group(group);
+}
+
+void test_increment_subgroup_counter()
+{
+ int counter_id = 1;
+ uint32_t counter_value = 100;
+ struct counters_subgroup *subgroup =
+ create_counters_subgroup("subgroup", 1, 10);
+ create_subgroup_counter(subgroup, counter_id, "counter");
+
+ struct counter *counter = subgroup->counters[counter_id];
+ counter->counter_value = counter_value;
+
+ CU_ASSERT_FALSE(increment_subgroup_counter(NULL, counter_id));
+ CU_ASSERT_FALSE(increment_subgroup_counter(subgroup, counter_id + 1));
+ CU_ASSERT_TRUE(increment_subgroup_counter(subgroup, counter_id));
+ CU_ASSERT_EQUAL(counter->counter_value, counter_value + 1);
+
+ delete_counters_subgroup(subgroup);
+}
+
+void test_dump_counters_group_to_log()
+{
+ uint16_t subgroup_id = 1;
+ uint16_t counter_id = 1;
+ struct counters_group *group = create_counters_group("group", 10);
+ struct counters_subgroup *subgroup =
+ create_counters_subgroup("subgroup", subgroup_id, 10);
+ create_subgroup_counter(subgroup, counter_id, "counter");
+ add_counters_subgroup(group, subgroup);
+
+ CU_ASSERT_FALSE(dump_counters_group_to_log(NULL));
+ CU_ASSERT_TRUE(dump_counters_group_to_log(group));
+
+ delete_counters_group(group);
+}
+
+void test_dump_counters_subgroup_to_log()
+{
+ uint16_t subgroup_id = 1;
+ uint16_t counter_id = 1;
+ struct counters_subgroup *subgroup =
+ create_counters_subgroup("subgroup", subgroup_id, 10);
+ create_subgroup_counter(subgroup, counter_id, "counter");
+
+ CU_ASSERT_FALSE(dump_counters_subgroup_to_log(NULL));
+ CU_ASSERT_TRUE(dump_counters_subgroup_to_log(subgroup));
+
+ delete_counters_subgroup(subgroup);
+}
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Javier Garcia <javier.garcia@voltanet.io>
+ *
+ */
+
+/*
+ * Timer definitions to be used internally by the pcep_timers library.
+ */
+
+#ifndef PCEP_UTILS_COUNTERS_TEST_H_
+#define PCEP_UTILS_COUNTERS_TEST_H_
+
+void test_create_counters_group(void);
+void test_create_counters_subgroup(void);
+void test_add_counters_subgroup(void);
+void test_create_subgroup_counter(void);
+void test_delete_counters_group(void);
+void test_delete_counters_subgroup(void);
+void test_reset_group_counters(void);
+void test_reset_subgroup_counters(void);
+void test_increment_counter(void);
+void test_increment_subgroup_counter(void);
+void test_dump_counters_group_to_log(void);
+void test_dump_counters_subgroup_to_log(void);
+
+#endif
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <CUnit/CUnit.h>
+
+#include "pcep_utils_double_linked_list.h"
+#include "pcep_utils_double_linked_list_test.h"
+
+typedef struct dll_node_data_ {
+ int int_data;
+
+} dll_node_data;
+
+void test_empty_dl_list()
+{
+ double_linked_list *handle = dll_initialize();
+
+ CU_ASSERT_PTR_NULL(dll_delete_first_node(handle));
+ CU_ASSERT_PTR_NULL(dll_delete_last_node(handle));
+ CU_ASSERT_PTR_NULL(dll_delete_node(handle, NULL));
+
+ dll_destroy(handle);
+}
+
+void test_null_dl_list_handle()
+{
+ dll_destroy(NULL);
+ CU_ASSERT_PTR_NULL(dll_prepend(NULL, NULL));
+ CU_ASSERT_PTR_NULL(dll_append(NULL, NULL));
+ CU_ASSERT_PTR_NULL(dll_delete_first_node(NULL));
+ CU_ASSERT_PTR_NULL(dll_delete_last_node(NULL));
+ CU_ASSERT_PTR_NULL(dll_delete_node(NULL, NULL));
+}
+
+void test_dll_prepend_data()
+{
+ dll_node_data data1, data2, data3;
+ data1.int_data = 1;
+ data2.int_data = 2;
+ data3.int_data = 3;
+
+ double_linked_list *handle = dll_initialize();
+
+ CU_ASSERT_PTR_NOT_NULL(dll_prepend(handle, &data3));
+ CU_ASSERT_PTR_NOT_NULL(dll_prepend(handle, &data2));
+ CU_ASSERT_PTR_NOT_NULL(dll_prepend(handle, &data1));
+
+ CU_ASSERT_EQUAL(handle->num_entries, 3);
+
+ double_linked_list_node *node = handle->head;
+ CU_ASSERT_PTR_EQUAL(node->data, &data1);
+ CU_ASSERT_PTR_NULL(node->prev_node);
+ CU_ASSERT_PTR_NOT_NULL(node->next_node);
+
+ node = node->next_node;
+ CU_ASSERT_PTR_EQUAL(node->data, &data2);
+ CU_ASSERT_PTR_NOT_NULL(node->prev_node);
+ CU_ASSERT_PTR_NOT_NULL(node->next_node);
+
+ node = node->next_node;
+ CU_ASSERT_PTR_EQUAL(node->data, &data3);
+ CU_ASSERT_PTR_NOT_NULL(node->prev_node);
+ CU_ASSERT_PTR_NULL(node->next_node);
+ CU_ASSERT_PTR_EQUAL(handle->tail, node);
+
+ dll_destroy(handle);
+}
+
+
+void test_dll_append_data()
+{
+ dll_node_data data1, data2, data3;
+ data1.int_data = 1;
+ data2.int_data = 2;
+ data3.int_data = 3;
+
+ double_linked_list *handle = dll_initialize();
+
+ CU_ASSERT_PTR_NOT_NULL(dll_append(handle, &data1));
+ CU_ASSERT_PTR_NOT_NULL(dll_append(handle, &data2));
+ CU_ASSERT_PTR_NOT_NULL(dll_append(handle, &data3));
+
+ CU_ASSERT_EQUAL(handle->num_entries, 3);
+
+ double_linked_list_node *node = handle->head;
+ CU_ASSERT_PTR_EQUAL(node->data, &data1);
+ CU_ASSERT_PTR_NULL(node->prev_node);
+ CU_ASSERT_PTR_NOT_NULL(node->next_node);
+
+ node = node->next_node;
+ CU_ASSERT_PTR_EQUAL(node->data, &data2);
+ CU_ASSERT_PTR_NOT_NULL(node->prev_node);
+ CU_ASSERT_PTR_NOT_NULL(node->next_node);
+
+ node = node->next_node;
+ CU_ASSERT_PTR_EQUAL(node->data, &data3);
+ CU_ASSERT_PTR_NOT_NULL(node->prev_node);
+ CU_ASSERT_PTR_NULL(node->next_node);
+ CU_ASSERT_PTR_EQUAL(handle->tail, node);
+
+ dll_destroy(handle);
+}
+
+
+void test_dll_delete_first_node()
+{
+ dll_node_data data1, data2;
+ data1.int_data = 1;
+ data2.int_data = 2;
+
+ double_linked_list *handle = dll_initialize();
+
+ /* Test deleting with just 1 node in the list */
+ CU_ASSERT_PTR_NOT_NULL(dll_append(handle, &data1));
+ CU_ASSERT_EQUAL(handle->num_entries, 1);
+
+ void *deleted_data = dll_delete_first_node(handle);
+ CU_ASSERT_PTR_NOT_NULL(deleted_data);
+ CU_ASSERT_PTR_EQUAL(&data1, deleted_data);
+
+ CU_ASSERT_EQUAL(handle->num_entries, 0);
+ CU_ASSERT_PTR_NULL(handle->head);
+ CU_ASSERT_PTR_NULL(handle->tail);
+
+ /* Test deleting with 2 nodes in the list */
+ CU_ASSERT_PTR_NOT_NULL(dll_append(handle, &data1));
+ CU_ASSERT_PTR_NOT_NULL(dll_append(handle, &data2));
+ CU_ASSERT_EQUAL(handle->num_entries, 2);
+
+ deleted_data = dll_delete_first_node(handle);
+ CU_ASSERT_PTR_NOT_NULL(deleted_data);
+ CU_ASSERT_PTR_EQUAL(&data1, deleted_data);
+
+ CU_ASSERT_EQUAL(handle->num_entries, 1);
+ CU_ASSERT_PTR_EQUAL(handle->head->data, &data2);
+ CU_ASSERT_PTR_EQUAL(handle->head, handle->tail);
+ CU_ASSERT_PTR_NULL(handle->head->prev_node);
+ CU_ASSERT_PTR_NULL(handle->head->next_node);
+
+ dll_destroy(handle);
+}
+
+
+void test_dll_delete_last_node()
+{
+ dll_node_data data1, data2;
+ data1.int_data = 1;
+ data2.int_data = 2;
+
+ double_linked_list *handle = dll_initialize();
+
+ /* Test deleting with just 1 node in the list */
+ CU_ASSERT_PTR_NOT_NULL(dll_append(handle, &data1));
+ CU_ASSERT_EQUAL(handle->num_entries, 1);
+
+ void *deleted_data = dll_delete_last_node(handle);
+ CU_ASSERT_PTR_NOT_NULL(deleted_data);
+ CU_ASSERT_PTR_EQUAL(&data1, deleted_data);
+
+ CU_ASSERT_EQUAL(handle->num_entries, 0);
+ CU_ASSERT_PTR_NULL(handle->head);
+ CU_ASSERT_PTR_NULL(handle->tail);
+
+ /* Test deleting with 2 nodes in the list */
+ CU_ASSERT_PTR_NOT_NULL(dll_append(handle, &data1));
+ CU_ASSERT_PTR_NOT_NULL(dll_append(handle, &data2));
+ CU_ASSERT_EQUAL(handle->num_entries, 2);
+
+ deleted_data = dll_delete_last_node(handle);
+ CU_ASSERT_PTR_NOT_NULL(deleted_data);
+ CU_ASSERT_PTR_EQUAL(&data2, deleted_data);
+
+ CU_ASSERT_EQUAL(handle->num_entries, 1);
+ CU_ASSERT_PTR_EQUAL(handle->head->data, &data1);
+ CU_ASSERT_PTR_EQUAL(handle->head, handle->tail);
+ CU_ASSERT_PTR_NULL(handle->head->prev_node);
+ CU_ASSERT_PTR_NULL(handle->head->next_node);
+
+ dll_destroy(handle);
+}
+
+
+void test_dll_delete_node()
+{
+ dll_node_data data1, data2, data3;
+ data1.int_data = 1;
+ data2.int_data = 2;
+ data3.int_data = 3;
+ double_linked_list_node *node1, *node2, *node3;
+ double_linked_list *handle;
+
+ /* Test deleting with just 1 node in the list */
+ handle = dll_initialize();
+ node1 = dll_append(handle, &data1);
+ CU_ASSERT_PTR_NOT_NULL(node1);
+ CU_ASSERT_EQUAL(handle->num_entries, 1);
+
+ void *deleted_data = dll_delete_node(handle, node1);
+ CU_ASSERT_PTR_NOT_NULL(deleted_data);
+ CU_ASSERT_PTR_EQUAL(&data1, deleted_data);
+
+ CU_ASSERT_EQUAL(handle->num_entries, 0);
+ CU_ASSERT_PTR_NULL(handle->head);
+ CU_ASSERT_PTR_NULL(handle->tail);
+
+ /*
+ * Test deleting the head with 2 nodes in the list
+ */
+ node1 = dll_append(handle, &data1);
+ node2 = dll_append(handle, &data2);
+ CU_ASSERT_PTR_NOT_NULL(node1);
+ CU_ASSERT_PTR_NOT_NULL(node2);
+ CU_ASSERT_EQUAL(handle->num_entries, 2);
+
+ /* Delete the head entry */
+ deleted_data = dll_delete_node(handle, node1);
+ CU_ASSERT_PTR_NOT_NULL(deleted_data);
+ CU_ASSERT_PTR_EQUAL(&data1, deleted_data);
+
+ CU_ASSERT_EQUAL(handle->num_entries, 1);
+ CU_ASSERT_PTR_EQUAL(handle->head->data, &data2);
+ CU_ASSERT_PTR_EQUAL(handle->head, handle->tail);
+ CU_ASSERT_PTR_NULL(handle->head->prev_node);
+ CU_ASSERT_PTR_NULL(handle->head->next_node);
+ dll_destroy(handle);
+
+ /*
+ * Test deleting the tail with 2 nodes in the list
+ */
+ handle = dll_initialize();
+ node1 = dll_append(handle, &data1);
+ node2 = dll_append(handle, &data2);
+ CU_ASSERT_PTR_NOT_NULL(node1);
+ CU_ASSERT_PTR_NOT_NULL(node2);
+ CU_ASSERT_EQUAL(handle->num_entries, 2);
+
+ /* Delete the tail entry */
+ deleted_data = dll_delete_node(handle, node2);
+ CU_ASSERT_PTR_NOT_NULL(deleted_data);
+ CU_ASSERT_PTR_EQUAL(&data2, deleted_data);
+
+ CU_ASSERT_EQUAL(handle->num_entries, 1);
+ CU_ASSERT_PTR_EQUAL(handle->head->data, &data1);
+ CU_ASSERT_PTR_EQUAL(handle->head, handle->tail);
+ CU_ASSERT_PTR_NULL(handle->head->prev_node);
+ CU_ASSERT_PTR_NULL(handle->head->next_node);
+ dll_destroy(handle);
+
+ /*
+ * Test deleting in the middle with 3 nodes in the list
+ */
+ handle = dll_initialize();
+ node1 = dll_append(handle, &data1);
+ node2 = dll_append(handle, &data2);
+ node3 = dll_append(handle, &data3);
+ CU_ASSERT_PTR_NOT_NULL(node1);
+ CU_ASSERT_PTR_NOT_NULL(node2);
+ CU_ASSERT_PTR_NOT_NULL(node3);
+ CU_ASSERT_EQUAL(handle->num_entries, 3);
+
+ /* Delete the middle entry */
+ deleted_data = dll_delete_node(handle, node2);
+ CU_ASSERT_PTR_NOT_NULL(deleted_data);
+ CU_ASSERT_PTR_EQUAL(&data2, deleted_data);
+
+ CU_ASSERT_EQUAL(handle->num_entries, 2);
+ CU_ASSERT_PTR_EQUAL(handle->head, node1);
+ CU_ASSERT_PTR_EQUAL(handle->tail, node3);
+ CU_ASSERT_PTR_EQUAL(node1->data, &data1);
+ CU_ASSERT_PTR_EQUAL(node3->data, &data3);
+ CU_ASSERT_PTR_EQUAL(node1->next_node, node3);
+ CU_ASSERT_PTR_EQUAL(node3->prev_node, node1);
+ CU_ASSERT_PTR_NULL(node1->prev_node);
+ CU_ASSERT_PTR_NULL(node3->next_node);
+
+ dll_destroy(handle);
+}
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Javier Garcia <javier.garcia@voltanet.io>
+ *
+ */
+
+/*
+ * Timer definitions to be used internally by the pcep_timers library.
+ */
+
+#ifndef PCEP_UTILS_DOUBLE_LINKED_LIST_TEST_H_
+#define PCEP_UTILS_DOUBLE_LINKED_LIST_TEST_H_
+
+void test_empty_dl_list(void);
+void test_null_dl_list_handle(void);
+void test_dll_prepend_data(void);
+void test_dll_append_data(void);
+void test_dll_delete_first_node(void);
+void test_dll_delete_last_node(void);
+void test_dll_delete_node(void);
+
+#endif /* PCEPTIMERINTERNALS_H_ */
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <stdlib.h>
+#include <stdint.h>
+
+#include <CUnit/CUnit.h>
+
+#include "pcep_utils_memory.h"
+#include "pcep_utils_memory_test.h"
+
+void *test_pceplib_malloc(void *mem_type, size_t size);
+void *test_pceplib_calloc(void *mem_type, size_t size);
+void *test_pceplib_realloc(void *mem_type, void *ptr, size_t size);
+void *test_pceplib_strdup(void *mem_type, const char *str);
+void test_pceplib_free(void *mem_type, void *ptr);
+void verify_memory_type(struct pceplib_memory_type *mt, uint32_t num_alloc,
+ uint32_t alloc_bytes, uint32_t num_free,
+ uint32_t free_bytes);
+void verify_ext_memory_type(void *mt, int num_malloc_calls,
+ int num_calloc_calls, int num_realloc_calls,
+ int num_strdup_calls, int num_free_calls);
+
+struct test_memory_type {
+ int num_malloc_calls;
+ int num_calloc_calls;
+ int num_realloc_calls;
+ int num_strdup_calls;
+ int num_free_calls;
+};
+
+void *test_pceplib_malloc(void *mem_type, size_t size)
+{
+ ((struct test_memory_type *)mem_type)->num_malloc_calls++;
+ return malloc(size);
+}
+
+void *test_pceplib_calloc(void *mem_type, size_t size)
+{
+ ((struct test_memory_type *)mem_type)->num_calloc_calls++;
+ return calloc(1, size);
+}
+
+void *test_pceplib_realloc(void *mem_type, void *ptr, size_t size)
+{
+ ((struct test_memory_type *)mem_type)->num_realloc_calls++;
+ return realloc(ptr, size);
+}
+
+void *test_pceplib_strdup(void *mem_type, const char *str)
+{
+ ((struct test_memory_type *)mem_type)->num_strdup_calls++;
+ return strdup(str);
+}
+
+void test_pceplib_free(void *mem_type, void *ptr)
+{
+ ((struct test_memory_type *)mem_type)->num_free_calls++;
+ free(ptr);
+}
+
+void verify_memory_type(struct pceplib_memory_type *mt, uint32_t num_alloc,
+ uint32_t alloc_bytes, uint32_t num_free,
+ uint32_t free_bytes)
+{
+ CU_ASSERT_EQUAL(num_alloc, mt->num_allocates);
+ CU_ASSERT_EQUAL(alloc_bytes, mt->total_bytes_allocated);
+ CU_ASSERT_EQUAL(num_free, mt->num_frees);
+ CU_ASSERT_EQUAL(free_bytes, mt->total_bytes_freed);
+}
+
+void verify_ext_memory_type(void *mt, int num_malloc_calls,
+ int num_calloc_calls, int num_realloc_calls,
+ int num_strdup_calls, int num_free_calls)
+{
+ struct test_memory_type *mt_ptr = (struct test_memory_type *)mt;
+ CU_ASSERT_EQUAL(num_malloc_calls, mt_ptr->num_malloc_calls);
+ CU_ASSERT_EQUAL(num_calloc_calls, mt_ptr->num_calloc_calls);
+ CU_ASSERT_EQUAL(num_realloc_calls, mt_ptr->num_realloc_calls);
+ CU_ASSERT_EQUAL(num_strdup_calls, mt_ptr->num_strdup_calls);
+ CU_ASSERT_EQUAL(num_free_calls, mt_ptr->num_free_calls);
+}
+
+void test_memory_internal_impl()
+{
+ int alloc_size = 100;
+ struct pceplib_memory_type *pceplib_infra_ptr =
+ (struct pceplib_memory_type *)PCEPLIB_INFRA;
+ struct pceplib_memory_type *pceplib_messages_ptr =
+ (struct pceplib_memory_type *)PCEPLIB_MESSAGES;
+ int alloc_counter = 1;
+ int free_counter = 1;
+
+ /* reset the memory type counters for easier testing */
+ pceplib_infra_ptr->num_allocates =
+ pceplib_infra_ptr->total_bytes_allocated =
+ pceplib_infra_ptr->num_frees =
+ pceplib_infra_ptr->total_bytes_freed = 0;
+ pceplib_messages_ptr->num_allocates =
+ pceplib_messages_ptr->total_bytes_allocated =
+ pceplib_messages_ptr->num_frees =
+ pceplib_messages_ptr->total_bytes_freed = 0;
+
+ /* Make sure nothing crashes when all these are set NULL, since the
+ * internal default values should still be used. */
+ pceplib_memory_initialize(NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+
+ /* Test malloc() */
+ void *ptr = pceplib_malloc(PCEPLIB_INFRA, alloc_size);
+ CU_ASSERT_PTR_NOT_NULL(ptr);
+ pceplib_free(PCEPLIB_INFRA, ptr);
+ verify_memory_type(pceplib_infra_ptr, alloc_counter, alloc_size,
+ free_counter++, 0);
+
+ /* Test calloc() */
+ ptr = pceplib_calloc(PCEPLIB_INFRA, alloc_size);
+ CU_ASSERT_PTR_NOT_NULL(ptr);
+ pceplib_free(PCEPLIB_INFRA, ptr);
+ alloc_counter++;
+ verify_memory_type(pceplib_infra_ptr, alloc_counter,
+ alloc_size * alloc_counter, free_counter++, 0);
+
+ /* Test realloc() */
+ ptr = pceplib_malloc(PCEPLIB_INFRA, alloc_size);
+ CU_ASSERT_PTR_NOT_NULL(ptr);
+ ptr = pceplib_realloc(PCEPLIB_INFRA, ptr, alloc_size);
+ CU_ASSERT_PTR_NOT_NULL(ptr);
+ pceplib_free(PCEPLIB_INFRA, ptr);
+ alloc_counter += 2;
+ verify_memory_type(pceplib_infra_ptr, alloc_counter,
+ alloc_size * alloc_counter, free_counter++, 0);
+
+ /* Test strdup() */
+ ptr = pceplib_malloc(PCEPLIB_INFRA, alloc_size);
+ /* Make strdup duplicate (alloc_size - 1) bytes */
+ memset(ptr, 'a', alloc_size);
+ ((char *)ptr)[alloc_size - 1] = '\0';
+ char *str = pceplib_strdup(PCEPLIB_INFRA, (char *)ptr);
+ CU_ASSERT_PTR_NOT_NULL(ptr);
+ pceplib_free(PCEPLIB_INFRA, ptr);
+ pceplib_free(PCEPLIB_INFRA, str);
+ alloc_counter += 2;
+ free_counter++;
+ verify_memory_type(pceplib_infra_ptr, alloc_counter,
+ (alloc_size * alloc_counter) - 1, free_counter, 0);
+
+ /* Make sure only the pceplib_infra_ptr memory counters are incremented
+ */
+ verify_memory_type(pceplib_messages_ptr, 0, 0, 0, 0);
+}
+
+void test_memory_external_impl()
+{
+ int alloc_size = 100;
+ struct pceplib_memory_type *pceplib_infra_ptr =
+ (struct pceplib_memory_type *)PCEPLIB_INFRA;
+ struct pceplib_memory_type *pceplib_messages_ptr =
+ (struct pceplib_memory_type *)PCEPLIB_MESSAGES;
+
+ /* reset the internal memory type counters to later verify they are NOT
+ * incremented since an external impl was provided */
+ pceplib_infra_ptr->num_allocates =
+ pceplib_infra_ptr->total_bytes_allocated =
+ pceplib_infra_ptr->num_frees =
+ pceplib_infra_ptr->total_bytes_freed = 0;
+ pceplib_messages_ptr->num_allocates =
+ pceplib_messages_ptr->total_bytes_allocated =
+ pceplib_messages_ptr->num_frees =
+ pceplib_messages_ptr->total_bytes_freed = 0;
+
+ /* Setup the external memory type */
+ struct test_memory_type infra_mt, messages_mt;
+ void *infra_ptr = &infra_mt;
+ void *messages_ptr = &messages_mt;
+ memset(infra_ptr, 0, sizeof(struct test_memory_type));
+ memset(messages_ptr, 0, sizeof(struct test_memory_type));
+ int free_counter = 1;
+
+ /* Initialize the PCEPlib memory system with an external implementation
+ */
+ pceplib_memory_initialize(infra_ptr, messages_ptr, test_pceplib_malloc,
+ test_pceplib_calloc, test_pceplib_realloc,
+ test_pceplib_strdup, test_pceplib_free);
+
+ /* Test malloc() */
+ void *ptr = pceplib_malloc(PCEPLIB_MESSAGES, alloc_size);
+ CU_ASSERT_PTR_NOT_NULL(ptr);
+ pceplib_free(PCEPLIB_MESSAGES, ptr);
+ verify_ext_memory_type(messages_ptr, 1, 0, 0, 0, free_counter++);
+
+ /* Test calloc() */
+ ptr = pceplib_calloc(PCEPLIB_MESSAGES, alloc_size);
+ CU_ASSERT_PTR_NOT_NULL(ptr);
+ pceplib_free(PCEPLIB_MESSAGES, ptr);
+ verify_ext_memory_type(messages_ptr, 1, 1, 0, 0, free_counter++);
+
+ /* Test realloc() */
+ ptr = pceplib_malloc(PCEPLIB_MESSAGES, alloc_size);
+ CU_ASSERT_PTR_NOT_NULL(ptr);
+ ptr = pceplib_realloc(PCEPLIB_MESSAGES, ptr, alloc_size);
+ CU_ASSERT_PTR_NOT_NULL(ptr);
+ pceplib_free(PCEPLIB_MESSAGES, ptr);
+ verify_ext_memory_type(messages_ptr, 2, 1, 1, 0, free_counter++);
+
+ /* Test strdup() */
+ ptr = pceplib_malloc(PCEPLIB_MESSAGES, alloc_size);
+ /* Make strdup duplicate (alloc_size - 1) bytes */
+ memset(ptr, 'a', alloc_size);
+ ((char *)ptr)[alloc_size - 1] = '\0';
+ char *str = pceplib_strdup(PCEPLIB_MESSAGES, (char *)ptr);
+ CU_ASSERT_PTR_NOT_NULL(ptr);
+ pceplib_free(PCEPLIB_MESSAGES, ptr);
+ pceplib_free(PCEPLIB_MESSAGES, str);
+ verify_ext_memory_type(messages_ptr, 3, 1, 1, 1, free_counter + 1);
+
+ /* Make sure the internal memory counters are NOT incremented */
+ verify_memory_type(pceplib_infra_ptr, 0, 0, 0, 0);
+ verify_memory_type(pceplib_messages_ptr, 0, 0, 0, 0);
+
+ verify_ext_memory_type(infra_ptr, 0, 0, 0, 0, 0);
+}
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Javier Garcia <javier.garcia@voltanet.io>
+ *
+ */
+
+/*
+ * Timer definitions to be used internally by the pcep_timers library.
+ */
+
+#ifndef PCEP_MEMORY_TEST_H_
+#define PCEP_MEMORY_TEST_H_
+
+void test_memory_internal_impl(void);
+void test_memory_external_impl(void);
+
+#endif /* PCEPTIMERINTERNALS_H_ */
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <CUnit/CUnit.h>
+
+#include "pcep_utils_ordered_list.h"
+#include "pcep_utils_ordered_list_test.h"
+
+typedef struct node_data_ {
+ int int_data;
+
+} node_data;
+
+
+int node_data_compare(void *list_entry, void *new_entry)
+{
+ /*
+ * < 0 if new_entry < list_entry
+ * == 0 if new_entry == list_entry (new_entry will be inserted after
+ * list_entry) > 0 if new_entry > list_entry
+ */
+
+ return ((node_data *)new_entry)->int_data
+ - ((node_data *)list_entry)->int_data;
+}
+
+
+void test_empty_list()
+{
+ ordered_list_handle *handle =
+ ordered_list_initialize(node_data_compare);
+
+ CU_ASSERT_PTR_NOT_NULL(handle);
+ CU_ASSERT_PTR_NULL(handle->head);
+ CU_ASSERT_PTR_NOT_NULL(handle->compare_function);
+ CU_ASSERT_EQUAL(handle->num_entries, 0);
+
+ ordered_list_destroy(handle);
+}
+
+
+void test_null_list_handle()
+{
+ node_data data;
+ ordered_list_node node_data;
+
+ void *ptr = ordered_list_add_node(NULL, &data);
+ CU_ASSERT_PTR_NULL(ptr);
+
+ ptr = ordered_list_find(NULL, &data);
+ CU_ASSERT_PTR_NULL(ptr);
+
+ ptr = ordered_list_remove_first_node(NULL);
+ CU_ASSERT_PTR_NULL(ptr);
+
+ ptr = ordered_list_remove_first_node_equals(NULL, &data);
+ CU_ASSERT_PTR_NULL(ptr);
+
+ ptr = ordered_list_remove_node(NULL, &node_data, &node_data);
+ CU_ASSERT_PTR_NULL(ptr);
+}
+
+
+void test_add_to_list()
+{
+ node_data data1, data2, data3;
+ data1.int_data = 1;
+ data2.int_data = 2;
+ data3.int_data = 3;
+
+ ordered_list_handle *handle =
+ ordered_list_initialize(node_data_compare);
+
+ ordered_list_add_node(handle, &data3);
+ ordered_list_add_node(handle, &data1);
+ ordered_list_add_node(handle, &data2);
+
+ CU_ASSERT_EQUAL(handle->num_entries, 3);
+
+ ordered_list_node *node = handle->head;
+ CU_ASSERT_PTR_EQUAL(node->data, &data1);
+
+ node = node->next_node;
+ CU_ASSERT_PTR_EQUAL(node->data, &data2);
+
+ node = node->next_node;
+ CU_ASSERT_PTR_EQUAL(node->data, &data3);
+
+ node = node->next_node;
+ CU_ASSERT_PTR_EQUAL(node, NULL);
+
+ ordered_list_destroy(handle);
+}
+
+
+void test_find()
+{
+ node_data data1, data2, data3, data_not_inList;
+ data1.int_data = 1;
+ data2.int_data = 2;
+ data3.int_data = 3;
+ data_not_inList.int_data = 5;
+
+ ordered_list_handle *handle =
+ ordered_list_initialize(node_data_compare);
+
+ ordered_list_add_node(handle, &data3);
+ ordered_list_add_node(handle, &data2);
+ ordered_list_add_node(handle, &data1);
+
+ ordered_list_node *node = ordered_list_find(handle, &data1);
+ CU_ASSERT_PTR_NOT_NULL(node);
+ CU_ASSERT_PTR_EQUAL(node->data, &data1);
+
+ node = ordered_list_find(handle, &data2);
+ CU_ASSERT_PTR_NOT_NULL(node);
+ CU_ASSERT_PTR_EQUAL(node->data, &data2);
+
+ node = ordered_list_find(handle, &data3);
+ CU_ASSERT_PTR_NOT_NULL(node);
+ CU_ASSERT_PTR_EQUAL(node->data, &data3);
+
+ node = ordered_list_find(handle, &data_not_inList);
+ CU_ASSERT_PTR_NULL(node);
+
+ ordered_list_destroy(handle);
+}
+
+
+void test_remove_first_node()
+{
+ node_data data1, data2, data3;
+ data1.int_data = 1;
+ data2.int_data = 2;
+ data3.int_data = 3;
+
+ ordered_list_handle *handle =
+ ordered_list_initialize(node_data_compare);
+
+ ordered_list_add_node(handle, &data1);
+ ordered_list_add_node(handle, &data2);
+ ordered_list_add_node(handle, &data3);
+
+ void *node_data = ordered_list_remove_first_node(handle);
+ CU_ASSERT_PTR_NOT_NULL(node_data);
+ CU_ASSERT_PTR_EQUAL(node_data, &data1);
+ CU_ASSERT_EQUAL(handle->num_entries, 2);
+
+ node_data = ordered_list_remove_first_node(handle);
+ CU_ASSERT_PTR_NOT_NULL(node_data);
+ CU_ASSERT_PTR_EQUAL(node_data, &data2);
+ CU_ASSERT_EQUAL(handle->num_entries, 1);
+
+ node_data = ordered_list_remove_first_node(handle);
+ CU_ASSERT_PTR_NOT_NULL(node_data);
+ CU_ASSERT_PTR_EQUAL(node_data, &data3);
+ CU_ASSERT_EQUAL(handle->num_entries, 0);
+ CU_ASSERT_PTR_NULL(handle->head);
+
+ node_data = ordered_list_remove_first_node(handle);
+ CU_ASSERT_PTR_NULL(node_data);
+
+ ordered_list_destroy(handle);
+}
+
+
+void test_remove_first_node_equals()
+{
+ node_data data1, data2, data3;
+ data1.int_data = 1;
+ data2.int_data = 2;
+ data3.int_data = 3;
+
+ ordered_list_handle *handle =
+ ordered_list_initialize(node_data_compare);
+
+ ordered_list_add_node(handle, &data1);
+ ordered_list_add_node(handle, &data2);
+ ordered_list_add_node(handle, &data3);
+
+ void *node_data = ordered_list_remove_first_node_equals(handle, &data2);
+ CU_ASSERT_PTR_NOT_NULL(node_data);
+ CU_ASSERT_PTR_EQUAL(node_data, &data2);
+ CU_ASSERT_EQUAL(handle->num_entries, 2);
+
+ node_data = ordered_list_remove_first_node_equals(handle, &data3);
+ CU_ASSERT_PTR_NOT_NULL(node_data);
+ CU_ASSERT_PTR_EQUAL(node_data, &data3);
+ CU_ASSERT_EQUAL(handle->num_entries, 1);
+
+ node_data = ordered_list_remove_first_node_equals(handle, &data1);
+ CU_ASSERT_PTR_NOT_NULL(node_data);
+ CU_ASSERT_PTR_EQUAL(node_data, &data1);
+ CU_ASSERT_EQUAL(handle->num_entries, 0);
+
+ node_data = ordered_list_remove_first_node_equals(handle, &data1);
+ CU_ASSERT_PTR_NULL(node_data);
+
+ ordered_list_destroy(handle);
+}
+
+
+void test_remove_node()
+{
+ node_data data1, data2, data3;
+ data1.int_data = 1;
+ data2.int_data = 2;
+ data3.int_data = 3;
+
+ ordered_list_handle *handle =
+ ordered_list_initialize(node_data_compare);
+
+ ordered_list_node *node1 = ordered_list_add_node(handle, &data1);
+ ordered_list_node *node2 = ordered_list_add_node(handle, &data2);
+ ordered_list_node *node3 = ordered_list_add_node(handle, &data3);
+
+ void *node_data = ordered_list_remove_node(handle, node2, node3);
+ CU_ASSERT_PTR_NOT_NULL(node_data);
+ CU_ASSERT_PTR_EQUAL(node_data, &data3);
+ CU_ASSERT_EQUAL(handle->num_entries, 2);
+
+ node_data = ordered_list_remove_node(handle, node1, node2);
+ CU_ASSERT_PTR_NOT_NULL(node_data);
+ CU_ASSERT_PTR_EQUAL(node_data, &data2);
+ CU_ASSERT_EQUAL(handle->num_entries, 1);
+
+ ordered_list_destroy(handle);
+}
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Javier Garcia <javier.garcia@voltanet.io>
+ *
+ */
+
+/*
+ * Timer definitions to be used internally by the pcep_timers library.
+ */
+
+#ifndef PCEP_UTILS_ORDERED_LIST_TEST_H_
+#define PCEP_UTILS_ORDERED_LIST_TEST_H_
+
+void test_empty_list(void);
+void test_null_list_handle(void);
+void test_add_to_list(void);
+void test_find(void);
+void test_remove_first_node(void);
+void test_remove_first_node_equals(void);
+void test_remove_node(void);
+int node_data_compare(void *list_entry, void *new_entry);
+
+#endif /* PCEPTIMERINTERNALS_H_ */
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <CUnit/CUnit.h>
+
+#include "pcep_utils_queue.h"
+#include "pcep_utils_queue_test.h"
+
+typedef struct node_data_ {
+ int int_data;
+
+} node_data;
+
+
+void test_empty_queue()
+{
+ queue_handle *handle = queue_initialize();
+
+ CU_ASSERT_PTR_NOT_NULL(handle);
+ CU_ASSERT_PTR_NULL(handle->head);
+ CU_ASSERT_EQUAL(handle->num_entries, 0);
+
+ queue_destroy(handle);
+}
+
+
+void test_null_queue_handle()
+{
+ /* test each method handles a NULL handle without crashing */
+ node_data data;
+ queue_destroy(NULL);
+ void *ptr = queue_enqueue(NULL, &data);
+ CU_ASSERT_PTR_NULL(ptr);
+
+ ptr = queue_dequeue(NULL);
+ CU_ASSERT_PTR_NULL(ptr);
+}
+
+
+void test_enqueue()
+{
+ node_data data1, data2, data3;
+ data1.int_data = 1;
+ data2.int_data = 2;
+ data3.int_data = 3;
+
+ queue_handle *handle = queue_initialize();
+
+ queue_enqueue(handle, &data1);
+ queue_enqueue(handle, &data2);
+ queue_enqueue(handle, &data3);
+
+ CU_ASSERT_EQUAL(handle->num_entries, 3);
+
+ queue_node *node = handle->head;
+ CU_ASSERT_PTR_EQUAL(node->data, &data1);
+
+ node = node->next_node;
+ CU_ASSERT_PTR_EQUAL(node->data, &data2);
+
+ node = node->next_node;
+ CU_ASSERT_PTR_EQUAL(node->data, &data3);
+
+ node = node->next_node;
+ CU_ASSERT_PTR_NULL(node);
+
+ queue_destroy(handle);
+}
+
+
+void test_enqueue_with_limit()
+{
+ node_data data1, data2, data3;
+ data1.int_data = 1;
+ data2.int_data = 2;
+ data3.int_data = 3;
+
+ queue_handle *handle = queue_initialize_with_size(2);
+
+ queue_node *node = queue_enqueue(handle, &data1);
+ CU_ASSERT_PTR_NOT_NULL(node);
+
+ node = queue_enqueue(handle, &data2);
+ CU_ASSERT_PTR_NOT_NULL(node);
+
+ node = queue_enqueue(handle, &data3);
+ CU_ASSERT_PTR_NULL(node);
+
+ CU_ASSERT_EQUAL(handle->num_entries, 2);
+
+ node = handle->head;
+ CU_ASSERT_PTR_EQUAL(node->data, &data1);
+
+ node = node->next_node;
+ CU_ASSERT_PTR_EQUAL(node->data, &data2);
+
+ node = node->next_node;
+ CU_ASSERT_PTR_NULL(node);
+
+ queue_destroy(handle);
+}
+
+
+void test_dequeue()
+{
+ node_data data1, data2, data3;
+ data1.int_data = 1;
+ data2.int_data = 2;
+ data3.int_data = 3;
+
+ queue_handle *handle = queue_initialize();
+
+ /* first test dequeue handles an empty queue */
+ void *node_data = queue_dequeue(handle);
+ CU_ASSERT_PTR_NULL(node_data);
+
+ queue_enqueue(handle, &data1);
+ queue_enqueue(handle, &data2);
+ queue_enqueue(handle, &data3);
+
+ node_data = queue_dequeue(handle);
+ CU_ASSERT_PTR_EQUAL(node_data, &data1);
+ CU_ASSERT_EQUAL(handle->num_entries, 2);
+
+ node_data = queue_dequeue(handle);
+ CU_ASSERT_PTR_EQUAL(node_data, &data2);
+ CU_ASSERT_EQUAL(handle->num_entries, 1);
+
+ node_data = queue_dequeue(handle);
+ CU_ASSERT_PTR_EQUAL(node_data, &data3);
+ CU_ASSERT_EQUAL(handle->num_entries, 0);
+
+ node_data = queue_dequeue(handle);
+ CU_ASSERT_PTR_NULL(node_data);
+
+ queue_destroy(handle);
+}
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Javier Garcia <javier.garcia@voltanet.io>
+ *
+ */
+
+/*
+ * Timer definitions to be used internally by the pcep_timers library.
+ */
+
+#ifndef PCEP_UTILS_QUEUE_TEST_H_
+#define PCEP_UTILS_QUEUE_TEST_H_
+
+void test_empty_queue(void);
+void test_null_queue_handle(void);
+void test_enqueue(void);
+void test_enqueue_with_limit(void);
+void test_dequeue(void);
+
+#endif /* PCEPTIMERINTERNALS_H_ */
--- /dev/null
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <CUnit/Basic.h>
+#include <CUnit/CUnit.h>
+#include <CUnit/TestDB.h>
+#include "pcep_utils_ordered_list_test.h"
+#include "pcep_utils_queue_test.h"
+#include "pcep_utils_double_linked_list_test.h"
+#include "pcep_utils_counters_test.h"
+#include "pcep_utils_memory_test.h"
+
+
+int main(int argc, char **argv)
+{
+ /* Unused parameters cause compilation warnings */
+ (void)argc;
+ (void)argv;
+
+ CU_initialize_registry();
+
+ CU_pSuite test_queue_suite =
+ CU_add_suite("PCEP Utils Queue Test Suite", NULL, NULL);
+ CU_add_test(test_queue_suite, "test_empty_queue", test_empty_queue);
+ CU_add_test(test_queue_suite, "test_null_queue_handle",
+ test_null_queue_handle);
+ CU_add_test(test_queue_suite, "test_enqueue", test_enqueue);
+ CU_add_test(test_queue_suite, "test_enqueue_with_limit",
+ test_enqueue_with_limit);
+ CU_add_test(test_queue_suite, "test_dequeue", test_dequeue);
+
+ CU_pSuite test_list_suite =
+ CU_add_suite("PCEP Utils Ordered List Test Suite", NULL, NULL);
+ CU_add_test(test_list_suite, "test_empty_list", test_empty_list);
+ CU_add_test(test_list_suite, "test_null_handle", test_null_list_handle);
+ CU_add_test(test_list_suite, "test_add_toList", test_add_to_list);
+ CU_add_test(test_list_suite, "test_find", test_find);
+ CU_add_test(test_list_suite, "test_remove_first_node",
+ test_remove_first_node);
+ CU_add_test(test_list_suite, "test_remove_first_node_equals",
+ test_remove_first_node_equals);
+ CU_add_test(test_list_suite, "test_remove_node", test_remove_node);
+
+ CU_pSuite test_dl_list_suite = CU_add_suite(
+ "PCEP Utils Double Linked List Test Suite", NULL, NULL);
+ CU_add_test(test_dl_list_suite, "test_empty_dl_list",
+ test_empty_dl_list);
+ CU_add_test(test_dl_list_suite, "test_null_dl_handle",
+ test_null_dl_list_handle);
+ CU_add_test(test_dl_list_suite, "test_dll_prepend_data",
+ test_dll_prepend_data);
+ CU_add_test(test_dl_list_suite, "test_dll_append_data",
+ test_dll_append_data);
+ CU_add_test(test_dl_list_suite, "test_dll_delete_first_node",
+ test_dll_delete_first_node);
+ CU_add_test(test_dl_list_suite, "test_dll_delete_last_node",
+ test_dll_delete_last_node);
+ CU_add_test(test_dl_list_suite, "test_dll_delete_node",
+ test_dll_delete_node);
+
+ CU_pSuite test_counters_suite =
+ CU_add_suite("PCEP Utils Counters Test Suite", NULL, NULL);
+ CU_add_test(test_counters_suite, "test_create_counters_group",
+ test_create_counters_group);
+ CU_add_test(test_counters_suite, "test_create_counters_subgroup",
+ test_create_counters_subgroup);
+ CU_add_test(test_counters_suite, "test_add_counters_subgroup",
+ test_add_counters_subgroup);
+ CU_add_test(test_counters_suite, "test_create_subgroup_counter",
+ test_create_subgroup_counter);
+ CU_add_test(test_counters_suite, "test_delete_counters_group",
+ test_delete_counters_group);
+ CU_add_test(test_counters_suite, "test_delete_counters_subgroup",
+ test_delete_counters_subgroup);
+ CU_add_test(test_counters_suite, "test_reset_group_counters",
+ test_reset_group_counters);
+ CU_add_test(test_counters_suite, "test_reset_subgroup_counters",
+ test_reset_subgroup_counters);
+ CU_add_test(test_counters_suite, "test_increment_counter",
+ test_increment_counter);
+ CU_add_test(test_counters_suite, "test_increment_subgroup_counter",
+ test_increment_subgroup_counter);
+ CU_add_test(test_counters_suite, "test_dump_counters_group_to_log",
+ test_dump_counters_group_to_log);
+ CU_add_test(test_counters_suite, "test_dump_counters_subgroup_to_log",
+ test_dump_counters_subgroup_to_log);
+
+ CU_pSuite test_memory_suite =
+ CU_add_suite("PCEP Utils Memory Test Suite", NULL, NULL);
+ CU_add_test(test_memory_suite, "test_memory_internal_impl",
+ test_memory_internal_impl);
+ CU_add_test(test_memory_suite, "test_memory_external_impl",
+ test_memory_external_impl);
+
+ CU_basic_set_mode(CU_BRM_VERBOSE);
+ CU_basic_run_tests();
+ CU_FailureRecord *failure_record = CU_get_failure_list();
+ if (failure_record != NULL) {
+ printf("\nFailed tests:\n\t [Suite] [Test] [File:line-number]\n");
+ do {
+ printf("\t [%s] [%s] [%s:%d]\n",
+ failure_record->pSuite->pName,
+ failure_record->pTest->pName,
+ failure_record->strFileName,
+ failure_record->uiLineNumber);
+ failure_record = failure_record->pNext;
+
+ } while (failure_record != NULL);
+ }
+
+ CU_pRunSummary run_summary = CU_get_run_summary();
+ int result = run_summary->nTestsFailed;
+ CU_cleanup_registry();
+
+ return result;
+}
--- /dev/null
+source pceplib/test/pcep_tests_valgrind.sh
+valgrind_test pceplib/test/pcep_utils_tests
--- /dev/null
+if PATHD_PCEP
+if PATHD_PCEP_TEST
+
+# The default Automake target is check, add a test target to call check.
+# Also make sure the binaries are current before running the tests.
+test: pceplib/test/pcep_msg_tests pceplib/test/pcep_pcc_api_tests pceplib/test/pcep_session_logic_tests pceplib/test/pcep_socket_comm_tests pceplib/test/pcep_timers_tests pceplib/test/pcep_utils_tests
+
+check_SCRIPTS = pceplib/test/pcep_msg_tests pceplib/test/pcep_pcc_api_tests pceplib/test/pcep_session_logic_tests pceplib/test/pcep_socket_comm_tests pceplib/test/pcep_timers_tests pceplib/test/pcep_utils_tests
+TESTS = $(check_SCRIPTS)
+
+
+# Definitions to build the Unit Test binaries with CUnit
+noinst_PROGRAMS += pceplib/test/pcep_msg_tests \
+ pceplib/test/pcep_pcc_api_tests \
+ pceplib/test/pcep_session_logic_tests \
+ pceplib/test/pcep_socket_comm_tests \
+ pceplib/test/pcep_timers_tests \
+ pceplib/test/pcep_utils_tests
+
+noinst_HEADERS += pceplib/test/pcep_msg_messages_test.h \
+ pceplib/test/pcep_msg_object_error_types_test.h \
+ pceplib/test/pcep_msg_objects_test.h \
+ pceplib/test/pcep_msg_tlvs_test.h \
+ pceplib/test/pcep_msg_tools_test.h \
+ pceplib/test/pcep_pcc_api_test.h \
+ pceplib/test/pcep_session_logic_loop_test.h \
+ pceplib/test/pcep_session_logic_states_test.h \
+ pceplib/test/pcep_session_logic_test.h \
+ pceplib/test/pcep_socket_comm_loop_test.h \
+ pceplib/test/pcep_socket_comm_test.h \
+ pceplib/test/pcep_timers_event_loop_test.h \
+ pceplib/test/pcep_timers_test.h \
+ pceplib/test/pcep_utils_counters_test.h \
+ pceplib/test/pcep_utils_double_linked_list_test.h \
+ pceplib/test/pcep_utils_memory_test.h \
+ pceplib/test/pcep_utils_ordered_list_test.h \
+ pceplib/test/pcep_utils_queue_test.h
+
+pceplib_test_pcep_msg_tests_CFLAGS = -I$(top_srcdir)/pceplib
+pceplib_test_pcep_msg_tests_LDADD = $(top_builddir)/pceplib/libpcep_pcc.la lib/libfrr.la -lcunit -lpthread
+pceplib_test_pcep_msg_tests_SOURCES = pceplib/test/pcep_msg_messages_test.c \
+ pceplib/test/pcep_msg_messages_tests.c \
+ pceplib/test/pcep_msg_object_error_types_test.c \
+ pceplib/test/pcep_msg_objects_test.c \
+ pceplib/test/pcep_msg_tlvs_test.c \
+ pceplib/test/pcep_msg_tools_test.c
+
+# The pcc_api_tests and pcep_session_logic_tests use the
+# socket_comm_mock, so the LDADD variable needs to be modified
+pceplib_test_pcep_pcc_api_tests_CFLAGS = -I$(top_srcdir)/pceplib
+pceplib_test_pcep_pcc_api_tests_LDADD = $(top_builddir)/pceplib/libsocket_comm_mock.la $(top_builddir)/pceplib/libpcep_pcc.la lib/libfrr.la -lcunit -lpthread
+pceplib_test_pcep_pcc_api_tests_SOURCES = pceplib/test/pcep_pcc_api_test.c pceplib/test/pcep_pcc_api_tests.c
+
+pceplib_test_pcep_session_logic_tests_CFLAGS = -I$(top_srcdir)/pceplib
+pceplib_test_pcep_session_logic_tests_LDADD = $(top_builddir)/pceplib/libsocket_comm_mock.la $(top_builddir)/pceplib/libpcep_pcc.la lib/libfrr.la -lcunit -lpthread
+pceplib_test_pcep_session_logic_tests_SOURCES = pceplib/test/pcep_session_logic_loop_test.c \
+ pceplib/test/pcep_session_logic_states_test.c \
+ pceplib/test/pcep_session_logic_test.c \
+ pceplib/test/pcep_session_logic_tests.c
+
+pceplib_test_pcep_socket_comm_tests_CFLAGS = -I$(top_srcdir)/pceplib
+pceplib_test_pcep_socket_comm_tests_LDADD = $(top_builddir)/pceplib/libpcep_pcc.la lib/libfrr.la -lcunit -lpthread
+pceplib_test_pcep_socket_comm_tests_SOURCES = pceplib/test/pcep_socket_comm_loop_test.c \
+ pceplib/test/pcep_socket_comm_test.c \
+ pceplib/test/pcep_socket_comm_tests.c
+
+pceplib_test_pcep_timers_tests_CFLAGS = -I$(top_srcdir)/pceplib
+pceplib_test_pcep_timers_tests_LDADD = $(top_builddir)/pceplib/libpcep_pcc.la lib/libfrr.la -lcunit -lpthread
+pceplib_test_pcep_timers_tests_SOURCES = pceplib/test/pcep_timers_event_loop_test.c \
+ pceplib/test/pcep_timers_test.c \
+ pceplib/test/pcep_timers_tests.c
+
+pceplib_test_pcep_utils_tests_CFLAGS = -I$(top_srcdir)/pceplib
+pceplib_test_pcep_utils_tests_LDADD = $(top_builddir)/pceplib/libpcep_pcc.la lib/libfrr.la -lcunit -lpthread
+pceplib_test_pcep_utils_tests_SOURCES = pceplib/test/pcep_utils_counters_test.c \
+ pceplib/test/pcep_utils_double_linked_list_test.c \
+ pceplib/test/pcep_utils_memory_test.c \
+ pceplib/test/pcep_utils_ordered_list_test.c \
+ pceplib/test/pcep_utils_queue_test.c \
+ pceplib/test/pcep_utils_tests.c
+
+# These test scripts will call the test binaries
+# defined above in noinst_PROGRAMS with Valgrind
+if HAVE_VALGRIND_PCEP
+
+dist_noinst_SCRIPTS = pceplib/test/pcep_pcc_api_tests_valgrind.sh \
+ pceplib/test/pcep_session_logic_tests_valgrind.sh \
+ pceplib/test/pcep_socket_comm_tests_valgrind.sh \
+ pceplib/test/pcep_timers_tests_valgrind.sh \
+ pceplib/test/pcep_utils_tests_valgrind.sh \
+ pceplib/test/pcep_msg_tests_valgrind.sh \
+ pceplib/test/pcep_tests_valgrind.sh
+
+check_SCRIPTS += pceplib/test/pcep_msg_tests_valgrind.sh \
+ pceplib/test/pcep_pcc_api_tests_valgrind.sh \
+ pceplib/test/pcep_session_logic_tests_valgrind.sh \
+ pceplib/test/pcep_socket_comm_tests_valgrind.sh \
+ pceplib/test/pcep_timers_tests_valgrind.sh \
+ pceplib/test/pcep_utils_tests_valgrind.sh
+
+TESTS += $(check_SCRIPTS)
+
+
+
+pceplib/test/pcep_msg_tests_valgrind.sh:
+ chmod +x pceplib/test/pcep_msg_tests_valgrind.sh
+pceplib/test/pcep_pcc_api_tests_valgrind.sh:
+ chmod +x pceplib/test/pcep_pcc_api_tests_valgrind.sh
+pceplib/test/pcep_session_logic_tests_valgrind.sh:
+ chmod +x pceplib/test/pcep_session_logic_tests_valgrind.sh
+pceplib/test/pcep_socket_comm_tests_valgrind.sh:
+ chmod +x pceplib/test/pcep_socket_comm_tests_valgrind.sh
+pceplib/test/pcep_timers_tests_valgrind.sh:
+ chmod +x pceplib/test/pcep_timers_tests_valgrind.sh
+pceplib/test/pcep_utils_tests_valgrind.sh:
+ chmod +x pceplib/test/pcep_utils_tests_valgrind.sh
+
+
+endif
+
+endif
+endif
int hold_time);
/* Memory Types */
-DEFINE_MTYPE_STATIC(PIMD, PIM_BSGRP_NODE, "PIM BSR advertised grp info")
-DEFINE_MTYPE_STATIC(PIMD, PIM_BSRP_NODE, "PIM BSR advertised RP info")
-DEFINE_MTYPE_STATIC(PIMD, PIM_BSM_INFO, "PIM BSM Info")
-DEFINE_MTYPE_STATIC(PIMD, PIM_BSM_PKT_VAR_MEM, "PIM BSM Packet")
+DEFINE_MTYPE_STATIC(PIMD, PIM_BSGRP_NODE, "PIM BSR advertised grp info");
+DEFINE_MTYPE_STATIC(PIMD, PIM_BSRP_NODE, "PIM BSR advertised RP info");
+DEFINE_MTYPE_STATIC(PIMD, PIM_BSM_INFO, "PIM BSM Info");
+DEFINE_MTYPE_STATIC(PIMD, PIM_BSM_PKT_VAR_MEM, "PIM BSM Packet");
/* All bsm packets forwarded shall be fit within ip mtu less iphdr(max) */
#define MAX_IP_HDR_LEN 24
.n_signals = 4 /* XXX array_size(pimd_signals) XXX*/,
.privs = &pimd_privs, .yang_modules = pimd_yang_modules,
- .n_yang_modules = array_size(pimd_yang_modules), )
+ .n_yang_modules = array_size(pimd_yang_modules),
+);
int main(int argc, char **argv, char **envp)
#include "pim_memory.h"
-DEFINE_MGROUP(PIMD, "pimd")
-DEFINE_MTYPE(PIMD, PIM_CHANNEL_OIL, "PIM SSM (S,G) channel OIL")
-DEFINE_MTYPE(PIMD, PIM_INTERFACE, "PIM interface")
-DEFINE_MTYPE(PIMD, PIM_IGMP_JOIN, "PIM interface IGMP static join")
-DEFINE_MTYPE(PIMD, PIM_IGMP_SOCKET, "PIM interface IGMP socket")
-DEFINE_MTYPE(PIMD, PIM_IGMP_GROUP, "PIM interface IGMP group")
-DEFINE_MTYPE(PIMD, PIM_IGMP_GROUP_SOURCE, "PIM interface IGMP source")
-DEFINE_MTYPE(PIMD, PIM_NEIGHBOR, "PIM interface neighbor")
-DEFINE_MTYPE(PIMD, PIM_IFCHANNEL, "PIM interface (S,G) state")
-DEFINE_MTYPE(PIMD, PIM_UPSTREAM, "PIM upstream (S,G) state")
-DEFINE_MTYPE(PIMD, PIM_SSMPINGD, "PIM sspimgd socket")
-DEFINE_MTYPE(PIMD, PIM_STATIC_ROUTE, "PIM Static Route")
-DEFINE_MTYPE(PIMD, PIM_BR, "PIM Bridge Router info")
-DEFINE_MTYPE(PIMD, PIM_RP, "PIM RP info")
-DEFINE_MTYPE(PIMD, PIM_FILTER_NAME, "PIM RP filter info")
-DEFINE_MTYPE(PIMD, PIM_MSDP_PEER, "PIM MSDP peer")
-DEFINE_MTYPE(PIMD, PIM_MSDP_MG_NAME, "PIM MSDP mesh-group name")
-DEFINE_MTYPE(PIMD, PIM_MSDP_SA, "PIM MSDP source-active cache")
-DEFINE_MTYPE(PIMD, PIM_MSDP_MG, "PIM MSDP mesh group")
-DEFINE_MTYPE(PIMD, PIM_MSDP_MG_MBR, "PIM MSDP mesh group mbr")
-DEFINE_MTYPE(PIMD, PIM_SEC_ADDR, "PIM secondary address")
-DEFINE_MTYPE(PIMD, PIM_JP_AGG_GROUP, "PIM JP AGG Group")
-DEFINE_MTYPE(PIMD, PIM_JP_AGG_SOURCE, "PIM JP AGG Source")
-DEFINE_MTYPE(PIMD, PIM_PIM_INSTANCE, "PIM global state")
-DEFINE_MTYPE(PIMD, PIM_NEXTHOP_CACHE, "PIM nexthop cache state")
-DEFINE_MTYPE(PIMD, PIM_SSM_INFO, "PIM SSM configuration")
-DEFINE_MTYPE(PIMD, PIM_PLIST_NAME, "PIM Prefix List Names")
-DEFINE_MTYPE(PIMD, PIM_VXLAN_SG, "PIM VxLAN mroute cache")
+DEFINE_MGROUP(PIMD, "pimd");
+DEFINE_MTYPE(PIMD, PIM_CHANNEL_OIL, "PIM SSM (S,G) channel OIL");
+DEFINE_MTYPE(PIMD, PIM_INTERFACE, "PIM interface");
+DEFINE_MTYPE(PIMD, PIM_IGMP_JOIN, "PIM interface IGMP static join");
+DEFINE_MTYPE(PIMD, PIM_IGMP_SOCKET, "PIM interface IGMP socket");
+DEFINE_MTYPE(PIMD, PIM_IGMP_GROUP, "PIM interface IGMP group");
+DEFINE_MTYPE(PIMD, PIM_IGMP_GROUP_SOURCE, "PIM interface IGMP source");
+DEFINE_MTYPE(PIMD, PIM_NEIGHBOR, "PIM interface neighbor");
+DEFINE_MTYPE(PIMD, PIM_IFCHANNEL, "PIM interface (S,G) state");
+DEFINE_MTYPE(PIMD, PIM_UPSTREAM, "PIM upstream (S,G) state");
+DEFINE_MTYPE(PIMD, PIM_SSMPINGD, "PIM sspimgd socket");
+DEFINE_MTYPE(PIMD, PIM_STATIC_ROUTE, "PIM Static Route");
+DEFINE_MTYPE(PIMD, PIM_BR, "PIM Bridge Router info");
+DEFINE_MTYPE(PIMD, PIM_RP, "PIM RP info");
+DEFINE_MTYPE(PIMD, PIM_FILTER_NAME, "PIM RP filter info");
+DEFINE_MTYPE(PIMD, PIM_MSDP_PEER, "PIM MSDP peer");
+DEFINE_MTYPE(PIMD, PIM_MSDP_MG_NAME, "PIM MSDP mesh-group name");
+DEFINE_MTYPE(PIMD, PIM_MSDP_SA, "PIM MSDP source-active cache");
+DEFINE_MTYPE(PIMD, PIM_MSDP_MG, "PIM MSDP mesh group");
+DEFINE_MTYPE(PIMD, PIM_MSDP_MG_MBR, "PIM MSDP mesh group mbr");
+DEFINE_MTYPE(PIMD, PIM_SEC_ADDR, "PIM secondary address");
+DEFINE_MTYPE(PIMD, PIM_JP_AGG_GROUP, "PIM JP AGG Group");
+DEFINE_MTYPE(PIMD, PIM_JP_AGG_SOURCE, "PIM JP AGG Source");
+DEFINE_MTYPE(PIMD, PIM_PIM_INSTANCE, "PIM global state");
+DEFINE_MTYPE(PIMD, PIM_NEXTHOP_CACHE, "PIM nexthop cache state");
+DEFINE_MTYPE(PIMD, PIM_SSM_INFO, "PIM SSM configuration");
+DEFINE_MTYPE(PIMD, PIM_PLIST_NAME, "PIM Prefix List Names");
+DEFINE_MTYPE(PIMD, PIM_VXLAN_SG, "PIM VxLAN mroute cache");
#include "memory.h"
-DECLARE_MGROUP(PIMD)
-DECLARE_MTYPE(PIM_CHANNEL_OIL)
-DECLARE_MTYPE(PIM_INTERFACE)
-DECLARE_MTYPE(PIM_IGMP_JOIN)
-DECLARE_MTYPE(PIM_IGMP_SOCKET)
-DECLARE_MTYPE(PIM_IGMP_GROUP)
-DECLARE_MTYPE(PIM_IGMP_GROUP_SOURCE)
-DECLARE_MTYPE(PIM_NEIGHBOR)
-DECLARE_MTYPE(PIM_IFCHANNEL)
-DECLARE_MTYPE(PIM_UPSTREAM)
-DECLARE_MTYPE(PIM_SSMPINGD)
-DECLARE_MTYPE(PIM_STATIC_ROUTE)
-DECLARE_MTYPE(PIM_BR)
-DECLARE_MTYPE(PIM_RP)
-DECLARE_MTYPE(PIM_FILTER_NAME)
-DECLARE_MTYPE(PIM_MSDP_PEER)
-DECLARE_MTYPE(PIM_MSDP_MG_NAME)
-DECLARE_MTYPE(PIM_MSDP_SA)
-DECLARE_MTYPE(PIM_MSDP_MG)
-DECLARE_MTYPE(PIM_MSDP_MG_MBR)
-DECLARE_MTYPE(PIM_SEC_ADDR)
-DECLARE_MTYPE(PIM_JP_AGG_GROUP)
-DECLARE_MTYPE(PIM_JP_AGG_SOURCE)
-DECLARE_MTYPE(PIM_PIM_INSTANCE)
-DECLARE_MTYPE(PIM_NEXTHOP_CACHE)
-DECLARE_MTYPE(PIM_SSM_INFO)
+DECLARE_MGROUP(PIMD);
+DECLARE_MTYPE(PIM_CHANNEL_OIL);
+DECLARE_MTYPE(PIM_INTERFACE);
+DECLARE_MTYPE(PIM_IGMP_JOIN);
+DECLARE_MTYPE(PIM_IGMP_SOCKET);
+DECLARE_MTYPE(PIM_IGMP_GROUP);
+DECLARE_MTYPE(PIM_IGMP_GROUP_SOURCE);
+DECLARE_MTYPE(PIM_NEIGHBOR);
+DECLARE_MTYPE(PIM_IFCHANNEL);
+DECLARE_MTYPE(PIM_UPSTREAM);
+DECLARE_MTYPE(PIM_SSMPINGD);
+DECLARE_MTYPE(PIM_STATIC_ROUTE);
+DECLARE_MTYPE(PIM_BR);
+DECLARE_MTYPE(PIM_RP);
+DECLARE_MTYPE(PIM_FILTER_NAME);
+DECLARE_MTYPE(PIM_MSDP_PEER);
+DECLARE_MTYPE(PIM_MSDP_MG_NAME);
+DECLARE_MTYPE(PIM_MSDP_SA);
+DECLARE_MTYPE(PIM_MSDP_MG);
+DECLARE_MTYPE(PIM_MSDP_MG_MBR);
+DECLARE_MTYPE(PIM_SEC_ADDR);
+DECLARE_MTYPE(PIM_JP_AGG_GROUP);
+DECLARE_MTYPE(PIM_JP_AGG_SOURCE);
+DECLARE_MTYPE(PIM_PIM_INSTANCE);
+DECLARE_MTYPE(PIM_NEXTHOP_CACHE);
+DECLARE_MTYPE(PIM_SSM_INFO);
DECLARE_MTYPE(PIM_PLIST_NAME);
-DECLARE_MTYPE(PIM_VXLAN_SG)
+DECLARE_MTYPE(PIM_VXLAN_SG);
#endif /* _QUAGGA_PIM_MEMORY_H */
#include "pim_msdp.h"
#include "pim_msdp_socket.h"
+#include "sockopt.h"
+
/* increase socket send buffer size */
static void pim_msdp_update_sock_send_buffer_size(int fd)
{
return rc;
}
+ /* Set socket DSCP byte */
+ if (setsockopt_ipv4_tos(sock, IPTOS_PREC_INTERNETCONTROL)) {
+ zlog_warn("can't set sockopt IP_TOS to MSDP socket %d: %s",
+ sock, safe_strerror(errno));
+ }
+
/* add accept thread */
listener->fd = sock;
memcpy(&listener->su, &sin, socklen);
return rc;
}
+ /* Set socket DSCP byte */
+ if (setsockopt_ipv4_tos(mp->fd, IPTOS_PREC_INTERNETCONTROL)) {
+ zlog_warn("can't set sockopt IP_TOS to MSDP socket %d: %s",
+ mp->fd, safe_strerror(errno));
+ }
+
/* Connect to the remote mp. */
return (sockunion_connect(mp->fd, &mp->su_peer,
htons(PIM_MSDP_TCP_PORT), 0));
installed: indicate if this entry is installed in the kernel.
*/
-PREDECL_RBTREE_UNIQ(rb_pim_oil)
+PREDECL_RBTREE_UNIQ(rb_pim_oil);
struct channel_oil {
struct pim_instance *pim;
extern int pim_channel_oil_compare(const struct channel_oil *c1,
const struct channel_oil *c2);
DECLARE_RBTREE_UNIQ(rb_pim_oil, struct channel_oil, oil_rb,
- pim_channel_oil_compare)
+ pim_channel_oil_compare);
extern struct list *pim_channel_oil_list;
int pim_upstream_compare(const struct pim_upstream *up1,
const struct pim_upstream *up2);
DECLARE_RBTREE_UNIQ(rb_pim_upstream, struct pim_upstream, upstream_rb,
- pim_upstream_compare)
+ pim_upstream_compare);
void pim_upstream_register_reevaluate(struct pim_instance *pim);
%endif
%if %{with_pathd}
%{_sbindir}/pathd
+ %{_libdir}/frr/modules/pathd_pcep.so
%endif
%{_libdir}/libfrr.so*
%{_libdir}/libfrrcares*
#include "ripd/rip_debug.h"
#include "ripd/rip_interface.h"
-DEFINE_MTYPE_STATIC(RIPD, RIP_INTERFACE, "RIP interface")
-DEFINE_MTYPE(RIPD, RIP_INTERFACE_STRING, "RIP Interface String")
-DEFINE_HOOK(rip_ifaddr_add, (struct connected * ifc), (ifc))
-DEFINE_HOOK(rip_ifaddr_del, (struct connected * ifc), (ifc))
+DEFINE_MTYPE_STATIC(RIPD, RIP_INTERFACE, "RIP interface");
+DEFINE_MTYPE(RIPD, RIP_INTERFACE_STRING, "RIP Interface String");
+DEFINE_HOOK(rip_ifaddr_add, (struct connected * ifc), (ifc));
+DEFINE_HOOK(rip_ifaddr_del, (struct connected * ifc), (ifc));
/* static prototypes */
static void rip_enable_apply(struct interface *);
#include "memory.h"
#include "zclient.h"
-DECLARE_MTYPE(RIP_INTERFACE_STRING)
+DECLARE_MTYPE(RIP_INTERFACE_STRING);
extern int rip_interface_down(int, struct zclient *, zebra_size_t, vrf_id_t);
extern int rip_interface_up(int, struct zclient *, zebra_size_t, vrf_id_t);
.signals = ripd_signals, .n_signals = array_size(ripd_signals),
.privs = &ripd_privs, .yang_modules = ripd_yang_modules,
- .n_yang_modules = array_size(ripd_yang_modules), )
+ .n_yang_modules = array_size(ripd_yang_modules),
+);
#define DEPRECATED_OPTIONS ""
#include "ripd/ripd.h"
-DEFINE_MTYPE_STATIC(RIPD, RIP_OFFSET_LIST, "RIP offset list")
+DEFINE_MTYPE_STATIC(RIPD, RIP_OFFSET_LIST, "RIP offset list");
#define OFFSET_LIST_IN_NAME(O) ((O)->direct[RIP_OFFSET_LIST_IN].alist_name)
#define OFFSET_LIST_IN_METRIC(O) ((O)->direct[RIP_OFFSET_LIST_IN].metric)
#include "ripd/ripd.h"
-DEFINE_MTYPE_STATIC(RIPD, RIP_PEER, "RIP peer")
+DEFINE_MTYPE_STATIC(RIPD, RIP_PEER, "RIP peer");
static struct rip_peer *rip_peer_new(void)
{
FRR_MODULE_SETUP(.name = "ripd_snmp", .version = FRR_VERSION,
.description = "ripd AgentX SNMP module",
- .init = rip_snmp_module_init, )
+ .init = rip_snmp_module_init,
+);
/* UDP receive buffer size */
#define RIP_UDP_RCV_BUF 41600
-DEFINE_MGROUP(RIPD, "ripd")
-DEFINE_MTYPE_STATIC(RIPD, RIP, "RIP structure")
-DEFINE_MTYPE_STATIC(RIPD, RIP_VRF_NAME, "RIP VRF name")
-DEFINE_MTYPE_STATIC(RIPD, RIP_INFO, "RIP route info")
-DEFINE_MTYPE_STATIC(RIPD, RIP_DISTANCE, "RIP distance")
+DEFINE_MGROUP(RIPD, "ripd");
+DEFINE_MTYPE_STATIC(RIPD, RIP, "RIP structure");
+DEFINE_MTYPE_STATIC(RIPD, RIP_VRF_NAME, "RIP VRF name");
+DEFINE_MTYPE_STATIC(RIPD, RIP_INFO, "RIP route info");
+DEFINE_MTYPE_STATIC(RIPD, RIP_DISTANCE, "RIP distance");
/* Prototypes. */
static void rip_output_process(struct connected *, struct sockaddr_in *, int,
#define RIP_INSTANCE "/frr-ripd:ripd/instance"
#define RIP_IFACE "/frr-interface:lib/interface/frr-ripd:rip"
-DECLARE_MGROUP(RIPD)
+DECLARE_MGROUP(RIPD);
/* RIP structure. */
struct rip {
/* Master thread strucutre. */
extern struct thread_master *master;
-DECLARE_HOOK(rip_ifaddr_add, (struct connected * ifc), (ifc))
-DECLARE_HOOK(rip_ifaddr_del, (struct connected * ifc), (ifc))
+DECLARE_HOOK(rip_ifaddr_add, (struct connected * ifc), (ifc));
+DECLARE_HOOK(rip_ifaddr_del, (struct connected * ifc), (ifc));
#endif /* _ZEBRA_RIP_H */
# end
ripd_ripd_snmp_la_SOURCES = ripd/rip_snmp.c
-ripd_ripd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu99
+ripd_ripd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu11
ripd_ripd_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
ripd_ripd_snmp_la_LIBADD = lib/libfrrsnmp.la
#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
#endif
-DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_IF, "ripng interface")
+DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_IF, "ripng interface");
/* Static utility function. */
static void ripng_enable_apply(struct interface *);
.privs = &ripngd_privs,
.yang_modules = ripngd_yang_modules,
- .n_yang_modules = array_size(ripngd_yang_modules), )
+ .n_yang_modules = array_size(ripngd_yang_modules),
+);
#define DEPRECATED_OPTIONS ""
#include "ripngd/ripng_debug.h"
#include "ripngd/ripng_nexthop.h"
-DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_RTE_DATA, "RIPng rte data")
+DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_RTE_DATA, "RIPng rte data");
#define DEBUG 1
#include "ripngd/ripngd.h"
-DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_OFFSET_LIST, "RIPng offset lst")
+DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_OFFSET_LIST, "RIPng offset lst");
#define OFFSET_LIST_IN_NAME(O) ((O)->direct[RIPNG_OFFSET_LIST_IN].alist_name)
#define OFFSET_LIST_IN_METRIC(O) ((O)->direct[RIPNG_OFFSET_LIST_IN].metric)
#include "ripngd/ripngd.h"
#include "ripngd/ripng_nexthop.h"
-DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_PEER, "RIPng peer")
+DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_PEER, "RIPng peer");
static struct ripng_peer *ripng_peer_new(void)
{
#include "ripngd/ripngd.h"
#include "ripngd/ripng_route.h"
-DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_AGGREGATE, "RIPng aggregate")
+DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_AGGREGATE, "RIPng aggregate");
static struct ripng_aggregate *ripng_aggregate_new(void)
{
#include "ripngd/ripng_debug.h"
#include "ripngd/ripng_nexthop.h"
-DEFINE_MGROUP(RIPNGD, "ripngd")
-DEFINE_MTYPE_STATIC(RIPNGD, RIPNG, "RIPng structure")
-DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_VRF_NAME, "RIPng VRF name")
-DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_ROUTE, "RIPng route info")
+DEFINE_MGROUP(RIPNGD, "ripngd");
+DEFINE_MTYPE_STATIC(RIPNGD, RIPNG, "RIPng structure");
+DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_VRF_NAME, "RIPng VRF name");
+DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_ROUTE, "RIPng route info");
enum { ripng_all_route,
ripng_changed_route,
#define RIPNG_INSTANCE "/frr-ripngd:ripngd/instance"
#define RIPNG_IFACE "/frr-interface:lib/interface/frr-ripngd:ripng"
-DECLARE_MGROUP(RIPNGD)
+DECLARE_MGROUP(RIPNGD);
/* RIPng structure. */
struct ripng {
#ifndef __SHARP_GLOBAL_H__
#define __SHARP_GLOBAL_H__
-DECLARE_MGROUP(SHARPD)
+DECLARE_MGROUP(SHARPD);
struct sharp_routes {
/* The original prefix for route installation */
#include "sharp_globals.h"
#include "sharp_nht.h"
-DEFINE_MGROUP(SHARPD, "sharpd")
+DEFINE_MGROUP(SHARPD, "sharpd");
zebra_capabilities_t _caps_p[] = {
};
.n_signals = array_size(sharp_signals),
.privs = &sharp_privs, .yang_modules = sharpd_yang_modules,
- .n_yang_modules = array_size(sharpd_yang_modules), )
+ .n_yang_modules = array_size(sharpd_yang_modules),
+);
struct sharp_global sg;
#include "sharp_globals.h"
#include "sharp_zebra.h"
-DEFINE_MTYPE_STATIC(SHARPD, NH_TRACKER, "Nexthop Tracker")
-DEFINE_MTYPE_STATIC(SHARPD, NHG, "Nexthop Group")
+DEFINE_MTYPE_STATIC(SHARPD, NH_TRACKER, "Nexthop Tracker");
+DEFINE_MTYPE_STATIC(SHARPD, NHG, "Nexthop Group");
struct sharp_nh_tracker *sharp_nh_tracker_get(struct prefix *p)
{
return 0;
}
- zlog_debug("Received update for %pFX", &nhr.prefix);
+ zlog_debug("Received update for %pFX metric: %u", &nhr.prefix,
+ nhr.metric);
nht = sharp_nh_tracker_get(&nhr.prefix);
nht->nhop_num = nhr.nexthop_num;
.privs = &static_privs, .yang_modules = staticd_yang_modules,
.n_yang_modules = array_size(staticd_yang_modules),
-)
+);
int main(int argc, char **argv, char **envp)
{
+++ /dev/null
-/*
- * static memory code.
- * Copyright (C) 2018 Cumulus Networks, Inc.
- * Donald Sharp
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-#include <zebra.h>
-
-#include <memory.h>
-
-#include "staticd/static_memory.h"
-
-DEFINE_MGROUP(STATIC, "staticd")
-
-DEFINE_MTYPE(STATIC, STATIC_NEXTHOP, "Static Nexthop");
+++ /dev/null
-/*
- * static memory code.
- * Copyright (C) 2018 Cumulus Networks, Inc.
- * Donald Sharp
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-#ifndef __STATIC_MEMORY_H__
-
-#include "memory.h"
-
-DECLARE_MGROUP(STATIC)
-
-DECLARE_MTYPE(STATIC_ROUTE);
-DECLARE_MTYPE(STATIC_NEXTHOP);
-DECLARE_MTYPE(STATIC_PATH);
-
-#endif
#include "static_vrf.h"
#include "static_routes.h"
-#include "static_memory.h"
#include "static_zebra.h"
#include "static_debug.h"
-DEFINE_MTYPE(STATIC, STATIC_ROUTE, "Static Route Info");
-DEFINE_MTYPE(STATIC, STATIC_PATH, "Static Path");
+DEFINE_MGROUP(STATIC, "staticd");
+
+DEFINE_MTYPE_STATIC(STATIC, STATIC_ROUTE, "Static Route Info");
+DEFINE_MTYPE_STATIC(STATIC, STATIC_PATH, "Static Path");
+DEFINE_MTYPE_STATIC(STATIC, STATIC_NEXTHOP, "Static Nexthop");
+
+void zebra_stable_node_cleanup(struct route_table *table,
+ struct route_node *node)
+{
+ struct static_nexthop *nh;
+ struct static_path *pn;
+ struct static_route_info *si;
+ struct route_table *src_table;
+ struct route_node *src_node;
+ struct static_path *src_pn;
+ struct static_route_info *src_si;
+
+ si = node->info;
+
+ if (si) {
+ frr_each_safe(static_path_list, &si->path_list, pn) {
+ frr_each_safe(static_nexthop_list, &pn->nexthop_list,
+ nh) {
+ static_nexthop_list_del(&pn->nexthop_list, nh);
+ XFREE(MTYPE_STATIC_NEXTHOP, nh);
+ }
+ static_path_list_del(&si->path_list, pn);
+ XFREE(MTYPE_STATIC_PATH, pn);
+ }
+
+ /* clean up for dst table */
+ src_table = srcdest_srcnode_table(node);
+ if (src_table) {
+ /* This means the route_node is part of the top
+ * hierarchy and refers to a destination prefix.
+ */
+ for (src_node = route_top(src_table); src_node;
+ src_node = route_next(src_node)) {
+ src_si = src_node->info;
+
+ frr_each_safe(static_path_list,
+ &src_si->path_list, src_pn) {
+ frr_each_safe(static_nexthop_list,
+ &src_pn->nexthop_list,
+ nh) {
+ static_nexthop_list_del(
+ &src_pn->nexthop_list,
+ nh);
+ XFREE(MTYPE_STATIC_NEXTHOP, nh);
+ }
+ static_path_list_del(&src_si->path_list,
+ src_pn);
+ XFREE(MTYPE_STATIC_PATH, src_pn);
+ }
+
+ XFREE(MTYPE_STATIC_ROUTE, src_node->info);
+ }
+ }
+
+ XFREE(MTYPE_STATIC_ROUTE, node->info);
+ }
+}
/* Install static path into rib. */
void static_install_path(struct route_node *rn, struct static_path *pn,
#include "lib/mpls.h"
#include "table.h"
+#include "memory.h"
+
+DECLARE_MGROUP(STATIC);
/* Static route label information */
struct static_nh_label {
extern struct stable_info *static_get_stable_info(struct route_node *rn);
extern void static_route_info_init(struct static_route_info *si);
+extern void zebra_stable_node_cleanup(struct route_table *table,
+ struct route_node *node);
+
/*
* Max string return via API static_get_nh_str in size_t
*/
#include "table.h"
#include "srcdest_table.h"
-#include "static_memory.h"
#include "static_vrf.h"
#include "static_routes.h"
#include "static_zebra.h"
DEFINE_MTYPE_STATIC(STATIC, STATIC_RTABLE_INFO, "Static Route Table Info");
-static void zebra_stable_node_cleanup(struct route_table *table,
- struct route_node *node)
-{
- struct static_nexthop *nh;
- struct static_path *pn;
- struct static_route_info *si;
- struct route_table *src_table;
- struct route_node *src_node;
- struct static_path *src_pn;
- struct static_route_info *src_si;
-
- si = node->info;
-
- if (si) {
- frr_each_safe(static_path_list, &si->path_list, pn) {
- frr_each_safe(static_nexthop_list, &pn->nexthop_list,
- nh) {
- static_nexthop_list_del(&pn->nexthop_list, nh);
- XFREE(MTYPE_STATIC_NEXTHOP, nh);
- }
- static_path_list_del(&si->path_list, pn);
- XFREE(MTYPE_STATIC_PATH, pn);
- }
-
- /* clean up for dst table */
- src_table = srcdest_srcnode_table(node);
- if (src_table) {
- /* This means the route_node is part of the top
- * hierarchy and refers to a destination prefix.
- */
- for (src_node = route_top(src_table); src_node;
- src_node = route_next(src_node)) {
- src_si = src_node->info;
-
- frr_each_safe(static_path_list,
- &src_si->path_list, src_pn) {
- frr_each_safe(static_nexthop_list,
- &src_pn->nexthop_list,
- nh) {
- static_nexthop_list_del(
- &src_pn->nexthop_list,
- nh);
- XFREE(MTYPE_STATIC_NEXTHOP, nh);
- }
- static_path_list_del(&src_si->path_list,
- src_pn);
- XFREE(MTYPE_STATIC_PATH, src_pn);
- }
-
- XFREE(MTYPE_STATIC_ROUTE, src_node->info);
- }
- }
-
- XFREE(MTYPE_STATIC_ROUTE, node->info);
- }
-}
-
static struct static_vrf *static_vrf_alloc(void)
{
struct route_table *table;
#include "northbound_cli.h"
#include "static_vrf.h"
-#include "static_memory.h"
#include "static_vty.h"
#include "static_routes.h"
#include "static_debug.h"
staticd_libstatic_a_SOURCES = \
staticd/static_debug.c \
- staticd/static_memory.c \
staticd/static_nht.c \
staticd/static_routes.c \
staticd/static_zebra.c \
noinst_HEADERS += \
staticd/static_debug.h \
- staticd/static_memory.h \
staticd/static_nht.h \
staticd/static_zebra.h \
staticd/static_routes.h \
#include "lib/zassert.h"
#include "lib/zclient.h"
-PREDECL_RBTREE_UNIQ(footree)
+PREDECL_RBTREE_UNIQ(footree);
struct foo {
int dummy;
struct footree_item item;
{
return memcmp(&a->dummy, &b->dummy, sizeof(a->dummy));
}
-DECLARE_RBTREE_UNIQ(footree, struct foo, item, foocmp)
+DECLARE_RBTREE_UNIQ(footree, struct foo, item, foocmp);
int main(int argc, char **argv)
{
static struct seqlock sqlo;
-PREDECL_ATOMLIST(alist)
-PREDECL_ATOMSORT_UNIQ(asort)
+PREDECL_ATOMLIST(alist);
+PREDECL_ATOMSORT_UNIQ(asort);
struct item {
uint64_t val1;
struct alist_item chain;
struct asort_item sortc;
uint64_t val2;
};
-DECLARE_ATOMLIST(alist, struct item, chain)
+DECLARE_ATOMLIST(alist, struct item, chain);
static int icmp(const struct item *a, const struct item *b);
-DECLARE_ATOMSORT_UNIQ(asort, struct item, sortc, icmp)
+DECLARE_ATOMSORT_UNIQ(asort, struct item, sortc, icmp);
static int icmp(const struct item *a, const struct item *b)
{
#include "tests.h"
-DEFINE_MGROUP(TEST_HEAVYWQ, "heavy-wq test")
-DEFINE_MTYPE_STATIC(TEST_HEAVYWQ, WQ_NODE, "heavy_wq_node")
-DEFINE_MTYPE_STATIC(TEST_HEAVYWQ, WQ_NODE_STR, "heavy_wq_node->str")
+DEFINE_MGROUP(TEST_HEAVYWQ, "heavy-wq test");
+DEFINE_MTYPE_STATIC(TEST_HEAVYWQ, WQ_NODE, "heavy_wq_node");
+DEFINE_MTYPE_STATIC(TEST_HEAVYWQ, WQ_NODE_STR, "heavy_wq_node->str");
extern struct thread_master *master;
static struct work_queue *heavy_wq;
#include <zebra.h>
#include <memory.h>
-DEFINE_MGROUP(TEST_MEMORY, "memory test")
-DEFINE_MTYPE_STATIC(TEST_MEMORY, TEST, "generic test mtype")
+DEFINE_MGROUP(TEST_MEMORY, "memory test");
+DEFINE_MTYPE_STATIC(TEST_MEMORY, TEST, "generic test mtype");
/* Memory torture tests
*
#define REALTYPE TYPE
#endif
-PREDECL(REALTYPE, list)
+PREDECL(REALTYPE, list);
struct item {
uint64_t val;
struct list_item itm;
#if IS_HASH(REALTYPE)
static uint32_t list_hash(const struct item *a);
-DECLARE(REALTYPE, list, struct item, itm, list_cmp, list_hash)
+DECLARE(REALTYPE, list, struct item, itm, list_cmp, list_hash);
static uint32_t list_hash(const struct item *a)
{
}
#else
-DECLARE(REALTYPE, list, struct item, itm, list_cmp)
+DECLARE(REALTYPE, list, struct item, itm, list_cmp);
#endif
static int list_cmp(const struct item *a, const struct item *b)
}
#else /* !IS_SORTED */
-DECLARE(REALTYPE, list, struct item, itm)
+DECLARE(REALTYPE, list, struct item, itm);
#endif
#define NITEM 10000
test_logcall,
};
-XREF_SETUP()
+XREF_SETUP();
int main(int argc, char **argv)
{
#include "sigevent.h"
#include "frr_zmq.h"
-DEFINE_MTYPE_STATIC(LIB, TESTBUF, "zmq test buffer")
-DEFINE_MTYPE_STATIC(LIB, ZMQMSG, "zmq message")
+DEFINE_MTYPE_STATIC(LIB, TESTBUF, "zmq test buffer");
+DEFINE_MTYPE_STATIC(LIB, ZMQMSG, "zmq message");
static struct thread_master *master;
#include "common.h"
DECLARE_RBTREE_UNIQ(p_spaces, struct p_space, p_spaces_item,
- p_spaces_compare_func)
+ p_spaces_compare_func);
DECLARE_RBTREE_UNIQ(q_spaces, struct q_space, q_spaces_item,
- q_spaces_compare_func)
+ q_spaces_compare_func);
static struct ospf *test_init(struct ospf_test_node *root)
{
libreadline-dev \
libc-ares-dev \
libcap-dev \
+ libelf-dev \
man \
mininet \
pkg-config \
"remote-diagnostic":"ok",
"receive-interval":300,
"transmit-interval":300,
- "echo-interval":0,
+ "echo-receive-interval":50,
+ "echo-transmit-interval":0,
"remote-receive-interval":300,
"remote-transmit-interval":300,
- "remote-echo-interval":50
+ "remote-echo-receive-interval":50
}
]
"status":"up",
"receive-interval":300,
"transmit-interval":300,
- "echo-interval":0,
+ "echo-receive-interval":50,
+ "echo-transmit-interval":0,
"remote-receive-interval":300,
"remote-transmit-interval":300,
- "remote-echo-interval":50
+ "remote-echo-receive-interval":50
}
]
"remote-diagnostic":"ok",
"receive-interval":300,
"transmit-interval":300,
- "echo-interval":0,
+ "echo-receive-interval":50,
+ "echo-transmit-interval":0,
"remote-receive-interval":300,
"remote-transmit-interval":300,
- "remote-echo-interval":50
+ "remote-echo-receive-interval":50
}
]
"status":"down",
"receive-interval":300,
"transmit-interval":300,
- "echo-interval":0,
+ "echo-receive-interval":50,
+ "echo-transmit-interval":0,
"remote-receive-interval":300,
"remote-transmit-interval":300,
- "remote-echo-interval":50
+ "remote-echo-receive-interval":50
}
]
"interface": "r1-eth1",
"multihop": false,
"peer": "172.16.100.2",
- "receive-interval": 300,
+ "receive-interval": 800,
"remote-detect-multiplier": 3,
"remote-diagnostic": "ok",
"remote-id": "*",
"remote-receive-interval": 300,
"remote-transmit-interval": 300,
"status": "up",
- "transmit-interval": 300,
+ "transmit-interval": 800,
"uptime": "*",
"vrf": "default"
},
profile slowtx
receive-interval 800
transmit-interval 800
+ echo receive-interval 400
!
peer 172.16.0.1 interface r1-eth0
profile slowtx
ip ospf area 0
ip ospf hello-interval 2
ip ospf dead-interval 10
- ip ospf bfd
+ ip ospf bfd profile slowtx
!
router ospf
ospf router-id 10.254.254.1
"remote-id": "*",
"remote-receive-interval": 800,
"remote-transmit-interval": 800,
+ "remote-echo-receive-interval": 400,
"status": "up",
"transmit-interval": 800,
"uptime": "*",
"receive-interval": 250,
"remote-detect-multiplier": 3,
"remote-diagnostic": "ok",
- "remote-echo-interval": 50,
+ "remote-echo-receive-interval": 50,
"remote-id": "*",
"remote-receive-interval": 300,
"remote-transmit-interval": 300,
profile fasttx
receive-interval 250
transmit-interval 250
+ echo receive-interval disabled
!
peer 172.16.0.2 interface r2-eth0
profile slowtx
"remote-id": "*",
"remote-receive-interval": 250,
"remote-transmit-interval": 250,
+ "remote-echo-receive-interval": 0,
"status": "up",
"transmit-interval": 300,
"uptime": "*",
"receive-interval": 300,
"remote-detect-multiplier": 3,
"remote-diagnostic": "ok",
- "remote-echo-interval": 50,
+ "remote-echo-receive-interval": 50,
"remote-id": "*",
"remote-receive-interval": 300,
"remote-transmit-interval": 300,
"remote-detect-multiplier": 3,
"remote-diagnostic": "ok",
"remote-id": "*",
- "remote-receive-interval": 300,
- "remote-transmit-interval": 300,
+ "remote-receive-interval": 800,
+ "remote-transmit-interval": 800,
"status": "up",
"transmit-interval": 300,
"uptime": "*",
"status": "up"
},
{
- "remote-echo-interval": 100,
+ "remote-echo-receive-interval": 100,
"peer": "192.168.1.1",
"status": "up"
},
"remote-diagnostic":"ok",
"receive-interval":300,
"transmit-interval":300,
- "echo-interval":0,
+ "echo-receive-interval":50,
+ "echo-transmit-interval":0,
"remote-receive-interval":300,
"remote-transmit-interval":300,
- "remote-echo-interval":50
+ "remote-echo-receive-interval":50
},
{
"multihop":false,
"remote-diagnostic":"ok",
"receive-interval":300,
"transmit-interval":300,
- "echo-interval":0,
+ "echo-receive-interval":50,
+ "echo-transmit-interval":0,
"remote-receive-interval":300,
"remote-transmit-interval":300,
- "remote-echo-interval":50
+ "remote-echo-receive-interval":50
}
]
"status": "up",
"transmit-interval": 300,
"remote-receive-interval": 300,
- "echo-interval": 0,
+ "echo-receive-interval": 50,
+ "echo-transmit-interval": 0,
"diagnostic": "ok",
"multihop": false,
"interface": "r2-eth0",
"remote-transmit-interval": 300,
"receive-interval": 300,
- "remote-echo-interval": 50,
+ "remote-echo-receive-interval": 50,
"remote-diagnostic": "ok"
},
{
"status": "up",
"transmit-interval": 300,
"remote-receive-interval": 300,
- "echo-interval": 0,
+ "echo-receive-interval": 50,
+ "echo-transmit-interval": 0,
"diagnostic": "ok",
"multihop": false,
"interface": "r2-eth2",
"remote-transmit-interval": 300,
"receive-interval": 300,
- "remote-echo-interval": 50,
+ "remote-echo-receive-interval": 50,
"remote-diagnostic": "ok"
},
{
"status": "up",
"transmit-interval": 300,
"remote-receive-interval": 300,
- "echo-interval": 0,
+ "echo-receive-interval": 50,
+ "echo-transmit-interval": 0,
"diagnostic": "ok",
"multihop": false,
"interface": "r2-eth1",
"remote-transmit-interval": 300,
"receive-interval": 300,
- "remote-echo-interval": 50,
+ "remote-echo-receive-interval": 50,
"remote-diagnostic": "ok",
"peer": "10.0.3.1"
}
"status": "up",
"transmit-interval": 300,
"remote-receive-interval": 300,
- "echo-interval": 0,
+ "echo-receive-interval": 50,
+ "echo-transmit-interval": 0,
"diagnostic": "ok",
"multihop": false,
"interface": "r3-eth0",
"remote-transmit-interval": 300,
"receive-interval": 300,
- "remote-echo-interval": 50,
+ "remote-echo-receive-interval": 50,
"remote-diagnostic": "ok",
"peer": "10.0.3.2"
}
"remote-diagnostic":"ok",
"receive-interval":300,
"transmit-interval":300,
- "echo-interval":0,
+ "echo-receive-interval": 50,
+ "echo-transmit-interval":0,
"remote-receive-interval":300,
"remote-transmit-interval":300,
- "remote-echo-interval":50
+ "remote-echo-receive-interval":50
},
{
"multihop":false,
"remote-diagnostic":"ok",
"receive-interval":300,
"transmit-interval":300,
- "echo-interval":0,
+ "echo-receive-interval": 50,
+ "echo-transmit-interval":0,
"remote-receive-interval":300,
"remote-transmit-interval":300,
- "remote-echo-interval":50
+ "remote-echo-receive-interval":50
}
]
{
"detect-multiplier": 3,
"diagnostic": "ok",
- "echo-interval": 0,
+ "echo-receive-interval": 50,
+ "echo-transmit-interval": 0,
"id": "*",
"local": "2001:db8:1::1",
"minimum-ttl": 253,
"receive-interval": 2000,
"remote-detect-multiplier": 3,
"remote-diagnostic": "ok",
- "remote-echo-interval": 50,
+ "remote-echo-receive-interval": 50,
"remote-id": "*",
"remote-receive-interval": 2000,
"remote-transmit-interval": 2000,
{
"detect-multiplier": 3,
"diagnostic": "ok",
- "echo-interval": 0,
+ "echo-receive-interval": 50,
+ "echo-transmit-interval": 0,
"id": "*",
"interface": "r1-eth0",
"local": "2001:db8:1::1",
"receive-interval": 600,
"remote-detect-multiplier": 3,
"remote-diagnostic": "ok",
- "remote-echo-interval": 50,
+ "remote-echo-receive-interval": 50,
"remote-id": "*",
"remote-receive-interval": 600,
"remote-transmit-interval": 600,
{
"detect-multiplier": 3,
"diagnostic": "ok",
- "echo-interval": 0,
+ "echo-receive-interval": 50,
+ "echo-transmit-interval": 0,
"id": "*",
"local": "192.168.1.1",
"minimum-ttl": 254,
"receive-interval": 2000,
"remote-detect-multiplier": 3,
"remote-diagnostic": "ok",
- "remote-echo-interval": 50,
+ "remote-echo-receive-interval": 50,
"remote-id": "*",
"remote-receive-interval": 2000,
"remote-transmit-interval": 2000,
{
"detect-multiplier": 3,
"diagnostic": "ok",
- "echo-interval": 0,
+ "echo-receive-interval": 50,
+ "echo-transmit-interval": 0,
"id": "*",
"interface": "r2-eth0",
"local": "2001:db8:1::2",
"receive-interval": 600,
"remote-detect-multiplier": 3,
"remote-diagnostic": "ok",
- "remote-echo-interval": 50,
+ "remote-echo-receive-interval": 50,
"remote-id": "*",
"remote-receive-interval": 600,
"remote-transmit-interval": 600,
{
"detect-multiplier": 3,
"diagnostic": "ok",
- "echo-interval": 0,
+ "echo-receive-interval": 50,
+ "echo-transmit-interval": 0,
"id": "*",
"interface": "r2-eth1",
"local": "2001:db8:2::2",
"receive-interval": 2000,
"remote-detect-multiplier": 3,
"remote-diagnostic": "ok",
- "remote-echo-interval": 50,
+ "remote-echo-receive-interval": 50,
"remote-id": "*",
"remote-receive-interval": 2000,
"remote-transmit-interval": 2000,
{
"detect-multiplier": 3,
"diagnostic": "ok",
- "echo-interval": 0,
+ "echo-receive-interval": 50,
+ "echo-transmit-interval": 0,
"id": "*",
"interface": "r3-eth1",
"local": "2001:db8:3::2",
"receive-interval": 2000,
"remote-detect-multiplier": 3,
"remote-diagnostic": "ok",
- "remote-echo-interval": 50,
+ "remote-echo-receive-interval": 50,
"remote-id": "*",
"remote-receive-interval": 2000,
"remote-transmit-interval": 2000,
{
"detect-multiplier": 3,
"diagnostic": "ok",
- "echo-interval": 0,
+ "echo-receive-interval": 50,
+ "echo-transmit-interval": 0,
"id": "*",
"interface": "r3-eth0",
"local": "2001:db8:2::1",
"receive-interval": 2000,
"remote-detect-multiplier": 3,
"remote-diagnostic": "ok",
- "remote-echo-interval": 50,
+ "remote-echo-receive-interval": 50,
"remote-id": "*",
"remote-receive-interval": 2000,
"remote-transmit-interval": 2000,
{
"detect-multiplier": 3,
"diagnostic": "ok",
- "echo-interval": 0,
+ "echo-receive-interval": 50,
+ "echo-transmit-interval": 0,
"id": "*",
"local": "192.168.2.1",
"minimum-ttl": 254,
"receive-interval": 2000,
"remote-detect-multiplier": 3,
"remote-diagnostic": "ok",
- "remote-echo-interval": 50,
+ "remote-echo-receive-interval": 50,
"remote-id": "*",
"remote-receive-interval": 2000,
"remote-transmit-interval": 2000,
{
"detect-multiplier": 3,
"diagnostic": "ok",
- "echo-interval": 0,
+ "echo-receive-interval": 50,
+ "echo-transmit-interval": 0,
"id": "*",
"local": "2001:db8:3::1",
"minimum-ttl": 253,
"receive-interval": 2000,
"remote-detect-multiplier": 3,
"remote-diagnostic": "ok",
- "remote-echo-interval": 50,
+ "remote-echo-receive-interval": 50,
"remote-id": "*",
"remote-receive-interval": 2000,
"remote-transmit-interval": 2000,
{
"detect-multiplier": 3,
"diagnostic": "ok",
- "echo-interval": 0,
+ "echo-receive-interval": 50,
+ "echo-transmit-interval": 0,
"id": "*",
"interface": "r4-eth0",
"local": "2001:db8:3::1",
"receive-interval": 2000,
"remote-detect-multiplier": 3,
"remote-diagnostic": "ok",
- "remote-echo-interval": 50,
+ "remote-echo-receive-interval": 50,
"remote-id": "*",
"remote-receive-interval": 2000,
"remote-transmit-interval": 2000,
"status": "up"
},
{
- "remote-echo-interval": 100,
+ "remote-echo-receive-interval": 100,
"peer": "192.168.1.1",
"status": "up"
},
--- /dev/null
+!
+router bgp 65001
+!
--- /dev/null
+!
+interface r1-eth0
+ ip address 192.168.255.1/24
+!
+ip forwarding
+!
+
--- /dev/null
+!
+router bgp 65001
+ no bgp default ipv4-unicast
+ bgp default ipv6-unicast
+!
--- /dev/null
+!
+interface r2-eth0
+ ip address 192.168.255.2/24
+!
+ip forwarding
+!
--- /dev/null
+!
+router bgp 65001
+ bgp default ipv6-unicast
+!
--- /dev/null
+!
+interface r3-eth0
+ ip address 192.168.255.3/24
+!
+ip forwarding
+!
--- /dev/null
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2021 by
+# Donatas Abraitis <donatas.abraitis@gmail.com>
+#
+# Permission to use, copy, modify, and/or 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 NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF 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.
+#
+
+"""
+Test if `bgp default ipv4-unicast` and `bgp default ipv6-unicast`
+commands work as expected.
+
+STEP 1: 'Check if neighbor 192.168.255.254 is enabled for ipv4 address-family only'
+STEP 2: 'Check if neighbor 192.168.255.254 is enabled for ipv6 address-family only'
+STEP 3: 'Check if neighbor 192.168.255.254 is enabled for ipv4 and ipv6 address-families'
+"""
+
+import os
+import sys
+import json
+import pytest
+import functools
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+from mininet.topo import Topo
+from lib.common_config import step
+
+
+class TemplateTopo(Topo):
+ def build(self, *_args, **_opts):
+ tgen = get_topogen(self)
+
+ for routern in range(1, 5):
+ tgen.add_router("r{}".format(routern))
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r2"])
+ switch.add_link(tgen.gears["r3"])
+ switch.add_link(tgen.gears["r4"])
+
+
+def setup_module(mod):
+ tgen = Topogen(TemplateTopo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ for i, (rname, router) in enumerate(router_list.items(), 1):
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
+ )
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_bgp_default_ipv4_ipv6_unicast():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ step("Check if neighbor 192.168.255.254 is enabled for ipv4 address-family only")
+
+ def _bgp_neighbor_ipv4_af_only():
+ tgen.gears["r1"].vtysh_cmd(
+ "conf t\nrouter bgp\nneighbor 192.168.255.254 remote-as external"
+ )
+
+ output = json.loads(tgen.gears["r1"].vtysh_cmd("show bgp summary json"))
+
+ if "ipv4Unicast" in output and "ipv6Unicast" not in output:
+ return True
+ return False
+
+ assert _bgp_neighbor_ipv4_af_only() == True
+
+ step("Check if neighbor 192.168.255.254 is enabled for ipv6 address-family only")
+
+ def _bgp_neighbor_ipv6_af_only():
+ tgen.gears["r2"].vtysh_cmd(
+ "conf t\nrouter bgp\nneighbor 192.168.255.254 remote-as external"
+ )
+
+ output = json.loads(tgen.gears["r2"].vtysh_cmd("show bgp summary json"))
+
+ if "ipv4Unicast" not in output and "ipv6Unicast" in output:
+ return True
+ return False
+
+ assert _bgp_neighbor_ipv6_af_only() == True
+
+ step(
+ "Check if neighbor 192.168.255.254 is enabled for ipv4 and ipv6 address-families"
+ )
+
+ def _bgp_neighbor_ipv4_and_ipv6_af():
+ tgen.gears["r3"].vtysh_cmd(
+ "conf t\nrouter bgp\nneighbor 192.168.255.254 remote-as external"
+ )
+
+ output = json.loads(tgen.gears["r3"].vtysh_cmd("show bgp summary json"))
+
+ if "ipv4Unicast" in output and "ipv6Unicast" in output:
+ return True
+ return False
+
+ assert _bgp_neighbor_ipv4_and_ipv6_af() == True
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
associated_int = r1_snmp.get(
"mplsL3VpnVrfAssociatedInterfaces.{}".format(snmp_str_to_oid("VRF-a"))
)
- assertmsg = (
- "mplsL3VpnVrfAssociatedInterfaces incorrect should be 3 value {}".format(
- associated_int
- )
+ assertmsg = "mplsL3VpnVrfAssociatedInterfaces incorrect should be 3 value {}".format(
+ associated_int
)
assert associated_int == "3", assertmsg
"C0 A8 C8 0A",
'""',
],
- "mplsL3VpnVrfRteInetCidrIfIndex": ["5", "6", "4", "5", "0", "6", "0"],
"mplsL3VpnVrfRteInetCidrType": [
"local(3)",
"local(3)",
)
if passed:
break
+ # generate ifindex row grabbing ifindices from vtysh
+ if passed:
+ ifindex_row = [
+ router_interface_get_ifindex(r1r, "eth3"),
+ router_interface_get_ifindex(r1r, "eth4"),
+ router_interface_get_ifindex(r1r, "eth2"),
+ router_interface_get_ifindex(r1r, "eth3"),
+ "0",
+ router_interface_get_ifindex(r1r, "eth4"),
+ "0",
+ ]
+ if not r1_snmp.test_oid_walk(
+ "mplsL3VpnVrfRteInetCidrIfIndex", ifindex_row, oid_list
+ ):
+ passed = False
+
print("passed {}".format(passed))
- # assert passed, assertmsg
+ assert passed, assertmsg
def test_memory_leak():
# Import topogen and topotest helpers
from lib.topogen import Topogen, get_topogen
from mininet.topo import Topo
-
+from lib.topotest import iproute2_is_vrf_capable
from lib.common_config import (
step,
verify_rib,
if result is not True:
pytest.skip("Kernel requirements are not met")
+ # iproute2 needs to support VRFs for this suite to run.
+ if not iproute2_is_vrf_capable():
+ pytest.skip("Installed iproute2 version does not support VRFs")
+
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: {}".format(testsuite_run_time))
logger.info("=" * 40)
# Import topogen and topotest helpers
from lib.topogen import Topogen, get_topogen
from mininet.topo import Topo
-
+from lib.topotest import iproute2_is_vrf_capable
from lib.common_config import (
step,
verify_rib,
if result is not True:
pytest.skip("Kernel requirements are not met")
+ # iproute2 needs to support VRFs for this suite to run.
+ if not iproute2_is_vrf_capable():
+ pytest.skip("Installed iproute2 version does not support VRFs")
+
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: {}".format(testsuite_run_time))
logger.info("=" * 40)
echo "frr-topotests only works if you have your tree in git." >&2
exit 1
fi
+ git -C "$TOPOTEST_FRR" ls-files -z > "${TOPOTEST_LOGS}/git-ls-files"
fi
if [ -z "$TOPOTEST_BUILDCACHE" ]; then
if [ "${TOPOTEST_CLEAN}" != "0" ]; then
log_info "Cleaning FRR builddir..."
- rm -rf $FRR_SYNC_DIR $FRR_BUILD_DIR &> /dev/null
+ rm -rf $FRR_BUILD_DIR &> /dev/null
fi
log_info "Syncing FRR source with host..."
-mkdir -p $FRR_SYNC_DIR
+mkdir -p $FRR_BUILD_DIR
rsync -a --info=progress2 \
- --exclude '*.o' \
- --exclude '*.lo'\
+ --from0 --files-from=/tmp/git-ls-files \
--chown root:root \
- $FRR_HOST_DIR/. $FRR_SYNC_DIR/
-(cd $FRR_SYNC_DIR && git clean -xdf > /dev/null)
-mkdir -p $FRR_BUILD_DIR
-rsync -a --info=progress2 --chown root:root $FRR_SYNC_DIR/. $FRR_BUILD_DIR/
+ $FRR_HOST_DIR/. $FRR_BUILD_DIR/
cd "$FRR_BUILD_DIR" || \
log_fatal "failed to find frr directory"
# SOFTWARE.
FRR_HOST_DIR=/root/host-frr
-FRR_SYNC_DIR=/root/persist/frr-sync
FRR_BUILD_DIR=/root/persist/frr-build
if [ ! -L "/root/frr" ]; then
from lib import topotest
from lib.topogen import Topogen, TopoRouter, get_topogen
from lib.topolog import logger
+from lib.topotest import iproute2_is_vrf_capable
+from lib.common_config import required_linux_kernel_version
from mininet.topo import Topo
def test_isis_linux_route_installation():
-
- dist = platform.dist()
-
- if dist[1] == "16.04":
- pytest.skip("Kernel not supported for vrf")
-
"Check whether all expected routes are present and installed in the OS"
tgen = get_topogen()
# Don't run this test if we have any failure.
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
+ # Required linux kernel version for this suite to run.
+ result = required_linux_kernel_version("4.15")
+ if result is not True:
+ pytest.skip("Kernel requirements are not met")
+
+ # iproute2 needs to support VRFs for this suite to run.
+ if not iproute2_is_vrf_capable():
+ pytest.skip("Installed iproute2 version does not support VRFs")
+
logger.info("Checking routers for installed ISIS vrf routes in OS")
# Check for routes in `ip route show vrf {}-cust1`
for rname, router in tgen.routers().items():
def test_isis_linux_route6_installation():
-
- dist = platform.dist()
-
- if dist[1] == "16.04":
- pytest.skip("Kernel not supported for vrf")
-
"Check whether all expected routes are present and installed in the OS"
tgen = get_topogen()
# Don't run this test if we have any failure.
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
+ # Required linux kernel version for this suite to run.
+ result = required_linux_kernel_version("4.15")
+ if result is not True:
+ pytest.skip("Kernel requirements are not met")
+
+ # iproute2 needs to support VRFs for this suite to run.
+ if not iproute2_is_vrf_capable():
+ pytest.skip("Installed iproute2 version does not support VRFs")
+
logger.info("Checking routers for installed ISIS vrf IPv6 routes in OS")
# Check for routes in `ip -6 route show vrf {}-cust1`
for rname, router in tgen.routers().items():
'mplsLdpEntityRowStatus', ['createAndGo(4)'])
+def test_r1_ldp_entity_stats_table():
+ "Test mplsLdpEntityStatsTable"
+ tgen = get_topogen()
+
+ r1 = tgen.net.get("r1")
+ r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c")
+
+ assert r1_snmp.test_oid_walk(
+ 'mplsLdpEntityStatsSessionAttempts', ['0'])
+ assert r1_snmp.test_oid_walk(
+ 'mplsLdpEntityStatsSessionRejectedNoHelloErrors', ['0'])
+ assert r1_snmp.test_oid_walk(
+ 'mplsLdpEntityStatsSessionRejectedAdErrors', ['0'])
+ assert r1_snmp.test_oid_walk(
+ 'mplsLdpEntityStatsSessionRejectedMaxPduErrors', ['0'])
+ assert r1_snmp.test_oid_walk(
+ 'mplsLdpEntityStatsSessionRejectedLRErrors', ['0'])
+ assert r1_snmp.test_oid_walk(
+ 'mplsLdpEntityStatsBadLdpIdentifierErrors', ['0'])
+ assert r1_snmp.test_oid_walk(
+ 'mplsLdpEntityStatsBadPduLengthErrors', ['0'])
+ assert r1_snmp.test_oid_walk(
+ 'mplsLdpEntityStatsBadMessageLengthErrors', ['0'])
+ assert r1_snmp.test_oid_walk(
+ 'mplsLdpEntityStatsBadTlvLengthErrors', ['0'])
+ assert r1_snmp.test_oid_walk(
+ 'mplsLdpEntityStatsMalformedTlvValueErrors', ['0'])
+ assert r1_snmp.test_oid_walk(
+ 'mplsLdpEntityStatsKeepAliveTimerExpErrors', ['0'])
+ assert r1_snmp.test_oid_walk(
+ 'mplsLdpEntityStatsShutdownReceivedNotifications', ['0'])
+ assert r1_snmp.test_oid_walk(
+ 'mplsLdpEntityStatsShutdownSentNotifications', ['0'])
+
+
def test_r1_ldp_peer_table():
"Test mplsLdpPeerTable"
tgen = get_topogen()
['(0) 0:00:00.00', '(0) 0:00:00.00'])
+def test_r1_ldp_session_stats_table():
+ "Test mplsLdpSessionStatsTable"
+ tgen = get_topogen()
+
+ r1 = tgen.net.get("r1")
+ r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c")
+
+ assert r1_snmp.test_oid_walk(
+ 'mplsLdpSessionStatsUnknownMesTypeErrors', ['0', '0'])
+ assert r1_snmp.test_oid_walk(
+ 'mplsLdpSessionStatsUnknownTlvErrors', ['0', '0'])
+
+
def test_r1_ldp_hello_adjacency_table():
"Test mplsLdpHelloAdjacencyTable"
tgen = get_topogen()
run_frr_cmd,
FRRCFG_FILE,
retry,
+ get_ipv6_linklocal_address
)
LOGDIR = "/tmp/topotests/"
cmd = "redistribute {}".format(redistribute["redist_type"])
redist_attr = redistribute.setdefault("attribute", None)
if redist_attr:
- if isinstance(redist_attr, dict):
+ if type(redist_attr) is dict:
for key, value in redist_attr.items():
cmd = "{} {} {}".format(cmd, key, value)
else:
if advertise_data:
for address_type, unicast_type in advertise_data.items():
- if isinstance(unicast_type, dict):
+ if type(unicast_type) is dict:
for key, value in unicast_type.items():
cmd = "advertise {} {}".format(address_type, key)
"ipv4"
].split("/")[0]
- if isinstance(action, dict):
+ if type(action) is dict:
next_hop_self = action.setdefault("next_hop_self", None)
route_maps = action.setdefault("route_maps", {})
router_list[router].run(cmd)
except Exception as e:
- # handle any exception
- logger.error("Error %s occured. Arguments %s.", e.message, e.args)
-
- # Traceback
errormsg = traceback.format_exc()
logger.error(errormsg)
return errormsg
logger.debug("Entering lib API: verify_bgp_convergence()")
for router, rnode in tgen.routers().items():
- if "bgp" not in topo["routers"][router]:
+ if dut is not None and dut != router:
continue
- if dut is not None and dut != router:
+ if "bgp" not in topo["routers"][router]:
continue
logger.info("Verifying BGP Convergence on router %s:", router)
# To find neighbor ip type
bgp_addr_type = bgp_data["address_family"]
- if "l2vpn" in bgp_addr_type:
- total_evpn_peer = 0
-
- if "neighbor" not in bgp_addr_type["l2vpn"]["evpn"]:
- continue
-
- bgp_neighbors = bgp_addr_type["l2vpn"]["evpn"]["neighbor"]
- total_evpn_peer += len(bgp_neighbors)
-
- no_of_evpn_peer = 0
- for bgp_neighbor, peer_data in bgp_neighbors.items():
- for _addr_type, dest_link_dict in peer_data.items():
- data = topo["routers"][bgp_neighbor]["links"]
- for dest_link in dest_link_dict.keys():
- if dest_link in data:
- peer_details = peer_data[_addr_type][dest_link]
-
- neighbor_ip = data[dest_link][_addr_type].split("/")[0]
- nh_state = None
-
- if (
- "ipv4Unicast" in show_bgp_json[vrf]
- or "ipv6Unicast" in show_bgp_json[vrf]
- ):
- errormsg = (
- "[DUT: %s] VRF: %s, "
- "ipv4Unicast/ipv6Unicast"
- " address-family present"
- " under l2vpn" % (router, vrf)
- )
- return errormsg
-
- l2VpnEvpn_data = show_bgp_json[vrf]["l2VpnEvpn"][
- "peers"
- ]
- nh_state = l2VpnEvpn_data[neighbor_ip]["state"]
-
- if nh_state == "Established":
- no_of_evpn_peer += 1
-
- if no_of_evpn_peer == total_evpn_peer:
- logger.info(
- "[DUT: %s] VRF: %s, BGP is Converged for " "epvn peers",
- router,
- vrf,
- )
- else:
- errormsg = (
- "[DUT: %s] VRF: %s, BGP is not converged "
- "for evpn peers" % (router, vrf)
- )
- return errormsg
- else:
+ if "ipv4" in bgp_addr_type or "ipv6" in bgp_addr_type:
for addr_type in bgp_addr_type.keys():
if not check_address_types(addr_type):
continue
nh_state = None
if addr_type == "ipv4":
- ipv4_data = show_bgp_json[vrf]["ipv4Unicast"][
- "peers"
- ]
- nh_state = ipv4_data[neighbor_ip]["state"]
+ if "ipv4Unicast" in show_bgp_json[vrf]:
+ ipv4_data = show_bgp_json[vrf]["ipv4Unicast"][
+ "peers"
+ ]
+ nh_state = ipv4_data[neighbor_ip]["state"]
else:
- ipv6_data = show_bgp_json[vrf]["ipv6Unicast"][
- "peers"
- ]
- nh_state = ipv6_data[neighbor_ip]["state"]
-
+ if "ipv6Unicast" in show_bgp_json[vrf]:
+ ipv6_data = show_bgp_json[vrf]["ipv6Unicast"][
+ "peers"
+ ]
+ nh_state = ipv6_data[neighbor_ip]["state"]
if nh_state == "Established":
no_of_peer += 1
- if no_of_peer == total_peer:
- logger.info(
- "[DUT: %s] VRF: %s, BGP is Converged for %s address-family",
- router,
- vrf,
- addr_type,
- )
+ if "l2vpn" in bgp_addr_type:
+ if "neighbor" not in bgp_addr_type["l2vpn"]["evpn"]:
+ if no_of_peer == total_peer:
+ logger.info(
+ "[DUT: %s] VRF: %s, BGP is Converged for %s address-family",
+ router,
+ vrf,
+ addr_type,
+ )
+ else:
+ errormsg = (
+ "[DUT: %s] VRF: %s, BGP is not converged for %s address-family"
+ % (router, vrf, addr_type)
+ )
+ return errormsg
else:
- errormsg = (
- "[DUT: %s] VRF: %s, BGP is not converged for %s address-family"
- % (router, vrf, addr_type)
- )
- return errormsg
+ if no_of_peer == total_peer:
+ logger.info(
+ "[DUT: %s] VRF: %s, BGP is Converged for %s address-family",
+ router,
+ vrf,
+ addr_type,
+ )
+ else:
+ errormsg = (
+ "[DUT: %s] VRF: %s, BGP is not converged for %s address-family"
+ % (router, vrf, addr_type)
+ )
+ return errormsg
+
+ if "l2vpn" in bgp_addr_type:
+ total_evpn_peer = 0
+
+ if "neighbor" not in bgp_addr_type["l2vpn"]["evpn"]:
+ continue
+
+ bgp_neighbors = bgp_addr_type["l2vpn"]["evpn"]["neighbor"]
+ total_evpn_peer += len(bgp_neighbors)
+
+ no_of_evpn_peer = 0
+ for bgp_neighbor, peer_data in bgp_neighbors.items():
+ for _addr_type, dest_link_dict in peer_data.items():
+ data = topo["routers"][bgp_neighbor]["links"]
+ for dest_link in dest_link_dict.keys():
+ if dest_link in data:
+ peer_details = peer_data[_addr_type][dest_link]
+
+ neighbor_ip = data[dest_link][_addr_type].split("/")[0]
+ nh_state = None
+
+ if (
+ "ipv4Unicast" in show_bgp_json[vrf]
+ or "ipv6Unicast" in show_bgp_json[vrf]
+ ):
+ errormsg = (
+ "[DUT: %s] VRF: %s, "
+ "ipv4Unicast/ipv6Unicast"
+ " address-family present"
+ " under l2vpn" % (router, vrf)
+ )
+ return errormsg
+
+ l2VpnEvpn_data = show_bgp_json[vrf]["l2VpnEvpn"][
+ "peers"
+ ]
+ nh_state = l2VpnEvpn_data[neighbor_ip]["state"]
+
+ if nh_state == "Established":
+ no_of_evpn_peer += 1
+
+ if no_of_evpn_peer == total_evpn_peer:
+ logger.info(
+ "[DUT: %s] VRF: %s, BGP is Converged for " "epvn peers",
+ router,
+ vrf,
+ )
+ else:
+ errormsg = (
+ "[DUT: %s] VRF: %s, BGP is not converged "
+ "for evpn peers" % (router, vrf)
+ )
+ return errormsg
logger.debug("Exiting API: verify_bgp_convergence()")
return True
create_router_bgp(tgen, new_topo)
except Exception as e:
- # handle any exception
- logger.error("Error %s occured. Arguments %s.", e.message, e.args)
-
- # Traceback
errormsg = traceback.format_exc()
logger.error(errormsg)
return errormsg
found_routes.append(st_rt)
if next_hop and multi_nh and st_found:
- if not isinstance(next_hop, list):
+ if type(next_hop) is not list:
next_hop = [next_hop]
list1 = next_hop
nh_found = True
elif next_hop and multi_nh is None:
- if not isinstance(next_hop, list):
+ if type(next_hop) is not list:
next_hop = [next_hop]
list1 = next_hop
found_hops = [
errormsg = (
"[DUT: %s] RD: %s, Route : %s "
"is not present in cli json "
- "output " % (dut, route)
+ "output " % (dut, _rd, route)
)
return errormsg
return errormsg
for key, route_data_json in evpn_value_json.items():
- if isinstance(route_data_json, dict):
+ if type(route_data_json) is dict:
rd_keys += 1
if prefix not in route_data_json:
missing_routes[key] = prefix
return errormsg
for key, route_data_json in evpn_value_json.items():
- if isinstance(route_data_json, dict):
+ if type(route_data_json) is dict:
if prefix not in route_data_json:
continue
if start_ip == "0.0.0.0" and mask == 0 and no_of_ips == 1:
ipaddress_list.append("{}/{}".format(start_ip, mask))
return ipaddress_list
- start_ip = ipaddress.IPv4Address(unicode(start_ip))
+ start_ip = ipaddress.IPv4Address(frr_unicode(start_ip))
step = 2 ** (32 - mask)
elif addr_type == "ipv6":
if start_ip == "0::0" and mask == 0 and no_of_ips == 1:
ipaddress_list.append("{}/{}".format(start_ip, mask))
return ipaddress_list
- start_ip = ipaddress.IPv6Address(unicode(start_ip))
+ start_ip = ipaddress.IPv6Address(frr_unicode(start_ip))
step = 2 ** (128 - mask)
else:
return []
load_config_to_router(tgen, router)
except Exception as e:
- # handle any exception
- logger.error("Error %s occured. Arguments %s.", e.message, e.args)
-
- # Traceback
errormsg = traceback.format_exc()
logger.error(errormsg)
return errormsg
interface_set_status(router_list[dut], intf_name, ifaceaction)
-def stop_router(tgen, router):
- """
- Router's current config would be saved to /tmp/topotest/<suite>/<router>
- for each daemon and router and its daemons would be stopped.
-
- * `tgen` : topogen object
- * `router`: Device under test
- """
-
- router_list = tgen.routers()
-
- # Saving router config to /etc/frr, which will be loaded to router
- # when it starts
- router_list[router].vtysh_cmd("write memory")
-
- # Stop router
- router_list[router].stop()
-
-
-def start_router(tgen, router):
- """
- Router will be started and config would be loaded from
- /tmp/topotest/<suite>/<router> for each daemon
-
- * `tgen` : topogen object
- * `router`: Device under test
- """
-
- logger.debug("Entering lib API: start_router")
-
- try:
- router_list = tgen.routers()
-
- # Router and its daemons would be started and config would
- # be loaded to router for each daemon from /etc/frr
- router_list[router].start()
-
- except Exception as e:
- errormsg = traceback.format_exc()
- logger.error(errormsg)
- return errormsg
-
- logger.debug("Exiting lib API: start_router()")
-
-
def addKernelRoute(
tgen, router, intf, group_addr_range, next_hop=None, src=None, del_action=None
):
return True
+def get_ipv6_linklocal_address(topo, node, intf):
+ """
+ API to get the link local ipv6 address of a perticular interface
+
+ Parameters
+ ----------
+ * `node`: node on which link local ip to be fetched.
+ * `intf` : interface for which link local ip needs to be returned.
+ * `topo` : base topo
+
+ Usage
+ -----
+ result = get_ipv6_linklocal_address(topo, 'r1', 'r2')
+
+ Returns link local ip of interface between r1 and r2.
+
+ Returns
+ -------
+ 1) link local ipv6 address from the interface
+ 2) errormsg - when link local ip not found
+ """
+ tgen = get_topogen()
+ ext_nh = tgen.net[node].get_ipv6_linklocal()
+ req_nh = topo[node]['links'][intf]['interface']
+ llip = None
+ for llips in ext_nh:
+ if llips[0] == req_nh:
+ llip = llips[1]
+ logger.info("Link local ip found = %s", llip)
+ return llip
+
+ errormsg = "Failed: Link local ip not found on router {}, "\
+ "interface {}".format(node, intf)
+
+ return errormsg
+
+
def verify_create_community_list(tgen, input_dict):
"""
API is to verify if large community list is created for any given DUT in
for lnk in input_dict[router]["links"].keys():
if "ospf" not in input_dict[router]["links"][lnk]:
logger.debug(
- "Router %s: ospf configs is not present in"
- "input_dict, passed input_dict",
- router,
- input_dict,
+ "Router %s: ospf config is not present in"
+ "input_dict",
+ router
)
continue
ospf_data = input_dict[router]["links"][lnk]["ospf"]
nh_state = neighbor["state"]
break
else:
- return "[DUT: {}] OSPF6 peer {} missing".format(router, data_rid)
+ return "[DUT: {}] OSPF6 peer {} missing".format(router, ospf_nbr_rid)
if nh_state == "Full":
no_of_peer += 1
return text
+def is_linux():
+ """
+ Parses unix name output to check if running on GNU/Linux.
+
+ Returns True if running on Linux, returns False otherwise.
+ """
+
+ if os.uname()[0] == "Linux":
+ return True
+ return False
+
+
+def iproute2_is_vrf_capable():
+ """
+ Checks if the iproute2 version installed on the system is capable of
+ handling VRFs by interpreting the output of the 'ip' utility found in PATH.
+
+ Returns True if capability can be detected, returns False otherwise.
+ """
+
+ if is_linux():
+ try:
+ subp = subprocess.Popen(
+ ["ip", "route", "show", "vrf"],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ stdin=subprocess.PIPE,
+ encoding="utf-8"
+ )
+ iproute2_err = subp.communicate()[1].splitlines()[0].split()[0]
+
+ if iproute2_err != "Error:":
+ return True
+ except Exception:
+ pass
+ return False
+
+
def module_present_linux(module, load):
"""
Returns whether `module` is present.
show zebra router table summary
show ip nht vrf all
show ipv6 nht vrf all
+show ip route vrf all
+show ipv6 route vrf all
show nexthop-group rib
show route-map
show memory
show interface vrf all
show vrf
-show zebra fpm stats
show work-queues
show debugging hashtable
show running-config
#define VRRP_LOGPFX "[CORE] "
-DEFINE_MTYPE_STATIC(VRRPD, VRRP_IP, "VRRP IP address")
-DEFINE_MTYPE_STATIC(VRRPD, VRRP_RTR, "VRRP Router")
+DEFINE_MTYPE_STATIC(VRRPD, VRRP_IP, "VRRP IP address");
+DEFINE_MTYPE_STATIC(VRRPD, VRRP_RTR, "VRRP Router");
/* statics */
struct hash *vrrp_vrouters_hash;
/* User compatibility constant */
#define CS2MS 10
-DECLARE_MGROUP(VRRPD)
+DECLARE_MGROUP(VRRPD);
/* Northbound */
extern const struct frr_yang_module_info frr_vrrpd_info;
#include "vrrp_vty.h"
#include "vrrp_zebra.h"
-DEFINE_MGROUP(VRRPD, "vrrpd")
+DEFINE_MGROUP(VRRPD, "vrrpd");
char backup_config_file[256];
.privs = &vrrp_privs,
.yang_modules = vrrp_yang_modules,
.n_yang_modules = array_size(vrrp_yang_modules),
-)
+);
int main(int argc, char **argv, char **envp)
{
#include "vrrp_debug.h"
#include "vrrp_packet.h"
-DEFINE_MTYPE_STATIC(VRRPD, VRRP_PKT, "VRRP packet")
+DEFINE_MTYPE_STATIC(VRRPD, VRRP_PKT, "VRRP packet");
/* clang-format off */
static const char *const vrrp_packet_names[16] = {
$cppadd = $fabricd ? "-DFABRICD=1" : "";
- open (FH, "@CPP@ -P -DHAVE_CONFIG_H -DVTYSH_EXTRACT_PL -Ivtysh/@top_builddir@ -Ivtysh/@top_srcdir@ -Ivtysh/@top_srcdir@/lib -Ivtysh/@top_builddir@/lib -Ivtysh/@top_srcdir@/bgpd -Ivtysh/@top_srcdir@/bgpd/rfapi @LUA_INCLUDE@ @CPPFLAGS@ $cppadd $file |");
+ open (FH, "@CPP@ -P -std=gnu11 -DHAVE_CONFIG_H -DVTYSH_EXTRACT_PL -Ivtysh/@top_builddir@ -Ivtysh/@top_srcdir@ -Ivtysh/@top_srcdir@/lib -Ivtysh/@top_builddir@/lib -Ivtysh/@top_srcdir@/bgpd -Ivtysh/@top_srcdir@/bgpd/rfapi @LUA_INCLUDE@ @CPPFLAGS@ $cppadd $file |");
local $/; undef $/;
$line = <FH>;
if (!close (FH)) {
#include "json.h"
#include "ferr.h"
-DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CMD, "Vtysh cmd copy")
+DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CMD, "Vtysh cmd copy");
/* Struct VTY. */
struct vty *vty;
#define VTYSH_H
#include "memory.h"
-DECLARE_MGROUP(MVTYSH)
+DECLARE_MGROUP(MVTYSH);
#define VTYSH_ZEBRA 0x00001
#define VTYSH_RIPD 0x00002
#include "vtysh/vtysh.h"
#include "vtysh/vtysh_user.h"
-DEFINE_MGROUP(MVTYSH, "vtysh")
-DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CONFIG, "Vtysh configuration")
-DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CONFIG_LINE, "Vtysh configuration line")
+DEFINE_MGROUP(MVTYSH, "vtysh");
+DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CONFIG, "Vtysh configuration");
+DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CONFIG_LINE, "Vtysh configuration line");
vector configvec;
return string_hash_make(c->name);
}
-DECLARE_LIST(config_master, struct config, rbt_item)
+DECLARE_LIST(config_master, struct config, rbt_item);
DECLARE_HASH(config_master_hash, struct config, hash_item, config_cmp,
- config_hash)
+ config_hash);
/*
* The config_master_head is a list for order of receipt
#define PING_TOKEN "PING"
-DEFINE_MGROUP(WATCHFRR, "watchfrr")
-DEFINE_MTYPE_STATIC(WATCHFRR, WATCHFRR_DAEMON, "watchfrr daemon entry")
+DEFINE_MGROUP(WATCHFRR, "watchfrr");
+DEFINE_MTYPE_STATIC(WATCHFRR, WATCHFRR_DAEMON, "watchfrr daemon entry");
/* Needs to be global, referenced somewhere inside libfrr. */
struct thread_master *master;
.signals = watchfrr_signals,
.n_signals = array_size(watchfrr_signals),
- .privs = &watchfrr_privs, )
+ .privs = &watchfrr_privs,
+);
#define DEPRECATED_OPTIONS "aAezR:"
#include "lib/memory.h"
-DECLARE_MGROUP(WATCHFRR)
+DECLARE_MGROUP(WATCHFRR);
extern void watchfrr_vty_init(void);
type uint32;
units microseconds;
default 50000;
- description "Minimum desired control packet transmission interval";
+ description "Minimum desired echo packet transmission interval";
+ }
+
+ leaf required-echo-receive-interval {
+ type uint32;
+ units microseconds;
+ default 50000;
+ description "Minimum required echo packet receive interval";
}
}
mandatory true;
case ipv4-prefix {
- when "../type = 'ipv4'";
-
leaf ipv4-prefix {
description "Configure IPv4 prefix to match";
type inet:ipv4-prefix;
}
}
case ipv6-prefix {
- when "../type = 'ipv6'";
-
leaf ipv6-prefix {
description "Configure IPv6 prefix to match";
type inet:ipv6-prefix;
#include "table.h"
#include "log.h"
#include "memory.h"
-#include "zebra_memory.h"
#include "vty.h"
#include "zebra/debug.h"
.version = "0.0.1",
.description = "Data plane plugin for FPM using netlink.",
.init = fpm_nl_init,
- )
+);
#include "ioctl.h"
#include "connected.h"
#include "memory.h"
-#include "zebra_memory.h"
#include "log.h"
#include "vrf.h"
#include "vty.h"
#include "connected.h"
#include "table.h"
#include "memory.h"
-#include "zebra_memory.h"
#include "rib.h"
#include "thread.h"
#include "privs.h"
#include "prefix.h"
#include "connected.h"
#include "memory.h"
-#include "zebra_memory.h"
#include "ioctl.h"
#include "log.h"
#include "interface.h"
#include "prefix.h"
#include "command.h"
#include "memory.h"
-#include "zebra_memory.h"
#include "ioctl.h"
#include "connected.h"
#include "log.h"
#include "zebra/zebra_errors.h"
#include "zebra/zebra_evpn_mh.h"
-DEFINE_MTYPE_STATIC(ZEBRA, ZINFO, "Zebra Interface Information")
+DEFINE_MTYPE_STATIC(ZEBRA, ZINFO, "Zebra Interface Information");
#define ZEBRA_PTM_SUPPORT
DEFINE_HOOK(zebra_if_extra_info, (struct vty * vty, struct interface *ifp),
- (vty, ifp))
+ (vty, ifp));
DEFINE_HOOK(zebra_if_config_wr, (struct vty * vty, struct interface *ifp),
- (vty, ifp))
+ (vty, ifp));
static void if_down_del_nbr_connected(struct interface *ifp);
};
DECLARE_HOOK(zebra_if_extra_info, (struct vty * vty, struct interface *ifp),
- (vty, ifp))
+ (vty, ifp));
DECLARE_HOOK(zebra_if_config_wr, (struct vty * vty, struct interface *ifp),
- (vty, ifp))
+ (vty, ifp));
#define IS_ZEBRA_IF_VRF(ifp) \
(((struct zebra_if *)(ifp->info))->zif_type == ZEBRA_IF_VRF)
#include "prefix.h"
#include "command.h"
#include "memory.h"
-#include "zebra_memory.h"
#include "stream.h"
#include "ioctl.h"
#include "connected.h"
extern int irdp_sock;
-DEFINE_MTYPE_STATIC(ZEBRA, IRDP_IF, "IRDP interface data")
+DEFINE_MTYPE_STATIC(ZEBRA, IRDP_IF, "IRDP interface data");
#define IRDP_CONFIGED \
do { \
#include "prefix.h"
#include "command.h"
#include "memory.h"
-#include "zebra_memory.h"
#include "stream.h"
#include "ioctl.h"
#include "connected.h"
}
FRR_MODULE_SETUP(.name = "zebra_irdp", .version = FRR_VERSION,
- .description = "zebra IRDP module", .init = irdp_module_init, )
+ .description = "zebra IRDP module", .init = irdp_module_init,
+);
#include "zclient.h"
#include "lib_errors.h"
-#include "zebra_memory.h"
#include "zebra/interface.h"
#include "zebra/rtadv.h"
#include "zebra/rib.h"
#include "connected.h"
#include "table.h"
#include "memory.h"
-#include "zebra_memory.h"
#include "rib.h"
#include "thread.h"
#include "privs.h"
extern struct zebra_privs_t zserv_privs;
-DEFINE_MTYPE_STATIC(ZEBRA, NL_BUF, "Zebra Netlink buffers")
+DEFINE_MTYPE_STATIC(ZEBRA, NL_BUF, "Zebra Netlink buffers");
size_t nl_batch_tx_bufsize;
char *nl_batch_tx_buf;
#include "sockunion.h"
#include "connected.h"
#include "memory.h"
-#include "zebra_memory.h"
#include "ioctl.h"
#include "log.h"
#include "table.h"
#include "thread.h"
#include "filter.h"
#include "memory.h"
-#include "zebra_memory.h"
#include "prefix.h"
#include "log.h"
#include "plist.h"
.privs = &zserv_privs,
.yang_modules = zebra_yang_modules,
- .n_yang_modules = array_size(zebra_yang_modules), )
+ .n_yang_modules = array_size(zebra_yang_modules),
+);
/* Main startup routine. */
int main(int argc, char **argv)
#include "zebra/debug.h"
#include "zebra/router-id.h"
#include "zebra/zapi_msg.h"
-#include "zebra/zebra_memory.h"
#include "zebra/zebra_vxlan.h"
#include "zebra/zebra_errors.h"
#define _ZEBRA_RIB_H
#include "zebra.h"
+#include "memory.h"
#include "hook.h"
#include "typesafe.h"
#include "linklist.h"
extern "C" {
#endif
+DECLARE_MGROUP(ZEBRA);
+
+DECLARE_MTYPE(RE);
+
enum rnh_type { RNH_NEXTHOP_TYPE, RNH_IMPORT_CHECK_TYPE };
-PREDECL_LIST(rnh_list)
+PREDECL_LIST(rnh_list);
/* Nexthop structure. */
struct rnh {
#define DISTANCE_INFINITY 255
#define ZEBRA_KERNEL_TABLE_MAX 252 /* support for no more than this rt tables */
-PREDECL_LIST(re_list)
+PREDECL_LIST(re_list);
struct opaque {
uint16_t length;
}
DECLARE_HOOK(rib_update, (struct route_node * rn, const char *reason),
- (rn, reason))
+ (rn, reason));
/*
* Access installed/fib nexthops, which may be a subset of the
#include "stream.h"
#include "command.h"
#include "memory.h"
-#include "zebra_memory.h"
#include "ioctl.h"
#include "connected.h"
#include "network.h"
#include "connected.h"
#include "table.h"
#include "memory.h"
-#include "zebra_memory.h"
#include "rib.h"
#include "thread.h"
#include "privs.h"
#include <zebra.h>
#include "memory.h"
-#include "zebra_memory.h"
#include "sockopt.h"
#include "thread.h"
#include "if.h"
#include "zebra/rtadv_clippy.c"
#endif
-DEFINE_MTYPE_STATIC(ZEBRA, RTADV_PREFIX, "Router Advertisement Prefix")
+DEFINE_MTYPE_STATIC(ZEBRA, RTADV_PREFIX, "Router Advertisement Prefix");
#ifdef OPEN_BSD
#include <netinet/icmp6.h>
#define ALLNODE "ff02::1"
#define ALLROUTER "ff02::2"
-DEFINE_MTYPE_STATIC(ZEBRA, RTADV_RDNSS, "Router Advertisement RDNSS")
-DEFINE_MTYPE_STATIC(ZEBRA, RTADV_DNSSL, "Router Advertisement DNSSL")
+DEFINE_MTYPE_STATIC(ZEBRA, RTADV_RDNSS, "Router Advertisement RDNSS");
+DEFINE_MTYPE_STATIC(ZEBRA, RTADV_DNSSL, "Router Advertisement DNSSL");
/* Order is intentional. Matches RFC4191. This array is also used for
command matching, so only modify with care. */
#if !defined(GNU_LINUX)
#include "memory.h"
-#include "zebra_memory.h"
#include "log.h"
#include "vrf.h"
.version = "0.0.1",
.description = "Dataplane Sample Plugin",
.init = module_init,
- )
+);
zebra/zebra_evpn_neigh.c \
zebra/zebra_mlag.c \
zebra/zebra_mlag_vty.c \
- zebra/zebra_memory.c \
zebra/zebra_mpls.c \
zebra/zebra_mpls_netlink.c \
zebra/zebra_mpls_openbsd.c \
zebra/zebra_evpn_vxlan.h \
zebra/zebra_fpm_private.h \
zebra/zebra_l2.h \
- zebra/zebra_memory.h \
zebra/zebra_mlag.h \
zebra/zebra_mlag_vty.h \
zebra/zebra_mpls.h \
zebra_zebra_irdp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
zebra_zebra_snmp_la_SOURCES = zebra/zebra_snmp.c
-zebra_zebra_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu99
+zebra_zebra_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu11
zebra_zebra_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
zebra_zebra_snmp_la_LIBADD = lib/libfrrsnmp.la
#include "zebra/zebra_router.h"
#include "zebra/rib.h"
-#include "zebra/zebra_memory.h"
#include "zebra/zebra_ns.h"
#include "zebra/zebra_vrf.h"
#include "zebra/router-id.h"
#include "zebra/zebra_opaque.h"
#include "zebra/zebra_srte.h"
+DEFINE_MTYPE_STATIC(ZEBRA, OPAQUE, "Opaque Data");
+
static int zapi_nhg_decode(struct stream *s, int cmd, struct zapi_nhg *api_nhg);
/* Encoding helpers -------------------------------------------------------- */
}
}
+void zapi_opaque_free(struct opaque *opaque)
+{
+ XFREE(MTYPE_OPAQUE, opaque);
+}
+
static void zread_route_del(ZAPI_HANDLER_ARGS)
{
struct stream *s;
int zsend_nhg_notify(uint16_t type, uint16_t instance, uint32_t session_id,
uint32_t id, enum zapi_nhg_notify_owner note);
+extern void zapi_opaque_free(struct opaque *opaque);
+
#ifdef __cplusplus
}
#endif
#include "lib/memory.h"
#include "lib/queue.h"
#include "lib/zebra.h"
-#include "zebra/zebra_memory.h"
#include "zebra/zebra_router.h"
#include "zebra/zebra_dplane.h"
#include "zebra/zebra_vxlan_private.h"
#include "printfrr.h"
/* Memory type for context blocks */
-DEFINE_MTYPE_STATIC(ZEBRA, DP_CTX, "Zebra DPlane Ctx")
-DEFINE_MTYPE_STATIC(ZEBRA, DP_INTF, "Zebra DPlane Intf")
-DEFINE_MTYPE_STATIC(ZEBRA, DP_PROV, "Zebra DPlane Provider")
-DEFINE_MTYPE_STATIC(ZEBRA, DP_NETFILTER, "Zebra Netfilter Internal Object")
+DEFINE_MTYPE_STATIC(ZEBRA, DP_CTX, "Zebra DPlane Ctx");
+DEFINE_MTYPE_STATIC(ZEBRA, DP_INTF, "Zebra DPlane Intf");
+DEFINE_MTYPE_STATIC(ZEBRA, DP_PROV, "Zebra DPlane Provider");
+DEFINE_MTYPE_STATIC(ZEBRA, DP_NETFILTER, "Zebra Netfilter Internal Object");
#ifndef AOK
# define AOK 0
#include "zebra/rt_netlink.h"
#include "zebra/zebra_errors.h"
#include "zebra/zebra_l2.h"
-#include "zebra/zebra_memory.h"
#include "zebra/zebra_ns.h"
#include "zebra/zebra_vrf.h"
#include "zebra/zebra_vxlan.h"
#include "zebra/zserv.h"
#include "zebra/debug.h"
#include "zebra/zebra_router.h"
-#include "zebra/zebra_memory.h"
#include "zebra/zebra_errors.h"
#include "zebra/zebra_vrf.h"
#include "zebra/zebra_evpn.h"
#include "zebra/if_netlink.h"
#include "zebra/zebra_errors.h"
#include "zebra/zebra_l2.h"
-#include "zebra/zebra_memory.h"
#include "zebra/zebra_ns.h"
#include "zebra/zebra_vrf.h"
#include "zebra/zebra_vxlan.h"
#include "zebra/debug.h"
#include "zebra/zebra_router.h"
#include "zebra/rt.h"
-#include "zebra/zebra_memory.h"
#include "zebra/zebra_errors.h"
#include "zebra/zebra_vrf.h"
#include "zebra/zebra_evpn.h"
#include "zebra/zebra_ns.h"
#include "zebra/zebra_vrf.h"
#include "zebra/zebra_errors.h"
-#include "zebra/zebra_memory.h"
#include "fpm/fpm.h"
#include "zebra_fpm_private.h"
FRR_MODULE_SETUP(.name = "zebra_fpm", .version = FRR_VERSION,
.description = "zebra FPM (Forwarding Plane Manager) module",
- .init = zebra_fpm_module_init, )
+ .init = zebra_fpm_module_init,
+);
#include "zebra/zserv.h"
#include "zebra/debug.h"
#include "zebra/interface.h"
-#include "zebra/zebra_memory.h"
#include "zebra/zebra_vrf.h"
#include "zebra/rt_netlink.h"
#include "zebra/interface.h"
+++ /dev/null
-/* zebra memory type definitions
- *
- * Copyright (C) 2015 David Lamparter
- *
- * This file is part of Quagga.
- *
- * Quagga is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * Quagga is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "zebra_memory.h"
-
-DEFINE_MGROUP(ZEBRA, "zebra")
-DEFINE_MTYPE(ZEBRA, RE, "Route Entry")
-DEFINE_MTYPE(ZEBRA, RIB_DEST, "RIB destination")
-DEFINE_MTYPE(ZEBRA, ZVLAN, "VLAN")
-DEFINE_MTYPE(ZEBRA, ZVLAN_BITMAP, "VLAN bitmap")
-DEFINE_MTYPE(ZEBRA, OPAQUE, "Opaque Data")
+++ /dev/null
-/* zebra memory type declarations
- *
- * Copyright (C) 2015 David Lamparter
- *
- * This file is part of Quagga.
- *
- * Quagga is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * Quagga is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef _QUAGGA_ZEBRA_MEMORY_H
-#define _QUAGGA_ZEBRA_MEMORY_H
-
-#include "memory.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-DECLARE_MGROUP(ZEBRA)
-DECLARE_MTYPE(ZEBRA_NS)
-DECLARE_MTYPE(RE)
-DECLARE_MTYPE(RIB_DEST)
-DECLARE_MTYPE(OPAQUE)
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _QUAGGA_ZEBRA_MEMORY_H */
#include "zebra/zebra_mlag.h"
#include "zebra/zebra_mlag_vty.h"
#include "zebra/zebra_router.h"
-#include "zebra/zebra_memory.h"
#include "zebra/zapi_msg.h"
#include "zebra/debug.h"
#endif
DEFINE_HOOK(zebra_mlag_private_write_data,
- (uint8_t *data, uint32_t len), (data, len))
-DEFINE_HOOK(zebra_mlag_private_monitor_state, (), ())
-DEFINE_HOOK(zebra_mlag_private_open_channel, (), ())
-DEFINE_HOOK(zebra_mlag_private_close_channel, (), ())
-DEFINE_HOOK(zebra_mlag_private_cleanup_data, (), ())
+ (uint8_t *data, uint32_t len), (data, len));
+DEFINE_HOOK(zebra_mlag_private_monitor_state, (), ());
+DEFINE_HOOK(zebra_mlag_private_open_channel, (), ());
+DEFINE_HOOK(zebra_mlag_private_close_channel, (), ());
+DEFINE_HOOK(zebra_mlag_private_cleanup_data, (), ());
#define ZEBRA_MLAG_METADATA_LEN 4
#define ZEBRA_MLAG_MSG_BCAST 0xFFFFFFFF
#ifdef HAVE_PROTOBUF_VERSION_3
-DEFINE_MTYPE_STATIC(ZEBRA, MLAG_PBUF, "ZEBRA MLAG PROTOBUF")
+DEFINE_MTYPE_STATIC(ZEBRA, MLAG_PBUF, "ZEBRA MLAG PROTOBUF");
int zebra_mlag_protobuf_encode_client_data(struct stream *s, uint32_t *msg_type)
{
#define ZEBRA_MLAG_LEN_SIZE 4
DECLARE_HOOK(zebra_mlag_private_write_data,
- (uint8_t *data, uint32_t len), (data, len))
-DECLARE_HOOK(zebra_mlag_private_monitor_state, (), ())
-DECLARE_HOOK(zebra_mlag_private_open_channel, (), ())
-DECLARE_HOOK(zebra_mlag_private_close_channel, (), ())
-DECLARE_HOOK(zebra_mlag_private_cleanup_data, (), ())
+ (uint8_t *data, uint32_t len), (data, len));
+DECLARE_HOOK(zebra_mlag_private_monitor_state, (), ());
+DECLARE_HOOK(zebra_mlag_private_open_channel, (), ());
+DECLARE_HOOK(zebra_mlag_private_close_channel, (), ());
+DECLARE_HOOK(zebra_mlag_private_cleanup_data, (), ());
extern uint8_t mlag_wr_buffer[ZEBRA_MLAG_BUF_LIMIT];
extern uint8_t mlag_rd_buffer[ZEBRA_MLAG_BUF_LIMIT];
.version = FRR_VERSION,
.description = "zebra Cumulus MLAG interface",
.init = zebra_mlag_module_init,
-)
+);
#include "zebra/zebra_router.h"
#include "zebra/redistribute.h"
#include "zebra/debug.h"
-#include "zebra/zebra_memory.h"
#include "zebra/zebra_vrf.h"
#include "zebra/zebra_mpls.h"
#include "zebra/zebra_srte.h"
#include "zebra/zebra_errors.h"
-DEFINE_MTYPE_STATIC(ZEBRA, LSP, "MPLS LSP object")
-DEFINE_MTYPE_STATIC(ZEBRA, FEC, "MPLS FEC object")
-DEFINE_MTYPE_STATIC(ZEBRA, NHLFE, "MPLS nexthop object")
+DEFINE_MTYPE_STATIC(ZEBRA, LSP, "MPLS LSP object");
+DEFINE_MTYPE_STATIC(ZEBRA, FEC, "MPLS FEC object");
+DEFINE_MTYPE_STATIC(ZEBRA, NHLFE, "MPLS nexthop object");
int mpls_enabled;
struct nb_cb_get_next_args *args);
int lib_vrf_zebra_ribs_rib_route_nexthop_group_frr_nexthops_nexthop_get_keys(
struct nb_cb_get_keys_args *args);
-int lib_vrf_zebra_ribs_rib_create(struct nb_cb_create_args *args);
-int lib_vrf_zebra_ribs_rib_destroy(struct nb_cb_destroy_args *args);
-const void *lib_vrf_zebra_ribs_rib_get_next(struct nb_cb_get_next_args *args);
-int lib_vrf_zebra_ribs_rib_get_keys(struct nb_cb_get_keys_args *args);
-const void *
-lib_vrf_zebra_ribs_rib_lookup_entry(struct nb_cb_lookup_entry_args *args);
-const void *
-lib_vrf_zebra_ribs_rib_route_get_next(struct nb_cb_get_next_args *args);
-int lib_vrf_zebra_ribs_rib_route_get_keys(struct nb_cb_get_keys_args *args);
-const void *
-lib_vrf_zebra_ribs_rib_route_lookup_entry(struct nb_cb_lookup_entry_args *args);
-struct yang_data *
-lib_vrf_zebra_ribs_rib_route_prefix_get_elem(struct nb_cb_get_elem_args *args);
const void *lib_vrf_zebra_ribs_rib_route_route_entry_get_next(
struct nb_cb_get_next_args *args);
int lib_vrf_zebra_ribs_rib_route_route_entry_get_keys(
#include "lib_errors.h"
#include "zebra_router.h"
-#include "zebra_memory.h"
#endif /* defined(HAVE_NETLINK) */
#include "zebra_netns_notify.h"
#define ZEBRA_NS_POLLING_INTERVAL_MSEC 1000
#define ZEBRA_NS_POLLING_MAX_RETRIES 200
-DEFINE_MTYPE_STATIC(ZEBRA, NETNS_MISC, "ZebraNetNSInfo")
+DEFINE_MTYPE_STATIC(ZEBRA, NETNS_MISC, "ZebraNetNSInfo");
static struct thread *zebra_netns_notify_current;
struct zebra_netns_info {
#include "zebra/zebra_nhg_private.h"
#include "zebra/zebra_rnh.h"
#include "zebra/zebra_routemap.h"
-#include "zebra/zebra_memory.h"
#include "zebra/zebra_srte.h"
#include "zebra/zserv.h"
#include "zebra/rt.h"
DEFINE_MTYPE_STATIC(ZEBRA, NHG_CONNECTED, "Nexthop Group Connected");
DEFINE_MTYPE_STATIC(ZEBRA, NHG_CTX, "Nexthop Group Context");
+/* Map backup nexthop indices between two nhes */
+struct backup_nh_map_s {
+ int map_count;
+
+ struct {
+ uint8_t orig_idx;
+ uint8_t new_idx;
+ } map[MULTIPATH_NUM];
+};
+
/* id counter to keep in sync with kernel */
uint32_t id_counter;
-/* */
+/* Controlled through ui */
static bool g_nexthops_enabled = true;
static bool proto_nexthops_only;
+static bool use_recursive_backups = true;
static struct nhg_hash_entry *depends_find(const struct nexthop *nh, afi_t afi,
int type, bool from_dplane);
*/
if (nh && (nh->next == NULL)) {
switch (nh->type) {
- case (NEXTHOP_TYPE_IFINDEX):
- case (NEXTHOP_TYPE_BLACKHOLE):
+ case NEXTHOP_TYPE_IFINDEX:
+ case NEXTHOP_TYPE_BLACKHOLE:
/*
* This switch case handles setting the afi different
* for ipv4/v6 routes. Ifindex/blackhole nexthop
*/
nhe->afi = afi;
break;
- case (NEXTHOP_TYPE_IPV4_IFINDEX):
- case (NEXTHOP_TYPE_IPV4):
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ case NEXTHOP_TYPE_IPV4:
nhe->afi = AFI_IP;
break;
- case (NEXTHOP_TYPE_IPV6_IFINDEX):
- case (NEXTHOP_TYPE_IPV6):
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ case NEXTHOP_TYPE_IPV6:
nhe->afi = AFI_IP6;
break;
}
nhg_connected_tree_increment_ref(&nhe->nhg_depends);
}
-static void nexthop_set_resolved(afi_t afi, const struct nexthop *newhop,
- struct nexthop *nexthop,
- struct zebra_sr_policy *policy)
+static struct nexthop *nexthop_set_resolved(afi_t afi,
+ const struct nexthop *newhop,
+ struct nexthop *nexthop,
+ struct zebra_sr_policy *policy)
{
struct nexthop *resolved_hop;
uint8_t num_labels = 0;
resolved_hop->rparent = nexthop;
_nexthop_add(&nexthop->resolved, resolved_hop);
+
+ return resolved_hop;
}
/* Checks if nexthop we are trying to resolve to is valid */
}
/*
- * Given a nexthop we need to properly recursively resolve
- * the route. As such, do a table lookup to find and match
- * if at all possible. Set the nexthop->ifindex and resolved_id
- * as appropriate
+ * When resolving a recursive nexthop, capture backup nexthop(s) also
+ * so they can be conveyed through the dataplane to the FIB. We'll look
+ * at the backups in the resolving nh 'nexthop' and its nhe, and copy them
+ * into the route's resolved nh 'resolved' and its nhe 'nhe'.
+ */
+static int resolve_backup_nexthops(const struct nexthop *nexthop,
+ const struct nhg_hash_entry *nhe,
+ struct nexthop *resolved,
+ struct nhg_hash_entry *resolve_nhe,
+ struct backup_nh_map_s *map)
+{
+ int i, j, idx;
+ const struct nexthop *bnh;
+ struct nexthop *nh, *newnh;
+
+ assert(nexthop->backup_num <= NEXTHOP_MAX_BACKUPS);
+
+ if (resolve_nhe->backup_info->nhe == NULL)
+ resolve_nhe->backup_info->nhe = zebra_nhg_alloc();
+
+ /* Locate backups from the original nexthop's backup index and nhe */
+ for (i = 0; i < nexthop->backup_num; i++) {
+ idx = nexthop->backup_idx[i];
+
+ /* Do we already know about this particular backup? */
+ for (j = 0; j < map->map_count; j++) {
+ if (map->map[j].orig_idx == idx)
+ break;
+ }
+
+ if (j < map->map_count) {
+ resolved->backup_idx[resolved->backup_num] =
+ map->map[j].new_idx;
+ resolved->backup_num++;
+
+ if (IS_ZEBRA_DEBUG_RIB_DETAILED)
+ zlog_debug("%s: found map idx orig %d, new %d",
+ __func__, map->map[j].orig_idx,
+ map->map[j].new_idx);
+
+ continue;
+ }
+
+ /* We can't handle any new map entries at this point. */
+ if (map->map_count == MULTIPATH_NUM)
+ break;
+
+ /* Need to create/copy a new backup */
+ bnh = nhe->backup_info->nhe->nhg.nexthop;
+ for (j = 0; j < idx; j++) {
+ if (bnh == NULL)
+ break;
+ bnh = bnh->next;
+ }
+
+ /* Whoops - bad index in the nexthop? */
+ if (bnh == NULL)
+ continue;
+
+ /* Update backup info in the resolving nexthop and its nhe */
+ newnh = nexthop_dup_no_recurse(bnh, NULL);
+
+ /* Need to compute the new backup index in the new
+ * backup list, and add to map struct.
+ */
+ j = 0;
+ nh = resolve_nhe->backup_info->nhe->nhg.nexthop;
+ if (nh) {
+ while (nh->next) {
+ nh = nh->next;
+ j++;
+ }
+
+ nh->next = newnh;
+
+ } else /* First one */
+ resolve_nhe->backup_info->nhe->nhg.nexthop = newnh;
+
+ /* Capture index */
+ resolved->backup_idx[resolved->backup_num] = j;
+ resolved->backup_num++;
+
+ if (IS_ZEBRA_DEBUG_RIB_DETAILED)
+ zlog_debug("%s: added idx orig %d, new %d",
+ __func__, idx, j);
+
+ /* Update map/cache */
+ map->map[map->map_count].orig_idx = idx;
+ map->map[map->map_count].new_idx = j;
+ map->map_count++;
+ }
+
+ return 0;
+}
+
+/*
+ * Given a nexthop we need to properly recursively resolve,
+ * do a table lookup to find and match if at all possible.
+ * Set the nexthop->ifindex and resolution info as appropriate.
*/
-static int nexthop_active(afi_t afi, struct route_entry *re,
- struct nexthop *nexthop, struct route_node *top)
+static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe,
+ const struct prefix *top, int type, uint32_t flags,
+ uint32_t *pmtu)
{
struct prefix p;
struct route_table *table;
struct zebra_vrf *zvrf;
struct in_addr local_ipv4;
struct in_addr *ipv4;
+ afi_t afi = AFI_IP;
+ /* Reset some nexthop attributes that we'll recompute if necessary */
if ((nexthop->type == NEXTHOP_TYPE_IPV4)
- || nexthop->type == NEXTHOP_TYPE_IPV6)
+ || (nexthop->type == NEXTHOP_TYPE_IPV6))
nexthop->ifindex = 0;
-
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
nexthops_free(nexthop->resolved);
nexthop->resolved = NULL;
- re->nexthop_mtu = 0;
-
- if (IS_ZEBRA_DEBUG_NHG_DETAIL)
- zlog_debug("%s: re %p, nexthop %pNHv",
- __func__, re, nexthop);
/*
- * If the kernel has sent us a NEW route, then
- * by golly gee whiz it's a good route.
- *
- * If its an already INSTALLED route we have already handled, then the
- * kernel route's nexthop might have became unreachable
- * and we have to handle that.
+ * Set afi based on nexthop type.
+ * Some nexthop types get special handling, possibly skipping
+ * the normal processing.
*/
- if (!CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)
- && (re->type == ZEBRA_ROUTE_KERNEL
- || re->type == ZEBRA_ROUTE_SYSTEM))
+ switch (nexthop->type) {
+ case NEXTHOP_TYPE_IFINDEX:
+
+ ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
+ /*
+ * If the interface exists and its operative or its a kernel
+ * route and interface is up, its active. We trust kernel routes
+ * to be good.
+ */
+ if (ifp
+ && (if_is_operative(ifp)
+ || (if_is_up(ifp)
+ && (type == ZEBRA_ROUTE_KERNEL
+ || type == ZEBRA_ROUTE_SYSTEM))))
+ return 1;
+ else
+ return 0;
+ break;
+
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ afi = AFI_IP6;
+
+ if (IN6_IS_ADDR_LINKLOCAL(&nexthop->gate.ipv6)) {
+ ifp = if_lookup_by_index(nexthop->ifindex,
+ nexthop->vrf_id);
+ if (ifp && if_is_operative(ifp))
+ return 1;
+ else
+ return 0;
+ }
+ break;
+
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ afi = AFI_IP;
+ break;
+ case NEXTHOP_TYPE_IPV6:
+ afi = AFI_IP6;
+ break;
+
+ case NEXTHOP_TYPE_BLACKHOLE:
return 1;
+ }
/*
* If the nexthop has been marked as 'onlink' we just need to make
return 1;
}
- if ((top->p.family == AF_INET && top->p.prefixlen == 32
- && nexthop->gate.ipv4.s_addr == top->p.u.prefix4.s_addr)
- || (top->p.family == AF_INET6 && top->p.prefixlen == 128
- && memcmp(&nexthop->gate.ipv6, &top->p.u.prefix6, 16) == 0)) {
+ if (top &&
+ ((top->family == AF_INET && top->prefixlen == 32
+ && nexthop->gate.ipv4.s_addr == top->u.prefix4.s_addr)
+ || (top->family == AF_INET6 && top->prefixlen == 128
+ && memcmp(&nexthop->gate.ipv6, &top->u.prefix6, 16) == 0))) {
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug(
" :%s: Attempting to install a max prefixlength route through itself",
ipv4 = &nexthop->gate.ipv4;
}
+ /* Processing for nexthops with SR 'color' attribute, using
+ * the corresponding SR policy object.
+ */
if (nexthop->srte_color) {
struct ipaddr endpoint = {0};
struct zebra_sr_policy *policy;
* resolved by a route NH1. The exception is if the route is a
* host route.
*/
- if (rn == top)
+ if (prefix_same(&rn->p, top))
if (((afi == AFI_IP) && (rn->p.prefixlen != 32))
|| ((afi == AFI_IP6) && (rn->p.prefixlen != 128))) {
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
match->nhe->id, newhop);
return 1;
- } else if (CHECK_FLAG(re->flags, ZEBRA_FLAG_ALLOW_RECURSION)) {
+ } else if (CHECK_FLAG(flags, ZEBRA_FLAG_ALLOW_RECURSION)) {
struct nexthop_group *nhg;
+ struct nexthop *resolver;
+ struct backup_nh_map_s map = {};
resolved = 0;
SET_FLAG(nexthop->flags,
NEXTHOP_FLAG_RECURSIVE);
- nexthop_set_resolved(afi, newhop, nexthop,
- NULL);
+ resolver = nexthop_set_resolved(afi, newhop,
+ nexthop, NULL);
resolved = 1;
+
+ /* If there are backup nexthops, capture
+ * that info with the resolving nexthop.
+ */
+ if (resolver && newhop->backup_num > 0) {
+ resolve_backup_nexthops(newhop,
+ match->nhe,
+ resolver, nhe,
+ &map);
+ }
}
/* Examine installed backup nexthops, if any. There
* are only installed backups *if* there is a
- * dedicated fib list.
+ * dedicated fib list. The UI can also control use
+ * of backups for resolution.
*/
nhg = rib_get_fib_backup_nhg(match);
- if (nhg == NULL || nhg->nexthop == NULL)
+ if (!use_recursive_backups ||
+ nhg == NULL || nhg->nexthop == NULL)
goto done_with_match;
for (ALL_NEXTHOPS_PTR(nhg, newhop)) {
NULL);
resolved = 1;
}
+
done_with_match:
- if (resolved)
- re->nexthop_mtu = match->mtu;
- else if (IS_ZEBRA_DEBUG_RIB_DETAILED)
+ /* Capture resolving mtu */
+ if (resolved) {
+ if (pmtu)
+ *pmtu = match->mtu;
+
+ } else if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug(
" %s: Recursion failed to find",
__func__);
if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
zlog_debug(
" %s: Route Type %s has not turned on recursion",
- __func__, zebra_route_string(re->type));
- if (re->type == ZEBRA_ROUTE_BGP
- && !CHECK_FLAG(re->flags, ZEBRA_FLAG_IBGP))
+ __func__, zebra_route_string(type));
+ if (type == ZEBRA_ROUTE_BGP
+ && !CHECK_FLAG(flags, ZEBRA_FLAG_IBGP))
zlog_debug(
" EBGP: see \"disable-ebgp-connected-route-check\" or \"disable-connected-check\"");
}
/* This function verifies reachability of one given nexthop, which can be
* numbered or unnumbered, IPv4 or IPv6. The result is unconditionally stored
* in nexthop->flags field. The nexthop->ifindex will be updated
- * appropriately as well. An existing route map can turn an
- * otherwise active nexthop into inactive, but not vice versa.
+ * appropriately as well.
*
- * If it finds a nexthop recursively, set the resolved_id
- * to match that nexthop's nhg_hash_entry ID;
+ * An existing route map can turn an otherwise active nexthop into inactive,
+ * but not vice versa.
*
* The return value is the final value of 'ACTIVE' flag.
*/
static unsigned nexthop_active_check(struct route_node *rn,
struct route_entry *re,
- struct nexthop *nexthop)
+ struct nexthop *nexthop,
+ struct nhg_hash_entry *nhe)
{
- struct interface *ifp;
route_map_result_t ret = RMAP_PERMITMATCH;
afi_t family;
const struct prefix *p, *src_p;
struct zebra_vrf *zvrf;
+ uint32_t mtu = 0;
srcdest_rnode_prefixes(rn, &p, &src_p);
else
family = 0;
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: re %p, nexthop %pNHv", __func__, re, nexthop);
+
+ /*
+ * If the kernel has sent us a NEW route, then
+ * by golly gee whiz it's a good route.
+ *
+ * If its an already INSTALLED route we have already handled, then the
+ * kernel route's nexthop might have became unreachable
+ * and we have to handle that.
+ */
+ if (!CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED) &&
+ (re->type == ZEBRA_ROUTE_KERNEL ||
+ re->type == ZEBRA_ROUTE_SYSTEM)) {
+ SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+ goto skip_check;
+ }
+
switch (nexthop->type) {
case NEXTHOP_TYPE_IFINDEX:
- ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
- /*
- * If the interface exists and its operative or its a kernel
- * route and interface is up, its active. We trust kernel routes
- * to be good.
- */
- if (ifp
- && (if_is_operative(ifp)
- || (if_is_up(ifp)
- && (re->type == ZEBRA_ROUTE_KERNEL
- || re->type == ZEBRA_ROUTE_SYSTEM))))
+ if (nexthop_active(nexthop, nhe, &rn->p, re->type,
+ re->flags, &mtu))
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
else
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
case NEXTHOP_TYPE_IPV4:
case NEXTHOP_TYPE_IPV4_IFINDEX:
family = AFI_IP;
- if (nexthop_active(AFI_IP, re, nexthop, rn))
+ if (nexthop_active(nexthop, nhe, &rn->p, re->type,
+ re->flags, &mtu))
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
else
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
break;
case NEXTHOP_TYPE_IPV6:
family = AFI_IP6;
- if (nexthop_active(AFI_IP6, re, nexthop, rn))
+ if (nexthop_active(nexthop, nhe, &rn->p, re->type,
+ re->flags, &mtu))
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
else
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
/* RFC 5549, v4 prefix with v6 NH */
if (rn->p.family != AF_INET)
family = AFI_IP6;
- if (IN6_IS_ADDR_LINKLOCAL(&nexthop->gate.ipv6)) {
- ifp = if_lookup_by_index(nexthop->ifindex,
- nexthop->vrf_id);
- if (ifp && if_is_operative(ifp))
- SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
- else
- UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
- } else {
- if (nexthop_active(AFI_IP6, re, nexthop, rn))
- SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
- else
- UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
- }
+
+ if (nexthop_active(nexthop, nhe, &rn->p, re->type,
+ re->flags, &mtu))
+ SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+ else
+ UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
break;
case NEXTHOP_TYPE_BLACKHOLE:
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
break;
}
+skip_check:
+
if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug(" %s: Unable to find active nexthop",
return 0;
}
+ /* Capture recursive nexthop mtu.
+ * TODO -- the code used to just reset the re's value to zero
+ * for each nexthop, and then jam any resolving route's mtu value in,
+ * whether or not that was zero, or lt/gt any existing value? The
+ * way this is used appears to be as a floor value, so let's try
+ * using it that way here.
+ */
+ if (mtu > 0) {
+ if (re->nexthop_mtu == 0 || re->nexthop_mtu > mtu)
+ re->nexthop_mtu = mtu;
+ }
+
/* XXX: What exactly do those checks do? Do we support
* e.g. IPv4 routes with IPv6 nexthops or vice versa?
*/
* Possibly it may be better to use only the rib_table_info
* in every case.
*/
- if (!family) {
+ if (family == 0) {
struct rib_table_info *info;
info = srcdest_rnode_table_info(rn);
}
/*
- * Process a list of nexthops, given an nhg, determining
+ * Process a list of nexthops, given an nhe, determining
* whether each one is ACTIVE/installable at this time.
*/
static uint32_t nexthop_list_active_update(struct route_node *rn,
struct route_entry *re,
- struct nexthop_group *nhg)
+ struct nhg_hash_entry *nhe,
+ bool is_backup)
{
union g_addr prev_src;
unsigned int prev_active, new_active;
ifindex_t prev_index;
uint32_t counter = 0;
struct nexthop *nexthop;
+ struct nexthop_group *nhg = &nhe->nhg;
nexthop = nhg->nexthop;
+ /* Init recursive nh mtu */
+ re->nexthop_mtu = 0;
+
/* Process nexthops one-by-one */
for ( ; nexthop; nexthop = nexthop->next) {
prev_src = nexthop->rmap_src;
prev_active = CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
prev_index = nexthop->ifindex;
+
+ /* Include the containing nhe for primary nexthops: if there's
+ * recursive resolution, we capture the backup info also.
+ */
+ new_active =
+ nexthop_active_check(rn, re, nexthop,
+ (is_backup ? NULL : nhe));
+
/*
* We need to respect the multipath_num here
* as that what we should be able to install from
* a multipath perspective should not be a data plane
* decision point.
*/
- new_active =
- nexthop_active_check(rn, re, nexthop);
-
if (new_active && counter >= zrouter.multipath_num) {
struct nexthop *nh;
if (new_active)
counter++;
- /* Don't allow src setting on IPv6 addr for now */
+ /* Check for changes to the nexthop - set ROUTE_ENTRY_CHANGED */
if (prev_active != new_active || prev_index != nexthop->ifindex
|| ((nexthop->type >= NEXTHOP_TYPE_IFINDEX
&& nexthop->type < NEXTHOP_TYPE_IPV6)
curr_nhe->id = 0;
/* Process nexthops */
- curr_active = nexthop_list_active_update(rn, re, &curr_nhe->nhg);
+ curr_active = nexthop_list_active_update(rn, re, curr_nhe, false);
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
zlog_debug("%s: re %p curr_active %u", __func__, re,
goto backups_done;
backup_active = nexthop_list_active_update(
- rn, re, zebra_nhg_get_backup_nhg(curr_nhe));
+ rn, re, curr_nhe->backup_info->nhe, true /*is_backup*/);
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
zlog_debug("%s: re %p backup_active %u", __func__, re,
return g_nexthops_enabled;
}
+/* Global control for use of activated backups for recursive resolution. */
+void zebra_nhg_set_recursive_use_backups(bool set)
+{
+ use_recursive_backups = set;
+}
+
+bool zebra_nhg_recursive_use_backups(void)
+{
+ return use_recursive_backups;
+}
+
/*
* Global control to only use kernel nexthops for protocol created NHGs.
* There are some use cases where you may not want zebra to implicitly
vrf_id_t vrf_id;
afi_t afi;
+
/*
- * This should only every be ZEBRA_ROUTE_NHG unless we get a a kernel
+ * This should only ever be ZEBRA_ROUTE_NHG unless we get a a kernel
* created nexthop not made by us.
*/
int type;
void zebra_nhg_set_proto_nexthops_only(bool set);
bool zebra_nhg_proto_nexthops_only(void);
+/* Global control for use of activated backups for recursive resolution. */
+void zebra_nhg_set_recursive_use_backups(bool set);
+bool zebra_nhg_recursive_use_backups(void);
+
/**
* NHE abstracted tree functions.
* Use these where possible instead of direct access.
#include "zebra_ns.h"
#include "zebra_vrf.h"
-#include "zebra_memory.h"
#include "rt.h"
#include "zebra_vxlan.h"
#include "debug.h"
extern struct zebra_privs_t zserv_privs;
-DEFINE_MTYPE(ZEBRA, ZEBRA_NS, "Zebra Name Space")
+DEFINE_MTYPE_STATIC(ZEBRA, ZEBRA_NS, "Zebra Name Space");
static struct zebra_ns *dzns;
#include "lib/stream.h"
#include "zebra/debug.h"
#include "zebra/zserv.h"
-#include "zebra/zebra_memory.h"
#include "zebra/zebra_opaque.h"
/* Mem type */
#include "zebra/zebra_pbr.h"
#include "zebra/rt.h"
#include "zebra/zapi_msg.h"
-#include "zebra/zebra_memory.h"
#include "zebra/zserv.h"
#include "zebra/debug.h"
/* definitions */
-DEFINE_MTYPE_STATIC(ZEBRA, PBR_IPTABLE_IFNAME, "PBR interface list")
+DEFINE_MTYPE_STATIC(ZEBRA, PBR_IPTABLE_IFNAME, "PBR interface list");
/* definitions */
static const struct message ipset_type_msg[] = {
DEFINE_HOOK(zebra_pbr_ipset_entry_get_stat,
(struct zebra_pbr_ipset_entry *ipset, uint64_t *pkts,
uint64_t *bytes),
- (ipset, pkts, bytes))
+ (ipset, pkts, bytes));
DEFINE_HOOK(zebra_pbr_iptable_get_stat,
(struct zebra_pbr_iptable *iptable, uint64_t *pkts,
uint64_t *bytes),
- (iptable, pkts, bytes))
+ (iptable, pkts, bytes));
DEFINE_HOOK(zebra_pbr_iptable_update,
(int cmd, struct zebra_pbr_iptable *iptable), (cmd, iptable));
DECLARE_HOOK(zebra_pbr_ipset_entry_get_stat,
(struct zebra_pbr_ipset_entry *ipset, uint64_t *pkts,
uint64_t *bytes),
- (ipset, pkts, bytes))
+ (ipset, pkts, bytes));
DECLARE_HOOK(zebra_pbr_iptable_get_stat,
(struct zebra_pbr_iptable *iptable, uint64_t *pkts,
uint64_t *bytes),
- (iptable, pkts, bytes))
+ (iptable, pkts, bytes));
DECLARE_HOOK(zebra_pbr_iptable_update,
(int cmd, struct zebra_pbr_iptable *iptable), (cmd, iptable));
#else /* HAVE_BFDD */
-#include "zebra/zebra_memory.h"
-
/*
* Data structures.
*/
#include "zebra/zapi_msg.h"
#include "zebra/zebra_ptm.h"
#include "zebra/zebra_ptm_redistribute.h"
-#include "zebra/zebra_memory.h"
static int zsend_interface_bfd_update(int cmd, struct zserv *client,
struct interface *ifp, struct prefix *dp,
#include "zebra/zebra_vrf.h"
#include "zebra/zebra_pw.h"
-DEFINE_MTYPE_STATIC(LIB, PW, "Pseudowire")
+DEFINE_MTYPE_STATIC(LIB, PW, "Pseudowire");
-DEFINE_QOBJ_TYPE(zebra_pw)
+DEFINE_QOBJ_TYPE(zebra_pw);
-DEFINE_HOOK(pw_install, (struct zebra_pw * pw), (pw))
-DEFINE_HOOK(pw_uninstall, (struct zebra_pw * pw), (pw))
+DEFINE_HOOK(pw_install, (struct zebra_pw * pw), (pw));
+DEFINE_HOOK(pw_uninstall, (struct zebra_pw * pw), (pw));
#define MPLS_NO_LABEL MPLS_INVALID_LABEL
struct zserv *client;
struct rnh *rnh;
struct thread *install_retry_timer;
- QOBJ_FIELDS
+ QOBJ_FIELDS;
};
-DECLARE_QOBJ_TYPE(zebra_pw)
+DECLARE_QOBJ_TYPE(zebra_pw);
RB_HEAD(zebra_pw_head, zebra_pw);
RB_PROTOTYPE(zebra_pw_head, zebra_pw, pw_entry, zebra_pw_compare);
RB_HEAD(zebra_static_pw_head, zebra_pw);
RB_PROTOTYPE(zebra_static_pw_head, zebra_pw, static_pw_entry, zebra_pw_compare);
-DECLARE_HOOK(pw_install, (struct zebra_pw * pw), (pw))
-DECLARE_HOOK(pw_uninstall, (struct zebra_pw * pw), (pw))
+DECLARE_HOOK(pw_install, (struct zebra_pw * pw), (pw));
+DECLARE_HOOK(pw_uninstall, (struct zebra_pw * pw), (pw));
struct zebra_pw *zebra_pw_add(struct zebra_vrf *zvrf, const char *ifname,
uint8_t protocol, struct zserv *client);
#include "zebra/rt.h"
#include "zebra/zapi_msg.h"
#include "zebra/zebra_errors.h"
-#include "zebra/zebra_memory.h"
#include "zebra/zebra_ns.h"
#include "zebra/zebra_rnh.h"
#include "zebra/zebra_routemap.h"
#include "zebra/zapi_msg.h"
#include "zebra/zebra_dplane.h"
+DEFINE_MGROUP(ZEBRA, "zebra");
+
+DEFINE_MTYPE(ZEBRA, RE, "Route Entry");
+DEFINE_MTYPE_STATIC(ZEBRA, RIB_DEST, "RIB destination");
DEFINE_MTYPE_STATIC(ZEBRA, RIB_UPDATE_CTX, "Rib update context object");
/*
static struct dplane_ctx_q rib_dplane_q;
DEFINE_HOOK(rib_update, (struct route_node * rn, const char *reason),
- (rn, reason))
+ (rn, reason));
/* Should we allow non Quagga processes to delete our routes */
extern int allow_delete;
return 1;
}
+void zebra_rtable_node_cleanup(struct route_table *table,
+ struct route_node *node)
+{
+ struct route_entry *re, *next;
+
+ RNODE_FOREACH_RE_SAFE (node, re, next) {
+ rib_unlink(node, re);
+ }
+
+ if (node->info) {
+ rib_dest_t *dest = node->info;
+
+ rnh_list_fini(&dest->nht);
+ XFREE(MTYPE_RIB_DEST, node->info);
+ }
+}
+
static void rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn,
struct route_entry *new)
{
nexthops_free(re->fib_ng.nexthop);
- XFREE(MTYPE_OPAQUE, re->opaque);
+ zapi_opaque_free(re->opaque);
XFREE(MTYPE_RE, re);
}
#include "zebra/zebra_routemap.h"
#include "zebra/zebra_srte.h"
#include "zebra/interface.h"
-#include "zebra/zebra_memory.h"
#include "zebra/zebra_errors.h"
-DEFINE_MTYPE_STATIC(ZEBRA, RNH, "Nexthop tracking object")
+DEFINE_MTYPE_STATIC(ZEBRA, RNH, "Nexthop tracking object");
static void free_state(vrf_id_t vrf_id, struct route_entry *re,
struct route_node *rn);
#include <zebra.h>
#include "memory.h"
-#include "zebra_memory.h"
#include "prefix.h"
#include "rib.h"
#include "vty.h"
#include "lib/frratomic.h"
#include "zebra_router.h"
-#include "zebra_memory.h"
#include "zebra_pbr.h"
#include "zebra_vxlan.h"
#include "zebra_mlag.h"
#include "zebra_nhg.h"
#include "debug.h"
-DEFINE_MTYPE_STATIC(ZEBRA, RIB_TABLE_INFO, "RIB table info")
+DEFINE_MTYPE_STATIC(ZEBRA, RIB_TABLE_INFO, "RIB table info");
+DEFINE_MTYPE_STATIC(ZEBRA, ZEBRA_RT_TABLE, "Zebra VRF table");
struct zebra_router zrouter = {
.multipath_num = MULTIPATH_NUM,
if (zrt)
return zrt->table;
- zrt = XCALLOC(MTYPE_ZEBRA_NS, sizeof(*zrt));
+ zrt = XCALLOC(MTYPE_ZEBRA_RT_TABLE, sizeof(*zrt));
zrt->tableid = tableid;
zrt->afi = afi;
zrt->safi = safi;
RB_REMOVE(zebra_router_table_head, &zrouter.tables, zrt);
XFREE(MTYPE_RIB_TABLE_INFO, table_info);
- XFREE(MTYPE_ZEBRA_NS, zrt);
+ XFREE(MTYPE_ZEBRA_RT_TABLE, zrt);
}
void zebra_router_release_table(struct zebra_vrf *zvrf, uint32_t tableid,
FRR_MODULE_SETUP(.name = "zebra_snmp", .version = FRR_VERSION,
.description = "zebra AgentX SNMP module",
- .init = zebra_snmp_module_init, )
+ .init = zebra_snmp_module_init,
+);
#include "lib/lib_errors.h"
#include "zebra/zebra_srte.h"
-#include "zebra/zebra_memory.h"
#include "zebra/zebra_mpls.h"
#include "zebra/zebra_rnh.h"
#include "zebra/zapi_msg.h"
-DEFINE_MTYPE_STATIC(ZEBRA, ZEBRA_SR_POLICY, "SR Policy")
+DEFINE_MTYPE_STATIC(ZEBRA, ZEBRA_SR_POLICY, "SR Policy");
static void zebra_sr_policy_deactivate(struct zebra_sr_policy *policy);
#include "zebra/zebra_vrf.h"
#include "zebra/zebra_rnh.h"
#include "zebra/router-id.h"
-#include "zebra/zebra_memory.h"
#include "zebra/interface.h"
#include "zebra/zebra_mpls.h"
#include "zebra/zebra_vxlan.h"
static void zebra_rnhtable_node_cleanup(struct route_table *table,
struct route_node *node);
-DEFINE_MTYPE_STATIC(ZEBRA, ZEBRA_VRF, "ZEBRA VRF")
-DEFINE_MTYPE_STATIC(ZEBRA, OTHER_TABLE, "Other Table")
+DEFINE_MTYPE_STATIC(ZEBRA, ZEBRA_VRF, "ZEBRA VRF");
+DEFINE_MTYPE_STATIC(ZEBRA, OTHER_TABLE, "Other Table");
/* VRF information update. */
static void zebra_vrf_add_update(struct zebra_vrf *zvrf)
return table;
}
-void zebra_rtable_node_cleanup(struct route_table *table,
- struct route_node *node)
-{
- struct route_entry *re, *next;
-
- RNODE_FOREACH_RE_SAFE (node, re, next) {
- rib_unlink(node, re);
- }
-
- if (node->info) {
- rib_dest_t *dest = node->info;
-
- rnh_list_fini(&dest->nht);
- XFREE(MTYPE_RIB_DEST, node->info);
- }
-}
-
static void zebra_rnhtable_node_cleanup(struct route_table *table,
struct route_node *node)
{
}
DECLARE_RBTREE_UNIQ(otable, struct other_route_table, next,
- zvrf_other_table_compare_func)
+ zvrf_other_table_compare_func);
extern struct route_table *
zebra_vrf_lookup_table_with_table_id(afi_t afi, safi_t safi, vrf_id_t vrf_id,
#include <zebra.h>
#include "memory.h"
-#include "zebra_memory.h"
#include "if.h"
#include "prefix.h"
#include "command.h"
return CMD_SUCCESS;
}
+DEFPY_HIDDEN(backup_nexthop_recursive_use_enable,
+ backup_nexthop_recursive_use_enable_cmd,
+ "[no] zebra nexthop resolve-via-backup",
+ NO_STR
+ ZEBRA_STR
+ "Nexthop configuration \n"
+ "Configure use of backup nexthops in recursive resolution\n")
+{
+ zebra_nhg_set_recursive_use_backups(!no);
+ return CMD_SUCCESS;
+}
+
DEFUN (no_ip_nht_default_route,
no_ip_nht_default_route_cmd,
"no ip nht resolve-via-default",
"VNI-ID\n"
"Prefix routes only \n")
{
- int ret = 0;
- char err[ERR_STR_SZ];
+ char xpath[XPATH_MAXLEN];
struct zebra_vrf *zvrf = NULL;
- vni_t vni = strtoul(argv[1]->arg, NULL, 10);
int filter = 0;
zvrf = vrf_info_lookup(VRF_DEFAULT);
if (argc == 3)
filter = 1;
- ret = zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, ERR_STR_SZ,
- filter, 1);
- if (ret != 0) {
- vty_out(vty, "%s\n", err);
- return CMD_WARNING;
+ snprintf(xpath, sizeof(xpath), FRR_VRF_KEY_XPATH "/frr-zebra:zebra",
+ VRF_DEFAULT_NAME);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+
+ snprintf(xpath, sizeof(xpath),
+ FRR_VRF_KEY_XPATH "/frr-zebra:zebra/l3vni-id",
+ VRF_DEFAULT_NAME);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, argv[1]->arg);
+
+ if (filter) {
+ snprintf(xpath, sizeof(xpath),
+ FRR_VRF_KEY_XPATH "/frr-zebra:zebra/prefix-only",
+ VRF_DEFAULT_NAME);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, "true");
}
- return CMD_SUCCESS;
+ return nb_cli_apply_changes(vty, NULL);
}
DEFUN (no_default_vrf_vni_mapping,
no_default_vrf_vni_mapping_cmd,
- "no vni " CMD_VNI_RANGE,
+ "no vni " CMD_VNI_RANGE "[prefix-routes-only]",
NO_STR
"VNI corresponding to DEFAULT VRF\n"
- "VNI-ID")
+ "VNI-ID\n"
+ "Prefix routes only \n")
{
- int ret = 0;
- char err[ERR_STR_SZ];
+ char xpath[XPATH_MAXLEN];
+ int filter = 0;
vni_t vni = strtoul(argv[2]->arg, NULL, 10);
struct zebra_vrf *zvrf = NULL;
if (!zvrf)
return CMD_WARNING;
- ret = zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, ERR_STR_SZ, 0, 0);
- if (ret != 0) {
- vty_out(vty, "%s\n", err);
+ if (argc == 4)
+ filter = 1;
+
+ if (zvrf->l3vni != vni) {
+ vty_out(vty, "VNI %d doesn't exist in VRF: %s \n", vni,
+ zvrf->vrf->name);
return CMD_WARNING;
}
- return CMD_SUCCESS;
+ snprintf(xpath, sizeof(xpath),
+ FRR_VRF_KEY_XPATH "/frr-zebra:zebra/l3vni-id",
+ VRF_DEFAULT_NAME);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, argv[2]->arg);
+
+ if (filter) {
+ snprintf(xpath, sizeof(xpath),
+ FRR_VRF_KEY_XPATH "/frr-zebra:zebra/prefix-only",
+ VRF_DEFAULT_NAME);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, "true");
+ }
+
+ snprintf(xpath, sizeof(xpath), FRR_VRF_KEY_XPATH "/frr-zebra:zebra",
+ VRF_DEFAULT_NAME);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
}
DEFUN (vrf_vni_mapping,
nb_cli_enqueue_change(vty, "./frr-zebra:zebra/prefix-only",
NB_OP_MODIFY, "true");
- nb_cli_apply_changes(vty, NULL);
-
- return CMD_SUCCESS;
+ return nb_cli_apply_changes(vty, NULL);
}
DEFUN (no_vrf_vni_mapping,
nb_cli_enqueue_change(vty, "./frr-zebra:zebra", NB_OP_DESTROY, NULL);
- nb_cli_apply_changes(vty, NULL);
-
- return CMD_SUCCESS;
+ return nb_cli_apply_changes(vty, NULL);
}
/* show vrf */
if (zebra_nhg_proto_nexthops_only())
vty_out(vty, "zebra nexthop proto only\n");
+ if (!zebra_nhg_recursive_use_backups())
+ vty_out(vty, "no zebra nexthop resolve-via-backup\n");
+
#ifdef HAVE_NETLINK
/* Include netlink info */
netlink_config_write_helper(vty);
install_element(CONFIG_NODE, &no_zebra_packet_process_cmd);
install_element(CONFIG_NODE, &nexthop_group_use_enable_cmd);
install_element(CONFIG_NODE, &proto_nexthop_group_only_cmd);
+ install_element(CONFIG_NODE, &backup_nexthop_recursive_use_enable_cmd);
install_element(VIEW_NODE, &show_nexthop_group_cmd);
install_element(VIEW_NODE, &show_interface_nexthop_group_cmd);
#include "zebra/rt_netlink.h"
#include "zebra/zebra_errors.h"
#include "zebra/zebra_l2.h"
-#include "zebra/zebra_memory.h"
#include "zebra/zebra_ns.h"
#include "zebra/zebra_vrf.h"
#include "zebra/zebra_vxlan.h"
DEFINE_MTYPE_STATIC(ZEBRA, ZVXLAN_SG, "zebra VxLAN multicast group");
DEFINE_HOOK(zebra_rmac_update, (zebra_mac_t *rmac, zebra_l3vni_t *zl3vni,
- bool delete, const char *reason), (rmac, zl3vni, delete, reason))
+ bool delete, const char *reason), (rmac, zl3vni, delete, reason));
/* static function declarations */
static void zevpn_print_neigh_hash_all_evpn(struct hash_bucket *bucket,
extern zebra_l3vni_t *zl3vni_lookup(vni_t vni);
DECLARE_HOOK(zebra_rmac_update, (zebra_mac_t *rmac, zebra_l3vni_t *zl3vni,
- bool delete, const char *reason), (rmac, zl3vni, delete, reason))
+ bool delete, const char *reason), (rmac, zl3vni, delete, reason));
#ifdef __cplusplus