Annotation of embedaddon/quagga/babeld/resend.c, revision 1.1.1.1
1.1 misho 1: /*
2: * This file is free software: you may copy, redistribute and/or modify it
3: * under the terms of the GNU General Public License as published by the
4: * Free Software Foundation, either version 2 of the License, or (at your
5: * option) any later version.
6: *
7: * This file is distributed in the hope that it will be useful, but
8: * WITHOUT ANY WARRANTY; without even the implied warranty of
9: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10: * General Public License for more details.
11: *
12: * You should have received a copy of the GNU General Public License
13: * along with this program. If not, see <http://www.gnu.org/licenses/>.
14: *
15: * This file incorporates work covered by the following copyright and
16: * permission notice:
17: *
18: Copyright (c) 2007, 2008 by Juliusz Chroboczek
19:
20: Permission is hereby granted, free of charge, to any person obtaining a copy
21: of this software and associated documentation files (the "Software"), to deal
22: in the Software without restriction, including without limitation the rights
23: to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
24: copies of the Software, and to permit persons to whom the Software is
25: furnished to do so, subject to the following conditions:
26:
27: The above copyright notice and this permission notice shall be included in
28: all copies or substantial portions of the Software.
29:
30: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
31: IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
32: FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
33: AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
34: LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
35: OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
36: THE SOFTWARE.
37: */
38:
39: #include <sys/time.h>
40: #include <time.h>
41: #include <string.h>
42: #include <stdlib.h>
43:
44: #include <zebra.h>
45: #include "if.h"
46:
47: #include "babel_main.h"
48: #include "babeld.h"
49: #include "util.h"
50: #include "neighbour.h"
51: #include "resend.h"
52: #include "message.h"
53: #include "babel_interface.h"
54:
55: struct timeval resend_time = {0, 0};
56: struct resend *to_resend = NULL;
57:
58: static int
59: resend_match(struct resend *resend,
60: int kind, const unsigned char *prefix, unsigned char plen)
61: {
62: return (resend->kind == kind &&
63: resend->plen == plen && memcmp(resend->prefix, prefix, 16) == 0);
64: }
65:
66: /* This is called by neigh.c when a neighbour is flushed */
67:
68: void
69: flush_resends(struct neighbour *neigh)
70: {
71: /* Nothing for now */
72: }
73:
74: static struct resend *
75: find_resend(int kind, const unsigned char *prefix, unsigned char plen,
76: struct resend **previous_return)
77: {
78: struct resend *current, *previous;
79:
80: previous = NULL;
81: current = to_resend;
82: while(current) {
83: if(resend_match(current, kind, prefix, plen)) {
84: if(previous_return)
85: *previous_return = previous;
86: return current;
87: }
88: previous = current;
89: current = current->next;
90: }
91:
92: return NULL;
93: }
94:
95: struct resend *
96: find_request(const unsigned char *prefix, unsigned char plen,
97: struct resend **previous_return)
98: {
99: return find_resend(RESEND_REQUEST, prefix, plen, previous_return);
100: }
101:
102: int
103: record_resend(int kind, const unsigned char *prefix, unsigned char plen,
104: unsigned short seqno, const unsigned char *id,
105: struct interface *ifp, int delay)
106: {
107: struct resend *resend;
108: unsigned int ifindex = ifp ? ifp->ifindex : 0;
109:
110: if((kind == RESEND_REQUEST &&
111: input_filter(NULL, prefix, plen, NULL, ifindex) >= INFINITY) ||
112: (kind == RESEND_UPDATE &&
113: output_filter(NULL, prefix, plen, ifindex) >= INFINITY))
114: return 0;
115:
116: if(delay >= 0xFFFF)
117: delay = 0xFFFF;
118:
119: resend = find_resend(kind, prefix, plen, NULL);
120: if(resend) {
121: if(resend->delay && delay)
122: resend->delay = MIN(resend->delay, delay);
123: else if(delay)
124: resend->delay = delay;
125: resend->time = babel_now;
126: resend->max = RESEND_MAX;
127: if(id && memcmp(resend->id, id, 8) == 0 &&
128: seqno_compare(resend->seqno, seqno) > 0) {
129: return 0;
130: }
131: if(id)
132: memcpy(resend->id, id, 8);
133: else
134: memset(resend->id, 0, 8);
135: resend->seqno = seqno;
136: if(resend->ifp != ifp)
137: resend->ifp = NULL;
138: } else {
139: resend = malloc(sizeof(struct resend));
140: if(resend == NULL)
141: return -1;
142: resend->kind = kind;
143: resend->max = RESEND_MAX;
144: resend->delay = delay;
145: memcpy(resend->prefix, prefix, 16);
146: resend->plen = plen;
147: resend->seqno = seqno;
148: if(id)
149: memcpy(resend->id, id, 8);
150: else
151: memset(resend->id, 0, 8);
152: resend->ifp = ifp;
153: resend->time = babel_now;
154: resend->next = to_resend;
155: to_resend = resend;
156: }
157:
158: if(resend->delay) {
159: struct timeval timeout;
160: timeval_add_msec(&timeout, &resend->time, resend->delay);
161: timeval_min(&resend_time, &timeout);
162: }
163: return 1;
164: }
165:
166: static int
167: resend_expired(struct resend *resend)
168: {
169: switch(resend->kind) {
170: case RESEND_REQUEST:
171: return timeval_minus_msec(&babel_now, &resend->time) >= REQUEST_TIMEOUT;
172: default:
173: return resend->max <= 0;
174: }
175: }
176:
177: int
178: unsatisfied_request(const unsigned char *prefix, unsigned char plen,
179: unsigned short seqno, const unsigned char *id)
180: {
181: struct resend *request;
182:
183: request = find_request(prefix, plen, NULL);
184: if(request == NULL || resend_expired(request))
185: return 0;
186:
187: if(memcmp(request->id, id, 8) != 0 ||
188: seqno_compare(request->seqno, seqno) <= 0)
189: return 1;
190:
191: return 0;
192: }
193:
194: /* Determine whether a given request should be forwarded. */
195: int
196: request_redundant(struct interface *ifp,
197: const unsigned char *prefix, unsigned char plen,
198: unsigned short seqno, const unsigned char *id)
199: {
200: struct resend *request;
201:
202: request = find_request(prefix, plen, NULL);
203: if(request == NULL || resend_expired(request))
204: return 0;
205:
206: if(memcmp(request->id, id, 8) == 0 &&
207: seqno_compare(request->seqno, seqno) > 0)
208: return 0;
209:
210: if(request->ifp != NULL && request->ifp != ifp)
211: return 0;
212:
213: if(request->max > 0)
214: /* Will be resent. */
215: return 1;
216:
217: if(timeval_minus_msec(&babel_now, &request->time) <
218: (ifp ? MIN(babel_get_if_nfo(ifp)->hello_interval, 1000) : 1000))
219: /* Fairly recent. */
220: return 1;
221:
222: return 0;
223: }
224:
225: int
226: satisfy_request(const unsigned char *prefix, unsigned char plen,
227: unsigned short seqno, const unsigned char *id,
228: struct interface *ifp)
229: {
230: struct resend *request, *previous;
231:
232: request = find_request(prefix, plen, &previous);
233: if(request == NULL)
234: return 0;
235:
236: if(ifp != NULL && request->ifp != ifp)
237: return 0;
238:
239: if(memcmp(request->id, id, 8) != 0 ||
240: seqno_compare(request->seqno, seqno) <= 0) {
241: /* We cannot remove the request, as we may be walking the list right
242: now. Mark it as expired, so that expire_resend will remove it. */
243: request->max = 0;
244: request->time.tv_sec = 0;
245: recompute_resend_time();
246: return 1;
247: }
248:
249: return 0;
250: }
251:
252: void
253: expire_resend()
254: {
255: struct resend *current, *previous;
256: int recompute = 0;
257:
258: previous = NULL;
259: current = to_resend;
260: while(current) {
261: if(resend_expired(current)) {
262: if(previous == NULL) {
263: to_resend = current->next;
264: free(current);
265: current = to_resend;
266: } else {
267: previous->next = current->next;
268: free(current);
269: current = previous->next;
270: }
271: recompute = 1;
272: } else {
273: previous = current;
274: current = current->next;
275: }
276: }
277: if(recompute)
278: recompute_resend_time();
279: }
280:
281: void
282: recompute_resend_time()
283: {
284: struct resend *request;
285: struct timeval resend = {0, 0};
286:
287: request = to_resend;
288: while(request) {
289: if(!resend_expired(request) && request->delay > 0 && request->max > 0) {
290: struct timeval timeout;
291: timeval_add_msec(&timeout, &request->time, request->delay);
292: timeval_min(&resend, &timeout);
293: }
294: request = request->next;
295: }
296:
297: resend_time = resend;
298: }
299:
300: void
301: do_resend()
302: {
303: struct resend *resend;
304:
305: resend = to_resend;
306: while(resend) {
307: if(!resend_expired(resend) && resend->delay > 0 && resend->max > 0) {
308: struct timeval timeout;
309: timeval_add_msec(&timeout, &resend->time, resend->delay);
310: if(timeval_compare(&babel_now, &timeout) >= 0) {
311: switch(resend->kind) {
312: case RESEND_REQUEST:
313: send_multihop_request(resend->ifp,
314: resend->prefix, resend->plen,
315: resend->seqno, resend->id, 127);
316: break;
317: case RESEND_UPDATE:
318: send_update(resend->ifp, 1,
319: resend->prefix, resend->plen);
320: break;
321: default: abort();
322: }
323: resend->delay = MIN(0xFFFF, resend->delay * 2);
324: resend->max--;
325: }
326: }
327: resend = resend->next;
328: }
329: recompute_resend_time();
330: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>