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