1 /* $OpenBSD: adjacency.c,v 1.3 2013/10/15 20:21:24 renato Exp $ */ 2 3 /* 4 * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> 5 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> 6 * Copyright (c) 2004, 2005, 2008 Esben Norby <norby@openbsd.org> 7 * 8 * Permission to use, copy, modify, and distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 */ 20 21 #include <sys/types.h> 22 #include <sys/socket.h> 23 #include <arpa/inet.h> 24 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <string.h> 28 29 #include "ldpd.h" 30 #include "ldpe.h" 31 #include "control.h" 32 #include "log.h" 33 34 extern struct ldpd_conf *leconf; 35 36 void adj_itimer(int, short, void *); 37 char *print_hello_src(struct hello_source *); 38 39 void tnbr_hello_timer(int, short, void *); 40 void tnbr_start_hello_timer(struct tnbr *); 41 void tnbr_stop_hello_timer(struct tnbr *); 42 43 struct adj * 44 adj_new(struct nbr *nbr, struct hello_source *source, u_int16_t holdtime, 45 struct in_addr addr) 46 { 47 struct adj *adj; 48 49 log_debug("adj_new: LSR ID %s, %s", inet_ntoa(nbr->id), 50 print_hello_src(source)); 51 52 if ((adj = calloc(1, sizeof(*adj))) == NULL) 53 fatal("adj_new"); 54 55 adj->nbr = nbr; 56 memcpy(&adj->source, source, sizeof(*source)); 57 adj->addr = addr; 58 59 evtimer_set(&adj->inactivity_timer, adj_itimer, adj); 60 61 LIST_INSERT_HEAD(&nbr->adj_list, adj, nbr_entry); 62 63 switch (source->type) { 64 case HELLO_LINK: 65 LIST_INSERT_HEAD(&source->link.iface->adj_list, adj, 66 iface_entry); 67 break; 68 case HELLO_TARGETED: 69 source->target->adj = adj; 70 break; 71 } 72 73 return (adj); 74 } 75 76 void 77 adj_del(struct adj *adj) 78 { 79 log_debug("adj_del: LSR ID %s, %s", inet_ntoa(adj->nbr->id), 80 print_hello_src(&adj->source)); 81 82 adj_stop_itimer(adj); 83 84 LIST_REMOVE(adj, nbr_entry); 85 86 /* last adjacency deleted */ 87 if (LIST_EMPTY(&adj->nbr->adj_list)) 88 nbr_del(adj->nbr); 89 90 free(adj); 91 } 92 93 struct adj * 94 adj_find(struct nbr *nbr, struct hello_source *source) 95 { 96 struct adj *adj; 97 98 LIST_FOREACH(adj, &nbr->adj_list, nbr_entry) { 99 if (adj->source.type != source->type) 100 continue; 101 102 switch (source->type) { 103 case HELLO_LINK: 104 if (adj->source.link.src_addr.s_addr == 105 source->link.src_addr.s_addr) 106 return (adj); 107 break; 108 case HELLO_TARGETED: 109 if (adj->source.target == source->target) 110 return (adj); 111 break; 112 } 113 } 114 115 return (NULL); 116 } 117 118 char * 119 print_hello_src(struct hello_source *src) 120 { 121 static char buffer[64]; 122 123 switch (src->type) { 124 case HELLO_LINK: 125 snprintf(buffer, sizeof(buffer), "iface %s", 126 src->link.iface->name); 127 break; 128 case HELLO_TARGETED: 129 snprintf(buffer, sizeof(buffer), "source %s", 130 inet_ntoa(src->target->addr)); 131 break; 132 } 133 134 return (buffer); 135 } 136 137 /* adjacency timers */ 138 139 /* ARGSUSED */ 140 void 141 adj_itimer(int fd, short event, void *arg) 142 { 143 struct adj *adj = arg; 144 145 log_debug("adj_itimer: LDP ID %s", inet_ntoa(adj->nbr->id)); 146 147 switch (adj->source.type) { 148 case HELLO_LINK: 149 LIST_REMOVE(adj, iface_entry); 150 break; 151 case HELLO_TARGETED: 152 adj->source.target->adj = NULL; 153 if (!(adj->source.target->flags & F_TNBR_CONFIGURED)) { 154 LIST_REMOVE(adj->source.target, entry); 155 tnbr_del(adj->source.target); 156 } 157 break; 158 } 159 160 adj_del(adj); 161 } 162 163 void 164 adj_start_itimer(struct adj *adj) 165 { 166 struct timeval tv; 167 168 timerclear(&tv); 169 tv.tv_sec = adj->holdtime; 170 171 if (evtimer_add(&adj->inactivity_timer, &tv) == -1) 172 fatal("adj_start_itimer"); 173 } 174 175 void 176 adj_stop_itimer(struct adj *adj) 177 { 178 if (evtimer_pending(&adj->inactivity_timer, NULL) && 179 evtimer_del(&adj->inactivity_timer) == -1) 180 fatal("adj_stop_itimer"); 181 } 182 183 /* targeted neighbors */ 184 185 struct tnbr * 186 tnbr_new(struct ldpd_conf *xconf, struct in_addr addr, int configured) 187 { 188 struct tnbr *tnbr; 189 190 if ((tnbr = calloc(1, sizeof(*tnbr))) == NULL) 191 fatal("tnbr_new"); 192 193 tnbr->addr.s_addr = addr.s_addr; 194 if (configured) 195 tnbr->flags |= F_TNBR_CONFIGURED; 196 else { 197 tnbr->hello_holdtime = xconf->thello_holdtime; 198 tnbr->hello_interval = xconf->thello_interval; 199 } 200 201 return (tnbr); 202 } 203 204 void 205 tnbr_del(struct tnbr *tnbr) 206 { 207 tnbr_stop_hello_timer(tnbr); 208 if (tnbr->adj) 209 adj_del(tnbr->adj); 210 free(tnbr); 211 } 212 213 void 214 tnbr_init(struct ldpd_conf *xconf, struct tnbr *tnbr) 215 { 216 /* set event handlers for targeted neighbor */ 217 evtimer_set(&tnbr->hello_timer, tnbr_hello_timer, tnbr); 218 219 tnbr->discovery_fd = xconf->ldp_ediscovery_socket; 220 tnbr_start_hello_timer(tnbr); 221 } 222 223 struct tnbr * 224 tnbr_find(struct in_addr addr) 225 { 226 struct tnbr *tnbr; 227 228 LIST_FOREACH(tnbr, &leconf->tnbr_list, entry) 229 if (addr.s_addr == tnbr->addr.s_addr) 230 return (tnbr); 231 232 return (NULL); 233 } 234 235 /* target neighbors timers */ 236 237 /* ARGSUSED */ 238 void 239 tnbr_hello_timer(int fd, short event, void *arg) 240 { 241 struct tnbr *tnbr = arg; 242 struct timeval tv; 243 244 send_hello(HELLO_TARGETED, NULL, tnbr); 245 246 /* reschedule hello_timer */ 247 timerclear(&tv); 248 tv.tv_sec = tnbr->hello_interval; 249 if (evtimer_add(&tnbr->hello_timer, &tv) == -1) 250 fatal("tnbr_hello_timer"); 251 } 252 253 void 254 tnbr_start_hello_timer(struct tnbr *tnbr) 255 { 256 struct timeval tv; 257 258 send_hello(HELLO_TARGETED, NULL, tnbr); 259 260 timerclear(&tv); 261 tv.tv_sec = tnbr->hello_interval; 262 if (evtimer_add(&tnbr->hello_timer, &tv) == -1) 263 fatal("tnbr_start_hello_timer"); 264 } 265 266 void 267 tnbr_stop_hello_timer(struct tnbr *tnbr) 268 { 269 if (evtimer_pending(&tnbr->hello_timer, NULL) && 270 evtimer_del(&tnbr->hello_timer) == -1) 271 fatal("tnbr_stop_hello_timer"); 272 } 273 274 struct ctl_adj * 275 adj_to_ctl(struct adj *adj) 276 { 277 static struct ctl_adj actl; 278 279 actl.id.s_addr = adj->nbr->id.s_addr; 280 actl.type = adj->source.type; 281 switch (adj->source.type) { 282 case HELLO_LINK: 283 memcpy(actl.ifname, adj->source.link.iface->name, 284 sizeof(actl.ifname)); 285 break; 286 case HELLO_TARGETED: 287 actl.src_addr.s_addr = adj->source.target->addr.s_addr; 288 break; 289 } 290 actl.holdtime = adj->holdtime; 291 292 return (&actl); 293 } 294 295 void 296 ldpe_adj_ctl(struct ctl_conn *c) 297 { 298 struct adj *adj; 299 struct iface *iface; 300 struct tnbr *tnbr; 301 struct ctl_adj *actl; 302 303 /* basic discovery mechanism */ 304 LIST_FOREACH(iface, &leconf->iface_list, entry) 305 LIST_FOREACH(adj, &iface->adj_list, iface_entry) { 306 actl = adj_to_ctl(adj); 307 imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISCOVERY, 308 0, 0, -1, actl, sizeof(struct ctl_adj)); 309 } 310 311 /* extended discovery mechanism */ 312 LIST_FOREACH(tnbr, &leconf->tnbr_list, entry) 313 if (tnbr->adj) { 314 actl = adj_to_ctl(tnbr->adj); 315 imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISCOVERY, 316 0, 0, -1, actl, sizeof(struct ctl_adj)); 317 } 318 319 imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0); 320 } 321