static struct ptm_client *pc_lookup(uint32_t pid);
static struct ptm_client *pc_new(uint32_t pid);
+static void pc_free(struct ptm_client *pc);
+static void pc_free_all(void);
static struct ptm_client_notification *pcn_new(struct ptm_client *pc,
struct bfd_session *bs);
static struct ptm_client_notification *pcn_lookup(struct ptm_client *pc,
static void bfdd_dest_register(struct stream *msg);
static void bfdd_dest_deregister(struct stream *msg);
static void bfdd_client_register(struct stream *msg);
+static void bfdd_client_deregister(struct stream *msg);
/*
* Functions
struct stream *msg;
struct sockaddr_any sac;
+ bs->stats.znotification++;
+
/*
* Message format:
* - header: command, vrf
return;
default:
- log_warning("%s: invalid family: %d", __func__, family);
+ log_warning("ptm-read-address: invalid family: %d", family);
break;
}
struct bfd_peer_cfg *bpc, struct ptm_client **pc)
{
uint32_t pid;
- uint8_t ttl;
- uint8_t ifnamelen;
+ uint8_t ttl __attribute__((unused));
+ size_t ifnamelen;
/*
* Register/Deregister/Update Message format:
*pc = pc_new(pid);
if (*pc == NULL) {
- log_debug("%s: failed to allocate memory", __func__);
+ log_debug("ptm-read: failed to allocate memory");
return -1;
}
/* Read multihop source address and TTL. */
_ptm_msg_read_address(msg, &bpc->bpc_local);
STREAM_GETC(msg, ttl);
-
- /*
- * TODO: use TTL for something. The line below removes
- * an unused variable compiler warning.
- */
- ttl = ttl;
} else {
/* If target is IPv6, then we must obtain local address. */
if (bpc->bpc_ipv4 == false)
* structure, otherwise fail.
*/
STREAM_GETC(msg, ifnamelen);
- if (ifnamelen > sizeof(bpc->bpc_localif)) {
- log_error("%s: interface name is too big", __func__);
+ if (ifnamelen >= sizeof(bpc->bpc_localif)) {
+ log_error("ptm-read: interface name is too big");
return -1;
}
if (bpc->bpc_has_localif) {
STREAM_GET(bpc->bpc_localif, msg, ifnamelen);
bpc->bpc_localif[ifnamelen] = 0;
+
+ /*
+ * IPv6 link-local addresses must use scope id,
+ * otherwise the session lookup will always fail
+ * and we'll have multiple sessions showing up.
+ *
+ * This problem only happens with single hop
+ * since it is not possible to have link-local
+ * address for multi hop sessions.
+ */
+ if (bpc->bpc_ipv4 == false
+ && IN6_IS_ADDR_LINKLOCAL(
+ &bpc->bpc_peer.sa_sin6.sin6_addr))
+ bpc->bpc_peer.sa_sin6.sin6_scope_id =
+ ptm_bfd_fetch_ifindex(bpc->bpc_localif);
}
}
if (bpc->bpc_local.sa_sin.sin_family != 0
&& (bpc->bpc_local.sa_sin.sin_family
!= bpc->bpc_peer.sa_sin.sin_family)) {
- log_warning("%s: peer family doesn't match local type",
- __func__);
+ log_warning("ptm-read: peer family doesn't match local type");
return -1;
}
if (bs == NULL) {
bs = ptm_bfd_sess_new(&bpc);
if (bs == NULL) {
- log_debug("%s: failed to create BFD session", __func__);
+ log_debug("ptm-add-dest: failed to create BFD session");
return;
}
} else {
/* Create client peer notification register. */
pcn = pcn_new(pc, bs);
if (pcn == NULL) {
- log_error("%s: failed to registrate notifications", __func__);
+ log_error("ptm-add-dest: failed to registrate notifications");
return;
}
/* Find or start new BFD session. */
bs = bs_peer_find(&bpc);
if (bs == NULL) {
- log_debug("%s: failed to create BFD session", __func__);
+ log_debug("ptm-del-dest: failed to find BFD session");
return;
}
pc = pc_new(pid);
if (pc == NULL) {
- log_error("%s: failed to register client: %u", __func__, pid);
+ log_error("ptm-add-client: failed to register client: %u", pid);
return;
}
return;
stream_failure:
- log_error("%s: failed to register client", __func__);
+ log_error("ptm-add-client: failed to register client");
+}
+
+/*
+ * header: command, VRF
+ * l: pid
+ */
+static void bfdd_client_deregister(struct stream *msg)
+{
+ struct ptm_client *pc;
+ uint32_t pid;
+
+ /* Find or allocate process context data. */
+ STREAM_GETL(msg, pid);
+
+ pc = pc_lookup(pid);
+ if (pc == NULL) {
+ log_debug("ptm-del-client: failed to find client: %u", pid);
+ return;
+ }
+
+ pc_free(pc);
+
+ return;
+
+stream_failure:
+ log_error("ptm-del-client: failed to deregister client");
}
static int bfdd_replay(int cmd, struct zclient *zc, uint16_t len, vrf_id_t vid)
case ZEBRA_BFD_CLIENT_REGISTER:
bfdd_client_register(msg);
break;
+ case ZEBRA_BFD_CLIENT_DEREGISTER:
+ bfdd_client_deregister(msg);
+ break;
default:
- log_debug("%s: invalid message type %u", __func__, rcmd);
+ log_debug("ptm-replay: invalid message type %u", rcmd);
return -1;
}
return 0;
stream_failure:
- log_error("%s: failed to find command", __func__);
+ log_error("ptm-replay: failed to find command");
return -1;
}
{
struct stream *msg = zc->obuf;
+ /* Clean-up and free ptm clients data memory. */
+ pc_free_all();
+
/*
* The replay is an empty message just to trigger client daemons
* configuration replay.
void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv)
{
- zclient = zclient_new_notify(master, &zclient_options_default);
+ zclient = zclient_new(master, &zclient_options_default);
assert(zclient != NULL);
zclient_init(zclient, ZEBRA_ROUTE_BFD, 0, bfdd_priv);
void bfdd_zclient_stop(void)
{
zclient_stop(zclient);
+
+ /* Clean-up and free ptm clients data memory. */
+ pc_free_all();
}
return pc;
}
+static void pc_free(struct ptm_client *pc)
+{
+ struct ptm_client_notification *pcn;
+
+ if (pc == NULL)
+ return;
+
+ TAILQ_REMOVE(&pcqueue, pc, pc_entry);
+
+ while (!TAILQ_EMPTY(&pc->pc_pcnqueue)) {
+ pcn = TAILQ_FIRST(&pc->pc_pcnqueue);
+ pcn_free(pcn);
+ }
+
+ XFREE(MTYPE_BFDD_CONTROL, pc);
+}
+
+static void pc_free_all(void)
+{
+ struct ptm_client *pc;
+
+ while (!TAILQ_EMPTY(&pcqueue)) {
+ pc = TAILQ_FIRST(&pcqueue);
+ pc_free(pc);
+ }
+}
+
static struct ptm_client_notification *pcn_new(struct ptm_client *pc,
struct bfd_session *bs)
{