1 /* $OpenBSD: adjacency.c,v 1.27 2019/12/12 00:10:29 yasuoka Exp $ */ 2 3 /* 4 * Copyright (c) 2013, 2015 Renato Westphal <renato@openbsd.org> 5 * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> 6 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> 7 * Copyright (c) 2004, 2005, 2008 Esben Norby <norby@openbsd.org> 8 * 9 * Permission to use, copy, modify, and distribute this software for any 10 * purpose with or without fee is hereby granted, provided that the above 11 * copyright notice and this permission notice appear in all copies. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20 */ 21 22 #include <sys/types.h> 23 #include <arpa/inet.h> 24 #include <stdlib.h> 25 #include <string.h> 26 27 #include "ldpd.h" 28 #include "ldpe.h" 29 #include "log.h" 30 31 static void adj_del_single(struct adj *); 32 static void adj_itimer(int, short, void *); 33 static void tnbr_del(struct tnbr *); 34 static void tnbr_hello_timer(int, short, void *); 35 static void tnbr_start_hello_timer(struct tnbr *); 36 static void tnbr_stop_hello_timer(struct tnbr *); 37 38 struct adj * 39 adj_new(struct in_addr lsr_id, struct hello_source *source, 40 union ldpd_addr *addr) 41 { 42 struct adj *adj; 43 44 log_debug("%s: lsr-id %s, %s", __func__, inet_ntoa(lsr_id), 45 log_hello_src(source)); 46 47 if ((adj = calloc(1, sizeof(*adj))) == NULL) 48 fatal(__func__); 49 50 adj->lsr_id = lsr_id; 51 adj->nbr = NULL; 52 adj->source = *source; 53 adj->trans_addr = *addr; 54 55 evtimer_set(&adj->inactivity_timer, adj_itimer, adj); 56 57 LIST_INSERT_HEAD(&global.adj_list, adj, global_entry); 58 59 switch (source->type) { 60 case HELLO_LINK: 61 LIST_INSERT_HEAD(&source->link.ia->adj_list, adj, ia_entry); 62 break; 63 case HELLO_TARGETED: 64 source->target->adj = adj; 65 break; 66 } 67 68 return (adj); 69 } 70 71 static void 72 adj_del_single(struct adj *adj) 73 { 74 log_debug("%s: lsr-id %s, %s (%s)", __func__, inet_ntoa(adj->lsr_id), 75 log_hello_src(&adj->source), af_name(adj_get_af(adj))); 76 77 adj_stop_itimer(adj); 78 79 LIST_REMOVE(adj, global_entry); 80 if (adj->nbr) 81 LIST_REMOVE(adj, nbr_entry); 82 switch (adj->source.type) { 83 case HELLO_LINK: 84 LIST_REMOVE(adj, ia_entry); 85 break; 86 case HELLO_TARGETED: 87 adj->source.target->adj = NULL; 88 break; 89 } 90 91 free(adj); 92 } 93 94 void 95 adj_del(struct adj *adj, uint32_t notif_status) 96 { 97 struct nbr *nbr = adj->nbr; 98 struct adj *atmp; 99 100 adj_del_single(adj); 101 102 /* 103 * If the neighbor still exists but none of its remaining 104 * adjacencies (if any) are from the preferred address-family, 105 * then delete it. 106 */ 107 if (nbr && nbr_adj_count(nbr, nbr->af) == 0) { 108 LIST_FOREACH_SAFE(adj, &nbr->adj_list, nbr_entry, atmp) 109 adj_del_single(adj); 110 session_shutdown(nbr, notif_status, 0, 0); 111 nbr_del(nbr); 112 } 113 } 114 115 struct adj * 116 adj_find(struct hello_source *source) 117 { 118 struct adj *adj; 119 120 LIST_FOREACH(adj, &global.adj_list, global_entry) { 121 if (adj->source.type != source->type) 122 continue; 123 124 if (adj->lsr_id.s_addr != source->lsr_id.s_addr) 125 continue; 126 127 switch (source->type) { 128 case HELLO_LINK: 129 if (ldp_addrcmp(source->link.ia->af, 130 &adj->source.link.src_addr, 131 &source->link.src_addr) == 0) 132 return (adj); 133 break; 134 case HELLO_TARGETED: 135 if (adj->source.target == source->target) 136 return (adj); 137 break; 138 } 139 } 140 141 return (NULL); 142 } 143 144 int 145 adj_get_af(struct adj *adj) 146 { 147 switch (adj->source.type) { 148 case HELLO_LINK: 149 return (adj->source.link.ia->af); 150 case HELLO_TARGETED: 151 return (adj->source.target->af); 152 default: 153 fatalx("adj_get_af: unknown hello type"); 154 } 155 } 156 157 /* adjacency timers */ 158 159 /* ARGSUSED */ 160 static void 161 adj_itimer(int fd, short event, void *arg) 162 { 163 struct adj *adj = arg; 164 165 log_debug("%s: lsr-id %s", __func__, inet_ntoa(adj->lsr_id)); 166 167 if (adj->source.type == HELLO_TARGETED) { 168 if (!(adj->source.target->flags & F_TNBR_CONFIGURED) && 169 adj->source.target->pw_count == 0) { 170 /* remove dynamic targeted neighbor */ 171 tnbr_del(adj->source.target); 172 return; 173 } 174 adj->source.target->adj = NULL; 175 } 176 177 adj_del(adj, S_HOLDTIME_EXP); 178 } 179 180 void 181 adj_start_itimer(struct adj *adj) 182 { 183 struct timeval tv; 184 185 timerclear(&tv); 186 tv.tv_sec = adj->holdtime; 187 if (evtimer_add(&adj->inactivity_timer, &tv) == -1) 188 fatal(__func__); 189 } 190 191 void 192 adj_stop_itimer(struct adj *adj) 193 { 194 if (evtimer_pending(&adj->inactivity_timer, NULL) && 195 evtimer_del(&adj->inactivity_timer) == -1) 196 fatal(__func__); 197 } 198 199 /* targeted neighbors */ 200 201 struct tnbr * 202 tnbr_new(struct ldpd_conf *xconf, int af, union ldpd_addr *addr) 203 { 204 struct tnbr *tnbr; 205 206 if ((tnbr = calloc(1, sizeof(*tnbr))) == NULL) 207 fatal(__func__); 208 209 tnbr->af = af; 210 tnbr->addr = *addr; 211 tnbr->state = TNBR_STA_DOWN; 212 tnbr->hello_holdtime = (ldp_af_conf_get(xconf, af))->thello_holdtime; 213 tnbr->hello_interval = (ldp_af_conf_get(xconf, af))->thello_interval; 214 215 return (tnbr); 216 } 217 218 static void 219 tnbr_del(struct tnbr *tnbr) 220 { 221 tnbr_stop_hello_timer(tnbr); 222 if (tnbr->adj) 223 adj_del(tnbr->adj, S_SHUTDOWN); 224 LIST_REMOVE(tnbr, entry); 225 free(tnbr); 226 } 227 228 struct tnbr * 229 tnbr_find(struct ldpd_conf *xconf, int af, union ldpd_addr *addr) 230 { 231 struct tnbr *tnbr; 232 233 LIST_FOREACH(tnbr, &xconf->tnbr_list, entry) 234 if (af == tnbr->af && 235 ldp_addrcmp(af, addr, &tnbr->addr) == 0) 236 return (tnbr); 237 238 return (NULL); 239 } 240 241 struct tnbr * 242 tnbr_check(struct tnbr *tnbr) 243 { 244 if (!(tnbr->flags & (F_TNBR_CONFIGURED|F_TNBR_DYNAMIC)) && 245 tnbr->pw_count == 0) { 246 tnbr_del(tnbr); 247 return (NULL); 248 } 249 250 return (tnbr); 251 } 252 253 void 254 tnbr_update(struct tnbr *tnbr) 255 { 256 int socket_ok, rtr_id_ok; 257 258 if ((ldp_af_global_get(&global, tnbr->af))->ldp_edisc_socket != -1) 259 socket_ok = 1; 260 else 261 socket_ok = 0; 262 263 if (leconf->rtr_id.s_addr != INADDR_ANY) 264 rtr_id_ok = 1; 265 else 266 rtr_id_ok = 0; 267 268 if (tnbr->state == TNBR_STA_DOWN) { 269 if (!socket_ok || !rtr_id_ok) 270 return; 271 272 tnbr->state = TNBR_STA_ACTIVE; 273 send_hello(HELLO_TARGETED, NULL, tnbr); 274 275 evtimer_set(&tnbr->hello_timer, tnbr_hello_timer, tnbr); 276 tnbr_start_hello_timer(tnbr); 277 } else if (tnbr->state == TNBR_STA_ACTIVE) { 278 if (socket_ok && rtr_id_ok) 279 return; 280 281 tnbr->state = TNBR_STA_DOWN; 282 tnbr_stop_hello_timer(tnbr); 283 } 284 } 285 286 void 287 tnbr_update_all(int af) 288 { 289 struct tnbr *tnbr; 290 291 /* update targeted neighbors */ 292 LIST_FOREACH(tnbr, &leconf->tnbr_list, entry) 293 if (tnbr->af == af || af == AF_UNSPEC) 294 tnbr_update(tnbr); 295 } 296 297 /* target neighbors timers */ 298 299 /* ARGSUSED */ 300 static void 301 tnbr_hello_timer(int fd, short event, void *arg) 302 { 303 struct tnbr *tnbr = arg; 304 305 send_hello(HELLO_TARGETED, NULL, tnbr); 306 tnbr_start_hello_timer(tnbr); 307 } 308 309 static void 310 tnbr_start_hello_timer(struct tnbr *tnbr) 311 { 312 struct timeval tv; 313 314 timerclear(&tv); 315 tv.tv_sec = tnbr->hello_interval; 316 if (evtimer_add(&tnbr->hello_timer, &tv) == -1) 317 fatal(__func__); 318 } 319 320 static void 321 tnbr_stop_hello_timer(struct tnbr *tnbr) 322 { 323 if (evtimer_pending(&tnbr->hello_timer, NULL) && 324 evtimer_del(&tnbr->hello_timer) == -1) 325 fatal(__func__); 326 } 327 328 struct ctl_adj * 329 adj_to_ctl(struct adj *adj) 330 { 331 static struct ctl_adj actl; 332 333 actl.af = adj_get_af(adj); 334 actl.id = adj->lsr_id; 335 actl.type = adj->source.type; 336 switch (adj->source.type) { 337 case HELLO_LINK: 338 memcpy(actl.ifname, adj->source.link.ia->iface->name, 339 sizeof(actl.ifname)); 340 break; 341 case HELLO_TARGETED: 342 actl.src_addr = adj->source.target->addr; 343 break; 344 } 345 actl.holdtime = adj->holdtime; 346 actl.trans_addr = adj->trans_addr; 347 348 return (&actl); 349 } 350