diff options
Diffstat (limited to 'zebra/kernel_netlink.c')
| -rw-r--r-- | zebra/kernel_netlink.c | 362 |
1 files changed, 268 insertions, 94 deletions
diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index d614aa26d0..d84b0c1325 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -36,8 +36,8 @@ #include "vrf.h" #include "mpls.h" #include "lib_errors.h" +#include "hash.h" -//#include "zebra/zserv.h" #include "zebra/zebra_router.h" #include "zebra/zebra_ns.h" #include "zebra/zebra_vrf.h" @@ -47,6 +47,7 @@ #include "zebra/rt_netlink.h" #include "zebra/if_netlink.h" #include "zebra/rule_netlink.h" +#include "zebra/netconf_netlink.h" #include "zebra/zebra_errors.h" #ifndef SO_RCVBUFFORCE @@ -89,8 +90,6 @@ */ #define NL_DEFAULT_BATCH_SEND_THRESHOLD (15 * NL_PKT_BUF_SIZE) -#define NL_BATCH_RX_BUFSIZE NL_RCV_PKT_BUF_SIZE - static const struct message nlmsg_str[] = {{RTM_NEWROUTE, "RTM_NEWROUTE"}, {RTM_DELROUTE, "RTM_DELROUTE"}, {RTM_GETROUTE, "RTM_GETROUTE"}, @@ -109,6 +108,8 @@ static const struct message nlmsg_str[] = {{RTM_NEWROUTE, "RTM_NEWROUTE"}, {RTM_NEWNEXTHOP, "RTM_NEWNEXTHOP"}, {RTM_DELNEXTHOP, "RTM_DELNEXTHOP"}, {RTM_GETNEXTHOP, "RTM_GETNEXTHOP"}, + {RTM_NEWNETCONF, "RTM_NEWNETCONF"}, + {RTM_DELNETCONF, "RTM_DELNETCONF"}, {0}}; static const struct message rtproto_str[] = { @@ -154,17 +155,25 @@ static const struct message rttype_str[] = {{RTN_UNSPEC, "none"}, {0}}; extern struct thread_master *master; -extern uint32_t nl_rcvbufsize; extern struct zebra_privs_t zserv_privs; DEFINE_MTYPE_STATIC(ZEBRA, NL_BUF, "Zebra Netlink buffers"); +/* Hashtable and mutex to allow lookup of nlsock structs by socket/fd value. + * We have both the main and dplane pthreads using these structs, so we have + * to protect the hash with a lock. + */ +static struct hash *nlsock_hash; +pthread_mutex_t nlsock_mutex; + +/* Lock and unlock wrappers for nlsock hash */ +#define NLSOCK_LOCK() pthread_mutex_lock(&nlsock_mutex) +#define NLSOCK_UNLOCK() pthread_mutex_unlock(&nlsock_mutex) + size_t nl_batch_tx_bufsize; char *nl_batch_tx_buf; -char nl_batch_rx_buf[NL_BATCH_RX_BUFSIZE]; - _Atomic uint32_t nl_batch_bufsize = NL_DEFAULT_BATCH_BUFSIZE; _Atomic uint32_t nl_batch_send_threshold = NL_DEFAULT_BATCH_SEND_THRESHOLD; @@ -251,12 +260,11 @@ static int netlink_recvbuf(struct nlsock *nl, uint32_t newsize) /* Try force option (linux >= 2.6.14) and fall back to normal set */ frr_with_privs(&zserv_privs) { ret = setsockopt(nl->sock, SOL_SOCKET, SO_RCVBUFFORCE, - &nl_rcvbufsize, - sizeof(nl_rcvbufsize)); + &rcvbufsize, sizeof(rcvbufsize)); } if (ret < 0) - ret = setsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, - &nl_rcvbufsize, sizeof(nl_rcvbufsize)); + ret = setsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &rcvbufsize, + sizeof(rcvbufsize)); if (ret < 0) { flog_err_sys(EC_LIB_SOCKET, "Can't set %s receive buffer size: %s", nl->name, @@ -318,6 +326,9 @@ static int netlink_socket(struct nlsock *nl, unsigned long groups, nl->snl = snl; nl->sock = sock; + nl->buflen = NL_RCV_PKT_BUF_SIZE; + nl->buf = XMALLOC(MTYPE_NL_BUF, nl->buflen); + return ret; } @@ -362,6 +373,8 @@ static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id, /* Messages handled in the dplane thread */ case RTM_NEWADDR: case RTM_DELADDR: + case RTM_NEWNETCONF: + case RTM_DELNETCONF: return 0; default: @@ -396,7 +409,12 @@ static int dplane_netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id, case RTM_DELADDR: return netlink_interface_addr_dplane(h, ns_id, startup); - /* TODO */ + case RTM_NEWNETCONF: + case RTM_DELNETCONF: + return netlink_netconf_change(h, ns_id, startup); + + /* TODO -- other messages for the dplane socket and pthread */ + case RTM_NEWLINK: case RTM_DELLINK: @@ -407,7 +425,7 @@ static int dplane_netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id, return 0; } -static int kernel_read(struct thread *thread) +static void kernel_read(struct thread *thread) { struct zebra_ns *zns = (struct zebra_ns *)THREAD_ARG(thread); struct zebra_dplane_info dp_info; @@ -420,8 +438,6 @@ static int kernel_read(struct thread *thread) thread_add_read(zrouter.master, kernel_read, zns, zns->netlink.sock, &zns->t_netlink); - - return 0; } /* @@ -429,8 +445,10 @@ static int kernel_read(struct thread *thread) */ int kernel_dplane_read(struct zebra_dplane_info *info) { - netlink_parse_info(dplane_netlink_information_fetch, &info->nls, info, - 5, false); + struct nlsock *nl = kernel_netlink_nlsock_lookup(info->sock); + + netlink_parse_info(dplane_netlink_information_fetch, nl, info, 5, + false); return 0; } @@ -445,8 +463,8 @@ int kernel_dplane_read(struct zebra_dplane_info *info) * then the normal course of operations). We are intentionally * allowing some messages from ourselves through * ( I'm looking at you Interface based netlink messages ) - * so that we only had to write one way to handle incoming - * address add/delete changes. + * so that we only have to write one way to handle incoming + * address add/delete and xxxNETCONF changes. */ static void netlink_install_filter(int sock, uint32_t pid, uint32_t dplane_pid) { @@ -462,7 +480,8 @@ static void netlink_install_filter(int sock, uint32_t pid, uint32_t dplane_pid) * if (nlmsg_pid == pid || * nlmsg_pid == dplane_pid) { * if (the incoming nlmsg_type == - * RTM_NEWADDR | RTM_DELADDR) + * RTM_NEWADDR || RTM_DELADDR || RTM_NEWNETCONF || + * RTM_DELNETCONF) * keep this message * else * skip this message @@ -481,7 +500,7 @@ static void netlink_install_filter(int sock, uint32_t pid, uint32_t dplane_pid) /* * 2: Compare to dplane pid */ - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htonl(dplane_pid), 0, 4), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htonl(dplane_pid), 0, 6), /* * 3: Load the nlmsg_type into BPF register */ @@ -490,17 +509,27 @@ static void netlink_install_filter(int sock, uint32_t pid, uint32_t dplane_pid) /* * 4: Compare to RTM_NEWADDR */ - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(RTM_NEWADDR), 2, 0), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(RTM_NEWADDR), 4, 0), /* * 5: Compare to RTM_DELADDR */ - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(RTM_DELADDR), 1, 0), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(RTM_DELADDR), 3, 0), /* - * 6: This is the end state of we want to skip the + * 6: Compare to RTM_NEWNETCONF + */ + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(RTM_NEWNETCONF), 2, + 0), + /* + * 7: Compare to RTM_DELNETCONF + */ + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(RTM_DELNETCONF), 1, + 0), + /* + * 8: This is the end state of we want to skip the * message */ BPF_STMT(BPF_RET | BPF_K, 0), - /* 7: This is the end state of we want to keep + /* 9: This is the end state of we want to keep * the message */ BPF_STMT(BPF_RET | BPF_K, 0xffff), @@ -781,19 +810,29 @@ static ssize_t netlink_send_msg(const struct nlsock *nl, void *buf, * * Returns -1 on error, 0 if read would block or the number of bytes received. */ -static int netlink_recv_msg(const struct nlsock *nl, struct msghdr msg, - void *buf, size_t buflen) +static int netlink_recv_msg(struct nlsock *nl, struct msghdr *msg) { struct iovec iov; int status; - iov.iov_base = buf; - iov.iov_len = buflen; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; + iov.iov_base = nl->buf; + iov.iov_len = nl->buflen; + msg->msg_iov = &iov; + msg->msg_iovlen = 1; do { - status = recvmsg(nl->sock, &msg, 0); + int bytes; + + bytes = recv(nl->sock, NULL, 0, MSG_PEEK | MSG_TRUNC); + + if (bytes >= 0 && (size_t)bytes > nl->buflen) { + nl->buf = XREALLOC(MTYPE_NL_BUF, nl->buf, bytes); + nl->buflen = bytes; + iov.iov_base = nl->buf; + iov.iov_len = nl->buflen; + } + + status = recvmsg(nl->sock, msg, 0); } while (status == -1 && errno == EINTR); if (status == -1) { @@ -813,19 +852,19 @@ static int netlink_recv_msg(const struct nlsock *nl, struct msghdr msg, return -1; } - if (msg.msg_namelen != sizeof(struct sockaddr_nl)) { + if (msg->msg_namelen != sizeof(struct sockaddr_nl)) { flog_err(EC_ZEBRA_NETLINK_LENGTH_ERROR, "%s sender address length error: length %d", nl->name, - msg.msg_namelen); + msg->msg_namelen); return -1; } if (IS_ZEBRA_DEBUG_KERNEL_MSGDUMP_RECV) { zlog_debug("%s: << netlink message dump [recv]", __func__); #ifdef NETLINK_DEBUG - nl_dump(buf, status); + nl_dump(nl->buf, status); #else - zlog_hexdump(buf, status); + zlog_hexdump(nl->buf, status); #endif /* NETLINK_DEBUG */ } @@ -928,8 +967,7 @@ static int netlink_parse_error(const struct nlsock *nl, struct nlmsghdr *h, * the filter. */ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int), - const struct nlsock *nl, - const struct zebra_dplane_info *zns, + struct nlsock *nl, const struct zebra_dplane_info *zns, int count, bool startup) { int status; @@ -938,7 +976,6 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int), int read_in = 0; while (1) { - char buf[NL_RCV_PKT_BUF_SIZE]; struct sockaddr_nl snl; struct msghdr msg = {.msg_name = (void *)&snl, .msg_namelen = sizeof(snl)}; @@ -947,14 +984,14 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int), if (count && read_in >= count) return 0; - status = netlink_recv_msg(nl, msg, buf, sizeof(buf)); + status = netlink_recv_msg(nl, &msg); if (status == -1) return -1; else if (status == 0) break; read_in++; - for (h = (struct nlmsghdr *)buf; + for (h = (struct nlmsghdr *)nl->buf; (status >= 0 && NLMSG_OK(h, (unsigned int)status)); h = NLMSG_NEXT(h, status)) { /* Finish of reading. */ @@ -1030,15 +1067,15 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int), * startup -> Are we reading in under startup conditions * This is passed through eventually to filter. */ -static int -netlink_talk_info(int (*filter)(struct nlmsghdr *, ns_id_t, int startup), - struct nlmsghdr *n, const struct zebra_dplane_info *dp_info, - bool startup) +static int netlink_talk_info(int (*filter)(struct nlmsghdr *, ns_id_t, + int startup), + struct nlmsghdr *n, + struct zebra_dplane_info *dp_info, bool startup) { - const struct nlsock *nl; + struct nlsock *nl; - nl = &(dp_info->nls); - n->nlmsg_seq = nl->seq; + nl = kernel_netlink_nlsock_lookup(dp_info->sock); + n->nlmsg_seq = dp_info->seq; n->nlmsg_pid = nl->snl.nl_pid; if (IS_ZEBRA_DEBUG_KERNEL) @@ -1109,11 +1146,11 @@ static int nl_batch_read_resp(struct nl_batch *bth) struct sockaddr_nl snl; struct msghdr msg = {}; int status, seq; - const struct nlsock *nl; + struct nlsock *nl; struct zebra_dplane_ctx *ctx; bool ignore_msg; - nl = &(bth->zns->nls); + nl = kernel_netlink_nlsock_lookup(bth->zns->sock); msg.msg_name = (void *)&snl; msg.msg_namelen = sizeof(snl); @@ -1123,12 +1160,28 @@ static int nl_batch_read_resp(struct nl_batch *bth) * message at a time. */ while (true) { - status = netlink_recv_msg(nl, msg, nl_batch_rx_buf, - sizeof(nl_batch_rx_buf)); - if (status == -1 || status == 0) + status = netlink_recv_msg(nl, &msg); + /* + * status == -1 is a full on failure somewhere + * since we don't know where the problem happened + * we must mark all as failed + * + * Else we mark everything as worked + * + */ + if (status == -1 || status == 0) { + while ((ctx = dplane_ctx_dequeue(&(bth->ctx_list))) != + NULL) { + if (status == -1) + dplane_ctx_set_status( + ctx, + ZEBRA_DPLANE_REQUEST_FAILURE); + dplane_ctx_enqueue_tail(bth->ctx_out_q, ctx); + } return status; + } - h = (struct nlmsghdr *)nl_batch_rx_buf; + h = (struct nlmsghdr *)nl->buf; ignore_msg = false; seq = h->nlmsg_seq; /* @@ -1138,22 +1191,25 @@ static int nl_batch_read_resp(struct nl_batch *bth) * requests at same time. */ while (true) { - ctx = dplane_ctx_dequeue(&(bth->ctx_list)); - if (ctx == NULL) - break; - - dplane_ctx_enqueue_tail(bth->ctx_out_q, ctx); - - /* We have found corresponding context object. */ - if (dplane_ctx_get_ns(ctx)->nls.seq == seq) + ctx = dplane_ctx_get_head(&(bth->ctx_list)); + if (ctx == NULL) { + /* + * This is a situation where we have gotten + * into a bad spot. We need to know that + * this happens( does it? ) + */ + zlog_err( + "%s:WARNING Received netlink Response for an error and no Contexts to associate with it", + __func__); break; + } /* * 'update' context objects take two consecutive * sequence numbers. */ - if (dplane_ctx_is_update(ctx) - && dplane_ctx_get_ns(ctx)->nls.seq + 1 == seq) { + if (dplane_ctx_is_update(ctx) && + dplane_ctx_get_ns(ctx)->seq + 1 == seq) { /* * This is the situation where we get a response * to a message that should be ignored. @@ -1161,10 +1217,35 @@ static int nl_batch_read_resp(struct nl_batch *bth) ignore_msg = true; break; } + + ctx = dplane_ctx_dequeue(&(bth->ctx_list)); + dplane_ctx_enqueue_tail(bth->ctx_out_q, ctx); + + /* We have found corresponding context object. */ + if (dplane_ctx_get_ns(ctx)->seq == seq) + break; + + if (dplane_ctx_get_ns(ctx)->seq > seq) + zlog_warn( + "%s:WARNING Received %u is less than any context on the queue ctx->seq %u", + __func__, seq, + dplane_ctx_get_ns(ctx)->seq); } - if (ignore_msg) + if (ignore_msg) { + /* + * If we ignore the message due to an update + * above we should still fricking decode the + * message for our operator to understand + * what is going on + */ + int err = netlink_parse_error(nl, h, bth->zns->is_cmd, + false); + + zlog_debug("%s: netlink error message seq=%d %d", + __func__, h->nlmsg_seq, err); continue; + } /* * We received a message with the sequence number that isn't @@ -1250,13 +1331,15 @@ static void nl_batch_send(struct nl_batch *bth) bool err = false; if (bth->curlen != 0 && bth->zns != NULL) { + struct nlsock *nl = + kernel_netlink_nlsock_lookup(bth->zns->sock); + if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("%s: %s, batch size=%zu, msg cnt=%zu", - __func__, bth->zns->nls.name, bth->curlen, + __func__, nl->name, bth->curlen, bth->msgcnt); - if (netlink_send_msg(&(bth->zns->nls), bth->buf, bth->curlen) - == -1) + if (netlink_send_msg(nl, bth->buf, bth->curlen) == -1) err = true; if (!err) { @@ -1289,6 +1372,7 @@ enum netlink_msg_status netlink_batch_add_msg( int seq; ssize_t size; struct nlmsghdr *msgh; + struct nlsock *nl; size = (*msg_encoder)(ctx, bth->buf_head, bth->bufsiz - bth->curlen); @@ -1315,13 +1399,15 @@ enum netlink_msg_status netlink_batch_add_msg( return FRR_NETLINK_ERROR; } - seq = dplane_ctx_get_ns(ctx)->nls.seq; + seq = dplane_ctx_get_ns(ctx)->seq; + nl = kernel_netlink_nlsock_lookup(dplane_ctx_get_ns_sock(ctx)); + if (ignore_res) seq++; msgh = (struct nlmsghdr *)bth->buf_head; msgh->nlmsg_seq = seq; - msgh->nlmsg_pid = dplane_ctx_get_ns(ctx)->nls.snl.nl_pid; + msgh->nlmsg_pid = nl->snl.nl_pid; bth->zns = dplane_ctx_get_ns(ctx); bth->buf_head = ((char *)bth->buf_head) + size; @@ -1402,6 +1488,7 @@ static enum netlink_msg_status nl_put_msg(struct nl_batch *bth, case DPLANE_OP_INTF_ADDR_ADD: case DPLANE_OP_INTF_ADDR_DEL: + case DPLANE_OP_INTF_NETCONFIG: case DPLANE_OP_NONE: return FRR_NETLINK_ERROR; } @@ -1451,11 +1538,58 @@ void kernel_update_multi(struct dplane_ctx_q *ctx_list) dplane_ctx_list_append(ctx_list, &handled_list); } +struct nlsock *kernel_netlink_nlsock_lookup(int sock) +{ + struct nlsock lookup, *retval; + + lookup.sock = sock; + + NLSOCK_LOCK(); + retval = hash_lookup(nlsock_hash, &lookup); + NLSOCK_UNLOCK(); + + return retval; +} + +/* Insert nlsock entry into hash */ +static void kernel_netlink_nlsock_insert(struct nlsock *nls) +{ + NLSOCK_LOCK(); + (void)hash_get(nlsock_hash, nls, hash_alloc_intern); + NLSOCK_UNLOCK(); +} + +/* Remove nlsock entry from hash */ +static void kernel_netlink_nlsock_remove(struct nlsock *nls) +{ + NLSOCK_LOCK(); + (void)hash_release(nlsock_hash, nls); + NLSOCK_UNLOCK(); +} + +static uint32_t kernel_netlink_nlsock_key(const void *arg) +{ + const struct nlsock *nl = arg; + + return nl->sock; +} + +static bool kernel_netlink_nlsock_hash_equal(const void *arg1, const void *arg2) +{ + const struct nlsock *nl1 = arg1; + const struct nlsock *nl2 = arg2; + + if (nl1->sock == nl2->sock) + return true; + + return false; +} + /* Exported interface function. This function simply calls netlink_socket (). */ void kernel_init(struct zebra_ns *zns) { - uint32_t groups; + uint32_t groups, dplane_groups; #if defined SOL_NETLINK int one, ret; #endif @@ -1480,6 +1614,14 @@ void kernel_init(struct zebra_ns *zns) ((uint32_t) 1 << (RTNLGRP_IPV6_RULE - 1)) | ((uint32_t) 1 << (RTNLGRP_NEXTHOP - 1)); + dplane_groups = (RTMGRP_LINK | + RTMGRP_IPV4_IFADDR | + RTMGRP_IPV6_IFADDR | + ((uint32_t) 1 << (RTNLGRP_IPV4_NETCONF - 1)) | + ((uint32_t) 1 << (RTNLGRP_IPV6_NETCONF - 1)) | + ((uint32_t) 1 << (RTNLGRP_MPLS_NETCONF - 1))); + + snprintf(zns->netlink.name, sizeof(zns->netlink.name), "netlink-listen (NS %u)", zns->ns_id); zns->netlink.sock = -1; @@ -1489,6 +1631,8 @@ void kernel_init(struct zebra_ns *zns) exit(-1); } + kernel_netlink_nlsock_insert(&zns->netlink); + snprintf(zns->netlink_cmd.name, sizeof(zns->netlink_cmd.name), "netlink-cmd (NS %u)", zns->ns_id); zns->netlink_cmd.sock = -1; @@ -1498,6 +1642,8 @@ void kernel_init(struct zebra_ns *zns) exit(-1); } + kernel_netlink_nlsock_insert(&zns->netlink_cmd); + /* Outbound socket for dplane programming of the host OS. */ snprintf(zns->netlink_dplane_out.name, sizeof(zns->netlink_dplane_out.name), "netlink-dp (NS %u)", @@ -1509,17 +1655,22 @@ void kernel_init(struct zebra_ns *zns) exit(-1); } + kernel_netlink_nlsock_insert(&zns->netlink_dplane_out); + /* Inbound socket for OS events coming to the dplane. */ snprintf(zns->netlink_dplane_in.name, sizeof(zns->netlink_dplane_in.name), "netlink-dp-in (NS %u)", zns->ns_id); zns->netlink_dplane_in.sock = -1; - if (netlink_socket(&zns->netlink_dplane_in, groups, zns->ns_id) < 0) { + if (netlink_socket(&zns->netlink_dplane_in, dplane_groups, + zns->ns_id) < 0) { zlog_err("Failure to create %s socket", zns->netlink_dplane_in.name); exit(-1); } + kernel_netlink_nlsock_insert(&zns->netlink_dplane_in); + /* * SOL_NETLINK is not available on all platforms yet * apparently. It's in bits/socket.h which I am not @@ -1579,11 +1730,11 @@ void kernel_init(struct zebra_ns *zns) errno); /* Set receive buffer size if it's set from command line */ - if (nl_rcvbufsize) { - netlink_recvbuf(&zns->netlink, nl_rcvbufsize); - netlink_recvbuf(&zns->netlink_cmd, nl_rcvbufsize); - netlink_recvbuf(&zns->netlink_dplane_out, nl_rcvbufsize); - netlink_recvbuf(&zns->netlink_dplane_in, nl_rcvbufsize); + if (rcvbufsize) { + netlink_recvbuf(&zns->netlink, rcvbufsize); + netlink_recvbuf(&zns->netlink_cmd, rcvbufsize); + netlink_recvbuf(&zns->netlink_dplane_out, rcvbufsize); + netlink_recvbuf(&zns->netlink_dplane_in, rcvbufsize); } /* Set filter for inbound sockets, to exclude events we've generated @@ -1604,33 +1755,56 @@ void kernel_init(struct zebra_ns *zns) rt_netlink_init(); } +/* Helper to clean up an nlsock */ +static void kernel_nlsock_fini(struct nlsock *nls) +{ + if (nls && nls->sock >= 0) { + kernel_netlink_nlsock_remove(nls); + close(nls->sock); + nls->sock = -1; + XFREE(MTYPE_NL_BUF, nls->buf); + nls->buflen = 0; + } +} + void kernel_terminate(struct zebra_ns *zns, bool complete) { thread_cancel(&zns->t_netlink); - if (zns->netlink.sock >= 0) { - close(zns->netlink.sock); - zns->netlink.sock = -1; - } + kernel_nlsock_fini(&zns->netlink); - if (zns->netlink_cmd.sock >= 0) { - close(zns->netlink_cmd.sock); - zns->netlink_cmd.sock = -1; - } + kernel_nlsock_fini(&zns->netlink_cmd); - if (zns->netlink_dplane_in.sock >= 0) { - close(zns->netlink_dplane_in.sock); - zns->netlink_dplane_in.sock = -1; - } + kernel_nlsock_fini(&zns->netlink_dplane_in); /* During zebra shutdown, we need to leave the dataplane socket * around until all work is done. */ - if (complete) { - if (zns->netlink_dplane_out.sock >= 0) { - close(zns->netlink_dplane_out.sock); - zns->netlink_dplane_out.sock = -1; - } - } + if (complete) + kernel_nlsock_fini(&zns->netlink_dplane_out); } + +/* + * Global init for platform-/OS-specific things + */ +void kernel_router_init(void) +{ + /* Init nlsock hash and lock */ + pthread_mutex_init(&nlsock_mutex, NULL); + nlsock_hash = hash_create_size(8, kernel_netlink_nlsock_key, + kernel_netlink_nlsock_hash_equal, + "Netlink Socket Hash"); +} + +/* + * Global deinit for platform-/OS-specific things + */ +void kernel_router_terminate(void) +{ + pthread_mutex_destroy(&nlsock_mutex); + + hash_free(nlsock_hash); + nlsock_hash = NULL; +} + #endif /* HAVE_NETLINK */ |
