tap_inject_netlink.c revision 2ab698c9
1/*
2 * Copyright 2016 Intel Corporation
3 *
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#include "tap_inject.h"
18#include <librtnl/netns.h>
19#include <vlibmemory/api.h>
20#include <vnet/ethernet/arp_packet.h>
21#include <vnet/ip/ip6_neighbor.h>
22
23#include <vnet/ip/ip.h>
24#include <vnet/ip/lookup.h>
25#ifdef ip6_add_del_route_next_hop
26#define FIB_VERSION 1
27#else
28#include <vnet/fib/fib.h>
29#define FIB_VERSION 2
30#endif
31
32#include <arpa/inet.h>
33#include <linux/mpls.h>
34#include <vnet/mpls/packet.h>
35
36static void
37add_del_addr (ns_addr_t * a, int is_del)
38{
39  vlib_main_t * vm = vlib_get_main ();
40  u32 sw_if_index;
41
42  sw_if_index = tap_inject_lookup_sw_if_index_from_tap_if_index (
43                                                                 a->ifaddr.ifa_index);
44
45  if (sw_if_index == ~0)
46    return;
47
48  if (a->ifaddr.ifa_family == AF_INET)
49    {
50      ip4_add_del_interface_address (vm, sw_if_index,
51                                     (ip4_address_t *) a->local, a->ifaddr.ifa_prefixlen, is_del);
52    }
53  else if (a->ifaddr.ifa_family == AF_INET6)
54    {
55      ip6_add_del_interface_address (vm, sw_if_index,
56                                     (ip6_address_t *) a->addr, a->ifaddr.ifa_prefixlen, is_del);
57    }
58}
59
60
61struct set_flags_args {
62  u32 index;
63  u8 flags;
64};
65
66static void
67set_flags_cb (struct set_flags_args * a)
68{
69  vnet_sw_interface_set_flags (vnet_get_main (), a->index, a->flags);
70}
71
72static void
73add_del_link (ns_link_t * l, int is_del)
74{
75  struct set_flags_args args = { ~0, 0 };
76  vnet_sw_interface_t * sw;
77  u8 flags = 0;
78  u32 sw_if_index;
79
80  sw_if_index = tap_inject_lookup_sw_if_index_from_tap_if_index (
81                                                                 l->ifi.ifi_index);
82
83  if (sw_if_index == ~0)
84    return;
85
86  sw = vnet_get_sw_interface (vnet_get_main (), sw_if_index);
87
88  flags = sw->flags;
89
90  if (l->ifi.ifi_flags & IFF_UP)
91    flags |= VNET_SW_INTERFACE_FLAG_ADMIN_UP;
92  else
93    flags &= ~VNET_SW_INTERFACE_FLAG_ADMIN_UP;
94
95  args.index = sw_if_index;
96  args.flags = flags;
97
98  vl_api_rpc_call_main_thread (set_flags_cb, (u8 *)&args, sizeof (args));
99}
100
101
102static void
103add_del_neigh (ns_neigh_t * n, int is_del)
104{
105  vnet_main_t * vnet_main = vnet_get_main ();
106  vlib_main_t * vm = vlib_get_main ();
107  u32 sw_if_index;
108
109  sw_if_index = tap_inject_lookup_sw_if_index_from_tap_if_index (
110                                                                 n->nd.ndm_ifindex);
111
112  if (sw_if_index == ~0)
113    return;
114
115  if (n->nd.ndm_family == AF_INET)
116    {
117      ethernet_arp_ip4_over_ethernet_address_t a;
118
119      memset (&a, 0, sizeof (a));
120
121      clib_memcpy (&a.ethernet, n->lladdr, ETHER_ADDR_LEN);
122      clib_memcpy (&a.ip4, n->dst, sizeof (a.ip4));
123
124
125      if (n->nd.ndm_state & NUD_REACHABLE)
126        {
127#if FIB_VERSION == 1
128          vnet_arp_set_ip4_over_ethernet (vnet_main, sw_if_index, ~0, &a, 0);
129#else
130          vnet_arp_set_ip4_over_ethernet (vnet_main, sw_if_index,
131                                          &a, 0 /* static */ ,
132                                          0 /* no fib entry */);
133
134#endif /* FIB_VERSION == 1 */
135        }
136      else if (n->nd.ndm_state & NUD_FAILED)
137        {
138#if FIB_VERSION == 1
139          vnet_arp_unset_ip4_over_ethernet (vnet_main, sw_if_index, ~0, &a);
140#else
141          vnet_arp_unset_ip4_over_ethernet (vnet_main, sw_if_index, &a);
142#endif /* FIB_VERSION == 1 */
143        }
144    }
145  else if (n->nd.ndm_family == AF_INET6)
146    {
147      if (n->nd.ndm_state & NUD_REACHABLE)
148        {
149#if FIB_VERSION == 1
150          vnet_set_ip6_ethernet_neighbor (vm, sw_if_index,
151                                          (ip6_address_t *) n->dst, n->lladdr, ETHER_ADDR_LEN, 0);
152#else
153          vnet_set_ip6_ethernet_neighbor (vm, sw_if_index,
154                                          (ip6_address_t *) n->dst, n->lladdr, ETHER_ADDR_LEN,
155                                          0 /* static */,
156                                          0 /* no fib entry */);
157#endif /* FIB_VERSION == 1 */
158        }
159      else
160        vnet_unset_ip6_ethernet_neighbor (vm, sw_if_index,
161                                          (ip6_address_t *) n->dst, n->lladdr, ETHER_ADDR_LEN);
162    }
163}
164
165
166#define TAP_INJECT_HOST_ROUTE_TABLE_MAIN 254
167
168static void
169get_mpls_label_stack(struct mpls_label *addr, u32* l)
170{
171  u32 entry = ntohl(addr[0].entry);
172  u32 label = (entry & MPLS_LS_LABEL_MASK) >> MPLS_LS_LABEL_SHIFT;
173
174  for(int i = 1; label != 0; i++) {
175    *l++ = label;
176    if(entry & MPLS_LS_S_MASK)
177      return;
178    entry = ntohl(addr[i].entry);
179    label = (entry & MPLS_LS_LABEL_MASK) >> MPLS_LS_LABEL_SHIFT;
180  }
181}
182
183static void
184add_del_route (ns_route_t * r, int is_del)
185{
186  u32 sw_if_index;
187
188  sw_if_index = tap_inject_lookup_sw_if_index_from_tap_if_index (r->oif);
189
190  if (sw_if_index == ~0)
191    return;
192
193  if (r->rtm.rtm_family == AF_INET)
194    {
195      u32 stack[MPLS_STACK_DEPTH] = {0};
196
197#if FIB_VERSION == 1
198      ip4_add_del_route_next_hop (&ip4_main,
199                                  is_del ? IP4_ROUTE_FLAG_DEL : IP4_ROUTE_FLAG_ADD,
200                                  (ip4_address_t *) r->dst, r->rtm.rtm_dst_len,
201                                  (ip4_address_t *) r->gateway, sw_if_index, 0, ~0, 0);
202#else
203      fib_prefix_t prefix;
204      ip46_address_t nh;
205
206      memset (&prefix, 0, sizeof (prefix));
207      prefix.fp_len = r->rtm.rtm_dst_len;
208      prefix.fp_proto = FIB_PROTOCOL_IP4;
209      clib_memcpy (&prefix.fp_addr.ip4, r->dst, sizeof (prefix.fp_addr.ip4));
210      get_mpls_label_stack(r->encap, stack);
211      memset (&nh, 0, sizeof (nh));
212      clib_memcpy (&nh.ip4, r->gateway, sizeof (nh.ip4));
213      if(*stack == 0)
214        fib_table_entry_path_add (0, &prefix, FIB_SOURCE_API,
215                                  FIB_ENTRY_FLAG_NONE, prefix.fp_proto,
216                                  &nh, sw_if_index, 0,
217                                  0 /* weight */, NULL,
218                                  FIB_ROUTE_PATH_FLAG_NONE);
219      else {
220        fib_route_path_t *rpaths = NULL, rpath;
221        memset(&rpath, 0, sizeof(rpath));
222        rpath.frp_weight = 1;
223        rpath.frp_proto = DPO_PROTO_IP4;
224        clib_memcpy(&rpath.frp_addr.ip4, r->gateway, sizeof(rpath.frp_addr.ip4));
225        rpath.frp_sw_if_index = sw_if_index;
226        for(int i = 0; i < MPLS_STACK_DEPTH && stack[i] != 0; i++) {
227          fib_mpls_label_t fib_label = {stack[i],0,0,0};
228          vec_add1(rpath.frp_label_stack, fib_label);
229        }
230        vec_add1(rpaths, rpath);
231        fib_table_entry_path_add2(0,
232                                  &prefix,
233                                  FIB_SOURCE_API,
234                                  FIB_ENTRY_FLAG_NONE,
235                                  rpaths);
236      }
237#endif /* FIB_VERSION == 1 */
238    }
239  else if (r->rtm.rtm_family == AF_INET6)
240    {
241#if FIB_VERSION == 1
242      ip6_add_del_route_next_hop (&ip6_main,
243                                  is_del ? IP6_ROUTE_FLAG_DEL : IP6_ROUTE_FLAG_ADD,
244                                  (ip6_address_t *) r->dst, r->rtm.rtm_dst_len,
245                                  (ip6_address_t *) r->gateway, sw_if_index, 0, ~0, 0);
246#else
247      fib_prefix_t prefix;
248      ip46_address_t nh;
249      memset (&prefix, 0, sizeof (prefix));
250      prefix.fp_len = r->rtm.rtm_dst_len;
251      prefix.fp_proto = FIB_PROTOCOL_IP6;
252      clib_memcpy (&prefix.fp_addr.ip6, r->dst, sizeof (prefix.fp_addr.ip6));
253      memset (&nh, 0, sizeof (nh));
254      clib_memcpy (&nh.ip6, r->gateway, sizeof (nh.ip6));
255      fib_table_entry_path_add (0, &prefix, FIB_SOURCE_API,
256                                FIB_ENTRY_FLAG_NONE, prefix.fp_proto,
257                                &nh, sw_if_index, 0,
258                                0 /* weight */, NULL,
259                                FIB_ROUTE_PATH_FLAG_NONE);
260#endif /* FIB_VERSION == 1 */
261    }
262  else if (r->rtm.rtm_family == AF_MPLS)
263    {
264      u32 dst_label;
265      get_mpls_label_stack((struct mpls_label*) r->dst, &dst_label);
266      struct rtvia *via = (struct rtvia*) r->via;
267      fib_prefix_t prefix;
268      fib_route_path_t *rpaths = NULL, rpath;
269      memset (&prefix, 0, sizeof (prefix));
270      prefix.fp_len = 21;
271      prefix.fp_label = dst_label;
272      prefix.fp_proto = FIB_PROTOCOL_MPLS;
273      prefix.fp_payload_proto = DPO_PROTO_IP4;
274      memset(&rpath, 0, sizeof(rpath));
275      clib_memcpy (&rpath.frp_addr.ip4, via->rtvia_addr, sizeof (rpath.frp_addr.ip4));
276      rpath.frp_weight = 1;
277      rpath.frp_proto = DPO_PROTO_IP4;
278      rpath.frp_fib_index = 0;
279      rpath.frp_sw_if_index = sw_if_index;
280      vec_add1(rpaths, rpath);
281      fib_table_entry_path_add2(0,
282                                &prefix,
283                                FIB_SOURCE_API,
284                                FIB_ENTRY_FLAG_NONE,
285                                rpaths);
286    }
287}
288
289
290static void
291netns_notify_cb (void * obj, netns_type_t type, u32 flags, uword opaque)
292{
293  if (type == NETNS_TYPE_ADDR)
294    add_del_addr ((ns_addr_t *)obj, flags & NETNS_F_DEL);
295
296  else if (type == NETNS_TYPE_LINK)
297    add_del_link ((ns_link_t *)obj, flags & NETNS_F_DEL);
298
299  else if (type == NETNS_TYPE_NEIGH)
300    add_del_neigh ((ns_neigh_t *)obj, flags & NETNS_F_DEL);
301
302  else if (type == NETNS_TYPE_ROUTE)
303    add_del_route ((ns_route_t *)obj, flags & NETNS_F_DEL);
304}
305
306void
307tap_inject_enable_netlink (void)
308{
309  char nsname = 0;
310  netns_sub_t sub = {
311    .notify = netns_notify_cb,
312    .opaque = 0,
313  };
314
315  netns_open (&nsname, &sub);
316}
317