Annotation of embedaddon/quagga/babeld/neighbour.c, revision 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 <stdlib.h>
! 40: #include <string.h>
! 41: #include <stdio.h>
! 42: #include <sys/time.h>
! 43: #include <time.h>
! 44:
! 45: #include <zebra.h>
! 46: #include "if.h"
! 47:
! 48: #include "babel_main.h"
! 49: #include "babeld.h"
! 50: #include "util.h"
! 51: #include "babel_interface.h"
! 52: #include "neighbour.h"
! 53: #include "source.h"
! 54: #include "route.h"
! 55: #include "message.h"
! 56: #include "resend.h"
! 57:
! 58: struct neighbour *neighs = NULL;
! 59:
! 60: static struct neighbour *
! 61: find_neighbour_nocreate(const unsigned char *address, struct interface *ifp)
! 62: {
! 63: struct neighbour *neigh;
! 64: FOR_ALL_NEIGHBOURS(neigh) {
! 65: if(memcmp(address, neigh->address, 16) == 0 &&
! 66: neigh->ifp == ifp)
! 67: return neigh;
! 68: }
! 69: return NULL;
! 70: }
! 71:
! 72: void
! 73: flush_neighbour(struct neighbour *neigh)
! 74: {
! 75: flush_neighbour_routes(neigh);
! 76: if(unicast_neighbour == neigh)
! 77: flush_unicast(1);
! 78: flush_resends(neigh);
! 79:
! 80: if(neighs == neigh) {
! 81: neighs = neigh->next;
! 82: } else {
! 83: struct neighbour *previous = neighs;
! 84: while(previous->next != neigh)
! 85: previous = previous->next;
! 86: previous->next = neigh->next;
! 87: }
! 88: free(neigh);
! 89: }
! 90:
! 91: struct neighbour *
! 92: find_neighbour(const unsigned char *address, struct interface *ifp)
! 93: {
! 94: struct neighbour *neigh;
! 95: const struct timeval zero = {0, 0};
! 96:
! 97: neigh = find_neighbour_nocreate(address, ifp);
! 98: if(neigh)
! 99: return neigh;
! 100:
! 101: debugf(BABEL_DEBUG_COMMON,"Creating neighbour %s on %s.",
! 102: format_address(address), ifp->name);
! 103:
! 104: neigh = malloc(sizeof(struct neighbour));
! 105: if(neigh == NULL) {
! 106: zlog_err("malloc(neighbour): %s", safe_strerror(errno));
! 107: return NULL;
! 108: }
! 109:
! 110: neigh->hello_seqno = -1;
! 111: memcpy(neigh->address, address, 16);
! 112: neigh->reach = 0;
! 113: neigh->txcost = INFINITY;
! 114: neigh->ihu_time = babel_now;
! 115: neigh->hello_time = zero;
! 116: neigh->hello_interval = 0;
! 117: neigh->ihu_interval = 0;
! 118: neigh->ifp = ifp;
! 119: neigh->next = neighs;
! 120: neighs = neigh;
! 121: send_hello(ifp);
! 122: return neigh;
! 123: }
! 124:
! 125: /* Recompute a neighbour's rxcost. Return true if anything changed.
! 126: This does not call local_notify_neighbour, see update_neighbour_metric. */
! 127: int
! 128: update_neighbour(struct neighbour *neigh, int hello, int hello_interval)
! 129: {
! 130: int missed_hellos;
! 131: int rc = 0;
! 132:
! 133: if(hello < 0) {
! 134: if(neigh->hello_interval <= 0)
! 135: return rc;
! 136: missed_hellos =
! 137: ((int)timeval_minus_msec(&babel_now, &neigh->hello_time) -
! 138: neigh->hello_interval * 7) /
! 139: (neigh->hello_interval * 10);
! 140: if(missed_hellos <= 0)
! 141: return rc;
! 142: timeval_add_msec(&neigh->hello_time, &neigh->hello_time,
! 143: missed_hellos * neigh->hello_interval * 10);
! 144: } else {
! 145: if(neigh->hello_seqno >= 0 && neigh->reach > 0) {
! 146: missed_hellos = seqno_minus(hello, neigh->hello_seqno) - 1;
! 147: if(missed_hellos < -8) {
! 148: /* Probably a neighbour that rebooted and lost its seqno.
! 149: Reboot the universe. */
! 150: neigh->reach = 0;
! 151: missed_hellos = 0;
! 152: rc = 1;
! 153: } else if(missed_hellos < 0) {
! 154: if(hello_interval > neigh->hello_interval) {
! 155: /* This neighbour has increased its hello interval,
! 156: and we didn't notice. */
! 157: neigh->reach <<= -missed_hellos;
! 158: missed_hellos = 0;
! 159: } else {
! 160: /* Late hello. Probably due to the link layer buffering
! 161: packets during a link outage. Ignore it, but reset
! 162: the expected seqno. */
! 163: neigh->hello_seqno = hello;
! 164: hello = -1;
! 165: missed_hellos = 0;
! 166: }
! 167: rc = 1;
! 168: }
! 169: } else {
! 170: missed_hellos = 0;
! 171: }
! 172: neigh->hello_time = babel_now;
! 173: neigh->hello_interval = hello_interval;
! 174: }
! 175:
! 176: if(missed_hellos > 0) {
! 177: neigh->reach >>= missed_hellos;
! 178: neigh->hello_seqno = seqno_plus(neigh->hello_seqno, missed_hellos);
! 179: missed_hellos = 0;
! 180: rc = 1;
! 181: }
! 182:
! 183: if(hello >= 0) {
! 184: neigh->hello_seqno = hello;
! 185: neigh->reach >>= 1;
! 186: neigh->reach |= 0x8000;
! 187: if((neigh->reach & 0xFC00) != 0xFC00)
! 188: rc = 1;
! 189: }
! 190:
! 191: /* Make sure to give neighbours some feedback early after association */
! 192: if((neigh->reach & 0xBF00) == 0x8000) {
! 193: /* A new neighbour */
! 194: send_hello(neigh->ifp);
! 195: } else {
! 196: /* Don't send hellos, in order to avoid a positive feedback loop. */
! 197: int a = (neigh->reach & 0xC000);
! 198: int b = (neigh->reach & 0x3000);
! 199: if((a == 0xC000 && b == 0) || (a == 0 && b == 0x3000)) {
! 200: /* Reachability is either 1100 or 0011 */
! 201: send_self_update(neigh->ifp);
! 202: }
! 203: }
! 204:
! 205: if((neigh->reach & 0xFC00) == 0xC000) {
! 206: /* This is a newish neighbour, let's request a full route dump.
! 207: We ought to avoid this when the network is dense */
! 208: send_unicast_request(neigh, NULL, 0);
! 209: send_ihu(neigh, NULL);
! 210: }
! 211: return rc;
! 212: }
! 213:
! 214: static int
! 215: reset_txcost(struct neighbour *neigh)
! 216: {
! 217: unsigned delay;
! 218:
! 219: delay = timeval_minus_msec(&babel_now, &neigh->ihu_time);
! 220:
! 221: if(neigh->ihu_interval > 0 && delay < neigh->ihu_interval * 10U * 3U)
! 222: return 0;
! 223:
! 224: /* If we're losing a lot of packets, we probably lost an IHU too */
! 225: if(delay >= 180000 || (neigh->reach & 0xFFF0) == 0 ||
! 226: (neigh->ihu_interval > 0 &&
! 227: delay >= neigh->ihu_interval * 10U * 10U)) {
! 228: neigh->txcost = INFINITY;
! 229: neigh->ihu_time = babel_now;
! 230: return 1;
! 231: }
! 232:
! 233: return 0;
! 234: }
! 235:
! 236: unsigned
! 237: neighbour_txcost(struct neighbour *neigh)
! 238: {
! 239: return neigh->txcost;
! 240: }
! 241:
! 242: unsigned
! 243: check_neighbours()
! 244: {
! 245: struct neighbour *neigh;
! 246: int changed, rc;
! 247: unsigned msecs = 50000;
! 248:
! 249: debugf(BABEL_DEBUG_COMMON,"Checking neighbours.");
! 250:
! 251: neigh = neighs;
! 252: while(neigh) {
! 253: changed = update_neighbour(neigh, -1, 0);
! 254:
! 255: if(neigh->reach == 0 ||
! 256: neigh->hello_time.tv_sec > babel_now.tv_sec || /* clock stepped */
! 257: timeval_minus_msec(&babel_now, &neigh->hello_time) > 300000) {
! 258: struct neighbour *old = neigh;
! 259: neigh = neigh->next;
! 260: flush_neighbour(old);
! 261: continue;
! 262: }
! 263:
! 264: rc = reset_txcost(neigh);
! 265: changed = changed || rc;
! 266:
! 267: update_neighbour_metric(neigh, changed);
! 268:
! 269: if(neigh->hello_interval > 0)
! 270: msecs = MIN(msecs, neigh->hello_interval * 10U);
! 271: if(neigh->ihu_interval > 0)
! 272: msecs = MIN(msecs, neigh->ihu_interval * 10U);
! 273: neigh = neigh->next;
! 274: }
! 275:
! 276: return msecs;
! 277: }
! 278:
! 279: unsigned
! 280: neighbour_rxcost(struct neighbour *neigh)
! 281: {
! 282: unsigned delay;
! 283: unsigned short reach = neigh->reach;
! 284:
! 285: delay = timeval_minus_msec(&babel_now, &neigh->hello_time);
! 286:
! 287: if((reach & 0xFFF0) == 0 || delay >= 180000) {
! 288: return INFINITY;
! 289: } else if(babel_get_if_nfo(neigh->ifp)->flags & BABEL_IF_LQ) {
! 290: int sreach =
! 291: ((reach & 0x8000) >> 2) +
! 292: ((reach & 0x4000) >> 1) +
! 293: (reach & 0x3FFF);
! 294: /* 0 <= sreach <= 0x7FFF */
! 295: int cost = (0x8000 * babel_get_if_nfo(neigh->ifp)->cost) / (sreach + 1);
! 296: /* cost >= interface->cost */
! 297: if(delay >= 40000)
! 298: cost = (cost * (delay - 20000) + 10000) / 20000;
! 299: return MIN(cost, INFINITY);
! 300: } else {
! 301: /* To lose one hello is a misfortune, to lose two is carelessness. */
! 302: if((reach & 0xC000) == 0xC000)
! 303: return babel_get_if_nfo(neigh->ifp)->cost;
! 304: else if((reach & 0xC000) == 0)
! 305: return INFINITY;
! 306: else if((reach & 0x2000))
! 307: return babel_get_if_nfo(neigh->ifp)->cost;
! 308: else
! 309: return INFINITY;
! 310: }
! 311: }
! 312:
! 313: unsigned
! 314: neighbour_cost(struct neighbour *neigh)
! 315: {
! 316: unsigned a, b;
! 317:
! 318: if(!if_up(neigh->ifp))
! 319: return INFINITY;
! 320:
! 321: a = neighbour_txcost(neigh);
! 322:
! 323: if(a >= INFINITY)
! 324: return INFINITY;
! 325:
! 326: b = neighbour_rxcost(neigh);
! 327: if(b >= INFINITY)
! 328: return INFINITY;
! 329:
! 330: if(!(babel_get_if_nfo(neigh->ifp)->flags & BABEL_IF_LQ)
! 331: || (a < 256 && b < 256)) {
! 332: return a;
! 333: } else {
! 334: /* a = 256/alpha, b = 256/beta, where alpha and beta are the expected
! 335: probabilities of a packet getting through in the direct and reverse
! 336: directions. */
! 337: a = MAX(a, 256);
! 338: b = MAX(b, 256);
! 339: /* 1/(alpha * beta), which is just plain ETX. */
! 340: /* Since a and b are capped to 16 bits, overflow is impossible. */
! 341: return (a * b + 128) >> 8;
! 342: }
! 343: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>