diff options
author | vivek <vivek@cumulusnetworks.com> | 2017-05-15 07:28:32 +0200 |
---|---|---|
committer | vivek <vivek@cumulusnetworks.com> | 2017-05-25 19:20:03 +0200 |
commit | 289602d73d192ba31977fda834a52454b9bbb5ab (patch) | |
tree | f6ddde5669668c0f6ca572cc51a24e91829e00aa | |
parent | zebra: Set nlmsg_pid in netlink_talk() (diff) | |
download | frr-289602d73d192ba31977fda834a52454b9bbb5ab.tar.xz frr-289602d73d192ba31977fda834a52454b9bbb5ab.zip |
zebra: Format netlink requests correctly
When zebra issues read (GET) requests to the kernel using the netlink
interface, it is incorrect to format all of them in a generic manner
using 'struct ifinfomsg' or 'struct rtgenmsg'. Rather, messages for a
particular entity (e.g., routes) should use the corresponding structure
for encoding (e.g., 'struct rtmsg'). Of course, this has to correlate
with what the kernel expects.
In the absence of this, there is the possibility of sending extraneous
information in the request which the kernel wouldn't like.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: David Ahern <dsa@cumulusnetworks.com>
-rw-r--r-- | zebra/if_netlink.c | 32 | ||||
-rw-r--r-- | zebra/kernel_netlink.c | 31 | ||||
-rw-r--r-- | zebra/kernel_netlink.h | 2 | ||||
-rw-r--r-- | zebra/rt_netlink.c | 23 |
4 files changed, 62 insertions, 26 deletions
diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index edfb564a6..46fd362ed 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -437,6 +437,32 @@ netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h, return 0; } +/* Request for specific interface or address information from the kernel */ +static int +netlink_request_intf_addr (struct zebra_ns *zns, + int family, int type, + u_int32_t filter_mask) +{ + struct + { + struct nlmsghdr n; + struct ifinfomsg ifm; + char buf[256]; + } req; + + /* Form the request, specifying filter (rtattr) if needed. */ + memset (&req, 0, sizeof (req)); + req.n.nlmsg_type = type; + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + req.ifm.ifi_family = family; + + /* Include filter, if specified. */ + if (filter_mask) + addattr32 (&req.n, sizeof(req), IFLA_EXT_MASK, filter_mask); + + return netlink_request (&zns->netlink_cmd, &req.n); +} + /* Interface lookup by netlink socket. */ int interface_lookup_netlink (struct zebra_ns *zns) @@ -444,7 +470,7 @@ interface_lookup_netlink (struct zebra_ns *zns) int ret; /* Get interface information. */ - ret = netlink_request (AF_PACKET, RTM_GETLINK, &zns->netlink_cmd); + ret = netlink_request_intf_addr (zns, AF_PACKET, RTM_GETLINK, 0); if (ret < 0) return ret; ret = netlink_parse_info (netlink_interface, &zns->netlink_cmd, zns, 0, 1); @@ -452,7 +478,7 @@ interface_lookup_netlink (struct zebra_ns *zns) return ret; /* Get IPv4 address of the interfaces. */ - ret = netlink_request (AF_INET, RTM_GETADDR, &zns->netlink_cmd); + ret = netlink_request_intf_addr (zns, AF_INET, RTM_GETADDR, 0); if (ret < 0) return ret; ret = netlink_parse_info (netlink_interface_addr, &zns->netlink_cmd, zns, 0, 1); @@ -460,7 +486,7 @@ interface_lookup_netlink (struct zebra_ns *zns) return ret; /* Get IPv6 address of the interfaces. */ - ret = netlink_request (AF_INET6, RTM_GETADDR, &zns->netlink_cmd); + ret = netlink_request_intf_addr (zns, AF_INET6, RTM_GETADDR, 0); if (ret < 0) return ret; ret = netlink_parse_info (netlink_interface_addr, &zns->netlink_cmd, zns, 0, 1); diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index 9a574110a..5ed7d43c2 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -728,20 +728,16 @@ netlink_talk (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *, return netlink_parse_info (filter, nl, zns, 0, startup); } -/* Get type specified information from netlink. */ +/* Issue request message to kernel via netlink socket. GET messages + * are issued through this interface. + */ int -netlink_request (int family, int type, struct nlsock *nl) +netlink_request (struct nlsock *nl, struct nlmsghdr *n) { int ret; struct sockaddr_nl snl; int save_errno; - struct - { - struct nlmsghdr nlh; - struct rtgenmsg g; - } req; - /* Check netlink socket. */ if (nl->sock < 0) { @@ -749,27 +745,22 @@ netlink_request (int family, int type, struct nlsock *nl) return -1; } + /* Fill common fields for all requests. */ + n->nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST; + n->nlmsg_pid = nl->snl.nl_pid; + n->nlmsg_seq = ++nl->seq; + memset (&snl, 0, sizeof snl); snl.nl_family = AF_NETLINK; - memset (&req, 0, sizeof req); - req.nlh.nlmsg_len = sizeof req; - req.nlh.nlmsg_type = type; - req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST; - req.nlh.nlmsg_pid = nl->snl.nl_pid; - req.nlh.nlmsg_seq = ++nl->seq; - req.g.rtgen_family = family; - - /* linux appears to check capabilities on every message - * have to raise caps for every message sent - */ + /* Raise capabilities and send message, then lower capabilities. */ if (zserv_privs.change (ZPRIVS_RAISE)) { zlog_err("Can't raise privileges"); return -1; } - ret = sendto (nl->sock, (void *) &req, sizeof req, 0, + ret = sendto (nl->sock, (void *)n, n->nlmsg_len, 0, (struct sockaddr *) &snl, sizeof snl); save_errno = errno; diff --git a/zebra/kernel_netlink.h b/zebra/kernel_netlink.h index 4a3ecccd7..d64242323 100644 --- a/zebra/kernel_netlink.h +++ b/zebra/kernel_netlink.h @@ -54,7 +54,7 @@ extern int netlink_talk (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *, ns_id_t, int startup), struct nlmsghdr *n, struct nlsock *nl, struct zebra_ns *zns, int startup); -extern int netlink_request (int family, int type, struct nlsock *nl); +extern int netlink_request (struct nlsock *nl, struct nlmsghdr *n); #endif /* HAVE_NETLINK */ diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 3c4f3171f..d140ddce6 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -569,6 +569,25 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h, return 0; } +/* Request for specific route information from the kernel */ +static int +netlink_request_route (struct zebra_ns *zns, int family, int type) +{ + struct + { + struct nlmsghdr n; + struct rtmsg rtm; + } req; + + /* Form the request, specifying filter (rtattr) if needed. */ + memset (&req, 0, sizeof (req)); + req.n.nlmsg_type = type; + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); + req.rtm.rtm_family = family; + + return netlink_request (&zns->netlink_cmd, &req.n); +} + /* Routing table read function using netlink interface. Only called bootstrap time. */ int @@ -577,7 +596,7 @@ netlink_route_read (struct zebra_ns *zns) int ret; /* Get IPv4 routing table. */ - ret = netlink_request (AF_INET, RTM_GETROUTE, &zns->netlink_cmd); + ret = netlink_request_route (zns, AF_INET, RTM_GETROUTE); if (ret < 0) return ret; ret = netlink_parse_info (netlink_route_change_read_unicast, &zns->netlink_cmd, zns, 0, 1); @@ -585,7 +604,7 @@ netlink_route_read (struct zebra_ns *zns) return ret; /* Get IPv6 routing table. */ - ret = netlink_request (AF_INET6, RTM_GETROUTE, &zns->netlink_cmd); + ret = netlink_request_route (zns, AF_INET6, RTM_GETROUTE); if (ret < 0) return ret; ret = netlink_parse_info (netlink_route_change_read_unicast, &zns->netlink_cmd, zns, 0, 1); |