Line data Source code
1 : /*
2 : * Copyright (c) 2017 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 <vnet/bonding/node.h>
18 : #include <lacp/node.h>
19 : #include <vlib/stats/stats.h>
20 :
21 : static int
22 15 : lacp_packet_scan (vlib_main_t * vm, member_if_t * mif)
23 : {
24 15 : lacp_pdu_t *lacpdu = (lacp_pdu_t *) mif->last_rx_pkt;
25 :
26 15 : if (lacpdu->subtype != LACP_SUBTYPE)
27 0 : return LACP_ERROR_UNSUPPORTED;
28 :
29 : /*
30 : * According to the spec, no checking on the version number and tlv types.
31 : * But we may check the tlv lengths.
32 : */
33 15 : if ((lacpdu->actor.tlv_length != sizeof (lacp_actor_partner_t)) ||
34 15 : (lacpdu->partner.tlv_length != sizeof (lacp_actor_partner_t)) ||
35 15 : (lacpdu->collector.tlv_length != sizeof (lacp_collector_t)) ||
36 15 : (lacpdu->terminator.tlv_length != 0))
37 0 : return (LACP_ERROR_BAD_TLV);
38 :
39 15 : return lacp_machine_dispatch (&lacp_rx_machine, vm, mif,
40 : LACP_RX_EVENT_PDU_RECEIVED, &mif->rx_state);
41 : }
42 :
43 : static void
44 1 : marker_fill_pdu (marker_pdu_t * marker, member_if_t * mif)
45 : {
46 1 : marker_pdu_t *pkt = (marker_pdu_t *) mif->last_marker_pkt;
47 :
48 1 : marker->marker_info = pkt->marker_info;
49 1 : marker->marker_info.tlv_type = MARKER_RESPONSE_INFORMATION;
50 1 : }
51 :
52 : void
53 0 : marker_fill_request_pdu (marker_pdu_t * marker, member_if_t * mif)
54 : {
55 0 : marker->marker_info.tlv_type = MARKER_INFORMATION;
56 0 : marker->marker_info.requester_port = mif->actor.port_number;
57 0 : clib_memcpy (marker->marker_info.requester_system, mif->actor.system, 6);
58 0 : marker->marker_info.requester_transaction_id = mif->marker_tx_id;
59 0 : mif->marker_tx_id++;
60 0 : }
61 :
62 : static void
63 1 : send_ethernet_marker_response_pdu (vlib_main_t * vm, member_if_t * mif)
64 : {
65 1 : lacp_main_t *lm = &lacp_main;
66 : u32 *to_next;
67 : ethernet_marker_pdu_t *h0;
68 : vnet_hw_interface_t *hw;
69 : u32 bi0;
70 : vlib_buffer_t *b0;
71 : vlib_frame_t *f;
72 1 : vnet_main_t *vnm = lm->vnet_main;
73 :
74 : /*
75 : * see lacp_periodic_init() to understand what's already painted
76 : * into the buffer by the packet template mechanism
77 : */
78 1 : h0 = vlib_packet_template_get_packet
79 1 : (vm, &lm->marker_packet_templates[mif->packet_template_index], &bi0);
80 :
81 1 : if (!h0)
82 0 : return;
83 :
84 : /* Add the interface's ethernet source address */
85 1 : hw = vnet_get_sup_hw_interface (vnm, mif->sw_if_index);
86 :
87 1 : clib_memcpy (h0->ethernet.src_address, hw->hw_address,
88 : vec_len (hw->hw_address));
89 :
90 1 : marker_fill_pdu (&h0->marker, mif);
91 :
92 : /* Set the outbound packet length */
93 1 : b0 = vlib_get_buffer (vm, bi0);
94 1 : b0->current_length = sizeof (ethernet_marker_pdu_t);
95 1 : b0->current_data = 0;
96 1 : b0->total_length_not_including_first_buffer = 0;
97 :
98 : /* And the outbound interface */
99 1 : vnet_buffer (b0)->sw_if_index[VLIB_TX] = hw->sw_if_index;
100 :
101 : /* And output the packet on the correct interface */
102 1 : f = vlib_get_frame_to_node (vm, hw->output_node_index);
103 :
104 1 : to_next = vlib_frame_vector_args (f);
105 1 : to_next[0] = bi0;
106 1 : f->n_vectors = 1;
107 :
108 1 : vlib_put_frame_to_node (vm, hw->output_node_index, f);
109 1 : mif->last_marker_pdu_sent_time = vlib_time_now (vm);
110 1 : mif->marker_pdu_sent++;
111 : }
112 :
113 : static int
114 1 : handle_marker_protocol (vlib_main_t * vm, member_if_t * mif)
115 : {
116 1 : marker_pdu_t *marker = (marker_pdu_t *) mif->last_marker_pkt;
117 :
118 : /*
119 : * According to the spec, no checking on the version number and tlv types.
120 : * But we may check the tlv lengths.
121 : */
122 1 : if ((marker->marker_info.tlv_length != sizeof (marker_information_t)) ||
123 1 : (marker->terminator.tlv_length != 0))
124 0 : return (LACP_ERROR_BAD_TLV);
125 :
126 1 : send_ethernet_marker_response_pdu (vm, mif);
127 :
128 1 : return LACP_ERROR_NONE;
129 : }
130 :
131 : /*
132 : * lacp input routine
133 : */
134 : lacp_error_t
135 24 : lacp_input (vlib_main_t * vm, vlib_buffer_t * b0, u32 bi0)
136 : {
137 24 : bond_main_t *bm = &bond_main;
138 : member_if_t *mif;
139 : uword nbytes;
140 : lacp_error_t e;
141 : marker_pdu_t *marker;
142 : uword last_packet_signature;
143 : bond_if_t *bif;
144 :
145 : mif =
146 24 : bond_get_member_by_sw_if_index (vnet_buffer (b0)->sw_if_index[VLIB_RX]);
147 24 : if ((mif == 0) || (mif->mode != BOND_MODE_LACP))
148 : {
149 2 : return LACP_ERROR_DISABLED;
150 : }
151 :
152 : /* Handle marker protocol */
153 22 : marker = (marker_pdu_t *) (b0->data + b0->current_data);
154 22 : if (marker->subtype == MARKER_SUBTYPE)
155 : {
156 1 : mif->last_marker_pdu_recd_time = vlib_time_now (vm);
157 1 : if (mif->last_marker_pkt)
158 0 : vec_set_len (mif->last_marker_pkt, 0);
159 1 : vec_validate (mif->last_marker_pkt,
160 : vlib_buffer_length_in_chain (vm, b0) - 1);
161 1 : nbytes = vlib_buffer_contents (vm, bi0, mif->last_marker_pkt);
162 1 : ASSERT (nbytes <= vec_len (mif->last_marker_pkt));
163 1 : if (nbytes < sizeof (lacp_pdu_t))
164 : {
165 0 : mif->marker_bad_pdu_received++;
166 0 : return LACP_ERROR_TOO_SMALL;
167 : }
168 1 : e = handle_marker_protocol (vm, mif);
169 1 : mif->marker_pdu_received++;
170 1 : return e;
171 : }
172 :
173 : /*
174 : * typical clib idiom. Don't repeatedly allocate and free
175 : * the per-neighbor rx buffer. Reset its apparent length to zero
176 : * and reuse it.
177 : */
178 21 : if (mif->last_rx_pkt)
179 16 : vec_set_len (mif->last_rx_pkt, 0);
180 :
181 : /*
182 : * Make sure the per-neighbor rx buffer is big enough to hold
183 : * the data we're about to copy
184 : */
185 21 : vec_validate (mif->last_rx_pkt, vlib_buffer_length_in_chain (vm, b0) - 1);
186 :
187 : /*
188 : * Coalesce / copy the buffer chain into the per-neighbor
189 : * rx buffer
190 : */
191 21 : nbytes = vlib_buffer_contents (vm, bi0, mif->last_rx_pkt);
192 21 : ASSERT (nbytes <= vec_len (mif->last_rx_pkt));
193 :
194 21 : mif->last_lacpdu_recd_time = vlib_time_now (vm);
195 21 : if (nbytes < sizeof (lacp_pdu_t))
196 : {
197 0 : mif->bad_pdu_received++;
198 0 : return LACP_ERROR_TOO_SMALL;
199 : }
200 :
201 : last_packet_signature =
202 21 : hash_memory (mif->last_rx_pkt, vec_len (mif->last_rx_pkt), 0xd00b);
203 :
204 21 : if (mif->last_packet_signature_valid &&
205 16 : (mif->last_packet_signature == last_packet_signature) &&
206 6 : ((mif->actor.state & LACP_STEADY_STATE) == LACP_STEADY_STATE))
207 : {
208 6 : lacp_start_current_while_timer (vm, mif, mif->ttl_in_seconds);
209 6 : e = LACP_ERROR_CACHE_HIT;
210 : }
211 : else
212 : {
213 : /* Actually scan the packet */
214 15 : e = lacp_packet_scan (vm, mif);
215 15 : bif = bond_get_bond_if_by_dev_instance (mif->bif_dev_instance);
216 15 : vlib_stats_set_gauge (
217 15 : bm->stats[bif->sw_if_index][mif->sw_if_index].actor_state,
218 15 : mif->actor.state);
219 15 : vlib_stats_set_gauge (
220 15 : bm->stats[bif->sw_if_index][mif->sw_if_index].partner_state,
221 15 : mif->partner.state);
222 15 : mif->last_packet_signature_valid = 1;
223 15 : mif->last_packet_signature = last_packet_signature;
224 : }
225 21 : mif->pdu_received++;
226 :
227 21 : if (mif->last_rx_pkt)
228 21 : vec_set_len (mif->last_rx_pkt, 0);
229 :
230 21 : return e;
231 : }
232 :
233 : /*
234 : * setup neighbor hash table
235 : */
236 : static clib_error_t *
237 575 : lacp_init (vlib_main_t * vm)
238 : {
239 575 : return 0;
240 : }
241 :
242 : /* *INDENT-OFF* */
243 1727 : VLIB_INIT_FUNCTION (lacp_init) =
244 : {
245 : .runs_after = VLIB_INITS("lacp_periodic_init"),
246 : };
247 : /* *INDENT-ON* */
248 :
249 : /*
250 : * packet trace format function, very similar to
251 : * lacp_packet_scan except that we call the per TLV format
252 : * functions instead of the per TLV processing functions
253 : */
254 : u8 *
255 2 : lacp_input_format_trace (u8 * s, va_list * args)
256 : {
257 2 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
258 2 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
259 2 : lacp_input_trace_t *t = va_arg (*args, lacp_input_trace_t *);
260 2 : lacp_pdu_t *lacpdu = &t->pkt.lacpdu;
261 2 : marker_pdu_t *marker = &t->pkt.marker;
262 : int i, len;
263 : u8 *p;
264 : lacp_state_struct *state_entry;
265 :
266 2 : s = format (s, "%U:\n", format_vnet_sw_if_index_name, vnet_get_main (),
267 : t->sw_if_index);
268 2 : s = format (s, "Length: %d\n", t->len);
269 2 : if (t->len >= sizeof (lacp_pdu_t))
270 : {
271 2 : switch (lacpdu->subtype)
272 : {
273 2 : case MARKER_SUBTYPE:
274 2 : if (marker->version_number == MARKER_PROTOCOL_VERSION)
275 2 : s = format (s, " Markerv1\n");
276 : else
277 0 : s = format (s, " Subtype %u, Version %u\n", marker->subtype,
278 0 : marker->version_number);
279 2 : s = format (s, " Marker Information TLV: type %u\n",
280 2 : marker->marker_info.tlv_type);
281 2 : s = format (s, " Marker Information TLV: length %u\n",
282 2 : marker->marker_info.tlv_length);
283 2 : s = format (s, " Requester port: %u\n",
284 2 : ntohs (marker->marker_info.requester_port));
285 2 : s = format (s, " Requester system: %U\n", format_ethernet_address,
286 2 : marker->marker_info.requester_system);
287 2 : s = format (s, " Requester transaction ID: %u\n",
288 : ntohl (marker->marker_info.requester_transaction_id));
289 2 : break;
290 :
291 0 : case LACP_SUBTYPE:
292 0 : if (lacpdu->version_number == LACP_ACTOR_LACP_VERSION)
293 0 : s = format (s, " LACPv1\n");
294 : else
295 0 : s = format (s, " Subtype %u, Version %u\n", lacpdu->subtype,
296 0 : lacpdu->version_number);
297 0 : s = format (s, " Actor Information TLV: length %u\n",
298 0 : lacpdu->actor.tlv_length);
299 0 : s = format (s, " System %U\n", format_ethernet_address,
300 0 : lacpdu->actor.port_info.system);
301 0 : s = format (s, " System priority %u\n",
302 0 : ntohs (lacpdu->actor.port_info.system_priority));
303 0 : s = format (s, " Key %u\n", ntohs (lacpdu->actor.port_info.key));
304 0 : s = format (s, " Port priority %u\n",
305 0 : ntohs (lacpdu->actor.port_info.port_priority));
306 0 : s = format (s, " Port number %u\n",
307 0 : ntohs (lacpdu->actor.port_info.port_number));
308 0 : s = format (s, " State 0x%x\n", lacpdu->actor.port_info.state);
309 0 : state_entry = (lacp_state_struct *) & lacp_state_array;
310 0 : while (state_entry->str)
311 : {
312 0 : if (lacpdu->actor.port_info.state & (1 << state_entry->bit))
313 0 : s = format (s, " %s (%d)\n", state_entry->str,
314 0 : state_entry->bit);
315 0 : state_entry++;
316 : }
317 :
318 0 : s = format (s, " Partner Information TLV: length %u\n",
319 0 : lacpdu->partner.tlv_length);
320 0 : s = format (s, " System %U\n", format_ethernet_address,
321 0 : lacpdu->partner.port_info.system);
322 0 : s = format (s, " System priority %u\n",
323 0 : ntohs (lacpdu->partner.port_info.system_priority));
324 : s =
325 0 : format (s, " Key %u\n", ntohs (lacpdu->partner.port_info.key));
326 : s =
327 0 : format (s, " Port priority %u\n",
328 0 : ntohs (lacpdu->partner.port_info.port_priority));
329 : s =
330 0 : format (s, " Port number %u\n",
331 0 : ntohs (lacpdu->partner.port_info.port_number));
332 0 : s = format (s, " State 0x%x\n", lacpdu->partner.port_info.state);
333 0 : state_entry = (lacp_state_struct *) & lacp_state_array;
334 0 : while (state_entry->str)
335 : {
336 0 : if (lacpdu->partner.port_info.state & (1 << state_entry->bit))
337 0 : s = format (s, " %s (%d)\n", state_entry->str,
338 0 : state_entry->bit);
339 0 : state_entry++;
340 : }
341 0 : break;
342 :
343 0 : default:
344 0 : break;
345 : }
346 0 : }
347 :
348 2 : if (t->len > sizeof (lacp_pdu_t))
349 0 : len = sizeof (lacp_pdu_t);
350 : else
351 2 : len = t->len;
352 2 : p = (u8 *) lacpdu;
353 222 : for (i = 0; i < len; i++)
354 : {
355 220 : if ((i % 16) == 0)
356 : {
357 14 : if (i)
358 12 : s = format (s, "\n");
359 14 : s = format (s, " 0x%04x: ", i);
360 : }
361 220 : if ((i % 2) == 0)
362 110 : s = format (s, " ");
363 220 : s = format (s, "%02x", p[i]);
364 : }
365 :
366 2 : return s;
367 : }
368 :
369 : /*
370 : * fd.io coding-style-patch-verification: ON
371 : *
372 : * Local Variables:
373 : * eval: (c-set-style "gnu")
374 : * End:
375 : */
|