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