Line data Source code
1 : /*
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>
19 : #include <vnet/mpls/mpls.h>
20 : #include <vnet/fib/mpls_fib.h>
21 : #include <vnet/fib/ip4_fib.h>
22 : #include <vnet/adj/adj_midchain.h>
23 : #include <vnet/dpo/classify_dpo.h>
24 :
25 : typedef 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. */
32 : static mpls_interface_state_change_callback_t *state_change_callbacks;
33 :
34 : u8
35 5 : mpls_sw_interface_is_enabled (u32 sw_if_index)
36 : {
37 5 : mpls_main_t * mm = &mpls_main;
38 :
39 5 : if (vec_len(mm->mpls_enabled_by_sw_if_index) <= sw_if_index)
40 0 : return (0);
41 :
42 5 : return (mm->mpls_enabled_by_sw_if_index[sw_if_index]);
43 : }
44 :
45 : void
46 2 : mpls_interface_state_change_add_callback (
47 : mpls_interface_state_change_function_t *function, uword opaque)
48 : {
49 2 : mpls_interface_state_change_callback_t cb = {
50 : .function = function,
51 : .function_opaque = opaque,
52 : };
53 2 : vec_add1 (state_change_callbacks, cb);
54 2 : }
55 :
56 : int
57 276 : mpls_sw_interface_enable_disable (mpls_main_t *mm, u32 sw_if_index,
58 : u8 is_enable)
59 : {
60 : fib_node_index_t lfib_index;
61 276 : vnet_main_t *vnm = vnet_get_main ();
62 276 : vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
63 :
64 276 : vec_validate_init_empty (mm->mpls_enabled_by_sw_if_index, sw_if_index, 0);
65 :
66 276 : lfib_index = fib_table_find(FIB_PROTOCOL_MPLS,
67 : MPLS_FIB_DEFAULT_TABLE_ID);
68 :
69 276 : if (~0 == lfib_index)
70 0 : return VNET_API_ERROR_NO_SUCH_FIB;
71 :
72 : /*
73 : * enable/disable only on the 1<->0 transition
74 : */
75 276 : if (is_enable)
76 : {
77 138 : if (1 != ++mm->mpls_enabled_by_sw_if_index[sw_if_index])
78 0 : return (0);
79 :
80 138 : fib_table_lock (lfib_index, FIB_PROTOCOL_MPLS, FIB_SOURCE_INTERFACE);
81 :
82 138 : vec_validate(mm->fib_index_by_sw_if_index, sw_if_index);
83 138 : mm->fib_index_by_sw_if_index[sw_if_index] = lfib_index;
84 : }
85 : else
86 : {
87 138 : ASSERT(mm->mpls_enabled_by_sw_if_index[sw_if_index] > 0);
88 138 : if (0 != --mm->mpls_enabled_by_sw_if_index[sw_if_index])
89 0 : return (0);
90 :
91 138 : fib_table_unlock (mm->fib_index_by_sw_if_index[sw_if_index],
92 : FIB_PROTOCOL_MPLS, FIB_SOURCE_INTERFACE);
93 : }
94 :
95 276 : vnet_feature_enable_disable ("mpls-input", "mpls-not-enabled",
96 : sw_if_index, !is_enable, 0, 0);
97 :
98 276 : if (is_enable)
99 138 : hi->l3_if_count++;
100 138 : else if (hi->l3_if_count)
101 138 : hi->l3_if_count--;
102 :
103 : {
104 : mpls_interface_state_change_callback_t *cb;
105 276 : vec_foreach (cb, state_change_callbacks)
106 0 : cb->function (mm, cb->function_opaque, sw_if_index, is_enable);
107 : }
108 :
109 276 : return (0);
110 : }
111 :
112 : static clib_error_t *
113 0 : mpls_interface_enable_disable (vlib_main_t * vm,
114 : unformat_input_t * input,
115 : vlib_cli_command_t * cmd)
116 : {
117 0 : vnet_main_t * vnm = vnet_get_main();
118 0 : clib_error_t * error = 0;
119 : u32 sw_if_index, enable;
120 : int rv;
121 :
122 0 : sw_if_index = ~0;
123 :
124 0 : if (! unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
125 : {
126 0 : error = clib_error_return (0, "unknown interface `%U'",
127 : format_unformat_error, input);
128 0 : goto done;
129 : }
130 :
131 0 : if (unformat (input, "enable"))
132 0 : enable = 1;
133 0 : else if (unformat (input, "disable"))
134 0 : enable = 0;
135 : else
136 : {
137 0 : error = clib_error_return (0, "expected 'enable' or 'disable'",
138 : format_unformat_error, input);
139 0 : goto done;
140 : }
141 :
142 0 : rv = mpls_sw_interface_enable_disable (&mpls_main, sw_if_index, enable);
143 :
144 0 : if (VNET_API_ERROR_NO_SUCH_FIB == rv)
145 0 : error = clib_error_return (0, "default MPLS table must be created first");
146 :
147 0 : done:
148 0 : return error;
149 : }
150 :
151 : /*?
152 : * This command enables an interface to accept MPLS packets
153 : *
154 : * @cliexpar
155 : * @cliexstart{set interface mpls}
156 : * set interface mpls GigEthernet0/8/0 enable
157 : * @cliexend
158 : ?*/
159 285289 : VLIB_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 : };
164 :
165 : static void
166 9 : show_mpls_one_interface (vnet_main_t *vnm, vlib_main_t *vm, u32 sw_if_index,
167 : bool verbose)
168 : {
169 9 : mpls_main_t *mm = &mpls_main;
170 : u8 enabled;
171 :
172 9 : enabled = mm->mpls_enabled_by_sw_if_index[sw_if_index];
173 :
174 9 : if (enabled)
175 : {
176 5 : vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name, vnm,
177 : sw_if_index);
178 5 : vlib_cli_output (vm, " MPLS enabled");
179 : }
180 4 : else if (verbose)
181 : {
182 1 : vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name, vnm,
183 : sw_if_index);
184 1 : vlib_cli_output (vm, " MPLS disabled");
185 : }
186 9 : }
187 :
188 : static walk_rc_t
189 6 : show_mpls_interface_walk (vnet_main_t *vnm, vnet_sw_interface_t *si, void *ctx)
190 : {
191 6 : show_mpls_one_interface (vnm, ctx, si->sw_if_index, false);
192 :
193 6 : return (WALK_CONTINUE);
194 : }
195 :
196 : static clib_error_t *
197 5 : show_mpls_interface (vlib_main_t *vm, unformat_input_t *input,
198 : vlib_cli_command_t *cmd)
199 : {
200 5 : vnet_main_t *vnm = vnet_get_main ();
201 : u32 sw_if_index;
202 :
203 5 : sw_if_index = ~0;
204 :
205 5 : if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
206 : ;
207 :
208 5 : if (~0 == sw_if_index)
209 : {
210 2 : vnet_sw_interface_walk (vnm, show_mpls_interface_walk, vm);
211 : }
212 : else
213 : {
214 3 : show_mpls_one_interface (vnm, vm, sw_if_index, true);
215 : }
216 :
217 5 : 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 : ?*/
228 285289 : VLIB_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 : };
|