Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : * Copyright Contributors to the OpenSDN project
4 : */
5 : #include <vr_os.h>
6 : #include <vr_packet.h>
7 : #include "vr_interface.h"
8 : #include "vr_message.h"
9 : #include "vr_sandesh.h"
10 : #include "vr_bridge.h"
11 : #include "vr_htable.h"
12 : #include "vr_nexthop.h"
13 : #include "vr_datapath.h"
14 : #include "vr_defs.h"
15 : #include "vr_hash.h"
16 :
17 : #if defined(__linux__) && defined(__KERNEL__)
18 : extern short vr_bridge_table_major;
19 : #endif
20 : unsigned char *vr_bridge_table_path;
21 :
22 : unsigned int vr_bridge_entries = VR_DEF_BRIDGE_ENTRIES;
23 : unsigned int vr_bridge_oentries = 0;
24 : static vr_htable_t vn_rtable;
25 : char vr_bcast_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
26 :
27 : int bridge_table_init(struct vr_rtable *, struct rtable_fspec *);
28 : void bridge_table_deinit(struct vr_rtable *, struct rtable_fspec *, bool);
29 : struct vr_bridge_entry *vr_find_bridge_entry(struct vr_bridge_entry_key *);
30 : struct vr_bridge_entry *vr_find_free_bridge_entry(unsigned int, char *);
31 : extern struct vr_vrf_stats *(*vr_inet_vrf_stats)(unsigned short, unsigned int);
32 : extern l4_pkt_type_t vr_ip_well_known_packet(struct vr_packet *);
33 : extern l4_pkt_type_t vr_ip6_well_known_packet(struct vr_packet *);
34 : extern int vr_bridge_get_mac_type(char *mac);
35 :
36 : void *vr_bridge_table = NULL;
37 : void *vr_obridge_table = NULL;
38 :
39 : int
40 110 : vr_bridge_get_mac_type(char *mac)
41 : {
42 110 : int flags = 0;
43 110 : if (IS_MAC_BCAST(mac)) {
44 0 : flags |= MAC_BC_BIT_SET;
45 110 : } else if (IS_MAC_BMCAST(mac)) {
46 0 : flags |= MAC_MC_BIT_SET;
47 : } else {
48 110 : flags |= MAC_UC_BIT_SET;
49 : }
50 :
51 110 : return flags;
52 : }
53 :
54 : void *
55 0 : vr_bridge_get_va(struct vrouter *router, uint64_t offset)
56 : {
57 0 : return vr_htable_get_address(vn_rtable, offset);
58 : }
59 :
60 : /*
61 : * This api is called to get bridge table size
62 : * NOTE: This api is also called from agent (via sandesh)
63 : * very early during init even before bridge table is
64 : * initialized to calculate huge page table size.
65 : * Hence this api should not use vr_htable structures
66 : */
67 : unsigned int
68 0 : vr_bridge_table_size(struct vrouter *router)
69 : {
70 : // set the overflow table size
71 0 : vr_compute_size_bridge_otable();
72 0 : return (VR_BRIDGE_TABLE_SIZE + VR_BRIDGE_OFLOW_TABLE_SIZE);
73 : }
74 :
75 : static bool
76 1 : vr_unknown_uc_flood(struct vr_interface *ingress_vif,
77 : struct vr_nexthop *ingress_nh)
78 : {
79 1 : if (!ingress_vif)
80 0 : return false;
81 :
82 1 : if (vif_is_virtual(ingress_vif)) {
83 1 : return ((ingress_vif->vif_flags & VIF_FLAG_UNKNOWN_UC_FLOOD) != 0);
84 0 : } else if (vif_is_fabric(ingress_vif) && ingress_nh) {
85 0 : return ((ingress_nh->nh_flags & NH_FLAG_UNKNOWN_UC_FLOOD) != 0);
86 : }
87 :
88 0 : return false;
89 : }
90 :
91 : struct vr_bridge_entry *
92 293 : vr_find_bridge_entry(struct vr_bridge_entry_key *key)
93 : {
94 293 : if (!vn_rtable || !key)
95 0 : return NULL;
96 :
97 293 : return (struct vr_bridge_entry *)vr_htable_find_hentry(vn_rtable, key, 0);
98 : }
99 :
100 : struct vr_bridge_entry *
101 86 : vr_find_free_bridge_entry(unsigned int vrf_id, char *mac)
102 : {
103 : struct vr_bridge_entry *be;
104 : struct vr_bridge_entry_key key;
105 :
106 86 : if (!vn_rtable || !mac)
107 0 : return NULL;
108 :
109 86 : key.be_vrf_id = vrf_id;
110 86 : VR_MAC_COPY(key.be_mac, mac);
111 86 : be = (struct vr_bridge_entry *)vr_htable_find_free_hentry(vn_rtable,
112 : &key, 0);
113 86 : return be;
114 : }
115 :
116 : static struct vr_bridge_entry *
117 91 : bridge_add(unsigned int router_id, unsigned int vrf,
118 : uint8_t *mac, int nh_id)
119 : {
120 : struct vr_bridge_entry *be;
121 : struct vr_bridge_entry_key key;
122 : struct vr_nexthop *old_nh;
123 :
124 91 : VR_MAC_COPY(key.be_mac, mac);
125 91 : key.be_vrf_id = vrf;
126 91 : be = vr_find_bridge_entry(&key);
127 91 : if (!be) {
128 86 : be = vr_find_free_bridge_entry(vrf, mac);
129 86 : if (!be)
130 0 : return NULL;
131 :
132 86 : VR_MAC_COPY(be->be_key.be_mac, mac);
133 86 : be->be_key.be_vrf_id = vrf;
134 86 : be->be_packets = 0;
135 86 : be->be_flags = VR_BE_VALID_FLAG;
136 86 : be->be_nh_id = -1;
137 : }
138 :
139 : /* Un ref the old nexthop */
140 91 : if (be->be_nh_id != nh_id) {
141 91 : old_nh = be->be_nh;
142 91 : be->be_nh = vrouter_get_nexthop(router_id, nh_id);
143 91 : if (be->be_nh) {
144 91 : be->be_nh_id = be->be_nh->nh_id;
145 : } else {
146 0 : be->be_nh_id = -1;
147 : }
148 :
149 91 : if (be->be_flags & VR_BE_MAC_MOVED_FLAG) {
150 0 : be->be_flags &= ~VR_BE_MAC_MOVED_FLAG;
151 : }
152 :
153 91 : if (old_nh)
154 5 : vrouter_put_nexthop(old_nh);
155 : }
156 :
157 91 : return be;
158 : }
159 :
160 : static int
161 91 : __bridge_table_add(struct vr_route_req *rt)
162 : {
163 : int ret;
164 : unsigned short flags, i;
165 :
166 : struct vr_bridge_entry *be;
167 :
168 91 : be = bridge_add(rt->rtr_req.rtr_rid, rt->rtr_req.rtr_vrf_id,
169 91 : rt->rtr_req.rtr_mac, rt->rtr_req.rtr_nh_id);
170 91 : if (!be)
171 0 : return -ENOMEM;
172 :
173 91 : rt->rtr_req.rtr_label_flags =
174 91 : VR_BRIDGE_FLAG_MASK(rt->rtr_req.rtr_label_flags);
175 :
176 91 : if (rt->rtr_req.rtr_label_flags & VR_BE_LABEL_VALID_FLAG)
177 37 : be->be_label = rt->rtr_req.rtr_label;
178 :
179 : /*
180 : * attempt the change for some number of times, if the set
181 : * turns out to be contested
182 : */
183 91 : ret = -EAGAIN;
184 91 : for (i = 0; i < 10; i++) {
185 91 : flags = be->be_flags;
186 91 : if (vr_sync_bool_compare_and_swap_16u(&be->be_flags, flags,
187 : VR_BE_VALID_FLAG | rt->rtr_req.rtr_label_flags)) {
188 91 : ret = 0;
189 91 : break;
190 : }
191 : }
192 :
193 91 : rt->rtr_req.rtr_index = be->be_hentry.hentry_index;
194 :
195 91 : return ret;
196 : }
197 :
198 : static int
199 92 : bridge_table_add(struct vr_rtable * _unused, struct vr_route_req *rt)
200 : {
201 : int ret;
202 :
203 92 : if (!vn_rtable)
204 0 : return -EINVAL;
205 :
206 92 : if (rt->rtr_req.rtr_mac_size != VR_ETHER_ALEN)
207 0 : return -EINVAL;
208 :
209 92 : if (IS_MAC_ZERO(rt->rtr_req.rtr_mac))
210 0 : return -EINVAL;
211 :
212 184 : rt->rtr_nh = vrouter_get_nexthop(rt->rtr_req.rtr_rid,
213 92 : rt->rtr_req.rtr_nh_id);
214 92 : if (!rt->rtr_nh)
215 1 : return -ENOENT;
216 :
217 91 : ret = __bridge_table_add(rt);
218 91 : vrouter_put_nexthop(rt->rtr_nh);
219 91 : return ret;
220 : }
221 :
222 : static void
223 16715861 : bridge_table_entry_free(vr_htable_t table, vr_hentry_t *hentry,
224 : unsigned int index, void *data)
225 : {
226 : struct vr_nexthop *nh;
227 16715861 : struct vr_bridge_entry *be = (struct vr_bridge_entry *)hentry;
228 :
229 16715861 : if (!be)
230 0 : return;
231 :
232 : /* Mark this entry as invalid */
233 16715861 : be->be_flags &= ~VR_BE_VALID_FLAG;
234 :
235 16715861 : if (be->be_nh) {
236 86 : nh = be->be_nh;
237 86 : be->be_nh = NULL;
238 86 : be->be_nh_id = -1;
239 86 : vrouter_put_nexthop(nh);
240 : }
241 :
242 16715861 : be->be_packets = 0;
243 16715861 : vr_htable_release_hentry(table, hentry);
244 :
245 16715861 : return;
246 : }
247 :
248 : static int
249 87 : bridge_table_delete(struct vr_rtable * _unused, struct vr_route_req *rt)
250 : {
251 : struct vr_bridge_entry_key key;
252 : struct vr_bridge_entry *be;
253 :
254 87 : if (!vn_rtable)
255 0 : return -EINVAL;
256 :
257 87 : if (rt->rtr_req.rtr_mac_size != VR_ETHER_ALEN)
258 0 : return -EINVAL;
259 :
260 87 : VR_MAC_COPY(key.be_mac, rt->rtr_req.rtr_mac);
261 87 : key.be_vrf_id = rt->rtr_req.rtr_vrf_id;
262 :
263 87 : be = vr_find_bridge_entry(&key);
264 87 : if (!be)
265 2 : return -ENOENT;
266 :
267 85 : bridge_table_entry_free(vn_rtable, (vr_hentry_t *)be, 0, NULL);
268 85 : return 0;
269 : }
270 :
271 : static void
272 9 : bridge_update_route_req(struct vr_bridge_entry *be, struct vr_route_req *rt)
273 : {
274 9 : rt->rtr_req.rtr_label_flags = be->be_flags;
275 9 : rt->rtr_req.rtr_label = be->be_label;
276 9 : rt->rtr_nh = be->be_nh;
277 9 : if (rt->rtr_nh)
278 9 : rt->rtr_req.rtr_nh_id = rt->rtr_nh->nh_id;
279 9 : if (rt->rtr_req.rtr_index != VR_BE_INVALID_INDEX) {
280 4 : if (rt->rtr_req.rtr_mac) {
281 4 : VR_MAC_COPY(rt->rtr_req.rtr_mac, be->be_key.be_mac);
282 : }
283 : } else {
284 5 : rt->rtr_req.rtr_index = be->be_hentry.hentry_index;
285 : }
286 :
287 9 : return;
288 : }
289 :
290 : static struct vr_bridge_entry *
291 125 : __bridge_lookup(unsigned int vrf_id, struct vr_route_req *rt)
292 : {
293 : struct vr_bridge_entry *be;
294 : struct vr_bridge_entry_key key;
295 :
296 125 : rt->rtr_req.rtr_label_flags = 0;
297 125 : rt->rtr_nh = NULL;
298 :
299 125 : if (rt->rtr_req.rtr_index != VR_BE_INVALID_INDEX) {
300 : be = (struct vr_bridge_entry *)
301 10 : vr_htable_get_hentry_by_index(vn_rtable, rt->rtr_req.rtr_index);
302 : } else {
303 115 : VR_MAC_COPY(key.be_mac, rt->rtr_req.rtr_mac);
304 115 : key.be_vrf_id = rt->rtr_req.rtr_vrf_id;
305 115 : be = vr_find_bridge_entry(&key);
306 : }
307 :
308 125 : return be;
309 : }
310 :
311 :
312 : static struct vr_nexthop *
313 16 : bridge_table_lookup(unsigned int vrf_id, struct vr_route_req *rt)
314 : {
315 : struct vr_bridge_entry *be;
316 :
317 16 : be = __bridge_lookup(vrf_id, rt);
318 16 : if (be)
319 9 : bridge_update_route_req(be, rt);
320 :
321 16 : return rt->rtr_nh;
322 : }
323 :
324 : struct vr_nexthop *
325 16 : vr_bridge_lookup(unsigned int vrf_id, struct vr_route_req *rt)
326 : {
327 16 : if (!vn_rtable)
328 0 : return NULL;
329 :
330 16 : return bridge_table_lookup(vrf_id, rt);
331 : }
332 :
333 : static struct vr_bridge_entry *
334 109 : bridge_lookup(uint8_t *mac, struct vr_forwarding_md *fmd)
335 : {
336 : struct vr_route_req rt;
337 : struct vr_bridge_entry *be;
338 :
339 109 : rt.rtr_req.rtr_label_flags = 0;
340 109 : rt.rtr_req.rtr_index = VR_BE_INVALID_INDEX;
341 109 : rt.rtr_req.rtr_mac_size = VR_ETHER_ALEN;
342 109 : rt.rtr_req.rtr_mac = mac;
343 109 : rt.rtr_req.rtr_vrf_id = fmd->fmd_dvrf;
344 109 : be = __bridge_lookup(rt.rtr_req.rtr_vrf_id, &rt);
345 :
346 109 : if (be && fmd) {
347 108 : if (be->be_flags & VR_BE_LABEL_VALID_FLAG)
348 64 : vr_fmd_set_label(fmd, be->be_label, VR_LABEL_TYPE_UNKNOWN);
349 108 : if (be->be_flags & VR_BE_L2_CONTROL_DATA_FLAG)
350 0 : vr_fmd_update_l2_control_data(fmd, true);
351 : }
352 :
353 109 : return be;
354 : }
355 :
356 : struct vr_nexthop *
357 2 : __vrouter_bridge_lookup(unsigned int vrf_id, unsigned char *mac)
358 : {
359 : struct vr_route_req rt;
360 :
361 2 : if (!mac)
362 0 : return NULL;
363 :
364 2 : rt.rtr_req.rtr_label_flags = 0;
365 2 : rt.rtr_req.rtr_index = VR_BE_INVALID_INDEX;
366 2 : rt.rtr_req.rtr_mac_size = VR_ETHER_ALEN;
367 2 : rt.rtr_req.rtr_mac = mac;
368 : /* If multicast L2 packet, use broadcast composite nexthop */
369 2 : if (IS_MAC_BMCAST(rt.rtr_req.rtr_mac))
370 0 : rt.rtr_req.rtr_mac = (int8_t *)vr_bcast_mac;
371 2 : rt.rtr_req.rtr_vrf_id = vrf_id;
372 :
373 2 : return vr_bridge_lookup(vrf_id, &rt);
374 : }
375 :
376 :
377 : unsigned short
378 0 : vr_bridge_route_flags(unsigned int vrf_id, unsigned char *mac)
379 : {
380 : struct vr_bridge_entry *be;
381 : struct vr_bridge_entry_key key;
382 :
383 0 : VR_MAC_COPY(key.be_mac, mac);
384 0 : key.be_vrf_id = vrf_id;
385 :
386 0 : be = vr_find_bridge_entry(&key);
387 0 : if (be && (be->be_flags & VR_BE_VALID_FLAG))
388 0 : return be->be_flags;
389 :
390 0 : return 0;
391 : }
392 :
393 : static int
394 0 : vr_bridge_set_route_flags(struct vr_bridge_entry *be, unsigned short flags)
395 : {
396 : unsigned short be_flags, be_flags_old;
397 :
398 0 : if (be) {
399 0 : be_flags = be_flags_old = be->be_flags;
400 0 : if (be_flags & VR_BE_VALID_FLAG) {
401 0 : if ((be_flags & flags) == flags)
402 0 : return -EEXIST;
403 :
404 0 : flags = VR_BRIDGE_FLAG_MASK(flags);
405 0 : be_flags = vr_sync_val_compare_and_swap_16u(&be->be_flags, be_flags,
406 : flags | be_flags);
407 :
408 0 : if ((be_flags & flags) == flags)
409 0 : return -EEXIST;
410 :
411 0 : if (be_flags == be_flags_old)
412 0 : return 0;
413 : }
414 : }
415 :
416 0 : return -EINVAL;
417 : }
418 :
419 : unsigned int
420 0 : vr_bridge_table_used_total_entries(struct vrouter *router)
421 : {
422 0 : if (vn_rtable)
423 0 : return vr_htable_used_total_entries(vn_rtable);
424 :
425 0 : return 0;
426 : }
427 :
428 : unsigned int
429 0 : vr_bridge_table_used_oflow_entries(struct vrouter *router)
430 : {
431 0 : if (vn_rtable)
432 0 : return vr_htable_used_oflow_entries(vn_rtable);
433 0 : return 0;
434 : }
435 :
436 : static int
437 0 : bridge_table_get(unsigned int vrf_id, struct vr_route_req *rt)
438 : {
439 : struct vr_nexthop *nh;
440 :
441 0 : nh = bridge_table_lookup(vrf_id, rt);
442 0 : if (nh)
443 0 : return 0;
444 :
445 0 : return -ENOENT;
446 : }
447 :
448 : static int
449 0 : bridge_entry_make_req(struct vr_route_req *resp, struct vr_bridge_entry *ent)
450 : {
451 0 : memset(resp, 0, sizeof(struct vr_route_req));
452 0 : resp->rtr_req.rtr_mac_size = VR_ETHER_ALEN;
453 0 : resp->rtr_req.rtr_mac = vr_zalloc(VR_ETHER_ALEN, VR_ROUTE_REQ_MAC_OBJECT);
454 0 : if (!resp->rtr_req.rtr_mac)
455 0 : return -ENOMEM;
456 0 : VR_MAC_COPY(resp->rtr_req.rtr_mac, ent->be_key.be_mac);
457 0 : resp->rtr_req.rtr_vrf_id = ent->be_key.be_vrf_id;
458 0 : if (ent->be_nh)
459 0 : resp->rtr_req.rtr_nh_id = ent->be_nh->nh_id;
460 0 : resp->rtr_req.rtr_family = AF_BRIDGE;
461 0 : resp->rtr_req.rtr_label = ent->be_label;
462 0 : resp->rtr_req.rtr_label_flags = ent->be_flags;
463 0 : resp->rtr_req.rtr_index = ent->be_hentry.hentry_index;
464 :
465 0 : return 0;
466 : }
467 :
468 : static void
469 0 : bridge_entry_req_destroy(struct vr_route_req *resp)
470 : {
471 0 : if (resp->rtr_req.rtr_mac)
472 0 : vr_free(resp->rtr_req.rtr_mac, VR_ROUTE_REQ_MAC_OBJECT);
473 0 : }
474 :
475 : static int
476 0 : __bridge_table_dump(struct vr_message_dumper *dumper)
477 : {
478 0 : struct vr_route_req *req = (struct vr_route_req *)(dumper->dump_req);
479 : struct vr_route_req resp;
480 : int ret;
481 : unsigned int i;
482 : struct vr_bridge_entry *be;
483 :
484 0 : for(i = 0; i < (vr_bridge_entries + vr_bridge_oentries); i++) {
485 : be = (struct vr_bridge_entry *)
486 0 : vr_htable_get_hentry_by_index(vn_rtable, i);
487 0 : if (!be)
488 0 : continue;
489 0 : if (be->be_flags & VR_BE_VALID_FLAG) {
490 0 : if (be->be_key.be_vrf_id != req->rtr_req.rtr_vrf_id)
491 0 : continue;
492 0 : if (dumper->dump_been_to_marker == 0) {
493 0 : if (VR_MAC_CMP(be->be_key.be_mac, req->rtr_req.rtr_mac)
494 0 : && (be->be_key.be_vrf_id == req->rtr_req.rtr_vrf_id)) {
495 0 : dumper->dump_been_to_marker = 1;
496 : }
497 : } else {
498 0 : if (!bridge_entry_make_req(&resp, be)) {
499 0 : ret = vr_message_dump_object(dumper, VR_ROUTE_OBJECT_ID, &resp);
500 0 : bridge_entry_req_destroy(&resp);
501 0 : if (ret <= 0) {
502 0 : return ret;
503 : }
504 : }
505 : }
506 : }
507 : }
508 :
509 0 : return 0;
510 : }
511 :
512 : static int
513 0 : bridge_table_dump(struct vr_rtable * __unsued, struct vr_route_req *rt)
514 : {
515 0 : int ret = 0;
516 : struct vr_message_dumper *dumper;
517 : char *mac;
518 :
519 0 : if (rt->rtr_req.rtr_mac_size != VR_ETHER_ALEN)
520 0 : return -EINVAL;
521 :
522 0 : dumper = vr_message_dump_init(&rt->rtr_req);
523 0 : if (!dumper) {
524 0 : ret = -ENOMEM;
525 0 : goto generate_response;
526 : }
527 :
528 :
529 0 : mac = (char *)(((vr_route_req *)(dumper->dump_req))->rtr_mac);
530 0 : if (!mac) {
531 0 : ret = -EINVAL;
532 0 : goto generate_response;
533 : }
534 :
535 0 : if (IS_MAC_ZERO(mac))
536 0 : dumper->dump_been_to_marker = 1;
537 :
538 0 : ret = __bridge_table_dump(dumper);
539 :
540 0 : generate_response:
541 0 : vr_message_dump_exit(dumper, ret);
542 :
543 0 : return 0;
544 : }
545 :
546 : static vr_hentry_key
547 203 : bridge_entry_key(vr_htable_t table, vr_hentry_t *entry, unsigned int
548 : *key_len)
549 : {
550 203 : struct vr_bridge_entry *be = CONTAINER_OF(be_hentry,
551 : struct vr_bridge_entry, entry);
552 :
553 203 : if (!entry || (!(be->be_flags & VR_BE_VALID_FLAG)))
554 0 : return NULL;
555 :
556 203 : if (key_len)
557 203 : *key_len = sizeof(be->be_key);
558 :
559 203 : return &be->be_key;
560 : }
561 :
562 : static void
563 0 : vr_bridge_table_data_destroy(vr_bridge_table_data *data)
564 : {
565 0 : if (data) {
566 0 : if (data->btable_file_path) {
567 0 : vr_free(data->btable_file_path, VR_BRIDGE_TABLE_DATA_OBJECT);
568 0 : data->btable_file_path = NULL;
569 : }
570 0 : vr_free(data, VR_BRIDGE_TABLE_DATA_OBJECT);
571 : }
572 :
573 0 : return;
574 : }
575 :
576 : static vr_bridge_table_data *
577 0 : vr_bridge_table_data_get(void)
578 : {
579 0 : vr_bridge_table_data *data = vr_zalloc(sizeof(vr_bridge_table_data),
580 : VR_BRIDGE_TABLE_DATA_OBJECT);
581 0 : if (!data)
582 0 : return NULL;
583 :
584 0 : if (vr_bridge_table_path) {
585 0 : data->btable_file_path = vr_zalloc(VR_UNIX_PATH_MAX,
586 : VR_BRIDGE_TABLE_DATA_OBJECT);
587 0 : if (!data->btable_file_path) {
588 0 : goto exit_func;
589 : }
590 : }
591 :
592 0 : return data;
593 :
594 0 : exit_func:
595 0 : vr_bridge_table_data_destroy(data);
596 0 : return NULL;
597 : }
598 :
599 :
600 : void
601 0 : vr_bridge_table_data_process(void *s_req)
602 : {
603 0 : int ret = 0;
604 : struct vrouter *router;
605 0 : vr_bridge_table_data *resp = NULL, *req = (vr_bridge_table_data *)s_req;
606 :
607 0 : router = vrouter_get(req->btable_rid);
608 0 : if (!router) {
609 0 : ret = -EINVAL;
610 0 : goto generate_response;
611 : }
612 :
613 0 : resp = vr_bridge_table_data_get();
614 0 : if (!resp) {
615 0 : ret = -ENOMEM;
616 0 : goto generate_response;
617 : }
618 :
619 0 : resp->btable_op = req->btable_op;
620 0 : switch (req->btable_op) {
621 0 : case SANDESH_OP_GET:
622 0 : resp->btable_size = vr_bridge_table_size(router);
623 : #if defined(__linux__) && defined(__KERNEL__)
624 : resp->btable_dev = vr_bridge_table_major;
625 : #endif
626 0 : if (vr_bridge_table_path) {
627 0 : strncpy(resp->btable_file_path, vr_bridge_table_path,
628 : VR_UNIX_PATH_MAX - 1);
629 : }
630 0 : break;
631 :
632 0 : default:
633 0 : ret = -EINVAL;
634 0 : break;
635 : }
636 :
637 0 : generate_response:
638 0 : vr_message_response(VR_BRIDGE_TABLE_DATA_OBJECT_ID, resp, ret, false);
639 0 : if (resp) {
640 0 : vr_bridge_table_data_destroy(resp);
641 0 : resp = NULL;
642 : }
643 :
644 0 : return;
645 : }
646 :
647 : int
648 53 : bridge_table_init(struct vr_rtable *rtable, struct rtable_fspec *fs)
649 : {
650 :
651 : /* If table already exists, dont create again */
652 53 : if (rtable->algo_data)
653 0 : return 0;
654 :
655 53 : vr_compute_size_bridge_otable();
656 :
657 53 : if (!vr_bridge_table && vr_huge_page_mem_get) {
658 0 : vr_bridge_table = vr_huge_page_mem_get((VR_BRIDGE_TABLE_SIZE +
659 : VR_BRIDGE_OFLOW_TABLE_SIZE), &vr_bridge_table_path);
660 0 : if (vr_bridge_table)
661 0 : vr_obridge_table = (unsigned char *)vr_bridge_table + VR_BRIDGE_TABLE_SIZE;
662 : }
663 :
664 53 : rtable->algo_data = vr_htable_attach(vrouter_get(0), vr_bridge_entries,
665 : vr_bridge_table, vr_bridge_oentries, vr_obridge_table,
666 : sizeof(struct vr_bridge_entry),
667 : sizeof(struct vr_bridge_entry_key), 0, bridge_entry_key);
668 :
669 53 : if (!rtable->algo_data)
670 0 : return vr_module_error(-ENOMEM, __FUNCTION__, __LINE__,
671 : vr_bridge_entries);
672 :
673 : /* Max VRF's does not matter as Bridge table is not per VRF. But
674 : * still this can be maintained in table
675 : */
676 53 : rtable->algo_max_vrfs = fs->rtb_max_vrfs;
677 53 : rtable->algo_add = bridge_table_add;
678 53 : rtable->algo_del = bridge_table_delete;
679 53 : rtable->algo_lookup = bridge_table_lookup;
680 53 : rtable->algo_get = bridge_table_get;
681 53 : rtable->algo_dump = bridge_table_dump;
682 :
683 53 : vn_rtable = rtable->algo_data;
684 :
685 53 : return 0;
686 : }
687 :
688 : void
689 53 : bridge_table_deinit(struct vr_rtable *rtable, struct rtable_fspec *fs,
690 : bool soft_reset)
691 : {
692 53 : if (!vn_rtable)
693 0 : return;
694 :
695 53 : vr_htable_reset(vn_rtable, bridge_table_entry_free, NULL);
696 :
697 53 : if (!soft_reset) {
698 53 : vr_htable_delete(vn_rtable);
699 53 : rtable->algo_data = NULL;
700 53 : vn_rtable = NULL;
701 : }
702 :
703 : }
704 :
705 : static void
706 0 : bridge_table_unlock(struct vr_interface *vif, uint8_t *mac, int cpu)
707 : {
708 0 : uint8_t *bridge_table_lock = vif->vif_bridge_table_lock;
709 :
710 0 : if (cpu < 0 || !bridge_table_lock)
711 0 : return;
712 :
713 0 : bridge_table_lock[cpu] = 0;
714 :
715 0 : return;
716 : }
717 :
718 : static int
719 0 : bridge_table_lock(struct vr_interface *vif, uint8_t *mac)
720 : {
721 0 : uint8_t lock = 1, *bridge_table_lock = vif->vif_bridge_table_lock;
722 : uint32_t hash;
723 : uint64_t t1s, t1ns, t2s, t2ns, diff;
724 :
725 0 : if (!bridge_table_lock)
726 0 : return -EINVAL;
727 :
728 0 : hash = vr_hash(mac, VR_ETHER_ALEN, 0);
729 0 : hash %= vr_num_cpus;
730 :
731 0 : vr_get_mono_time(&t1s, &t1ns);
732 0 : while (lock) {
733 0 : lock = vr_sync_lock_test_and_set_8u(&bridge_table_lock[hash], lock);
734 0 : if (lock) {
735 0 : vr_get_mono_time(&t2s, &t2ns);
736 0 : if (t2ns >= t1ns) {
737 0 : diff = t2ns - t1ns;
738 : } else {
739 0 : diff = 999999999 - t1ns + t2ns;
740 : }
741 :
742 0 : if (diff >= 50000) {
743 0 : return -EINVAL;
744 : }
745 : }
746 : }
747 :
748 0 : return hash;
749 : }
750 :
751 : mac_learn_t
752 0 : vr_bridge_learn(struct vrouter *router, struct vr_packet *pkt,
753 : struct vr_eth *eth, struct vr_forwarding_md *fmd)
754 : {
755 : int lock, valid_src;
756 : unsigned int trap_reason;
757 0 : bool trap = false, root = false;
758 0 : mac_learn_t ml_res = MAC_EXISTS;
759 : struct vr_packet *pkt_c;
760 0 : struct vr_nexthop *nh = NULL;
761 : struct vr_bridge_entry *be;
762 :
763 0 : if (!eth)
764 0 : return MAC_LEARN_FAILURE;
765 :
766 0 : if (IS_MAC_BMCAST(eth->eth_smac))
767 0 : return MAC_LEARN_FAILURE;
768 :
769 0 : vr_fmd_update_etree(fmd, true);
770 0 : if (vif_is_virtual(pkt->vp_if)) {
771 0 : if (pkt->vp_if->vif_flags & VIF_FLAG_ETREE_ROOT)
772 0 : root = true;
773 0 : vr_fmd_update_etree_root(fmd, root);
774 : }
775 :
776 0 : be = bridge_lookup(eth->eth_smac, fmd);
777 0 : if (be) {
778 0 : nh = be->be_nh;
779 : }
780 :
781 0 : if (!nh) {
782 0 : be = bridge_lookup((uint8_t *)vr_bcast_mac, fmd);
783 0 : if (be) {
784 0 : nh = be->be_nh;
785 : }
786 :
787 0 : if (!nh)
788 0 : return MAC_LEARN_FAILURE;
789 :
790 0 : lock = bridge_table_lock(pkt->vp_if, eth->eth_smac);
791 0 : if (lock < 0)
792 0 : return MAC_LEARN_FAILURE;
793 :
794 0 : be = bridge_add(0, fmd->fmd_dvrf, eth->eth_smac, nh->nh_id);
795 0 : if (be)
796 0 : be->be_flags |= VR_BE_MAC_NEW_FLAG;
797 0 : bridge_table_unlock(pkt->vp_if, eth->eth_smac, lock);
798 0 : if (!be)
799 0 : return MAC_LEARN_FAILURE;
800 :
801 0 : trap_reason = AGENT_TRAP_MAC_LEARN;
802 0 : trap = true;
803 0 : ml_res = MAC_LEARNT;
804 : } else {
805 0 : if (!(be->be_flags & VR_BE_MAC_MOVED_FLAG) && (nh->nh_validate_src)) {
806 0 : valid_src = nh->nh_validate_src(pkt, nh, fmd, NULL);
807 0 : if (valid_src != NH_SOURCE_VALID) {
808 0 : if (!vr_bridge_set_route_flags(be, VR_BE_MAC_MOVED_FLAG)) {
809 : /* trap the packet for mac move */
810 0 : trap_reason = AGENT_TRAP_MAC_MOVE;
811 0 : trap = true;
812 : }
813 : }
814 : }
815 0 : if (be->be_flags & VR_BE_MAC_MOVED_FLAG)
816 0 : ml_res = MAC_MOVED;
817 : }
818 :
819 0 : vr_sync_fetch_and_add_64u(&be->be_packets, 1);
820 :
821 0 : if (trap) {
822 0 : pkt_c = pkt_cow(pkt, 0);
823 0 : if (!pkt_c) {
824 0 : pkt_c = pkt;
825 0 : ml_res = MAC_TRAPPED;
826 : }
827 :
828 0 : vr_trap(pkt_c, fmd->fmd_dvrf,
829 0 : trap_reason, (void *)&be->be_hentry.hentry_index);
830 : }
831 :
832 :
833 0 : return ml_res;
834 : }
835 :
836 : unsigned int
837 110 : vr_bridge_input(struct vrouter *router, struct vr_packet *pkt,
838 : struct vr_forwarding_md *fmd)
839 : {
840 : int reason, handled;
841 110 : l4_pkt_type_t l4_type = L4_TYPE_UNKNOWN;
842 110 : unsigned short pull_len, overlay_len = VROUTER_OVERLAY_LEN;
843 : int8_t *dmac;
844 : int8_t *lookup_mac;
845 : mac_learn_t ml_res;
846 : struct vr_bridge_entry *be;
847 110 : struct vr_nexthop *nh = NULL;
848 110 : struct vr_vrf_stats *stats = NULL;
849 : int mac_flags;
850 :
851 110 : if ((pkt->vp_type == VP_TYPE_IP) || (pkt->vp_type == VP_TYPE_IP6)) {
852 106 : if (fmd->fmd_dscp < 0) {
853 101 : if (pkt->vp_type == VP_TYPE_IP) {
854 93 : fmd->fmd_dscp =
855 93 : vr_inet_get_tos((struct vr_ip *)pkt_network_header(pkt));
856 8 : } else if (pkt->vp_type == VP_TYPE_IP6) {
857 8 : fmd->fmd_dscp =
858 8 : vr_inet6_get_tos((struct vr_ip6 *)pkt_network_header(pkt));
859 : }
860 : }
861 : } else {
862 4 : if (fmd->fmd_dotonep < 0) {
863 4 : fmd->fmd_dotonep = vr_vlan_get_tos(pkt_data(pkt));
864 : }
865 : }
866 :
867 110 : if (!fmd->fmd_to_me) {
868 110 : if ((pkt->vp_if->vif_flags & VIF_FLAG_MAC_LEARN) ||
869 110 : (pkt->vp_nh && (pkt->vp_nh->nh_flags & NH_FLAG_MAC_LEARN))) {
870 0 : ml_res = vr_bridge_learn(router, pkt,
871 0 : (struct vr_eth *)pkt_data(pkt), fmd);
872 0 : if (ml_res == MAC_TRAPPED)
873 0 : return 0;
874 : }
875 : }
876 :
877 110 : dmac = (int8_t *) pkt_data(pkt);
878 110 : mac_flags = vr_bridge_get_mac_type((char *)dmac);
879 110 : pull_len = 0;
880 110 : if ((pkt->vp_type == VP_TYPE_IP) || (pkt->vp_type == VP_TYPE_IP6) ||
881 4 : (pkt->vp_type == VP_TYPE_ARP)) {
882 110 : pull_len = pkt_get_network_header_off(pkt) - pkt_head_space(pkt);
883 110 : if (pull_len && !pkt_pull(pkt, pull_len)) {
884 0 : PKT_LOG(VP_DROP_PULL, pkt, 0, VR_BRIDGE_C, __LINE__);
885 0 : vr_pfree(pkt, VP_DROP_PULL);
886 0 : return 0;
887 : }
888 : }
889 :
890 : /* Do the bridge lookup for the packets not meant for "me" */
891 110 : if (!fmd->fmd_to_me) {
892 : /*
893 : * If DHCP packet coming from VM, Trap it to Agent before doing the bridge
894 : * lookup itself
895 : */
896 110 : if (vif_is_virtual(pkt->vp_if)) {
897 :
898 108 : if (pkt->vp_type == VP_TYPE_IP)
899 97 : l4_type = vr_ip_well_known_packet(pkt);
900 11 : else if (pkt->vp_type == VP_TYPE_IP6)
901 7 : l4_type = vr_ip6_well_known_packet(pkt);
902 :
903 108 : if (l4_type == L4_TYPE_DHCP_REQUEST) {
904 0 : if (pkt->vp_if->vif_flags & VIF_FLAG_DHCP_ENABLED) {
905 0 : vr_trap(pkt, fmd->fmd_dvrf, AGENT_TRAP_L3_PROTOCOLS, NULL);
906 0 : return 0;
907 : }
908 : }
909 :
910 108 : if (l4_type == L4_TYPE_IGMP) {
911 0 : if (pkt->vp_if->vif_flags & VIF_FLAG_IGMP_ENABLED) {
912 0 : vr_trap(pkt, fmd->fmd_dvrf, AGENT_TRAP_L3_PROTOCOLS, NULL);
913 0 : return 0;
914 : }
915 : }
916 :
917 : /*
918 : * Handle the unicast ARP, coming from VM, not
919 : * destined to us. Broadcast ARP requests would be handled
920 : * in L2 multicast nexthop. Multicast ARP on fabric
921 : * interface also would be handled in L2 multicast nexthop.
922 : * Unicast ARP packets on fabric interface would be handled
923 : * in plug routines of interface.
924 : */
925 108 : if (!(mac_flags & MAC_BMC_BIT_SET) ||
926 0 : (pkt->vp_if->vif_flags & VIF_FLAG_MAC_PROXY)) {
927 108 : handled = 0;
928 108 : if (pkt->vp_type == VP_TYPE_ARP) {
929 4 : handled = vr_arp_input(pkt, fmd, dmac);
930 4 : if (VR_RX_HANDLER_PASS == handled)
931 0 : return handled;
932 104 : } else if (l4_type == L4_TYPE_NEIGHBOUR_SOLICITATION) {
933 0 : handled = vr_neighbor_input(pkt, fmd, dmac);
934 : }
935 :
936 108 : if (handled)
937 1 : return 0;
938 : }
939 : }
940 :
941 109 : if ((mac_flags & MAC_BMC_BIT_SET) &&
942 0 : (pkt->vp_if->vif_mcast_vrf != 65535)) {
943 :
944 0 : fmd->fmd_dvrf = pkt->vp_if->vif_mcast_vrf;
945 : }
946 :
947 109 : be = NULL;
948 109 : lookup_mac = dmac;
949 109 : if (mac_flags & MAC_UC_BIT_SET) {
950 109 : be = bridge_lookup(lookup_mac, fmd);
951 : } else {
952 0 : if (pkt->vp_type == VP_TYPE_IP) {
953 0 : if (!(pkt->vp_if->vif_flags & VIF_FLAG_IGMP_ENABLED)) {
954 0 : if (!vif_is_fabric(pkt->vp_if) && vif_is_tap(pkt->vp_if)) {
955 : /*
956 : * - Comes here for VxLAN tunnel based multicast data.
957 : * For this, IGMP is always disabled on fabric vif.
958 : *
959 : * - Packets originating from VM with IGMP disabled.
960 : * Locally generated multicast packets are not handled
961 : * by EVPN multicast in P1. We should do lookup for
962 : * broadcast mac to be able to use IMET route.
963 : */
964 0 : lookup_mac = (int8_t *)vr_bcast_mac;
965 : }
966 : }
967 : } else {
968 0 : lookup_mac = (int8_t *)vr_bcast_mac;
969 : }
970 0 : be = bridge_lookup(lookup_mac, fmd);
971 0 : if (!be) {
972 : /* Fallback MAC lookup */
973 0 : lookup_mac = (int8_t *)vr_bcast_mac;
974 0 : be = bridge_lookup(lookup_mac, fmd);
975 : }
976 : }
977 109 : if (be)
978 108 : nh = be->be_nh;
979 :
980 109 : if (!nh || nh->nh_type == NH_DISCARD) {
981 :
982 : /* If Flooding of unknown unicast not allowed, drop the packet */
983 1 : if (!vr_unknown_uc_flood(pkt->vp_if, pkt->vp_nh) ||
984 0 : (mac_flags & MAC_BMC_BIT_SET)) {
985 1 : PKT_LOG(VP_DROP_L2_NO_ROUTE, pkt, 0, VR_BRIDGE_C, __LINE__);
986 1 : vr_pfree(pkt, VP_DROP_L2_NO_ROUTE);
987 1 : return 0;
988 : }
989 :
990 0 : be = bridge_lookup(vr_bcast_mac, fmd);
991 0 : if (!be || !(nh = be->be_nh)) {
992 0 : PKT_LOG(VP_DROP_L2_NO_ROUTE, pkt, 0, VR_BRIDGE_C, __LINE__);
993 0 : vr_pfree(pkt, VP_DROP_L2_NO_ROUTE);
994 0 : return 0;
995 : }
996 0 : if (vr_inet_vrf_stats) {
997 0 : stats = vr_inet_vrf_stats(fmd->fmd_dvrf, pkt->vp_cpu);
998 0 : if (stats)
999 0 : stats->vrf_uuc_floods++;
1000 : }
1001 :
1002 : /* Treat this unknown unicast packet as multicast */
1003 0 : pkt->vp_flags |= VP_FLAG_MULTICAST;
1004 : }
1005 :
1006 108 : if (be)
1007 108 : vr_sync_fetch_and_add_64u(&be->be_packets, 1);
1008 :
1009 108 : if (nh->nh_type != NH_L2_RCV)
1010 79 : overlay_len = VROUTER_L2_OVERLAY_LEN;
1011 :
1012 : /*
1013 : * If the tunnel is a PBB tunnel, we need to accomodate for Itag
1014 : * and an extra ethernet (for Bmac) + Vlan header
1015 : */
1016 108 : if (nh->nh_flags & NH_FLAG_TUNNEL_PBB) {
1017 0 : overlay_len += VR_ETHER_HLEN + sizeof(struct vr_vlan_hdr) +
1018 : sizeof(struct vr_pbb_itag);
1019 : }
1020 : }
1021 :
1022 : /* Adjust MSS for V4 and V6 packets */
1023 108 : if ((pkt->vp_type == VP_TYPE_IP) || (pkt->vp_type == VP_TYPE_IP6)) {
1024 :
1025 105 : if (vif_is_virtual(pkt->vp_if) &&
1026 103 : vr_from_vm_mss_adj && vr_pkt_from_vm_tcp_mss_adj) {
1027 :
1028 103 : if ((reason = vr_pkt_from_vm_tcp_mss_adj(pkt, overlay_len))) {
1029 0 : PKT_LOG(reason, pkt, 0, VR_BRIDGE_C, __LINE__);
1030 0 : vr_pfree(pkt, reason);
1031 0 : return 0;
1032 : }
1033 : }
1034 :
1035 105 : if (fmd->fmd_to_me) {
1036 0 : handled = vr_l3_input(pkt, fmd);
1037 0 : if (!handled) {
1038 0 : PKT_LOG(VP_DROP_NOWHERE_TO_GO, pkt, 0, VR_BRIDGE_C, __LINE__);
1039 0 : vr_pfree(pkt, VP_DROP_NOWHERE_TO_GO);
1040 : }
1041 0 : return 0;
1042 : }
1043 :
1044 : /* If a ucast packet is coming from fabric and going to fabric, drop it */
1045 105 : if (be && (mac_flags & MAC_UC_BIT_SET) && vif_is_fabric(pkt->vp_if) &&
1046 1 : (nh->nh_type == NH_TUNNEL) &&
1047 1 : (!(pkt->vp_if->vif_flags & VIF_FLAG_FAB_GW_MODE))) {
1048 1 : PKT_LOG(VP_DROP_INVALID_SOURCE, pkt, 0, VR_BRIDGE_C, __LINE__);
1049 1 : vr_pfree(pkt, VP_DROP_INVALID_SOURCE);
1050 1 : return 0;
1051 : }
1052 : }
1053 :
1054 :
1055 107 : if (pull_len && !pkt_push(pkt, pull_len)) {
1056 0 : PKT_LOG(VP_DROP_PUSH, pkt, 0, VR_BRIDGE_C, __LINE__);
1057 0 : vr_pfree(pkt, VP_DROP_PUSH);
1058 0 : return 0;
1059 : }
1060 :
1061 107 : nh_output(pkt, nh, fmd);
1062 107 : return 0;
1063 : }
1064 :
1065 53 : void vr_compute_size_bridge_otable(void)
1066 : {
1067 53 : if (!vr_bridge_oentries)
1068 0 : vr_bridge_oentries = ((vr_bridge_entries / 5) + 1023) & ~1023;
1069 53 : }
|