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>