LCOV - code coverage report
Current view: top level - vnet/devices - netlink.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 143 236 60.6 %
Date: 2023-10-26 01:39:38 Functions: 10 16 62.5 %

          Line data    Source code
       1             : /*
       2             :  *------------------------------------------------------------------
       3             :  * Copyright (c) 2017 Cisco and/or its affiliates.
       4             :  * Licensed under the Apache License, Version 2.0 (the "License");
       5             :  * you may not use this file except in compliance with the License.
       6             :  * You may obtain a copy of the License at:
       7             :  *
       8             :  *     http://www.apache.org/licenses/LICENSE-2.0
       9             :  *
      10             :  * Unless required by applicable law or agreed to in writing, software
      11             :  * distributed under the License is distributed on an "AS IS" BASIS,
      12             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13             :  * See the License for the specific language governing permissions and
      14             :  * limitations under the License.
      15             :  *------------------------------------------------------------------
      16             :  */
      17             : 
      18             : #include <sys/types.h>
      19             : #include <sys/stat.h>
      20             : #include <fcntl.h>
      21             : #include <net/if.h>
      22             : 
      23             : #include <linux/netlink.h>
      24             : #include <linux/rtnetlink.h>
      25             : 
      26             : #include <vlib/vlib.h>
      27             : #include <vlib/unix/unix.h>
      28             : #include <vnet/devices/netlink.h>
      29             : 
      30             : typedef struct
      31             : {
      32             :   u8 *data;
      33             : } vnet_netlink_msg_t;
      34             : 
      35             : static void
      36        1872 : vnet_netlink_msg_init (vnet_netlink_msg_t * m, u16 type, u16 flags,
      37             :                        void *msg_data, int msg_len)
      38             : {
      39             :   struct nlmsghdr *nh;
      40             :   u8 *p;
      41        1872 :   clib_memset (m, 0, sizeof (vnet_netlink_msg_t));
      42        1872 :   vec_add2 (m->data, p, NLMSG_SPACE (msg_len));
      43        1872 :   ASSERT (m->data == p);
      44             : 
      45        1872 :   nh = (struct nlmsghdr *) p;
      46        1872 :   nh->nlmsg_flags = flags | NLM_F_ACK;
      47        1872 :   nh->nlmsg_type = type;
      48        1872 :   clib_memcpy (m->data + sizeof (struct nlmsghdr), msg_data, msg_len);
      49        1872 : }
      50             : 
      51             : static void
      52        1164 : vnet_netlink_msg_add_rtattr (vnet_netlink_msg_t * m, u16 rta_type,
      53             :                              void *rta_data, int rta_data_len)
      54             : {
      55             :   struct rtattr *rta;
      56             :   u8 *p;
      57             : 
      58        1164 :   vec_add2 (m->data, p, RTA_SPACE (rta_data_len));
      59        1164 :   rta = (struct rtattr *) p;
      60        1164 :   rta->rta_type = rta_type;
      61        1164 :   rta->rta_len = RTA_LENGTH (rta_data_len);
      62        1164 :   clib_memcpy (RTA_DATA (rta), rta_data, rta_data_len);
      63        1164 : }
      64             : 
      65             : static clib_error_t *
      66        1872 : vnet_netlink_msg_send (vnet_netlink_msg_t *m, vnet_netlink_msg_t **replies)
      67             : {
      68        1872 :   clib_error_t *err = 0;
      69        1872 :   struct sockaddr_nl ra = { 0 };
      70             :   int len, sock;
      71        1872 :   struct nlmsghdr *nh = (struct nlmsghdr *) m->data;
      72        1872 :   nh->nlmsg_len = vec_len (m->data);
      73             :   char buf[4096];
      74             : 
      75        1872 :   if ((sock = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1)
      76           0 :     return clib_error_return_unix (0, "socket(AF_NETLINK)");
      77             : 
      78        1872 :   ra.nl_family = AF_NETLINK;
      79        1872 :   ra.nl_pid = 0;
      80             : 
      81        1872 :   if ((bind (sock, (struct sockaddr *) &ra, sizeof (ra))) == -1)
      82             :     {
      83           0 :       err = clib_error_return_unix (0, "bind");
      84           0 :       goto done;
      85             :     }
      86             : 
      87        1872 :   if ((send (sock, m->data, vec_len (m->data), 0)) == -1)
      88           0 :     err = clib_error_return_unix (0, "send");
      89             : 
      90        1872 :   if ((len = recv (sock, buf, sizeof (buf), 0)) == -1)
      91           0 :     err = clib_error_return_unix (0, "recv");
      92             : 
      93        2124 :   for (nh = (struct nlmsghdr *) buf; NLMSG_OK (nh, len);
      94         252 :        nh = NLMSG_NEXT (nh, len))
      95             :     {
      96        1872 :       if (nh->nlmsg_type == NLMSG_DONE)
      97           0 :         goto done;
      98             : 
      99        1872 :       if (nh->nlmsg_type == NLMSG_ERROR)
     100             :         {
     101        1620 :           struct nlmsgerr *e = (struct nlmsgerr *) NLMSG_DATA (nh);
     102        1620 :           if (e->error)
     103           0 :             err = clib_error_return (0, "netlink error %d", e->error);
     104        1620 :           goto done;
     105             :         }
     106             : 
     107         252 :       if (replies)
     108             :         {
     109         252 :           vnet_netlink_msg_t msg = { NULL };
     110             :           u8 *p;
     111         252 :           vec_add2 (msg.data, p, nh->nlmsg_len);
     112         252 :           clib_memcpy (p, nh, nh->nlmsg_len);
     113         252 :           vec_add1 (*replies, msg);
     114             :         }
     115             :     }
     116             : 
     117         252 : done:
     118        1872 :   close (sock);
     119        1872 :   vec_free (m->data);
     120        1872 :   return err;
     121             : }
     122             : 
     123             : clib_error_t *
     124           0 : vnet_netlink_set_link_name (int ifindex, char *new_ifname)
     125             : {
     126             :   vnet_netlink_msg_t m;
     127           0 :   struct ifinfomsg ifmsg = { 0 };
     128           0 :   clib_error_t *err = 0;
     129             : 
     130           0 :   ifmsg.ifi_index = ifindex;
     131           0 :   vnet_netlink_msg_init (&m, RTM_SETLINK, NLM_F_REQUEST,
     132             :                          &ifmsg, sizeof (struct ifinfomsg));
     133             : 
     134           0 :   vnet_netlink_msg_add_rtattr (&m, IFLA_IFNAME, new_ifname,
     135           0 :                                strlen (new_ifname) + 1);
     136             : 
     137           0 :   err = vnet_netlink_msg_send (&m, NULL);
     138           0 :   if (err)
     139           0 :     err = clib_error_return (0, "set link name %U", format_clib_error, err);
     140           0 :   return err;
     141             : }
     142             : 
     143             : clib_error_t *
     144           0 : vnet_netlink_set_link_netns (int ifindex, int netns_fd, char *new_ifname)
     145             : {
     146             :   vnet_netlink_msg_t m;
     147           0 :   struct ifinfomsg ifmsg = { 0 };
     148           0 :   clib_error_t *err = 0;
     149             : 
     150           0 :   ifmsg.ifi_index = ifindex;
     151           0 :   vnet_netlink_msg_init (&m, RTM_SETLINK, NLM_F_REQUEST,
     152             :                          &ifmsg, sizeof (struct ifinfomsg));
     153             : 
     154           0 :   vnet_netlink_msg_add_rtattr (&m, IFLA_NET_NS_FD, &netns_fd, sizeof (int));
     155           0 :   if (new_ifname)
     156           0 :     vnet_netlink_msg_add_rtattr (&m, IFLA_IFNAME, new_ifname,
     157           0 :                                  strlen (new_ifname) + 1);
     158             : 
     159           0 :   err = vnet_netlink_msg_send (&m, NULL);
     160           0 :   if (err)
     161           0 :     err = clib_error_return (0, "set link netns %U", format_clib_error, err);
     162           0 :   return err;
     163             : }
     164             : 
     165             : clib_error_t *
     166           0 : vnet_netlink_set_link_master (int ifindex, char *master_ifname)
     167             : {
     168             :   vnet_netlink_msg_t m;
     169           0 :   struct ifinfomsg ifmsg = { 0 };
     170             :   int i;
     171           0 :   clib_error_t *err = 0;
     172             : 
     173           0 :   ifmsg.ifi_index = ifindex;
     174             : 
     175           0 :   if ((i = if_nametoindex (master_ifname)) == 0)
     176           0 :     clib_error_return_unix (0, "unknown master interface '%s'",
     177             :                             master_ifname);
     178             : 
     179           0 :   vnet_netlink_msg_init (&m, RTM_SETLINK, NLM_F_REQUEST,
     180             :                          &ifmsg, sizeof (struct ifinfomsg));
     181           0 :   vnet_netlink_msg_add_rtattr (&m, IFLA_MASTER, &i, sizeof (int));
     182           0 :   err = vnet_netlink_msg_send (&m, NULL);
     183           0 :   if (err)
     184           0 :     err = clib_error_return (0, "set link master %U", format_clib_error, err);
     185           0 :   return err;
     186             : }
     187             : 
     188             : clib_error_t *
     189         324 : vnet_netlink_set_link_addr (int ifindex, u8 * mac)
     190             : {
     191             :   vnet_netlink_msg_t m;
     192         324 :   struct ifinfomsg ifmsg = { 0 };
     193         324 :   clib_error_t *err = 0;
     194             : 
     195         324 :   ifmsg.ifi_index = ifindex;
     196             : 
     197         324 :   vnet_netlink_msg_init (&m, RTM_SETLINK, NLM_F_REQUEST,
     198             :                          &ifmsg, sizeof (struct ifinfomsg));
     199         324 :   vnet_netlink_msg_add_rtattr (&m, IFLA_ADDRESS, mac, 6);
     200         324 :   err = vnet_netlink_msg_send (&m, NULL);
     201         324 :   if (err)
     202           0 :     err = clib_error_return (0, "set link addr %U", format_clib_error, err);
     203         324 :   return err;
     204             : }
     205             : 
     206             : clib_error_t *
     207         876 : vnet_netlink_set_link_state (int ifindex, int up)
     208             : {
     209             :   vnet_netlink_msg_t m;
     210         876 :   struct ifinfomsg ifmsg = { 0 };
     211         876 :   clib_error_t *err = 0;
     212             : 
     213         876 :   ifmsg.ifi_flags = ((up) ? IFF_UP : 0);
     214         876 :   ifmsg.ifi_change = IFF_UP;
     215         876 :   ifmsg.ifi_index = ifindex;
     216             : 
     217         876 :   vnet_netlink_msg_init (&m, RTM_SETLINK, NLM_F_REQUEST,
     218             :                          &ifmsg, sizeof (struct ifinfomsg));
     219         876 :   err = vnet_netlink_msg_send (&m, NULL);
     220         876 :   if (err)
     221           0 :     err = clib_error_return (0, "set link state %U", format_clib_error, err);
     222         876 :   return err;
     223             : }
     224             : 
     225             : clib_error_t *
     226         252 : vnet_netlink_get_link_mtu (int ifindex, u32 *mtu)
     227             : {
     228             :   vnet_netlink_msg_t m, *msg;
     229         252 :   struct ifinfomsg ifmsg = { 0 };
     230             :   struct nlattr *attr;
     231         252 :   clib_error_t *err = 0;
     232         252 :   vnet_netlink_msg_t *replies = NULL;
     233         252 :   int len = 0, offset = 0;
     234             :   u32 msg_mtu;
     235             : 
     236         252 :   ifmsg.ifi_index = ifindex;
     237             : 
     238         252 :   vnet_netlink_msg_init (&m, RTM_GETLINK, NLM_F_REQUEST, &ifmsg,
     239             :                          sizeof (struct ifinfomsg));
     240             :   // vnet_netlink_msg_add_rtattr (&m, IFLA_MTU, &mtu, sizeof (int));
     241         252 :   err = vnet_netlink_msg_send (&m, &replies);
     242         252 :   if (err)
     243             :     {
     244           0 :       err = clib_error_return (0, "get link mtu %U", format_clib_error, err);
     245           0 :       goto done;
     246             :     }
     247             : 
     248         252 :   if (vec_len (replies) != 1)
     249             :     {
     250           0 :       err = clib_error_return (0, "got %d != 1 netlink reply msg",
     251             :                                vec_len (replies));
     252           0 :       goto done;
     253             :     }
     254             : 
     255         252 :   struct nlmsghdr *nh = (struct nlmsghdr *) replies[0].data;
     256         252 :   if (nh->nlmsg_type != RTM_NEWLINK)
     257             :     {
     258           0 :       err = clib_error_return (
     259             :         0, "netlink reply has wrong type: %d != RTM_NEWLINK", nh->nlmsg_type);
     260           0 :       goto done;
     261             :     }
     262             : 
     263         252 :   offset = NLMSG_HDRLEN + NLMSG_ALIGN (sizeof (struct ifinfomsg));
     264         252 :   attr = (struct nlattr *) ((u8 *) nh + offset);
     265         252 :   len = nh->nlmsg_len - offset;
     266             : 
     267             :   do
     268             :     {
     269        1260 :       if ((attr->nla_type & NLA_TYPE_MASK) == IFLA_MTU)
     270             :         {
     271         252 :           msg_mtu = *(u32 *) ((u8 *) attr + NLA_HDRLEN);
     272         252 :           if (attr->nla_type & NLA_F_NET_BYTEORDER)
     273           0 :             *mtu = clib_net_to_host_u32 (msg_mtu);
     274             :           else
     275         252 :             *mtu = msg_mtu;
     276         252 :           goto done;
     277             :         }
     278        1008 :       offset = NLA_ALIGN (attr->nla_len);
     279        1008 :       len -= offset;
     280        1008 :       attr = (struct nlattr *) ((u8 *) attr + offset);
     281             :     }
     282        1008 :   while (len > sizeof (struct nlattr));
     283             : 
     284             :   /* not found */
     285           0 :   err = clib_error_return (0, "mtu not found in netlink message");
     286             : 
     287         252 : done:
     288         504 :   vec_foreach (msg, replies)
     289             :     {
     290         252 :       vec_free (msg->data);
     291             :     }
     292         252 :   vec_free (replies);
     293             : 
     294         252 :   return err;
     295             : }
     296             : 
     297             : clib_error_t *
     298           0 : vnet_netlink_set_link_mtu (int ifindex, int mtu)
     299             : {
     300             :   vnet_netlink_msg_t m;
     301           0 :   struct ifinfomsg ifmsg = { 0 };
     302           0 :   clib_error_t *err = 0;
     303             : 
     304           0 :   ifmsg.ifi_index = ifindex;
     305             : 
     306           0 :   vnet_netlink_msg_init (&m, RTM_SETLINK, NLM_F_REQUEST,
     307             :                          &ifmsg, sizeof (struct ifinfomsg));
     308           0 :   vnet_netlink_msg_add_rtattr (&m, IFLA_MTU, &mtu, sizeof (int));
     309           0 :   err = vnet_netlink_msg_send (&m, NULL);
     310           0 :   if (err)
     311           0 :     err = clib_error_return (0, "set link mtu %U", format_clib_error, err);
     312           0 :   return err;
     313             : }
     314             : 
     315             : clib_error_t *
     316         186 : vnet_netlink_add_ip4_addr (int ifindex, void *addr, int pfx_len)
     317             : {
     318             :   vnet_netlink_msg_t m;
     319         186 :   struct ifaddrmsg ifa = { 0 };
     320         186 :   clib_error_t *err = 0;
     321             : 
     322         186 :   ifa.ifa_family = AF_INET;
     323         186 :   ifa.ifa_prefixlen = pfx_len;
     324         186 :   ifa.ifa_index = ifindex;
     325             : 
     326         186 :   vnet_netlink_msg_init (&m, RTM_NEWADDR,
     327             :                          NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE,
     328             :                          &ifa, sizeof (struct ifaddrmsg));
     329             : 
     330         186 :   vnet_netlink_msg_add_rtattr (&m, IFA_LOCAL, addr, 4);
     331         186 :   vnet_netlink_msg_add_rtattr (&m, IFA_ADDRESS, addr, 4);
     332         186 :   err = vnet_netlink_msg_send (&m, NULL);
     333         186 :   if (err)
     334           0 :     err = clib_error_return (0, "add ip4 addr %U", format_clib_error, err);
     335         186 :   return err;
     336             : }
     337             : 
     338             : clib_error_t *
     339         186 : vnet_netlink_add_ip6_addr (int ifindex, void *addr, int pfx_len)
     340             : {
     341             :   vnet_netlink_msg_t m;
     342         186 :   struct ifaddrmsg ifa = { 0 };
     343         186 :   clib_error_t *err = 0;
     344             : 
     345         186 :   ifa.ifa_family = AF_INET6;
     346         186 :   ifa.ifa_prefixlen = pfx_len;
     347         186 :   ifa.ifa_index = ifindex;
     348             : 
     349         186 :   vnet_netlink_msg_init (&m, RTM_NEWADDR,
     350             :                          NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE,
     351             :                          &ifa, sizeof (struct ifaddrmsg));
     352             : 
     353         186 :   vnet_netlink_msg_add_rtattr (&m, IFA_LOCAL, addr, 16);
     354         186 :   vnet_netlink_msg_add_rtattr (&m, IFA_ADDRESS, addr, 16);
     355         186 :   err = vnet_netlink_msg_send (&m, NULL);
     356         186 :   if (err)
     357           0 :     err = clib_error_return (0, "add ip6 addr %U", format_clib_error, err);
     358         186 :   return err;
     359             : }
     360             : 
     361             : clib_error_t *
     362          24 : vnet_netlink_add_ip4_route (void *dst, u8 dst_len, void *gw)
     363             : {
     364             :   vnet_netlink_msg_t m;
     365          24 :   struct rtmsg rtm = { 0 };
     366          24 :   u8 dflt[4] = { 0 };
     367          24 :   clib_error_t *err = 0;
     368             : 
     369          24 :   rtm.rtm_family = AF_INET;
     370          24 :   rtm.rtm_table = RT_TABLE_MAIN;
     371          24 :   rtm.rtm_type = RTN_UNICAST;
     372          24 :   rtm.rtm_dst_len = dst_len;
     373             : 
     374          24 :   vnet_netlink_msg_init (&m, RTM_NEWROUTE,
     375             :                          NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE,
     376             :                          &rtm, sizeof (struct rtmsg));
     377             : 
     378          24 :   vnet_netlink_msg_add_rtattr (&m, RTA_GATEWAY, gw, 4);
     379          24 :   vnet_netlink_msg_add_rtattr (&m, RTA_DST, dst ? dst : dflt, 4);
     380          24 :   err = vnet_netlink_msg_send (&m, NULL);
     381          24 :   if (err)
     382           0 :     err = clib_error_return (0, "add ip4 route %U", format_clib_error, err);
     383          24 :   return err;
     384             : }
     385             : 
     386             : clib_error_t *
     387          24 : vnet_netlink_add_ip6_route (void *dst, u8 dst_len, void *gw)
     388             : {
     389             :   vnet_netlink_msg_t m;
     390          24 :   struct rtmsg rtm = { 0 };
     391          24 :   u8 dflt[16] = { 0 };
     392          24 :   clib_error_t *err = 0;
     393             : 
     394          24 :   rtm.rtm_family = AF_INET6;
     395          24 :   rtm.rtm_table = RT_TABLE_MAIN;
     396          24 :   rtm.rtm_type = RTN_UNICAST;
     397          24 :   rtm.rtm_dst_len = dst_len;
     398             : 
     399          24 :   vnet_netlink_msg_init (&m, RTM_NEWROUTE,
     400             :                          NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE,
     401             :                          &rtm, sizeof (struct rtmsg));
     402             : 
     403          24 :   vnet_netlink_msg_add_rtattr (&m, RTA_GATEWAY, gw, 16);
     404          24 :   vnet_netlink_msg_add_rtattr (&m, RTA_DST, dst ? dst : dflt, 16);
     405          24 :   err = vnet_netlink_msg_send (&m, NULL);
     406          24 :   if (err)
     407           0 :     err = clib_error_return (0, "add ip6 route %U", format_clib_error, err);
     408          24 :   return err;
     409             : }
     410             : 
     411             : clib_error_t *
     412           0 : vnet_netlink_del_ip4_addr (int ifindex, void *addr, int pfx_len)
     413             : {
     414             :   vnet_netlink_msg_t m;
     415           0 :   struct ifaddrmsg ifa = { 0 };
     416           0 :   clib_error_t *err = 0;
     417             : 
     418           0 :   ifa.ifa_family = AF_INET;
     419           0 :   ifa.ifa_prefixlen = pfx_len;
     420           0 :   ifa.ifa_index = ifindex;
     421             : 
     422           0 :   vnet_netlink_msg_init (&m, RTM_DELADDR, NLM_F_REQUEST, &ifa,
     423             :                          sizeof (struct ifaddrmsg));
     424             : 
     425           0 :   vnet_netlink_msg_add_rtattr (&m, IFA_LOCAL, addr, 4);
     426           0 :   vnet_netlink_msg_add_rtattr (&m, IFA_ADDRESS, addr, 4);
     427           0 :   err = vnet_netlink_msg_send (&m, NULL);
     428           0 :   if (err)
     429           0 :     err = clib_error_return (0, "del ip4 addr %U", format_clib_error, err);
     430           0 :   return err;
     431             : }
     432             : 
     433             : clib_error_t *
     434           0 : vnet_netlink_del_ip6_addr (int ifindex, void *addr, int pfx_len)
     435             : {
     436             :   vnet_netlink_msg_t m;
     437           0 :   struct ifaddrmsg ifa = { 0 };
     438           0 :   clib_error_t *err = 0;
     439             : 
     440           0 :   ifa.ifa_family = AF_INET6;
     441           0 :   ifa.ifa_prefixlen = pfx_len;
     442           0 :   ifa.ifa_index = ifindex;
     443             : 
     444           0 :   vnet_netlink_msg_init (&m, RTM_DELADDR, NLM_F_REQUEST, &ifa,
     445             :                          sizeof (struct ifaddrmsg));
     446             : 
     447           0 :   vnet_netlink_msg_add_rtattr (&m, IFA_LOCAL, addr, 16);
     448           0 :   vnet_netlink_msg_add_rtattr (&m, IFA_ADDRESS, addr, 16);
     449           0 :   err = vnet_netlink_msg_send (&m, NULL);
     450           0 :   if (err)
     451           0 :     err = clib_error_return (0, "del ip6 addr %U", format_clib_error, err);
     452           0 :   return err;
     453             : }
     454             : 
     455             : /*
     456             :  * fd.io coding-style-patch-verification: ON
     457             :  *
     458             :  * Local Variables:
     459             :  * eval: (c-set-style "gnu")
     460             :  * End:
     461             :  */

Generated by: LCOV version 1.14