-
Notifications
You must be signed in to change notification settings - Fork 8
/
fib.c
180 lines (162 loc) · 5.34 KB
/
fib.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
/*
* Copyright (C) 2016 Wentao Shang
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup net_ndn
* @{
*
* @file
*
* @author Wentao Shang <[email protected]>
*/
#include "fib.h"
#include "encoding/name.h"
#include <debug.h>
#include <utlist.h>
#include <assert.h>
#include <stdlib.h>
static ndn_fib_entry_t *_fib;
static ndn_fib_entry_t* _fib_entry_add_face(ndn_fib_entry_t* entry,
kernel_pid_t id, int type)
{
if (entry->face_list == NULL) {
entry->face_list =
(_face_list_entry_t*)malloc(sizeof(_face_list_entry_t));
if (entry->face_list == NULL) {
DEBUG("ndn: fail to allocate memory for face list\n");
return NULL;
}
entry->face_list_size = 1;
entry->face_list[0].id = id;
entry->face_list[0].type = type;
return entry;
} else {
// check for existing face entry
for (int i = 0; i < entry->face_list_size; ++i) {
if (entry->face_list[i].id == id) {
DEBUG("ndn: same face exists in the fib entry\n");
return entry;
}
}
// need to add a new entry to the face list
_face_list_entry_t *list =
(_face_list_entry_t*)realloc(
entry->face_list,
(entry->face_list_size + 1) * sizeof(_face_list_entry_t));
if (list == NULL) {
DEBUG("ndn: fail to reallocate memory for face list (size=%d)\n",
entry->face_list_size);
return NULL;
}
entry->face_list = list;
entry->face_list[entry->face_list_size].id = id;
entry->face_list[entry->face_list_size].type = type;
++entry->face_list_size;
return entry;
}
}
int ndn_fib_add(ndn_shared_block_t* prefix, kernel_pid_t face_id,
int face_type)
{
assert(prefix != NULL);
int max_plen = -1;
ndn_fib_entry_t *entry, *max = NULL;
bool match_found = false;
DL_FOREACH(_fib, entry) {
int r =
ndn_name_compare_block(&prefix->block, &entry->prefix->block);
if (r == 0) {
// found an entry with identical name
ndn_shared_block_release(prefix);
// add face to fib entry
if (_fib_entry_add_face(entry, face_id, face_type) == NULL) {
DEBUG("ndn: cannot add face %" PRIkernel_pid
" (type=%d) to existing fib entry\n",
face_id, face_type);
return -1;
}
match_found = true;
} else if (r == -2) {
// the prefix to add is a shorter prefix of an existing prefix
// the destination face should be added to the existing entry
// (aka. child inherit)
if (_fib_entry_add_face(entry, face_id, face_type) == NULL) {
DEBUG("ndn: cannot add face %" PRIkernel_pid
" (type=%d) to existing fib entry\n",
face_id, face_type);
return -1;
}
// continue to check other entries
} else if (r == 2) {
// the existing prefix is a shorter prefix of the prefix to add
// track the longest one of such prefixes
if (entry->plen > max_plen) {
max_plen = entry->plen;
max = entry;
}
}
}
if (match_found) {
// no need to create new entry
return 0;
}
// allocate new entry
entry = (ndn_fib_entry_t*)malloc(sizeof(ndn_fib_entry_t));
if (entry == NULL) {
DEBUG("ndn: cannot allocate fib entry\n");
return -1;
}
entry->prefix = prefix; // move semantics
entry->plen = ndn_name_get_size_from_block(&prefix->block);
entry->prev = entry->next = NULL;
entry->face_list = NULL;
entry->face_list_size = 0;
if (NULL == _fib_entry_add_face(entry, face_id, face_type)) {
ndn_shared_block_release(entry->prefix);
free(entry->face_list);
free(entry);
return -1;
}
// inherit faces from the immediate parent (i.e., longest matching prefix)
if (max != NULL) {
for (int i = 0; i < max->face_list_size; ++i) {
if (NULL == _fib_entry_add_face(entry, max->face_list[i].id,
max->face_list[i].type)) {
ndn_shared_block_release(entry->prefix);
free(entry->face_list);
free(entry);
return -1;
}
}
}
DL_PREPEND(_fib, entry);
DEBUG("ndn: add new fib entry (face=%" PRIkernel_pid ","
" face_list_size=%d)\n", face_id, entry->face_list_size);
return 0;
}
ndn_fib_entry_t* ndn_fib_lookup(ndn_block_t* name)
{
int max_plen = -1;
ndn_fib_entry_t *entry, *max = NULL;
DL_FOREACH(_fib, entry) {
int r =
ndn_name_compare_block(&entry->prefix->block, name);
if (r == 0 || r == -2) {
// prefix in this entry matches the name
if (entry->plen > max_plen) {
max_plen = entry->plen;
max = entry;
}
}
}
return max;
}
void ndn_fib_init(void)
{
_fib = NULL;
}
/** @} */