auto-attach: Add auto-attach support to bridge layer and command set
[cascardo/ovs.git] / tests / test-aa.c
1 /*
2  * Copyright (c) 2015 Avaya, Inc.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 #include <config.h>
18 #undef NDEBUG
19 #include <assert.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include "ovs-lldp.h"
24 #include "ovstest.h"
25
26 #define ETH_TYPE_LLDP   0x88cc
27
28 /* Dummy MAC addresses */
29 char chassis_mac[ETHER_ADDR_LEN] = { 0x5e, 0x10, 0x8e, 0xe7, 0x84, 0xad };
30 uint8_t eth_src[ETHER_ADDR_LEN] = { 0x5e, 0x10, 0x8e, 0xe7, 0x84, 0xad };
31
32 /* LLDP multicast address */
33 static const uint8_t eth_addr_lldp[6] = {0x01, 0x80, 0xC2, 0x00, 0x00, 0x0e};
34
35 /* Count of tests run */
36 int num_tests = 0;
37
38
39 /*
40  * Helper function to validate port info
41  */
42 static void
43 check_received_port(struct lldpd_port *sport,
44                     struct lldpd_port *rport)
45 {
46     assert(rport->p_id_subtype == sport->p_id_subtype);
47     assert(rport->p_id_len == sport->p_id_len);
48     assert(strncmp(rport->p_id, sport->p_id, sport->p_id_len) == 0);
49     assert(strcmp(rport->p_descr, sport->p_descr) == 0);
50
51     return;
52 }
53
54
55 /*
56  * Helper function to validate chassis info
57  */
58 static void
59 check_received_chassis(struct lldpd_chassis *schassis,
60                        struct lldpd_chassis *rchassis)
61 {
62     assert(rchassis->c_id_subtype == schassis->c_id_subtype);
63     assert(rchassis->c_id_len == schassis->c_id_len);
64     assert(strncmp(rchassis->c_id, schassis->c_id, schassis->c_id_len) == 0);
65     assert(strcmp(rchassis->c_name, schassis->c_name) == 0);
66     assert(strcmp(rchassis->c_descr, schassis->c_descr) == 0);
67     assert(rchassis->c_cap_available == schassis->c_cap_available);
68     assert(rchassis->c_cap_enabled == schassis->c_cap_enabled);
69
70     return;
71 }
72
73
74 /*
75  * Helper function to validate auto-attach info
76  */
77 static void
78 check_received_aa(struct lldpd_port *sport,
79                   struct lldpd_port *rport,
80                   struct lldpd_aa_isid_vlan_maps_tlv *smap)
81 {
82     struct lldpd_aa_isid_vlan_maps_tlv *received_map;
83     int i = 0;
84
85     assert(rport->p_element.type == sport->p_element.type);
86     assert(rport->p_element.mgmt_vlan == sport->p_element.mgmt_vlan);
87     assert(rport->p_element.system_id.system_mac[0] ==
88            sport->p_element.system_id.system_mac[0]);
89     assert(rport->p_element.system_id.system_mac[1] ==
90            sport->p_element.system_id.system_mac[1]);
91     assert(rport->p_element.system_id.system_mac[2] ==
92            sport->p_element.system_id.system_mac[2]);
93     assert(rport->p_element.system_id.system_mac[3] ==
94            sport->p_element.system_id.system_mac[3]);
95     assert(rport->p_element.system_id.system_mac[4] ==
96            sport->p_element.system_id.system_mac[4]);
97     assert(rport->p_element.system_id.system_mac[5] ==
98            sport->p_element.system_id.system_mac[5]);
99     assert(rport->p_element.system_id.conn_type ==
100            sport->p_element.system_id.conn_type);
101     assert(rport->p_element.system_id.smlt_id ==
102            sport->p_element.system_id.smlt_id);
103     assert(rport->p_element.system_id.mlt_id[0] ==
104            sport->p_element.system_id.mlt_id[0]);
105     assert(rport->p_element.system_id.mlt_id[1] ==
106            sport->p_element.system_id.mlt_id[1]);
107
108     /* Should receive 2 mappings */
109     assert(!list_is_empty(&rport->p_isid_vlan_maps.m_entries));
110
111     /* For each received isid/vlan mapping */
112     LIST_FOR_EACH (received_map, m_entries,
113                    &rport->p_isid_vlan_maps.m_entries) {
114
115         /* Validate against mapping sent */
116         assert(smap[i].isid_vlan_data.status ==
117                received_map->isid_vlan_data.status);
118         assert(smap[i].isid_vlan_data.vlan ==
119                received_map->isid_vlan_data.vlan);
120         assert(smap[i].isid_vlan_data.isid[0] ==
121                received_map->isid_vlan_data.isid[0]);
122         assert(smap[i].isid_vlan_data.isid[1] ==
123                received_map->isid_vlan_data.isid[1]);
124         assert(smap[i].isid_vlan_data.isid[2] ==
125                received_map->isid_vlan_data.isid[2]);
126
127         /* Next mapping sent */
128         i++;
129     }
130     assert(i == 2);
131
132     return;
133 }
134
135
136 /*
137  * Validate basic send/receive processing
138  */
139 static int
140 test_aa_send(void)
141 {
142     struct lldp           *lldp;
143     struct lldpd_hardware hardware;
144     struct lldpd_chassis  chassis;
145
146     struct lldpd_chassis *nchassis = NULL;
147     struct lldpd_port    *nport = NULL;
148
149     struct lldpd_hardware *hw = NULL;
150     struct lldpd_chassis  *ch = NULL;
151
152     struct lldpd_aa_isid_vlan_maps_tlv map_init[2];
153     struct lldpd_aa_isid_vlan_maps_tlv map[2];
154
155     uint32_t      stub[512 / 4];
156     struct ofpbuf packet;
157
158     int n;
159
160     /* Prepare data used to construct and validate LLDPPDU */
161     hardware.h_lport.p_id_subtype = LLDP_PORTID_SUBTYPE_IFNAME;
162     hardware.h_lport.p_id = "FastEthernet 1/5";
163     hardware.h_lport.p_id_len = strlen(hardware.h_lport.p_id);
164     hardware.h_lport.p_descr = "Fake port description";
165     hardware.h_lport.p_mfs = 1516;
166
167     /* Auto attach element discovery info */
168     hardware.h_lport.p_element.type = LLDP_TLV_AA_ELEM_TYPE_TAG_CLIENT;
169     hardware.h_lport.p_element.mgmt_vlan = 0xCDC;
170     hardware.h_lport.p_element.system_id.system_mac[0] = 0x1;
171     hardware.h_lport.p_element.system_id.system_mac[1] = 0x2;
172     hardware.h_lport.p_element.system_id.system_mac[2] = 0x3;
173     hardware.h_lport.p_element.system_id.system_mac[3] = 0x4;
174     hardware.h_lport.p_element.system_id.system_mac[4] = 0x5;
175     hardware.h_lport.p_element.system_id.system_mac[5] = 0x6;
176
177     hardware.h_lport.p_element.system_id.conn_type = 0x5;
178     hardware.h_lport.p_element.system_id.smlt_id = 0x3CC;
179     hardware.h_lport.p_element.system_id.mlt_id[0] = 0xB;
180     hardware.h_lport.p_element.system_id.mlt_id[1] = 0xE;
181
182     /* Local chassis info */
183     chassis.c_id_subtype = LLDP_CHASSISID_SUBTYPE_LLADDR;
184     chassis.c_id = chassis_mac;
185     chassis.c_id_len = ETHER_ADDR_LEN;
186     chassis.c_name = "Dummy chassis";
187     chassis.c_descr = "Long dummy chassis description";
188     chassis.c_cap_available = LLDP_CAP_BRIDGE;
189     chassis.c_cap_enabled = LLDP_CAP_BRIDGE;
190
191     /* ISID/VLAN mappings */
192     map_init[0].isid_vlan_data.status  = 0xC;
193     map_init[0].isid_vlan_data.vlan    = 0x64;
194     map_init[0].isid_vlan_data.isid[0] = 1;
195     map_init[0].isid_vlan_data.isid[1] = 2;
196     map_init[0].isid_vlan_data.isid[2] = 3;
197
198     map_init[1].isid_vlan_data.status  = 0xD;
199     map_init[1].isid_vlan_data.vlan    = 0xF;
200     map_init[1].isid_vlan_data.isid[0] = 4;
201     map_init[1].isid_vlan_data.isid[1] = 5;
202     map_init[1].isid_vlan_data.isid[2] = 6;
203
204     /* Prepare an empty packet buffer */
205     ofpbuf_use_stub(&packet, stub, sizeof stub);
206     ofpbuf_clear(&packet);
207
208     /* Create a dummy lldp instance */
209     lldp = lldp_create_dummy();
210     if ((lldp == NULL) ||
211         (lldp->lldpd == NULL) ||
212         (lldp->lldpd->g_hardware.h_entries.next == NULL)) {
213
214         printf("Error: unable to create dummy lldp instance");
215         return 1;
216     }
217
218     /* Populate instance with local chassis info */
219     hw = (struct lldpd_hardware *) lldp->lldpd->g_hardware.h_entries.next;
220     ch = hw->h_lport.p_chassis;
221     ch->c_id_subtype = chassis.c_id_subtype;
222     ch->c_id = chassis.c_id;
223     ch->c_id_len = chassis.c_id_len;
224     ch->c_name = chassis.c_name;
225     ch->c_descr = chassis.c_descr;
226     ch->c_cap_available = chassis.c_cap_available;
227     ch->c_cap_enabled = chassis.c_cap_enabled;
228
229     /* Populate instance with local port info */
230     hw->h_lport.p_id_subtype = hardware.h_lport.p_id_subtype;
231     hw->h_lport.p_id = hardware.h_lport.p_id;
232     hw->h_lport.p_id_len = strlen(hw->h_lport.p_id);
233     hw->h_lport.p_descr = hardware.h_lport.p_descr;
234     hw->h_lport.p_mfs = hardware.h_lport.p_mfs;
235
236     /* Populate instance with auto attach element discovery info */
237
238     hw->h_lport.p_element.type = hardware.h_lport.p_element.type;
239     hw->h_lport.p_element.mgmt_vlan = hardware.h_lport.p_element.mgmt_vlan;
240     hw->h_lport.p_element.system_id.system_mac[0] =
241         hardware.h_lport.p_element.system_id.system_mac[0];
242     hw->h_lport.p_element.system_id.system_mac[1] =
243         hardware.h_lport.p_element.system_id.system_mac[1];
244     hw->h_lport.p_element.system_id.system_mac[2] =
245         hardware.h_lport.p_element.system_id.system_mac[2];
246     hw->h_lport.p_element.system_id.system_mac[3] =
247         hardware.h_lport.p_element.system_id.system_mac[3];
248     hw->h_lport.p_element.system_id.system_mac[4] =
249         hardware.h_lport.p_element.system_id.system_mac[4];
250     hw->h_lport.p_element.system_id.system_mac[5] =
251         hardware.h_lport.p_element.system_id.system_mac[5];
252
253     hw->h_lport.p_element.system_id.conn_type =
254         hardware.h_lport.p_element.system_id.conn_type;
255     hw->h_lport.p_element.system_id.smlt_id =
256         hardware.h_lport.p_element.system_id.smlt_id;
257     hw->h_lport.p_element.system_id.mlt_id[0] =
258         hardware.h_lport.p_element.system_id.mlt_id[0];
259     hw->h_lport.p_element.system_id.mlt_id[1] =
260         hardware.h_lport.p_element.system_id.mlt_id[1];
261
262     /* Populate instance with two auto attach isid/vlan mappings */
263     map[0].isid_vlan_data.status  = map_init[0].isid_vlan_data.status;
264     map[0].isid_vlan_data.vlan    = map_init[0].isid_vlan_data.vlan;
265     map[0].isid_vlan_data.isid[0] = map_init[0].isid_vlan_data.isid[0];
266     map[0].isid_vlan_data.isid[1] = map_init[0].isid_vlan_data.isid[1];
267     map[0].isid_vlan_data.isid[2] = map_init[0].isid_vlan_data.isid[2];
268
269     map[1].isid_vlan_data.status  = map_init[1].isid_vlan_data.status;
270     map[1].isid_vlan_data.vlan    = map_init[1].isid_vlan_data.vlan;
271     map[1].isid_vlan_data.isid[0] = map_init[1].isid_vlan_data.isid[0];
272     map[1].isid_vlan_data.isid[1] = map_init[1].isid_vlan_data.isid[1];
273     map[1].isid_vlan_data.isid[2] = map_init[1].isid_vlan_data.isid[2];
274
275     list_init(&hw->h_lport.p_isid_vlan_maps.m_entries);
276     list_push_back(&hw->h_lport.p_isid_vlan_maps.m_entries,
277                    &map[0].m_entries);
278     list_push_back(&hw->h_lport.p_isid_vlan_maps.m_entries,
279                    &map[1].m_entries);
280
281     /* Construct LLDPPDU (including Ethernet header) */
282     eth_compose(&packet, eth_addr_lldp, eth_src, ETH_TYPE_LLDP, 0);
283     n = lldp_send(lldp->lldpd, hw, &packet);
284
285     if (n == 0) {
286         printf("Error: unable to build packet\n");
287         return 1;
288     }
289
290     /* Decode the constructed LLDPPDU */
291     assert(lldp_decode(NULL, packet.data_, packet.size_, hw,
292                        &nchassis, &nport) != -1);
293
294     /* Expecting returned pointers to allocated structures */
295     if (!nchassis || !nport) {
296         printf("Error: unable to decode packet");
297         return 1;
298     }
299
300     /* Verify chassis values */
301     check_received_chassis(&chassis, nchassis);
302
303     /* Verify port values */
304     check_received_port(&hardware.h_lport, nport);
305
306     /* Verify auto attach values */
307     check_received_aa(&hardware.h_lport, nport, map_init);
308
309     return 0;
310 }
311
312
313 static void
314 test_aa_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
315 {
316     int num_errors = 0;
317
318     /* Make sure we emit valid auto-attach LLDPPDUs */
319     num_tests++;
320     num_errors += test_aa_send();
321
322     /* Add more tests here */
323
324     printf("executed %d tests, %d errors\n", num_tests, num_errors);
325
326     exit(num_errors != 0);
327 }
328
329 OVSTEST_REGISTER("test-aa", test_aa_main);