Commit 01b5c40c authored by Stanislaw Gruszka's avatar Stanislaw Gruszka
Browse files

map-topology: use cmdu_ackq from libieee1905

parent f2e578ef
Pipeline #35515 passed with stages
in 1 minute and 29 seconds
......@@ -4,7 +4,7 @@ CFLAGS+=-I. -D_GNU_SOURCE
CFLAGS+= -g3 -Wall -pthread
OBJS = main.o debug.o config.o json_utils.o nodes.o topo_ieee1905.o topologyd.o mdns_avahi.o
OBJS+= host_nodes.o host_config.o host_utils.o host.o cmdu_ackq.o timer.o
OBJS+= host_nodes.o host_config.o host_utils.o host.o timer.o
LIBS = -lubus -lubox -ljson-c -lblobmsg_json -luci -pthread -leasy -lavahi-core -lavahi-common
LIBS+= -lieee1905 -lmaputil
......
/*
* delm_cmdu_ackq.c
* CMDU response and ack queue management
*
* Copyright (C) 2020 IOPSYS Software Solutions AB. All rights reserved.
*
* Author: anjan.chanda@iopsys.eu
*
* See LICENSE file for license related information.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <libubus.h>
#include <libubox/utils.h>
#include <easy/easy.h>
#include "timer.h"
#include "cmdu_ackq.h"
#include "topologyd.h"
static int timeradd_msecs(struct timeval *a, unsigned long msecs,
struct timeval *res)
{
if (res) {
struct timeval t = { 0 };
if (msecs > 1000) {
t.tv_sec += msecs / 1000;
t.tv_usec = (msecs % 1000) * 1000;
} else {
t.tv_usec = msecs * 1000;
}
timeradd(a, &t, res);
return 0;
}
return -1;
}
struct cmdu_ackq_entry *cmdu_ackq_create_msg(uint16_t type, uint16_t mid,
uint8_t *dest, uint32_t timeout)
{
struct cmdu_ackq_entry *msg;
struct timeval tsp = { 0 };
msg = calloc(1, sizeof(*msg));
if (!msg) {
fprintf(stderr, "calloc failed. err = NOMEM\n");
return NULL;
}
msg->type = type;
msg->mid = mid;
gettimeofday(&tsp, NULL);
msg->ageing_time = timeout;
timeradd_msecs(&tsp, msg->ageing_time, &msg->ageing_tmo);
//msg->ageing_tmo.tv_usec = roundup(msg->ageing_tmo.tv_usec, 1000);
msg->ageing_tmo.tv_usec = (msg->ageing_tmo.tv_usec / 1000) * 1000;
memcpy(msg->origin, dest, 6);
dbg("CREATE msg: type = 0x%04x mid = %hu origin = " MACFMT " timeout = { %u (%lu:%lu) }\n",
type, mid, MAC2STR(dest), msg->ageing_time, msg->ageing_tmo.tv_sec, msg->ageing_tmo.tv_usec / 1000);
return msg;
}
static void cmdu_ackq_delete_msg(struct cmdu_ackq_entry *msg)
{
if (msg)
free(msg);
}
static void cmdu_ackq_ageout_entry(struct cmdu_ackq *st, struct hlist_head *head,
struct timeval *min_next_tmo)
{
//struct delm_private *p = container_of(st,
// struct delm_private, cmdu_ack_q);
//struct wifi_network_device *dev = NULL;
struct topologyd_private *p =
container_of(st, struct topologyd_private, cmdu_ack_q);
struct cmdu_ackq_entry *msg;
struct hlist_node *tmp;
struct timeval now = { 0 };
gettimeofday(&now, NULL);
now.tv_usec = (now.tv_usec / 1000) * 1000;
hlist_for_each_entry_safe(msg, tmp, head, hlist) {
dbg("%s(): Entry msg->ageout = (%lu.%lu), now = (%lu.%lu)\n",
__func__,
msg->ageing_tmo.tv_sec, msg->ageing_tmo.tv_usec,
now.tv_sec, now.tv_usec);
if (timercmp(&msg->ageing_tmo, &now, <=)) {
st->pending_cnt--;
hlist_del(&msg->hlist, head);
dbg("No response from " MACFMT " for CMDU 0x%x with mid = %hu\n",
MAC2STR(msg->origin), msg->type, msg->mid);
/* mark the node as invalid node,
* reduce the pending count & update the datamodel
*/
dbg("response timeout \n");
#if 0
dev = delm_get_origin_dev(p, msg->origin);
if (dev) {
/* TODO/REMOVE:
* mark the node as valid node to show the available data
*/
dev->is_valid_node = true;
//fprintf(stderr, "marking the node as invalid node: "
// MACFMT "\n", MAC2STR(dev->macaddr));
fprintf(stderr, "partial data has been received from this node: "
MACFMT "\n", MAC2STR(dev->macaddr));
if (p->pending <= 0)
delm_update_datamodel(p);
}
#endif
cmdu_ackq_delete_msg(msg);
} else {
struct timeval new_next_tmo = { 0 };
timersub(&msg->ageing_tmo, &now, &new_next_tmo);
if (!timercmp(min_next_tmo, &new_next_tmo, <)) {
min_next_tmo->tv_sec = new_next_tmo.tv_sec;
min_next_tmo->tv_usec = new_next_tmo.tv_usec;
/* fprintf("next-tmo = (%lu.%lu)\n",
* min_next_tmo->tv_sec,
* min_next_tmo->tv_usec);
*/
}
}
}
}
static void cmdu_ackq_ageing_timer_run(atimer_t *t)
{
struct cmdu_ackq *st = container_of(t, struct cmdu_ackq, ageing_timer);
//struct topologyd_private *p =
// container_of(t, struct topologyd_private, ageing_timer);
struct timeval min_next_tmo = { .tv_sec = 999999 };
int remain_cnt = 0;
int i;
struct timeval nu;
gettimeofday(&nu, NULL);
dbg("\n ----Timer now = %lu.%lu --- cnt = %d---\n",
nu.tv_sec, nu.tv_usec, st->pending_cnt);
//spin_lock(&st->hash_lock);
for (i = 0; i < CMDU_BACKLOG_MAX; i++) {
if (hlist_empty(&st->table[i]))
continue;
//fprintf(stderr, "i = %d\t", i);
cmdu_ackq_ageout_entry(st, &st->table[i], &min_next_tmo);
}
remain_cnt = st->pending_cnt;
st->next_tmo.tv_sec = min_next_tmo.tv_sec;
st->next_tmo.tv_usec = min_next_tmo.tv_usec;
//spin_unlock(&st->hash_lock);
if (remain_cnt) {
uint32_t tmo_msecs =
st->next_tmo.tv_sec * 1000 + st->next_tmo.tv_usec / 1000;
/* printf("%s(): remain = %d next_tmo = {(%lu s, %lu us) %u}\n",
__func__, remain_cnt, next_tmo->tv_sec, next_tmo->tv_usec, tmo_msecs); */
if (tmo_msecs > 0)
timer_set(&st->ageing_timer, tmo_msecs);
}
}
int cmdu_ackq_init(void *cmdu_q)
{
struct cmdu_ackq *q = (struct cmdu_ackq *)cmdu_q;
memset(q, 0, sizeof(*q));
pthread_mutex_init(&q->qlock, NULL);
timer_init(&q->ageing_timer, cmdu_ackq_ageing_timer_run);
return 0;
}
struct cmdu_ackq_entry *cmdu_ackq_lookup(void *cmdu_q, uint16_t type,
uint16_t mid, uint8_t *dest)
{
struct cmdu_ackq *q = (struct cmdu_ackq *)cmdu_q;
int idx = cmdu_ackq_hash(type, mid, dest);
struct cmdu_ackq_entry *msg = NULL;
pthread_mutex_lock(&q->qlock);
hlist_for_each_entry(msg, &q->table[idx], hlist) {
if (msg->type == type && msg->mid == mid &&
!memcmp(msg->origin, dest, 6)) {
pthread_mutex_unlock(&q->qlock);
return msg;
}
}
pthread_mutex_unlock(&q->qlock);
return NULL;
}
void cmdu_ackq_reset(void *cmdu_q)
{
struct cmdu_ackq *q = (struct cmdu_ackq *)cmdu_q;
struct cmdu_ackq_entry *msg = NULL;
int idx = 0;
dbg("Resetting CMDU Message Queue..\n");
dbg("*****************************************\n");
pthread_mutex_lock(&q->qlock);
for (idx = 0; idx < CMDU_BACKLOG_MAX; idx++) {
hlist_for_each_entry(msg, &q->table[idx], hlist) {
dbg("idx:%d, type:%d, mid:%d\n", idx, msg->type, msg->mid);
cmdu_ackq_delete_msg(msg);
}
q->table[idx].first = NULL;
}
dbg("*****************************************\n");
q->pending_cnt = 0;
pthread_mutex_unlock(&q->qlock);
}
void cmdu_ackq_free(void *cmdu_q)
{
struct cmdu_ackq *q = (struct cmdu_ackq *)cmdu_q;
cmdu_ackq_reset(q);
timer_del(&q->ageing_timer);
pthread_mutex_destroy(&q->qlock);
}
/* In this function, type = cmdutype that is expected with 'mid' from 'dest' */
int cmdu_ackq_enqueue(void *cmdu_q, uint16_t type, uint16_t mid, uint8_t *dest,
uint32_t timeout)
{
struct cmdu_ackq *q = (struct cmdu_ackq *)cmdu_q;
struct cmdu_ackq_entry *msg = NULL;
msg = cmdu_ackq_lookup(cmdu_q, type, mid, dest);
if (msg) {
dbg("Duplicate: type = 0x%04x mid = %hu origin = " MACFMT "\n",
type, mid, MAC2STR(dest));
return -1;
}
msg = cmdu_ackq_create_msg(type, mid, dest, timeout);
if (msg) {
int idx = cmdu_ackq_hash(type, mid, dest);
pthread_mutex_lock(&q->qlock);
hlist_add_head(&msg->hlist, &q->table[idx]);
q->pending_cnt++;
dbg("ENQ: type = 0x%04x mid = %hu origin = " MACFMT "\n",
type, mid, MAC2STR(dest));
if (timer_pending(&q->ageing_timer)) {
if (timercmp(&q->next_tmo, &msg->ageing_tmo, >)) {
q->next_tmo.tv_sec = msg->ageing_tmo.tv_sec;
q->next_tmo.tv_usec = msg->ageing_tmo.tv_usec;
timer_set(&q->ageing_timer, msg->ageing_time);
dbg("Adjust ageout timer ========>\n");
}
} else {
dbg("Start ageout timer ========>\n");
q->next_tmo.tv_sec = msg->ageing_tmo.tv_sec;
q->next_tmo.tv_usec = msg->ageing_tmo.tv_usec;
timer_set(&q->ageing_timer, msg->ageing_time);
}
pthread_mutex_unlock(&q->qlock);
return 0;
}
return -1;
}
int cmdu_ackq_dequeue(void *cmdu_q, uint16_t type, uint16_t mid, uint8_t *src)
{
struct cmdu_ackq *q = (struct cmdu_ackq *)cmdu_q;
struct cmdu_ackq_entry *msg = NULL;
int idx;
msg = cmdu_ackq_lookup(cmdu_q, type, mid, src);
if (!msg) {
dbg("DROP! CMDU not found: type = 0x%04x mid = %hu origin = " MACFMT "\n",
type, mid, MAC2STR(src));
return -1;
}
idx = cmdu_ackq_hash(type, mid, src);
pthread_mutex_lock(&q->qlock);
hlist_del(&msg->hlist, &q->table[idx]);
q->pending_cnt--;
pthread_mutex_unlock(&q->qlock);
dbg("DEQ: type = 0x%04x mid = %hu origin = " MACFMT "\n",
type, mid, MAC2STR(src));
cmdu_ackq_delete_msg(msg);
return 0;
}
/*
* cmdu_ackq.h
* CMDU pending response and ack queue management
*
* Copyright (C) 2020 IOPSYS Software Solutions AB. All rights reserved.
*
* Author: anjan.chanda@iopsys.eu
*
* See LICENSE file for license related information.
*
*/
#ifndef CMDU_ACKQ_H
#define CMDU_ACKQ_H
#include <easy/easy.h>
#include <wifi.h>
#include "debug.h"
#define CMDU_BACKLOG_MAX 128
#define MAC_ADDR_HASH(a) (a[0] ^ a[1] ^ a[2] ^ a[3] ^ a[4] ^ a[5])
// TODO: improve hash func
#define cmdu_ackq_hash(t, m, o) \
((MAC_ADDR_HASH(o) ^ (t) ^ (m)) & (CMDU_BACKLOG_MAX - 1))
/* struct holds a pending cmdu with 'mid' from 'origin' */
struct cmdu_ackq_entry {
uint16_t type;
uint16_t mid;
uint8_t origin[6];
struct hlist_node hlist;
uint32_t ageing_time; /* in msecs */
struct timeval ageing_tmo;
};
/* queue of cmdus for which response is pending */
struct cmdu_ackq {
pthread_mutex_t qlock;
/* hashtable of pending cmdu_ackq_entry */
struct hlist_head table[CMDU_BACKLOG_MAX];
int pending_cnt;
atimer_t ageing_timer;
struct timeval next_tmo;
};
extern int cmdu_ackq_init(void *q);
extern void cmdu_ackq_free(void *q);
extern void cmdu_ackq_reset(void *q);
extern int cmdu_ackq_dequeue(void *q, uint16_t type, uint16_t mid, uint8_t *src);
extern int cmdu_ackq_enqueue(void *q, uint16_t type, uint16_t mid, uint8_t *dest,
uint32_t timeout);
#endif /* CMDU_ACKQ_H */
......@@ -224,7 +224,7 @@ void topologyd_event_handler(void *c, struct blob_attr *msg)
dbg("Inside %s...DEQUEUE msg_type = [%d] msg_mid = [%d] src =["MACFMT"]\n", __func__,
msg_type, msg_mid, MAC2STR(origin));
ret = cmdu_ackq_dequeue(&priv->cmdu_ack_q, msg_type,
msg_mid, origin);
msg_mid, origin, NULL);
if (ret) {
err("topologyd: drop unexpected CMDU (mid = %d)\n",
msg_mid);
......@@ -2658,7 +2658,7 @@ uint16_t send_cmdu(struct topologyd_private *priv, struct cmdu_buff *cmdu, uint8
if (ret != 0)
goto out;
cmdu_ackq_enqueue(&priv->cmdu_ack_q, resp_type, msgid,
dst, 60000);
dst, 60000, 0, NULL);
dbg("Inside %s...ENQUEUE msg_type = [%d] msg_mid = [%d] src =["MACFMT"]\n", __func__,
resp_type, msgid, MAC2STR(dst));
ret = msgid;
......
......@@ -18,9 +18,9 @@
#include <1905_tlvs.h>
#include <map_module.h>
#include <map2.h>
#include <cmdu_ackq.h>
#include "host.h"
#include "cmdu_ackq.h"
#include "host_config.h"
#define IEEE1905_OBJECT "ieee1905"
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment