diff options
Diffstat (limited to 'zebra/kernel_netlink.c')
| -rw-r--r-- | zebra/kernel_netlink.c | 94 |
1 files changed, 88 insertions, 6 deletions
diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index 35f3274c65..7e47822a2c 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -289,7 +289,7 @@ static int netlink_recvbuf(struct nlsock *nl, uint32_t newsize) /* Make socket for Linux netlink interface. */ static int netlink_socket(struct nlsock *nl, unsigned long groups, - ns_id_t ns_id) + unsigned long ext_groups, ns_id_t ns_id) { int ret; struct sockaddr_nl snl; @@ -308,6 +308,19 @@ static int netlink_socket(struct nlsock *nl, unsigned long groups, snl.nl_family = AF_NETLINK; snl.nl_groups = groups; +#if defined SOL_NETLINK + if (ext_groups) { + ret = setsockopt(sock, SOL_NETLINK, + NETLINK_ADD_MEMBERSHIP, &ext_groups, + sizeof(ext_groups)); + if (ret < 0) { + zlog_notice( + "can't setsockopt NETLINK_ADD_MEMBERSHIP: %s(%d)", + safe_strerror(errno), errno); + } + } +#endif + /* Bind the socket to the netlink structure for anything. */ ret = bind(sock, (struct sockaddr *)&snl, sizeof(snl)); } @@ -587,6 +600,21 @@ void netlink_parse_rtattr_nested(struct rtattr **tb, int max, netlink_parse_rtattr(tb, max, RTA_DATA(rta), RTA_PAYLOAD(rta)); } +bool nl_addraw_l(struct nlmsghdr *n, unsigned int maxlen, const void *data, + unsigned int len) +{ + if (NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len) > maxlen) { + zlog_err("ERROR message exceeded bound of %d", maxlen); + return false; + } + + memcpy(NLMSG_TAIL(n), data, len); + memset((uint8_t *)NLMSG_TAIL(n) + len, 0, NLMSG_ALIGN(len) - len); + n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len); + + return true; +} + bool nl_attr_put(struct nlmsghdr *n, unsigned int maxlen, int type, const void *data, unsigned int alen) { @@ -667,6 +695,58 @@ void nl_attr_rtnh_end(struct nlmsghdr *n, struct rtnexthop *rtnh) rtnh->rtnh_len = (uint8_t *)NLMSG_TAIL(n) - (uint8_t *)rtnh; } +bool nl_rta_put(struct rtattr *rta, unsigned int maxlen, int type, + const void *data, int alen) +{ + struct rtattr *subrta; + int len = RTA_LENGTH(alen); + + if (RTA_ALIGN(rta->rta_len) + RTA_ALIGN(len) > maxlen) { + zlog_err("ERROR max allowed bound %d exceeded for rtattr", + maxlen); + return false; + } + subrta = (struct rtattr *)(((char *)rta) + RTA_ALIGN(rta->rta_len)); + subrta->rta_type = type; + subrta->rta_len = len; + if (alen) + memcpy(RTA_DATA(subrta), data, alen); + rta->rta_len = NLMSG_ALIGN(rta->rta_len) + RTA_ALIGN(len); + + return true; +} + +bool nl_rta_put16(struct rtattr *rta, unsigned int maxlen, int type, + uint16_t data) +{ + return nl_rta_put(rta, maxlen, type, &data, sizeof(uint16_t)); +} + +bool nl_rta_put64(struct rtattr *rta, unsigned int maxlen, int type, + uint64_t data) +{ + return nl_rta_put(rta, maxlen, type, &data, sizeof(uint64_t)); +} + +struct rtattr *nl_rta_nest(struct rtattr *rta, unsigned int maxlen, int type) +{ + struct rtattr *nest = RTA_TAIL(rta); + + if (nl_rta_put(rta, maxlen, type, NULL, 0)) + return NULL; + + nest->rta_type |= NLA_F_NESTED; + + return nest; +} + +int nl_rta_nest_end(struct rtattr *rta, struct rtattr *nest) +{ + nest->rta_len = (uint8_t *)RTA_TAIL(rta) - (uint8_t *)nest; + + return rta->rta_len; +} + const char *nl_msg_type_to_str(uint16_t msg_type) { return lookup_msg(nlmsg_str, msg_type, ""); @@ -1611,7 +1691,7 @@ static bool kernel_netlink_nlsock_hash_equal(const void *arg1, const void *arg2) netlink_socket (). */ void kernel_init(struct zebra_ns *zns) { - uint32_t groups, dplane_groups; + uint32_t groups, dplane_groups, ext_groups; #if defined SOL_NETLINK int one, ret; #endif @@ -1643,11 +1723,13 @@ void kernel_init(struct zebra_ns *zns) ((uint32_t) 1 << (RTNLGRP_IPV6_NETCONF - 1)) | ((uint32_t) 1 << (RTNLGRP_MPLS_NETCONF - 1))); + /* Use setsockopt for > 31 group */ + ext_groups = RTNLGRP_TUNNEL; snprintf(zns->netlink.name, sizeof(zns->netlink.name), "netlink-listen (NS %u)", zns->ns_id); zns->netlink.sock = -1; - if (netlink_socket(&zns->netlink, groups, zns->ns_id) < 0) { + if (netlink_socket(&zns->netlink, groups, ext_groups, zns->ns_id) < 0) { zlog_err("Failure to create %s socket", zns->netlink.name); exit(-1); @@ -1658,7 +1740,7 @@ void kernel_init(struct zebra_ns *zns) snprintf(zns->netlink_cmd.name, sizeof(zns->netlink_cmd.name), "netlink-cmd (NS %u)", zns->ns_id); zns->netlink_cmd.sock = -1; - if (netlink_socket(&zns->netlink_cmd, 0, zns->ns_id) < 0) { + if (netlink_socket(&zns->netlink_cmd, 0, 0, zns->ns_id) < 0) { zlog_err("Failure to create %s socket", zns->netlink_cmd.name); exit(-1); @@ -1671,7 +1753,7 @@ void kernel_init(struct zebra_ns *zns) sizeof(zns->netlink_dplane_out.name), "netlink-dp (NS %u)", zns->ns_id); zns->netlink_dplane_out.sock = -1; - if (netlink_socket(&zns->netlink_dplane_out, 0, zns->ns_id) < 0) { + if (netlink_socket(&zns->netlink_dplane_out, 0, 0, zns->ns_id) < 0) { zlog_err("Failure to create %s socket", zns->netlink_dplane_out.name); exit(-1); @@ -1684,7 +1766,7 @@ void kernel_init(struct zebra_ns *zns) 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, dplane_groups, + if (netlink_socket(&zns->netlink_dplane_in, dplane_groups, 0, zns->ns_id) < 0) { zlog_err("Failure to create %s socket", zns->netlink_dplane_in.name); |
