blob: fd654dca891394571ae832caf0daf0babd02198c [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
2 * interface.c: mpls interfaces
3 *
4 * Copyright (c) 2012 Cisco and/or its affiliates.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#include <vnet/vnet.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010019#include <vnet/mpls/mpls.h>
Neale Rannsa3af3372017-03-28 03:49:52 -070020#include <vnet/fib/mpls_fib.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010021#include <vnet/fib/ip4_fib.h>
22#include <vnet/adj/adj_midchain.h>
23#include <vnet/dpo/classify_dpo.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070024
Adrian Pistolae48ffb2023-05-14 00:00:41 +020025typedef struct
26{
27 mpls_interface_state_change_function_t *function;
28 uword function_opaque;
29} mpls_interface_state_change_callback_t;
30
31/** Functions to call when interface becomes MPLS enabled/disabled. */
32static mpls_interface_state_change_callback_t *state_change_callbacks;
Ed Warnickecb9cada2015-12-08 15:45:58 -070033
Neale Ranns0bfe5d82016-08-25 15:29:12 +010034u8
35mpls_sw_interface_is_enabled (u32 sw_if_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -070036{
Neale Ranns0bfe5d82016-08-25 15:29:12 +010037 mpls_main_t * mm = &mpls_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -070038
Eyal Baricd307742018-07-22 12:45:15 +030039 if (vec_len(mm->mpls_enabled_by_sw_if_index) <= sw_if_index)
Neale Ranns0bfe5d82016-08-25 15:29:12 +010040 return (0);
Ed Warnickecb9cada2015-12-08 15:45:58 -070041
Neale Ranns0bfe5d82016-08-25 15:29:12 +010042 return (mm->mpls_enabled_by_sw_if_index[sw_if_index]);
43}
44
Adrian Pistolae48ffb2023-05-14 00:00:41 +020045void
46mpls_interface_state_change_add_callback (
47 mpls_interface_state_change_function_t *function, uword opaque)
48{
49 mpls_interface_state_change_callback_t cb = {
50 .function = function,
51 .function_opaque = opaque,
52 };
53 vec_add1 (state_change_callbacks, cb);
54}
55
Neale Ranns15002542017-09-10 04:39:11 -070056int
Nathan Skrzypczak275bd792021-09-17 17:29:14 +020057mpls_sw_interface_enable_disable (mpls_main_t *mm, u32 sw_if_index,
58 u8 is_enable)
Neale Ranns0bfe5d82016-08-25 15:29:12 +010059{
Neale Ranns0bfe5d82016-08-25 15:29:12 +010060 fib_node_index_t lfib_index;
John Lo4a302ee2020-05-12 22:34:39 -040061 vnet_main_t *vnm = vnet_get_main ();
62 vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +010063
64 vec_validate_init_empty (mm->mpls_enabled_by_sw_if_index, sw_if_index, 0);
65
Neale Ranns15002542017-09-10 04:39:11 -070066 lfib_index = fib_table_find(FIB_PROTOCOL_MPLS,
67 MPLS_FIB_DEFAULT_TABLE_ID);
68
69 if (~0 == lfib_index)
70 return VNET_API_ERROR_NO_SUCH_FIB;
71
Neale Ranns0bfe5d82016-08-25 15:29:12 +010072 /*
73 * enable/disable only on the 1<->0 transition
74 */
75 if (is_enable)
Ed Warnickecb9cada2015-12-08 15:45:58 -070076 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +010077 if (1 != ++mm->mpls_enabled_by_sw_if_index[sw_if_index])
Neale Ranns15002542017-09-10 04:39:11 -070078 return (0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +010079
Nathan Skrzypczak275bd792021-09-17 17:29:14 +020080 fib_table_lock (lfib_index, FIB_PROTOCOL_MPLS, FIB_SOURCE_INTERFACE);
Neale Ranns15002542017-09-10 04:39:11 -070081
Neale Ranns44cea222018-12-04 09:39:40 +000082 vec_validate(mm->fib_index_by_sw_if_index, sw_if_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +010083 mm->fib_index_by_sw_if_index[sw_if_index] = lfib_index;
84 }
85 else
86 {
87 ASSERT(mm->mpls_enabled_by_sw_if_index[sw_if_index] > 0);
88 if (0 != --mm->mpls_enabled_by_sw_if_index[sw_if_index])
Neale Ranns15002542017-09-10 04:39:11 -070089 return (0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +010090
Nathan Skrzypczak275bd792021-09-17 17:29:14 +020091 fib_table_unlock (mm->fib_index_by_sw_if_index[sw_if_index],
92 FIB_PROTOCOL_MPLS, FIB_SOURCE_INTERFACE);
Ed Warnickecb9cada2015-12-08 15:45:58 -070093 }
94
Neale Rannsb85e4392017-03-16 16:12:57 -040095 vnet_feature_enable_disable ("mpls-input", "mpls-not-enabled",
96 sw_if_index, !is_enable, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -070097
John Lo4a302ee2020-05-12 22:34:39 -040098 if (is_enable)
99 hi->l3_if_count++;
100 else if (hi->l3_if_count)
101 hi->l3_if_count--;
102
Adrian Pistolae48ffb2023-05-14 00:00:41 +0200103 {
104 mpls_interface_state_change_callback_t *cb;
105 vec_foreach (cb, state_change_callbacks)
106 cb->function (mm, cb->function_opaque, sw_if_index, is_enable);
107 }
108
Neale Ranns15002542017-09-10 04:39:11 -0700109 return (0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100110}
111
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100112static clib_error_t *
113mpls_interface_enable_disable (vlib_main_t * vm,
114 unformat_input_t * input,
115 vlib_cli_command_t * cmd)
116{
117 vnet_main_t * vnm = vnet_get_main();
118 clib_error_t * error = 0;
119 u32 sw_if_index, enable;
Neale Ranns3ce7bcb2017-11-22 02:49:13 -0800120 int rv;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100121
122 sw_if_index = ~0;
123
124 if (! unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
125 {
126 error = clib_error_return (0, "unknown interface `%U'",
127 format_unformat_error, input);
128 goto done;
129 }
130
131 if (unformat (input, "enable"))
132 enable = 1;
133 else if (unformat (input, "disable"))
134 enable = 0;
135 else
136 {
137 error = clib_error_return (0, "expected 'enable' or 'disable'",
138 format_unformat_error, input);
139 goto done;
140 }
141
Nathan Skrzypczak275bd792021-09-17 17:29:14 +0200142 rv = mpls_sw_interface_enable_disable (&mpls_main, sw_if_index, enable);
Neale Ranns3ce7bcb2017-11-22 02:49:13 -0800143
144 if (VNET_API_ERROR_NO_SUCH_FIB == rv)
145 error = clib_error_return (0, "default MPLS table must be created first");
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100146
147 done:
148 return error;
149}
150
Neale Rannsad422ed2016-11-02 14:20:04 +0000151/*?
Nathan Skrzypczak2c77ae42021-09-29 15:36:51 +0200152 * This command enables an interface to accept MPLS packets
Neale Rannsad422ed2016-11-02 14:20:04 +0000153 *
154 * @cliexpar
155 * @cliexstart{set interface mpls}
156 * set interface mpls GigEthernet0/8/0 enable
157 * @cliexend
158 ?*/
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100159VLIB_CLI_COMMAND (set_interface_ip_table_command, static) = {
160 .path = "set interface mpls",
161 .function = mpls_interface_enable_disable,
162 .short_help = "Enable/Disable an interface for MPLS forwarding",
163};
Neale Rannsde0b3b52021-06-15 12:43:12 +0000164
165static void
166show_mpls_one_interface (vnet_main_t *vnm, vlib_main_t *vm, u32 sw_if_index,
167 bool verbose)
168{
169 mpls_main_t *mm = &mpls_main;
170 u8 enabled;
171
172 enabled = mm->mpls_enabled_by_sw_if_index[sw_if_index];
173
174 if (enabled)
175 {
176 vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name, vnm,
177 sw_if_index);
178 vlib_cli_output (vm, " MPLS enabled");
179 }
180 else if (verbose)
181 {
182 vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name, vnm,
183 sw_if_index);
184 vlib_cli_output (vm, " MPLS disabled");
185 }
186}
187
188static walk_rc_t
189show_mpls_interface_walk (vnet_main_t *vnm, vnet_sw_interface_t *si, void *ctx)
190{
191 show_mpls_one_interface (vnm, ctx, si->sw_if_index, false);
192
193 return (WALK_CONTINUE);
194}
195
196static clib_error_t *
197show_mpls_interface (vlib_main_t *vm, unformat_input_t *input,
198 vlib_cli_command_t *cmd)
199{
200 vnet_main_t *vnm = vnet_get_main ();
201 u32 sw_if_index;
202
203 sw_if_index = ~0;
204
205 if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
206 ;
207
208 if (~0 == sw_if_index)
209 {
210 vnet_sw_interface_walk (vnm, show_mpls_interface_walk, vm);
211 }
212 else
213 {
214 show_mpls_one_interface (vnm, vm, sw_if_index, true);
215 }
216
217 return NULL;
218}
219
220/*?
221 * This command displays the MPLS forwarding state of an interface
222 *
223 * @cliexpar
224 * @cliexstart{show mpls interface}
225 * set mpls interface GigEthernet0/8/0
226 * @cliexend
227 ?*/
228VLIB_CLI_COMMAND (show_mpls_interface_command, static) = {
229 .path = "show mpls interface",
230 .function = show_mpls_interface,
231 .short_help = "Show MPLS interface forwarding",
232};