Paul Jakma | 5734509 | 2011-12-25 17:52:09 +0100 | [diff] [blame] | 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 | int |
| 127 | update_neighbour(struct neighbour *neigh, int hello, int hello_interval) |
| 128 | { |
| 129 | int missed_hellos; |
| 130 | int rc = 0; |
| 131 | |
| 132 | if(hello < 0) { |
| 133 | if(neigh->hello_interval <= 0) |
| 134 | return rc; |
| 135 | missed_hellos = |
| 136 | ((int)timeval_minus_msec(&babel_now, &neigh->hello_time) - |
| 137 | neigh->hello_interval * 7) / |
| 138 | (neigh->hello_interval * 10); |
| 139 | if(missed_hellos <= 0) |
| 140 | return rc; |
| 141 | timeval_add_msec(&neigh->hello_time, &neigh->hello_time, |
| 142 | missed_hellos * neigh->hello_interval * 10); |
| 143 | } else { |
| 144 | if(neigh->hello_seqno >= 0 && neigh->reach > 0) { |
| 145 | missed_hellos = seqno_minus(hello, neigh->hello_seqno) - 1; |
| 146 | if(missed_hellos < -8) { |
| 147 | /* Probably a neighbour that rebooted and lost its seqno. |
| 148 | Reboot the universe. */ |
| 149 | neigh->reach = 0; |
| 150 | missed_hellos = 0; |
| 151 | rc = 1; |
| 152 | } else if(missed_hellos < 0) { |
| 153 | if(hello_interval > neigh->hello_interval) { |
| 154 | /* This neighbour has increased its hello interval, |
| 155 | and we didn't notice. */ |
| 156 | neigh->reach <<= -missed_hellos; |
| 157 | missed_hellos = 0; |
| 158 | } else { |
| 159 | /* Late hello. Probably due to the link layer buffering |
| 160 | packets during a link outage. Ignore it, but reset |
| 161 | the expected seqno. */ |
| 162 | neigh->hello_seqno = hello; |
| 163 | hello = -1; |
| 164 | missed_hellos = 0; |
| 165 | } |
| 166 | rc = 1; |
| 167 | } |
| 168 | } else { |
| 169 | missed_hellos = 0; |
| 170 | } |
| 171 | neigh->hello_time = babel_now; |
| 172 | neigh->hello_interval = hello_interval; |
| 173 | } |
| 174 | |
| 175 | if(missed_hellos > 0) { |
| 176 | neigh->reach >>= missed_hellos; |
| 177 | neigh->hello_seqno = seqno_plus(neigh->hello_seqno, missed_hellos); |
| 178 | missed_hellos = 0; |
| 179 | rc = 1; |
| 180 | } |
| 181 | |
| 182 | if(hello >= 0) { |
| 183 | neigh->hello_seqno = hello; |
| 184 | neigh->reach >>= 1; |
| 185 | neigh->reach |= 0x8000; |
| 186 | if((neigh->reach & 0xFC00) != 0xFC00) |
| 187 | rc = 1; |
| 188 | } |
| 189 | |
| 190 | /* Make sure to give neighbours some feedback early after association */ |
| 191 | if((neigh->reach & 0xBF00) == 0x8000) { |
| 192 | /* A new neighbour */ |
| 193 | send_hello(neigh->ifp); |
| 194 | } else { |
| 195 | /* Don't send hellos, in order to avoid a positive feedback loop. */ |
| 196 | int a = (neigh->reach & 0xC000); |
| 197 | int b = (neigh->reach & 0x3000); |
| 198 | if((a == 0xC000 && b == 0) || (a == 0 && b == 0x3000)) { |
| 199 | /* Reachability is either 1100 or 0011 */ |
| 200 | send_self_update(neigh->ifp); |
| 201 | } |
| 202 | } |
| 203 | |
| 204 | if((neigh->reach & 0xFC00) == 0xC000) { |
| 205 | /* This is a newish neighbour, let's request a full route dump. |
| 206 | We ought to avoid this when the network is dense */ |
| 207 | send_unicast_request(neigh, NULL, 0); |
| 208 | send_ihu(neigh, NULL); |
| 209 | } |
| 210 | return rc; |
| 211 | } |
| 212 | |
| 213 | static int |
| 214 | reset_txcost(struct neighbour *neigh) |
| 215 | { |
| 216 | unsigned delay; |
| 217 | |
| 218 | delay = timeval_minus_msec(&babel_now, &neigh->ihu_time); |
| 219 | |
| 220 | if(neigh->ihu_interval > 0 && delay < neigh->ihu_interval * 10 * 3) |
| 221 | return 0; |
| 222 | |
| 223 | /* If we're losing a lot of packets, we probably lost an IHU too */ |
| 224 | if(delay >= 180000 || (neigh->reach & 0xFFF0) == 0 || |
| 225 | (neigh->ihu_interval > 0 && |
| 226 | delay >= neigh->ihu_interval * 10 * 10)) { |
| 227 | neigh->txcost = INFINITY; |
| 228 | neigh->ihu_time = babel_now; |
| 229 | return 1; |
| 230 | } |
| 231 | |
| 232 | return 0; |
| 233 | } |
| 234 | |
| 235 | unsigned |
| 236 | neighbour_txcost(struct neighbour *neigh) |
| 237 | { |
| 238 | return neigh->txcost; |
| 239 | } |
| 240 | |
| 241 | unsigned |
| 242 | check_neighbours() |
| 243 | { |
| 244 | struct neighbour *neigh; |
| 245 | int changed, rc; |
| 246 | unsigned msecs = 50000; |
| 247 | |
| 248 | debugf(BABEL_DEBUG_COMMON,"Checking neighbours."); |
| 249 | |
| 250 | neigh = neighs; |
| 251 | while(neigh) { |
| 252 | changed = update_neighbour(neigh, -1, 0); |
| 253 | |
| 254 | if(neigh->reach == 0 || |
| 255 | neigh->hello_time.tv_sec > babel_now.tv_sec || /* clock stepped */ |
| 256 | timeval_minus_msec(&babel_now, &neigh->hello_time) > 300000) { |
| 257 | struct neighbour *old = neigh; |
| 258 | neigh = neigh->next; |
| 259 | flush_neighbour(old); |
| 260 | continue; |
| 261 | } |
| 262 | |
| 263 | rc = reset_txcost(neigh); |
| 264 | changed = changed || rc; |
| 265 | |
| 266 | update_neighbour_metric(neigh, changed); |
| 267 | |
| 268 | if(neigh->hello_interval > 0) |
| 269 | msecs = MIN(msecs, neigh->hello_interval * 10); |
| 270 | if(neigh->ihu_interval > 0) |
| 271 | msecs = MIN(msecs, neigh->ihu_interval * 10); |
| 272 | neigh = neigh->next; |
| 273 | } |
| 274 | |
| 275 | return msecs; |
| 276 | } |
| 277 | |
| 278 | unsigned |
| 279 | neighbour_rxcost(struct neighbour *neigh) |
| 280 | { |
| 281 | unsigned delay; |
| 282 | unsigned short reach = neigh->reach; |
| 283 | |
| 284 | delay = timeval_minus_msec(&babel_now, &neigh->hello_time); |
| 285 | |
| 286 | if((reach & 0xFFF0) == 0 || delay >= 180000) { |
| 287 | return INFINITY; |
| 288 | } else if(babel_get_if_nfo(neigh->ifp)->flags & BABEL_IF_LQ) { |
| 289 | int sreach = |
| 290 | ((reach & 0x8000) >> 2) + |
| 291 | ((reach & 0x4000) >> 1) + |
| 292 | (reach & 0x3FFF); |
| 293 | /* 0 <= sreach <= 0x7FFF */ |
| 294 | int cost = (0x8000 * babel_get_if_nfo(neigh->ifp)->cost) / (sreach + 1); |
| 295 | /* cost >= interface->cost */ |
| 296 | if(delay >= 40000) |
| 297 | cost = (cost * (delay - 20000) + 10000) / 20000; |
| 298 | return MIN(cost, INFINITY); |
| 299 | } else { |
| 300 | /* To lose one hello is a misfortune, to lose two is carelessness. */ |
| 301 | if((reach & 0xC000) == 0xC000) |
| 302 | return babel_get_if_nfo(neigh->ifp)->cost; |
| 303 | else if((reach & 0xC000) == 0) |
| 304 | return INFINITY; |
| 305 | else if((reach & 0x2000)) |
| 306 | return babel_get_if_nfo(neigh->ifp)->cost; |
| 307 | else |
| 308 | return INFINITY; |
| 309 | } |
| 310 | } |
| 311 | |
| 312 | unsigned |
| 313 | neighbour_cost(struct neighbour *neigh) |
| 314 | { |
| 315 | unsigned a, b; |
| 316 | |
| 317 | if(!if_up(neigh->ifp)) |
| 318 | return INFINITY; |
| 319 | |
| 320 | a = neighbour_txcost(neigh); |
| 321 | |
| 322 | if(a >= INFINITY) |
| 323 | return INFINITY; |
| 324 | |
| 325 | b = neighbour_rxcost(neigh); |
| 326 | if(b >= INFINITY) |
| 327 | return INFINITY; |
| 328 | |
| 329 | if(!(babel_get_if_nfo(neigh->ifp)->flags & BABEL_IF_LQ) |
| 330 | || (a <= 256 && b <= 256)) { |
| 331 | return a; |
| 332 | } else { |
| 333 | /* a = 256/alpha, b = 256/beta, where alpha and beta are the expected |
| 334 | probabilities of a packet getting through in the direct and reverse |
| 335 | directions. */ |
| 336 | a = MAX(a, 256); |
| 337 | b = MAX(b, 256); |
| 338 | /* 1/(alpha * beta), which is just plain ETX. */ |
| 339 | /* Since a and b are capped to 16 bits, overflow is impossible. */ |
| 340 | return (a * b + 128) >> 8; |
| 341 | } |
| 342 | } |