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