tap_inject_netlink.c revision dfae7756
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
23
24static void
25add_del_addr (ns_addr_t * a, int is_del)
26{
27  vlib_main_t * vm = vlib_get_main ();
28  u32 sw_if_index;
29
30  sw_if_index = tap_inject_lookup_sw_if_index_from_tap_if_index (
31                        a->ifaddr.ifa_index);
32
33  if (sw_if_index == ~0)
34    return;
35
36  if (a->ifaddr.ifa_family == AF_INET)
37    {
38      ip4_add_del_interface_address (vm, sw_if_index,
39          (ip4_address_t *) a->local, a->ifaddr.ifa_prefixlen, is_del);
40    }
41  else if (a->ifaddr.ifa_family == AF_INET6)
42    {
43      ip6_add_del_interface_address (vm, sw_if_index,
44          (ip6_address_t *) a->addr, a->ifaddr.ifa_prefixlen, is_del);
45    }
46}
47
48
49struct set_flags_args {
50  u32 index;
51  u8 flags;
52};
53
54static void
55set_flags_cb (struct set_flags_args * a)
56{
57  vnet_sw_interface_set_flags (vnet_get_main (), a->index, a->flags);
58}
59
60static void
61add_del_link (ns_link_t * l, int is_del)
62{
63  struct set_flags_args args = { ~0, 0 };
64  vnet_sw_interface_t * sw;
65  u8 flags = 0;
66  u32 sw_if_index;
67
68  sw_if_index = tap_inject_lookup_sw_if_index_from_tap_if_index (
69                        l->ifi.ifi_index);
70
71  if (sw_if_index == ~0)
72    return;
73
74  sw = vnet_get_sw_interface (vnet_get_main (), sw_if_index);
75
76  flags = sw->flags;
77
78  if (l->ifi.ifi_flags & IFF_UP)
79    flags |= VNET_SW_INTERFACE_FLAG_ADMIN_UP;
80  else
81    flags &= ~VNET_SW_INTERFACE_FLAG_ADMIN_UP;
82
83  args.index = sw_if_index;
84  args.flags = flags;
85
86  vl_api_rpc_call_main_thread (set_flags_cb, (u8 *)&args, sizeof (args));
87}
88
89
90static void
91add_del_neigh (ns_neigh_t * n, int is_del)
92{
93  vnet_main_t * vnet_main = vnet_get_main ();
94  vlib_main_t * vm = vlib_get_main ();
95  u32 sw_if_index;
96
97  sw_if_index = tap_inject_lookup_sw_if_index_from_tap_if_index (
98                        n->nd.ndm_ifindex);
99
100  if (sw_if_index == ~0)
101    return;
102
103  if (n->nd.ndm_family == AF_INET)
104    {
105      ethernet_arp_ip4_over_ethernet_address_t a;
106
107      memset (&a, 0, sizeof (a));
108
109      clib_memcpy (&a.ethernet, n->lladdr, ETHER_ADDR_LEN);
110      clib_memcpy (&a.ip4, n->dst, sizeof (a.ip4));
111
112      if (n->nd.ndm_state & NUD_REACHABLE)
113        vnet_arp_set_ip4_over_ethernet (vnet_main, sw_if_index, ~0, &a, 0);
114      else if (n->nd.ndm_state & NUD_FAILED)
115        vnet_arp_unset_ip4_over_ethernet (vnet_main, sw_if_index, ~0, &a);
116    }
117  else if (n->nd.ndm_family == AF_INET6)
118    {
119      if (n->nd.ndm_state & NUD_REACHABLE)
120        vnet_set_ip6_ethernet_neighbor (vm, sw_if_index,
121            (ip6_address_t *) n->dst, n->lladdr, ETHER_ADDR_LEN, 0);
122      else
123        vnet_unset_ip6_ethernet_neighbor (vm, sw_if_index,
124            (ip6_address_t *) n->dst, n->lladdr, ETHER_ADDR_LEN);
125    }
126}
127
128
129#define TAP_INJECT_HOST_ROUTE_TABLE_MAIN 254
130
131static void
132add_del_route (ns_route_t * r, int is_del)
133{
134  u32 sw_if_index;
135
136  sw_if_index = tap_inject_lookup_sw_if_index_from_tap_if_index (r->oif);
137
138  if (sw_if_index == ~0 || r->table != TAP_INJECT_HOST_ROUTE_TABLE_MAIN)
139    return;
140
141  if (r->rtm.rtm_family == AF_INET)
142    {
143      ip4_add_del_route_next_hop (&ip4_main,
144          is_del ? IP4_ROUTE_FLAG_DEL : IP4_ROUTE_FLAG_ADD,
145          (ip4_address_t *) r->dst, r->rtm.rtm_dst_len,
146          (ip4_address_t *) r->gateway, sw_if_index, 0, ~0, 0);
147    }
148  else if (r->rtm.rtm_family == AF_INET6)
149    {
150      ip6_add_del_route_next_hop (&ip6_main,
151          is_del ? IP6_ROUTE_FLAG_DEL : IP6_ROUTE_FLAG_ADD,
152          (ip6_address_t *) r->dst, r->rtm.rtm_dst_len,
153          (ip6_address_t *) r->gateway, sw_if_index, 0, ~0, 0);
154    }
155}
156
157
158static void
159netns_notify_cb (void * obj, netns_type_t type, u32 flags, uword opaque)
160{
161  if (type == NETNS_TYPE_ADDR)
162    add_del_addr ((ns_addr_t *)obj, flags & NETNS_F_DEL);
163
164  else if (type == NETNS_TYPE_LINK)
165    add_del_link ((ns_link_t *)obj, flags & NETNS_F_DEL);
166
167  else if (type == NETNS_TYPE_NEIGH)
168    add_del_neigh ((ns_neigh_t *)obj, flags & NETNS_F_DEL);
169
170  else if (type == NETNS_TYPE_ROUTE)
171    add_del_route ((ns_route_t *)obj, flags & NETNS_F_DEL);
172}
173
174void
175tap_inject_enable_netlink (void)
176{
177  char nsname = 0;
178  netns_sub_t sub = {
179    .notify = netns_notify_cb,
180    .opaque = 0,
181  };
182
183  netns_open (&nsname, &sub);
184}
185