]> git.puffer.fish Git - mirror/frr.git/commitdiff
zebra: Format netlink requests correctly
authorvivek <vivek@cumulusnetworks.com>
Mon, 15 May 2017 05:28:32 +0000 (22:28 -0700)
committervivek <vivek@cumulusnetworks.com>
Thu, 25 May 2017 17:20:03 +0000 (10:20 -0700)
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>
zebra/if_netlink.c
zebra/kernel_netlink.c
zebra/kernel_netlink.h
zebra/rt_netlink.c

index edfb564a6cbb460e6bd7bdcdce0f5022d113c65f..46fd362edbf4cd9fb057c00ff34ff1590a54a644 100644 (file)
@@ -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);
index 9a574110aa88f3b9d08b2766702c8ddc67270936..5ed7d43c2cf205ee52395e6f281fae16087eca47 100644 (file)
@@ -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;
 
index 4a3ecccd7a7bac4fb9d67d02037ee83ec5232aac..d642423232e7d983a3c8e6f03a2c6b555bb99d86 100644 (file)
@@ -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 */
 
index 3c4f3171ffd9a46e62d707e992b6c061bf8c048a..d140ddce6e3c5e6ddc35ff47f69ff4a5d47a2cd3 100644 (file)
@@ -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);