117fdae73SDamjan Marion/*
217fdae73SDamjan Marion *------------------------------------------------------------------
317fdae73SDamjan Marion * Copyright (c) 2017 Cisco and/or its affiliates.
417fdae73SDamjan Marion * Licensed under the Apache License, Version 2.0 (the "License");
517fdae73SDamjan Marion * you may not use this file except in compliance with the License.
617fdae73SDamjan Marion * You may obtain a copy of the License at:
717fdae73SDamjan Marion *
817fdae73SDamjan Marion *     http://www.apache.org/licenses/LICENSE-2.0
917fdae73SDamjan Marion *
1017fdae73SDamjan Marion * Unless required by applicable law or agreed to in writing, software
1117fdae73SDamjan Marion * distributed under the License is distributed on an "AS IS" BASIS,
1217fdae73SDamjan Marion * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1317fdae73SDamjan Marion * See the License for the specific language governing permissions and
1417fdae73SDamjan Marion * limitations under the License.
1517fdae73SDamjan Marion *------------------------------------------------------------------
1617fdae73SDamjan Marion */
1717fdae73SDamjan Marion
1817fdae73SDamjan Marion#include <sys/types.h>
1917fdae73SDamjan Marion#include <sys/stat.h>
2017fdae73SDamjan Marion#include <fcntl.h>
2117fdae73SDamjan Marion#include <net/if.h>
2217fdae73SDamjan Marion
2317fdae73SDamjan Marion#include <linux/netlink.h>
2417fdae73SDamjan Marion#include <linux/rtnetlink.h>
2517fdae73SDamjan Marion
2617fdae73SDamjan Marion#include <vlib/vlib.h>
2717fdae73SDamjan Marion#include <vlib/unix/unix.h>
282df39094SDamjan Marion#include <vnet/devices/netlink.h>
2917fdae73SDamjan Marion
3091c6ef7cSDamjan Mariontypedef struct
3191c6ef7cSDamjan Marion{
3291c6ef7cSDamjan Marion  u8 *data;
3391c6ef7cSDamjan Marion} vnet_netlink_msg_t;
3491c6ef7cSDamjan Marion
352df39094SDamjan Marionstatic void
3691c6ef7cSDamjan Marionvnet_netlink_msg_init (vnet_netlink_msg_t * m, u16 type, u16 flags,
3791c6ef7cSDamjan Marion		       void *msg_data, int msg_len)
3891c6ef7cSDamjan Marion{
3991c6ef7cSDamjan Marion  struct nlmsghdr *nh;
4091c6ef7cSDamjan Marion  u8 *p;
41b7b92993SDave Barach  clib_memset (m, 0, sizeof (vnet_netlink_msg_t));
422df39094SDamjan Marion  vec_add2 (m->data, p, NLMSG_SPACE (msg_len));
4391c6ef7cSDamjan Marion  ASSERT (m->data == p);
4491c6ef7cSDamjan Marion
4591c6ef7cSDamjan Marion  nh = (struct nlmsghdr *) p;
462df39094SDamjan Marion  nh->nlmsg_flags = flags | NLM_F_ACK;
4791c6ef7cSDamjan Marion  nh->nlmsg_type = type;
4891c6ef7cSDamjan Marion  clib_memcpy (m->data + sizeof (struct nlmsghdr), msg_data, msg_len);
4991c6ef7cSDamjan Marion}
5091c6ef7cSDamjan Marion
5191c6ef7cSDamjan Marionstatic void
5291c6ef7cSDamjan Marionvnet_netlink_msg_add_rtattr (vnet_netlink_msg_t * m, u16 rta_type,
5391c6ef7cSDamjan Marion			     void *rta_data, int rta_data_len)
5491c6ef7cSDamjan Marion{
5591c6ef7cSDamjan Marion  struct rtattr *rta;
5691c6ef7cSDamjan Marion  u8 *p;
5791c6ef7cSDamjan Marion
582df39094SDamjan Marion  vec_add2 (m->data, p, RTA_SPACE (rta_data_len));
5991c6ef7cSDamjan Marion  rta = (struct rtattr *) p;
6091c6ef7cSDamjan Marion  rta->rta_type = rta_type;
6191c6ef7cSDamjan Marion  rta->rta_len = RTA_LENGTH (rta_data_len);
6291c6ef7cSDamjan Marion  clib_memcpy (RTA_DATA (rta), rta_data, rta_data_len);
6391c6ef7cSDamjan Marion}
6491c6ef7cSDamjan Marion
6591c6ef7cSDamjan Marionstatic clib_error_t *
6691c6ef7cSDamjan Marionvnet_netlink_msg_send (vnet_netlink_msg_t * m)
6717fdae73SDamjan Marion{
6817fdae73SDamjan Marion  clib_error_t *err = 0;
6917fdae73SDamjan Marion  struct sockaddr_nl ra = { 0 };
702df39094SDamjan Marion  int len, sock;
7191c6ef7cSDamjan Marion  struct nlmsghdr *nh = (struct nlmsghdr *) m->data;
7291c6ef7cSDamjan Marion  nh->nlmsg_len = vec_len (m->data);
732df39094SDamjan Marion  char buf[4096];
7417fdae73SDamjan Marion
7517fdae73SDamjan Marion  if ((sock = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1)
76f953dfc8SSteven    return clib_error_return_unix (0, "socket(AF_NETLINK)");
7717fdae73SDamjan Marion
7817fdae73SDamjan Marion  ra.nl_family = AF_NETLINK;
79258fefd9SJon Loeliger  ra.nl_pid = 0;
8017fdae73SDamjan Marion
8117fdae73SDamjan Marion  if ((bind (sock, (struct sockaddr *) &ra, sizeof (ra))) == -1)
82f953dfc8SSteven    {
83f953dfc8SSteven      err = clib_error_return_unix (0, "bind");
842df39094SDamjan Marion      goto done;
85f953dfc8SSteven    }
8617fdae73SDamjan Marion
8791c6ef7cSDamjan Marion  if ((send (sock, m->data, vec_len (m->data), 0)) == -1)
8817fdae73SDamjan Marion    err = clib_error_return_unix (0, "send");
8917fdae73SDamjan Marion
902df39094SDamjan Marion  if ((len = recv (sock, buf, sizeof (buf), 0)) == -1)
912df39094SDamjan Marion    err = clib_error_return_unix (0, "recv");
922df39094SDamjan Marion
932df39094SDamjan Marion  for (nh = (struct nlmsghdr *) buf; NLMSG_OK (nh, len);
942df39094SDamjan Marion       nh = NLMSG_NEXT (nh, len))
952df39094SDamjan Marion    {
962df39094SDamjan Marion      if (nh->nlmsg_type == NLMSG_DONE)
972df39094SDamjan Marion	goto done;
982df39094SDamjan Marion
992df39094SDamjan Marion      if (nh->nlmsg_type == NLMSG_ERROR)
1002df39094SDamjan Marion	{
1012df39094SDamjan Marion	  struct nlmsgerr *e = (struct nlmsgerr *) NLMSG_DATA (nh);
1022df39094SDamjan Marion	  if (e->error)
1032df39094SDamjan Marion	    err = clib_error_return (0, "netlink error %d", e->error);
1042df39094SDamjan Marion	  goto done;
1052df39094SDamjan Marion	}
1062df39094SDamjan Marion    }
1072df39094SDamjan Marion
1082df39094SDamjan Mariondone:
109f953dfc8SSteven  close (sock);
11091c6ef7cSDamjan Marion  vec_free (m->data);
11117fdae73SDamjan Marion  return err;
11217fdae73SDamjan Marion}
11317fdae73SDamjan Marion
11417fdae73SDamjan Marionclib_error_t *
1152df39094SDamjan Marionvnet_netlink_set_link_name (int ifindex, char *new_ifname)
11617fdae73SDamjan Marion{
11791c6ef7cSDamjan Marion  vnet_netlink_msg_t m;
11891c6ef7cSDamjan Marion  struct ifinfomsg ifmsg = { 0 };
119b9f1f158SMohsin Kazmi  clib_error_t *err = 0;
12091c6ef7cSDamjan Marion
1212df39094SDamjan Marion  ifmsg.ifi_index = ifindex;
1222df39094SDamjan Marion  vnet_netlink_msg_init (&m, RTM_SETLINK, NLM_F_REQUEST,
1232df39094SDamjan Marion			 &ifmsg, sizeof (struct ifinfomsg));
12491c6ef7cSDamjan Marion
1252df39094SDamjan Marion  vnet_netlink_msg_add_rtattr (&m, IFLA_IFNAME, new_ifname,
1262df39094SDamjan Marion			       strlen (new_ifname) + 1);
1272df39094SDamjan Marion
128b9f1f158SMohsin Kazmi  err = vnet_netlink_msg_send (&m);
129b9f1f158SMohsin Kazmi  if (err)
130b9f1f158SMohsin Kazmi    err = clib_error_return (0, "set link name %U", format_clib_error, err);
131b9f1f158SMohsin Kazmi  return err;
1322df39094SDamjan Marion}
1332df39094SDamjan Marion
1342df39094SDamjan Marionclib_error_t *
1352df39094SDamjan Marionvnet_netlink_set_link_netns (int ifindex, int netns_fd, char *new_ifname)
1362df39094SDamjan Marion{
1372df39094SDamjan Marion  vnet_netlink_msg_t m;
1382df39094SDamjan Marion  struct ifinfomsg ifmsg = { 0 };
139b9f1f158SMohsin Kazmi  clib_error_t *err = 0;
14017fdae73SDamjan Marion
14191c6ef7cSDamjan Marion  ifmsg.ifi_index = ifindex;
14291c6ef7cSDamjan Marion  vnet_netlink_msg_init (&m, RTM_SETLINK, NLM_F_REQUEST,
14391c6ef7cSDamjan Marion			 &ifmsg, sizeof (struct ifinfomsg));
14491c6ef7cSDamjan Marion
1452df39094SDamjan Marion  vnet_netlink_msg_add_rtattr (&m, IFLA_NET_NS_FD, &netns_fd, sizeof (int));
1462df39094SDamjan Marion  if (new_ifname)
1472df39094SDamjan Marion    vnet_netlink_msg_add_rtattr (&m, IFLA_IFNAME, new_ifname,
1482df39094SDamjan Marion				 strlen (new_ifname) + 1);
14991c6ef7cSDamjan Marion
150b9f1f158SMohsin Kazmi  err = vnet_netlink_msg_send (&m);
151b9f1f158SMohsin Kazmi  if (err)
152b9f1f158SMohsin Kazmi    err = clib_error_return (0, "set link netns %U", format_clib_error, err);
153b9f1f158SMohsin Kazmi  return err;
15417fdae73SDamjan Marion}
15517fdae73SDamjan Marion
15617fdae73SDamjan Marionclib_error_t *
1572df39094SDamjan Marionvnet_netlink_set_link_master (int ifindex, char *master_ifname)
15817fdae73SDamjan Marion{
15991c6ef7cSDamjan Marion  vnet_netlink_msg_t m;
16091c6ef7cSDamjan Marion  struct ifinfomsg ifmsg = { 0 };
1612df39094SDamjan Marion  int i;
162b9f1f158SMohsin Kazmi  clib_error_t *err = 0;
16391c6ef7cSDamjan Marion
16491c6ef7cSDamjan Marion  ifmsg.ifi_index = ifindex;
1652df39094SDamjan Marion
1662df39094SDamjan Marion  if ((i = if_nametoindex (master_ifname)) == 0)
1672df39094SDamjan Marion    clib_error_return_unix (0, "unknown master interface '%s'",
1682df39094SDamjan Marion			    master_ifname);
1692df39094SDamjan Marion
17091c6ef7cSDamjan Marion  vnet_netlink_msg_init (&m, RTM_SETLINK, NLM_F_REQUEST,
17191c6ef7cSDamjan Marion			 &ifmsg, sizeof (struct ifinfomsg));
1722df39094SDamjan Marion  vnet_netlink_msg_add_rtattr (&m, IFLA_MASTER, &i, sizeof (int));
173b9f1f158SMohsin Kazmi  err = vnet_netlink_msg_send (&m);
174b9f1f158SMohsin Kazmi  if (err)
175b9f1f158SMohsin Kazmi    err = clib_error_return (0, "set link master %U", format_clib_error, err);
176b9f1f158SMohsin Kazmi  return err;
17791c6ef7cSDamjan Marion}
17891c6ef7cSDamjan Marion
17991c6ef7cSDamjan Marionclib_error_t *
1802df39094SDamjan Marionvnet_netlink_set_link_addr (int ifindex, u8 * mac)
18191c6ef7cSDamjan Marion{
18291c6ef7cSDamjan Marion  vnet_netlink_msg_t m;
18391c6ef7cSDamjan Marion  struct ifinfomsg ifmsg = { 0 };
184b9f1f158SMohsin Kazmi  clib_error_t *err = 0;
18591c6ef7cSDamjan Marion
18691c6ef7cSDamjan Marion  ifmsg.ifi_index = ifindex;
1872df39094SDamjan Marion
1882df39094SDamjan Marion  vnet_netlink_msg_init (&m, RTM_SETLINK, NLM_F_REQUEST,
1892df39094SDamjan Marion			 &ifmsg, sizeof (struct ifinfomsg));
1902df39094SDamjan Marion  vnet_netlink_msg_add_rtattr (&m, IFLA_ADDRESS, mac, 6);
191b9f1f158SMohsin Kazmi  err = vnet_netlink_msg_send (&m);
192b9f1f158SMohsin Kazmi  if (err)
193b9f1f158SMohsin Kazmi    err = clib_error_return (0, "set link addr %U", format_clib_error, err);
194b9f1f158SMohsin Kazmi  return err;
1952df39094SDamjan Marion}
1962df39094SDamjan Marion
1972df39094SDamjan Marionclib_error_t *
1982df39094SDamjan Marionvnet_netlink_set_link_state (int ifindex, int up)
1992df39094SDamjan Marion{
2002df39094SDamjan Marion  vnet_netlink_msg_t m;
2012df39094SDamjan Marion  struct ifinfomsg ifmsg = { 0 };
202b9f1f158SMohsin Kazmi  clib_error_t *err = 0;
2032df39094SDamjan Marion
20481284163SMatthew Smith  ifmsg.ifi_flags = ((up) ? IFF_UP : 0);
2052df39094SDamjan Marion  ifmsg.ifi_change = IFF_UP;
2062df39094SDamjan Marion  ifmsg.ifi_index = ifindex;
2072df39094SDamjan Marion
2082df39094SDamjan Marion  vnet_netlink_msg_init (&m, RTM_SETLINK, NLM_F_REQUEST,
2092df39094SDamjan Marion			 &ifmsg, sizeof (struct ifinfomsg));
210b9f1f158SMohsin Kazmi  err = vnet_netlink_msg_send (&m);
211b9f1f158SMohsin Kazmi  if (err)
212b9f1f158SMohsin Kazmi    err = clib_error_return (0, "set link state %U", format_clib_error, err);
213b9f1f158SMohsin Kazmi  return err;
2142df39094SDamjan Marion}
2152df39094SDamjan Marion
2162df39094SDamjan Marionclib_error_t *
2172df39094SDamjan Marionvnet_netlink_set_link_mtu (int ifindex, int mtu)
2182df39094SDamjan Marion{
2192df39094SDamjan Marion  vnet_netlink_msg_t m;
2202df39094SDamjan Marion  struct ifinfomsg ifmsg = { 0 };
221b9f1f158SMohsin Kazmi  clib_error_t *err = 0;
2222df39094SDamjan Marion
2232df39094SDamjan Marion  ifmsg.ifi_index = ifindex;
2242df39094SDamjan Marion
22591c6ef7cSDamjan Marion  vnet_netlink_msg_init (&m, RTM_SETLINK, NLM_F_REQUEST,
22691c6ef7cSDamjan Marion			 &ifmsg, sizeof (struct ifinfomsg));
22791c6ef7cSDamjan Marion  vnet_netlink_msg_add_rtattr (&m, IFLA_MTU, &mtu, sizeof (int));
228b9f1f158SMohsin Kazmi  err = vnet_netlink_msg_send (&m);
229b9f1f158SMohsin Kazmi  if (err)
230b9f1f158SMohsin Kazmi    err = clib_error_return (0, "set link mtu %U", format_clib_error, err);
231b9f1f158SMohsin Kazmi  return err;
23291c6ef7cSDamjan Marion}
23391c6ef7cSDamjan Marion
23491c6ef7cSDamjan Marionclib_error_t *
23591c6ef7cSDamjan Marionvnet_netlink_add_ip4_addr (int ifindex, void *addr, int pfx_len)
23691c6ef7cSDamjan Marion{
23791c6ef7cSDamjan Marion  vnet_netlink_msg_t m;
23891c6ef7cSDamjan Marion  struct ifaddrmsg ifa = { 0 };
239b9f1f158SMohsin Kazmi  clib_error_t *err = 0;
24091c6ef7cSDamjan Marion
24191c6ef7cSDamjan Marion  ifa.ifa_family = AF_INET;
24291c6ef7cSDamjan Marion  ifa.ifa_prefixlen = pfx_len;
24391c6ef7cSDamjan Marion  ifa.ifa_index = ifindex;
24491c6ef7cSDamjan Marion
24591c6ef7cSDamjan Marion  vnet_netlink_msg_init (&m, RTM_NEWADDR,
2467e86947dSDave Barach			 NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE,
24791c6ef7cSDamjan Marion			 &ifa, sizeof (struct ifaddrmsg));
24891c6ef7cSDamjan Marion
24991c6ef7cSDamjan Marion  vnet_netlink_msg_add_rtattr (&m, IFA_LOCAL, addr, 4);
25091c6ef7cSDamjan Marion  vnet_netlink_msg_add_rtattr (&m, IFA_ADDRESS, addr, 4);
251b9f1f158SMohsin Kazmi  err = vnet_netlink_msg_send (&m);
252b9f1f158SMohsin Kazmi  if (err)
253b9f1f158SMohsin Kazmi    err = clib_error_return (0, "add ip4 addr %U", format_clib_error, err);
254b9f1f158SMohsin Kazmi  return err;
25591c6ef7cSDamjan Marion}
25691c6ef7cSDamjan Marion
25791c6ef7cSDamjan Marionclib_error_t *
25891c6ef7cSDamjan Marionvnet_netlink_add_ip6_addr (int ifindex, void *addr, int pfx_len)
25991c6ef7cSDamjan Marion{
26091c6ef7cSDamjan Marion  vnet_netlink_msg_t m;
26191c6ef7cSDamjan Marion  struct ifaddrmsg ifa = { 0 };
262b9f1f158SMohsin Kazmi  clib_error_t *err = 0;
26391c6ef7cSDamjan Marion
26491c6ef7cSDamjan Marion  ifa.ifa_family = AF_INET6;
26591c6ef7cSDamjan Marion  ifa.ifa_prefixlen = pfx_len;
26691c6ef7cSDamjan Marion  ifa.ifa_index = ifindex;
26791c6ef7cSDamjan Marion
26891c6ef7cSDamjan Marion  vnet_netlink_msg_init (&m, RTM_NEWADDR,
2697e86947dSDave Barach			 NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE,
27091c6ef7cSDamjan Marion			 &ifa, sizeof (struct ifaddrmsg));
27191c6ef7cSDamjan Marion
27291c6ef7cSDamjan Marion  vnet_netlink_msg_add_rtattr (&m, IFA_LOCAL, addr, 16);
27391c6ef7cSDamjan Marion  vnet_netlink_msg_add_rtattr (&m, IFA_ADDRESS, addr, 16);
274b9f1f158SMohsin Kazmi  err = vnet_netlink_msg_send (&m);
275b9f1f158SMohsin Kazmi  if (err)
276b9f1f158SMohsin Kazmi    err = clib_error_return (0, "add ip6 addr %U", format_clib_error, err);
277b9f1f158SMohsin Kazmi  return err;
27817fdae73SDamjan Marion}
27917fdae73SDamjan Marion
2807866c459SDamjan Marionclib_error_t *
2817866c459SDamjan Marionvnet_netlink_add_ip4_route (void *dst, u8 dst_len, void *gw)
2827866c459SDamjan Marion{
2837866c459SDamjan Marion  vnet_netlink_msg_t m;
2847866c459SDamjan Marion  struct rtmsg rtm = { 0 };
2857866c459SDamjan Marion  u8 dflt[4] = { 0 };
286b9f1f158SMohsin Kazmi  clib_error_t *err = 0;
2877866c459SDamjan Marion
2887866c459SDamjan Marion  rtm.rtm_family = AF_INET;
2897866c459SDamjan Marion  rtm.rtm_table = RT_TABLE_MAIN;
2907866c459SDamjan Marion  rtm.rtm_type = RTN_UNICAST;
2917866c459SDamjan Marion  rtm.rtm_dst_len = dst_len;
2927866c459SDamjan Marion
2937866c459SDamjan Marion  vnet_netlink_msg_init (&m, RTM_NEWROUTE,
2947e86947dSDave Barach			 NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE,
2957866c459SDamjan Marion			 &rtm, sizeof (struct rtmsg));
2967866c459SDamjan Marion
2977866c459SDamjan Marion  vnet_netlink_msg_add_rtattr (&m, RTA_GATEWAY, gw, 4);
2987866c459SDamjan Marion  vnet_netlink_msg_add_rtattr (&m, RTA_DST, dst ? dst : dflt, 4);
299b9f1f158SMohsin Kazmi  err = vnet_netlink_msg_send (&m);
300b9f1f158SMohsin Kazmi  if (err)
301b9f1f158SMohsin Kazmi    err = clib_error_return (0, "add ip4 route %U", format_clib_error, err);
302b9f1f158SMohsin Kazmi  return err;
3037866c459SDamjan Marion}
3047866c459SDamjan Marion
3057866c459SDamjan Marionclib_error_t *
3067866c459SDamjan Marionvnet_netlink_add_ip6_route (void *dst, u8 dst_len, void *gw)
3077866c459SDamjan Marion{
3087866c459SDamjan Marion  vnet_netlink_msg_t m;
3097866c459SDamjan Marion  struct rtmsg rtm = { 0 };
3107866c459SDamjan Marion  u8 dflt[16] = { 0 };
311b9f1f158SMohsin Kazmi  clib_error_t *err = 0;
3127866c459SDamjan Marion
3137866c459SDamjan Marion  rtm.rtm_family = AF_INET6;
3147866c459SDamjan Marion  rtm.rtm_table = RT_TABLE_MAIN;
3157866c459SDamjan Marion  rtm.rtm_type = RTN_UNICAST;
3167866c459SDamjan Marion  rtm.rtm_dst_len = dst_len;
3177866c459SDamjan Marion
3187866c459SDamjan Marion  vnet_netlink_msg_init (&m, RTM_NEWROUTE,
3197e86947dSDave Barach			 NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE,
3207866c459SDamjan Marion			 &rtm, sizeof (struct rtmsg));
3217866c459SDamjan Marion
3227866c459SDamjan Marion  vnet_netlink_msg_add_rtattr (&m, RTA_GATEWAY, gw, 16);
3237866c459SDamjan Marion  vnet_netlink_msg_add_rtattr (&m, RTA_DST, dst ? dst : dflt, 16);
324b9f1f158SMohsin Kazmi  err = vnet_netlink_msg_send (&m);
325b9f1f158SMohsin Kazmi  if (err)
326b9f1f158SMohsin Kazmi    err = clib_error_return (0, "add ip6 route %U", format_clib_error, err);
327b9f1f158SMohsin Kazmi  return err;
3287866c459SDamjan Marion}
3297866c459SDamjan Marion
33017fdae73SDamjan Marion/*
33117fdae73SDamjan Marion * fd.io coding-style-patch-verification: ON
33217fdae73SDamjan Marion *
33317fdae73SDamjan Marion * Local Variables:
33417fdae73SDamjan Marion * eval: (c-set-style "gnu")
33517fdae73SDamjan Marion * End:
33617fdae73SDamjan Marion */