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
30typedef struct
31{
32  u8 *data;
33} vnet_netlink_msg_t;
34
35static void
36vnet_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  clib_memset (m, 0, sizeof (vnet_netlink_msg_t));
42  vec_add2 (m->data, p, NLMSG_SPACE (msg_len));
43  ASSERT (m->data == p);
44
45  nh = (struct nlmsghdr *) p;
46  nh->nlmsg_flags = flags | NLM_F_ACK;
47  nh->nlmsg_type = type;
48  clib_memcpy (m->data + sizeof (struct nlmsghdr), msg_data, msg_len);
49}
50
51static void
52vnet_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  vec_add2 (m->data, p, RTA_SPACE (rta_data_len));
59  rta = (struct rtattr *) p;
60  rta->rta_type = rta_type;
61  rta->rta_len = RTA_LENGTH (rta_data_len);
62  clib_memcpy (RTA_DATA (rta), rta_data, rta_data_len);
63}
64
65static clib_error_t *
66vnet_netlink_msg_send (vnet_netlink_msg_t * m)
67{
68  clib_error_t *err = 0;
69  struct sockaddr_nl ra = { 0 };
70  int len, sock;
71  struct nlmsghdr *nh = (struct nlmsghdr *) m->data;
72  nh->nlmsg_len = vec_len (m->data);
73  char buf[4096];
74
75  if ((sock = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1)
76    return clib_error_return_unix (0, "socket(AF_NETLINK)");
77
78  ra.nl_family = AF_NETLINK;
79  ra.nl_pid = 0;
80
81  if ((bind (sock, (struct sockaddr *) &ra, sizeof (ra))) == -1)
82    {
83      err = clib_error_return_unix (0, "bind");
84      goto done;
85    }
86
87  if ((send (sock, m->data, vec_len (m->data), 0)) == -1)
88    err = clib_error_return_unix (0, "send");
89
90  if ((len = recv (sock, buf, sizeof (buf), 0)) == -1)
91    err = clib_error_return_unix (0, "recv");
92
93  for (nh = (struct nlmsghdr *) buf; NLMSG_OK (nh, len);
94       nh = NLMSG_NEXT (nh, len))
95    {
96      if (nh->nlmsg_type == NLMSG_DONE)
97	goto done;
98
99      if (nh->nlmsg_type == NLMSG_ERROR)
100	{
101	  struct nlmsgerr *e = (struct nlmsgerr *) NLMSG_DATA (nh);
102	  if (e->error)
103	    err = clib_error_return (0, "netlink error %d", e->error);
104	  goto done;
105	}
106    }
107
108done:
109  close (sock);
110  vec_free (m->data);
111  return err;
112}
113
114clib_error_t *
115vnet_netlink_set_link_name (int ifindex, char *new_ifname)
116{
117  vnet_netlink_msg_t m;
118  struct ifinfomsg ifmsg = { 0 };
119  clib_error_t *err = 0;
120
121  ifmsg.ifi_index = ifindex;
122  vnet_netlink_msg_init (&m, RTM_SETLINK, NLM_F_REQUEST,
123			 &ifmsg, sizeof (struct ifinfomsg));
124
125  vnet_netlink_msg_add_rtattr (&m, IFLA_IFNAME, new_ifname,
126			       strlen (new_ifname) + 1);
127
128  err = vnet_netlink_msg_send (&m);
129  if (err)
130    err = clib_error_return (0, "set link name %U", format_clib_error, err);
131  return err;
132}
133
134clib_error_t *
135vnet_netlink_set_link_netns (int ifindex, int netns_fd, char *new_ifname)
136{
137  vnet_netlink_msg_t m;
138  struct ifinfomsg ifmsg = { 0 };
139  clib_error_t *err = 0;
140
141  ifmsg.ifi_index = ifindex;
142  vnet_netlink_msg_init (&m, RTM_SETLINK, NLM_F_REQUEST,
143			 &ifmsg, sizeof (struct ifinfomsg));
144
145  vnet_netlink_msg_add_rtattr (&m, IFLA_NET_NS_FD, &netns_fd, sizeof (int));
146  if (new_ifname)
147    vnet_netlink_msg_add_rtattr (&m, IFLA_IFNAME, new_ifname,
148				 strlen (new_ifname) + 1);
149
150  err = vnet_netlink_msg_send (&m);
151  if (err)
152    err = clib_error_return (0, "set link netns %U", format_clib_error, err);
153  return err;
154}
155
156clib_error_t *
157vnet_netlink_set_link_master (int ifindex, char *master_ifname)
158{
159  vnet_netlink_msg_t m;
160  struct ifinfomsg ifmsg = { 0 };
161  int i;
162  clib_error_t *err = 0;
163
164  ifmsg.ifi_index = ifindex;
165
166  if ((i = if_nametoindex (master_ifname)) == 0)
167    clib_error_return_unix (0, "unknown master interface '%s'",
168			    master_ifname);
169
170  vnet_netlink_msg_init (&m, RTM_SETLINK, NLM_F_REQUEST,
171			 &ifmsg, sizeof (struct ifinfomsg));
172  vnet_netlink_msg_add_rtattr (&m, IFLA_MASTER, &i, sizeof (int));
173  err = vnet_netlink_msg_send (&m);
174  if (err)
175    err = clib_error_return (0, "set link master %U", format_clib_error, err);
176  return err;
177}
178
179clib_error_t *
180vnet_netlink_set_link_addr (int ifindex, u8 * mac)
181{
182  vnet_netlink_msg_t m;
183  struct ifinfomsg ifmsg = { 0 };
184  clib_error_t *err = 0;
185
186  ifmsg.ifi_index = ifindex;
187
188  vnet_netlink_msg_init (&m, RTM_SETLINK, NLM_F_REQUEST,
189			 &ifmsg, sizeof (struct ifinfomsg));
190  vnet_netlink_msg_add_rtattr (&m, IFLA_ADDRESS, mac, 6);
191  err = vnet_netlink_msg_send (&m);
192  if (err)
193    err = clib_error_return (0, "set link addr %U", format_clib_error, err);
194  return err;
195}
196
197clib_error_t *
198vnet_netlink_set_link_state (int ifindex, int up)
199{
200  vnet_netlink_msg_t m;
201  struct ifinfomsg ifmsg = { 0 };
202  clib_error_t *err = 0;
203
204  ifmsg.ifi_flags = ((up) ? IFF_UP : 0);
205  ifmsg.ifi_change = IFF_UP;
206  ifmsg.ifi_index = ifindex;
207
208  vnet_netlink_msg_init (&m, RTM_SETLINK, NLM_F_REQUEST,
209			 &ifmsg, sizeof (struct ifinfomsg));
210  err = vnet_netlink_msg_send (&m);
211  if (err)
212    err = clib_error_return (0, "set link state %U", format_clib_error, err);
213  return err;
214}
215
216clib_error_t *
217vnet_netlink_set_link_mtu (int ifindex, int mtu)
218{
219  vnet_netlink_msg_t m;
220  struct ifinfomsg ifmsg = { 0 };
221  clib_error_t *err = 0;
222
223  ifmsg.ifi_index = ifindex;
224
225  vnet_netlink_msg_init (&m, RTM_SETLINK, NLM_F_REQUEST,
226			 &ifmsg, sizeof (struct ifinfomsg));
227  vnet_netlink_msg_add_rtattr (&m, IFLA_MTU, &mtu, sizeof (int));
228  err = vnet_netlink_msg_send (&m);
229  if (err)
230    err = clib_error_return (0, "set link mtu %U", format_clib_error, err);
231  return err;
232}
233
234clib_error_t *
235vnet_netlink_add_ip4_addr (int ifindex, void *addr, int pfx_len)
236{
237  vnet_netlink_msg_t m;
238  struct ifaddrmsg ifa = { 0 };
239  clib_error_t *err = 0;
240
241  ifa.ifa_family = AF_INET;
242  ifa.ifa_prefixlen = pfx_len;
243  ifa.ifa_index = ifindex;
244
245  vnet_netlink_msg_init (&m, RTM_NEWADDR,
246			 NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE,
247			 &ifa, sizeof (struct ifaddrmsg));
248
249  vnet_netlink_msg_add_rtattr (&m, IFA_LOCAL, addr, 4);
250  vnet_netlink_msg_add_rtattr (&m, IFA_ADDRESS, addr, 4);
251  err = vnet_netlink_msg_send (&m);
252  if (err)
253    err = clib_error_return (0, "add ip4 addr %U", format_clib_error, err);
254  return err;
255}
256
257clib_error_t *
258vnet_netlink_add_ip6_addr (int ifindex, void *addr, int pfx_len)
259{
260  vnet_netlink_msg_t m;
261  struct ifaddrmsg ifa = { 0 };
262  clib_error_t *err = 0;
263
264  ifa.ifa_family = AF_INET6;
265  ifa.ifa_prefixlen = pfx_len;
266  ifa.ifa_index = ifindex;
267
268  vnet_netlink_msg_init (&m, RTM_NEWADDR,
269			 NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE,
270			 &ifa, sizeof (struct ifaddrmsg));
271
272  vnet_netlink_msg_add_rtattr (&m, IFA_LOCAL, addr, 16);
273  vnet_netlink_msg_add_rtattr (&m, IFA_ADDRESS, addr, 16);
274  err = vnet_netlink_msg_send (&m);
275  if (err)
276    err = clib_error_return (0, "add ip6 addr %U", format_clib_error, err);
277  return err;
278}
279
280clib_error_t *
281vnet_netlink_add_ip4_route (void *dst, u8 dst_len, void *gw)
282{
283  vnet_netlink_msg_t m;
284  struct rtmsg rtm = { 0 };
285  u8 dflt[4] = { 0 };
286  clib_error_t *err = 0;
287
288  rtm.rtm_family = AF_INET;
289  rtm.rtm_table = RT_TABLE_MAIN;
290  rtm.rtm_type = RTN_UNICAST;
291  rtm.rtm_dst_len = dst_len;
292
293  vnet_netlink_msg_init (&m, RTM_NEWROUTE,
294			 NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE,
295			 &rtm, sizeof (struct rtmsg));
296
297  vnet_netlink_msg_add_rtattr (&m, RTA_GATEWAY, gw, 4);
298  vnet_netlink_msg_add_rtattr (&m, RTA_DST, dst ? dst : dflt, 4);
299  err = vnet_netlink_msg_send (&m);
300  if (err)
301    err = clib_error_return (0, "add ip4 route %U", format_clib_error, err);
302  return err;
303}
304
305clib_error_t *
306vnet_netlink_add_ip6_route (void *dst, u8 dst_len, void *gw)
307{
308  vnet_netlink_msg_t m;
309  struct rtmsg rtm = { 0 };
310  u8 dflt[16] = { 0 };
311  clib_error_t *err = 0;
312
313  rtm.rtm_family = AF_INET6;
314  rtm.rtm_table = RT_TABLE_MAIN;
315  rtm.rtm_type = RTN_UNICAST;
316  rtm.rtm_dst_len = dst_len;
317
318  vnet_netlink_msg_init (&m, RTM_NEWROUTE,
319			 NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE,
320			 &rtm, sizeof (struct rtmsg));
321
322  vnet_netlink_msg_add_rtattr (&m, RTA_GATEWAY, gw, 16);
323  vnet_netlink_msg_add_rtattr (&m, RTA_DST, dst ? dst : dflt, 16);
324  err = vnet_netlink_msg_send (&m);
325  if (err)
326    err = clib_error_return (0, "add ip6 route %U", format_clib_error, err);
327  return err;
328}
329
330/*
331 * fd.io coding-style-patch-verification: ON
332 *
333 * Local Variables:
334 * eval: (c-set-style "gnu")
335 * End:
336 */
337