diff options
Diffstat (limited to 'zebra/kernel_netlink.c')
| -rw-r--r-- | zebra/kernel_netlink.c | 127 |
1 files changed, 92 insertions, 35 deletions
diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index e6610f21be..360f596b8f 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -136,6 +136,7 @@ extern uint32_t nl_rcvbufsize; extern struct zebra_privs_t zserv_privs; + int netlink_talk_filter(struct nlmsghdr *h, ns_id_t ns_id, int startup) { /* @@ -313,11 +314,17 @@ bool netlink_read; */ void netlink_read_init(const char *fname) { + struct zebra_dplane_info dp_info; + snprintf(netlink_fuzz_file, MAXPATHLEN, "%s", fname); /* Creating this fake socket for testing purposes */ struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT); - netlink_parse_info(netlink_information_fetch, &zns->netlink, zns, 1, 0); + /* Capture key info from zns struct */ + zebra_dplane_info_from_zns(&dp_info, zns, false); + + netlink_parse_info(netlink_information_fetch, &zns->netlink, + &dp_info, 1, 0); } /** @@ -389,7 +396,7 @@ static int kernel_read(struct thread *thread) /* * Filter out messages from self that occur on listener socket, - * caused by our actions on the command socket + * caused by our actions on the command socket(s) * * When we add new Netlink message types we probably * do not need to add them here as that we are filtering @@ -400,7 +407,7 @@ static int kernel_read(struct thread *thread) * so that we only had to write one way to handle incoming * address add/delete changes. */ -static void netlink_install_filter(int sock, __u32 pid) +static void netlink_install_filter(int sock, __u32 pid, __u32 dplane_pid) { /* * BPF_JUMP instructions and where you jump to are based upon @@ -411,7 +418,8 @@ static void netlink_install_filter(int sock, __u32 pid) struct sock_filter filter[] = { /* * Logic: - * if (nlmsg_pid == pid) { + * if (nlmsg_pid == pid || + * nlmsg_pid == dplane_pid) { * if (the incoming nlmsg_type == * RTM_NEWADDR | RTM_DELADDR) * keep this message @@ -428,26 +436,30 @@ static void netlink_install_filter(int sock, __u32 pid) /* * 1: Compare to pid */ - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htonl(pid), 0, 4), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htonl(pid), 1, 0), + /* + * 2: Compare to dplane pid + */ + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htonl(dplane_pid), 0, 4), /* - * 2: Load the nlmsg_type into BPF register + * 3: Load the nlmsg_type into BPF register */ BPF_STMT(BPF_LD | BPF_ABS | BPF_H, offsetof(struct nlmsghdr, nlmsg_type)), /* - * 3: Compare to RTM_NEWADDR + * 4: Compare to RTM_NEWADDR */ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(RTM_NEWADDR), 2, 0), /* - * 4: Compare to RTM_DELADDR + * 5: Compare to RTM_DELADDR */ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(RTM_DELADDR), 1, 0), /* - * 5: This is the end state of we want to skip the + * 6: This is the end state of we want to skip the * message */ BPF_STMT(BPF_RET | BPF_K, 0), - /* 6: This is the end state of we want to keep + /* 7: This is the end state of we want to keep * the message */ BPF_STMT(BPF_RET | BPF_K, 0xffff), @@ -678,7 +690,8 @@ static void netlink_parse_extended_ack(struct nlmsghdr *h) * the filter. */ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int), - struct nlsock *nl, struct zebra_dplane_info *zns, + const struct nlsock *nl, + const struct zebra_dplane_info *zns, int count, int startup) { int status; @@ -771,7 +784,8 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int), if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) { - zlog_err("%s error: message truncated", + flog_err(EC_ZEBRA_NETLINK_LENGTH_ERROR, + "%s error: message truncated", nl->name); return -1; } @@ -807,14 +821,6 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int), continue; } - if (h->nlmsg_len - < NLMSG_LENGTH(sizeof(struct nlmsgerr))) { - flog_err(EC_ZEBRA_NETLINK_LENGTH_ERROR, - "%s error: message truncated", - nl->name); - return -1; - } - /* Deal with errors that occur because of races * in link handling */ if (zns->is_cmd @@ -919,28 +925,27 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int), } /* - * netlink_talk + * netlink_talk_info * * sendmsg() to netlink socket then recvmsg(). * Calls netlink_parse_info to parse returned data * * filter -> The filter to read final results from kernel * nlmsghdr -> The data to send to the kernel - * nl -> The netlink socket information - * zns -> The zebra namespace information + * dp_info -> The dataplane and netlink socket information * startup -> Are we reading in under startup conditions * This is passed through eventually to filter. */ -int netlink_talk(int (*filter)(struct nlmsghdr *, ns_id_t, int startup), - struct nlmsghdr *n, struct nlsock *nl, struct zebra_ns *zns, - int startup) +int netlink_talk_info(int (*filter)(struct nlmsghdr *, ns_id_t, int startup), + struct nlmsghdr *n, + const struct zebra_dplane_info *dp_info, int startup) { int status = 0; struct sockaddr_nl snl; struct iovec iov; struct msghdr msg; int save_errno = 0; - struct zebra_dplane_info dp_info; + const struct nlsock *nl; memset(&snl, 0, sizeof snl); memset(&iov, 0, sizeof iov); @@ -955,7 +960,8 @@ int netlink_talk(int (*filter)(struct nlmsghdr *, ns_id_t, int startup), snl.nl_family = AF_NETLINK; - n->nlmsg_seq = ++nl->seq; + nl = &(dp_info->nls); + n->nlmsg_seq = nl->seq; n->nlmsg_pid = nl->snl.nl_pid; if (IS_ZEBRA_DEBUG_KERNEL) @@ -982,13 +988,32 @@ int netlink_talk(int (*filter)(struct nlmsghdr *, ns_id_t, int startup), return -1; } - /* * Get reply from netlink socket. * The reply should either be an acknowlegement or an error. */ + return netlink_parse_info(filter, nl, dp_info, 0, startup); +} + +/* + * Synchronous version of netlink_talk_info. Converts args to suit the + * common version, which is suitable for both sync and async use. + */ +int netlink_talk(int (*filter)(struct nlmsghdr *, ns_id_t, int startup), + struct nlmsghdr *n, struct nlsock *nl, struct zebra_ns *zns, + int startup) +{ + struct zebra_dplane_info dp_info; + + /* Increment sequence number before capturing snapshot of ns socket + * info. + */ + nl->seq++; + + /* Capture info in intermediate info struct */ zebra_dplane_info_from_zns(&dp_info, zns, (nl == &(zns->netlink_cmd))); - return netlink_parse_info(filter, nl, &dp_info, 0, startup); + + return netlink_talk_info(filter, n, &dp_info, startup); } /* Issue request message to kernel via netlink socket. GET messages @@ -1075,6 +1100,15 @@ void kernel_init(struct zebra_ns *zns) exit(-1); } + snprintf(zns->netlink_dplane.name, sizeof(zns->netlink_dplane.name), + "netlink-dp (NS %u)", zns->ns_id); + zns->netlink_dplane.sock = -1; + if (netlink_socket(&zns->netlink_dplane, 0, zns->ns_id) < 0) { + zlog_err("Failure to create %s socket", + zns->netlink_dplane.name); + exit(-1); + } + /* * SOL_NETLINK is not available on all platforms yet * apparently. It's in bits/socket.h which I am not @@ -1083,14 +1117,22 @@ void kernel_init(struct zebra_ns *zns) #if defined SOL_NETLINK /* * Let's tell the kernel that we want to receive extended - * ACKS over our command socket + * ACKS over our command socket(s) */ one = 1; ret = setsockopt(zns->netlink_cmd.sock, SOL_NETLINK, NETLINK_EXT_ACK, &one, sizeof(one)); if (ret < 0) - zlog_notice("Registration for extended ACK failed : %d %s", + zlog_notice("Registration for extended cmd ACK failed : %d %s", + errno, safe_strerror(errno)); + + one = 1; + ret = setsockopt(zns->netlink_dplane.sock, SOL_NETLINK, NETLINK_EXT_ACK, + &one, sizeof(one)); + + if (ret < 0) + zlog_notice("Registration for extended dp ACK failed : %d %s", errno, safe_strerror(errno)); #endif @@ -1103,12 +1145,18 @@ void kernel_init(struct zebra_ns *zns) zlog_err("Can't set %s socket error: %s(%d)", zns->netlink_cmd.name, safe_strerror(errno), errno); + if (fcntl(zns->netlink_dplane.sock, F_SETFL, O_NONBLOCK) < 0) + zlog_err("Can't set %s socket error: %s(%d)", + zns->netlink_dplane.name, safe_strerror(errno), errno); + /* Set receive buffer size if it's set from command line */ if (nl_rcvbufsize) netlink_recvbuf(&zns->netlink, nl_rcvbufsize); netlink_install_filter(zns->netlink.sock, - zns->netlink_cmd.snl.nl_pid); + zns->netlink_cmd.snl.nl_pid, + zns->netlink_dplane.snl.nl_pid); + zns->t_netlink = NULL; thread_add_read(zebrad.master, kernel_read, zns, @@ -1117,7 +1165,7 @@ void kernel_init(struct zebra_ns *zns) rt_netlink_init(); } -void kernel_terminate(struct zebra_ns *zns) +void kernel_terminate(struct zebra_ns *zns, bool complete) { THREAD_READ_OFF(zns->t_netlink); @@ -1130,6 +1178,15 @@ void kernel_terminate(struct zebra_ns *zns) close(zns->netlink_cmd.sock); zns->netlink_cmd.sock = -1; } -} + /* During zebra shutdown, we need to leave the dataplane socket + * around until all work is done. + */ + if (complete) { + if (zns->netlink_dplane.sock >= 0) { + close(zns->netlink_dplane.sock); + zns->netlink_dplane.sock = -1; + } + } +} #endif /* HAVE_NETLINK */ |
