📄 link-cache.c
字号:
/* Copyright (C) Uppsala University * * This file is distributed under the terms of the GNU general Public * License (GPL), see the file LICENSE * * Author: Erik Nordström, <erikn@it.uu.se> */#ifdef __KERNEL__#include <linux/proc_fs.h>#include <linux/module.h>#undef DEBUG#endif#ifdef NS2#include "ns-agent.h"#endif/* #include "debug.h" */#include "dsr-rtc.h"#include "dsr-srt.h"#include "tbl.h"#include "link-cache.h"#ifdef __KERNEL__#define DEBUG(f, args...)MODULE_AUTHOR("erik.nordstrom@it.uu.se");MODULE_DESCRIPTION("DSR link cache kernel module");MODULE_LICENSE("GPL");static struct lc_graph LC;#define LC_PROC_NAME "dsr_lc"#endif /* __KERNEL__ */#define LC_NODES_MAX 500#define LC_LINKS_MAX 100 /* TODO: Max links should be calculated from Max * nodes */#ifndef UINT_MAX#define UINT_MAX 4294967295U /* Max for 32-bit integer */#endif#define LC_COST_INF UINT_MAX#define LC_HOPS_INF UINT_MAX#ifdef LC_TIMER#define LC_GARBAGE_COLLECT_INTERVAL 5 * 1000000 /* 5 Seconds */#endif /* LC_TIMER */struct lc_node { list_t l; struct in_addr addr; unsigned int links; unsigned int cost; /* Cost estimate from source when running Dijkstra */ unsigned int hops; /* Number of hops from source. Used to get the * length of the source route to allocate. Same as * cost if cost is hops. */ struct lc_node *pred; /* predecessor */};struct lc_link { list_t l; struct lc_node *src, *dst; int status; unsigned int cost; struct timeval expires;};struct link_query { struct in_addr src, dst;};struct cheapest_node { struct lc_node *n;};#ifdef __KERNEL__static int lc_print(struct lc_graph *LC, char *buf);#endifstatic inline void __lc_link_del(struct lc_graph *lc, struct lc_link *link){ /* Also free the nodes if they lack other links */ if (--link->src->links == 0) __tbl_del(&lc->nodes, &link->src->l); if (--link->dst->links == 0) __tbl_del(&lc->nodes, &link->dst->l); __tbl_del(&lc->links, &link->l);}static inline int crit_addr(void *pos, void *addr){ struct in_addr *a = (struct in_addr *)addr; struct lc_node *p = (struct lc_node *)pos; if (p->addr.s_addr == a->s_addr) return 1; return 0;}static inline int crit_link_query(void *pos, void *query){ struct lc_link *p = (struct lc_link *)pos; struct link_query *q = (struct link_query *)query; if (p->src->addr.s_addr == q->src.s_addr && p->dst->addr.s_addr == q->dst.s_addr) return 1; return 0;}static inline int crit_expire(void *pos, void *data){ struct lc_link *link = (struct lc_link *)pos; struct lc_graph *lc = (struct lc_graph *)data; struct timeval now; gettime(&now); /* printf("ptr=0x%x exp_ptr=0x%x now_ptr=0x%x %s<->%s\n", (unsigned int)link, (unsigned int)&link->expires, (unsigned int)&now, print_ip(link->src->addr), print_ip(link->dst->addr)); *//* fflush(stdout); */ if (timeval_diff(&link->expires, &now) <= 0) { __lc_link_del(lc, link); return 1; } return 0;}static inline int do_lowest_cost(void *pos, void *data){ struct lc_node *n = (struct lc_node *)pos; struct cheapest_node *cn = (struct cheapest_node *)data; if (n->cost != LC_COST_INF && (!cn->n || n->cost < cn->n->cost)) { cn->n = n; } return 0;}static inline int do_relax(void *pos, void *node){ struct lc_link *link = (struct lc_link *)pos; struct lc_node *u = (struct lc_node *)node; struct lc_node *v = link->dst; /* If u and v have a link between them, update cost if cheaper */ if (link->src == u) { unsigned int w = link->cost; if ((u->cost + w) < v->cost) { v->cost = u->cost + w; v->hops = u->hops + 1; v->pred = u; return 1; } } return 0;}static inline int do_init(void *pos, void *addr){ struct in_addr *a = (struct in_addr *)addr; struct lc_node *n = (struct lc_node *)pos; if (!a || !n) return -1; if (n->addr.s_addr == a->s_addr) { n->cost = 0; n->hops = 0; n->pred = n; } else { n->cost = LC_COST_INF; n->hops = LC_HOPS_INF; n->pred = NULL; } return 0;}#ifdef LC_TIMERvoid NSCLASS lc_garbage_collect(unsigned long data){ char buf[204859]; lc_print(&LC, buf);/* printf("#node %d\n%s\n", this->myaddr_.s_addr, buf); *//* fflush(stdout); *//* printf("#end\n"); *//* fflush(stdout); */ tbl_do_for_each(&LC.links, &LC, crit_expire); if (!tbl_empty(&LC.links)) lc_garbage_collect_set();}void NSCLASS lc_garbage_collect_set(void){ DSRUUTimer *lctimer; struct timeval expires;#ifdef NS2 lctimer = &lc_timer;#else lctimer = &LC.timer;#endif lctimer->function = &NSCLASS lc_garbage_collect; lctimer->data = 0; gettime(&expires); timeval_add_usecs(&expires, LC_GARBAGE_COLLECT_INTERVAL); set_timer(lctimer, &expires);}#endif /* LC_TIMER */static inline struct lc_node *lc_node_create(struct in_addr addr){ struct lc_node *n; n = (struct lc_node *)MALLOC(sizeof(struct lc_node), GFP_ATOMIC); if (!n) return NULL; memset(n, 0, sizeof(struct lc_node)); n->addr = addr; n->links = 0; n->cost = LC_COST_INF; n->pred = NULL; return n;};static inline struct lc_link *__lc_link_find(struct tbl *t, struct in_addr src, struct in_addr dst){ struct link_query q = { src, dst }; return (struct lc_link *)__tbl_find(t, &q, crit_link_query);}static int __lc_link_tbl_add(struct tbl *t, struct lc_node *src, struct lc_node *dst, usecs_t timeout, int status, int cost){ struct lc_link *link; int res; if (!src || !dst) return -1; link = (struct lc_link *)__lc_link_find(t, src->addr, dst->addr); if (!link) { link = (struct lc_link *)MALLOC(sizeof(struct lc_link), GFP_ATOMIC); if (!link) return -1; memset(link, 0, sizeof(struct lc_link)); __tbl_add_tail(t, &link->l); link->src = src; link->dst = dst; src->links++; dst->links++; res = 1; } else res = 0; link->status = status; link->cost = cost; gettime(&link->expires); timeval_add_usecs(&link->expires, timeout); return res;}int NSCLASS lc_link_add(struct in_addr src, struct in_addr dst, usecs_t timeout, int status, int cost){ struct lc_node *sn, *dn; int res; DSR_WRITE_LOCK(&LC.lock); sn = (struct lc_node *)__tbl_find(&LC.nodes, &src, crit_addr); if (!sn) { sn = lc_node_create(src); if (!sn) { DEBUG("Could not allocate nodes\n"); DSR_WRITE_UNLOCK(&LC.lock); return -1; } __tbl_add_tail(&LC.nodes, &sn->l); } dn = (struct lc_node *)__tbl_find(&LC.nodes, &dst, crit_addr); if (!dn) { dn = lc_node_create(dst); if (!dn) { DEBUG("Could not allocate nodes\n"); DSR_WRITE_UNLOCK(&LC.lock); return -1; } __tbl_add_tail(&LC.nodes, &dn->l); } res = __lc_link_tbl_add(&LC.links, sn, dn, timeout, status, cost); if (res) {#ifdef LC_TIMER#ifdef NS2 if (!timer_pending(&lc_timer))#else if (!timer_pending(&LC.timer))#endif lc_garbage_collect_set();#endif } else if (res < 0) DEBUG("Could not add new link\n"); DSR_WRITE_UNLOCK(&LC.lock); return 0;}int NSCLASS lc_link_del(struct in_addr src, struct in_addr dst){ struct lc_link *link; int res = 1; DSR_WRITE_LOCK(&LC.lock); link = __lc_link_find(&LC.links, src, dst); if (!link) { res = -1; goto out; } __lc_link_del(&LC, link); /* Assume bidirectional links for now */ link = __lc_link_find(&LC.links, dst, src); if (!link) { res = -1; goto out; } __lc_link_del(&LC, link); out: LC.src = NULL; DSR_WRITE_UNLOCK(&LC.lock); return res;}static inline void__dijkstra_init_single_source(struct tbl *t, struct in_addr src){ __tbl_do_for_each(t, &src, do_init);}static inline struct lc_node *__dijkstra_find_lowest_cost_node(struct tbl *t){ struct cheapest_node cn = { NULL }; __tbl_do_for_each(t, &cn, do_lowest_cost); return cn.n;}/* relax( Node u, Node v, double w[][] ) if d[v] > d[u] + w[u,v] then d[v] := d[u] + w[u,v] pi[v] := u*/static void __lc_move(struct tbl *to, struct tbl *from){ while (!TBL_EMPTY(from)) { struct lc_node *n; n = (struct lc_node *)tbl_detach_first(from); tbl_add_tail(to, &n->l); }}void NSCLASS __dijkstra(struct in_addr src){ TBL(S, LC_NODES_MAX); struct lc_node *src_node, *u; int i = 0; if (TBL_EMPTY(&LC.nodes)) { DEBUG("No nodes in Link Cache\n"); return; } __dijkstra_init_single_source(&LC.nodes, src); src_node = (struct lc_node *)__tbl_find(&LC.nodes, &src, crit_addr); if (!src_node) return; while ((u = __dijkstra_find_lowest_cost_node(&LC.nodes))) { tbl_detach(&LC.nodes, &u->l); /* Add to S */ tbl_add_tail(&S, &u->l); tbl_do_for_each(&LC.links, u, do_relax); i++; } /* Restore the nodes in the LC graph */ /* memcpy(&LC.nodes, &S, sizeof(S)); *//* LC.nodes = S; */ __lc_move(&LC.nodes, &S); /* Set currently calculated source */ LC.src = src_node;}struct dsr_srt *NSCLASS lc_srt_find(struct in_addr src, struct in_addr dst){ struct dsr_srt *srt = NULL; struct lc_node *dst_node; if (src.s_addr == dst.s_addr) return NULL; DSR_WRITE_LOCK(&LC.lock);/* if (!LC.src || LC.src->addr.s_addr != src.s_addr) */ __dijkstra(src); dst_node = (struct lc_node *)__tbl_find(&LC.nodes, &dst, crit_addr); if (!dst_node) { DEBUG("%s not found\n", print_ip(dst)); goto out; }/* lc_print(&LC, lc_print_buf); *//* DEBUG("Find SR to node %s\n%s\n", print_ip(dst_node->addr), lc_print_buf); *//* DEBUG("Hops to %s: %u\n", print_ip(dst), dst_node->hops); */ if (dst_node->cost != LC_COST_INF && dst_node->pred) { struct lc_node *d, *n;/* struct lc_link *l; */ int k = (dst_node->hops - 1); int i = 0; srt = (struct dsr_srt *)MALLOC(sizeof(struct dsr_srt) + (k * sizeof(struct in_addr)), GFP_ATOMIC); if (!srt) { DEBUG("Could not allocate source route!!!\n"); goto out; } srt->dst = dst; srt->src = src; srt->laddrs = k * sizeof(struct in_addr); /* l = __lc_link_find(&LC.links, dst_node->pred->addr, dst_node->addr); *//* if (!l) { *//* DEBUG("Link not found for timeout update!\n"); *//* } else { *//* /\* DEBUG("Updating timeout for link %s->%s\n", *\/ *//* /\* print_ip(l->src->addr), *\/ *//* /\* print_ip(l->dst->addr)); *\/ *//* gettime(&l->expires); *//* } */ d = dst_node; /* Fill in the source route by traversing the nodes starting * from the destination predecessor */ for (n = dst_node->pred; (n != n->pred); n = n->pred) { /* l = __lc_link_find(&LC.links, n->addr, d->addr); *//* if (!l) { *//* DEBUG("Link not found for timeout update!\n"); *//* } else { *//* /\* DEBUG("Updating timeout for link %s->%s\n", *\/ *//* /\* print_ip(l->src->addr), *\/ *//* /\* print_ip(l->dst->addr)); *\/ *//* gettime(&l->expires); *//* } */ srt->addrs[k - i - 1] = n->addr; i++; d = n; } if ((i + 1) != (int)dst_node->hops) { DEBUG("hop count ERROR i+1=%d hops=%d!!!\n", i + 1, dst_node->hops); FREE(srt); srt = NULL; } } out: DSR_WRITE_UNLOCK(&LC.lock); return srt;}int NSCLASSlc_srt_add(struct dsr_srt *srt, usecs_t timeout, unsigned short flags){ int i, n, links = 0; struct in_addr addr1, addr2; if (!srt) return -1; n = srt->laddrs / sizeof(struct in_addr); addr1 = srt->src; for (i = 0; i < n; i++) { addr2 = srt->addrs[i]; lc_link_add(addr1, addr2, timeout, 0, 1); links++; if (srt->flags & SRT_BIDIR) { lc_link_add(addr2, addr1, timeout, 0, 1); links++; } addr1 = addr2; } addr2 = srt->dst; lc_link_add(addr1, addr2, timeout, 0, 1); links++; if (srt->flags & SRT_BIDIR) { lc_link_add(addr2, addr1, timeout, 0, 1); links++; } return links;}int lc_srt_del(struct in_addr src, struct in_addr dst){ return 0;}void NSCLASS lc_flush(void){ DSR_WRITE_LOCK(&LC.lock);#ifdef LC_TIMER#ifdef NS2 if (timer_pending(&lc_timer)) del_timer(&lc_timer);#else if (timer_pending(&LC.timer)) del_timer(&LC.timer);#endif#endif tbl_flush(&LC.links, NULL); tbl_flush(&LC.nodes, NULL); LC.src = NULL; DSR_WRITE_UNLOCK(&LC.lock);}#ifdef __KERNEL__static char *print_hops(unsigned int hops){ static char c[18]; if (hops == LC_HOPS_INF) sprintf(c, "INF"); else sprintf(c, "%u", hops); return c;}static char *print_cost(unsigned int cost){ static char c[18]; if (cost == LC_COST_INF) sprintf(c, "INF"); else sprintf(c, "%u", cost); return c;}static int lc_print(struct lc_graph *LC, char *buf){ list_t *pos; int len = 0; struct timeval now; if (!LC) return 0; gettime(&now); DSR_READ_LOCK(&LC->lock); len += sprintf(buf, "# %-15s %-15s %-4s Timeout\n", "Src Addr", "Dst Addr", "Cost"); list_for_each(pos, &LC->links.head) { struct lc_link *link = (struct lc_link *)pos; len += sprintf(buf + len, " %-15s %-15s %-4u %lu\n", print_ip(link->src->addr), print_ip(link->dst->addr), link->cost, timeval_diff(&link->expires, &now) / 1000000); } len += sprintf(buf + len, "\n# %-15s %-4s %-4s %-5s %12s %12s\n", "Addr", "Hops", "Cost", "Links", "This", "Pred"); list_for_each(pos, &LC->nodes.head) { struct lc_node *n = (struct lc_node *)pos; len += sprintf(buf + len, " %-15s %4s %4s %5u %12lX %12lX\n", print_ip(n->addr), print_hops(n->hops), print_cost(n->cost), n->links, (unsigned long)n, (unsigned long)n->pred); } DSR_READ_UNLOCK(&LC->lock); return len;}static int lc_proc_info(char *buffer, char **start, off_t offset, int length){ int len; len = lc_print(&LC, buffer); *start = buffer + offset; len -= offset; if (len > length) len = length; else if (len < 0) len = 0; return len;}EXPORT_SYMBOL(lc_srt_add);EXPORT_SYMBOL(lc_srt_find);EXPORT_SYMBOL(lc_flush);EXPORT_SYMBOL(lc_link_del);EXPORT_SYMBOL(lc_link_add);module_init(lc_init);module_exit(lc_cleanup);#endif /* __KERNEL__ */int __init NSCLASS lc_init(void){ /* Initialize Graph */ INIT_TBL(&LC.links, LC_LINKS_MAX); INIT_TBL(&LC.nodes, LC_NODES_MAX); LC.src = NULL;#ifdef __KERNEL__ LC.lock = RW_LOCK_UNLOCKED;#ifdef LC_TIMER init_timer(&LC.timer);#endif proc_net_create(LC_PROC_NAME, 0, lc_proc_info);#endif return 0;}void __exit NSCLASS lc_cleanup(void){ lc_flush();#ifdef __KERNEL__ proc_net_remove(LC_PROC_NAME);#endif}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -