]>
Commit | Line | Data |
---|---|---|
99eef98b DF |
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 */ | |
134fefa4 BP |
29 | static const struct eth_addr chassis_mac = ETH_ADDR_C(5e,10,8e,e7,84,ad); |
30 | static const struct eth_addr eth_src = ETH_ADDR_C(5e,10,8e,e7,84,ad); | |
99eef98b DF |
31 | |
32 | /* LLDP multicast address */ | |
134fefa4 | 33 | static const struct eth_addr eth_addr_lldp = ETH_ADDR_C(01,80,c2,00,00,0e); |
99eef98b DF |
34 | |
35 | /* Count of tests run */ | |
24885e32 | 36 | static int num_tests = 0; |
99eef98b DF |
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); | |
99eef98b DF |
50 | } |
51 | ||
52 | ||
53 | /* | |
54 | * Helper function to validate chassis info | |
55 | */ | |
56 | static void | |
57 | check_received_chassis(struct lldpd_chassis *schassis, | |
58 | struct lldpd_chassis *rchassis) | |
59 | { | |
60 | assert(rchassis->c_id_subtype == schassis->c_id_subtype); | |
61 | assert(rchassis->c_id_len == schassis->c_id_len); | |
1acaf4ac | 62 | assert(memcmp(rchassis->c_id, schassis->c_id, schassis->c_id_len) == 0); |
99eef98b DF |
63 | assert(strcmp(rchassis->c_name, schassis->c_name) == 0); |
64 | assert(strcmp(rchassis->c_descr, schassis->c_descr) == 0); | |
65 | assert(rchassis->c_cap_available == schassis->c_cap_available); | |
66 | assert(rchassis->c_cap_enabled == schassis->c_cap_enabled); | |
99eef98b DF |
67 | } |
68 | ||
69 | ||
70 | /* | |
71 | * Helper function to validate auto-attach info | |
72 | */ | |
73 | static void | |
74 | check_received_aa(struct lldpd_port *sport, | |
75 | struct lldpd_port *rport, | |
76 | struct lldpd_aa_isid_vlan_maps_tlv *smap) | |
77 | { | |
78 | struct lldpd_aa_isid_vlan_maps_tlv *received_map; | |
79 | int i = 0; | |
80 | ||
81 | assert(rport->p_element.type == sport->p_element.type); | |
82 | assert(rport->p_element.mgmt_vlan == sport->p_element.mgmt_vlan); | |
74ff3298 JR |
83 | assert(eth_addr_equals(rport->p_element.system_id.system_mac, |
84 | sport->p_element.system_id.system_mac)); | |
99eef98b DF |
85 | assert(rport->p_element.system_id.conn_type == |
86 | sport->p_element.system_id.conn_type); | |
14691214 DF |
87 | assert(rport->p_element.system_id.rsvd == |
88 | sport->p_element.system_id.rsvd); | |
89 | assert(rport->p_element.system_id.rsvd2[0] == | |
90 | sport->p_element.system_id.rsvd2[0]); | |
91 | assert(rport->p_element.system_id.rsvd2[1] == | |
92 | sport->p_element.system_id.rsvd2[1]); | |
99eef98b DF |
93 | |
94 | /* Should receive 2 mappings */ | |
417e7e66 | 95 | assert(!ovs_list_is_empty(&rport->p_isid_vlan_maps)); |
99eef98b DF |
96 | |
97 | /* For each received isid/vlan mapping */ | |
854560f8 | 98 | LIST_FOR_EACH (received_map, m_entries, &rport->p_isid_vlan_maps) { |
99eef98b DF |
99 | |
100 | /* Validate against mapping sent */ | |
101 | assert(smap[i].isid_vlan_data.status == | |
102 | received_map->isid_vlan_data.status); | |
103 | assert(smap[i].isid_vlan_data.vlan == | |
104 | received_map->isid_vlan_data.vlan); | |
02c842eb BP |
105 | assert(smap[i].isid_vlan_data.isid == |
106 | received_map->isid_vlan_data.isid); | |
99eef98b DF |
107 | |
108 | /* Next mapping sent */ | |
109 | i++; | |
110 | } | |
111 | assert(i == 2); | |
99eef98b DF |
112 | } |
113 | ||
114 | ||
115 | /* | |
116 | * Validate basic send/receive processing | |
117 | */ | |
118 | static int | |
119 | test_aa_send(void) | |
120 | { | |
121 | struct lldp *lldp; | |
122 | struct lldpd_hardware hardware; | |
123 | struct lldpd_chassis chassis; | |
124 | ||
125 | struct lldpd_chassis *nchassis = NULL; | |
126 | struct lldpd_port *nport = NULL; | |
127 | ||
128 | struct lldpd_hardware *hw = NULL; | |
129 | struct lldpd_chassis *ch = NULL; | |
130 | ||
131 | struct lldpd_aa_isid_vlan_maps_tlv map_init[2]; | |
132 | struct lldpd_aa_isid_vlan_maps_tlv map[2]; | |
133 | ||
134 | uint32_t stub[512 / 4]; | |
22736f59 | 135 | struct dp_packet packet; |
99eef98b DF |
136 | |
137 | int n; | |
138 | ||
139 | /* Prepare data used to construct and validate LLDPPDU */ | |
140 | hardware.h_lport.p_id_subtype = LLDP_PORTID_SUBTYPE_IFNAME; | |
141 | hardware.h_lport.p_id = "FastEthernet 1/5"; | |
142 | hardware.h_lport.p_id_len = strlen(hardware.h_lport.p_id); | |
143 | hardware.h_lport.p_descr = "Fake port description"; | |
144 | hardware.h_lport.p_mfs = 1516; | |
145 | ||
146 | /* Auto attach element discovery info */ | |
14691214 DF |
147 | hardware.h_lport.p_element.type = |
148 | LLDP_TLV_AA_ELEM_TYPE_CLIENT_VIRTUAL_SWITCH; | |
99eef98b | 149 | hardware.h_lport.p_element.mgmt_vlan = 0xCDC; |
37ba4764 | 150 | eth_addr_from_uint64(0x010203040506ULL, |
74ff3298 | 151 | &hardware.h_lport.p_element.system_id.system_mac); |
99eef98b DF |
152 | |
153 | hardware.h_lport.p_element.system_id.conn_type = 0x5; | |
14691214 DF |
154 | hardware.h_lport.p_element.system_id.rsvd = 0x3CC; |
155 | hardware.h_lport.p_element.system_id.rsvd2[0] = 0xB; | |
156 | hardware.h_lport.p_element.system_id.rsvd2[1] = 0xE; | |
99eef98b DF |
157 | |
158 | /* Local chassis info */ | |
159 | chassis.c_id_subtype = LLDP_CHASSISID_SUBTYPE_LLADDR; | |
74ff3298 | 160 | chassis.c_id = CONST_CAST(uint8_t *, chassis_mac.ea); |
09c28fa3 | 161 | chassis.c_id_len = ETH_ADDR_LEN; |
99eef98b DF |
162 | chassis.c_name = "Dummy chassis"; |
163 | chassis.c_descr = "Long dummy chassis description"; | |
164 | chassis.c_cap_available = LLDP_CAP_BRIDGE; | |
165 | chassis.c_cap_enabled = LLDP_CAP_BRIDGE; | |
166 | ||
167 | /* ISID/VLAN mappings */ | |
168 | map_init[0].isid_vlan_data.status = 0xC; | |
169 | map_init[0].isid_vlan_data.vlan = 0x64; | |
02c842eb | 170 | map_init[0].isid_vlan_data.isid = 0x010203; |
99eef98b DF |
171 | |
172 | map_init[1].isid_vlan_data.status = 0xD; | |
173 | map_init[1].isid_vlan_data.vlan = 0xF; | |
02c842eb | 174 | map_init[1].isid_vlan_data.isid = 0x040506; |
99eef98b DF |
175 | |
176 | /* Prepare an empty packet buffer */ | |
22736f59 BP |
177 | dp_packet_use_stub(&packet, stub, sizeof stub); |
178 | dp_packet_clear(&packet); | |
99eef98b DF |
179 | |
180 | /* Create a dummy lldp instance */ | |
181 | lldp = lldp_create_dummy(); | |
182 | if ((lldp == NULL) || | |
183 | (lldp->lldpd == NULL) || | |
417e7e66 | 184 | ovs_list_is_empty(&lldp->lldpd->g_hardware)) { |
99eef98b DF |
185 | printf("Error: unable to create dummy lldp instance"); |
186 | return 1; | |
187 | } | |
188 | ||
189 | /* Populate instance with local chassis info */ | |
2cbb2d90 | 190 | hw = lldpd_first_hardware(lldp->lldpd); |
99eef98b DF |
191 | ch = hw->h_lport.p_chassis; |
192 | ch->c_id_subtype = chassis.c_id_subtype; | |
193 | ch->c_id = chassis.c_id; | |
194 | ch->c_id_len = chassis.c_id_len; | |
195 | ch->c_name = chassis.c_name; | |
196 | ch->c_descr = chassis.c_descr; | |
197 | ch->c_cap_available = chassis.c_cap_available; | |
198 | ch->c_cap_enabled = chassis.c_cap_enabled; | |
199 | ||
200 | /* Populate instance with local port info */ | |
201 | hw->h_lport.p_id_subtype = hardware.h_lport.p_id_subtype; | |
202 | hw->h_lport.p_id = hardware.h_lport.p_id; | |
203 | hw->h_lport.p_id_len = strlen(hw->h_lport.p_id); | |
204 | hw->h_lport.p_descr = hardware.h_lport.p_descr; | |
205 | hw->h_lport.p_mfs = hardware.h_lport.p_mfs; | |
206 | ||
207 | /* Populate instance with auto attach element discovery info */ | |
208 | ||
209 | hw->h_lport.p_element.type = hardware.h_lport.p_element.type; | |
210 | hw->h_lport.p_element.mgmt_vlan = hardware.h_lport.p_element.mgmt_vlan; | |
74ff3298 JR |
211 | hw->h_lport.p_element.system_id.system_mac = |
212 | hardware.h_lport.p_element.system_id.system_mac; | |
99eef98b DF |
213 | |
214 | hw->h_lport.p_element.system_id.conn_type = | |
215 | hardware.h_lport.p_element.system_id.conn_type; | |
14691214 DF |
216 | hw->h_lport.p_element.system_id.rsvd = |
217 | hardware.h_lport.p_element.system_id.rsvd; | |
218 | hw->h_lport.p_element.system_id.rsvd2[0] = | |
219 | hardware.h_lport.p_element.system_id.rsvd2[0]; | |
220 | hw->h_lport.p_element.system_id.rsvd2[1] = | |
221 | hardware.h_lport.p_element.system_id.rsvd2[1]; | |
99eef98b DF |
222 | |
223 | /* Populate instance with two auto attach isid/vlan mappings */ | |
224 | map[0].isid_vlan_data.status = map_init[0].isid_vlan_data.status; | |
225 | map[0].isid_vlan_data.vlan = map_init[0].isid_vlan_data.vlan; | |
02c842eb | 226 | map[0].isid_vlan_data.isid = map_init[0].isid_vlan_data.isid; |
99eef98b DF |
227 | |
228 | map[1].isid_vlan_data.status = map_init[1].isid_vlan_data.status; | |
229 | map[1].isid_vlan_data.vlan = map_init[1].isid_vlan_data.vlan; | |
02c842eb | 230 | map[1].isid_vlan_data.isid = map_init[1].isid_vlan_data.isid; |
99eef98b | 231 | |
417e7e66 BW |
232 | ovs_list_init(&hw->h_lport.p_isid_vlan_maps); |
233 | ovs_list_push_back(&hw->h_lport.p_isid_vlan_maps, &map[0].m_entries); | |
234 | ovs_list_push_back(&hw->h_lport.p_isid_vlan_maps, &map[1].m_entries); | |
99eef98b DF |
235 | |
236 | /* Construct LLDPPDU (including Ethernet header) */ | |
237 | eth_compose(&packet, eth_addr_lldp, eth_src, ETH_TYPE_LLDP, 0); | |
238 | n = lldp_send(lldp->lldpd, hw, &packet); | |
239 | ||
240 | if (n == 0) { | |
241 | printf("Error: unable to build packet\n"); | |
242 | return 1; | |
243 | } | |
244 | ||
245 | /* Decode the constructed LLDPPDU */ | |
09c28fa3 | 246 | assert(lldp_decode(NULL, dp_packet_data(&packet), dp_packet_size(&packet), hw, |
99eef98b DF |
247 | &nchassis, &nport) != -1); |
248 | ||
249 | /* Expecting returned pointers to allocated structures */ | |
250 | if (!nchassis || !nport) { | |
251 | printf("Error: unable to decode packet"); | |
252 | return 1; | |
253 | } | |
254 | ||
255 | /* Verify chassis values */ | |
256 | check_received_chassis(&chassis, nchassis); | |
257 | ||
258 | /* Verify port values */ | |
259 | check_received_port(&hardware.h_lport, nport); | |
260 | ||
261 | /* Verify auto attach values */ | |
262 | check_received_aa(&hardware.h_lport, nport, map_init); | |
263 | ||
9547cc66 WT |
264 | lldpd_chassis_cleanup(nchassis, true); |
265 | lldpd_port_cleanup(nport, true); | |
266 | free(nport); | |
267 | lldp_destroy_dummy(lldp); | |
268 | ||
99eef98b DF |
269 | return 0; |
270 | } | |
271 | ||
272 | ||
273 | static void | |
274 | test_aa_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) | |
275 | { | |
276 | int num_errors = 0; | |
277 | ||
278 | /* Make sure we emit valid auto-attach LLDPPDUs */ | |
279 | num_tests++; | |
280 | num_errors += test_aa_send(); | |
281 | ||
282 | /* Add more tests here */ | |
283 | ||
284 | printf("executed %d tests, %d errors\n", num_tests, num_errors); | |
285 | ||
286 | exit(num_errors != 0); | |
287 | } | |
288 | ||
289 | OVSTEST_REGISTER("test-aa", test_aa_main); |