From ae8b7d007476ed517c60363ef4073cf7e1e938c1 Mon Sep 17 00:00:00 2001 From: kefren Date: Sat, 20 Jul 2013 05:16:08 +0000 Subject: [PATCH] don't connect on first hello, there are chances that ours is not seen yet setproctitle with ldp id - useful for rump kernels testing fix a memory leak in ldp_peer_new don't holddown if already holded down peer sockets are now non-blocking connected routes deletes are now processed check if peer is connected before attempting to sending label mappings --- usr.sbin/ldpd/fsm.c | 4 +- usr.sbin/ldpd/ldp_peer.c | 76 +++++++++++++++++++------------------ usr.sbin/ldpd/ldp_peer.h | 4 +- usr.sbin/ldpd/mpls_routes.c | 4 +- usr.sbin/ldpd/socketops.c | 17 +++++---- usr.sbin/ldpd/tlv_stack.c | 12 +++--- 6 files changed, 62 insertions(+), 55 deletions(-) diff --git a/usr.sbin/ldpd/fsm.c b/usr.sbin/ldpd/fsm.c index 645a105fceb4..3383cc1815a8 100644 --- a/usr.sbin/ldpd/fsm.c +++ b/usr.sbin/ldpd/fsm.c @@ -1,4 +1,4 @@ -/* $NetBSD: fsm.c,v 1.13 2013/07/12 08:55:52 kefren Exp $ */ +/* $NetBSD: fsm.c,v 1.14 2013/07/20 05:16:08 kefren Exp $ */ /*- * Copyright (c) 2010 The NetBSD Foundation, Inc. @@ -112,6 +112,7 @@ run_ldp_hello(const struct ldp_pdu * pduid, const struct hello_tlv * ht, hi->ldp_id.s_addr = pduid->ldp_id.s_addr; memcpy(&hi->transport_address, &traddr, traddr.sa.sa_len); SLIST_INSERT_HEAD(&hello_info_head, hi, infos); + may_connect = false; } /* Update expire timer */ @@ -236,5 +237,6 @@ set_my_ldp_id() freeifaddrs(ifa); debugp("LDP ID: %s\n", inet_ntoa(a)); strlcpy(my_ldp_id, inet_ntoa(a), INET_ADDRSTRLEN); + setproctitle("LDP ID: %s", my_ldp_id); return LDP_E_OK; } diff --git a/usr.sbin/ldpd/ldp_peer.c b/usr.sbin/ldpd/ldp_peer.c index 9d26fe51d83e..7c865d0cfa3d 100644 --- a/usr.sbin/ldpd/ldp_peer.c +++ b/usr.sbin/ldpd/ldp_peer.c @@ -1,4 +1,4 @@ -/* $NetBSD: ldp_peer.c,v 1.14 2013/07/18 06:07:45 kefren Exp $ */ +/* $NetBSD: ldp_peer.c,v 1.15 2013/07/20 05:16:08 kefren Exp $ */ /* * Copyright (c) 2010 The NetBSD Foundation, Inc. @@ -38,6 +38,7 @@ #include #include +#include #include #include #include @@ -77,12 +78,11 @@ ldp_peer_new(const struct in_addr * ldp_id, const struct sockaddr * padd, const struct sockaddr * tradd, uint16_t holdtime, int soc) { struct ldp_peer *p; - int s = soc; - struct sockaddr *connecting_sa = NULL; + int s = soc, sopts; + union sockunion connecting_su; struct conf_neighbour *cn; - if (tradd != NULL) - assert(tradd->sa_family == padd->sa_family); + assert(tradd == NULL || tradd->sa_family == padd->sa_family); if (soc < 1) { s = socket(PF_INET, SOCK_STREAM, 0); @@ -91,22 +91,20 @@ ldp_peer_new(const struct in_addr * ldp_id, const struct sockaddr * padd, return NULL; } if (tradd != NULL) { - connecting_sa = malloc(tradd->sa_len); - memcpy(connecting_sa, tradd, tradd->sa_len); + assert(tradd->sa_len <= sizeof(connecting_su)); + memcpy(&connecting_su, tradd, tradd->sa_len); } else { - connecting_sa = malloc(padd->sa_len); - memcpy(connecting_sa, padd, padd->sa_len); + assert(padd->sa_len <= sizeof(connecting_su)); + memcpy(&connecting_su, padd, padd->sa_len); } - assert(connecting_sa->sa_family == AF_INET || - connecting_sa->sa_family == AF_INET6); + assert(connecting_su.sa.sa_family == AF_INET || + connecting_su.sa.sa_family == AF_INET6); - if (connecting_sa->sa_family == AF_INET) - ((struct sockaddr_in*)connecting_sa)->sin_port = - htons(LDP_PORT); + if (connecting_su.sa.sa_family == AF_INET) + connecting_su.sin.sin_port = htons(LDP_PORT); else - ((struct sockaddr_in6*)connecting_sa)->sin6_port = - htons(LDP_PORT); + connecting_su.sin6.sin6_port = htons(LDP_PORT); set_ttl(s); } @@ -155,20 +153,23 @@ ldp_peer_new(const struct in_addr * ldp_id, const struct sockaddr * padd, SLIST_INIT(&p->label_mapping_head); p->timeout = p->holdtime; + sopts = fcntl(p->socket, F_GETFL); + if (sopts >= 0) { + sopts |= O_NONBLOCK; + fcntl(p->socket, F_SETFL, &sopts); + } + /* And connect to peer */ - if (soc < 1) - if (connect(s, connecting_sa, connecting_sa->sa_len) == -1) { - if (errno == EINTR) { - free(connecting_sa); - return p; /* We take care of this in - * big_loop */ - } - warnp("connect to %s failed: %s\n", - satos(connecting_sa), strerror(errno)); - free(connecting_sa); - ldp_peer_holddown(p); - return NULL; - } + if (soc < 1 && + connect(s, &connecting_su.sa, connecting_su.sa.sa_len) == -1) { + if (errno == EINTR || errno == EINPROGRESS) + /* We take care of this in big_loop */ + return p; + warnp("connect to %s failed: %s\n", + satos(&connecting_su.sa), strerror(errno)); + ldp_peer_holddown(p); + return NULL; + } p->state = LDP_PEER_CONNECTED; return p; } @@ -176,12 +177,15 @@ ldp_peer_new(const struct in_addr * ldp_id, const struct sockaddr * padd, void ldp_peer_holddown(struct ldp_peer * p) { - if (!p) + + if (!p || p->state == LDP_PEER_HOLDDOWN) return; - if (p->state == LDP_PEER_ESTABLISHED) + if (p->state == LDP_PEER_ESTABLISHED) { + p->state = LDP_PEER_HOLDDOWN; mpls_delete_ldp_peer(p); - p->state = LDP_PEER_HOLDDOWN; - p->timeout = ldp_holddown_time; + } else + p->state = LDP_PEER_HOLDDOWN; + p->timeout = p->holdtime; shutdown(p->socket, SHUT_RDWR); ldp_peer_delete_all_mappings(p); del_all_ifaddr(p); @@ -457,7 +461,7 @@ ldp_peer_delete_mapping(struct ldp_peer * p, const struct sockaddr * a, struct label_mapping *lma; if (!a) - return ldp_peer_delete_all_mappings(p); + return LDP_E_NOENT; lma = ldp_peer_get_lm(p, a, prefix); if (!lma) @@ -486,7 +490,7 @@ ldp_peer_get_lm(const struct ldp_peer * p, const struct sockaddr * a, } -int +void ldp_peer_delete_all_mappings(struct ldp_peer * p) { struct label_mapping *lma; @@ -496,8 +500,6 @@ ldp_peer_delete_all_mappings(struct ldp_peer * p) SLIST_REMOVE_HEAD(&p->label_mapping_head, mappings); free(lma); } - - return LDP_E_OK; } /* returns a mapping and its peer */ diff --git a/usr.sbin/ldpd/ldp_peer.h b/usr.sbin/ldpd/ldp_peer.h index dd05b83f40b3..5ad13a30f678 100644 --- a/usr.sbin/ldpd/ldp_peer.h +++ b/usr.sbin/ldpd/ldp_peer.h @@ -1,4 +1,4 @@ -/* $NetBSD: ldp_peer.h,v 1.6 2013/07/11 05:55:13 kefren Exp $ */ +/* $NetBSD: ldp_peer.h,v 1.7 2013/07/20 05:16:08 kefren Exp $ */ /*- * Copyright (c) 2010 The NetBSD Foundation, Inc. @@ -108,7 +108,7 @@ int ldp_peer_add_mapping(struct ldp_peer *, const struct sockaddr *, int, int); int ldp_peer_delete_mapping(struct ldp_peer *, const struct sockaddr *, int); struct label_mapping * ldp_peer_get_lm(const struct ldp_peer *, const struct sockaddr *, uint); -int ldp_peer_delete_all_mappings(struct ldp_peer *); +void ldp_peer_delete_all_mappings(struct ldp_peer *); void ldp_peer_holddown_all(void); struct peer_map * ldp_test_mapping(const struct sockaddr *, int, diff --git a/usr.sbin/ldpd/mpls_routes.c b/usr.sbin/ldpd/mpls_routes.c index 8eeba84ee370..27ecabd5331d 100644 --- a/usr.sbin/ldpd/mpls_routes.c +++ b/usr.sbin/ldpd/mpls_routes.c @@ -1,4 +1,4 @@ -/* $NetBSD: mpls_routes.c,v 1.18 2013/07/18 11:45:36 kefren Exp $ */ +/* $NetBSD: mpls_routes.c,v 1.19 2013/07/20 05:16:08 kefren Exp $ */ /*- * Copyright (c) 2010 The NetBSD Foundation, Inc. @@ -678,8 +678,6 @@ check_route(struct rt_msg * rg, uint rlen) satos(&so_dest->sa), prefixlen); break; case RTM_DELETE: - if (!so_gate) - break; /* Non-existent route XXX ?! */ /* * Send withdraw check the binding, delete the route, delete * the binding diff --git a/usr.sbin/ldpd/socketops.c b/usr.sbin/ldpd/socketops.c index 9e50749c2b32..c99166a11cd8 100644 --- a/usr.sbin/ldpd/socketops.c +++ b/usr.sbin/ldpd/socketops.c @@ -1,4 +1,4 @@ -/* $NetBSD: socketops.c,v 1.29 2013/07/18 06:07:45 kefren Exp $ */ +/* $NetBSD: socketops.c,v 1.30 2013/07/20 05:16:08 kefren Exp $ */ /* * Copyright (c) 2010 The NetBSD Foundation, Inc. @@ -932,6 +932,7 @@ the_big_loop(void) p = get_ldp_peer_by_socket(pfd[i].fd); if (!p) continue; + assert(p->state == LDP_PEER_CONNECTING); if (getsockopt(pfd[i].fd, SOL_SOCKET, SO_ERROR, &sock_error, &sock_error_size) != 0 || sock_error != 0) { @@ -1078,7 +1079,9 @@ recv_session_pdu(struct ldp_peer * p) memset(recvspace, 0, MAX_PDU_SIZE); - c = recv(p->socket, (void *) recvspace, MAX_PDU_SIZE, MSG_PEEK); + do { + c = recv(p->socket, (void *) recvspace, MAX_PDU_SIZE, MSG_PEEK); + } while (c == -1 && errno == EINTR); debugp("Ready to read %d bytes\n", c); @@ -1097,12 +1100,12 @@ recv_session_pdu(struct ldp_peer * p) return; } rpdu = (struct ldp_pdu *) recvspace; - /* XXX: buggy messages may crash the whole thing */ - c = recv(p->socket, (void *) recvspace, - ntohs(rpdu->length) + PDU_VER_LENGTH, MSG_WAITALL); - rpdu = (struct ldp_pdu *) recvspace; + do { + c = recv(p->socket, (void *) recvspace, + ntohs(rpdu->length) + PDU_VER_LENGTH, MSG_WAITALL); + } while (c == -1 && errno == EINTR); - /* Check if it's somehow OK... */ + /* sanity check */ if (check_recv_pdu(p, rpdu, c) != 0) return; diff --git a/usr.sbin/ldpd/tlv_stack.c b/usr.sbin/ldpd/tlv_stack.c index 095dbbbf7686..0b74b4f5fb8f 100644 --- a/usr.sbin/ldpd/tlv_stack.c +++ b/usr.sbin/ldpd/tlv_stack.c @@ -1,4 +1,4 @@ -/* $NetBSD: tlv_stack.c,v 1.11 2013/07/18 11:45:36 kefren Exp $ */ +/* $NetBSD: tlv_stack.c,v 1.12 2013/07/20 05:16:08 kefren Exp $ */ /*- * Copyright (c) 2010 The NetBSD Foundation, Inc. @@ -209,7 +209,7 @@ withdraw_label(struct ldp_peer * p, struct fec_tlv * f) case FEC_WILDCARD: fatalp("LDP neighbour %s: Wildcard withdraw !!!\n", satos(p->address)); - ldp_peer_delete_mapping(p, NULL, 0); + ldp_peer_delete_all_mappings(p); label_reattach_all_peer_labels(p, REATT_INET_CHANGE); break; default: @@ -222,7 +222,7 @@ withdraw_label(struct ldp_peer * p, struct fec_tlv * f) /* - * In case of label redraw, reuse the same buffer to send label release + * In case of label withdraw, reuse the same buffer to send label release * Simply replace type and message id */ void @@ -322,7 +322,8 @@ send_label_tlv_to_all(const struct sockaddr * addr, uint8_t prefixlen, { struct ldp_peer *p; SLIST_FOREACH(p, &ldp_peer_head, peers) - send_label_tlv(p, addr, prefixlen, label, NULL); + if (p->state == LDP_PEER_ESTABLISHED) + send_label_tlv(p, addr, prefixlen, label, NULL); } /* @@ -400,7 +401,8 @@ send_withdraw_tlv_to_all(const struct sockaddr * addr, uint8_t prefixlen) { struct ldp_peer *p; SLIST_FOREACH(p, &ldp_peer_head, peers) - send_withdraw_tlv(p, addr, prefixlen); + if (p->state == LDP_PEER_ESTABLISHED) + send_withdraw_tlv(p, addr, prefixlen); } int