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