mapper.c revision 41d2e788
1/*
2 * Copyright (c) 2016 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include <librtnl/mapper.h>
17#include <librtnl/netns.h>
18
19#include <vnet/ip/ip.h>
20#include <vnet/ip/lookup.h>
21
22typedef struct {
23  int linux_ifindex;
24  u32 sw_if_index;
25} mapper_map_t;
26
27typedef struct {
28  char nsname[RTNL_NETNS_NAMELEN + 1];
29  mapper_map_t *mappings;
30  u32 netns_handle; //Used to receive notifications
31  u32 v4fib_index; //One fib index for the namespace
32  u32 v6fib_index;
33} mapper_ns_t;
34
35typedef struct {
36  mapper_ns_t *namespaces;
37} mapper_main_t;
38
39static mapper_main_t mapper_main;
40
41mapper_map_t *mapper_get_by_ifindex(mapper_ns_t *ns, int ifindex)
42{
43  mapper_map_t *map;
44  pool_foreach(map, ns->mappings, {
45      if (ifindex == map->linux_ifindex)
46        return map;
47  });
48  return NULL;
49}
50
51int mapper_add_del_route(mapper_ns_t *ns, ns_route_t *route, int del)
52{
53  mapper_main_t *mm = &mapper_main;
54  clib_warning("NS %d %s %U", ns - mm->namespaces, del?"del":"add", format_ns_route, route);
55
56  mapper_map_t *map = mapper_get_by_ifindex(ns, route->oif);
57  if (!map)
58    return 0;
59
60  if (route->rtm.rtm_family == AF_INET6) {
61
62    //Filter-out multicast
63    if (route->rtm.rtm_dst_len >= 8 && route->dst[0] == 0xff)
64      return 0;
65
66    struct ip6_main_t *im = &ip6_main;
67    ip6_add_del_route_next_hop(im, //ip6_main
68                               del?IP6_ROUTE_FLAG_DEL:IP6_ROUTE_FLAG_ADD,  //flags (not del)
69                               (ip6_address_t *)&route->dst[0], //Dst addr
70                               route->rtm.rtm_dst_len, //Plen
71                               (ip6_address_t *)&route->gateway[0], //next-hop
72                               map->sw_if_index, //sw_if_index
73                               0, //weight
74                               ~0, //adj_index
75                               ns->v6fib_index);
76  } else {
77    struct ip4_main_t *im = &ip4_main;
78    ip4_add_del_route_next_hop(im, //ip4_main
79                               del?IP4_ROUTE_FLAG_DEL:IP4_ROUTE_FLAG_ADD,  //flags (not del)
80                               (ip4_address_t *)&route->dst[0], //Dst addr
81                               route->rtm.rtm_dst_len, //Plen
82                               (ip4_address_t *)&route->gateway[0], //next-hop
83                               map->sw_if_index, //sw_if_index
84                               0, //weight
85                               ~0, //adj_index
86                               ns->v4fib_index);
87  }
88
89  return 0;
90}
91
92static void
93mapper_netns_notify_cb(void *obj, netns_type_t type,
94                       u32 flags, uword opaque)
95{
96  mapper_main_t *mm = &mapper_main;
97  mapper_ns_t *ns = &mm->namespaces[(u32) opaque];
98  ASSERT(!pool_is_free_index(mm->namespaces, (u32) opaque));
99  if (type != NETNS_TYPE_ROUTE)
100    return; //For now...
101
102  ns_route_t *route = obj;
103  if (flags & NETNS_F_DEL) {
104    mapper_add_del_route(ns, route, 1);
105  } else if (flags & NETNS_F_ADD) {
106    mapper_add_del_route(ns, route, 0);
107  }
108}
109
110void
111mapper_delmap(mapper_ns_t*ns, mapper_map_t *map)
112{
113  ns_route_t *route;
114  netns_t *netns = netns_getns(ns->netns_handle);
115  pool_foreach(route, netns->routes, {
116      if (route->oif == map->linux_ifindex)
117        mapper_add_del_route(ns, route, 1);
118  });
119  pool_put(ns->mappings, map);
120}
121
122mapper_map_t *
123mapper_getmap(mapper_ns_t*ns, u32 sw_if_index,
124              int linux_ifindex, int create)
125{
126  mapper_map_t *map;
127  pool_foreach(map, ns->mappings, {
128      if (linux_ifindex == map->linux_ifindex) {
129        if (sw_if_index != map->sw_if_index)
130          return NULL; //Cannot have multiple mapping with the same ifindex
131        else
132          return map;
133      }
134  });
135
136  if (!create)
137    return NULL;
138
139  pool_get(ns->mappings, map);
140  map->linux_ifindex = linux_ifindex;
141  map->sw_if_index = sw_if_index;
142  ip6_main.fib_index_by_sw_if_index[sw_if_index] = ns->v6fib_index;
143  ip4_main.fib_index_by_sw_if_index[sw_if_index] = ns->v4fib_index;
144
145  //Load available routes
146  ns_route_t *route;
147  netns_t *netns = netns_getns(ns->netns_handle);
148  pool_foreach(route, netns->routes, {
149      if (route->oif == map->linux_ifindex)
150        mapper_add_del_route(ns, route, 0);
151  });
152  return map;
153}
154
155u32
156mapper_get_ns(char *nsname)
157{
158  mapper_main_t *mm = &mapper_main;
159  mapper_ns_t *ns;
160  pool_foreach(ns, mm->namespaces, {
161      if (!strcmp(nsname, ns->nsname))
162        return ns - mm->namespaces;
163  });
164  return ~0;
165}
166
167int
168mapper_add_del(u32 nsindex, int linux_ifindex,
169               u32 sw_if_index, int del)
170{
171  mapper_main_t *mm = &mapper_main;
172  //ip6_main_t *im6 = &ip6_main;
173  mapper_ns_t *ns = &mm->namespaces[nsindex];
174  mapper_map_t *map;
175  //vnet_sw_interface_t *iface = vnet_get_sw_interface(vnet_get_main(), sw_if_index);
176
177  if (pool_is_free(mm->namespaces, ns))
178    return -1;
179
180  /*if (!del) {
181    if ((iface->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) &&
182        im6->fib_index_by_sw_if_index[sw_if_index] != ~0) {
183      //A custom fib index will be used...
184      clib_warning("Cannot add interface with a custom fib index (current is %d)",
185                   im6->fib_index_by_sw_if_index[sw_if_index]);
186      return -1;
187    }
188  }*/
189
190  if (!(map = mapper_getmap(ns, sw_if_index, linux_ifindex, !del)))
191    return -1;
192
193  if (del)
194    mapper_delmap(ns, map);
195
196  return 0;
197}
198
199int
200mapper_add_ns(char *nsname, u32 v4fib_index, u32 v6fib_index, u32 *nsindex)
201{
202  mapper_main_t *mm = &mapper_main;
203  mapper_ns_t *ns;
204  if (mapper_get_ns(nsname) != ~0)
205    return -1; //Already exists
206
207  pool_get(mm->namespaces, ns);
208  strcpy(ns->nsname, nsname);
209  ns->v4fib_index = v4fib_index;
210  ns->v6fib_index = v6fib_index;
211  ns->mappings = 0;
212
213  netns_sub_t sub;
214  sub.notify = mapper_netns_notify_cb;
215  sub.opaque = (uword)(ns - mm->namespaces);
216  if ((ns->netns_handle = netns_open(ns->nsname, &sub)) == ~0) {
217    pool_put(mm->namespaces, ns);
218    return -1;
219  }
220  *nsindex = ns - mm->namespaces;
221  return 0;
222}
223
224int
225mapper_del_ns(u32 nsindex)
226{
227  mapper_main_t *mm = &mapper_main;
228  mapper_ns_t *ns = &mm->namespaces[nsindex];
229  if (pool_is_free(mm->namespaces, ns))
230    return -1;
231
232  //Remove all existing mappings
233  int i, *indexes = 0;
234  pool_foreach_index(i, ns->mappings, {
235    vec_add1(indexes, i);
236  });
237  vec_foreach_index(i, indexes) {
238    mapper_delmap(ns, &ns->mappings[indexes[i]]);
239  }
240  vec_free(indexes);
241
242  netns_close(ns->netns_handle);
243  pool_put(mm->namespaces, ns);
244  return 0;
245}
246
247clib_error_t *
248mapper_init (vlib_main_t * vm)
249{
250  mapper_main_t *mm = &mapper_main;
251  mm->namespaces = 0;
252  return 0;
253}
254
255VLIB_INIT_FUNCTION (mapper_init);
256