Line data Source code
1 : /*
2 : * Copyright (c) 2020 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 : #define _GNU_SOURCE
17 : #include <fcntl.h>
18 : #include <ctype.h>
19 : #include <sys/socket.h>
20 : #include <net/if.h>
21 :
22 : #include <linux-cp/lcp_interface.h>
23 : #include <netlink/route/link/vlan.h>
24 : #include <linux/if_ether.h>
25 :
26 : #include <vnet/plugin/plugin.h>
27 : #include <vnet/plugin/plugin.h>
28 :
29 : #include <vppinfra/linux/netns.h>
30 :
31 : #include <vnet/ip/ip_punt_drop.h>
32 : #include <vnet/fib/fib_table.h>
33 : #include <vnet/adj/adj_mcast.h>
34 : #include <vnet/udp/udp.h>
35 : #include <vnet/tcp/tcp.h>
36 : #include <vnet/devices/tap/tap.h>
37 : #include <vnet/devices/virtio/virtio.h>
38 : #include <vnet/devices/netlink.h>
39 : #include <vlibapi/api_helper_macros.h>
40 : #include <vnet/ipsec/ipsec_punt.h>
41 :
42 : vlib_log_class_t lcp_itf_pair_logger;
43 :
44 : /**
45 : * Pool of LIP objects
46 : */
47 : lcp_itf_pair_t *lcp_itf_pair_pool = NULL;
48 :
49 : u32
50 0 : lcp_itf_num_pairs (void)
51 : {
52 0 : return pool_elts (lcp_itf_pair_pool);
53 : }
54 :
55 : /**
56 : * DBs of interface-pair objects:
57 : * - key'd by VIF (linux ID)
58 : * - key'd by VPP's physical interface
59 : * - number of shared uses of VPP's tap/host interface
60 : */
61 : static uword *lip_db_by_vif;
62 : index_t *lip_db_by_phy;
63 : u32 *lip_db_by_host;
64 :
65 : /**
66 : * vector of virtual function table
67 : */
68 : static lcp_itf_pair_vft_t *lcp_itf_vfts = NULL;
69 :
70 : void
71 2 : lcp_itf_pair_register_vft (lcp_itf_pair_vft_t *lcp_itf_vft)
72 : {
73 2 : vec_add1 (lcp_itf_vfts, *lcp_itf_vft);
74 2 : }
75 :
76 : u8 *
77 5 : format_lcp_itf_pair (u8 *s, va_list *args)
78 : {
79 5 : vnet_main_t *vnm = vnet_get_main ();
80 5 : lcp_itf_pair_t *lip = va_arg (*args, lcp_itf_pair_t *);
81 : vnet_sw_interface_t *swif_phy;
82 : vnet_sw_interface_t *swif_host;
83 :
84 5 : s = format (s, "itf-pair: [%d]", lip - lcp_itf_pair_pool);
85 :
86 5 : swif_phy = vnet_get_sw_interface_or_null (vnm, lip->lip_phy_sw_if_index);
87 5 : if (!swif_phy)
88 0 : s = format (s, " <no-phy-if>");
89 : else
90 5 : s = format (s, " %U", format_vnet_sw_interface_name, vnm, swif_phy);
91 :
92 5 : swif_host = vnet_get_sw_interface_or_null (vnm, lip->lip_host_sw_if_index);
93 5 : if (!swif_host)
94 0 : s = format (s, " <no-host-if>");
95 : else
96 5 : s = format (s, " %U", format_vnet_sw_interface_name, vnm, swif_host);
97 :
98 5 : s = format (s, " %v %d type %s", lip->lip_host_name, lip->lip_vif_index,
99 5 : (lip->lip_host_type == LCP_ITF_HOST_TAP) ? "tap" : "tun");
100 :
101 5 : if (lip->lip_namespace)
102 0 : s = format (s, " netns %s", lip->lip_namespace);
103 :
104 5 : return s;
105 : }
106 :
107 : static walk_rc_t
108 5 : lcp_itf_pair_walk_show_cb (index_t api, void *ctx)
109 : {
110 : vlib_main_t *vm;
111 : lcp_itf_pair_t *lip;
112 :
113 5 : lip = lcp_itf_pair_get (api);
114 5 : if (!lip)
115 0 : return WALK_STOP;
116 :
117 5 : vm = vlib_get_main ();
118 5 : vlib_cli_output (vm, "%U\n", format_lcp_itf_pair, lip);
119 :
120 5 : return WALK_CONTINUE;
121 : }
122 :
123 : void
124 3 : lcp_itf_pair_show (u32 phy_sw_if_index)
125 : {
126 : vlib_main_t *vm;
127 : u8 *ns;
128 : index_t api;
129 :
130 3 : vm = vlib_get_main ();
131 3 : ns = lcp_get_default_ns ();
132 3 : vlib_cli_output (vm, "lcp default netns '%s'\n",
133 : ns ? (char *) ns : "<unset>");
134 3 : vlib_cli_output (vm, "lcp lcp-auto-subint %s\n",
135 3 : lcp_auto_subint () ? "on" : "off");
136 3 : vlib_cli_output (vm, "lcp lcp-sync %s\n", lcp_sync () ? "on" : "off");
137 3 : vlib_cli_output (vm, "lcp del-static-on-link-down %s\n",
138 3 : lcp_get_del_static_on_link_down () ? "on" : "off");
139 3 : vlib_cli_output (vm, "lcp del-dynamic-on-link-down %s\n",
140 3 : lcp_get_del_dynamic_on_link_down () ? "on" : "off");
141 :
142 3 : if (phy_sw_if_index == ~0)
143 : {
144 3 : lcp_itf_pair_walk (lcp_itf_pair_walk_show_cb, 0);
145 : }
146 : else
147 : {
148 0 : api = lcp_itf_pair_find_by_phy (phy_sw_if_index);
149 0 : if (api != INDEX_INVALID)
150 0 : lcp_itf_pair_walk_show_cb (api, 0);
151 : }
152 3 : }
153 :
154 : lcp_itf_pair_t *
155 236 : lcp_itf_pair_get (u32 index)
156 : {
157 236 : if (!lcp_itf_pair_pool)
158 0 : return NULL;
159 236 : if (index == INDEX_INVALID)
160 0 : return NULL;
161 :
162 236 : return pool_elt_at_index (lcp_itf_pair_pool, index);
163 : }
164 :
165 : index_t
166 0 : lcp_itf_pair_find_by_vif (u32 vif_index)
167 : {
168 : uword *p;
169 :
170 0 : p = hash_get (lip_db_by_vif, vif_index);
171 :
172 0 : if (p)
173 0 : return p[0];
174 :
175 0 : return INDEX_INVALID;
176 : }
177 :
178 : const char *lcp_itf_l3_feat_names[N_LCP_ITF_HOST][N_AF] = {
179 : [LCP_ITF_HOST_TAP] = {
180 : [AF_IP4] = "linux-cp-xc-ip4",
181 : [AF_IP6] = "linux-cp-xc-ip6",
182 : },
183 : [LCP_ITF_HOST_TUN] = {
184 : [AF_IP4] = "linux-cp-xc-l3-ip4",
185 : [AF_IP6] = "linux-cp-xc-l3-ip6",
186 : },
187 : };
188 :
189 : const fib_route_path_flags_t lcp_itf_route_path_flags[N_LCP_ITF_HOST] = {
190 : [LCP_ITF_HOST_TAP] = FIB_ROUTE_PATH_DVR,
191 : [LCP_ITF_HOST_TUN] = FIB_ROUTE_PATH_FLAG_NONE,
192 : };
193 :
194 : static void
195 5 : lcp_itf_unset_adjs (lcp_itf_pair_t *lip)
196 : {
197 5 : adj_unlock (lip->lip_phy_adjs.adj_index[AF_IP4]);
198 5 : adj_unlock (lip->lip_phy_adjs.adj_index[AF_IP6]);
199 5 : }
200 :
201 : static void
202 5 : lcp_itf_set_adjs (lcp_itf_pair_t *lip)
203 : {
204 5 : if (lip->lip_host_type == LCP_ITF_HOST_TUN)
205 : {
206 3 : lip->lip_phy_adjs.adj_index[AF_IP4] = adj_nbr_add_or_lock (
207 : FIB_PROTOCOL_IP4, VNET_LINK_IP4, &zero_addr, lip->lip_phy_sw_if_index);
208 3 : lip->lip_phy_adjs.adj_index[AF_IP6] = adj_nbr_add_or_lock (
209 : FIB_PROTOCOL_IP6, VNET_LINK_IP6, &zero_addr, lip->lip_phy_sw_if_index);
210 : }
211 : else
212 : {
213 2 : lip->lip_phy_adjs.adj_index[AF_IP4] = adj_mcast_add_or_lock (
214 : FIB_PROTOCOL_IP4, VNET_LINK_IP4, lip->lip_phy_sw_if_index);
215 2 : lip->lip_phy_adjs.adj_index[AF_IP6] = adj_mcast_add_or_lock (
216 : FIB_PROTOCOL_IP6, VNET_LINK_IP6, lip->lip_phy_sw_if_index);
217 : }
218 :
219 : ip_adjacency_t *adj;
220 :
221 5 : adj = adj_get (lip->lip_phy_adjs.adj_index[AF_IP4]);
222 :
223 5 : lip->lip_rewrite_len = adj->rewrite_header.data_bytes;
224 5 : }
225 :
226 : int
227 5 : lcp_itf_pair_add (u32 host_sw_if_index, u32 phy_sw_if_index, u8 *host_name,
228 : u32 host_index, lip_host_type_t host_type, u8 *ns)
229 : {
230 : index_t lipi;
231 : lcp_itf_pair_t *lip;
232 :
233 5 : if (host_sw_if_index == ~0)
234 : {
235 0 : LCP_ITF_PAIR_ERR ("pair_add: Cannot add LIP - invalid host");
236 0 : return VNET_API_ERROR_INVALID_SW_IF_INDEX;
237 : }
238 :
239 5 : lipi = lcp_itf_pair_find_by_phy (phy_sw_if_index);
240 :
241 5 : if (lipi != INDEX_INVALID)
242 0 : return VNET_API_ERROR_VALUE_EXIST;
243 :
244 5 : LCP_ITF_PAIR_INFO ("add: host:%U phy:%U, host_if:%v vif:%d ns:%s",
245 : format_vnet_sw_if_index_name, vnet_get_main (),
246 : host_sw_if_index, format_vnet_sw_if_index_name,
247 : vnet_get_main (), phy_sw_if_index, host_name, host_index,
248 : ns);
249 :
250 : /*
251 : * Create a new pair.
252 : */
253 5 : pool_get (lcp_itf_pair_pool, lip);
254 :
255 5 : lipi = lip - lcp_itf_pair_pool;
256 :
257 21 : vec_validate_init_empty (lip_db_by_phy, phy_sw_if_index, INDEX_INVALID);
258 17 : vec_validate_init_empty (lip_db_by_host, host_sw_if_index, INDEX_INVALID);
259 5 : lip_db_by_phy[phy_sw_if_index] = lipi;
260 5 : lip_db_by_host[host_sw_if_index] = lipi;
261 5 : hash_set (lip_db_by_vif, host_index, lipi);
262 :
263 5 : lip->lip_host_sw_if_index = host_sw_if_index;
264 5 : lip->lip_phy_sw_if_index = phy_sw_if_index;
265 5 : lip->lip_host_name = vec_dup (host_name);
266 5 : lip->lip_host_type = host_type;
267 5 : lip->lip_vif_index = host_index;
268 5 : lip->lip_namespace = vec_dup (ns);
269 :
270 : /*
271 : * First use of this host interface.
272 : * Enable the x-connect feature on the host to send
273 : * all packets to the phy.
274 : */
275 : ip_address_family_t af;
276 :
277 15 : FOR_EACH_IP_ADDRESS_FAMILY (af)
278 10 : ip_feature_enable_disable (af, N_SAFI, IP_FEATURE_INPUT,
279 10 : lcp_itf_l3_feat_names[lip->lip_host_type][af],
280 10 : lip->lip_host_sw_if_index, 1, NULL, 0);
281 :
282 : /*
283 : * Configure passive punt to the host interface.
284 : */
285 5 : fib_route_path_t *rpaths = NULL, rpath = {
286 5 : .frp_flags = lcp_itf_route_path_flags[lip->lip_host_type],
287 : .frp_proto = DPO_PROTO_IP4,
288 5 : .frp_sw_if_index = lip->lip_host_sw_if_index,
289 : .frp_weight = 1,
290 : .frp_fib_index = ~0,
291 : };
292 :
293 5 : vec_add1 (rpaths, rpath);
294 :
295 5 : ip4_punt_redirect_add_paths (lip->lip_phy_sw_if_index, rpaths);
296 :
297 5 : rpaths[0].frp_proto = DPO_PROTO_IP6;
298 :
299 5 : ip6_punt_redirect_add_paths (lip->lip_phy_sw_if_index, rpaths);
300 :
301 5 : vec_free (rpaths);
302 :
303 5 : lcp_itf_set_adjs (lip);
304 :
305 : /* enable ARP feature node for broadcast interfaces */
306 5 : if (lip->lip_host_type != LCP_ITF_HOST_TUN)
307 : {
308 2 : vnet_feature_enable_disable ("arp", "linux-cp-arp-phy",
309 2 : lip->lip_phy_sw_if_index, 1, NULL, 0);
310 2 : vnet_feature_enable_disable ("arp", "linux-cp-arp-host",
311 2 : lip->lip_host_sw_if_index, 1, NULL, 0);
312 : }
313 : else
314 : {
315 3 : if (hash_elts (lip_db_by_vif) == 1)
316 : {
317 2 : vnet_feature_enable_disable ("ip4-punt", "linux-cp-punt-l3", 0, 1,
318 : NULL, 0);
319 2 : vnet_feature_enable_disable ("ip6-punt", "linux-cp-punt-l3", 0, 1,
320 : NULL, 0);
321 : }
322 : }
323 :
324 : /* invoke registered callbacks for pair addition */
325 : lcp_itf_pair_vft_t *vft;
326 :
327 10 : vec_foreach (vft, lcp_itf_vfts)
328 : {
329 5 : if (vft->pair_add_fn)
330 5 : vft->pair_add_fn (lip);
331 : }
332 :
333 : /* set timestamp when pair entered service */
334 5 : lip->lip_create_ts = vlib_time_now (vlib_get_main ());
335 :
336 5 : return 0;
337 : }
338 :
339 : static clib_error_t *
340 0 : lcp_netlink_add_link_vlan (int parent, u32 vlan, u16 proto, const char *name)
341 : {
342 : struct rtnl_link *link;
343 : struct nl_sock *sk;
344 : int err;
345 :
346 0 : sk = nl_socket_alloc ();
347 0 : if ((err = nl_connect (sk, NETLINK_ROUTE)) < 0)
348 : {
349 0 : LCP_ITF_PAIR_ERR ("netlink_add_link_vlan: connect error: %s",
350 : nl_geterror (err));
351 0 : return clib_error_return (NULL, "Unable to connect socket: %d", err);
352 : }
353 :
354 0 : link = rtnl_link_vlan_alloc ();
355 :
356 0 : rtnl_link_set_link (link, parent);
357 0 : rtnl_link_set_name (link, name);
358 0 : rtnl_link_vlan_set_id (link, vlan);
359 0 : rtnl_link_vlan_set_protocol (link, htons (proto));
360 :
361 0 : if ((err = rtnl_link_add (sk, link, NLM_F_CREATE)) < 0)
362 : {
363 0 : LCP_ITF_PAIR_ERR ("netlink_add_link_vlan: link add error: %s",
364 : nl_geterror (err));
365 0 : return clib_error_return (NULL, "Unable to add link %s: %d", name, err);
366 : }
367 :
368 0 : rtnl_link_put (link);
369 0 : nl_close (sk);
370 :
371 0 : return NULL;
372 : }
373 :
374 : static clib_error_t *
375 0 : lcp_netlink_del_link (const char *name)
376 : {
377 : struct rtnl_link *link;
378 : struct nl_sock *sk;
379 : int err;
380 :
381 0 : sk = nl_socket_alloc ();
382 0 : if ((err = nl_connect (sk, NETLINK_ROUTE)) < 0)
383 0 : return clib_error_return (NULL, "Unable to connect socket: %d", err);
384 :
385 0 : link = rtnl_link_alloc ();
386 0 : rtnl_link_set_name (link, name);
387 :
388 0 : if ((err = rtnl_link_delete (sk, link)) < 0)
389 0 : return clib_error_return (NULL, "Unable to del link %s: %d", name, err);
390 :
391 0 : rtnl_link_put (link);
392 0 : nl_close (sk);
393 :
394 0 : return NULL;
395 : }
396 :
397 : int
398 5 : lcp_itf_pair_del (u32 phy_sw_if_index)
399 : {
400 : ip_address_family_t af;
401 : lcp_itf_pair_t *lip;
402 : u32 lipi;
403 : lcp_itf_pair_vft_t *vft;
404 :
405 5 : lipi = lcp_itf_pair_find_by_phy (phy_sw_if_index);
406 :
407 5 : if (lipi == INDEX_INVALID)
408 0 : return VNET_API_ERROR_INVALID_SW_IF_INDEX;
409 :
410 5 : lip = lcp_itf_pair_get (lipi);
411 :
412 5 : LCP_ITF_PAIR_NOTICE (
413 : "pair_del: host:%U phy:%U host_if:%v vif:%d ns:%v",
414 : format_vnet_sw_if_index_name, vnet_get_main (), lip->lip_host_sw_if_index,
415 : format_vnet_sw_if_index_name, vnet_get_main (), lip->lip_phy_sw_if_index,
416 : lip->lip_host_name, lip->lip_vif_index, lip->lip_namespace);
417 :
418 : /* invoke registered callbacks for pair deletion */
419 10 : vec_foreach (vft, lcp_itf_vfts)
420 : {
421 5 : if (vft->pair_del_fn)
422 0 : vft->pair_del_fn (lip);
423 : }
424 :
425 15 : FOR_EACH_IP_ADDRESS_FAMILY (af)
426 10 : ip_feature_enable_disable (af, N_SAFI, IP_FEATURE_INPUT,
427 10 : lcp_itf_l3_feat_names[lip->lip_host_type][af],
428 : lip->lip_host_sw_if_index, 0, NULL, 0);
429 :
430 5 : lcp_itf_unset_adjs (lip);
431 :
432 5 : ip4_punt_redirect_del (lip->lip_phy_sw_if_index);
433 5 : ip6_punt_redirect_del (lip->lip_phy_sw_if_index);
434 :
435 : /* disable ARP feature node for broadcast interfaces */
436 5 : if (lip->lip_host_type != LCP_ITF_HOST_TUN)
437 : {
438 2 : vnet_feature_enable_disable ("arp", "linux-cp-arp-phy",
439 : lip->lip_phy_sw_if_index, 0, NULL, 0);
440 2 : vnet_feature_enable_disable ("arp", "linux-cp-arp-host",
441 : lip->lip_host_sw_if_index, 0, NULL, 0);
442 : }
443 : else
444 : {
445 3 : if (hash_elts (lip_db_by_vif) == 1)
446 : {
447 2 : vnet_feature_enable_disable ("ip4-punt", "linux-cp-punt-l3", 0, 0,
448 : NULL, 0);
449 2 : vnet_feature_enable_disable ("ip6-punt", "linux-cp-punt-l3", 0, 0,
450 : NULL, 0);
451 : }
452 : }
453 5 : lip_db_by_phy[phy_sw_if_index] = INDEX_INVALID;
454 5 : lip_db_by_host[lip->lip_host_sw_if_index] = INDEX_INVALID;
455 5 : hash_unset (lip_db_by_vif, lip->lip_vif_index);
456 :
457 5 : vec_free (lip->lip_host_name);
458 5 : vec_free (lip->lip_namespace);
459 5 : pool_put (lcp_itf_pair_pool, lip);
460 :
461 5 : return 0;
462 : }
463 :
464 : static void
465 0 : lcp_itf_pair_delete_by_index (index_t lipi)
466 : {
467 : u32 host_sw_if_index;
468 : lcp_itf_pair_t *lip;
469 : u8 *host_name, *ns;
470 :
471 0 : lip = lcp_itf_pair_get (lipi);
472 :
473 0 : host_name = vec_dup (lip->lip_host_name);
474 0 : host_sw_if_index = lip->lip_host_sw_if_index;
475 0 : ns = vec_dup (lip->lip_namespace);
476 :
477 0 : lcp_itf_pair_del (lip->lip_phy_sw_if_index);
478 :
479 0 : if (vnet_sw_interface_is_sub (vnet_get_main (), host_sw_if_index))
480 : {
481 0 : int curr_ns_fd = -1;
482 0 : int vif_ns_fd = -1;
483 0 : if (ns)
484 : {
485 0 : curr_ns_fd = clib_netns_open (NULL /* self */);
486 0 : vif_ns_fd = clib_netns_open ((u8 *) ns);
487 0 : if (vif_ns_fd != -1)
488 0 : clib_setns (vif_ns_fd);
489 : }
490 :
491 0 : lcp_netlink_del_link ((const char *) host_name);
492 0 : if (vif_ns_fd != -1)
493 0 : close (vif_ns_fd);
494 :
495 0 : if (curr_ns_fd != -1)
496 : {
497 0 : clib_setns (curr_ns_fd);
498 0 : close (curr_ns_fd);
499 : }
500 :
501 0 : vnet_delete_sub_interface (host_sw_if_index);
502 : }
503 : else
504 0 : tap_delete_if (vlib_get_main (), host_sw_if_index);
505 :
506 0 : vec_free (host_name);
507 0 : vec_free (ns);
508 0 : }
509 :
510 : int
511 3 : lcp_itf_pair_delete (u32 phy_sw_if_index)
512 : {
513 : index_t lipi;
514 :
515 3 : lipi = lcp_itf_pair_find_by_phy (phy_sw_if_index);
516 :
517 3 : if (lipi == INDEX_INVALID)
518 3 : return VNET_API_ERROR_INVALID_SW_IF_INDEX;
519 :
520 0 : lcp_itf_pair_delete_by_index (lipi);
521 :
522 0 : return 0;
523 : }
524 :
525 : /**
526 : * lcp_itf_interface_add_del
527 : *
528 : * Registered to receive interface Add and delete notifications
529 : */
530 : static clib_error_t *
531 19 : lcp_itf_interface_add_del (vnet_main_t *vnm, u32 sw_if_index, u32 is_add)
532 : {
533 19 : if (!is_add)
534 : /* remove any interface pair we have for this interface */
535 3 : lcp_itf_pair_delete (sw_if_index);
536 :
537 19 : return (NULL);
538 : }
539 :
540 6 : VNET_SW_INTERFACE_ADD_DEL_FUNCTION (lcp_itf_interface_add_del);
541 :
542 : void
543 3 : lcp_itf_pair_walk (lcp_itf_pair_walk_cb_t cb, void *ctx)
544 : {
545 : u32 api;
546 :
547 8 : pool_foreach_index (api, lcp_itf_pair_pool)
548 : {
549 5 : if (!cb (api, ctx))
550 0 : break;
551 : };
552 3 : }
553 :
554 : static clib_error_t *
555 2 : lcp_itf_pair_config (vlib_main_t *vm, unformat_input_t *input)
556 : {
557 : u8 *default_ns;
558 :
559 2 : default_ns = NULL;
560 :
561 2 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
562 : {
563 0 : if (unformat (input, "default netns %v", &default_ns))
564 : {
565 0 : vec_add1 (default_ns, 0);
566 0 : if (lcp_set_default_ns (default_ns) < 0)
567 : {
568 0 : return clib_error_return (0,
569 : "linux-cp default namespace must"
570 : " be less than %d characters",
571 : LCP_NS_LEN);
572 : }
573 : }
574 0 : else if (unformat (input, "lcp-auto-subint"))
575 0 : lcp_set_auto_subint (1 /* is_auto */);
576 0 : else if (unformat (input, "lcp-sync"))
577 0 : lcp_set_sync (1 /* is_auto */);
578 0 : else if (unformat (input, "del-static-on-link-down"))
579 0 : lcp_set_del_static_on_link_down (1 /* is_del */);
580 0 : else if (unformat (input, "del-dynamic-on-link-down"))
581 0 : lcp_set_del_dynamic_on_link_down (1 /* is_del */);
582 : else
583 0 : return clib_error_return (0, "interfaces not found");
584 : }
585 :
586 2 : vec_free (default_ns);
587 :
588 2 : return NULL;
589 : }
590 :
591 10 : VLIB_EARLY_CONFIG_FUNCTION (lcp_itf_pair_config, "linux-cp");
592 :
593 : /*
594 : * Returns 1 if the tap name is valid.
595 : * Returns 0 if the tap name is invalid.
596 : */
597 : static int
598 0 : lcp_validate_if_name (u8 *name)
599 : {
600 : int len;
601 : char *p;
602 :
603 0 : p = (char *) name;
604 0 : len = clib_strnlen (p, IFNAMSIZ);
605 0 : if (len >= IFNAMSIZ)
606 0 : return 0;
607 :
608 0 : for (; *p; ++p)
609 : {
610 0 : if (isalnum (*p))
611 0 : continue;
612 :
613 0 : switch (*p)
614 : {
615 0 : case '-':
616 : case '_':
617 : case '%':
618 : case '@':
619 : case ':':
620 : case '.':
621 0 : continue;
622 : }
623 :
624 0 : return 0;
625 : }
626 :
627 0 : return 1;
628 : }
629 :
630 : void
631 0 : lcp_itf_set_link_state (const lcp_itf_pair_t *lip, u8 state)
632 : {
633 : int curr_ns_fd, vif_ns_fd;
634 :
635 0 : if (!lip)
636 0 : return;
637 :
638 0 : curr_ns_fd = vif_ns_fd = -1;
639 :
640 0 : if (lip->lip_namespace)
641 : {
642 0 : curr_ns_fd = clib_netns_open (NULL /* self */);
643 0 : vif_ns_fd = clib_netns_open (lip->lip_namespace);
644 0 : if (vif_ns_fd != -1)
645 0 : clib_setns (vif_ns_fd);
646 : }
647 :
648 : /* Set the same link state on the netlink interface
649 : */
650 0 : vnet_netlink_set_link_state (lip->lip_vif_index, state);
651 :
652 0 : if (vif_ns_fd != -1)
653 0 : close (vif_ns_fd);
654 :
655 0 : if (curr_ns_fd != -1)
656 : {
657 0 : clib_setns (curr_ns_fd);
658 0 : close (curr_ns_fd);
659 : }
660 :
661 0 : return;
662 : }
663 :
664 : void
665 0 : lcp_itf_set_interface_addr (const lcp_itf_pair_t *lip)
666 : {
667 0 : ip4_main_t *im4 = &ip4_main;
668 0 : ip6_main_t *im6 = &ip6_main;
669 0 : ip_lookup_main_t *lm4 = &im4->lookup_main;
670 0 : ip_lookup_main_t *lm6 = &im6->lookup_main;
671 0 : ip_interface_address_t *ia = 0;
672 0 : int vif_ns_fd = -1;
673 0 : int curr_ns_fd = -1;
674 :
675 0 : if (!lip)
676 0 : return;
677 :
678 0 : if (lip->lip_namespace)
679 : {
680 0 : curr_ns_fd = clib_netns_open (NULL /* self */);
681 0 : vif_ns_fd = clib_netns_open (lip->lip_namespace);
682 0 : if (vif_ns_fd != -1)
683 0 : clib_setns (vif_ns_fd);
684 : }
685 :
686 : /* Sync any IP4 addressing info into LCP */
687 0 : foreach_ip_interface_address (
688 : lm4, ia, lip->lip_phy_sw_if_index, 1 /* honor unnumbered */, ({
689 : ip4_address_t *r4 = ip_interface_address_get_address (lm4, ia);
690 : LCP_ITF_PAIR_NOTICE ("set_interface_addr: %U add ip4 %U/%d",
691 : format_lcp_itf_pair, lip, format_ip4_address, r4,
692 : ia->address_length);
693 : vnet_netlink_add_ip4_addr (lip->lip_vif_index, r4, ia->address_length);
694 : }));
695 :
696 : /* Sync any IP6 addressing info into LCP */
697 0 : foreach_ip_interface_address (
698 : lm6, ia, lip->lip_phy_sw_if_index, 1 /* honor unnumbered */, ({
699 : ip6_address_t *r6 = ip_interface_address_get_address (lm6, ia);
700 : LCP_ITF_PAIR_NOTICE ("set_interface_addr: %U add ip6 %U/%d",
701 : format_lcp_itf_pair, lip, format_ip6_address, r6,
702 : ia->address_length);
703 : vnet_netlink_add_ip6_addr (lip->lip_vif_index, r6, ia->address_length);
704 : }));
705 :
706 0 : if (vif_ns_fd != -1)
707 0 : close (vif_ns_fd);
708 :
709 0 : if (curr_ns_fd != -1)
710 : {
711 0 : clib_setns (curr_ns_fd);
712 0 : close (curr_ns_fd);
713 : }
714 : }
715 :
716 : typedef struct
717 : {
718 : u32 vlan;
719 : bool dot1ad;
720 :
721 : u32 matched_sw_if_index;
722 : } lcp_itf_match_t;
723 :
724 : static walk_rc_t
725 0 : lcp_itf_pair_find_walk (vnet_main_t *vnm, u32 sw_if_index, void *arg)
726 : {
727 0 : lcp_itf_match_t *match = arg;
728 : const vnet_sw_interface_t *sw;
729 :
730 0 : sw = vnet_get_sw_interface (vnm, sw_if_index);
731 0 : if (sw && (sw->sub.eth.inner_vlan_id == 0) &&
732 0 : (sw->sub.eth.outer_vlan_id == match->vlan) &&
733 0 : (sw->sub.eth.flags.dot1ad == match->dot1ad))
734 : {
735 0 : LCP_ITF_PAIR_DBG ("find_walk: found match outer %d dot1ad %d "
736 : "inner-dot1q %d: interface %U",
737 : sw->sub.eth.outer_vlan_id, sw->sub.eth.flags.dot1ad,
738 : sw->sub.eth.inner_vlan_id,
739 : format_vnet_sw_if_index_name, vnet_get_main (),
740 : sw->sw_if_index);
741 0 : match->matched_sw_if_index = sw->sw_if_index;
742 0 : return WALK_STOP;
743 : }
744 :
745 0 : return WALK_CONTINUE;
746 : }
747 :
748 : /* Return the index of the sub-int on the phy that has the given vlan and
749 : * proto,
750 : */
751 : static index_t
752 0 : lcp_itf_pair_find_by_outer_vlan (u32 sup_if_index, u16 vlan, bool dot1ad)
753 : {
754 : lcp_itf_match_t match;
755 : const vnet_hw_interface_t *hw;
756 :
757 0 : match.vlan = vlan;
758 0 : match.dot1ad = dot1ad;
759 0 : match.matched_sw_if_index = INDEX_INVALID;
760 0 : hw = vnet_get_sup_hw_interface (vnet_get_main (), sup_if_index);
761 :
762 0 : vnet_hw_interface_walk_sw (vnet_get_main (), hw->hw_if_index,
763 : lcp_itf_pair_find_walk, &match);
764 :
765 0 : if (match.matched_sw_if_index >= vec_len (lip_db_by_phy))
766 0 : return INDEX_INVALID;
767 :
768 0 : return lip_db_by_phy[match.matched_sw_if_index];
769 : }
770 :
771 : static clib_error_t *lcp_itf_pair_link_up_down (vnet_main_t *vnm,
772 : u32 hw_if_index, u32 flags);
773 :
774 : int
775 0 : lcp_itf_pair_create (u32 phy_sw_if_index, u8 *host_if_name,
776 : lip_host_type_t host_if_type, u8 *ns,
777 : u32 *host_sw_if_indexp)
778 : {
779 : vlib_main_t *vm;
780 : vnet_main_t *vnm;
781 0 : u32 vif_index = 0, host_sw_if_index = ~0;
782 : const vnet_sw_interface_t *sw;
783 : const vnet_hw_interface_t *hw;
784 : const lcp_itf_pair_t *lip;
785 : index_t lipi;
786 :
787 0 : lipi = lcp_itf_pair_find_by_phy (phy_sw_if_index);
788 :
789 0 : if (lipi != INDEX_INVALID)
790 : {
791 0 : LCP_ITF_PAIR_ERR ("pair_create: already created");
792 0 : return VNET_API_ERROR_VALUE_EXIST;
793 : }
794 :
795 0 : if (!vnet_sw_if_index_is_api_valid (phy_sw_if_index))
796 : {
797 0 : LCP_ITF_PAIR_ERR ("pair_create: invalid phy index %u", phy_sw_if_index);
798 0 : return VNET_API_ERROR_INVALID_SW_IF_INDEX;
799 : }
800 :
801 0 : if (!lcp_validate_if_name (host_if_name))
802 : {
803 0 : LCP_ITF_PAIR_ERR ("pair_create: invalid host-if-name '%s'",
804 : host_if_name);
805 0 : return VNET_API_ERROR_INVALID_ARGUMENT;
806 : }
807 :
808 0 : vnm = vnet_get_main ();
809 0 : sw = vnet_get_sw_interface (vnm, phy_sw_if_index);
810 0 : hw = vnet_get_sup_hw_interface (vnm, phy_sw_if_index);
811 0 : if (!sw || !hw)
812 : {
813 0 : LCP_ITF_PAIR_ERR ("pair_create: invalid interface");
814 0 : return VNET_API_ERROR_INVALID_SW_IF_INDEX;
815 : }
816 :
817 0 : if (hw->hw_class_index != ethernet_hw_interface_class.index &&
818 : host_if_type == LCP_ITF_HOST_TAP)
819 : {
820 0 : LCP_ITF_PAIR_ERR (
821 : "pair_create: don't create TAP for non-eth interface; use tun");
822 0 : return VNET_API_ERROR_INVALID_ARGUMENT;
823 : }
824 :
825 : /*
826 : * Use interface-specific netns if supplied.
827 : * Otherwise, use netns if defined, otherwise use the OS default.
828 : */
829 0 : if (ns == 0 || ns[0] == 0)
830 0 : ns = lcp_get_default_ns ();
831 :
832 : /* sub interfaces do not need a tap created */
833 0 : if (vnet_sw_interface_is_sub (vnm, phy_sw_if_index))
834 : {
835 : index_t parent_if_index;
836 : int orig_ns_fd, ns_fd;
837 : clib_error_t *err;
838 : u16 outer_vlan, inner_vlan;
839 : u16 outer_proto, inner_proto;
840 : u16 vlan, proto;
841 : u32 parent_vif_index;
842 :
843 0 : err = vnet_sw_interface_supports_addressing (vnm, phy_sw_if_index);
844 0 : if (err)
845 : {
846 0 : LCP_ITF_PAIR_ERR ("pair_create: can't create LCP for a "
847 : "sub-interface without exact-match set");
848 0 : return VNET_API_ERROR_INVALID_ARGUMENT;
849 : }
850 :
851 0 : outer_vlan = sw->sub.eth.outer_vlan_id;
852 0 : inner_vlan = sw->sub.eth.inner_vlan_id;
853 0 : outer_proto = inner_proto = ETH_P_8021Q;
854 0 : if (1 == sw->sub.eth.flags.dot1ad)
855 0 : outer_proto = ETH_P_8021AD;
856 :
857 0 : LCP_ITF_PAIR_INFO ("pair_create: subif: dot1%s outer %d inner %d on %U",
858 : sw->sub.eth.flags.dot1ad ? "ad" : "q", outer_vlan,
859 : inner_vlan, format_vnet_sw_if_index_name, vnm,
860 : hw->sw_if_index);
861 :
862 0 : parent_if_index = lcp_itf_pair_find_by_phy (sw->sup_sw_if_index);
863 0 : if (INDEX_INVALID == parent_if_index)
864 : {
865 0 : LCP_ITF_PAIR_ERR ("pair_create: can't find LCP for %U",
866 : format_vnet_sw_if_index_name, vnet_get_main (),
867 : sw->sup_sw_if_index);
868 0 : return VNET_API_ERROR_INVALID_SW_IF_INDEX;
869 : }
870 0 : lip = lcp_itf_pair_get (parent_if_index);
871 0 : if (!lip)
872 : {
873 0 : LCP_ITF_PAIR_ERR ("pair_create: can't create LCP for a "
874 : "sub-interface without an LCP on the parent");
875 0 : return VNET_API_ERROR_INVALID_ARGUMENT;
876 : }
877 0 : LCP_ITF_PAIR_DBG ("pair_create: parent %U", format_lcp_itf_pair, lip);
878 0 : parent_vif_index = lip->lip_vif_index;
879 :
880 : /*
881 : * see if the requested host interface has already been created
882 : */
883 0 : orig_ns_fd = ns_fd = -1;
884 0 : err = NULL;
885 :
886 0 : if (ns && ns[0] != 0)
887 : {
888 0 : orig_ns_fd = clib_netns_open (NULL /* self */);
889 0 : ns_fd = clib_netns_open (ns);
890 0 : if (orig_ns_fd == -1 || ns_fd == -1)
891 0 : goto socket_close;
892 :
893 0 : clib_setns (ns_fd);
894 : }
895 :
896 0 : vif_index = if_nametoindex ((const char *) host_if_name);
897 :
898 0 : if (!vif_index)
899 : {
900 : /*
901 : * no existing host interface, create it now
902 : */
903 :
904 : /*
905 : * Find the parent tap:
906 : * - if this is an outer VLAN, use the pair from the parent phy
907 : * - if this is an inner VLAN, find the pair from the outer sub-int,
908 : * which must exist.
909 : */
910 0 : if (inner_vlan)
911 : {
912 : index_t linux_parent_if_index;
913 : const lcp_itf_pair_t *llip;
914 :
915 0 : vlan = inner_vlan;
916 0 : proto = inner_proto;
917 0 : linux_parent_if_index = lcp_itf_pair_find_by_outer_vlan (
918 0 : hw->sw_if_index, sw->sub.eth.outer_vlan_id,
919 0 : sw->sub.eth.flags.dot1ad);
920 0 : if (INDEX_INVALID == linux_parent_if_index ||
921 0 : !(llip = lcp_itf_pair_get (linux_parent_if_index)))
922 : {
923 0 : LCP_ITF_PAIR_ERR (
924 : "pair_create: can't find LCP for outer vlan %d "
925 : "proto %s on %U",
926 : outer_vlan,
927 : outer_proto == ETH_P_8021AD ? "dot1ad" : "dot1q",
928 : format_vnet_sw_if_index_name, vnm, hw->sw_if_index);
929 0 : err = clib_error_return (0, "parent pair not found");
930 0 : goto socket_close;
931 : }
932 :
933 0 : LCP_ITF_PAIR_DBG ("pair_create: linux parent %U",
934 : format_lcp_itf_pair, llip);
935 0 : parent_vif_index = llip->lip_vif_index;
936 : }
937 : else
938 : {
939 0 : vlan = outer_vlan;
940 0 : proto = outer_proto;
941 : }
942 :
943 0 : err = lcp_netlink_add_link_vlan (parent_vif_index, vlan, proto,
944 : (const char *) host_if_name);
945 0 : if (err != 0)
946 : {
947 0 : LCP_ITF_PAIR_ERR ("pair_create: cannot create link "
948 : "outer(proto:0x%04x,vlan:%u).inner(proto:0x%"
949 : "04x,vlan:%u) name:'%s'",
950 : outer_proto, outer_vlan, inner_proto,
951 : inner_vlan, host_if_name);
952 : }
953 :
954 0 : if (!err)
955 0 : vif_index = if_nametoindex ((char *) host_if_name);
956 : }
957 :
958 : /*
959 : * create a sub-interface on the tap
960 : */
961 0 : if (!err &&
962 0 : vnet_create_sub_interface (lip->lip_host_sw_if_index, sw->sub.id,
963 0 : sw->sub.eth.raw_flags, inner_vlan,
964 : outer_vlan, &host_sw_if_index))
965 : {
966 0 : LCP_ITF_PAIR_ERR (
967 : "pair_create: failed to create tap subint: %d.%d on %U",
968 : outer_vlan, inner_vlan, format_vnet_sw_if_index_name, vnm,
969 : lip->lip_host_sw_if_index);
970 0 : err = clib_error_return (
971 : 0, "failed to create tap subint: %d.%d. on %U", outer_vlan,
972 : inner_vlan, format_vnet_sw_if_index_name, vnm,
973 : lip->lip_host_sw_if_index);
974 : }
975 :
976 0 : socket_close:
977 0 : if (orig_ns_fd != -1)
978 : {
979 0 : clib_setns (orig_ns_fd);
980 0 : close (orig_ns_fd);
981 : }
982 0 : if (ns_fd != -1)
983 0 : close (ns_fd);
984 :
985 0 : if (err)
986 0 : return VNET_API_ERROR_INVALID_ARGUMENT;
987 : }
988 : else
989 : {
990 0 : tap_create_if_args_t args = {
991 0 : .num_rx_queues = clib_max (1, vlib_num_workers ()),
992 : .num_tx_queues = 1,
993 0 : .id = hw->hw_if_index,
994 : .sw_if_index = ~0,
995 : .rx_ring_sz = 256,
996 : .tx_ring_sz = 256,
997 : .host_if_name = host_if_name,
998 : .host_namespace = 0,
999 : .rv = 0,
1000 : .error = NULL,
1001 : };
1002 : ethernet_interface_t *ei;
1003 : u32 host_sw_mtu_size;
1004 :
1005 0 : if (host_if_type == LCP_ITF_HOST_TUN)
1006 0 : args.tap_flags |= TAP_FLAG_TUN;
1007 : else
1008 : {
1009 0 : ei = pool_elt_at_index (ethernet_main.interfaces, hw->hw_instance);
1010 0 : mac_address_copy (&args.host_mac_addr, &ei->address.mac);
1011 : }
1012 :
1013 : /*
1014 : * The TAP interface does copy forward the host MTU based on the VPP
1015 : * interface's L3 MTU, but it should also ensure that the VPP tap
1016 : * interface has an MTU that is greater-or-equal to those. Considering
1017 : * users can set the interfaces at runtime (set interface mtu packet ...)
1018 : * ensure that the tap MTU is large enough, taking the VPP interface L3
1019 : * if it's set, and otherwise a sensible default.
1020 : */
1021 0 : host_sw_mtu_size = sw->mtu[VNET_MTU_L3];
1022 0 : if (host_sw_mtu_size)
1023 : {
1024 0 : args.host_mtu_set = 1;
1025 0 : args.host_mtu_size = host_sw_mtu_size;
1026 : }
1027 : else
1028 0 : host_sw_mtu_size = ETHERNET_MAX_PACKET_BYTES;
1029 :
1030 0 : if (ns && ns[0] != 0)
1031 0 : args.host_namespace = ns;
1032 :
1033 0 : vm = vlib_get_main ();
1034 0 : tap_create_if (vm, &args);
1035 0 : if (args.rv < 0)
1036 : {
1037 0 : LCP_ITF_PAIR_ERR ("pair_create: could not create tap, retval:%d",
1038 : args.rv);
1039 0 : clib_error_free (args.error);
1040 0 : return args.rv;
1041 : }
1042 :
1043 0 : vnet_sw_interface_set_mtu (vnm, args.sw_if_index, host_sw_mtu_size);
1044 :
1045 : /*
1046 : * get the hw and ethernet of the tap
1047 : */
1048 0 : hw = vnet_get_sup_hw_interface (vnm, args.sw_if_index);
1049 0 : virtio_main_t *mm = &virtio_main;
1050 0 : virtio_if_t *vif = pool_elt_at_index (mm->interfaces, hw->dev_instance);
1051 :
1052 : /*
1053 : * Leave the TAP permanently up on the VPP side.
1054 : * This TAP will be shared by many sub-interface.
1055 : * Therefore we can't use it to manage admin state.
1056 : * force the tap in promiscuous mode.
1057 : */
1058 0 : if (host_if_type == LCP_ITF_HOST_TAP)
1059 : {
1060 0 : ei = pool_elt_at_index (ethernet_main.interfaces, hw->hw_instance);
1061 0 : ei->flags |= ETHERNET_INTERFACE_FLAG_STATUS_L3;
1062 : }
1063 :
1064 0 : vif_index = vif->ifindex;
1065 0 : host_sw_if_index = args.sw_if_index;
1066 : }
1067 :
1068 0 : if (!vif_index)
1069 : {
1070 0 : LCP_ITF_PAIR_INFO ("failed pair add (no vif index): {%U, %U, %s}",
1071 : format_vnet_sw_if_index_name, vnet_get_main (),
1072 : phy_sw_if_index, format_vnet_sw_if_index_name,
1073 : vnet_get_main (), host_sw_if_index, host_if_name);
1074 0 : return -1;
1075 : }
1076 :
1077 0 : LCP_ITF_PAIR_INFO ("pair create: {%U, %U, %s}", format_vnet_sw_if_index_name,
1078 : vnet_get_main (), phy_sw_if_index,
1079 : format_vnet_sw_if_index_name, vnet_get_main (),
1080 : host_sw_if_index, host_if_name);
1081 0 : lcp_itf_pair_add (host_sw_if_index, phy_sw_if_index, host_if_name, vif_index,
1082 : host_if_type, ns);
1083 :
1084 : /*
1085 : * Copy the link state from VPP into the host side.
1086 : * The TAP is shared by many interfaces, always keep it up.
1087 : * This controls whether the host can RX/TX.
1088 : */
1089 0 : sw = vnet_get_sw_interface (vnm, phy_sw_if_index);
1090 0 : lip = lcp_itf_pair_get (lcp_itf_pair_find_by_vif (vif_index));
1091 0 : LCP_ITF_PAIR_INFO ("pair create: %U sw-flags %u hw-flags %u",
1092 : format_lcp_itf_pair, lip, sw->flags, hw->flags);
1093 0 : vnet_sw_interface_admin_up (vnm, host_sw_if_index);
1094 0 : lcp_itf_set_link_state (lip, sw->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP);
1095 :
1096 : /*
1097 : * Reflect current link state and link speed of the hardware interface on the
1098 : * TAP interface.
1099 : */
1100 0 : if (host_if_type == LCP_ITF_HOST_TAP &&
1101 0 : !vnet_sw_interface_is_sub (vnm, phy_sw_if_index))
1102 : {
1103 0 : hw = vnet_get_sup_hw_interface (vnm, phy_sw_if_index);
1104 0 : lcp_itf_pair_link_up_down (vnm, hw->hw_if_index, hw->flags);
1105 : }
1106 :
1107 0 : if (host_sw_if_indexp)
1108 0 : *host_sw_if_indexp = host_sw_if_index;
1109 :
1110 0 : return 0;
1111 : }
1112 :
1113 : static walk_rc_t
1114 0 : lcp_itf_pair_walk_mark (index_t lipi, void *ctx)
1115 : {
1116 : lcp_itf_pair_t *lip;
1117 :
1118 0 : lip = lcp_itf_pair_get (lipi);
1119 :
1120 0 : lip->lip_flags |= LIP_FLAG_STALE;
1121 :
1122 0 : return (WALK_CONTINUE);
1123 : }
1124 :
1125 : int
1126 0 : lcp_itf_pair_replace_begin (void)
1127 : {
1128 0 : lcp_itf_pair_walk (lcp_itf_pair_walk_mark, NULL);
1129 :
1130 0 : return (0);
1131 : }
1132 :
1133 : typedef struct lcp_itf_pair_sweep_ctx_t_
1134 : {
1135 : index_t *indicies;
1136 : } lcp_itf_pair_sweep_ctx_t;
1137 :
1138 : static walk_rc_t
1139 0 : lcp_itf_pair_walk_sweep (index_t lipi, void *arg)
1140 : {
1141 0 : lcp_itf_pair_sweep_ctx_t *ctx = arg;
1142 : lcp_itf_pair_t *lip;
1143 :
1144 0 : lip = lcp_itf_pair_get (lipi);
1145 :
1146 0 : if (lip->lip_flags & LIP_FLAG_STALE)
1147 0 : vec_add1 (ctx->indicies, lipi);
1148 :
1149 0 : return (WALK_CONTINUE);
1150 : }
1151 :
1152 : int
1153 0 : lcp_itf_pair_replace_end (void)
1154 : {
1155 0 : lcp_itf_pair_sweep_ctx_t ctx = {
1156 : .indicies = NULL,
1157 : };
1158 : index_t *lipi;
1159 :
1160 0 : lcp_itf_pair_walk (lcp_itf_pair_walk_sweep, &ctx);
1161 :
1162 0 : vec_foreach (lipi, ctx.indicies)
1163 0 : lcp_itf_pair_delete_by_index (*lipi);
1164 :
1165 0 : vec_free (ctx.indicies);
1166 0 : return (0);
1167 : }
1168 :
1169 : static clib_error_t *
1170 37 : lcp_itf_pair_link_up_down (vnet_main_t *vnm, u32 hw_if_index, u32 flags)
1171 : {
1172 : vnet_hw_interface_t *hi;
1173 : vnet_sw_interface_t *si;
1174 : index_t lipi;
1175 : lcp_itf_pair_t *lip;
1176 :
1177 37 : hi = vnet_get_hw_interface_or_null (vnm, hw_if_index);
1178 37 : if (!hi)
1179 0 : return 0;
1180 :
1181 37 : lipi = lcp_itf_pair_find_by_phy (hi->sw_if_index);
1182 37 : if (lipi == INDEX_INVALID)
1183 35 : return 0;
1184 :
1185 2 : lip = lcp_itf_pair_get (lipi);
1186 2 : si = vnet_get_sw_interface_or_null (vnm, lip->lip_host_sw_if_index);
1187 2 : if (!si)
1188 0 : return 0;
1189 :
1190 2 : if (!lcp_main.test_mode)
1191 : {
1192 0 : tap_set_carrier (si->hw_if_index,
1193 : (flags & VNET_HW_INTERFACE_FLAG_LINK_UP));
1194 :
1195 0 : if (flags & VNET_HW_INTERFACE_FLAG_LINK_UP &&
1196 0 : hi->link_speed != UINT32_MAX)
1197 : {
1198 0 : tap_set_speed (si->hw_if_index, hi->link_speed / 1000);
1199 : }
1200 : }
1201 :
1202 2 : return 0;
1203 : }
1204 :
1205 6 : VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION (lcp_itf_pair_link_up_down);
1206 :
1207 : static clib_error_t *
1208 2 : lcp_interface_init (vlib_main_t *vm)
1209 : {
1210 2 : vlib_punt_hdl_t punt_hdl = vlib_punt_client_register ("linux-cp");
1211 :
1212 : /* punt IKE */
1213 2 : vlib_punt_register (punt_hdl, ipsec_punt_reason[IPSEC_PUNT_IP4_SPI_UDP_0],
1214 : "linux-cp-punt");
1215 2 : vlib_punt_register (punt_hdl, ipsec_punt_reason[IPSEC_PUNT_IP6_SPI_UDP_0],
1216 : "linux-cp-punt");
1217 :
1218 : /* punt all unknown ports */
1219 2 : udp_punt_unknown (vm, 0, 1);
1220 2 : udp_punt_unknown (vm, 1, 1);
1221 2 : tcp_punt_unknown (vm, 0, 1);
1222 2 : tcp_punt_unknown (vm, 1, 1);
1223 :
1224 2 : lcp_itf_pair_logger = vlib_log_register_class ("linux-cp", "itf");
1225 :
1226 2 : return NULL;
1227 : }
1228 :
1229 4 : VLIB_INIT_FUNCTION (lcp_interface_init) = {
1230 : .runs_after = VLIB_INITS ("vnet_interface_init", "tcp_init", "udp_init"),
1231 : };
1232 :
1233 : /*
1234 : * fd.io coding-style-patch-verification: ON
1235 : *
1236 : * Local Variables:
1237 : * eval: (c-set-style "gnu")
1238 : * End:
1239 : */
|