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 0 : lcp_itf_pair_register_vft (lcp_itf_pair_vft_t *lcp_itf_vft)
72 : {
73 0 : vec_add1 (lcp_itf_vfts, *lcp_itf_vft);
74 0 : }
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 5 : vec_foreach (vft, lcp_itf_vfts)
328 : {
329 0 : if (vft->pair_add_fn)
330 0 : 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 5 : vec_foreach (vft, lcp_itf_vfts)
420 : {
421 0 : 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 :
786 0 : if (!vnet_sw_if_index_is_api_valid (phy_sw_if_index))
787 : {
788 0 : LCP_ITF_PAIR_ERR ("pair_create: invalid phy index %u", phy_sw_if_index);
789 0 : return VNET_API_ERROR_INVALID_SW_IF_INDEX;
790 : }
791 :
792 0 : if (!lcp_validate_if_name (host_if_name))
793 : {
794 0 : LCP_ITF_PAIR_ERR ("pair_create: invalid host-if-name '%s'",
795 : host_if_name);
796 0 : return VNET_API_ERROR_INVALID_ARGUMENT;
797 : }
798 :
799 0 : vnm = vnet_get_main ();
800 0 : sw = vnet_get_sw_interface (vnm, phy_sw_if_index);
801 0 : hw = vnet_get_sup_hw_interface (vnm, phy_sw_if_index);
802 0 : if (!sw || !hw)
803 : {
804 0 : LCP_ITF_PAIR_ERR ("pair_create: invalid interface");
805 0 : return VNET_API_ERROR_INVALID_SW_IF_INDEX;
806 : }
807 :
808 0 : if (hw->hw_class_index != ethernet_hw_interface_class.index &&
809 : host_if_type == LCP_ITF_HOST_TAP)
810 : {
811 0 : LCP_ITF_PAIR_ERR (
812 : "pair_create: don't create TAP for non-eth interface; use tun");
813 0 : return VNET_API_ERROR_INVALID_ARGUMENT;
814 : }
815 :
816 : /*
817 : * Use interface-specific netns if supplied.
818 : * Otherwise, use netns if defined, otherwise use the OS default.
819 : */
820 0 : if (ns == 0 || ns[0] == 0)
821 0 : ns = lcp_get_default_ns ();
822 :
823 : /* sub interfaces do not need a tap created */
824 0 : if (vnet_sw_interface_is_sub (vnm, phy_sw_if_index))
825 : {
826 : index_t parent_if_index;
827 : int orig_ns_fd, ns_fd;
828 : clib_error_t *err;
829 : u16 outer_vlan, inner_vlan;
830 : u16 outer_proto, inner_proto;
831 : u16 vlan, proto;
832 : u32 parent_vif_index;
833 :
834 0 : err = vnet_sw_interface_supports_addressing (vnm, phy_sw_if_index);
835 0 : if (err)
836 : {
837 0 : LCP_ITF_PAIR_ERR ("pair_create: can't create LCP for a "
838 : "sub-interface without exact-match set");
839 0 : return VNET_API_ERROR_INVALID_ARGUMENT;
840 : }
841 :
842 0 : outer_vlan = sw->sub.eth.outer_vlan_id;
843 0 : inner_vlan = sw->sub.eth.inner_vlan_id;
844 0 : outer_proto = inner_proto = ETH_P_8021Q;
845 0 : if (1 == sw->sub.eth.flags.dot1ad)
846 0 : outer_proto = ETH_P_8021AD;
847 :
848 0 : LCP_ITF_PAIR_INFO ("pair_create: subif: dot1%s outer %d inner %d on %U",
849 : sw->sub.eth.flags.dot1ad ? "ad" : "q", outer_vlan,
850 : inner_vlan, format_vnet_sw_if_index_name, vnm,
851 : hw->sw_if_index);
852 :
853 0 : parent_if_index = lcp_itf_pair_find_by_phy (sw->sup_sw_if_index);
854 0 : if (INDEX_INVALID == parent_if_index)
855 : {
856 0 : LCP_ITF_PAIR_ERR ("pair_create: can't find LCP for %U",
857 : format_vnet_sw_if_index_name, vnet_get_main (),
858 : sw->sup_sw_if_index);
859 0 : return VNET_API_ERROR_INVALID_SW_IF_INDEX;
860 : }
861 0 : lip = lcp_itf_pair_get (parent_if_index);
862 0 : if (!lip)
863 : {
864 0 : LCP_ITF_PAIR_ERR ("pair_create: can't create LCP for a "
865 : "sub-interface without an LCP on the parent");
866 0 : return VNET_API_ERROR_INVALID_ARGUMENT;
867 : }
868 0 : LCP_ITF_PAIR_DBG ("pair_create: parent %U", format_lcp_itf_pair, lip);
869 0 : parent_vif_index = lip->lip_vif_index;
870 :
871 : /*
872 : * see if the requested host interface has already been created
873 : */
874 0 : orig_ns_fd = ns_fd = -1;
875 0 : err = NULL;
876 :
877 0 : if (ns && ns[0] != 0)
878 : {
879 0 : orig_ns_fd = clib_netns_open (NULL /* self */);
880 0 : ns_fd = clib_netns_open (ns);
881 0 : if (orig_ns_fd == -1 || ns_fd == -1)
882 0 : goto socket_close;
883 :
884 0 : clib_setns (ns_fd);
885 : }
886 :
887 0 : vif_index = if_nametoindex ((const char *) host_if_name);
888 :
889 0 : if (!vif_index)
890 : {
891 : /*
892 : * no existing host interface, create it now
893 : */
894 :
895 : /*
896 : * Find the parent tap:
897 : * - if this is an outer VLAN, use the pair from the parent phy
898 : * - if this is an inner VLAN, find the pair from the outer sub-int,
899 : * which must exist.
900 : */
901 0 : if (inner_vlan)
902 : {
903 : index_t linux_parent_if_index;
904 : const lcp_itf_pair_t *llip;
905 :
906 0 : vlan = inner_vlan;
907 0 : proto = inner_proto;
908 0 : linux_parent_if_index = lcp_itf_pair_find_by_outer_vlan (
909 0 : hw->sw_if_index, sw->sub.eth.outer_vlan_id,
910 0 : sw->sub.eth.flags.dot1ad);
911 0 : if (INDEX_INVALID == linux_parent_if_index ||
912 0 : !(llip = lcp_itf_pair_get (linux_parent_if_index)))
913 : {
914 0 : LCP_ITF_PAIR_ERR (
915 : "pair_create: can't find LCP for outer vlan %d "
916 : "proto %s on %U",
917 : outer_vlan,
918 : outer_proto == ETH_P_8021AD ? "dot1ad" : "dot1q",
919 : format_vnet_sw_if_index_name, vnm, hw->sw_if_index);
920 0 : err = clib_error_return (0, "parent pair not found");
921 0 : goto socket_close;
922 : }
923 :
924 0 : LCP_ITF_PAIR_DBG ("pair_create: linux parent %U",
925 : format_lcp_itf_pair, llip);
926 0 : parent_vif_index = llip->lip_vif_index;
927 : }
928 : else
929 : {
930 0 : vlan = outer_vlan;
931 0 : proto = outer_proto;
932 : }
933 :
934 0 : err = lcp_netlink_add_link_vlan (parent_vif_index, vlan, proto,
935 : (const char *) host_if_name);
936 0 : if (err != 0)
937 : {
938 0 : LCP_ITF_PAIR_ERR ("pair_create: cannot create link "
939 : "outer(proto:0x%04x,vlan:%u).inner(proto:0x%"
940 : "04x,vlan:%u) name:'%s'",
941 : outer_proto, outer_vlan, inner_proto,
942 : inner_vlan, host_if_name);
943 : }
944 :
945 0 : if (!err)
946 0 : vif_index = if_nametoindex ((char *) host_if_name);
947 : }
948 :
949 : /*
950 : * create a sub-interface on the tap
951 : */
952 0 : if (!err &&
953 0 : vnet_create_sub_interface (lip->lip_host_sw_if_index, sw->sub.id,
954 0 : sw->sub.eth.raw_flags, inner_vlan,
955 : outer_vlan, &host_sw_if_index))
956 : {
957 0 : LCP_ITF_PAIR_ERR (
958 : "pair_create: failed to create tap subint: %d.%d on %U",
959 : outer_vlan, inner_vlan, format_vnet_sw_if_index_name, vnm,
960 : lip->lip_host_sw_if_index);
961 0 : err = clib_error_return (
962 : 0, "failed to create tap subint: %d.%d. on %U", outer_vlan,
963 : inner_vlan, format_vnet_sw_if_index_name, vnm,
964 : lip->lip_host_sw_if_index);
965 : }
966 :
967 0 : socket_close:
968 0 : if (orig_ns_fd != -1)
969 : {
970 0 : clib_setns (orig_ns_fd);
971 0 : close (orig_ns_fd);
972 : }
973 0 : if (ns_fd != -1)
974 0 : close (ns_fd);
975 :
976 0 : if (err)
977 0 : return VNET_API_ERROR_INVALID_ARGUMENT;
978 : }
979 : else
980 : {
981 0 : tap_create_if_args_t args = {
982 0 : .num_rx_queues = clib_max (1, vlib_num_workers ()),
983 : .num_tx_queues = 1,
984 0 : .id = hw->hw_if_index,
985 : .sw_if_index = ~0,
986 : .rx_ring_sz = 256,
987 : .tx_ring_sz = 256,
988 : .host_if_name = host_if_name,
989 : .host_namespace = 0,
990 : .rv = 0,
991 : .error = NULL,
992 : };
993 : ethernet_interface_t *ei;
994 : u32 host_sw_mtu_size;
995 :
996 0 : if (host_if_type == LCP_ITF_HOST_TUN)
997 0 : args.tap_flags |= TAP_FLAG_TUN;
998 : else
999 : {
1000 0 : ei = pool_elt_at_index (ethernet_main.interfaces, hw->hw_instance);
1001 0 : mac_address_copy (&args.host_mac_addr, &ei->address.mac);
1002 : }
1003 :
1004 : /*
1005 : * The TAP interface does copy forward the host MTU based on the VPP
1006 : * interface's L3 MTU, but it should also ensure that the VPP tap
1007 : * interface has an MTU that is greater-or-equal to those. Considering
1008 : * users can set the interfaces at runtime (set interface mtu packet ...)
1009 : * ensure that the tap MTU is large enough, taking the VPP interface L3
1010 : * if it's set, and otherwise a sensible default.
1011 : */
1012 0 : host_sw_mtu_size = sw->mtu[VNET_MTU_L3];
1013 0 : if (host_sw_mtu_size)
1014 : {
1015 0 : args.host_mtu_set = 1;
1016 0 : args.host_mtu_size = host_sw_mtu_size;
1017 : }
1018 : else
1019 0 : host_sw_mtu_size = ETHERNET_MAX_PACKET_BYTES;
1020 :
1021 0 : if (ns && ns[0] != 0)
1022 0 : args.host_namespace = ns;
1023 :
1024 0 : vm = vlib_get_main ();
1025 0 : tap_create_if (vm, &args);
1026 0 : if (args.rv < 0)
1027 : {
1028 0 : LCP_ITF_PAIR_ERR ("pair_create: could not create tap, retval:%d",
1029 : args.rv);
1030 0 : clib_error_free (args.error);
1031 0 : return args.rv;
1032 : }
1033 :
1034 0 : vnet_sw_interface_set_mtu (vnm, args.sw_if_index, host_sw_mtu_size);
1035 :
1036 : /*
1037 : * get the hw and ethernet of the tap
1038 : */
1039 0 : hw = vnet_get_sup_hw_interface (vnm, args.sw_if_index);
1040 0 : virtio_main_t *mm = &virtio_main;
1041 0 : virtio_if_t *vif = pool_elt_at_index (mm->interfaces, hw->dev_instance);
1042 :
1043 : /*
1044 : * Leave the TAP permanently up on the VPP side.
1045 : * This TAP will be shared by many sub-interface.
1046 : * Therefore we can't use it to manage admin state.
1047 : * force the tap in promiscuous mode.
1048 : */
1049 0 : if (host_if_type == LCP_ITF_HOST_TAP)
1050 : {
1051 0 : ei = pool_elt_at_index (ethernet_main.interfaces, hw->hw_instance);
1052 0 : ei->flags |= ETHERNET_INTERFACE_FLAG_STATUS_L3;
1053 : }
1054 :
1055 0 : vif_index = vif->ifindex;
1056 0 : host_sw_if_index = args.sw_if_index;
1057 : }
1058 :
1059 0 : if (!vif_index)
1060 : {
1061 0 : LCP_ITF_PAIR_INFO ("failed pair add (no vif index): {%U, %U, %s}",
1062 : format_vnet_sw_if_index_name, vnet_get_main (),
1063 : phy_sw_if_index, format_vnet_sw_if_index_name,
1064 : vnet_get_main (), host_sw_if_index, host_if_name);
1065 0 : return -1;
1066 : }
1067 :
1068 0 : LCP_ITF_PAIR_INFO ("pair create: {%U, %U, %s}", format_vnet_sw_if_index_name,
1069 : vnet_get_main (), phy_sw_if_index,
1070 : format_vnet_sw_if_index_name, vnet_get_main (),
1071 : host_sw_if_index, host_if_name);
1072 0 : lcp_itf_pair_add (host_sw_if_index, phy_sw_if_index, host_if_name, vif_index,
1073 : host_if_type, ns);
1074 :
1075 : /*
1076 : * Copy the link state from VPP into the host side.
1077 : * The TAP is shared by many interfaces, always keep it up.
1078 : * This controls whether the host can RX/TX.
1079 : */
1080 0 : sw = vnet_get_sw_interface (vnm, phy_sw_if_index);
1081 0 : lip = lcp_itf_pair_get (lcp_itf_pair_find_by_vif (vif_index));
1082 0 : LCP_ITF_PAIR_INFO ("pair create: %U sw-flags %u hw-flags %u",
1083 : format_lcp_itf_pair, lip, sw->flags, hw->flags);
1084 0 : vnet_sw_interface_admin_up (vnm, host_sw_if_index);
1085 0 : lcp_itf_set_link_state (lip, sw->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP);
1086 :
1087 : /*
1088 : * Reflect current link state and link speed of the hardware interface on the
1089 : * TAP interface.
1090 : */
1091 0 : if (host_if_type == LCP_ITF_HOST_TAP &&
1092 0 : !vnet_sw_interface_is_sub (vnm, phy_sw_if_index))
1093 : {
1094 0 : hw = vnet_get_sup_hw_interface (vnm, phy_sw_if_index);
1095 0 : lcp_itf_pair_link_up_down (vnm, hw->hw_if_index, hw->flags);
1096 : }
1097 :
1098 0 : if (host_sw_if_indexp)
1099 0 : *host_sw_if_indexp = host_sw_if_index;
1100 :
1101 0 : return 0;
1102 : }
1103 :
1104 : static walk_rc_t
1105 0 : lcp_itf_pair_walk_mark (index_t lipi, void *ctx)
1106 : {
1107 : lcp_itf_pair_t *lip;
1108 :
1109 0 : lip = lcp_itf_pair_get (lipi);
1110 :
1111 0 : lip->lip_flags |= LIP_FLAG_STALE;
1112 :
1113 0 : return (WALK_CONTINUE);
1114 : }
1115 :
1116 : int
1117 0 : lcp_itf_pair_replace_begin (void)
1118 : {
1119 0 : lcp_itf_pair_walk (lcp_itf_pair_walk_mark, NULL);
1120 :
1121 0 : return (0);
1122 : }
1123 :
1124 : typedef struct lcp_itf_pair_sweep_ctx_t_
1125 : {
1126 : index_t *indicies;
1127 : } lcp_itf_pair_sweep_ctx_t;
1128 :
1129 : static walk_rc_t
1130 0 : lcp_itf_pair_walk_sweep (index_t lipi, void *arg)
1131 : {
1132 0 : lcp_itf_pair_sweep_ctx_t *ctx = arg;
1133 : lcp_itf_pair_t *lip;
1134 :
1135 0 : lip = lcp_itf_pair_get (lipi);
1136 :
1137 0 : if (lip->lip_flags & LIP_FLAG_STALE)
1138 0 : vec_add1 (ctx->indicies, lipi);
1139 :
1140 0 : return (WALK_CONTINUE);
1141 : }
1142 :
1143 : int
1144 0 : lcp_itf_pair_replace_end (void)
1145 : {
1146 0 : lcp_itf_pair_sweep_ctx_t ctx = {
1147 : .indicies = NULL,
1148 : };
1149 : index_t *lipi;
1150 :
1151 0 : lcp_itf_pair_walk (lcp_itf_pair_walk_sweep, &ctx);
1152 :
1153 0 : vec_foreach (lipi, ctx.indicies)
1154 0 : lcp_itf_pair_delete_by_index (*lipi);
1155 :
1156 0 : vec_free (ctx.indicies);
1157 0 : return (0);
1158 : }
1159 :
1160 : static clib_error_t *
1161 37 : lcp_itf_pair_link_up_down (vnet_main_t *vnm, u32 hw_if_index, u32 flags)
1162 : {
1163 : vnet_hw_interface_t *hi;
1164 : vnet_sw_interface_t *si;
1165 : index_t lipi;
1166 : lcp_itf_pair_t *lip;
1167 :
1168 37 : hi = vnet_get_hw_interface_or_null (vnm, hw_if_index);
1169 37 : if (!hi)
1170 0 : return 0;
1171 :
1172 37 : lipi = lcp_itf_pair_find_by_phy (hi->sw_if_index);
1173 37 : if (lipi == INDEX_INVALID)
1174 35 : return 0;
1175 :
1176 2 : lip = lcp_itf_pair_get (lipi);
1177 2 : si = vnet_get_sw_interface_or_null (vnm, lip->lip_host_sw_if_index);
1178 2 : if (!si)
1179 0 : return 0;
1180 :
1181 2 : if (!lcp_main.test_mode)
1182 : {
1183 0 : tap_set_carrier (si->hw_if_index,
1184 : (flags & VNET_HW_INTERFACE_FLAG_LINK_UP));
1185 :
1186 0 : if (flags & VNET_HW_INTERFACE_FLAG_LINK_UP &&
1187 0 : hi->link_speed != UINT32_MAX)
1188 : {
1189 0 : tap_set_speed (si->hw_if_index, hi->link_speed / 1000);
1190 : }
1191 : }
1192 :
1193 2 : return 0;
1194 : }
1195 :
1196 6 : VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION (lcp_itf_pair_link_up_down);
1197 :
1198 : static clib_error_t *
1199 2 : lcp_interface_init (vlib_main_t *vm)
1200 : {
1201 2 : vlib_punt_hdl_t punt_hdl = vlib_punt_client_register ("linux-cp");
1202 :
1203 : /* punt IKE */
1204 2 : vlib_punt_register (punt_hdl, ipsec_punt_reason[IPSEC_PUNT_IP4_SPI_UDP_0],
1205 : "linux-cp-punt");
1206 2 : vlib_punt_register (punt_hdl, ipsec_punt_reason[IPSEC_PUNT_IP6_SPI_UDP_0],
1207 : "linux-cp-punt");
1208 :
1209 : /* punt all unknown ports */
1210 2 : udp_punt_unknown (vm, 0, 1);
1211 2 : udp_punt_unknown (vm, 1, 1);
1212 2 : tcp_punt_unknown (vm, 0, 1);
1213 2 : tcp_punt_unknown (vm, 1, 1);
1214 :
1215 2 : lcp_itf_pair_logger = vlib_log_register_class ("linux-cp", "itf");
1216 :
1217 2 : return NULL;
1218 : }
1219 :
1220 4 : VLIB_INIT_FUNCTION (lcp_interface_init) = {
1221 : .runs_after = VLIB_INITS ("vnet_interface_init", "tcp_init", "udp_init"),
1222 : };
1223 :
1224 : /*
1225 : * fd.io coding-style-patch-verification: ON
1226 : *
1227 : * Local Variables:
1228 : * eval: (c-set-style "gnu")
1229 : * End:
1230 : */
|