summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorvivek <vivek@cumulusnetworks.com>2017-05-15 07:28:32 +0200
committervivek <vivek@cumulusnetworks.com>2017-05-25 19:20:03 +0200
commit289602d73d192ba31977fda834a52454b9bbb5ab (patch)
treef6ddde5669668c0f6ca572cc51a24e91829e00aa
parentzebra: Set nlmsg_pid in netlink_talk() (diff)
downloadfrr-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.c32
-rw-r--r--zebra/kernel_netlink.c31
-rw-r--r--zebra/kernel_netlink.h2
-rw-r--r--zebra/rt_netlink.c23
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);