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