diff options
author | Sander Vrijders <[email protected]> | 2017-09-29 13:20:20 +0000 |
---|---|---|
committer | dimitri staessens <[email protected]> | 2017-09-29 13:20:20 +0000 |
commit | 5e974395fadc5e1922f200855c14ca0538ba50dc (patch) | |
tree | bc3808da222d245ab0aecf9d73e22eed5bfb6fd7 /src/ipcpd/normal/pol | |
parent | ddba836eb79ace3bd80ea6af69801f402cbffd20 (diff) | |
parent | 39c7f82f4714f8515860d1c0e2726bff29e22944 (diff) | |
download | ouroboros-5e974395fadc5e1922f200855c14ca0538ba50dc.tar.gz ouroboros-5e974395fadc5e1922f200855c14ca0538ba50dc.zip |
Merged in sandervrijders/ouroboros/be-lfas (pull request #620)
ipcpd: normal: Add Loop-Free Alternates routing
Diffstat (limited to 'src/ipcpd/normal/pol')
-rw-r--r-- | src/ipcpd/normal/pol/graph.c | 199 | ||||
-rw-r--r-- | src/ipcpd/normal/pol/graph.h | 4 | ||||
-rw-r--r-- | src/ipcpd/normal/pol/link_state.c | 76 | ||||
-rw-r--r-- | src/ipcpd/normal/pol/link_state.h | 2 |
4 files changed, 249 insertions, 32 deletions
diff --git a/src/ipcpd/normal/pol/graph.c b/src/ipcpd/normal/pol/graph.c index 9e723737..eade23e0 100644 --- a/src/ipcpd/normal/pol/graph.c +++ b/src/ipcpd/normal/pol/graph.c @@ -379,37 +379,43 @@ static int get_min_vertex(struct graph * graph, return index; } -static struct vertex ** dijkstra(struct graph * graph, - uint64_t src) +static int dijkstra(struct graph * graph, + uint64_t src, + struct vertex *** nhops, + int ** dist) { - int dist[graph->nr_vertices]; bool used[graph->nr_vertices]; struct list_head * p = NULL; int i = 0; struct vertex * v = NULL; struct edge * e = NULL; int alt; - struct vertex ** nhop; - nhop = malloc(sizeof(*nhop) * graph->nr_vertices); - if (nhop == NULL) - return NULL; + *nhops = malloc(sizeof(**nhops) * graph->nr_vertices); + if (*nhops == NULL) + return -1; + + *dist = malloc(sizeof(**dist) * graph->nr_vertices); + if (*dist == NULL) { + free(*nhops); + return -1; + } /* Init the data structures */ list_for_each(p, &graph->vertices) { v = list_entry(p, struct vertex, next); if (v->addr == src) - dist[i] = 0; + (*dist)[i] = 0; else - dist[i] = INT_MAX; + (*dist)[i] = INT_MAX; - nhop[i] = NULL; + (*nhops)[i] = NULL; used[i] = false; i++; } /* Perform actual Dijkstra */ - i = get_min_vertex(graph, dist, used, &v); + i = get_min_vertex(graph, *dist, used, &v); while (v != NULL) { list_for_each(p, &v->edges) { e = list_entry(p, struct edge, next); @@ -423,19 +429,19 @@ static struct vertex ** dijkstra(struct graph * graph, * Method could be extended to use a different * weight for a different QoS cube. */ - alt = dist[i] + 1; - if (alt < dist[e->nb->index]) { - dist[e->nb->index] = alt; + alt = (*dist)[i] + 1; + if (alt < (*dist)[e->nb->index]) { + (*dist)[e->nb->index] = alt; if (v->addr == src) - nhop[e->nb->index] = e->nb; + (*nhops)[e->nb->index] = e->nb; else - nhop[e->nb->index] = nhop[i]; + (*nhops)[e->nb->index] = (*nhops)[i]; } } - i = get_min_vertex(graph, dist, used, &v); + i = get_min_vertex(graph, *dist, used, &v); } - return nhop; + return 0; } static void free_routing_table(struct list_head * table) @@ -471,9 +477,10 @@ void graph_free_routing_table(struct graph * graph, pthread_mutex_unlock(&graph->lock); } -int graph_routing_table(struct graph * graph, - uint64_t s_addr, - struct list_head * table) +static int graph_routing_table_simple(struct graph * graph, + uint64_t s_addr, + struct list_head * table, + int ** dist) { struct vertex ** nhops; struct list_head * p; @@ -482,14 +489,11 @@ int graph_routing_table(struct graph * graph, struct routing_table * t; struct nhop * n; - pthread_mutex_lock(&graph->lock); - /* We need at least 2 vertices for a table */ if (graph->nr_vertices < 2) goto fail_vertices; - nhops = dijkstra(graph, s_addr); - if (nhops == NULL) + if (dijkstra(graph, s_addr, &nhops, dist)) goto fail_vertices; list_head_init(table); @@ -523,8 +527,6 @@ int graph_routing_table(struct graph * graph, i++; } - pthread_mutex_unlock(&graph->lock); - free(nhops); return 0; @@ -535,6 +537,149 @@ int graph_routing_table(struct graph * graph, free_routing_table(table); free(nhops); fail_vertices: + return -1; +} + +int graph_routing_table(struct graph * graph, + uint64_t s_addr, + struct list_head * table) +{ + int ret = 0; + int * dist; + + assert(graph); + assert(table); + + pthread_mutex_lock(&graph->lock); + + ret = graph_routing_table_simple(graph, s_addr, table, &dist); + + free(dist); + pthread_mutex_unlock(&graph->lock); + + return ret; +} + +static int add_lfa_to_table(struct list_head * table, + uint64_t addr, + uint64_t lfa) +{ + struct list_head * p = NULL; + struct nhop * n; + + n = malloc(sizeof(*n)); + if (n == NULL) + return -1; + + n->nhop = lfa; + + list_for_each(p, table) { + struct routing_table * t = + list_entry(p, struct routing_table, next); + if (t->dst == addr) { + list_add_tail(&n->next, &t->nhops); + return 0; + } + } + + return -1; +} + +int graph_routing_table_lfa(struct graph * graph, + uint64_t s_addr, + struct list_head * table) +{ + int * s_dist; + int * n_dist[AP_MAX_FLOWS]; + uint64_t addrs[AP_MAX_FLOWS]; + int n_index[AP_MAX_FLOWS]; + struct list_head * p; + struct list_head * q; + struct vertex * v; + struct edge * e; + struct vertex ** nhops; + int i = 0; + int j = 0; + int k; + + assert(graph); + assert(table); + + pthread_mutex_lock(&graph->lock); + + for (j = 0; j < AP_MAX_FLOWS; j++) { + n_dist[i] = NULL; + n_index[i] = -1; + addrs[i] = -1; + } + + /* Get the normal next hops routing table. */ + if (graph_routing_table_simple(graph, s_addr, table, &s_dist)) + goto fail_table_simple; + + list_for_each(p, &graph->vertices) { + v = list_entry(p, struct vertex, next); + + if (v->addr != s_addr) + continue; + + /* Get the distances for every neighbor of the source. */ + list_for_each(q, &v->edges) { + e = list_entry(q, struct edge, next); + + addrs[i] = e->nb->addr; + n_index[i] = e->nb->index; + if (dijkstra(graph, e->nb->addr, + &nhops, &(n_dist[i++]))) + goto fail_dijkstra; + + free(nhops); + } + + break; + } + + /* Loop though all nodes to see if we have a LFA for them. */ + list_for_each(p, &graph->vertices) { + v = list_entry(p, struct vertex, next); + + if (v->addr == s_addr) + continue; + + /* + * Check for every neighbor if dist(neighbor, destination) < + * dist(neighbor, source) + dist(source, destination). + */ + for (j = 0; j < i; j++) { + /* Exclude ourselves. */ + if (addrs[j] == v->addr) + continue; + + if (n_dist[j][v->index] < + s_dist[n_index[j]] + s_dist[v->index]) { + if (add_lfa_to_table(table, v->addr, addrs[j])) + goto fail_add_lfa; + } + + free(n_dist[j]); + } + } + + pthread_mutex_unlock(&graph->lock); + + free(s_dist); + + return 0; + + fail_add_lfa: + for (k = j; k < i; k++) + free(n_dist[k]); + fail_dijkstra: + free_routing_table(table); + free(s_dist); + fail_table_simple: + pthread_mutex_unlock(&graph->lock); + return -1; } diff --git a/src/ipcpd/normal/pol/graph.h b/src/ipcpd/normal/pol/graph.h index 7340ecb9..66c8f780 100644 --- a/src/ipcpd/normal/pol/graph.h +++ b/src/ipcpd/normal/pol/graph.h @@ -56,6 +56,10 @@ int graph_routing_table(struct graph * graph, uint64_t s_addr, struct list_head * table); +int graph_routing_table_lfa(struct graph * graph, + uint64_t s_addr, + struct list_head * table); + void graph_free_routing_table(struct graph * graph, struct list_head * table); diff --git a/src/ipcpd/normal/pol/link_state.c b/src/ipcpd/normal/pol/link_state.c index 51d317bc..f3af2771 100644 --- a/src/ipcpd/normal/pol/link_state.c +++ b/src/ipcpd/normal/pol/link_state.c @@ -62,8 +62,10 @@ typedef LinkStateMsg link_state_msg_t; #endif struct routing_i { - struct pff * pff; - pthread_t calculator; + struct list_head next; + + struct pff * pff; + pthread_t calculator; }; /* TODO: link weight support. */ @@ -89,6 +91,10 @@ struct nb { enum nb_type type; }; +typedef int (* rtable_fn_t)(struct graph * graph, + uint64_t s_addr, + struct list_head * table); + struct { struct list_head nbs; fset_t * mgmt_set; @@ -103,6 +109,11 @@ struct { pthread_t lsupdate; pthread_t lsreader; pthread_t listener; + + struct list_head routing_instances; + pthread_mutex_t routing_i_lock; + + rtable_fn_t rtable; } ls; struct pol_routing_ops link_state_ops = { @@ -388,7 +399,7 @@ static void * calculate_pff(void * o) instance = (struct routing_i *) o; while (true) { - if (graph_routing_table(ls.graph, ipcpi.dt_addr, &table)) { + if (ls.rtable(ls.graph, ipcpi.dt_addr, &table)) { sleep(RECALC_TIME); continue; } @@ -584,6 +595,24 @@ static void * lsreader(void * o) return (void *) 0; } +static void flow_event(int fd, + bool up) +{ + + struct list_head * p; + + log_dbg("Notifying routing instances of flow event."); + + pthread_mutex_lock(&ls.routing_i_lock); + + list_for_each(p, &ls.routing_instances) { + struct routing_i * ri = list_entry(p, struct routing_i, next); + pff_flow_state_change(ri->pff, fd, up); + } + + pthread_mutex_unlock(&ls.routing_i_lock); +} + static void handle_event(void * self, int event, const void * o) @@ -608,6 +637,8 @@ static void handle_event(void * self, send_lsm(ipcpi.dt_addr, c->conn_info.addr); break; case NOTIFY_DT_CONN_DEL: + flow_event(c->flow_info.fd, false); + if (lsdb_del_nb(c->conn_info.addr, c->flow_info.fd)) log_dbg("Failed to delete neighbor from LSDB."); @@ -617,6 +648,12 @@ static void handle_event(void * self, case NOTIFY_DT_CONN_QOS: log_dbg("QoS changes currently unsupported."); break; + case NOTIFY_DT_CONN_UP: + flow_event(c->flow_info.fd, true); + break; + case NOTIFY_DT_CONN_DOWN: + flow_event(c->flow_info.fd, false); + break; case NOTIFY_MGMT_CONN_ADD: fset_add(ls.mgmt_set, c->flow_info.fd); if (lsdb_add_nb(c->conn_info.addr, c->flow_info.fd, NB_MGMT)) @@ -650,6 +687,12 @@ struct routing_i * link_state_routing_i_create(struct pff * pff) return NULL; } + pthread_mutex_lock(&ls.routing_i_lock); + + list_add(&tmp->next, &ls.routing_instances); + + pthread_mutex_unlock(&ls.routing_i_lock); + return tmp; } @@ -657,6 +700,12 @@ void link_state_routing_i_destroy(struct routing_i * instance) { assert(instance); + pthread_mutex_lock(&ls.routing_i_lock); + + list_del(&instance->next); + + pthread_mutex_unlock(&ls.routing_i_lock); + pthread_cancel(instance->calculator); pthread_join(instance->calculator, NULL); @@ -664,7 +713,7 @@ void link_state_routing_i_destroy(struct routing_i * instance) free(instance); } -int link_state_init(void) +int link_state_init(enum pol_routing pr) { struct conn_info info; @@ -676,6 +725,17 @@ int link_state_init(void) info.pref_syntax = PROTO_GPB; info.addr = ipcpi.dt_addr; + switch (pr) { + case ROUTING_LINK_STATE: + ls.rtable = graph_routing_table; + break; + case ROUTING_LINK_STATE_LFA: + ls.rtable = graph_routing_table_lfa; + break; + default: + goto fail_graph; + } + ls.graph = graph_create(); if (ls.graph == NULL) goto fail_graph; @@ -686,6 +746,9 @@ int link_state_init(void) if (pthread_rwlock_init(&ls.db_lock, NULL)) goto fail_db_lock_init; + if (pthread_mutex_init(&ls.routing_i_lock, NULL)) + goto fail_routing_i_lock_init; + if (connmgr_ae_init(AEID_MGMT, &info)) goto fail_connmgr_ae_init; @@ -695,6 +758,7 @@ int link_state_init(void) list_head_init(&ls.db); list_head_init(&ls.nbs); + list_head_init(&ls.routing_instances); if (pthread_create(&ls.lsupdate, NULL, lsupdate, NULL)) goto fail_pthread_create_lsupdate; @@ -722,6 +786,8 @@ int link_state_init(void) fail_fset_create: connmgr_ae_fini(AEID_MGMT); fail_connmgr_ae_init: + pthread_mutex_destroy(&ls.routing_i_lock); + fail_routing_i_lock_init: pthread_rwlock_destroy(&ls.db_lock); fail_db_lock_init: notifier_unreg(handle_event); @@ -765,5 +831,7 @@ void link_state_fini(void) pthread_rwlock_destroy(&ls.db_lock); + pthread_mutex_destroy(&ls.routing_i_lock); + notifier_unreg(handle_event); } diff --git a/src/ipcpd/normal/pol/link_state.h b/src/ipcpd/normal/pol/link_state.h index 58f90d91..cfdeb09d 100644 --- a/src/ipcpd/normal/pol/link_state.h +++ b/src/ipcpd/normal/pol/link_state.h @@ -28,7 +28,7 @@ #include "pol-routing-ops.h" -int link_state_init(void); +int link_state_init(enum pol_routing pr); void link_state_fini(void); |